From fba22d2facf66409602ca82d7a8477db1226de3d Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 6 Nov 2017 15:32:02 +0100 Subject: [PATCH 001/227] design document for handling recursive functions --- doc/design_recfuns.md | 85 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 doc/design_recfuns.md diff --git a/doc/design_recfuns.md b/doc/design_recfuns.md new file mode 100644 index 000000000..9dbe5c874 --- /dev/null +++ b/doc/design_recfuns.md @@ -0,0 +1,85 @@ +# Design for handling recursive functions + +Main source of inspiration is [Sutter, Köksal & Kuncak 2011], +as implemented in Leon, but the main +differences is that we should unroll function definitions directly from the +inside of Z3, in a backtracking way. Termination and fairness are ensured by +iterative-deepening on the maximum number of unrollings in a given branch. + +## Unfolding + +The idea is that every function definition `f(x1…xn) := rhs[x1…xn]` is +compiled into: + +- a list of cases `A_f_i[x1…xn] => f(x1…xn) = rhs_i[x1…xn]`. + When `A_f_i[t1…tn]` becomes true in the model, `f(t1…tn)` is said to be + *unfolded* and the clause `A_f_i[t1…tn] => f(t1…tn) = rhs_i[t1…tn]` + is added as an auxiliary clause. +- a list of constraints `Γ_f_i[x1…xn] <=> A_f_i[x1…xn]` + that states when `A_f_i[x1…xn]` should be true, depending on inputs `x1…xn`. + For every term `f(t1…tn)` present in congruence closure, we + immediately add all the `Γ_f_i[t1…tn] <=> A_f_i[t1…tn]` as auxiliary clauses + (maybe during internalization of `f(t1…tn)`?). + +where each `A_f_i[x1…xn]` is a special new predicate representing the +given case of `f`, and `rhs_i` does not contain any `ite`. +We assume pattern matching has been compiled to `ite` beforehand. + +For example, `fact(n) := if n<2 then 1 else n * fact(n-1)` is compiled into: + +- `A_fact_0[n] => fact(n) = 1` +- `A_fact_1[n] => fact(n) = n * fact(n-1)` +- `A_fact_0[n] <=> n < 2` +- `A_fact_1[n] <=> ¬(n < 2)` + +The 2 first clauses are only added when `A_fact_0[t]` is true +(respectively `A_fact_1[t]` is true). +The 2 other clauses are added as soon as `fact(t)` is internalized. + +## Termination + +To ensure termination, we define variables: + +- `unfold_depth: int` +- `current_max_unfold_depth: int` +- `global_max_unfold_depth: int` + +and a special literal `[max_depth=$n]` for each `n:int`. +Solving is done under the local assumption +`[max_depth=$current_max_unfold_depth]` (this should be handled in some outer +loop, e.g. in a custom tactic). + +Whenever `A_f_i[t1…tn]` becomes true (for any `f`), we increment +`unfold_depth`. If `unfold_depth > current_max_unfold_depth`, then +the conflict clause `[max_depth=$current_max_unfold_depth] => Γ => false` +where `Γ` is the conjunction of all `A_f_i[t1…tn]` true in the trail. + +For non-recursive functions, we don't have to increment `unfold_depth`. Some other functions that are known + +If the solver answers "SAT", we have a model. +Otherwise, if `[max_depth=$current_max_unfold_depth]` is part of the +unsat-core, then we increase `current_max_unfold_depth`. +If `current_max_unfold_depth == global_max_unfold_depth` then +we report "UNKNOWN" (reached global depth limit), otherwise we can +try to `solve()` again with the new assumption (higher depth limit). + +## Tactic + +there should be a parametrized tactic `funrec(t, n)` where `t` is the tactic +used to solve (under assumption that depth is limited to `current_max_unfold_depth`) +and `n` is an integer that is assigned to `global_max_unfold_depth`. + +This way, to try and find models for a problem with recursive functions + LIA, +one could use something like `(funrec (then simplify dl smt) 100)`. + +## Expected benefits + +This addition to Z3 would bring many benefits compared to current alternatives (Leon, quantifiers, …) + +- should be very fast and lightweight + (compared to Leon or quantifiers). + In particular, every function call is very lightweight even compared to Leon (no need for full model building, followed by unsat core extraction) +- possibility of answering "SAT" for any `QF_*` fragment + + recursive functions +- makes `define-funs-rec` a first-class citizen of the language, usable to model user-defined theories or to analyze functional + programs directly From d5e134dd948c103d8883afe9398f7dc31a398ed5 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 7 Nov 2017 15:57:27 +0100 Subject: [PATCH 002/227] wip: add recursive functions --- doc/design_recfuns.md | 8 + src/ast/CMakeLists.txt | 1 + src/ast/ast_pp.h | 22 ++ src/ast/recfun_decl_plugin.cpp | 469 +++++++++++++++++++++++++++ src/ast/recfun_decl_plugin.h | 246 ++++++++++++++ src/ast/reg_decl_plugins.cpp | 4 + src/cmd_context/cmd_context.cpp | 48 ++- src/cmd_context/cmd_context.h | 5 + src/parsers/smt2/smt2parser.cpp | 6 +- src/smt/CMakeLists.txt | 1 + src/smt/params/smt_params.cpp | 1 + src/smt/params/smt_params.h | 4 + src/smt/params/smt_params_helper.pyg | 3 +- src/smt/smt_setup.cpp | 10 + src/smt/smt_setup.h | 1 + src/smt/theory_recfun.cpp | 363 +++++++++++++++++++++ src/smt/theory_recfun.h | 155 +++++++++ src/util/scoped_ptr_vector.h | 8 + src/util/trail.h | 11 + 19 files changed, 1362 insertions(+), 4 deletions(-) create mode 100644 src/ast/recfun_decl_plugin.cpp create mode 100644 src/ast/recfun_decl_plugin.h create mode 100644 src/smt/theory_recfun.cpp create mode 100644 src/smt/theory_recfun.h diff --git a/doc/design_recfuns.md b/doc/design_recfuns.md index 9dbe5c874..89980931e 100644 --- a/doc/design_recfuns.md +++ b/doc/design_recfuns.md @@ -83,3 +83,11 @@ This addition to Z3 would bring many benefits compared to current alternatives ( recursive functions - makes `define-funs-rec` a first-class citizen of the language, usable to model user-defined theories or to analyze functional programs directly + +## Optimizations + +- maybe `C_f_i` literals should never be decided on + (they can always be propagated). + Even stronger: they should not be part of conflicts? + (i.e. tune conflict resolution to always resolve + these literals away, disregarding their level) diff --git a/src/ast/CMakeLists.txt b/src/ast/CMakeLists.txt index 4dcdd2a35..f452c07d5 100644 --- a/src/ast/CMakeLists.txt +++ b/src/ast/CMakeLists.txt @@ -36,6 +36,7 @@ z3_add_component(ast occurs.cpp pb_decl_plugin.cpp pp.cpp + recfun_decl_plugin.cpp reg_decl_plugins.cpp seq_decl_plugin.cpp shared_occs.cpp diff --git a/src/ast/ast_pp.h b/src/ast/ast_pp.h index 997b1a6e0..514aba32f 100644 --- a/src/ast/ast_pp.h +++ b/src/ast/ast_pp.h @@ -32,5 +32,27 @@ struct mk_pp : public mk_ismt2_pp { } }; +// +#include +#include "ast/expr_functors.h" +#include "ast/expr_substitution.h" +#include "ast/recfun_decl_plugin.h" +#include "ast/ast_pp.h" +#include "util/scoped_ptr_vector.h" + +#define DEBUG(x) do { auto& out = std::cout; out << "recfun: "; x; out << '\n' << std::flush; } while(0) +#define VALIDATE_PARAM(m, _pred_) if (!(_pred_)) m.raise_exception("invalid parameter to recfun " #_pred_); + + +namespace recfun { + case_pred::case_pred(ast_manager & m, family_id fid, std::string const & s, sort_ref_vector const & domain) + : m_name(), m_name_buf(s), m_domain(domain), m_decl(m) + { + m_name = symbol(m_name_buf.c_str()); + func_decl_info info(fid, OP_FUN_CASE_PRED); + m_decl = m.mk_func_decl(m_name, domain.size(), domain.c_ptr(), m.mk_bool_sort(), info); + } + + case_def::case_def(ast_manager &m, + family_id fid, + def * d, + std::string & name, + sort_ref_vector const & arg_sorts, + unsigned num_guards, expr ** guards, expr* rhs) + : m_pred(m, fid, name, arg_sorts), m_guards(m), m_rhs(expr_ref(rhs,m)), m_def(d) { + for (unsigned i=0; i m_branches; + + public: + case_state(ast_manager & m) : m_reg(), m_manager(m), m_branches() {} + + bool empty() const { return m_branches.empty(); } + ast_manager & m() const { return m_manager; } + region & reg() { return m_reg; } + + branch pop_branch() { + branch res = m_branches.back(); + m_branches.pop_back(); + return res; + } + + void push_branch(branch const & b) { m_branches.push_back(b); } + + + unfold_lst const * cons_unfold(expr * e, unfold_lst const * next) { + return new (reg()) unfold_lst{e, next}; + } + unfold_lst const * cons_unfold(expr * e1, expr * e2, unfold_lst const * next) { + return cons_unfold(e1, cons_unfold(e2, next)); + } + unfold_lst const * mk_unfold_lst(expr * e) { + return cons_unfold(e, nullptr); + } + + ite_lst const * cons_ite(app * ite, ite_lst const * next) { + return new (reg()) ite_lst{ite, next}; + } + + choice_lst const * cons_choice(app * ite, bool sign, choice_lst const * next) { + return new (reg()) choice_lst{ite, sign, next}; + } + }; + + //next) { + app * ite = choices->ite; + SASSERT(m.is_ite(ite)); + + // condition to add to the guard + expr * cond0 = ite->get_arg(0); + conditions.push_back(choices->sign ? cond0 : m.mk_not(cond0)); + + // binding to add to the substitution + subst.insert(ite, choices->sign ? ite->get_arg(1) : ite->get_arg(2)); + } + } + + // substitute `subst` in `e` + expr_ref replace_subst(th_rewriter & th_rw, ast_manager & m, + expr_substitution & subst, expr * e) { + th_rw.reset(); + th_rw.set_substitution(&subst); + expr_ref res(m); + th_rw(e, res); + return res; + } + + void def::add_case(std::string & name, unsigned n_conditions, expr ** conditions, expr * rhs, bool is_imm) { + case_def c(m(), m_fid, this, name, get_domain(), n_conditions, conditions, rhs); + c.set_is_immediate(is_imm); + TRACE("recfun", tout << "add_case " << name << " " << mk_pp(rhs, m()) + << " :is_imm " << is_imm + << " :guards " << mk_pp_vec(n_conditions, (ast**)conditions, m());); + DEBUG(out << "add_case " << name << " " << mk_pp(rhs, m()) + << " :is_imm " << is_imm + << " :guards " << mk_pp_vec(n_conditions, (ast**)conditions, m())); + m_cases.push_back(c); + } + + + // Compute a set of cases, given the RHS + void def::compute_cases(is_immediate_pred & is_i, th_rewriter & th_rw, + unsigned n_vars, var *const * vars, expr* rhs0) + { + if (m_cases.size() != 0) { + TRACE("recfun", tout << "bug: cases for " << m_name << " has cases already";); + UNREACHABLE(); + } + SASSERT(n_vars = m_domain.size()); + + DEBUG(out << "compute cases " << mk_pp(rhs0, m())); + + unsigned case_idx = 0; + std::string name; + + name.append("case_"); + name.append(m_name.bare_str()); + name.append("_"); + + for (unsigned i=0; i stack; + stack.push_back(b.to_unfold->e); + + b.to_unfold = b.to_unfold->next; + + while (! stack.empty()) { + expr * e = stack.back(); + stack.pop_back(); + + if (m().is_ite(e)) { + // need to do a case split on `e`, forking the search space + b.to_split = st.cons_ite(to_app(e), b.to_split); + } else if (is_app(e)) { + // explore arguments + app * a = to_app(e); + + for (unsigned i=0; i < a->get_num_args(); ++i) + stack.push_back(a->get_arg(i)); + } + } + } + + if (b.to_split != nullptr) { + // split one `ite`, which will lead to distinct (sets of) cases + app * ite = b.to_split->ite; + SASSERT(m().is_ite(ite)); + + /* explore both positive choice and negative choice. + * each contains a longer path, with `ite` mapping to `true` (resp. `false), + * and must unfold the `then` (resp. `else`) branch. + * We must also unfold the test itself, for it could contain + * tests. + */ + + branch b_pos(st.cons_choice(ite, true, b.path), + b.to_split->next, + st.cons_unfold(ite->get_arg(0), ite->get_arg(1), b.to_unfold)); + branch b_neg(st.cons_choice(ite, false, b.path), + b.to_split->next, + st.cons_unfold(ite->get_arg(0), ite->get_arg(2), b.to_unfold)); + + st.push_branch(b_neg); + st.push_branch(b_pos); + } + else { + // leaf of the search tree + + expr_ref_vector conditions_raw(m()); + expr_substitution subst(m()); + convert_path(m(), b.path, conditions_raw, subst); + + // substitute, to get rid of `ite` terms + expr_ref case_rhs = replace_subst(th_rw, m(), subst, rhs); + expr_ref_vector conditions(m()); + for (expr * g : conditions_raw) { + expr_ref g_subst(replace_subst(th_rw, m(), subst, g), m()); + conditions.push_back(g_subst); + } + + + unsigned old_name_len = name.size(); + { // TODO: optimize? this does many copies + std::ostringstream sout; + sout << ((unsigned long) case_idx); + name.append(sout.str()); + } + case_idx ++; + + // yield new case + bool is_imm = is_i(case_rhs); + add_case(name, conditions.size(), conditions.c_ptr(), case_rhs, is_imm); + name.resize(old_name_len); + } + } + + TRACE("recfun", tout << "done analysing " << get_name();); + } + + /* + * Main manager for defined functions + */ + + util::util(ast_manager & m, family_id id) + : m_manager(m), m_family_id(id), m_th_rw(m), m_plugin(0) { + m_plugin = dynamic_cast(m.get_plugin(m_family_id)); + } + + def * util::decl_fun(symbol const& name, unsigned n, sort *const * domain, sort * range) { + return alloc(def, m(), m_family_id, name, n, domain, range); + } + + void util::set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) { + d.set_definition(n_vars, vars, rhs); + } + + + // used to know which `app` are from this theory + struct is_imm_pred : is_immediate_pred { + util & u; + is_imm_pred(util & u) : u(u) {} + bool operator()(expr * rhs) { + // find an `app` that is an application of a defined function + struct find : public i_expr_pred { + util & u; + find(util & u) : u(u) {} + bool operator()(expr * e) override { + //return is_app(e) ? u.owns_app(to_app(e)) : false; + if (! is_app(e)) return false; + + app * a = to_app(e); + return u.is_defined(a); + } + }; + find f(u); + check_pred cp(f, u.m()); + bool contains_defined_fun = cp(rhs); + return ! contains_defined_fun; + } + }; + + // set definition + void promise_def::set_definition(unsigned n_vars, var * const * vars, expr * rhs) { + SASSERT(n_vars == d->get_arity()); + + is_imm_pred is_i(*u); + d->compute_cases(is_i, u->get_th_rewriter(), n_vars, vars, rhs); + } + + namespace decl { + plugin::plugin() : decl_plugin(), m_defs(), m_case_defs(), m_def_block() {} + plugin::~plugin() { finalize(); } + + void plugin::finalize() { + for (auto& kv : m_defs) { + dealloc(kv.m_value); + } + m_defs.reset(); + // m_case_defs does not own its data, no need to deallocate + m_case_defs.reset(); + m_util = 0; // force deletion + } + + util & plugin::u() const { + SASSERT(m_manager); + SASSERT(m_family_id != null_family_id); + if (m_util.get() == 0) { + m_util = alloc(util, *m_manager, m_family_id); + } + return *(m_util.get()); + } + + promise_def plugin::mk_def(symbol const& name, unsigned n, sort *const * params, sort * range) { + SASSERT(! m_defs.contains(name)); + def* d = u().decl_fun(name, n, params, range); + m_defs.insert(name, d); + return promise_def(&u(), d); + } + + void plugin::set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) { + u().set_definition(d, n_vars, vars, rhs); + for (case_def & c : d.get_def()->get_cases()) { + m_case_defs.insert(c.get_name(), &c); + } + } + + def* plugin::mk_def(symbol const& name, unsigned n, sort ** params, sort * range, + unsigned n_vars, var ** vars, expr * rhs) { + SASSERT(! m_defs.contains(name)); + promise_def d = mk_def(name, n, params, range); + set_definition(d, n_vars, vars, rhs); + return d.get_def(); + } + + func_decl * plugin::mk_fun_pred_decl(unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) + { + VALIDATE_PARAM(m(), m().is_bool(range) && num_parameters == 1 && parameters[0].is_ast()); + func_decl_info info(m_family_id, OP_FUN_CASE_PRED, num_parameters, parameters); + info.m_private_parameters = true; + return m().mk_func_decl(symbol(parameters[0].get_symbol()), arity, domain, range, info); + } + + func_decl * plugin::mk_fun_defined_decl(decl_kind k, unsigned num_parameters, + parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) + { + VALIDATE_PARAM(m(), num_parameters == 1 && parameters[0].is_ast()); + func_decl_info info(m_family_id, k, num_parameters, parameters); + info.m_private_parameters = true; + return m().mk_func_decl(symbol(parameters[0].get_symbol()), arity, + domain, range, info); + } + + // generic declaration of symbols + func_decl * plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) + { + switch(k) { + case OP_FUN_CASE_PRED: + return mk_fun_pred_decl(num_parameters, parameters, arity, domain, range); + case OP_FUN_DEFINED: + return mk_fun_defined_decl(k, num_parameters, parameters, arity, domain, range); + default: + UNREACHABLE(); return 0; + } + } + } +} \ No newline at end of file diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h new file mode 100644 index 000000000..e9b75a409 --- /dev/null +++ b/src/ast/recfun_decl_plugin.h @@ -0,0 +1,246 @@ +/*++ +Module Name: + + recfun_decl_plugin.h + +Abstract: + + Declaration and definition of (potentially recursive) functions + +Author: + + Simon Cruanes 2017-11 + +Revision History: + +--*/ + +#pragma once + +#include "ast/ast.h" +#include "ast/rewriter/th_rewriter.h" + +namespace recfun { + class case_def; // cases; + + ast_manager & m_manager; + symbol m_name; // def_map; + typedef map case_def_map; + + mutable scoped_ptr m_util; + def_map m_defs; // function->def + case_def_map m_case_defs; // case_pred->def + svector m_def_block; + + ast_manager & m() { return *m_manager; } + public: + plugin(); + virtual ~plugin() override; + virtual void finalize() override; + + util & u() const; // build or return util + + virtual bool is_fully_interp(sort * s) const override { return false; } // might depend on unin sorts + + virtual decl_plugin * mk_fresh() override { return alloc(plugin); } + + virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override { UNREACHABLE(); return 0; } + + virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; + + promise_def mk_def(symbol const& name, unsigned n, sort *const * params, sort * range); + + void set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs); + + def* mk_def(symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs); + + bool has_def(const symbol& s) const { return m_defs.contains(s); } + def const& get_def(const symbol& s) const { return *(m_defs[s]); } + promise_def get_promise_def(const symbol &s) const { return promise_def(&u(), m_defs[s]); } + def& get_def(symbol const& s) { return *(m_defs[s]); } + bool has_case_def(const symbol& s) const { return m_case_defs.contains(s); } + case_def& get_case_def(symbol const& s) { SASSERT(has_case_def(s)); return *(m_case_defs[s]); } + bool is_declared(symbol const& s) const { return m_defs.contains(s); } + private: + func_decl * mk_fun_pred_decl(unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + func_decl * mk_fun_defined_decl(decl_kind k, + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + }; + } + + // Varus utils for recursive functions + class util { + friend class decl::plugin; + + ast_manager & m_manager; + family_id m_family_id; + th_rewriter m_th_rw; + decl::plugin * m_plugin; + + bool compute_is_immediate(expr * rhs); + void set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs); + public: + util(ast_manager &m, family_id); + + ast_manager & m() { return m_manager; } + th_rewriter & get_th_rewriter() { return m_th_rw; } + bool is_case_pred(app * e) const { return is_app_of(e, m_family_id, OP_FUN_CASE_PRED); } + bool is_defined(app * e) const { return is_app_of(e, m_family_id, OP_FUN_DEFINED); } + bool owns_app(app * e) const { return e->get_family_id() == m_family_id; } + + //has_def(s)); + return m_plugin->get_def(s); + } + + case_def& get_case_def(symbol const & s) { + SASSERT(m_plugin->has_case_def(s)); + return m_plugin->get_case_def(s); + } + + app* mk_fun_defined(def const & d, unsigned n_args, expr * const * args) { + return m().mk_app(d.get_decl(), n_args, args); + } + app* mk_fun_defined(def const & d, ptr_vector const & args) { + return mk_fun_defined(d, args.size(), args.c_ptr()); + } + app* mk_case_pred(case_pred const & p, ptr_vector const & args) { + return m().mk_app(p.get_decl(), args.size(), args.c_ptr()); + } + }; +} + +typedef recfun::def recfun_def; +typedef recfun::case_def recfun_case_def; +typedef recfun::decl::plugin recfun_decl_plugin; +typedef recfun::util recfun_util; diff --git a/src/ast/reg_decl_plugins.cpp b/src/ast/reg_decl_plugins.cpp index 985ecee9e..f8abe81d8 100644 --- a/src/ast/reg_decl_plugins.cpp +++ b/src/ast/reg_decl_plugins.cpp @@ -22,6 +22,7 @@ Revision History: #include "ast/array_decl_plugin.h" #include "ast/bv_decl_plugin.h" #include "ast/datatype_decl_plugin.h" +#include "ast/recfun_decl_plugin.h" #include "ast/dl_decl_plugin.h" #include "ast/seq_decl_plugin.h" #include "ast/pb_decl_plugin.h" @@ -40,6 +41,9 @@ void reg_decl_plugins(ast_manager & m) { if (!m.get_plugin(m.mk_family_id(symbol("datatype")))) { m.register_plugin(symbol("datatype"), alloc(datatype_decl_plugin)); } + if (!m.get_plugin(m.mk_family_id(symbol("recfun")))) { + m.register_plugin(symbol("recfun"), alloc(recfun_decl_plugin)); + } if (!m.get_plugin(m.mk_family_id(symbol("datalog_relation")))) { m.register_plugin(symbol("datalog_relation"), alloc(datalog::dl_decl_plugin)); } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index ec2eea032..75ed4e7eb 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -678,6 +678,8 @@ bool cmd_context::logic_has_datatype() const { return !has_logic() || smt_logics::logic_has_datatype(m_logic); } +bool cmd_context::logic_has_recfun() const { return true; } + void cmd_context::init_manager_core(bool new_manager) { SASSERT(m_manager != 0); SASSERT(m_pmanager != 0); @@ -690,6 +692,7 @@ void cmd_context::init_manager_core(bool new_manager) { register_plugin(symbol("bv"), alloc(bv_decl_plugin), logic_has_bv()); register_plugin(symbol("array"), alloc(array_decl_plugin), logic_has_array()); register_plugin(symbol("datatype"), alloc(datatype_decl_plugin), logic_has_datatype()); + register_plugin(symbol("recfun"), alloc(recfun_decl_plugin), logic_has_recfun()); register_plugin(symbol("seq"), alloc(seq_decl_plugin), logic_has_seq()); register_plugin(symbol("pb"), alloc(pb_decl_plugin), logic_has_pb()); register_plugin(symbol("fpa"), alloc(fpa_decl_plugin), logic_has_fpa()); @@ -705,6 +708,7 @@ void cmd_context::init_manager_core(bool new_manager) { load_plugin(symbol("bv"), logic_has_bv(), fids); load_plugin(symbol("array"), logic_has_array(), fids); load_plugin(symbol("datatype"), logic_has_datatype(), fids); + load_plugin(symbol("recfun"), logic_has_recfun(), fids); load_plugin(symbol("seq"), logic_has_seq(), fids); load_plugin(symbol("fpa"), logic_has_fpa(), fids); load_plugin(symbol("pb"), logic_has_pb(), fids); @@ -868,7 +872,24 @@ void cmd_context::insert(symbol const & s, object_ref * r) { m_object_refs.insert(s, r); } -void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, svector const& ids, expr* e) { +recfun_decl_plugin * cmd_context::get_recfun_plugin() { + ast_manager & m = get_ast_manager(); + family_id id = m.get_family_id("recfun"); + recfun_decl_plugin* p = reinterpret_cast(m.get_plugin(id)); + SASSERT(p); + return p; +} + + +recfun::promise_def cmd_context::decl_rec_fun(const symbol &name, unsigned int arity, sort *const *domain, sort *range) { + SASSERT(logic_has_recfun()); + recfun_decl_plugin* p = get_recfun_plugin(); + recfun::promise_def def = p->mk_def(name, arity, domain, range); + return def; +} + +// insert a recursive function as a regular quantified axiom +void cmd_context::insert_rec_fun_as_axiom(func_decl *f, expr_ref_vector const& binding, svector const &ids, expr* e) { expr_ref eq(m()); app_ref lhs(m()); lhs = m().mk_app(f, binding.size(), binding.c_ptr()); @@ -899,6 +920,31 @@ void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, s assert_expr(eq); } +// TODO: make this a parameter +#define USE_NATIVE_RECFUN 1 + +void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, svector const& ids, expr* rhs) { + TRACE("recfun", tout<<"define recfun " << f->get_name() + <<" = " << mk_pp(rhs, m()) << "\n";); + + if (! USE_NATIVE_RECFUN) { + // just use an axiom + insert_rec_fun_as_axiom(f, binding, ids, rhs); + return; + } + + recfun_decl_plugin* p = get_recfun_plugin(); + + var_ref_vector vars(m()); + for (expr* b : binding) { + SASSERT(is_var(b)); + vars.push_back(to_var(b)); + } + + recfun::promise_def d = p->get_promise_def(f->get_name()); + p->set_definition(d, vars.size(), vars.c_ptr(), rhs); +} + func_decl * cmd_context::find_func_decl(symbol const & s) const { builtin_decl d; if (m_builtin_decls.find(s, d)) { diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 99d6c8284..b41eab42d 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -29,6 +29,7 @@ Notes: #include "util/dictionary.h" #include "solver/solver.h" #include "ast/datatype_decl_plugin.h" +#include "ast/recfun_decl_plugin.h" #include "util/stopwatch.h" #include "util/cmd_context_types.h" #include "util/event_handler.h" @@ -289,6 +290,7 @@ protected: bool logic_has_array() const; bool logic_has_datatype() const; bool logic_has_fpa() const; + bool logic_has_recfun() const; void print_unsupported_msg() { regular_stream() << "unsupported" << std::endl; } void print_unsupported_info(symbol const& s, int line, int pos) { if (s != symbol::null) diagnostic_stream() << "; " << s << " line: " << line << " position: " << pos << std::endl;} @@ -304,6 +306,7 @@ protected: void erase_macro(symbol const& s); bool macros_find(symbol const& s, unsigned n, expr*const* args, expr*& t) const; + recfun_decl_plugin * get_recfun_plugin(); public: cmd_context(bool main_ctx = true, ast_manager * m = 0, symbol const & l = symbol::null); @@ -382,9 +385,11 @@ public: void insert_user_tactic(symbol const & s, sexpr * d); void insert_aux_pdecl(pdecl * p); void insert_rec_fun(func_decl* f, expr_ref_vector const& binding, svector const& ids, expr* e); + void insert_rec_fun_as_axiom(func_decl* f, expr_ref_vector const& binding, svector const& ids, expr* e); func_decl * find_func_decl(symbol const & s) const; func_decl * find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices, unsigned arity, sort * const * domain, sort * range) const; + recfun::promise_def decl_rec_fun(const symbol &name, unsigned int arity, sort *const *domain, sort *range); psort_decl * find_psort_decl(symbol const & s) const; cmd * find_cmd(symbol const & s) const; sexpr * find_user_tactic(symbol const & s) const; diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index a06438c73..58cc80b08 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -2278,7 +2278,7 @@ namespace smt2 { next(); } - void parse_rec_fun_decl(func_decl_ref& f, expr_ref_vector& bindings, svector& ids) { + recfun::promise_def parse_rec_fun_decl(func_decl_ref& f, expr_ref_vector& bindings, svector& ids) { SASSERT(m_num_bindings == 0); check_identifier("invalid function/constant definition, symbol expected"); symbol id = curr_id(); @@ -2289,7 +2289,8 @@ namespace smt2 { unsigned num_vars = parse_sorted_vars(); SASSERT(num_vars == m_num_bindings); parse_sort("Invalid recursive function definition"); - f = m().mk_func_decl(id, num_vars, sort_stack().c_ptr() + sort_spos, sort_stack().back()); + recfun::promise_def pdef = m_ctx.decl_rec_fun(id, num_vars, sort_stack().c_ptr() + sort_spos, sort_stack().back()); + f = pdef.get_def()->get_decl(); bindings.append(num_vars, expr_stack().c_ptr() + expr_spos); ids.append(num_vars, symbol_stack().c_ptr() + sym_spos); symbol_stack().shrink(sym_spos); @@ -2297,6 +2298,7 @@ namespace smt2 { expr_stack().shrink(expr_spos); m_env.end_scope(); m_num_bindings = 0; + return pdef; } void parse_rec_fun_bodies(func_decl_ref_vector const& decls, vector const& bindings, vector >const & ids) { diff --git a/src/smt/CMakeLists.txt b/src/smt/CMakeLists.txt index e102bd28b..0d98472b7 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -58,6 +58,7 @@ z3_add_component(smt theory_lra.cpp theory_opt.cpp theory_pb.cpp + theory_recfun.cpp theory_seq.cpp theory_str.cpp theory_utvpi.cpp diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp index a8eb81a2e..ec91ec608 100644 --- a/src/smt/params/smt_params.cpp +++ b/src/smt/params/smt_params.cpp @@ -27,6 +27,7 @@ void smt_params::updt_local_params(params_ref const & _p) { m_random_seed = p.random_seed(); m_relevancy_lvl = p.relevancy(); m_ematching = p.ematching(); + m_recfun_max_depth = p.recfun_max_depth(); m_phase_selection = static_cast(p.phase_selection()); m_restart_strategy = static_cast(p.restart_strategy()); m_restart_factor = p.restart_factor(); diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index b01499c04..e46b89401 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -105,6 +105,9 @@ struct smt_params : public preprocessor_params, bool m_new_core2th_eq; bool m_ematching; + // TODO: move into its own file? + unsigned m_recfun_max_depth; + // ----------------------------------- // // Case split strategy @@ -258,6 +261,7 @@ struct smt_params : public preprocessor_params, m_display_features(false), m_new_core2th_eq(true), m_ematching(true), + m_recfun_max_depth(500), m_case_split_strategy(CS_ACTIVITY_DELAY_NEW), m_rel_case_split_order(0), m_lookahead_diseq(false), diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 937aa6a2b..96923ec5e 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -83,5 +83,6 @@ def_module_params(module_name='smt', ('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'), ('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core'), ('core.extend_nonlocal_patterns', BOOL, False, 'extend unsat cores with literals that have quantifiers with patterns that contain symbols which are not in the quantifier\'s body'), - ('lemma_gc_strategy', UINT, 0, 'lemma garbage collection strategy: 0 - fixed, 1 - geometric, 2 - at restart, 3 - none') + ('lemma_gc_strategy', UINT, 0, 'lemma garbage collection strategy: 0 - fixed, 1 - geometric, 2 - at restart, 3 - none'), + ('recfun.max_depth', UINT, 500, 'maximum depth of unrolling for recursive functions') )) diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index bbc91e4c6..e8d55e0d4 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -28,6 +28,7 @@ Revision History: #include "smt/theory_array_full.h" #include "smt/theory_bv.h" #include "smt/theory_datatype.h" +#include "smt/theory_recfun.h" #include "smt/theory_dummy.h" #include "smt/theory_dl.h" #include "smt/theory_seq_empty.h" @@ -217,6 +218,7 @@ namespace smt { void setup::setup_QF_DT() { setup_QF_UF(); setup_datatypes(); + setup_recfuns(); } void setup::setup_QF_BVRE() { @@ -845,6 +847,13 @@ namespace smt { m_context.register_plugin(alloc(theory_datatype, m_manager, m_params)); } + void setup::setup_recfuns() { + TRACE("recfun", tout << "registering theory recfun...\n";); + theory_recfun * th = alloc(theory_recfun, m_manager); + m_context.register_plugin(th); + th->setup_params(); + } + void setup::setup_dl() { m_context.register_plugin(mk_theory_dl(m_manager)); } @@ -898,6 +907,7 @@ namespace smt { setup_arrays(); setup_bv(); setup_datatypes(); + setup_recfuns(); setup_dl(); setup_seq_str(st); setup_card(); diff --git a/src/smt/smt_setup.h b/src/smt/smt_setup.h index 924c2caec..ce8f44047 100644 --- a/src/smt/smt_setup.h +++ b/src/smt/smt_setup.h @@ -93,6 +93,7 @@ namespace smt { void setup_unknown(static_features & st); void setup_arrays(); void setup_datatypes(); + void setup_recfuns(); void setup_bv(); void setup_arith(); void setup_dl(); diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp new file mode 100644 index 000000000..db9f7d938 --- /dev/null +++ b/src/smt/theory_recfun.cpp @@ -0,0 +1,363 @@ + +#include "util/stats.h" +#include "ast/ast_util.h" +#include "smt/theory_recfun.h" +#include "smt/params/smt_params_helper.hpp" + +#define DEBUG(x) \ + do { \ + TRACE("recfun", tout << x << '\n';); \ + auto& out = std::cout; out << "recfun: "; out << x; out << '\n' << std::flush; } while(0) + +// NOTE: debug +struct pp_lits { + smt::context & ctx; + smt::literal *lits; + unsigned len; + pp_lits(smt::context & ctx, unsigned len, smt::literal *lits) : ctx(ctx), lits(lits), len(len) {} +}; + +std::ostream & operator<<(std::ostream & out, pp_lits const & pp) { + out << "clause{"; + bool first = true; + for (auto i = 0; i < pp.len; ++i) { + if (first) { first = false; } else { out << " ∨ "; } + pp.ctx.display_detailed_literal(out, pp.lits[i]); + } + return out << "}"; +} + +namespace smt { + + theory_recfun::theory_recfun(ast_manager & m) + : theory(m.mk_family_id("recfun")), m_util(0), m_trail(*this), + m_guards(), m_max_depth(0), m_q_case_expand(), m_q_body_expand() + { + recfun_decl_plugin * plugin = + reinterpret_cast(m.get_plugin(get_family_id())); + SASSERT(plugin); + m_util = & plugin->u(); + SASSERT(m_util); + } + + theory_recfun::~theory_recfun() { + reset_queues(); + for (auto & kv : m_guards) { + m().dec_ref(kv.m_key); + } + m_guards.reset(); + } + + char const * theory_recfun::get_name() const { return "recfun"; } + + void theory_recfun::setup_params() { + // obtain max depth via parameters + smt_params_helper p(get_context().get_params()); + set_max_depth(p.recfun_max_depth()); + } + + theory* theory_recfun::mk_fresh(context* new_ctx) { + return alloc(theory_recfun, new_ctx->get_manager()); + } + + bool theory_recfun::internalize_atom(app * atom, bool gate_ctx) { + context & ctx = get_context(); + if (! ctx.e_internalized(atom)) { + unsigned num_args = atom->get_num_args(); + for (unsigned i = 0; i < num_args; ++i) + ctx.internalize(atom->get_arg(i), false); + ctx.mk_enode(atom, false, true, false); + } + if (! ctx.b_internalized(atom)) { + bool_var v = ctx.mk_bool_var(atom); + ctx.set_var_theory(v, get_id()); + } + return true; + } + + bool theory_recfun::internalize_term(app * term) { + DEBUG("internalizing term: " << mk_pp(term, m())); + context & ctx = get_context(); + for (expr* e : *term) ctx.internalize(e, false); + // the internalization of the arguments may have triggered the internalization of term. + if (ctx.e_internalized(term)) + return true; + ctx.mk_enode(term, false, false, true); + return true; // the theory doesn't actually map terms to variables + } + + void theory_recfun::reset_queues() { + m_q_case_expand.reset(); + m_q_body_expand.reset(); + } + + void theory_recfun::reset_eh() { + m_trail.reset(); + reset_queues(); + } + + /* + * when `n` becomes relevant, if it's `f(t1…tn)` with `f` defined, + * then case-expand `n`. If it's a macro we can also immediately + * body-expand it. + */ + void theory_recfun::relevant_eh(app * n) { + SASSERT(get_context().relevancy()); + if (u().is_defined(n)) { + DEBUG("relevant_eh: (defined) " << mk_pp(n, m())); + + case_expansion e(u(), n); + push_case_expand(std::move(e)); + } + } + + void theory_recfun::push_scope_eh() { + theory::push_scope_eh(); + m_trail.push_scope(); + } + + void theory_recfun::pop_scope_eh(unsigned num_scopes) { + m_trail.pop_scope(num_scopes); + theory::pop_scope_eh(num_scopes); + reset_queues(); + } + + void theory_recfun::restart_eh() { + m_trail.reset(); + reset_queues(); + } + + bool theory_recfun::can_propagate() { + return ! (m_q_case_expand.empty() && m_q_body_expand.empty()); + } + + void theory_recfun::propagate() { + for (case_expansion & e : m_q_case_expand) { + if (e.m_def->is_fun_macro()) { + // body expand immediately + assert_macro_axiom(e); + } + else { + // case expand + SASSERT(e.m_def->is_fun_defined()); + assert_case_axioms(e); + } + } + m_q_case_expand.clear(); + + for (body_expansion & e : m_q_body_expand) { + assert_body_axiom(e); + } + m_q_body_expand.clear(); + } + + void theory_recfun::max_depth_conflict() { + DEBUG("max-depth conflict"); + // TODO: build clause from `m_guards` + /* + context & ctx = get_context(); + region & r = ctx.get_region(); + ctx.set_conflict( + */ + } + + // if `is_true` and `v = C_f_i(t1…tn)`, then body-expand i-th case of `f(t1…tn)` + void theory_recfun::assign_eh(bool_var v, bool is_true) { + expr* e = get_context().bool_var2expr(v); + DEBUG("assign_eh "<< mk_pp(e,m())); + if (!is_true) return; + if (!is_app(e)) return; + app* a = to_app(e); + if (u().is_case_pred(a)) { + DEBUG("assign_case_pred_true "<< mk_pp(e,m())); + // add to set of local assumptions, for depth-limit purpose + { + m_guards.insert(e, empty()); + m().inc_ref(e); + insert_ref_map trail_elt(m(), m_guards, e); + m_trail.push(trail_elt); + } + if (m_guards.size() > get_max_depth()) { + // too many body-expansions: depth-limit conflict + max_depth_conflict(); + } + else { + // body-expand + body_expansion b_e(u(), a); + push_body_expand(std::move(b_e)); + } + } + } + + // replace `vars` by `args` in `e` + expr_ref theory_recfun::apply_args(recfun::vars const & vars, + ptr_vector const & args, + expr * e) { + // check that var order is standard + SASSERT(vars.size() == 0 || vars[vars.size()-1]->get_idx() == 0); + var_subst subst(m(), true); + expr_ref new_body(m()); + subst(e, args.size(), args.c_ptr(), new_body); + get_context().get_rewriter()(new_body); // simplify + return new_body; + } + + app_ref theory_recfun::apply_pred(recfun::case_pred const & p, + ptr_vector const & args){ + app_ref res(u().mk_case_pred(p, args), m()); + return res; + } + + void theory_recfun::assert_macro_axiom(case_expansion & e) { + DEBUG("assert_macro_axiom " << pp_case_expansion(e,m())); + SASSERT(e.m_def->is_fun_macro()); + expr * lhs = e.m_lhs; + context & ctx = get_context(); + auto & vars = e.m_def->get_vars(); + // substitute `e.args` into the macro RHS + expr * rhs = apply_args(vars, e.m_args, e.m_def->get_macro_rhs()); + DEBUG("macro expansion yields" << mk_pp(rhs,m())); + // now build the axiom `lhs = rhs` + ctx.internalize(rhs, false); + DEBUG("adding axiom: " << mk_pp(lhs, m()) << " = " << mk_pp(rhs, m())); + if (m().proofs_enabled()) { + // add unit clause `lhs=rhs` + literal l(mk_eq(lhs, rhs, true)); + ctx.mark_as_relevant(l); + literal lits[1] = {l}; + ctx.mk_th_axiom(get_id(), 1, lits); + } + else { + //region r; + enode * e_lhs = ctx.get_enode(lhs); + enode * e_rhs = ctx.get_enode(rhs); + // TODO: proper justification + //justification * js = ctx.mk_justification( + ctx.assign_eq(e_lhs, e_rhs, eq_justification()); + } + } + + void theory_recfun::assert_case_axioms(case_expansion & e) { + DEBUG("assert_case_axioms "<< pp_case_expansion(e,m()) + << " with " << e.m_def->get_cases().size() << " cases"); + SASSERT(e.m_def->is_fun_defined()); + context & ctx = get_context(); + // add case-axioms for all case-paths + auto & vars = e.m_def->get_vars(); + for (recfun::case_def const & c : e.m_def->get_cases()) { + // applied predicate to `args` + app_ref pred_applied = apply_pred(c.get_pred(), e.m_args); + SASSERT(u().owns_app(pred_applied)); + // substitute arguments in `path` + expr_ref_vector path(m()); + for (auto & g : c.get_guards()) { + expr_ref g_applied = apply_args(vars, e.m_args, g); + path.push_back(g_applied); + } + // assert `p(args) <=> And(guards)` (with CNF on the fly) + ctx.internalize(pred_applied, false); + // FIXME: we need to be informed wen `pred_applied` is true!! + ctx.mark_as_relevant(ctx.get_bool_var(pred_applied)); + literal concl = ctx.get_literal(pred_applied); + { + // assert `guards=>p(args)` + literal_vector c; + c.push_back(concl); + for (expr* g : path) { + ctx.internalize(g, false); + c.push_back(~ ctx.get_literal(g)); + } + + //TRACE("recfun", tout << "assert_case_axioms " << pp_case_expansion(e) + // << " axiom " << mk_pp(*l) <<"\n";); + DEBUG("assert_case_axiom " << pp_lits(get_context(), path.size()+1, c.c_ptr())); + get_context().mk_th_axiom(get_id(), path.size()+1, c.c_ptr()); + } + { + // assert `p(args) => guards[i]` for each `i` + for (expr * _g : path) { + SASSERT(ctx.b_internalized(_g)); + literal g = ctx.get_literal(_g); + literal c[2] = {~ concl, g}; + + DEBUG("assert_case_axiom " << pp_lits(get_context(), 2, c)); + get_context().mk_th_axiom(get_id(), 2, c); + } + } + + // also body-expand paths that do not depend on any defined fun + if (c.is_immediate()) { + body_expansion be(c, e.m_args); + assert_body_axiom(be); + } + } + } + + void theory_recfun::assert_body_axiom(body_expansion & e) { + DEBUG("assert_body_axioms "<< pp_body_expansion(e,m())); + context & ctx = get_context(); + recfun::def & d = *e.m_cdef->get_def(); + auto & vars = d.get_vars(); + auto & args = e.m_args; + // check that var order is standard + SASSERT(vars.size() == 0 || vars[vars.size()-1]->get_idx() == 0); + expr_ref lhs(u().mk_fun_defined(d, args), m()); + // substitute `e.args` into the RHS of this particular case + expr_ref rhs = apply_args(vars, args, e.m_cdef->get_rhs()); + // substitute `e.args` into the guard of this particular case, to make + // the `condition` part of the clause `conds => lhs=rhs` + expr_ref_vector guards(m()); + for (auto & g : e.m_cdef->get_guards()) { + expr_ref new_guard = apply_args(vars, args, g); + guards.push_back(new_guard); + } + // now build the axiom `conds => lhs = rhs` + ctx.internalize(rhs, false); + for (auto& g : guards) ctx.internalize(g, false); + + // add unit clause `conds => lhs=rhs` + literal_vector clause; + for (auto& g : guards) { + ctx.internalize(g, false); + literal l = ~ ctx.get_literal(g); + ctx.mark_as_relevant(l); + clause.push_back(l); + } + literal l(mk_eq(lhs, rhs, true)); + ctx.mark_as_relevant(l); + clause.push_back(l); + DEBUG("assert_body_axiom " << pp_lits(get_context(), clause.size(), clause.c_ptr())); + ctx.mk_th_axiom(get_id(), clause.size(), clause.c_ptr()); + } + + final_check_status theory_recfun::final_check_eh() { + return FC_DONE; + } + + void theory_recfun::add_theory_assumptions(expr_ref_vector & assumptions) { + DEBUG("add_theory_assumptions"); + // TODO: add depth-limit assumptions? + } + + void theory_recfun::display(std::ostream & out) const { + out << "recfun{}"; + } + + void theory_recfun::collect_statistics(::statistics & st) const { + st.update("recfun macro expansion", m_stats.m_macro_expansions); + st.update("recfun case expansion", m_stats.m_case_expansions); + st.update("recfun body expansion", m_stats.m_body_expansions); + } + + std::ostream& operator<<(std::ostream & out, theory_recfun::pp_case_expansion const & e) { + return out << "case_exp(" << mk_pp(e.e.m_lhs, e.m) << ")"; + } + + std::ostream& operator<<(std::ostream & out, theory_recfun::pp_body_expansion const & e) { + out << "body_exp(" << e.e.m_cdef->get_name(); + for (auto* t : e.e.m_args) { + out << " " << mk_pp(t,e.m); + } + return out << ")"; + } +} diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h new file mode 100644 index 000000000..5645a1893 --- /dev/null +++ b/src/smt/theory_recfun.h @@ -0,0 +1,155 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + theory_recfun.h + +Abstract: + + Theory responsible for unrolling recursive functions + +Author: + + Leonardo de Moura (leonardo) 2008-10-31. + +Revision History: + +--*/ +#ifndef THEORY_RECFUN_H_ +#define THEORY_RECFUN_H_ + +#include "smt/smt_theory.h" +#include "smt/smt_context.h" +#include "ast/ast_pp.h" +#include "ast/recfun_decl_plugin.h" + +namespace smt { + + class theory_recfun : public theory { + struct stats { + unsigned m_case_expansions, m_body_expansions, m_macro_expansions; + void reset() { memset(this, 0, sizeof(stats)); } + stats() { reset(); } + }; + + // one case-expansion of `f(t1…tn)` + struct case_expansion { + expr * m_lhs; // the term to expand + recfun_def * m_def; + ptr_vector m_args; + case_expansion(recfun_util& u, app * n) : m_lhs(n), m_def(0), m_args() + { + SASSERT(u.is_defined(n)); + func_decl * d = n->get_decl(); + const symbol& name = d->get_name(); + m_def = &u.get_def(name); + m_args.append(n->get_num_args(), n->get_args()); + } + case_expansion(case_expansion const & from) + : m_lhs(from.m_lhs), + m_def(from.m_def), + m_args(from.m_args) {} + case_expansion(case_expansion && from) + : m_lhs(from.m_lhs), + m_def(from.m_def), + m_args(std::move(from.m_args)) {} + }; + + struct pp_case_expansion { + case_expansion & e; + ast_manager & m; + pp_case_expansion(case_expansion & e, ast_manager & m) : e(e), m(m) {} + }; + + friend std::ostream& operator<<(std::ostream&, pp_case_expansion const &); + + // one body-expansion of `f(t1…tn)` using a `C_f_i(t1…tn)` + struct body_expansion { + recfun_case_def const * m_cdef; + ptr_vector m_args; + + body_expansion(recfun_util& u, app * n) : m_cdef(0), m_args() { + SASSERT(u.is_case_pred(n)); + func_decl * d = n->get_decl(); + const symbol& name = d->get_name(); + m_cdef = &u.get_case_def(name); + for (unsigned i = 0; i < n->get_num_args(); ++i) + m_args.push_back(n->get_arg(i)); + } + body_expansion(recfun_case_def const & d, ptr_vector & args) : m_cdef(&d), m_args(args) {} + body_expansion(body_expansion const & from): m_cdef(from.m_cdef), m_args(from.m_args) {} + body_expansion(body_expansion && from) : m_cdef(from.m_cdef), m_args(std::move(from.m_args)) {} + }; + + struct pp_body_expansion { + body_expansion & e; + ast_manager & m; + pp_body_expansion(body_expansion & e, ast_manager & m) : e(e), m(m) {} + }; + + friend std::ostream& operator<<(std::ostream&, pp_body_expansion const &); + + struct empty{}; + + typedef trail_stack th_trail_stack; + typedef obj_map guard_set; + + recfun_util * m_util; + stats m_stats; + th_trail_stack m_trail; + guard_set m_guards; // true case-preds + unsigned m_max_depth; // for fairness and termination + + vector m_q_case_expand; + vector m_q_body_expand; + + recfun_util & u() const { SASSERT(m_util); return *m_util; } + ast_manager & m() { return get_manager(); } + bool is_defined(app * f) const { return u().is_defined(f); } + bool is_case_pred(app * f) const { return u().is_case_pred(f); } + + bool is_defined(enode * e) const { return is_defined(e->get_owner()); } + bool is_case_pred(enode * e) const { return is_case_pred(e->get_owner()); } + + void reset_queues(); + expr_ref apply_args(recfun::vars const & vars, ptr_vector const & args, expr * e); //!< substitute variables by args + app_ref apply_pred(recfun::case_pred const & p, ptr_vector const & args); //0); m_max_depth = n; } + }; +} + +#endif diff --git a/src/util/scoped_ptr_vector.h b/src/util/scoped_ptr_vector.h index 0bd0fd47e..15b9b889c 100644 --- a/src/util/scoped_ptr_vector.h +++ b/src/util/scoped_ptr_vector.h @@ -31,6 +31,7 @@ public: void reset() { std::for_each(m_vector.begin(), m_vector.end(), delete_proc()); m_vector.reset(); } void push_back(T * ptr) { m_vector.push_back(ptr); } void pop_back() { SASSERT(!empty()); set(size()-1, 0); m_vector.pop_back(); } + T * back() const { return m_vector.back(); } T * operator[](unsigned idx) const { return m_vector[idx]; } void set(unsigned idx, T * ptr) { if (m_vector[idx] == ptr) @@ -51,6 +52,13 @@ public: push_back(0); } } + //!< swap last element with given pointer + void swap_back(scoped_ptr & ptr) { + SASSERT(!empty()); + T * tmp = ptr.detach(); + ptr = m_vector.back(); + m_vector[m_vector.size()-1] = tmp; + } }; #endif diff --git a/src/util/trail.h b/src/util/trail.h index bba71fb00..0503bcfa7 100644 --- a/src/util/trail.h +++ b/src/util/trail.h @@ -143,6 +143,17 @@ public: }; +template +class insert_ref_map : public trail { + Mgr& m; + M& m_map; + D m_obj; +public: + insert_ref_map(Mgr& m, M& t, D o) : m(m), m_map(t), m_obj(o) {} + virtual ~insert_ref_map() {} + virtual void undo(Ctx & ctx) { m_map.remove(m_obj); m.dec_ref(m_obj); } +}; + template class push_back_vector : public trail { From 06e0b12700b85f90dfa344958642bc1e0fd2ab9b Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Wed, 6 Dec 2017 13:01:54 +0100 Subject: [PATCH 003/227] add a predicate for depth limit assumptions --- src/ast/recfun_decl_plugin.cpp | 29 +++++++++++++++++++++++++- src/ast/recfun_decl_plugin.h | 38 ++++++++++++++++++++++++++++++++++ src/smt/params/smt_params.h | 2 +- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 331114910..b8bf1637a 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -342,7 +342,7 @@ namespace recfun { */ util::util(ast_manager & m, family_id id) - : m_manager(m), m_family_id(id), m_th_rw(m), m_plugin(0) { + : m_manager(m), m_family_id(id), m_th_rw(m), m_plugin(0), m_dlimit_map() { m_plugin = dynamic_cast(m.get_plugin(m_family_id)); } @@ -354,6 +354,15 @@ namespace recfun { d.set_definition(n_vars, vars, rhs); } + // get or create predicate for depth limit + depth_limit_pred_ref util::get_depth_limit_pred(unsigned d) { + depth_limit_pred * pred = nullptr; + if (! m_dlimit_map.find(d, pred)) { + pred = alloc(depth_limit_pred, m(), m_family_id, d); + m_dlimit_map.insert(d, pred); + } + return depth_limit_pred_ref(pred, *this); + } // used to know which `app` are from this theory struct is_imm_pred : is_immediate_pred { @@ -387,6 +396,17 @@ namespace recfun { d->compute_cases(is_i, u->get_th_rewriter(), n_vars, vars, rhs); } + depth_limit_pred::depth_limit_pred(ast_manager & m, family_id fid, unsigned d) + : m_name_buf(), m_name(""), m_depth(d), m_decl(m) { + // build name, then build decl + std::ostringstream tmpname(m_name_buf); + tmpname << "depth_limit_" << d; + m_name = symbol(m_name_buf.c_str()); + parameter params[1] = { parameter(d) }; + func_decl_info info(fid, OP_DEPTH_LIMIT, 1, params); + m_decl = m.mk_func_decl(m_name, 0, ((sort*const *)nullptr), m.mk_bool_sort(), info); + } + namespace decl { plugin::plugin() : decl_plugin(), m_defs(), m_case_defs(), m_def_block() {} plugin::~plugin() { finalize(); } @@ -424,6 +444,13 @@ namespace recfun { } } + app_ref plugin::mk_depth_limit_pred(unsigned d) { + depth_limit_pred_ref p = u().get_depth_limit_pred(d); + app_ref res(m()); + m().mk_app(p->get_decl(), 0, nullptr, res); + return res; + } + def* plugin::mk_def(symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs) { SASSERT(! m_defs.contains(name)); diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index e9b75a409..677a44302 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -30,6 +30,7 @@ namespace recfun { enum op_kind { OP_FUN_DEFINED, // defined function with one or more cases, possibly recursive OP_FUN_CASE_PRED, // predicate guarding a given control flow path + OP_DEPTH_LIMIT, // predicate enforcing some depth limit }; /*! A predicate `p(t1…tn)`, that, if true, means `f(t1…tn)` is following @@ -145,6 +146,27 @@ namespace recfun { def * get_def() const { return d; } }; + // predicate for limiting unrolling depth, to be used in assumptions and conflicts + class depth_limit_pred { + friend class util; + std::string m_name_buf; + symbol m_name; + unsigned m_depth; + func_decl_ref m_decl; + unsigned m_refcount; + + void inc_ref() { m_refcount ++; } + void dec_ref() { SASSERT(m_refcount > 0); m_refcount --; } + public: + depth_limit_pred(ast_manager & m, family_id fid, unsigned d); + unsigned get_depth() const { return m_depth; } + symbol const & get_name() const { return m_name; } + func_decl * get_decl() const { return m_decl.get(); } + }; + + // A reference to `depth_limit_pred` + typedef obj_ref depth_limit_pred_ref; + namespace decl { class plugin : public decl_plugin { @@ -186,6 +208,7 @@ namespace recfun { bool has_case_def(const symbol& s) const { return m_case_defs.contains(s); } case_def& get_case_def(symbol const& s) { SASSERT(has_case_def(s)); return *(m_case_defs[s]); } bool is_declared(symbol const& s) const { return m_defs.contains(s); } + app_ref mk_depth_limit_pred(unsigned d); private: func_decl * mk_fun_pred_decl(unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); @@ -198,11 +221,14 @@ namespace recfun { // Varus utils for recursive functions class util { friend class decl::plugin; + + typedef map> depth_limit_map; ast_manager & m_manager; family_id m_family_id; th_rewriter m_th_rw; decl::plugin * m_plugin; + depth_limit_map m_dlimit_map; bool compute_is_immediate(expr * rhs); void set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs); @@ -237,10 +263,22 @@ namespace recfun { app* mk_case_pred(case_pred const & p, ptr_vector const & args) { return m().mk_app(p.get_decl(), args.size(), args.c_ptr()); } + + void inc_ref(depth_limit_pred * p) { p->inc_ref(); } + void dec_ref(depth_limit_pred * p) { + p->dec_ref(); + if (p->m_refcount == 0) { + m_dlimit_map.remove(p->m_depth); + dealloc(p); + } + } + + depth_limit_pred_ref get_depth_limit_pred(unsigned d); }; } typedef recfun::def recfun_def; typedef recfun::case_def recfun_case_def; +typedef recfun::depth_limit_pred recfun_depth_limit_pred; typedef recfun::decl::plugin recfun_decl_plugin; typedef recfun::util recfun_util; diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index e46b89401..330d284c4 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -261,7 +261,7 @@ struct smt_params : public preprocessor_params, m_display_features(false), m_new_core2th_eq(true), m_ematching(true), - m_recfun_max_depth(500), + m_recfun_max_depth(50), m_case_split_strategy(CS_ACTIVITY_DELAY_NEW), m_rel_case_split_order(0), m_lookahead_diseq(false), From 7b1e1d52e72dd06c2cf06a8604bb189c602eec14 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Wed, 6 Dec 2017 14:05:14 +0100 Subject: [PATCH 004/227] wip: conflicts for pruning branches with too many unrollings use the local assumption on depth to ensure the conflict clause is valid --- src/ast/recfun_decl_plugin.cpp | 38 +++++++--------- src/ast/recfun_decl_plugin.h | 2 +- src/smt/theory_recfun.cpp | 81 ++++++++++++++++++++++++++++------ 3 files changed, 85 insertions(+), 36 deletions(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index b8bf1637a..3ebd888c7 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -23,10 +23,9 @@ Revision History: #include "ast/ast_pp.h" #include "util/scoped_ptr_vector.h" -#define DEBUG(x) do { auto& out = std::cout; out << "recfun: "; x; out << '\n' << std::flush; } while(0) +#define DEBUG(x) TRACE("recfun", tout << x << '\n';) #define VALIDATE_PARAM(m, _pred_) if (!(_pred_)) m.raise_exception("invalid parameter to recfun " #_pred_); - namespace recfun { case_pred::case_pred(ast_manager & m, family_id fid, std::string const & s, sort_ref_vector const & domain) : m_name(), m_name_buf(s), m_domain(domain), m_decl(m) @@ -186,10 +185,7 @@ namespace recfun { void def::add_case(std::string & name, unsigned n_conditions, expr ** conditions, expr * rhs, bool is_imm) { case_def c(m(), m_fid, this, name, get_domain(), n_conditions, conditions, rhs); c.set_is_immediate(is_imm); - TRACE("recfun", tout << "add_case " << name << " " << mk_pp(rhs, m()) - << " :is_imm " << is_imm - << " :guards " << mk_pp_vec(n_conditions, (ast**)conditions, m());); - DEBUG(out << "add_case " << name << " " << mk_pp(rhs, m()) + DEBUG("add_case " << name << " " << mk_pp(rhs, m()) << " :is_imm " << is_imm << " :guards " << mk_pp_vec(n_conditions, (ast**)conditions, m())); m_cases.push_back(c); @@ -201,12 +197,12 @@ namespace recfun { unsigned n_vars, var *const * vars, expr* rhs0) { if (m_cases.size() != 0) { - TRACE("recfun", tout << "bug: cases for " << m_name << " has cases already";); + DEBUG("bug: cases for " << m_name << " has cases already"); UNREACHABLE(); } SASSERT(n_vars = m_domain.size()); - DEBUG(out << "compute cases " << mk_pp(rhs0, m())); + DEBUG("compute cases " << mk_pp(rhs0, m())); unsigned case_idx = 0; std::string name; @@ -226,7 +222,7 @@ namespace recfun { th_rw(rhs0, simplified_rhs); rhs = simplified_rhs.get(); - DEBUG(out << "simplified into " << mk_pp(rhs, m())); + DEBUG("simplified into " << mk_pp(rhs, m())); #else expr* rhs = rhs0; #endif @@ -252,7 +248,7 @@ namespace recfun { } while (! st.empty()) { - DEBUG(out << "main loop iter"); + DEBUG("main loop iter"); branch b = st.pop_branch(); @@ -334,7 +330,7 @@ namespace recfun { } } - TRACE("recfun", tout << "done analysing " << get_name();); + DEBUG("done analysing " << get_name()); } /* @@ -364,6 +360,12 @@ namespace recfun { return depth_limit_pred_ref(pred, *this); } + app_ref util::mk_depth_limit_pred(unsigned d) { + depth_limit_pred_ref p = get_depth_limit_pred(d); + app_ref res(m().mk_const(p->get_decl()), m()); + return res; + } + // used to know which `app` are from this theory struct is_imm_pred : is_immediate_pred { util & u; @@ -399,12 +401,13 @@ namespace recfun { depth_limit_pred::depth_limit_pred(ast_manager & m, family_id fid, unsigned d) : m_name_buf(), m_name(""), m_depth(d), m_decl(m) { // build name, then build decl - std::ostringstream tmpname(m_name_buf); - tmpname << "depth_limit_" << d; + std::ostringstream tmpname; + tmpname << "depth_limit_" << d << std::flush; + m_name_buf.append(tmpname.str()); m_name = symbol(m_name_buf.c_str()); parameter params[1] = { parameter(d) }; func_decl_info info(fid, OP_DEPTH_LIMIT, 1, params); - m_decl = m.mk_func_decl(m_name, 0, ((sort*const *)nullptr), m.mk_bool_sort(), info); + m_decl = m.mk_const_decl(m_name, m.mk_bool_sort(), info); } namespace decl { @@ -444,13 +447,6 @@ namespace recfun { } } - app_ref plugin::mk_depth_limit_pred(unsigned d) { - depth_limit_pred_ref p = u().get_depth_limit_pred(d); - app_ref res(m()); - m().mk_app(p->get_decl(), 0, nullptr, res); - return res; - } - def* plugin::mk_def(symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs) { SASSERT(! m_defs.contains(name)); diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index 677a44302..272ab43c4 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -208,7 +208,6 @@ namespace recfun { bool has_case_def(const symbol& s) const { return m_case_defs.contains(s); } case_def& get_case_def(symbol const& s) { SASSERT(has_case_def(s)); return *(m_case_defs[s]); } bool is_declared(symbol const& s) const { return m_defs.contains(s); } - app_ref mk_depth_limit_pred(unsigned d); private: func_decl * mk_fun_pred_decl(unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); @@ -274,6 +273,7 @@ namespace recfun { } depth_limit_pred_ref get_depth_limit_pred(unsigned d); + app_ref mk_depth_limit_pred(unsigned d); }; } diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index db9f7d938..b572f0bf7 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -4,10 +4,18 @@ #include "smt/theory_recfun.h" #include "smt/params/smt_params_helper.hpp" -#define DEBUG(x) \ - do { \ - TRACE("recfun", tout << x << '\n';); \ - auto& out = std::cout; out << "recfun: "; out << x; out << '\n' << std::flush; } while(0) +#define DEBUG(x) TRACE("recfun", tout << x << '\n';) + +struct pp_lit { + smt::context & ctx; + smt::literal lit; + pp_lit(smt::context & ctx, smt::literal lit) : ctx(ctx), lit(lit) {} +}; + +std::ostream & operator<<(std::ostream & out, pp_lit const & pp) { + pp.ctx.display_detailed_literal(out, pp.lit); + return out; +} // NOTE: debug struct pp_lits { @@ -76,7 +84,6 @@ namespace smt { } bool theory_recfun::internalize_term(app * term) { - DEBUG("internalizing term: " << mk_pp(term, m())); context & ctx = get_context(); for (expr* e : *term) ctx.internalize(e, false); // the internalization of the arguments may have triggered the internalization of term. @@ -112,11 +119,13 @@ namespace smt { } void theory_recfun::push_scope_eh() { + DEBUG("push_scope"); theory::push_scope_eh(); m_trail.push_scope(); } void theory_recfun::pop_scope_eh(unsigned num_scopes) { + DEBUG("pop_scope"); m_trail.pop_scope(num_scopes); theory::pop_scope_eh(num_scopes); reset_queues(); @@ -151,20 +160,64 @@ namespace smt { m_q_body_expand.clear(); } + class depth_conflict_justification : public justification { + literal_vector lits; + theory_recfun * th; + ast_manager & m() const { return th->get_manager(); } + public: + depth_conflict_justification(theory_recfun * th, region & r, literal_vector const & lits) + : lits(lits), th(th) {} + depth_conflict_justification(depth_conflict_justification const & from) + : lits(from.lits), th(from.th) {} + depth_conflict_justification(depth_conflict_justification && from) + : lits(std::move(from.lits)), th(from.th) {} + char const * get_name() const override { return "depth-conflict"; } + theory_id get_from_theory() const override { return th->get_id(); } + + void get_antecedents(conflict_resolution & cr) override { + auto & ctx = cr.get_context(); + for (unsigned i=0; i < lits.size(); ++i) { + DEBUG("mark literal " << pp_lit(ctx, lits[i])); + cr.mark_literal(lits[i]); + } + } + proof * mk_proof(conflict_resolution & cr) override { + UNREACHABLE(); + /* FIXME: actual proof + app * lemma = m().mk_or(c.size(), c.c_ptr()); + return m().mk_lemma(m().mk_false(), lemma); + */ + } + }; + + void theory_recfun::max_depth_conflict() { DEBUG("max-depth conflict"); - // TODO: build clause from `m_guards` - /* context & ctx = get_context(); - region & r = ctx.get_region(); - ctx.set_conflict( - */ + literal_vector c; + // make clause `depth_limit => V_{g : guards} ~ g` + { + // first literal must be the depth limit one + app_ref dlimit = m_util->mk_depth_limit_pred(get_max_depth()); + ctx.internalize(dlimit, false); + c.push_back(~ ctx.get_literal(dlimit)); + SASSERT(ctx.get_assignment(ctx.get_literal(dlimit)) == l_true); + } + for (auto& kv : m_guards) { + expr * g = & kv.get_key(); + c.push_back(~ ctx.get_literal(g)); + } + DEBUG("max-depth conflict: add clause " << pp_lits(ctx, c.size(), c.c_ptr())); + SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx.get_assignment(l) == l_false; })); // conflict + region r; + + depth_conflict_justification js(this, r, c); + ctx.set_conflict(ctx.mk_justification(js)); } // if `is_true` and `v = C_f_i(t1…tn)`, then body-expand i-th case of `f(t1…tn)` void theory_recfun::assign_eh(bool_var v, bool is_true) { expr* e = get_context().bool_var2expr(v); - DEBUG("assign_eh "<< mk_pp(e,m())); if (!is_true) return; if (!is_app(e)) return; app* a = to_app(e); @@ -256,7 +309,6 @@ namespace smt { } // assert `p(args) <=> And(guards)` (with CNF on the fly) ctx.internalize(pred_applied, false); - // FIXME: we need to be informed wen `pred_applied` is true!! ctx.mark_as_relevant(ctx.get_bool_var(pred_applied)); literal concl = ctx.get_literal(pred_applied); { @@ -335,8 +387,9 @@ namespace smt { } void theory_recfun::add_theory_assumptions(expr_ref_vector & assumptions) { - DEBUG("add_theory_assumptions"); - // TODO: add depth-limit assumptions? + app_ref dlimit = m_util->mk_depth_limit_pred(get_max_depth()); + DEBUG("add_theory_assumption " << mk_pp(dlimit.get(), m())); + assumptions.push_back(dlimit); } void theory_recfun::display(std::ostream & out) const { From 3b4718b99a9ce60105b6b811100128b4f518b946 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Thu, 14 Dec 2017 19:03:13 +0100 Subject: [PATCH 005/227] simpler conflicts when reaching unrolling limit (just add a clause) --- src/smt/theory_recfun.cpp | 51 +++++++++++---------------------------- src/smt/theory_recfun.h | 1 + 2 files changed, 15 insertions(+), 37 deletions(-) diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index b572f0bf7..2e81dd188 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -39,7 +39,7 @@ namespace smt { theory_recfun::theory_recfun(ast_manager & m) : theory(m.mk_family_id("recfun")), m_util(0), m_trail(*this), - m_guards(), m_max_depth(0), m_q_case_expand(), m_q_body_expand() + m_guards(), m_max_depth(0), m_q_case_expand(), m_q_body_expand(), m_q_clauses() { recfun_decl_plugin * plugin = reinterpret_cast(m.get_plugin(get_family_id())); @@ -96,6 +96,7 @@ namespace smt { void theory_recfun::reset_queues() { m_q_case_expand.reset(); m_q_body_expand.reset(); + m_q_clauses.reset(); } void theory_recfun::reset_eh() { @@ -137,10 +138,19 @@ namespace smt { } bool theory_recfun::can_propagate() { - return ! (m_q_case_expand.empty() && m_q_body_expand.empty()); + return ! (m_q_case_expand.empty() && + m_q_body_expand.empty() && + m_q_clauses.empty()); } void theory_recfun::propagate() { + context & ctx = get_context(); + + for (literal_vector & c : m_q_clauses) { + ctx.mk_th_axiom(get_id(), c.size(), c.c_ptr()); + } + m_q_clauses.clear(); + for (case_expansion & e : m_q_case_expand) { if (e.m_def->is_fun_macro()) { // body expand immediately @@ -160,37 +170,6 @@ namespace smt { m_q_body_expand.clear(); } - class depth_conflict_justification : public justification { - literal_vector lits; - theory_recfun * th; - ast_manager & m() const { return th->get_manager(); } - public: - depth_conflict_justification(theory_recfun * th, region & r, literal_vector const & lits) - : lits(lits), th(th) {} - depth_conflict_justification(depth_conflict_justification const & from) - : lits(from.lits), th(from.th) {} - depth_conflict_justification(depth_conflict_justification && from) - : lits(std::move(from.lits)), th(from.th) {} - char const * get_name() const override { return "depth-conflict"; } - theory_id get_from_theory() const override { return th->get_id(); } - - void get_antecedents(conflict_resolution & cr) override { - auto & ctx = cr.get_context(); - for (unsigned i=0; i < lits.size(); ++i) { - DEBUG("mark literal " << pp_lit(ctx, lits[i])); - cr.mark_literal(lits[i]); - } - } - proof * mk_proof(conflict_resolution & cr) override { - UNREACHABLE(); - /* FIXME: actual proof - app * lemma = m().mk_or(c.size(), c.c_ptr()); - return m().mk_lemma(m().mk_false(), lemma); - */ - } - }; - - void theory_recfun::max_depth_conflict() { DEBUG("max-depth conflict"); context & ctx = get_context(); @@ -207,12 +186,10 @@ namespace smt { expr * g = & kv.get_key(); c.push_back(~ ctx.get_literal(g)); } - DEBUG("max-depth conflict: add clause " << pp_lits(ctx, c.size(), c.c_ptr())); + DEBUG("max-depth limit: add clause " << pp_lits(ctx, c.size(), c.c_ptr())); SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx.get_assignment(l) == l_false; })); // conflict - region r; - depth_conflict_justification js(this, r, c); - ctx.set_conflict(ctx.mk_justification(js)); + m_q_clauses.push_back(std::move(c)); } // if `is_true` and `v = C_f_i(t1…tn)`, then body-expand i-th case of `f(t1…tn)` diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 5645a1893..2439c07ff 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -103,6 +103,7 @@ namespace smt { vector m_q_case_expand; vector m_q_body_expand; + vector m_q_clauses; recfun_util & u() const { SASSERT(m_util); return *m_util; } ast_manager & m() { return get_manager(); } From b877bd8286eb9a91b859b9dc14e98eec1ce6ddf0 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Thu, 14 Dec 2017 20:17:02 +0100 Subject: [PATCH 006/227] debug messages and gating --- src/smt/theory_recfun.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 2e81dd188..fdbdeac47 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -4,6 +4,8 @@ #include "smt/theory_recfun.h" #include "smt/params/smt_params_helper.hpp" +#ifdef Z3DEBUG + #define DEBUG(x) TRACE("recfun", tout << x << '\n';) struct pp_lit { @@ -17,7 +19,6 @@ std::ostream & operator<<(std::ostream & out, pp_lit const & pp) { return out; } -// NOTE: debug struct pp_lits { smt::context & ctx; smt::literal *lits; @@ -35,6 +36,14 @@ std::ostream & operator<<(std::ostream & out, pp_lits const & pp) { return out << "}"; } +#else + +#define DEBUG(x) do{}while(0) + +#endif + + + namespace smt { theory_recfun::theory_recfun(ast_manager & m) @@ -147,6 +156,7 @@ namespace smt { context & ctx = get_context(); for (literal_vector & c : m_q_clauses) { + DEBUG("add axiom " << pp_lits(ctx, c.size(), c.c_ptr())); ctx.mk_th_axiom(get_id(), c.size(), c.c_ptr()); } m_q_clauses.clear(); @@ -379,6 +389,7 @@ namespace smt { st.update("recfun body expansion", m_stats.m_body_expansions); } +#ifdef Z3DEBUG std::ostream& operator<<(std::ostream & out, theory_recfun::pp_case_expansion const & e) { return out << "case_exp(" << mk_pp(e.e.m_lhs, e.m) << ")"; } @@ -390,4 +401,5 @@ namespace smt { } return out << ")"; } +#endif } From 0c753aa86ac908af28703a5885a50ddd0e0ce6d1 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Thu, 14 Dec 2017 20:17:11 +0100 Subject: [PATCH 007/227] fix bugs related to backtracking and restarts --- src/smt/theory_recfun.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index fdbdeac47..a910a62ef 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -111,6 +111,8 @@ namespace smt { void theory_recfun::reset_eh() { m_trail.reset(); reset_queues(); + m_stats.reset(); + theory::reset_eh(); } /* @@ -135,15 +137,16 @@ namespace smt { } void theory_recfun::pop_scope_eh(unsigned num_scopes) { - DEBUG("pop_scope"); + DEBUG("pop_scope " << num_scopes); m_trail.pop_scope(num_scopes); theory::pop_scope_eh(num_scopes); reset_queues(); } void theory_recfun::restart_eh() { - m_trail.reset(); + DEBUG("restart"); reset_queues(); + theory::restart_eh(); } bool theory_recfun::can_propagate() { From 35c802d8692a3615a9fa52af0ef69accbccf14aa Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 25 Dec 2017 17:01:53 +0100 Subject: [PATCH 008/227] simplify and strenghten some code --- src/smt/theory_recfun.cpp | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index a910a62ef..f9e032c87 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -193,14 +193,14 @@ namespace smt { app_ref dlimit = m_util->mk_depth_limit_pred(get_max_depth()); ctx.internalize(dlimit, false); c.push_back(~ ctx.get_literal(dlimit)); - SASSERT(ctx.get_assignment(ctx.get_literal(dlimit)) == l_true); + //SASSERT(ctx.get_assignment(ctx.get_literal(dlimit)) == l_true); } for (auto& kv : m_guards) { expr * g = & kv.get_key(); c.push_back(~ ctx.get_literal(g)); } DEBUG("max-depth limit: add clause " << pp_lits(ctx, c.size(), c.c_ptr())); - SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx.get_assignment(l) == l_false; })); // conflict + //SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx.get_assignment(l) == l_false; })); // conflict m_q_clauses.push_back(std::move(c)); } @@ -254,30 +254,21 @@ namespace smt { void theory_recfun::assert_macro_axiom(case_expansion & e) { DEBUG("assert_macro_axiom " << pp_case_expansion(e,m())); SASSERT(e.m_def->is_fun_macro()); - expr * lhs = e.m_lhs; + expr_ref lhs(e.m_lhs, m()); context & ctx = get_context(); auto & vars = e.m_def->get_vars(); // substitute `e.args` into the macro RHS - expr * rhs = apply_args(vars, e.m_args, e.m_def->get_macro_rhs()); + expr_ref rhs(apply_args(vars, e.m_args, e.m_def->get_macro_rhs()), m()); DEBUG("macro expansion yields" << mk_pp(rhs,m())); // now build the axiom `lhs = rhs` ctx.internalize(rhs, false); - DEBUG("adding axiom: " << mk_pp(lhs, m()) << " = " << mk_pp(rhs, m())); - if (m().proofs_enabled()) { - // add unit clause `lhs=rhs` - literal l(mk_eq(lhs, rhs, true)); - ctx.mark_as_relevant(l); - literal lits[1] = {l}; - ctx.mk_th_axiom(get_id(), 1, lits); - } - else { - //region r; - enode * e_lhs = ctx.get_enode(lhs); - enode * e_rhs = ctx.get_enode(rhs); - // TODO: proper justification - //justification * js = ctx.mk_justification( - ctx.assign_eq(e_lhs, e_rhs, eq_justification()); - } + // add unit clause `lhs=rhs` + literal l(mk_eq(lhs, rhs, true)); + ctx.mark_as_relevant(l); + literal_vector lits; + lits.push_back(l); + DEBUG("assert_macro_axiom: " << pp_lits(ctx, lits.size(), lits.c_ptr())); + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } void theory_recfun::assert_case_axioms(case_expansion & e) { @@ -368,7 +359,7 @@ namespace smt { literal l(mk_eq(lhs, rhs, true)); ctx.mark_as_relevant(l); clause.push_back(l); - DEBUG("assert_body_axiom " << pp_lits(get_context(), clause.size(), clause.c_ptr())); + DEBUG("assert_body_axiom " << pp_lits(ctx, clause.size(), clause.c_ptr())); ctx.mk_th_axiom(get_id(), clause.size(), clause.c_ptr()); } From f7e5977b9e1edf9f15d2d078e5991ecd61c25a73 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 25 Dec 2017 22:48:37 +0100 Subject: [PATCH 009/227] fix memleak --- src/ast/recfun_decl_plugin.cpp | 6 ++++++ src/ast/recfun_decl_plugin.h | 1 + src/smt/theory_recfun.cpp | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 3ebd888c7..f4b237f9a 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -342,6 +342,12 @@ namespace recfun { m_plugin = dynamic_cast(m.get_plugin(m_family_id)); } + util::~util() { + for (auto & kv : m_dlimit_map) { + dealloc(kv.m_value); + } + } + def * util::decl_fun(symbol const& name, unsigned n, sort *const * domain, sort * range) { return alloc(def, m(), m_family_id, name, n, domain, range); } diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index 272ab43c4..206b2c951 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -233,6 +233,7 @@ namespace recfun { void set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs); public: util(ast_manager &m, family_id); + virtual ~util(); ast_manager & m() { return m_manager; } th_rewriter & get_th_rewriter() { return m_th_rw; } diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index f9e032c87..3bafaf925 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -62,7 +62,7 @@ namespace smt { for (auto & kv : m_guards) { m().dec_ref(kv.m_key); } - m_guards.reset(); + m_guards.reset(); } char const * theory_recfun::get_name() const { return "recfun"; } From cfcff78754e4db5176d7ff7a3e08b9287e070f09 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 25 Dec 2017 23:35:54 +0100 Subject: [PATCH 010/227] validate unsat cores in recfun --- src/ast/recfun_decl_plugin.h | 1 + src/smt/theory_recfun.cpp | 14 ++++++++++++-- src/smt/theory_recfun.h | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index 206b2c951..b51717c1d 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -239,6 +239,7 @@ namespace recfun { th_rewriter & get_th_rewriter() { return m_th_rw; } bool is_case_pred(app * e) const { return is_app_of(e, m_family_id, OP_FUN_CASE_PRED); } bool is_defined(app * e) const { return is_app_of(e, m_family_id, OP_FUN_DEFINED); } + bool is_depth_limit(app * e) const { return is_app_of(e, m_family_id, OP_DEPTH_LIMIT); } bool owns_app(app * e) const { return e->get_family_id() == m_family_id; } //mk_depth_limit_pred(get_max_depth()); ctx.internalize(dlimit, false); c.push_back(~ ctx.get_literal(dlimit)); - //SASSERT(ctx.get_assignment(ctx.get_literal(dlimit)) == l_true); + SASSERT(ctx.get_assignment(ctx.get_literal(dlimit)) == l_true); } for (auto& kv : m_guards) { expr * g = & kv.get_key(); c.push_back(~ ctx.get_literal(g)); } DEBUG("max-depth limit: add clause " << pp_lits(ctx, c.size(), c.c_ptr())); - //SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx.get_assignment(l) == l_false; })); // conflict + SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx.get_assignment(l) == l_false; })); // conflict m_q_clauses.push_back(std::move(c)); } @@ -373,6 +373,16 @@ namespace smt { assumptions.push_back(dlimit); } + + // if `dlimit` occurs in unsat core, return "unknown" + lbool theory_recfun::validate_unsat_core(expr_ref_vector & unsat_core) { + for (auto & e : unsat_core) { + if (is_app(e) && m_util->is_depth_limit(to_app(e))) + return l_undef; + } + return l_false; + } + void theory_recfun::display(std::ostream & out) const { out << "recfun{}"; } diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 2439c07ff..e73b43a7d 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -136,6 +136,7 @@ namespace smt { void restart_eh() override; bool can_propagate() override; void propagate() override; + lbool validate_unsat_core(expr_ref_vector &) override; void new_eq_eh(theory_var v1, theory_var v2) override {} void new_diseq_eh(theory_var v1, theory_var v2) override {} From 2b968f9e6348a04893c2787ca3f66f1a27c61bc6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 9 Aug 2018 15:29:39 -0700 Subject: [PATCH 011/227] initial decl plugin Signed-off-by: Nikolaj Bjorner --- src/ast/CMakeLists.txt | 1 + src/ast/jobshop_decl_plugin.cpp | 178 ++++++++++++++++++++++++++++++++ src/ast/jobshop_decl_plugin.h | 129 +++++++++++++++++++++++ 3 files changed, 308 insertions(+) create mode 100644 src/ast/jobshop_decl_plugin.cpp create mode 100644 src/ast/jobshop_decl_plugin.h diff --git a/src/ast/CMakeLists.txt b/src/ast/CMakeLists.txt index 80543bb05..5340d4e7b 100644 --- a/src/ast/CMakeLists.txt +++ b/src/ast/CMakeLists.txt @@ -30,6 +30,7 @@ z3_add_component(ast fpa_decl_plugin.cpp func_decl_dependencies.cpp has_free_vars.cpp + jobshop_decl_plugin.cpp macro_substitution.cpp num_occurs.cpp occurs.cpp diff --git a/src/ast/jobshop_decl_plugin.cpp b/src/ast/jobshop_decl_plugin.cpp new file mode 100644 index 000000000..41d8ad241 --- /dev/null +++ b/src/ast/jobshop_decl_plugin.cpp @@ -0,0 +1,178 @@ +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + jobshop_decl_plugin.h + +Abstract: + + Declarations used for a job-shop scheduling domain. + +Author: + + Nikolaj Bjorner (nbjorner) 2018-8-9 + +Revision History: + + +--*/ +#include "ast/jobshop_decl_plugin.h" +#include "ast/arith_decl_plugin.h" + +void jobshop_decl_plugin::set_manager(ast_manager* m, family_id fid) { + decl_plugin::set_manager(m, fid); + m_int_sort = m_manager->mk_sort(m_manager->mk_family_id("arith"), INT_SORT); + m_job_sort = m_manager->mk_sort(symbol("Job"), sort_info(m_family_id, JOB_SORT)); + m_resource_sort = m_manager->mk_sort(symbol("Resource"), sort_info(m_family_id, RESOURCE_SORT)); + m_manager->inc_ref(m_int_sort); + m_manager->inc_ref(m_resource_sort); + m_manager->inc_ref(m_job_sort); +} + +void jobshop_decl_plugin::finalize() { + m_manager->dec_ref(m_job_sort); + m_manager->dec_ref(m_resource_sort); + m_manager->dec_ref(m_int_sort); +} + +sort * jobshop_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { + if (num_parameters != 0) { + m_manager->raise_exception("no parameters expected with job-shop sort"); + } + switch (static_cast(k)) { + case JOB_SORT: return m_job_sort; + case RESOURCE_SORT: return m_resource_sort; + default: UNREACHABLE(); return nullptr; + } +} + +func_decl * jobshop_decl_plugin::mk_func_decl( + decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const *, sort *) { + switch (static_cast(k)) { + case OP_JS_JOB: + check_arity(arity); + check_index1(num_parameters, parameters); + return m_manager->mk_func_decl(symbol("job"), 0, (sort* const*)nullptr, m_job_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + case OP_JS_RESOURCE: + check_arity(arity); + check_index1(num_parameters, parameters); + return m_manager->mk_func_decl(symbol("resource"), 0, (sort* const*)nullptr, m_resource_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + case OP_JS_START: + check_arity(arity); + check_index1(num_parameters, parameters); + return m_manager->mk_func_decl(symbol("job-start"), 0, (sort* const*)nullptr, m_int_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + case OP_JS_END: + check_arity(arity); + check_index1(num_parameters, parameters); + return m_manager->mk_func_decl(symbol("job-end"), 0, (sort* const*)nullptr, m_int_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + case OP_JS_JOB2RESOURCE: + check_arity(arity); + check_index1(num_parameters, parameters); + return m_manager->mk_func_decl(symbol("job2resource"), 0, (sort* const*)nullptr, m_int_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + case OP_JS_JOB_ON_RESOURCE: + check_arity(arity); + check_index1(num_parameters, parameters); + return m_manager->mk_func_decl(symbol("job-on-resource"), 0, (sort* const*)nullptr, m_manager->mk_bool_sort(), func_decl_info(m_family_id, k, num_parameters, parameters)); + default: + UNREACHABLE(); return nullptr; + } +} + +void jobshop_decl_plugin::check_arity(unsigned arity) { + if (arity > 0) + m_manager->raise_exception("jobshop variables use parameters only and take no arguments"); +} + +void jobshop_decl_plugin::check_index1(unsigned num_parameters, parameter const* ps) { + if (num_parameters != 1 || !ps[0].is_int()) + m_manager->raise_exception("jobshop variable expects a single integer parameter"); +} + +void jobshop_decl_plugin::check_index2(unsigned num_parameters, parameter const* ps) { + if (num_parameters != 2 || !ps[0].is_int() || !ps[1].is_int()) + m_manager->raise_exception("jobshop variable expects two integer parameters"); +} + + +bool jobshop_decl_plugin::is_value(app * e) const { + return is_app_of(e, m_family_id, OP_JS_JOB) || is_app_of(e, m_family_id, OP_JS_RESOURCE); +} + +void jobshop_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { + if (logic == symbol("JOBSHOP")) { + op_names.push_back(builtin_name("job", OP_JS_JOB)); + op_names.push_back(builtin_name("resource", OP_JS_RESOURCE)); + op_names.push_back(builtin_name("job-start", OP_JS_START)); + op_names.push_back(builtin_name("job-end", OP_JS_END)); + op_names.push_back(builtin_name("job2resource", OP_JS_JOB2RESOURCE)); + op_names.push_back(builtin_name("job-on-resource", OP_JS_JOB_ON_RESOURCE)); + } +} + +void jobshop_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { + if (logic == symbol("JOBSHOP")) { + sort_names.push_back(builtin_name("Job", JOB_SORT)); + sort_names.push_back(builtin_name("Resource", RESOURCE_SORT)); + } +} + +expr * jobshop_decl_plugin::get_some_value(sort * s) { + parameter p(0); + if (is_sort_of(s, m_family_id, JOB_SORT)) + return m_manager->mk_const(mk_func_decl(OP_JS_JOB, 1, &p, 0, nullptr, nullptr)); + if (is_sort_of(s, m_family_id, RESOURCE_SORT)) + return m_manager->mk_const(mk_func_decl(OP_JS_RESOURCE, 1, &p, 0, nullptr, nullptr)); + UNREACHABLE(); + return nullptr; +} + + +jobshop_util::jobshop_util(ast_manager& m): m(m) { + m_fid = m.mk_family_id("jobshop"); + m_plugin = static_cast(m.get_plugin(m_fid)); +} + +sort* jobshop_util::mk_job_sort() { + return m_plugin->mk_job_sort(); +} + +sort* jobshop_util::mk_resource_sort() { + return m_plugin->mk_resource_sort(); +} + +app* jobshop_util::mk_job(unsigned j) { + parameter p(j); + return m.mk_const(m.mk_func_decl(m_fid, OP_JS_JOB, 1, &p, 0, (sort*const*)nullptr, nullptr)); +} + +unsigned jobshop_util::job2id(expr* j) { + SASSERT(is_app_of(j, m_fid, OP_JS_JOB)); + return to_app(j)->get_decl()->get_parameter(0).get_int(); +} + +app* jobshop_util::mk_resource(unsigned r) { + parameter p(r); + return m.mk_const(m.mk_func_decl(m_fid, OP_JS_RESOURCE, 1, &p, 0, (sort*const*)nullptr, nullptr)); +} + +unsigned jobshop_util::resource2id(expr* r) { + SASSERT(is_app_of(r, m_fid, OP_JS_RESOURCE)); + return to_app(r)->get_decl()->get_parameter(0).get_int(); +} + +app* jobshop_util::mk_start(unsigned j) { + parameter p(j); + return m.mk_const(m.mk_func_decl(m_fid, OP_JS_START, 1, &p, 0, (sort*const*)nullptr, nullptr)); +} + +app* jobshop_util::mk_end(unsigned j) { + parameter p(j); + return m.mk_const(m.mk_func_decl(m_fid, OP_JS_END, 1, &p, 0, (sort*const*)nullptr, nullptr)); +} + +app* jobshop_util::mk_on_resource(unsigned j) { + parameter p(j); + return m.mk_const(m.mk_func_decl(m_fid, OP_JS_END, 1, &p, 0, (sort*const*)nullptr, nullptr)); +} + diff --git a/src/ast/jobshop_decl_plugin.h b/src/ast/jobshop_decl_plugin.h new file mode 100644 index 000000000..94936c5aa --- /dev/null +++ b/src/ast/jobshop_decl_plugin.h @@ -0,0 +1,129 @@ +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + jobshop_decl_plugin.h + +Abstract: + + Declarations used for a job-shop scheduling domain. + + The job-shop domain comprises of constants job(j), resource(r) + + It finds values to variables: + - start(j), end(j), job2resource(j), job-on-resource(j, r) + + It assumes a background of: + - resources : Job -> Resource -> Int * LoadPct - time to run job j on resource r assuming LoadPct + - runtime : Job -> Int - time to run job j if not associated with any resource + - capacity : Resource -> Int -> LoadPct - capacity of resource r at time t, given as sequence of time intervals + + // Theory: + job-on-resource(j) => resource(j) in dom j.resources; + end(j) - start(j) = time-to-execute(j) + time-to-execute(j) := runtime(j) if !job-on-resource(j) + time-to-execute(j) := time-to-execute(j, resource(j)) otherwise + + time-to-execute(j, r) := (T - start(j)) + where capacity(j,r) = sum_{t = start(j)}^{T} load(loadpct(j,r), r, t) + + capacity(j, r) := cap where (cap, loadpct) = resources j r + loadpct(j, r) := loadpct where (cap, loadpct) = resources j r + + load(loadpct, r, t) := min(capacity r t, loadpct) / loadpct + + capacity(r, t) >= sum_{j | job-on-resource(j, r, t) } min(capacity r t, loadpct(j, r)) + + // Macros: + job-on-resource(j, r) := (job-on-resource(j) & r = resource(j)); + job-on-resource(j, r, t) := (job-on-resource(j, r) & start(j) <= t <= end(j)); + start_min(j, t) := start(j) >= t; + end_max(j, t) := end(j) <= t; + job_link(j1, j2, startstart, hard) := start(j1) = start(j2); + job_link(j1, j2, startstart, soft) := start(j1) <= start(j2); + job_link(j1, j2, endend, hard) := end(j1) = end(j2); + job_link(j1, j2, endend, soft) := end(j2) <= end(j1); + job_link(j1, j2, endstart, hard) := end(j1) = start(j2); + job_link(j1, j2, endstart, soft) := end(j2) <= start(j1); + job_link(j1, j2, startend, hard) := end(j2) = start(j1); + job_link(j1, j2, startend, soft) := end(j1) <= start(j2); + job_delay(j1, j2, t) := end(j1) + t <= end(j2); + job_on_same_resource(j1, j2) := job-on-resource(j1) & job-on-resource(j2) & resource(j1) = resource(j2); + job_not_on_same_resource(j1, j2) := !(job-on-resource(j1) & job-on-resource(j2) & resource(j1) = resource(j2)); + job_time_intersect(j1, j2) := start(j1) <= end(j2) <= end(j1) || start(j2) <= end(j1) <= end(j2); + run_time_bound(j) := !(job-on-resource(j)); + + job-on-resource(j, r, t) => job-property(j) = null or job_property(j) in working_time_property(r, t); + +Author: + + Nikolaj Bjorner (nbjorner) 2018-8-9 + +Revision History: + + +--*/ +#pragma once; +#include "ast/ast.h" + +enum js_sort_kind { + JOB_SORT, + RESOURCE_SORT +}; + +enum js_op_kind { + OP_JS_JOB, // value of type job + OP_JS_RESOURCE, // value of type resource + OP_JS_START, // start time of a job + OP_JS_END, // end time of a job + OP_JS_JOB2RESOURCE, // resource associated with job + OP_JS_JOB_ON_RESOURCE // is a job associated with a resource +}; + +class jobshop_decl_plugin : public decl_plugin { +public: + jobshop_decl_plugin() {} + ~jobshop_decl_plugin() override {} + void finalize() override; + void set_manager(ast_manager* m, family_id fid) override; + decl_plugin * mk_fresh() override { return alloc(jobshop_decl_plugin); } + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; + bool is_value(app * e) const override; + bool is_unique_value(app * e) const override { return is_value(e); } + void get_op_names(svector & op_names, symbol const & logic) override; + void get_sort_names(svector & sort_names, symbol const & logic) override; + expr * get_some_value(sort * s) override; + sort * mk_job_sort() const { return m_job_sort; } + sort * mk_resource_sort() const { return m_resource_sort; } +private: + sort* m_job_sort; + sort* m_resource_sort; + sort* m_int_sort; + + void check_arity(unsigned arity); + void check_index1(unsigned n, parameter const* ps); + void check_index2(unsigned n, parameter const* ps); +}; + +class jobshop_util { + ast_manager& m; + family_id m_fid; + jobshop_decl_plugin* m_plugin; +public: + jobshop_util(ast_manager& m); + sort* mk_job_sort(); + sort* mk_resource_sort(); + + app* mk_job(unsigned j); + unsigned job2id(expr* j); + + app* mk_resource(unsigned r); + unsigned resource2id(expr* r); + + app* mk_start(unsigned j); + app* mk_end(unsigned j); + app* mk_on_resource(unsigned j); +}; From 0d8de8f65fd4d3500d1db093bd5148d645bbfb97 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 9 Aug 2018 20:19:26 -0700 Subject: [PATCH 012/227] add theory outlline Signed-off-by: Nikolaj Bjorner --- src/ast/jobshop_decl_plugin.cpp | 10 --- src/ast/jobshop_decl_plugin.h | 21 ++--- src/smt/CMakeLists.txt | 1 + src/smt/theory_jobscheduler.cpp | 146 ++++++++++++++++++++++++++++++++ src/smt/theory_jobscheduler.h | 124 +++++++++++++++++++++++++++ 5 files changed, 280 insertions(+), 22 deletions(-) create mode 100644 src/smt/theory_jobscheduler.cpp create mode 100644 src/smt/theory_jobscheduler.h diff --git a/src/ast/jobshop_decl_plugin.cpp b/src/ast/jobshop_decl_plugin.cpp index 41d8ad241..ced77690d 100644 --- a/src/ast/jobshop_decl_plugin.cpp +++ b/src/ast/jobshop_decl_plugin.cpp @@ -70,10 +70,6 @@ func_decl * jobshop_decl_plugin::mk_func_decl( check_arity(arity); check_index1(num_parameters, parameters); return m_manager->mk_func_decl(symbol("job2resource"), 0, (sort* const*)nullptr, m_int_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); - case OP_JS_JOB_ON_RESOURCE: - check_arity(arity); - check_index1(num_parameters, parameters); - return m_manager->mk_func_decl(symbol("job-on-resource"), 0, (sort* const*)nullptr, m_manager->mk_bool_sort(), func_decl_info(m_family_id, k, num_parameters, parameters)); default: UNREACHABLE(); return nullptr; } @@ -106,7 +102,6 @@ void jobshop_decl_plugin::get_op_names(svector & op_names, symbol op_names.push_back(builtin_name("job-start", OP_JS_START)); op_names.push_back(builtin_name("job-end", OP_JS_END)); op_names.push_back(builtin_name("job2resource", OP_JS_JOB2RESOURCE)); - op_names.push_back(builtin_name("job-on-resource", OP_JS_JOB_ON_RESOURCE)); } } @@ -171,8 +166,3 @@ app* jobshop_util::mk_end(unsigned j) { return m.mk_const(m.mk_func_decl(m_fid, OP_JS_END, 1, &p, 0, (sort*const*)nullptr, nullptr)); } -app* jobshop_util::mk_on_resource(unsigned j) { - parameter p(j); - return m.mk_const(m.mk_func_decl(m_fid, OP_JS_END, 1, &p, 0, (sort*const*)nullptr, nullptr)); -} - diff --git a/src/ast/jobshop_decl_plugin.h b/src/ast/jobshop_decl_plugin.h index 94936c5aa..6a78646b0 100644 --- a/src/ast/jobshop_decl_plugin.h +++ b/src/ast/jobshop_decl_plugin.h @@ -12,17 +12,17 @@ Abstract: The job-shop domain comprises of constants job(j), resource(r) It finds values to variables: - - start(j), end(j), job2resource(j), job-on-resource(j, r) + - start(j), end(j), job2resource(j) It assumes a background of: - resources : Job -> Resource -> Int * LoadPct - time to run job j on resource r assuming LoadPct - runtime : Job -> Int - time to run job j if not associated with any resource - capacity : Resource -> Int -> LoadPct - capacity of resource r at time t, given as sequence of time intervals - + // assume each job has at least one resource associated with it. + // introduce a dummy resource if needed. + // Theory: - job-on-resource(j) => resource(j) in dom j.resources; end(j) - start(j) = time-to-execute(j) - time-to-execute(j) := runtime(j) if !job-on-resource(j) time-to-execute(j) := time-to-execute(j, resource(j)) otherwise time-to-execute(j, r) := (T - start(j)) @@ -36,7 +36,7 @@ Abstract: capacity(r, t) >= sum_{j | job-on-resource(j, r, t) } min(capacity r t, loadpct(j, r)) // Macros: - job-on-resource(j, r) := (job-on-resource(j) & r = resource(j)); + job-on-resource(j, r) := r = resource(j); job-on-resource(j, r, t) := (job-on-resource(j, r) & start(j) <= t <= end(j)); start_min(j, t) := start(j) >= t; end_max(j, t) := end(j) <= t; @@ -49,11 +49,10 @@ Abstract: job_link(j1, j2, startend, hard) := end(j2) = start(j1); job_link(j1, j2, startend, soft) := end(j1) <= start(j2); job_delay(j1, j2, t) := end(j1) + t <= end(j2); - job_on_same_resource(j1, j2) := job-on-resource(j1) & job-on-resource(j2) & resource(j1) = resource(j2); - job_not_on_same_resource(j1, j2) := !(job-on-resource(j1) & job-on-resource(j2) & resource(j1) = resource(j2)); + job_on_same_resource(j1, j2) := resource(j1) = resource(j2); + job_not_on_same_resource(j1, j2) := resource(j1) != resource(j2); job_time_intersect(j1, j2) := start(j1) <= end(j2) <= end(j1) || start(j2) <= end(j1) <= end(j2); - run_time_bound(j) := !(job-on-resource(j)); - + job-on-resource(j, r, t) => job-property(j) = null or job_property(j) in working_time_property(r, t); Author: @@ -77,8 +76,7 @@ enum js_op_kind { OP_JS_RESOURCE, // value of type resource OP_JS_START, // start time of a job OP_JS_END, // end time of a job - OP_JS_JOB2RESOURCE, // resource associated with job - OP_JS_JOB_ON_RESOURCE // is a job associated with a resource + OP_JS_JOB2RESOURCE // resource associated with job }; class jobshop_decl_plugin : public decl_plugin { @@ -125,5 +123,4 @@ public: app* mk_start(unsigned j); app* mk_end(unsigned j); - app* mk_on_resource(unsigned j); }; diff --git a/src/smt/CMakeLists.txt b/src/smt/CMakeLists.txt index fb1997fb4..13a00d44e 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -55,6 +55,7 @@ z3_add_component(smt theory_dl.cpp theory_dummy.cpp theory_fpa.cpp + theory_jobscheduler.cpp theory_lra.cpp theory_opt.cpp theory_pb.cpp diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp new file mode 100644 index 000000000..bf49a00fb --- /dev/null +++ b/src/smt/theory_jobscheduler.cpp @@ -0,0 +1,146 @@ +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + theory_jobscheduler.cpp + +Abstract: + + +Author: + + Nikolaj Bjorner (nbjorner) 2018-09-08. + +Revision History: + +--*/ + +#include "smt/theory_jobscheduler.h" +#include "smt/smt_context.h" + +namespace smt { + + theory_var theory_jobscheduler::mk_var(enode * n) { + theory_var v = theory::mk_var(n); + return v; + } + + bool theory_jobscheduler::internalize_atom(app * atom, bool gate_ctx) { + return false; + } + + bool theory_jobscheduler::internalize_term(app * term) { + return false; + } + + void theory_jobscheduler::assign_eh(bool_var v, bool is_true) { + + } + + void theory_jobscheduler::new_eq_eh(theory_var v1, theory_var v2) { + + } + + void theory_jobscheduler::new_diseq_eh(theory_var v1, theory_var v2) { + + } + + void theory_jobscheduler::push_scope_eh() { + + } + + void theory_jobscheduler::pop_scope_eh(unsigned num_scopes) { + + } + + final_check_status theory_jobscheduler::final_check_eh() { + return FC_DONE; + } + + bool theory_jobscheduler::can_propagate() { + return false; + } + + void theory_jobscheduler::propagate() { + + } + + theory_jobscheduler::theory_jobscheduler(ast_manager& m): theory(m.get_family_id("jobshop")), m(m), u(m) { + + } + + void theory_jobscheduler::display(std::ostream & out) const { + + } + + void theory_jobscheduler::collect_statistics(::statistics & st) const { + + } + + void theory_jobscheduler::init_model(model_generator & m) { + + } + + model_value_proc * theory_jobscheduler::mk_value(enode * n, model_generator & mg) { + return nullptr; + } + + bool theory_jobscheduler::get_value(enode * n, expr_ref & r) { + return false; + } + + theory * theory_jobscheduler::mk_fresh(context * new_ctx) { + return alloc(theory_jobscheduler, new_ctx->get_manager()); + } + + uint64_t theory_jobscheduler::est(unsigned j) { + return 0; + } + + uint64_t theory_jobscheduler::lst(unsigned j) { + return 0; + } + + uint64_t theory_jobscheduler::ect(unsigned j) { + return 0; + } + + uint64_t theory_jobscheduler::lct(unsigned j) { + return 0; + } + + uint64_t theory_jobscheduler::start(unsigned j) { + return 0; + } + + uint64_t theory_jobscheduler::end(unsigned j) { + return 0; + } + + unsigned theory_jobscheduler::resource(unsigned j) { + return 0; + } + + + void theory_jobscheduler::add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, uint64_t end) { + m_jobs.reserve(j + 1); + m_resources.reserve(r + 1); + job_info& ji = m_jobs[j]; + if (ji.m_resource2index.contains(r)) { + throw default_exception("resource already bound to job"); + } + ji.m_resource2index.insert(r, ji.m_resources.size()); + ji.m_resources.push_back(job_resource(r, cap, loadpct, end)); + SASSERT(!m_resources[r].m_jobs.contains(j)); + m_resources[r].m_jobs.push_back(j); + } + + void theory_jobscheduler::add_resource_available(unsigned r, unsigned max_loadpct, uint64_t start, uint64_t end) { + SASSERT(start < end); + m_resources.reserve(r + 1); + m_resources[r].m_available.push_back(res_available(max_loadpct, start, end)); + } + +}; + diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h new file mode 100644 index 000000000..7e93e3454 --- /dev/null +++ b/src/smt/theory_jobscheduler.h @@ -0,0 +1,124 @@ +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + theory_jobscheduling.h + +Abstract: + + Propagation solver for jobscheduling problems. + It relies on an external module to tighten bounds of + job variables. + +Author: + + Nikolaj Bjorner (nbjorner) 2018-09-08. + +Revision History: + +--*/ +#pragma once; + +#include "smt/smt_theory.h" +#include "ast/jobshop_decl_plugin.h" + +namespace smt { + + class theory_jobscheduler : public theory { + + struct job_resource { + unsigned m_resource_id; // id of resource + unsigned m_capacity; // amount of resource to use + unsigned m_loadpct; // assuming loadpct + uint64_t m_end; // must run before + job_resource(unsigned r, unsigned cap, unsigned loadpct, uint64_t end): + m_resource_id(r), m_capacity(cap), m_loadpct(loadpct), m_end(end) {} + }; + + struct job_info { + vector m_resources; // resources allowed to run job. + u_map m_resource2index; // resource to index into vector + }; + + struct res_available { + unsigned m_loadpct; + uint64_t m_start; + uint64_t m_end; + res_available(unsigned load_pct, uint64_t start, uint64_t end): + m_loadpct(load_pct), + m_start(start), + m_end(end) + {} + }; + + struct res_info { + unsigned_vector m_jobs; // jobs allocated to run on resource + vector m_available; // time intervals where resource is available + uint64_t m_end; // can't run after + res_info(): m_end(std::numeric_limits::max()) {} + }; + + ast_manager& m; + jobshop_util u; + vector m_jobs; + vector m_resources; + + protected: + + theory_var mk_var(enode * n) override; + + bool internalize_atom(app * atom, bool gate_ctx) override; + + bool internalize_term(app * term) override; + + void assign_eh(bool_var v, bool is_true) override; + + void new_eq_eh(theory_var v1, theory_var v2) override; + + void new_diseq_eh(theory_var v1, theory_var v2) override; + + void push_scope_eh() override; + + void pop_scope_eh(unsigned num_scopes) override; + + final_check_status final_check_eh() override; + + bool can_propagate() override; + + void propagate() override; + + public: + + theory_jobscheduler(ast_manager& m); + + ~theory_jobscheduler() override {} + + void display(std::ostream & out) const override; + + void collect_statistics(::statistics & st) const override; + + void init_model(model_generator & m) override; + + model_value_proc * mk_value(enode * n, model_generator & mg) override; + + bool get_value(enode * n, expr_ref & r) override; + + theory * mk_fresh(context * new_ctx) override; // { return alloc(theory_jobscheduler, new_ctx->get_manager()); } + + public: + // assignments: + uint64_t est(unsigned j); // earliest start time of job j + uint64_t lst(unsigned j); // last start time + uint64_t ect(unsigned j); // earliest completion time + uint64_t lct(unsigned j); // last completion time + uint64_t start(unsigned j); // start time of job j + uint64_t end(unsigned j); // end time of job j + unsigned resource(unsigned j); // resource of job j + + // set up model + void add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, uint64_t end); + void add_resource_available(unsigned r, unsigned max_loadpct, uint64_t start, uint64_t end); + }; +}; + From baeff82e5995dd9d7da9bd2a5095c6833fa1c8fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Aug 2018 09:46:21 -0700 Subject: [PATCH 013/227] na Signed-off-by: Nikolaj Bjorner --- src/ast/jobshop_decl_plugin.cpp | 10 +++++- src/ast/jobshop_decl_plugin.h | 1 + src/smt/theory_jobscheduler.cpp | 61 +++++++++++++++++++++++---------- src/smt/theory_jobscheduler.h | 13 ++++--- 4 files changed, 62 insertions(+), 23 deletions(-) diff --git a/src/ast/jobshop_decl_plugin.cpp b/src/ast/jobshop_decl_plugin.cpp index ced77690d..7a7b1b590 100644 --- a/src/ast/jobshop_decl_plugin.cpp +++ b/src/ast/jobshop_decl_plugin.cpp @@ -142,7 +142,10 @@ app* jobshop_util::mk_job(unsigned j) { } unsigned jobshop_util::job2id(expr* j) { - SASSERT(is_app_of(j, m_fid, OP_JS_JOB)); + SASSERT(is_app_of(j, m_fid, OP_JS_JOB) || + is_app_of(j, m_fid, OP_JS_START) || + is_app_of(j, m_fid, OP_JS_END) || + is_app_of(j, m_fid, OP_JS_JOB2RESOURCE)); return to_app(j)->get_decl()->get_parameter(0).get_int(); } @@ -166,3 +169,8 @@ app* jobshop_util::mk_end(unsigned j) { return m.mk_const(m.mk_func_decl(m_fid, OP_JS_END, 1, &p, 0, (sort*const*)nullptr, nullptr)); } +app* jobshop_util::mk_job2resource(unsigned j) { + parameter p(j); + return m.mk_const(m.mk_func_decl(m_fid, OP_JS_JOB2RESOURCE, 1, &p, 0, (sort*const*)nullptr, nullptr)); +} + diff --git a/src/ast/jobshop_decl_plugin.h b/src/ast/jobshop_decl_plugin.h index 6a78646b0..48bdde6c1 100644 --- a/src/ast/jobshop_decl_plugin.h +++ b/src/ast/jobshop_decl_plugin.h @@ -123,4 +123,5 @@ public: app* mk_start(unsigned j); app* mk_end(unsigned j); + app* mk_job2resource(unsigned j); }; diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index bf49a00fb..f8439917e 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -26,32 +26,55 @@ namespace smt { return v; } - bool theory_jobscheduler::internalize_atom(app * atom, bool gate_ctx) { - return false; - } - bool theory_jobscheduler::internalize_term(app * term) { - return false; + context & ctx = get_context(); + if (ctx.e_internalized(term)) + return true; + enode* e = ctx.mk_enode(term, false, false, true); + switch (static_cast(term->get_decl()->get_decl_kind())) { + case OP_JS_JOB: { + unsigned j = u.job2id(term); + app_ref start(u.mk_start(j), m); + app_ref end(u.mk_end(j), m); + app_ref res(u.mk_resource(j), m); + if (!ctx.e_internalized(start)) ctx.internalize(start, false); + if (!ctx.e_internalized(end)) ctx.internalize(end, false); + if (!ctx.e_internalized(res)) ctx.internalize(res, false); + theory_var v = mk_var(e); + SASSERT(m_var2index.size() == v); + m_var2index.push_back(j); + m_jobs.reserve(j + 1); + m_jobs[j].m_start = ctx.get_enode(start); + m_jobs[j].m_end = ctx.get_enode(end); + m_jobs[j].m_resource = ctx.get_enode(res); + ctx.attach_th_var(e, this, v); + break; + } + case OP_JS_RESOURCE: { + theory_var v = mk_var(e); + SASSERT(m_var2index.size() == v); + unsigned r = u.resource2id(term); + m_var2index.push_back(r); + ctx.attach_th_var(e, this, v); + break; + } + case OP_JS_START: + case OP_JS_END: + case OP_JS_JOB2RESOURCE: { + unsigned j = u.job2id(term); + app_ref job(u.mk_job(j), m); + if (!ctx.e_internalized(job)) ctx.internalize(job, false); + break; + } + } + return true; } - void theory_jobscheduler::assign_eh(bool_var v, bool is_true) { - - } - - void theory_jobscheduler::new_eq_eh(theory_var v1, theory_var v2) { - - } - - void theory_jobscheduler::new_diseq_eh(theory_var v1, theory_var v2) { - - } void theory_jobscheduler::push_scope_eh() { - } void theory_jobscheduler::pop_scope_eh(unsigned num_scopes) { - } final_check_status theory_jobscheduler::final_check_eh() { @@ -124,6 +147,7 @@ namespace smt { void theory_jobscheduler::add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, uint64_t end) { + // assert: done at base level m_jobs.reserve(j + 1); m_resources.reserve(r + 1); job_info& ji = m_jobs[j]; @@ -137,6 +161,7 @@ namespace smt { } void theory_jobscheduler::add_resource_available(unsigned r, unsigned max_loadpct, uint64_t start, uint64_t end) { + // assert: done at base level SASSERT(start < end); m_resources.reserve(r + 1); m_resources[r].m_available.push_back(res_available(max_loadpct, start, end)); diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index 7e93e3454..ec09ce0ce 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -39,6 +39,10 @@ namespace smt { struct job_info { vector m_resources; // resources allowed to run job. u_map m_resource2index; // resource to index into vector + enode* m_start; + enode* m_end; + enode* m_resource; + job_info(): m_start(nullptr), m_end(nullptr), m_resource(nullptr) {} }; struct res_available { @@ -61,6 +65,7 @@ namespace smt { ast_manager& m; jobshop_util u; + unsigned_vector m_var2index; vector m_jobs; vector m_resources; @@ -68,15 +73,15 @@ namespace smt { theory_var mk_var(enode * n) override; - bool internalize_atom(app * atom, bool gate_ctx) override; + bool internalize_atom(app * atom, bool gate_ctx) override { return false; } bool internalize_term(app * term) override; - void assign_eh(bool_var v, bool is_true) override; + void assign_eh(bool_var v, bool is_true) override {} - void new_eq_eh(theory_var v1, theory_var v2) override; + void new_eq_eh(theory_var v1, theory_var v2) override {} - void new_diseq_eh(theory_var v1, theory_var v2) override; + void new_diseq_eh(theory_var v1, theory_var v2) override {} void push_scope_eh() override; From 55f15b09214404a80f7918d2aaa15cc9b48c7cbe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Aug 2018 17:52:34 -0700 Subject: [PATCH 014/227] na Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.h | 3 + src/smt/theory_jobscheduler.cpp | 232 ++++++++++++++++++++++++++++++-- src/smt/theory_jobscheduler.h | 66 ++++++--- 3 files changed, 273 insertions(+), 28 deletions(-) diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 09f082522..aea8863af 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -361,6 +361,9 @@ public: app * mk_int(int i) { return mk_numeral(rational(i), true); } + app * mk_int(rational const& r) { + return mk_numeral(r, true); + } app * mk_real(int i) { return mk_numeral(rational(i), false); } diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index f8439917e..d2cab8bf8 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -89,12 +89,41 @@ namespace smt { } - theory_jobscheduler::theory_jobscheduler(ast_manager& m): theory(m.get_family_id("jobshop")), m(m), u(m) { + theory_jobscheduler::theory_jobscheduler(ast_manager& m): + theory(m.get_family_id("jobshop")), m(m), u(m), a(m) { } - - void theory_jobscheduler::display(std::ostream & out) const { + std::ostream& theory_jobscheduler::display(std::ostream & out, job_resource const& jr) const { + return out << " r:" << jr.m_resource_id << " cap:" << jr.m_capacity << " load:" << jr.m_loadpct << " end:" << jr.m_end << "\n"; + } + + std::ostream& theory_jobscheduler::display(std::ostream & out, job_info const& j) const { + for (job_resource const& jr : j.m_resources) { + display(out, jr); + } + return out; + } + + std::ostream& theory_jobscheduler::display(std::ostream & out, res_available const& r) const { + out << "[" << r.m_start << ":" << r.m_end << "] @ " << r.m_loadpct << "%%\n"; + return out; + } + + std::ostream& theory_jobscheduler::display(std::ostream & out, res_info const& r) const { + for (res_available const& ra : r.m_available) { + display(out, ra); + } + return out; + } + + void theory_jobscheduler::display(std::ostream & out) const { + for (unsigned j = 0; j < m_jobs.size(); ++j) { + display(out << "job " << j << ":\n", m_jobs[j]); + } + for (unsigned r = 0; r < m_resources.size(); ++r) { + display(out << "resource " << r << ":\n", m_resources[r]); + } } void theory_jobscheduler::collect_statistics(::statistics & st) const { @@ -117,27 +146,27 @@ namespace smt { return alloc(theory_jobscheduler, new_ctx->get_manager()); } - uint64_t theory_jobscheduler::est(unsigned j) { + time_t theory_jobscheduler::est(unsigned j) { return 0; } - uint64_t theory_jobscheduler::lst(unsigned j) { + time_t theory_jobscheduler::lst(unsigned j) { return 0; } - uint64_t theory_jobscheduler::ect(unsigned j) { + time_t theory_jobscheduler::ect(unsigned j) { return 0; } - uint64_t theory_jobscheduler::lct(unsigned j) { + time_t theory_jobscheduler::lct(unsigned j) { return 0; } - uint64_t theory_jobscheduler::start(unsigned j) { + time_t theory_jobscheduler::start(unsigned j) { return 0; } - uint64_t theory_jobscheduler::end(unsigned j) { + time_t theory_jobscheduler::end(unsigned j) { return 0; } @@ -146,8 +175,8 @@ namespace smt { } - void theory_jobscheduler::add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, uint64_t end) { - // assert: done at base level + void theory_jobscheduler::add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, time_t end) { + SASSERT(get_context().at_base_level()); m_jobs.reserve(j + 1); m_resources.reserve(r + 1); job_info& ji = m_jobs[j]; @@ -160,12 +189,189 @@ namespace smt { m_resources[r].m_jobs.push_back(j); } - void theory_jobscheduler::add_resource_available(unsigned r, unsigned max_loadpct, uint64_t start, uint64_t end) { - // assert: done at base level + void theory_jobscheduler::add_resource_available(unsigned r, unsigned max_loadpct, time_t start, time_t end) { + SASSERT(get_context().at_base_level()); SASSERT(start < end); m_resources.reserve(r + 1); m_resources[r].m_available.push_back(res_available(max_loadpct, start, end)); } + + /* + * Initialze the state based on the set of jobs and resources added. + * For each job j, with possible resources r1, ..., r_n assert + * resource(j) = r_1 || resource(j) = r_2 || ... || resource(j) = r_n + * For each job and resource r with deadline end(j,r) assert + * resource(j) = r => end(j) <= end(j,r) + * + * Ensure that the availability slots for each resource is sorted by time. + */ + void theory_jobscheduler::add_done() { + context & ctx = get_context(); + for (unsigned j = 0; j < m_jobs.size(); ++j) { + job_info const& ji = m_jobs[j]; + expr_ref_vector disj(m); + app_ref job(u.mk_job(j), m); + if (ji.m_resources.empty()) { + throw default_exception("every job should be associated with at least one resource"); + } + // resource(j) = r => end(j) <= end(j, r) + for (job_resource const& jr : ji.m_resources) { + app_ref res(u.mk_resource(jr.m_resource_id), m); + expr_ref eq(m.mk_eq(job, res), m); + expr_ref imp(m.mk_implies(eq, a.mk_le(ji.m_start->get_owner(), a.mk_int(rational(jr.m_end, rational::ui64())))), m); + ctx.assert_expr(imp); + disj.push_back(eq); + } + // resource(j) = r1 || ... || resource(j) = r_n + expr_ref fml = mk_or(disj); + ctx.assert_expr(fml); + } + for (unsigned r = 0; r < m_resources.size(); ++r) { + vector& available = m_resources[r].m_available; + res_available::compare cmp; + std::sort(available.begin(), available.end(), cmp); + for (unsigned i = 0; i < available.size(); ++i) { + if (i + 1 < available.size() && + available[i].m_end > available[i + 1].m_start) { + throw default_exception("availability intervals should be disjoint"); + } + } + } + } + + /** + * check that each job is run on some resource according to + * requested capacity. + * + * Check that the sum of jobs run in each time instance + * does not exceed capacity. + */ + void theory_jobscheduler::validate_assignment() { + vector> start_times, end_times; + start_times.reserve(m_resources.size()); + end_times.reserve(m_resources.size()); + for (unsigned j = 0; j < m_jobs.size(); ++j) { + unsigned r = resource(j); + start_times[r].push_back(job_time(j, start(j))); + end_times[r].push_back(job_time(j, end(j))); + time_t cap = capacity_used(j, r, start(j), end(j)); + job_resource const& jr = get_job_resource(j, r); + if (jr.m_capacity > cap) { + throw default_exception("job not assigned full capacity"); + } + } + for (unsigned r = 0; r < m_resources.size(); ++r) { + unsigned load_pct = 0; + unsigned idx; + time_t next = 0, start = 0; + + // order jobs running on r by start, end-time intervals + // then consume ordered list to find jobs in scope. + vector& starts = start_times[r]; + vector& ends = end_times[r]; + job_time::compare cmp; + std::sort(starts.begin(), starts.end(), cmp); + std::sort(ends.begin(), ends.end(), cmp); + unsigned s_idx = 0, e_idx = 0; + + uint_set jobs; // set of jobs currently in scope. + while (resource_available(r, start, load_pct, next, idx)) { + if (load_pct == 0) { + start = next + 1; + continue; + } + // add jobs that begin at or before start. + while (s_idx < starts.size() && starts[s_idx].m_time <= start) { + jobs.insert(starts[s_idx].m_job); + ++s_idx; + } + // remove jobs that end before start. + while (e_idx < ends.size() && ends[s_idx].m_time < start) { + jobs.remove(ends[e_idx].m_job); + ++e_idx; + } + + // check that sum of job loads does not exceed 100% + unsigned cap = 0; + for (auto j : jobs) { + cap += get_job_resource(j, r).m_loadpct; + } + if (cap > 100) { + throw default_exception("capacity on resource exceeded"); + } + if (s_idx < starts.size()) { + // start time of the next unprocessed job. + start = starts[s_idx].m_time; + } + else { + // done checking. + break; + } + } + } + } + + theory_jobscheduler::job_resource const& theory_jobscheduler::get_job_resource(unsigned j, unsigned r) const { + job_info const& ji = m_jobs[j]; + return ji.m_resources[ji.m_resource2index[r]]; + } + + bool theory_jobscheduler::resource_available(unsigned r, time_t t, unsigned& load_pct, time_t& end, unsigned& idx) { + vector& available = m_resources[r].m_available; + unsigned lo = 0, hi = available.size(), mid = hi / 2; + while (lo < hi) { + res_available const& ra = available[mid]; + if (ra.m_start <= t && t <= ra.m_end) { + end = ra.m_end; + load_pct = ra.m_loadpct; + idx = mid; + return true; + } + else if (ra.m_start > t && mid > 0) { + hi = mid - 1; + mid = lo + (mid - lo) / 2; + } + else if (ra.m_end < t) { + lo = mid + 1; + mid += (hi - mid) / 2; + } + else { + break; + } + } + return false; + } + + /** + * compute the capacity used by job j on resource r between start and end. + * The resource r partitions time intervals into segments where a fraction of + * the full capacity of the resource is available. The resource can use up to the + * available fraction. + */ + time_t theory_jobscheduler::capacity_used(unsigned j, unsigned r, time_t start, time_t end) { + time_t cap = 0; + unsigned j_load_pct = get_job_resource(j, r).m_loadpct; + vector& available = m_resources[r].m_available; + unsigned load_pct = 0; + time_t next = 0; + unsigned idx = 0; + if (!resource_available(r, start, load_pct, next, idx)) { + return cap; + } + while (start < end) { + next = std::min(end, next); + SASSERT(start < next); + cap += (std::min(j_load_pct, load_pct) / j_load_pct) * (next - start - 1); + ++idx; + if (idx == available.size()) { + break; + } + start = available[idx].m_start; + next = available[idx].m_end; + load_pct = available[idx].m_loadpct; + } + return cap; + } }; diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index ec09ce0ce..f10b72d81 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -22,20 +22,35 @@ Revision History: #include "smt/smt_theory.h" #include "ast/jobshop_decl_plugin.h" +#include "ast/arith_decl_plugin.h" namespace smt { + typedef uint64_t time_t; + class theory_jobscheduler : public theory { struct job_resource { unsigned m_resource_id; // id of resource unsigned m_capacity; // amount of resource to use unsigned m_loadpct; // assuming loadpct - uint64_t m_end; // must run before - job_resource(unsigned r, unsigned cap, unsigned loadpct, uint64_t end): + time_t m_end; // must run before + job_resource(unsigned r, unsigned cap, unsigned loadpct, time_t end): m_resource_id(r), m_capacity(cap), m_loadpct(loadpct), m_end(end) {} }; + struct job_time { + unsigned m_job; + time_t m_time; + job_time(unsigned j, time_t time): m_job(j), m_time(time) {} + + struct compare { + bool operator()(job_time const& jt1, job_time const& jt2) const { + return jt1.m_time < jt2.m_time; + } + }; + }; + struct job_info { vector m_resources; // resources allowed to run job. u_map m_resource2index; // resource to index into vector @@ -47,24 +62,31 @@ namespace smt { struct res_available { unsigned m_loadpct; - uint64_t m_start; - uint64_t m_end; - res_available(unsigned load_pct, uint64_t start, uint64_t end): + time_t m_start; + time_t m_end; + res_available(unsigned load_pct, time_t start, time_t end): m_loadpct(load_pct), m_start(start), m_end(end) {} + struct compare { + bool operator()(res_available const& ra1, res_available const& ra2) const { + return ra1.m_start < ra2.m_start; + } + }; + }; struct res_info { unsigned_vector m_jobs; // jobs allocated to run on resource vector m_available; // time intervals where resource is available - uint64_t m_end; // can't run after - res_info(): m_end(std::numeric_limits::max()) {} + time_t m_end; // can't run after + res_info(): m_end(std::numeric_limits::max()) {} }; ast_manager& m; jobshop_util u; + arith_util a; unsigned_vector m_var2index; vector m_jobs; vector m_resources; @@ -113,17 +135,31 @@ namespace smt { public: // assignments: - uint64_t est(unsigned j); // earliest start time of job j - uint64_t lst(unsigned j); // last start time - uint64_t ect(unsigned j); // earliest completion time - uint64_t lct(unsigned j); // last completion time - uint64_t start(unsigned j); // start time of job j - uint64_t end(unsigned j); // end time of job j + time_t est(unsigned j); // earliest start time of job j + time_t lst(unsigned j); // last start time + time_t ect(unsigned j); // earliest completion time + time_t lct(unsigned j); // last completion time + time_t start(unsigned j); // start time of job j + time_t end(unsigned j); // end time of job j unsigned resource(unsigned j); // resource of job j // set up model - void add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, uint64_t end); - void add_resource_available(unsigned r, unsigned max_loadpct, uint64_t start, uint64_t end); + void add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, time_t end); + void add_resource_available(unsigned r, unsigned max_loadpct, time_t start, time_t end); + void add_done(); + + // validate assignment + void validate_assignment(); + bool resource_available(unsigned r, time_t t, unsigned& load_pct, time_t& end, unsigned& idx); // load available on resource r at time t. + time_t capacity_used(unsigned j, unsigned r, time_t start, time_t end); // capacity used between start and end + + job_resource const& get_job_resource(unsigned j, unsigned r) const; + + std::ostream& display(std::ostream & out, res_info const& r) const; + std::ostream& display(std::ostream & out, res_available const& r) const; + std::ostream& display(std::ostream & out, job_info const& r) const; + std::ostream& display(std::ostream & out, job_resource const& r) const; + }; }; From abd902d58c8144da339c3700f407a4cc7f04cf79 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Aug 2018 18:14:32 -0700 Subject: [PATCH 015/227] n/a Signed-off-by: Nikolaj Bjorner --- src/smt/theory_jobscheduler.cpp | 396 ++++++++++++++++++++++++++------ src/smt/theory_jobscheduler.h | 58 ++++- 2 files changed, 372 insertions(+), 82 deletions(-) diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index d2cab8bf8..f12193c2e 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -78,6 +78,18 @@ namespace smt { } final_check_status theory_jobscheduler::final_check_eh() { + + // ensure that each job starts within an avaialable interval. + // ! (end_previous_interval < start(j) < start_of_next_interval) + + bool blocked = false; + for (unsigned r = 0; r < m_resources.size(); ++r) { + if (constrain_resource_energy(r)) { + blocked = true; + } + } + + if (blocked) return FC_CONTINUE; return FC_DONE; } @@ -85,13 +97,199 @@ namespace smt { return false; } - void theory_jobscheduler::propagate() { + literal theory_jobscheduler::mk_literal(expr * e) { + expr_ref _e(e, m); + context& ctx = get_context(); + if (!ctx.e_internalized(e)) { + ctx.internalize(e, false); + } + ctx.mark_as_relevant(ctx.get_enode(e)); + return ctx.get_literal(e); + } + + literal theory_jobscheduler::mk_ge_lit(expr* e, time_t t) { + return mk_literal(mk_ge(e, t)); + } + + expr* theory_jobscheduler::mk_ge(expr* e, time_t t) { + return a.mk_ge(e, a.mk_int(rational(t, rational::ui64()))); + } + + expr* theory_jobscheduler::mk_ge(enode* e, time_t t) { + return mk_ge(e->get_owner(), t); + } + + literal theory_jobscheduler::mk_le_lit(expr* e, time_t t) { + return mk_literal(mk_le(e, t)); + } + + expr* theory_jobscheduler::mk_le(expr* e, time_t t) { + return a.mk_le(e, a.mk_int(rational(t, rational::ui64()))); + } + + literal theory_jobscheduler::mk_le(enode* l, enode* r) { + context& ctx = get_context(); + expr_ref le(a.mk_le(l->get_owner(), r->get_owner()), m); + ctx.get_rewriter()(le); + return mk_literal(le); + } + + expr* theory_jobscheduler::mk_le(enode* e, time_t t) { + return mk_le(e->get_owner(), t); + } + + /** + * iterator of job overlaps. + */ + theory_jobscheduler::job_overlap::job_overlap(vector& starts, vector& ends): + m_starts(starts), m_ends(ends), s_idx(0), e_idx(0) { + job_time::compare cmp; + std::sort(starts.begin(), starts.end(), cmp); + std::sort(ends.begin(), ends.end(), cmp); + } + + bool theory_jobscheduler::job_overlap::next(time_t& start) { + if (s_idx == m_starts.size()) { + return false; + } + while (s_idx < m_starts.size() && m_starts[s_idx].m_time <= start) { + m_jobs.insert(m_starts[s_idx].m_job); + ++s_idx; + } + // remove jobs that end before start. + while (e_idx < m_ends.size() && m_ends[s_idx].m_time < start) { + m_jobs.remove(m_ends[e_idx].m_job); + ++e_idx; + } + // TBD: check logic + if (s_idx < m_starts.size()) { + start = m_starts[s_idx].m_time; + } + return true; + } + + + /** + * r = resource(j) & start(j) >= slb => end(j) >= ect(j, r, slb) + */ + void theory_jobscheduler::propagate_end_time(unsigned j, unsigned r) { + time_t slb = est(j); + time_t clb = ect(j, r, slb); + context& ctx = get_context(); + + if (clb > end(j)) { + job_info const& ji = m_jobs[j]; + literal start_ge_lo = mk_literal(mk_ge(ji.m_start, slb)); + if (ctx.get_assignment(start_ge_lo) != l_true) { + return; + } + enode_pair eq(ji.m_resource, ctx.get_enode(u.mk_resource(r))); + if (eq.first->get_root() != eq.second->get_root()) { + return; + } + + literal end_ge_lo = mk_literal(mk_ge(ji.m_end, clb)); + // Initialization ensures that satisfiable states have completion time below end. + VERIFY(clb <= get_job_resource(j, r).m_end); + region& r = ctx.get_region(); + ctx.assign(end_ge_lo, + ctx.mk_justification( + ext_theory_propagation_justification(get_id(), r, 1, &start_ge_lo, 1, &eq, end_ge_lo, 0, nullptr))); + } + } + + /** + * For time interval [t0, t1] the end-time can be computed as a function + * of start time based on reource load availability. + * + * r = resource(j) & t1 >= start(j) >= t0 => end(j) = start(j) + ect(j, r, t0) - t0 + */ + void theory_jobscheduler::propagate_end_time_interval(unsigned j, unsigned r) { + // TBD + // establish maximal intervals around start, such that end time is a linear function of start. + } + + void theory_jobscheduler::propagate_resource_energy(unsigned r) { } + + /** + * Ensure that job overlaps don't exceed available energy + */ + bool theory_jobscheduler::constrain_resource_energy(unsigned r) { + bool blocked = false; + vector starts, ends; + res_info const& ri = m_resources[r]; + for (unsigned j : ri.m_jobs) { + if (resource(j) == r) { + starts.push_back(job_time(j, start(j))); + ends.push_back(job_time(j, end(j))); + } + } + job_overlap overlap(starts, ends); + time_t start = 0; + while (overlap.next(start)) { + unsigned cap = 0; + auto const& jobs = overlap.jobs(); + for (auto j : jobs) { + cap += get_job_resource(j, r).m_loadpct; + if (cap > 100) { + block_job_overlap(r, jobs, j); + blocked = true; + goto try_next_overlap; + } + } + try_next_overlap: + ; + } + return blocked; + } + + void theory_jobscheduler::block_job_overlap(unsigned r, uint_set const& jobs, unsigned last_job) { + // + // block the following case: + // each job is assigned to r. + // max { start(j) | j0..last_job } <= min { end(j) | j0..last_job } + // joint capacity of jobs exceeds availability of resource. + // + time_t max_start = 0; + unsigned max_j = last_job; + for (auto j : jobs) { + if (max_start < start(j)) { + max_start = start(j); + max_j = j; + } + if (j == last_job) break; + } + literal_vector lits; + for (auto j : jobs) { + // create literals for: + // resource(j) == r + // m_jobs[j].m_start <= m_jobs[max_j].m_start; + // m_jobs[max_j].m_start <= m_jobs[j].m_end; + lits.push_back(~mk_eq(u.mk_job2resource(j), u.mk_resource(r), false)); + lits.push_back(~mk_le(m_jobs[j].m_start, m_jobs[max_j].m_start)); + lits.push_back(~mk_le(m_jobs[max_j].m_start, m_jobs[max_j].m_end)); + if (j == last_job) break; + } + context& ctx = get_context(); + ctx.mk_clause(lits.size(), lits.c_ptr(), nullptr, CLS_AUX_LEMMA, nullptr); + } + + void theory_jobscheduler::propagate() { + for (unsigned j = 0; j < m_jobs.size(); ++j) { + job_info const& ji = m_jobs[j]; + unsigned r = resource(j); + propagate_end_time(j, r); + propagate_end_time_interval(j, r); + } + for (unsigned r = 0; r < m_resources.size(); ++r) { + // TBD: check energy constraints on resources. + } + } theory_jobscheduler::theory_jobscheduler(ast_manager& m): theory(m.get_family_id("jobshop")), m(m), u(m), a(m) { - } std::ostream& theory_jobscheduler::display(std::ostream & out, job_resource const& jr) const { @@ -147,30 +345,37 @@ namespace smt { } time_t theory_jobscheduler::est(unsigned j) { + NOT_IMPLEMENTED_YET(); return 0; } time_t theory_jobscheduler::lst(unsigned j) { + NOT_IMPLEMENTED_YET(); return 0; } time_t theory_jobscheduler::ect(unsigned j) { + NOT_IMPLEMENTED_YET(); return 0; } time_t theory_jobscheduler::lct(unsigned j) { + NOT_IMPLEMENTED_YET(); return 0; } time_t theory_jobscheduler::start(unsigned j) { + NOT_IMPLEMENTED_YET(); return 0; } time_t theory_jobscheduler::end(unsigned j) { + NOT_IMPLEMENTED_YET(); return 0; } unsigned theory_jobscheduler::resource(unsigned j) { + NOT_IMPLEMENTED_YET(); return 0; } @@ -191,7 +396,7 @@ namespace smt { void theory_jobscheduler::add_resource_available(unsigned r, unsigned max_loadpct, time_t start, time_t end) { SASSERT(get_context().at_base_level()); - SASSERT(start < end); + SASSERT(start <= end); m_resources.reserve(r + 1); m_resources[r].m_available.push_back(res_available(max_loadpct, start, end)); } @@ -215,16 +420,27 @@ namespace smt { throw default_exception("every job should be associated with at least one resource"); } // resource(j) = r => end(j) <= end(j, r) + // resource(j) = r => start(j) <= lst(j, r, end(j, r)) for (job_resource const& jr : ji.m_resources) { - app_ref res(u.mk_resource(jr.m_resource_id), m); + unsigned r = jr.m_resource_id; + app_ref res(u.mk_resource(r), m); expr_ref eq(m.mk_eq(job, res), m); - expr_ref imp(m.mk_implies(eq, a.mk_le(ji.m_start->get_owner(), a.mk_int(rational(jr.m_end, rational::ui64())))), m); - ctx.assert_expr(imp); + expr_ref imp(m.mk_implies(eq, mk_le(ji.m_end, jr.m_end)), m); + ctx.assert_expr(imp); + imp = m.mk_implies(eq, mk_le(ji.m_start, lst(j, r))); + ctx.assert_expr(imp); disj.push_back(eq); } // resource(j) = r1 || ... || resource(j) = r_n expr_ref fml = mk_or(disj); ctx.assert_expr(fml); + + // start(j) >= 0 + fml = mk_ge(ji.m_start, 0); + ctx.assert_expr(fml); + + // end(j) <= time_t::max + // is implied by resource(j) = r => end(j) <= end(j, r) } for (unsigned r = 0; r < m_resources.size(); ++r) { vector& available = m_resources[r].m_available; @@ -254,59 +470,24 @@ namespace smt { unsigned r = resource(j); start_times[r].push_back(job_time(j, start(j))); end_times[r].push_back(job_time(j, end(j))); - time_t cap = capacity_used(j, r, start(j), end(j)); - job_resource const& jr = get_job_resource(j, r); - if (jr.m_capacity > cap) { + if (ect(j, r, start(j)) > end(j)) { throw default_exception("job not assigned full capacity"); } } for (unsigned r = 0; r < m_resources.size(); ++r) { - unsigned load_pct = 0; - unsigned idx; - time_t next = 0, start = 0; - // order jobs running on r by start, end-time intervals // then consume ordered list to find jobs in scope. - vector& starts = start_times[r]; - vector& ends = end_times[r]; - job_time::compare cmp; - std::sort(starts.begin(), starts.end(), cmp); - std::sort(ends.begin(), ends.end(), cmp); - unsigned s_idx = 0, e_idx = 0; - - uint_set jobs; // set of jobs currently in scope. - while (resource_available(r, start, load_pct, next, idx)) { - if (load_pct == 0) { - start = next + 1; - continue; - } - // add jobs that begin at or before start. - while (s_idx < starts.size() && starts[s_idx].m_time <= start) { - jobs.insert(starts[s_idx].m_job); - ++s_idx; - } - // remove jobs that end before start. - while (e_idx < ends.size() && ends[s_idx].m_time < start) { - jobs.remove(ends[e_idx].m_job); - ++e_idx; - } - + time_t start = 0; + job_overlap overlap(start_times[r], end_times[r]); + while (overlap.next(start)) { // check that sum of job loads does not exceed 100% unsigned cap = 0; - for (auto j : jobs) { + for (auto j : overlap.jobs()) { cap += get_job_resource(j, r).m_loadpct; } if (cap > 100) { throw default_exception("capacity on resource exceeded"); } - if (s_idx < starts.size()) { - // start time of the next unprocessed job. - start = starts[s_idx].m_time; - } - else { - // done checking. - break; - } } } } @@ -316,14 +497,12 @@ namespace smt { return ji.m_resources[ji.m_resource2index[r]]; } - bool theory_jobscheduler::resource_available(unsigned r, time_t t, unsigned& load_pct, time_t& end, unsigned& idx) { + bool theory_jobscheduler::resource_available(unsigned r, time_t t, unsigned& idx) { vector& available = m_resources[r].m_available; unsigned lo = 0, hi = available.size(), mid = hi / 2; while (lo < hi) { res_available const& ra = available[mid]; if (ra.m_start <= t && t <= ra.m_end) { - end = ra.m_end; - load_pct = ra.m_loadpct; idx = mid; return true; } @@ -342,35 +521,108 @@ namespace smt { return false; } + /** - * compute the capacity used by job j on resource r between start and end. - * The resource r partitions time intervals into segments where a fraction of - * the full capacity of the resource is available. The resource can use up to the - * available fraction. - */ - time_t theory_jobscheduler::capacity_used(unsigned j, unsigned r, time_t start, time_t end) { - time_t cap = 0; - unsigned j_load_pct = get_job_resource(j, r).m_loadpct; + * compute earliest completion time for job j on resource r starting at time start. + */ + time_t theory_jobscheduler::ect(unsigned j, unsigned r, time_t start) { + job_resource const& jr = get_job_resource(j, r); vector& available = m_resources[r].m_available; - unsigned load_pct = 0; - time_t next = 0; + + unsigned j_load_pct = jr.m_loadpct; + time_t cap = jr.m_capacity; unsigned idx = 0; - if (!resource_available(r, start, load_pct, next, idx)) { - return cap; + if (!resource_available(r, start, idx)) { + return std::numeric_limits::max(); } - while (start < end) { - next = std::min(end, next); - SASSERT(start < next); - cap += (std::min(j_load_pct, load_pct) / j_load_pct) * (next - start - 1); - ++idx; - if (idx == available.size()) { - break; + SASSERT(cap > 0); + + for (; idx < available.size(); ++idx) { + start = std::max(start, available[idx].m_start); + time_t end = available[idx].m_end; + unsigned load_pct = available[idx].m_loadpct; + time_t delta = solve_for_capacity(load_pct, j_load_pct, start, end); + if (delta > cap) { + // + // solve for end: + // cap = load * (end - start + 1) + // <=> + // cap / load = (end - start + 1) + // <=> + // end = cap / load + start - 1 + // + end = solve_for_end(load_pct, j_load_pct, start, cap); + cap = 0; + } + else { + cap -= delta; + } + if (cap == 0) { + return end; } - start = available[idx].m_start; - next = available[idx].m_end; - load_pct = available[idx].m_loadpct; } - return cap; + return std::numeric_limits::max(); + } + + time_t theory_jobscheduler::solve_for_end(unsigned load_pct, unsigned job_load_pct, time_t start, time_t cap) { + SASSERT(load_pct > 0); + SASSERT(job_load_pct > 0); + // cap = (load / job_load_pct) * (start - end + 1) + // <=> + // start - end + 1 = (cap * job_load_pct) / load + // <=> + // end = start + 1 - (cap * job_load_pct) / load + // <=> + // end = (load * (start + 1) - cap * job_load_pct) / load + unsigned load = std::min(load_pct, job_load_pct); + return (load * (start + 1) - cap * job_load_pct) / load; + } + + time_t theory_jobscheduler::solve_for_start(unsigned load_pct, unsigned job_load_pct, time_t end, time_t cap) { + SASSERT(load_pct > 0); + SASSERT(job_load_pct > 0); + // cap = (load / job_load_pct) * (start - end + 1) + // <=> + // start - end + 1 = (cap * job_load_pct) / load + // <=> + // start = (cap * job_load_pct) / load + end - 1 + // <=> + // start = (load * (end - 1) + cap * job_load_pct) / load + unsigned load = std::min(load_pct, job_load_pct); + return (load * (end - 1) + cap * job_load_pct) / load; + } + + time_t theory_jobscheduler::solve_for_capacity(unsigned load_pct, unsigned job_load_pct, time_t start, time_t end) { + SASSERT(job_load_pct > 0); + unsigned load = std::min(load_pct, job_load_pct); + return (load * (end - start + 1)) / job_load_pct; + } + + /** + * Compute last start time for job on resource r. + */ + time_t theory_jobscheduler::lst(unsigned j, unsigned r) { + job_resource const& jr = get_job_resource(j, r); + vector& available = m_resources[r].m_available; + unsigned j_load_pct = jr.m_loadpct; + time_t cap = jr.m_capacity; + for (unsigned idx = available.size(); idx-- > 0; ) { + time_t start = available[idx].m_start; + time_t end = available[idx].m_end; + unsigned load_pct = available[idx].m_loadpct; + time_t delta = solve_for_capacity(load_pct, j_load_pct, start, end); + if (delta > cap) { + start = solve_for_start(load_pct, j_load_pct, start, cap); + cap = 0; + } + else { + cap -= delta; + } + if (cap == 0) { + return start; + } + } + throw default_exception("there is insufficient capacity on the resource to run the job"); } }; diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index f10b72d81..369cc1955 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -20,9 +20,10 @@ Revision History: --*/ #pragma once; -#include "smt/smt_theory.h" +#include "util/uint_set.h" #include "ast/jobshop_decl_plugin.h" #include "ast/arith_decl_plugin.h" +#include "smt/smt_theory.h" namespace smt { @@ -74,13 +75,12 @@ namespace smt { return ra1.m_start < ra2.m_start; } }; - }; struct res_info { unsigned_vector m_jobs; // jobs allocated to run on resource vector m_available; // time intervals where resource is available - time_t m_end; // can't run after + time_t m_end; // can't run after res_info(): m_end(std::numeric_limits::max()) {} }; @@ -131,10 +131,15 @@ namespace smt { bool get_value(enode * n, expr_ref & r) override; - theory * mk_fresh(context * new_ctx) override; // { return alloc(theory_jobscheduler, new_ctx->get_manager()); } + theory * mk_fresh(context * new_ctx) override; public: - // assignments: + // set up job/resource global constraints + void add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, time_t end); + void add_resource_available(unsigned r, unsigned max_loadpct, time_t start, time_t end); + void add_done(); + + // assignments time_t est(unsigned j); // earliest start time of job j time_t lst(unsigned j); // last start time time_t ect(unsigned j); // earliest completion time @@ -142,19 +147,52 @@ namespace smt { time_t start(unsigned j); // start time of job j time_t end(unsigned j); // end time of job j unsigned resource(unsigned j); // resource of job j + + // derived bounds + time_t ect(unsigned j, unsigned r, time_t start); + time_t lst(unsigned j, unsigned r); - // set up model - void add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, time_t end); - void add_resource_available(unsigned r, unsigned max_loadpct, time_t start, time_t end); - void add_done(); + time_t solve_for_start(unsigned load_pct, unsigned job_load_pct, time_t end, time_t cap); + time_t solve_for_end(unsigned load_pct, unsigned job_load_pct, time_t start, time_t cap); + time_t solve_for_capacity(unsigned load_pct, unsigned job_load_pct, time_t start, time_t end); // validate assignment void validate_assignment(); - bool resource_available(unsigned r, time_t t, unsigned& load_pct, time_t& end, unsigned& idx); // load available on resource r at time t. + bool resource_available(unsigned r, time_t t, unsigned& idx); // load available on resource r at time t. time_t capacity_used(unsigned j, unsigned r, time_t start, time_t end); // capacity used between start and end job_resource const& get_job_resource(unsigned j, unsigned r) const; + // propagation + void propagate_end_time(unsigned j, unsigned r); + void propagate_end_time_interval(unsigned j, unsigned r); + void propagate_resource_energy(unsigned r); + + // final check constraints + bool constrain_resource_energy(unsigned r); + + void block_job_overlap(unsigned r, uint_set const& jobs, unsigned last_job); + + class job_overlap { + vector & m_starts, &m_ends; + unsigned s_idx, e_idx; // index into starts/ends + uint_set m_jobs; + public: + job_overlap(vector& starts, vector& ends); + bool next(time_t& start); + uint_set const& jobs() const { return m_jobs; } + }; + + // term builders + literal mk_ge_lit(expr* e, time_t t); + expr* mk_ge(expr* e, time_t t); + expr* mk_ge(enode* e, time_t t); + literal mk_le_lit(expr* e, time_t t); + expr* mk_le(expr* e, time_t t); + expr* mk_le(enode* e, time_t t); + literal mk_le(enode* l, enode* r); + literal mk_literal(expr* e); + std::ostream& display(std::ostream & out, res_info const& r) const; std::ostream& display(std::ostream & out, res_available const& r) const; std::ostream& display(std::ostream & out, job_info const& r) const; From 0af00e62dee673c8025bf7a7a5a7e865f1192f12 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 12 Aug 2018 12:42:26 -0700 Subject: [PATCH 016/227] abstract arithmetic value extraction Signed-off-by: Nikolaj Bjorner --- src/smt/CMakeLists.txt | 1 + src/smt/smt_arith_value.cpp | 113 ++++++++++++++++ src/smt/smt_arith_value.h | 37 ++++++ src/smt/smt_context.h | 5 + src/smt/theory_jobscheduler.cpp | 224 +++++++++++++++++++++++++++----- src/smt/theory_jobscheduler.h | 34 +++-- src/smt/theory_lra.cpp | 45 +++++-- src/smt/theory_lra.h | 3 + 8 files changed, 405 insertions(+), 57 deletions(-) create mode 100644 src/smt/smt_arith_value.cpp create mode 100644 src/smt/smt_arith_value.h diff --git a/src/smt/CMakeLists.txt b/src/smt/CMakeLists.txt index 13a00d44e..4b640f8ca 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -13,6 +13,7 @@ z3_add_component(smt old_interval.cpp qi_queue.cpp smt_almost_cg_table.cpp + smt_arith_value.cpp smt_case_split_queue.cpp smt_cg_table.cpp smt_checker.cpp diff --git a/src/smt/smt_arith_value.cpp b/src/smt/smt_arith_value.cpp new file mode 100644 index 000000000..ecf924111 --- /dev/null +++ b/src/smt/smt_arith_value.cpp @@ -0,0 +1,113 @@ + +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + smt_arith_value.cpp + +Abstract: + + Utility to extract arithmetic values from context. + +Author: + + Nikolaj Bjorner (nbjorner) 2018-12-08. + +Revision History: + +--*/ +#pragma once; + +#include "smt/smt_arith_value.h" +#include "smt/theory_lra.h" +#include "smt/theory_arith.h" + +namespace smt { + + arith_value::arith_value(context& ctx): + m_ctx(ctx), m(ctx.get_manager()), a(m) {} + + bool arith_value::get_lo(expr* e, rational& lo, bool& is_strict) { + if (!m_ctx.e_internalized(e)) return false; + expr_ref _lo(m); + family_id afid = a.get_family_id(); + is_strict = false; + enode* next = m_ctx.get_enode(e), *n = next; + bool found = false; + bool is_strict1; + rational lo1; + theory* th = m_ctx.get_theory(afid); + theory_mi_arith* tha = dynamic_cast(th); + theory_i_arith* thi = dynamic_cast(th); + theory_lra* thr = dynamic_cast(th); + do { + if (tha && tha->get_lower(next, _lo) && a.is_numeral(_lo, lo1)) { + if (!found || lo1 > lo) lo = lo1; + found = true; + } + else if (thi && thi->get_lower(next, _lo) && a.is_numeral(_lo, lo1)) { + if (!found || lo1 > lo) lo = lo1; + found = true; + } + else if (thr && thr->get_lower(next, lo1, is_strict1)) { + if (!found || lo1 > lo || (lo == lo1 && is_strict1)) lo = lo1, is_strict = is_strict1; + found = true; + } + next = next->get_next(); + } + while (n != next); + return found; + } + + bool arith_value::get_up(expr* e, rational& up, bool& is_strict) { + if (!m_ctx.e_internalized(e)) return false; + expr_ref _up(m); + family_id afid = a.get_family_id(); + is_strict = false; + enode* next = m_ctx.get_enode(e), *n = next; + bool found = false, is_strict1; + rational up1; + theory* th = m_ctx.get_theory(afid); + theory_mi_arith* tha = dynamic_cast(th); + theory_i_arith* thi = dynamic_cast(th); + theory_lra* thr = dynamic_cast(th); + do { + if (tha && tha->get_upper(next, _up) && a.is_numeral(_up, up1)) { + if (!found || up1 < up) up = up1; + found = true; + } + else if (thi && thi->get_upper(next, _up) && a.is_numeral(_up, up1)) { + if (!found || up1 < up) up = up1; + found = true; + } + else if (thr && thr->get_upper(next, up1, is_strict1)) { + if (!found || up1 < up || (up1 == up && is_strict1)) up = up1, is_strict = is_strict1; + found = true; + } + next = next->get_next(); + } + while (n != next); + return found; + } + + bool arith_value::get_value(expr* e, rational& val) { + if (!m_ctx.e_internalized(e)) return false; + expr_ref _val(m); + enode* next = m_ctx.get_enode(e), *n = next; + family_id afid = a.get_family_id(); + theory* th = m_ctx.get_theory(afid); + theory_mi_arith* tha = dynamic_cast(th); + theory_i_arith* thi = dynamic_cast(th); + theory_lra* thr = dynamic_cast(th); + do { + e = next->get_owner(); + if (tha && tha->get_value(next, _val) && a.is_numeral(_val, val)) return true; + if (thi && thi->get_value(next, _val) && a.is_numeral(_val, val)) return true; + if (thr && thr->get_value(next, val)) return true; + next = next->get_next(); + } + while (next != n); + return false; + } +}; diff --git a/src/smt/smt_arith_value.h b/src/smt/smt_arith_value.h new file mode 100644 index 000000000..9b0f833ac --- /dev/null +++ b/src/smt/smt_arith_value.h @@ -0,0 +1,37 @@ + +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + smt_arith_value.h + +Abstract: + + Utility to extract arithmetic values from context. + +Author: + + Nikolaj Bjorner (nbjorner) 2018-12-08. + +Revision History: + +--*/ +#pragma once; + +#include "ast/arith_decl_plugin.h" +#include "smt/smt_context.h" + + +namespace smt { + class arith_value { + context& m_ctx; + ast_manager& m; + arith_util a; + public: + arith_value(context& ctx); + bool get_lo(expr* e, rational& lo, bool& strict); + bool get_up(expr* e, rational& up, bool& strict); + bool get_value(expr* e, rational& value); + }; +}; diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index ff92f6f95..f545f7c6d 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1243,6 +1243,11 @@ namespace smt { public: bool can_propagate() const; + // Retrieve arithmetic values. + bool get_arith_lo(expr* e, rational& lo, bool& strict); + bool get_arith_up(expr* e, rational& up, bool& strict); + bool get_arith_value(expr* e, rational& value); + // ----------------------------------- // // Model checking... (must be improved) diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index f12193c2e..173d44c52 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -14,10 +14,39 @@ Author: Revision History: +TODO: + +- arithmetic interface + +- propagation queue: + - register theory variables for catching when jobs are bound to resources + - register bounds on start times to propagate energy constraints + - more general registration mechanism for arithmetic theory. +- csp_cmds + - use predicates for add_ feature set? Closed world. + set up environment in one swoop. + - interact with opt +- jobs without resources + - complain or add dummy resource? At which level. + +Features: +- properties +- priority + - try mss based from outside +- job-goal + - try optimization based on arithmetic solver. + - earliest start, latest start +- constraint level +- resource groups + - resource groups like a resource + - resources bound to resource groups within time intervals + - job can require to use K resources from a resource group simultaneously. + --*/ #include "smt/theory_jobscheduler.h" #include "smt/smt_context.h" +#include "smt/smt_arith_value.h" namespace smt { @@ -79,16 +108,18 @@ namespace smt { final_check_status theory_jobscheduler::final_check_eh() { - // ensure that each job starts within an avaialable interval. - // ! (end_previous_interval < start(j) < start_of_next_interval) - bool blocked = false; for (unsigned r = 0; r < m_resources.size(); ++r) { if (constrain_resource_energy(r)) { blocked = true; } } - + for (unsigned j = 0; j < m_jobs.size(); ++j) { + if (constrain_end_time_interval(j, resource(j))) { + blocked = true; + } + } + if (blocked) return FC_CONTINUE; return FC_DONE; } @@ -204,9 +235,56 @@ namespace smt { * * r = resource(j) & t1 >= start(j) >= t0 => end(j) = start(j) + ect(j, r, t0) - t0 */ - void theory_jobscheduler::propagate_end_time_interval(unsigned j, unsigned r) { - // TBD - // establish maximal intervals around start, such that end time is a linear function of start. + bool theory_jobscheduler::constrain_end_time_interval(unsigned j, unsigned r) { + unsigned idx1 = 0, idx2 = 0; + time_t s = start(j); + if (!resource_available(r, s, idx1)) return false; + vector& available = m_resources[r].m_available; + time_t e = ect(j, r, s); + if (!resource_available(r, e, idx2)) return false; + time_t start1 = available[idx1].m_start; + time_t end1 = available[idx1].m_end; + unsigned cap1 = available[idx1].m_loadpct; + time_t start2 = available[idx2].m_start; + time_t end2 = available[idx2].m_end; + unsigned cap2 = available[idx2].m_loadpct; + // calculate minimal start1 <= t0 <= s, such that ect(j, r, t0) >= start2 + // calculate maximal s <= t1 <= end1, such that ect(j, r, t1) <= end2 + time_t delta1 = (s - start1)*cap1; + time_t delta2 = (e - start2)*cap2; + time_t t0, t1; + if (delta1 <= delta2) { + t0 = start1; + } + else { + // solve for t0: + // (s - t0)*cap1 = (e - start2)*cap2; + t0 = s - (delta2 / cap1); + } + delta1 = (end1 - s)*cap1; + delta2 = (end2 - e)*cap2; + if (delta1 <= delta2) { + t1 = end1; + } + else { + // solve for t1: + // (t1 - s)*cap1 = (end2 - e)*cap2 + t1 = s + (delta2 / cap1); + } + + time_t delta = ect(j, r, t0) - t0; + if (end(j) == start(j) + delta) { + return false; + } + literal_vector lits; + lits.push_back(~mk_eq(u.mk_job2resource(j), u.mk_resource(r), false)); + lits.push_back(~mk_ge_lit(u.mk_start(j), t0)); + lits.push_back(~mk_le_lit(u.mk_start(j), t1)); + expr_ref rhs(a.mk_add(u.mk_start(j), a.mk_int(rational(delta, rational::ui64()))), m); + lits.push_back(mk_eq(u.mk_end(j), rhs, false)); + context& ctx = get_context(); + ctx.mk_clause(lits.size(), lits.c_ptr(), nullptr, CLS_AUX_LEMMA, nullptr); + return true; } void theory_jobscheduler::propagate_resource_energy(unsigned r) { @@ -268,8 +346,10 @@ namespace smt { // m_jobs[j].m_start <= m_jobs[max_j].m_start; // m_jobs[max_j].m_start <= m_jobs[j].m_end; lits.push_back(~mk_eq(u.mk_job2resource(j), u.mk_resource(r), false)); - lits.push_back(~mk_le(m_jobs[j].m_start, m_jobs[max_j].m_start)); - lits.push_back(~mk_le(m_jobs[max_j].m_start, m_jobs[max_j].m_end)); + if (j != max_j) { + lits.push_back(~mk_le(m_jobs[j].m_start, m_jobs[max_j].m_start)); + lits.push_back(~mk_le(m_jobs[max_j].m_start, m_jobs[j].m_end)); + } if (j == last_job) break; } context& ctx = get_context(); @@ -281,7 +361,6 @@ namespace smt { job_info const& ji = m_jobs[j]; unsigned r = resource(j); propagate_end_time(j, r); - propagate_end_time_interval(j, r); } for (unsigned r = 0; r < m_resources.size(); ++r) { // TBD: check energy constraints on resources. @@ -345,13 +424,23 @@ namespace smt { } time_t theory_jobscheduler::est(unsigned j) { - NOT_IMPLEMENTED_YET(); + arith_value av(get_context()); + rational val; + bool is_strict; + if (av.get_lo(u.mk_start(j), val, is_strict) && !is_strict && val.is_uint64()) { + return val.get_uint64(); + } return 0; } time_t theory_jobscheduler::lst(unsigned j) { - NOT_IMPLEMENTED_YET(); - return 0; + arith_value av(get_context()); + rational val; + bool is_strict; + if (av.get_up(u.mk_start(j), val, is_strict) && !is_strict && val.is_uint64()) { + return val.get_uint64(); + } + return std::numeric_limits::max(); } time_t theory_jobscheduler::ect(unsigned j) { @@ -379,9 +468,15 @@ namespace smt { return 0; } + void theory_jobscheduler::set_preemptable(unsigned j, bool is_preemptable) { + m_jobs.reserve(j + 1); + m_jobs[j].m_is_preemptable = is_preemptable; + } - void theory_jobscheduler::add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, time_t end) { + void theory_jobscheduler::add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, time_t end, properties const& ps) { SASSERT(get_context().at_base_level()); + SASSERT(1 <= loadpct && loadpct <= 100); + SASSERT(0 < cap); m_jobs.reserve(j + 1); m_resources.reserve(r + 1); job_info& ji = m_jobs[j]; @@ -389,16 +484,17 @@ namespace smt { throw default_exception("resource already bound to job"); } ji.m_resource2index.insert(r, ji.m_resources.size()); - ji.m_resources.push_back(job_resource(r, cap, loadpct, end)); + ji.m_resources.push_back(job_resource(r, cap, loadpct, end, ps)); SASSERT(!m_resources[r].m_jobs.contains(j)); m_resources[r].m_jobs.push_back(j); } - void theory_jobscheduler::add_resource_available(unsigned r, unsigned max_loadpct, time_t start, time_t end) { + void theory_jobscheduler::add_resource_available(unsigned r, unsigned max_loadpct, time_t start, time_t end, properties const& ps) { SASSERT(get_context().at_base_level()); + SASSERT(1 <= max_loadpct && max_loadpct <= 100); SASSERT(start <= end); m_resources.reserve(r + 1); - m_resources[r].m_available.push_back(res_available(max_loadpct, start, end)); + m_resources[r].m_available.push_back(res_available(max_loadpct, start, end, ps)); } /* @@ -411,7 +507,18 @@ namespace smt { * Ensure that the availability slots for each resource is sorted by time. */ void theory_jobscheduler::add_done() { - context & ctx = get_context(); + context & ctx = get_context(); + + // sort availability intervals + for (unsigned r = 0; r < m_resources.size(); ++r) { + res_info& ri = m_resources[r]; + vector& available = ri.m_available; + res_available::compare cmp; + std::sort(available.begin(), available.end(), cmp); + } + + expr_ref fml(m); + for (unsigned j = 0; j < m_jobs.size(); ++j) { job_info const& ji = m_jobs[j]; expr_ref_vector disj(m); @@ -419,38 +526,83 @@ namespace smt { if (ji.m_resources.empty()) { throw default_exception("every job should be associated with at least one resource"); } - // resource(j) = r => end(j) <= end(j, r) - // resource(j) = r => start(j) <= lst(j, r, end(j, r)) + + // start(j) <= end(j) + fml = a.mk_le(ji.m_start->get_owner(), ji.m_end->get_owner()); + ctx.assert_expr(fml); + + time_t start_lb = std::numeric_limits::max(); + time_t end_ub = 0; for (job_resource const& jr : ji.m_resources) { + // resource(j) = r => end(j) <= end(j, r) + // resource(j) = r => start(j) <= lst(j, r, end(j, r)) unsigned r = jr.m_resource_id; app_ref res(u.mk_resource(r), m); expr_ref eq(m.mk_eq(job, res), m); expr_ref imp(m.mk_implies(eq, mk_le(ji.m_end, jr.m_end)), m); ctx.assert_expr(imp); - imp = m.mk_implies(eq, mk_le(ji.m_start, lst(j, r))); + time_t t; + if (!lst(j, r, t)) { + imp = m.mk_implies(eq, mk_le(ji.m_start, t)); + } + else { + imp = m.mk_not(eq); + } ctx.assert_expr(imp); disj.push_back(eq); + res_info const& ri = m_resources[r]; + start_lb = std::min(start_lb, ri.m_available[0].m_start); + end_ub = std::max(end_ub, ri.m_available.back().m_end); + } // resource(j) = r1 || ... || resource(j) = r_n expr_ref fml = mk_or(disj); ctx.assert_expr(fml); - // start(j) >= 0 - fml = mk_ge(ji.m_start, 0); + // start(j) >= start_lb + fml = mk_ge(ji.m_start, start_lb); ctx.assert_expr(fml); - // end(j) <= time_t::max - // is implied by resource(j) = r => end(j) <= end(j, r) + // end(j) <= end_ub + fml = mk_le(ji.m_end, end_ub); + ctx.assert_expr(fml); } for (unsigned r = 0; r < m_resources.size(); ++r) { - vector& available = m_resources[r].m_available; - res_available::compare cmp; - std::sort(available.begin(), available.end(), cmp); - for (unsigned i = 0; i < available.size(); ++i) { - if (i + 1 < available.size() && - available[i].m_end > available[i + 1].m_start) { + res_info& ri = m_resources[r]; + vector& available = ri.m_available; + if (available.empty()) continue; + app_ref res(u.mk_resource(r), m); + for (unsigned j : ri.m_jobs) { + // resource(j) == r => start(j) >= available[0].m_start; + app_ref job(u.mk_job(j), m); + expr_ref eq(m.mk_eq(job, res), m); + expr_ref ge(mk_ge(u.mk_start(j), available[0].m_start), m); + expr_ref fml(m.mk_implies(eq, ge), m); + ctx.assert_expr(fml); + } + for (unsigned i = 0; i + 1 < available.size(); ++i) { + if (available[i].m_end > available[i + 1].m_start) { throw default_exception("availability intervals should be disjoint"); } + for (unsigned j : ri.m_jobs) { + // jobs start within an interval. + // resource(j) == r => start(j) <= available[i].m_end || start(j) >= available[i + 1].m_start; + app_ref job(u.mk_job(j), m); + expr_ref eq(m.mk_eq(job, res), m); + expr_ref ge(mk_ge(u.mk_start(j), available[i + 1].m_start), m); + expr_ref le(mk_le(u.mk_start(j), available[i].m_end), m); + fml = m.mk_implies(eq, m.mk_or(le, ge)); + ctx.assert_expr(fml); + + // if job is not pre-emptable, start and end have to align within contiguous interval. + // resource(j) == r => end(j) <= available[i].m_end || start(j) >= available[i + 1].m_start + if (!m_jobs[j].m_is_preemptable && available[i].m_end + 1 < available[i+1].m_start) { + le = mk_le(u.mk_end(j), available[i].m_end); + ge = mk_ge(u.mk_start(j), available[i+1].m_start); + fml = m.mk_implies(eq, m.mk_or(le, ge)); + ctx.assert_expr(fml); + } + } } } } @@ -473,6 +625,10 @@ namespace smt { if (ect(j, r, start(j)) > end(j)) { throw default_exception("job not assigned full capacity"); } + unsigned idx; + if (!resource_available(r, start(j), idx)) { + throw default_exception("resource is not available at job start time"); + } } for (unsigned r = 0; r < m_resources.size(); ++r) { // order jobs running on r by start, end-time intervals @@ -601,7 +757,7 @@ namespace smt { /** * Compute last start time for job on resource r. */ - time_t theory_jobscheduler::lst(unsigned j, unsigned r) { + bool theory_jobscheduler::lst(unsigned j, unsigned r, time_t& start) { job_resource const& jr = get_job_resource(j, r); vector& available = m_resources[r].m_available; unsigned j_load_pct = jr.m_loadpct; @@ -619,10 +775,10 @@ namespace smt { cap -= delta; } if (cap == 0) { - return start; + return true; } } - throw default_exception("there is insufficient capacity on the resource to run the job"); + return false; } }; diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index 369cc1955..117303ff7 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -28,16 +28,20 @@ Revision History: namespace smt { typedef uint64_t time_t; - + class theory_jobscheduler : public theory { + public: + typedef map properties; + protected: struct job_resource { unsigned m_resource_id; // id of resource unsigned m_capacity; // amount of resource to use unsigned m_loadpct; // assuming loadpct time_t m_end; // must run before - job_resource(unsigned r, unsigned cap, unsigned loadpct, time_t end): - m_resource_id(r), m_capacity(cap), m_loadpct(loadpct), m_end(end) {} + properties m_properties; + job_resource(unsigned r, unsigned cap, unsigned loadpct, time_t end, properties const& ps): + m_resource_id(r), m_capacity(cap), m_loadpct(loadpct), m_end(end), m_properties(ps) {} }; struct job_time { @@ -53,22 +57,25 @@ namespace smt { }; struct job_info { + bool m_is_preemptable; // can job be pre-empted vector m_resources; // resources allowed to run job. u_map m_resource2index; // resource to index into vector enode* m_start; enode* m_end; enode* m_resource; - job_info(): m_start(nullptr), m_end(nullptr), m_resource(nullptr) {} + job_info(): m_is_preemptable(true), m_start(nullptr), m_end(nullptr), m_resource(nullptr) {} }; struct res_available { - unsigned m_loadpct; - time_t m_start; - time_t m_end; - res_available(unsigned load_pct, time_t start, time_t end): + unsigned m_loadpct; + time_t m_start; + time_t m_end; + properties m_properties; + res_available(unsigned load_pct, time_t start, time_t end, properties const& ps): m_loadpct(load_pct), m_start(start), - m_end(end) + m_end(end), + m_properties(ps) {} struct compare { bool operator()(res_available const& ra1, res_available const& ra2) const { @@ -135,8 +142,9 @@ namespace smt { public: // set up job/resource global constraints - void add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, time_t end); - void add_resource_available(unsigned r, unsigned max_loadpct, time_t start, time_t end); + void set_preemptable(unsigned j, bool is_preemptable); + void add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, time_t end, properties const& ps); + void add_resource_available(unsigned r, unsigned max_loadpct, time_t start, time_t end, properties const& ps); void add_done(); // assignments @@ -150,7 +158,7 @@ namespace smt { // derived bounds time_t ect(unsigned j, unsigned r, time_t start); - time_t lst(unsigned j, unsigned r); + bool lst(unsigned j, unsigned r, time_t& t); time_t solve_for_start(unsigned load_pct, unsigned job_load_pct, time_t end, time_t cap); time_t solve_for_end(unsigned load_pct, unsigned job_load_pct, time_t start, time_t cap); @@ -165,10 +173,10 @@ namespace smt { // propagation void propagate_end_time(unsigned j, unsigned r); - void propagate_end_time_interval(unsigned j, unsigned r); void propagate_resource_energy(unsigned r); // final check constraints + bool constrain_end_time_interval(unsigned j, unsigned r); bool constrain_resource_energy(unsigned r); void block_job_overlap(unsigned r, uint_set const& jobs, unsigned last_job); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 267412da6..6c66de91d 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2658,13 +2658,22 @@ public: } } - bool get_value(enode* n, expr_ref& r) { + bool get_value(enode* n, rational& val) { theory_var v = n->get_th_var(get_id()); if (!can_get_bound(v)) return false; lp::var_index vi = m_theory_var2var_index[v]; - rational val; if (m_solver->has_value(vi, val)) { if (is_int(n) && !val.is_int()) return false; + return true; + } + else { + return false; + } + } + + bool get_value(enode* n, expr_ref& r) { + rational val; + if (get_value(n, val)) { r = a.mk_numeral(val, is_int(n)); return true; } @@ -2673,7 +2682,7 @@ public: } } - bool get_lower(enode* n, expr_ref& r) { + bool get_lower(enode* n, rational& val, bool& is_strict) { theory_var v = n->get_th_var(get_id()); if (!can_get_bound(v)) { TRACE("arith", tout << "cannot get lower for " << v << "\n";); @@ -2681,29 +2690,36 @@ public: } lp::var_index vi = m_theory_var2var_index[v]; lp::constraint_index ci; - rational val; + return m_solver->has_lower_bound(vi, ci, val, is_strict); + } + + bool get_lower(enode* n, expr_ref& r) { bool is_strict; - if (m_solver->has_lower_bound(vi, ci, val, is_strict)) { + rational val; + if (get_lower(n, val, is_strict) && !is_strict) { r = a.mk_numeral(val, is_int(n)); return true; } - TRACE("arith", m_solver->print_constraints(tout << "does not have lower bound " << vi << "\n");); return false; } - bool get_upper(enode* n, expr_ref& r) { + bool get_upper(enode* n, rational& val, bool& is_strict) { theory_var v = n->get_th_var(get_id()); if (!can_get_bound(v)) return false; lp::var_index vi = m_theory_var2var_index[v]; lp::constraint_index ci; - rational val; + return m_solver->has_upper_bound(vi, ci, val, is_strict); + + } + + bool get_upper(enode* n, expr_ref& r) { bool is_strict; - if (m_solver->has_upper_bound(vi, ci, val, is_strict)) { + rational val; + if (get_upper(n, val, is_strict) && !is_strict) { r = a.mk_numeral(val, is_int(n)); return true; } - TRACE("arith", m_solver->print_constraints(tout << "does not have upper bound " << vi << "\n");); return false; } @@ -3132,6 +3148,9 @@ void theory_lra::init_model(model_generator & m) { model_value_proc * theory_lra::mk_value(enode * n, model_generator & mg) { return m_imp->mk_value(n, mg); } +bool theory_lra::get_value(enode* n, rational& r) { + return m_imp->get_value(n, r); +} bool theory_lra::get_value(enode* n, expr_ref& r) { return m_imp->get_value(n, r); } @@ -3141,6 +3160,12 @@ bool theory_lra::get_lower(enode* n, expr_ref& r) { bool theory_lra::get_upper(enode* n, expr_ref& r) { return m_imp->get_upper(n, r); } +bool theory_lra::get_lower(enode* n, rational& r, bool& is_strict) { + return m_imp->get_lower(n, r, is_strict); +} +bool theory_lra::get_upper(enode* n, rational& r, bool& is_strict) { + return m_imp->get_upper(n, r, is_strict); +} bool theory_lra::validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const { return m_imp->validate_eq_in_model(v1, v2, is_true); diff --git a/src/smt/theory_lra.h b/src/smt/theory_lra.h index 074b11ba7..811fa1812 100644 --- a/src/smt/theory_lra.h +++ b/src/smt/theory_lra.h @@ -80,6 +80,9 @@ namespace smt { bool get_value(enode* n, expr_ref& r) override; bool get_lower(enode* n, expr_ref& r); bool get_upper(enode* n, expr_ref& r); + bool get_value(enode* n, rational& r); + bool get_lower(enode* n, rational& r, bool& is_strict); + bool get_upper(enode* n, rational& r, bool& is_strict); bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const override; From 3478b8b924b21a5541b05e1d574789dbe15097a6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 12 Aug 2018 18:14:06 -0700 Subject: [PATCH 017/227] add js-model interfacing Signed-off-by: Nikolaj Bjorner --- src/ast/jobshop_decl_plugin.cpp | 35 +++++++- src/ast/jobshop_decl_plugin.h | 57 ++++++++++++- src/cmd_context/cmd_context.cpp | 3 + src/parsers/smt2/smt2parser.cpp | 16 +++- src/smt/smt_arith_value.cpp | 26 ++---- src/smt/theory_arith.h | 2 + src/smt/theory_arith_core.h | 14 +++ src/smt/theory_jobscheduler.cpp | 145 ++++++++++++++++++++++++++++---- src/smt/theory_jobscheduler.h | 15 +++- src/solver/smt_logics.cpp | 19 +++-- src/solver/smt_logics.h | 2 + 11 files changed, 275 insertions(+), 59 deletions(-) diff --git a/src/ast/jobshop_decl_plugin.cpp b/src/ast/jobshop_decl_plugin.cpp index 7a7b1b590..b1abc7fa3 100644 --- a/src/ast/jobshop_decl_plugin.cpp +++ b/src/ast/jobshop_decl_plugin.cpp @@ -23,14 +23,17 @@ Revision History: void jobshop_decl_plugin::set_manager(ast_manager* m, family_id fid) { decl_plugin::set_manager(m, fid); m_int_sort = m_manager->mk_sort(m_manager->mk_family_id("arith"), INT_SORT); + m_alist_sort = m_manager->mk_sort(symbol("AList"), sort_info(m_family_id, ALIST_SORT)); m_job_sort = m_manager->mk_sort(symbol("Job"), sort_info(m_family_id, JOB_SORT)); m_resource_sort = m_manager->mk_sort(symbol("Resource"), sort_info(m_family_id, RESOURCE_SORT)); m_manager->inc_ref(m_int_sort); m_manager->inc_ref(m_resource_sort); m_manager->inc_ref(m_job_sort); + m_manager->inc_ref(m_alist_sort); } void jobshop_decl_plugin::finalize() { + m_manager->dec_ref(m_alist_sort); m_manager->dec_ref(m_job_sort); m_manager->dec_ref(m_resource_sort); m_manager->dec_ref(m_int_sort); @@ -43,12 +46,13 @@ sort * jobshop_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parame switch (static_cast(k)) { case JOB_SORT: return m_job_sort; case RESOURCE_SORT: return m_resource_sort; + case ALIST_SORT: return m_alist_sort; default: UNREACHABLE(); return nullptr; } } func_decl * jobshop_decl_plugin::mk_func_decl( - decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const *, sort *) { + decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort *) { switch (static_cast(k)) { case OP_JS_JOB: check_arity(arity); @@ -70,6 +74,18 @@ func_decl * jobshop_decl_plugin::mk_func_decl( check_arity(arity); check_index1(num_parameters, parameters); return m_manager->mk_func_decl(symbol("job2resource"), 0, (sort* const*)nullptr, m_int_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + case OP_JS_MODEL: + // has no parameters + // all arguments are of sort alist + return m_manager->mk_func_decl(symbol("js-model"), arity, domain, m_manager->mk_bool_sort(), func_decl_info(m_family_id, k, num_parameters, parameters)); + case OP_AL_KV: + // has two parameters, first is symbol + // has no arguments + return m_manager->mk_func_decl(symbol("kv"), arity, domain, m_alist_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + case OP_AL_LIST: + // has no parameters + // all arguments are of sort alist + return m_manager->mk_func_decl(symbol("alist"), arity, domain, m_alist_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); default: UNREACHABLE(); return nullptr; } @@ -96,17 +112,20 @@ bool jobshop_decl_plugin::is_value(app * e) const { } void jobshop_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { - if (logic == symbol("JOBSHOP")) { + if (logic == symbol("CSP")) { op_names.push_back(builtin_name("job", OP_JS_JOB)); op_names.push_back(builtin_name("resource", OP_JS_RESOURCE)); op_names.push_back(builtin_name("job-start", OP_JS_START)); op_names.push_back(builtin_name("job-end", OP_JS_END)); op_names.push_back(builtin_name("job2resource", OP_JS_JOB2RESOURCE)); + op_names.push_back(builtin_name("js-model", OP_JS_MODEL)); + op_names.push_back(builtin_name("kv", OP_AL_KV)); + op_names.push_back(builtin_name("alist", OP_AL_LIST)); } } void jobshop_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { - if (logic == symbol("JOBSHOP")) { + if (logic == symbol("CSP")) { sort_names.push_back(builtin_name("Job", JOB_SORT)); sort_names.push_back(builtin_name("Resource", RESOURCE_SORT)); } @@ -124,7 +143,7 @@ expr * jobshop_decl_plugin::get_some_value(sort * s) { jobshop_util::jobshop_util(ast_manager& m): m(m) { - m_fid = m.mk_family_id("jobshop"); + m_fid = m.mk_family_id("csp"); m_plugin = static_cast(m.get_plugin(m_fid)); } @@ -174,3 +193,11 @@ app* jobshop_util::mk_job2resource(unsigned j) { return m.mk_const(m.mk_func_decl(m_fid, OP_JS_JOB2RESOURCE, 1, &p, 0, (sort*const*)nullptr, nullptr)); } +bool jobshop_util::is_resource(expr* e, unsigned& r) { + return is_app_of(e, m_fid, OP_JS_RESOURCE) && (r = resource2id(e), true); +} + +bool jobshop_util::is_job(expr* e, unsigned& j) { + return is_app_of(e, m_fid, OP_JS_JOB) && (j = job2id(e), true); +} + diff --git a/src/ast/jobshop_decl_plugin.h b/src/ast/jobshop_decl_plugin.h index 48bdde6c1..f2cc7a849 100644 --- a/src/ast/jobshop_decl_plugin.h +++ b/src/ast/jobshop_decl_plugin.h @@ -68,7 +68,8 @@ Revision History: enum js_sort_kind { JOB_SORT, - RESOURCE_SORT + RESOURCE_SORT, + ALIST_SORT }; enum js_op_kind { @@ -76,7 +77,10 @@ enum js_op_kind { OP_JS_RESOURCE, // value of type resource OP_JS_START, // start time of a job OP_JS_END, // end time of a job - OP_JS_JOB2RESOURCE // resource associated with job + OP_JS_JOB2RESOURCE, // resource associated with job + OP_JS_MODEL, // jobscheduler model + OP_AL_KV, // key-value pair + OP_AL_LIST // tagged list }; class jobshop_decl_plugin : public decl_plugin { @@ -96,9 +100,11 @@ public: expr * get_some_value(sort * s) override; sort * mk_job_sort() const { return m_job_sort; } sort * mk_resource_sort() const { return m_resource_sort; } + sort * mk_alist_sort() const { return m_alist_sort; } private: sort* m_job_sort; sort* m_resource_sort; + sort* m_alist_sort; sort* m_int_sort; void check_arity(unsigned arity); @@ -116,12 +122,59 @@ public: sort* mk_resource_sort(); app* mk_job(unsigned j); + bool is_job(expr* e, unsigned& j); unsigned job2id(expr* j); app* mk_resource(unsigned r); + bool is_resource(expr* e, unsigned& r); unsigned resource2id(expr* r); app* mk_start(unsigned j); app* mk_end(unsigned j); app* mk_job2resource(unsigned j); + + // alist features + app* mk_kv(symbol const& key, rational const& r) { + parameter ps[2] = { parameter(key), parameter(r) }; + return m.mk_const(m.mk_func_decl(m_fid, OP_AL_KV, 2, ps, 0, (sort*const*)nullptr, nullptr)); + } + app* mk_kv(symbol const& key, symbol const& val) { + parameter ps[2] = { parameter(key), parameter(val) }; + return m.mk_const(m.mk_func_decl(m_fid, OP_AL_KV, 2, ps, 0, (sort*const*)nullptr, nullptr)); + } + app* mk_alist(symbol const& key, unsigned n, expr* const* args) { + parameter p(key); + return m.mk_app(m.mk_func_decl(m_fid, OP_AL_LIST, 1, &p, n, args, nullptr), n, args); + + } + bool is_kv(expr* e, symbol& key, rational& r) { + return + (is_app_of(e, m_fid, OP_AL_KV) && + to_app(e)->get_decl()->get_num_parameters() == 2 && + to_app(e)->get_decl()->get_parameter(1).is_rational() && + (r = to_app(e)->get_decl()->get_parameter(1).get_rational(), key = to_app(e)->get_decl()->get_parameter(0).get_symbol(), true)) || + (is_app_of(e, m_fid, OP_AL_KV) && + to_app(e)->get_decl()->get_num_parameters() == 2 && + to_app(e)->get_decl()->get_parameter(1).is_int() && + (r = rational(to_app(e)->get_decl()->get_parameter(1).get_int()), key = to_app(e)->get_decl()->get_parameter(0).get_symbol(), true)); + + + } + bool is_kv(expr* e, symbol& key, symbol& s) { + return is_app_of(e, m_fid, OP_AL_KV) && + to_app(e)->get_decl()->get_num_parameters() == 2 && + to_app(e)->get_decl()->get_parameter(1).is_symbol() && + (s = to_app(e)->get_decl()->get_parameter(1).get_symbol(), key = to_app(e)->get_decl()->get_parameter(0).get_symbol(), true); + } + + bool is_model(expr* e) const { return is_app_of(e, m_fid, OP_JS_MODEL); } + bool is_alist(expr* e) const { return is_app_of(e, m_fid, OP_AL_LIST); } + bool is_alist(expr* e, symbol& key) const { + return is_alist(e) && + to_app(e)->get_decl()->get_num_parameters() == 1 && + to_app(e)->get_decl()->get_parameter(0).is_symbol() && + (key = to_app(e)->get_decl()->get_parameter(0).get_symbol(), true); + } + + // app* mk_model(unsigned n, expr* const* alist); }; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index be3acc261..8387722b9 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -30,6 +30,7 @@ Notes: #include "ast/seq_decl_plugin.h" #include "ast/pb_decl_plugin.h" #include "ast/fpa_decl_plugin.h" +#include "ast/jobshop_decl_plugin.h" #include "ast/ast_pp.h" #include "ast/rewriter/var_subst.h" #include "ast/pp.h" @@ -695,6 +696,7 @@ void cmd_context::init_manager_core(bool new_manager) { register_plugin(symbol("pb"), alloc(pb_decl_plugin), logic_has_pb()); register_plugin(symbol("fpa"), alloc(fpa_decl_plugin), logic_has_fpa()); register_plugin(symbol("datalog_relation"), alloc(datalog::dl_decl_plugin), !has_logic()); + register_plugin(symbol("csp"), alloc(jobshop_decl_plugin), smt_logics::logic_is_csp(m_logic)); } else { // the manager was created by an external module @@ -709,6 +711,7 @@ void cmd_context::init_manager_core(bool new_manager) { load_plugin(symbol("seq"), logic_has_seq(), fids); load_plugin(symbol("fpa"), logic_has_fpa(), fids); load_plugin(symbol("pb"), logic_has_pb(), fids); + load_plugin(symbol("csp"), smt_logics::logic_is_csp(m_logic), fids); for (family_id fid : fids) { decl_plugin * p = m_manager->get_plugin(fid); if (p) { diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 403ea4c85..d1b4847cc 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -1523,8 +1523,20 @@ namespace smt2 { unsigned num_indices = 0; while (!curr_is_rparen()) { if (curr_is_int()) { - unsigned u = curr_unsigned(); - m_param_stack.push_back(parameter(u)); + if (!curr_numeral().is_unsigned()) { + m_param_stack.push_back(parameter(curr_numeral())); + } + else { + m_param_stack.push_back(parameter(curr_unsigned())); + } + next(); + } + else if (curr_is_float()) { + m_param_stack.push_back(parameter(curr_numeral())); + next(); + } + else if (curr_is_keyword()) { + m_param_stack.push_back(parameter(curr_id())); next(); } else if (curr_is_identifier() || curr_is_lparen()) { diff --git a/src/smt/smt_arith_value.cpp b/src/smt/smt_arith_value.cpp index ecf924111..ce4c0d9a9 100644 --- a/src/smt/smt_arith_value.cpp +++ b/src/smt/smt_arith_value.cpp @@ -30,7 +30,6 @@ namespace smt { bool arith_value::get_lo(expr* e, rational& lo, bool& is_strict) { if (!m_ctx.e_internalized(e)) return false; - expr_ref _lo(m); family_id afid = a.get_family_id(); is_strict = false; enode* next = m_ctx.get_enode(e), *n = next; @@ -42,15 +41,9 @@ namespace smt { theory_i_arith* thi = dynamic_cast(th); theory_lra* thr = dynamic_cast(th); do { - if (tha && tha->get_lower(next, _lo) && a.is_numeral(_lo, lo1)) { - if (!found || lo1 > lo) lo = lo1; - found = true; - } - else if (thi && thi->get_lower(next, _lo) && a.is_numeral(_lo, lo1)) { - if (!found || lo1 > lo) lo = lo1; - found = true; - } - else if (thr && thr->get_lower(next, lo1, is_strict1)) { + if ((tha && tha->get_lower(next, lo1, is_strict1)) || + (thi && thi->get_lower(next, lo1, is_strict1)) || + (thr && thr->get_lower(next, lo1, is_strict1))) { if (!found || lo1 > lo || (lo == lo1 && is_strict1)) lo = lo1, is_strict = is_strict1; found = true; } @@ -62,7 +55,6 @@ namespace smt { bool arith_value::get_up(expr* e, rational& up, bool& is_strict) { if (!m_ctx.e_internalized(e)) return false; - expr_ref _up(m); family_id afid = a.get_family_id(); is_strict = false; enode* next = m_ctx.get_enode(e), *n = next; @@ -73,15 +65,9 @@ namespace smt { theory_i_arith* thi = dynamic_cast(th); theory_lra* thr = dynamic_cast(th); do { - if (tha && tha->get_upper(next, _up) && a.is_numeral(_up, up1)) { - if (!found || up1 < up) up = up1; - found = true; - } - else if (thi && thi->get_upper(next, _up) && a.is_numeral(_up, up1)) { - if (!found || up1 < up) up = up1; - found = true; - } - else if (thr && thr->get_upper(next, up1, is_strict1)) { + if ((tha && tha->get_upper(next, up1, is_strict1)) || + (thi && thi->get_upper(next, up1, is_strict1)) || + (thr && thr->get_upper(next, up1, is_strict1))) { if (!found || up1 < up || (up1 == up && is_strict1)) up = up1, is_strict = is_strict1; found = true; } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 4b3ee52f6..a2c6c1191 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -1071,6 +1071,8 @@ namespace smt { bool get_lower(enode* n, expr_ref& r); bool get_upper(enode* n, expr_ref& r); + bool get_lower(enode* n, rational& r, bool &is_strict); + bool get_upper(enode* n, rational& r, bool &is_strict); bool to_expr(inf_numeral const& val, bool is_int, expr_ref& r); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 54f61a09a..1eb91f1fc 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -3303,6 +3303,20 @@ namespace smt { return b && to_expr(b->get_value(), is_int(v), r); } + template + bool theory_arith::get_lower(enode * n, rational& r, bool& is_strict) { + theory_var v = n->get_th_var(get_id()); + bound* b = (v == null_theory_var) ? nullptr : lower(v); + return b && (r = b->get_value().get_rational().to_rational(), is_strict = b->get_value().get_infinitesimal().is_pos(), true); + } + + template + bool theory_arith::get_upper(enode * n, rational& r, bool& is_strict) { + theory_var v = n->get_th_var(get_id()); + bound* b = (v == null_theory_var) ? nullptr : upper(v); + return b && (r = b->get_value().get_rational().to_rational(), is_strict = b->get_value().get_infinitesimal().is_neg(), true); + } + // ----------------------------------- // // Backtracking diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index 173d44c52..5064fc037 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -65,7 +65,7 @@ namespace smt { unsigned j = u.job2id(term); app_ref start(u.mk_start(j), m); app_ref end(u.mk_end(j), m); - app_ref res(u.mk_resource(j), m); + app_ref res(u.mk_job2resource(j), m); if (!ctx.e_internalized(start)) ctx.internalize(start, false); if (!ctx.e_internalized(end)) ctx.internalize(end, false); if (!ctx.e_internalized(res)) ctx.internalize(res, false); @@ -75,7 +75,7 @@ namespace smt { m_jobs.reserve(j + 1); m_jobs[j].m_start = ctx.get_enode(start); m_jobs[j].m_end = ctx.get_enode(end); - m_jobs[j].m_resource = ctx.get_enode(res); + m_jobs[j].m_job2resource = ctx.get_enode(res); ctx.attach_th_var(e, this, v); break; } @@ -99,6 +99,89 @@ namespace smt { return true; } + bool theory_jobscheduler::internalize_atom(app * atom, bool gate_ctx) { + SASSERT(u.is_model(atom)); + for (expr* arg : *atom) { + internalize_cmd(arg); + } + add_done(); + return true; + } + + // TBD: stronger parameter validation + void theory_jobscheduler::internalize_cmd(expr* cmd) { + symbol key, val; + rational r; + if (u.is_kv(cmd, key, r)) { + if (key == ":set-preemptable" && r.is_unsigned()) { + set_preemptable(r.get_unsigned(), true); + return; + } + warning_msg("command not recognized"); + } + else if (u.is_alist(cmd, key) && key == ":add-job-resource") { + properties ps; + unsigned j = 0, res = 0, cap = 0, loadpct = 100; + time_t end = std::numeric_limits::max(); + for (expr* arg : *to_app(cmd)) { + if (u.is_kv(arg, key, r)) { + if (key == ":job") { + j = r.get_unsigned(); + } + else if (key == ":resource") { + res = r.get_unsigned(); + } + else if (key == ":capacity") { + cap = r.get_unsigned(); + } + else if (key == ":loadpct") { + loadpct = r.get_unsigned(); + } + else if (key == ":end") { + end = r.get_uint64(); + } + } + else if (u.is_alist(arg, key) && key == ":properties") { + // TBD + } + } + if (cap > 0) { + add_job_resource(j, res, cap, loadpct, end, ps); + } + else { + warning_msg("no job capacity provided"); + } + } + else if (u.is_alist(cmd, key) && key == ":add-resource-available") { + properties ps; + unsigned res = 0, loadpct = 100; + time_t start = 0, end = 0; + for (expr* arg : *to_app(cmd)) { + if (u.is_kv(arg, key, r)) { + if (key == ":resource") { + res = r.get_unsigned(); + } + else if (key == ":start") { + start = r.get_unsigned(); + } + else if (key == ":end") { + end = r.get_unsigned(); + } + else if (key == ":loadpct") { + loadpct = r.get_unsigned(); + } + } + else if (u.is_alist(arg, key) && key == ":properties") { + // TBD + } + add_resource_available(res, loadpct, start, end, ps); + } + + } + else { + warning_msg("command not recognized"); + } + } void theory_jobscheduler::push_scope_eh() { } @@ -214,7 +297,7 @@ namespace smt { if (ctx.get_assignment(start_ge_lo) != l_true) { return; } - enode_pair eq(ji.m_resource, ctx.get_enode(u.mk_resource(r))); + enode_pair eq(ji.m_job2resource, resource2enode(r)); if (eq.first->get_root() != eq.second->get_root()) { return; } @@ -368,7 +451,7 @@ namespace smt { } theory_jobscheduler::theory_jobscheduler(ast_manager& m): - theory(m.get_family_id("jobshop")), m(m), u(m), a(m) { + theory(m.get_family_id("csp")), m(m), u(m), a(m) { } std::ostream& theory_jobscheduler::display(std::ostream & out, job_resource const& jr) const { @@ -423,51 +506,76 @@ namespace smt { return alloc(theory_jobscheduler, new_ctx->get_manager()); } - time_t theory_jobscheduler::est(unsigned j) { + time_t theory_jobscheduler::get_lo(expr* e) { arith_value av(get_context()); rational val; bool is_strict; - if (av.get_lo(u.mk_start(j), val, is_strict) && !is_strict && val.is_uint64()) { + if (av.get_lo(e, val, is_strict) && !is_strict && val.is_uint64()) { return val.get_uint64(); } return 0; } - time_t theory_jobscheduler::lst(unsigned j) { + time_t theory_jobscheduler::get_up(expr* e) { arith_value av(get_context()); rational val; bool is_strict; - if (av.get_up(u.mk_start(j), val, is_strict) && !is_strict && val.is_uint64()) { + if (av.get_up(e, val, is_strict) && !is_strict && val.is_uint64()) { return val.get_uint64(); } return std::numeric_limits::max(); } - time_t theory_jobscheduler::ect(unsigned j) { - NOT_IMPLEMENTED_YET(); + time_t theory_jobscheduler::get_value(expr* e) { + arith_value av(get_context()); + rational val; + if (av.get_value(e, val) && val.is_uint64()) { + return val.get_uint64(); + } return 0; + } + + time_t theory_jobscheduler::est(unsigned j) { + return get_lo(m_jobs[j].m_start->get_owner()); + } + + time_t theory_jobscheduler::lst(unsigned j) { + return get_up(m_jobs[j].m_start->get_owner()); + } + + time_t theory_jobscheduler::ect(unsigned j) { + return get_lo(m_jobs[j].m_end->get_owner()); } time_t theory_jobscheduler::lct(unsigned j) { - NOT_IMPLEMENTED_YET(); - return 0; + return get_up(m_jobs[j].m_end->get_owner()); } time_t theory_jobscheduler::start(unsigned j) { - NOT_IMPLEMENTED_YET(); - return 0; + return get_value(m_jobs[j].m_start->get_owner()); } time_t theory_jobscheduler::end(unsigned j) { - NOT_IMPLEMENTED_YET(); - return 0; + return get_value(m_jobs[j].m_end->get_owner()); } unsigned theory_jobscheduler::resource(unsigned j) { - NOT_IMPLEMENTED_YET(); + unsigned r; + enode* next = m_jobs[j].m_job2resource, *n = next; + do { + if (u.is_resource(next->get_owner(), r)) { + return r; + } + next = next->get_next(); + } + while (next != n); return 0; } + enode* theory_jobscheduler::resource2enode(unsigned r) { + return get_context().get_enode(u.mk_resource(r)); + } + void theory_jobscheduler::set_preemptable(unsigned j, bool is_preemptable) { m_jobs.reserve(j + 1); m_jobs[j].m_is_preemptable = is_preemptable; @@ -494,7 +602,8 @@ namespace smt { SASSERT(1 <= max_loadpct && max_loadpct <= 100); SASSERT(start <= end); m_resources.reserve(r + 1); - m_resources[r].m_available.push_back(res_available(max_loadpct, start, end, ps)); + res_info& ri = m_resources[r]; + ri.m_available.push_back(res_available(max_loadpct, start, end, ps)); } /* diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index 117303ff7..3647e6a1b 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -62,8 +62,8 @@ namespace smt { u_map m_resource2index; // resource to index into vector enode* m_start; enode* m_end; - enode* m_resource; - job_info(): m_is_preemptable(true), m_start(nullptr), m_end(nullptr), m_resource(nullptr) {} + enode* m_job2resource; + job_info(): m_is_preemptable(false), m_start(nullptr), m_end(nullptr), m_job2resource(nullptr) {} }; struct res_available { @@ -88,7 +88,8 @@ namespace smt { unsigned_vector m_jobs; // jobs allocated to run on resource vector m_available; // time intervals where resource is available time_t m_end; // can't run after - res_info(): m_end(std::numeric_limits::max()) {} + enode* m_resource; + res_info(): m_end(std::numeric_limits::max()), m_resource(nullptr) {} }; ast_manager& m; @@ -102,7 +103,7 @@ namespace smt { theory_var mk_var(enode * n) override; - bool internalize_atom(app * atom, bool gate_ctx) override { return false; } + bool internalize_atom(app * atom, bool gate_ctx) override; bool internalize_term(app * term) override; @@ -154,7 +155,11 @@ namespace smt { time_t lct(unsigned j); // last completion time time_t start(unsigned j); // start time of job j time_t end(unsigned j); // end time of job j + time_t get_lo(expr* e); + time_t get_up(expr* e); + time_t get_value(expr* e); unsigned resource(unsigned j); // resource of job j + enode* resource2enode(unsigned r); // derived bounds time_t ect(unsigned j, unsigned r, time_t start); @@ -201,6 +206,8 @@ namespace smt { literal mk_le(enode* l, enode* r); literal mk_literal(expr* e); + void internalize_cmd(expr* cmd); + std::ostream& display(std::ostream & out, res_info const& r) const; std::ostream& display(std::ostream & out, res_available const& r) const; std::ostream& display(std::ostream & out, job_info const& r) const; diff --git a/src/solver/smt_logics.cpp b/src/solver/smt_logics.cpp index 59a9a1562..d0fd8f809 100644 --- a/src/solver/smt_logics.cpp +++ b/src/solver/smt_logics.cpp @@ -22,7 +22,7 @@ Revision History: bool smt_logics::supported_logic(symbol const & s) { - return logic_has_uf(s) || logic_is_all(s) || logic_has_fd(s) || + return logic_has_uf(s) || logic_is_allcsp(s) || logic_has_fd(s) || logic_has_arith(s) || logic_has_bv(s) || logic_has_array(s) || logic_has_seq(s) || logic_has_str(s) || logic_has_horn(s) || logic_has_fpa(s); @@ -83,7 +83,7 @@ bool smt_logics::logic_has_arith(symbol const & s) { s == "QF_FPBV" || s == "QF_BVFP" || s == "QF_S" || - s == "ALL" || + logic_is_allcsp(s) || s == "QF_FD" || s == "HORN" || s == "QF_FPLRA"; @@ -102,7 +102,7 @@ bool smt_logics::logic_has_bv(symbol const & s) { s == "QF_BVRE" || s == "QF_FPBV" || s == "QF_BVFP" || - s == "ALL" || + logic_is_allcsp(s) || s == "QF_FD" || s == "HORN"; } @@ -123,22 +123,22 @@ bool smt_logics::logic_has_array(symbol const & s) { s == "AUFNIRA" || s == "AUFBV" || s == "ABV" || - s == "ALL" || + logic_is_allcsp(s) || s == "QF_ABV" || s == "QF_AUFBV" || s == "HORN"; } bool smt_logics::logic_has_seq(symbol const & s) { - return s == "QF_BVRE" || s == "QF_S" || s == "ALL"; + return s == "QF_BVRE" || s == "QF_S" || logic_is_allcsp(s); } bool smt_logics::logic_has_str(symbol const & s) { - return s == "QF_S" || s == "ALL"; + return s == "QF_S" || logic_is_allcsp(s); } bool smt_logics::logic_has_fpa(symbol const & s) { - return s == "QF_FP" || s == "QF_FPBV" || s == "QF_BVFP" || s == "QF_FPLRA" || s == "ALL"; + return s == "QF_FP" || s == "QF_FPBV" || s == "QF_BVFP" || s == "QF_FPLRA" || logic_is_allcsp(s); } bool smt_logics::logic_has_uf(symbol const & s) { @@ -150,9 +150,10 @@ bool smt_logics::logic_has_horn(symbol const& s) { } bool smt_logics::logic_has_pb(symbol const& s) { - return s == "QF_FD" || s == "ALL" || logic_has_horn(s); + return s == "QF_FD" || logic_is_allcsp(s) || logic_has_horn(s); } bool smt_logics::logic_has_datatype(symbol const& s) { - return s == "QF_FD" || s == "ALL" || s == "QF_DT"; + return s == "QF_FD" || logic_is_allcsp(s) || s == "QF_DT"; } + diff --git a/src/solver/smt_logics.h b/src/solver/smt_logics.h index 702431cdd..4382f575b 100644 --- a/src/solver/smt_logics.h +++ b/src/solver/smt_logics.h @@ -25,6 +25,8 @@ public: static bool supported_logic(symbol const & s); static bool logic_has_reals_only(symbol const& l); static bool logic_is_all(symbol const& s) { return s == "ALL"; } + static bool logic_is_csp(symbol const& s) { return s == "CSP"; } + static bool logic_is_allcsp(symbol const& s) { return logic_is_all(s) || logic_is_csp(s); } static bool logic_has_uf(symbol const& s); static bool logic_has_arith(symbol const & s); static bool logic_has_bv(symbol const & s); From 540baa88f4b4b2849a606fe7db72956d6b39cbcd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 Aug 2018 17:08:34 -0700 Subject: [PATCH 018/227] na Signed-off-by: Nikolaj Bjorner --- src/smt/smt_setup.cpp | 10 +++ src/smt/smt_setup.h | 1 + src/smt/theory_jobscheduler.cpp | 143 ++++++++++++++++++++------------ src/smt/theory_jobscheduler.h | 5 +- 4 files changed, 106 insertions(+), 53 deletions(-) diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 9e38fef69..585e7e841 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -35,6 +35,7 @@ Revision History: #include "smt/theory_pb.h" #include "smt/theory_fpa.h" #include "smt/theory_str.h" +#include "smt/theory_jobscheduler.h" namespace smt { @@ -119,6 +120,8 @@ namespace smt { setup_UFLRA(); else if (m_logic == "LRA") setup_LRA(); + else if (m_logic == "CSP") + setup_CSP(); else if (m_logic == "QF_FP") setup_QF_FP(); else if (m_logic == "QF_FPBV" || m_logic == "QF_BVFP") @@ -196,6 +199,8 @@ namespace smt { setup_QF_DT(); else if (m_logic == "LRA") setup_LRA(); + else if (m_logic == "CSP") + setup_CSP(); else setup_unknown(st); } @@ -916,6 +921,11 @@ namespace smt { m_context.register_plugin(alloc(smt::theory_seq, m_manager, m_params)); } + void setup::setup_CSP() { + setup_unknown(); + m_context.register_plugin(alloc(smt::theory_jobscheduler, m_manager)); + } + void setup::setup_unknown() { static_features st(m_manager); ptr_vector fmls; diff --git a/src/smt/smt_setup.h b/src/smt/smt_setup.h index ed0ab066d..61bfa386e 100644 --- a/src/smt/smt_setup.h +++ b/src/smt/smt_setup.h @@ -81,6 +81,7 @@ namespace smt { void setup_QF_FPBV(); void setup_QF_S(); void setup_LRA(); + void setup_CSP(); void setup_AUFLIA(bool simple_array = true); void setup_AUFLIA(static_features const & st); void setup_AUFLIRA(bool simple_array = true); diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index 5064fc037..70c891b8d 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -44,6 +44,7 @@ Features: --*/ +#include "ast/ast_pp.h" #include "smt/theory_jobscheduler.h" #include "smt/smt_context.h" #include "smt/smt_arith_value.h" @@ -100,6 +101,7 @@ namespace smt { } bool theory_jobscheduler::internalize_atom(app * atom, bool gate_ctx) { + TRACE("csp", tout << mk_pp(atom, m) << "\n";); SASSERT(u.is_model(atom)); for (expr* arg : *atom) { internalize_cmd(arg); @@ -112,77 +114,108 @@ namespace smt { void theory_jobscheduler::internalize_cmd(expr* cmd) { symbol key, val; rational r; - if (u.is_kv(cmd, key, r)) { - if (key == ":set-preemptable" && r.is_unsigned()) { - set_preemptable(r.get_unsigned(), true); - return; - } - warning_msg("command not recognized"); + if (u.is_kv(cmd, key, r) && key == ":set-preemptable" && r.is_unsigned()) { + set_preemptable(r.get_unsigned(), true); } else if (u.is_alist(cmd, key) && key == ":add-job-resource") { properties ps; unsigned j = 0, res = 0, cap = 0, loadpct = 100; time_t end = std::numeric_limits::max(); + bool has_j = false, has_res = false, has_cap = false, has_load = false, has_end = false; for (expr* arg : *to_app(cmd)) { if (u.is_kv(arg, key, r)) { - if (key == ":job") { + if (key == ":job" && r.is_unsigned()) { j = r.get_unsigned(); + has_j = true; } - else if (key == ":resource") { + else if (key == ":resource" && r.is_unsigned()) { res = r.get_unsigned(); + has_res = true; } - else if (key == ":capacity") { + else if (key == ":capacity" && r.is_unsigned()) { cap = r.get_unsigned(); + has_cap = true; } - else if (key == ":loadpct") { + else if (key == ":loadpct" && r.is_unsigned()) { loadpct = r.get_unsigned(); + has_load = true; } - else if (key == ":end") { + else if (key == ":end" && r.is_uint64()) { end = r.get_uint64(); + has_end = true; + } + else { + unrecognized_argument(arg); } } else if (u.is_alist(arg, key) && key == ":properties") { // TBD } + else { + unrecognized_argument(arg); + } } - if (cap > 0) { - add_job_resource(j, res, cap, loadpct, end, ps); - } - else { - warning_msg("no job capacity provided"); - } + if (!has_j) invalid_argument(":job argument expected ", cmd); + if (!has_res) invalid_argument(":resource argument expected ", cmd); + if (!has_cap) invalid_argument(":capacity argument expected ", cmd); + if (!has_load) invalid_argument(":loadpct argument expected ", cmd); + if (!has_end) invalid_argument(":end argument expected ", cmd); + if (cap == 0) invalid_argument(":capacity should be positive ", cmd); + add_job_resource(j, res, cap, loadpct, end, ps); } else if (u.is_alist(cmd, key) && key == ":add-resource-available") { properties ps; unsigned res = 0, loadpct = 100; time_t start = 0, end = 0; + bool has_start = false, has_res = false, has_load = false, has_end = false; + for (expr* arg : *to_app(cmd)) { if (u.is_kv(arg, key, r)) { - if (key == ":resource") { + if (key == ":resource" && r.is_unsigned()) { res = r.get_unsigned(); + has_res = true; } - else if (key == ":start") { - start = r.get_unsigned(); + else if (key == ":start" && r.is_uint64()) { + start = r.get_uint64(); + has_start = true; } - else if (key == ":end") { - end = r.get_unsigned(); + else if (key == ":end" && r.is_uint64()) { + end = r.get_uint64(); + has_end = true; } - else if (key == ":loadpct") { + else if (key == ":loadpct" && r.is_unsigned()) { loadpct = r.get_unsigned(); + has_load = true; + } + else { + unrecognized_argument(arg); } } else if (u.is_alist(arg, key) && key == ":properties") { // TBD } + else { + unrecognized_argument(arg); + } + if (!has_res) invalid_argument(":resource argument expected ", cmd); + if (!has_load) invalid_argument(":loadpct argument expected ", cmd); + if (!has_end) invalid_argument(":end argument expected ", cmd); + if (!has_start) invalid_argument(":start argument expected ", cmd); add_resource_available(res, loadpct, start, end, ps); } } else { - warning_msg("command not recognized"); + invalid_argument("command not recognized ", cmd); } } + void theory_jobscheduler::invalid_argument(char const* msg, expr* arg) { + std::ostringstream strm; + strm << msg << mk_pp(arg, m); + throw default_exception(strm.str()); + } + void theory_jobscheduler::push_scope_eh() { } @@ -256,29 +289,34 @@ namespace smt { * iterator of job overlaps. */ theory_jobscheduler::job_overlap::job_overlap(vector& starts, vector& ends): - m_starts(starts), m_ends(ends), s_idx(0), e_idx(0) { + m_start(0), m_starts(starts), m_ends(ends), s_idx(0), e_idx(0) { job_time::compare cmp; std::sort(starts.begin(), starts.end(), cmp); std::sort(ends.begin(), ends.end(), cmp); } - bool theory_jobscheduler::job_overlap::next(time_t& start) { + bool theory_jobscheduler::job_overlap::next() { if (s_idx == m_starts.size()) { return false; } - while (s_idx < m_starts.size() && m_starts[s_idx].m_time <= start) { - m_jobs.insert(m_starts[s_idx].m_job); - ++s_idx; - } - // remove jobs that end before start. - while (e_idx < m_ends.size() && m_ends[s_idx].m_time < start) { - m_jobs.remove(m_ends[e_idx].m_job); - ++e_idx; - } - // TBD: check logic - if (s_idx < m_starts.size()) { - start = m_starts[s_idx].m_time; + do { + m_start = std::max(m_start, m_starts[s_idx].m_time); + + // add jobs that start before or at m_start + while (s_idx < m_starts.size() && m_starts[s_idx].m_time <= m_start) { + m_jobs.insert(m_starts[s_idx].m_job); + ++s_idx; + } + // remove jobs that end before m_start. + while (e_idx < m_ends.size() && m_ends[s_idx].m_time < m_start) { + m_jobs.remove(m_ends[e_idx].m_job); + ++e_idx; + } } + // as long as set of jobs increments, add to m_start + while (s_idx < m_starts.size() && e_idx < m_ends.size() && + m_starts[s_idx].m_time <= m_ends[e_idx].m_time); + return true; } @@ -360,11 +398,13 @@ namespace smt { return false; } literal_vector lits; - lits.push_back(~mk_eq(u.mk_job2resource(j), u.mk_resource(r), false)); - lits.push_back(~mk_ge_lit(u.mk_start(j), t0)); - lits.push_back(~mk_le_lit(u.mk_start(j), t1)); - expr_ref rhs(a.mk_add(u.mk_start(j), a.mk_int(rational(delta, rational::ui64()))), m); - lits.push_back(mk_eq(u.mk_end(j), rhs, false)); + expr* start_e = m_jobs[j].m_start->get_owner(); + expr* end_e = m_jobs[j].m_end->get_owner(); + lits.push_back(~mk_eq(m_jobs[j].m_job2resource->get_owner(), u.mk_resource(r), false)); + lits.push_back(~mk_ge_lit(start_e, t0)); + lits.push_back(~mk_le_lit(start_e, t1)); + expr_ref rhs(a.mk_add(start_e, a.mk_int(rational(delta, rational::ui64()))), m); + lits.push_back(mk_eq(end_e, rhs, false)); context& ctx = get_context(); ctx.mk_clause(lits.size(), lits.c_ptr(), nullptr, CLS_AUX_LEMMA, nullptr); return true; @@ -388,8 +428,7 @@ namespace smt { } } job_overlap overlap(starts, ends); - time_t start = 0; - while (overlap.next(start)) { + while (overlap.next()) { unsigned cap = 0; auto const& jobs = overlap.jobs(); for (auto j : jobs) { @@ -478,6 +517,7 @@ namespace smt { } void theory_jobscheduler::display(std::ostream & out) const { + out << "jobscheduler:\n"; for (unsigned j = 0; j < m_jobs.size(); ++j) { display(out << "job " << j << ":\n", m_jobs[j]); } @@ -685,7 +725,7 @@ namespace smt { // resource(j) == r => start(j) >= available[0].m_start; app_ref job(u.mk_job(j), m); expr_ref eq(m.mk_eq(job, res), m); - expr_ref ge(mk_ge(u.mk_start(j), available[0].m_start), m); + expr_ref ge(mk_ge(m_jobs[j].m_start, available[0].m_start), m); expr_ref fml(m.mk_implies(eq, ge), m); ctx.assert_expr(fml); } @@ -698,16 +738,16 @@ namespace smt { // resource(j) == r => start(j) <= available[i].m_end || start(j) >= available[i + 1].m_start; app_ref job(u.mk_job(j), m); expr_ref eq(m.mk_eq(job, res), m); - expr_ref ge(mk_ge(u.mk_start(j), available[i + 1].m_start), m); - expr_ref le(mk_le(u.mk_start(j), available[i].m_end), m); + expr_ref ge(mk_ge(m_jobs[j].m_start, available[i + 1].m_start), m); + expr_ref le(mk_le(m_jobs[j].m_start, available[i].m_end), m); fml = m.mk_implies(eq, m.mk_or(le, ge)); ctx.assert_expr(fml); // if job is not pre-emptable, start and end have to align within contiguous interval. // resource(j) == r => end(j) <= available[i].m_end || start(j) >= available[i + 1].m_start if (!m_jobs[j].m_is_preemptable && available[i].m_end + 1 < available[i+1].m_start) { - le = mk_le(u.mk_end(j), available[i].m_end); - ge = mk_ge(u.mk_start(j), available[i+1].m_start); + le = mk_le(m_jobs[j].m_end, available[i].m_end); + ge = mk_ge(m_jobs[j].m_start, available[i+1].m_start); fml = m.mk_implies(eq, m.mk_or(le, ge)); ctx.assert_expr(fml); } @@ -742,9 +782,8 @@ namespace smt { for (unsigned r = 0; r < m_resources.size(); ++r) { // order jobs running on r by start, end-time intervals // then consume ordered list to find jobs in scope. - time_t start = 0; job_overlap overlap(start_times[r], end_times[r]); - while (overlap.next(start)) { + while (overlap.next()) { // check that sum of job loads does not exceed 100% unsigned cap = 0; for (auto j : overlap.jobs()) { diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index 3647e6a1b..7c5520548 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -187,12 +187,13 @@ namespace smt { void block_job_overlap(unsigned r, uint_set const& jobs, unsigned last_job); class job_overlap { + time_t m_start; vector & m_starts, &m_ends; unsigned s_idx, e_idx; // index into starts/ends uint_set m_jobs; public: job_overlap(vector& starts, vector& ends); - bool next(time_t& start); + bool next(); uint_set const& jobs() const { return m_jobs; } }; @@ -207,6 +208,8 @@ namespace smt { literal mk_literal(expr* e); void internalize_cmd(expr* cmd); + void unrecognized_argument(expr* arg) { invalid_argument("unrecognized argument ", arg); } + void invalid_argument(char const* msg, expr* arg); std::ostream& display(std::ostream & out, res_info const& r) const; std::ostream& display(std::ostream & out, res_available const& r) const; From a096ec648c96387804b561397c39420222ba64b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 Aug 2018 17:11:22 -0700 Subject: [PATCH 019/227] na Signed-off-by: Nikolaj Bjorner --- src/smt/theory_jobscheduler.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index 70c891b8d..c640c346a 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -197,13 +197,12 @@ namespace smt { else { unrecognized_argument(arg); } - if (!has_res) invalid_argument(":resource argument expected ", cmd); - if (!has_load) invalid_argument(":loadpct argument expected ", cmd); - if (!has_end) invalid_argument(":end argument expected ", cmd); - if (!has_start) invalid_argument(":start argument expected ", cmd); - add_resource_available(res, loadpct, start, end, ps); } - + if (!has_res) invalid_argument(":resource argument expected ", cmd); + if (!has_load) invalid_argument(":loadpct argument expected ", cmd); + if (!has_end) invalid_argument(":end argument expected ", cmd); + if (!has_start) invalid_argument(":start argument expected ", cmd); + add_resource_available(res, loadpct, start, end, ps); } else { invalid_argument("command not recognized ", cmd); From d55fe1ac59072c962b0d0d0ad28e718a09b0b6d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Aug 2018 09:41:43 -0700 Subject: [PATCH 020/227] na' Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 1 + src/ast/jobshop_decl_plugin.cpp | 60 +++++- src/ast/jobshop_decl_plugin.h | 7 + src/smt/smt_model_generator.cpp | 5 +- src/smt/theory_jobscheduler.cpp | 371 +++++++++++++++----------------- src/smt/theory_jobscheduler.h | 32 ++- 6 files changed, 261 insertions(+), 215 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 11a15492c..e889d0233 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1056,6 +1056,7 @@ sort* basic_decl_plugin::join(sort* s1, sort* s2) { return s2; } std::ostringstream buffer; + SASSERT(false); buffer << "Sorts " << mk_pp(s1, *m_manager) << " and " << mk_pp(s2, *m_manager) << " are incompatible"; throw ast_exception(buffer.str()); } diff --git a/src/ast/jobshop_decl_plugin.cpp b/src/ast/jobshop_decl_plugin.cpp index b1abc7fa3..79a2cf177 100644 --- a/src/ast/jobshop_decl_plugin.cpp +++ b/src/ast/jobshop_decl_plugin.cpp @@ -73,7 +73,9 @@ func_decl * jobshop_decl_plugin::mk_func_decl( case OP_JS_JOB2RESOURCE: check_arity(arity); check_index1(num_parameters, parameters); - return m_manager->mk_func_decl(symbol("job2resource"), 0, (sort* const*)nullptr, m_int_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + return m_manager->mk_func_decl(symbol("job2resource"), 0, (sort* const*)nullptr, m_resource_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + + case OP_JS_MODEL: // has no parameters // all arguments are of sort alist @@ -86,6 +88,24 @@ func_decl * jobshop_decl_plugin::mk_func_decl( // has no parameters // all arguments are of sort alist return m_manager->mk_func_decl(symbol("alist"), arity, domain, m_alist_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + case OP_JS_JOB_RESOURCE: + if (arity != 5) m_manager->raise_exception("add-job-resource expects 5 arguments"); + if (domain[0] != m_job_sort) m_manager->raise_exception("first argument of add-job-resource expects should be a job"); + if (domain[1] != m_resource_sort) m_manager->raise_exception("second argument of add-job-resource expects should be a resource"); + if (domain[2] != m_int_sort) m_manager->raise_exception("3rd argument of add-job-resource expects should be an integer"); + if (domain[3] != m_int_sort) m_manager->raise_exception("4th argument of add-job-resource expects should be an integer"); + if (domain[4] != m_int_sort) m_manager->raise_exception("5th argument of add-job-resource expects should be an integer"); + return m_manager->mk_func_decl(symbol("add-job-resource"), arity, domain, m_alist_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + case OP_JS_RESOURCE_AVAILABLE: + if (arity != 4) m_manager->raise_exception("add-resource-available expects 4 arguments"); + if (domain[0] != m_resource_sort) m_manager->raise_exception("first argument of add-resource-available expects should be a resource"); + if (domain[1] != m_int_sort) m_manager->raise_exception("2nd argument of add-resource-available expects should be an integer"); + if (domain[2] != m_int_sort) m_manager->raise_exception("3rd argument of add-resource-available expects should be an integer"); + if (domain[3] != m_int_sort) m_manager->raise_exception("4th argument of add-resource-available expects should be an integer"); + return m_manager->mk_func_decl(symbol("add-resource-available"), arity, domain, m_alist_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + case OP_JS_JOB_PREEMPTABLE: + if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("set-preemptable expects one argument, which is a job"); + return m_manager->mk_func_decl(symbol("set-preemptable"), arity, domain, m_alist_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); default: UNREACHABLE(); return nullptr; } @@ -121,6 +141,10 @@ void jobshop_decl_plugin::get_op_names(svector & op_names, symbol op_names.push_back(builtin_name("js-model", OP_JS_MODEL)); op_names.push_back(builtin_name("kv", OP_AL_KV)); op_names.push_back(builtin_name("alist", OP_AL_LIST)); + op_names.push_back(builtin_name("add-job-resource", OP_JS_JOB_RESOURCE)); + op_names.push_back(builtin_name("add-resource-available", OP_JS_RESOURCE_AVAILABLE)); + op_names.push_back(builtin_name("set-preemptable", OP_JS_JOB_PREEMPTABLE)); + } } @@ -201,3 +225,37 @@ bool jobshop_util::is_job(expr* e, unsigned& j) { return is_app_of(e, m_fid, OP_JS_JOB) && (j = job2id(e), true); } +bool jobshop_util::is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, uint64_t& start, uint64_t& end) { + if (!is_app_of(e, m_fid, OP_JS_RESOURCE_AVAILABLE)) return false; + res = to_app(e)->get_arg(0); + arith_util a(m); + rational r; + if (!a.is_numeral(to_app(e)->get_arg(1), r) || !r.is_unsigned()) return false; + loadpct = r.get_unsigned(); + if (!a.is_numeral(to_app(e)->get_arg(2), r) || !r.is_uint64()) return false; + start = r.get_uint64(); + if (!a.is_numeral(to_app(e)->get_arg(3), r) || !r.is_uint64()) return false; + end = r.get_uint64(); + return true; +} + +bool jobshop_util::is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end) { + if (!is_app_of(e, m_fid, OP_JS_JOB_RESOURCE)) return false; + job = to_app(e)->get_arg(0); + res = to_app(e)->get_arg(1); + arith_util a(m); + rational r; + if (!a.is_numeral(to_app(e)->get_arg(2), r) || !r.is_unsigned()) return false; + loadpct = r.get_unsigned(); + if (!a.is_numeral(to_app(e)->get_arg(3), r) || !r.is_uint64()) return false; + capacity = r.get_uint64(); + if (!a.is_numeral(to_app(e)->get_arg(4), r) || !r.is_uint64()) return false; + end = r.get_uint64(); + return true; +} + +bool jobshop_util::is_set_preemptable(expr* e, expr *& job) { + if (!is_app_of(e, m_fid, OP_JS_JOB_PREEMPTABLE)) return false; + job = to_app(e)->get_arg(0); + return true; +} diff --git a/src/ast/jobshop_decl_plugin.h b/src/ast/jobshop_decl_plugin.h index f2cc7a849..f295c901f 100644 --- a/src/ast/jobshop_decl_plugin.h +++ b/src/ast/jobshop_decl_plugin.h @@ -79,6 +79,9 @@ enum js_op_kind { OP_JS_END, // end time of a job OP_JS_JOB2RESOURCE, // resource associated with job OP_JS_MODEL, // jobscheduler model + OP_JS_JOB_RESOURCE, + OP_JS_JOB_PREEMPTABLE, + OP_JS_RESOURCE_AVAILABLE, OP_AL_KV, // key-value pair OP_AL_LIST // tagged list }; @@ -133,6 +136,10 @@ public: app* mk_end(unsigned j); app* mk_job2resource(unsigned j); + bool is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, uint64_t& start, uint64_t& end); + bool is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end); + bool is_set_preemptable(expr* e, expr *& job); + // alist features app* mk_kv(symbol const& key, rational const& r) { parameter ps[2] = { parameter(key), parameter(r) }; diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index a4b3029e2..c27845ff6 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -402,7 +402,10 @@ namespace smt { enode * n = m_context->get_enode(t); unsigned num_args = n->get_num_args(); func_decl * f = n->get_decl(); - if (num_args > 0 && n->get_cg() == n && include_func_interp(f)) { + if (num_args == 0 && include_func_interp(f)) { + m_model->register_decl(f, get_value(n)); + } + else if (num_args > 0 && n->get_cg() == n && include_func_interp(f)) { ptr_buffer args; expr * result = get_value(n); SASSERT(result); diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index c640c346a..c138b6012 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -48,6 +48,7 @@ Features: #include "smt/theory_jobscheduler.h" #include "smt/smt_context.h" #include "smt/smt_arith_value.h" +#include "smt/smt_model_generator.h" namespace smt { @@ -60,53 +61,28 @@ namespace smt { context & ctx = get_context(); if (ctx.e_internalized(term)) return true; + for (expr* arg : *term) { + if (!ctx.e_internalized(arg)) + ctx.internalize(arg, false); + } enode* e = ctx.mk_enode(term, false, false, true); - switch (static_cast(term->get_decl()->get_decl_kind())) { - case OP_JS_JOB: { - unsigned j = u.job2id(term); - app_ref start(u.mk_start(j), m); - app_ref end(u.mk_end(j), m); - app_ref res(u.mk_job2resource(j), m); - if (!ctx.e_internalized(start)) ctx.internalize(start, false); - if (!ctx.e_internalized(end)) ctx.internalize(end, false); - if (!ctx.e_internalized(res)) ctx.internalize(res, false); - theory_var v = mk_var(e); - SASSERT(m_var2index.size() == v); - m_var2index.push_back(j); - m_jobs.reserve(j + 1); - m_jobs[j].m_start = ctx.get_enode(start); - m_jobs[j].m_end = ctx.get_enode(end); - m_jobs[j].m_job2resource = ctx.get_enode(res); - ctx.attach_th_var(e, this, v); - break; - } - case OP_JS_RESOURCE: { - theory_var v = mk_var(e); - SASSERT(m_var2index.size() == v); - unsigned r = u.resource2id(term); - m_var2index.push_back(r); - ctx.attach_th_var(e, this, v); - break; - } - case OP_JS_START: - case OP_JS_END: - case OP_JS_JOB2RESOURCE: { - unsigned j = u.job2id(term); - app_ref job(u.mk_job(j), m); - if (!ctx.e_internalized(job)) ctx.internalize(job, false); - break; - } - } + theory_var v = mk_var(e); + ctx.attach_th_var(e, this, v); + ctx.mark_as_relevant(e); return true; } bool theory_jobscheduler::internalize_atom(app * atom, bool gate_ctx) { TRACE("csp", tout << mk_pp(atom, m) << "\n";); + context & ctx = get_context(); SASSERT(u.is_model(atom)); for (expr* arg : *atom) { + if (!ctx.e_internalized(arg)) ctx.internalize(arg, false); internalize_cmd(arg); } add_done(); + bool_var bv = ctx.mk_bool_var(atom); + ctx.set_var_theory(bv, get_id()); return true; } @@ -114,95 +90,18 @@ namespace smt { void theory_jobscheduler::internalize_cmd(expr* cmd) { symbol key, val; rational r; - if (u.is_kv(cmd, key, r) && key == ":set-preemptable" && r.is_unsigned()) { - set_preemptable(r.get_unsigned(), true); + expr* job, *resource; + unsigned j = 0, res = 0, cap = 0, loadpct = 100; + time_t start = 0, end = std::numeric_limits::max(), capacity = 0; + properties ps; + if (u.is_set_preemptable(cmd, job) && u.is_job(job, j)) { + set_preemptable(j, true); } - else if (u.is_alist(cmd, key) && key == ":add-job-resource") { - properties ps; - unsigned j = 0, res = 0, cap = 0, loadpct = 100; - time_t end = std::numeric_limits::max(); - bool has_j = false, has_res = false, has_cap = false, has_load = false, has_end = false; - for (expr* arg : *to_app(cmd)) { - if (u.is_kv(arg, key, r)) { - if (key == ":job" && r.is_unsigned()) { - j = r.get_unsigned(); - has_j = true; - } - else if (key == ":resource" && r.is_unsigned()) { - res = r.get_unsigned(); - has_res = true; - } - else if (key == ":capacity" && r.is_unsigned()) { - cap = r.get_unsigned(); - has_cap = true; - } - else if (key == ":loadpct" && r.is_unsigned()) { - loadpct = r.get_unsigned(); - has_load = true; - } - else if (key == ":end" && r.is_uint64()) { - end = r.get_uint64(); - has_end = true; - } - else { - unrecognized_argument(arg); - } - } - else if (u.is_alist(arg, key) && key == ":properties") { - // TBD - } - else { - unrecognized_argument(arg); - } - } - if (!has_j) invalid_argument(":job argument expected ", cmd); - if (!has_res) invalid_argument(":resource argument expected ", cmd); - if (!has_cap) invalid_argument(":capacity argument expected ", cmd); - if (!has_load) invalid_argument(":loadpct argument expected ", cmd); - if (!has_end) invalid_argument(":end argument expected ", cmd); - if (cap == 0) invalid_argument(":capacity should be positive ", cmd); - add_job_resource(j, res, cap, loadpct, end, ps); + else if (u.is_add_resource_available(cmd, resource, loadpct, start, end) && u.is_resource(resource, res)) { + add_resource_available(res, loadpct, start, end, ps); } - else if (u.is_alist(cmd, key) && key == ":add-resource-available") { - properties ps; - unsigned res = 0, loadpct = 100; - time_t start = 0, end = 0; - bool has_start = false, has_res = false, has_load = false, has_end = false; - - for (expr* arg : *to_app(cmd)) { - if (u.is_kv(arg, key, r)) { - if (key == ":resource" && r.is_unsigned()) { - res = r.get_unsigned(); - has_res = true; - } - else if (key == ":start" && r.is_uint64()) { - start = r.get_uint64(); - has_start = true; - } - else if (key == ":end" && r.is_uint64()) { - end = r.get_uint64(); - has_end = true; - } - else if (key == ":loadpct" && r.is_unsigned()) { - loadpct = r.get_unsigned(); - has_load = true; - } - else { - unrecognized_argument(arg); - } - } - else if (u.is_alist(arg, key) && key == ":properties") { - // TBD - } - else { - unrecognized_argument(arg); - } - } - if (!has_res) invalid_argument(":resource argument expected ", cmd); - if (!has_load) invalid_argument(":loadpct argument expected ", cmd); - if (!has_end) invalid_argument(":end argument expected ", cmd); - if (!has_start) invalid_argument(":start argument expected ", cmd); - add_resource_available(res, loadpct, start, end, ps); + else if (u.is_add_job_resource(cmd, job, resource, loadpct, capacity, end) && u.is_job(job, j) && u.is_resource(resource, res)) { + add_job_resource(j, res, loadpct, capacity, end, ps); } else { invalid_argument("command not recognized ", cmd); @@ -222,7 +121,7 @@ namespace smt { } final_check_status theory_jobscheduler::final_check_eh() { - + TRACE("csp", tout << "\n";); bool blocked = false; for (unsigned r = 0; r < m_resources.size(); ++r) { if (constrain_resource_energy(r)) { @@ -253,23 +152,23 @@ namespace smt { return ctx.get_literal(e); } - literal theory_jobscheduler::mk_ge_lit(expr* e, time_t t) { - return mk_literal(mk_ge(e, t)); + literal theory_jobscheduler::mk_ge(expr* e, time_t t) { + return mk_literal(mk_ge_expr(e, t)); } - expr* theory_jobscheduler::mk_ge(expr* e, time_t t) { + expr* theory_jobscheduler::mk_ge_expr(expr* e, time_t t) { return a.mk_ge(e, a.mk_int(rational(t, rational::ui64()))); } - expr* theory_jobscheduler::mk_ge(enode* e, time_t t) { + literal theory_jobscheduler::mk_ge(enode* e, time_t t) { return mk_ge(e->get_owner(), t); } - literal theory_jobscheduler::mk_le_lit(expr* e, time_t t) { - return mk_literal(mk_le(e, t)); + literal theory_jobscheduler::mk_le(expr* e, time_t t) { + return mk_literal(mk_le_expr(e, t)); } - expr* theory_jobscheduler::mk_le(expr* e, time_t t) { + expr* theory_jobscheduler::mk_le_expr(expr* e, time_t t) { return a.mk_le(e, a.mk_int(rational(t, rational::ui64()))); } @@ -280,10 +179,17 @@ namespace smt { return mk_literal(le); } - expr* theory_jobscheduler::mk_le(enode* e, time_t t) { + literal theory_jobscheduler::mk_le(enode* e, time_t t) { return mk_le(e->get_owner(), t); } + literal theory_jobscheduler::mk_eq_lit(expr * l, expr * r) { + literal lit = mk_eq(l, r, false); + get_context().mark_as_relevant(lit); + return lit; + } + + /** * iterator of job overlaps. */ @@ -307,7 +213,7 @@ namespace smt { ++s_idx; } // remove jobs that end before m_start. - while (e_idx < m_ends.size() && m_ends[s_idx].m_time < m_start) { + while (e_idx < m_ends.size() && m_ends[e_idx].m_time < m_start) { m_jobs.remove(m_ends[e_idx].m_job); ++e_idx; } @@ -330,7 +236,7 @@ namespace smt { if (clb > end(j)) { job_info const& ji = m_jobs[j]; - literal start_ge_lo = mk_literal(mk_ge(ji.m_start, slb)); + literal start_ge_lo = mk_ge(ji.m_start, slb); if (ctx.get_assignment(start_ge_lo) != l_true) { return; } @@ -339,7 +245,7 @@ namespace smt { return; } - literal end_ge_lo = mk_literal(mk_ge(ji.m_end, clb)); + literal end_ge_lo = mk_ge(ji.m_end, clb); // Initialization ensures that satisfiable states have completion time below end. VERIFY(clb <= get_job_resource(j, r).m_end); region& r = ctx.get_region(); @@ -358,10 +264,12 @@ namespace smt { bool theory_jobscheduler::constrain_end_time_interval(unsigned j, unsigned r) { unsigned idx1 = 0, idx2 = 0; time_t s = start(j); + TRACE("csp", tout << "job: " << j << " resource: " << r << " start: " << s << "\n";); if (!resource_available(r, s, idx1)) return false; vector& available = m_resources[r].m_available; time_t e = ect(j, r, s); - if (!resource_available(r, e, idx2)) return false; + TRACE("csp", tout << "job: " << j << " resource: " << r << " ect: " << e << "\n";); + if (!resource_available(r, e, idx2)) return false; // infeasible.. time_t start1 = available[idx1].m_start; time_t end1 = available[idx1].m_end; unsigned cap1 = available[idx1].m_loadpct; @@ -396,14 +304,15 @@ namespace smt { if (end(j) == start(j) + delta) { return false; } + TRACE("csp", tout << "job: " << j << " resource " << r << " t0: " << t0 << " t1: " << t1 << " delta: " << delta << "\n";); literal_vector lits; - expr* start_e = m_jobs[j].m_start->get_owner(); - expr* end_e = m_jobs[j].m_end->get_owner(); - lits.push_back(~mk_eq(m_jobs[j].m_job2resource->get_owner(), u.mk_resource(r), false)); - lits.push_back(~mk_ge_lit(start_e, t0)); - lits.push_back(~mk_le_lit(start_e, t1)); - expr_ref rhs(a.mk_add(start_e, a.mk_int(rational(delta, rational::ui64()))), m); - lits.push_back(mk_eq(end_e, rhs, false)); + enode* start_e = m_jobs[j].m_start; + enode* end_e = m_jobs[j].m_end; + lits.push_back(~mk_eq_lit(m_jobs[j].m_job2resource, m_resources[r].m_resource)); + lits.push_back(~mk_ge(start_e, t0)); + lits.push_back(~mk_le(start_e, t1)); + expr_ref rhs(a.mk_add(start_e->get_owner(), a.mk_int(rational(delta, rational::ui64()))), m); + lits.push_back(mk_eq_lit(end_e->get_owner(), rhs)); context& ctx = get_context(); ctx.mk_clause(lits.size(), lits.c_ptr(), nullptr, CLS_AUX_LEMMA, nullptr); return true; @@ -466,7 +375,7 @@ namespace smt { // resource(j) == r // m_jobs[j].m_start <= m_jobs[max_j].m_start; // m_jobs[max_j].m_start <= m_jobs[j].m_end; - lits.push_back(~mk_eq(u.mk_job2resource(j), u.mk_resource(r), false)); + lits.push_back(~mk_eq_lit(m_jobs[j].m_job2resource, m_resources[r].m_resource)); if (j != max_j) { lits.push_back(~mk_le(m_jobs[j].m_start, m_jobs[max_j].m_start)); lits.push_back(~mk_le(m_jobs[max_j].m_start, m_jobs[j].m_end)); @@ -478,6 +387,7 @@ namespace smt { } void theory_jobscheduler::propagate() { + return; for (unsigned j = 0; j < m_jobs.size(); ++j) { job_info const& ji = m_jobs[j]; unsigned r = resource(j); @@ -493,24 +403,23 @@ namespace smt { } std::ostream& theory_jobscheduler::display(std::ostream & out, job_resource const& jr) const { - return out << " r:" << jr.m_resource_id << " cap:" << jr.m_capacity << " load:" << jr.m_loadpct << " end:" << jr.m_end << "\n"; + return out << "r:" << jr.m_resource_id << " cap:" << jr.m_capacity << " load:" << jr.m_loadpct << " end:" << jr.m_end << "\n"; } std::ostream& theory_jobscheduler::display(std::ostream & out, job_info const& j) const { for (job_resource const& jr : j.m_resources) { - display(out, jr); + display(out << " ", jr); } return out; } std::ostream& theory_jobscheduler::display(std::ostream & out, res_available const& r) const { - out << "[" << r.m_start << ":" << r.m_end << "] @ " << r.m_loadpct << "%%\n"; - return out; + return out << "[" << r.m_start << ":" << r.m_end << "] @ " << r.m_loadpct << "%\n"; } std::ostream& theory_jobscheduler::display(std::ostream & out, res_info const& r) const { for (res_available const& ra : r.m_available) { - display(out, ra); + display(out << " ", ra); } return out; } @@ -529,15 +438,23 @@ namespace smt { } + bool theory_jobscheduler::include_func_interp(func_decl* f) { + return + f->get_decl_kind() == OP_JS_START || + f->get_decl_kind() == OP_JS_END || + f->get_decl_kind() == OP_JS_JOB2RESOURCE; + } + void theory_jobscheduler::init_model(model_generator & m) { } model_value_proc * theory_jobscheduler::mk_value(enode * n, model_generator & mg) { - return nullptr; + return alloc(expr_wrapper_proc, n->get_root()->get_owner()); } bool theory_jobscheduler::get_value(enode * n, expr_ref & r) { + std::cout << mk_pp(n->get_owner(), m) << "\n"; return false; } @@ -620,7 +537,7 @@ namespace smt { m_jobs[j].m_is_preemptable = is_preemptable; } - void theory_jobscheduler::add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, time_t end, properties const& ps) { + void theory_jobscheduler::add_job_resource(unsigned j, unsigned r, unsigned loadpct, uint64_t cap, time_t end, properties const& ps) { SASSERT(get_context().at_base_level()); SASSERT(1 <= loadpct && loadpct <= 100); SASSERT(0 < cap); @@ -630,6 +547,21 @@ namespace smt { if (ji.m_resource2index.contains(r)) { throw default_exception("resource already bound to job"); } + if (!ji.m_start) { + context& ctx = get_context(); + app_ref job(u.mk_job(j), m); + app_ref start(u.mk_start(j), m); + app_ref end(u.mk_end(j), m); + app_ref res(u.mk_job2resource(j), m); + if (!ctx.e_internalized(job)) ctx.internalize(job, false); + if (!ctx.e_internalized(start)) ctx.internalize(start, false); + if (!ctx.e_internalized(end)) ctx.internalize(end, false); + if (!ctx.e_internalized(res)) ctx.internalize(res, false); + ji.m_job = ctx.get_enode(job); + ji.m_start = ctx.get_enode(start); + ji.m_end = ctx.get_enode(end); + ji.m_job2resource = ctx.get_enode(res); + } ji.m_resource2index.insert(r, ji.m_resources.size()); ji.m_resources.push_back(job_resource(r, cap, loadpct, end, ps)); SASSERT(!m_resources[r].m_jobs.contains(j)); @@ -642,6 +574,12 @@ namespace smt { SASSERT(start <= end); m_resources.reserve(r + 1); res_info& ri = m_resources[r]; + if (!ri.m_resource) { + context& ctx = get_context(); + app_ref res(u.mk_resource(r), m); + if (!ctx.e_internalized(res)) ctx.internalize(res, false); + ri.m_resource = ctx.get_enode(res); + } ri.m_available.push_back(res_available(max_loadpct, start, end, ps)); } @@ -655,6 +593,7 @@ namespace smt { * Ensure that the availability slots for each resource is sorted by time. */ void theory_jobscheduler::add_done() { + TRACE("csp", tout << "add-done begin\n";); context & ctx = get_context(); // sort availability intervals @@ -666,18 +605,19 @@ namespace smt { } expr_ref fml(m); + literal lit, l1, l2, l3; for (unsigned j = 0; j < m_jobs.size(); ++j) { job_info const& ji = m_jobs[j]; - expr_ref_vector disj(m); + literal_vector disj; app_ref job(u.mk_job(j), m); if (ji.m_resources.empty()) { throw default_exception("every job should be associated with at least one resource"); } - // start(j) <= end(j) - fml = a.mk_le(ji.m_start->get_owner(), ji.m_end->get_owner()); - ctx.assert_expr(fml); + // start(j) <= end(j) + lit = mk_le(ji.m_start, ji.m_end); + ctx.mk_th_axiom(get_id(), 1, &lit); time_t start_lb = std::numeric_limits::max(); time_t end_ub = 0; @@ -685,48 +625,36 @@ namespace smt { // resource(j) = r => end(j) <= end(j, r) // resource(j) = r => start(j) <= lst(j, r, end(j, r)) unsigned r = jr.m_resource_id; - app_ref res(u.mk_resource(r), m); - expr_ref eq(m.mk_eq(job, res), m); - expr_ref imp(m.mk_implies(eq, mk_le(ji.m_end, jr.m_end)), m); - ctx.assert_expr(imp); - time_t t; - if (!lst(j, r, t)) { - imp = m.mk_implies(eq, mk_le(ji.m_start, t)); - } - else { - imp = m.mk_not(eq); - } - ctx.assert_expr(imp); - disj.push_back(eq); res_info const& ri = m_resources[r]; + enode* j2r = m_jobs[j].m_job2resource; + literal eq = mk_eq_lit(j2r, ri.m_resource); + assert_last_end_time(j, r, jr, eq); + assert_last_start_time(j, r, eq); + disj.push_back(eq); start_lb = std::min(start_lb, ri.m_available[0].m_start); end_ub = std::max(end_ub, ri.m_available.back().m_end); } // resource(j) = r1 || ... || resource(j) = r_n - expr_ref fml = mk_or(disj); - ctx.assert_expr(fml); + ctx.mk_th_axiom(get_id(), disj.size(), disj.c_ptr()); // start(j) >= start_lb - fml = mk_ge(ji.m_start, start_lb); - ctx.assert_expr(fml); + lit = mk_ge(ji.m_start, start_lb); + ctx.mk_th_axiom(get_id(), 1, &lit); // end(j) <= end_ub - fml = mk_le(ji.m_end, end_ub); - ctx.assert_expr(fml); + lit = mk_le(ji.m_end, end_ub); + ctx.mk_th_axiom(get_id(), 1, &lit); } for (unsigned r = 0; r < m_resources.size(); ++r) { res_info& ri = m_resources[r]; vector& available = ri.m_available; if (available.empty()) continue; - app_ref res(u.mk_resource(r), m); + enode* res = m_resources[r].m_resource; for (unsigned j : ri.m_jobs) { // resource(j) == r => start(j) >= available[0].m_start; - app_ref job(u.mk_job(j), m); - expr_ref eq(m.mk_eq(job, res), m); - expr_ref ge(mk_ge(m_jobs[j].m_start, available[0].m_start), m); - expr_ref fml(m.mk_implies(eq, ge), m); - ctx.assert_expr(fml); + enode* j2r = m_jobs[j].m_job2resource; + assert_first_start_time(j, r, mk_eq_lit(j2r, res)); } for (unsigned i = 0; i + 1 < available.size(); ++i) { if (available[i].m_end > available[i + 1].m_start) { @@ -735,26 +663,61 @@ namespace smt { for (unsigned j : ri.m_jobs) { // jobs start within an interval. // resource(j) == r => start(j) <= available[i].m_end || start(j) >= available[i + 1].m_start; - app_ref job(u.mk_job(j), m); - expr_ref eq(m.mk_eq(job, res), m); - expr_ref ge(mk_ge(m_jobs[j].m_start, available[i + 1].m_start), m); - expr_ref le(mk_le(m_jobs[j].m_start, available[i].m_end), m); - fml = m.mk_implies(eq, m.mk_or(le, ge)); - ctx.assert_expr(fml); + enode* j2r = m_jobs[j].m_job2resource; + literal eq = mk_eq_lit(j2r, res); + assert_job_not_in_gap(j, r, i, eq); // if job is not pre-emptable, start and end have to align within contiguous interval. // resource(j) == r => end(j) <= available[i].m_end || start(j) >= available[i + 1].m_start if (!m_jobs[j].m_is_preemptable && available[i].m_end + 1 < available[i+1].m_start) { - le = mk_le(m_jobs[j].m_end, available[i].m_end); - ge = mk_ge(m_jobs[j].m_start, available[i+1].m_start); - fml = m.mk_implies(eq, m.mk_or(le, ge)); - ctx.assert_expr(fml); + assert_job_non_preemptable(j, r, i, eq); } } } } + TRACE("csp", tout << "add-done end\n";); } + void theory_jobscheduler::assert_last_end_time(unsigned j, unsigned r, job_resource const& jr, literal eq) { + job_info const& ji = m_jobs[j]; + literal l2 = mk_le(ji.m_end, jr.m_end); + get_context().mk_th_axiom(get_id(), ~eq, l2); + } + + void theory_jobscheduler::assert_last_start_time(unsigned j, unsigned r, literal eq) { + context& ctx = get_context(); + time_t t; + if (lst(j, r, t)) { + ctx.mk_th_axiom(get_id(), ~eq, mk_le(m_jobs[j].m_start, t)); + } + else { + eq.neg(); + ctx.mk_th_axiom(get_id(), 1, &eq); + } + } + + void theory_jobscheduler::assert_first_start_time(unsigned j, unsigned r, literal eq) { + vector& available = m_resources[r].m_available; + literal l2 = mk_ge(m_jobs[j].m_start, available[0].m_start); + get_context().mk_th_axiom(get_id(), ~eq, l2); + } + + void theory_jobscheduler::assert_job_not_in_gap(unsigned j, unsigned r, unsigned idx, literal eq) { + vector& available = m_resources[r].m_available; + literal l2 = mk_ge(m_jobs[j].m_start, available[idx + 1].m_start); + literal l3 = mk_le(m_jobs[j].m_start, available[idx].m_end); + get_context().mk_th_axiom(get_id(), ~eq, l2, l3); + } + + void theory_jobscheduler::assert_job_non_preemptable(unsigned j, unsigned r, unsigned idx, literal eq) { + vector& available = m_resources[r].m_available; + literal l2 = mk_le(m_jobs[j].m_end, available[idx].m_end); + literal l3 = mk_ge(m_jobs[j].m_start, available[idx + 1].m_start); + get_context().mk_th_axiom(get_id(), ~eq, l2, l3); + } + + + /** * check that each job is run on some resource according to * requested capacity. @@ -836,6 +799,7 @@ namespace smt { time_t cap = jr.m_capacity; unsigned idx = 0; if (!resource_available(r, start, idx)) { + TRACE("csp", tout << "resource is not available for " << j << " " << r << "\n";); return std::numeric_limits::max(); } SASSERT(cap > 0); @@ -845,6 +809,7 @@ namespace smt { time_t end = available[idx].m_end; unsigned load_pct = available[idx].m_loadpct; time_t delta = solve_for_capacity(load_pct, j_load_pct, start, end); + TRACE("csp", tout << "delta: " << delta << " capacity: " << cap << " load " << load_pct << " jload: " << j_load_pct << " start: " << start << " end " << end << "\n";); if (delta > cap) { // // solve for end: @@ -870,29 +835,29 @@ namespace smt { time_t theory_jobscheduler::solve_for_end(unsigned load_pct, unsigned job_load_pct, time_t start, time_t cap) { SASSERT(load_pct > 0); SASSERT(job_load_pct > 0); - // cap = (load / job_load_pct) * (start - end + 1) + // cap = (load / job_load_pct) * (end - start + 1) // <=> - // start - end + 1 = (cap * job_load_pct) / load + // end - start + 1 = (cap * job_load_pct) / load // <=> - // end = start + 1 - (cap * job_load_pct) / load + // end = start - 1 + (cap * job_load_pct) / load // <=> - // end = (load * (start + 1) - cap * job_load_pct) / load + // end = (load * (start - 1) + cap * job_load_pct) / load unsigned load = std::min(load_pct, job_load_pct); - return (load * (start + 1) - cap * job_load_pct) / load; + return (load * (start - 1) + cap * job_load_pct) / load; } time_t theory_jobscheduler::solve_for_start(unsigned load_pct, unsigned job_load_pct, time_t end, time_t cap) { SASSERT(load_pct > 0); SASSERT(job_load_pct > 0); - // cap = (load / job_load_pct) * (start - end + 1) + // cap = (load / job_load_pct) * (end - start + 1) // <=> - // start - end + 1 = (cap * job_load_pct) / load + // end - start + 1 = (cap * job_load_pct) / load // <=> - // start = (cap * job_load_pct) / load + end - 1 + // start = end + 1 - (cap * job_load_pct) / load // <=> - // start = (load * (end - 1) + cap * job_load_pct) / load + // start = (load * (end + 1) - cap * job_load_pct) / load unsigned load = std::min(load_pct, job_load_pct); - return (load * (end - 1) + cap * job_load_pct) / load; + return (load * (end + 1) - cap * job_load_pct) / load; } time_t theory_jobscheduler::solve_for_capacity(unsigned load_pct, unsigned job_load_pct, time_t start, time_t end) { @@ -905,23 +870,25 @@ namespace smt { * Compute last start time for job on resource r. */ bool theory_jobscheduler::lst(unsigned j, unsigned r, time_t& start) { + start = 0; job_resource const& jr = get_job_resource(j, r); vector& available = m_resources[r].m_available; unsigned j_load_pct = jr.m_loadpct; time_t cap = jr.m_capacity; for (unsigned idx = available.size(); idx-- > 0; ) { - time_t start = available[idx].m_start; + start = available[idx].m_start; time_t end = available[idx].m_end; unsigned load_pct = available[idx].m_loadpct; time_t delta = solve_for_capacity(load_pct, j_load_pct, start, end); if (delta > cap) { - start = solve_for_start(load_pct, j_load_pct, start, cap); + start = solve_for_start(load_pct, j_load_pct, end, cap); cap = 0; } else { cap -= delta; } if (cap == 0) { + std::cout << "start " << start << "\n"; return true; } } diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index 7c5520548..b83f99251 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -36,11 +36,11 @@ namespace smt { struct job_resource { unsigned m_resource_id; // id of resource - unsigned m_capacity; // amount of resource to use + time_t m_capacity; // amount of resource to use unsigned m_loadpct; // assuming loadpct time_t m_end; // must run before properties m_properties; - job_resource(unsigned r, unsigned cap, unsigned loadpct, time_t end, properties const& ps): + job_resource(unsigned r, time_t cap, unsigned loadpct, time_t end, properties const& ps): m_resource_id(r), m_capacity(cap), m_loadpct(loadpct), m_end(end), m_properties(ps) {} }; @@ -60,10 +60,11 @@ namespace smt { bool m_is_preemptable; // can job be pre-empted vector m_resources; // resources allowed to run job. u_map m_resource2index; // resource to index into vector + enode* m_job; enode* m_start; enode* m_end; enode* m_job2resource; - job_info(): m_is_preemptable(false), m_start(nullptr), m_end(nullptr), m_job2resource(nullptr) {} + job_info(): m_is_preemptable(false), m_job(nullptr), m_start(nullptr), m_end(nullptr), m_job2resource(nullptr) {} }; struct res_available { @@ -95,7 +96,6 @@ namespace smt { ast_manager& m; jobshop_util u; arith_util a; - unsigned_vector m_var2index; vector m_jobs; vector m_resources; @@ -133,6 +133,8 @@ namespace smt { void collect_statistics(::statistics & st) const override; + bool include_func_interp(func_decl* f) override; + void init_model(model_generator & m) override; model_value_proc * mk_value(enode * n, model_generator & mg) override; @@ -144,7 +146,7 @@ namespace smt { public: // set up job/resource global constraints void set_preemptable(unsigned j, bool is_preemptable); - void add_job_resource(unsigned j, unsigned r, unsigned cap, unsigned loadpct, time_t end, properties const& ps); + void add_job_resource(unsigned j, unsigned r, unsigned loadpct, time_t cap, time_t end, properties const& ps); void add_resource_available(unsigned r, unsigned max_loadpct, time_t start, time_t end, properties const& ps); void add_done(); @@ -184,6 +186,12 @@ namespace smt { bool constrain_end_time_interval(unsigned j, unsigned r); bool constrain_resource_energy(unsigned r); + void assert_last_end_time(unsigned j, unsigned r, job_resource const& jr, literal eq); + void assert_last_start_time(unsigned j, unsigned r, literal eq); + void assert_first_start_time(unsigned j, unsigned r, literal eq); + void assert_job_not_in_gap(unsigned j, unsigned r, unsigned idx, literal eq); + void assert_job_non_preemptable(unsigned j, unsigned r, unsigned idx, literal eq); + void block_job_overlap(unsigned r, uint_set const& jobs, unsigned last_job); class job_overlap { @@ -198,14 +206,16 @@ namespace smt { }; // term builders - literal mk_ge_lit(expr* e, time_t t); - expr* mk_ge(expr* e, time_t t); - expr* mk_ge(enode* e, time_t t); - literal mk_le_lit(expr* e, time_t t); - expr* mk_le(expr* e, time_t t); - expr* mk_le(enode* e, time_t t); + literal mk_ge(expr* e, time_t t); + expr* mk_ge_expr(expr* e, time_t t); + literal mk_ge(enode* e, time_t t); + literal mk_le(expr* e, time_t t); + expr* mk_le_expr(expr* e, time_t t); + literal mk_le(enode* e, time_t t); literal mk_le(enode* l, enode* r); literal mk_literal(expr* e); + literal mk_eq_lit(enode * l, enode * r) { return mk_eq_lit(l->get_owner(), r->get_owner()); } + literal mk_eq_lit(expr * l, expr * r); void internalize_cmd(expr* cmd); void unrecognized_argument(expr* arg) { invalid_argument("unrecognized argument ", arg); } From 502c07126640f7912b34c01c35cb7a06c37941ea Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Aug 2018 09:57:06 -0700 Subject: [PATCH 021/227] na Signed-off-by: Nikolaj Bjorner --- src/ast/jobshop_decl_plugin.cpp | 49 ++++++++++++++++++--------------- src/ast/jobshop_decl_plugin.h | 35 ----------------------- src/smt/theory_jobscheduler.cpp | 7 +---- src/smt/theory_jobscheduler.h | 1 - 4 files changed, 28 insertions(+), 64 deletions(-) diff --git a/src/ast/jobshop_decl_plugin.cpp b/src/ast/jobshop_decl_plugin.cpp index 79a2cf177..0eb14aad3 100644 --- a/src/ast/jobshop_decl_plugin.cpp +++ b/src/ast/jobshop_decl_plugin.cpp @@ -57,23 +57,23 @@ func_decl * jobshop_decl_plugin::mk_func_decl( case OP_JS_JOB: check_arity(arity); check_index1(num_parameters, parameters); - return m_manager->mk_func_decl(symbol("job"), 0, (sort* const*)nullptr, m_job_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + return m_manager->mk_func_decl(symbol("job"), arity, domain, m_job_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); case OP_JS_RESOURCE: check_arity(arity); check_index1(num_parameters, parameters); - return m_manager->mk_func_decl(symbol("resource"), 0, (sort* const*)nullptr, m_resource_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + return m_manager->mk_func_decl(symbol("resource"), arity, domain, m_resource_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); case OP_JS_START: - check_arity(arity); - check_index1(num_parameters, parameters); - return m_manager->mk_func_decl(symbol("job-start"), 0, (sort* const*)nullptr, m_int_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("start expects a job argument"); + if (num_parameters > 0) m_manager->raise_exception("no parameters"); + return m_manager->mk_func_decl(symbol("job-start"), arity, domain, m_int_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); case OP_JS_END: - check_arity(arity); - check_index1(num_parameters, parameters); - return m_manager->mk_func_decl(symbol("job-end"), 0, (sort* const*)nullptr, m_int_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("resource expects a job argument"); + if (num_parameters > 0) m_manager->raise_exception("no parameters"); + return m_manager->mk_func_decl(symbol("job-end"), arity, domain, m_int_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); case OP_JS_JOB2RESOURCE: - check_arity(arity); - check_index1(num_parameters, parameters); - return m_manager->mk_func_decl(symbol("job2resource"), 0, (sort* const*)nullptr, m_resource_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("job2resource expects a job argument"); + if (num_parameters > 0) m_manager->raise_exception("no parameters"); + return m_manager->mk_func_decl(symbol("job2resource"), arity, domain, m_resource_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); case OP_JS_MODEL: @@ -185,11 +185,13 @@ app* jobshop_util::mk_job(unsigned j) { } unsigned jobshop_util::job2id(expr* j) { - SASSERT(is_app_of(j, m_fid, OP_JS_JOB) || - is_app_of(j, m_fid, OP_JS_START) || + if (is_app_of(j, m_fid, OP_JS_JOB)) { + return to_app(j)->get_decl()->get_parameter(0).get_int(); + } + SASSERT(is_app_of(j, m_fid, OP_JS_START) || is_app_of(j, m_fid, OP_JS_END) || is_app_of(j, m_fid, OP_JS_JOB2RESOURCE)); - return to_app(j)->get_decl()->get_parameter(0).get_int(); + return job2id(to_app(j)->get_arg(0)); } app* jobshop_util::mk_resource(unsigned r) { @@ -203,18 +205,21 @@ unsigned jobshop_util::resource2id(expr* r) { } app* jobshop_util::mk_start(unsigned j) { - parameter p(j); - return m.mk_const(m.mk_func_decl(m_fid, OP_JS_START, 1, &p, 0, (sort*const*)nullptr, nullptr)); + app_ref job(mk_job(j), m); + sort* js = m.get_sort(job); + return m.mk_app(m.mk_func_decl(m_fid, OP_JS_START, 0, nullptr, 1, &js, nullptr), job); } - -app* jobshop_util::mk_end(unsigned j) { - parameter p(j); - return m.mk_const(m.mk_func_decl(m_fid, OP_JS_END, 1, &p, 0, (sort*const*)nullptr, nullptr)); + +app* jobshop_util::mk_end(unsigned j) { + app_ref job(mk_job(j), m); + sort* js = m.get_sort(job); + return m.mk_app(m.mk_func_decl(m_fid, OP_JS_END, 0, nullptr, 1, &js, nullptr), job); } app* jobshop_util::mk_job2resource(unsigned j) { - parameter p(j); - return m.mk_const(m.mk_func_decl(m_fid, OP_JS_JOB2RESOURCE, 1, &p, 0, (sort*const*)nullptr, nullptr)); + app_ref job(mk_job(j), m); + sort* js = m.get_sort(job); + return m.mk_app(m.mk_func_decl(m_fid, OP_JS_JOB2RESOURCE, 0, nullptr, 1, &js, nullptr), job); } bool jobshop_util::is_resource(expr* e, unsigned& r) { diff --git a/src/ast/jobshop_decl_plugin.h b/src/ast/jobshop_decl_plugin.h index f295c901f..e7751436c 100644 --- a/src/ast/jobshop_decl_plugin.h +++ b/src/ast/jobshop_decl_plugin.h @@ -140,40 +140,6 @@ public: bool is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end); bool is_set_preemptable(expr* e, expr *& job); - // alist features - app* mk_kv(symbol const& key, rational const& r) { - parameter ps[2] = { parameter(key), parameter(r) }; - return m.mk_const(m.mk_func_decl(m_fid, OP_AL_KV, 2, ps, 0, (sort*const*)nullptr, nullptr)); - } - app* mk_kv(symbol const& key, symbol const& val) { - parameter ps[2] = { parameter(key), parameter(val) }; - return m.mk_const(m.mk_func_decl(m_fid, OP_AL_KV, 2, ps, 0, (sort*const*)nullptr, nullptr)); - } - app* mk_alist(symbol const& key, unsigned n, expr* const* args) { - parameter p(key); - return m.mk_app(m.mk_func_decl(m_fid, OP_AL_LIST, 1, &p, n, args, nullptr), n, args); - - } - bool is_kv(expr* e, symbol& key, rational& r) { - return - (is_app_of(e, m_fid, OP_AL_KV) && - to_app(e)->get_decl()->get_num_parameters() == 2 && - to_app(e)->get_decl()->get_parameter(1).is_rational() && - (r = to_app(e)->get_decl()->get_parameter(1).get_rational(), key = to_app(e)->get_decl()->get_parameter(0).get_symbol(), true)) || - (is_app_of(e, m_fid, OP_AL_KV) && - to_app(e)->get_decl()->get_num_parameters() == 2 && - to_app(e)->get_decl()->get_parameter(1).is_int() && - (r = rational(to_app(e)->get_decl()->get_parameter(1).get_int()), key = to_app(e)->get_decl()->get_parameter(0).get_symbol(), true)); - - - } - bool is_kv(expr* e, symbol& key, symbol& s) { - return is_app_of(e, m_fid, OP_AL_KV) && - to_app(e)->get_decl()->get_num_parameters() == 2 && - to_app(e)->get_decl()->get_parameter(1).is_symbol() && - (s = to_app(e)->get_decl()->get_parameter(1).get_symbol(), key = to_app(e)->get_decl()->get_parameter(0).get_symbol(), true); - } - bool is_model(expr* e) const { return is_app_of(e, m_fid, OP_JS_MODEL); } bool is_alist(expr* e) const { return is_app_of(e, m_fid, OP_AL_LIST); } bool is_alist(expr* e, symbol& key) const { @@ -183,5 +149,4 @@ public: (key = to_app(e)->get_decl()->get_parameter(0).get_symbol(), true); } - // app* mk_model(unsigned n, expr* const* alist); }; diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index c138b6012..918f349cd 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -240,7 +240,7 @@ namespace smt { if (ctx.get_assignment(start_ge_lo) != l_true) { return; } - enode_pair eq(ji.m_job2resource, resource2enode(r)); + enode_pair eq(ji.m_job2resource, m_resources[r].m_resource); if (eq.first->get_root() != eq.second->get_root()) { return; } @@ -528,10 +528,6 @@ namespace smt { return 0; } - enode* theory_jobscheduler::resource2enode(unsigned r) { - return get_context().get_enode(u.mk_resource(r)); - } - void theory_jobscheduler::set_preemptable(unsigned j, bool is_preemptable) { m_jobs.reserve(j + 1); m_jobs[j].m_is_preemptable = is_preemptable; @@ -610,7 +606,6 @@ namespace smt { for (unsigned j = 0; j < m_jobs.size(); ++j) { job_info const& ji = m_jobs[j]; literal_vector disj; - app_ref job(u.mk_job(j), m); if (ji.m_resources.empty()) { throw default_exception("every job should be associated with at least one resource"); } diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index b83f99251..778d8baa8 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -161,7 +161,6 @@ namespace smt { time_t get_up(expr* e); time_t get_value(expr* e); unsigned resource(unsigned j); // resource of job j - enode* resource2enode(unsigned r); // derived bounds time_t ect(unsigned j, unsigned r, time_t start); From a478f95999788b2266134bc64015fdf3f096e1db Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Aug 2018 10:56:52 -0700 Subject: [PATCH 022/227] remove debug assert Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index e889d0233..11a15492c 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1056,7 +1056,6 @@ sort* basic_decl_plugin::join(sort* s1, sort* s2) { return s2; } std::ostringstream buffer; - SASSERT(false); buffer << "Sorts " << mk_pp(s1, *m_manager) << " and " << mk_pp(s2, *m_manager) << " are incompatible"; throw ast_exception(buffer.str()); } From 2839f64f0db6744d14875456b5f78c36e978498d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Aug 2018 11:05:55 -0700 Subject: [PATCH 023/227] rename to csp Signed-off-by: Nikolaj Bjorner --- src/ast/CMakeLists.txt | 2 +- ...op_decl_plugin.cpp => csp_decl_plugin.cpp} | 119 ++++++++++-------- ...obshop_decl_plugin.h => csp_decl_plugin.h} | 27 ++-- src/cmd_context/cmd_context.cpp | 4 +- src/smt/theory_jobscheduler.h | 4 +- 5 files changed, 79 insertions(+), 77 deletions(-) rename src/ast/{jobshop_decl_plugin.cpp => csp_decl_plugin.cpp} (66%) rename src/ast/{jobshop_decl_plugin.h => csp_decl_plugin.h} (86%) diff --git a/src/ast/CMakeLists.txt b/src/ast/CMakeLists.txt index 5340d4e7b..54e3c27e4 100644 --- a/src/ast/CMakeLists.txt +++ b/src/ast/CMakeLists.txt @@ -14,6 +14,7 @@ z3_add_component(ast ast_translation.cpp ast_util.cpp bv_decl_plugin.cpp + csp_decl_plugin.cpp datatype_decl_plugin.cpp decl_collector.cpp dl_decl_plugin.cpp @@ -30,7 +31,6 @@ z3_add_component(ast fpa_decl_plugin.cpp func_decl_dependencies.cpp has_free_vars.cpp - jobshop_decl_plugin.cpp macro_substitution.cpp num_occurs.cpp occurs.cpp diff --git a/src/ast/jobshop_decl_plugin.cpp b/src/ast/csp_decl_plugin.cpp similarity index 66% rename from src/ast/jobshop_decl_plugin.cpp rename to src/ast/csp_decl_plugin.cpp index 0eb14aad3..395677a4c 100644 --- a/src/ast/jobshop_decl_plugin.cpp +++ b/src/ast/csp_decl_plugin.cpp @@ -3,7 +3,7 @@ Copyright (c) 2018 Microsoft Corporation Module Name: - jobshop_decl_plugin.h + csp_decl_plugin.h Abstract: @@ -17,10 +17,10 @@ Revision History: --*/ -#include "ast/jobshop_decl_plugin.h" +#include "ast/csp_decl_plugin.h" #include "ast/arith_decl_plugin.h" -void jobshop_decl_plugin::set_manager(ast_manager* m, family_id fid) { +void csp_decl_plugin::set_manager(ast_manager* m, family_id fid) { decl_plugin::set_manager(m, fid); m_int_sort = m_manager->mk_sort(m_manager->mk_family_id("arith"), INT_SORT); m_alist_sort = m_manager->mk_sort(symbol("AList"), sort_info(m_family_id, ALIST_SORT)); @@ -32,14 +32,14 @@ void jobshop_decl_plugin::set_manager(ast_manager* m, family_id fid) { m_manager->inc_ref(m_alist_sort); } -void jobshop_decl_plugin::finalize() { +void csp_decl_plugin::finalize() { m_manager->dec_ref(m_alist_sort); m_manager->dec_ref(m_job_sort); m_manager->dec_ref(m_resource_sort); m_manager->dec_ref(m_int_sort); } -sort * jobshop_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { +sort * csp_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { if (num_parameters != 0) { m_manager->raise_exception("no parameters expected with job-shop sort"); } @@ -51,43 +51,47 @@ sort * jobshop_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parame } } -func_decl * jobshop_decl_plugin::mk_func_decl( +func_decl * csp_decl_plugin::mk_func_decl( decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort *) { + symbol name; + sort* rng = nullptr; switch (static_cast(k)) { case OP_JS_JOB: check_arity(arity); check_index1(num_parameters, parameters); - return m_manager->mk_func_decl(symbol("job"), arity, domain, m_job_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + name = symbol("job"); + rng = m_job_sort; + break; case OP_JS_RESOURCE: check_arity(arity); check_index1(num_parameters, parameters); - return m_manager->mk_func_decl(symbol("resource"), arity, domain, m_resource_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + name = symbol("resource"); + rng = m_resource_sort; + break; case OP_JS_START: if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("start expects a job argument"); if (num_parameters > 0) m_manager->raise_exception("no parameters"); - return m_manager->mk_func_decl(symbol("job-start"), arity, domain, m_int_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + name = symbol("job-start"); + rng = m_int_sort; + break; case OP_JS_END: if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("resource expects a job argument"); if (num_parameters > 0) m_manager->raise_exception("no parameters"); - return m_manager->mk_func_decl(symbol("job-end"), arity, domain, m_int_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + name = symbol("job-end"); + rng = m_int_sort; + break; case OP_JS_JOB2RESOURCE: if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("job2resource expects a job argument"); if (num_parameters > 0) m_manager->raise_exception("no parameters"); - return m_manager->mk_func_decl(symbol("job2resource"), arity, domain, m_resource_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); - - + name = symbol("job2resource"); + rng = m_resource_sort; + break; case OP_JS_MODEL: // has no parameters // all arguments are of sort alist - return m_manager->mk_func_decl(symbol("js-model"), arity, domain, m_manager->mk_bool_sort(), func_decl_info(m_family_id, k, num_parameters, parameters)); - case OP_AL_KV: - // has two parameters, first is symbol - // has no arguments - return m_manager->mk_func_decl(symbol("kv"), arity, domain, m_alist_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); - case OP_AL_LIST: - // has no parameters - // all arguments are of sort alist - return m_manager->mk_func_decl(symbol("alist"), arity, domain, m_alist_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + name = symbol("js-model"); + rng = m_manager->mk_bool_sort(); + break; case OP_JS_JOB_RESOURCE: if (arity != 5) m_manager->raise_exception("add-job-resource expects 5 arguments"); if (domain[0] != m_job_sort) m_manager->raise_exception("first argument of add-job-resource expects should be a job"); @@ -95,43 +99,52 @@ func_decl * jobshop_decl_plugin::mk_func_decl( if (domain[2] != m_int_sort) m_manager->raise_exception("3rd argument of add-job-resource expects should be an integer"); if (domain[3] != m_int_sort) m_manager->raise_exception("4th argument of add-job-resource expects should be an integer"); if (domain[4] != m_int_sort) m_manager->raise_exception("5th argument of add-job-resource expects should be an integer"); - return m_manager->mk_func_decl(symbol("add-job-resource"), arity, domain, m_alist_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + name = symbol("add-job-resource"); + rng = m_alist_sort; + break; case OP_JS_RESOURCE_AVAILABLE: if (arity != 4) m_manager->raise_exception("add-resource-available expects 4 arguments"); if (domain[0] != m_resource_sort) m_manager->raise_exception("first argument of add-resource-available expects should be a resource"); if (domain[1] != m_int_sort) m_manager->raise_exception("2nd argument of add-resource-available expects should be an integer"); if (domain[2] != m_int_sort) m_manager->raise_exception("3rd argument of add-resource-available expects should be an integer"); if (domain[3] != m_int_sort) m_manager->raise_exception("4th argument of add-resource-available expects should be an integer"); - return m_manager->mk_func_decl(symbol("add-resource-available"), arity, domain, m_alist_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + name = symbol("add-resource-available"); + rng = m_alist_sort; + break; case OP_JS_JOB_PREEMPTABLE: if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("set-preemptable expects one argument, which is a job"); - return m_manager->mk_func_decl(symbol("set-preemptable"), arity, domain, m_alist_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); + name = symbol("set-preemptable"); + rng = m_alist_sort; + break; default: - UNREACHABLE(); return nullptr; + UNREACHABLE(); + return nullptr; } + return m_manager->mk_func_decl(name, arity, domain, rng, func_decl_info(m_family_id, k, num_parameters, parameters)); + } -void jobshop_decl_plugin::check_arity(unsigned arity) { +void csp_decl_plugin::check_arity(unsigned arity) { if (arity > 0) - m_manager->raise_exception("jobshop variables use parameters only and take no arguments"); + m_manager->raise_exception("csp variables use parameters only and take no arguments"); } -void jobshop_decl_plugin::check_index1(unsigned num_parameters, parameter const* ps) { +void csp_decl_plugin::check_index1(unsigned num_parameters, parameter const* ps) { if (num_parameters != 1 || !ps[0].is_int()) - m_manager->raise_exception("jobshop variable expects a single integer parameter"); + m_manager->raise_exception("csp variable expects a single integer parameter"); } -void jobshop_decl_plugin::check_index2(unsigned num_parameters, parameter const* ps) { +void csp_decl_plugin::check_index2(unsigned num_parameters, parameter const* ps) { if (num_parameters != 2 || !ps[0].is_int() || !ps[1].is_int()) - m_manager->raise_exception("jobshop variable expects two integer parameters"); + m_manager->raise_exception("csp variable expects two integer parameters"); } -bool jobshop_decl_plugin::is_value(app * e) const { +bool csp_decl_plugin::is_value(app * e) const { return is_app_of(e, m_family_id, OP_JS_JOB) || is_app_of(e, m_family_id, OP_JS_RESOURCE); } -void jobshop_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { +void csp_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { if (logic == symbol("CSP")) { op_names.push_back(builtin_name("job", OP_JS_JOB)); op_names.push_back(builtin_name("resource", OP_JS_RESOURCE)); @@ -139,8 +152,6 @@ void jobshop_decl_plugin::get_op_names(svector & op_names, symbol op_names.push_back(builtin_name("job-end", OP_JS_END)); op_names.push_back(builtin_name("job2resource", OP_JS_JOB2RESOURCE)); op_names.push_back(builtin_name("js-model", OP_JS_MODEL)); - op_names.push_back(builtin_name("kv", OP_AL_KV)); - op_names.push_back(builtin_name("alist", OP_AL_LIST)); op_names.push_back(builtin_name("add-job-resource", OP_JS_JOB_RESOURCE)); op_names.push_back(builtin_name("add-resource-available", OP_JS_RESOURCE_AVAILABLE)); op_names.push_back(builtin_name("set-preemptable", OP_JS_JOB_PREEMPTABLE)); @@ -148,14 +159,14 @@ void jobshop_decl_plugin::get_op_names(svector & op_names, symbol } } -void jobshop_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { +void csp_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { if (logic == symbol("CSP")) { sort_names.push_back(builtin_name("Job", JOB_SORT)); sort_names.push_back(builtin_name("Resource", RESOURCE_SORT)); } } -expr * jobshop_decl_plugin::get_some_value(sort * s) { +expr * csp_decl_plugin::get_some_value(sort * s) { parameter p(0); if (is_sort_of(s, m_family_id, JOB_SORT)) return m_manager->mk_const(mk_func_decl(OP_JS_JOB, 1, &p, 0, nullptr, nullptr)); @@ -166,25 +177,25 @@ expr * jobshop_decl_plugin::get_some_value(sort * s) { } -jobshop_util::jobshop_util(ast_manager& m): m(m) { +csp_util::csp_util(ast_manager& m): m(m) { m_fid = m.mk_family_id("csp"); - m_plugin = static_cast(m.get_plugin(m_fid)); + m_plugin = static_cast(m.get_plugin(m_fid)); } -sort* jobshop_util::mk_job_sort() { +sort* csp_util::mk_job_sort() { return m_plugin->mk_job_sort(); } -sort* jobshop_util::mk_resource_sort() { +sort* csp_util::mk_resource_sort() { return m_plugin->mk_resource_sort(); } -app* jobshop_util::mk_job(unsigned j) { +app* csp_util::mk_job(unsigned j) { parameter p(j); return m.mk_const(m.mk_func_decl(m_fid, OP_JS_JOB, 1, &p, 0, (sort*const*)nullptr, nullptr)); } -unsigned jobshop_util::job2id(expr* j) { +unsigned csp_util::job2id(expr* j) { if (is_app_of(j, m_fid, OP_JS_JOB)) { return to_app(j)->get_decl()->get_parameter(0).get_int(); } @@ -194,43 +205,43 @@ unsigned jobshop_util::job2id(expr* j) { return job2id(to_app(j)->get_arg(0)); } -app* jobshop_util::mk_resource(unsigned r) { +app* csp_util::mk_resource(unsigned r) { parameter p(r); return m.mk_const(m.mk_func_decl(m_fid, OP_JS_RESOURCE, 1, &p, 0, (sort*const*)nullptr, nullptr)); } -unsigned jobshop_util::resource2id(expr* r) { +unsigned csp_util::resource2id(expr* r) { SASSERT(is_app_of(r, m_fid, OP_JS_RESOURCE)); return to_app(r)->get_decl()->get_parameter(0).get_int(); } -app* jobshop_util::mk_start(unsigned j) { +app* csp_util::mk_start(unsigned j) { app_ref job(mk_job(j), m); sort* js = m.get_sort(job); return m.mk_app(m.mk_func_decl(m_fid, OP_JS_START, 0, nullptr, 1, &js, nullptr), job); } -app* jobshop_util::mk_end(unsigned j) { +app* csp_util::mk_end(unsigned j) { app_ref job(mk_job(j), m); sort* js = m.get_sort(job); return m.mk_app(m.mk_func_decl(m_fid, OP_JS_END, 0, nullptr, 1, &js, nullptr), job); } -app* jobshop_util::mk_job2resource(unsigned j) { +app* csp_util::mk_job2resource(unsigned j) { app_ref job(mk_job(j), m); sort* js = m.get_sort(job); return m.mk_app(m.mk_func_decl(m_fid, OP_JS_JOB2RESOURCE, 0, nullptr, 1, &js, nullptr), job); } -bool jobshop_util::is_resource(expr* e, unsigned& r) { +bool csp_util::is_resource(expr* e, unsigned& r) { return is_app_of(e, m_fid, OP_JS_RESOURCE) && (r = resource2id(e), true); } -bool jobshop_util::is_job(expr* e, unsigned& j) { +bool csp_util::is_job(expr* e, unsigned& j) { return is_app_of(e, m_fid, OP_JS_JOB) && (j = job2id(e), true); } -bool jobshop_util::is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, uint64_t& start, uint64_t& end) { +bool csp_util::is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, uint64_t& start, uint64_t& end) { if (!is_app_of(e, m_fid, OP_JS_RESOURCE_AVAILABLE)) return false; res = to_app(e)->get_arg(0); arith_util a(m); @@ -244,7 +255,7 @@ bool jobshop_util::is_add_resource_available(expr * e, expr *& res, unsigned& lo return true; } -bool jobshop_util::is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end) { +bool csp_util::is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end) { if (!is_app_of(e, m_fid, OP_JS_JOB_RESOURCE)) return false; job = to_app(e)->get_arg(0); res = to_app(e)->get_arg(1); @@ -259,7 +270,7 @@ bool jobshop_util::is_add_job_resource(expr * e, expr *& job, expr*& res, unsign return true; } -bool jobshop_util::is_set_preemptable(expr* e, expr *& job) { +bool csp_util::is_set_preemptable(expr* e, expr *& job) { if (!is_app_of(e, m_fid, OP_JS_JOB_PREEMPTABLE)) return false; job = to_app(e)->get_arg(0); return true; diff --git a/src/ast/jobshop_decl_plugin.h b/src/ast/csp_decl_plugin.h similarity index 86% rename from src/ast/jobshop_decl_plugin.h rename to src/ast/csp_decl_plugin.h index e7751436c..5443180a4 100644 --- a/src/ast/jobshop_decl_plugin.h +++ b/src/ast/csp_decl_plugin.h @@ -3,7 +3,7 @@ Copyright (c) 2018 Microsoft Corporation Module Name: - jobshop_decl_plugin.h + csp_decl_plugin.h Abstract: @@ -81,18 +81,16 @@ enum js_op_kind { OP_JS_MODEL, // jobscheduler model OP_JS_JOB_RESOURCE, OP_JS_JOB_PREEMPTABLE, - OP_JS_RESOURCE_AVAILABLE, - OP_AL_KV, // key-value pair - OP_AL_LIST // tagged list + OP_JS_RESOURCE_AVAILABLE }; -class jobshop_decl_plugin : public decl_plugin { +class csp_decl_plugin : public decl_plugin { public: - jobshop_decl_plugin() {} - ~jobshop_decl_plugin() override {} + csp_decl_plugin() {} + ~csp_decl_plugin() override {} void finalize() override; void set_manager(ast_manager* m, family_id fid) override; - decl_plugin * mk_fresh() override { return alloc(jobshop_decl_plugin); } + decl_plugin * mk_fresh() override { return alloc(csp_decl_plugin); } sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) override; @@ -115,12 +113,12 @@ private: void check_index2(unsigned n, parameter const* ps); }; -class jobshop_util { +class csp_util { ast_manager& m; family_id m_fid; - jobshop_decl_plugin* m_plugin; + csp_decl_plugin* m_plugin; public: - jobshop_util(ast_manager& m); + csp_util(ast_manager& m); sort* mk_job_sort(); sort* mk_resource_sort(); @@ -141,12 +139,5 @@ public: bool is_set_preemptable(expr* e, expr *& job); bool is_model(expr* e) const { return is_app_of(e, m_fid, OP_JS_MODEL); } - bool is_alist(expr* e) const { return is_app_of(e, m_fid, OP_AL_LIST); } - bool is_alist(expr* e, symbol& key) const { - return is_alist(e) && - to_app(e)->get_decl()->get_num_parameters() == 1 && - to_app(e)->get_decl()->get_parameter(0).is_symbol() && - (key = to_app(e)->get_decl()->get_parameter(0).get_symbol(), true); - } }; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 8387722b9..da495968a 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -30,7 +30,7 @@ Notes: #include "ast/seq_decl_plugin.h" #include "ast/pb_decl_plugin.h" #include "ast/fpa_decl_plugin.h" -#include "ast/jobshop_decl_plugin.h" +#include "ast/csp_decl_plugin.h" #include "ast/ast_pp.h" #include "ast/rewriter/var_subst.h" #include "ast/pp.h" @@ -696,7 +696,7 @@ void cmd_context::init_manager_core(bool new_manager) { register_plugin(symbol("pb"), alloc(pb_decl_plugin), logic_has_pb()); register_plugin(symbol("fpa"), alloc(fpa_decl_plugin), logic_has_fpa()); register_plugin(symbol("datalog_relation"), alloc(datalog::dl_decl_plugin), !has_logic()); - register_plugin(symbol("csp"), alloc(jobshop_decl_plugin), smt_logics::logic_is_csp(m_logic)); + register_plugin(symbol("csp"), alloc(csp_decl_plugin), smt_logics::logic_is_csp(m_logic)); } else { // the manager was created by an external module diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index 778d8baa8..9031f9e78 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -21,7 +21,7 @@ Revision History: #pragma once; #include "util/uint_set.h" -#include "ast/jobshop_decl_plugin.h" +#include "ast/csp_decl_plugin.h" #include "ast/arith_decl_plugin.h" #include "smt/smt_theory.h" @@ -94,7 +94,7 @@ namespace smt { }; ast_manager& m; - jobshop_util u; + csp_util u; arith_util a; vector m_jobs; vector m_resources; From 40a79694ea8a80076b73a30cb2be865375d2a0b2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Aug 2018 16:33:34 -0700 Subject: [PATCH 024/227] add job/resource axioms on demand Signed-off-by: Nikolaj Bjorner --- src/ast/csp_decl_plugin.cpp | 4 + src/ast/csp_decl_plugin.h | 1 + src/smt/theory_jobscheduler.cpp | 170 +++++++++++++++++++++----------- src/smt/theory_jobscheduler.h | 16 ++- 4 files changed, 133 insertions(+), 58 deletions(-) diff --git a/src/ast/csp_decl_plugin.cpp b/src/ast/csp_decl_plugin.cpp index 395677a4c..cfe67fd2d 100644 --- a/src/ast/csp_decl_plugin.cpp +++ b/src/ast/csp_decl_plugin.cpp @@ -241,6 +241,10 @@ bool csp_util::is_job(expr* e, unsigned& j) { return is_app_of(e, m_fid, OP_JS_JOB) && (j = job2id(e), true); } +bool csp_util::is_job2resource(expr* e, unsigned& j) { + return is_app_of(e, m_fid, OP_JS_JOB2RESOURCE) && (j = job2id(e), true); +} + bool csp_util::is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, uint64_t& start, uint64_t& end) { if (!is_app_of(e, m_fid, OP_JS_RESOURCE_AVAILABLE)) return false; res = to_app(e)->get_arg(0); diff --git a/src/ast/csp_decl_plugin.h b/src/ast/csp_decl_plugin.h index 5443180a4..b450f1fc2 100644 --- a/src/ast/csp_decl_plugin.h +++ b/src/ast/csp_decl_plugin.h @@ -124,6 +124,7 @@ public: app* mk_job(unsigned j); bool is_job(expr* e, unsigned& j); + bool is_job2resource(expr* e, unsigned& j); unsigned job2id(expr* j); app* mk_resource(unsigned r); diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index 918f349cd..a415212c3 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -114,15 +114,57 @@ namespace smt { throw default_exception(strm.str()); } + void theory_jobscheduler::new_eq_eh(theory_var v1, theory_var v2) { + enode* e1 = get_enode(v1); + enode* e2 = get_enode(v2); + enode* root = e1->get_root(); + unsigned r; + if (u.is_resource(root->get_owner(), r)) { + enode* next = e1; + do { + unsigned j; + if (u.is_job2resource(next->get_owner(), j) && !m_jobs[j].m_is_bound) { + m_bound_jobs.push_back(j); + m_jobs[j].m_is_bound = true; + } + next = next->get_next(); + } + while (e1 != next); + } + } + + + void theory_jobscheduler::new_diseq_eh(theory_var v1, theory_var v2) { + + } + void theory_jobscheduler::push_scope_eh() { + scope s; + s.m_bound_jobs_lim = m_bound_jobs.size(); + s.m_bound_qhead = m_bound_qhead; + m_scopes.push_back(s); } void theory_jobscheduler::pop_scope_eh(unsigned num_scopes) { + unsigned new_lvl = m_scopes.size() - num_scopes; + scope const& s = m_scopes[new_lvl]; + for (unsigned i = s.m_bound_jobs_lim; i < m_bound_jobs.size(); ++i) { + unsigned j = m_bound_jobs[i]; + m_jobs[j].m_is_bound = false; + } + m_bound_jobs.shrink(s.m_bound_jobs_lim); + m_bound_qhead = s.m_bound_qhead; + m_scopes.shrink(new_lvl); } final_check_status theory_jobscheduler::final_check_eh() { TRACE("csp", tout << "\n";); bool blocked = false; + for (unsigned j = 0; j < m_jobs.size(); ++j) { + if (split_job2resource(j)) { + return FC_CONTINUE; + } + } for (unsigned r = 0; r < m_resources.size(); ++r) { if (constrain_resource_energy(r)) { blocked = true; @@ -139,7 +181,7 @@ namespace smt { } bool theory_jobscheduler::can_propagate() { - return false; + return m_bound_qhead < m_bound_jobs.size(); } literal theory_jobscheduler::mk_literal(expr * e) { @@ -387,19 +429,40 @@ namespace smt { } void theory_jobscheduler::propagate() { - return; - for (unsigned j = 0; j < m_jobs.size(); ++j) { + while (m_bound_qhead < m_bound_jobs.size()) { + unsigned j = m_bound_jobs[m_bound_qhead++]; + unsigned r = 0; job_info const& ji = m_jobs[j]; - unsigned r = resource(j); - propagate_end_time(j, r); + VERIFY(u.is_resource(ji.m_job2resource->get_root()->get_owner(), r)); + TRACE("csp", tout << "job: " << j << " resource: " << r << "\n";); + propagate_job2resource(j, r); } - for (unsigned r = 0; r < m_resources.size(); ++r) { - // TBD: check energy constraints on resources. + } + + void theory_jobscheduler::propagate_job2resource(unsigned j, unsigned r) { + job_info const& ji = m_jobs[j]; + res_info const& ri = m_resources[r]; + job_resource const& jr = get_job_resource(j, r); + literal eq = mk_eq_lit(ji.m_job2resource, ri.m_resource); + assert_last_end_time(j, r, jr, eq); + assert_last_start_time(j, r, eq); + assert_first_start_time(j, r, eq); + vector const& available = ri.m_available; + for (unsigned i = 0; i + 1 < available.size(); ++i) { + SASSERT(available[i].m_end < available[i + 1].m_start); + assert_job_not_in_gap(j, r, i, eq); + if (!ji.m_is_preemptable && available[i].m_end + 1 < available[i+1].m_start) { + assert_job_non_preemptable(j, r, i, eq); + } } } theory_jobscheduler::theory_jobscheduler(ast_manager& m): - theory(m.get_family_id("csp")), m(m), u(m), a(m) { + theory(m.get_family_id("csp")), + m(m), + u(m), + a(m), + m_bound_qhead(0) { } std::ostream& theory_jobscheduler::display(std::ostream & out, job_resource const& jr) const { @@ -593,8 +656,7 @@ namespace smt { context & ctx = get_context(); // sort availability intervals - for (unsigned r = 0; r < m_resources.size(); ++r) { - res_info& ri = m_resources[r]; + for (res_info& ri : m_resources) { vector& available = ri.m_available; res_available::compare cmp; std::sort(available.begin(), available.end(), cmp); @@ -603,9 +665,7 @@ namespace smt { expr_ref fml(m); literal lit, l1, l2, l3; - for (unsigned j = 0; j < m_jobs.size(); ++j) { - job_info const& ji = m_jobs[j]; - literal_vector disj; + for (job_info const& ji : m_jobs) { if (ji.m_resources.empty()) { throw default_exception("every job should be associated with at least one resource"); } @@ -617,21 +677,15 @@ namespace smt { time_t start_lb = std::numeric_limits::max(); time_t end_ub = 0; for (job_resource const& jr : ji.m_resources) { - // resource(j) = r => end(j) <= end(j, r) - // resource(j) = r => start(j) <= lst(j, r, end(j, r)) unsigned r = jr.m_resource_id; res_info const& ri = m_resources[r]; - enode* j2r = m_jobs[j].m_job2resource; - literal eq = mk_eq_lit(j2r, ri.m_resource); - assert_last_end_time(j, r, jr, eq); - assert_last_start_time(j, r, eq); - disj.push_back(eq); + // literal eq = mk_eq_lit(ji.m_job2resource, ri.m_resource); + // disj.push_back(eq); start_lb = std::min(start_lb, ri.m_available[0].m_start); - end_ub = std::max(end_ub, ri.m_available.back().m_end); - + end_ub = std::max(end_ub, ri.m_available.back().m_end); } // resource(j) = r1 || ... || resource(j) = r_n - ctx.mk_th_axiom(get_id(), disj.size(), disj.c_ptr()); + // ctx.mk_th_axiom(get_id(), disj.size(), disj.c_ptr()); // start(j) >= start_lb lit = mk_ge(ji.m_start, start_lb); @@ -641,44 +695,18 @@ namespace smt { lit = mk_le(ji.m_end, end_ub); ctx.mk_th_axiom(get_id(), 1, &lit); } - for (unsigned r = 0; r < m_resources.size(); ++r) { - res_info& ri = m_resources[r]; - vector& available = ri.m_available; - if (available.empty()) continue; - enode* res = m_resources[r].m_resource; - for (unsigned j : ri.m_jobs) { - // resource(j) == r => start(j) >= available[0].m_start; - enode* j2r = m_jobs[j].m_job2resource; - assert_first_start_time(j, r, mk_eq_lit(j2r, res)); - } - for (unsigned i = 0; i + 1 < available.size(); ++i) { - if (available[i].m_end > available[i + 1].m_start) { - throw default_exception("availability intervals should be disjoint"); - } - for (unsigned j : ri.m_jobs) { - // jobs start within an interval. - // resource(j) == r => start(j) <= available[i].m_end || start(j) >= available[i + 1].m_start; - enode* j2r = m_jobs[j].m_job2resource; - literal eq = mk_eq_lit(j2r, res); - assert_job_not_in_gap(j, r, i, eq); - - // if job is not pre-emptable, start and end have to align within contiguous interval. - // resource(j) == r => end(j) <= available[i].m_end || start(j) >= available[i + 1].m_start - if (!m_jobs[j].m_is_preemptable && available[i].m_end + 1 < available[i+1].m_start) { - assert_job_non_preemptable(j, r, i, eq); - } - } - } - } + TRACE("csp", tout << "add-done end\n";); } + // resource(j) = r => end(j) <= end(j, r) void theory_jobscheduler::assert_last_end_time(unsigned j, unsigned r, job_resource const& jr, literal eq) { job_info const& ji = m_jobs[j]; literal l2 = mk_le(ji.m_end, jr.m_end); get_context().mk_th_axiom(get_id(), ~eq, l2); } + // resource(j) = r => start(j) <= lst(j, r, end(j, r)) void theory_jobscheduler::assert_last_start_time(unsigned j, unsigned r, literal eq) { context& ctx = get_context(); time_t t; @@ -691,12 +719,14 @@ namespace smt { } } + // resource(j) = r => start(j) >= avaialble[0].m_start void theory_jobscheduler::assert_first_start_time(unsigned j, unsigned r, literal eq) { vector& available = m_resources[r].m_available; literal l2 = mk_ge(m_jobs[j].m_start, available[0].m_start); get_context().mk_th_axiom(get_id(), ~eq, l2); } + // resource(j) = r => start[idx] <= end(j) || start(j) <= start[idx+1]; void theory_jobscheduler::assert_job_not_in_gap(unsigned j, unsigned r, unsigned idx, literal eq) { vector& available = m_resources[r].m_available; literal l2 = mk_ge(m_jobs[j].m_start, available[idx + 1].m_start); @@ -704,14 +734,45 @@ namespace smt { get_context().mk_th_axiom(get_id(), ~eq, l2, l3); } + // resource(j) = r => end(j) <= end[idx] || start(j) >= start[idx+1]; void theory_jobscheduler::assert_job_non_preemptable(unsigned j, unsigned r, unsigned idx, literal eq) { vector& available = m_resources[r].m_available; literal l2 = mk_le(m_jobs[j].m_end, available[idx].m_end); literal l3 = mk_ge(m_jobs[j].m_start, available[idx + 1].m_start); get_context().mk_th_axiom(get_id(), ~eq, l2, l3); - } + } - + bool theory_jobscheduler::split_job2resource(unsigned j) { + job_info const& ji = m_jobs[j]; + context& ctx = get_context(); + if (ji.m_is_bound) return false; + auto const& jrs = ji.m_resources; + for (job_resource const& jr : jrs) { + unsigned r = jr.m_resource_id; + res_info const& ri = m_resources[r]; + enode* e1 = ji.m_job2resource; + enode* e2 = ri.m_resource; + if (ctx.is_diseq(e1, e2)) + continue; + literal eq = mk_eq_lit(e1, e2); + if (ctx.get_assignment(eq) != l_false) { + ctx.mark_as_relevant(eq); + if (assume_eq(e1, e2)) { + return true; + } + } + } + literal_vector lits; + for (job_resource const& jr : jrs) { + unsigned r = jr.m_resource_id; + res_info const& ri = m_resources[r]; + enode* e1 = ji.m_job2resource; + enode* e2 = ri.m_resource; + lits.push_back(mk_eq_lit(e1, e2)); + } + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + return true; + } /** * check that each job is run on some resource according to @@ -883,7 +944,6 @@ namespace smt { cap -= delta; } if (cap == 0) { - std::cout << "start " << start << "\n"; return true; } } diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index 9031f9e78..43f55f35a 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -64,7 +64,8 @@ namespace smt { enode* m_start; enode* m_end; enode* m_job2resource; - job_info(): m_is_preemptable(false), m_job(nullptr), m_start(nullptr), m_end(nullptr), m_job2resource(nullptr) {} + bool m_is_bound; + job_info(): m_is_preemptable(false), m_job(nullptr), m_start(nullptr), m_end(nullptr), m_job2resource(nullptr), m_is_bound(false) {} }; struct res_available { @@ -98,6 +99,13 @@ namespace smt { arith_util a; vector m_jobs; vector m_resources; + unsigned_vector m_bound_jobs; + unsigned m_bound_qhead; + struct scope { + unsigned m_bound_jobs_lim; + unsigned m_bound_qhead; + }; + svector m_scopes; protected: @@ -109,9 +117,9 @@ namespace smt { void assign_eh(bool_var v, bool is_true) override {} - void new_eq_eh(theory_var v1, theory_var v2) override {} + void new_eq_eh(theory_var v1, theory_var v2) override; - void new_diseq_eh(theory_var v1, theory_var v2) override {} + void new_diseq_eh(theory_var v1, theory_var v2) override; void push_scope_eh() override; @@ -180,10 +188,12 @@ namespace smt { // propagation void propagate_end_time(unsigned j, unsigned r); void propagate_resource_energy(unsigned r); + void propagate_job2resource(unsigned j, unsigned r); // final check constraints bool constrain_end_time_interval(unsigned j, unsigned r); bool constrain_resource_energy(unsigned r); + bool split_job2resource(unsigned j); void assert_last_end_time(unsigned j, unsigned r, job_resource const& jr, literal eq); void assert_last_start_time(unsigned j, unsigned r, literal eq); From d67bfd78b971066f8052c458a3fabf7cf59224c3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Aug 2018 21:15:55 -0700 Subject: [PATCH 025/227] na Signed-off-by: Nikolaj Bjorner --- src/ast/csp_decl_plugin.cpp | 16 ++++++++++++++++ src/ast/csp_decl_plugin.h | 26 ++++++++++++++------------ src/smt/theory_jobscheduler.cpp | 9 +++++++-- src/smt/theory_jobscheduler.h | 3 ++- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/ast/csp_decl_plugin.cpp b/src/ast/csp_decl_plugin.cpp index cfe67fd2d..a6255d676 100644 --- a/src/ast/csp_decl_plugin.cpp +++ b/src/ast/csp_decl_plugin.cpp @@ -68,6 +68,11 @@ func_decl * csp_decl_plugin::mk_func_decl( name = symbol("resource"); rng = m_resource_sort; break; + case OP_JS_RESOURCE_MAKESPAN: + if (arity != 1 || domain[0] != m_resource_sort) m_manager->raise_exception("makespan expects a resource argument"); + name = symbol("makespan"); + rng = m_int_sort; + break; case OP_JS_START: if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("start expects a job argument"); if (num_parameters > 0) m_manager->raise_exception("no parameters"); @@ -148,6 +153,7 @@ void csp_decl_plugin::get_op_names(svector & op_names, symbol cons if (logic == symbol("CSP")) { op_names.push_back(builtin_name("job", OP_JS_JOB)); op_names.push_back(builtin_name("resource", OP_JS_RESOURCE)); + op_names.push_back(builtin_name("makespan", OP_JS_RESOURCE_MAKESPAN)); op_names.push_back(builtin_name("job-start", OP_JS_START)); op_names.push_back(builtin_name("job-end", OP_JS_END)); op_names.push_back(builtin_name("job2resource", OP_JS_JOB2RESOURCE)); @@ -233,10 +239,20 @@ app* csp_util::mk_job2resource(unsigned j) { return m.mk_app(m.mk_func_decl(m_fid, OP_JS_JOB2RESOURCE, 0, nullptr, 1, &js, nullptr), job); } +app* csp_util::mk_makespan(unsigned r) { + app_ref resource(mk_resource(r), m); + sort* rs = m.get_sort(resource); + return m.mk_app(m.mk_func_decl(m_fid, OP_JS_RESOURCE_MAKESPAN, 0, nullptr, 1, &rs, nullptr), resource); +} + bool csp_util::is_resource(expr* e, unsigned& r) { return is_app_of(e, m_fid, OP_JS_RESOURCE) && (r = resource2id(e), true); } +bool csp_util::is_makespan(expr * e, unsigned& r) { + return is_app_of(e, m_fid, OP_JS_RESOURCE_MAKESPAN) && is_resource(to_app(e)->get_arg(0), r); +} + bool csp_util::is_job(expr* e, unsigned& j) { return is_app_of(e, m_fid, OP_JS_JOB) && (j = job2id(e), true); } diff --git a/src/ast/csp_decl_plugin.h b/src/ast/csp_decl_plugin.h index b450f1fc2..faaaf344c 100644 --- a/src/ast/csp_decl_plugin.h +++ b/src/ast/csp_decl_plugin.h @@ -75,13 +75,14 @@ enum js_sort_kind { enum js_op_kind { OP_JS_JOB, // value of type job OP_JS_RESOURCE, // value of type resource + OP_JS_RESOURCE_MAKESPAN, // makespan of resource: the minimal resource time required for assigned jobs. OP_JS_START, // start time of a job OP_JS_END, // end time of a job OP_JS_JOB2RESOURCE, // resource associated with job OP_JS_MODEL, // jobscheduler model - OP_JS_JOB_RESOURCE, - OP_JS_JOB_PREEMPTABLE, - OP_JS_RESOURCE_AVAILABLE + OP_JS_JOB_RESOURCE, // model declaration for job assignment to resource + OP_JS_JOB_PREEMPTABLE, // model declaration for whether job is pre-emptable + OP_JS_RESOURCE_AVAILABLE // model declaration for availability intervals of resource }; class csp_decl_plugin : public decl_plugin { @@ -116,29 +117,30 @@ private: class csp_util { ast_manager& m; family_id m_fid; - csp_decl_plugin* m_plugin; + csp_decl_plugin* m_plugin; public: csp_util(ast_manager& m); sort* mk_job_sort(); sort* mk_resource_sort(); app* mk_job(unsigned j); - bool is_job(expr* e, unsigned& j); - bool is_job2resource(expr* e, unsigned& j); - unsigned job2id(expr* j); - app* mk_resource(unsigned r); - bool is_resource(expr* e, unsigned& r); - unsigned resource2id(expr* r); - app* mk_start(unsigned j); app* mk_end(unsigned j); app* mk_job2resource(unsigned j); + app* mk_makespan(unsigned r); + bool is_job(expr* e, unsigned& j); + bool is_job2resource(expr* e, unsigned& j); + bool is_resource(expr* e, unsigned& r); + bool is_makespan(expr* e, unsigned& r); bool is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, uint64_t& start, uint64_t& end); bool is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end); bool is_set_preemptable(expr* e, expr *& job); - bool is_model(expr* e) const { return is_app_of(e, m_fid, OP_JS_MODEL); } +private: + unsigned job2id(expr* j); + unsigned resource2id(expr* r); + }; diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index a415212c3..ce1b2a82b 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -37,6 +37,7 @@ Features: - try optimization based on arithmetic solver. - earliest start, latest start - constraint level + - add constraints gradually - resource groups - resource groups like a resource - resources bound to resource groups within time intervals @@ -638,6 +639,9 @@ namespace smt { app_ref res(u.mk_resource(r), m); if (!ctx.e_internalized(res)) ctx.internalize(res, false); ri.m_resource = ctx.get_enode(res); + app_ref ms(u.mk_makespan(r), m); + if (!ctx.e_internalized(ms)) ctx.internalize(ms, false); + ri.m_makespan = ctx.get_enode(ms); } ri.m_available.push_back(res_available(max_loadpct, start, end, ps)); } @@ -823,18 +827,19 @@ namespace smt { vector& available = m_resources[r].m_available; unsigned lo = 0, hi = available.size(), mid = hi / 2; while (lo < hi) { + SASSERT(lo <= mid && mid < hi); res_available const& ra = available[mid]; if (ra.m_start <= t && t <= ra.m_end) { idx = mid; return true; } else if (ra.m_start > t && mid > 0) { - hi = mid - 1; + hi = mid; mid = lo + (mid - lo) / 2; } else if (ra.m_end < t) { lo = mid + 1; - mid += (hi - mid) / 2; + mid += (hi - mid + 1) / 2; } else { break; diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index 43f55f35a..f18299a12 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -91,7 +91,8 @@ namespace smt { vector m_available; // time intervals where resource is available time_t m_end; // can't run after enode* m_resource; - res_info(): m_end(std::numeric_limits::max()), m_resource(nullptr) {} + enode* m_makespan; + res_info(): m_end(std::numeric_limits::max()), m_resource(nullptr), m_makespan(nullptr) {} }; ast_manager& m; From 03bd010b0523c72883c83d033fe67e03a89555f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Aug 2018 21:19:06 -0700 Subject: [PATCH 026/227] na Signed-off-by: Nikolaj Bjorner --- src/smt/theory_jobscheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index ce1b2a82b..0e8e828a0 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -839,7 +839,7 @@ namespace smt { } else if (ra.m_end < t) { lo = mid + 1; - mid += (hi - mid + 1) / 2; + mid += (hi - mid) / 2; } else { break; From fd5cfbe40248d44e3cfa99e9a319bfb4c0ce8c9b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 15 Aug 2018 10:38:23 -0700 Subject: [PATCH 027/227] na Signed-off-by: Nikolaj Bjorner --- src/smt/theory_jobscheduler.cpp | 70 +++++++++++++++++---------------- src/smt/theory_jobscheduler.h | 1 - 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index 0e8e828a0..f27efd5a3 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -19,13 +19,9 @@ TODO: - arithmetic interface - propagation queue: - - register theory variables for catching when jobs are bound to resources - register bounds on start times to propagate energy constraints - more general registration mechanism for arithmetic theory. -- csp_cmds - - use predicates for add_ feature set? Closed world. - set up environment in one swoop. - - interact with opt +- interact with opt - jobs without resources - complain or add dummy resource? At which level. @@ -271,6 +267,9 @@ namespace smt { /** * r = resource(j) & start(j) >= slb => end(j) >= ect(j, r, slb) + * + * note: not used so far + * note: subsumed by constrain_end_time_interval used in final-check */ void theory_jobscheduler::propagate_end_time(unsigned j, unsigned r) { time_t slb = est(j); @@ -361,9 +360,6 @@ namespace smt { return true; } - void theory_jobscheduler::propagate_resource_energy(unsigned r) { - - } /** * Ensure that job overlaps don't exceed available energy @@ -613,7 +609,7 @@ namespace smt { app_ref start(u.mk_start(j), m); app_ref end(u.mk_end(j), m); app_ref res(u.mk_job2resource(j), m); - if (!ctx.e_internalized(job)) ctx.internalize(job, false); + if (!ctx.e_internalized(job)) ctx.internalize(job, false); if (!ctx.e_internalized(start)) ctx.internalize(start, false); if (!ctx.e_internalized(end)) ctx.internalize(end, false); if (!ctx.e_internalized(res)) ctx.internalize(res, false); @@ -648,12 +644,18 @@ namespace smt { /* * Initialze the state based on the set of jobs and resources added. - * For each job j, with possible resources r1, ..., r_n assert - * resource(j) = r_1 || resource(j) = r_2 || ... || resource(j) = r_n - * For each job and resource r with deadline end(j,r) assert - * resource(j) = r => end(j) <= end(j,r) - * * Ensure that the availability slots for each resource is sorted by time. + * + * For each resource j: + * est(j) <= start(j) <= end(j) <= lct(j) + * + * possible strengthenings: + * - start(j) <= lst(j) + * - start(j) + min_completion_time(j) <= end(j) + * - start(j) + max_completion_time(j) >= end(j) + * + * makespan constraints? + * */ void theory_jobscheduler::add_done() { TRACE("csp", tout << "add-done begin\n";); @@ -666,8 +668,7 @@ namespace smt { std::sort(available.begin(), available.end(), cmp); } - expr_ref fml(m); - literal lit, l1, l2, l3; + literal lit; for (job_info const& ji : m_jobs) { if (ji.m_resources.empty()) { @@ -683,13 +684,9 @@ namespace smt { for (job_resource const& jr : ji.m_resources) { unsigned r = jr.m_resource_id; res_info const& ri = m_resources[r]; - // literal eq = mk_eq_lit(ji.m_job2resource, ri.m_resource); - // disj.push_back(eq); start_lb = std::min(start_lb, ri.m_available[0].m_start); end_ub = std::max(end_ub, ri.m_available.back().m_end); } - // resource(j) = r1 || ... || resource(j) = r_n - // ctx.mk_th_axiom(get_id(), disj.size(), disj.c_ptr()); // start(j) >= start_lb lit = mk_ge(ji.m_start, start_lb); @@ -723,14 +720,14 @@ namespace smt { } } - // resource(j) = r => start(j) >= avaialble[0].m_start + // resource(j) = r => start(j) >= available[0].m_start void theory_jobscheduler::assert_first_start_time(unsigned j, unsigned r, literal eq) { vector& available = m_resources[r].m_available; literal l2 = mk_ge(m_jobs[j].m_start, available[0].m_start); get_context().mk_th_axiom(get_id(), ~eq, l2); } - // resource(j) = r => start[idx] <= end(j) || start(j) <= start[idx+1]; + // resource(j) = r => start(j) <= end[idx] || start[idx+1] <= start(j); void theory_jobscheduler::assert_job_not_in_gap(unsigned j, unsigned r, unsigned idx, literal eq) { vector& available = m_resources[r].m_available; literal l2 = mk_ge(m_jobs[j].m_start, available[idx + 1].m_start); @@ -738,7 +735,7 @@ namespace smt { get_context().mk_th_axiom(get_id(), ~eq, l2, l3); } - // resource(j) = r => end(j) <= end[idx] || start(j) >= start[idx+1]; + // resource(j) = r => end(j) <= end[idx] || start[idx+1] <= start(j); void theory_jobscheduler::assert_job_non_preemptable(unsigned j, unsigned r, unsigned idx, literal eq) { vector& available = m_resources[r].m_available; literal l2 = mk_le(m_jobs[j].m_end, available[idx].m_end); @@ -746,6 +743,9 @@ namespace smt { get_context().mk_th_axiom(get_id(), ~eq, l2, l3); } + /** + * bind a job to one of the resources it can run on. + */ bool theory_jobscheduler::split_job2resource(unsigned j) { job_info const& ji = m_jobs[j]; context& ctx = get_context(); @@ -823,6 +823,9 @@ namespace smt { return ji.m_resources[ji.m_resource2index[r]]; } + /** + * find idx, if any, such that t is within the time interval of available[idx] + */ bool theory_jobscheduler::resource_available(unsigned r, time_t t, unsigned& idx) { vector& available = m_resources[r].m_available; unsigned lo = 0, hi = available.size(), mid = hi / 2; @@ -848,7 +851,6 @@ namespace smt { return false; } - /** * compute earliest completion time for job j on resource r starting at time start. */ @@ -870,16 +872,9 @@ namespace smt { time_t end = available[idx].m_end; unsigned load_pct = available[idx].m_loadpct; time_t delta = solve_for_capacity(load_pct, j_load_pct, start, end); - TRACE("csp", tout << "delta: " << delta << " capacity: " << cap << " load " << load_pct << " jload: " << j_load_pct << " start: " << start << " end " << end << "\n";); + TRACE("csp", tout << "delta: " << delta << " capacity: " << cap << " load " + << load_pct << " jload: " << j_load_pct << " start: " << start << " end " << end << "\n";); if (delta > cap) { - // - // solve for end: - // cap = load * (end - start + 1) - // <=> - // cap / load = (end - start + 1) - // <=> - // end = cap / load + start - 1 - // end = solve_for_end(load_pct, j_load_pct, start, cap); cap = 0; } @@ -893,6 +888,9 @@ namespace smt { return std::numeric_limits::max(); } + /** + * find end, such that cap = (load / job_load_pct) * (end - start + 1) + */ time_t theory_jobscheduler::solve_for_end(unsigned load_pct, unsigned job_load_pct, time_t start, time_t cap) { SASSERT(load_pct > 0); SASSERT(job_load_pct > 0); @@ -907,6 +905,9 @@ namespace smt { return (load * (start - 1) + cap * job_load_pct) / load; } + /** + * find start, such that cap = (load / job_load_pct) * (end - start + 1) + */ time_t theory_jobscheduler::solve_for_start(unsigned load_pct, unsigned job_load_pct, time_t end, time_t cap) { SASSERT(load_pct > 0); SASSERT(job_load_pct > 0); @@ -921,6 +922,9 @@ namespace smt { return (load * (end + 1) - cap * job_load_pct) / load; } + /** + * find cap, such that cap = (load / job_load_pct) * (end - start + 1) + */ time_t theory_jobscheduler::solve_for_capacity(unsigned load_pct, unsigned job_load_pct, time_t start, time_t end) { SASSERT(job_load_pct > 0); unsigned load = std::min(load_pct, job_load_pct); diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index f18299a12..4fc5ba567 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -188,7 +188,6 @@ namespace smt { // propagation void propagate_end_time(unsigned j, unsigned r); - void propagate_resource_energy(unsigned r); void propagate_job2resource(unsigned j, unsigned r); // final check constraints From 72304616712b5366993218ca9c5812520342f7d9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 20 Aug 2018 23:51:51 +0200 Subject: [PATCH 028/227] adding properities Signed-off-by: Nikolaj Bjorner --- src/api/api_datalog.cpp | 95 +++++++++++++++++++++++++- src/api/api_qe.cpp | 2 +- src/ast/csp_decl_plugin.cpp | 33 +++++++-- src/ast/csp_decl_plugin.h | 8 ++- src/smt/theory_jobscheduler.cpp | 116 +++++++++++++++++++++++++++----- src/smt/theory_jobscheduler.h | 10 ++- 6 files changed, 235 insertions(+), 29 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index b0a4def55..61c0dc3a5 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -623,6 +623,99 @@ extern "C" { to_fixedpoint_ref(d)->ctx().add_constraint(to_expr(e), lvl); } -#include "api_datalog_spacer.inc" + Z3_lbool Z3_API Z3_fixedpoint_query_from_lvl (Z3_context c, Z3_fixedpoint d, Z3_ast q, unsigned lvl) { + Z3_TRY; + LOG_Z3_fixedpoint_query_from_lvl (c, d, q, lvl); + RESET_ERROR_CODE(); + lbool r = l_undef; + unsigned timeout = to_fixedpoint(d)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); + unsigned rlimit = to_fixedpoint(d)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); + { + scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); + cancel_eh eh(mk_c(c)->m().limit()); + api::context::set_interruptable si(*(mk_c(c)), eh); + scoped_timer timer(timeout, &eh); + try { + r = to_fixedpoint_ref(d)->ctx().query_from_lvl (to_expr(q), lvl); + } + catch (z3_exception& ex) { + mk_c(c)->handle_exception(ex); + r = l_undef; + } + to_fixedpoint_ref(d)->ctx().cleanup(); + } + return of_lbool(r); + Z3_CATCH_RETURN(Z3_L_UNDEF); + } + + Z3_ast Z3_API Z3_fixedpoint_get_ground_sat_answer(Z3_context c, Z3_fixedpoint d) { + Z3_TRY; + LOG_Z3_fixedpoint_get_ground_sat_answer(c, d); + RESET_ERROR_CODE(); + expr* e = to_fixedpoint_ref(d)->ctx().get_ground_sat_answer(); + mk_c(c)->save_ast_trail(e); + RETURN_Z3(of_expr(e)); + Z3_CATCH_RETURN(nullptr); + } + + Z3_ast_vector Z3_API Z3_fixedpoint_get_rules_along_trace( + Z3_context c, + Z3_fixedpoint d) + { + Z3_TRY; + LOG_Z3_fixedpoint_get_rules_along_trace(c, d); + ast_manager& m = mk_c(c)->m(); + Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, *mk_c(c), m); + mk_c(c)->save_object(v); + expr_ref_vector rules(m); + svector names; + + to_fixedpoint_ref(d)->ctx().get_rules_along_trace_as_formulas(rules, names); + for (unsigned i = 0; i < rules.size(); ++i) { + v->m_ast_vector.push_back(rules[i].get()); + } + RETURN_Z3(of_ast_vector(v)); + Z3_CATCH_RETURN(nullptr); + } + + Z3_symbol Z3_API Z3_fixedpoint_get_rule_names_along_trace( + Z3_context c, + Z3_fixedpoint d) + { + Z3_TRY; + LOG_Z3_fixedpoint_get_rule_names_along_trace(c, d); + ast_manager& m = mk_c(c)->m(); + Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, *mk_c(c), m); + mk_c(c)->save_object(v); + expr_ref_vector rules(m); + svector names; + std::stringstream ss; + + to_fixedpoint_ref(d)->ctx().get_rules_along_trace_as_formulas(rules, names); + for (unsigned i = 0; i < names.size(); ++i) { + ss << ";" << names[i].str(); + } + RETURN_Z3(of_symbol(symbol(ss.str().substr(1).c_str()))); + Z3_CATCH_RETURN(nullptr); + } + + void Z3_API Z3_fixedpoint_add_invariant(Z3_context c, Z3_fixedpoint d, Z3_func_decl pred, Z3_ast property) { + Z3_TRY; + LOG_Z3_fixedpoint_add_invariant(c, d, pred, property); + RESET_ERROR_CODE(); + to_fixedpoint_ref(d)->ctx ().add_invariant(to_func_decl(pred), to_expr(property)); + Z3_CATCH; + } + + Z3_ast Z3_API Z3_fixedpoint_get_reachable(Z3_context c, Z3_fixedpoint d, Z3_func_decl pred) { + Z3_TRY; + LOG_Z3_fixedpoint_get_reachable(c, d, pred); + RESET_ERROR_CODE(); + expr_ref r = to_fixedpoint_ref(d)->ctx().get_reachable(to_func_decl(pred)); + mk_c(c)->save_ast_trail(r); + RETURN_Z3(of_expr(r.get())); + Z3_CATCH_RETURN(nullptr); + } + }; diff --git a/src/api/api_qe.cpp b/src/api/api_qe.cpp index 94e83144f..167a694aa 100644 --- a/src/api/api_qe.cpp +++ b/src/api/api_qe.cpp @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2017 Arie Gurfinkel +Copyright (c) 2018 Microsoft Corporation Module Name: diff --git a/src/ast/csp_decl_plugin.cpp b/src/ast/csp_decl_plugin.cpp index a6255d676..27feadc6d 100644 --- a/src/ast/csp_decl_plugin.cpp +++ b/src/ast/csp_decl_plugin.cpp @@ -98,21 +98,23 @@ func_decl * csp_decl_plugin::mk_func_decl( rng = m_manager->mk_bool_sort(); break; case OP_JS_JOB_RESOURCE: - if (arity != 5) m_manager->raise_exception("add-job-resource expects 5 arguments"); + if (arity != 6) m_manager->raise_exception("add-job-resource expects 6 arguments"); if (domain[0] != m_job_sort) m_manager->raise_exception("first argument of add-job-resource expects should be a job"); if (domain[1] != m_resource_sort) m_manager->raise_exception("second argument of add-job-resource expects should be a resource"); if (domain[2] != m_int_sort) m_manager->raise_exception("3rd argument of add-job-resource expects should be an integer"); if (domain[3] != m_int_sort) m_manager->raise_exception("4th argument of add-job-resource expects should be an integer"); if (domain[4] != m_int_sort) m_manager->raise_exception("5th argument of add-job-resource expects should be an integer"); + if (domain[5] != m_alist_sort) m_manager->raise_exception("6th argument of add-job-resource should be an a list of properties"); name = symbol("add-job-resource"); rng = m_alist_sort; break; case OP_JS_RESOURCE_AVAILABLE: - if (arity != 4) m_manager->raise_exception("add-resource-available expects 4 arguments"); + if (arity != 5) m_manager->raise_exception("add-resource-available expects 5 arguments"); if (domain[0] != m_resource_sort) m_manager->raise_exception("first argument of add-resource-available expects should be a resource"); if (domain[1] != m_int_sort) m_manager->raise_exception("2nd argument of add-resource-available expects should be an integer"); if (domain[2] != m_int_sort) m_manager->raise_exception("3rd argument of add-resource-available expects should be an integer"); if (domain[3] != m_int_sort) m_manager->raise_exception("4th argument of add-resource-available expects should be an integer"); + if (domain[4] != m_alist_sort) m_manager->raise_exception("5th argument of add-resource-available should be an a list of properties"); name = symbol("add-resource-available"); rng = m_alist_sort; break; @@ -121,6 +123,14 @@ func_decl * csp_decl_plugin::mk_func_decl( name = symbol("set-preemptable"); rng = m_alist_sort; break; + case OP_JS_PROPERTIES: + if (arity != 0) m_manager->raise_exception("js-properties takes no arguments"); + for (unsigned i = 0; i < num_parameters; ++i) { + if (!parameters[i].is_symbol()) m_manager->raise_exception("js-properties expects a list of keyword parameters"); + } + name = symbol("js-properties"); + rng = m_alist_sort; + break; default: UNREACHABLE(); return nullptr; @@ -161,7 +171,7 @@ void csp_decl_plugin::get_op_names(svector & op_names, symbol cons op_names.push_back(builtin_name("add-job-resource", OP_JS_JOB_RESOURCE)); op_names.push_back(builtin_name("add-resource-available", OP_JS_RESOURCE_AVAILABLE)); op_names.push_back(builtin_name("set-preemptable", OP_JS_JOB_PREEMPTABLE)); - + op_names.push_back(builtin_name("js-properties", OP_JS_PROPERTIES)); } } @@ -261,7 +271,7 @@ bool csp_util::is_job2resource(expr* e, unsigned& j) { return is_app_of(e, m_fid, OP_JS_JOB2RESOURCE) && (j = job2id(e), true); } -bool csp_util::is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, uint64_t& start, uint64_t& end) { +bool csp_util::is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, uint64_t& start, uint64_t& end, svector& properties) { if (!is_app_of(e, m_fid, OP_JS_RESOURCE_AVAILABLE)) return false; res = to_app(e)->get_arg(0); arith_util a(m); @@ -272,10 +282,11 @@ bool csp_util::is_add_resource_available(expr * e, expr *& res, unsigned& loadpc start = r.get_uint64(); if (!a.is_numeral(to_app(e)->get_arg(3), r) || !r.is_uint64()) return false; end = r.get_uint64(); + if (!is_js_properties(to_app(e)->get_arg(4), properties)) return false; return true; } -bool csp_util::is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end) { +bool csp_util::is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end, svector& properties) { if (!is_app_of(e, m_fid, OP_JS_JOB_RESOURCE)) return false; job = to_app(e)->get_arg(0); res = to_app(e)->get_arg(1); @@ -287,6 +298,7 @@ bool csp_util::is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& capacity = r.get_uint64(); if (!a.is_numeral(to_app(e)->get_arg(4), r) || !r.is_uint64()) return false; end = r.get_uint64(); + if (!is_js_properties(to_app(e)->get_arg(5), properties)) return false; return true; } @@ -295,3 +307,14 @@ bool csp_util::is_set_preemptable(expr* e, expr *& job) { job = to_app(e)->get_arg(0); return true; } + +bool csp_util::is_js_properties(expr* e, svector& properties) { + if (!is_app_of(e, m_fid, OP_JS_PROPERTIES)) return false; + unsigned sz = to_app(e)->get_decl()->get_num_parameters(); + for (unsigned i = 0; i < sz; ++i) { + properties.push_back(to_app(e)->get_decl()->get_parameter(i).get_symbol()); + } + return true; +} + + diff --git a/src/ast/csp_decl_plugin.h b/src/ast/csp_decl_plugin.h index faaaf344c..8d6ad56fa 100644 --- a/src/ast/csp_decl_plugin.h +++ b/src/ast/csp_decl_plugin.h @@ -82,7 +82,8 @@ enum js_op_kind { OP_JS_MODEL, // jobscheduler model OP_JS_JOB_RESOURCE, // model declaration for job assignment to resource OP_JS_JOB_PREEMPTABLE, // model declaration for whether job is pre-emptable - OP_JS_RESOURCE_AVAILABLE // model declaration for availability intervals of resource + OP_JS_RESOURCE_AVAILABLE, // model declaration for availability intervals of resource + OP_JS_PROPERTIES // model declaration of a set of properties. Each property is a keyword. }; class csp_decl_plugin : public decl_plugin { @@ -134,10 +135,11 @@ public: bool is_job2resource(expr* e, unsigned& j); bool is_resource(expr* e, unsigned& r); bool is_makespan(expr* e, unsigned& r); - bool is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, uint64_t& start, uint64_t& end); - bool is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end); + bool is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, uint64_t& start, uint64_t& end, svector& properites); + bool is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end, svector& properites); bool is_set_preemptable(expr* e, expr *& job); bool is_model(expr* e) const { return is_app_of(e, m_fid, OP_JS_MODEL); } + bool is_js_properties(expr* e, svector& properties); private: unsigned job2id(expr* j); diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index f27efd5a3..48009be31 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -83,6 +83,12 @@ namespace smt { return true; } + struct symbol_cmp { + bool operator()(symbol const& s1, symbol const& s2) const { + return lt(s1, s2); + } + }; + // TBD: stronger parameter validation void theory_jobscheduler::internalize_cmd(expr* cmd) { symbol key, val; @@ -94,10 +100,12 @@ namespace smt { if (u.is_set_preemptable(cmd, job) && u.is_job(job, j)) { set_preemptable(j, true); } - else if (u.is_add_resource_available(cmd, resource, loadpct, start, end) && u.is_resource(resource, res)) { + else if (u.is_add_resource_available(cmd, resource, loadpct, start, end, ps) && u.is_resource(resource, res)) { + std::sort(ps.begin(), ps.end(), symbol_cmp()); add_resource_available(res, loadpct, start, end, ps); } - else if (u.is_add_job_resource(cmd, job, resource, loadpct, capacity, end) && u.is_job(job, j) && u.is_resource(resource, res)) { + else if (u.is_add_job_resource(cmd, job, resource, loadpct, capacity, end, ps) && u.is_job(job, j) && u.is_resource(resource, res)) { + std::sort(ps.begin(), ps.end(), symbol_cmp()); add_job_resource(j, res, loadpct, capacity, end, ps); } else { @@ -306,12 +314,15 @@ namespace smt { bool theory_jobscheduler::constrain_end_time_interval(unsigned j, unsigned r) { unsigned idx1 = 0, idx2 = 0; time_t s = start(j); + job_resource const& jr = get_job_resource(j, r); TRACE("csp", tout << "job: " << j << " resource: " << r << " start: " << s << "\n";); - if (!resource_available(r, s, idx1)) return false; vector& available = m_resources[r].m_available; + if (!resource_available(r, s, idx1)) return false; + if (!resource_available(jr, available[idx1])) return false; time_t e = ect(j, r, s); TRACE("csp", tout << "job: " << j << " resource: " << r << " ect: " << e << "\n";); if (!resource_available(r, e, idx2)) return false; // infeasible.. + if (!resource_available(jr, available[idx2])) return false; time_t start1 = available[idx1].m_start; time_t end1 = available[idx1].m_end; unsigned cap1 = available[idx1].m_loadpct; @@ -445,12 +456,19 @@ namespace smt { assert_last_start_time(j, r, eq); assert_first_start_time(j, r, eq); vector const& available = ri.m_available; - for (unsigned i = 0; i + 1 < available.size(); ++i) { - SASSERT(available[i].m_end < available[i + 1].m_start); - assert_job_not_in_gap(j, r, i, eq); + // TBD: needs to take properties into account + + unsigned i = 0; + if (!first_available(jr, ri, i)) return; + while (true) { + unsigned next = i + 1; + if (!first_available(jr, ri, next)) return; + SASSERT(available[i].m_end < available[next].m_start); + assert_job_not_in_gap(j, r, i, next, eq); if (!ji.m_is_preemptable && available[i].m_end + 1 < available[i+1].m_start) { - assert_job_non_preemptable(j, r, i, eq); + assert_job_non_preemptable(j, r, i, next, eq); } + i = next; } } @@ -463,7 +481,8 @@ namespace smt { } std::ostream& theory_jobscheduler::display(std::ostream & out, job_resource const& jr) const { - return out << "r:" << jr.m_resource_id << " cap:" << jr.m_capacity << " load:" << jr.m_loadpct << " end:" << jr.m_end << "\n"; + return out << "r:" << jr.m_resource_id << " cap:" << jr.m_capacity << " load:" << jr.m_loadpct << " end:" << jr.m_end; + for (auto const& s : jr.m_properties) out << " " << s; out << "\n"; } std::ostream& theory_jobscheduler::display(std::ostream & out, job_info const& j) const { @@ -474,7 +493,8 @@ namespace smt { } std::ostream& theory_jobscheduler::display(std::ostream & out, res_available const& r) const { - return out << "[" << r.m_start << ":" << r.m_end << "] @ " << r.m_loadpct << "%\n"; + return out << "[" << r.m_start << ":" << r.m_end << "] @ " << r.m_loadpct << "%"; + for (auto const& s : r.m_properties) out << " " << s; out << "\n"; } std::ostream& theory_jobscheduler::display(std::ostream & out, res_info const& r) const { @@ -624,6 +644,7 @@ namespace smt { m_resources[r].m_jobs.push_back(j); } + void theory_jobscheduler::add_resource_available(unsigned r, unsigned max_loadpct, time_t start, time_t end, properties const& ps) { SASSERT(get_context().at_base_level()); SASSERT(1 <= max_loadpct && max_loadpct <= 100); @@ -684,8 +705,15 @@ namespace smt { for (job_resource const& jr : ji.m_resources) { unsigned r = jr.m_resource_id; res_info const& ri = m_resources[r]; - start_lb = std::min(start_lb, ri.m_available[0].m_start); - end_ub = std::max(end_ub, ri.m_available.back().m_end); + if (ri.m_available.empty()) continue; + unsigned idx = 0; + if (first_available(jr, ri, idx)) { + start_lb = std::min(start_lb, ri.m_available[idx].m_start); + } + idx = ri.m_available.size(); + if (last_available(jr, ri, idx)) { + end_ub = std::max(end_ub, ri.m_available[idx].m_end); + } } // start(j) >= start_lb @@ -722,24 +750,31 @@ namespace smt { // resource(j) = r => start(j) >= available[0].m_start void theory_jobscheduler::assert_first_start_time(unsigned j, unsigned r, literal eq) { + job_resource const& jr = get_job_resource(j, r); + unsigned idx = 0; + if (!first_available(jr, m_resources[r], idx)) return; vector& available = m_resources[r].m_available; - literal l2 = mk_ge(m_jobs[j].m_start, available[0].m_start); + literal l2 = mk_ge(m_jobs[j].m_start, available[idx].m_start); get_context().mk_th_axiom(get_id(), ~eq, l2); } // resource(j) = r => start(j) <= end[idx] || start[idx+1] <= start(j); - void theory_jobscheduler::assert_job_not_in_gap(unsigned j, unsigned r, unsigned idx, literal eq) { + void theory_jobscheduler::assert_job_not_in_gap(unsigned j, unsigned r, unsigned idx, unsigned idx1, literal eq) { + job_resource const& jr = get_job_resource(j, r); vector& available = m_resources[r].m_available; - literal l2 = mk_ge(m_jobs[j].m_start, available[idx + 1].m_start); + SASSERT(resource_available(jr, available[idx])); + literal l2 = mk_ge(m_jobs[j].m_start, available[idx1].m_start); literal l3 = mk_le(m_jobs[j].m_start, available[idx].m_end); get_context().mk_th_axiom(get_id(), ~eq, l2, l3); } // resource(j) = r => end(j) <= end[idx] || start[idx+1] <= start(j); - void theory_jobscheduler::assert_job_non_preemptable(unsigned j, unsigned r, unsigned idx, literal eq) { + void theory_jobscheduler::assert_job_non_preemptable(unsigned j, unsigned r, unsigned idx, unsigned idx1, literal eq) { vector& available = m_resources[r].m_available; + job_resource const& jr = get_job_resource(j, r); + SASSERT(resource_available(jr, available[idx])); literal l2 = mk_le(m_jobs[j].m_end, available[idx].m_end); - literal l3 = mk_ge(m_jobs[j].m_start, available[idx + 1].m_start); + literal l3 = mk_ge(m_jobs[j].m_start, available[idx1].m_start); get_context().mk_th_axiom(get_id(), ~eq, l2, l3); } @@ -868,6 +903,7 @@ namespace smt { SASSERT(cap > 0); for (; idx < available.size(); ++idx) { + if (!resource_available(jr, available[idx])) continue; start = std::max(start, available[idx].m_start); time_t end = available[idx].m_end; unsigned load_pct = available[idx].m_loadpct; @@ -941,6 +977,7 @@ namespace smt { unsigned j_load_pct = jr.m_loadpct; time_t cap = jr.m_capacity; for (unsigned idx = available.size(); idx-- > 0; ) { + if (!resource_available(jr, available[idx])) continue; start = available[idx].m_start; time_t end = available[idx].m_end; unsigned load_pct = available[idx].m_loadpct; @@ -958,6 +995,53 @@ namespace smt { } return false; } + + /** + * \brief check that job properties is a subset of resource properties. + * It assumes that both vectors are sorted. + */ + + bool theory_jobscheduler::resource_available(job_resource const& jr, res_available const& ra) const { + auto const& jps = jr.m_properties; + auto const& rps = ra.m_properties; + if (jps.size() > rps.size()) return false; + unsigned j = 0, i = 0; + for (; i < jps.size() && j < rps.size(); ) { + if (jps[i] == rps[j]) { + ++i; ++j; + } + else if (lt(rps[j], jps[i])) { + ++j; + } + else { + break; + } + } + return i == jps.size(); + } + + /** + * \brief minimal current resource available for job resource, includes idx. + */ + bool theory_jobscheduler::first_available(job_resource const& jr, res_info const& ri, unsigned& idx) const { + for (; idx < ri.m_available.size(); ++idx) { + if (resource_available(jr, ri.m_available[idx])) + return true; + } + return false; + } + + /** + * \brief maximal previous resource available for job resource, excludes idx. + */ + bool theory_jobscheduler::last_available(job_resource const& jr, res_info const& ri, unsigned& idx) const { + while (idx-- > 0) { + if (resource_available(jr, ri.m_available[idx])) + return true; + } + return false; + } + }; diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index 4fc5ba567..59c3b975d 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -31,7 +31,7 @@ namespace smt { class theory_jobscheduler : public theory { public: - typedef map properties; + typedef svector properties; protected: struct job_resource { @@ -175,6 +175,10 @@ namespace smt { time_t ect(unsigned j, unsigned r, time_t start); bool lst(unsigned j, unsigned r, time_t& t); + bool resource_available(job_resource const& jr, res_available const& ra) const; + bool first_available(job_resource const& jr, res_info const& ri, unsigned& idx) const; + bool last_available(job_resource const& jr, res_info const& ri, unsigned& idx) const; + time_t solve_for_start(unsigned load_pct, unsigned job_load_pct, time_t end, time_t cap); time_t solve_for_end(unsigned load_pct, unsigned job_load_pct, time_t start, time_t cap); time_t solve_for_capacity(unsigned load_pct, unsigned job_load_pct, time_t start, time_t end); @@ -198,8 +202,8 @@ namespace smt { void assert_last_end_time(unsigned j, unsigned r, job_resource const& jr, literal eq); void assert_last_start_time(unsigned j, unsigned r, literal eq); void assert_first_start_time(unsigned j, unsigned r, literal eq); - void assert_job_not_in_gap(unsigned j, unsigned r, unsigned idx, literal eq); - void assert_job_non_preemptable(unsigned j, unsigned r, unsigned idx, literal eq); + void assert_job_not_in_gap(unsigned j, unsigned r, unsigned idx, unsigned idx1, literal eq); + void assert_job_non_preemptable(unsigned j, unsigned r, unsigned idx, unsigned idx1, literal eq); void block_job_overlap(unsigned r, uint_set const& jobs, unsigned last_job); From 43807a7edc7fba4cd785470dfe565f797d096553 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 31 Aug 2018 20:25:49 -0500 Subject: [PATCH 029/227] adding roundingSat strategy Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 497 +++++++++++++++++++++++--------- src/sat/ba_solver.h | 27 +- src/smt/theory_jobscheduler.cpp | 9 +- 3 files changed, 401 insertions(+), 132 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 4226b9791..c86ea3317 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1009,21 +1009,6 @@ namespace sat { // --------------------------- // conflict resolution - void ba_solver::normalize_active_coeffs() { - reset_active_var_set(); - unsigned i = 0, j = 0, sz = m_active_vars.size(); - for (; i < sz; ++i) { - bool_var v = m_active_vars[i]; - if (!m_active_var_set.contains(v) && get_coeff(v) != 0) { - m_active_var_set.insert(v); - if (j != i) { - m_active_vars[j] = m_active_vars[i]; - } - ++j; - } - } - m_active_vars.shrink(j); - } void ba_solver::inc_coeff(literal l, unsigned offset) { SASSERT(offset > 0); @@ -1066,44 +1051,46 @@ namespace sat { return m_coeffs.get(v, 0); } + uint64_t ba_solver::get_coeff(literal lit) const { + int64_t c1 = get_coeff(lit.var()); + SASSERT(c1 < 0 == lit.sign()); + uint64_t c = static_cast(std::abs(c1)); + m_overflow |= c != c1; + return c; + } + + void ba_solver::get_coeff(bool_var v, literal& l, unsigned& c) { + int64_t c1 = get_coeff(v); + l = literal(v, c1 < 0); + c1 = std::abs(c1); + c = static_cast(c1); + m_overflow |= c != c1; + } + unsigned ba_solver::get_abs_coeff(bool_var v) const { - int64_t c = get_coeff(v); - if (c < INT_MIN+1 || c > UINT_MAX) { - m_overflow = true; - return UINT_MAX; - } - return static_cast(std::abs(c)); + int64_t c1 = std::abs(get_coeff(v)); + unsigned c = static_cast(c1); + m_overflow |= c != c1; + return c; } int ba_solver::get_int_coeff(bool_var v) const { - int64_t c = m_coeffs.get(v, 0); - if (c < INT_MIN || c > INT_MAX) { - m_overflow = true; - return 0; - } - return static_cast(c); + int64_t c1 = m_coeffs.get(v, 0); + int c = static_cast(c1); + m_overflow |= c != c1; + return c; } void ba_solver::inc_bound(int64_t i) { - if (i < INT_MIN || i > INT_MAX) { - m_overflow = true; - return; - } int64_t new_bound = m_bound; new_bound += i; - if (new_bound < 0) { - m_overflow = true; - } - else if (new_bound > UINT_MAX) { - m_overflow = true; - } - else { - m_bound = static_cast(new_bound); - } + unsigned nb = static_cast(new_bound); + m_overflow |= new_bound < 0 || nb != new_bound; + m_bound = nb; } void ba_solver::reset_coeffs() { - for (unsigned i = 0; i < m_active_vars.size(); ++i) { + for (unsigned i = m_active_vars.size(); i-- > 0; ) { m_coeffs[m_active_vars[i]] = 0; } m_active_vars.reset(); @@ -1115,7 +1102,47 @@ namespace sat { // #define DEBUG_CODE(_x_) _x_ - lbool ba_solver::resolve_conflict() { + void ba_solver::bail_resolve_conflict(unsigned idx) { + m_overflow = false; + literal_vector const& lits = s().m_trail; + while (m_num_marks > 0) { + bool_var v = lits[idx].var(); + if (s().is_marked(v)) { + s().reset_mark(v); + --m_num_marks; + } + if (idx == 0 && !_debug_conflict) { + _debug_conflict = true; + _debug_var2position.reserve(s().num_vars()); + for (unsigned i = 0; i < lits.size(); ++i) { + _debug_var2position[lits[i].var()] = i; + } + IF_VERBOSE(0, + active2pb(m_A); + uint64_t c = 0; + for (uint64_t c1 : m_A.m_coeffs) c += c1; + verbose_stream() << "sum of coefficients: " << c << "\n"; + display(verbose_stream(), m_A, true); + verbose_stream() << "conflicting literal: " << s().m_not_l << "\n";); + + for (literal l : lits) { + if (s().is_marked(l.var())) { + IF_VERBOSE(0, verbose_stream() << "missing mark: " << l << "\n";); + s().reset_mark(l.var()); + } + } + m_num_marks = 0; + resolve_conflict(); + } + --idx; + } + } + + lbool ba_solver::resolve_conflict() { +#if 1 + return resolve_conflict_rs(); +#endif + if (0 == m_num_propagations_since_pop) { return l_undef; } @@ -1256,7 +1283,6 @@ namespace sat { process_next_resolvent: // find the next marked variable in the assignment stack - // bool_var v; while (true) { consequent = lits[idx]; @@ -1290,7 +1316,6 @@ namespace sat { DEBUG_CODE(for (bool_var i = 0; i < static_cast(s().num_vars()); ++i) SASSERT(!s().is_marked(i));); SASSERT(validate_lemma()); - normalize_active_coeffs(); if (!create_asserting_lemma()) { goto bail_out; @@ -1315,43 +1340,243 @@ namespace sat { return l_true; bail_out: + bail_resolve_conflict(idx); + return l_undef; + } - m_overflow = false; + uint64_t ba_solver::ineq::coeff(literal l) const { + bool_var v = l.var(); + for (unsigned i = size(); i-- > 0; ) { + if (lit(i).var() == v) return coeff(i); + } + UNREACHABLE(); + return 0; + } + + void ba_solver::ineq::divide(uint64_t c) { + if (c == 1) return; + for (unsigned i = size(); i-- > 0; ) { + m_coeffs[i] = (m_coeffs[i] + c - 1) / c; + } + m_k = (m_k + c - 1) / c; + } + + /** + * Remove literal at position i, subtract coefficient from bound. + */ + void ba_solver::ineq::weaken(unsigned i) { + uint64_t ci = coeff(i); + SASSERT(m_k >= ci); + m_k -= ci; + m_lits[i] = m_lits.back(); + m_coeffs[i] = m_coeffs.back(); + m_lits.pop_back(); + m_coeffs.pop_back(); + } + + /** + * Round coefficient of inequality to 1. + */ + void ba_solver::round_to_one(ineq& ineq, literal lit) { + uint64_t c = ineq.coeff(lit); + if (c == 1) return; + unsigned sz = ineq.size(); + for (unsigned i = 0; i < sz; ++i) { + uint64_t ci = ineq.coeff(i); + if (ci % c != 0 && !is_false(ineq.lit(i))) { + ineq.weaken(i); + --i; + --sz; + } + } + ineq.divide(c); + } + + void ba_solver::round_to_one(literal lit) { + uint64_t c = get_coeff(lit); + if (c == 1) return; + for (bool_var v : m_active_vars) { + literal l; + unsigned ci; + get_coeff(v, l, ci); + if (ci > 0 && ci % c != 0 && !is_false(l)) { + m_coeffs[v] = 0; + } + } + divide(c); + } + + void ba_solver::divide(uint64_t c) { + SASSERT(c != 0); + if (c == 1) return; + reset_active_var_set(); + unsigned j = 0, sz = m_active_vars.size(); + for (unsigned i = 0; i < sz; ++i) { + bool_var v = m_active_vars[i]; + int ci = get_int_coeff(v); + if (m_active_var_set.contains(v) || ci == 0) continue; + m_active_var_set.insert(v); + if (ci > 0) { + m_coeffs[v] = (ci + c - 1) / c; + } + else { + m_coeffs[v] = -static_cast((-ci + c - 1) / c); + } + m_active_vars[j++] = v; + } + m_active_vars.shrink(j); + if (m_bound % c != 0) { + ++m_stats.m_num_cut; + m_bound = static_cast((m_bound + c - 1) / c); + } + } + + void ba_solver::resolve_on(literal consequent) { + round_to_one(consequent); + m_coeffs[consequent.var()] = 0; + } + + void ba_solver::resolve_with(ineq const& ineq) { + TRACE("ba", display(tout, ineq, true);); + inc_bound(1 + ineq.m_k); + for (unsigned i = ineq.size(); i-- > 0; ) { + literal l = ineq.lit(i); + inc_coeff(l, static_cast(ineq.coeff(i))); + } + } + + void ba_solver::reset_marks(unsigned idx) { while (m_num_marks > 0) { - bool_var v = lits[idx].var(); + SASSERT(idx > 0); + bool_var v = s().m_trail[idx].var(); if (s().is_marked(v)) { s().reset_mark(v); --m_num_marks; } - if (idx == 0 && !_debug_conflict) { - _debug_conflict = true; - _debug_var2position.reserve(s().num_vars()); - for (unsigned i = 0; i < lits.size(); ++i) { - _debug_var2position[lits[i].var()] = i; - } - IF_VERBOSE(0, - active2pb(m_A); - uint64_t c = 0; - for (uint64_t c1 : m_A.m_coeffs) c += c1; - verbose_stream() << "sum of coefficients: " << c << "\n"; - display(verbose_stream(), m_A, true); - verbose_stream() << "conflicting literal: " << s().m_not_l << "\n";); - - for (literal l : lits) { - if (s().is_marked(l.var())) { - IF_VERBOSE(0, verbose_stream() << "missing mark: " << l << "\n";); - s().reset_mark(l.var()); - } - } - m_num_marks = 0; - resolve_conflict(); - } --idx; } + } + + lbool ba_solver::resolve_conflict_rs() { + if (0 == m_num_propagations_since_pop) { + return l_undef; + } + m_overflow = false; + reset_coeffs(); + m_num_marks = 0; + m_bound = 0; + literal consequent = s().m_not_l; + justification js = s().m_conflict; + TRACE("ba", tout << consequent << " " << js << "\n";); + m_conflict_lvl = s().get_max_lvl(consequent, js); + if (consequent != null_literal) { + consequent.neg(); + process_antecedent(consequent, 1); + } + unsigned idx = s().m_trail.size() - 1; + + do { + // TBD: termination condition + // if UIP is below m_conflict level + + TRACE("ba", s().display_justification(tout << "process consequent: " << consequent << " : ", js) << "\n"; + active2pb(m_A); display(tout, m_A, true); + ); + switch (js.get_kind()) { + case justification::NONE: + SASSERT(consequent != null_literal); + resolve_on(consequent); + break; + case justification::BINARY: + SASSERT(consequent != null_literal); + resolve_on(consequent); + process_antecedent(js.get_literal()); + break; + case justification::TERNARY: + SASSERT(consequent != null_literal); + resolve_on(consequent); + process_antecedent(js.get_literal1()); + process_antecedent(js.get_literal2()); + break; + case justification::CLAUSE: { + clause & c = s().get_clause(js); + unsigned i = 0; + if (consequent == null_literal) { + m_bound = 1; + } + else { + resolve_on(consequent); + if (c[0] == consequent) { + i = 1; + } + else { + SASSERT(c[1] == consequent); + process_antecedent(c[0]); + i = 2; + } + } + unsigned sz = c.size(); + for (; i < sz; i++) + process_antecedent(c[i]); + break; + } + case justification::EXT_JUSTIFICATION: { + ++m_stats.m_num_resolves; + ext_justification_idx index = js.get_ext_justification_idx(); + constraint& cnstr = index2constraint(index); + constraint2pb(cnstr, consequent, 1, m_A); + if (consequent == null_literal) { + m_bound = static_cast(m_A.m_k); + for (unsigned i = m_A.size(); i-- > 0; ) { + inc_coeff(m_A.lit(i), static_cast(m_A.coeff(i))); + } + } + else { + round_to_one(consequent); + round_to_one(m_A, consequent); + resolve_with(m_A); + } + break; + } + default: + UNREACHABLE(); + break; + } + + cut(); + + // find the next marked variable in the assignment stack + bool_var v; + while (true) { + consequent = s().m_trail[idx]; + v = consequent.var(); + if (s().is_marked(v)) break; + if (idx == 0) { + goto bail_out; + } + --idx; + } + + SASSERT(lvl(v) == m_conflict_lvl); + s().reset_mark(v); + --idx; + --m_num_marks; + js = s().m_justification[v]; + } + while (m_num_marks > 0 && !m_overflow); + TRACE("ba", active2pb(m_A); display(tout, m_A, true);); + + active2constraint(); + if (!m_overflow) { + return l_true; + } + bail_out: + m_overflow = false; return l_undef; } + bool ba_solver::create_asserting_lemma() { bool adjusted = false; @@ -1461,10 +1686,17 @@ namespace sat { } if (g >= 2) { - normalize_active_coeffs(); - for (bool_var v : m_active_vars) { + reset_active_var_set(); + unsigned j = 0, sz = m_active_vars.size(); + for (unsigned i = 0; i < sz; ++i) { + bool_var v = m_active_vars[i]; + int64_t c = m_coeffs[v]; + if (m_active_var_set.contains(v) || c == 0) continue; + m_active_var_set.insert(v); m_coeffs[v] /= static_cast(g); + m_active_vars[j++] = v; } + m_active_vars.shrink(j); m_bound = (m_bound + g - 1) / g; ++m_stats.m_num_cut; } @@ -1502,7 +1734,6 @@ namespace sat { if (level > 0 && !s().is_marked(v) && level == m_conflict_lvl) { s().mark(v); - TRACE("sat_verbose", tout << "Mark: v" << v << "\n";); ++m_num_marks; if (_debug_conflict && _debug_consequent != null_literal && _debug_var2position[_debug_consequent.var()] < _debug_var2position[l.var()]) { IF_VERBOSE(0, verbose_stream() << "antecedent " << l << " is above consequent in stack\n";); @@ -1551,10 +1782,10 @@ namespace sat { if (k == 1 && lit == null_literal) { literal_vector _lits(lits); s().mk_clause(_lits.size(), _lits.c_ptr(), learned); - return 0; + return nullptr; } if (!learned && clausify(lit, lits.size(), lits.c_ptr(), k)) { - return 0; + return nullptr; } void * mem = m_allocator.allocate(card::get_obj_size(lits.size())); card* c = new (mem) card(next_id(), lit, lits, k); @@ -1615,7 +1846,7 @@ namespace sat { bool units = true; for (wliteral wl : wlits) units &= wl.first == 1; if (k == 0 && lit == null_literal) { - return 0; + return nullptr; } if (units || k == 1) { literal_vector lits; @@ -3612,7 +3843,7 @@ namespace sat { } } - void ba_solver::display(std::ostream& out, ineq& ineq, bool values) const { + void ba_solver::display(std::ostream& out, ineq const& ineq, bool values) const { for (unsigned i = 0; i < ineq.m_lits.size(); ++i) { out << ineq.m_coeffs[i] << "*" << ineq.m_lits[i] << " "; if (values) out << value(ineq.m_lits[i]) << " "; @@ -3824,37 +4055,38 @@ namespace sat { p.reset(m_bound); for (bool_var v : m_active_vars) { if (m_active_var_set.contains(v)) continue; - int64_t coeff = get_coeff(v); + unsigned coeff; + literal lit; + get_coeff(v, lit, coeff); if (coeff == 0) continue; m_active_var_set.insert(v); - literal lit(v, coeff < 0); p.m_lits.push_back(lit); - p.m_coeffs.push_back(std::abs(coeff)); + p.m_coeffs.push_back(coeff); } } - ba_solver::constraint* ba_solver::active2constraint() { + void ba_solver::active2wlits() { reset_active_var_set(); m_wlits.reset(); - uint64_t sum = 0; - if (m_bound == 1) return 0; - if (m_overflow) return 0; - + uint64_t sum = 0; for (bool_var v : m_active_vars) { - int coeff = get_int_coeff(v); + unsigned coeff; + literal lit; + get_coeff(v, lit, coeff); if (m_active_var_set.contains(v) || coeff == 0) continue; m_active_var_set.insert(v); - literal lit(v, coeff < 0); - m_wlits.push_back(wliteral(get_abs_coeff(v), lit)); - sum += get_abs_coeff(v); + m_wlits.push_back(wliteral(static_cast(coeff), lit)); + sum += coeff; } + m_overflow |= sum >= UINT_MAX/2; + } - if (m_overflow || sum >= UINT_MAX/2) { - return 0; + ba_solver::constraint* ba_solver::active2constraint() { + active2wlits(); + if (m_overflow) { + return nullptr; } - else { - return add_pb_ge(null_literal, m_wlits, m_bound, true); - } + return add_pb_ge(null_literal, m_wlits, m_bound, true); } /* @@ -3889,11 +4121,9 @@ namespace sat { ba_solver::constraint* ba_solver::active2card() { - normalize_active_coeffs(); - m_wlits.reset(); - for (bool_var v : m_active_vars) { - int coeff = get_int_coeff(v); - m_wlits.push_back(std::make_pair(get_abs_coeff(v), literal(v, coeff < 0))); + active2wlits(); + if (m_overflow) { + return nullptr; } std::sort(m_wlits.begin(), m_wlits.end(), compare_wlit()); unsigned k = 0; @@ -3905,7 +4135,7 @@ namespace sat { ++k; } if (k == 1) { - return 0; + return nullptr; } while (!m_wlits.empty()) { wliteral wl = m_wlits.back(); @@ -3928,7 +4158,9 @@ namespace sat { ++num_max_level; } } - if (m_overflow) return 0; + if (m_overflow) { + return nullptr; + } if (slack >= k) { #if 0 @@ -3963,15 +4195,18 @@ namespace sat { void ba_solver::justification2pb(justification const& js, literal lit, unsigned offset, ineq& ineq) { switch (js.get_kind()) { case justification::NONE: + SASSERT(lit != null_literal); ineq.reset(offset); ineq.push(lit, offset); break; case justification::BINARY: + SASSERT(lit != null_literal); ineq.reset(offset); ineq.push(lit, offset); ineq.push(js.get_literal(), offset); break; case justification::TERNARY: + SASSERT(lit != null_literal); ineq.reset(offset); ineq.push(lit, offset); ineq.push(js.get_literal1(), offset); @@ -3986,35 +4221,7 @@ namespace sat { case justification::EXT_JUSTIFICATION: { ext_justification_idx index = js.get_ext_justification_idx(); constraint& cnstr = index2constraint(index); - switch (cnstr.tag()) { - case card_t: { - card& c = cnstr.to_card(); - ineq.reset(offset*c.k()); - for (literal l : c) ineq.push(l, offset); - if (c.lit() != null_literal) ineq.push(~c.lit(), offset*c.k()); - break; - } - case pb_t: { - pb& p = cnstr.to_pb(); - ineq.reset(p.k()); - for (wliteral wl : p) ineq.push(wl.second, wl.first); - if (p.lit() != null_literal) ineq.push(~p.lit(), p.k()); - break; - } - case xr_t: { - xr& x = cnstr.to_xr(); - literal_vector ls; - get_antecedents(lit, x, ls); - ineq.reset(offset); - for (literal l : ls) ineq.push(~l, offset); - literal lxr = x.lit(); - if (lxr != null_literal) ineq.push(~lxr, offset); - break; - } - default: - UNREACHABLE(); - break; - } + constraint2pb(cnstr, lit, offset, ineq); break; } default: @@ -4023,6 +4230,38 @@ namespace sat { } } + void ba_solver::constraint2pb(constraint& cnstr, literal lit, unsigned offset, ineq& ineq) { + switch (cnstr.tag()) { + case card_t: { + card& c = cnstr.to_card(); + ineq.reset(offset*c.k()); + for (literal l : c) ineq.push(l, offset); + if (c.lit() != null_literal) ineq.push(~c.lit(), offset*c.k()); + break; + } + case pb_t: { + pb& p = cnstr.to_pb(); + ineq.reset(offset * p.k()); + for (wliteral wl : p) ineq.push(wl.second, offset * wl.first); + if (p.lit() != null_literal) ineq.push(~p.lit(), offset * p.k()); + break; + } + case xr_t: { + xr& x = cnstr.to_xr(); + literal_vector ls; + SASSERT(lit != null_literal); + get_antecedents(lit, x, ls); + ineq.reset(offset); + for (literal l : ls) ineq.push(~l, offset); + literal lxr = x.lit(); + if (lxr != null_literal) ineq.push(~lxr, offset); + break; + } + default: + UNREACHABLE(); + break; + } + } // validate that m_A & m_B implies m_C diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index bae59f45a..6adde156d 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -208,8 +208,14 @@ namespace sat { svector m_coeffs; uint64_t m_k; ineq(): m_k(0) {} + unsigned size() const { return m_lits.size(); } + literal lit(unsigned i) const { return m_lits[i]; } + uint64_t coeff(unsigned i) const { return m_coeffs[i]; } void reset(uint64_t k) { m_lits.reset(); m_coeffs.reset(); m_k = k; } void push(literal l, uint64_t c) { m_lits.push_back(l); m_coeffs.push_back(c); } + uint64_t coeff(literal lit) const; + void divide(uint64_t c); + void weaken(unsigned i); }; solver* m_solver; @@ -396,10 +402,22 @@ namespace sat { lbool eval(model const& m, pb const& p) const; double get_reward(pb const& p, literal_occs_fun& occs) const; + // RoundingPb conflict resolution + lbool resolve_conflict_rs(); + void round_to_one(ineq& ineq, literal lit); + void round_to_one(literal lit); + void divide(uint64_t c); + void resolve_on(literal lit); + void resolve_with(ineq const& ineq); + void reset_marks(unsigned idx); + + void bail_resolve_conflict(unsigned idx); + // access solver inline lbool value(bool_var v) const { return value(literal(v, false)); } inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } inline lbool value(model const& m, literal l) const { return l.sign() ? ~m[l.var()] : m[l.var()]; } + inline bool is_false(literal lit) const { return l_false == value(lit); } inline unsigned lvl(literal lit) const { return m_lookahead || m_unit_walk ? 0 : m_solver->lvl(lit); } inline unsigned lvl(bool_var v) const { return m_lookahead || m_unit_walk ? 0 : m_solver->lvl(v); } @@ -426,9 +444,10 @@ namespace sat { mutable bool m_overflow; void reset_active_var_set(); - void normalize_active_coeffs(); void inc_coeff(literal l, unsigned offset); int64_t get_coeff(bool_var v) const; + uint64_t get_coeff(literal lit) const; + void get_coeff(bool_var v, literal& l, unsigned& c); unsigned get_abs_coeff(bool_var v) const; int get_int_coeff(bool_var v) const; unsigned get_bound() const; @@ -436,6 +455,7 @@ namespace sat { literal get_asserting_literal(literal conseq); void process_antecedent(literal l, unsigned offset); + void process_antecedent(literal l) { process_antecedent(l, 1); } void process_card(card& c, unsigned offset); void cut(); bool create_asserting_lemma(); @@ -466,10 +486,13 @@ namespace sat { void active2pb(ineq& p); constraint* active2constraint(); constraint* active2card(); + void active2wlits(); void justification2pb(justification const& j, literal lit, unsigned offset, ineq& p); + void constraint2pb(constraint& cnstr, literal lit, unsigned offset, ineq& p); bool validate_resolvent(); + unsigned get_coeff(ineq const& pb, literal lit); - void display(std::ostream& out, ineq& p, bool values = false) const; + void display(std::ostream& out, ineq const& p, bool values = false) const; void display(std::ostream& out, card const& c, bool values) const; void display(std::ostream& out, pb const& p, bool values) const; void display(std::ostream& out, xr const& c, bool values) const; diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index 48009be31..0cf2d9be4 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -701,7 +701,8 @@ namespace smt { ctx.mk_th_axiom(get_id(), 1, &lit); time_t start_lb = std::numeric_limits::max(); - time_t end_ub = 0; + time_t runtime_lb = std::numeric_limits::max(); + time_t end_ub = 0, runtime_ub = 0; for (job_resource const& jr : ji.m_resources) { unsigned r = jr.m_resource_id; res_info const& ri = m_resources[r]; @@ -714,6 +715,9 @@ namespace smt { if (last_available(jr, ri, idx)) { end_ub = std::max(end_ub, ri.m_available[idx].m_end); } + runtime_lb = std::min(runtime_lb, jr.m_capacity); + // TBD: more accurate estimates for runtime_lb based on gaps + // TBD: correct estimate of runtime_ub taking gaps into account. } // start(j) >= start_lb @@ -723,6 +727,9 @@ namespace smt { // end(j) <= end_ub lit = mk_le(ji.m_end, end_ub); ctx.mk_th_axiom(get_id(), 1, &lit); + + // start(j) + runtime_lb <= end(j) + // end(j) <= start(j) + runtime_ub } TRACE("csp", tout << "add-done end\n";); From c39d7c8565c1cbf37252c40ace6900c79c834f8b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Sep 2018 11:17:50 -0700 Subject: [PATCH 030/227] updated resolvents Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 2 +- src/sat/ba_solver.cpp | 443 ++++++++++++++++++++++++++-------------- src/sat/ba_solver.h | 46 +++-- src/sat/sat_big.cpp | 34 +-- src/sat/sat_big.h | 6 +- src/sat/sat_scc.h | 1 - 6 files changed, 349 insertions(+), 183 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index e5c0bcddb..5d4eb3fc5 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -351,7 +351,7 @@ namespace opt { void context::get_model_core(model_ref& mdl) { mdl = m_model; fix_model(mdl); - mdl->set_model_completion(true); + if (mdl) mdl->set_model_completion(true); TRACE("opt", tout << *mdl;); } diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index c86ea3317..2c33bd955 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -49,6 +49,11 @@ namespace sat { return static_cast(*this); } + ba_solver::pb_base const& ba_solver::constraint::to_pb_base() const{ + SASSERT(is_pb() || is_card()); + return static_cast(*this); + } + ba_solver::xr& ba_solver::constraint::to_xr() { SASSERT(is_xr()); return static_cast(*this); @@ -1015,6 +1020,7 @@ namespace sat { bool_var v = l.var(); SASSERT(v != null_bool_var); m_coeffs.reserve(v + 1, 0); + TRACE("ba_verbose", tout << l << " " << offset << "\n";); int64_t coeff0 = m_coeffs[v]; if (coeff0 == 0) { @@ -1064,6 +1070,7 @@ namespace sat { l = literal(v, c1 < 0); c1 = std::abs(c1); c = static_cast(c1); + // TRACE("ba", tout << l << " " << c << "\n";); m_overflow |= c != c1; } @@ -1096,6 +1103,17 @@ namespace sat { m_active_vars.reset(); } + void ba_solver::init_visited() { + m_visited_ts++; + if (m_visited_ts == 0) { + m_visited_ts = 1; + m_visited.reset(); + } + while (m_visited.size() < 2*s().num_vars()) { + m_visited.push_back(0); + } + } + static bool _debug_conflict = false; static literal _debug_consequent = null_literal; static unsigned_vector _debug_var2position; @@ -1120,7 +1138,7 @@ namespace sat { IF_VERBOSE(0, active2pb(m_A); uint64_t c = 0; - for (uint64_t c1 : m_A.m_coeffs) c += c1; + for (wliteral l : m_A.m_wlits) c += l.first; verbose_stream() << "sum of coefficients: " << c << "\n"; display(verbose_stream(), m_A, true); verbose_stream() << "conflicting literal: " << s().m_not_l << "\n";); @@ -1154,6 +1172,9 @@ namespace sat { justification js = s().m_conflict; TRACE("ba", tout << consequent << " " << js << "\n";); m_conflict_lvl = s().get_max_lvl(consequent, js); + if (m_conflict_lvl == 0) { + return l_undef; + } if (consequent != null_literal) { consequent.neg(); process_antecedent(consequent, 1); @@ -1316,27 +1337,14 @@ namespace sat { DEBUG_CODE(for (bool_var i = 0; i < static_cast(s().num_vars()); ++i) SASSERT(!s().is_marked(i));); SASSERT(validate_lemma()); - if (!create_asserting_lemma()) { goto bail_out; } + active2card(); + DEBUG_CODE(VERIFY(validate_conflict(m_lemma, m_A));); - TRACE("ba", tout << m_lemma << "\n";); - - if (get_config().m_drat) { - svector ps; // TBD fill in - drat_add(m_lemma, ps); - } - - s().m_lemma.reset(); - s().m_lemma.append(m_lemma); - for (unsigned i = 1; i < m_lemma.size(); ++i) { - CTRACE("ba", s().is_marked(m_lemma[i].var()), tout << "marked: " << m_lemma[i] << "\n";); - s().mark(m_lemma[i].var()); - } - return l_true; bail_out: @@ -1345,8 +1353,7 @@ namespace sat { } - uint64_t ba_solver::ineq::coeff(literal l) const { - bool_var v = l.var(); + unsigned ba_solver::ineq::bv_coeff(bool_var v) const { for (unsigned i = size(); i-- > 0; ) { if (lit(i).var() == v) return coeff(i); } @@ -1354,10 +1361,10 @@ namespace sat { return 0; } - void ba_solver::ineq::divide(uint64_t c) { + void ba_solver::ineq::divide(unsigned c) { if (c == 1) return; for (unsigned i = size(); i-- > 0; ) { - m_coeffs[i] = (m_coeffs[i] + c - 1) / c; + m_wlits[i].first = (coeff(i) + c - 1) / c; } m_k = (m_k + c - 1) / c; } @@ -1366,48 +1373,57 @@ namespace sat { * Remove literal at position i, subtract coefficient from bound. */ void ba_solver::ineq::weaken(unsigned i) { - uint64_t ci = coeff(i); + unsigned ci = coeff(i); SASSERT(m_k >= ci); m_k -= ci; - m_lits[i] = m_lits.back(); - m_coeffs[i] = m_coeffs.back(); - m_lits.pop_back(); - m_coeffs.pop_back(); + m_wlits[i] = m_wlits.back(); + m_wlits.pop_back(); } /** * Round coefficient of inequality to 1. */ - void ba_solver::round_to_one(ineq& ineq, literal lit) { - uint64_t c = ineq.coeff(lit); + void ba_solver::round_to_one(ineq& ineq, bool_var v) { + unsigned c = ineq.bv_coeff(v); if (c == 1) return; unsigned sz = ineq.size(); for (unsigned i = 0; i < sz; ++i) { - uint64_t ci = ineq.coeff(i); - if (ci % c != 0 && !is_false(ineq.lit(i))) { - ineq.weaken(i); - --i; - --sz; + unsigned ci = ineq.coeff(i); + unsigned q = ci % c; + if (q != 0 && !is_false(ineq.lit(i))) { + if (q == ci) { + ineq.weaken(i); + --i; + --sz; + } + else { + ineq.m_wlits[i].first -= q; + ineq.m_k -= q; + } } } ineq.divide(c); } - void ba_solver::round_to_one(literal lit) { - uint64_t c = get_coeff(lit); - if (c == 1) return; + void ba_solver::round_to_one(bool_var w) { + unsigned c = get_abs_coeff(w); + if (c == 1 || c == 0) return; for (bool_var v : m_active_vars) { literal l; unsigned ci; get_coeff(v, l, ci); - if (ci > 0 && ci % c != 0 && !is_false(l)) { - m_coeffs[v] = 0; + unsigned q = ci % c; + if (q != 0 && !is_false(l)) { + m_coeffs[v] = ci - q; + m_bound -= q; + SASSERT(m_bound > 0); } } divide(c); + SASSERT(validate_lemma()); } - void ba_solver::divide(uint64_t c) { + void ba_solver::divide(unsigned c) { SASSERT(c != 0); if (c == 1) return; reset_active_var_set(); @@ -1426,20 +1442,17 @@ namespace sat { m_active_vars[j++] = v; } m_active_vars.shrink(j); - if (m_bound % c != 0) { - ++m_stats.m_num_cut; - m_bound = static_cast((m_bound + c - 1) / c); - } + m_bound = static_cast((m_bound + c - 1) / c); } void ba_solver::resolve_on(literal consequent) { - round_to_one(consequent); + round_to_one(consequent.var()); m_coeffs[consequent.var()] = 0; } void ba_solver::resolve_with(ineq const& ineq) { TRACE("ba", display(tout, ineq, true);); - inc_bound(1 + ineq.m_k); + inc_bound(ineq.m_k); for (unsigned i = ineq.size(); i-- > 0; ) { literal l = ineq.lit(i); inc_coeff(l, static_cast(ineq.coeff(i))); @@ -1457,6 +1470,23 @@ namespace sat { --idx; } } + + /** + * \brief mark variables that are on the assignment stack but + * below the current processing level. + */ + void ba_solver::mark_variables(ineq const& ineq) { + for (wliteral wl : ineq.m_wlits) { + literal l = wl.second; + if (!is_false(l)) continue; + bool_var v = l.var(); + unsigned level = lvl(v); + if (!s().is_marked(v) && !is_visited(v) && level == m_conflict_lvl) { + s().mark(v); + ++m_num_marks; + } + } + } lbool ba_solver::resolve_conflict_rs() { if (0 == m_num_propagations_since_pop) { @@ -1464,49 +1494,56 @@ namespace sat { } m_overflow = false; reset_coeffs(); + init_visited(); m_num_marks = 0; m_bound = 0; literal consequent = s().m_not_l; justification js = s().m_conflict; - TRACE("ba", tout << consequent << " " << js << "\n";); m_conflict_lvl = s().get_max_lvl(consequent, js); + if (m_conflict_lvl == 0) { + return l_undef; + } if (consequent != null_literal) { consequent.neg(); process_antecedent(consequent, 1); } + TRACE("ba", tout << consequent << " " << js << "\n";); unsigned idx = s().m_trail.size() - 1; do { - // TBD: termination condition - // if UIP is below m_conflict level - TRACE("ba", s().display_justification(tout << "process consequent: " << consequent << " : ", js) << "\n"; - active2pb(m_A); display(tout, m_A, true); + if (consequent != null_literal) { active2pb(m_A); display(tout, m_A, true); } ); + switch (js.get_kind()) { case justification::NONE: SASSERT(consequent != null_literal); - resolve_on(consequent); + inc_bound(1); + round_to_one(consequent.var()); + inc_coeff(consequent, 1); break; case justification::BINARY: SASSERT(consequent != null_literal); - resolve_on(consequent); + inc_bound(1); + round_to_one(consequent.var()); + inc_coeff(consequent, 1); process_antecedent(js.get_literal()); break; case justification::TERNARY: SASSERT(consequent != null_literal); - resolve_on(consequent); + inc_bound(1); + round_to_one(consequent.var()); + inc_coeff(consequent, 1); process_antecedent(js.get_literal1()); process_antecedent(js.get_literal2()); break; case justification::CLAUSE: { + inc_bound(1); clause & c = s().get_clause(js); unsigned i = 0; - if (consequent == null_literal) { - m_bound = 1; - } - else { - resolve_on(consequent); + if (consequent != null_literal) { + round_to_one(consequent.var()); + inc_coeff(consequent, 1); if (c[0] == consequent) { i = 1; } @@ -1525,25 +1562,51 @@ namespace sat { ++m_stats.m_num_resolves; ext_justification_idx index = js.get_ext_justification_idx(); constraint& cnstr = index2constraint(index); - constraint2pb(cnstr, consequent, 1, m_A); + switch (cnstr.tag()) { + case card_t: + case pb_t: { + pb_base const& p = cnstr.to_pb_base(); + unsigned k = p.k(), sz = p.size(); + m_A.reset(0); + for (unsigned i = 0; i < sz; ++i) { + literal l = p.get_lit(i); + unsigned c = p.get_coeff(i); + if (l == consequent || !is_visited(l.var())) { + m_A.push(l, c); + } + else { + SASSERT(k > c); + k -= c; + } + } + SASSERT(k > 0); + if (p.lit() != null_literal) m_A.push(~p.lit(), k); + m_A.m_k = k; + break; + } + default: + constraint2pb(cnstr, consequent, 1, m_A); + break; + } + mark_variables(m_A); if (consequent == null_literal) { m_bound = static_cast(m_A.m_k); - for (unsigned i = m_A.size(); i-- > 0; ) { - inc_coeff(m_A.lit(i), static_cast(m_A.coeff(i))); + for (wliteral wl : m_A.m_wlits) { + process_antecedent(wl.second, wl.first); } } else { - round_to_one(consequent); - round_to_one(m_A, consequent); + round_to_one(consequent.var()); + if (cnstr.tag() == pb_t) round_to_one(m_A, consequent.var()); resolve_with(m_A); } - break; } default: UNREACHABLE(); break; } + SASSERT(validate_lemma()); cut(); // find the next marked variable in the assignment stack @@ -1551,7 +1614,14 @@ namespace sat { while (true) { consequent = s().m_trail[idx]; v = consequent.var(); - if (s().is_marked(v)) break; + mark_visited(v); + if (s().is_marked(v)) { + if (get_coeff(v) != 0) { + break; + } + s().reset_mark(v); + --m_num_marks; + } if (idx == 0) { goto bail_out; } @@ -1567,20 +1637,24 @@ namespace sat { while (m_num_marks > 0 && !m_overflow); TRACE("ba", active2pb(m_A); display(tout, m_A, true);); - active2constraint(); - if (!m_overflow) { +#if 0 + // why this? + if (!m_overflow && consequent != null_literal) { + round_to_one(consequent.var()); + } +#endif + if (!m_overflow && create_asserting_lemma()) { + active2constraint(); return l_true; } bail_out: + IF_VERBOSE(1, verbose_stream() << "bail\n"); m_overflow = false; return l_undef; } bool ba_solver::create_asserting_lemma() { - bool adjusted = false; - - adjust_conflict_level: int64_t bound64 = m_bound; int64_t slack = -bound64; for (bool_var v : m_active_vars) { @@ -1629,20 +1703,22 @@ namespace sat { if (m_lemma[0] == null_literal) { if (m_lemma.size() == 1) { s().set_conflict(justification()); - return false; } return false; - unsigned old_level = m_conflict_lvl; - m_conflict_lvl = 0; - for (unsigned i = 1; i < m_lemma.size(); ++i) { - m_conflict_lvl = std::max(m_conflict_lvl, lvl(m_lemma[i])); - } - IF_VERBOSE(1, verbose_stream() << "(sat.backjump :new-level " << m_conflict_lvl << " :old-level " << old_level << ")\n";); - adjusted = true; - goto adjust_conflict_level; } - if (!adjusted) { - active2card(); + + TRACE("ba", tout << m_lemma << "\n";); + + if (get_config().m_drat) { + svector ps; // TBD fill in + drat_add(m_lemma, ps); + } + + s().m_lemma.reset(); + s().m_lemma.append(m_lemma); + for (unsigned i = 1; i < m_lemma.size(); ++i) { + CTRACE("ba", s().is_marked(m_lemma[i].var()), tout << "marked: " << m_lemma[i] << "\n";); + s().mark(m_lemma[i].var()); } return true; } @@ -1732,7 +1808,7 @@ namespace sat { bool_var v = l.var(); unsigned level = lvl(v); - if (level > 0 && !s().is_marked(v) && level == m_conflict_lvl) { + if (!s().is_marked(v) && level == m_conflict_lvl) { s().mark(v); ++m_num_marks; if (_debug_conflict && _debug_consequent != null_literal && _debug_var2position[_debug_consequent.var()] < _debug_var2position[l.var()]) { @@ -2724,7 +2800,8 @@ namespace sat { set_non_external(); if (get_config().m_elim_vars) elim_pure(); for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) subsumption(*m_constraints[i]); - for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) subsumption(*m_learned[i]); + for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) subsumption(*m_learned[i]); + unit_strengthen(); cleanup_clauses(); cleanup_constraints(); update_pure(); @@ -3170,9 +3247,10 @@ namespace sat { bool found_dup = false; bool found_root = false; + init_visited(); for (unsigned i = 0; i < c.size(); ++i) { literal l = c.get_lit(i); - if (is_marked(l)) { + if (is_visited(l)) { found_dup = true; break; } @@ -3182,10 +3260,7 @@ namespace sat { } } for (unsigned i = 0; i < c.size(); ++i) { - literal l = c.get_lit(i); - unmark_visited(l); - unmark_visited(~l); - found_root |= l.var() == root.var(); + found_root |= c.get_lit(i).var() == root.var(); } if (found_root) { @@ -3342,6 +3417,78 @@ namespace sat { return pure_literals; } + /** + * Strengthen inequalities using binary implication information. + * + * x -> ~y, x -> ~z, y + z + u >= 2 + * ---------------------------------- + * y + z + u + ~x >= 3 + * + * for c : constraints + * for l : c: + * slack <- of c under root(~l) + * if slack < 0: + * add ~root(~l) to c, k <- k + 1 + */ + void ba_solver::unit_strengthen() { + big big(s().m_rand); + big.init(s(), true); + for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) + unit_strengthen(big, *m_constraints[i]); + for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) + unit_strengthen(big, *m_learned[i]); + } + + void ba_solver::unit_strengthen(big& big, constraint& c) { + if (c.was_removed()) return; + switch (c.tag()) { + case card_t: + unit_strengthen(big, c.to_card()); + break; + case pb_t: + unit_strengthen(big, c.to_pb()); + break; + default: + break; + } + } + + void ba_solver::unit_strengthen(big& big, card& c) { + for (literal l : c) { + literal r = big.get_root(~l); + if (r == ~l) continue; + unsigned k = c.k(); + for (literal u : c) { + if (big.reaches(r, ~u)) { + if (k == 0) { + // ~r + C >= c.k() + 1 + IF_VERBOSE(0, verbose_stream() << "TBD add " << ~r << " to " << c << "\n";); + return; + } + --k; + } + } + } + } + + void ba_solver::unit_strengthen(big& big, pb& p) { + for (wliteral wl : p) { + literal r = big.get_root(~wl.second); + if (r == ~wl.second) continue; + unsigned k = p.k(); + for (wliteral u : p) { + if (big.reaches(r, ~u.second)) { + if (k < u.first) { + // ~r + p >= p.k() + 1 + IF_VERBOSE(0, verbose_stream() << "TBD add " << ~r << " to " << p << "\n";); + return; + } + k -= u.first; + } + } + } + } + void ba_solver::subsumption(constraint& cnstr) { if (cnstr.was_removed()) return; switch (cnstr.tag()) { @@ -3430,10 +3577,10 @@ namespace sat { unsigned common = 0; comp.reset(); for (literal l : c2) { - if (is_marked(l)) { + if (is_visited(l)) { ++common; } - else if (is_marked(~l)) { + else if (is_visited(~l)) { comp.push_back(l); } else { @@ -3455,10 +3602,10 @@ namespace sat { self = false; for (literal l : c2) { - if (is_marked(l)) { + if (is_visited(l)) { ++common; } - else if (is_marked(~l)) { + else if (is_visited(~l)) { ++complement; } else { @@ -3482,10 +3629,10 @@ namespace sat { unsigned num_sub = 0; for (unsigned i = 0; i < p2.size(); ++i) { literal l = p2.get_lit(i); - if (is_marked(l) && m_weights[l.index()] <= p2.get_coeff(i)) { + if (is_visited(l) && m_weights[l.index()] <= p2.get_coeff(i)) { ++num_sub; } - if (p1.size() + i > p2.size() + num_sub) return false; + if (p1.size() + i > p2.size() + num_sub) return false; } return num_sub == p1.size(); } @@ -3550,7 +3697,7 @@ namespace sat { clear_watch(c2); unsigned j = 0; for (unsigned i = 0; i < c2.size(); ++i) { - if (!is_marked(~c2[i])) { + if (!is_visited(~c2[i])) { c2[j++] = c2[i]; } } @@ -3586,7 +3733,7 @@ namespace sat { void ba_solver::binary_subsumption(card& c1, literal lit) { if (c1.k() + 1 != c1.size()) return; - SASSERT(is_marked(lit)); + SASSERT(is_visited(lit)); SASSERT(!c1.was_removed()); watch_list & wlist = get_wlist(~lit); watch_list::iterator it = wlist.begin(); @@ -3594,7 +3741,7 @@ namespace sat { watch_list::iterator end = wlist.end(); for (; it != end; ++it) { watched w = *it; - if (w.is_binary_clause() && is_marked(w.get_literal())) { + if (w.is_binary_clause() && is_visited(w.get_literal())) { ++m_stats.m_num_bin_subsumes; IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); if (!w.is_learned()) { @@ -3616,6 +3763,7 @@ namespace sat { return; } clause_vector removed_clauses; + init_visited(); for (literal l : c1) mark_visited(l); for (unsigned i = 0; i < std::min(c1.size(), c1.k() + 1); ++i) { literal lit = c1[i]; @@ -3623,7 +3771,6 @@ namespace sat { clause_subsumption(c1, lit, removed_clauses); binary_subsumption(c1, lit); } - for (literal l : c1) unmark_visited(l); m_clause_removed |= !removed_clauses.empty(); for (clause *c : removed_clauses) { c->set_removed(true); @@ -3635,6 +3782,7 @@ namespace sat { if (p1.was_removed() || p1.lit() != null_literal) { return; } + init_visited(); for (wliteral l : p1) { SASSERT(m_weights[l.second.index()] == 0); m_weights.setx(l.second.index(), l.first, 0); @@ -3646,7 +3794,6 @@ namespace sat { } for (wliteral l : p1) { m_weights[l.second.index()] = 0; - unmark_visited(l.second); } } @@ -3844,9 +3991,9 @@ namespace sat { } void ba_solver::display(std::ostream& out, ineq const& ineq, bool values) const { - for (unsigned i = 0; i < ineq.m_lits.size(); ++i) { - out << ineq.m_coeffs[i] << "*" << ineq.m_lits[i] << " "; - if (values) out << value(ineq.m_lits[i]) << " "; + for (unsigned i = 0; i < ineq.size(); ++i) { + out << ineq.coeff(i) << "*" << ineq.lit(i) << " "; + if (values) out << value(ineq.lit(i)) << " "; } out << ">= " << ineq.m_k << "\n"; } @@ -4031,14 +4178,11 @@ namespace sat { reset_active_var_set(); for (bool_var v : m_active_vars) { if (m_active_var_set.contains(v)) continue; - int64_t coeff = get_coeff(v); + unsigned coeff; + literal lit; + get_coeff(v, lit, coeff); if (coeff == 0) continue; - m_active_var_set.insert(v); - literal lit(v, false); - if (coeff < 0 && value(lit) != l_true) { - val -= coeff; - } - else if (coeff > 0 && value(lit) != l_false) { + if (!is_false(lit)) { val += coeff; } } @@ -4051,31 +4195,26 @@ namespace sat { } void ba_solver::active2pb(ineq& p) { - reset_active_var_set(); p.reset(m_bound); + active2wlits(p.m_wlits); + } + + void ba_solver::active2wlits() { + m_wlits.reset(); + active2wlits(m_wlits); + } + + void ba_solver::active2wlits(svector& wlits) { + reset_active_var_set(); + uint64_t sum = 0; for (bool_var v : m_active_vars) { - if (m_active_var_set.contains(v)) continue; + if (m_active_var_set.contains(v)) continue; unsigned coeff; literal lit; get_coeff(v, lit, coeff); if (coeff == 0) continue; m_active_var_set.insert(v); - p.m_lits.push_back(lit); - p.m_coeffs.push_back(coeff); - } - } - - void ba_solver::active2wlits() { - reset_active_var_set(); - m_wlits.reset(); - uint64_t sum = 0; - for (bool_var v : m_active_vars) { - unsigned coeff; - literal lit; - get_coeff(v, lit, coeff); - if (m_active_var_set.contains(v) || coeff == 0) continue; - m_active_var_set.insert(v); - m_wlits.push_back(wliteral(static_cast(coeff), lit)); + wlits.push_back(wliteral(coeff, lit)); sum += coeff; } m_overflow |= sum >= UINT_MAX/2; @@ -4086,7 +4225,9 @@ namespace sat { if (m_overflow) { return nullptr; } - return add_pb_ge(null_literal, m_wlits, m_bound, true); + constraint* c = add_pb_ge(null_literal, m_wlits, m_bound, true); + TRACE("ba", if (c) display(tout, *c, true);); + return c; } /* @@ -4269,14 +4410,14 @@ namespace sat { return true; u_map coeffs; uint64_t k = m_A.m_k + m_B.m_k; - for (unsigned i = 0; i < m_A.m_lits.size(); ++i) { - uint64_t coeff = m_A.m_coeffs[i]; - SASSERT(!coeffs.contains(m_A.m_lits[i].index())); - coeffs.insert(m_A.m_lits[i].index(), coeff); + for (unsigned i = 0; i < m_A.size(); ++i) { + uint64_t coeff = m_A.coeff(i); + SASSERT(!coeffs.contains(m_A.lit(i).index())); + coeffs.insert(m_A.lit(i).index(), coeff); } - for (unsigned i = 0; i < m_B.m_lits.size(); ++i) { - uint64_t coeff1 = m_B.m_coeffs[i], coeff2; - literal lit = m_B.m_lits[i]; + for (unsigned i = 0; i < m_B.size(); ++i) { + uint64_t coeff1 = m_B.coeff(i), coeff2; + literal lit = m_B.lit(i); if (coeffs.find((~lit).index(), coeff2)) { if (coeff1 == coeff2) { coeffs.remove((~lit).index()); @@ -4301,11 +4442,11 @@ namespace sat { } } // C is above the sum of A and B - for (unsigned i = 0; i < m_C.m_lits.size(); ++i) { - literal lit = m_C.m_lits[i]; + for (unsigned i = 0; i < m_C.size(); ++i) { + literal lit = m_C.lit(i); uint64_t coeff; if (coeffs.find(lit.index(), coeff)) { - if (coeff > m_C.m_coeffs[i] && m_C.m_coeffs[i] < m_C.m_k) { + if (coeff > m_C.coeff(i) && m_C.coeff(i) < m_C.m_k) { goto violated; } coeffs.remove(lit.index()); @@ -4352,15 +4493,15 @@ namespace sat { */ literal ba_solver::translate_to_sat(solver& s, u_map& translation, ineq const& pb) { SASSERT(pb.m_k > 0); - if (pb.m_lits.size() > 1) { + if (pb.size() > 1) { ineq a, b; a.reset(pb.m_k); b.reset(pb.m_k); - for (unsigned i = 0; i < pb.m_lits.size()/2; ++i) { - a.push(pb.m_lits[i], pb.m_coeffs[i]); + for (unsigned i = 0; i < pb.size()/2; ++i) { + a.push(pb.lit(i), pb.coeff(i)); } - for (unsigned i = pb.m_lits.size()/2; i < pb.m_lits.size(); ++i) { - b.push(pb.m_lits[i], pb.m_coeffs[i]); + for (unsigned i = pb.size()/2; i < pb.size(); ++i) { + b.push(pb.lit(i), pb.coeff(i)); } bool_var v = s.mk_var(); literal lit(v, false); @@ -4372,8 +4513,8 @@ namespace sat { s.mk_clause(lits); return lit; } - if (pb.m_coeffs[0] >= pb.m_k) { - return translate_to_sat(s, translation, pb.m_lits[0]); + if (pb.coeff(0) >= pb.m_k) { + return translate_to_sat(s, translation, pb.lit(0)); } else { return null_literal; @@ -4425,9 +4566,9 @@ namespace sat { ba_solver::ineq ba_solver::negate(ineq const& a) const { ineq result; uint64_t sum = 0; - for (unsigned i = 0; i < a.m_lits.size(); ++i) { - result.push(~a.m_lits[i], a.m_coeffs[i]); - sum += a.m_coeffs[i]; + for (unsigned i = 0; i < a.size(); ++i) { + result.push(~a.lit(i), a.coeff(i)); + sum += a.coeff(i); } SASSERT(sum >= a.m_k + 1); result.m_k = sum + 1 - a.m_k; @@ -4446,15 +4587,15 @@ namespace sat { TRACE("ba", tout << "literal " << l << " is not false\n";); return false; } - if (!p.m_lits.contains(l)) { + if (!p.contains(l)) { TRACE("ba", tout << "lemma contains literal " << l << " not in inequality\n";); return false; } } uint64_t value = 0; - for (unsigned i = 0; i < p.m_lits.size(); ++i) { - uint64_t coeff = p.m_coeffs[i]; - if (!lits.contains(p.m_lits[i])) { + for (unsigned i = 0; i < p.size(); ++i) { + uint64_t coeff = p.coeff(i); + if (!lits.contains(p.lit(i))) { value += coeff; } } diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 6adde156d..9418cdd99 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -25,6 +25,7 @@ Revision History: #include "sat/sat_solver.h" #include "sat/sat_lookahead.h" #include "sat/sat_unit_walk.h" +#include "sat/sat_big.h" #include "util/scoped_ptr_vector.h" #include "util/sorting_network.h" @@ -57,6 +58,7 @@ namespace sat { class card; class pb; class xr; + class pb_base; class constraint { protected: @@ -104,6 +106,7 @@ namespace sat { card const& to_card() const; pb const& to_pb() const; xr const& to_xr() const; + pb_base const& to_pb_base() const; bool is_card() const { return m_tag == card_t; } bool is_pb() const { return m_tag == pb_t; } bool is_xr() const { return m_tag == xr_t; } @@ -118,7 +121,7 @@ namespace sat { }; friend std::ostream& operator<<(std::ostream& out, constraint const& c); - + // base class for pb and cardinality constraints class pb_base : public constraint { protected: @@ -204,18 +207,18 @@ namespace sat { protected: struct ineq { - literal_vector m_lits; - svector m_coeffs; + svector m_wlits; uint64_t m_k; ineq(): m_k(0) {} - unsigned size() const { return m_lits.size(); } - literal lit(unsigned i) const { return m_lits[i]; } - uint64_t coeff(unsigned i) const { return m_coeffs[i]; } - void reset(uint64_t k) { m_lits.reset(); m_coeffs.reset(); m_k = k; } - void push(literal l, uint64_t c) { m_lits.push_back(l); m_coeffs.push_back(c); } - uint64_t coeff(literal lit) const; - void divide(uint64_t c); + unsigned size() const { return m_wlits.size(); } + literal lit(unsigned i) const { return m_wlits[i].second; } + unsigned coeff(unsigned i) const { return m_wlits[i].first; } + void reset(uint64_t k) { m_wlits.reset(); m_k = k; } + void push(literal l, unsigned c) { m_wlits.push_back(wliteral(c,l)); } + unsigned bv_coeff(bool_var v) const; + void divide(unsigned c); void weaken(unsigned i); + bool contains(literal l) const { for (auto wl : m_wlits) if (wl.second == l) return true; return false; } }; solver* m_solver; @@ -279,7 +282,8 @@ namespace sat { // simplification routines - svector m_visited; + svector m_visited; + unsigned m_visited_ts; vector> m_cnstr_use_list; use_list m_clause_use_list; bool m_simplify_change; @@ -298,9 +302,11 @@ namespace sat { void binary_subsumption(card& c1, literal lit); void clause_subsumption(card& c1, literal lit, clause_vector& removed_clauses); void card_subsumption(card& c1, literal lit); - void mark_visited(literal l) { m_visited[l.index()] = true; } - void unmark_visited(literal l) { m_visited[l.index()] = false; } - bool is_marked(literal l) const { return m_visited[l.index()] != 0; } + void init_visited(); + void mark_visited(literal l) { m_visited[l.index()] = m_visited_ts; } + void mark_visited(bool_var v) { mark_visited(literal(v, false)); } + bool is_visited(bool_var v) const { return is_visited(literal(v, false)); } + bool is_visited(literal l) const { return m_visited[l.index()] == m_visited_ts; } unsigned get_num_unblocked_bin(literal l); literal get_min_occurrence_literal(card const& c); void init_use_lists(); @@ -308,6 +314,10 @@ namespace sat { unsigned set_non_external(); unsigned elim_pure(); bool elim_pure(literal lit); + void unit_strengthen(); + void unit_strengthen(big& big, constraint& cs); + void unit_strengthen(big& big, card& c); + void unit_strengthen(big& big, pb& p); void subsumption(constraint& c1); void subsumption(card& c1); void gc_half(char const* _method); @@ -404,12 +414,13 @@ namespace sat { // RoundingPb conflict resolution lbool resolve_conflict_rs(); - void round_to_one(ineq& ineq, literal lit); - void round_to_one(literal lit); - void divide(uint64_t c); + void round_to_one(ineq& ineq, bool_var v); + void round_to_one(bool_var v); + void divide(unsigned c); void resolve_on(literal lit); void resolve_with(ineq const& ineq); void reset_marks(unsigned idx); + void mark_variables(ineq const& ineq); void bail_resolve_conflict(unsigned idx); @@ -487,6 +498,7 @@ namespace sat { constraint* active2constraint(); constraint* active2card(); void active2wlits(); + void active2wlits(svector& wlits); void justification2pb(justification const& j, literal lit, unsigned offset, ineq& p); void constraint2pb(constraint& cnstr, literal lit, unsigned offset, ineq& p); bool validate_resolvent(); diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index 35898a110..c1eeecd27 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -22,7 +22,8 @@ Revision History: namespace sat { big::big(random_gen& rand): - m_rand(rand) { + m_rand(rand), + m_include_cardinality(false) { } void big::init(solver& s, bool learned) { @@ -42,22 +43,22 @@ namespace sat { m_roots[v.index()] = false; edges.push_back(v); } -#if 0 - if (w.is_ext_constraint() && + if (m_include_cardinality && + w.is_ext_constraint() && s.m_ext && - learned && + learned && // cannot (yet) observe if ext constraints are learned !seen_idx.contains(w.get_ext_constraint_idx()) && s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), r)) { seen_idx.insert(w.get_ext_constraint_idx(), true); - for (unsigned i = 0; i < r.size(); ++i) { - literal u = r[i]; - for (unsigned j = i + 1; j < r.size(); ++j) { - // add ~r[i] -> r[j] - literal v = r[j]; - literal u = ~r[j]; + for (unsigned i = 0; i < std::min(4u, r.size()); ++i) { + shuffle(r.size(), r.c_ptr(), m_rand); + literal u = r[0]; + for (unsigned j = 1; j < r.size(); ++j) { + literal v = ~r[j]; + // add u -> v m_roots[v.index()] = false; m_dag[u.index()].push_back(v); - // add ~r[j] -> r[i] + // add ~v -> ~u v.neg(); u.neg(); m_roots[u.index()] = false; @@ -65,7 +66,6 @@ namespace sat { } } } -#endif } } done_adding_edges(); @@ -268,6 +268,16 @@ namespace sat { return out << v; } + literal big::get_root(literal l) { + literal r = l; + do { + l = r; + r = m_root[l.index()]; + } + while (r != l); + return r; + } + void big::display(std::ostream& out) const { unsigned idx = 0; for (auto& next : m_dag) { diff --git a/src/sat/sat_big.h b/src/sat/sat_big.h index 898ddd1e8..25093fd60 100644 --- a/src/sat/sat_big.h +++ b/src/sat/sat_big.h @@ -34,6 +34,7 @@ namespace sat { svector m_left, m_right; literal_vector m_root, m_parent; bool m_learned; + bool m_include_cardinality; svector> m_del_bin; @@ -54,6 +55,9 @@ namespace sat { // static svector> s_del_bin; big(random_gen& rand); + + void set_include_cardinality(bool f) { m_include_cardinality = f; } + /** \brief initialize a BIG from a solver. */ @@ -77,7 +81,7 @@ namespace sat { int get_left(literal l) const { return m_left[l.index()]; } int get_right(literal l) const { return m_right[l.index()]; } literal get_parent(literal l) const { return m_parent[l.index()]; } - literal get_root(literal l) const { return m_root[l.index()]; } + literal get_root(literal l); bool reaches(literal u, literal v) const { return m_left[u.index()] < m_left[v.index()] && m_right[v.index()] < m_right[u.index()]; } bool connected(literal u, literal v) const { return reaches(u, v) || reaches(~v, ~u); } void display(std::ostream& out) const; diff --git a/src/sat/sat_scc.h b/src/sat/sat_scc.h index 146bd2366..1ba646992 100644 --- a/src/sat/sat_scc.h +++ b/src/sat/sat_scc.h @@ -60,7 +60,6 @@ namespace sat { void ensure_big(bool learned) { m_big.ensure_big(m_solver, learned); } int get_left(literal l) const { return m_big.get_left(l); } int get_right(literal l) const { return m_big.get_right(l); } - literal get_root(literal l) const { return m_big.get_root(l); } bool connected(literal u, literal v) const { return m_big.connected(u, v); } }; }; From c8730daea783dd8bbb9ae46230d5e0b3235ddfb7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Sep 2018 16:56:07 -0700 Subject: [PATCH 031/227] fix memory leak, add strengthening Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 237 ++++++++++++++++++++++++------------ src/sat/ba_solver.h | 9 +- src/sat/sat_config.cpp | 8 ++ src/sat/sat_config.h | 6 + src/sat/sat_params.pyg | 3 +- src/sat/tactic/goal2sat.cpp | 1 + src/util/uint_set.h | 7 +- 7 files changed, 183 insertions(+), 88 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 2c33bd955..5e1febe9e 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1065,13 +1065,14 @@ namespace sat { return c; } - void ba_solver::get_coeff(bool_var v, literal& l, unsigned& c) { + ba_solver::wliteral ba_solver::get_wliteral(bool_var v) { int64_t c1 = get_coeff(v); - l = literal(v, c1 < 0); + literal l = literal(v, c1 < 0); c1 = std::abs(c1); - c = static_cast(c1); + unsigned c = static_cast(c1); // TRACE("ba", tout << l << " " << c << "\n";); m_overflow |= c != c1; + return wliteral(c, l); } unsigned ba_solver::get_abs_coeff(bool_var v) const { @@ -1121,7 +1122,6 @@ namespace sat { // #define DEBUG_CODE(_x_) _x_ void ba_solver::bail_resolve_conflict(unsigned idx) { - m_overflow = false; literal_vector const& lits = s().m_trail; while (m_num_marks > 0) { bool_var v = lits[idx].var(); @@ -1157,13 +1157,14 @@ namespace sat { } lbool ba_solver::resolve_conflict() { -#if 1 - return resolve_conflict_rs(); -#endif - if (0 == m_num_propagations_since_pop) { return l_undef; } + + if (s().m_config.m_pb_resolve == PB_ROUNDING) { + return resolve_conflict_rs(); + } + m_overflow = false; reset_coeffs(); m_num_marks = 0; @@ -1348,6 +1349,10 @@ namespace sat { return l_true; bail_out: + if (m_overflow) { + ++m_stats.m_num_overflow; + m_overflow = false; + } bail_resolve_conflict(idx); return l_undef; } @@ -1403,24 +1408,25 @@ namespace sat { } } ineq.divide(c); + TRACE("ba", display(tout << "var: " << v << " " << c << ": ", ineq, true);); } void ba_solver::round_to_one(bool_var w) { unsigned c = get_abs_coeff(w); if (c == 1 || c == 0) return; for (bool_var v : m_active_vars) { - literal l; - unsigned ci; - get_coeff(v, l, ci); - unsigned q = ci % c; - if (q != 0 && !is_false(l)) { - m_coeffs[v] = ci - q; + wliteral wl = get_wliteral(v); + unsigned q = wl.first % c; + if (q != 0 && !is_false(wl.second)) { + m_coeffs[v] = wl.first - q; m_bound -= q; SASSERT(m_bound > 0); } } + SASSERT(validate_lemma()); divide(c); SASSERT(validate_lemma()); + TRACE("ba", active2pb(m_B); display(tout, m_B, true);); } void ba_solver::divide(unsigned c) { @@ -1431,8 +1437,7 @@ namespace sat { for (unsigned i = 0; i < sz; ++i) { bool_var v = m_active_vars[i]; int ci = get_int_coeff(v); - if (m_active_var_set.contains(v) || ci == 0) continue; - m_active_var_set.insert(v); + if (!test_and_set_active(v) || ci == 0) continue; if (ci > 0) { m_coeffs[v] = (ci + c - 1) / c; } @@ -1452,10 +1457,13 @@ namespace sat { void ba_solver::resolve_with(ineq const& ineq) { TRACE("ba", display(tout, ineq, true);); - inc_bound(ineq.m_k); + inc_bound(ineq.m_k); + TRACE("ba", tout << "bound: " << m_bound << "\n";); + for (unsigned i = ineq.size(); i-- > 0; ) { literal l = ineq.lit(i); inc_coeff(l, static_cast(ineq.coeff(i))); + TRACE("ba", tout << "bound: " << m_bound << " lit: " << l << " coeff: " << ineq.coeff(i) << "\n";); } } @@ -1518,27 +1526,26 @@ namespace sat { switch (js.get_kind()) { case justification::NONE: SASSERT(consequent != null_literal); - inc_bound(1); round_to_one(consequent.var()); + inc_bound(1); inc_coeff(consequent, 1); break; case justification::BINARY: SASSERT(consequent != null_literal); - inc_bound(1); round_to_one(consequent.var()); + inc_bound(1); inc_coeff(consequent, 1); process_antecedent(js.get_literal()); break; case justification::TERNARY: SASSERT(consequent != null_literal); - inc_bound(1); round_to_one(consequent.var()); + inc_bound(1); inc_coeff(consequent, 1); process_antecedent(js.get_literal1()); process_antecedent(js.get_literal2()); break; case justification::CLAUSE: { - inc_bound(1); clause & c = s().get_clause(js); unsigned i = 0; if (consequent != null_literal) { @@ -1553,6 +1560,7 @@ namespace sat { i = 2; } } + inc_bound(1); unsigned sz = c.size(); for (; i < sz; i++) process_antecedent(c[i]); @@ -1576,6 +1584,7 @@ namespace sat { } else { SASSERT(k > c); + TRACE("ba", tout << "visited: " << l << "\n";); k -= c; } } @@ -1590,6 +1599,7 @@ namespace sat { } mark_variables(m_A); if (consequent == null_literal) { + SASSERT(validate_ineq(m_A)); m_bound = static_cast(m_A.m_k); for (wliteral wl : m_A.m_wlits) { process_antecedent(wl.second, wl.first); @@ -1597,9 +1607,11 @@ namespace sat { } else { round_to_one(consequent.var()); - if (cnstr.tag() == pb_t) round_to_one(m_A, consequent.var()); + if (cnstr.tag() == pb_t) round_to_one(m_A, consequent.var()); + SASSERT(validate_ineq(m_A)); resolve_with(m_A); } + break; } default: UNREACHABLE(); @@ -1616,13 +1628,18 @@ namespace sat { v = consequent.var(); mark_visited(v); if (s().is_marked(v)) { - if (get_coeff(v) != 0) { + int64_t c = get_coeff(v); + if (c == 0) { + CTRACE("ba", c != 0, active2pb(m_A); display(tout << consequent << ": ", m_A, true);); + s().reset_mark(v); + --m_num_marks; + } + else { break; } - s().reset_mark(v); - --m_num_marks; } if (idx == 0) { + TRACE("ba", tout << "there is no consequent\n";); goto bail_out; } --idx; @@ -1647,9 +1664,14 @@ namespace sat { active2constraint(); return l_true; } + bail_out: - IF_VERBOSE(1, verbose_stream() << "bail\n"); - m_overflow = false; + IF_VERBOSE(1, verbose_stream() << "bail " << m_overflow << "\n"); + TRACE("ba", tout << "bail " << m_overflow << "\n";); + if (m_overflow) { + ++m_stats.m_num_overflow; + m_overflow = false; + } return l_undef; } @@ -1657,9 +1679,16 @@ namespace sat { bool ba_solver::create_asserting_lemma() { int64_t bound64 = m_bound; int64_t slack = -bound64; - for (bool_var v : m_active_vars) { - slack += get_abs_coeff(v); + reset_active_var_set(); + unsigned j = 0, sz = m_active_vars.size(); + for (unsigned i = 0; i < sz; ++i) { + bool_var v = m_active_vars[i]; + unsigned c = get_abs_coeff(v); + if (!test_and_set_active(v) || c == 0) continue; + slack += c; + m_active_vars[j++] = v; } + m_active_vars.shrink(j); m_lemma.reset(); m_lemma.push_back(null_literal); unsigned num_skipped = 0; @@ -1694,16 +1723,19 @@ namespace sat { } } if (slack >= 0) { + TRACE("ba", tout << "slack is non-negative\n";); IF_VERBOSE(20, verbose_stream() << "(sat.card slack: " << slack << " skipped: " << num_skipped << ")\n";); return false; } if (m_overflow) { + TRACE("ba", tout << "overflow\n";); return false; } if (m_lemma[0] == null_literal) { if (m_lemma.size() == 1) { s().set_conflict(justification()); } + TRACE("ba", tout << "no asserting literal\n";); return false; } @@ -1767,8 +1799,7 @@ namespace sat { for (unsigned i = 0; i < sz; ++i) { bool_var v = m_active_vars[i]; int64_t c = m_coeffs[v]; - if (m_active_var_set.contains(v) || c == 0) continue; - m_active_var_set.insert(v); + if (!test_and_set_active(v) || c == 0) continue; m_coeffs[v] /= static_cast(g); m_active_vars[j++] = v; } @@ -1834,7 +1865,8 @@ namespace sat { return p; } - ba_solver::ba_solver(): m_solver(0), m_lookahead(0), m_unit_walk(0), m_constraint_id(0), m_ba(*this), m_sort(m_ba) { + ba_solver::ba_solver(): m_solver(0), m_lookahead(0), m_unit_walk(0), + m_allocator("ba"), m_constraint_id(0), m_ba(*this), m_sort(m_ba) { TRACE("ba", tout << this << "\n";); m_num_propagations_since_pop = 0; } @@ -2649,8 +2681,12 @@ namespace sat { constraint* c = m_learned[i]; if (!m_constraint_to_reinit.contains(c)) { remove_constraint(*c, "gc"); + m_allocator.deallocate(c->obj_size(), c); ++removed; } + else { + m_learned[new_sz++] = c; + } } m_stats.m_num_gc += removed; m_learned.shrink(new_sz); @@ -3453,38 +3489,58 @@ namespace sat { } } - void ba_solver::unit_strengthen(big& big, card& c) { - for (literal l : c) { - literal r = big.get_root(~l); - if (r == ~l) continue; - unsigned k = c.k(); - for (literal u : c) { - if (big.reaches(r, ~u)) { - if (k == 0) { - // ~r + C >= c.k() + 1 - IF_VERBOSE(0, verbose_stream() << "TBD add " << ~r << " to " << c << "\n";); - return; - } - --k; + void ba_solver::unit_strengthen(big& big, pb_base& p) { + if (p.lit() != null_literal) return; + unsigned sz = p.size(); + for (unsigned i = 0; i < sz; ++i) { + literal u = p.get_lit(i); + literal r = big.get_root(u); + if (r == u) continue; + unsigned k = p.k(), b = 0; + for (unsigned j = 0; j < sz; ++j) { + literal v = p.get_lit(j); + if (r == big.get_root(v)) { + b += p.get_coeff(j); } - } - } - } - - void ba_solver::unit_strengthen(big& big, pb& p) { - for (wliteral wl : p) { - literal r = big.get_root(~wl.second); - if (r == ~wl.second) continue; - unsigned k = p.k(); - for (wliteral u : p) { - if (big.reaches(r, ~u.second)) { - if (k < u.first) { - // ~r + p >= p.k() + 1 - IF_VERBOSE(0, verbose_stream() << "TBD add " << ~r << " to " << p << "\n";); - return; + } + if (b > k) { + r.neg(); + unsigned coeff = b - k; + + svector wlits; + // add coeff * r to p + wlits.push_back(wliteral(coeff, r)); + for (unsigned j = 0; j < sz; ++j) { + u = p.get_lit(j); + unsigned c = p.get_coeff(j); + if (r == u) { + wlits[0].first += c; + } + else if (~r == u) { + if (coeff == c) { + wlits[0] = wlits.back(); + wlits.pop_back(); + b -= c; + } + else if (coeff < c) { + wlits[0].first = c - coeff; + wlits[0].second.neg(); + b -= coeff; + } + else { + // coeff > c + wlits[0].first = coeff - c; + b -= c; + } + } + else { + wlits.push_back(wliteral(c, u)); } - k -= u.first; } + ++m_stats.m_num_big_strengthenings; + p.set_removed(); + constraint* c = add_pb_ge(null_literal, wlits, b, p.learned()); + return; } } } @@ -3784,7 +3840,7 @@ namespace sat { } init_visited(); for (wliteral l : p1) { - SASSERT(m_weights[l.second.index()] == 0); + SASSERT(m_weights.get(l.second.index(), 0) == 0); m_weights.setx(l.second.index(), l.first, 0); mark_visited(l.second); } @@ -3992,7 +4048,8 @@ namespace sat { void ba_solver::display(std::ostream& out, ineq const& ineq, bool values) const { for (unsigned i = 0; i < ineq.size(); ++i) { - out << ineq.coeff(i) << "*" << ineq.lit(i) << " "; + if (ineq.coeff(i) != 1) out << ineq.coeff(i) << "*"; + out << ineq.lit(i) << " "; if (values) out << value(ineq.lit(i)) << " "; } out << ">= " << ineq.m_k << "\n"; @@ -4083,6 +4140,8 @@ namespace sat { st.update("ba resolves", m_stats.m_num_resolves); st.update("ba cuts", m_stats.m_num_cut); st.update("ba gc", m_stats.m_num_gc); + st.update("ba overflow", m_stats.m_num_overflow); + st.update("ba big strengthenings", m_stats.m_num_big_strengthenings); } bool ba_solver::validate_unit_propagation(card const& c, literal alit) const { @@ -4177,23 +4236,44 @@ namespace sat { int64_t val = -bound64; reset_active_var_set(); for (bool_var v : m_active_vars) { - if (m_active_var_set.contains(v)) continue; - unsigned coeff; - literal lit; - get_coeff(v, lit, coeff); - if (coeff == 0) continue; - if (!is_false(lit)) { - val += coeff; + if (!test_and_set_active(v)) continue; + wliteral wl = get_wliteral(v); + if (wl.first == 0) continue; + if (!is_false(wl.second)) { + val += wl.first; } } - CTRACE("ba", val >= 0, active2pb(m_A); display(tout, m_A);); + CTRACE("ba", val >= 0, active2pb(m_A); display(tout, m_A, true);); return val < 0; } + /** + * the slack of inequalities on the stack should be non-positive. + */ + bool ba_solver::validate_ineq(ineq const& ineq) const { + int64_t k = -static_cast(ineq.m_k); + for (wliteral wl : ineq.m_wlits) { + if (!is_false(wl.second)) + k += wl.first; + } + CTRACE("ba", k > 0, display(tout, ineq, true);); + return k <= 0; + } + void ba_solver::reset_active_var_set() { while (!m_active_var_set.empty()) m_active_var_set.erase(); } + bool ba_solver::test_and_set_active(bool_var v) { + if (m_active_var_set.contains(v)) { + return false; + } + else { + m_active_var_set.insert(v); + return true; + } + } + void ba_solver::active2pb(ineq& p) { p.reset(m_bound); active2wlits(p.m_wlits); @@ -4205,17 +4285,14 @@ namespace sat { } void ba_solver::active2wlits(svector& wlits) { - reset_active_var_set(); uint64_t sum = 0; + reset_active_var_set(); for (bool_var v : m_active_vars) { - if (m_active_var_set.contains(v)) continue; - unsigned coeff; - literal lit; - get_coeff(v, lit, coeff); - if (coeff == 0) continue; - m_active_var_set.insert(v); - wlits.push_back(wliteral(coeff, lit)); - sum += coeff; + if (!test_and_set_active(v)) continue; + wliteral wl = get_wliteral(v); + if (wl.first == 0) continue; + wlits.push_back(wl); + sum += wl.first; } m_overflow |= sum >= UINT_MAX/2; } diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 9418cdd99..b547c2292 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -42,8 +42,10 @@ namespace sat { unsigned m_num_bin_subsumes; unsigned m_num_clause_subsumes; unsigned m_num_pb_subsumes; + unsigned m_num_big_strengthenings; unsigned m_num_cut; unsigned m_num_gc; + unsigned m_num_overflow; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; @@ -316,8 +318,7 @@ namespace sat { bool elim_pure(literal lit); void unit_strengthen(); void unit_strengthen(big& big, constraint& cs); - void unit_strengthen(big& big, card& c); - void unit_strengthen(big& big, pb& p); + void unit_strengthen(big& big, pb_base& p); void subsumption(constraint& c1); void subsumption(card& c1); void gc_half(char const* _method); @@ -455,10 +456,11 @@ namespace sat { mutable bool m_overflow; void reset_active_var_set(); + bool test_and_set_active(bool_var v); void inc_coeff(literal l, unsigned offset); int64_t get_coeff(bool_var v) const; uint64_t get_coeff(literal lit) const; - void get_coeff(bool_var v, literal& l, unsigned& c); + wliteral get_wliteral(bool_var v); unsigned get_abs_coeff(bool_var v) const; int get_int_coeff(bool_var v) const; unsigned get_bound() const; @@ -477,6 +479,7 @@ namespace sat { bool validate_conflict(pb const& p) const; bool validate_assign(literal_vector const& lits, literal lit); bool validate_lemma(); + bool validate_ineq(ineq const& ineq) const; bool validate_unit_propagation(card const& c, literal alit) const; bool validate_unit_propagation(pb const& p, literal alit) const; bool validate_unit_propagation(pb const& p, literal_vector const& r, literal alit) const; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index c7f2377c9..ad83fac7a 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -196,6 +196,14 @@ namespace sat { else throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting, segmented"); + s = p.pb_resolve(); + if (s == "cardinality") + m_pb_resolve = PB_CARDINALITY; + else if (s == "rounding") + m_pb_resolve = PB_ROUNDING; + else + throw sat_param_exception("invalid PB resolve: 'cardinality' or 'resolve' expected"); + m_card_solver = p.cardinality_solver(); sat_simplifier_params sp(_p); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 37efe69ed..40ab5fa38 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -60,6 +60,11 @@ namespace sat { PB_SEGMENTED }; + enum pb_resolve { + PB_CARDINALITY, + PB_ROUNDING + }; + enum reward_t { ternary_reward, unit_literal_reward, @@ -148,6 +153,7 @@ namespace sat { pb_solver m_pb_solver; bool m_card_solver; + pb_resolve m_pb_resolve; // branching heuristic settings. branching_heuristic m_branching_heuristic; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 89776c479..7c289a900 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -42,8 +42,9 @@ def_module_params('sat', ('drat.check_sat', BOOL, False, 'build up internal trace, check satisfying model'), ('cardinality.solver', BOOL, True, 'use cardinality solver'), ('pb.solver', SYMBOL, 'solver', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use native solver)'), - ('xor.solver', BOOL, False, 'use xor solver'), + ('xor.solver', BOOL, False, 'use xor solver'), ('cardinality.encoding', SYMBOL, 'grouped', 'encoding used for at-most-k constraints: grouped, bimander, ordered, unate, circuit'), + ('pb.resolve', SYMBOL, 'cardinality', 'resolution strategy for boolean algebra solver: cardinality, rounding'), ('local_search', BOOL, False, 'use local search instead of CDCL'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search_mode', SYMBOL, 'wsat', 'local search algorithm, either default wsat or qsat'), diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 7faa89370..9d0d29ac0 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -82,6 +82,7 @@ struct goal2sat::imp { m_is_lemma(false) { updt_params(p); m_true = sat::null_bool_var; + mk_true(); } void updt_params(params_ref const & p) { diff --git a/src/util/uint_set.h b/src/util/uint_set.h index 0f3715cb1..e6518b435 100644 --- a/src/util/uint_set.h +++ b/src/util/uint_set.h @@ -269,10 +269,9 @@ public: void remove(unsigned v) { if (contains(v)) { m_in_set[v] = false; - unsigned i = 0; - for (i = 0; i < m_set.size() && m_set[i] != v; ++i) - ; - SASSERT(i < m_set.size()); + unsigned i = m_set.size(); + for (; i > 0 && m_set[--i] != v; ) ; + SASSERT(m_set[i] == v); m_set[i] = m_set.back(); m_set.pop_back(); } From 9ad17296c2e49b078c4ea343e58944f5f675b692 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Sep 2018 17:22:48 -0700 Subject: [PATCH 032/227] update parameters Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 35 +++++++++++++++++++++-------------- src/sat/ba_solver.h | 2 ++ src/sat/sat_config.cpp | 8 ++++++++ src/sat/sat_config.h | 6 ++++++ src/sat/sat_params.pyg | 1 + 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 5e1febe9e..f6c544cdf 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1341,7 +1341,7 @@ namespace sat { if (!create_asserting_lemma()) { goto bail_out; } - active2card(); + active2lemma(); DEBUG_CODE(VERIFY(validate_conflict(m_lemma, m_A));); @@ -1654,19 +1654,16 @@ namespace sat { while (m_num_marks > 0 && !m_overflow); TRACE("ba", active2pb(m_A); display(tout, m_A, true);); -#if 0 - // why this? + // TBD: check if this is useful if (!m_overflow && consequent != null_literal) { round_to_one(consequent.var()); } -#endif if (!m_overflow && create_asserting_lemma()) { - active2constraint(); + active2lemma(); return l_true; } bail_out: - IF_VERBOSE(1, verbose_stream() << "bail " << m_overflow << "\n"); TRACE("ba", tout << "bail " << m_overflow << "\n";); if (m_overflow) { ++m_stats.m_num_overflow; @@ -4142,6 +4139,8 @@ namespace sat { st.update("ba gc", m_stats.m_num_gc); st.update("ba overflow", m_stats.m_num_overflow); st.update("ba big strengthenings", m_stats.m_num_big_strengthenings); + st.update("ba lemmas", m_stats.m_num_lemmas); + st.update("ba subsumes", m_stats.m_num_bin_subsumes + m_stats.m_num_clause_subsumes + m_stats.m_num_pb_subsumes); } bool ba_solver::validate_unit_propagation(card const& c, literal alit) const { @@ -4297,6 +4296,18 @@ namespace sat { m_overflow |= sum >= UINT_MAX/2; } + ba_solver::constraint* ba_solver::active2lemma() { + switch (s().m_config.m_pb_lemma_format) { + case PB_LEMMA_CARDINALITY: + return active2card(); + case PB_LEMMA_PB: + return active2constraint(); + default: + UNREACHABLE(); + return nullptr; + } + } + ba_solver::constraint* ba_solver::active2constraint() { active2wlits(); if (m_overflow) { @@ -4304,6 +4315,7 @@ namespace sat { } constraint* c = add_pb_ge(null_literal, m_wlits, m_bound, true); TRACE("ba", if (c) display(tout, *c, true);); + ++m_stats.m_num_lemmas; return c; } @@ -4381,13 +4393,7 @@ namespace sat { } if (slack >= k) { -#if 0 - return active2constraint(); - active2pb(m_A); - std::cout << "not asserting\n"; - display(std::cout, m_A, true); -#endif - return 0; + return nullptr; } // produce asserting cardinality constraint @@ -4397,8 +4403,9 @@ namespace sat { } constraint* c = add_at_least(null_literal, lits, k, true); + ++m_stats.m_num_lemmas; + if (c) { - // IF_VERBOSE(0, verbose_stream() << *c << "\n";); lits.reset(); for (wliteral wl : m_wlits) { if (value(wl.second) == l_false) lits.push_back(wl.second); diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index b547c2292..8f9488167 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -46,6 +46,7 @@ namespace sat { unsigned m_num_cut; unsigned m_num_gc; unsigned m_num_overflow; + unsigned m_num_lemmas; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; @@ -498,6 +499,7 @@ namespace sat { ineq m_A, m_B, m_C; void active2pb(ineq& p); + constraint* active2lemma(); constraint* active2constraint(); constraint* active2card(); void active2wlits(); diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index ad83fac7a..a864579f8 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -204,6 +204,14 @@ namespace sat { else throw sat_param_exception("invalid PB resolve: 'cardinality' or 'resolve' expected"); + s = p.pb_lemma_format(); + if (s == "cardinality") + m_pb_lemma_format = PB_LEMMA_CARDINALITY; + else if (s == "pb") + m_pb_lemma_format = PB_LEMMA_PB; + else + throw sat_param_exception("invalid PB lemma format: 'cardinality' or 'pb' expected"); + m_card_solver = p.cardinality_solver(); sat_simplifier_params sp(_p); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 40ab5fa38..b5cfb9e28 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -65,6 +65,11 @@ namespace sat { PB_ROUNDING }; + enum pb_lemma_format { + PB_LEMMA_CARDINALITY, + PB_LEMMA_PB + }; + enum reward_t { ternary_reward, unit_literal_reward, @@ -154,6 +159,7 @@ namespace sat { pb_solver m_pb_solver; bool m_card_solver; pb_resolve m_pb_resolve; + pb_lemma_format m_pb_lemma_format; // branching heuristic settings. branching_heuristic m_branching_heuristic; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 7c289a900..390cdfa53 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -45,6 +45,7 @@ def_module_params('sat', ('xor.solver', BOOL, False, 'use xor solver'), ('cardinality.encoding', SYMBOL, 'grouped', 'encoding used for at-most-k constraints: grouped, bimander, ordered, unate, circuit'), ('pb.resolve', SYMBOL, 'cardinality', 'resolution strategy for boolean algebra solver: cardinality, rounding'), + ('pb.lemma_format', SYMBOL, 'cardinality', 'generate either cardinality or pb lemmas'), ('local_search', BOOL, False, 'use local search instead of CDCL'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search_mode', SYMBOL, 'wsat', 'local search algorithm, either default wsat or qsat'), From f53b7aaca2e1882f0e835947ceb24ae9533a7f41 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Sep 2018 15:46:10 -0700 Subject: [PATCH 033/227] fix none-case Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 5 ++--- src/sat/sat_config.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index f6c544cdf..acc3bbd21 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1607,7 +1607,7 @@ namespace sat { } else { round_to_one(consequent.var()); - if (cnstr.tag() == pb_t) round_to_one(m_A, consequent.var()); + if (cnstr.is_pb()) round_to_one(m_A, consequent.var()); SASSERT(validate_ineq(m_A)); resolve_with(m_A); } @@ -1629,8 +1629,7 @@ namespace sat { mark_visited(v); if (s().is_marked(v)) { int64_t c = get_coeff(v); - if (c == 0) { - CTRACE("ba", c != 0, active2pb(m_A); display(tout << consequent << ": ", m_A, true);); + if (c == 0 || (c < 0 == consequent.sign())) { s().reset_mark(v); --m_num_marks; } diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index a864579f8..07aacd9ee 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -202,7 +202,7 @@ namespace sat { else if (s == "rounding") m_pb_resolve = PB_ROUNDING; else - throw sat_param_exception("invalid PB resolve: 'cardinality' or 'resolve' expected"); + throw sat_param_exception("invalid PB resolve: 'cardinality' or 'rounding' expected"); s = p.pb_lemma_format(); if (s == "cardinality") From 13abf5c6a6dec1a364cb335f497b92593b7481fb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 6 Sep 2018 17:49:52 -0700 Subject: [PATCH 034/227] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 7ddc80813..065dc1d39 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -340,12 +340,6 @@ namespace sat { } void solver::mk_bin_clause(literal l1, literal l2, bool learned) { -#if 0 - if ((l1.var() == 2039 || l2.var() == 2039) && - (l1.var() == 27042 || l2.var() == 27042)) { - IF_VERBOSE(1, verbose_stream() << "mk_bin: " << l1 << " " << l2 << " " << learned << "\n"); - } -#endif if (find_binary_watch(get_wlist(~l1), ~l2)) { assign(l1, justification()); return; From 386cbade89415ff9328e08e31e4751c421f91b46 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 7 Sep 2018 16:06:17 -0700 Subject: [PATCH 035/227] na Signed-off-by: Nikolaj Bjorner --- src/smt/theory_jobscheduler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index 918f349cd..a372a274f 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -86,7 +86,6 @@ namespace smt { return true; } - // TBD: stronger parameter validation void theory_jobscheduler::internalize_cmd(expr* cmd) { symbol key, val; rational r; From 445546b684ceb512330e25f2a569dc11c0f05e6a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 10 Sep 2018 17:20:40 -0700 Subject: [PATCH 036/227] fix gc Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index acc3bbd21..88de3b6a1 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1570,6 +1570,7 @@ namespace sat { ++m_stats.m_num_resolves; ext_justification_idx index = js.get_ext_justification_idx(); constraint& cnstr = index2constraint(index); + SASSERT(!cnstr.was_removed()); switch (cnstr.tag()) { case card_t: case pb_t: { @@ -2660,7 +2661,8 @@ namespace sat { } void ba_solver::gc() { - if (m_learned.size() >= 2 * m_constraints.size()) { + if (m_learned.size() >= 2 * m_constraints.size() && + (s().at_search_lvl() || s().at_base_lvl())) { for (auto & c : m_learned) update_psm(*c); std::stable_sort(m_learned.begin(), m_learned.end(), constraint_glue_psm_lt()); gc_half("glue-psm"); From 13183b7c7c533be01392b7d169c8b43175254037 Mon Sep 17 00:00:00 2001 From: nabice Date: Wed, 10 Oct 2018 17:12:16 +0800 Subject: [PATCH 037/227] Ignore current dir when searching for jni --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 471edd7cb..97e2b65f2 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -396,7 +396,7 @@ def check_java(): libdirs = m.group(1).split(',') for libdir in libdirs: q = os.path.dirname(libdir) - if cdirs.count(q) == 0: + if cdirs.count(q) == 0 and len(q) > 0: cdirs.append(q) t.close() From 3b86ea3f8afa0771e58d140099282154d4b05519 Mon Sep 17 00:00:00 2001 From: xlauko Date: Wed, 10 Oct 2018 14:27:08 +0200 Subject: [PATCH 038/227] Add a floating-point support to c++ api. --- src/api/c++/z3++.h | 325 ++++++++++++++++++++++++++++++++------------- 1 file changed, 236 insertions(+), 89 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 13232dd28..ff953ca8f 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -138,11 +138,22 @@ namespace z3 { \brief A Context manages all other Z3 objects, global configuration options, etc. */ class context { + public: + enum class rounding_mode { + RNA, + RNE, + RTP, + RTN, + RTZ + }; + private: bool m_enable_exceptions; + rounding_mode m_rounding_mode; Z3_context m_ctx; void init(config & c) { m_ctx = Z3_mk_context_rc(c); m_enable_exceptions = true; + m_rounding_mode = rounding_mode::RNA; Z3_set_error_handler(m_ctx, 0); Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); } @@ -171,7 +182,7 @@ namespace z3 { } /** - \brief The C++ API uses by defaults exceptions on errors. + \brief The C++ API uses by defaults exceptions on errors. For applications that don't work well with exceptions (there should be only few) you have the ability to turn off exceptions. The tradeoffs are that applications have to be very careful about using check_error() after calls that may result in an @@ -247,6 +258,26 @@ namespace z3 { */ sort array_sort(sort d, sort r); sort array_sort(sort_vector const& d, sort r); + /** + \brief Return a floating point sort. + \c ebits is a number of exponent bits, + \c sbits is a number of significand bits, + \pre where ebits must be larger than 1 and sbits must be larger than 2. + */ + sort fpa_sort(unsigned ebits, unsigned sbits); + /** + \brief Return a FloatingPoint sort with given precision bitwidth (16, 32, 64 or 128). + */ + template + sort fpa_sort(); + /** + \brief Return a RoundingMode sort. + */ + sort fpa_rounding_mode(); + /** + \breif Sets RoundingMode of FloatingPoints. + */ + void set_rounding_mode(rounding_mode rm); /** \brief Return an enumeration sort: enum_names[0], ..., enum_names[n-1]. \c cs and \c ts are output parameters. The method stores in \c cs the constants corresponding to the enumerated elements, @@ -284,6 +315,10 @@ namespace z3 { expr int_const(char const * name); expr real_const(char const * name); expr bv_const(char const * name, unsigned sz); + expr fpa_const(char const * name, unsigned ebits, unsigned sbits); + + template + expr fpa_const(char const * name); expr bool_val(bool b); @@ -307,6 +342,9 @@ namespace z3 { expr bv_val(char const * n, unsigned sz); expr bv_val(unsigned n, bool const* bits); + expr fpa_val(double n); + expr fpa_val(float n); + expr string_val(char const* s); expr string_val(std::string const& s); @@ -465,6 +503,7 @@ namespace z3 { public: sort(context & c):ast(c) {} sort(context & c, Z3_sort s):ast(c, reinterpret_cast(s)) {} + sort(context & c, Z3_ast a):ast(c, a) {} sort(sort const & s):ast(s) {} operator Z3_sort() const { return reinterpret_cast(m_ast); } /** @@ -523,6 +562,10 @@ namespace z3 { \brief Return true if this sort is a Finite domain sort. */ bool is_finite_domain() const { return sort_kind() == Z3_FINITE_DOMAIN_SORT; } + /** + \brief Return true if this sort is a Floating point sort. + */ + bool is_fpa() const { return sort_kind() == Z3_FLOATING_POINT_SORT; } /** \brief Return the size of this Bit-vector sort. @@ -531,6 +574,9 @@ namespace z3 { */ unsigned bv_size() const { assert(is_bv()); unsigned r = Z3_get_bv_sort_size(ctx(), *this); check_error(); return r; } + unsigned fpa_ebits() const { assert(is_fpa()); unsigned r = Z3_fpa_get_ebits(ctx(), *this); check_error(); return r; } + + unsigned fpa_sbits() const { assert(is_fpa()); unsigned r = Z3_fpa_get_sbits(ctx(), *this); check_error(); return r; } /** \brief Return the domain of this Array sort. @@ -634,7 +680,7 @@ namespace z3 { \brief Return true if this is a regular expression. */ bool is_re() const { return get_sort().is_re(); } - + /** \brief Return true if this is a Finite-domain expression. @@ -644,6 +690,10 @@ namespace z3 { */ bool is_finite_domain() const { return get_sort().is_finite_domain(); } + /** + \brief Return true if this is a FloatingPoint expression. . + */ + bool is_fpa() const { return get_sort().is_fpa(); } /** \brief Return true if this expression is a numeral. @@ -696,29 +746,29 @@ namespace z3 { \brief Return true if this expression is well sorted (aka type correct). */ bool is_well_sorted() const { bool r = Z3_is_well_sorted(ctx(), m_ast) != 0; check_error(); return r; } - + /** \brief Return string representation of numeral or algebraic number This method assumes the expression is numeral or algebraic - + \pre is_numeral() || is_algebraic() */ std::string get_decimal_string(int precision) const { assert(is_numeral() || is_algebraic()); return std::string(Z3_get_numeral_decimal_string(ctx(), m_ast, precision)); } - + /** \brief Return int value of numeral, throw if result cannot fit in machine int It only makes sense to use this function if the caller can ensure that - the result is an integer or if exceptions are enabled. + the result is an integer or if exceptions are enabled. If exceptions are disabled, then use the is_numeral_i function. - + \pre is_numeral() */ - int get_numeral_int() const { + int get_numeral_int() const { int result = 0; if (!is_numeral_i(result)) { assert(ctx().enable_exceptions()); @@ -727,13 +777,13 @@ namespace z3 { } return result; } - + /** \brief Return uint value of numeral, throw if result cannot fit in machine uint It only makes sense to use this function if the caller can ensure that - the result is an integer or if exceptions are enabled. + the result is an integer or if exceptions are enabled. If exceptions are disabled, then use the is_numeral_u function. \pre is_numeral() */ @@ -747,11 +797,11 @@ namespace z3 { } return result; } - + /** \brief Return \c int64_t value of numeral, throw if result cannot fit in \c int64_t. - + \pre is_numeral() */ int64_t get_numeral_int64() const { @@ -764,11 +814,11 @@ namespace z3 { } return result; } - + /** \brief Return \c uint64_t value of numeral, throw if result cannot fit in \c uint64_t. - + \pre is_numeral() */ uint64_t get_numeral_uint64() const { @@ -786,7 +836,7 @@ namespace z3 { return Z3_get_bool_value(ctx(), m_ast); } - expr numerator() const { + expr numerator() const { assert(is_numeral()); Z3_ast r = Z3_get_numerator(ctx(), m_ast); check_error(); @@ -794,7 +844,7 @@ namespace z3 { } - expr denominator() const { + expr denominator() const { assert(is_numeral()); Z3_ast r = Z3_get_denominator(ctx(), m_ast); check_error(); @@ -803,6 +853,17 @@ namespace z3 { operator Z3_app() const { assert(is_app()); return reinterpret_cast(m_ast); } + /** + \brief Return a RoundingMode sort. + */ + sort fpa_rounding_mode() { + assert(is_fpa()); + Z3_sort s = ctx().fpa_rounding_mode(); + check_error(); + return sort(ctx(), s); + } + + /** \brief Return the declaration associated with this application. This method assumes the expression is an application. @@ -905,7 +966,7 @@ namespace z3 { bool is_implies() const { return is_app() && Z3_OP_IMPLIES == decl().decl_kind(); } bool is_eq() const { return is_app() && Z3_OP_EQ == decl().decl_kind(); } bool is_ite() const { return is_app() && Z3_OP_ITE == decl().decl_kind(); } - + friend expr distinct(expr_vector const& args); friend expr concat(expr const& a, expr const& b); friend expr concat(expr_vector const& args); @@ -992,23 +1053,34 @@ namespace z3 { friend expr nor(expr const& a, expr const& b); friend expr xnor(expr const& a, expr const& b); + friend expr min(expr const& a, expr const& b); + friend expr max(expr const& a, expr const& b); + expr rotate_left(unsigned i) { Z3_ast r = Z3_mk_rotate_left(ctx(), i, *this); ctx().check_error(); return expr(ctx(), r); } expr rotate_right(unsigned i) { Z3_ast r = Z3_mk_rotate_right(ctx(), i, *this); ctx().check_error(); return expr(ctx(), r); } expr repeat(unsigned i) { Z3_ast r = Z3_mk_repeat(ctx(), i, *this); ctx().check_error(); return expr(ctx(), r); } + friend expr abs(expr const & a); + friend expr sqrt(expr const & a, expr const & rm); + friend expr operator~(expr const & a); - expr extract(unsigned hi, unsigned lo) const { Z3_ast r = Z3_mk_extract(ctx(), hi, lo, *this); ctx().check_error(); return expr(ctx(), r); } + expr extract(unsigned hi, unsigned lo) const { Z3_ast r = Z3_mk_extract(ctx(), hi, lo, *this); ctx().check_error(); return expr(ctx(), r); } unsigned lo() const { assert (is_app() && Z3_get_decl_num_parameters(ctx(), decl()) == 2); return static_cast(Z3_get_decl_int_parameter(ctx(), decl(), 1)); } unsigned hi() const { assert (is_app() && Z3_get_decl_num_parameters(ctx(), decl()) == 2); return static_cast(Z3_get_decl_int_parameter(ctx(), decl(), 0)); } + /** + \brief FloatingPoint fused multiply-add. + */ + friend expr fma(expr const& a, expr const& b, expr const& c); + /** \brief sequence and regular expression operations. + is overloaded as sequence concatenation and regular expression union. concat is overloaded to handle sequences and regular expressions */ - expr extract(expr const& offset, expr const& length) const { + expr extract(expr const& offset, expr const& length) const { check_context(*this, offset); check_context(offset, length); - Z3_ast r = Z3_mk_seq_extract(ctx(), *this, offset, length); check_error(); return expr(ctx(), r); + Z3_ast r = Z3_mk_seq_extract(ctx(), *this, offset, length); check_error(); return expr(ctx(), r); } expr replace(expr const& src, expr const& dst) const { check_context(*this, src); check_context(src, dst); @@ -1049,19 +1121,19 @@ namespace z3 { return expr(ctx(), r); } - friend expr range(expr const& lo, expr const& hi); + friend expr range(expr const& lo, expr const& hi); /** \brief create a looping regular expression. */ expr loop(unsigned lo) { - Z3_ast r = Z3_mk_re_loop(ctx(), m_ast, lo, 0); - check_error(); - return expr(ctx(), r); + Z3_ast r = Z3_mk_re_loop(ctx(), m_ast, lo, 0); + check_error(); + return expr(ctx(), r); } expr loop(unsigned lo, unsigned hi) { - Z3_ast r = Z3_mk_re_loop(ctx(), m_ast, lo, hi); - check_error(); - return expr(ctx(), r); + Z3_ast r = Z3_mk_re_loop(ctx(), m_ast, lo, hi); + check_error(); + return expr(ctx(), r); } @@ -1094,7 +1166,7 @@ namespace z3 { inline expr implies(expr const & a, expr const & b) { - assert(a.is_bool() && b.is_bool()); + assert(a.is_bool() && b.is_bool()); _Z3_MK_BIN_(a, b, Z3_mk_implies); } inline expr implies(expr const & a, bool b) { return implies(a, a.ctx().bool_val(b)); } @@ -1109,7 +1181,13 @@ namespace z3 { inline expr mod(expr const & a, int b) { return mod(a, a.ctx().num_val(b, a.get_sort())); } inline expr mod(int a, expr const & b) { return mod(b.ctx().num_val(a, b.get_sort()), b); } - inline expr rem(expr const& a, expr const& b) { _Z3_MK_BIN_(a, b, Z3_mk_rem); } + inline expr rem(expr const& a, expr const& b) { + if (a.is_fpa() && b.is_fpa()) { + _Z3_MK_BIN_(a, b, Z3_mk_fpa_rem); + } else { + _Z3_MK_BIN_(a, b, Z3_mk_rem); + } + } inline expr rem(expr const & a, int b) { return rem(a, a.ctx().num_val(b, a.get_sort())); } inline expr rem(int a, expr const & b) { return rem(b.ctx().num_val(a, b.get_sort()), b); } @@ -1158,8 +1236,8 @@ namespace z3 { a.check_error(); return expr(a.ctx(), r); } - inline expr operator==(expr const & a, int b) { assert(a.is_arith() || a.is_bv()); return a == a.ctx().num_val(b, a.get_sort()); } - inline expr operator==(int a, expr const & b) { assert(b.is_arith() || b.is_bv()); return b.ctx().num_val(a, b.get_sort()) == b; } + inline expr operator==(expr const & a, int b) { assert(a.is_arith() || a.is_bv() || a.is_fpa()); return a == a.ctx().num_val(b, a.get_sort()); } + inline expr operator==(int a, expr const & b) { assert(b.is_arith() || b.is_bv() || b.is_fpa()); return b.ctx().num_val(a, b.get_sort()) == b; } inline expr operator!=(expr const & a, expr const & b) { check_context(a, b); @@ -1168,8 +1246,8 @@ namespace z3 { a.check_error(); return expr(a.ctx(), r); } - inline expr operator!=(expr const & a, int b) { assert(a.is_arith() || a.is_bv()); return a != a.ctx().num_val(b, a.get_sort()); } - inline expr operator!=(int a, expr const & b) { assert(b.is_arith() || b.is_bv()); return b.ctx().num_val(a, b.get_sort()) != b; } + inline expr operator!=(expr const & a, int b) { assert(a.is_arith() || a.is_bv() || a.is_fpa()); return a != a.ctx().num_val(b, a.get_sort()); } + inline expr operator!=(int a, expr const & b) { assert(b.is_arith() || b.is_bv() || b.is_fpa()); return b.ctx().num_val(a, b.get_sort()) != b; } inline expr operator+(expr const & a, expr const & b) { check_context(a, b); @@ -1188,6 +1266,9 @@ namespace z3 { Z3_ast _args[2] = { a, b }; r = Z3_mk_re_union(a.ctx(), 2, _args); } + else if (a.is_fpa() && b.is_fpa()) { + r = Z3_mk_fpa_add(a.ctx(), a.ctx().fpa_rounding_mode(), a, b); + } else { // operator is not supported by given arguments. assert(false); @@ -1208,6 +1289,9 @@ namespace z3 { else if (a.is_bv() && b.is_bv()) { r = Z3_mk_bvmul(a.ctx(), a, b); } + else if (a.is_fpa() && b.is_fpa()) { + r = Z3_mk_fpa_mul(a.ctx(), a.ctx().fpa_rounding_mode(), a, b); + } else { // operator is not supported by given arguments. assert(false); @@ -1245,6 +1329,9 @@ namespace z3 { else if (a.is_bv() && b.is_bv()) { r = Z3_mk_bvsdiv(a.ctx(), a, b); } + else if (a.is_fpa() && b.is_fpa()) { + r = Z3_mk_fpa_div(a.ctx(), a.ctx().fpa_rounding_mode(), a, b); + } else { // operator is not supported by given arguments. assert(false); @@ -1263,6 +1350,9 @@ namespace z3 { else if (a.is_bv()) { r = Z3_mk_bvneg(a.ctx(), a); } + else if (a.is_fpa()) { + r = Z3_mk_fpa_neg(a.ctx(), a); + } else { // operator is not supported by given arguments. assert(false); @@ -1281,6 +1371,9 @@ namespace z3 { else if (a.is_bv() && b.is_bv()) { r = Z3_mk_bvsub(a.ctx(), a, b); } + else if (a.is_fpa() && b.is_fpa()) { + r = Z3_mk_fpa_sub(a.ctx(), a.ctx().fpa_rounding_mode(), a, b); + } else { // operator is not supported by given arguments. assert(false); @@ -1300,6 +1393,9 @@ namespace z3 { else if (a.is_bv() && b.is_bv()) { r = Z3_mk_bvsle(a.ctx(), a, b); } + else if (a.is_fpa() && b.is_fpa()) { + r = Z3_mk_fpa_leq(a.ctx(), a, b); + } else { // operator is not supported by given arguments. assert(false); @@ -1322,6 +1418,9 @@ namespace z3 { else if (a.is_bv() && b.is_bv()) { r = Z3_mk_bvslt(a.ctx(), a, b); } + else if (a.is_fpa() && b.is_fpa()) { + r = Z3_mk_fpa_lt(a.ctx(), a, b); + } else { // operator is not supported by given arguments. assert(false); @@ -1341,6 +1440,9 @@ namespace z3 { else if (a.is_bv() && b.is_bv()) { r = Z3_mk_bvsgt(a.ctx(), a, b); } + else if (a.is_fpa() && b.is_fpa()) { + r = Z3_mk_fpa_gt(a.ctx(), a, b); + } else { // operator is not supported by given arguments. assert(false); @@ -1366,17 +1468,30 @@ namespace z3 { inline expr nand(expr const& a, expr const& b) { check_context(a, b); Z3_ast r = Z3_mk_bvnand(a.ctx(), a, b); return expr(a.ctx(), r); } inline expr nor(expr const& a, expr const& b) { check_context(a, b); Z3_ast r = Z3_mk_bvnor(a.ctx(), a, b); return expr(a.ctx(), r); } inline expr xnor(expr const& a, expr const& b) { check_context(a, b); Z3_ast r = Z3_mk_bvxnor(a.ctx(), a, b); return expr(a.ctx(), r); } - + inline expr min(expr const& a, expr const& b) { check_context(a, b); Z3_ast r = Z3_mk_fpa_min(a.ctx(), a, b); return expr(a.ctx(), r); } + inline expr max(expr const& a, expr const& b) { check_context(a, b); Z3_ast r = Z3_mk_fpa_max(a.ctx(), a, b); return expr(a.ctx(), r); } + inline expr abs(expr const & a) { Z3_ast r = Z3_mk_fpa_abs(a.ctx(), a); return expr(a.ctx(), r); } + inline expr sqrt(expr const & a, expr const& rm) { + check_context(a, rm); + assert(a.is_fpa()); + Z3_ast r = Z3_mk_fpa_sqrt(a.ctx(), rm, a); + return expr(a.ctx(), r); + } inline expr operator~(expr const & a) { Z3_ast r = Z3_mk_bvnot(a.ctx(), a); return expr(a.ctx(), r); } - + inline expr fma(expr const& a, expr const& b, expr const& c, expr const& rm) { + check_context(a, b); check_context(a, c); check_context(a, rm); + assert(a.is_fpa() && b.is_fpa() && c.is_fpa()); + Z3_ast r = Z3_mk_fpa_fma(a.ctx(), rm, a, b, c); + a.check_error(); + return expr(a.ctx(), r); + } /** \brief Create the if-then-else expression ite(c, t, e) \pre c.is_bool() */ - inline expr ite(expr const & c, expr const & t, expr const & e) { check_context(c, t); check_context(c, e); assert(c.is_bool()); @@ -1453,45 +1568,45 @@ namespace z3 { inline expr smod(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvsmod(a.ctx(), a, b)); } inline expr smod(expr const & a, int b) { return smod(a, a.ctx().num_val(b, a.get_sort())); } inline expr smod(int a, expr const & b) { return smod(b.ctx().num_val(a, b.get_sort()), b); } - + /** \brief unsigned reminder operator for bitvectors */ inline expr urem(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvurem(a.ctx(), a, b)); } inline expr urem(expr const & a, int b) { return urem(a, a.ctx().num_val(b, a.get_sort())); } inline expr urem(int a, expr const & b) { return urem(b.ctx().num_val(a, b.get_sort()), b); } - + /** \brief shift left operator for bitvectors */ inline expr shl(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvshl(a.ctx(), a, b)); } inline expr shl(expr const & a, int b) { return shl(a, a.ctx().num_val(b, a.get_sort())); } inline expr shl(int a, expr const & b) { return shl(b.ctx().num_val(a, b.get_sort()), b); } - + /** \brief logic shift right operator for bitvectors */ inline expr lshr(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvlshr(a.ctx(), a, b)); } inline expr lshr(expr const & a, int b) { return lshr(a, a.ctx().num_val(b, a.get_sort())); } inline expr lshr(int a, expr const & b) { return lshr(b.ctx().num_val(a, b.get_sort()), b); } - + /** \brief arithmetic shift right operator for bitvectors */ inline expr ashr(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvashr(a.ctx(), a, b)); } inline expr ashr(expr const & a, int b) { return ashr(a, a.ctx().num_val(b, a.get_sort())); } inline expr ashr(int a, expr const & b) { return ashr(b.ctx().num_val(a, b.get_sort()), b); } - + /** \brief Extend the given bit-vector with zeros to the (unsigned) equivalent bitvector of size m+i, where m is the size of the given bit-vector. */ inline expr zext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_zero_ext(a.ctx(), i, a)); } - + /** \brief Sign-extend of the given bit-vector to the (signed) equivalent bitvector of size m+i, where m is the size of the given bit-vector. */ inline expr sext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_sign_ext(a.ctx(), i, a)); } - + template class cast_ast; template<> class cast_ast { @@ -1563,7 +1678,7 @@ namespace z3 { unsigned m_index; public: iterator(ast_vector_tpl const* v, unsigned i): m_vector(v), m_index(i) {} - iterator(iterator& other): m_vector(other.m_vector), m_index(other.m_index) {} + iterator(iterator& other): m_vector(other.m_vector), m_index(other.m_index) {} iterator operator=(iterator const& other) { m_vector = other.m_vector; m_index = other.m_index; return *this; } bool operator==(iterator const& other) { @@ -1773,7 +1888,7 @@ namespace z3 { return expr(ctx, r); } - inline expr mk_or(expr_vector const& args) { + inline expr mk_or(expr_vector const& args) { array _args(args); Z3_ast r = Z3_mk_or(args.ctx(), _args.size(), _args.ptr()); args.check_error(); @@ -1852,7 +1967,7 @@ namespace z3 { model(context & c):object(c) { init(Z3_mk_model(c)); } model(context & c, Z3_model m):object(c) { init(m); } model(model const & s):object(s) { init(s.m_model); } - model(model& src, context& dst, translate) : object(dst) { init(Z3_model_translate(src.ctx(), src, dst)); } + model(model& src, context& dst, translate) : object(dst) { init(Z3_model_translate(src.ctx(), src, dst)); } ~model() { Z3_model_dec_ref(ctx(), m_model); } operator Z3_model() const { return m_model; } model & operator=(model const & s) { @@ -1884,7 +1999,7 @@ namespace z3 { } // returns interpretation of constant declaration c. - // If c is not assigned any value in the model it returns + // If c is not assigned any value in the model it returns // an expression with a null ast reference. expr get_const_interp(func_decl c) const { check_context(*this, c); @@ -1898,7 +2013,7 @@ namespace z3 { check_error(); return func_interp(ctx(), r); } - + // returns true iff the model contains an interpretation // for function f. bool has_interp(func_decl f) const { @@ -1945,7 +2060,7 @@ namespace z3 { bool is_uint(unsigned i) const { Z3_bool r = Z3_stats_is_uint(ctx(), m_stats, i); check_error(); return r != 0; } bool is_double(unsigned i) const { Z3_bool r = Z3_stats_is_double(ctx(), m_stats, i); check_error(); return r != 0; } unsigned uint_value(unsigned i) const { unsigned r = Z3_stats_get_uint_value(ctx(), m_stats, i); check_error(); return r; } - double double_value(unsigned i) const { double r = Z3_stats_get_double_value(ctx(), m_stats, i); check_error(); return r; } + double double_value(unsigned i) const { double r = Z3_stats_get_double_value(ctx(), m_stats, i); check_error(); return r; } friend std::ostream & operator<<(std::ostream & out, stats const & s); }; inline std::ostream & operator<<(std::ostream & out, stats const & s) { out << Z3_stats_to_string(s.ctx(), s); return out; } @@ -2001,7 +2116,7 @@ namespace z3 { void add(expr const & e, char const * p) { add(e, ctx().bool_const(p)); } - // fails for some compilers: + // fails for some compilers: // void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } void from_file(char const* file) { Z3_solver_from_file(ctx(), m_solver, file); ctx().check_parser_error(); } void from_string(char const* s) { Z3_solver_from_string(ctx(), m_solver, s); ctx().check_parser_error(); } @@ -2066,11 +2181,11 @@ namespace z3 { param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_solver_get_param_descrs(ctx(), m_solver)); } - expr_vector cube(expr_vector& vars, unsigned cutoff) { - Z3_ast_vector r = Z3_solver_cube(ctx(), m_solver, vars, cutoff); - check_error(); - return expr_vector(ctx(), r); - } + expr_vector cube(expr_vector& vars, unsigned cutoff) { + Z3_ast_vector r = Z3_solver_cube(ctx(), m_solver, vars, cutoff); + check_error(); + return expr_vector(ctx(), r); + } class cube_iterator { solver& m_solver; @@ -2118,7 +2233,7 @@ namespace z3 { cube_iterator operator++(int) { assert(false); return *this; } expr_vector const * operator->() const { return &(operator*()); } expr_vector const& operator*() const { return m_cube; } - + bool operator==(cube_iterator const& other) { return other.m_end == m_end; }; @@ -2407,7 +2522,7 @@ namespace z3 { class optimize : public object { Z3_optimize m_opt; - + public: class handle { unsigned m_h; @@ -2456,16 +2571,16 @@ namespace z3 { Z3_optimize_pop(ctx(), m_opt); } check_result check() { Z3_lbool r = Z3_optimize_check(ctx(), m_opt, 0, 0); check_error(); return to_check_result(r); } - check_result check(expr_vector const& asms) { + check_result check(expr_vector const& asms) { unsigned n = asms.size(); array _asms(n); for (unsigned i = 0; i < n; i++) { check_context(*this, asms[i]); _asms[i] = asms[i]; } - Z3_lbool r = Z3_optimize_check(ctx(), m_opt, n, _asms.ptr()); - check_error(); - return to_check_result(r); + Z3_lbool r = Z3_optimize_check(ctx(), m_opt, n, _asms.ptr()); + check_error(); + return to_check_result(r); } model get_model() const { Z3_model m = Z3_optimize_get_model(ctx(), m_opt); check_error(); return model(ctx(), m); } expr_vector unsat_core() const { Z3_ast_vector r = Z3_optimize_get_unsat_core(ctx(), m_opt); check_error(); return expr_vector(ctx(), r); } @@ -2495,25 +2610,25 @@ namespace z3 { public: fixedpoint(context& c):object(c) { m_fp = Z3_mk_fixedpoint(c); Z3_fixedpoint_inc_ref(c, m_fp); } ~fixedpoint() { Z3_fixedpoint_dec_ref(ctx(), m_fp); } - operator Z3_fixedpoint() const { return m_fp; } + operator Z3_fixedpoint() const { return m_fp; } void from_string(char const* s) { Z3_fixedpoint_from_string(ctx(), m_fp, s); check_error(); } void from_file(char const* s) { Z3_fixedpoint_from_file(ctx(), m_fp, s); check_error(); } void add_rule(expr& rule, symbol const& name) { Z3_fixedpoint_add_rule(ctx(), m_fp, rule, name); check_error(); } void add_fact(func_decl& f, unsigned * args) { Z3_fixedpoint_add_fact(ctx(), m_fp, f, f.arity(), args); check_error(); } check_result query(expr& q) { Z3_lbool r = Z3_fixedpoint_query(ctx(), m_fp, q); check_error(); return to_check_result(r); } - check_result query(func_decl_vector& relations) { + check_result query(func_decl_vector& relations) { array rs(relations); - Z3_lbool r = Z3_fixedpoint_query_relations(ctx(), m_fp, rs.size(), rs.ptr()); - check_error(); - return to_check_result(r); + Z3_lbool r = Z3_fixedpoint_query_relations(ctx(), m_fp, rs.size(), rs.ptr()); + check_error(); + return to_check_result(r); } expr get_answer() { Z3_ast r = Z3_fixedpoint_get_answer(ctx(), m_fp); check_error(); return expr(ctx(), r); } std::string reason_unknown() { return Z3_fixedpoint_get_reason_unknown(ctx(), m_fp); } void update_rule(expr& rule, symbol const& name) { Z3_fixedpoint_update_rule(ctx(), m_fp, rule, name); check_error(); } unsigned get_num_levels(func_decl& p) { unsigned r = Z3_fixedpoint_get_num_levels(ctx(), m_fp, p); check_error(); return r; } - expr get_cover_delta(int level, func_decl& p) { - Z3_ast r = Z3_fixedpoint_get_cover_delta(ctx(), m_fp, level, p); - check_error(); + expr get_cover_delta(int level, func_decl& p) { + Z3_ast r = Z3_fixedpoint_get_cover_delta(ctx(), m_fp, level, p); + check_error(); return expr(ctx(), r); } void add_cover(int level, func_decl& p, expr& property) { Z3_fixedpoint_add_cover(ctx(), m_fp, level, p, property); check_error(); } @@ -2527,7 +2642,7 @@ namespace z3 { std::string to_string() { return Z3_fixedpoint_to_string(ctx(), m_fp, 0, 0); } std::string to_string(expr_vector const& queries) { array qs(queries); - return Z3_fixedpoint_to_string(ctx(), m_fp, qs.size(), qs.ptr()); + return Z3_fixedpoint_to_string(ctx(), m_fp, qs.size(), qs.ptr()); } void push() { Z3_fixedpoint_push(ctx(), m_fp); check_error(); } void pop() { Z3_fixedpoint_pop(ctx(), m_fp); check_error(); } @@ -2562,11 +2677,36 @@ namespace z3 { inline sort context::string_sort() { Z3_sort s = Z3_mk_string_sort(m_ctx); check_error(); return sort(*this, s); } inline sort context::seq_sort(sort& s) { Z3_sort r = Z3_mk_seq_sort(m_ctx, s); check_error(); return sort(*this, r); } inline sort context::re_sort(sort& s) { Z3_sort r = Z3_mk_re_sort(m_ctx, s); check_error(); return sort(*this, r); } + inline sort context::fpa_sort(unsigned ebits, unsigned sbits) { Z3_sort s = Z3_mk_fpa_sort(m_ctx, ebits, sbits); check_error(); return sort(*this, s); } + + template<> + inline sort context::fpa_sort<16>() { return fpa_sort(5, 11); } + + template<> + inline sort context::fpa_sort<32>() { return fpa_sort(8, 24); } + + template<> + inline sort context::fpa_sort<64>() { return fpa_sort(11, 53); } + + template<> + inline sort context::fpa_sort<128>() { return fpa_sort(15, 113); } + + inline sort context::fpa_rounding_mode() { + switch (m_rounding_mode) { + case rounding_mode::RNA: return sort(*this, Z3_mk_fpa_rna(m_ctx)); + case rounding_mode::RNE: return sort(*this, Z3_mk_fpa_rne(m_ctx)); + case rounding_mode::RTP: return sort(*this, Z3_mk_fpa_rtp(m_ctx)); + case rounding_mode::RTN: return sort(*this, Z3_mk_fpa_rtn(m_ctx)); + case rounding_mode::RTZ: return sort(*this, Z3_mk_fpa_rtz(m_ctx)); + } + } + + inline void context::set_rounding_mode(rounding_mode rm) { m_rounding_mode = rm; } inline sort context::array_sort(sort d, sort r) { Z3_sort s = Z3_mk_array_sort(m_ctx, d, r); check_error(); return sort(*this, s); } inline sort context::array_sort(sort_vector const& d, sort r) { array dom(d); - Z3_sort s = Z3_mk_array_sort_n(m_ctx, dom.size(), dom.ptr(), r); check_error(); return sort(*this, s); + Z3_sort s = Z3_mk_array_sort_n(m_ctx, dom.size(), dom.ptr(), r); check_error(); return sort(*this, s); } inline sort context::enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts) { array _enum_names(n); @@ -2681,6 +2821,10 @@ namespace z3 { inline expr context::int_const(char const * name) { return constant(name, int_sort()); } inline expr context::real_const(char const * name) { return constant(name, real_sort()); } inline expr context::bv_const(char const * name, unsigned sz) { return constant(name, bv_sort(sz)); } + inline expr context::fpa_const(char const * name, unsigned ebits, unsigned sbits) { return constant(name, fpa_sort(ebits, sbits)); } + + template + inline expr context::fpa_const(char const * name) { return constant(name, fpa_sort()); } inline expr context::bool_val(bool b) { return b ? expr(*this, Z3_mk_true(m_ctx)) : expr(*this, Z3_mk_false(m_ctx)); } @@ -2702,12 +2846,15 @@ namespace z3 { inline expr context::bv_val(int64_t n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_int64(m_ctx, n, s); check_error(); return expr(*this, r); } inline expr context::bv_val(uint64_t n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, s); check_error(); return expr(*this, r); } inline expr context::bv_val(char const * n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_numeral(m_ctx, n, s); check_error(); return expr(*this, r); } - inline expr context::bv_val(unsigned n, bool const* bits) { + inline expr context::bv_val(unsigned n, bool const* bits) { array _bits(n); for (unsigned i = 0; i < n; ++i) _bits[i] = bits[i] ? 1 : 0; - Z3_ast r = Z3_mk_bv_numeral(m_ctx, n, _bits.ptr()); check_error(); return expr(*this, r); + Z3_ast r = Z3_mk_bv_numeral(m_ctx, n, _bits.ptr()); check_error(); return expr(*this, r); } + inline expr context::fpa_val(double n) { sort s = fpa_sort<64>(); Z3_ast r = Z3_mk_fpa_numeral_double(m_ctx, n, s); check_error(); return expr(*this, r); } + inline expr context::fpa_val(float n) { sort s = fpa_sort<32>(); Z3_ast r = Z3_mk_fpa_numeral_float(m_ctx, n, s); check_error(); return expr(*this, r); } + inline expr context::string_val(char const* s) { Z3_ast r = Z3_mk_string(m_ctx, s); check_error(); return expr(*this, r); } inline expr context::string_val(std::string const& s) { Z3_ast r = Z3_mk_string(m_ctx, s.c_str()); check_error(); return expr(*this, r); } @@ -2831,8 +2978,8 @@ namespace z3 { a.check_error(); return expr(a.ctx(), r); } - inline expr select(expr const & a, int i) { - return select(a, a.ctx().num_val(i, a.get_sort().array_domain())); + inline expr select(expr const & a, int i) { + return select(a, a.ctx().num_val(i, a.get_sort().array_domain())); } inline expr select(expr const & a, expr_vector const & i) { check_context(a, i); @@ -2862,10 +3009,10 @@ namespace z3 { return expr(a.ctx(), r); } - inline expr as_array(func_decl & f) { - Z3_ast r = Z3_mk_as_array(f.ctx(), f); - f.check_error(); - return expr(f.ctx(), r); + inline expr as_array(func_decl & f) { + Z3_ast r = Z3_mk_as_array(f.ctx(), f); + f.check_error(); + return expr(f.ctx(), r); } #define MK_EXPR1(_fn, _arg) \ @@ -2897,21 +3044,21 @@ namespace z3 { inline expr set_del(expr const& s, expr const& e) { MK_EXPR2(Z3_mk_set_del, s, e); - } + } inline expr set_union(expr const& a, expr const& b) { - check_context(a, b); + check_context(a, b); Z3_ast es[2] = { a, b }; Z3_ast r = Z3_mk_set_union(a.ctx(), 2, es); - a.check_error(); + a.check_error(); return expr(a.ctx(), r); } inline expr set_intersect(expr const& a, expr const& b) { - check_context(a, b); + check_context(a, b); Z3_ast es[2] = { a, b }; Z3_ast r = Z3_mk_set_intersect(a.ctx(), 2, es); - a.check_error(); + a.check_error(); return expr(a.ctx(), r); } @@ -2995,10 +3142,10 @@ namespace z3 { MK_EXPR1(Z3_mk_re_complement, a); } inline expr range(expr const& lo, expr const& hi) { - check_context(lo, hi); - Z3_ast r = Z3_mk_re_range(lo.ctx(), lo, hi); - lo.check_error(); - return expr(lo.ctx(), r); + check_context(lo, hi); + Z3_ast r = Z3_mk_re_range(lo.ctx(), lo, hi); + lo.check_error(); + return expr(lo.ctx(), r); } @@ -3009,7 +3156,7 @@ namespace z3 { Z3_ast_vector r = Z3_parse_smtlib2_string(*this, s, 0, 0, 0, 0, 0, 0); check_error(); return expr_vector(*this, r); - + } inline expr_vector context::parse_file(char const* s) { Z3_ast_vector r = Z3_parse_smtlib2_file(*this, s, 0, 0, 0, 0, 0, 0); From f5fea8ae3040ee05d20f0b8515902ab7d657e512 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Oct 2018 22:05:04 -0700 Subject: [PATCH 039/227] add parameter to force sat-cleaning on initialization and on simplification phases Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 2 ++ src/sat/sat_config.h | 2 ++ src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 10 +++++----- src/sat/sat_solver.h | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index c7f2377c9..e9e6c4ee6 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -152,6 +152,8 @@ namespace sat { m_gc_burst = p.gc_burst(); m_gc_defrag = p.gc_defrag(); + m_force_cleanup = p.force_cleanup(); + m_minimize_lemmas = p.minimize_lemmas(); m_core_minimize = p.core_minimize(); m_core_minimize_partial = p.core_minimize_partial(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 37efe69ed..63e979394 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -136,6 +136,8 @@ namespace sat { bool m_gc_burst; bool m_gc_defrag; + bool m_force_cleanup; + bool m_minimize_lemmas; bool m_dyn_sub_res; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 113a8133e..6202ff155 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -31,6 +31,7 @@ def_module_params('sat', ('gc.burst', BOOL, False, 'perform eager garbage collection during initialization'), ('gc.defrag', BOOL, True, 'defragment clauses when garbage collecting'), ('simplify.delay', UINT, 0, 'set initial delay of simplification by a conflict count'), + ('force_cleanup', BOOL, False, 'force cleanup to remove tautologies and simplify clauses'), ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), ('core.minimize', BOOL, False, 'minimize computed core'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 426caa6dd..8b0d23f9c 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1086,7 +1086,7 @@ namespace sat { init_assumptions(num_lits, lits); propagate(false); if (check_inconsistent()) return l_false; - cleanup(); + cleanup(m_config.m_force_cleanup); if (m_config.m_unit_walk) { return do_unit_walk(); @@ -1458,7 +1458,7 @@ namespace sat { if (should_restart()) return l_undef; if (at_base_lvl()) { - cleanup(); // cleaner may propagate frozen clauses + cleanup(false); // cleaner may propagate frozen clauses if (inconsistent()) { TRACE("sat", tout << "conflict at level 0\n";); return l_false; @@ -1654,7 +1654,7 @@ namespace sat { SASSERT(at_base_lvl()); - m_cleaner(); + m_cleaner(m_config.m_force_cleanup); CASSERT("sat_simplify_bug", check_invariant()); m_scc(); @@ -3695,10 +3695,10 @@ namespace sat { // Simplification // // ----------------------- - void solver::cleanup() { + void solver::cleanup(bool force) { if (!at_base_lvl() || inconsistent()) return; - if (m_cleaner() && m_ext) + if (m_cleaner(force) && m_ext) m_ext->clauses_modifed(); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index e6e6c9d7b..fd9af4a02 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -549,7 +549,7 @@ namespace sat { // // ----------------------- public: - void cleanup(); + void cleanup(bool force); void simplify(bool learned = true); void asymmetric_branching(); unsigned scc_bin(); From 5bd93b8a778139ce238d6dcc024db606855e8f9b Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 12 Oct 2018 23:38:53 +0700 Subject: [PATCH 040/227] Typo fixes. --- RELEASE_NOTES | 4 ++-- src/sat/sat_params.pyg | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 3337f098b..acdb627d8 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -21,7 +21,7 @@ Version 4.8.0 extracting models from apply_result have been replaced. - An optional mode handles xor constraints using a custom xor propagator. It is off by default and its value not demonstrated. - - The SAT solver includes new inprocessing technques that are available during simplification. + - The SAT solver includes new inprocessing techniques that are available during simplification. It performs asymmetric tautology elimination by default, and one can turn on more powerful inprocessing techniques (known as ACCE, ABCE, CCE). Asymmetric branching also uses features introduced in Lingeling by exploiting binary implication graphs. Use sat.acce=true to enable the full repertoire of inprocessing methods. By default, clauses that are "eliminated" by acce are tagged @@ -318,7 +318,7 @@ First source code release (October 2, 2012) - Added support for numbers in scientific notation at Z3_ast Z3_mk_numeral(__in Z3_context c, __in Z3_string numeral, __in Z3_sort ty). -- New builtin symbols in the arithmetic theory: pi, euler, sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh. The first two are constants, and the others are unary functions. These symbols are not available if the a SMT 2.0 logic is specified (e.g., QF_LRA, QF_NRA, QF_LIA, etc) because these symbols are not defined in these logics. That is, the new symbols are only available if the logic is not specified. +- New builtin symbols in the arithmetic theory: pi, euler, sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh. The first two are constants, and the others are unary functions. These symbols are not available if a SMT 2.0 logic is specified (e.g., QF_LRA, QF_NRA, QF_LIA, etc) because these symbols are not defined in these logics. That is, the new symbols are only available if the logic is not specified. Version 4.1 =========== diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 6202ff155..3f0479707 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -15,7 +15,7 @@ def_module_params('sat', ('restart.margin', DOUBLE, 1.1, 'margin between fast and slow restart factors. For ema'), ('restart.emafastglue', DOUBLE, 3e-2, 'ema alpha factor for fast moving average'), ('restart.emaslowglue', DOUBLE, 1e-5, 'ema alpha factor for slow moving average'), - ('variable_decay', UINT, 110, 'multiplier (divided by 100) for the VSIDS activity increement'), + ('variable_decay', UINT, 110, 'multiplier (divided by 100) for the VSIDS activity increment'), ('inprocess.max', UINT, UINT_MAX, 'maximal number of inprocessing passes'), ('branching.heuristic', SYMBOL, 'vsids', 'branching heuristic vsids, lrb or chb'), ('branching.anti_exploration', BOOL, False, 'apply anti-exploration heuristic for branch selection'), @@ -58,7 +58,7 @@ def_module_params('sat', # - psat: Let psat_heur := (Sum_{clause C} (psat.clause_base ^ {-|C|+1})) / |freevars|^psat.var_exp # Cut if the value of psat_heur exceeds psat.trigger # - adaptive_freevars: Cut if the number of current unassigned variables drops below a fraction of free variables - # at the time of the last conflict. The fraction is increased every time the a cutoff is created. + # at the time of the last conflict. The fraction is increased every time the cutoff is created. # - adative_psat: Cut based on psat_heur in an adaptive way. ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead.cube.cutoff is adaptive_freevars or adaptive_psat'), ('lookahead.cube.depth', UINT, 1, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is depth.'), From 58682c20be2fb53adf5bbfb08898469dcbbb161e Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sat, 13 Oct 2018 07:58:27 +0700 Subject: [PATCH 041/227] dl_util: Use an unsigned to match other values. --- src/muz/base/dl_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index 1a2b64dc4..c6e214f79 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -276,7 +276,7 @@ namespace datalog { } unsigned n = container.size(); unsigned ofs = 1; - int r_i = 1; + unsigned r_i = 1; for(unsigned i=removed_cols[0]+1; i Date: Fri, 12 Oct 2018 22:44:23 -0700 Subject: [PATCH 042/227] remove class from enum class, add default to avoid compiler warning Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index ff953ca8f..e009113fb 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -139,7 +139,7 @@ namespace z3 { */ class context { public: - enum class rounding_mode { + enum rounding_mode { RNA, RNE, RTP, @@ -2693,11 +2693,12 @@ namespace z3 { inline sort context::fpa_rounding_mode() { switch (m_rounding_mode) { - case rounding_mode::RNA: return sort(*this, Z3_mk_fpa_rna(m_ctx)); - case rounding_mode::RNE: return sort(*this, Z3_mk_fpa_rne(m_ctx)); - case rounding_mode::RTP: return sort(*this, Z3_mk_fpa_rtp(m_ctx)); - case rounding_mode::RTN: return sort(*this, Z3_mk_fpa_rtn(m_ctx)); - case rounding_mode::RTZ: return sort(*this, Z3_mk_fpa_rtz(m_ctx)); + case rounding_mode::RNA: return sort(*this, Z3_mk_fpa_rna(m_ctx)); + case rounding_mode::RNE: return sort(*this, Z3_mk_fpa_rne(m_ctx)); + case rounding_mode::RTP: return sort(*this, Z3_mk_fpa_rtp(m_ctx)); + case rounding_mode::RTN: return sort(*this, Z3_mk_fpa_rtn(m_ctx)); + case rounding_mode::RTZ: return sort(*this, Z3_mk_fpa_rtz(m_ctx)); + default: return sort(*this); } } From 6277ed61c942f1f150c8d792d9f9d3f09da925ae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 13 Oct 2018 02:09:35 -0700 Subject: [PATCH 043/227] pull rounding mode top-level to deal with build Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index e009113fb..54fc735b0 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -127,6 +127,14 @@ namespace z3 { unsat, sat, unknown }; + enum rounding_mode { + RNA, + RNE, + RTP, + RTN, + RTZ + }; + inline check_result to_check_result(Z3_lbool l) { if (l == Z3_L_TRUE) return sat; else if (l == Z3_L_FALSE) return unsat; @@ -137,15 +145,9 @@ namespace z3 { /** \brief A Context manages all other Z3 objects, global configuration options, etc. */ + + class context { - public: - enum rounding_mode { - RNA, - RNE, - RTP, - RTN, - RTZ - }; private: bool m_enable_exceptions; rounding_mode m_rounding_mode; From 70f3fa36c5e14026a332be40299bbd7f9b731d1d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 13 Oct 2018 09:39:48 -0700 Subject: [PATCH 044/227] remove qualifiers that downlevel compilers complain about Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 54fc735b0..1b1820909 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -155,7 +155,7 @@ namespace z3 { void init(config & c) { m_ctx = Z3_mk_context_rc(c); m_enable_exceptions = true; - m_rounding_mode = rounding_mode::RNA; + m_rounding_mode = RNA; Z3_set_error_handler(m_ctx, 0); Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); } @@ -2695,11 +2695,11 @@ namespace z3 { inline sort context::fpa_rounding_mode() { switch (m_rounding_mode) { - case rounding_mode::RNA: return sort(*this, Z3_mk_fpa_rna(m_ctx)); - case rounding_mode::RNE: return sort(*this, Z3_mk_fpa_rne(m_ctx)); - case rounding_mode::RTP: return sort(*this, Z3_mk_fpa_rtp(m_ctx)); - case rounding_mode::RTN: return sort(*this, Z3_mk_fpa_rtn(m_ctx)); - case rounding_mode::RTZ: return sort(*this, Z3_mk_fpa_rtz(m_ctx)); + case RNA: return sort(*this, Z3_mk_fpa_rna(m_ctx)); + case RNE: return sort(*this, Z3_mk_fpa_rne(m_ctx)); + case RTP: return sort(*this, Z3_mk_fpa_rtp(m_ctx)); + case RTN: return sort(*this, Z3_mk_fpa_rtn(m_ctx)); + case RTZ: return sort(*this, Z3_mk_fpa_rtz(m_ctx)); default: return sort(*this); } } From 77e43404703f2bc37f4b7579c7f56905d4ab2eca Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 14 Oct 2018 13:06:09 -0700 Subject: [PATCH 045/227] update parser Signed-off-by: Nikolaj Bjorner --- src/ast/csp_decl_plugin.cpp | 55 +++++++++++++++++++++++++++++++-- src/ast/csp_decl_plugin.h | 16 +++++++++- src/parsers/smt2/smt2parser.cpp | 6 ---- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/ast/csp_decl_plugin.cpp b/src/ast/csp_decl_plugin.cpp index 27feadc6d..9cdd20376 100644 --- a/src/ast/csp_decl_plugin.cpp +++ b/src/ast/csp_decl_plugin.cpp @@ -119,7 +119,8 @@ func_decl * csp_decl_plugin::mk_func_decl( rng = m_alist_sort; break; case OP_JS_JOB_PREEMPTABLE: - if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("set-preemptable expects one argument, which is a job"); + if (arity != 1 || domain[0] != m_job_sort) + m_manager->raise_exception("set-preemptable expects one argument, which is a job"); name = symbol("set-preemptable"); rng = m_alist_sort; break; @@ -131,6 +132,22 @@ func_decl * csp_decl_plugin::mk_func_decl( name = symbol("js-properties"); rng = m_alist_sort; break; + case OP_JS_JOB_GOAL: + if (arity != 1 || domain[0] != m_job_sort) + m_manager->raise_exception("add-job-goal expects one argument, which is a job"); + if (num_parameters != 2 || !parameters[0].is_symbol() || !parameters[1].is_int()) + m_manager->raise_exception("add-job-goal expects one symbol and one integer parameter"); + name = symbol("add-job-goal"); + rng = m_alist_sort; + break; + case OP_JS_OBJECTIVE: + if (arity != 0) + m_manager->raise_exception("add-optimization-objective expects no arguments"); + if (num_parameters != 1 || !parameters[0].is_symbol()) + m_manager->raise_exception("add-optimization-objective expects one symbol parameter"); + name = symbol("add-optimization-objective"); + rng = m_alist_sort; + break; default: UNREACHABLE(); return nullptr; @@ -172,6 +189,8 @@ void csp_decl_plugin::get_op_names(svector & op_names, symbol cons op_names.push_back(builtin_name("add-resource-available", OP_JS_RESOURCE_AVAILABLE)); op_names.push_back(builtin_name("set-preemptable", OP_JS_JOB_PREEMPTABLE)); op_names.push_back(builtin_name("js-properties", OP_JS_PROPERTIES)); + op_names.push_back(builtin_name("add-job-goal", OP_JS_JOB_GOAL)); + op_names.push_back(builtin_name("add-optimization-objective", OP_JS_OBJECTIVE)); } } @@ -309,7 +328,8 @@ bool csp_util::is_set_preemptable(expr* e, expr *& job) { } bool csp_util::is_js_properties(expr* e, svector& properties) { - if (!is_app_of(e, m_fid, OP_JS_PROPERTIES)) return false; + if (!is_app_of(e, m_fid, OP_JS_PROPERTIES)) + return false; unsigned sz = to_app(e)->get_decl()->get_num_parameters(); for (unsigned i = 0; i < sz; ++i) { properties.push_back(to_app(e)->get_decl()->get_parameter(i).get_symbol()); @@ -317,4 +337,35 @@ bool csp_util::is_js_properties(expr* e, svector& properties) { return true; } +bool csp_util::is_job_goal(expr* e, js_job_goal& goal, unsigned& level, expr*& job) { + if (!is_app_of(e, m_fid, OP_JS_JOB_GOAL)) + return false; + SASSERT(2 == to_app(e)->get_decl()->get_num_parameters()); + SASSERT(1 == to_app(e)->get_num_args()); + symbol g = to_app(e)->get_decl()->get_parameter(0).get_symbol(); + level = to_app(e)->get_decl()->get_parameter(1).get_int(); + if (g == ":earliest-end-time" || g == "earliest-end-time") + goal = JS_JOB_GOAL_EARLIEST_END_TIME; + else if (g == ":latest-start-time" || g == "latest-start-time") + goal = JS_JOB_GOAL_LATEST_START_TIME; + else + return false; + job = to_app(e)->get_arg(0); + return true; +} + +bool csp_util::is_objective(expr* e, js_optimization_objective& objective) { + if (!is_app_of(e, m_fid, OP_JS_OBJECTIVE)) + return false; + SASSERT(1 == to_app(e)->get_decl()->get_num_parameters()); + symbol obj = to_app(e)->get_decl()->get_parameter(0).get_symbol(); + if (obj == ":duration" || obj == "duration") + objective = JS_OBJECTIVE_DURATION; + else if (obj == ":priority" || obj == "priority") + objective = JS_OBJECTIVE_PRIORITY; + else + return false; + return true; +} + diff --git a/src/ast/csp_decl_plugin.h b/src/ast/csp_decl_plugin.h index 8d6ad56fa..05d6bfa7e 100644 --- a/src/ast/csp_decl_plugin.h +++ b/src/ast/csp_decl_plugin.h @@ -83,7 +83,19 @@ enum js_op_kind { OP_JS_JOB_RESOURCE, // model declaration for job assignment to resource OP_JS_JOB_PREEMPTABLE, // model declaration for whether job is pre-emptable OP_JS_RESOURCE_AVAILABLE, // model declaration for availability intervals of resource - OP_JS_PROPERTIES // model declaration of a set of properties. Each property is a keyword. + OP_JS_PROPERTIES, // model declaration of a set of properties. Each property is a keyword. + OP_JS_JOB_GOAL, // job goal objective :earliest-end-time or :latest-start-time + OP_JS_OBJECTIVE // duration or completion-time +}; + +enum js_job_goal { + JS_JOB_GOAL_EARLIEST_END_TIME, + JS_JOB_GOAL_LATEST_START_TIME +}; + +enum js_optimization_objective { + JS_OBJECTIVE_DURATION, + JS_OBJECTIVE_PRIORITY }; class csp_decl_plugin : public decl_plugin { @@ -140,6 +152,8 @@ public: bool is_set_preemptable(expr* e, expr *& job); bool is_model(expr* e) const { return is_app_of(e, m_fid, OP_JS_MODEL); } bool is_js_properties(expr* e, svector& properties); + bool is_job_goal(expr* e, js_job_goal& goal, unsigned& level, expr*& job); + bool is_objective(expr* e, js_optimization_objective& objective); private: unsigned job2id(expr* j); diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index d1b4847cc..fe7c048a9 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -625,8 +625,6 @@ namespace smt2 { args.push_back(u); next(); } - if (args.empty()) - throw parser_exception("invalid indexed sort, index expected"); sort * r = d->instantiate(pm(), args.size(), args.c_ptr()); if (r == nullptr) throw parser_exception("invalid sort application"); @@ -1520,7 +1518,6 @@ namespace smt2 { check_identifier("invalid indexed identifier, symbol expected"); symbol r = curr_id(); next(); - unsigned num_indices = 0; while (!curr_is_rparen()) { if (curr_is_int()) { if (!curr_numeral().is_unsigned()) { @@ -1545,10 +1542,7 @@ namespace smt2 { else { throw parser_exception("invalid indexed identifier, integer, identifier or '(' expected"); } - num_indices++; } - if (num_indices == 0) - throw parser_exception("invalid indexed identifier, index expected"); next(); return r; } From 5b51e691375d238da9878b3125f3a5e7f205ec93 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 14 Oct 2018 18:17:34 -0700 Subject: [PATCH 046/227] fix #1874 by removing nnf.skolemize option Signed-off-by: Nikolaj Bjorner --- src/ast/normal_forms/nnf.cpp | 6 +-- src/ast/normal_forms/nnf_params.pyg | 3 +- src/ast/normal_forms/pull_quant.cpp | 77 +++++++++++++++-------------- src/sat/sat_solver.cpp | 15 ++---- src/sat/sat_solver.h | 2 - 5 files changed, 47 insertions(+), 56 deletions(-) diff --git a/src/ast/normal_forms/nnf.cpp b/src/ast/normal_forms/nnf.cpp index 7786def0b..c03ff1d0f 100644 --- a/src/ast/normal_forms/nnf.cpp +++ b/src/ast/normal_forms/nnf.cpp @@ -258,7 +258,6 @@ struct nnf::imp { // configuration ---------------- nnf_mode m_mode; bool m_ignore_labels; - bool m_skolemize; // ------------------------------ name_exprs * m_name_nested_formulas; @@ -312,7 +311,6 @@ struct nnf::imp { TRACE("nnf", tout << "nnf-mode: " << m_mode << " " << mode_sym << "\n" << _p << "\n";); m_ignore_labels = p.ignore_labels(); - m_skolemize = p.skolemize(); m_max_memory = megabytes_to_bytes(p.max_memory()); m_skolemizer.set_sk_hack(p.sk_hack()); } @@ -759,7 +757,7 @@ struct nnf::imp { if (!visit(q->get_expr(), fr.m_pol, true)) return false; } - else if (is_forall(q) == fr.m_pol || !m_skolemize) { + else if (is_forall(q) == fr.m_pol) { if (!visit(q->get_expr(), fr.m_pol, true)) return false; } @@ -788,7 +786,7 @@ struct nnf::imp { } return true; } - else if (is_forall(q) == fr.m_pol || !m_skolemize) { + else if (is_forall(q) == fr.m_pol) { expr * new_expr = m_result_stack.back(); proof * new_expr_pr = proofs_enabled() ? m_result_pr_stack.back() : nullptr; diff --git a/src/ast/normal_forms/nnf_params.pyg b/src/ast/normal_forms/nnf_params.pyg index aac8fbb86..999465efc 100644 --- a/src/ast/normal_forms/nnf_params.pyg +++ b/src/ast/normal_forms/nnf_params.pyg @@ -5,5 +5,4 @@ def_module_params('nnf', ('sk_hack', BOOL, False, 'hack for VCC'), ('mode', SYMBOL, 'skolem', 'NNF translation mode: skolem (skolem normal form), quantifiers (skolem normal form + quantifiers in NNF), full'), - ('ignore_labels', BOOL, False, 'remove/ignore labels in the input formula, this option is ignored if proofs are enabled'), - ('skolemize', BOOL, True, 'skolemize (existential force) quantifiers'))) + ('ignore_labels', BOOL, False, 'remove/ignore labels in the input formula, this option is ignored if proofs are enabled'))) diff --git a/src/ast/normal_forms/pull_quant.cpp b/src/ast/normal_forms/pull_quant.cpp index 9ff75ca25..441db5234 100644 --- a/src/ast/normal_forms/pull_quant.cpp +++ b/src/ast/normal_forms/pull_quant.cpp @@ -24,11 +24,11 @@ Notes: struct pull_quant::imp { struct rw_cfg : public default_rewriter_cfg { - ast_manager & m_manager; + ast_manager & m; shift_vars m_shift; rw_cfg(ast_manager & m): - m_manager(m), + m(m), m_shift(m) { } @@ -43,14 +43,14 @@ struct pull_quant::imp { // Remark: (AND a1 ...) may be represented (NOT (OR (NOT a1) ...))) // So, when pulling a quantifier over a NOT, it becomes an exists. - if (m_manager.is_not(d)) { + if (m.is_not(d)) { SASSERT(num_children == 1); expr * child = children[0]; if (is_quantifier(child)) { quantifier * q = to_quantifier(child); expr * body = q->get_expr(); quantifier_kind k = q->get_kind() == forall_k ? exists_k : forall_k; - result = m_manager.update_quantifier(q, k, m_manager.mk_not(body)); + result = m.update_quantifier(q, k, m.mk_not(body)); return true; } else { @@ -86,7 +86,7 @@ struct pull_quant::imp { var_sorts.push_back(nested_q->get_decl_sort(j)); symbol s = nested_q->get_decl_name(j); if (std::find(var_names.begin(), var_names.end(), s) != var_names.end()) - var_names.push_back(m_manager.mk_fresh_var_name(s.is_numerical() ? nullptr : s.bare_str())); + var_names.push_back(m.mk_fresh_var_name(s.is_numerical() ? nullptr : s.bare_str())); else var_names.push_back(s); } @@ -96,8 +96,8 @@ struct pull_quant::imp { if (!var_sorts.empty()) { SASSERT(found_quantifier); // adjust the variable ids in formulas in new_children - expr_ref_buffer new_adjusted_children(m_manager); - expr_ref adjusted_child(m_manager); + expr_ref_buffer new_adjusted_children(m); + expr_ref adjusted_child(m); unsigned num_decls = var_sorts.size(); unsigned shift_amount = 0; TRACE("pull_quant", tout << "Result num decls:" << num_decls << "\n";); @@ -108,7 +108,7 @@ struct pull_quant::imp { // child will be in the scope of num_decls bound variables. m_shift(child, num_decls, adjusted_child); TRACE("pull_quant", tout << "shifted by: " << num_decls << "\n" << - mk_pp(child, m_manager) << "\n---->\n" << mk_pp(adjusted_child, m_manager) << "\n";); + mk_pp(child, m) << "\n---->\n" << mk_pp(adjusted_child, m) << "\n";); } else { quantifier * nested_q = to_quantifier(child); @@ -130,8 +130,8 @@ struct pull_quant::imp { shift_amount, // shift2 (shift by this amount if var idx < bound) adjusted_child); TRACE("pull_quant", tout << "shifted bound: " << nested_q->get_num_decls() << " shift1: " << shift_amount << - " shift2: " << (num_decls - nested_q->get_num_decls()) << "\n" << mk_pp(nested_q->get_expr(), m_manager) << - "\n---->\n" << mk_pp(adjusted_child, m_manager) << "\n";); + " shift2: " << (num_decls - nested_q->get_num_decls()) << "\n" << mk_pp(nested_q->get_expr(), m) << + "\n---->\n" << mk_pp(adjusted_child, m) << "\n";); shift_amount += nested_q->get_num_decls(); } new_adjusted_children.push_back(adjusted_child); @@ -150,11 +150,11 @@ struct pull_quant::imp { // 3) MBQI std::reverse(var_sorts.begin(), var_sorts.end()); std::reverse(var_names.begin(), var_names.end()); - result = m_manager.mk_quantifier(forall_children ? forall_k : exists_k, + result = m.mk_quantifier(forall_children ? forall_k : exists_k, var_sorts.size(), var_sorts.c_ptr(), var_names.c_ptr(), - m_manager.mk_app(d, new_adjusted_children.size(), new_adjusted_children.c_ptr()), + m.mk_app(d, new_adjusted_children.size(), new_adjusted_children.c_ptr()), w, qid); return true; @@ -167,7 +167,7 @@ struct pull_quant::imp { void pull_quant1(func_decl * d, unsigned num_children, expr * const * children, expr_ref & result) { if (!pull_quant1_core(d, num_children, children, result)) { - result = m_manager.mk_app(d, num_children, children); + result = m.mk_app(d, num_children, children); } } @@ -185,7 +185,7 @@ struct pull_quant::imp { var_names.append(nested_q->get_num_decls(), const_cast(nested_q->get_decl_names())); // Remark: patterns are ignored. // See comment in reduce1_app - result = m_manager.mk_forall(var_sorts.size(), + result = m.mk_forall(var_sorts.size(), var_sorts.c_ptr(), var_names.c_ptr(), nested_q->get_expr(), @@ -201,7 +201,7 @@ struct pull_quant::imp { } else { SASSERT(!is_quantifier(new_expr)); - result = m_manager.update_quantifier(q, new_expr); + result = m.update_quantifier(q, new_expr); } } @@ -218,36 +218,36 @@ struct pull_quant::imp { void pull_quant2(expr * n, expr_ref & r, proof_ref & pr) { pr = nullptr; if (is_app(n)) { - expr_ref_buffer new_args(m_manager); - expr_ref new_arg(m_manager); + expr_ref_buffer new_args(m); + expr_ref new_arg(m); ptr_buffer proofs; for (expr * arg : *to_app(n)) { pull_quant1(arg , new_arg); new_args.push_back(new_arg); if (new_arg != arg) - proofs.push_back(m_manager.mk_pull_quant(arg, to_quantifier(new_arg))); + proofs.push_back(m.mk_pull_quant(arg, to_quantifier(new_arg))); } pull_quant1(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr(), r); - if (m_manager.proofs_enabled()) { - app * r1 = m_manager.mk_app(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr()); - proof * p1 = proofs.empty() ? nullptr : m_manager.mk_congruence(to_app(n), r1, proofs.size(), proofs.c_ptr()); - proof * p2 = r1 == r ? nullptr : m_manager.mk_pull_quant(r1, to_quantifier(r)); - pr = m_manager.mk_transitivity(p1, p2); + if (m.proofs_enabled()) { + app * r1 = m.mk_app(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr()); + proof * p1 = proofs.empty() ? nullptr : m.mk_congruence(to_app(n), r1, proofs.size(), proofs.c_ptr()); + proof * p2 = r1 == r ? nullptr : m.mk_pull_quant(r1, to_quantifier(r)); + pr = m.mk_transitivity(p1, p2); } } else if (is_quantifier(n)) { - expr_ref new_expr(m_manager); + expr_ref new_expr(m); pull_quant1(to_quantifier(n)->get_expr(), new_expr); pull_quant1(to_quantifier(n), new_expr, r); - if (m_manager.proofs_enabled()) { - quantifier * q1 = m_manager.update_quantifier(to_quantifier(n), new_expr); + if (m.proofs_enabled()) { + quantifier * q1 = m.update_quantifier(to_quantifier(n), new_expr); proof * p1 = nullptr; if (n != q1) { - proof * p0 = m_manager.mk_pull_quant(n, to_quantifier(new_expr)); - p1 = m_manager.mk_quant_intro(to_quantifier(n), q1, p0); + proof * p0 = m.mk_pull_quant(n, to_quantifier(new_expr)); + p1 = m.mk_quant_intro(to_quantifier(n), q1, p0); } - proof * p2 = q1 == r ? nullptr : m_manager.mk_pull_quant(q1, to_quantifier(r)); - pr = m_manager.mk_transitivity(p1, p2); + proof * p2 = q1 == r ? nullptr : m.mk_pull_quant(q1, to_quantifier(r)); + pr = m.mk_transitivity(p1, p2); } } else { @@ -256,14 +256,14 @@ struct pull_quant::imp { } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - if (!m_manager.is_or(f) && !m_manager.is_and(f) && !m_manager.is_not(f)) + if (!m.is_or(f) && !m.is_and(f) && !m.is_not(f)) return BR_FAILED; if (!pull_quant1_core(f, num, args, result)) return BR_FAILED; - if (m_manager.proofs_enabled()) { - result_pr = m_manager.mk_pull_quant(m_manager.mk_app(f, num, args), + if (m.proofs_enabled()) { + result_pr = m.mk_pull_quant(m.mk_app(f, num, args), to_quantifier(result.get())); } return BR_DONE; @@ -277,8 +277,11 @@ struct pull_quant::imp { proof_ref & result_pr) { if (is_exists(old_q)) { - UNREACHABLE(); - return false; + result = m.mk_not(new_body); + result = m.mk_not(m.update_quantifier(old_q, exists_k, result)); + if (m.proofs_enabled()) + m.mk_rewrite(old_q, result); + return true; } if (is_lambda(old_q)) { return false; @@ -288,8 +291,8 @@ struct pull_quant::imp { return false; pull_quant1_core(old_q, new_body, result); - if (m_manager.proofs_enabled()) - result_pr = m_manager.mk_pull_quant(old_q, to_quantifier(result.get())); + if (m.proofs_enabled()) + result_pr = m.mk_pull_quant(old_q, to_quantifier(result.get())); return true; } }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 8b0d23f9c..f48ac57a6 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1106,6 +1106,10 @@ namespace sat { m_restart_threshold = m_config.m_restart_initial; } + if (reached_max_conflicts()) { + return l_undef; + } + // iff3_finder(*this)(); simplify_problem(); if (check_inconsistent()) return l_false; @@ -1718,17 +1722,6 @@ namespace sat { #endif } - unsigned solver::get_hash() const { - unsigned result = 0; - for (clause* cp : m_clauses) { - result = combine_hash(cp->size(), combine_hash(result, cp->id())); - } - for (clause* cp : m_learned) { - result = combine_hash(cp->size(), combine_hash(result, cp->id())); - } - return result; - } - bool solver::set_root(literal l, literal r) { return !m_ext || m_ext->set_root(l, r); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index fd9af4a02..a9a9fcee0 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -569,8 +569,6 @@ namespace sat { private: - unsigned get_hash() const; - typedef hashtable index_set; u_map m_antecedents; From 0457b5a73f2326202fb2cd35bc37e508d85e1d31 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 14 Oct 2018 20:39:54 -0700 Subject: [PATCH 047/227] add arguments to optimize_check fix #1866 Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.ml | 6 +++++- src/api/ml/z3.mli | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 2ad07aee4..3c583eaef 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -705,6 +705,10 @@ struct let mk_forall_const = _internal_mk_quantifier_const ~universal:true let mk_exists = _internal_mk_quantifier ~universal:false let mk_exists_const = _internal_mk_quantifier_const ~universal:false + let mk_lambda_const ctx bound body = Z3native.mk_lambda_const ctx (List.length bound) bound body + let mk_lambda ctx bound body = + let (names, sorts) = List.unzip bound in + Z3native.mk_lambda ctx (List.length bound) sorts names body let mk_quantifier (ctx:context) (universal:bool) (sorts:Sort.sort list) (names:Symbol.symbol list) (body:expr) (weight:int option) (patterns:Pattern.pattern list) (nopatterns:expr list) (quantifier_id:Symbol.symbol option) (skolem_id:Symbol.symbol option) = if universal then @@ -1947,7 +1951,7 @@ struct let minimize (x:optimize) (e:Expr.expr) = mk_handle x (Z3native.optimize_minimize (gc x) x e) let check (x:optimize) = - let r = lbool_of_int (Z3native.optimize_check (gc x) x) 0 [] in + let r = lbool_of_int (Z3native.optimize_check (gc x) x 0 []) 0 in match r with | L_TRUE -> Solver.SATISFIABLE | L_FALSE -> Solver.UNSATISFIABLE diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 18ade29bf..ddc9f2a41 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -736,6 +736,12 @@ sig (** Create an existential Quantifier. *) val mk_exists_const : context -> Expr.expr list -> Expr.expr -> int option -> Pattern.pattern list -> Expr.expr list -> Symbol.symbol option -> Symbol.symbol option -> quantifier + (** Create a lambda binding. *) + val mk_lambda_const : context -> Expr.expr list -> Expr.expr -> quantifier + + (** Create a lambda binding where bound variables are given by symbols and sorts *) + val mk_lambda : context -> (Symbol.symbol * Sort.sort) list -> Expr.expr -> quantifier + (** Create a Quantifier. *) val mk_quantifier : context -> Sort.sort list -> Symbol.symbol list -> Expr.expr -> int option -> Pattern.pattern list -> Expr.expr list -> Symbol.symbol option -> Symbol.symbol option -> quantifier From 09e40f6e23351c3da40676b81c61b5f7ee82b234 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 14 Oct 2018 20:43:35 -0700 Subject: [PATCH 048/227] add arguments to optimize_check fix #1866 Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 3c583eaef..d1049615c 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -707,7 +707,8 @@ struct let mk_exists_const = _internal_mk_quantifier_const ~universal:false let mk_lambda_const ctx bound body = Z3native.mk_lambda_const ctx (List.length bound) bound body let mk_lambda ctx bound body = - let (names, sorts) = List.unzip bound in + let names = List.map (fun (x,_) -> x) bound in + let sorts = List.map (fun (_,y) -> y) bound in Z3native.mk_lambda ctx (List.length bound) sorts names body let mk_quantifier (ctx:context) (universal:bool) (sorts:Sort.sort list) (names:Symbol.symbol list) (body:expr) (weight:int option) (patterns:Pattern.pattern list) (nopatterns:expr list) (quantifier_id:Symbol.symbol option) (skolem_id:Symbol.symbol option) = From b1ab4730351bfcc8db3707bab2dc467d66223d74 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 14 Oct 2018 20:44:46 -0700 Subject: [PATCH 049/227] add arguments to optimize_check fix #1866 Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index d1049615c..9d8a9c923 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1952,7 +1952,7 @@ struct let minimize (x:optimize) (e:Expr.expr) = mk_handle x (Z3native.optimize_minimize (gc x) x e) let check (x:optimize) = - let r = lbool_of_int (Z3native.optimize_check (gc x) x 0 []) 0 in + let r = lbool_of_int (Z3native.optimize_check (gc x) x 0 []) in match r with | L_TRUE -> Solver.SATISFIABLE | L_FALSE -> Solver.UNSATISFIABLE From a8f26ae1d8f94b886b4518b261868cfedf756ecd Mon Sep 17 00:00:00 2001 From: Chris Moore <0xCM00@gmail.com> Date: Mon, 15 Oct 2018 10:09:41 -0500 Subject: [PATCH 050/227] Fixes the git submodule error discussed in https://github.com/Z3Prover/z3/pull/1552 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ace973a1..4c1f46ed4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,7 +99,7 @@ set(GIT_DIR "${CMAKE_SOURCE_DIR}/.git") if (EXISTS "${GIT_DIR}") # Try to make CMake configure depend on the current git HEAD so that # a re-configure is triggered when the HEAD changes. - add_git_dir_dependency("${GIT_DIR}" ADD_GIT_DEP_SUCCESS) + add_git_dir_dependency("${CMAKE_SOURCE_DIR}" ADD_GIT_DEP_SUCCESS) if (ADD_GIT_DEP_SUCCESS) if (INCLUDE_GIT_HASH) get_git_head_hash("${GIT_DIR}" Z3GITHASH) From 01005a46f69e3d4e0c6012b676a1fe87352e6cb2 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Mon, 15 Oct 2018 16:59:31 +0100 Subject: [PATCH 051/227] Made it more legal C++17 --- src/muz/base/dl_rule_set.cpp | 3 ++- src/muz/spacer/spacer_context.h | 7 ++++--- src/muz/spacer/spacer_quant_generalizer.cpp | 3 ++- src/qe/qe_vartest.h | 3 ++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/muz/base/dl_rule_set.cpp b/src/muz/base/dl_rule_set.cpp index 80af80266..fdafefcdc 100644 --- a/src/muz/base/dl_rule_set.cpp +++ b/src/muz/base/dl_rule_set.cpp @@ -696,9 +696,10 @@ namespace datalog { } strats_index++; } + using namespace std::placeholders; //we have managed to topologicaly order all the components SASSERT(std::find_if(m_components.begin(), m_components.end(), - std::bind1st(std::not_equal_to(), (item_set*)0)) == m_components.end()); + std::bind(std::not_equal_to(), (item_set*)0, _1)) == m_components.end()); //reverse the strats array, so that the only the later components would depend on earlier ones std::reverse(m_strats.begin(), m_strats.end()); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 0d8b2daf6..614f46d29 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -28,6 +28,7 @@ Notes: #undef max #endif #include +#include #include "util/scoped_ptr_vector.h" #include "muz/spacer/spacer_manager.h" #include "muz/spacer/spacer_prop_solver.h" @@ -189,7 +190,7 @@ public: } }; -struct lemma_lt_proc : public std::binary_function { +struct lemma_lt_proc : public std::function { bool operator() (lemma *a, lemma *b) { return (a->level () < b->level ()) || (a->level () == b->level () && @@ -727,11 +728,11 @@ inline std::ostream &operator<<(std::ostream &out, pob const &p) { return p.display(out); } -struct pob_lt_proc : public std::binary_function { +struct pob_lt_proc : public std::function { bool operator() (const pob *pn1, const pob *pn2) const; }; -struct pob_gt_proc : public std::binary_function { +struct pob_gt_proc : public std::function { bool operator() (const pob *n1, const pob *n2) const { return pob_lt_proc()(n2, n1); } diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp index a11ab4d9e..6443b9b7d 100644 --- a/src/muz/spacer/spacer_quant_generalizer.cpp +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -19,6 +19,7 @@ Revision History: --*/ +#include #include "muz/spacer/spacer_context.h" #include "muz/spacer/spacer_generalizers.h" @@ -36,7 +37,7 @@ Revision History: using namespace spacer; namespace { -struct index_lt_proc : public std::binary_function { +struct index_lt_proc : public std::function { arith_util m_arith; index_lt_proc(ast_manager &m) : m_arith(m) {} bool operator() (app *a, app *b) { diff --git a/src/qe/qe_vartest.h b/src/qe/qe_vartest.h index 52609893f..04acacbd9 100644 --- a/src/qe/qe_vartest.h +++ b/src/qe/qe_vartest.h @@ -21,9 +21,10 @@ Revision History: #include "ast/ast.h" #include "util/uint_set.h" +#include // TBD: move under qe namespace -class is_variable_proc : public std::unary_function { +class is_variable_proc : public std::function { public: virtual bool operator()(const expr* e) const = 0; }; From c8d00fb5b4d98072644980a4fb35947447066733 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Oct 2018 11:44:47 -0700 Subject: [PATCH 052/227] follow instructions from #1879 Signed-off-by: Nikolaj Bjorner --- noarch/repodata.json | 0 noarch/repodata.json.bz2 | Bin 0 -> 14 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 noarch/repodata.json create mode 100644 noarch/repodata.json.bz2 diff --git a/noarch/repodata.json b/noarch/repodata.json new file mode 100644 index 000000000..e69de29bb diff --git a/noarch/repodata.json.bz2 b/noarch/repodata.json.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..b56f3b974d6a345462b5a64b15a84c9b23bb40ec GIT binary patch literal 14 TcmZ>Y%CHnKa Date: Mon, 15 Oct 2018 12:44:19 -0700 Subject: [PATCH 053/227] increment patch Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ace973a1..9bb2141a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() ################################################################################ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 8) -set(Z3_VERSION_PATCH 0) +set(Z3_VERSION_PATCH 1) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 1ec5f05b5..d94089a9c 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 8, 0, 0) + set_version(4, 8, 1, 0) add_lib('util', [], includes2install = ['z3_version.h']) add_lib('polynomial', ['util'], 'math/polynomial') add_lib('sat', ['util']) From 6704a4be0298a0b19c69663965d187cb1b6ccbda Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Oct 2018 12:52:19 -0700 Subject: [PATCH 054/227] Revert "Made Z3 compile for C++17 with MSVC" --- src/muz/base/dl_rule_set.cpp | 3 +-- src/muz/spacer/spacer_context.h | 7 +++---- src/muz/spacer/spacer_quant_generalizer.cpp | 3 +-- src/qe/qe_vartest.h | 3 +-- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/muz/base/dl_rule_set.cpp b/src/muz/base/dl_rule_set.cpp index fdafefcdc..80af80266 100644 --- a/src/muz/base/dl_rule_set.cpp +++ b/src/muz/base/dl_rule_set.cpp @@ -696,10 +696,9 @@ namespace datalog { } strats_index++; } - using namespace std::placeholders; //we have managed to topologicaly order all the components SASSERT(std::find_if(m_components.begin(), m_components.end(), - std::bind(std::not_equal_to(), (item_set*)0, _1)) == m_components.end()); + std::bind1st(std::not_equal_to(), (item_set*)0)) == m_components.end()); //reverse the strats array, so that the only the later components would depend on earlier ones std::reverse(m_strats.begin(), m_strats.end()); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 614f46d29..0d8b2daf6 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -28,7 +28,6 @@ Notes: #undef max #endif #include -#include #include "util/scoped_ptr_vector.h" #include "muz/spacer/spacer_manager.h" #include "muz/spacer/spacer_prop_solver.h" @@ -190,7 +189,7 @@ public: } }; -struct lemma_lt_proc : public std::function { +struct lemma_lt_proc : public std::binary_function { bool operator() (lemma *a, lemma *b) { return (a->level () < b->level ()) || (a->level () == b->level () && @@ -728,11 +727,11 @@ inline std::ostream &operator<<(std::ostream &out, pob const &p) { return p.display(out); } -struct pob_lt_proc : public std::function { +struct pob_lt_proc : public std::binary_function { bool operator() (const pob *pn1, const pob *pn2) const; }; -struct pob_gt_proc : public std::function { +struct pob_gt_proc : public std::binary_function { bool operator() (const pob *n1, const pob *n2) const { return pob_lt_proc()(n2, n1); } diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp index 6443b9b7d..a11ab4d9e 100644 --- a/src/muz/spacer/spacer_quant_generalizer.cpp +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -19,7 +19,6 @@ Revision History: --*/ -#include #include "muz/spacer/spacer_context.h" #include "muz/spacer/spacer_generalizers.h" @@ -37,7 +36,7 @@ Revision History: using namespace spacer; namespace { -struct index_lt_proc : public std::function { +struct index_lt_proc : public std::binary_function { arith_util m_arith; index_lt_proc(ast_manager &m) : m_arith(m) {} bool operator() (app *a, app *b) { diff --git a/src/qe/qe_vartest.h b/src/qe/qe_vartest.h index 04acacbd9..52609893f 100644 --- a/src/qe/qe_vartest.h +++ b/src/qe/qe_vartest.h @@ -21,10 +21,9 @@ Revision History: #include "ast/ast.h" #include "util/uint_set.h" -#include // TBD: move under qe namespace -class is_variable_proc : public std::function { +class is_variable_proc : public std::unary_function { public: virtual bool operator()(const expr* e) const = 0; }; From cfd048658278c7079e52a41e9ec34fa2b4ed1abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Fri, 12 Oct 2018 21:15:31 +0200 Subject: [PATCH 055/227] Catch exceptions by const-reference Exceptions caught by value incur needless cost in C++, most of them can be caught by const-reference, especially as nearly none are actually used. This could allow compiler generate a slightly more efficient code. --- src/ast/datatype_decl_plugin.cpp | 2 +- src/ast/for_each_expr.cpp | 2 +- src/ast/occurs.cpp | 4 ++-- src/cmd_context/check_logic.cpp | 4 ++-- src/cmd_context/cmd_context.cpp | 2 +- src/math/polynomial/algebraic_numbers.cpp | 2 +- src/math/polynomial/polynomial.cpp | 2 +- src/math/subpaving/tactic/subpaving_tactic.cpp | 4 ++-- src/muz/base/dl_rule.cpp | 2 +- src/muz/base/hnf.cpp | 2 +- src/muz/spacer/spacer_context.cpp | 2 +- src/muz/spacer/spacer_farkas_learner.cpp | 2 +- src/muz/spacer/spacer_iuc_proof.cpp | 2 +- src/muz/spacer/spacer_manager.cpp | 2 +- src/muz/spacer/spacer_quant_generalizer.cpp | 2 +- src/muz/spacer/spacer_util.cpp | 2 +- src/muz/tab/tab_context.cpp | 2 +- src/muz/transforms/dl_mk_elim_term_ite.cpp | 2 +- src/opt/opt_context.cpp | 4 ++-- src/parsers/smt2/smt2parser.cpp | 2 +- src/parsers/util/simple_parser.cpp | 2 +- src/qe/qe_datatypes.cpp | 2 +- src/qe/qe_term_graph.cpp | 2 +- src/sat/sat_bdd.cpp | 6 +++--- src/sat/sat_solver.cpp | 2 +- src/smt/smt_model_checker.cpp | 2 +- src/smt/smt_model_finder.cpp | 6 +++--- src/smt/uses_theory.cpp | 2 +- src/tactic/arith/bv2real_rewriter.cpp | 2 +- src/tactic/arith/fix_dl_var_tactic.cpp | 2 +- src/tactic/arith/lia2pb_tactic.cpp | 2 +- src/tactic/arith/pb2bv_tactic.cpp | 2 +- src/tactic/bv/bv1_blaster_tactic.cpp | 2 +- src/tactic/goal.h | 2 +- src/tactic/probe.cpp | 4 ++-- src/tactic/ufbv/ufbv_rewriter.cpp | 2 +- 36 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 284c4df93..9cb685ccc 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -231,7 +231,7 @@ namespace datatype { } return s; } - catch (invalid_datatype) { + catch (const invalid_datatype &) { m_manager->raise_exception("invalid datatype"); return nullptr; } diff --git a/src/ast/for_each_expr.cpp b/src/ast/for_each_expr.cpp index d46388801..311133e05 100644 --- a/src/ast/for_each_expr.cpp +++ b/src/ast/for_each_expr.cpp @@ -58,7 +58,7 @@ bool has_skolem_functions(expr * n) { try { for_each_expr(p, n); } - catch (has_skolem_functions_ns::found) { + catch (const has_skolem_functions_ns::found &) { return true; } return false; diff --git a/src/ast/occurs.cpp b/src/ast/occurs.cpp index c76e73748..9ddb2fa56 100644 --- a/src/ast/occurs.cpp +++ b/src/ast/occurs.cpp @@ -58,7 +58,7 @@ bool occurs(expr * n1, expr * n2) { try { quick_for_each_expr(p, n2); } - catch (occurs_namespace::found) { + catch (const occurs_namespace::found &) { return true; } return false; @@ -69,7 +69,7 @@ bool occurs(func_decl * d, expr * n) { try { quick_for_each_expr(p, n); } - catch (occurs_namespace::found) { + catch (const occurs_namespace::found &) { return true; } return false; diff --git a/src/cmd_context/check_logic.cpp b/src/cmd_context/check_logic.cpp index 57e15c6a3..47c919d4a 100644 --- a/src/cmd_context/check_logic.cpp +++ b/src/cmd_context/check_logic.cpp @@ -476,7 +476,7 @@ struct check_logic::imp { quick_for_each_expr(*this, n); return true; } - catch (failed) { + catch (const failed &) { return false; } } @@ -495,7 +495,7 @@ struct check_logic::imp { check_sort(f->get_range()); return true; } - catch (failed) { + catch (const failed &) { return false; } } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 8a23f80a0..7b7f81561 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1833,7 +1833,7 @@ void cmd_context::validate_model() { for_each_expr(contains_underspecified, a); for_each_expr(contains_underspecified, r); } - catch (contains_underspecified_op_proc::found) { + catch (const contains_underspecified_op_proc::found &) { continue; } TRACE("model_validate", model_smt2_pp(tout, *this, *md, 0);); diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index aa4fc5a39..528c10537 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -1989,7 +1989,7 @@ namespace algebraic_numbers { TRACE("anum_eval_sign", tout << "all variables are assigned to rationals, value of p: " << r << "\n";); return qm().sign(r); } - catch (opt_var2basic::failed) { + catch (const opt_var2basic::failed &) { // continue } diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index 24658fdcf..00a4d0593 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -4493,7 +4493,7 @@ namespace polynomial { } #endif } - catch (sparse_mgcd_failed) { + catch (const sparse_mgcd_failed &) { flet use_prs(m_use_prs_gcd, false); gcd_prs(u, v, x, r); } diff --git a/src/math/subpaving/tactic/subpaving_tactic.cpp b/src/math/subpaving/tactic/subpaving_tactic.cpp index 935fd5e19..7a3f2e7b3 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.cpp +++ b/src/math/subpaving/tactic/subpaving_tactic.cpp @@ -183,7 +183,7 @@ class subpaving_tactic : public tactic { process_clause(g.form(i)); } } - catch (subpaving::exception) { + catch (const subpaving::exception &) { throw tactic_exception("failed to internalize goal into subpaving module"); } } @@ -195,7 +195,7 @@ class subpaving_tactic : public tactic { try { (*m_ctx)(); } - catch (subpaving::exception) { + catch (const subpaving::exception &) { throw tactic_exception("failed building subpaving tree..."); } if (m_display) { diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index 0dbeba5b3..fe1f101b1 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -422,7 +422,7 @@ namespace datalog { try { quick_for_each_expr(proc, fml); } - catch (contains_predicate_proc::found) { + catch (const contains_predicate_proc::found &) { return true; } return false; diff --git a/src/muz/base/hnf.cpp b/src/muz/base/hnf.cpp index f0cbc0620..1e6196950 100644 --- a/src/muz/base/hnf.cpp +++ b/src/muz/base/hnf.cpp @@ -219,7 +219,7 @@ private: quick_for_each_expr(m_proc, m_mark1, fml); m_mark1.reset(); } - catch (contains_predicate_proc::found) { + catch (const contains_predicate_proc::found &) { m_mark1.reset(); return true; } diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 30b68ebf6..9a9043f2f 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2737,7 +2737,7 @@ lbool context::solve(unsigned from_lvl) // } } VERIFY (validate ()); - } catch (unknown_exception) + } catch (const unknown_exception &) {} if (m_last_result == l_true) { diff --git a/src/muz/spacer/spacer_farkas_learner.cpp b/src/muz/spacer/spacer_farkas_learner.cpp index d97bee49f..291226b55 100644 --- a/src/muz/spacer/spacer_farkas_learner.cpp +++ b/src/muz/spacer/spacer_farkas_learner.cpp @@ -95,7 +95,7 @@ bool farkas_learner::is_pure_expr(func_decl_set const& symbs, expr* e, ast_manag is_pure_expr_proc proc(symbs, m); try { for_each_expr(proc, e); - } catch (is_pure_expr_proc::non_pure) { + } catch (const is_pure_expr_proc::non_pure &) { return false; } return true; diff --git a/src/muz/spacer/spacer_iuc_proof.cpp b/src/muz/spacer/spacer_iuc_proof.cpp index b6a522b76..949507fb4 100644 --- a/src/muz/spacer/spacer_iuc_proof.cpp +++ b/src/muz/spacer/spacer_iuc_proof.cpp @@ -88,7 +88,7 @@ bool iuc_proof::is_core_pure(expr* e) const try { for_each_expr(proc, e); } - catch (is_pure_expr_proc::non_pure) + catch (const is_pure_expr_proc::non_pure &) {return false;} return true; diff --git a/src/muz/spacer/spacer_manager.cpp b/src/muz/spacer/spacer_manager.cpp index 856207463..817d620c9 100644 --- a/src/muz/spacer/spacer_manager.cpp +++ b/src/muz/spacer/spacer_manager.cpp @@ -247,7 +247,7 @@ bool has_zk_const(expr *e){ try { for_each_expr(p, e); } - catch (has_zk_const_ns::found) { + catch (const has_zk_const_ns::found &) { return true; } return false; diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp index a11ab4d9e..f3307a596 100644 --- a/src/muz/spacer/spacer_quant_generalizer.cpp +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -120,7 +120,7 @@ struct index_lt_proc : public std::binary_function { for (expr *e : v) quick_for_each_expr(fn, visited, e); } - catch (has_nlira_functor::found ) { + catch (const has_nlira_functor::found &) { return true; } return false; diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index ec01218f1..2a5f1e2cc 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -891,7 +891,7 @@ namespace { for_each_expr(cs, fml); return false; } - catch(found) { + catch(const found &) { return true; } } diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index c60c770bf..b5be996dc 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -415,7 +415,7 @@ namespace tb { try { quick_for_each_expr(p, t); } - catch (non_constructor) { + catch (const non_constructor &) { return false; } return true; diff --git a/src/muz/transforms/dl_mk_elim_term_ite.cpp b/src/muz/transforms/dl_mk_elim_term_ite.cpp index f0d9a8843..7e0356e7e 100644 --- a/src/muz/transforms/dl_mk_elim_term_ite.cpp +++ b/src/muz/transforms/dl_mk_elim_term_ite.cpp @@ -57,7 +57,7 @@ namespace { term_ite_proc f(m); try { quick_for_each_expr(f, e); - } catch (term_ite_proc::found) { + } catch (const term_ite_proc::found &) { return true; } return false; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ff37bfa95..d9c3457fa 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -706,7 +706,7 @@ namespace opt { quick_for_each_expr(proc, visited, f); } } - catch (is_bv::found) { + catch (const is_bv::found &) { return false; } return true; @@ -737,7 +737,7 @@ namespace opt { try { quick_for_each_expr(proc, visited, p); } - catch (is_propositional_fn::found) { + catch (const is_propositional_fn::found &) { return false; } return true; diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 1a16b817b..58b16717d 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -3084,7 +3084,7 @@ namespace smt2 { << ": " << ex.msg() << "\")" << std::endl; exit(ex.error_code()); } - catch (stop_parser_exception) { + catch (const stop_parser_exception &) { m_scanner.stop_caching(); return !found_errors; } diff --git a/src/parsers/util/simple_parser.cpp b/src/parsers/util/simple_parser.cpp index c9d00ebcc..48c42c240 100644 --- a/src/parsers/util/simple_parser.cpp +++ b/src/parsers/util/simple_parser.cpp @@ -118,7 +118,7 @@ bool simple_parser::parse(std::istream & in, expr_ref & result) { if (!result) throw parser_error(); } - catch (parser_error) { + catch (const parser_error &) { warning_msg("parser error"); return false; } diff --git a/src/qe/qe_datatypes.cpp b/src/qe/qe_datatypes.cpp index 5499d638d..7ade47458 100644 --- a/src/qe/qe_datatypes.cpp +++ b/src/qe/qe_datatypes.cpp @@ -61,7 +61,7 @@ namespace qe { project_nonrec(model, vars, lits); } } - catch (cant_project) { + catch (const cant_project &) { TRACE("qe", tout << "can't project:" << mk_pp(var, m) << "\n";); return false; } diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index faa9cfed8..97b044f5b 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -62,7 +62,7 @@ namespace qe { is_pure_ns::proc v(is_var); quick_for_each_expr(v, e); } - catch (is_pure_ns::found) { + catch (const is_pure_ns::found &) { return false; } return true; diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index bd1745765..e7b0632d8 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -87,7 +87,7 @@ namespace sat { try { return apply_rec(arg1, arg2, op); } - catch (mem_out) { + catch (const mem_out &) { try_reorder(); if (!first) throw; first = false; @@ -546,7 +546,7 @@ namespace sat { try { return bdd(mk_not_rec(b.root), this); } - catch (mem_out) { + catch (const mem_out &) { try_reorder(); if (!first) throw; first = false; @@ -575,7 +575,7 @@ namespace sat { try { return bdd(mk_ite_rec(c.root, t.root, e.root), this); } - catch (mem_out) { + catch (const mem_out &) { try_reorder(); if (!first) throw; first = false; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f48ac57a6..2032445ed 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1147,7 +1147,7 @@ namespace sat { } } - catch (abort_solver) { + catch (const abort_solver &) { m_reason_unknown = "sat.giveup"; return l_undef; } diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 02b0e16be..58158ec06 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -261,7 +261,7 @@ namespace smt { try { for_each_expr(*this, m_visited, n); } - catch (is_model_value) { + catch (const is_model_value &) { return true; } return false; diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index b8b22b067..30ea7b18e 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -177,7 +177,7 @@ namespace smt { try { for_each_expr(*this, m_visited, n); } - catch (is_model_value) { + catch (const is_model_value &) { return true; } return false; @@ -2892,7 +2892,7 @@ namespace smt { try { for_each_expr(oc, m_visited, def); } - catch (occurs) { + catch (const occurs &) { return false; } return true; @@ -2981,7 +2981,7 @@ namespace smt { try { process(f); } - catch (found_satisfied_subset) { + catch (const found_satisfied_subset &) { set_interp(); copy_non_satisfied(qcandidates, new_qs); return true; diff --git a/src/smt/uses_theory.cpp b/src/smt/uses_theory.cpp index 517951a7b..64565dc78 100644 --- a/src/smt/uses_theory.cpp +++ b/src/smt/uses_theory.cpp @@ -41,7 +41,7 @@ bool uses_theory(expr * n, family_id fid, expr_mark & visited) { try { for_each_expr(p, visited, n); } - catch (uses_theory_ns::found) { + catch (const uses_theory_ns::found &) { return true; } return false; diff --git a/src/tactic/arith/bv2real_rewriter.cpp b/src/tactic/arith/bv2real_rewriter.cpp index 5839ff7a2..67fca873e 100644 --- a/src/tactic/arith/bv2real_rewriter.cpp +++ b/src/tactic/arith/bv2real_rewriter.cpp @@ -89,7 +89,7 @@ bool bv2real_util::contains_bv2real(expr* e) const { try { for_each_expr(p, e); } - catch (contains_bv2real_proc::found) { + catch (const contains_bv2real_proc::found &) { return true; } return false; diff --git a/src/tactic/arith/fix_dl_var_tactic.cpp b/src/tactic/arith/fix_dl_var_tactic.cpp index 669ded49d..d198ce498 100644 --- a/src/tactic/arith/fix_dl_var_tactic.cpp +++ b/src/tactic/arith/fix_dl_var_tactic.cpp @@ -226,7 +226,7 @@ class fix_dl_var_tactic : public tactic { } return most_occs(); } - catch (failed) { + catch (const failed &) { return nullptr; } } diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index db1c22866..c177f35be 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -156,7 +156,7 @@ class lia2pb_tactic : public tactic { } return true; } - catch (failed) { + catch (const failed &) { return false; } } diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index f36e3a6db..7a64c9f16 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -1034,7 +1034,7 @@ struct is_pb_probe : public probe { return true; } - catch (pb2bv_tactic::non_pb) { + catch (const pb2bv_tactic::non_pb &) { return false; } } diff --git a/src/tactic/bv/bv1_blaster_tactic.cpp b/src/tactic/bv/bv1_blaster_tactic.cpp index b81bc5687..bf9ca4101 100644 --- a/src/tactic/bv/bv1_blaster_tactic.cpp +++ b/src/tactic/bv/bv1_blaster_tactic.cpp @@ -371,7 +371,7 @@ class bv1_blaster_tactic : public tactic { for_each_expr_core(proc, visited, f); } } - catch (not_target) { + catch (const not_target &) { return false; } return true; diff --git a/src/tactic/goal.h b/src/tactic/goal.h index 4125fab99..fa2f16eb6 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -195,7 +195,7 @@ bool test(goal const & g, Predicate & proc) { for (unsigned i = 0; i < sz; i++) quick_for_each_expr(proc, visited, g.form(i)); } - catch (typename Predicate::found) { + catch (const typename Predicate::found &) { return true; } return false; diff --git a/src/tactic/probe.cpp b/src/tactic/probe.cpp index dcd1dc500..432c9d123 100644 --- a/src/tactic/probe.cpp +++ b/src/tactic/probe.cpp @@ -524,7 +524,7 @@ public: } return false; } - catch (found) { + catch (const found &) { return true; } } @@ -554,7 +554,7 @@ public: } return false; } - catch (found) { + catch (const found &) { return true; } } diff --git a/src/tactic/ufbv/ufbv_rewriter.cpp b/src/tactic/ufbv/ufbv_rewriter.cpp index ee8a4605b..66a26be00 100644 --- a/src/tactic/ufbv/ufbv_rewriter.cpp +++ b/src/tactic/ufbv/ufbv_rewriter.cpp @@ -870,7 +870,7 @@ bool ufbv_rewriter::match_subst::match_args(app * lhs, expr * const * args) { m_cache.insert(p); continue; } - catch (match_args_aux_proc::no_match) { + catch (const match_args_aux_proc::no_match &) { return false; } } From 844f400a62172bb9331ad7c9f3a6446e30fab169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Tue, 16 Oct 2018 19:30:48 +0200 Subject: [PATCH 056/227] Remove superfluous const from returned types --- src/smt/theory_arith.h | 8 ++++---- src/util/lp/static_matrix.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index a2c6c1191..70ce6b397 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -156,9 +156,9 @@ namespace smt { row_entry & operator[](unsigned idx) { return m_entries[idx]; } row_entry const & operator[](unsigned idx) const { return m_entries[idx]; } typename vector::iterator begin_entries() { return m_entries.begin(); } - const typename vector::const_iterator begin_entries() const { return m_entries.begin(); } + typename vector::const_iterator begin_entries() const { return m_entries.begin(); } typename vector::iterator end_entries() { return m_entries.end(); } - const typename vector::const_iterator end_entries() const { return m_entries.end(); } + typename vector::const_iterator end_entries() const { return m_entries.end(); } row_entry & add_row_entry(int & pos_idx); void del_row_entry(unsigned idx); void compress(vector & cols); @@ -195,9 +195,9 @@ namespace smt { col_entry & operator[](unsigned idx) { return m_entries[idx]; } col_entry const & operator[](unsigned idx) const { return m_entries[idx]; } typename svector::iterator begin_entries() { return m_entries.begin(); } - const typename svector::const_iterator begin_entries() const { return m_entries.begin(); } + typename svector::const_iterator begin_entries() const { return m_entries.begin(); } typename svector::iterator end_entries() { return m_entries.end(); } - const typename svector::const_iterator end_entries() const { return m_entries.end(); } + typename svector::const_iterator end_entries() const { return m_entries.end(); } col_entry & add_col_entry(int & pos_idx); void del_col_entry(unsigned idx); }; diff --git a/src/util/lp/static_matrix.h b/src/util/lp/static_matrix.h index bb6cdefc8..1a0ee1bdc 100644 --- a/src/util/lp/static_matrix.h +++ b/src/util/lp/static_matrix.h @@ -93,7 +93,7 @@ public: unsigned m_row; public: ref_row(const static_matrix & m, unsigned row): m_matrix(m), m_row(row) {} - const T operator[](unsigned col) const { return m_matrix.get_elem(m_row, col); } + T operator[](unsigned col) const { return m_matrix.get_elem(m_row, col); } }; public: From 9dd9d5e18ab9735001782e386cca0ce59bc8dbee Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Oct 2018 05:22:43 -0700 Subject: [PATCH 057/227] more integration Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.h | 17 ++++--- src/smt/theory_recfun.cpp | 94 ++++++++++++++++++++++++--------------- src/smt/theory_recfun.h | 4 +- 3 files changed, 67 insertions(+), 48 deletions(-) diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 5049eb3fc..a349880e3 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1614,23 +1614,22 @@ namespace smt { void insert_macro(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep) { m_asserted_formulas.insert_macro(f, m, pr, dep); } }; - struct pp_lit { - smt::context & ctx; - smt::literal lit; - pp_lit(smt::context & ctx, smt::literal lit) : ctx(ctx), lit(lit) {} + context & ctx; + literal lit; + pp_lit(context & ctx, literal lit) : ctx(ctx), lit(lit) {} }; inline std::ostream & operator<<(std::ostream & out, pp_lit const & pp) { - pp.ctx.display_detailed_literal(out, pp.lit); - return out; + return pp.ctx.display_detailed_literal(out, pp.lit); } struct pp_lits { - smt::context & ctx; - smt::literal *lits; + context & ctx; + literal const *lits; unsigned len; - pp_lits(smt::context & ctx, unsigned len, smt::literal *lits) : ctx(ctx), lits(lits), len(len) {} + pp_lits(context & ctx, unsigned len, literal const *lits) : ctx(ctx), lits(lits), len(len) {} + pp_lits(context & ctx, literal_vector const& ls) : ctx(ctx), lits(ls.c_ptr()), len(ls.size()) {} }; inline std::ostream & operator<<(std::ostream & out, pp_lits const & pp) { diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index dcb8ad097..b108512ba 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -1,11 +1,29 @@ +/*++ +Copyright (c) 2018 Microsoft Corporation, Simon Cuares + +Module Name: + + theory_recfun.cpp + +Abstract: + + Theory responsible for unrolling recursive functions + +Author: + + Simon Cuares December 2017 + +Revision History: + +--*/ #include "util/stats.h" #include "ast/ast_util.h" #include "smt/theory_recfun.h" #include "smt/params/smt_params_helper.hpp" -#define DEBUG(x) TRACE("recfun", tout << x << '\n';) +#define TRACEFN(x) TRACE("recfun", tout << x << '\n';) namespace smt { @@ -14,7 +32,11 @@ namespace smt { m_plugin(*reinterpret_cast(m.get_plugin(get_family_id()))), m_util(m_plugin.u()), m_trail(*this), - m_guards(), m_max_depth(0), m_q_case_expand(), m_q_body_expand(), m_q_clauses() + m_guards(), + m_max_depth(0), + m_q_case_expand(), + m_q_body_expand(), + m_q_clauses() { } @@ -40,13 +62,13 @@ namespace smt { bool theory_recfun::internalize_atom(app * atom, bool gate_ctx) { context & ctx = get_context(); - if (! ctx.e_internalized(atom)) { - unsigned num_args = atom->get_num_args(); - for (unsigned i = 0; i < num_args; ++i) - ctx.internalize(atom->get_arg(i), false); + for (expr * arg : *atom) { + ctx.internalize(arg, false); + } + if (!ctx.e_internalized(atom)) { ctx.mk_enode(atom, false, true, false); } - if (! ctx.b_internalized(atom)) { + if (!ctx.b_internalized(atom)) { bool_var v = ctx.mk_bool_var(atom); ctx.set_var_theory(v, get_id()); } @@ -55,12 +77,14 @@ namespace smt { bool theory_recfun::internalize_term(app * term) { context & ctx = get_context(); - for (expr* e : *term) ctx.internalize(e, false); + for (expr* e : *term) { + ctx.internalize(e, false); + } // the internalization of the arguments may have triggered the internalization of term. - if (ctx.e_internalized(term)) - return true; - ctx.mk_enode(term, false, false, true); - return true; // the theory doesn't actually map terms to variables + if (!ctx.e_internalized(term)) { + ctx.mk_enode(term, false, false, true); + } + return true; } void theory_recfun::reset_queues() { @@ -77,35 +101,34 @@ namespace smt { } /* - * when `n` becomes relevant, if it's `f(t1…tn)` with `f` defined, + * when `n` becomes relevant, if it's `f(t1...tn)` with `f` defined, * then case-expand `n`. If it's a macro we can also immediately * body-expand it. */ void theory_recfun::relevant_eh(app * n) { SASSERT(get_context().relevancy()); if (u().is_defined(n)) { - DEBUG("relevant_eh: (defined) " << mk_pp(n, m())); - + TRACEFN("relevant_eh: (defined) " << mk_pp(n, m())); case_expansion e(u(), n); push_case_expand(std::move(e)); } } void theory_recfun::push_scope_eh() { - DEBUG("push_scope"); + TRACEFN("push_scope"); theory::push_scope_eh(); m_trail.push_scope(); } void theory_recfun::pop_scope_eh(unsigned num_scopes) { - DEBUG("pop_scope " << num_scopes); + TRACEFN("pop_scope " << num_scopes); m_trail.pop_scope(num_scopes); theory::pop_scope_eh(num_scopes); reset_queues(); } void theory_recfun::restart_eh() { - DEBUG("restart"); + TRACEFN("restart"); reset_queues(); theory::restart_eh(); } @@ -120,7 +143,7 @@ namespace smt { context & ctx = get_context(); for (literal_vector & c : m_q_clauses) { - DEBUG("add axiom " << pp_lits(ctx, c.size(), c.c_ptr())); + TRACEFN("add axiom " << pp_lits(ctx, c)); ctx.mk_th_axiom(get_id(), c.size(), c.c_ptr()); } m_q_clauses.clear(); @@ -145,7 +168,7 @@ namespace smt { } void theory_recfun::max_depth_conflict() { - DEBUG("max-depth conflict"); + TRACEFN("max-depth conflict"); context & ctx = get_context(); literal_vector c; // make clause `depth_limit => V_{g : guards} ~ g` @@ -160,20 +183,20 @@ namespace smt { expr * g = & kv.get_key(); c.push_back(~ ctx.get_literal(g)); } - DEBUG("max-depth limit: add clause " << pp_lits(ctx, c.size(), c.c_ptr())); + TRACEFN("max-depth limit: add clause " << pp_lits(ctx, c)); SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx.get_assignment(l) == l_false; })); // conflict m_q_clauses.push_back(std::move(c)); } - // if `is_true` and `v = C_f_i(t1…tn)`, then body-expand i-th case of `f(t1…tn)` + // if `is_true` and `v = C_f_i(t1...tn)`, then body-expand i-th case of `f(t1…tn)` void theory_recfun::assign_eh(bool_var v, bool is_true) { expr* e = get_context().bool_var2expr(v); if (!is_true) return; if (!is_app(e)) return; app* a = to_app(e); if (u().is_case_pred(a)) { - DEBUG("assign_case_pred_true "<< mk_pp(e,m())); + TRACEFN("assign_case_pred_true "<< mk_pp(e,m())); // add to set of local assumptions, for depth-limit purpose { m_guards.insert(e, empty()); @@ -207,20 +230,19 @@ namespace smt { } app_ref theory_recfun::apply_pred(recfun::case_pred const & p, - ptr_vector const & args){ - app_ref res(u().mk_case_pred(p, args), m()); - return res; + ptr_vector const & args) { + return app_ref(u().mk_case_pred(p, args), m()); } void theory_recfun::assert_macro_axiom(case_expansion & e) { - DEBUG("assert_macro_axiom " << pp_case_expansion(e,m())); + TRACEFN("assert_macro_axiom " << pp_case_expansion(e,m())); SASSERT(e.m_def->is_fun_macro()); expr_ref lhs(e.m_lhs, m()); context & ctx = get_context(); auto & vars = e.m_def->get_vars(); // substitute `e.args` into the macro RHS expr_ref rhs(apply_args(vars, e.m_args, e.m_def->get_macro_rhs()), m()); - DEBUG("macro expansion yields" << mk_pp(rhs,m())); + TRACEFN("macro expansion yields" << mk_pp(rhs,m())); // now build the axiom `lhs = rhs` ctx.internalize(rhs, false); // add unit clause `lhs=rhs` @@ -228,12 +250,12 @@ namespace smt { ctx.mark_as_relevant(l); literal_vector lits; lits.push_back(l); - DEBUG("assert_macro_axiom: " << pp_lits(ctx, lits.size(), lits.c_ptr())); + TRACEFN("assert_macro_axiom: " << pp_lits(ctx, lits)); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } void theory_recfun::assert_case_axioms(case_expansion & e) { - DEBUG("assert_case_axioms "<< pp_case_expansion(e,m()) + TRACEFN("assert_case_axioms "<< pp_case_expansion(e,m()) << " with " << e.m_def->get_cases().size() << " cases"); SASSERT(e.m_def->is_fun_defined()); context & ctx = get_context(); @@ -264,7 +286,7 @@ namespace smt { //TRACE("recfun", tout << "assert_case_axioms " << pp_case_expansion(e) // << " axiom " << mk_pp(*l) <<"\n";); - DEBUG("assert_case_axiom " << pp_lits(get_context(), path.size()+1, c.c_ptr())); + TRACEFN("assert_case_axiom " << pp_lits(get_context(), path.size()+1, c.c_ptr())); get_context().mk_th_axiom(get_id(), path.size()+1, c.c_ptr()); } { @@ -274,7 +296,7 @@ namespace smt { literal g = ctx.get_literal(_g); literal c[2] = {~ concl, g}; - DEBUG("assert_case_axiom " << pp_lits(get_context(), 2, c)); + TRACEFN("assert_case_axiom " << pp_lits(get_context(), 2, c)); get_context().mk_th_axiom(get_id(), 2, c); } } @@ -288,7 +310,7 @@ namespace smt { } void theory_recfun::assert_body_axiom(body_expansion & e) { - DEBUG("assert_body_axioms "<< pp_body_expansion(e,m())); + TRACEFN("assert_body_axioms "<< pp_body_expansion(e,m())); context & ctx = get_context(); recfun::def & d = *e.m_cdef->get_def(); auto & vars = d.get_vars(); @@ -320,7 +342,7 @@ namespace smt { literal l(mk_eq(lhs, rhs, true)); ctx.mark_as_relevant(l); clause.push_back(l); - DEBUG("assert_body_axiom " << pp_lits(ctx, clause.size(), clause.c_ptr())); + TRACEFN("assert_body_axiom " << pp_lits(ctx, clause)); ctx.mk_th_axiom(get_id(), clause.size(), clause.c_ptr()); } @@ -330,7 +352,7 @@ namespace smt { void theory_recfun::add_theory_assumptions(expr_ref_vector & assumptions) { app_ref dlimit = m_util.mk_depth_limit_pred(get_max_depth()); - DEBUG("add_theory_assumption " << mk_pp(dlimit.get(), m())); + TRACEFN("add_theory_assumption " << mk_pp(dlimit.get(), m())); assumptions.push_back(dlimit); } @@ -354,7 +376,6 @@ namespace smt { st.update("recfun body expansion", m_stats.m_body_expansions); } -#ifdef Z3DEBUG std::ostream& operator<<(std::ostream & out, theory_recfun::pp_case_expansion const & e) { return out << "case_exp(" << mk_pp(e.e.m_lhs, e.m) << ")"; } @@ -366,5 +387,4 @@ namespace smt { } return out << ")"; } -#endif } diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index a1d9048c1..68833be63 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2006 Microsoft Corporation +Copyright (c) 2018 Microsoft Corporation Module Name: @@ -11,7 +11,7 @@ Abstract: Author: - Leonardo de Moura (leonardo) 2008-10-31. + Simon Cuares December 2017 Revision History: From 48cdd12a471193ea87c7ca22ba16f0c3dcd2e5c6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Oct 2018 05:56:04 -0700 Subject: [PATCH 058/227] cleanup Signed-off-by: Nikolaj Bjorner --- src/smt/theory_recfun.cpp | 85 +++++++++++++-------------------------- 1 file changed, 29 insertions(+), 56 deletions(-) diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index b108512ba..45902c3dd 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -189,11 +189,10 @@ namespace smt { m_q_clauses.push_back(std::move(c)); } - // if `is_true` and `v = C_f_i(t1...tn)`, then body-expand i-th case of `f(t1…tn)` + // if `is_true` and `v = C_f_i(t1...tn)`, then body-expand i-th case of `f(t1...tn)` void theory_recfun::assign_eh(bool_var v, bool is_true) { expr* e = get_context().bool_var2expr(v); - if (!is_true) return; - if (!is_app(e)) return; + if (!is_true || !is_app(e)) return; app* a = to_app(e); if (u().is_case_pred(a)) { TRACEFN("assign_case_pred_true "<< mk_pp(e,m())); @@ -235,23 +234,19 @@ namespace smt { } void theory_recfun::assert_macro_axiom(case_expansion & e) { - TRACEFN("assert_macro_axiom " << pp_case_expansion(e,m())); + TRACEFN("assert_macro_axiom " << pp_case_expansion(e, m())); SASSERT(e.m_def->is_fun_macro()); - expr_ref lhs(e.m_lhs, m()); context & ctx = get_context(); auto & vars = e.m_def->get_vars(); + expr_ref lhs(e.m_lhs, m()); // substitute `e.args` into the macro RHS expr_ref rhs(apply_args(vars, e.m_args, e.m_def->get_macro_rhs()), m()); TRACEFN("macro expansion yields" << mk_pp(rhs,m())); - // now build the axiom `lhs = rhs` - ctx.internalize(rhs, false); - // add unit clause `lhs=rhs` + // add unit clause `lhs = rhs` literal l(mk_eq(lhs, rhs, true)); ctx.mark_as_relevant(l); - literal_vector lits; - lits.push_back(l); - TRACEFN("assert_macro_axiom: " << pp_lits(ctx, lits)); - ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + TRACEFN("assert_macro_axiom: " << pp_lit(ctx, l)); + ctx.mk_th_axiom(get_id(), 1, &l); } void theory_recfun::assert_case_axioms(case_expansion & e) { @@ -263,43 +258,27 @@ namespace smt { auto & vars = e.m_def->get_vars(); for (recfun::case_def const & c : e.m_def->get_cases()) { // applied predicate to `args` + literal_vector guards; + for (auto & g : c.get_guards()) { + expr_ref guard = apply_args(vars, e.m_args, g); + ctx.internalize(guard, false); + guards.push_back(~ctx.get_literal(guard)); + } app_ref pred_applied = apply_pred(c.get_pred(), e.m_args); SASSERT(u().owns_app(pred_applied)); - // substitute arguments in `path` - expr_ref_vector path(m()); - for (auto & g : c.get_guards()) { - expr_ref g_applied = apply_args(vars, e.m_args, g); - path.push_back(g_applied); - } - // assert `p(args) <=> And(guards)` (with CNF on the fly) ctx.internalize(pred_applied, false); - ctx.mark_as_relevant(ctx.get_bool_var(pred_applied)); literal concl = ctx.get_literal(pred_applied); - { - // assert `guards=>p(args)` - literal_vector c; - c.push_back(concl); - for (expr* g : path) { - ctx.internalize(g, false); - c.push_back(~ ctx.get_literal(g)); - } + ctx.mark_as_relevant(concl); - //TRACE("recfun", tout << "assert_case_axioms " << pp_case_expansion(e) - // << " axiom " << mk_pp(*l) <<"\n";); - TRACEFN("assert_case_axiom " << pp_lits(get_context(), path.size()+1, c.c_ptr())); - get_context().mk_th_axiom(get_id(), path.size()+1, c.c_ptr()); - } - { - // assert `p(args) => guards[i]` for each `i` - for (expr * _g : path) { - SASSERT(ctx.b_internalized(_g)); - literal g = ctx.get_literal(_g); - literal c[2] = {~ concl, g}; + // assert `p(args) <=> And(guards)` (with CNF on the fly) - TRACEFN("assert_case_axiom " << pp_lits(get_context(), 2, c)); - get_context().mk_th_axiom(get_id(), 2, c); - } + for (literal g : guards) { + literal c[2] = {~ concl, ~g}; + ctx.mark_as_relevant(g); + get_context().mk_th_axiom(get_id(), 2, c); } + guards.push_back(concl); + get_context().mk_th_axiom(get_id(), guards.size(), guards.c_ptr()); // also body-expand paths that do not depend on any defined fun if (c.is_immediate()) { @@ -322,23 +301,17 @@ namespace smt { expr_ref rhs = apply_args(vars, args, e.m_cdef->get_rhs()); // substitute `e.args` into the guard of this particular case, to make // the `condition` part of the clause `conds => lhs=rhs` - expr_ref_vector guards(m()); - for (auto & g : e.m_cdef->get_guards()) { - expr_ref new_guard = apply_args(vars, args, g); - guards.push_back(new_guard); - } - // now build the axiom `conds => lhs = rhs` - ctx.internalize(rhs, false); - for (auto& g : guards) ctx.internalize(g, false); - - // add unit clause `conds => lhs=rhs` + + // now build the axiom `conds => lhs = rhs` + literal_vector clause; - for (auto& g : guards) { - ctx.internalize(g, false); - literal l = ~ ctx.get_literal(g); + for (auto & g : e.m_cdef->get_guards()) { + expr_ref guard = apply_args(vars, args, g); + ctx.internalize(guard, false); + literal l = ~ ctx.get_literal(guard); ctx.mark_as_relevant(l); clause.push_back(l); - } + } literal l(mk_eq(lhs, rhs, true)); ctx.mark_as_relevant(l); clause.push_back(l); From dda62ae78c7422e27c60b5bc01b3ff825acbe9fc Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 17 Oct 2018 22:42:57 +0700 Subject: [PATCH 059/227] Use bool literals instead of 0/1. --- src/ackermannization/lackr.cpp | 2 +- src/api/api_fpa.cpp | 36 +++++++++---------- src/api/api_quant.cpp | 4 +-- src/ast/rewriter/bv_bounds.cpp | 6 ++-- .../transforms/dl_mk_array_instantiation.cpp | 2 +- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/ackermannization/lackr.cpp b/src/ackermannization/lackr.cpp index 8c18df7b2..9130d628c 100644 --- a/src/ackermannization/lackr.cpp +++ b/src/ackermannization/lackr.cpp @@ -220,7 +220,7 @@ lbool lackr::lazy() { lackr_model_constructor mc(m_m, m_info); push_abstraction(); unsigned ackr_head = 0; - while (1) { + while (true) { m_st.m_it++; checkpoint(); TRACE("lackr", tout << "lazy check: " << m_st.m_it << "\n";); diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index cdc592527..604267536 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -913,7 +913,7 @@ extern "C" { CHECK_VALID_AST(t, 0); if (sgn == nullptr) { SET_ERROR_CODE(Z3_INVALID_ARG, "sign cannot be a nullpointer"); - return 0; + return false; } ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); @@ -922,13 +922,13 @@ extern "C" { expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); - return 0; + return false; } scoped_mpf val(mpfm); bool r = plugin->is_numeral(to_expr(t), val); if (!r || mpfm.is_nan(val)) { SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); - return 0; + return false; } *sgn = mpfm.sgn(val); return r; @@ -1043,7 +1043,7 @@ extern "C" { CHECK_VALID_AST(t, 0); if (n == nullptr) { SET_ERROR_CODE(Z3_INVALID_ARG, "invalid nullptr argument"); - return 0; + return false; } ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); @@ -1055,7 +1055,7 @@ extern "C" { if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); *n = 0; - return 0; + return false; } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); @@ -1065,10 +1065,10 @@ extern "C" { !mpzm.is_uint64(z)) { SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); *n = 0; - return 0; + return false; } *n = mpzm.get_uint64(z); - return 1; + return true; Z3_CATCH_RETURN(0); } @@ -1121,7 +1121,7 @@ extern "C" { CHECK_VALID_AST(t, 0); if (n == nullptr) { SET_ERROR_CODE(Z3_INVALID_ARG, "invalid null argument"); - return 0; + return false; } ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); @@ -1132,14 +1132,14 @@ extern "C" { if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); *n = 0; - return 0; + return false; } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); *n = 0; - return 0; + return false; } unsigned ebits = val.get().get_ebits(); if (biased) { @@ -1153,7 +1153,7 @@ extern "C" { mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : mpfm.exp(val); } - return 1; + return true; Z3_CATCH_RETURN(0); } @@ -1240,7 +1240,7 @@ extern "C" { fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return 0; + return false; } return fu.is_nan(to_expr(t)); Z3_CATCH_RETURN(Z3_FALSE); @@ -1254,7 +1254,7 @@ extern "C" { fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return 0; + return false; } return fu.is_inf(to_expr(t)); Z3_CATCH_RETURN(Z3_FALSE); @@ -1268,7 +1268,7 @@ extern "C" { fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return 0; + return false; } return fu.is_zero(to_expr(t)); Z3_CATCH_RETURN(Z3_FALSE); @@ -1282,7 +1282,7 @@ extern "C" { fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return 0; + return false; } return fu.is_normal(to_expr(t)); Z3_CATCH_RETURN(Z3_FALSE); @@ -1296,7 +1296,7 @@ extern "C" { fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return 0; + return false; } return fu.is_subnormal(to_expr(t)); Z3_CATCH_RETURN(Z3_FALSE); @@ -1310,7 +1310,7 @@ extern "C" { fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return 0; + return false; } return fu.is_positive(to_expr(t)); Z3_CATCH_RETURN(Z3_FALSE); @@ -1324,7 +1324,7 @@ extern "C" { fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return 0; + return false; } return fu.is_negative(to_expr(t)); Z3_CATCH_RETURN(Z3_FALSE); diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index 49aa09727..fe9faa2a5 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -132,7 +132,7 @@ extern "C" { unsigned num_decls, Z3_sort const types[], Z3_symbol const decl_names[], Z3_ast body) { - return Z3_mk_quantifier(c, 1, weight, num_patterns, patterns, num_decls, types, decl_names, body); + return Z3_mk_quantifier(c, true, weight, num_patterns, patterns, num_decls, types, decl_names, body); } Z3_ast Z3_API Z3_mk_exists(Z3_context c, @@ -141,7 +141,7 @@ extern "C" { unsigned num_decls, Z3_sort const types[], Z3_symbol const decl_names[], Z3_ast body) { - return Z3_mk_quantifier(c, 0, weight, num_patterns, patterns, num_decls, types, decl_names, body); + return Z3_mk_quantifier(c, false, weight, num_patterns, patterns, num_decls, types, decl_names, body); } Z3_ast Z3_API Z3_mk_lambda(Z3_context c, diff --git a/src/ast/rewriter/bv_bounds.cpp b/src/ast/rewriter/bv_bounds.cpp index f337ca638..f30df7890 100644 --- a/src/ast/rewriter/bv_bounds.cpp +++ b/src/ast/rewriter/bv_bounds.cpp @@ -111,7 +111,7 @@ bv_bounds::conv_res bv_bounds::convert(expr * e, vector& nis, bool ne numeral val, val1; unsigned bv_sz1; - if (0) { + if (false) { if (m_m.is_eq(e, lhs, rhs) && to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz1)) { return record(to_app(lhs), val, val, negated, nis); } @@ -125,7 +125,7 @@ bv_bounds::conv_res bv_bounds::convert(expr * e, vector& nis, bool ne return record(to_app(lhs), numeral::zero(), val, negated, nis); } - if (1) { + if (true) { numeral rhs_val; unsigned rhs_sz; if (m_m.is_eq(e, lhs, rhs) @@ -343,7 +343,7 @@ bool bv_bounds::add_constraint(expr* e) { numeral val, val1; unsigned bv_sz1; - if (0) { + if (false) { if (m_m.is_eq(e, lhs, rhs) && to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz1)) { return add_bound_unsigned(to_app(lhs), val, val, negated); } diff --git a/src/muz/transforms/dl_mk_array_instantiation.cpp b/src/muz/transforms/dl_mk_array_instantiation.cpp index 6a8f0ce81..626109528 100644 --- a/src/muz/transforms/dl_mk_array_instantiation.cpp +++ b/src/muz/transforms/dl_mk_array_instantiation.cpp @@ -300,7 +300,7 @@ namespace datalog { expr_ref_vector res(m); svector chosen(arg_correspondance.size(), 0u); - while(1) + while(true) { expr_ref_vector new_args(m); for(unsigned i=0;i Date: Wed, 17 Oct 2018 22:47:39 +0700 Subject: [PATCH 060/227] Fix doxygen warnings. --- src/api/c++/z3++.h | 2 +- src/api/z3_optimization.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 1b1820909..7083ae468 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -277,7 +277,7 @@ namespace z3 { */ sort fpa_rounding_mode(); /** - \breif Sets RoundingMode of FloatingPoints. + \brief Sets RoundingMode of FloatingPoints. */ void set_rounding_mode(rounding_mode rm); /** diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h index 8f9e2470c..f15d8ff9c 100644 --- a/src/api/z3_optimization.h +++ b/src/api/z3_optimization.h @@ -146,7 +146,7 @@ extern "C" { Z3_model Z3_API Z3_optimize_get_model(Z3_context c, Z3_optimize o); /** - \brief Retrieve the unsat core for the last #Z3_optimize_chec + \brief Retrieve the unsat core for the last #Z3_optimize_check The unsat core is a subset of the assumptions \c a. def_API('Z3_optimize_get_unsat_core', AST_VECTOR, (_in(CONTEXT), _in(OPTIMIZE))) From 372cab2c5bc2705eb7c2dee9ed35c01e09691405 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 17 Oct 2018 22:49:39 +0700 Subject: [PATCH 061/227] Fix some typos. --- examples/maxsat/maxsat.c | 4 ++-- src/api/c++/z3++.h | 2 +- src/api/python/z3/z3.py | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/maxsat/maxsat.c b/examples/maxsat/maxsat.c index 5696f5b89..50550106e 100644 --- a/examples/maxsat/maxsat.c +++ b/examples/maxsat/maxsat.c @@ -138,7 +138,7 @@ void assert_hard_constraints(Z3_context ctx, Z3_solver s, unsigned num_cnstrs, Z /** \brief Assert soft constraints stored in the given array. - This funtion will assert each soft-constraint C_i as (C_i or k_i) where k_i is a fresh boolean variable. + This function will assert each soft-constraint C_i as (C_i or k_i) where k_i is a fresh boolean variable. It will also return an array containing these fresh variables. */ Z3_ast * assert_soft_constraints(Z3_context ctx, Z3_solver s, unsigned num_cnstrs, Z3_ast * cnstrs) @@ -565,7 +565,7 @@ int fu_malik_maxsat(Z3_context ctx, Z3_solver s, unsigned num_hard_cnstrs, Z3_as /** \brief Finds the maximal number of assumptions that can be satisfied. - An assumption is any formula preceeded with the :assumption keyword. + An assumption is any formula preceded with the :assumption keyword. "Hard" constraints can be supported by using the :formula keyword. Input: file in SMT-LIB format, and MaxSAT algorithm to be used: 0 - Naive, 1 - Fu&Malik's algo. diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 1b1820909..a355e0233 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -291,7 +291,7 @@ namespace z3 { \brief Return a tuple constructor. \c name is the name of the returned constructor, \c n are the number of arguments, \c names and \c sorts are their projected sorts. - \c projs is an output paramter. It contains the set of projection functions. + \c projs is an output parameter. It contains the set of projection functions. */ func_decl tuple_sort(char const * name, unsigned n, char const * const * names, sort const* sorts, func_decl_vector & projs); diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 703105356..d466d2e77 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8327,7 +8327,7 @@ def prove(claim, **keywords): print(s.model()) def _solve_html(*args, **keywords): - """Version of funcion `solve` used in RiSE4Fun.""" + """Version of function `solve` used in RiSE4Fun.""" s = Solver() s.set(**keywords) s.add(*args) @@ -8349,7 +8349,7 @@ def _solve_html(*args, **keywords): print(s.model()) def _solve_using_html(s, *args, **keywords): - """Version of funcion `solve_using` used in RiSE4Fun.""" + """Version of function `solve_using` used in RiSE4Fun.""" if __debug__: _z3_assert(isinstance(s, Solver), "Solver object expected") s.set(**keywords) @@ -8372,7 +8372,7 @@ def _solve_using_html(s, *args, **keywords): print(s.model()) def _prove_html(claim, **keywords): - """Version of funcion `prove` used in RiSE4Fun.""" + """Version of function `prove` used in RiSE4Fun.""" if __debug__: _z3_assert(is_bool(claim), "Z3 Boolean expression expected") s = Solver() From a6ad893f54dca0ea700d13348e6a6d09780157b6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Oct 2018 09:47:44 -0700 Subject: [PATCH 062/227] add instructions as gift for Klaus Signed-off-by: Nikolaj Bjorner --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e02719161..2abffb2df 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,9 @@ under the [MIT license](LICENSE.txt). If you are not familiar with Z3, you can start [here](https://github.com/Z3Prover/z3/wiki#background). Z3 can be built using [Visual Studio][1], a [Makefile][2] or using [CMake][3]. It provides -[bindings for several programming languages][4]. +[bindings for several programming languages][4]. +Pre-built binaries for releases are available from [here](https://github.com/Z3Prover/z3/releases), +and nightly builds from [here](https://github.com/Z3Prover/bin/tree/master/nightly). See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z3. From 566bdf3a826a2e73570433455c0f1451cd1f14bd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Oct 2018 09:55:15 -0700 Subject: [PATCH 063/227] add self-contained section on where to retrieve binaries Signed-off-by: Nikolaj Bjorner --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2abffb2df..fef293fac 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,12 @@ under the [MIT license](LICENSE.txt). If you are not familiar with Z3, you can start [here](https://github.com/Z3Prover/z3/wiki#background). -Z3 can be built using [Visual Studio][1], a [Makefile][2] or using [CMake][3]. It provides -[bindings for several programming languages][4]. Pre-built binaries for releases are available from [here](https://github.com/Z3Prover/z3/releases), and nightly builds from [here](https://github.com/Z3Prover/bin/tree/master/nightly). +Z3 can be built using [Visual Studio][1], a [Makefile][2] or using [CMake][3]. It provides +[bindings for several programming languages][4]. + See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z3. ## Build status From 8a9837a8b575cd2da7219ff4afd66643b3f88c0f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Oct 2018 10:02:56 -0700 Subject: [PATCH 064/227] more refinements for recfun Signed-off-by: Nikolaj Bjorner --- src/smt/smt_theory.h | 2 ++ src/smt/theory_recfun.cpp | 70 +++++++++++++++++++-------------------- src/smt/theory_recfun.h | 2 ++ 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index b791d890e..fa0ec0c82 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -294,6 +294,8 @@ namespace smt { SASSERT(m_context); return *m_context; } + + context & ctx() const { return get_context(); } ast_manager & get_manager() const { SASSERT(m_manager); diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 45902c3dd..23d9e7f2c 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -52,7 +52,7 @@ namespace smt { void theory_recfun::setup_params() { // obtain max depth via parameters - smt_params_helper p(get_context().get_params()); + smt_params_helper p(ctx().get_params()); set_max_depth(p.recfun_max_depth()); } @@ -175,13 +175,11 @@ namespace smt { { // first literal must be the depth limit one app_ref dlimit = m_util.mk_depth_limit_pred(get_max_depth()); - ctx.internalize(dlimit, false); - c.push_back(~ ctx.get_literal(dlimit)); - SASSERT(ctx.get_assignment(ctx.get_literal(dlimit)) == l_true); + c.push_back(~mk_literal(dlimit)); + SASSERT(ctx.get_assignment(c.back()) == l_true); } for (auto& kv : m_guards) { - expr * g = & kv.get_key(); - c.push_back(~ ctx.get_literal(g)); + c.push_back(~ mk_literal(&kv.get_key())); } TRACEFN("max-depth limit: add clause " << pp_lits(ctx, c)); SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx.get_assignment(l) == l_false; })); // conflict @@ -197,12 +195,12 @@ namespace smt { if (u().is_case_pred(a)) { TRACEFN("assign_case_pred_true "<< mk_pp(e,m())); // add to set of local assumptions, for depth-limit purpose - { - m_guards.insert(e, empty()); - m().inc_ref(e); - insert_ref_map trail_elt(m(), m_guards, e); - m_trail.push(trail_elt); - } + SASSERT(!m_guards.contains(e)); + m_guards.insert(e, empty()); + m().inc_ref(e); + insert_ref_map trail_elt(m(), m_guards, e); + m_trail.push(trail_elt); + if (m_guards.size() > get_max_depth()) { // too many body-expansions: depth-limit conflict max_depth_conflict(); @@ -233,27 +231,37 @@ namespace smt { return app_ref(u().mk_case_pred(p, args), m()); } + literal theory_recfun::mk_literal(expr* e) { + ctx().internalize(e, false); + literal lit = ctx().get_literal(e); + ctx().mark_as_relevant(lit); + return lit; + } + + literal theory_recfun::mk_eq_lit(expr* l, expr* r) { + literal lit = mk_eq(l, r, false); + ctx().mark_as_relevant(lit); + return lit; + } + void theory_recfun::assert_macro_axiom(case_expansion & e) { TRACEFN("assert_macro_axiom " << pp_case_expansion(e, m())); SASSERT(e.m_def->is_fun_macro()); - context & ctx = get_context(); auto & vars = e.m_def->get_vars(); expr_ref lhs(e.m_lhs, m()); // substitute `e.args` into the macro RHS expr_ref rhs(apply_args(vars, e.m_args, e.m_def->get_macro_rhs()), m()); TRACEFN("macro expansion yields" << mk_pp(rhs,m())); // add unit clause `lhs = rhs` - literal l(mk_eq(lhs, rhs, true)); - ctx.mark_as_relevant(l); - TRACEFN("assert_macro_axiom: " << pp_lit(ctx, l)); - ctx.mk_th_axiom(get_id(), 1, &l); + literal lit = mk_eq_lit(lhs, rhs); + TRACEFN("assert_macro_axiom: " << pp_lit(ctx(), lit)); + ctx().mk_th_axiom(get_id(), 1, &lit); } void theory_recfun::assert_case_axioms(case_expansion & e) { TRACEFN("assert_case_axioms "<< pp_case_expansion(e,m()) << " with " << e.m_def->get_cases().size() << " cases"); SASSERT(e.m_def->is_fun_defined()); - context & ctx = get_context(); // add case-axioms for all case-paths auto & vars = e.m_def->get_vars(); for (recfun::case_def const & c : e.m_def->get_cases()) { @@ -261,24 +269,20 @@ namespace smt { literal_vector guards; for (auto & g : c.get_guards()) { expr_ref guard = apply_args(vars, e.m_args, g); - ctx.internalize(guard, false); - guards.push_back(~ctx.get_literal(guard)); + guards.push_back(~mk_literal(guard)); } app_ref pred_applied = apply_pred(c.get_pred(), e.m_args); SASSERT(u().owns_app(pred_applied)); - ctx.internalize(pred_applied, false); - literal concl = ctx.get_literal(pred_applied); - ctx.mark_as_relevant(concl); + literal concl = mk_literal(pred_applied); // assert `p(args) <=> And(guards)` (with CNF on the fly) for (literal g : guards) { literal c[2] = {~ concl, ~g}; - ctx.mark_as_relevant(g); - get_context().mk_th_axiom(get_id(), 2, c); + ctx().mk_th_axiom(get_id(), 2, c); } guards.push_back(concl); - get_context().mk_th_axiom(get_id(), guards.size(), guards.c_ptr()); + ctx().mk_th_axiom(get_id(), guards.size(), guards.c_ptr()); // also body-expand paths that do not depend on any defined fun if (c.is_immediate()) { @@ -290,7 +294,6 @@ namespace smt { void theory_recfun::assert_body_axiom(body_expansion & e) { TRACEFN("assert_body_axioms "<< pp_body_expansion(e,m())); - context & ctx = get_context(); recfun::def & d = *e.m_cdef->get_def(); auto & vars = d.get_vars(); auto & args = e.m_args; @@ -307,16 +310,11 @@ namespace smt { literal_vector clause; for (auto & g : e.m_cdef->get_guards()) { expr_ref guard = apply_args(vars, args, g); - ctx.internalize(guard, false); - literal l = ~ ctx.get_literal(guard); - ctx.mark_as_relevant(l); - clause.push_back(l); + clause.push_back(~mk_literal(guard)); } - literal l(mk_eq(lhs, rhs, true)); - ctx.mark_as_relevant(l); - clause.push_back(l); - TRACEFN("assert_body_axiom " << pp_lits(ctx, clause)); - ctx.mk_th_axiom(get_id(), clause.size(), clause.c_ptr()); + clause.push_back(mk_eq_lit(lhs, rhs)); + TRACEFN("assert_body_axiom " << pp_lits(ctx(), clause)); + ctx().mk_th_axiom(get_id(), clause.size(), clause.c_ptr()); } final_check_status theory_recfun::final_check_eh() { diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 68833be63..275d2ef59 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -121,6 +121,8 @@ namespace smt { void assert_case_axioms(case_expansion & e); void assert_body_axiom(body_expansion & e); void max_depth_conflict(void); + literal mk_literal(expr* e); + literal mk_eq_lit(expr* l, expr* r); protected: void push_case_expand(case_expansion&& e) { m_q_case_expand.push_back(e); } void push_body_expand(body_expansion&& e) { m_q_body_expand.push_back(e); } From bd53fa801edbe6166e95c0fda60f499c513e44a7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Oct 2018 21:42:18 -0700 Subject: [PATCH 065/227] handle case input format Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 6 +++ src/parsers/smt2/smt2parser.cpp | 64 ++++++++++++++++++------- src/smt/smt_context.cpp | 4 +- src/smt/smt_context.h | 6 +-- 4 files changed, 59 insertions(+), 21 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 235576735..bdd2c8b97 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -91,6 +91,11 @@ UNARY_CMD(pp_shared_cmd, "dbg-pp-shared", "", "display shared subterms of ctx.regular_stream() << ")" << std::endl; }); +UNARY_CMD(assert_not_cmd, "assert-not", "", "assert negation", CPK_EXPR, expr *, { + expr_ref ne(ctx.m().mk_not(arg), ctx.m()); + ctx.assert_expr(ne); +}); + UNARY_CMD(num_shared_cmd, "dbg-num-shared", "", "return the number of shared subterms", CPK_EXPR, expr *, { shared_occs s(ctx.m()); s(arg); @@ -537,6 +542,7 @@ void install_dbg_cmds(cmd_context & ctx) { ctx.insert(alloc(shift_vars_cmd)); ctx.insert(alloc(pp_shared_cmd)); ctx.insert(alloc(num_shared_cmd)); + ctx.insert(alloc(assert_not_cmd)); ctx.insert(alloc(size_cmd)); ctx.insert(alloc(subst_cmd)); ctx.insert(alloc(bool_rewriter_cmd)); diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 8db6388ab..7458fc578 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -114,6 +114,7 @@ namespace smt2 { symbol m_define_fun_rec; symbol m_define_funs_rec; symbol m_match; + symbol m_case; symbol m_underscore; typedef std::pair named_expr; @@ -382,7 +383,9 @@ namespace smt2 { next(); return; } - throw parser_exception(msg); + std::ostringstream str; + str << msg << " got " << curr_id(); + throw parser_exception(str.str()); } symbol const & curr_id() const { return m_scanner.get_id(); } @@ -406,6 +409,7 @@ namespace smt2 { bool curr_id_is_underscore() const { SASSERT(curr_is_identifier()); return curr_id() == m_underscore; } bool curr_id_is_as() const { SASSERT(curr_is_identifier()); return curr_id() == m_as; } bool curr_id_is_match() const { SASSERT(curr_is_identifier()); return curr_id() == m_match; } + bool curr_id_is_case() const { return curr_id() == m_case; } bool curr_id_is_forall() const { SASSERT(curr_is_identifier()); return curr_id() == m_forall; } bool curr_id_is_exists() const { SASSERT(curr_is_identifier()); return curr_id() == m_exists; } bool curr_id_is_lambda() const { SASSERT(curr_is_identifier()); return curr_id() == m_lambda; } @@ -1319,7 +1323,13 @@ namespace smt2 { /** * SMT-LIB 2.6 pattern matches are of the form - * (match t ((p1 t1) ... (pm+1 tm+1))) + * + * (match t ((p1 t1) ... (pm+1 tm+1))) + * + * precursor form is + * + * (match t (case p1 t1) (case p2 t2) ... ) + * */ void push_match_frame() { SASSERT(curr_is_identifier()); @@ -1336,21 +1346,42 @@ namespace smt2 { sort* srt = m().get_sort(t); check_lparen_next("pattern bindings should be enclosed in a parenthesis"); - while (!curr_is_rparen()) { - m_env.begin_scope(); - unsigned num_bindings = m_num_bindings; - check_lparen_next("invalid pattern binding, '(' expected"); - parse_match_pattern(srt); - patterns.push_back(expr_stack().back()); - expr_stack().pop_back(); - parse_expr(); - cases.push_back(expr_stack().back()); - expr_stack().pop_back(); - m_num_bindings = num_bindings; - m_env.end_scope(); - check_rparen_next("invalid pattern binding, ')' expected"); + if (curr_id_is_case()) { + while (curr_id_is_case()) { + next(); + m_env.begin_scope(); + unsigned num_bindings = m_num_bindings; + parse_match_pattern(srt); + patterns.push_back(expr_stack().back()); + expr_stack().pop_back(); + parse_expr(); + cases.push_back(expr_stack().back()); + expr_stack().pop_back(); + m_num_bindings = num_bindings; + m_env.end_scope(); + check_rparen_next("invalid pattern binding, ')' expected"); + if (curr_is_lparen()) { + next(); + } + } + } + else { + while (!curr_is_rparen()) { + m_env.begin_scope(); + unsigned num_bindings = m_num_bindings; + parse_match_pattern(srt); + patterns.push_back(expr_stack().back()); + expr_stack().pop_back(); + check_lparen_next("invalid pattern binding, '(' expected"); + parse_expr(); + cases.push_back(expr_stack().back()); + expr_stack().pop_back(); + m_num_bindings = num_bindings; + m_env.end_scope(); + check_rparen_next("invalid pattern binding, ')' expected"); + } + next(); } - next(); m_num_expr_frames = num_frames + 1; expr_stack().push_back(compile_patterns(t, patterns, cases)); } @@ -3013,6 +3044,7 @@ namespace smt2 { m_define_fun_rec("define-fun-rec"), m_define_funs_rec("define-funs-rec"), m_match("match"), + m_case("case"), m_underscore("_"), m_num_open_paren(0), m_current_file(filename) { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index f275b0ebf..f7b7bdbea 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3207,7 +3207,7 @@ namespace smt { } else { set_conflict(b_justification(tmp_clause.first), null_literal); - } + } VERIFY(!resolve_conflict()); return l_false; next_clause: @@ -3770,7 +3770,7 @@ namespace smt { } m_stats.m_num_final_checks++; - TRACE("final_check_stats", tout << "m_stats.m_num_final_checks = " << m_stats.m_num_final_checks << "\n";); + TRACE("final_check_stats", tout << "m_stats.m_num_final_checks = " << m_stats.m_num_final_checks << "\n";); final_check_status ok = m_qmanager->final_check_eh(false); if (ok != FC_DONE) diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index a349880e3..c3e9c3ffc 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1010,9 +1010,9 @@ namespace smt { void restore_theory_vars(enode * r2, enode * r1); void push_eq(enode * lhs, enode * rhs, eq_justification const & js) { - SASSERT(lhs != rhs); - SASSERT(lhs->get_root() != rhs->get_root()); - m_eq_propagation_queue.push_back(new_eq(lhs, rhs, js)); + if (lhs->get_root() != rhs->get_root()) { + m_eq_propagation_queue.push_back(new_eq(lhs, rhs, js)); + } } void push_new_congruence(enode * n1, enode * n2, bool used_commutativity) { From 2f5f5469901f2bc3c77a414a14c0ee7b67afcaf8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Oct 2018 09:02:20 -0700 Subject: [PATCH 066/227] ctx Signed-off-by: Nikolaj Bjorner --- src/smt/theory_recfun.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 23d9e7f2c..32c2fe8c5 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -106,7 +106,7 @@ namespace smt { * body-expand it. */ void theory_recfun::relevant_eh(app * n) { - SASSERT(get_context().relevancy()); + SASSERT(ctx().relevancy()); if (u().is_defined(n)) { TRACEFN("relevant_eh: (defined) " << mk_pp(n, m())); case_expansion e(u(), n); @@ -140,11 +140,10 @@ namespace smt { } void theory_recfun::propagate() { - context & ctx = get_context(); for (literal_vector & c : m_q_clauses) { - TRACEFN("add axiom " << pp_lits(ctx, c)); - ctx.mk_th_axiom(get_id(), c.size(), c.c_ptr()); + TRACEFN("add axiom " << pp_lits(ctx(), c)); + ctx().mk_th_axiom(get_id(), c.size(), c.c_ptr()); } m_q_clauses.clear(); @@ -169,20 +168,19 @@ namespace smt { void theory_recfun::max_depth_conflict() { TRACEFN("max-depth conflict"); - context & ctx = get_context(); literal_vector c; // make clause `depth_limit => V_{g : guards} ~ g` { // first literal must be the depth limit one app_ref dlimit = m_util.mk_depth_limit_pred(get_max_depth()); c.push_back(~mk_literal(dlimit)); - SASSERT(ctx.get_assignment(c.back()) == l_true); + SASSERT(ctx().get_assignment(c.back()) == l_true); } for (auto& kv : m_guards) { - c.push_back(~ mk_literal(&kv.get_key())); + c.push_back(~ mk_literal(kv.m_key)); } - TRACEFN("max-depth limit: add clause " << pp_lits(ctx, c)); - SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx.get_assignment(l) == l_false; })); // conflict + TRACEFN("max-depth limit: add clause " << pp_lits(ctx(), c)); + SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx().get_assignment(l) == l_false; })); // conflict m_q_clauses.push_back(std::move(c)); } @@ -222,7 +220,7 @@ namespace smt { var_subst subst(m(), true); expr_ref new_body(m()); new_body = subst(e, args.size(), args.c_ptr()); - get_context().get_rewriter()(new_body); // simplify + ctx().get_rewriter()(new_body); // simplify return new_body; } From 28a5a515a8ffb34adca978284527d59e7390c45c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Oct 2018 09:20:12 -0700 Subject: [PATCH 067/227] fix #1889 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_parse.cpp | 23 +++++++++++++++++++++++ src/util/stopwatch.h | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp index fec97d675..09845ff07 100644 --- a/src/opt/opt_parse.cpp +++ b/src/opt/opt_parse.cpp @@ -323,6 +323,15 @@ struct asymbol { asymbol(rational const& r, unsigned l): m_is_num(true), m_num(r), m_line(l) {} }; +std::ostream& operator<<(std::ostream& out, asymbol const& c) { + if (c.m_is_num) { + return out << c.m_num; + } + else { + return out << c.m_sym; + } +} + class lp_tokenizer { vector m_tokens; unsigned m_pos; @@ -416,6 +425,7 @@ private: } if (c == '.') { in.next(); + c = in.ch(); while (is_num(c) && !in.eof()) { n = n*rational(10) + rational(c - '0'); in.next(); @@ -426,6 +436,7 @@ private: if (div > 1) n = n / rational(div); if (neg) n.neg(); m_tokens.push_back(asymbol(n, in.line())); + IF_VERBOSE(10, verbose_stream() << "num: " << m_tokens.back() << "\n"); continue; } m_buffer.reset(); @@ -445,6 +456,7 @@ private: } m_buffer.push_back(0); m_tokens.push_back(asymbol(symbol(m_buffer.c_ptr()), in.line())); + IF_VERBOSE(10, verbose_stream() << "tok: " << m_tokens.back() << "\n"); } } @@ -466,6 +478,7 @@ private: is_num(c) || c == '!' || c == '"' || + c == '-' || c == '#' || c == '$' || c == '%' || @@ -612,6 +625,7 @@ private: name = peek(0); tok.next(2); } + IF_VERBOSE(10, verbose_stream() << name << "\n"); rational val(0); symbol var; parse_indicator(var, val); @@ -624,6 +638,9 @@ private: } void parse_expr(lin_term& terms) { + if (is_relation()) { + return; + } bool pos = true; if (peek(0) == "-") { pos = false; @@ -693,6 +710,7 @@ private: return false; } + bool is_relation() { return peek(0) == "=" || peek(0) == "=<" || peek(0) == ">=" || peek(0) == "=>" || peek(0) == "<="; } bool is_section() { return is_general() || is_binary() || is_bounds() || is_end();} bool is_bounds() { return peek(0) == "bounds"; } bool is_general() { return peek(0) == "general" || peek(0) == "gen" || peek(0) == "generals"; } @@ -770,6 +788,11 @@ private: } void parse_general() { + if (peek(1) == ":" && peek(3) == "=") { + symbol const& v = peek(2); + std::cout << "TBD: " << v << "\n"; + return; + } symbol const& v = peek(0); bound b; m_bounds.find(v, b); diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index 2c7551df0..a11a87484 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -20,7 +20,7 @@ Revision History: #ifndef STOPWATCH_H_ #define STOPWATCH_H_ -#if defined(_WINDOWS) || defined(_CYGWIN) +#if defined(_WINDOWS) || defined(_CYGWIN) || defined(_MINGW) // Does this redefinition work? From d22a0d04ed78e874cfa87ad295b0d1b826b9c231 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Oct 2018 10:01:32 -0700 Subject: [PATCH 068/227] n/a Signed-off-by: Nikolaj Bjorner --- src/ast/ast.h | 4 + src/ast/recfun_decl_plugin.cpp | 88 +++++++++++---------- src/ast/recfun_decl_plugin.h | 21 +++-- src/smt/smt_context.h | 4 + src/smt/theory_recfun.cpp | 135 ++++++++++++++++++--------------- src/smt/theory_recfun.h | 18 ++--- 6 files changed, 144 insertions(+), 126 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index c1193dfbd..acef0c659 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -707,6 +707,10 @@ public: func_decl * get_decl() const { return m_decl; } family_id get_family_id() const { return get_decl()->get_family_id(); } decl_kind get_decl_kind() const { return get_decl()->get_decl_kind(); } + symbol const& get_name() const { return get_decl()->get_name(); } + unsigned get_num_parameters() const { return get_decl()->get_num_parameters(); } + parameter const& get_parameter(unsigned idx) const { return get_decl()->get_parameter(idx); } + parameter const* get_parameters() const { return get_decl()->get_parameters(); } bool is_app_of(family_id fid, decl_kind k) const { return get_family_id() == fid && get_decl_kind() == k; } unsigned get_num_args() const { return m_num_args; } expr * get_arg(unsigned idx) const { SASSERT(idx < m_num_args); return m_args[idx]; } diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index f4b237f9a..de8bf94b1 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -23,7 +23,7 @@ Revision History: #include "ast/ast_pp.h" #include "util/scoped_ptr_vector.h" -#define DEBUG(x) TRACE("recfun", tout << x << '\n';) +#define TRACEFN(x) TRACE("recfun", tout << x << '\n';) #define VALIDATE_PARAM(m, _pred_) if (!(_pred_)) m.raise_exception("invalid parameter to recfun " #_pred_); namespace recfun { @@ -42,18 +42,18 @@ namespace recfun { sort_ref_vector const & arg_sorts, unsigned num_guards, expr ** guards, expr* rhs) : m_pred(m, fid, name, arg_sorts), m_guards(m), m_rhs(expr_ref(rhs,m)), m_def(d) { - for (unsigned i=0; inext) { app * ite = choices->ite; - SASSERT(m.is_ite(ite)); + expr* c = nullptr, *th = nullptr, *el = nullptr; + VERIFY(m.is_ite(ite, c, th, el)); // condition to add to the guard - expr * cond0 = ite->get_arg(0); - conditions.push_back(choices->sign ? cond0 : m.mk_not(cond0)); + conditions.push_back(choices->sign ? c : m.mk_not(c)); // binding to add to the substitution - subst.insert(ite, choices->sign ? ite->get_arg(1) : ite->get_arg(2)); + subst.insert(ite, choices->sign ? th : el); } } @@ -183,11 +185,11 @@ namespace recfun { } void def::add_case(std::string & name, unsigned n_conditions, expr ** conditions, expr * rhs, bool is_imm) { - case_def c(m(), m_fid, this, name, get_domain(), n_conditions, conditions, rhs); + case_def c(m, m_fid, this, name, get_domain(), n_conditions, conditions, rhs); c.set_is_immediate(is_imm); - DEBUG("add_case " << name << " " << mk_pp(rhs, m()) + TRACEFN("add_case " << name << " " << mk_pp(rhs, m) << " :is_imm " << is_imm - << " :guards " << mk_pp_vec(n_conditions, (ast**)conditions, m())); + << " :guards " << mk_pp_vec(n_conditions, (ast**)conditions, m)); m_cases.push_back(c); } @@ -197,12 +199,12 @@ namespace recfun { unsigned n_vars, var *const * vars, expr* rhs0) { if (m_cases.size() != 0) { - DEBUG("bug: cases for " << m_name << " has cases already"); + TRACEFN("bug: " << m_name << " has cases already"); UNREACHABLE(); } SASSERT(n_vars = m_domain.size()); - DEBUG("compute cases " << mk_pp(rhs0, m())); + TRACEFN("compute cases " << mk_pp(rhs0, m)); unsigned case_idx = 0; std::string name; @@ -211,18 +213,18 @@ namespace recfun { name.append(m_name.bare_str()); name.append("_"); - for (unsigned i=0; iget_num_args(); ++i) - stack.push_back(a->get_arg(i)); + for (expr * arg : *to_app(e)) { + stack.push_back(arg); + } } } } @@ -280,7 +282,8 @@ namespace recfun { if (b.to_split != nullptr) { // split one `ite`, which will lead to distinct (sets of) cases app * ite = b.to_split->ite; - SASSERT(m().is_ite(ite)); + expr* c = nullptr, *th = nullptr, *el = nullptr; + VERIFY(m.is_ite(ite, c, th, el)); /* explore both positive choice and negative choice. * each contains a longer path, with `ite` mapping to `true` (resp. `false), @@ -291,10 +294,11 @@ namespace recfun { branch b_pos(st.cons_choice(ite, true, b.path), b.to_split->next, - st.cons_unfold(ite->get_arg(0), ite->get_arg(1), b.to_unfold)); + st.cons_unfold(c, th, b.to_unfold)); + branch b_neg(st.cons_choice(ite, false, b.path), b.to_split->next, - st.cons_unfold(ite->get_arg(0), ite->get_arg(2), b.to_unfold)); + st.cons_unfold(c, el, b.to_unfold)); st.push_branch(b_neg); st.push_branch(b_pos); @@ -302,20 +306,20 @@ namespace recfun { else { // leaf of the search tree - expr_ref_vector conditions_raw(m()); - expr_substitution subst(m()); - convert_path(m(), b.path, conditions_raw, subst); + expr_ref_vector conditions_raw(m); + expr_substitution subst(m); + convert_path(m, b.path, conditions_raw, subst); // substitute, to get rid of `ite` terms - expr_ref case_rhs = replace_subst(th_rw, m(), subst, rhs); - expr_ref_vector conditions(m()); + expr_ref case_rhs = replace_subst(th_rw, m, subst, rhs); + expr_ref_vector conditions(m); for (expr * g : conditions_raw) { - expr_ref g_subst(replace_subst(th_rw, m(), subst, g), m()); + expr_ref g_subst(replace_subst(th_rw, m, subst, g), m); conditions.push_back(g_subst); } - unsigned old_name_len = name.size(); + size_t old_name_len = name.size(); { // TODO: optimize? this does many copies std::ostringstream sout; sout << ((unsigned long) case_idx); @@ -330,7 +334,7 @@ namespace recfun { } } - DEBUG("done analysing " << get_name()); + TRACEFN("done analysing " << get_name()); } /* @@ -495,4 +499,4 @@ namespace recfun { } } } -} \ No newline at end of file +} diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index b51717c1d..6c8824a6a 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -21,10 +21,10 @@ Revision History: #include "ast/rewriter/th_rewriter.h" namespace recfun { - class case_def; // cases; - ast_manager & m_manager; + ast_manager & m; symbol m_name; //get_family_id() == m_family_id; } //(m.get_plugin(get_family_id()))), m_util(m_plugin.u()), m_trail(*this), @@ -42,8 +43,8 @@ namespace smt { theory_recfun::~theory_recfun() { reset_queues(); - for (auto & kv : m_guards) { - m().dec_ref(kv.m_key); + for (expr* g : m_guards) { + m.dec_ref(g); } m_guards.reset(); } @@ -61,28 +62,26 @@ namespace smt { } bool theory_recfun::internalize_atom(app * atom, bool gate_ctx) { - context & ctx = get_context(); for (expr * arg : *atom) { - ctx.internalize(arg, false); + ctx().internalize(arg, false); } - if (!ctx.e_internalized(atom)) { - ctx.mk_enode(atom, false, true, false); + if (!ctx().e_internalized(atom)) { + ctx().mk_enode(atom, false, true, false); } - if (!ctx.b_internalized(atom)) { - bool_var v = ctx.mk_bool_var(atom); - ctx.set_var_theory(v, get_id()); + if (!ctx().b_internalized(atom)) { + bool_var v = ctx().mk_bool_var(atom); + ctx().set_var_theory(v, get_id()); } return true; } bool theory_recfun::internalize_term(app * term) { - context & ctx = get_context(); for (expr* e : *term) { - ctx.internalize(e, false); + ctx().internalize(e, false); } // the internalization of the arguments may have triggered the internalization of term. - if (!ctx.e_internalized(term)) { - ctx.mk_enode(term, false, false, true); + if (!ctx().e_internalized(term)) { + ctx().mk_enode(term, false, false, true); } return true; } @@ -108,7 +107,7 @@ namespace smt { void theory_recfun::relevant_eh(app * n) { SASSERT(ctx().relevancy()); if (u().is_defined(n)) { - TRACEFN("relevant_eh: (defined) " << mk_pp(n, m())); + TRACEFN("relevant_eh: (defined) " << mk_pp(n, m)); case_expansion e(u(), n); push_case_expand(std::move(e)); } @@ -143,7 +142,7 @@ namespace smt { for (literal_vector & c : m_q_clauses) { TRACEFN("add axiom " << pp_lits(ctx(), c)); - ctx().mk_th_axiom(get_id(), c.size(), c.c_ptr()); + ctx().mk_th_axiom(get_id(), c); } m_q_clauses.clear(); @@ -176,8 +175,8 @@ namespace smt { c.push_back(~mk_literal(dlimit)); SASSERT(ctx().get_assignment(c.back()) == l_true); } - for (auto& kv : m_guards) { - c.push_back(~ mk_literal(kv.m_key)); + for (expr * g : m_guards) { + c.push_back(~ mk_literal(g)); } TRACEFN("max-depth limit: add clause " << pp_lits(ctx(), c)); SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx().get_assignment(l) == l_false; })); // conflict @@ -185,18 +184,21 @@ namespace smt { m_q_clauses.push_back(std::move(c)); } - // if `is_true` and `v = C_f_i(t1...tn)`, then body-expand i-th case of `f(t1...tn)` + /** + * if `is_true` and `v = C_f_i(t1...tn)`, + * then body-expand i-th case of `f(t1...tn)` + */ void theory_recfun::assign_eh(bool_var v, bool is_true) { - expr* e = get_context().bool_var2expr(v); + expr* e = ctx().bool_var2expr(v); if (!is_true || !is_app(e)) return; app* a = to_app(e); if (u().is_case_pred(a)) { - TRACEFN("assign_case_pred_true "<< mk_pp(e,m())); + TRACEFN("assign_case_pred_true "<< mk_pp(e,m)); // add to set of local assumptions, for depth-limit purpose SASSERT(!m_guards.contains(e)); - m_guards.insert(e, empty()); - m().inc_ref(e); - insert_ref_map trail_elt(m(), m_guards, e); + m_guards.insert(e); + m.inc_ref(e); + insert_ref_map trail_elt(m, m_guards, e); m_trail.push(trail_elt); if (m_guards.size() > get_max_depth()) { @@ -215,18 +217,17 @@ namespace smt { expr_ref theory_recfun::apply_args(recfun::vars const & vars, ptr_vector const & args, expr * e) { - // check that var order is standard - SASSERT(vars.size() == 0 || vars[vars.size()-1]->get_idx() == 0); - var_subst subst(m(), true); - expr_ref new_body(m()); + SASSERT(is_standard_order(vars)); + var_subst subst(m, true); + expr_ref new_body(m); new_body = subst(e, args.size(), args.c_ptr()); ctx().get_rewriter()(new_body); // simplify return new_body; } app_ref theory_recfun::apply_pred(recfun::case_pred const & p, - ptr_vector const & args) { - return app_ref(u().mk_case_pred(p, args), m()); + ptr_vector const & args) { + return app_ref(u().mk_case_pred(p, args), m); } literal theory_recfun::mk_literal(expr* e) { @@ -242,47 +243,54 @@ namespace smt { return lit; } + /** + * For functions f(args) that are given as macros f(vs) = rhs + * + * 1. substitute `e.args` for `vs` into the macro rhs + * 2. add unit clause `f(args) = rhs` + */ void theory_recfun::assert_macro_axiom(case_expansion & e) { - TRACEFN("assert_macro_axiom " << pp_case_expansion(e, m())); SASSERT(e.m_def->is_fun_macro()); auto & vars = e.m_def->get_vars(); - expr_ref lhs(e.m_lhs, m()); - // substitute `e.args` into the macro RHS - expr_ref rhs(apply_args(vars, e.m_args, e.m_def->get_macro_rhs()), m()); - TRACEFN("macro expansion yields" << mk_pp(rhs,m())); - // add unit clause `lhs = rhs` + expr_ref lhs(e.m_lhs, m); + expr_ref rhs(apply_args(vars, e.m_args, e.m_def->get_macro_rhs()), m); literal lit = mk_eq_lit(lhs, rhs); - TRACEFN("assert_macro_axiom: " << pp_lit(ctx(), lit)); ctx().mk_th_axiom(get_id(), 1, &lit); + TRACEFN("case expansion " << pp_case_expansion(e, m) << "\n" << + "macro expansion yields " << mk_pp(rhs,m) << "\n" << + "literal " << pp_lit(ctx(), lit)); } + /** + * Add case axioms for every case expansion path. + * + * assert `p(args) <=> And(guards)` (with CNF on the fly) + * + * also body-expand paths that do not depend on any defined fun + */ void theory_recfun::assert_case_axioms(case_expansion & e) { - TRACEFN("assert_case_axioms "<< pp_case_expansion(e,m()) + TRACEFN("assert_case_axioms "<< pp_case_expansion(e,m) << " with " << e.m_def->get_cases().size() << " cases"); SASSERT(e.m_def->is_fun_defined()); // add case-axioms for all case-paths auto & vars = e.m_def->get_vars(); for (recfun::case_def const & c : e.m_def->get_cases()) { // applied predicate to `args` - literal_vector guards; - for (auto & g : c.get_guards()) { - expr_ref guard = apply_args(vars, e.m_args, g); - guards.push_back(~mk_literal(guard)); - } app_ref pred_applied = apply_pred(c.get_pred(), e.m_args); SASSERT(u().owns_app(pred_applied)); literal concl = mk_literal(pred_applied); - // assert `p(args) <=> And(guards)` (with CNF on the fly) - - for (literal g : guards) { - literal c[2] = {~ concl, ~g}; + literal_vector guards; + guards.push_back(concl); + for (auto & g : c.get_guards()) { + expr_ref ga = apply_args(vars, e.m_args, g); + literal guard = mk_literal(ga); + guards.push_back(~guard); + literal c[2] = {~concl, guard}; ctx().mk_th_axiom(get_id(), 2, c); } - guards.push_back(concl); - ctx().mk_th_axiom(get_id(), guards.size(), guards.c_ptr()); + ctx().mk_th_axiom(get_id(), guards); - // also body-expand paths that do not depend on any defined fun if (c.is_immediate()) { body_expansion be(c, e.m_args); assert_body_axiom(be); @@ -290,20 +298,21 @@ namespace smt { } } + /** + * For a guarded definition guards => f(vars) = rhs + * and occurrence f(args) + * + * substitute `args` for `vars` in guards, and rhs + * add axiom guards[args/vars] => f(args) = rhs[args/vars] + * + */ void theory_recfun::assert_body_axiom(body_expansion & e) { - TRACEFN("assert_body_axioms "<< pp_body_expansion(e,m())); recfun::def & d = *e.m_cdef->get_def(); auto & vars = d.get_vars(); auto & args = e.m_args; - // check that var order is standard - SASSERT(vars.size() == 0 || vars[vars.size()-1]->get_idx() == 0); - expr_ref lhs(u().mk_fun_defined(d, args), m()); - // substitute `e.args` into the RHS of this particular case + SASSERT(is_standard_order(vars)); + expr_ref lhs(u().mk_fun_defined(d, args), m); expr_ref rhs = apply_args(vars, args, e.m_cdef->get_rhs()); - // substitute `e.args` into the guard of this particular case, to make - // the `condition` part of the clause `conds => lhs=rhs` - - // now build the axiom `conds => lhs = rhs` literal_vector clause; for (auto & g : e.m_cdef->get_guards()) { @@ -311,8 +320,9 @@ namespace smt { clause.push_back(~mk_literal(guard)); } clause.push_back(mk_eq_lit(lhs, rhs)); - TRACEFN("assert_body_axiom " << pp_lits(ctx(), clause)); - ctx().mk_th_axiom(get_id(), clause.size(), clause.c_ptr()); + ctx().mk_th_axiom(get_id(), clause); + TRACEFN("body " << pp_body_expansion(e,m)); + TRACEFN("clause " << pp_lits(ctx(), clause)); } final_check_status theory_recfun::final_check_eh() { @@ -321,15 +331,14 @@ namespace smt { void theory_recfun::add_theory_assumptions(expr_ref_vector & assumptions) { app_ref dlimit = m_util.mk_depth_limit_pred(get_max_depth()); - TRACEFN("add_theory_assumption " << mk_pp(dlimit.get(), m())); + TRACEFN("add_theory_assumption " << mk_pp(dlimit.get(), m)); assumptions.push_back(dlimit); } - // if `dlimit` occurs in unsat core, return "unknown" lbool theory_recfun::validate_unsat_core(expr_ref_vector & unsat_core) { for (auto & e : unsat_core) { - if (is_app(e) && m_util.is_depth_limit(to_app(e))) + if (u().is_depth_limit(e)) return l_undef; } return l_false; diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 275d2ef59..019ef7918 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -33,7 +33,7 @@ namespace smt { stats() { reset(); } }; - // one case-expansion of `f(t1…tn)` + // one case-expansion of `f(t1...tn)` struct case_expansion { expr * m_lhs; // the term to expand recfun_def * m_def; @@ -64,18 +64,16 @@ namespace smt { friend std::ostream& operator<<(std::ostream&, pp_case_expansion const &); - // one body-expansion of `f(t1…tn)` using a `C_f_i(t1…tn)` + // one body-expansion of `f(t1...tn)` using a `C_f_i(t1...tn)` struct body_expansion { recfun_case_def const * m_cdef; ptr_vector m_args; body_expansion(recfun_util& u, app * n) : m_cdef(0), m_args() { SASSERT(u.is_case_pred(n)); - func_decl * d = n->get_decl(); - const symbol& name = d->get_name(); - m_cdef = &u.get_case_def(name); - for (unsigned i = 0; i < n->get_num_args(); ++i) - m_args.push_back(n->get_arg(i)); + m_cdef = &u.get_case_def(n->get_name()); + for (expr * arg : *n) + m_args.push_back(arg); } body_expansion(recfun_case_def const & d, ptr_vector & args) : m_cdef(&d), m_args(args) {} body_expansion(body_expansion const & from): m_cdef(from.m_cdef), m_args(from.m_args) {} @@ -90,11 +88,11 @@ namespace smt { friend std::ostream& operator<<(std::ostream&, pp_body_expansion const &); - struct empty{}; typedef trail_stack th_trail_stack; - typedef obj_map guard_set; + typedef obj_hashtable guard_set; + ast_manager& m; recfun_decl_plugin& m_plugin; recfun_util& m_util; stats m_stats; @@ -107,7 +105,6 @@ namespace smt { vector m_q_clauses; recfun_util & u() const { return m_util; } - ast_manager & m() { return get_manager(); } bool is_defined(app * f) const { return u().is_defined(f); } bool is_case_pred(app * f) const { return u().is_case_pred(f); } @@ -123,6 +120,7 @@ namespace smt { void max_depth_conflict(void); literal mk_literal(expr* e); literal mk_eq_lit(expr* l, expr* r); + bool is_standard_order(recfun::vars const& vars) const { return vars.size() == 0 || vars[vars.size()-1]->get_idx() == 0; } protected: void push_case_expand(case_expansion&& e) { m_q_case_expand.push_back(e); } void push_body_expand(body_expansion&& e) { m_q_body_expand.push_back(e); } From 35eb6eccd1daaacbcda760a43f25f37e0a3eda56 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Oct 2018 17:14:10 -0700 Subject: [PATCH 069/227] iterative deepening Signed-off-by: Nikolaj Bjorner --- src/ast/recfun_decl_plugin.cpp | 7 +-- src/smt/smt_context.cpp | 34 +++++++++++--- src/smt/smt_context.h | 4 +- src/smt/smt_theory.h | 9 ++++ src/smt/theory_recfun.cpp | 85 +++++++++++++++++++++------------- src/smt/theory_recfun.h | 15 ++---- 6 files changed, 101 insertions(+), 53 deletions(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index de8bf94b1..1cd9a4fb8 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -184,7 +184,8 @@ namespace recfun { return res; } - void def::add_case(std::string & name, unsigned n_conditions, expr ** conditions, expr * rhs, bool is_imm) { + void def::add_case(std::string & name, unsigned n_conditions, + expr ** conditions, expr * rhs, bool is_imm) { case_def c(m, m_fid, this, name, get_domain(), n_conditions, conditions, rhs); c.set_is_immediate(is_imm); TRACEFN("add_case " << name << " " << mk_pp(rhs, m) @@ -202,7 +203,7 @@ namespace recfun { TRACEFN("bug: " << m_name << " has cases already"); UNREACHABLE(); } - SASSERT(n_vars = m_domain.size()); + SASSERT(n_vars == m_domain.size()); TRACEFN("compute cases " << mk_pp(rhs0, m)); @@ -235,7 +236,7 @@ namespace recfun { if (m_macro) { // constant function or trivial control flow, only one (dummy) case name.append("dummy"); - add_case(name, 0, 0, rhs); + add_case(name, 0, nullptr, rhs); return; } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index f7b7bdbea..4b8b1b9d9 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3266,6 +3266,18 @@ namespace smt { m_assumptions.reset(); } + bool context::should_research(lbool r) { + if (r != l_false || m_unsat_core.empty()) { + return false; + } + for (theory* th : m_theory_set) { + if (th->should_research(m_unsat_core)) { + return true; + } + } + return false; + } + lbool context::mk_unsat_core(lbool r) { if (r != l_false) return r; SASSERT(inconsistent()); @@ -3353,7 +3365,7 @@ namespace smt { add_theory_assumptions(theory_assumptions); if (!theory_assumptions.empty()) { TRACE("search", tout << "Adding theory assumptions to context" << std::endl;); - return check(theory_assumptions.size(), theory_assumptions.c_ptr(), reset_cancel, true); + return check(0, nullptr, reset_cancel); } internalize_assertions(); @@ -3407,19 +3419,23 @@ namespace smt { } } - lbool context::check(unsigned num_assumptions, expr * const * assumptions, bool reset_cancel, bool already_did_theory_assumptions) { + lbool context::check(unsigned num_assumptions, expr * const * assumptions, bool reset_cancel) { if (!check_preamble(reset_cancel)) return l_undef; SASSERT(at_base_level()); setup_context(false); expr_ref_vector asms(m_manager, num_assumptions, assumptions); - if (!already_did_theory_assumptions) add_theory_assumptions(asms); + add_theory_assumptions(asms); // introducing proxies: if (!validate_assumptions(asms)) return l_undef; TRACE("unsat_core_bug", tout << asms << "\n";); internalize_assertions(); init_assumptions(asms); TRACE("before_search", display(tout);); - lbool r = search(); - r = mk_unsat_core(r); + lbool r; + do { + r = search(); + r = mk_unsat_core(r); + } + while (should_research(r)); r = check_finalize(r); return r; } @@ -3435,8 +3451,12 @@ namespace smt { internalize_assertions(); init_assumptions(asms); for (auto const& clause : clauses) init_clause(clause); - lbool r = search(); - r = mk_unsat_core(r); + lbool r; + do { + r = search(); + r = mk_unsat_core(r); + } + while (should_research(r)); r = check_finalize(r); return r; } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 5902f9b2c..45341d368 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1137,6 +1137,8 @@ namespace smt { void add_theory_assumptions(expr_ref_vector & theory_assumptions); lbool mk_unsat_core(lbool result); + + bool should_research(lbool result); void validate_unsat_core(); @@ -1524,7 +1526,7 @@ namespace smt { void pop(unsigned num_scopes); - lbool check(unsigned num_assumptions = 0, expr * const * assumptions = nullptr, bool reset_cancel = true, bool already_did_theory_assumptions = false); + lbool check(unsigned num_assumptions = 0, expr * const * assumptions = nullptr, bool reset_cancel = true); lbool check(expr_ref_vector const& cube, vector const& clauses); diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index fa0ec0c82..15b0aeed6 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -194,6 +194,15 @@ namespace smt { return l_false; } + /** + \brief This method is called from the smt_context when an unsat core is generated. + The theory may tell the solver to perform iterative deepening by invalidating + this unsat core and increasing some resource constraints. + */ + virtual bool should_research(expr_ref_vector & unsat_core) { + return false; + } + /** \brief This method is invoked before the search starts. */ diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 220cfcbbf..6f62cccc0 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -32,12 +32,10 @@ namespace smt { m(m), m_plugin(*reinterpret_cast(m.get_plugin(get_family_id()))), m_util(m_plugin.u()), - m_trail(*this), - m_guards(), + m_guards(m), m_max_depth(0), m_q_case_expand(), - m_q_body_expand(), - m_q_clauses() + m_q_body_expand() { } @@ -89,11 +87,9 @@ namespace smt { void theory_recfun::reset_queues() { m_q_case_expand.reset(); m_q_body_expand.reset(); - m_q_clauses.reset(); } void theory_recfun::reset_eh() { - m_trail.reset(); reset_queues(); m_stats.reset(); theory::reset_eh(); @@ -116,12 +112,10 @@ namespace smt { void theory_recfun::push_scope_eh() { TRACEFN("push_scope"); theory::push_scope_eh(); - m_trail.push_scope(); } void theory_recfun::pop_scope_eh(unsigned num_scopes) { TRACEFN("pop_scope " << num_scopes); - m_trail.pop_scope(num_scopes); theory::pop_scope_eh(num_scopes); reset_queues(); } @@ -131,15 +125,15 @@ namespace smt { reset_queues(); theory::restart_eh(); } - + bool theory_recfun::can_propagate() { return ! (m_q_case_expand.empty() && m_q_body_expand.empty() && m_q_clauses.empty()); } - + void theory_recfun::propagate() { - + for (literal_vector & c : m_q_clauses) { TRACEFN("add axiom " << pp_lits(ctx(), c)); ctx().mk_th_axiom(get_id(), c); @@ -179,7 +173,7 @@ namespace smt { c.push_back(~ mk_literal(g)); } TRACEFN("max-depth limit: add clause " << pp_lits(ctx(), c)); - SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx().get_assignment(l) == l_false; })); // conflict + SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx().get_assignment(l) == l_false; })); // conflict m_q_clauses.push_back(std::move(c)); } @@ -190,26 +184,23 @@ namespace smt { */ void theory_recfun::assign_eh(bool_var v, bool is_true) { expr* e = ctx().bool_var2expr(v); - if (!is_true || !is_app(e)) return; - app* a = to_app(e); - if (u().is_case_pred(a)) { - TRACEFN("assign_case_pred_true "<< mk_pp(e,m)); + if (is_true && u().is_case_pred(e)) { + app* a = to_app(e); + TRACEFN("assign_case_pred_true " << mk_pp(e, m)); // add to set of local assumptions, for depth-limit purpose - SASSERT(!m_guards.contains(e)); - m_guards.insert(e); - m.inc_ref(e); - insert_ref_map trail_elt(m, m_guards, e); - m_trail.push(trail_elt); + SASSERT(!m_guards.contains(a)); + m_guards.push_back(a); + ctx().push_trail(push_back_vector(m_guards)); - if (m_guards.size() > get_max_depth()) { - // too many body-expansions: depth-limit conflict - max_depth_conflict(); - } - else { + if (m_guards.size() <= get_max_depth()) { // body-expand body_expansion b_e(u(), a); push_body_expand(std::move(b_e)); } + else { + // too many body-expansions: depth-limit conflict + max_depth_conflict(); + } } } @@ -238,7 +229,19 @@ namespace smt { } literal theory_recfun::mk_eq_lit(expr* l, expr* r) { - literal lit = mk_eq(l, r, false); + literal lit; + if (m.is_true(r) || m.is_false(r)) { + std::swap(l, r); + } + if (m.is_true(l)) { + lit = mk_literal(r); + } + else if (m.is_false(l)) { + lit = ~mk_literal(r); + } + else { + lit = mk_eq(l, r, false); + } ctx().mark_as_relevant(lit); return lit; } @@ -326,6 +329,21 @@ namespace smt { } final_check_status theory_recfun::final_check_eh() { + if (m_guards.size() > get_max_depth()) { +#if 1 + return FC_GIVEUP; +#else + for (unsigned i = get_max_depth(); i < m_guards.size(); ++i) { + app* a = m_guards.get(i); + body_expansion b_e(u(), a); + push_body_expand(std::move(b_e)); + } + unsigned new_depth = m_guards.size() + 1; + IF_VERBOSE(2, verbose_stream() << "(smt.recfun :new-depth " << new_depth << ")\n"); + set_max_depth(new_depth); + return FC_CONTINUE; +#endif + } return FC_DONE; } @@ -335,13 +353,16 @@ namespace smt { assumptions.push_back(dlimit); } - // if `dlimit` occurs in unsat core, return "unknown" - lbool theory_recfun::validate_unsat_core(expr_ref_vector & unsat_core) { + // if `dlimit` occurs in unsat core, return 'true' + bool theory_recfun::should_research(expr_ref_vector & unsat_core) { for (auto & e : unsat_core) { - if (u().is_depth_limit(e)) - return l_undef; + if (u().is_depth_limit(e)) { + unsigned new_depth = (3 * (1 + get_max_depth())) / 2; + set_max_depth(new_depth); + return true; + } } - return l_false; + return false; } void theory_recfun::display(std::ostream & out) const { diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 019ef7918..a2ec27314 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -72,8 +72,7 @@ namespace smt { body_expansion(recfun_util& u, app * n) : m_cdef(0), m_args() { SASSERT(u.is_case_pred(n)); m_cdef = &u.get_case_def(n->get_name()); - for (expr * arg : *n) - m_args.push_back(arg); + m_args.append(n->get_num_args(), n->get_args()); } body_expansion(recfun_case_def const & d, ptr_vector & args) : m_cdef(&d), m_args(args) {} body_expansion(body_expansion const & from): m_cdef(from.m_cdef), m_args(from.m_args) {} @@ -88,16 +87,11 @@ namespace smt { friend std::ostream& operator<<(std::ostream&, pp_body_expansion const &); - - typedef trail_stack th_trail_stack; - typedef obj_hashtable guard_set; - ast_manager& m; recfun_decl_plugin& m_plugin; recfun_util& m_util; stats m_stats; - th_trail_stack m_trail; - guard_set m_guards; // true case-preds + app_ref_vector m_guards; // true case-preds unsigned m_max_depth; // for fairness and termination vector m_q_case_expand; @@ -117,8 +111,8 @@ namespace smt { void assert_macro_axiom(case_expansion & e); void assert_case_axioms(case_expansion & e); void assert_body_axiom(body_expansion & e); - void max_depth_conflict(void); literal mk_literal(expr* e); + void max_depth_conflict(); literal mk_eq_lit(expr* l, expr* r); bool is_standard_order(recfun::vars const& vars) const { return vars.size() == 0 || vars[vars.size()-1]->get_idx() == 0; } protected: @@ -137,7 +131,7 @@ namespace smt { void restart_eh() override; bool can_propagate() override; void propagate() override; - lbool validate_unsat_core(expr_ref_vector &) override; + bool should_research(expr_ref_vector &) override; void new_eq_eh(theory_var v1, theory_var v2) override {} void new_diseq_eh(theory_var v1, theory_var v2) override {} @@ -152,6 +146,7 @@ namespace smt { virtual void collect_statistics(::statistics & st) const override; unsigned get_max_depth() const { return m_max_depth; } void set_max_depth(unsigned n) { SASSERT(n>0); m_max_depth = n; } + void inc_max_depth() { ++m_max_depth; } }; } From c0556b2f643de03c47f0d3887349b73adb849be2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Oct 2018 17:53:11 -0700 Subject: [PATCH 070/227] iterative deepening per recursive function Signed-off-by: Nikolaj Bjorner --- src/ast/recfun_decl_plugin.h | 5 +++ src/smt/theory_recfun.cpp | 67 ++++++++++++++++++------------------ src/smt/theory_recfun.h | 25 +++++++------- 3 files changed, 52 insertions(+), 45 deletions(-) diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index 6c8824a6a..e470b8d9d 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -249,6 +249,11 @@ namespace recfun { return m_plugin->get_def(s); } + case_def& get_case_def(expr* e) { + SASSERT(is_case_pred(e)); + return get_case_def(to_app(e)->get_name()); + } + case_def& get_case_def(symbol const & s) { SASSERT(m_plugin->has_case_def(s)); return m_plugin->get_case_def(s); diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 6f62cccc0..e0b43c7ed 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -32,7 +32,7 @@ namespace smt { m(m), m_plugin(*reinterpret_cast(m.get_plugin(get_family_id()))), m_util(m_plugin.u()), - m_guards(m), + m_guard_preds(m), m_max_depth(0), m_q_case_expand(), m_q_body_expand() @@ -41,10 +41,6 @@ namespace smt { theory_recfun::~theory_recfun() { reset_queues(); - for (expr* g : m_guards) { - m.dec_ref(g); - } - m_guards.reset(); } char const * theory_recfun::get_name() const { return "recfun"; } @@ -112,12 +108,21 @@ namespace smt { void theory_recfun::push_scope_eh() { TRACEFN("push_scope"); theory::push_scope_eh(); + m_guard_preds_lim.push_back(m_guard_preds.size()); } void theory_recfun::pop_scope_eh(unsigned num_scopes) { TRACEFN("pop_scope " << num_scopes); theory::pop_scope_eh(num_scopes); reset_queues(); + + // restore guards + unsigned new_lim = m_guard_preds_lim.size()-num_scopes; + for (unsigned i = new_lim; i < m_guard_preds.size(); ++i) { + m_guards[m_guard_preds.get(i)->get_decl()].pop_back(); + } + m_guard_preds.resize(m_guard_preds_lim[new_lim]); + m_guard_preds_lim.shrink(new_lim); } void theory_recfun::restart_eh() { @@ -159,22 +164,20 @@ namespace smt { m_q_body_expand.clear(); } - void theory_recfun::max_depth_conflict() { - TRACEFN("max-depth conflict"); + void theory_recfun::max_depth_limit(ptr_vector const& guards) { + TRACEFN("max-depth limit"); literal_vector c; - // make clause `depth_limit => V_{g : guards} ~ g` - { - // first literal must be the depth limit one - app_ref dlimit = m_util.mk_depth_limit_pred(get_max_depth()); - c.push_back(~mk_literal(dlimit)); - SASSERT(ctx().get_assignment(c.back()) == l_true); - } - for (expr * g : m_guards) { - c.push_back(~ mk_literal(g)); + // make clause `depth_limit => V_{g : guards of non-recursive cases} g` + + // first literal must be the depth limit one + app_ref dlimit = m_util.mk_depth_limit_pred(get_max_depth()); + c.push_back(~mk_literal(dlimit)); + SASSERT(ctx().get_assignment(c.back()) == l_false); + + for (expr * g : guards) { + c.push_back(mk_literal(g)); } TRACEFN("max-depth limit: add clause " << pp_lits(ctx(), c)); - SASSERT(std::all_of(c.begin(), c.end(), [&](literal & l) { return ctx().get_assignment(l) == l_false; })); // conflict - m_q_clauses.push_back(std::move(c)); } @@ -185,22 +188,11 @@ namespace smt { void theory_recfun::assign_eh(bool_var v, bool is_true) { expr* e = ctx().bool_var2expr(v); if (is_true && u().is_case_pred(e)) { - app* a = to_app(e); TRACEFN("assign_case_pred_true " << mk_pp(e, m)); - // add to set of local assumptions, for depth-limit purpose - SASSERT(!m_guards.contains(a)); - m_guards.push_back(a); - ctx().push_trail(push_back_vector(m_guards)); - - if (m_guards.size() <= get_max_depth()) { - // body-expand - body_expansion b_e(u(), a); - push_body_expand(std::move(b_e)); - } - else { - // too many body-expansions: depth-limit conflict - max_depth_conflict(); - } + app* a = to_app(e); + // body-expand + body_expansion b_e(u(), a); + push_body_expand(std::move(b_e)); } } @@ -297,6 +289,15 @@ namespace smt { if (c.is_immediate()) { body_expansion be(c, e.m_args); assert_body_axiom(be); + + // add to set of local assumptions, for depth-limit purpose + func_decl* d = pred_applied->get_decl(); + m_guard_preds.push_back(pred_applied); + auto& vec = m_guards.insert_if_not_there2(d, ptr_vector())->get_data().m_value; + vec.push_back(pred_applied); + if (vec.size() == get_max_depth()) { + max_depth_limit(vec); + } } } } diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index a2ec27314..ab09e4f45 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -70,8 +70,7 @@ namespace smt { ptr_vector m_args; body_expansion(recfun_util& u, app * n) : m_cdef(0), m_args() { - SASSERT(u.is_case_pred(n)); - m_cdef = &u.get_case_def(n->get_name()); + m_cdef = &u.get_case_def(n); m_args.append(n->get_num_args(), n->get_args()); } body_expansion(recfun_case_def const & d, ptr_vector & args) : m_cdef(&d), m_args(args) {} @@ -87,16 +86,18 @@ namespace smt { friend std::ostream& operator<<(std::ostream&, pp_body_expansion const &); - ast_manager& m; - recfun_decl_plugin& m_plugin; - recfun_util& m_util; - stats m_stats; - app_ref_vector m_guards; // true case-preds - unsigned m_max_depth; // for fairness and termination + ast_manager& m; + recfun_decl_plugin& m_plugin; + recfun_util& m_util; + stats m_stats; + obj_map > m_guards; + app_ref_vector m_guard_preds; + unsigned_vector m_guard_preds_lim; + unsigned m_max_depth; // for fairness and termination - vector m_q_case_expand; - vector m_q_body_expand; - vector m_q_clauses; + vector m_q_case_expand; + vector m_q_body_expand; + vector m_q_clauses; recfun_util & u() const { return m_util; } bool is_defined(app * f) const { return u().is_defined(f); } @@ -112,7 +113,7 @@ namespace smt { void assert_case_axioms(case_expansion & e); void assert_body_axiom(body_expansion & e); literal mk_literal(expr* e); - void max_depth_conflict(); + void max_depth_limit(ptr_vector const& guards); literal mk_eq_lit(expr* l, expr* r); bool is_standard_order(recfun::vars const& vars) const { return vars.size() == 0 || vars[vars.size()-1]->get_idx() == 0; } protected: From 2d4a5e0a5e33847d55a6174c759cadf8f0c18d77 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Oct 2018 18:07:04 -0700 Subject: [PATCH 071/227] n/a Signed-off-by: Nikolaj Bjorner --- src/ast/recfun_decl_plugin.h | 3 +++ src/smt/smt_setup.cpp | 1 - src/smt/theory_recfun.cpp | 25 ++++++------------------- src/smt/theory_recfun.h | 16 ++++++++-------- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index e470b8d9d..f2da9d053 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -201,6 +201,7 @@ namespace recfun { def* mk_def(symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs); bool has_def(const symbol& s) const { return m_defs.contains(s); } + bool has_def() const { return !m_defs.empty(); } def const& get_def(const symbol& s) const { return *(m_defs[s]); } promise_def get_promise_def(const symbol &s) const { return promise_def(&u(), m_defs[s]); } def& get_def(symbol const& s) { return *(m_defs[s]); } @@ -241,6 +242,8 @@ namespace recfun { bool is_depth_limit(expr * e) const { return is_app_of(e, m_family_id, OP_DEPTH_LIMIT); } bool owns_app(app * e) const { return e->get_family_id() == m_family_id; } + bool has_def() const { return m_plugin->has_def(); } + //setup_params(); } void setup::setup_dl() { diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index e0b43c7ed..477e8c26a 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -45,7 +45,7 @@ namespace smt { char const * theory_recfun::get_name() const { return "recfun"; } - void theory_recfun::setup_params() { + void theory_recfun::init_search_eh() { // obtain max depth via parameters smt_params_helper p(ctx().get_params()); set_max_depth(p.recfun_max_depth()); @@ -330,28 +330,15 @@ namespace smt { } final_check_status theory_recfun::final_check_eh() { - if (m_guards.size() > get_max_depth()) { -#if 1 - return FC_GIVEUP; -#else - for (unsigned i = get_max_depth(); i < m_guards.size(); ++i) { - app* a = m_guards.get(i); - body_expansion b_e(u(), a); - push_body_expand(std::move(b_e)); - } - unsigned new_depth = m_guards.size() + 1; - IF_VERBOSE(2, verbose_stream() << "(smt.recfun :new-depth " << new_depth << ")\n"); - set_max_depth(new_depth); - return FC_CONTINUE; -#endif - } return FC_DONE; } void theory_recfun::add_theory_assumptions(expr_ref_vector & assumptions) { - app_ref dlimit = m_util.mk_depth_limit_pred(get_max_depth()); - TRACEFN("add_theory_assumption " << mk_pp(dlimit.get(), m)); - assumptions.push_back(dlimit); + if (u().has_def()) { + app_ref dlimit = m_util.mk_depth_limit_pred(get_max_depth()); + TRACEFN("add_theory_assumption " << mk_pp(dlimit.get(), m)); + assumptions.push_back(dlimit); + } } // if `dlimit` occurs in unsat core, return 'true' diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index ab09e4f45..265d8f305 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -138,16 +138,16 @@ namespace smt { void new_diseq_eh(theory_var v1, theory_var v2) override {} void add_theory_assumptions(expr_ref_vector & assumptions) override; + void set_max_depth(unsigned n) { SASSERT(n>0); m_max_depth = n; } + unsigned get_max_depth() const { return m_max_depth; } + public: theory_recfun(ast_manager & m); - virtual ~theory_recfun() override; - void setup_params(); // read parameters - virtual theory * mk_fresh(context * new_ctx) override; - virtual void display(std::ostream & out) const override; - virtual void collect_statistics(::statistics & st) const override; - unsigned get_max_depth() const { return m_max_depth; } - void set_max_depth(unsigned n) { SASSERT(n>0); m_max_depth = n; } - void inc_max_depth() { ++m_max_depth; } + ~theory_recfun() override; + void init_search_eh() override; + theory * mk_fresh(context * new_ctx) override; + void display(std::ostream & out) const override; + void collect_statistics(::statistics & st) const override; }; } From 936312cfd216ec7bb1b0b5e6860a79b0ee7f70e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Oct 2018 18:15:35 -0700 Subject: [PATCH 072/227] fix location of research Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 4b8b1b9d9..6dbf06a2a 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3423,15 +3423,16 @@ namespace smt { if (!check_preamble(reset_cancel)) return l_undef; SASSERT(at_base_level()); setup_context(false); - expr_ref_vector asms(m_manager, num_assumptions, assumptions); - add_theory_assumptions(asms); - // introducing proxies: if (!validate_assumptions(asms)) return l_undef; - TRACE("unsat_core_bug", tout << asms << "\n";); - internalize_assertions(); - init_assumptions(asms); - TRACE("before_search", display(tout);); lbool r; do { + pop_to_base_lvl(); + expr_ref_vector asms(m_manager, num_assumptions, assumptions); + add_theory_assumptions(asms); + // introducing proxies: if (!validate_assumptions(asms)) return l_undef; + TRACE("unsat_core_bug", tout << asms << "\n";); + internalize_assertions(); + init_assumptions(asms); + TRACE("before_search", display(tout);); r = search(); r = mk_unsat_core(r); } @@ -3444,15 +3445,16 @@ namespace smt { if (!check_preamble(true)) return l_undef; TRACE("before_search", display(tout);); setup_context(false); - expr_ref_vector asms(cube); - add_theory_assumptions(asms); - // introducing proxies: if (!validate_assumptions(asms)) return l_undef; - for (auto const& clause : clauses) if (!validate_assumptions(clause)) return l_undef; - internalize_assertions(); - init_assumptions(asms); - for (auto const& clause : clauses) init_clause(clause); lbool r; do { + pop_to_base_lvl(); + expr_ref_vector asms(cube); + add_theory_assumptions(asms); + // introducing proxies: if (!validate_assumptions(asms)) return l_undef; + for (auto const& clause : clauses) if (!validate_assumptions(clause)) return l_undef; + internalize_assertions(); + init_assumptions(asms); + for (auto const& clause : clauses) init_clause(clause); r = search(); r = mk_unsat_core(r); } From 694a6a26c9297b28132dc97a797919369d0dbfa2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Oct 2018 20:20:08 -0700 Subject: [PATCH 073/227] bump version, add double access Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- examples/c++/example.cpp | 12 ++++++++++++ scripts/mk_project.py | 2 +- src/api/api_numeral.cpp | 5 +++++ src/api/c++/z3++.h | 1 + src/api/dotnet/RatNum.cs | 8 ++++++++ src/api/dotnet/core/project.json | 22 ---------------------- src/api/z3_api.h | 9 +++++++++ 8 files changed, 37 insertions(+), 24 deletions(-) delete mode 100644 src/api/dotnet/core/project.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ace973a1..583e757aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() ################################################################################ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 8) -set(Z3_VERSION_PATCH 0) +set(Z3_VERSION_PATCH 2) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 6faeb3edc..3089f5e2b 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -835,6 +835,17 @@ void tst_visit() { visit(f); } +void tst_numeral() { + context c; + expr x = c.real_val("1/3"); + double d = 0; + if (!x.is_numeral(d)) { + std::cout << x << " is not recognized as a numeral\n"; + return; + } + std::cout << x << " is " << d << "\n"; +} + void incremental_example1() { std::cout << "incremental example1\n"; context c; @@ -1212,6 +1223,7 @@ int main() { tactic_example9(); std::cout << "\n"; tactic_qe(); std::cout << "\n"; tst_visit(); std::cout << "\n"; + tst_numeral(); std::cout << "\n"; incremental_example1(); std::cout << "\n"; incremental_example2(); std::cout << "\n"; incremental_example3(); std::cout << "\n"; diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 1ec5f05b5..3003578bf 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 8, 0, 0) + set_version(4, 8, 2, 0) add_lib('util', [], includes2install = ['z3_version.h']) add_lib('polynomial', ['util'], 'math/polynomial') add_lib('sat', ['util']) diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 2891e8cc4..11afed82e 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -227,6 +227,11 @@ extern "C" { Z3_CATCH_RETURN(""); } + double Z3_API Z3_get_numeral_double(Z3_context c, Z3_ast a) { + Z3_string s = Z3_get_numeral_decimal_string(c, a, 12); + return std::stod(std::string(s)); + } + Z3_string Z3_API Z3_get_numeral_decimal_string(Z3_context c, Z3_ast a, unsigned precision) { Z3_TRY; LOG_Z3_get_numeral_decimal_string(c, a, precision); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 1b1820909..9434323fb 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -709,6 +709,7 @@ namespace z3 { bool is_numeral_u(unsigned& i) const { bool r = 0 != Z3_get_numeral_uint(ctx(), m_ast, &i); check_error(); return r;} bool is_numeral(std::string& s) const { if (!is_numeral()) return false; s = Z3_get_numeral_string(ctx(), m_ast); check_error(); return true; } bool is_numeral(std::string& s, unsigned precision) const { if (!is_numeral()) return false; s = Z3_get_numeral_decimal_string(ctx(), m_ast, precision); check_error(); return true; } + bool is_numeral(double& d) const { if (!is_numeral()) return false; d = Z3_get_numeral_double(ctx(), m_ast); check_error(); return true; } /** \brief Return true if this expression is an application. */ diff --git a/src/api/dotnet/RatNum.cs b/src/api/dotnet/RatNum.cs index bad6b323d..ef5f1a867 100644 --- a/src/api/dotnet/RatNum.cs +++ b/src/api/dotnet/RatNum.cs @@ -92,6 +92,14 @@ namespace Microsoft.Z3 return Native.Z3_get_numeral_decimal_string(Context.nCtx, NativeObject, precision); } + /// + /// Returns a double representing the value. + /// + public double Double + { + get { return Native.Z3_get_numeral_double(Context.nCtx, NativeObject); } + } + /// /// Returns a string representation of the numeral. /// diff --git a/src/api/dotnet/core/project.json b/src/api/dotnet/core/project.json deleted file mode 100644 index d54b6877b..000000000 --- a/src/api/dotnet/core/project.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "version": "1.0.0-*", - "buildOptions": { - "debugType": "portable", - "emitEntryPoint": false, - "outputName": "Microsoft.Z3", - "compile": [ "../*.cs", "*.cs" ], - "define": ["DOTNET_CORE"] - }, - "dependencies": { }, - "frameworks": { - "netcoreapp1.0": { - "dependencies": { - "Microsoft.NETCore.App": { - "type": "platform", - "version": "1.0.1" - } - }, - "imports": "dnxcore50" - } - } -} diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 03bce5d5e..bb88c1f98 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4438,6 +4438,15 @@ extern "C" { */ Z3_string Z3_API Z3_get_numeral_decimal_string(Z3_context c, Z3_ast a, unsigned precision); + /** + \brief Return numeral as a double. + + \pre Z3_get_ast_kind(c, a) == Z3_NUMERAL_AST || Z3_is_algebraic_number(c, a) + + def_API('Z3_get_numeral_double', STRING, (_in(CONTEXT), _in(AST))) + */ + double Z3_API Z3_get_numeral_double(Z3_context c, Z3_ast a); + /** \brief Return the numerator (as a numeral AST) of a numeral AST of sort Real. From eb15f8249ab79e16d891d2040d9728f9f852b4ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Oct 2018 21:01:25 -0700 Subject: [PATCH 074/227] fix backtrack Signed-off-by: Nikolaj Bjorner --- src/smt/theory_recfun.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 477e8c26a..059a34f29 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -118,10 +118,11 @@ namespace smt { // restore guards unsigned new_lim = m_guard_preds_lim.size()-num_scopes; - for (unsigned i = new_lim; i < m_guard_preds.size(); ++i) { + unsigned start = m_guard_preds_lim[new_lim]; + for (unsigned i = start; i < m_guard_preds.size(); ++i) { m_guards[m_guard_preds.get(i)->get_decl()].pop_back(); } - m_guard_preds.resize(m_guard_preds_lim[new_lim]); + m_guard_preds.resize(start); m_guard_preds_lim.shrink(new_lim); } From 7835091a26d2b3653a74bfe285f112ac75b7f309 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Oct 2018 21:03:47 -0700 Subject: [PATCH 075/227] good luck! Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/core/README.txt | 4 +++- src/api/dotnet/core/core.csproj | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/api/dotnet/core/core.csproj diff --git a/src/api/dotnet/core/README.txt b/src/api/dotnet/core/README.txt index 72331d7f9..883b23056 100644 --- a/src/api/dotnet/core/README.txt +++ b/src/api/dotnet/core/README.txt @@ -6,4 +6,6 @@ functions, so that the API will compile, but not perform any contract checking. To build this using .NET core, run (in this directory): dotnet restore -dotnet build project.json +dotnet build core.json + +-- good luck! diff --git a/src/api/dotnet/core/core.csproj b/src/api/dotnet/core/core.csproj new file mode 100644 index 000000000..5fa3275cf --- /dev/null +++ b/src/api/dotnet/core/core.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp1.0 + $(DefineConstants);DOTNET_CORE + portable + Microsoft.Z3 + Library + core + $(PackageTargetFallback);dnxcore50 + 1.0.4 + + + + + + + From 6233dee505b5c7c81edddb7a1e7cdb653a27c015 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Oct 2018 21:05:32 -0700 Subject: [PATCH 076/227] double happiness Signed-off-by: Nikolaj Bjorner --- src/api/z3_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index bb88c1f98..b02b3eb3b 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4443,7 +4443,7 @@ extern "C" { \pre Z3_get_ast_kind(c, a) == Z3_NUMERAL_AST || Z3_is_algebraic_number(c, a) - def_API('Z3_get_numeral_double', STRING, (_in(CONTEXT), _in(AST))) + def_API('Z3_get_numeral_double', DOUBLE, (_in(CONTEXT), _in(AST))) */ double Z3_API Z3_get_numeral_double(Z3_context c, Z3_ast a); From 880ce12e2d3bd565860976846168d1c0b0ecff27 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 20 Oct 2018 12:03:47 +0100 Subject: [PATCH 077/227] Fixed .NET Core API build. --- src/api/dotnet/Microsoft.Z3.csproj | 3 ++- src/api/dotnet/core/README.txt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/Microsoft.Z3.csproj b/src/api/dotnet/Microsoft.Z3.csproj index cde8b78c9..045c610dd 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj +++ b/src/api/dotnet/Microsoft.Z3.csproj @@ -342,6 +342,7 @@ + @@ -360,11 +361,11 @@ - + diff --git a/src/api/dotnet/core/README.txt b/src/api/dotnet/core/README.txt index 883b23056..7af9cbf2c 100644 --- a/src/api/dotnet/core/README.txt +++ b/src/api/dotnet/core/README.txt @@ -6,6 +6,6 @@ functions, so that the API will compile, but not perform any contract checking. To build this using .NET core, run (in this directory): dotnet restore -dotnet build core.json +dotnet build core.csproj -c Release -- good luck! From 326bf401b9e50d5234b1504176bf715b8159c9a9 Mon Sep 17 00:00:00 2001 From: Florian Pigorsch Date: Sat, 20 Oct 2018 17:07:41 +0200 Subject: [PATCH 078/227] Fix some spelling errors (mostly in comments). --- cmake/msvc_legacy_quirks.cmake | 6 +++--- cmake/z3_add_component.cmake | 6 +++--- contrib/ci/README.md | 4 ++-- doc/z3api.cfg.in | 4 ++-- examples/c++/CMakeLists.txt | 4 ++-- examples/c/CMakeLists.txt | 4 ++-- examples/maxsat/CMakeLists.txt | 4 ++-- .../Z3BaseSolver.cs | 2 +- examples/tptp/CMakeLists.txt | 4 ++-- examples/tptp/tptp5.cpp | 2 +- scripts/mk_util.py | 2 +- .../lackr_model_constructor.cpp | 2 +- src/api/api_context.cpp | 2 +- src/api/api_datalog.cpp | 2 +- src/api/dotnet/ArithExpr.cs | 2 +- src/api/dotnet/Context.cs | 4 ++-- src/api/dotnet/Expr.cs | 2 +- src/api/python/z3/z3util.py | 4 ++-- src/api/z3_api.h | 8 ++++---- src/ast/ast_util.h | 2 +- src/ast/fpa/fpa2bv_rewriter.cpp | 2 +- src/ast/func_decl_dependencies.h | 2 +- src/ast/macros/quasi_macros.cpp | 4 ++-- src/ast/pattern/pattern_inference.cpp | 2 +- src/ast/rewriter/bv_rewriter.cpp | 2 +- src/ast/rewriter/datatype_rewriter.cpp | 2 +- src/ast/rewriter/der.h | 2 +- src/ast/rewriter/push_app_ite.h | 2 +- src/cmd_context/tactic_cmds.cpp | 2 +- src/math/euclid/euclidean_solver.cpp | 2 +- src/math/polynomial/algebraic_numbers.cpp | 6 +++--- src/math/polynomial/polynomial.cpp | 4 ++-- src/math/polynomial/polynomial.h | 4 ++-- src/math/polynomial/upolynomial.cpp | 14 ++++++------- src/math/polynomial/upolynomial.h | 4 ++-- .../upolynomial_factorization_int.h | 2 +- src/math/realclosure/mpz_matrix.h | 2 +- src/math/realclosure/rcf_params.pyg | 2 +- src/math/realclosure/realclosure.cpp | 4 ++-- src/math/simplex/network_flow.h | 2 +- src/math/subpaving/subpaving_t.h | 2 +- src/math/subpaving/subpaving_t_def.h | 2 +- src/muz/base/dl_context.h | 2 +- src/muz/base/dl_rule.h | 2 +- src/muz/base/dl_util.h | 2 +- src/muz/base/fp_params.pyg | 4 ++-- src/muz/base/hnf.h | 2 +- src/muz/ddnf/ddnf.cpp | 2 +- src/muz/fp/datalog_parser.cpp | 4 ++-- src/muz/rel/dl_base.h | 2 +- src/muz/rel/dl_finite_product_relation.cpp | 2 +- src/muz/rel/dl_instruction.cpp | 2 +- src/muz/rel/dl_relation_manager.h | 4 ++-- src/muz/rel/dl_sparse_table.cpp | 2 +- src/muz/rel/rel_context.h | 2 +- src/muz/spacer/spacer_farkas_learner.cpp | 6 +++--- src/muz/spacer/spacer_quant_generalizer.cpp | 20 +++++++++---------- src/muz/spacer/spacer_unsat_core_plugin.cpp | 2 +- src/muz/tab/tab_context.cpp | 2 +- .../dl_mk_quantifier_instantiation.cpp | 2 +- .../transforms/dl_mk_subsumption_checker.cpp | 4 ++-- src/nlsat/nlsat_evaluator.cpp | 6 +++--- src/parsers/smt2/smt2parser.cpp | 4 ++-- src/qe/qe_arith_plugin.cpp | 2 +- src/qe/qe_datatype_plugin.cpp | 2 +- src/qe/qe_lite.cpp | 2 +- src/qe/qe_mbi.h | 2 +- src/qe/qe_term_graph.cpp | 2 +- src/sat/ba_solver.cpp | 2 +- src/sat/sat_local_search.h | 6 +++--- src/sat/sat_lookahead.cpp | 10 +++++----- src/sat/sat_lookahead.h | 2 +- src/sat/sat_parallel.cpp | 2 +- src/sat/sat_simplifier.cpp | 2 +- src/sat/sat_simplifier.h | 2 +- src/smt/arith_eq_solver.cpp | 2 +- src/smt/params/qi_params.h | 4 ++-- src/smt/params/smt_params_helper.pyg | 2 +- src/smt/qi_queue.cpp | 2 +- src/smt/smt_conflict_resolution.cpp | 2 +- src/smt/smt_context.cpp | 8 ++++---- src/smt/smt_enode.h | 2 +- src/smt/smt_model_generator.h | 2 +- src/smt/smt_setup.cpp | 4 ++-- src/smt/smt_theory.h | 4 ++-- src/smt/theory_arith_aux.h | 4 ++-- src/smt/theory_arith_core.h | 4 ++-- src/smt/theory_arith_nl.h | 6 +++--- src/smt/theory_dense_diff_logic_def.h | 2 +- src/smt/theory_lra.cpp | 2 +- src/smt/theory_pb.h | 4 ++-- src/smt/theory_seq.cpp | 2 +- src/smt/theory_str.cpp | 2 +- src/solver/combined_solver.cpp | 2 +- src/solver/parallel_params.pyg | 2 +- src/tactic/arith/fm_tactic.cpp | 2 +- src/tactic/bv/bvarray2uf_rewriter.cpp | 2 +- src/tactic/core/cofactor_elim_term_ite.cpp | 4 ++-- src/tactic/core/pb_preprocess_tactic.cpp | 4 ++-- src/tactic/model_converter.h | 4 ++-- src/tactic/nlsat_smt/nl_purify_tactic.cpp | 6 +++--- src/tactic/sls/sls_engine.cpp | 2 +- src/tactic/smtlogics/qfbv_tactic.cpp | 2 +- src/test/ast.cpp | 2 +- src/test/ddnf.cpp | 2 +- src/test/fuzzing/expr_delta.h | 2 +- src/test/lp/lp.cpp | 20 +++++++++---------- src/test/sat_local_search.cpp | 6 +++--- src/util/bit_util.cpp | 2 +- src/util/bit_util.h | 4 ++-- src/util/list.h | 2 +- src/util/lp/binary_heap_priority_queue_def.h | 2 +- src/util/lp/bound_analyzer_on_row.h | 2 +- src/util/lp/lp_core_solver_base_def.h | 2 +- src/util/lp/lp_dual_core_solver_def.h | 2 +- src/util/lp/lp_primal_core_solver_def.h | 6 +++--- src/util/lp/lp_settings.h | 4 ++-- src/util/lp/scaler_def.h | 2 +- src/util/lp/square_sparse_matrix_def.h | 2 +- src/util/mpf.cpp | 4 ++-- src/util/obj_ref_hashtable.h | 2 +- 121 files changed, 205 insertions(+), 205 deletions(-) diff --git a/cmake/msvc_legacy_quirks.cmake b/cmake/msvc_legacy_quirks.cmake index 36fe82bb3..a8006e2d3 100644 --- a/cmake/msvc_legacy_quirks.cmake +++ b/cmake/msvc_legacy_quirks.cmake @@ -8,13 +8,13 @@ # FIXME: All the commented out defines should be removed once # we are confident it is correct to not set them. set(Z3_MSVC_LEGACY_DEFINES - # Don't set `_DEBUG`. The old build sytem sets this but this + # Don't set `_DEBUG`. The old build system sets this but this # is wrong. MSVC will set this depending on which runtime is being used. # See https://msdn.microsoft.com/en-us/library/b0084kay.aspx # _DEBUG # The old build system only set `UNICODE` and `_UNICODE` for x86_64 release. - # That seems completly wrong so set it for all configurations. + # That seems completely wrong so set it for all configurations. # According to https://blogs.msdn.microsoft.com/oldnewthing/20040212-00/?p=40643/ # `UNICODE` affects Windows headers and `_UNICODE` affects C runtime header files. # There is some discussion of this define at https://msdn.microsoft.com/en-us/library/dybsewaf.aspx @@ -116,7 +116,7 @@ z3_add_cxx_flag("/analyze-" REQUIRED) ################################################################################ # By default CMake enables incremental linking for Debug and RelWithDebInfo -# builds. The old build sytem disables it for all builds so try to do the same +# builds. The old build system disables it for all builds so try to do the same # by changing all configurations if necessary string(TOUPPER "${available_build_types}" _build_types_as_upper) foreach (_build_type ${_build_types_as_upper}) diff --git a/cmake/z3_add_component.cmake b/cmake/z3_add_component.cmake index d87ffbe61..8ab6e045d 100644 --- a/cmake/z3_add_component.cmake +++ b/cmake/z3_add_component.cmake @@ -7,7 +7,7 @@ function(z3_expand_dependencies output_var) if (ARGC LESS 2) message(FATAL_ERROR "Invalid number of arguments") endif() - # Remaing args should be component names + # Remaining args should be component names set(_expanded_deps ${ARGN}) set(_old_number_of_deps 0) list(LENGTH _expanded_deps _number_of_deps) @@ -33,7 +33,7 @@ function(z3_add_component_dependencies_to_target target_name) if (NOT (TARGET ${target_name})) message(FATAL_ERROR "Target \"${target_name}\" does not exist") endif() - # Remaing args should be component names + # Remaining args should be component names set(_expanded_deps ${ARGN}) foreach (dependency ${_expanded_deps}) # Ensure this component's dependencies are built before this component. @@ -219,7 +219,7 @@ macro(z3_add_component component_name) # Record this component's dependencies foreach (dependency ${Z3_MOD_COMPONENT_DEPENDENCIES}) if (NOT (TARGET ${dependency})) - message(FATAL_ERROR "Component \"${component_name}\" depends on a non existant component \"${dependency}\"") + message(FATAL_ERROR "Component \"${component_name}\" depends on a non existent component \"${dependency}\"") endif() set_property(GLOBAL APPEND PROPERTY Z3_${component_name}_DEPS "${dependency}") endforeach() diff --git a/contrib/ci/README.md b/contrib/ci/README.md index bd1c52792..d0f336f92 100644 --- a/contrib/ci/README.md +++ b/contrib/ci/README.md @@ -1,4 +1,4 @@ -# Continous integration scripts +# Continuous integration scripts ## TravisCI @@ -45,7 +45,7 @@ the future. * `Z3_VERBOSE_BUILD_OUTPUT` - Show compile commands in CMake builds (`0` or `1`) * `Z3_STATIC_BUILD` - Build Z3 binaries and libraries statically (`0` or `1`) * `Z3_SYSTEM_TEST_GIT_REVISION` - Git revision of [z3test](https://github.com/Z3Prover/z3test). If empty lastest revision will be used. -* `Z3_WARNINGS_AS_ERRORS` - Set the `WARNINGS_AS_ERRORS` CMake option pased to Z3 (`OFF`, `ON`, or `SERIOUS_ONLY`) +* `Z3_WARNINGS_AS_ERRORS` - Set the `WARNINGS_AS_ERRORS` CMake option passed to Z3 (`OFF`, `ON`, or `SERIOUS_ONLY`) ### Linux diff --git a/doc/z3api.cfg.in b/doc/z3api.cfg.in index 9c4b464c2..e58b561c9 100644 --- a/doc/z3api.cfg.in +++ b/doc/z3api.cfg.in @@ -944,7 +944,7 @@ HTML_STYLESHEET = # user-defined cascading style sheet that is included after the standard # style sheets created by doxygen. Using this option one can overrule # certain style aspects. This is preferred over using HTML_STYLESHEET -# since it does not replace the standard style sheet and is therefor more +# since it does not replace the standard style sheet and is therefore more # robust against future updates. Doxygen will copy the style sheet file to # the output directory. @@ -1711,7 +1711,7 @@ UML_LOOK = NO # the class node. If there are many fields or methods and many nodes the # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS # threshold limits the number of items for each type to make the size more -# managable. Set this to 0 for no limit. Note that the threshold may be +# manageable. Set this to 0 for no limit. Note that the threshold may be # exceeded by 50% before the limit is enforced. UML_LIMIT_NUM_FIELDS = 10 diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index 0a41d6a93..52758889d 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -7,8 +7,8 @@ find_package(Z3 REQUIRED CONFIG # `NO_DEFAULT_PATH` is set so that -DZ3_DIR has to be passed to find Z3. - # This should prevent us from accidently picking up an installed - # copy of Z3. This is here to benefit Z3's build sytem when building + # This should prevent us from accidentally picking up an installed + # copy of Z3. This is here to benefit Z3's build system when building # this project. When making your own project you probably shouldn't # use this option. NO_DEFAULT_PATH diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index c47a4947a..e45c82d37 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -24,8 +24,8 @@ find_package(Z3 REQUIRED CONFIG # `NO_DEFAULT_PATH` is set so that -DZ3_DIR has to be passed to find Z3. - # This should prevent us from accidently picking up an installed - # copy of Z3. This is here to benefit Z3's build sytem when building + # This should prevent us from accidentally picking up an installed + # copy of Z3. This is here to benefit Z3's build system when building # this project. When making your own project you probably shouldn't # use this option. NO_DEFAULT_PATH diff --git a/examples/maxsat/CMakeLists.txt b/examples/maxsat/CMakeLists.txt index 019243ecf..e59486297 100644 --- a/examples/maxsat/CMakeLists.txt +++ b/examples/maxsat/CMakeLists.txt @@ -11,8 +11,8 @@ find_package(Z3 REQUIRED CONFIG # `NO_DEFAULT_PATH` is set so that -DZ3_DIR has to be passed to find Z3. - # This should prevent us from accidently picking up an installed - # copy of Z3. This is here to benefit Z3's build sytem when building + # This should prevent us from accidentally picking up an installed + # copy of Z3. This is here to benefit Z3's build system when building # this project. When making your own project you probably shouldn't # use this option. NO_DEFAULT_PATH diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs index 1c82406be..5297d3e67 100644 --- a/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs +++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs @@ -226,7 +226,7 @@ namespace Microsoft.SolverFoundation.Plugin.Z3 } /// - /// Adds a MSF variable with the coresponding assertion to the Z3 variables. + /// Adds a MSF variable with the corresponding assertion to the Z3 variables. /// /// The MSF id of the variable internal void AddVariable(int vid) diff --git a/examples/tptp/CMakeLists.txt b/examples/tptp/CMakeLists.txt index 8e8dfb8ea..7870e5408 100644 --- a/examples/tptp/CMakeLists.txt +++ b/examples/tptp/CMakeLists.txt @@ -7,8 +7,8 @@ find_package(Z3 REQUIRED CONFIG # `NO_DEFAULT_PATH` is set so that -DZ3_DIR has to be passed to find Z3. - # This should prevent us from accidently picking up an installed - # copy of Z3. This is here to benefit Z3's build sytem when building + # This should prevent us from accidentally picking up an installed + # copy of Z3. This is here to benefit Z3's build system when building # this project. When making your own project you probably shouldn't # use this option. NO_DEFAULT_PATH diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index facbf6c0a..882c2bbe2 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -233,7 +233,7 @@ class env { void check_arity(unsigned num_args, unsigned arity) { if (num_args != arity) { - throw failure_ex("arity missmatch"); + throw failure_ex("arity mismatch"); } } diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 97e2b65f2..0657a2686 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -3276,7 +3276,7 @@ class MakeRuleCmd(object): needed commands used in Makefile rules Note that several of the method are meant for use during ``make install`` and ``make uninstall``. These methods correctly use - ``$(PREFIX)`` and ``$(DESTDIR)`` and therefore are preferrable + ``$(PREFIX)`` and ``$(DESTDIR)`` and therefore are preferable to writing commands manually which can be error prone. """ @classmethod diff --git a/src/ackermannization/lackr_model_constructor.cpp b/src/ackermannization/lackr_model_constructor.cpp index 420fbda10..df0aac15e 100644 --- a/src/ackermannization/lackr_model_constructor.cpp +++ b/src/ackermannization/lackr_model_constructor.cpp @@ -276,7 +276,7 @@ struct lackr_model_constructor::imp { SASSERT(a->get_num_args() == 0); func_decl * const fd = a->get_decl(); expr * val = m_abstr_model->get_const_interp(fd); - if (val == nullptr) { // TODO: avoid model completetion? + if (val == nullptr) { // TODO: avoid model completion? sort * s = fd->get_range(); val = m_abstr_model->get_some_value(s); } diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 4b3b85399..c236ba3e8 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -219,7 +219,7 @@ namespace api { if (m_user_ref_count) { // Corner case bug: n may be in m_last_result, and this is the only reference to n. // When, we execute reset() it is deleted - // To avoid this bug, I bump the reference counter before reseting m_last_result + // To avoid this bug, I bump the reference counter before resetting m_last_result ast_ref node(n, m()); m_last_result.reset(); m_last_result.push_back(std::move(node)); diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index c2f437391..06207cee6 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -210,7 +210,7 @@ extern "C" { if (!out) { return Z3_FALSE; } - // must start loggging here, since function uses Z3_get_sort_kind above + // must start logging here, since function uses Z3_get_sort_kind above LOG_Z3_get_finite_domain_sort_size(c, s, out); RESET_ERROR_CODE(); VERIFY(mk_c(c)->datalog_util().try_get_size(to_sort(s), *out)); diff --git a/src/api/dotnet/ArithExpr.cs b/src/api/dotnet/ArithExpr.cs index b6beaef0c..1c42fd78a 100644 --- a/src/api/dotnet/ArithExpr.cs +++ b/src/api/dotnet/ArithExpr.cs @@ -45,7 +45,7 @@ namespace Microsoft.Z3 private static ArithExpr MkNum(ArithExpr e, double d) { return (ArithExpr)e.Context.MkNumeral(d.ToString(), e.Context.MkRealSort()); } - /// Operator overloading for arithmetical divsion operator (over reals) + /// Operator overloading for arithmetical division operator (over reals) public static ArithExpr operator /(ArithExpr a, ArithExpr b) { return a.Context.MkDiv(a, b); } /// Operator overloading for arithmetical operator diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index c8decb59b..ef85a8713 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2459,7 +2459,7 @@ namespace Microsoft.Z3 #endregion - #region Sequence, string and regular expresions + #region Sequence, string and regular expressions /// /// Create the empty sequence. @@ -3131,7 +3131,7 @@ namespace Microsoft.Z3 /// /// Create a bit-vector numeral. /// - /// An array of bits representing the bit-vector. Least signficant bit is at position 0. + /// An array of bits representing the bit-vector. Least significant bit is at position 0. public BitVecNum MkBV(bool[] bits) { Contract.Ensures(Contract.Result() != null); diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 99baaa8e4..5d1896221 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -842,7 +842,7 @@ namespace Microsoft.Z3 public string String { get { return Native.Z3_get_string(Context.nCtx, NativeObject); } } /// - /// Check whether expression is a concatentation. + /// Check whether expression is a concatenation. /// /// a Boolean public bool IsConcat { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_CONCAT; } } diff --git a/src/api/python/z3/z3util.py b/src/api/python/z3/z3util.py index fe7e76b86..6e5165c9a 100644 --- a/src/api/python/z3/z3util.py +++ b/src/api/python/z3/z3util.py @@ -199,7 +199,7 @@ def prove(claim,assume=None,verbose=0): >>> r,m = prove(True,assume=And(x,Not(x)),verbose=0) Traceback (most recent call last): ... - AssertionError: Assumption is alway False! + AssertionError: Assumption is always False! >>> r,m = prove(Implies(x,x),assume=y,verbose=2); r,model_str(m,as_str=False) assume: @@ -238,7 +238,7 @@ def prove(claim,assume=None,verbose=0): is_proved,_ = prove(Not(assume)) def _f(): - emsg = "Assumption is alway False!" + emsg = "Assumption is always False!" if verbose >= 2: emsg = "{}\n{}".format(assume,emsg) return emsg diff --git a/src/api/z3_api.h b/src/api/z3_api.h index b02b3eb3b..de446d9a8 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3772,7 +3772,7 @@ extern "C" { ); /** - \brief Create a lambda expression. It taks an expression \c body that contains bound variables + \brief Create a lambda expression. It takes an expression \c body that contains bound variables of the same sorts as the sorts listed in the array \c sorts. The bound variables are de-Bruijn indices created using #Z3_mk_bound. The array \c decl_names contains the names that the quantified formula uses for the bound variables. Z3 applies the convention that the last element in the \c decl_names and \c sorts array @@ -4609,7 +4609,7 @@ extern "C" { Z3_bool Z3_API Z3_is_quantifier_exists(Z3_context c, Z3_ast a); /** - \brief Determine if ast is a lambda expresion. + \brief Determine if ast is a lambda expression. \pre Z3_get_ast_kind(a) == Z3_QUANTIFIER_AST @@ -5996,7 +5996,7 @@ extern "C" { Z3_solver Z3_API Z3_solver_translate(Z3_context source, Z3_solver s, Z3_context target); /** - \brief Ad-hoc method for importing model convertion from solver. + \brief Ad-hoc method for importing model conversion from solver. def_API('Z3_solver_import_model_converter', VOID, (_in(CONTEXT), _in(SOLVER), _in(SOLVER))) */ @@ -6215,7 +6215,7 @@ extern "C" { The third argument is a vector of variables that may be used for cubing. The contents of the vector is only used in the first call. The initial list of variables is used in subsequent calls until it returns the unsatisfiable cube. - The vector is modified to contain a set of Autarky variables that occor in clauses that + The vector is modified to contain a set of Autarky variables that occur in clauses that are affected by the (last literal in the) cube. These variables could be used by a different cuber (on a different solver object) for further recursive cubing. diff --git a/src/ast/ast_util.h b/src/ast/ast_util.h index 23c2205bb..a45c65d82 100644 --- a/src/ast/ast_util.h +++ b/src/ast/ast_util.h @@ -123,7 +123,7 @@ inline expr_ref mk_or(expr_ref_vector const& args) { return expr_ref(mk_or(args. /** Return a if arg = (not a) - Retur (not arg) otherwise + Return (not arg) otherwise */ expr * mk_not(ast_manager & m, expr * arg); diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index b2614e27d..7195f7179 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -31,7 +31,7 @@ fpa2bv_rewriter_cfg::fpa2bv_rewriter_cfg(ast_manager & m, fpa2bv_converter & c, m_bindings(m) { updt_params(p); - // We need to make sure that the mananger has the BV plugin loaded. + // We need to make sure that the manager has the BV plugin loaded. symbol s_bv("bv"); if (!m_manager.has_plugin(s_bv)) m_manager.register_plugin(s_bv, alloc(bv_decl_plugin)); diff --git a/src/ast/func_decl_dependencies.h b/src/ast/func_decl_dependencies.h index b813dc31f..9bc0be22d 100644 --- a/src/ast/func_decl_dependencies.h +++ b/src/ast/func_decl_dependencies.h @@ -58,7 +58,7 @@ public: void reset(); /** - \brief Create a dependecy set. + \brief Create a dependency set. This set should be populated using #collect_func_decls. After populating the set, it must be used as an argument for the #insert method. diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index ee1b77545..c91f19df8 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -263,7 +263,7 @@ bool quasi_macros::find_macros(unsigned n, expr * const * exprs) { m_occurrences.reset(); - // Find out how many non-ground appearences for each uninterpreted function there are + // Find out how many non-ground appearances for each uninterpreted function there are for (unsigned i = 0 ; i < n ; i++) find_occurrences(exprs[i]); @@ -301,7 +301,7 @@ bool quasi_macros::find_macros(unsigned n, justified_expr const * exprs) { m_occurrences.reset(); - // Find out how many non-ground appearences for each uninterpreted function there are + // Find out how many non-ground appearances for each uninterpreted function there are for ( unsigned i = 0 ; i < n ; i++ ) find_occurrences(exprs[i].get_fml()); diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index f6c8788d0..cf3c8bc31 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -687,7 +687,7 @@ bool pattern_inference_cfg::reduce_quantifier( mk_patterns(result2->get_num_decls(), result2->get_expr(), 0, nullptr, new_patterns); if (!new_patterns.empty()) { if (m_params.m_pi_warnings) { - warning_msg("pulled nested quantifier to be able to find an useable pattern (quantifier id: %s)", q->get_qid().str().c_str()); + warning_msg("pulled nested quantifier to be able to find an usable pattern (quantifier id: %s)", q->get_qid().str().c_str()); } new_q = m.update_quantifier(result2, new_patterns.size(), (expr**) new_patterns.c_ptr(), result2->get_expr()); if (m.proofs_enabled()) { diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index c81c7385a..81226b010 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2679,7 +2679,7 @@ br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resu } const unsigned sz = m_util.get_bv_size(rhs); - if (sz == 1) { // detect (lhs = N) ? C : D, where N, C, D are 1 bit numberals + if (sz == 1) { // detect (lhs = N) ? C : D, where N, C, D are 1 bit numerals numeral rhs_n, e_n, t_n; unsigned rhs_sz, e_sz, t_sz; if (is_numeral(rhs, rhs_n, rhs_sz) diff --git a/src/ast/rewriter/datatype_rewriter.cpp b/src/ast/rewriter/datatype_rewriter.cpp index 194668b9c..4d688e682 100644 --- a/src/ast/rewriter/datatype_rewriter.cpp +++ b/src/ast/rewriter/datatype_rewriter.cpp @@ -124,7 +124,7 @@ br_status datatype_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & resul // (= (+ c5 a5) b5) <<< NOT SIMPLIFIED WITH RESPECT TO ARITHMETIC // (= (cons a6 nil) (cons b6 nil))) <<< NOT SIMPLIFIED WITH RESPECT TO DATATYPE theory // - // Note that asserted_formulas::reduce() applied the simplier many times. + // Note that asserted_formulas::reduce() applied the simplifier many times. // After the first simplification step we had: // (= a1 b1) // (= (cons a2 (cons a3 (cons (+ a4 1) (cons (+ a5 c5) (cons a6 nil)))))) diff --git a/src/ast/rewriter/der.h b/src/ast/rewriter/der.h index 47e57c4fb..4dcf1e537 100644 --- a/src/ast/rewriter/der.h +++ b/src/ast/rewriter/der.h @@ -108,7 +108,7 @@ Revision History: apply var_subst using m_map to this child, and store the result in a new children array Create a new OR (new body of the quantifier) using the new children Then, we create a new quantifier using this new body, and use the function elim_unused_vars to - eliminate the ununsed variables. + eliminate the unused variables. Remark: let us implement the new version inside the class der. Use #if 0 ... #endif to comment the old version. diff --git a/src/ast/rewriter/push_app_ite.h b/src/ast/rewriter/push_app_ite.h index 8f737ea4d..a04cb6fbc 100644 --- a/src/ast/rewriter/push_app_ite.h +++ b/src/ast/rewriter/push_app_ite.h @@ -41,7 +41,7 @@ struct push_app_ite_cfg : public default_rewriter_cfg { \brief Variation of push_app_ite that applies the transformation on nonground terms only. \remark This functor uses the app::is_ground method. This method is not - completly precise, for instance, any term containing a quantifier is marked as non ground. + completely precise, for instance, any term containing a quantifier is marked as non ground. */ class ng_push_app_ite_cfg : public push_app_ite_cfg { protected: diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index cf0fd5111..a89e76edb 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -85,7 +85,7 @@ ATOMIC_CMD(get_user_tactics_cmd, "get-user-tactics", "display tactics defined us void help_tactic(cmd_context & ctx) { std::ostringstream buf; buf << "combinators:\n"; - buf << "- (and-then +) executes the given tactics sequencially.\n"; + buf << "- (and-then +) executes the given tactics sequentially.\n"; buf << "- (or-else +) tries the given tactics in sequence until one of them succeeds (i.e., the first that doesn't fail).\n"; buf << "- (par-or +) executes the given tactics in parallel until one of them succeeds (i.e., the first that doesn't fail).\n"; buf << "- (par-then ) executes tactic1 and then tactic2 to every subgoal produced by tactic1. All subgoals are processed in parallel.\n"; diff --git a/src/math/euclid/euclidean_solver.cpp b/src/math/euclid/euclidean_solver.cpp index 70b424375..4b65ab6ea 100644 --- a/src/math/euclid/euclidean_solver.cpp +++ b/src/math/euclid/euclidean_solver.cpp @@ -690,7 +690,7 @@ struct euclidean_solver::imp { m().del(eq.m_as[j]); eq.m_as.shrink(new_sz); eq.m_xs.shrink(new_sz); - // ajust c + // adjust c mpz new_c; decompose(m_next_pos_a, m_next_a, eq.m_c, new_c, eq.m_c); // create auxiliary equation diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index 528c10537..17360f35b 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -948,7 +948,7 @@ namespace algebraic_numbers { // zero is a root of p, and r_i is an isolating interval containing zero, // then c is zero reset(c); - TRACE("algebraic", tout << "reseting\nresult: "; display_root(tout, c); tout << "\n";); + TRACE("algebraic", tout << "resetting\nresult: "; display_root(tout, c); tout << "\n";); return; } int zV = upm().sign_variations_at_zero(seq); @@ -1728,7 +1728,7 @@ namespace algebraic_numbers { COMPARE_INTERVAL(); // if cell_a and cell_b, contain the same polynomial, - // and the intervals are overlaping, then they are + // and the intervals are overlapping, then they are // the same root. if (compare_p(cell_a, cell_b)) { m_compare_poly_eq++; @@ -1825,7 +1825,7 @@ namespace algebraic_numbers { // Here is an unexplored option for comparing numbers. // - // The isolating intervals of a and b are still overlaping + // The isolating intervals of a and b are still overlapping // Then we compute // r(x) = Resultant(x - y1 + y2, p1(y1), p2(y2)) // where p1(y1) and p2(y2) are the polynomials defining a and b. diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index 00a4d0593..aec901f61 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -4052,7 +4052,7 @@ namespace polynomial { // select a new random value in GF(p) that is not in vals, and store it in r void peek_fresh(scoped_numeral_vector const & vals, unsigned p, scoped_numeral & r) { - SASSERT(vals.size() < p); // otherwise we cant keep the fresh value + SASSERT(vals.size() < p); // otherwise we can't keep the fresh value unsigned sz = vals.size(); while (true) { m().set(r, rand() % p); @@ -4149,7 +4149,7 @@ namespace polynomial { TRACE("mgcd_detail", tout << "counter: " << counter << "\nidx: " << idx << "\nq: " << q << "\ndeg_q: " << deg_q << "\nmin_deg_q: " << min_deg_q << "\nnext_x: x" << vars[idx+1] << "\nmax_var(q): " << q_var << "\n";); if (deg_q < min_deg_q) { - TRACE("mgcd_detail", tout << "reseting...\n";); + TRACE("mgcd_detail", tout << "resetting...\n";); counter = 0; min_deg_q = deg_q; // start from scratch diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index 374a51084..169ee8273 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -131,12 +131,12 @@ namespace polynomial { ~factors(); /** - \brief Numer of distinct factors (not counting multiplicities). + \brief Number of distinct factors (not counting multiplicities). */ unsigned distinct_factors() const { return m_factors.size(); } /** - \brief Numer of distinct factors (counting multiplicities). + \brief Number of distinct factors (counting multiplicities). */ unsigned total_factors() const { return m_total_factors; } diff --git a/src/math/polynomial/upolynomial.cpp b/src/math/polynomial/upolynomial.cpp index cc2442981..39bdb6812 100644 --- a/src/math/polynomial/upolynomial.cpp +++ b/src/math/polynomial/upolynomial.cpp @@ -362,7 +362,7 @@ namespace upolynomial { set_size(sz-1, buffer); } - // Divide coeffients of p by their GCD + // Divide coefficients of p by their GCD void core_manager::normalize(unsigned sz, numeral * p) { if (sz == 0) return; @@ -395,7 +395,7 @@ namespace upolynomial { } } - // Divide coeffients of p by their GCD + // Divide coefficients of p by their GCD void core_manager::normalize(numeral_vector & p) { normalize(p.size(), p.c_ptr()); } @@ -568,7 +568,7 @@ namespace upolynomial { SASSERT(!is_alias(p1, buffer)); SASSERT(!is_alias(p2, buffer)); unsigned d; rem(sz1, p1, sz2, p2, d, buffer); - // We don't ned to flip the sign if d is odd and leading coefficient of p2 is negative + // We don't need to flip the sign if d is odd and leading coefficient of p2 is negative if (d % 2 == 0 || (sz2 > 0 && m().is_pos(p2[sz2-1]))) neg(buffer.size(), buffer.c_ptr()); } @@ -2005,7 +2005,7 @@ namespace upolynomial { continue; bool pos_a_n_k = m().is_pos(a_n_k); if (pos_a_n_k == pos_a_n) - continue; // must have oposite signs + continue; // must have opposite signs unsigned log2_a_n_k = pos_a_n_k ? m().log2(a_n_k) : m().mlog2(a_n_k); if (log2_a_n > log2_a_n_k) continue; @@ -2103,7 +2103,7 @@ namespace upolynomial { frame_stack.pop_back(); } - // Auxiliar method for isolating the roots of p in the interval (0, 1). + // Auxiliary method for isolating the roots of p in the interval (0, 1). // The basic idea is to split the interval in: (0, 1/2) and (1/2, 1). // This is accomplished by analyzing the roots in the interval (0, 1) of the following polynomials. // p1(x) := 2^n * p(x/2) where n = sz-1 @@ -2574,10 +2574,10 @@ namespace upolynomial { We say an interval (a, b) of a polynomial p is ISOLATING if p has only one root in the interval (a, b). - We say an isolating interval (a, b) of a square free polynomial p is REFINEABLE if + We say an isolating interval (a, b) of a square free polynomial p is REFINABLE if sign(p(a)) = -sign(p(b)) - Not every isolating interval (a, b) of a square free polynomial p is refineable, because + Not every isolating interval (a, b) of a square free polynomial p is refinable, because sign(p(a)) or sign(p(b)) may be zero. Refinable intervals of square free polynomials are useful, because we can increase precision diff --git a/src/math/polynomial/upolynomial.h b/src/math/polynomial/upolynomial.h index 439b4be9f..ad6942ffb 100644 --- a/src/math/polynomial/upolynomial.h +++ b/src/math/polynomial/upolynomial.h @@ -256,12 +256,12 @@ namespace upolynomial { void derivative(numeral_vector const & p, numeral_vector & d_p) { derivative(p.size(), p.c_ptr(), d_p); } /** - \brief Divide coeffients of p by their GCD + \brief Divide coefficients of p by their GCD */ void normalize(unsigned sz, numeral * p); /** - \brief Divide coeffients of p by their GCD + \brief Divide coefficients of p by their GCD */ void normalize(numeral_vector & p); diff --git a/src/math/polynomial/upolynomial_factorization_int.h b/src/math/polynomial/upolynomial_factorization_int.h index e422c15a6..10bfb4d8b 100644 --- a/src/math/polynomial/upolynomial_factorization_int.h +++ b/src/math/polynomial/upolynomial_factorization_int.h @@ -195,7 +195,7 @@ namespace upolynomial { // the index we are currently trying to fix int current_i = m_current_size - 1; - // the value we found as plausable (-1 we didn't find anything) + // the value we found as plausible (-1 we didn't find anything) int current_value = -1; if (remove_current) { diff --git a/src/math/realclosure/mpz_matrix.h b/src/math/realclosure/mpz_matrix.h index 92716ec0d..99ff8bce4 100644 --- a/src/math/realclosure/mpz_matrix.h +++ b/src/math/realclosure/mpz_matrix.h @@ -107,7 +107,7 @@ public: this method will give preference to the row that occurs first. \remark The vector r must have at least A.n() capacity - The numer of linear independent rows is returned. + The number of linear independent rows is returned. Store the new matrix in B. */ diff --git a/src/math/realclosure/rcf_params.pyg b/src/math/realclosure/rcf_params.pyg index 36c13035b..fc15dbe93 100644 --- a/src/math/realclosure/rcf_params.pyg +++ b/src/math/realclosure/rcf_params.pyg @@ -6,5 +6,5 @@ def_module_params('rcf', ('initial_precision', UINT, 24, "a value k that is the initial interval size (as 1/2^k) when creating transcendentals and approximated division"), ('inf_precision', UINT, 24, "a value k that is the initial interval size (i.e., (0, 1/2^l)) used as an approximation for infinitesimal values"), ('max_precision', UINT, 128, "during sign determination we switch from interval arithmetic to complete methods when the interval size is less than 1/2^k, where k is the max_precision"), - ('lazy_algebraic_normalization', BOOL, True, "during sturm-seq and square-free polynomial computations, only normalize algebraic polynomial expressions when the definining polynomial is monic") + ('lazy_algebraic_normalization', BOOL, True, "during sturm-seq and square-free polynomial computations, only normalize algebraic polynomial expressions when the defining polynomial is monic") )) diff --git a/src/math/realclosure/realclosure.cpp b/src/math/realclosure/realclosure.cpp index d41937c29..77623a2df 100644 --- a/src/math/realclosure/realclosure.cpp +++ b/src/math/realclosure/realclosure.cpp @@ -4790,7 +4790,7 @@ namespace realclosure { /** \brief Determine the sign of the new rational function value. - The idea is to keep refinining the interval until interval of v does not contain 0. + The idea is to keep refining the interval until interval of v does not contain 0. After a couple of steps we switch to expensive sign determination procedure. Return false if v is actually zero. @@ -5474,7 +5474,7 @@ namespace realclosure { } else { // Let sdt be alpha->sdt(); - // In pricipal, the signs of the polynomials sdt->qs can be used + // In principal, the signs of the polynomials sdt->qs can be used // to discriminate the roots of new_p. The signs of this polynomials // depend only on alpha, and not on the polynomial used to define alpha // So, in principle, we can reuse m_qs and m_sign_conditions. diff --git a/src/math/simplex/network_flow.h b/src/math/simplex/network_flow.h index d4c7df77f..f4147b16f 100644 --- a/src/math/simplex/network_flow.h +++ b/src/math/simplex/network_flow.h @@ -148,7 +148,7 @@ namespace smt { vector m_potentials; // nodes + 1 |-> initial: +/- 1 // Duals of flows which are convenient to compute dual solutions // become solutions to Dual simplex. - vector m_flows; // edges + nodes |-> assignemnt Basic feasible flows + vector m_flows; // edges + nodes |-> assignment Basic feasible flows svector m_states; unsigned m_step; edge_id m_enter_id; diff --git a/src/math/subpaving/subpaving_t.h b/src/math/subpaving/subpaving_t.h index 02c538828..ec514df8f 100644 --- a/src/math/subpaving/subpaving_t.h +++ b/src/math/subpaving/subpaving_t.h @@ -202,7 +202,7 @@ public: public: node(context_t & s, unsigned id); node(node * parent, unsigned id); - // return unique indentifier. + // return unique identifier. unsigned id() const { return m_id; } bound_array_manager & bm() const { return m_bm; } bound_array & lowers() { return m_lowers; } diff --git a/src/math/subpaving/subpaving_t_def.h b/src/math/subpaving/subpaving_t_def.h index cf93fbfad..b13f41c54 100644 --- a/src/math/subpaving/subpaving_t_def.h +++ b/src/math/subpaving/subpaving_t_def.h @@ -248,7 +248,7 @@ public: /** - \brief Auxiliary static method used to diplay a bound specified by (x, k, lower, open). + \brief Auxiliary static method used to display a bound specified by (x, k, lower, open). */ template void context_t::display(std::ostream & out, numeral_manager & nm, display_var_proc const & proc, var x, numeral & k, bool lower, bool open) { diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 23926c3d1..a14ef163f 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -615,7 +615,7 @@ namespace datalog { void ensure_engine(); - // auxilary functions for SMT2 pretty-printer. + // auxiliary functions for SMT2 pretty-printer. void declare_vars(expr_ref_vector& rules, mk_fresh_name& mk_fresh, std::ostream& out); //undefined and private copy constructor and operator= diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index 7e85199cf..45b75c254 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -110,7 +110,7 @@ namespace datalog { /** \brief Manager for the \c rule class - \remark \c rule_manager objects are interchangable as long as they + \remark \c rule_manager objects are interchangeable as long as they contain the same \c ast_manager object. */ class rule_manager diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index c6e214f79..7e38b9e9f 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -97,7 +97,7 @@ namespace datalog { \brief Auxiliary function used to create a tail based on \c pred for a new rule. The variables in \c pred are re-assigned using \c next_idx and \c varidx2var. A variable is considered non-local to the rule if it is in the set \c non_local_vars. - Non-local variables are coppied to new_rule_args, and their sorts to \c new_rule_domain. + Non-local variables are copied to new_rule_args, and their sorts to \c new_rule_domain. The new predicate is stored in \c new_pred. */ void mk_new_rule_tail(ast_manager & m, app * pred, diff --git a/src/muz/base/fp_params.pyg b/src/muz/base/fp_params.pyg index 18eb85662..325ecaaa6 100644 --- a/src/muz/base/fp_params.pyg +++ b/src/muz/base/fp_params.pyg @@ -143,8 +143,8 @@ def_module_params('fp', ('spacer.native_mbp', BOOL, True, "Use native mbp of Z3"), ('spacer.eq_prop', BOOL, True, "Enable equality and bound propagation in arithmetic"), ('spacer.weak_abs', BOOL, True, "Weak abstraction"), - ('spacer.restarts', BOOL, False, "Enable reseting obligation queue"), - ('spacer.restart_initial_threshold', UINT, 10, "Intial threshold for restarts"), + ('spacer.restarts', BOOL, False, "Enable resetting obligation queue"), + ('spacer.restart_initial_threshold', UINT, 10, "Initial threshold for restarts"), ('spacer.random_seed', UINT, 0, "Random seed to be used by SMT solver"), ('spacer.mbqi', BOOL, True, 'Enable mbqi'), diff --git a/src/muz/base/hnf.h b/src/muz/base/hnf.h index 330dfab70..70f803975 100644 --- a/src/muz/base/hnf.h +++ b/src/muz/base/hnf.h @@ -11,7 +11,7 @@ Copyright (c) 2015 Microsoft Corporation Abstract: - Horn normal form convertion. + Horn normal form conversion. Author: diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index a4fe5f0fa..d3460738c 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -332,7 +332,7 @@ namespace datalog { void internalize() { - // populate maps (should be bit-sets) of decendants. + // populate maps (should be bit-sets) of descendants. if (m_internalized) { return; } diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index a23d654b0..1cc85e6cd 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -120,7 +120,7 @@ public: This operation invalidates the line previously retrieved. - This operatio can be called only if we are not at the end of file. + This operation can be called only if we are not at the end of file. User is free to modify the content of the returned array until the terminating NULL character. */ @@ -876,7 +876,7 @@ protected: /** \brief Parse predicate arguments. If \c f==0, they are arguments of a predicate declaration. - If parsing a declaration, argumens names are pushed to the \c arg_names vector. + If parsing a declaration, argument names are pushed to the \c arg_names vector. */ dtoken parse_args(dtoken tok, func_decl* f, expr_ref_vector& args, svector & arg_names) { if (tok != TK_LP) { diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index 4d202f2a2..decf499a2 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -295,7 +295,7 @@ namespace datalog { Precondition: &orig.get_plugin()==this */ virtual base_object * mk_empty(const signature & s, family_id kind) { - SASSERT(kind==get_kind()); //if plugin uses multiple kinds, this function needs to be overriden + SASSERT(kind==get_kind()); //if plugin uses multiple kinds, this function needs to be overridden return mk_empty(s); } diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index fb80a2105..0b1fbc840 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -1319,7 +1319,7 @@ namespace datalog { if(!m_table_cond_columns.empty()) { //We will keep the table variables that appear in the condition together - //with the index column and then iterate throught the tuples, evaluating + //with the index column and then iterate through the tuples, evaluating //the rest of the condition on the inner relations. unsigned_vector removed_cols; unsigned table_data_col_cnt = r.m_table_sig.size()-1; diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index f7d1665d2..2b76d99f7 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -640,7 +640,7 @@ namespace datalog { reg_idx m_src; reg_idx m_tgt; reg_idx m_delta; - bool m_widen; //if true, widening is performed intead of an union + bool m_widen; //if true, widening is performed instead of an union public: instr_union(reg_idx src, reg_idx tgt, reg_idx delta, bool widen) : m_src(src), m_tgt(tgt), m_delta(delta), m_widen(widen) {} diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index bd7b9ae8c..5fb468ef5 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -253,7 +253,7 @@ namespace datalog { \brief Return functor that transforms a table into one that lacks columns listed in \c removed_cols array. - The \c removed_cols cotains columns of table \c t in strictly ascending order. + The \c removed_cols contains columns of table \c t in strictly ascending order. */ relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, const unsigned * removed_cols); @@ -420,7 +420,7 @@ namespace datalog { \brief Return functor that transforms a table into one that lacks columns listed in \c removed_cols array. - The \c removed_cols cotains columns of table \c t in strictly ascending order. + The \c removed_cols contains columns of table \c t in strictly ascending order. If a project operation removes a non-functional column, all functional columns become non-functional (so that none of the values in functional columns are lost) diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp index bb48211c7..a51fbf3b1 100644 --- a/src/muz/rel/dl_sparse_table.cpp +++ b/src/muz/rel/dl_sparse_table.cpp @@ -568,7 +568,7 @@ namespace datalog { } /** - In this function we modify the content of table functional columns without reseting indexes. + In this function we modify the content of table functional columns without resetting indexes. This is ok as long as we do not allow indexing on functional columns. */ void sparse_table::ensure_fact(const table_fact & f) { diff --git a/src/muz/rel/rel_context.h b/src/muz/rel/rel_context.h index 0a31c4e9f..dbcc42248 100644 --- a/src/muz/rel/rel_context.h +++ b/src/muz/rel/rel_context.h @@ -85,7 +85,7 @@ namespace datalog { /** \brief Restrict the set of used predicates to \c res. - The function deallocates unsused relations, it does not deal with rules. + The function deallocates unused relations, it does not deal with rules. */ void restrict_predicates(func_decl_set const& predicates) override; diff --git a/src/muz/spacer/spacer_farkas_learner.cpp b/src/muz/spacer/spacer_farkas_learner.cpp index 291226b55..b8d8324fb 100644 --- a/src/muz/spacer/spacer_farkas_learner.cpp +++ b/src/muz/spacer/spacer_farkas_learner.cpp @@ -7,8 +7,8 @@ Module Name: Abstract: - Proviced abstract interface and some inplementations of algorithms - for strenghtning lemmas + Provides abstract interface and some implementations of algorithms + for strenghtening lemmas Author: @@ -161,7 +161,7 @@ bool farkas_learner::is_pure_expr(func_decl_set const& symbs, expr* e, ast_manag in a clausal version. NB: the routine is not interpolating, though an interpolating variant would - be preferrable because then we can also use it for model propagation. + be preferable because then we can also use it for model propagation. We collect the unit derivable nodes from bs. These are the weakenings of bs, besides the diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp index f3307a596..63b204736 100644 --- a/src/muz/spacer/spacer_quant_generalizer.cpp +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -186,7 +186,7 @@ void lemma_quantifier_generalizer::find_candidates(expr *e, std::sort(candidates.c_ptr(), candidates.c_ptr() + candidates.size(), index_lt_proc(m)); - // keep actual select indecies in the order found at the back of + // keep actual select indices in the order found at the back of // candidate list. There is no particular reason for this order candidates.append(extra); } @@ -199,24 +199,24 @@ bool lemma_quantifier_generalizer::match_sk_idx(expr *e, app_ref_vector const &z contains_app has_zk(m, zks.get(0)); if (!contains_selects(e, m)) return false; - app_ref_vector indicies(m); - get_select_indices(e, indicies); - if (indicies.size() > 2) return false; + app_ref_vector indices(m); + get_select_indices(e, indices); + if (indices.size() > 2) return false; unsigned i=0; - if (indicies.size() == 1) { - if (!has_zk(indicies.get(0))) return false; + if (indices.size() == 1) { + if (!has_zk(indices.get(0))) return false; } else { - if (has_zk(indicies.get(0)) && !has_zk(indicies.get(1))) + if (has_zk(indices.get(0)) && !has_zk(indices.get(1))) i = 0; - else if (!has_zk(indicies.get(0)) && has_zk(indicies.get(1))) + else if (!has_zk(indices.get(0)) && has_zk(indices.get(1))) i = 1; - else if (!has_zk(indicies.get(0)) && !has_zk(indicies.get(1))) + else if (!has_zk(indices.get(0)) && !has_zk(indices.get(1))) return false; } - idx = indicies.get(i); + idx = indices.get(i); sk = zks.get(0); return true; } diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index aeb509c2e..77e88fb32 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -124,7 +124,7 @@ namespace spacer { * We can rewrite (E2) to rewrite (E1) to * (BP*Fark(BP)) => (neg(A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D))) (E3) * and since we can derive (A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D)) from - * A, BNP and D, we also know that it is inconsisent. Therefore + * A, BNP and D, we also know that it is inconsistent. Therefore * neg(A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D)) is a solution. * * Finally we also need the following workaround: diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index b5be996dc..3b8fd2ee0 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -1097,7 +1097,7 @@ namespace tb { m_S1.apply(2, delta, expr_offset(src.get_constraint(), 1), tmp2); constraint = m.mk_and(tmp, tmp2); - // perform trival quantifier-elimination: + // perform trivial quantifier-elimination: uint_set index_set; expr_free_vars fv; fv(head); diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index 058d9dca8..0a183b923 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -280,7 +280,7 @@ namespace datalog { } } - // model convertion: identity function. + // model conversion: identity function. if (instantiated) { result->inherit_predicates(source); diff --git a/src/muz/transforms/dl_mk_subsumption_checker.cpp b/src/muz/transforms/dl_mk_subsumption_checker.cpp index da41b4ba4..c970aedeb 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.cpp +++ b/src/muz/transforms/dl_mk_subsumption_checker.cpp @@ -45,7 +45,7 @@ namespace datalog { unsigned pt_len = r->get_positive_tail_size(); if(pt_len != r->get_uninterpreted_tail_size()) { - // we dont' expect rules with negative tails to be total + // we don't expect rules with negative tails to be total return false; } @@ -97,7 +97,7 @@ namespace datalog { void mk_subsumption_checker::scan_for_total_rules(const rule_set & rules) { bool new_discovered; //we cycle through the rules until we keep discovering new total relations - //(discovering a total relation migh reveal other total relations) + //(discovering a total relation might reveal other total relations) do { new_discovered = false; rule_set::iterator rend = rules.end(); diff --git a/src/nlsat/nlsat_evaluator.cpp b/src/nlsat/nlsat_evaluator.cpp index a93c4fb3e..e04b95a40 100644 --- a/src/nlsat/nlsat_evaluator.cpp +++ b/src/nlsat/nlsat_evaluator.cpp @@ -377,7 +377,7 @@ namespace nlsat { } /** - \brief Return the sign of the polynomial in the current interpration. + \brief Return the sign of the polynomial in the current interpretation. \pre All variables of p are assigned in the current interpretation. */ @@ -469,7 +469,7 @@ namespace nlsat { } } - // Evalute the sign of p1^e1*...*pn^en (of atom a) in cell c of table t. + // Evaluate the sign of p1^e1*...*pn^en (of atom a) in cell c of table t. int sign_at(ineq_atom * a, sign_table const & t, unsigned c) const { int sign = 1; unsigned num_ps = a->size(); @@ -556,7 +556,7 @@ namespace nlsat { result = m_ism.mk(true, true, dummy, true, true, dummy, jst); } else { - // save -oo as begining of infeasible interval + // save -oo as beginning of infeasible interval prev_open = true; prev_inf = true; prev_root_id = UINT_MAX; diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 58b16717d..0662cacb5 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -1987,7 +1987,7 @@ namespace smt2 { if (expr_stack().size() == fr->m_expr_spos) { if (!ignore_bad_patterns()) throw parser_exception("invalid empty pattern"); - // ingoring empty pattern + // ignoring empty pattern expr_stack().shrink(fr->m_expr_spos); } else { @@ -2698,7 +2698,7 @@ namespace smt2 { next(); } unsigned spos = sort_stack().size(); - parse_sorts("Invalid function name. Expecting sort list startig with '(' to disambiguate function name"); + parse_sorts("Invalid function name. Expecting sort list starting with '(' to disambiguate function name"); unsigned domain_size = sort_stack().size() - spos; parse_sort("Invalid function name"); func_decl * d = m_ctx.find_func_decl(id, indices.size(), indices.c_ptr(), domain_size, sort_stack().c_ptr() + spos, sort_stack().back()); diff --git a/src/qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp index f8c519285..a09c4046e 100644 --- a/src/qe/qe_arith_plugin.cpp +++ b/src/qe/qe_arith_plugin.cpp @@ -316,7 +316,7 @@ namespace qe { void mk_bound_aux(rational const& a, expr* t, rational const& b, expr* s, expr_ref& result) { SASSERT(a.is_neg() == b.is_neg()); expr_ref tt(t, m), ss(s, m), e(m); - // hack to fix wierd gcc compilation error + // hack to fix weird gcc compilation error rational abs_a(a); rational abs_b(b); if (abs_a.is_neg()) abs_a.neg(); diff --git a/src/qe/qe_datatype_plugin.cpp b/src/qe/qe_datatype_plugin.cpp index 81a402ba4..25332d164 100644 --- a/src/qe/qe_datatype_plugin.cpp +++ b/src/qe/qe_datatype_plugin.cpp @@ -46,7 +46,7 @@ Copyright (c) 2015 Microsoft Corporation // -> \/_i R_C(t_i) & phi[t_i/x] \/ phi[false, true] // // Justification: -// - We will asume that each of t_i, s_j are constructor terms. +// - We will assume that each of t_i, s_j are constructor terms. // - We can assume that x \notin t_i, x \notin s_j, or otherwise use simplification. // - We can assume that x occurs only in equalities or disequalities, or the recognizer, since // otherwise, we could simplify equalities, or QE does not apply. diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index d900bff5d..3226f7554 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -1816,7 +1816,7 @@ namespace fm { } // An integer variable x may be eliminated, if - // 1- All variables in the contraints it occur are integer. + // 1- All variables in the constraints it occur are integer. // 2- The coefficient of x in all lower bounds (or all upper bounds) is unit. bool can_eliminate(var x) const { if (!is_int(x)) diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index fdc4c3c6a..1cc2be0cb 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -47,7 +47,7 @@ namespace qe { /** * \brief Utility that works modulo a background state. * - vars - * variables to preferrably project onto (other variables would require quantification to fit interpolation signature) + * variables to preferably project onto (other variables would require quantification to fit interpolation signature) * - lits * set of literals to check satisfiability with respect to. * - mdl diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 97b044f5b..b5de20368 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -669,7 +669,7 @@ namespace qe { // Here we could also walk equivalence classes that // contain interpreted values by sort and extract - // disequalities bewteen non-unique value + // disequalities between non-unique value // representatives. these disequalities are implied // and can be mined using other means, such as theory // aware core minimization diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 4f06c2e98..01d627115 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2519,7 +2519,7 @@ namespace sat { * ~lit does not occur in clauses * ~lit is only in one constraint use list * lit == C - * -> ignore assignemnts to ~lit for C + * -> ignore assignments to ~lit for C * * ~lit does not occur in clauses * lit is only in one constraint use list diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 5fd69a740..baf072419 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -118,7 +118,7 @@ namespace sat { local_search_config m_config; // objective function: maximize - svector ob_constraint; // the objective function *constraint*, sorted in decending order + svector ob_constraint; // the objective function *constraint*, sorted in descending order // information about the variable int_vector coefficient_in_ob_constraint; // var! initialized to be 0 @@ -169,8 +169,8 @@ namespace sat { // unsat constraint stack bool m_is_unsat; - unsigned_vector m_unsat_stack; // store all the unsat constraits - unsigned_vector m_index_in_unsat_stack; // which position is a contraint in the unsat_stack + unsigned_vector m_unsat_stack; // store all the unsat constraints + unsigned_vector m_index_in_unsat_stack; // which position is a constraint in the unsat_stack // configuration changed decreasing variables (score>0 and conf_change==true) bool_var_vector m_goodvar_stack; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 72792b182..389cdb19b 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1220,7 +1220,7 @@ namespace sat { double operator()(literal l) override { return lh.literal_occs(l); } }; - // Ternary clause managagement: + // Ternary clause management: void lookahead::add_ternary(literal u, literal v, literal w) { SASSERT(u != w && u != v && v != w && ~u != w && ~u != v && ~w != v); @@ -1377,7 +1377,7 @@ namespace sat { } - // new n-ary clause managment + // new n-ary clause management void lookahead::add_clause(clause const& c) { SASSERT(c.size() > 3); @@ -1636,7 +1636,7 @@ namespace sat { } // Sum_{ clause C that contains ~l } 1 - // FIXME: counts occurences of ~l; misleading + // FIXME: counts occurrences of ~l; misleading double lookahead::literal_occs(literal l) { double result = m_binary[l.index()].size(); result += literal_big_occs(l); @@ -1644,7 +1644,7 @@ namespace sat { } // Sum_{ clause C that contains ~l such that |C| > 2} 1 - // FIXME: counts occurences of ~l; misleading + // FIXME: counts occurrences of ~l; misleading double lookahead::literal_big_occs(literal l) { double result = m_nary_count[(~l).index()]; result += m_ternary_count[(~l).index()]; @@ -1718,7 +1718,7 @@ namespace sat { } // VERIFY(!missed_propagation()); if (unsat) { - TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); + TRACE("sat", tout << "backtracking and setting " << ~lit << "\n";); lookahead_backtrack(); assign(~lit); propagate(); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index c2282e779..046750832 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -471,7 +471,7 @@ namespace sat { watch_list& get_wlist(literal l) { return m_watches[l.index()]; } watch_list const& get_wlist(literal l) const { return m_watches[l.index()]; } - // new clause managment: + // new clause management: void add_ternary(literal u, literal v, literal w); void propagate_ternary(literal l); lbool propagate_ternary(literal l1, literal l2); diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index c6e29f64c..33cb02a87 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -232,7 +232,7 @@ namespace sat { } if (m_consumer_ready && (m_num_clauses == 0 || (m_num_clauses > s.m_clauses.size()))) { // time to update local search with new clauses. - // there could be multiple local search engines runing at the same time. + // there could be multiple local search engines running at the same time. IF_VERBOSE(1, verbose_stream() << "(sat-parallel refresh :from " << m_num_clauses << " :to " << s.m_clauses.size() << ")\n";); m_solver_copy = alloc(solver, s.m_params, s.rlimit()); m_solver_copy->copy(s); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index d19cd14d4..21d264af5 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -984,7 +984,7 @@ namespace sat { queue m_queue; literal_vector m_covered_clause; // covered clause - svector m_covered_antecedent; // explainations for literals in covered clause + svector m_covered_antecedent; // explanations for literals in covered clause literal_vector m_intersection; // current resolution intersection literal_vector m_tautology; // literals that are used in blocking tautology literal_vector m_new_intersection; diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 3787b5894..990b87b10 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -74,7 +74,7 @@ namespace sat { // config bool m_abce; // block clauses using asymmetric added literals bool m_cce; // covered clause elimination - bool m_acce; // cce with asymetric literal addition + bool m_acce; // cce with asymmetric literal addition bool m_bca; // blocked (binary) clause addition. unsigned m_bce_delay; bool m_bce; // blocked clause elimination diff --git a/src/smt/arith_eq_solver.cpp b/src/smt/arith_eq_solver.cpp index 883255b8a..4b1c6e4a6 100644 --- a/src/smt/arith_eq_solver.cpp +++ b/src/smt/arith_eq_solver.cpp @@ -492,7 +492,7 @@ bool arith_eq_solver::solve_integer_equations_omega( return false; } else if (r[index].is_zero()) { - // Row is trival + // Row is trivial rows_solved.pop_back(); continue; } diff --git a/src/smt/params/qi_params.h b/src/smt/params/qi_params.h index 0f6c03f5b..d1434103b 100644 --- a/src/smt/params/qi_params.h +++ b/src/smt/params/qi_params.h @@ -64,14 +64,14 @@ struct qi_params { Enodes in the input problem have generation 0. Some combinations of m_qi_cost and m_qi_new_gen will prevent Z3 from breaking matching loops. - For example, the "Weight 0" peformace bug was triggered by the following combination: + For example, the "Weight 0" performance bug was triggered by the following combination: - m_qi_cost: (+ weight generation) - m_qi_new_gen: cost If a quantifier has weight 0, then the cost of instantiating it with a term in the input problem has cost 0. The new enodes created during the instantiation will be tagged with generation = const = 0. So, every enode will have generation 0, and consequently every quantifier instantiation will have cost 0. - Although dangerous, this feature was requested by the Boogie team. In their case, the patterns are carefully constructred, + Although dangerous, this feature was requested by the Boogie team. In their case, the patterns are carefully constructed, and there are no matching loops. Moreover, the tag some quantifiers with weight 0 to instruct Z3 to never block their instances. An example is the select-store axiom. They need this feature to be able to analyze code that contains very long execution paths. diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 76e9f03b1..b8b561e37 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -12,7 +12,7 @@ def_module_params(module_name='smt', ('ematching', BOOL, True, 'E-Matching based quantifier instantiation'), ('phase_selection', UINT, 3, 'phase selection heuristic: 0 - always false, 1 - always true, 2 - phase caching, 3 - phase caching conservative, 4 - phase caching conservative 2, 5 - random, 6 - number of occurrences'), ('restart_strategy', UINT, 1, '0 - geometric, 1 - inner-outer-geometric, 2 - luby, 3 - fixed, 4 - arithmetic'), - ('restart_factor', DOUBLE, 1.1, 'when using geometric (or inner-outer-geometric) progression of restarts, it specifies the constant used to multiply the currect restart threshold'), + ('restart_factor', DOUBLE, 1.1, 'when using geometric (or inner-outer-geometric) progression of restarts, it specifies the constant used to multiply the current restart threshold'), ('case_split', UINT, 1, '0 - case split based on variable activity, 1 - similar to 0, but delay case splits created during the search, 2 - similar to 0, but cache the relevancy, 3 - case split based on relevancy (structural splitting), 4 - case split on relevancy and activity, 5 - case split on relevancy and current goal, 6 - activity-based case split with theory-aware branching activity'), ('delay_units', BOOL, False, 'if true then z3 will not restart when a unit clause is learned'), ('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ignored if delay_units is false'), diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 94868ef6e..d621a9f50 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -175,7 +175,7 @@ namespace smt { } } m_new_entries.reset(); - TRACE("new_entries_bug", tout << "[qi:instatiate]\n";); + TRACE("new_entries_bug", tout << "[qi:instantiate]\n";); } void qi_queue::display_instance_profile(fingerprint * f, quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned proof_id, unsigned generation) { diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index f7bc60051..93c172bf1 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -51,7 +51,7 @@ namespace smt { } /** - \brief Mark all enodes in a 'proof' tree brach starting at n + \brief Mark all enodes in a 'proof' tree branch starting at n n -> ... -> root */ template diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index f275b0ebf..17a7ce3a3 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -518,7 +518,7 @@ namespace smt { // 2. r1 is interpreted but r2 is not. // // The second condition is used to enforce the invariant that if a class contain - // an interepreted enode then the root is also interpreted. + // an interpreted enode then the root is also interpreted. if ((r1->get_class_size() > r2->get_class_size() && !r2->is_interpreted()) || r1->is_interpreted()) { SASSERT(!r2->is_interpreted()); std::swap(n1, n2); @@ -529,7 +529,7 @@ namespace smt { " n1: #" << n1->get_owner_id() << "\n";); // It is necessary to propagate relevancy to other elements of - // the equivalence class. This is nessary to enforce the invariant + // the equivalence class. This is necessary to enforce the invariant // in the field m_parent of the enode class. if (is_relevant(r1)) { // && !m_manager.is_eq(r1->get_owner())) !is_eq HACK // NOTE for !is_eq HACK... the !is_eq HACK does not propagate relevancy when two @@ -4067,7 +4067,7 @@ namespace smt { A literal may have been marked relevant within the scope that gets popped during conflict resolution. In this case, the literal is no longer marked as relevant after the pop. This can cause quantifier instantiation to miss relevant triggers and thereby - cause incmpleteness. + cause incompleteness. */ void context::record_relevancy(unsigned n, literal const* lits) { m_relevant_conflict_literals.reset(); @@ -4281,7 +4281,7 @@ namespace smt { return true; } - // the variabe is shared if the equivalence class of n + // the variable is shared if the equivalence class of n // contains a parent application. theory_var_list * l = n->get_th_var_list(); diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index 61fed786b..74fcbfb45 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -73,7 +73,7 @@ namespace smt { class tmp_enode; /** - \brief Aditional data-structure for implementing congruence closure, + \brief Additional data-structure for implementing congruence closure, equality propagation, and the theory central bus of equalities. */ class enode { diff --git a/src/smt/smt_model_generator.h b/src/smt/smt_model_generator.h index 1f69eb324..a26113a16 100644 --- a/src/smt/smt_model_generator.h +++ b/src/smt/smt_model_generator.h @@ -96,7 +96,7 @@ namespace smt { class model_value_dependency { bool m_fresh; //!< True if the dependency is a new fresh value; union { - enode * m_enode; //!< When m_fresh == false, contains an enode depedency. + enode * m_enode; //!< When m_fresh == false, contains an enode dependency. extra_fresh_value * m_value; //!< When m_fresh == true, contains the sort of the fresh value }; public: diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 9e38fef69..6dcc9448c 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -203,7 +203,7 @@ namespace smt { static void check_no_arithmetic(static_features const & st, char const * logic) { if (st.m_num_arith_ineqs > 0 || st.m_num_arith_terms > 0 || st.m_num_arith_eqs > 0) - throw default_exception("Benchmark constains arithmetic, but specified loging does not support it."); + throw default_exception("Benchmark constains arithmetic, but specified logic does not support it."); } void setup::setup_QF_UF() { @@ -519,7 +519,7 @@ namespace smt { m_params.m_arith_eq2ineq = true; m_params.m_eliminate_term_ite = true; // if (st.m_num_exprs < 5000 && st.m_num_ite_terms < 50) { // safeguard to avoid high memory consumption - // TODO: implement analsysis function to decide where lift ite is too expensive. + // TODO: implement analysis function to decide where lift ite is too expensive. // m_params.m_lift_ite = LI_FULL; // } } diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index b791d890e..f65ffe922 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -68,7 +68,7 @@ namespace smt { public: /** - \brief Return ture if the given enode is attached to a + \brief Return true if the given enode is attached to a variable of the theory. \remark The result is not equivalent to @@ -389,7 +389,7 @@ namespace smt { \brief When an eq atom n is created during the search, the default behavior is to make sure that the n->get_arg(0)->get_id() < n->get_arg(1)->get_id(). This may create some redundant atoms, since some theories/families use different - convetions in their simplifiers. For example, arithmetic always force a numeral + conventions in their simplifiers. For example, arithmetic always force a numeral to be in the right hand side. So, this method should be redefined if the default behavior conflicts with a convention used by the theory/family. */ diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 89737fb42..9561aa089 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1073,7 +1073,7 @@ namespace smt { /** \brief: Create an atom that enforces the inequality v > val The arithmetical expression encoding the inequality suffices - for the theory of aritmetic. + for the theory of arithmetic. */ template expr_ref theory_arith::mk_gt(theory_var v) { @@ -1146,7 +1146,7 @@ namespace smt { template void theory_arith::enable_record_conflict(expr* bound) { m_params.m_arith_bound_prop = BP_NONE; - SASSERT(propagation_mode() == BP_NONE); // bound propagtion rules are not (yet) handled. + SASSERT(propagation_mode() == BP_NONE); // bound propagation rules are not (yet) handled. if (bound) { context& ctx = get_context(); m_bound_watch = ctx.get_bool_var(bound); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index bce029753..3da78e8ee 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -3128,7 +3128,7 @@ namespace smt { // // 1) Handling inequalities: (n1, k1) <= (n2, k2) // - // The only intersting case is n1 < n2 and k1 > k2. + // The only interesting case is n1 < n2 and k1 > k2. // Using the definition of infinitesimal numbers // we have: // n1 + k1 * epsilon <= n2 + k2 - epsilon @@ -3533,7 +3533,7 @@ namespace smt { } /** - \brief reset and retrieve built-in explanation hints for arithmetic lemmmas. + \brief reset and retrieve built-in explanation hints for arithmetic lemmas. */ template diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index c27d3b44a..24e1020fd 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -1337,7 +1337,7 @@ namespace smt { } /** - \brief Diplay a nested form expression + \brief Display a nested form expression */ template void theory_arith::display_nested_form(std::ostream & out, expr * p) { @@ -1682,7 +1682,7 @@ namespace smt { if (!get_manager().int_real_coercions() && is_mixed_real_integer(r)) return true; // giving up... see comment above - TRACE("cross_nested", tout << "cheking problematic row...\n";); + TRACE("cross_nested", tout << "checking problematic row...\n";); rational c = rational::one(); if (is_integer(r)) @@ -1764,7 +1764,7 @@ namespace smt { updated with the fixed variables in m. A variable is only added to dep if it is not already in already_found. - Return null if the monomial was simplied to 0. + Return null if the monomial was simplified to 0. */ template grobner::monomial * theory_arith::mk_gb_monomial(rational const & _coeff, expr * m, grobner & gb, v_dependency * & dep, var_set & already_found) { diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index 3dfba6b1b..369209e49 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -756,7 +756,7 @@ namespace smt { (n_x, k_x) <= (n_y + n_c, k_y + k_c) - The only intersting case is n_x < n_y + n_c and k_x > k_y + k_c. + The only interesting case is n_x < n_y + n_c and k_x > k_y + k_c. Using the definition of infinitesimal numbers we have: diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 24309ba88..4a04fdaaf 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -3225,7 +3225,7 @@ public: theory_var w; if (m_solver->is_term(ti.var())) { //w = m_term_index2theory_var.get(m_solver->adjust_term_index(ti.var()), null_theory_var); - //if (w == null_theory_var) // if extracing expressions directly from nested term + //if (w == null_theory_var) // if extracting expressions directly from nested term lp::lar_term const& term1 = m_solver->get_term(ti.var()); rational coeff2 = coeff * ti.coeff(); term2coeffs(term1, coeffs, coeff2, offset); diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 3a0ee723f..c20683d73 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -107,7 +107,7 @@ namespace smt { struct ineq { unsynch_mpz_manager& m_mpz; // mpz manager. - literal m_lit; // literal repesenting predicate + literal m_lit; // literal representing predicate bool m_is_eq; // is this an = or >=. arg_t m_args[2]; // encode args[0]*coeffs[0]+...+args[n-1]*coeffs[n-1] >= k(); // Watch the first few positions until the sum satisfies: @@ -192,7 +192,7 @@ namespace smt { // If none are available, then perform unit propagation. // class card { - literal m_lit; // literal repesenting predicate + literal m_lit; // literal representing predicate literal_vector m_args; unsigned m_bound; unsigned m_num_propagations; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 093a47146..2fb95e676 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1412,7 +1412,7 @@ bool theory_seq::is_complex(eq const& e) { \brief Decompose ls = rs into Xa = bYc, such that 1. - X != Y - - |b| <= |X| <= |bY| in currrent model + - |b| <= |X| <= |bY| in current model - b is non-empty. 2. X != Y - b is empty diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index ec192cd89..856ba728e 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -5074,7 +5074,7 @@ namespace smt { } } else { // ------------------------------------------------------------------------------------------------ - // subStr doesn't have an eqc contant value + // subStr doesn't have an eqc constant value // however, subStr equals to some concat(arg_1, arg_2, ..., arg_n) // if arg_j is a constant and is not a part of the strConst, it's sure that the contains is false // ** This check is needed here because the "strConst" and "strAst" may not be in a same eqc yet diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 61094c29c..e8fb34815 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -39,7 +39,7 @@ Notes: The object switches to incremental when: - push is used - - assertions are peformed after a check_sat + - assertions are performed after a check_sat - parameter ignore_solver1==false */ class combined_solver : public solver { diff --git a/src/solver/parallel_params.pyg b/src/solver/parallel_params.pyg index 2d58cbb81..cb37138ee 100644 --- a/src/solver/parallel_params.pyg +++ b/src/solver/parallel_params.pyg @@ -9,7 +9,7 @@ def_module_params('parallel', ('conquer.restart.max', UINT, 5, 'maximal number of restarts during conquer phase'), ('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 multipled by simplify.exp ^ depth'), + ('simplify.exp', DOUBLE, 1, 'restart and inprocess max is multiplied by simplify.exp ^ depth'), ('simplify.restart.max', UINT, 5000, 'maximal number of restarts during simplification phase'), ('simplify.inprocess.max', UINT, 2, 'maximal number of inprocessing steps during simplification'), )) diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index fc41f54a4..bd99e4303 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -1231,7 +1231,7 @@ class fm_tactic : public tactic { } // An integer variable x may be eliminated, if - // 1- All variables in the contraints it occur are integer. + // 1- All variables in the constraints it occur are integer. // 2- The coefficient of x in all lower bounds (or all upper bounds) is unit. bool can_eliminate(var x) const { if (!is_int(x)) diff --git a/src/tactic/bv/bvarray2uf_rewriter.cpp b/src/tactic/bv/bvarray2uf_rewriter.cpp index 3ca296eb7..97947c03a 100644 --- a/src/tactic/bv/bvarray2uf_rewriter.cpp +++ b/src/tactic/bv/bvarray2uf_rewriter.cpp @@ -40,7 +40,7 @@ bvarray2uf_rewriter_cfg::bvarray2uf_rewriter_cfg(ast_manager & m, params_ref con m_fmc(nullptr), extra_assertions(m) { updt_params(p); - // We need to make sure that the mananger has the BV and array plugins loaded. + // We need to make sure that the manager has the BV and array plugins loaded. symbol s_bv("bv"); if (!m_manager.has_plugin(s_bv)) m_manager.register_plugin(s_bv, alloc(bv_decl_plugin)); diff --git a/src/tactic/core/cofactor_elim_term_ite.cpp b/src/tactic/core/cofactor_elim_term_ite.cpp index 1b435791c..6afcdee41 100644 --- a/src/tactic/core/cofactor_elim_term_ite.cpp +++ b/src/tactic/core/cofactor_elim_term_ite.cpp @@ -197,7 +197,7 @@ struct cofactor_elim_term_ite::imp { switch (arg->get_kind()) { case AST_VAR: case AST_QUANTIFIER: - // ingore quantifiers + // ignore quantifiers break; case AST_APP: if (to_app(arg)->get_num_args() > 0) { @@ -264,7 +264,7 @@ struct cofactor_elim_term_ite::imp { switch (arg->get_kind()) { case AST_VAR: case AST_QUANTIFIER: - // ingore quantifiers + // ignore quantifiers break; case AST_APP: if (to_app(arg)->get_num_args() > 0) { diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 7f17c8dae..50d606197 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -273,8 +273,8 @@ private: } /** - \brief decompose large sums into smaller sums by intoducing - auxilary variables. + \brief decompose large sums into smaller sums by introducing + auxiliary variables. */ void decompose(goal_ref const& g) { expr_ref fml1(m), fml2(m); diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index 9c5b72830..73432219f 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -31,7 +31,7 @@ Notes: This property holds for both eval, that decides on a fixed value for constants that have no interpretation in m and for 'peval' - (partial eval) that retuns just the constants that are unfixed. + (partial eval) that returns just the constants that are unfixed. (in the model evaluator one can control this behavior using a configuration flag) @@ -48,7 +48,7 @@ Notes: mc(G) & F_s is SAT iff G & F is SAT For a model converter that is a sequence of definitions and removals - of functions we can obtain mc(G) by adding back or expanding definitinos + of functions we can obtain mc(G) by adding back or expanding definitions that are required to interpret G fully in the context of F_s. --*/ diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index 745b0352d..a02c2d327 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -8,7 +8,7 @@ Module Name: Abstract: Tactic for purifying quantifier-free formulas that mix QF_NRA and other theories. - It is designed to allow cooprating between the nlsat solver and other theories + It is designed to allow cooperation between the nlsat solver and other theories in a decoupled way. Let goal be formula F. @@ -446,7 +446,7 @@ private: expr* pred = fresh_preds[i]; if (mdl->eval(pred, tmp)) { polarity_t pol = m_polarities.find(pred); - // if assumptinon literals are used to satisfy NL state, + // if assumption literals are used to satisfy NL state, // we have to assume them when satisfying SMT state if (pol != pol_neg && m.is_false(tmp)) { m_asms.push_back(m.mk_not(pred)); @@ -767,7 +767,7 @@ public: // then annotate subformulas by polarities, // finally extract polynomial inequalities by // creating a place-holder predicate inside the - // original goal and extracing pure nlsat clauses. + // original goal and extracting pure nlsat clauses. r.set_interface_var_mode(); rewrite_goal(r, g); if (!g->unsat_core_enabled()) { diff --git a/src/tactic/sls/sls_engine.cpp b/src/tactic/sls/sls_engine.cpp index f5b5ec1b2..1285e46cf 100644 --- a/src/tactic/sls/sls_engine.cpp +++ b/src/tactic/sls/sls_engine.cpp @@ -182,7 +182,7 @@ bool sls_engine::what_if( // Andreas: Had this idea on my last day. Maybe we could add a noise here similar to the one that worked so well for ucb assertion selection. // r += 0.0001 * m_tracker.get_random_uint(8); - // Andreas: For some reason it is important to use > here instead of >=. Probably related to prefering the LSB. + // Andreas: For some reason it is important to use > here instead of >=. Probably related to preferring the LSB. if (r > best_score) { best_score = r; best_const = fd_inx; diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index a8ad95319..7c410e721 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -36,7 +36,7 @@ Notes: static tactic * mk_qfbv_preamble(ast_manager& m, params_ref const& p) { params_ref solve_eq_p; - // conservative guassian elimination. + // conservative gaussian elimination. solve_eq_p.set_uint("solve_eqs_max_occs", 2); params_ref simp2_p = p; diff --git a/src/test/ast.cpp b/src/test/ast.cpp index 59bdfc8e4..0826306f2 100644 --- a/src/test/ast.cpp +++ b/src/test/ast.cpp @@ -44,7 +44,7 @@ static void tst1() { // ast_ref v3 (m.mk_var(1), m); // ENSURE(v1 != v2); // ENSURE(v1 == v3); -// TRACE("ast", tout << "reseting v1\n";); +// TRACE("ast", tout << "resetting v1\n";); // v1.reset(); // TRACE("ast", tout << "overwriting v3\n";); // v3 = v2; diff --git a/src/test/ddnf.cpp b/src/test/ddnf.cpp index 003e5bdb8..b1bb624a2 100644 --- a/src/test/ddnf.cpp +++ b/src/test/ddnf.cpp @@ -15,7 +15,7 @@ Copyright (c) 2015 Microsoft Corporation #include /* -TBD: count number of nodes, number of operations accross all insertions +TBD: count number of nodes, number of operations across all insertions */ void read_nums(std::istream& is, unsigned & x, unsigned& y) { diff --git a/src/test/fuzzing/expr_delta.h b/src/test/fuzzing/expr_delta.h index d69ed33f1..f59e4c4d5 100644 --- a/src/test/fuzzing/expr_delta.h +++ b/src/test/fuzzing/expr_delta.h @@ -33,7 +33,7 @@ public: // // Create the n'th delta in dfs mode. - // resturn 'true' if a delta was obtained. + // return 'true' if a delta was obtained. // bool delta_dfs(unsigned n, expr_ref_vector& result); diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index ffdbb5af8..192bd46b0 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -117,7 +117,7 @@ void test_matrix(square_sparse_matrix & a) { } void tst1() { - std::cout << "testing the minimial matrix with 1 row and 1 column" << std::endl; + std::cout << "testing the minimal matrix with 1 row and 1 column" << std::endl; square_sparse_matrix m0(1, 1); m0.set(0, 0, 1); // print_matrix(m0); @@ -192,7 +192,7 @@ void tst1() { // print_matrix(m10by9); } -vector allocate_basis_heading(unsigned count) { // the rest of initilization will be handled by lu_QR +vector allocate_basis_heading(unsigned count) { // the rest of initialization will be handled by lu_QR vector basis_heading(count, -1); return basis_heading; } @@ -850,7 +850,7 @@ void fill_uniformly(dense_matrix & m, unsigned dim) { } } -void square_sparse_matrix_with_permutaions_test() { +void square_sparse_matrix_with_permutations_test() { unsigned dim = 4; square_sparse_matrix m(dim, dim); fill_uniformly(m, dim); @@ -1023,7 +1023,7 @@ void test_dense_matrix() { -vector> vector_of_permutaions() { +vector> vector_of_permutations() { vector> ret; { permutation_matrix p0(5); @@ -1058,7 +1058,7 @@ void test_apply_reverse_from_right_to_perm(permutation_matrix & } void test_apply_reverse_from_right() { - auto vec = vector_of_permutaions(); + auto vec = vector_of_permutations(); for (unsigned i = 0; i < vec.size(); i++) { test_apply_reverse_from_right_to_perm(vec[i]); } @@ -1901,17 +1901,17 @@ void setup_args_parser(argument_parser & parser) { parser.add_option_with_after_string_with_help("--density", "the percentage of non-zeroes in the matrix below which it is not dense"); parser.add_option_with_after_string_with_help("--harris_toler", "harris tolerance"); parser.add_option_with_help_string("--test_swaps", "test row swaps with a permutation"); - parser.add_option_with_help_string("--test_perm", "test permutaions"); + parser.add_option_with_help_string("--test_perm", "test permutations"); parser.add_option_with_after_string_with_help("--checklu", "the file name for lu checking"); parser.add_option_with_after_string_with_help("--partial_pivot", "the partial pivot constant, a number somewhere between 10 and 100"); parser.add_option_with_after_string_with_help("--percent_for_enter", "which percent of columns check for entering column"); - parser.add_option_with_help_string("--totalinf", "minimizes the total infeasibility instead of diminishin infeasibility of the rows"); + parser.add_option_with_help_string("--totalinf", "minimizes the total infeasibility instead of diminishing infeasibility of the rows"); parser.add_option_with_after_string_with_help("--rep_frq", "the report frequency, in how many iterations print the cost and other info "); parser.add_option_with_help_string("--smt", "smt file format"); parser.add_option_with_after_string_with_help("--filelist", "the file containing the list of files"); parser.add_option_with_after_string_with_help("--file", "the input file name"); parser.add_option_with_after_string_with_help("--random_seed", "random seed"); - parser.add_option_with_help_string("--bp", "bound propogation"); + parser.add_option_with_help_string("--bp", "bound propagation"); parser.add_option_with_help_string("--min", "will look for the minimum for the given file if --file is used; the default is looking for the max"); parser.add_option_with_help_string("--max", "will look for the maximum for the given file if --file is used; it is the default behavior"); parser.add_option_with_after_string_with_help("--max_iters", "maximum total iterations in a core solver stage"); @@ -1932,7 +1932,7 @@ void setup_args_parser(argument_parser & parser) { parser.add_option_with_help_string("--lar", "test lar_solver"); parser.add_option_with_after_string_with_help("--maxng", "max iterations without progress"); parser.add_option_with_help_string("-tbq", "test binary queue"); - parser.add_option_with_help_string("--randomize_lar", "test randomize funclionality"); + parser.add_option_with_help_string("--randomize_lar", "test randomize functionality"); parser.add_option_with_help_string("--smap", "test stacked_map"); parser.add_option_with_help_string("--term", "simple term test"); parser.add_option_with_help_string("--eti"," run a small evidence test for total infeasibility scenario"); @@ -3722,7 +3722,7 @@ void test_lp_local(int argn, char**argv) { test_init_U(); test_replace_column(); #ifdef Z3DEBUG - square_sparse_matrix_with_permutaions_test(); + square_sparse_matrix_with_permutations_test(); test_dense_matrix(); test_swap_operations(); test_permutations(); diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index 1116c5420..ad982d024 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -7,7 +7,7 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_search& local_search) { char line[16383]; - // for temperally storage + // for temporary storage std::ifstream infile(filename); //if (infile == NULL) //linux @@ -28,7 +28,7 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea sat::literal_vector lits; // process objective function: - // read coefficents + // read coefficients infile >> cur_term; while (cur_term != 0) { coefficients.push_back(cur_term); @@ -43,7 +43,7 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea } if (lits.size() != coefficients.size()) { - std::cout << "Objective function format error. They have different lenghts.\n"; + std::cout << "Objective function format error. They have different lengths.\n"; return false; } diff --git a/src/util/bit_util.cpp b/src/util/bit_util.cpp index a38f42fdd..fdca2dc83 100644 --- a/src/util/bit_util.cpp +++ b/src/util/bit_util.cpp @@ -126,7 +126,7 @@ unsigned ntz(unsigned sz, unsigned const * data) { /** \brief dst <- src - Trucate if src_sz > dst_sz. + Truncate if src_sz > dst_sz. Fill range [src_sz, dst_sz) of dst with zeros if dst_sz > src_sz. */ void copy(unsigned src_sz, unsigned const * src, diff --git a/src/util/bit_util.h b/src/util/bit_util.h index 5729e8eed..7a0923400 100644 --- a/src/util/bit_util.h +++ b/src/util/bit_util.h @@ -48,7 +48,7 @@ unsigned ntz(unsigned sz, unsigned const * data); /** \brief dst <- src - Trucate if src_sz > dst_sz. + Truncate if src_sz > dst_sz. Fill range [src_sz, dst_sz) of dst with zeros if dst_sz > src_sz. */ void copy(unsigned src_sz, unsigned const * src, unsigned dst_sz, unsigned * dst); @@ -87,7 +87,7 @@ void shr(unsigned sz, unsigned const * src, unsigned k, unsigned * dst); \brief dst <- src >> k Store in dst the result of shifting src k bits to the right. - Trucate if src_sz > dst_sz. + Truncate if src_sz > dst_sz. Fill range [src_sz, dst_sz) of dst with zeros if dst_sz > src_sz. \pre src_sz != 0 diff --git a/src/util/list.h b/src/util/list.h index 075d5a0e1..82ca73308 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -68,7 +68,7 @@ unsigned length(list * l) { } /** - \brief Non destructive apppend operation. The new nodes are allocated + \brief Non destructive append operation. The new nodes are allocated using the given region allocator. */ template diff --git a/src/util/lp/binary_heap_priority_queue_def.h b/src/util/lp/binary_heap_priority_queue_def.h index 232959c83..d0a08c27d 100644 --- a/src/util/lp/binary_heap_priority_queue_def.h +++ b/src/util/lp/binary_heap_priority_queue_def.h @@ -76,7 +76,7 @@ template void binary_heap_priority_queue::remove(unsigned o) { put_at(o_in_heap, m_heap[m_heap_size--]); if (m_priorities[m_heap[o_in_heap]] > priority_of_o) { fix_heap_under(o_in_heap); - } else { // we need to propogate the m_heap[o_in_heap] up + } else { // we need to propagate the m_heap[o_in_heap] up unsigned i = o_in_heap; while (i > 1) { unsigned ip = i >> 1; diff --git a/src/util/lp/bound_analyzer_on_row.h b/src/util/lp/bound_analyzer_on_row.h index 549c8e5ce..a20b4850a 100644 --- a/src/util/lp/bound_analyzer_on_row.h +++ b/src/util/lp/bound_analyzer_on_row.h @@ -270,7 +270,7 @@ public : } } - // // it is the coefficent before the bounded column + // // it is the coefficient before the bounded column // void provide_evidence(bool coeff_is_pos) { // /* // auto & be = m_ibounds.back(); diff --git a/src/util/lp/lp_core_solver_base_def.h b/src/util/lp/lp_core_solver_base_def.h index c3a0a0a00..6844ab839 100644 --- a/src/util/lp/lp_core_solver_base_def.h +++ b/src/util/lp/lp_core_solver_base_def.h @@ -74,7 +74,7 @@ lp_core_solver_base(static_matrix & A, } template void lp_core_solver_base:: -allocate_basis_heading() { // the rest of initilization will be handled by the factorization class +allocate_basis_heading() { // the rest of initialization will be handled by the factorization class init_basis_heading_and_non_basic_columns_vector(); lp_assert(basis_heading_is_correct()); } diff --git a/src/util/lp/lp_dual_core_solver_def.h b/src/util/lp/lp_dual_core_solver_def.h index 86e6231fc..e7ab73928 100644 --- a/src/util/lp/lp_dual_core_solver_def.h +++ b/src/util/lp/lp_dual_core_solver_def.h @@ -276,7 +276,7 @@ template bool lp_dual_core_solver::can_be_breakpo bool grawing = m_sign_of_alpha_r * this->m_pivot_row[j] > 0; return lower_bound == grawing; } - case column_type::fixed: // is always dual feasible so we ingore it + case column_type::fixed: // is always dual feasible so we ignore it return false; case column_type::free_column: return true; diff --git a/src/util/lp/lp_primal_core_solver_def.h b/src/util/lp/lp_primal_core_solver_def.h index 872922f60..d86ebf548 100644 --- a/src/util/lp/lp_primal_core_solver_def.h +++ b/src/util/lp/lp_primal_core_solver_def.h @@ -284,7 +284,7 @@ template int lp_primal_core_solver::advance_on_so break; } else { if ((numeric_traits::precise() == false) || ( numeric_traits::is_zero(slope_at_entering) && this->m_settings.random_next() % 2 == 0)) { - // it is not cost benefitial to advance the delta more, so just break to increas the randomness + // it is not cost beneficial to advance the delta more, so just break to increase the randomness break; } } @@ -612,7 +612,7 @@ template int lp_primal_core_solver::refresh_re return 2; // abort entering } else { if (refreshed_cost > -m_epsilon_of_reduced_cost) - return 2; // abort entiring + return 2; // abort entering } return 1; // go on with this entering } else { @@ -621,7 +621,7 @@ template int lp_primal_core_solver::refresh_re return 2; // abort entering } else { if (refreshed_cost > -m_epsilon_of_reduced_cost) - return 2; // abort entiring + return 2; // abort entering } } return 0; diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index 1bbefd154..d0bdc284d 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -68,7 +68,7 @@ enum class lp_status { CANCELLED }; -// when the ratio of the vector lenth to domain size to is greater than the return value we switch to solve_By_for_T_indexed_only +// when the ratio of the vector length to domain size to is greater than the return value we switch to solve_By_for_T_indexed_only template unsigned ratio_of_index_size_to_all_size() { if (numeric_traits::precise()) @@ -145,7 +145,7 @@ public: double pivot_epsilon; // see Chatal, page 115 double positive_price_epsilon; - // a quatation "if some choice of the entering vairable leads to an eta matrix + // a quotation "if some choice of the entering variable leads to an eta matrix // whose diagonal element in the eta column is less than e2 (entering_diag_epsilon) in magnitude, the this choice is rejected ... double entering_diag_epsilon; int c_partial_pivoting; // this is the constant c from page 410 diff --git a/src/util/lp/scaler_def.h b/src/util/lp/scaler_def.h index 2710f89bf..4c9784a43 100644 --- a/src/util/lp/scaler_def.h +++ b/src/util/lp/scaler_def.h @@ -126,7 +126,7 @@ template void scaler::scale_once_for_ratio() { T max_ratio_on_rows = get_max_ratio_on_rows(); T max_ratio_on_columns = get_max_ratio_on_columns(); bool scale_rows_first = max_ratio_on_rows > max_ratio_on_columns; - // if max_ratio_on_columns is the largerst then the rows are in worser shape then columns + // if max_ratio_on_columns is the largest then the rows are in worse shape than columns if (scale_rows_first) { scale_rows_with_geometric_mean(); scale_columns_with_geometric_mean(); diff --git a/src/util/lp/square_sparse_matrix_def.h b/src/util/lp/square_sparse_matrix_def.h index 791bdb6ae..cc6625453 100644 --- a/src/util/lp/square_sparse_matrix_def.h +++ b/src/util/lp/square_sparse_matrix_def.h @@ -186,7 +186,7 @@ void square_sparse_matrix::init_row_headers() { } template -void square_sparse_matrix::init_column_headers() { // we alway have only square square_sparse_matrix +void square_sparse_matrix::init_column_headers() { // we always have only square square_sparse_matrix for (unsigned l = 0; l < m_row_permutation.size(); l++) { m_columns.push_back(col_header()); } diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 7549a7bb3..49335467d 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -952,7 +952,7 @@ void my_mpz_sqrt(unsynch_mpz_manager & m, unsigned sbits, bool odd_exp, mpz & in scoped_mpz lower(m), upper(m); scoped_mpz mid(m), product(m), diff(m); // we have lower <= a.significand <= upper and we need 1.[52+3 bits] in the bounds. - // since we comapre upper*upper to a.significand further down, we need a.significand + // since we compare upper*upper to a.significand further down, we need a.significand // to be of twice the size. m.set(lower, 1); m.mul2k(lower, sbits+2-1); @@ -978,7 +978,7 @@ void my_mpz_sqrt(unsynch_mpz_manager & m, unsigned sbits, bool odd_exp, mpz & in } else { STRACE("mpf_dbg", tout << "choosing upper" << std::endl;); - m.set(o, upper); // chosing upper is like a sticky bit here. + m.set(o, upper); // choosing upper is like a sticky bit here. } break; } diff --git a/src/util/obj_ref_hashtable.h b/src/util/obj_ref_hashtable.h index 23a2a1867..80d198607 100644 --- a/src/util/obj_ref_hashtable.h +++ b/src/util/obj_ref_hashtable.h @@ -7,7 +7,7 @@ Module Name: Abstract: - corresponding obj_map with reference count managment. + corresponding obj_map with reference count management. Author: From 3d37060fa97d25337334b1a0c1afeb3001ccb13c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Oct 2018 10:24:36 -0700 Subject: [PATCH 079/227] remove dependencies on contracts Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/AST.cs | 14 +- src/api/dotnet/ASTMap.cs | 18 +- src/api/dotnet/ASTVector.cs | 14 +- src/api/dotnet/AlgebraicNum.cs | 8 +- src/api/dotnet/ApplyResult.cs | 7 +- src/api/dotnet/ArithExpr.cs | 4 +- src/api/dotnet/ArithSort.cs | 4 +- src/api/dotnet/ArrayExpr.cs | 4 +- src/api/dotnet/ArraySort.cs | 19 +- src/api/dotnet/BitVecExpr.cs | 4 +- src/api/dotnet/BitVecNum.cs | 5 +- src/api/dotnet/BitVecSort.cs | 4 +- src/api/dotnet/BoolExpr.cs | 4 +- src/api/dotnet/BoolSort.cs | 6 +- src/api/dotnet/Constructor.cs | 12 +- src/api/dotnet/ConstructorList.cs | 8 +- src/api/dotnet/Context.cs | 1203 ++++++++++----------------- src/api/dotnet/DatatypeExpr.cs | 4 +- src/api/dotnet/DatatypeSort.cs | 14 +- src/api/dotnet/Deprecated.cs | 3 +- src/api/dotnet/EnumSort.cs | 12 +- src/api/dotnet/Expr.cs | 52 +- src/api/dotnet/FPExpr.cs | 4 +- src/api/dotnet/FPNum.cs | 5 +- src/api/dotnet/FPRMExpr.cs | 4 +- src/api/dotnet/FPRMNum.cs | 4 +- src/api/dotnet/FPRMSort.cs | 6 +- src/api/dotnet/FPSort.cs | 6 +- src/api/dotnet/FiniteDomainExpr.cs | 4 +- src/api/dotnet/FiniteDomainNum.cs | 5 +- src/api/dotnet/FiniteDomainSort.cs | 9 +- src/api/dotnet/Fixedpoint.cs | 37 +- src/api/dotnet/FuncDecl.cs | 25 +- src/api/dotnet/FuncInterp.cs | 13 +- src/api/dotnet/Global.cs | 2 +- src/api/dotnet/Goal.cs | 18 +- src/api/dotnet/IDecRefQueue.cs | 15 +- src/api/dotnet/IntExpr.cs | 4 +- src/api/dotnet/IntNum.cs | 5 +- src/api/dotnet/IntSort.cs | 6 +- src/api/dotnet/IntSymbol.cs | 7 +- src/api/dotnet/Lambda.cs | 31 +- src/api/dotnet/ListSort.cs | 16 +- src/api/dotnet/Log.cs | 6 +- src/api/dotnet/Model.cs | 24 +- src/api/dotnet/Optimize.cs | 20 +- src/api/dotnet/ParamDescrs.cs | 11 +- src/api/dotnet/Params.cs | 23 +- src/api/dotnet/Pattern.cs | 6 +- src/api/dotnet/Probe.cs | 11 +- src/api/dotnet/Quantifier.cs | 41 +- src/api/dotnet/RatNum.cs | 7 +- src/api/dotnet/ReExpr.cs | 4 +- src/api/dotnet/ReSort.cs | 6 +- src/api/dotnet/RealExpr.cs | 4 +- src/api/dotnet/RealSort.cs | 6 +- src/api/dotnet/RelationSort.cs | 6 +- src/api/dotnet/SeqExpr.cs | 4 +- src/api/dotnet/SeqSort.cs | 6 +- src/api/dotnet/SetSort.cs | 9 +- src/api/dotnet/Solver.cs | 30 +- src/api/dotnet/Sort.cs | 10 +- src/api/dotnet/Statistics.cs | 11 +- src/api/dotnet/Status.cs | 1 + src/api/dotnet/StringSymbol.cs | 8 +- src/api/dotnet/Symbol.cs | 8 +- src/api/dotnet/Tactic.cs | 15 +- src/api/dotnet/TupleSort.cs | 9 +- src/api/dotnet/UninterpretedSort.cs | 8 +- src/api/dotnet/Version.cs | 4 +- src/api/dotnet/Z3Exception.cs | 1 + src/api/dotnet/Z3Object.cs | 18 +- 72 files changed, 734 insertions(+), 1232 deletions(-) diff --git a/src/api/dotnet/AST.cs b/src/api/dotnet/AST.cs index 2460c50f0..0afff2c42 100644 --- a/src/api/dotnet/AST.cs +++ b/src/api/dotnet/AST.cs @@ -17,17 +17,16 @@ Notes: --*/ +using System.Diagnostics; using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// The abstract syntax tree (AST) class. /// - [ContractVerification(true)] public class AST : Z3Object, IComparable { /// @@ -114,8 +113,7 @@ namespace Microsoft.Z3 /// A copy of the AST which is associated with public AST Translate(Context ctx) { - Contract.Requires(ctx != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ctx != null); if (ReferenceEquals(Context, ctx)) return this; @@ -202,14 +200,13 @@ namespace Microsoft.Z3 /// public string SExpr() { - Contract.Ensures(Contract.Result() != null); return Native.Z3_ast_to_string(Context.nCtx, NativeObject); } #region Internal - internal AST(Context ctx) : base(ctx) { Contract.Requires(ctx != null); } - internal AST(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal AST(Context ctx) : base(ctx) { Debug.Assert(ctx != null); } + internal AST(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue { @@ -246,8 +243,7 @@ namespace Microsoft.Z3 internal static AST Create(Context ctx, IntPtr obj) { - Contract.Requires(ctx != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ctx != null); switch ((Z3_ast_kind)Native.Z3_get_ast_kind(ctx.nCtx, obj)) { diff --git a/src/api/dotnet/ASTMap.cs b/src/api/dotnet/ASTMap.cs index f7c1c5914..f678f71c3 100644 --- a/src/api/dotnet/ASTMap.cs +++ b/src/api/dotnet/ASTMap.cs @@ -17,15 +17,14 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// Map from AST to AST /// - [ContractVerification(true)] internal class ASTMap : Z3Object { /// @@ -35,7 +34,7 @@ namespace Microsoft.Z3 /// True if is a key in the map, false otherwise. public bool Contains(AST k) { - Contract.Requires(k != null); + Debug.Assert(k != null); return 0 != Native.Z3_ast_map_contains(Context.nCtx, NativeObject, k.NativeObject); } @@ -49,8 +48,7 @@ namespace Microsoft.Z3 /// An AST public AST Find(AST k) { - Contract.Requires(k != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(k != null); return new AST(Context, Native.Z3_ast_map_find(Context.nCtx, NativeObject, k.NativeObject)); } @@ -62,8 +60,8 @@ namespace Microsoft.Z3 /// The value AST public void Insert(AST k, AST v) { - Contract.Requires(k != null); - Contract.Requires(v != null); + Debug.Assert(k != null); + Debug.Assert(v != null); Native.Z3_ast_map_insert(Context.nCtx, NativeObject, k.NativeObject, v.NativeObject); } @@ -74,7 +72,7 @@ namespace Microsoft.Z3 /// An AST public void Erase(AST k) { - Contract.Requires(k != null); + Debug.Assert(k != null); Native.Z3_ast_map_erase(Context.nCtx, NativeObject, k.NativeObject); } @@ -119,12 +117,12 @@ namespace Microsoft.Z3 internal ASTMap(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal ASTMap(Context ctx) : base(ctx, Native.Z3_mk_ast_map(ctx.nCtx)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/dotnet/ASTVector.cs b/src/api/dotnet/ASTVector.cs index 8b599ca48..fcfa6bd65 100644 --- a/src/api/dotnet/ASTVector.cs +++ b/src/api/dotnet/ASTVector.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -45,13 +45,12 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new AST(Context, Native.Z3_ast_vector_get(Context.nCtx, NativeObject, i)); } set { - Contract.Requires(value != null); + Debug.Assert(value != null); Native.Z3_ast_vector_set(Context.nCtx, NativeObject, i, value.NativeObject); } @@ -73,7 +72,7 @@ namespace Microsoft.Z3 /// An AST public void Push(AST a) { - Contract.Requires(a != null); + Debug.Assert(a != null); Native.Z3_ast_vector_push(Context.nCtx, NativeObject, a.NativeObject); } @@ -85,8 +84,7 @@ namespace Microsoft.Z3 /// A new ASTVector public ASTVector Translate(Context ctx) { - Contract.Requires(ctx != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ctx != null); return new ASTVector(Context, Native.Z3_ast_vector_translate(Context.nCtx, NativeObject, ctx.nCtx)); } @@ -232,8 +230,8 @@ namespace Microsoft.Z3 } #region Internal - internal ASTVector(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } - internal ASTVector(Context ctx) : base(ctx, Native.Z3_mk_ast_vector(ctx.nCtx)) { Contract.Requires(ctx != null); } + internal ASTVector(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } + internal ASTVector(Context ctx) : base(ctx, Native.Z3_mk_ast_vector(ctx.nCtx)) { Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue { diff --git a/src/api/dotnet/AlgebraicNum.cs b/src/api/dotnet/AlgebraicNum.cs index 3687e1f83..cd1e4e922 100644 --- a/src/api/dotnet/AlgebraicNum.cs +++ b/src/api/dotnet/AlgebraicNum.cs @@ -16,8 +16,8 @@ Author: Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; #if !FRAMEWORK_LT_4 using System.Numerics; @@ -28,7 +28,6 @@ namespace Microsoft.Z3 /// /// Algebraic numbers /// - [ContractVerification(true)] public class AlgebraicNum : ArithExpr { /// @@ -40,7 +39,6 @@ namespace Microsoft.Z3 /// A numeral Expr of sort Real public RatNum ToUpper(uint precision) { - Contract.Ensures(Contract.Result() != null); return new RatNum(Context, Native.Z3_get_algebraic_number_upper(Context.nCtx, NativeObject, precision)); } @@ -54,7 +52,6 @@ namespace Microsoft.Z3 /// A numeral Expr of sort Real public RatNum ToLower(uint precision) { - Contract.Ensures(Contract.Result() != null); return new RatNum(Context, Native.Z3_get_algebraic_number_lower(Context.nCtx, NativeObject, precision)); } @@ -65,7 +62,6 @@ namespace Microsoft.Z3 /// The result has at most decimal places. public string ToDecimal(uint precision) { - Contract.Ensures(Contract.Result() != null); return Native.Z3_get_numeral_decimal_string(Context.nCtx, NativeObject, precision); } @@ -74,7 +70,7 @@ namespace Microsoft.Z3 internal AlgebraicNum(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/ApplyResult.cs b/src/api/dotnet/ApplyResult.cs index db2922460..342bf3216 100644 --- a/src/api/dotnet/ApplyResult.cs +++ b/src/api/dotnet/ApplyResult.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -26,7 +26,6 @@ namespace Microsoft.Z3 /// ApplyResult objects represent the result of an application of a /// tactic to a goal. It contains the subgoals that were produced. /// - [ContractVerification(true)] public class ApplyResult : Z3Object { /// @@ -44,8 +43,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.Result().Length == this.NumSubgoals); uint n = NumSubgoals; Goal[] res = new Goal[n]; @@ -67,7 +64,7 @@ namespace Microsoft.Z3 internal ApplyResult(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/dotnet/ArithExpr.cs b/src/api/dotnet/ArithExpr.cs index 1c42fd78a..53b9db21d 100644 --- a/src/api/dotnet/ArithExpr.cs +++ b/src/api/dotnet/ArithExpr.cs @@ -16,12 +16,12 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -35,7 +35,7 @@ namespace Microsoft.Z3 internal ArithExpr(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion diff --git a/src/api/dotnet/ArithSort.cs b/src/api/dotnet/ArithSort.cs index f19774246..985aec7a9 100644 --- a/src/api/dotnet/ArithSort.cs +++ b/src/api/dotnet/ArithSort.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -28,7 +28,7 @@ namespace Microsoft.Z3 public class ArithSort : Sort { #region Internal - internal ArithSort(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal ArithSort(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } #endregion }; } diff --git a/src/api/dotnet/ArrayExpr.cs b/src/api/dotnet/ArrayExpr.cs index 6c51bfc5b..c53763886 100644 --- a/src/api/dotnet/ArrayExpr.cs +++ b/src/api/dotnet/ArrayExpr.cs @@ -16,12 +16,12 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -35,7 +35,7 @@ namespace Microsoft.Z3 internal ArrayExpr(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/ArraySort.cs b/src/api/dotnet/ArraySort.cs index 47a73ae1f..c5d15938e 100644 --- a/src/api/dotnet/ArraySort.cs +++ b/src/api/dotnet/ArraySort.cs @@ -17,15 +17,14 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// Array sorts. /// - [ContractVerification(true)] public class ArraySort : Sort { /// @@ -35,7 +34,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Sort.Create(Context, Native.Z3_get_array_sort_domain(Context.nCtx, NativeObject)); } @@ -48,27 +46,26 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Sort.Create(Context, Native.Z3_get_array_sort_range(Context.nCtx, NativeObject)); } } #region Internal - internal ArraySort(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal ArraySort(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } internal ArraySort(Context ctx, Sort domain, Sort range) : base(ctx, Native.Z3_mk_array_sort(ctx.nCtx, domain.NativeObject, range.NativeObject)) { - Contract.Requires(ctx != null); - Contract.Requires(domain != null); - Contract.Requires(range != null); + Debug.Assert(ctx != null); + Debug.Assert(domain != null); + Debug.Assert(range != null); } internal ArraySort(Context ctx, Sort[] domain, Sort range) : base(ctx, Native.Z3_mk_array_sort_n(ctx.nCtx, (uint)domain.Length, AST.ArrayToNative(domain), range.NativeObject)) { - Contract.Requires(ctx != null); - Contract.Requires(domain != null); - Contract.Requires(range != null); + Debug.Assert(ctx != null); + Debug.Assert(domain != null); + Debug.Assert(range != null); } #endregion }; diff --git a/src/api/dotnet/BitVecExpr.cs b/src/api/dotnet/BitVecExpr.cs index b019f8845..3efa0e9bd 100644 --- a/src/api/dotnet/BitVecExpr.cs +++ b/src/api/dotnet/BitVecExpr.cs @@ -16,12 +16,12 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -41,7 +41,7 @@ namespace Microsoft.Z3 #region Internal /// Constructor for BitVecExpr - internal BitVecExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal BitVecExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } #endregion } } diff --git a/src/api/dotnet/BitVecNum.cs b/src/api/dotnet/BitVecNum.cs index 66054761a..5ee2d2ed8 100644 --- a/src/api/dotnet/BitVecNum.cs +++ b/src/api/dotnet/BitVecNum.cs @@ -16,8 +16,8 @@ Author: Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; #if !FRAMEWORK_LT_4 using System.Numerics; @@ -28,7 +28,6 @@ namespace Microsoft.Z3 /// /// Bit-vector numerals /// - [ContractVerification(true)] public class BitVecNum : BitVecExpr { /// @@ -109,7 +108,7 @@ namespace Microsoft.Z3 } #region Internal - internal BitVecNum(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal BitVecNum(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } #endregion } } diff --git a/src/api/dotnet/BitVecSort.cs b/src/api/dotnet/BitVecSort.cs index d865159f4..fb41e76fe 100644 --- a/src/api/dotnet/BitVecSort.cs +++ b/src/api/dotnet/BitVecSort.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -36,7 +36,7 @@ namespace Microsoft.Z3 } #region Internal - internal BitVecSort(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal BitVecSort(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } #endregion }; } diff --git a/src/api/dotnet/BoolExpr.cs b/src/api/dotnet/BoolExpr.cs index c52109352..906090d2a 100644 --- a/src/api/dotnet/BoolExpr.cs +++ b/src/api/dotnet/BoolExpr.cs @@ -16,12 +16,12 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -32,7 +32,7 @@ namespace Microsoft.Z3 { #region Internal /// Constructor for BoolExpr - internal BoolExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal BoolExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } #endregion #region Operators diff --git a/src/api/dotnet/BoolSort.cs b/src/api/dotnet/BoolSort.cs index 50f44c858..7fd6706a3 100644 --- a/src/api/dotnet/BoolSort.cs +++ b/src/api/dotnet/BoolSort.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -28,8 +28,8 @@ namespace Microsoft.Z3 public class BoolSort : Sort { #region Internal - internal BoolSort(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } - internal BoolSort(Context ctx) : base(ctx, Native.Z3_mk_bool_sort(ctx.nCtx)) { Contract.Requires(ctx != null); } + internal BoolSort(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } + internal BoolSort(Context ctx) : base(ctx, Native.Z3_mk_bool_sort(ctx.nCtx)) { Debug.Assert(ctx != null); } #endregion }; } diff --git a/src/api/dotnet/Constructor.cs b/src/api/dotnet/Constructor.cs index 527b8bc13..f635d78e4 100644 --- a/src/api/dotnet/Constructor.cs +++ b/src/api/dotnet/Constructor.cs @@ -17,15 +17,14 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// Constructors are used for datatype sorts. /// - [ContractVerification(true)] public class Constructor : Z3Object { /// @@ -46,7 +45,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); IntPtr constructor = IntPtr.Zero; IntPtr tester = IntPtr.Zero; IntPtr[] accessors = new IntPtr[n]; @@ -62,7 +60,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); IntPtr constructor = IntPtr.Zero; IntPtr tester = IntPtr.Zero; IntPtr[] accessors = new IntPtr[n]; @@ -78,7 +75,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); IntPtr constructor = IntPtr.Zero; IntPtr tester = IntPtr.Zero; IntPtr[] accessors = new IntPtr[n]; @@ -105,9 +101,9 @@ namespace Microsoft.Z3 Sort[] sorts, uint[] sortRefs) : base(ctx) { - Contract.Requires(ctx != null); - Contract.Requires(name != null); - Contract.Requires(recognizer != null); + Debug.Assert(ctx != null); + Debug.Assert(name != null); + Debug.Assert(recognizer != null); n = AST.ArrayLength(fieldNames); diff --git a/src/api/dotnet/ConstructorList.cs b/src/api/dotnet/ConstructorList.cs index d625b5ade..9b9ba8561 100644 --- a/src/api/dotnet/ConstructorList.cs +++ b/src/api/dotnet/ConstructorList.cs @@ -17,12 +17,12 @@ Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -43,14 +43,14 @@ namespace Microsoft.Z3 internal ConstructorList(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal ConstructorList(Context ctx, Constructor[] constructors) : base(ctx) { - Contract.Requires(ctx != null); - Contract.Requires(constructors != null); + Debug.Assert(ctx != null); + Debug.Assert(constructors != null); NativeObject = Native.Z3_mk_constructor_list(Context.nCtx, (uint)constructors.Length, Constructor.ArrayToNative(constructors)); } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index ef85a8713..97541e31f 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -18,9 +18,9 @@ Notes: --*/ using System; +using System.Diagnostics; using System.Collections.Generic; using System.Runtime.InteropServices; -using System.Diagnostics.Contracts; using System.Linq; namespace Microsoft.Z3 @@ -28,7 +28,6 @@ namespace Microsoft.Z3 /// /// The main interaction with Z3 happens via the Context. /// - [ContractVerification(true)] public class Context : IDisposable { #region Constructors @@ -66,7 +65,7 @@ namespace Microsoft.Z3 public Context(Dictionary settings) : base() { - Contract.Requires(settings != null); + Debug.Assert(settings != null); lock (creation_lock) { @@ -90,7 +89,6 @@ namespace Microsoft.Z3 /// public IntSymbol MkSymbol(int i) { - Contract.Ensures(Contract.Result() != null); return new IntSymbol(this, i); } @@ -100,7 +98,6 @@ namespace Microsoft.Z3 /// public StringSymbol MkSymbol(string name) { - Contract.Ensures(Contract.Result() != null); return new StringSymbol(this, name); } @@ -110,10 +107,6 @@ namespace Microsoft.Z3 /// internal Symbol[] MkSymbols(string[] names) { - Contract.Ensures(names == null || Contract.Result() != null); - Contract.Ensures(names != null || Contract.Result() == null); - Contract.Ensures(Contract.Result() == null || Contract.Result().Length == names.Length); - Contract.Ensures(Contract.Result() == null || Contract.ForAll(Contract.Result(), s => s != null)); if (names == null) return null; Symbol[] result = new Symbol[names.Length]; @@ -135,7 +128,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); if (m_boolSort == null) m_boolSort = new BoolSort(this); return m_boolSort; } } @@ -147,7 +139,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); if (m_intSort == null) m_intSort = new IntSort(this); return m_intSort; } } @@ -160,7 +151,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); if (m_realSort == null) m_realSort = new RealSort(this); return m_realSort; } } @@ -172,7 +162,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); if (m_stringSort == null) m_stringSort = new SeqSort(this, Native.Z3_mk_string_sort(nCtx)); return m_stringSort; } @@ -184,7 +173,6 @@ namespace Microsoft.Z3 /// public BoolSort MkBoolSort() { - Contract.Ensures(Contract.Result() != null); return new BoolSort(this); } @@ -193,8 +181,7 @@ namespace Microsoft.Z3 /// public UninterpretedSort MkUninterpretedSort(Symbol s) { - Contract.Requires(s != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); CheckContextMatch(s); return new UninterpretedSort(this, s); @@ -205,7 +192,6 @@ namespace Microsoft.Z3 /// public UninterpretedSort MkUninterpretedSort(string str) { - Contract.Ensures(Contract.Result() != null); return MkUninterpretedSort(MkSymbol(str)); } @@ -215,7 +201,6 @@ namespace Microsoft.Z3 /// public IntSort MkIntSort() { - Contract.Ensures(Contract.Result() != null); return new IntSort(this); } @@ -225,7 +210,6 @@ namespace Microsoft.Z3 /// public RealSort MkRealSort() { - Contract.Ensures(Contract.Result() != null); return new RealSort(this); } @@ -234,7 +218,6 @@ namespace Microsoft.Z3 /// public BitVecSort MkBitVecSort(uint size) { - Contract.Ensures(Contract.Result() != null); return new BitVecSort(this, Native.Z3_mk_bv_sort(nCtx, size)); } @@ -245,8 +228,7 @@ namespace Microsoft.Z3 /// public SeqSort MkSeqSort(Sort s) { - Contract.Requires(s != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); return new SeqSort(this, Native.Z3_mk_seq_sort(nCtx, s.NativeObject)); } @@ -255,8 +237,7 @@ namespace Microsoft.Z3 /// public ReSort MkReSort(SeqSort s) { - Contract.Requires(s != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); return new ReSort(this, Native.Z3_mk_re_sort(nCtx, s.NativeObject)); } @@ -265,9 +246,8 @@ namespace Microsoft.Z3 /// public ArraySort MkArraySort(Sort domain, Sort range) { - Contract.Requires(domain != null); - Contract.Requires(range != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(domain != null); + Debug.Assert(range != null); CheckContextMatch(domain); CheckContextMatch(range); @@ -279,9 +259,8 @@ namespace Microsoft.Z3 /// public ArraySort MkArraySort(Sort[] domain, Sort range) { - Contract.Requires(domain != null); - Contract.Requires(range != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(domain != null); + Debug.Assert(range != null); CheckContextMatch(domain); CheckContextMatch(range); @@ -293,11 +272,10 @@ namespace Microsoft.Z3 /// public TupleSort MkTupleSort(Symbol name, Symbol[] fieldNames, Sort[] fieldSorts) { - Contract.Requires(name != null); - Contract.Requires(fieldNames != null); - Contract.Requires(Contract.ForAll(fieldNames, fn => fn != null)); - Contract.Requires(fieldSorts == null || Contract.ForAll(fieldSorts, fs => fs != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); + Debug.Assert(fieldNames != null); + Debug.Assert(fieldNames.All(fn => fn != null)); + Debug.Assert(fieldSorts == null || fieldSorts.All(fs => fs != null)); CheckContextMatch(name); CheckContextMatch(fieldNames); @@ -310,11 +288,10 @@ namespace Microsoft.Z3 /// public EnumSort MkEnumSort(Symbol name, params Symbol[] enumNames) { - Contract.Requires(name != null); - Contract.Requires(enumNames != null); - Contract.Requires(Contract.ForAll(enumNames, f => f != null)); + Debug.Assert(name != null); + Debug.Assert(enumNames != null); + Debug.Assert(enumNames.All(f => f != null)); - Contract.Ensures(Contract.Result() != null); CheckContextMatch(name); CheckContextMatch(enumNames); @@ -326,8 +303,7 @@ namespace Microsoft.Z3 /// public EnumSort MkEnumSort(string name, params string[] enumNames) { - Contract.Requires(enumNames != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(enumNames != null); return new EnumSort(this, MkSymbol(name), MkSymbols(enumNames)); } @@ -337,9 +313,8 @@ namespace Microsoft.Z3 /// public ListSort MkListSort(Symbol name, Sort elemSort) { - Contract.Requires(name != null); - Contract.Requires(elemSort != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); + Debug.Assert(elemSort != null); CheckContextMatch(name); CheckContextMatch(elemSort); @@ -351,8 +326,7 @@ namespace Microsoft.Z3 /// public ListSort MkListSort(string name, Sort elemSort) { - Contract.Requires(elemSort != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(elemSort != null); CheckContextMatch(elemSort); return new ListSort(this, MkSymbol(name), elemSort); @@ -366,8 +340,7 @@ namespace Microsoft.Z3 /// The size of the sort public FiniteDomainSort MkFiniteDomainSort(Symbol name, ulong size) { - Contract.Requires(name != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); CheckContextMatch(name); return new FiniteDomainSort(this, name, size); @@ -383,7 +356,6 @@ namespace Microsoft.Z3 /// The size of the sort public FiniteDomainSort MkFiniteDomainSort(string name, ulong size) { - Contract.Ensures(Contract.Result() != null); return new FiniteDomainSort(this, MkSymbol(name), size); } @@ -402,9 +374,8 @@ namespace Microsoft.Z3 /// referring to one of the recursive datatypes that is declared. public Constructor MkConstructor(Symbol name, Symbol recognizer, Symbol[] fieldNames = null, Sort[] sorts = null, uint[] sortRefs = null) { - Contract.Requires(name != null); - Contract.Requires(recognizer != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); + Debug.Assert(recognizer != null); return new Constructor(this, name, recognizer, fieldNames, sorts, sortRefs); } @@ -420,7 +391,6 @@ namespace Microsoft.Z3 /// public Constructor MkConstructor(string name, string recognizer, string[] fieldNames = null, Sort[] sorts = null, uint[] sortRefs = null) { - Contract.Ensures(Contract.Result() != null); return new Constructor(this, MkSymbol(name), MkSymbol(recognizer), MkSymbols(fieldNames), sorts, sortRefs); } @@ -430,11 +400,10 @@ namespace Microsoft.Z3 /// public DatatypeSort MkDatatypeSort(Symbol name, Constructor[] constructors) { - Contract.Requires(name != null); - Contract.Requires(constructors != null); - Contract.Requires(Contract.ForAll(constructors, c => c != null)); + Debug.Assert(name != null); + Debug.Assert(constructors != null); + Debug.Assert(constructors.All(c => c != null)); - Contract.Ensures(Contract.Result() != null); CheckContextMatch(name); CheckContextMatch(constructors); @@ -446,9 +415,8 @@ namespace Microsoft.Z3 /// public DatatypeSort MkDatatypeSort(string name, Constructor[] constructors) { - Contract.Requires(constructors != null); - Contract.Requires(Contract.ForAll(constructors, c => c != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(constructors != null); + Debug.Assert(constructors.All(c => c != null)); CheckContextMatch(constructors); return new DatatypeSort(this, MkSymbol(name), constructors); @@ -461,12 +429,11 @@ namespace Microsoft.Z3 /// list of constructors, one list per sort. public DatatypeSort[] MkDatatypeSorts(Symbol[] names, Constructor[][] c) { - Contract.Requires(names != null); - Contract.Requires(c != null); - Contract.Requires(names.Length == c.Length); - Contract.Requires(Contract.ForAll(0, c.Length, j => c[j] != null)); - Contract.Requires(Contract.ForAll(names, name => name != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(names != null); + Debug.Assert(c != null); + Debug.Assert(names.Length == c.Length); + //Debug.Assert(Contract.ForAll(0, c.Length, j => c[j] != null)); + Debug.Assert(names.All(name => name != null)); CheckContextMatch(names); uint n = (uint)names.Length; @@ -475,7 +442,6 @@ namespace Microsoft.Z3 for (uint i = 0; i < n; i++) { Constructor[] constructor = c[i]; - Contract.Assume(Contract.ForAll(constructor, arr => arr != null), "Clousot does not support yet quantified formula on multidimensional arrays"); CheckContextMatch(constructor); cla[i] = new ConstructorList(this, constructor); n_constr[i] = cla[i].NativeObject; @@ -496,12 +462,11 @@ namespace Microsoft.Z3 /// public DatatypeSort[] MkDatatypeSorts(string[] names, Constructor[][] c) { - Contract.Requires(names != null); - Contract.Requires(c != null); - Contract.Requires(names.Length == c.Length); - Contract.Requires(Contract.ForAll(0, c.Length, j => c[j] != null)); - Contract.Requires(Contract.ForAll(names, name => name != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(names != null); + Debug.Assert(c != null); + Debug.Assert(names.Length == c.Length); + //Debug.Assert(Contract.ForAll(0, c.Length, j => c[j] != null)); + //Debug.Assert(names.All(name => name != null)); return MkDatatypeSorts(MkSymbols(names), c); } @@ -528,10 +493,9 @@ namespace Microsoft.Z3 /// public FuncDecl MkFuncDecl(Symbol name, Sort[] domain, Sort range) { - Contract.Requires(name != null); - Contract.Requires(range != null); - Contract.Requires(Contract.ForAll(domain, d => d != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); + Debug.Assert(range != null); + Debug.Assert(domain.All(d => d != null)); CheckContextMatch(name); CheckContextMatch(domain); @@ -544,10 +508,9 @@ namespace Microsoft.Z3 /// public FuncDecl MkFuncDecl(Symbol name, Sort domain, Sort range) { - Contract.Requires(name != null); - Contract.Requires(domain != null); - Contract.Requires(range != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); + Debug.Assert(domain != null); + Debug.Assert(range != null); CheckContextMatch(name); CheckContextMatch(domain); @@ -561,9 +524,8 @@ namespace Microsoft.Z3 /// public FuncDecl MkFuncDecl(string name, Sort[] domain, Sort range) { - Contract.Requires(range != null); - Contract.Requires(Contract.ForAll(domain, d => d != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(range != null); + Debug.Assert(domain.All(d => d != null)); CheckContextMatch(domain); CheckContextMatch(range); @@ -575,9 +537,8 @@ namespace Microsoft.Z3 /// public FuncDecl MkFuncDecl(string name, Sort domain, Sort range) { - Contract.Requires(range != null); - Contract.Requires(domain != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(range != null); + Debug.Assert(domain != null); CheckContextMatch(domain); CheckContextMatch(range); @@ -592,9 +553,8 @@ namespace Microsoft.Z3 /// public FuncDecl MkFreshFuncDecl(string prefix, Sort[] domain, Sort range) { - Contract.Requires(range != null); - Contract.Requires(Contract.ForAll(domain, d => d != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(range != null); + Debug.Assert(domain.All(d => d != null)); CheckContextMatch(domain); CheckContextMatch(range); @@ -606,9 +566,8 @@ namespace Microsoft.Z3 /// public FuncDecl MkConstDecl(Symbol name, Sort range) { - Contract.Requires(name != null); - Contract.Requires(range != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); + Debug.Assert(range != null); CheckContextMatch(name); CheckContextMatch(range); @@ -620,8 +579,7 @@ namespace Microsoft.Z3 /// public FuncDecl MkConstDecl(string name, Sort range) { - Contract.Requires(range != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(range != null); CheckContextMatch(range); return new FuncDecl(this, MkSymbol(name), null, range); @@ -634,8 +592,7 @@ namespace Microsoft.Z3 /// public FuncDecl MkFreshConstDecl(string prefix, Sort range) { - Contract.Requires(range != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(range != null); CheckContextMatch(range); return new FuncDecl(this, prefix, null, range); @@ -650,8 +607,7 @@ namespace Microsoft.Z3 /// The sort of the variable public Expr MkBound(uint index, Sort ty) { - Contract.Requires(ty != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ty != null); return Expr.Create(this, Native.Z3_mk_bound(nCtx, index, ty.NativeObject)); } @@ -663,14 +619,10 @@ namespace Microsoft.Z3 /// public Pattern MkPattern(params Expr[] terms) { - Contract.Requires(terms != null); + Debug.Assert(terms != null); if (terms.Length == 0) throw new Z3Exception("Cannot create a pattern from zero terms"); - Contract.Ensures(Contract.Result() != null); - - Contract.EndContractBlock(); - IntPtr[] termsNative = AST.ArrayToNative(terms); return new Pattern(this, Native.Z3_mk_pattern(nCtx, (uint)terms.Length, termsNative)); } @@ -682,9 +634,8 @@ namespace Microsoft.Z3 /// public Expr MkConst(Symbol name, Sort range) { - Contract.Requires(name != null); - Contract.Requires(range != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); + Debug.Assert(range != null); CheckContextMatch(name); CheckContextMatch(range); @@ -697,8 +648,7 @@ namespace Microsoft.Z3 /// public Expr MkConst(string name, Sort range) { - Contract.Requires(range != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(range != null); return MkConst(MkSymbol(name), range); } @@ -709,8 +659,7 @@ namespace Microsoft.Z3 /// public Expr MkFreshConst(string prefix, Sort range) { - Contract.Requires(range != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(range != null); CheckContextMatch(range); return Expr.Create(this, Native.Z3_mk_fresh_const(nCtx, prefix, range.NativeObject)); @@ -722,8 +671,7 @@ namespace Microsoft.Z3 /// A decl of a 0-arity function public Expr MkConst(FuncDecl f) { - Contract.Requires(f != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(f != null); return MkApp(f); } @@ -733,8 +681,7 @@ namespace Microsoft.Z3 /// public BoolExpr MkBoolConst(Symbol name) { - Contract.Requires(name != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); return (BoolExpr)MkConst(name, BoolSort); } @@ -744,7 +691,6 @@ namespace Microsoft.Z3 /// public BoolExpr MkBoolConst(string name) { - Contract.Ensures(Contract.Result() != null); return (BoolExpr)MkConst(MkSymbol(name), BoolSort); } @@ -754,8 +700,7 @@ namespace Microsoft.Z3 /// public IntExpr MkIntConst(Symbol name) { - Contract.Requires(name != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); return (IntExpr)MkConst(name, IntSort); } @@ -765,8 +710,7 @@ namespace Microsoft.Z3 /// public IntExpr MkIntConst(string name) { - Contract.Requires(name != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); return (IntExpr)MkConst(name, IntSort); } @@ -776,8 +720,7 @@ namespace Microsoft.Z3 /// public RealExpr MkRealConst(Symbol name) { - Contract.Requires(name != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); return (RealExpr)MkConst(name, RealSort); } @@ -787,7 +730,6 @@ namespace Microsoft.Z3 /// public RealExpr MkRealConst(string name) { - Contract.Ensures(Contract.Result() != null); return (RealExpr)MkConst(name, RealSort); } @@ -797,8 +739,7 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVConst(Symbol name, uint size) { - Contract.Requires(name != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); return (BitVecExpr)MkConst(name, MkBitVecSort(size)); } @@ -808,7 +749,6 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVConst(string name, uint size) { - Contract.Ensures(Contract.Result() != null); return (BitVecExpr)MkConst(name, MkBitVecSort(size)); } @@ -820,9 +760,8 @@ namespace Microsoft.Z3 /// public Expr MkApp(FuncDecl f, params Expr[] args) { - Contract.Requires(f != null); - Contract.Requires(args == null || Contract.ForAll(args, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(f != null); + Debug.Assert(args == null || args.All(a => a != null)); CheckContextMatch(f); CheckContextMatch(args); @@ -834,9 +773,8 @@ namespace Microsoft.Z3 /// public Expr MkApp(FuncDecl f, IEnumerable args) { - Contract.Requires(f != null); - Contract.Requires(args == null || Contract.ForAll(args, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(f != null); + Debug.Assert(args == null || args.All( a => a != null)); CheckContextMatch(f); CheckContextMatch(args); @@ -849,7 +787,6 @@ namespace Microsoft.Z3 /// public BoolExpr MkTrue() { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_true(nCtx)); } @@ -859,7 +796,6 @@ namespace Microsoft.Z3 /// public BoolExpr MkFalse() { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_false(nCtx)); } @@ -869,7 +805,6 @@ namespace Microsoft.Z3 /// public BoolExpr MkBool(bool value) { - Contract.Ensures(Contract.Result() != null); return value ? MkTrue() : MkFalse(); } @@ -879,9 +814,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkEq(Expr x, Expr y) { - Contract.Requires(x != null); - Contract.Requires(y != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(x != null); + Debug.Assert(y != null); CheckContextMatch(x); CheckContextMatch(y); @@ -893,10 +827,9 @@ namespace Microsoft.Z3 /// public BoolExpr MkDistinct(params Expr[] args) { - Contract.Requires(args != null); - Contract.Requires(Contract.ForAll(args, a => a != null)); + Debug.Assert(args != null); + Debug.Assert(args.All(a => a != null)); - Contract.Ensures(Contract.Result() != null); CheckContextMatch(args); return new BoolExpr(this, Native.Z3_mk_distinct(nCtx, (uint)args.Length, AST.ArrayToNative(args))); @@ -907,8 +840,7 @@ namespace Microsoft.Z3 /// public BoolExpr MkNot(BoolExpr a) { - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(a != null); CheckContextMatch(a); return new BoolExpr(this, Native.Z3_mk_not(nCtx, a.NativeObject)); @@ -922,10 +854,9 @@ namespace Microsoft.Z3 /// An expression with the same sort as public Expr MkITE(BoolExpr t1, Expr t2, Expr t3) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Requires(t3 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); + Debug.Assert(t3 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -938,9 +869,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkIff(BoolExpr t1, BoolExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -952,9 +882,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkImplies(BoolExpr t1, BoolExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -966,9 +895,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkXor(BoolExpr t1, BoolExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -980,9 +908,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkAnd(params BoolExpr[] t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return new BoolExpr(this, Native.Z3_mk_and(nCtx, (uint)t.Length, AST.ArrayToNative(t))); @@ -993,9 +920,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkAnd(IEnumerable t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return new BoolExpr(this, Native.Z3_mk_and(nCtx, (uint)t.Count(), AST.EnumToNative(t))); } @@ -1005,9 +931,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkOr(params BoolExpr[] t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return new BoolExpr(this, Native.Z3_mk_or(nCtx, (uint)t.Length, AST.ArrayToNative(t))); @@ -1019,9 +944,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkOr(IEnumerable t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return new BoolExpr(this, Native.Z3_mk_or(nCtx, (uint)t.Count(), AST.EnumToNative(t))); @@ -1035,9 +959,8 @@ namespace Microsoft.Z3 /// public ArithExpr MkAdd(params ArithExpr[] t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return (ArithExpr)Expr.Create(this, Native.Z3_mk_add(nCtx, (uint)t.Length, AST.ArrayToNative(t))); @@ -1048,9 +971,8 @@ namespace Microsoft.Z3 /// public ArithExpr MkAdd(IEnumerable t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return (ArithExpr)Expr.Create(this, Native.Z3_mk_add(nCtx, (uint)t.Count(), AST.EnumToNative(t))); @@ -1061,9 +983,8 @@ namespace Microsoft.Z3 /// public ArithExpr MkMul(params ArithExpr[] t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return (ArithExpr)Expr.Create(this, Native.Z3_mk_mul(nCtx, (uint)t.Length, AST.ArrayToNative(t))); @@ -1074,9 +995,8 @@ namespace Microsoft.Z3 /// public ArithExpr MkMul(IEnumerable t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return (ArithExpr)Expr.Create(this, Native.Z3_mk_mul(nCtx, (uint)t.Count(), AST.EnumToNative(t))); @@ -1087,9 +1007,8 @@ namespace Microsoft.Z3 /// public ArithExpr MkSub(params ArithExpr[] t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return (ArithExpr)Expr.Create(this, Native.Z3_mk_sub(nCtx, (uint)t.Length, AST.ArrayToNative(t))); @@ -1100,8 +1019,7 @@ namespace Microsoft.Z3 /// public ArithExpr MkUnaryMinus(ArithExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return (ArithExpr)Expr.Create(this, Native.Z3_mk_unary_minus(nCtx, t.NativeObject)); @@ -1112,9 +1030,8 @@ namespace Microsoft.Z3 /// public ArithExpr MkDiv(ArithExpr t1, ArithExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1127,9 +1044,8 @@ namespace Microsoft.Z3 /// The arguments must have int type. public IntExpr MkMod(IntExpr t1, IntExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1142,9 +1058,8 @@ namespace Microsoft.Z3 /// The arguments must have int type. public IntExpr MkRem(IntExpr t1, IntExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1156,9 +1071,8 @@ namespace Microsoft.Z3 /// public ArithExpr MkPower(ArithExpr t1, ArithExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1170,9 +1084,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkLt(ArithExpr t1, ArithExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1184,9 +1097,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkLe(ArithExpr t1, ArithExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1198,9 +1110,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkGt(ArithExpr t1, ArithExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1212,9 +1123,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkGe(ArithExpr t1, ArithExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1233,8 +1143,7 @@ namespace Microsoft.Z3 /// public RealExpr MkInt2Real(IntExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new RealExpr(this, Native.Z3_mk_int2real(nCtx, t.NativeObject)); @@ -1249,8 +1158,7 @@ namespace Microsoft.Z3 /// public IntExpr MkReal2Int(RealExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new IntExpr(this, Native.Z3_mk_real2int(nCtx, t.NativeObject)); @@ -1261,8 +1169,7 @@ namespace Microsoft.Z3 /// public BoolExpr MkIsInteger(RealExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BoolExpr(this, Native.Z3_mk_is_int(nCtx, t.NativeObject)); @@ -1276,8 +1183,7 @@ namespace Microsoft.Z3 /// The argument must have a bit-vector sort. public BitVecExpr MkBVNot(BitVecExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BitVecExpr(this, Native.Z3_mk_bvnot(nCtx, t.NativeObject)); @@ -1289,8 +1195,7 @@ namespace Microsoft.Z3 /// The argument must have a bit-vector sort. public BitVecExpr MkBVRedAND(BitVecExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BitVecExpr(this, Native.Z3_mk_bvredand(nCtx, t.NativeObject)); @@ -1302,8 +1207,7 @@ namespace Microsoft.Z3 /// The argument must have a bit-vector sort. public BitVecExpr MkBVRedOR(BitVecExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BitVecExpr(this, Native.Z3_mk_bvredor(nCtx, t.NativeObject)); @@ -1315,9 +1219,8 @@ namespace Microsoft.Z3 /// The arguments must have a bit-vector sort. public BitVecExpr MkBVAND(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1330,9 +1233,8 @@ namespace Microsoft.Z3 /// The arguments must have a bit-vector sort. public BitVecExpr MkBVOR(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1345,9 +1247,8 @@ namespace Microsoft.Z3 /// The arguments must have a bit-vector sort. public BitVecExpr MkBVXOR(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1360,9 +1261,8 @@ namespace Microsoft.Z3 /// The arguments must have a bit-vector sort. public BitVecExpr MkBVNAND(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1375,9 +1275,8 @@ namespace Microsoft.Z3 /// The arguments must have a bit-vector sort. public BitVecExpr MkBVNOR(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1390,9 +1289,8 @@ namespace Microsoft.Z3 /// The arguments must have a bit-vector sort. public BitVecExpr MkBVXNOR(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1405,8 +1303,7 @@ namespace Microsoft.Z3 /// The arguments must have a bit-vector sort. public BitVecExpr MkBVNeg(BitVecExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BitVecExpr(this, Native.Z3_mk_bvneg(nCtx, t.NativeObject)); @@ -1418,9 +1315,8 @@ namespace Microsoft.Z3 /// The arguments must have the same bit-vector sort. public BitVecExpr MkBVAdd(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1433,9 +1329,8 @@ namespace Microsoft.Z3 /// The arguments must have the same bit-vector sort. public BitVecExpr MkBVSub(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1448,9 +1343,8 @@ namespace Microsoft.Z3 /// The arguments must have the same bit-vector sort. public BitVecExpr MkBVMul(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1468,9 +1362,8 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVUDiv(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1492,9 +1385,8 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVSDiv(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1511,9 +1403,8 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVURem(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1532,9 +1423,8 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVSRem(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1550,9 +1440,8 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVSMod(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1567,9 +1456,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVULT(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1584,9 +1472,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVSLT(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1601,9 +1488,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVULE(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1618,9 +1504,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVSLE(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1635,9 +1520,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVUGE(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1652,9 +1536,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVSGE(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1669,9 +1552,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVUGT(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1686,9 +1568,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVSGT(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1707,9 +1588,8 @@ namespace Microsoft.Z3 /// public BitVecExpr MkConcat(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1727,8 +1607,7 @@ namespace Microsoft.Z3 /// public BitVecExpr MkExtract(uint high, uint low, BitVecExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BitVecExpr(this, Native.Z3_mk_extract(nCtx, high, low, t.NativeObject)); @@ -1744,8 +1623,7 @@ namespace Microsoft.Z3 /// public BitVecExpr MkSignExt(uint i, BitVecExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BitVecExpr(this, Native.Z3_mk_sign_ext(nCtx, i, t.NativeObject)); @@ -1762,8 +1640,7 @@ namespace Microsoft.Z3 /// public BitVecExpr MkZeroExt(uint i, BitVecExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BitVecExpr(this, Native.Z3_mk_zero_ext(nCtx, i, t.NativeObject)); @@ -1777,8 +1654,7 @@ namespace Microsoft.Z3 /// public BitVecExpr MkRepeat(uint i, BitVecExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BitVecExpr(this, Native.Z3_mk_repeat(nCtx, i, t.NativeObject)); @@ -1798,9 +1674,8 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVSHL(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1821,9 +1696,8 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVLSHR(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1846,9 +1720,8 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVASHR(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1864,8 +1737,7 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVRotateLeft(uint i, BitVecExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BitVecExpr(this, Native.Z3_mk_rotate_left(nCtx, i, t.NativeObject)); @@ -1880,8 +1752,7 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVRotateRight(uint i, BitVecExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BitVecExpr(this, Native.Z3_mk_rotate_right(nCtx, i, t.NativeObject)); @@ -1896,9 +1767,8 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVRotateLeft(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1914,9 +1784,8 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVRotateRight(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1935,8 +1804,7 @@ namespace Microsoft.Z3 /// public BitVecExpr MkInt2BV(uint n, IntExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BitVecExpr(this, Native.Z3_mk_int2bv(nCtx, n, t.NativeObject)); @@ -1959,8 +1827,7 @@ namespace Microsoft.Z3 /// public IntExpr MkBV2Int(BitVecExpr t, bool signed) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new IntExpr(this, Native.Z3_mk_bv2int(nCtx, t.NativeObject, (byte)(signed ? 1 : 0))); @@ -1974,9 +1841,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVAddNoOverflow(BitVecExpr t1, BitVecExpr t2, bool isSigned) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -1991,9 +1857,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVAddNoUnderflow(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -2008,9 +1873,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVSubNoOverflow(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -2025,9 +1889,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVSubNoUnderflow(BitVecExpr t1, BitVecExpr t2, bool isSigned) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -2042,9 +1905,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVSDivNoOverflow(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -2059,8 +1921,7 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVNegNoOverflow(BitVecExpr t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new BoolExpr(this, Native.Z3_mk_bvneg_no_overflow(nCtx, t.NativeObject)); @@ -2074,9 +1935,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVMulNoOverflow(BitVecExpr t1, BitVecExpr t2, bool isSigned) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -2091,9 +1951,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBVMulNoUnderflow(BitVecExpr t1, BitVecExpr t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -2107,10 +1966,9 @@ namespace Microsoft.Z3 /// public ArrayExpr MkArrayConst(Symbol name, Sort domain, Sort range) { - Contract.Requires(name != null); - Contract.Requires(domain != null); - Contract.Requires(range != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(name != null); + Debug.Assert(domain != null); + Debug.Assert(range != null); return (ArrayExpr)MkConst(name, MkArraySort(domain, range)); } @@ -2120,9 +1978,8 @@ namespace Microsoft.Z3 /// public ArrayExpr MkArrayConst(string name, Sort domain, Sort range) { - Contract.Requires(domain != null); - Contract.Requires(range != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(domain != null); + Debug.Assert(range != null); return (ArrayExpr)MkConst(MkSymbol(name), MkArraySort(domain, range)); } @@ -2143,9 +2000,8 @@ namespace Microsoft.Z3 /// public Expr MkSelect(ArrayExpr a, Expr i) { - Contract.Requires(a != null); - Contract.Requires(i != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(a != null); + Debug.Assert(i != null); CheckContextMatch(a); CheckContextMatch(i); @@ -2167,9 +2023,8 @@ namespace Microsoft.Z3 /// public Expr MkSelect(ArrayExpr a, params Expr[] args) { - Contract.Requires(a != null); - Contract.Requires(args != null && Contract.ForAll(args, n => n != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(a != null); + Debug.Assert(args != null && args.All(n => n != null)); CheckContextMatch(a); CheckContextMatch(args); @@ -2196,10 +2051,9 @@ namespace Microsoft.Z3 /// public ArrayExpr MkStore(ArrayExpr a, Expr i, Expr v) { - Contract.Requires(a != null); - Contract.Requires(i != null); - Contract.Requires(v != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(a != null); + Debug.Assert(i != null); + Debug.Assert(v != null); CheckContextMatch(a); CheckContextMatch(i); @@ -2227,10 +2081,9 @@ namespace Microsoft.Z3 /// public ArrayExpr MkStore(ArrayExpr a, Expr[] args, Expr v) { - Contract.Requires(a != null); - Contract.Requires(args != null); - Contract.Requires(v != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(a != null); + Debug.Assert(args != null); + Debug.Assert(v != null); CheckContextMatch(args); CheckContextMatch(a); @@ -2249,9 +2102,8 @@ namespace Microsoft.Z3 /// public ArrayExpr MkConstArray(Sort domain, Expr v) { - Contract.Requires(domain != null); - Contract.Requires(v != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(domain != null); + Debug.Assert(v != null); CheckContextMatch(domain); CheckContextMatch(v); @@ -2271,9 +2123,8 @@ namespace Microsoft.Z3 /// public ArrayExpr MkMap(FuncDecl f, params ArrayExpr[] args) { - Contract.Requires(f != null); - Contract.Requires(args == null || Contract.ForAll(args, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(f != null); + Debug.Assert(args == null || args.All(a => a != null)); CheckContextMatch(f); CheckContextMatch(args); @@ -2289,8 +2140,7 @@ namespace Microsoft.Z3 /// public Expr MkTermArray(ArrayExpr array) { - Contract.Requires(array != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(array != null); CheckContextMatch(array); return Expr.Create(this, Native.Z3_mk_array_default(nCtx, array.NativeObject)); @@ -2301,9 +2151,8 @@ namespace Microsoft.Z3 /// public Expr MkArrayExt(ArrayExpr arg1, ArrayExpr arg2) { - Contract.Requires(arg1 != null); - Contract.Requires(arg2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(arg1 != null); + Debug.Assert(arg2 != null); CheckContextMatch(arg1); CheckContextMatch(arg2); @@ -2318,8 +2167,7 @@ namespace Microsoft.Z3 /// public SetSort MkSetSort(Sort ty) { - Contract.Requires(ty != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ty != null); CheckContextMatch(ty); return new SetSort(this, ty); @@ -2330,8 +2178,7 @@ namespace Microsoft.Z3 /// public ArrayExpr MkEmptySet(Sort domain) { - Contract.Requires(domain != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(domain != null); CheckContextMatch(domain); return (ArrayExpr)Expr.Create(this, Native.Z3_mk_empty_set(nCtx, domain.NativeObject)); @@ -2342,8 +2189,7 @@ namespace Microsoft.Z3 /// public ArrayExpr MkFullSet(Sort domain) { - Contract.Requires(domain != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(domain != null); CheckContextMatch(domain); return (ArrayExpr)Expr.Create(this, Native.Z3_mk_full_set(nCtx, domain.NativeObject)); @@ -2354,9 +2200,8 @@ namespace Microsoft.Z3 /// public ArrayExpr MkSetAdd(ArrayExpr set, Expr element) { - Contract.Requires(set != null); - Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(set != null); + Debug.Assert(element != null); CheckContextMatch(set); CheckContextMatch(element); @@ -2369,9 +2214,8 @@ namespace Microsoft.Z3 /// public ArrayExpr MkSetDel(ArrayExpr set, Expr element) { - Contract.Requires(set != null); - Contract.Requires(element != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(set != null); + Debug.Assert(element != null); CheckContextMatch(set); CheckContextMatch(element); @@ -2383,8 +2227,8 @@ namespace Microsoft.Z3 /// public ArrayExpr MkSetUnion(params ArrayExpr[] args) { - Contract.Requires(args != null); - Contract.Requires(Contract.ForAll(args, a => a != null)); + Debug.Assert(args != null); + Debug.Assert(args.All(a => a != null)); CheckContextMatch(args); return (ArrayExpr)Expr.Create(this, Native.Z3_mk_set_union(nCtx, (uint)args.Length, AST.ArrayToNative(args))); @@ -2395,9 +2239,8 @@ namespace Microsoft.Z3 /// public ArrayExpr MkSetIntersection(params ArrayExpr[] args) { - Contract.Requires(args != null); - Contract.Requires(Contract.ForAll(args, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(args != null); + Debug.Assert(args.All(a => a != null)); CheckContextMatch(args); return (ArrayExpr)Expr.Create(this, Native.Z3_mk_set_intersect(nCtx, (uint)args.Length, AST.ArrayToNative(args))); @@ -2408,9 +2251,8 @@ namespace Microsoft.Z3 /// public ArrayExpr MkSetDifference(ArrayExpr arg1, ArrayExpr arg2) { - Contract.Requires(arg1 != null); - Contract.Requires(arg2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(arg1 != null); + Debug.Assert(arg2 != null); CheckContextMatch(arg1); CheckContextMatch(arg2); @@ -2422,8 +2264,7 @@ namespace Microsoft.Z3 /// public ArrayExpr MkSetComplement(ArrayExpr arg) { - Contract.Requires(arg != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(arg != null); CheckContextMatch(arg); return (ArrayExpr)Expr.Create(this, Native.Z3_mk_set_complement(nCtx, arg.NativeObject)); @@ -2434,9 +2275,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkSetMembership(Expr elem, ArrayExpr set) { - Contract.Requires(elem != null); - Contract.Requires(set != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(elem != null); + Debug.Assert(set != null); CheckContextMatch(elem); CheckContextMatch(set); @@ -2448,9 +2288,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkSetSubset(ArrayExpr arg1, ArrayExpr arg2) { - Contract.Requires(arg1 != null); - Contract.Requires(arg2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(arg1 != null); + Debug.Assert(arg2 != null); CheckContextMatch(arg1); CheckContextMatch(arg2); @@ -2466,8 +2305,7 @@ namespace Microsoft.Z3 /// public SeqExpr MkEmptySeq(Sort s) { - Contract.Requires(s != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); return new SeqExpr(this, Native.Z3_mk_seq_empty(nCtx, s.NativeObject)); } @@ -2476,8 +2314,7 @@ namespace Microsoft.Z3 /// public SeqExpr MkUnit(Expr elem) { - Contract.Requires(elem != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(elem != null); return new SeqExpr(this, Native.Z3_mk_seq_unit(nCtx, elem.NativeObject)); } @@ -2486,8 +2323,7 @@ namespace Microsoft.Z3 /// public SeqExpr MkString(string s) { - Contract.Requires(s != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); return new SeqExpr(this, Native.Z3_mk_string(nCtx, s)); } @@ -2496,9 +2332,8 @@ namespace Microsoft.Z3 /// public SeqExpr IntToString(Expr e) { - Contract.Requires(e != null); - Contract.Requires(e is ArithExpr); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(e != null); + Debug.Assert(e is ArithExpr); return new SeqExpr(this, Native.Z3_mk_int_to_str(nCtx, e.NativeObject)); } @@ -2507,9 +2342,8 @@ namespace Microsoft.Z3 /// public IntExpr StringToInt(Expr e) { - Contract.Requires(e != null); - Contract.Requires(e is SeqExpr); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(e != null); + Debug.Assert(e is SeqExpr); return new IntExpr(this, Native.Z3_mk_str_to_int(nCtx, e.NativeObject)); } @@ -2519,9 +2353,8 @@ namespace Microsoft.Z3 /// public SeqExpr MkConcat(params SeqExpr[] t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return new SeqExpr(this, Native.Z3_mk_seq_concat(nCtx, (uint)t.Length, AST.ArrayToNative(t))); @@ -2533,8 +2366,7 @@ namespace Microsoft.Z3 /// public IntExpr MkLength(SeqExpr s) { - Contract.Requires(s != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); return (IntExpr) Expr.Create(this, Native.Z3_mk_seq_length(nCtx, s.NativeObject)); } @@ -2543,9 +2375,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2) { - Contract.Requires(s1 != null); - Contract.Requires(s2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s1 != null); + Debug.Assert(s2 != null); CheckContextMatch(s1, s2); return new BoolExpr(this, Native.Z3_mk_seq_prefix(nCtx, s1.NativeObject, s2.NativeObject)); } @@ -2555,9 +2386,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2) { - Contract.Requires(s1 != null); - Contract.Requires(s2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s1 != null); + Debug.Assert(s2 != null); CheckContextMatch(s1, s2); return new BoolExpr(this, Native.Z3_mk_seq_suffix(nCtx, s1.NativeObject, s2.NativeObject)); } @@ -2567,9 +2397,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkContains(SeqExpr s1, SeqExpr s2) { - Contract.Requires(s1 != null); - Contract.Requires(s2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s1 != null); + Debug.Assert(s2 != null); CheckContextMatch(s1, s2); return new BoolExpr(this, Native.Z3_mk_seq_contains(nCtx, s1.NativeObject, s2.NativeObject)); } @@ -2579,9 +2408,8 @@ namespace Microsoft.Z3 /// public SeqExpr MkAt(SeqExpr s, IntExpr index) { - Contract.Requires(s != null); - Contract.Requires(index != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); + Debug.Assert(index != null); CheckContextMatch(s, index); return new SeqExpr(this, Native.Z3_mk_seq_at(nCtx, s.NativeObject, index.NativeObject)); } @@ -2591,10 +2419,9 @@ namespace Microsoft.Z3 /// public SeqExpr MkExtract(SeqExpr s, IntExpr offset, IntExpr length) { - Contract.Requires(s != null); - Contract.Requires(offset != null); - Contract.Requires(length != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); + Debug.Assert(offset != null); + Debug.Assert(length != null); CheckContextMatch(s, offset, length); return new SeqExpr(this, Native.Z3_mk_seq_extract(nCtx, s.NativeObject, offset.NativeObject, length.NativeObject)); } @@ -2604,10 +2431,9 @@ namespace Microsoft.Z3 /// public IntExpr MkIndexOf(SeqExpr s, SeqExpr substr, ArithExpr offset) { - Contract.Requires(s != null); - Contract.Requires(offset != null); - Contract.Requires(substr != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); + Debug.Assert(offset != null); + Debug.Assert(substr != null); CheckContextMatch(s, substr, offset); return new IntExpr(this, Native.Z3_mk_seq_index(nCtx, s.NativeObject, substr.NativeObject, offset.NativeObject)); } @@ -2617,10 +2443,9 @@ namespace Microsoft.Z3 /// public SeqExpr MkReplace(SeqExpr s, SeqExpr src, SeqExpr dst) { - Contract.Requires(s != null); - Contract.Requires(src != null); - Contract.Requires(dst != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); + Debug.Assert(src != null); + Debug.Assert(dst != null); CheckContextMatch(s, src, dst); return new SeqExpr(this, Native.Z3_mk_seq_replace(nCtx, s.NativeObject, src.NativeObject, dst.NativeObject)); } @@ -2630,8 +2455,7 @@ namespace Microsoft.Z3 /// public ReExpr MkToRe(SeqExpr s) { - Contract.Requires(s != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); return new ReExpr(this, Native.Z3_mk_seq_to_re(nCtx, s.NativeObject)); } @@ -2641,9 +2465,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkInRe(SeqExpr s, ReExpr re) { - Contract.Requires(s != null); - Contract.Requires(re != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); + Debug.Assert(re != null); CheckContextMatch(s, re); return new BoolExpr(this, Native.Z3_mk_seq_in_re(nCtx, s.NativeObject, re.NativeObject)); } @@ -2653,8 +2476,7 @@ namespace Microsoft.Z3 /// public ReExpr MkStar(ReExpr re) { - Contract.Requires(re != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(re != null); return new ReExpr(this, Native.Z3_mk_re_star(nCtx, re.NativeObject)); } @@ -2663,8 +2485,7 @@ namespace Microsoft.Z3 /// public ReExpr MkLoop(ReExpr re, uint lo, uint hi = 0) { - Contract.Requires(re != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(re != null); return new ReExpr(this, Native.Z3_mk_re_loop(nCtx, re.NativeObject, lo, hi)); } @@ -2673,8 +2494,7 @@ namespace Microsoft.Z3 /// public ReExpr MkPlus(ReExpr re) { - Contract.Requires(re != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(re != null); return new ReExpr(this, Native.Z3_mk_re_plus(nCtx, re.NativeObject)); } @@ -2683,8 +2503,7 @@ namespace Microsoft.Z3 /// public ReExpr MkOption(ReExpr re) { - Contract.Requires(re != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(re != null); return new ReExpr(this, Native.Z3_mk_re_option(nCtx, re.NativeObject)); } @@ -2693,8 +2512,7 @@ namespace Microsoft.Z3 /// public ReExpr MkComplement(ReExpr re) { - Contract.Requires(re != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(re != null); return new ReExpr(this, Native.Z3_mk_re_complement(nCtx, re.NativeObject)); } @@ -2703,9 +2521,8 @@ namespace Microsoft.Z3 /// public ReExpr MkConcat(params ReExpr[] t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return new ReExpr(this, Native.Z3_mk_re_concat(nCtx, (uint)t.Length, AST.ArrayToNative(t))); @@ -2716,9 +2533,8 @@ namespace Microsoft.Z3 /// public ReExpr MkUnion(params ReExpr[] t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return new ReExpr(this, Native.Z3_mk_re_union(nCtx, (uint)t.Length, AST.ArrayToNative(t))); @@ -2729,9 +2545,8 @@ namespace Microsoft.Z3 /// public ReExpr MkIntersect(params ReExpr[] t) { - Contract.Requires(t != null); - Contract.Requires(Contract.ForAll(t, a => a != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != null)); CheckContextMatch(t); return new ReExpr(this, Native.Z3_mk_re_intersect(nCtx, (uint)t.Length, AST.ArrayToNative(t))); @@ -2742,8 +2557,7 @@ namespace Microsoft.Z3 /// public ReExpr MkEmptyRe(Sort s) { - Contract.Requires(s != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); return new ReExpr(this, Native.Z3_mk_re_empty(nCtx, s.NativeObject)); } @@ -2752,8 +2566,7 @@ namespace Microsoft.Z3 /// public ReExpr MkFullRe(Sort s) { - Contract.Requires(s != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); return new ReExpr(this, Native.Z3_mk_re_full(nCtx, s.NativeObject)); } @@ -2763,9 +2576,8 @@ namespace Microsoft.Z3 /// public ReExpr MkRange(SeqExpr lo, SeqExpr hi) { - Contract.Requires(lo != null); - Contract.Requires(hi != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(lo != null); + Debug.Assert(hi != null); CheckContextMatch(lo, hi); return new ReExpr(this, Native.Z3_mk_re_range(nCtx, lo.NativeObject, hi.NativeObject)); } @@ -2779,8 +2591,7 @@ namespace Microsoft.Z3 /// public BoolExpr MkAtMost(IEnumerable args, uint k) { - Contract.Requires(args != null); - Contract.Requires(Contract.Result() != null); + Debug.Assert(args != null); CheckContextMatch(args); return new BoolExpr(this, Native.Z3_mk_atmost(nCtx, (uint) args.Count(), AST.EnumToNative(args), k)); @@ -2791,8 +2602,7 @@ namespace Microsoft.Z3 /// public BoolExpr MkAtLeast(IEnumerable args, uint k) { - Contract.Requires(args != null); - Contract.Requires(Contract.Result() != null); + Debug.Assert(args != null); CheckContextMatch(args); return new BoolExpr(this, Native.Z3_mk_atleast(nCtx, (uint) args.Count(), AST.EnumToNative(args), k)); @@ -2803,10 +2613,9 @@ namespace Microsoft.Z3 /// public BoolExpr MkPBLe(int[] coeffs, BoolExpr[] args, int k) { - Contract.Requires(args != null); - Contract.Requires(coeffs != null); - Contract.Requires(args.Length == coeffs.Length); - Contract.Requires(Contract.Result() != null); + Debug.Assert(args != null); + Debug.Assert(coeffs != null); + Debug.Assert(args.Length == coeffs.Length); CheckContextMatch(args); return new BoolExpr(this, Native.Z3_mk_pble(nCtx, (uint) args.Length, AST.ArrayToNative(args), @@ -2818,10 +2627,9 @@ namespace Microsoft.Z3 /// public BoolExpr MkPBGe(int[] coeffs, BoolExpr[] args, int k) { - Contract.Requires(args != null); - Contract.Requires(coeffs != null); - Contract.Requires(args.Length == coeffs.Length); - Contract.Requires(Contract.Result() != null); + Debug.Assert(args != null); + Debug.Assert(coeffs != null); + Debug.Assert(args.Length == coeffs.Length); CheckContextMatch(args); return new BoolExpr(this, Native.Z3_mk_pbge(nCtx, (uint) args.Length, AST.ArrayToNative(args), @@ -2832,10 +2640,9 @@ namespace Microsoft.Z3 /// public BoolExpr MkPBEq(int[] coeffs, BoolExpr[] args, int k) { - Contract.Requires(args != null); - Contract.Requires(coeffs != null); - Contract.Requires(args.Length == coeffs.Length); - Contract.Requires(Contract.Result() != null); + Debug.Assert(args != null); + Debug.Assert(coeffs != null); + Debug.Assert(args.Length == coeffs.Length); CheckContextMatch(args); return new BoolExpr(this, Native.Z3_mk_pbeq(nCtx, (uint) args.Length, AST.ArrayToNative(args), @@ -2854,8 +2661,7 @@ namespace Microsoft.Z3 /// A Term with value and sort public Expr MkNumeral(string v, Sort ty) { - Contract.Requires(ty != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ty != null); CheckContextMatch(ty); return Expr.Create(this, Native.Z3_mk_numeral(nCtx, v, ty.NativeObject)); @@ -2870,8 +2676,7 @@ namespace Microsoft.Z3 /// A Term with value and type public Expr MkNumeral(int v, Sort ty) { - Contract.Requires(ty != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ty != null); CheckContextMatch(ty); return Expr.Create(this, Native.Z3_mk_int(nCtx, v, ty.NativeObject)); @@ -2886,8 +2691,7 @@ namespace Microsoft.Z3 /// A Term with value and type public Expr MkNumeral(uint v, Sort ty) { - Contract.Requires(ty != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ty != null); CheckContextMatch(ty); return Expr.Create(this, Native.Z3_mk_unsigned_int(nCtx, v, ty.NativeObject)); @@ -2902,8 +2706,7 @@ namespace Microsoft.Z3 /// A Term with value and type public Expr MkNumeral(long v, Sort ty) { - Contract.Requires(ty != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ty != null); CheckContextMatch(ty); return Expr.Create(this, Native.Z3_mk_int64(nCtx, v, ty.NativeObject)); @@ -2918,8 +2721,7 @@ namespace Microsoft.Z3 /// A Term with value and type public Expr MkNumeral(ulong v, Sort ty) { - Contract.Requires(ty != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ty != null); CheckContextMatch(ty); return Expr.Create(this, Native.Z3_mk_unsigned_int64(nCtx, v, ty.NativeObject)); @@ -2939,9 +2741,6 @@ namespace Microsoft.Z3 if (den == 0) throw new Z3Exception("Denominator is zero"); - Contract.Ensures(Contract.Result() != null); - Contract.EndContractBlock(); - return new RatNum(this, Native.Z3_mk_real(nCtx, num, den)); } @@ -2952,7 +2751,6 @@ namespace Microsoft.Z3 /// A Term with value and sort Real public RatNum MkReal(string v) { - Contract.Ensures(Contract.Result() != null); return new RatNum(this, Native.Z3_mk_numeral(nCtx, v, RealSort.NativeObject)); } @@ -2964,7 +2762,6 @@ namespace Microsoft.Z3 /// A Term with value and sort Real public RatNum MkReal(int v) { - Contract.Ensures(Contract.Result() != null); return new RatNum(this, Native.Z3_mk_int(nCtx, v, RealSort.NativeObject)); } @@ -2976,7 +2773,6 @@ namespace Microsoft.Z3 /// A Term with value and sort Real public RatNum MkReal(uint v) { - Contract.Ensures(Contract.Result() != null); return new RatNum(this, Native.Z3_mk_unsigned_int(nCtx, v, RealSort.NativeObject)); } @@ -2988,7 +2784,6 @@ namespace Microsoft.Z3 /// A Term with value and sort Real public RatNum MkReal(long v) { - Contract.Ensures(Contract.Result() != null); return new RatNum(this, Native.Z3_mk_int64(nCtx, v, RealSort.NativeObject)); } @@ -3000,7 +2795,6 @@ namespace Microsoft.Z3 /// A Term with value and sort Real public RatNum MkReal(ulong v) { - Contract.Ensures(Contract.Result() != null); return new RatNum(this, Native.Z3_mk_unsigned_int64(nCtx, v, RealSort.NativeObject)); } @@ -3013,7 +2807,6 @@ namespace Microsoft.Z3 /// A string representing the Term value in decimal notation. public IntNum MkInt(string v) { - Contract.Ensures(Contract.Result() != null); return new IntNum(this, Native.Z3_mk_numeral(nCtx, v, IntSort.NativeObject)); } @@ -3025,7 +2818,6 @@ namespace Microsoft.Z3 /// A Term with value and sort Integer public IntNum MkInt(int v) { - Contract.Ensures(Contract.Result() != null); return new IntNum(this, Native.Z3_mk_int(nCtx, v, IntSort.NativeObject)); } @@ -3037,7 +2829,6 @@ namespace Microsoft.Z3 /// A Term with value and sort Integer public IntNum MkInt(uint v) { - Contract.Ensures(Contract.Result() != null); return new IntNum(this, Native.Z3_mk_unsigned_int(nCtx, v, IntSort.NativeObject)); } @@ -3049,7 +2840,6 @@ namespace Microsoft.Z3 /// A Term with value and sort Integer public IntNum MkInt(long v) { - Contract.Ensures(Contract.Result() != null); return new IntNum(this, Native.Z3_mk_int64(nCtx, v, IntSort.NativeObject)); } @@ -3061,7 +2851,6 @@ namespace Microsoft.Z3 /// A Term with value and sort Integer public IntNum MkInt(ulong v) { - Contract.Ensures(Contract.Result() != null); return new IntNum(this, Native.Z3_mk_unsigned_int64(nCtx, v, IntSort.NativeObject)); } @@ -3075,7 +2864,6 @@ namespace Microsoft.Z3 /// the size of the bit-vector public BitVecNum MkBV(string v, uint size) { - Contract.Ensures(Contract.Result() != null); return (BitVecNum)MkNumeral(v, MkBitVecSort(size)); } @@ -3087,7 +2875,6 @@ namespace Microsoft.Z3 /// the size of the bit-vector public BitVecNum MkBV(int v, uint size) { - Contract.Ensures(Contract.Result() != null); return (BitVecNum)MkNumeral(v, MkBitVecSort(size)); } @@ -3099,7 +2886,6 @@ namespace Microsoft.Z3 /// the size of the bit-vector public BitVecNum MkBV(uint v, uint size) { - Contract.Ensures(Contract.Result() != null); return (BitVecNum)MkNumeral(v, MkBitVecSort(size)); } @@ -3111,7 +2897,6 @@ namespace Microsoft.Z3 /// the size of the bit-vector public BitVecNum MkBV(long v, uint size) { - Contract.Ensures(Contract.Result() != null); return (BitVecNum)MkNumeral(v, MkBitVecSort(size)); } @@ -3123,7 +2908,6 @@ namespace Microsoft.Z3 /// the size of the bit-vector public BitVecNum MkBV(ulong v, uint size) { - Contract.Ensures(Contract.Result() != null); return (BitVecNum)MkNumeral(v, MkBitVecSort(size)); } @@ -3134,7 +2918,6 @@ namespace Microsoft.Z3 /// An array of bits representing the bit-vector. Least significant bit is at position 0. public BitVecNum MkBV(bool[] bits) { - Contract.Ensures(Contract.Result() != null); byte[] _bits = new byte[bits.Length]; for (int i = 0; i < bits.Length; ++i) _bits[i] = (byte)(bits[i] ? 1 : 0); return (BitVecNum)Expr.Create(this, Native.Z3_mk_bv_numeral(nCtx, (uint)bits.Length, _bits)); @@ -3172,16 +2955,15 @@ namespace Microsoft.Z3 /// optional symbol to track skolem constants. public Quantifier MkForall(Sort[] sorts, Symbol[] names, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { - Contract.Requires(sorts != null); - Contract.Requires(names != null); - Contract.Requires(body != null); - Contract.Requires(sorts.Length == names.Length); - Contract.Requires(Contract.ForAll(sorts, s => s != null)); - Contract.Requires(Contract.ForAll(names, n => n != null)); - Contract.Requires(patterns == null || Contract.ForAll(patterns, p => p != null)); - Contract.Requires(noPatterns == null || Contract.ForAll(noPatterns, np => np != null)); + Debug.Assert(sorts != null); + Debug.Assert(names != null); + Debug.Assert(body != null); + Debug.Assert(sorts.Length == names.Length); + Debug.Assert(sorts.All(s => s != null)); + Debug.Assert(names.All(n => n != null)); + Debug.Assert(patterns == null || patterns.All(p => p != null)); + Debug.Assert(noPatterns == null || noPatterns.All(np => np != null)); - Contract.Ensures(Contract.Result() != null); return new Quantifier(this, true, sorts, names, body, weight, patterns, noPatterns, quantifierID, skolemID); } @@ -3197,12 +2979,11 @@ namespace Microsoft.Z3 /// public Quantifier MkForall(Expr[] boundConstants, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { - Contract.Requires(body != null); - Contract.Requires(boundConstants == null || Contract.ForAll(boundConstants, b => b != null)); - Contract.Requires(patterns == null || Contract.ForAll(patterns, p => p != null)); - Contract.Requires(noPatterns == null || Contract.ForAll(noPatterns, np => np != null)); + Debug.Assert(body != null); + Debug.Assert(boundConstants == null || boundConstants.All(b => b != null)); + Debug.Assert(patterns == null || patterns.All(p => p != null)); + Debug.Assert(noPatterns == null || noPatterns.All(np => np != null)); - Contract.Ensures(Contract.Result() != null); return new Quantifier(this, true, boundConstants, body, weight, patterns, noPatterns, quantifierID, skolemID); } @@ -3216,15 +2997,14 @@ namespace Microsoft.Z3 /// public Quantifier MkExists(Sort[] sorts, Symbol[] names, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { - Contract.Requires(sorts != null); - Contract.Requires(names != null); - Contract.Requires(body != null); - Contract.Requires(sorts.Length == names.Length); - Contract.Requires(Contract.ForAll(sorts, s => s != null)); - Contract.Requires(Contract.ForAll(names, n => n != null)); - Contract.Requires(patterns == null || Contract.ForAll(patterns, p => p != null)); - Contract.Requires(noPatterns == null || Contract.ForAll(noPatterns, np => np != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(sorts != null); + Debug.Assert(names != null); + Debug.Assert(body != null); + Debug.Assert(sorts.Length == names.Length); + Debug.Assert(sorts.All(s => s != null)); + Debug.Assert(names.All(n => n != null)); + Debug.Assert(patterns == null || patterns.All(p => p != null)); + Debug.Assert(noPatterns == null || noPatterns.All(np => np != null)); return new Quantifier(this, false, sorts, names, body, weight, patterns, noPatterns, quantifierID, skolemID); } @@ -3239,11 +3019,10 @@ namespace Microsoft.Z3 /// public Quantifier MkExists(Expr[] boundConstants, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { - Contract.Requires(body != null); - Contract.Requires(boundConstants == null || Contract.ForAll(boundConstants, n => n != null)); - Contract.Requires(patterns == null || Contract.ForAll(patterns, p => p != null)); - Contract.Requires(noPatterns == null || Contract.ForAll(noPatterns, np => np != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(body != null); + Debug.Assert(boundConstants == null || boundConstants.All(n => n != null)); + Debug.Assert(patterns == null || patterns.All(p => p != null)); + Debug.Assert(noPatterns == null || noPatterns.All(np => np != null)); return new Quantifier(this, false, boundConstants, body, weight, patterns, noPatterns, quantifierID, skolemID); } @@ -3255,16 +3034,15 @@ namespace Microsoft.Z3 /// public Quantifier MkQuantifier(bool universal, Sort[] sorts, Symbol[] names, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { - Contract.Requires(body != null); - Contract.Requires(names != null); - Contract.Requires(sorts != null); - Contract.Requires(sorts.Length == names.Length); - Contract.Requires(Contract.ForAll(sorts, s => s != null)); - Contract.Requires(Contract.ForAll(names, n => n != null)); - Contract.Requires(patterns == null || Contract.ForAll(patterns, p => p != null)); - Contract.Requires(noPatterns == null || Contract.ForAll(noPatterns, np => np != null)); + Debug.Assert(body != null); + Debug.Assert(names != null); + Debug.Assert(sorts != null); + Debug.Assert(sorts.Length == names.Length); + Debug.Assert(sorts.All(s => s != null)); + Debug.Assert(names.All(n => n != null)); + Debug.Assert(patterns == null || patterns.All(p => p != null)); + Debug.Assert(noPatterns == null || noPatterns.All(np => np != null)); - Contract.Ensures(Contract.Result() != null); if (universal) return MkForall(sorts, names, body, weight, patterns, noPatterns, quantifierID, skolemID); @@ -3279,12 +3057,11 @@ namespace Microsoft.Z3 /// public Quantifier MkQuantifier(bool universal, Expr[] boundConstants, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { - Contract.Requires(body != null); - Contract.Requires(boundConstants == null || Contract.ForAll(boundConstants, n => n != null)); - Contract.Requires(patterns == null || Contract.ForAll(patterns, p => p != null)); - Contract.Requires(noPatterns == null || Contract.ForAll(noPatterns, np => np != null)); + Debug.Assert(body != null); + Debug.Assert(boundConstants == null || boundConstants.All(n => n != null)); + Debug.Assert(patterns == null || patterns.All(p => p != null)); + Debug.Assert(noPatterns == null || noPatterns.All(np => np != null)); - Contract.Ensures(Contract.Result() != null); if (universal) return MkForall(boundConstants, body, weight, patterns, noPatterns, quantifierID, skolemID); @@ -3312,13 +3089,12 @@ namespace Microsoft.Z3 /// the body of the quantifier. public Lambda MkLambda(Sort[] sorts, Symbol[] names, Expr body) { - Contract.Requires(sorts != null); - Contract.Requires(names != null); - Contract.Requires(body != null); - Contract.Requires(sorts.Length == names.Length); - Contract.Requires(Contract.ForAll(sorts, s => s != null)); - Contract.Requires(Contract.ForAll(names, n => n != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(sorts != null); + Debug.Assert(names != null); + Debug.Assert(body != null); + Debug.Assert(sorts.Length == names.Length); + Debug.Assert(sorts.All(s => s != null)); + Debug.Assert(names.All(n => n != null)); return new Lambda(this, sorts, names, body); } @@ -3332,9 +3108,8 @@ namespace Microsoft.Z3 /// public Lambda MkLambda(Expr[] boundConstants, Expr body) { - Contract.Requires(body != null); - Contract.Requires(boundConstants != null && Contract.ForAll(boundConstants, b => b != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(body != null); + Debug.Assert(boundConstants != null && boundConstants.All(b => b != null)); return new Lambda(this, boundConstants, body); } @@ -3374,7 +3149,6 @@ namespace Microsoft.Z3 /// A conjunction of assertions in the scope (up to push/pop) at the end of the string. public BoolExpr[] ParseSMTLIB2String(string str, Symbol[] sortNames = null, Sort[] sorts = null, Symbol[] declNames = null, FuncDecl[] decls = null) { - Contract.Ensures(Contract.Result() != null); uint csn = Symbol.ArrayLength(sortNames); uint cs = Sort.ArrayLength(sorts); @@ -3394,7 +3168,6 @@ namespace Microsoft.Z3 /// public BoolExpr[] ParseSMTLIB2File(string fileName, Symbol[] sortNames = null, Sort[] sorts = null, Symbol[] declNames = null, FuncDecl[] decls = null) { - Contract.Ensures(Contract.Result() != null); uint csn = Symbol.ArrayLength(sortNames); uint cs = Sort.ArrayLength(sorts); @@ -3422,7 +3195,6 @@ namespace Microsoft.Z3 /// Indicates whether proof generation should be enabled. public Goal MkGoal(bool models = true, bool unsatCores = false, bool proofs = false) { - Contract.Ensures(Contract.Result() != null); return new Goal(this, models, unsatCores, proofs); } @@ -3434,7 +3206,6 @@ namespace Microsoft.Z3 /// public Params MkParams() { - Contract.Ensures(Contract.Result() != null); return new Params(this); } @@ -3456,7 +3227,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumTactics; string[] res = new string[n]; @@ -3471,7 +3241,6 @@ namespace Microsoft.Z3 /// public string TacticDescription(string name) { - Contract.Ensures(Contract.Result() != null); return Native.Z3_tactic_get_descr(nCtx, name); } @@ -3481,7 +3250,6 @@ namespace Microsoft.Z3 /// public Tactic MkTactic(string name) { - Contract.Ensures(Contract.Result() != null); return new Tactic(this, name); } @@ -3492,10 +3260,9 @@ namespace Microsoft.Z3 /// public Tactic AndThen(Tactic t1, Tactic t2, params Tactic[] ts) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Requires(ts == null || Contract.ForAll(0, ts.Length, j => ts[j] != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); + // Debug.Assert(ts == null || Contract.ForAll(0, ts.Length, j => ts[j] != null)); CheckContextMatch(t1); @@ -3527,10 +3294,9 @@ namespace Microsoft.Z3 /// public Tactic Then(Tactic t1, Tactic t2, params Tactic[] ts) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Requires(ts == null || Contract.ForAll(0, ts.Length, j => ts[j] != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); + // Debug.Assert(ts == null || Contract.ForAll(0, ts.Length, j => ts[j] != null)); return AndThen(t1, t2, ts); } @@ -3541,9 +3307,8 @@ namespace Microsoft.Z3 /// public Tactic OrElse(Tactic t1, Tactic t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -3558,8 +3323,7 @@ namespace Microsoft.Z3 /// public Tactic TryFor(Tactic t, uint ms) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new Tactic(this, Native.Z3_tactic_try_for(nCtx, t.NativeObject, ms)); @@ -3574,9 +3338,8 @@ namespace Microsoft.Z3 /// public Tactic When(Probe p, Tactic t) { - Contract.Requires(p != null); - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(p != null); + Debug.Assert(t != null); CheckContextMatch(t); CheckContextMatch(p); @@ -3589,10 +3352,9 @@ namespace Microsoft.Z3 /// public Tactic Cond(Probe p, Tactic t1, Tactic t2) { - Contract.Requires(p != null); - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(p != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(p); CheckContextMatch(t1); @@ -3606,8 +3368,7 @@ namespace Microsoft.Z3 /// public Tactic Repeat(Tactic t, uint max = uint.MaxValue) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); CheckContextMatch(t); return new Tactic(this, Native.Z3_tactic_repeat(nCtx, t.NativeObject, max)); @@ -3618,7 +3379,6 @@ namespace Microsoft.Z3 /// public Tactic Skip() { - Contract.Ensures(Contract.Result() != null); return new Tactic(this, Native.Z3_tactic_skip(nCtx)); } @@ -3628,7 +3388,6 @@ namespace Microsoft.Z3 /// public Tactic Fail() { - Contract.Ensures(Contract.Result() != null); return new Tactic(this, Native.Z3_tactic_fail(nCtx)); } @@ -3638,8 +3397,7 @@ namespace Microsoft.Z3 /// public Tactic FailIf(Probe p) { - Contract.Requires(p != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(p != null); CheckContextMatch(p); return new Tactic(this, Native.Z3_tactic_fail_if(nCtx, p.NativeObject)); @@ -3651,7 +3409,6 @@ namespace Microsoft.Z3 /// public Tactic FailIfNotDecided() { - Contract.Ensures(Contract.Result() != null); return new Tactic(this, Native.Z3_tactic_fail_if_not_decided(nCtx)); } @@ -3661,9 +3418,8 @@ namespace Microsoft.Z3 /// public Tactic UsingParams(Tactic t, Params p) { - Contract.Requires(t != null); - Contract.Requires(p != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(p != null); CheckContextMatch(t); CheckContextMatch(p); @@ -3676,9 +3432,8 @@ namespace Microsoft.Z3 /// Alias for UsingParams public Tactic With(Tactic t, Params p) { - Contract.Requires(t != null); - Contract.Requires(p != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); + Debug.Assert(p != null); return UsingParams(t, p); } @@ -3688,8 +3443,7 @@ namespace Microsoft.Z3 /// public Tactic ParOr(params Tactic[] t) { - Contract.Requires(t == null || Contract.ForAll(t, tactic => tactic != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t == null || t.All(tactic => tactic != null)); CheckContextMatch(t); return new Tactic(this, Native.Z3_tactic_par_or(nCtx, Tactic.ArrayLength(t), Tactic.ArrayToNative(t))); @@ -3701,9 +3455,8 @@ namespace Microsoft.Z3 /// public Tactic ParAndThen(Tactic t1, Tactic t2) { - Contract.Requires(t1 != null); - Contract.Requires(t2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t1 != null); + Debug.Assert(t2 != null); CheckContextMatch(t1); CheckContextMatch(t2); @@ -3736,7 +3489,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumProbes; string[] res = new string[n]; @@ -3751,7 +3503,6 @@ namespace Microsoft.Z3 /// public string ProbeDescription(string name) { - Contract.Ensures(Contract.Result() != null); return Native.Z3_probe_get_descr(nCtx, name); } @@ -3761,7 +3512,6 @@ namespace Microsoft.Z3 /// public Probe MkProbe(string name) { - Contract.Ensures(Contract.Result() != null); return new Probe(this, name); } @@ -3771,7 +3521,6 @@ namespace Microsoft.Z3 /// public Probe ConstProbe(double val) { - Contract.Ensures(Contract.Result() != null); return new Probe(this, Native.Z3_probe_const(nCtx, val)); } @@ -3782,9 +3531,8 @@ namespace Microsoft.Z3 /// public Probe Lt(Probe p1, Probe p2) { - Contract.Requires(p1 != null); - Contract.Requires(p2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(p1 != null); + Debug.Assert(p2 != null); CheckContextMatch(p1); CheckContextMatch(p2); @@ -3797,9 +3545,8 @@ namespace Microsoft.Z3 /// public Probe Gt(Probe p1, Probe p2) { - Contract.Requires(p1 != null); - Contract.Requires(p2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(p1 != null); + Debug.Assert(p2 != null); CheckContextMatch(p1); CheckContextMatch(p2); @@ -3812,9 +3559,8 @@ namespace Microsoft.Z3 /// public Probe Le(Probe p1, Probe p2) { - Contract.Requires(p1 != null); - Contract.Requires(p2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(p1 != null); + Debug.Assert(p2 != null); CheckContextMatch(p1); CheckContextMatch(p2); @@ -3827,9 +3573,8 @@ namespace Microsoft.Z3 /// public Probe Ge(Probe p1, Probe p2) { - Contract.Requires(p1 != null); - Contract.Requires(p2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(p1 != null); + Debug.Assert(p2 != null); CheckContextMatch(p1); CheckContextMatch(p2); @@ -3842,9 +3587,8 @@ namespace Microsoft.Z3 /// public Probe Eq(Probe p1, Probe p2) { - Contract.Requires(p1 != null); - Contract.Requires(p2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(p1 != null); + Debug.Assert(p2 != null); CheckContextMatch(p1); CheckContextMatch(p2); @@ -3857,9 +3601,8 @@ namespace Microsoft.Z3 /// public Probe And(Probe p1, Probe p2) { - Contract.Requires(p1 != null); - Contract.Requires(p2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(p1 != null); + Debug.Assert(p2 != null); CheckContextMatch(p1); CheckContextMatch(p2); @@ -3872,9 +3615,8 @@ namespace Microsoft.Z3 /// public Probe Or(Probe p1, Probe p2) { - Contract.Requires(p1 != null); - Contract.Requires(p2 != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(p1 != null); + Debug.Assert(p2 != null); CheckContextMatch(p1); CheckContextMatch(p2); @@ -3887,8 +3629,7 @@ namespace Microsoft.Z3 /// public Probe Not(Probe p) { - Contract.Requires(p != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(p != null); CheckContextMatch(p); return new Probe(this, Native.Z3_probe_not(nCtx, p.NativeObject)); @@ -3906,7 +3647,6 @@ namespace Microsoft.Z3 /// public Solver MkSolver(Symbol logic = null) { - Contract.Ensures(Contract.Result() != null); if (logic == null) return new Solver(this, Native.Z3_mk_solver(nCtx)); @@ -3920,7 +3660,6 @@ namespace Microsoft.Z3 /// public Solver MkSolver(string logic) { - Contract.Ensures(Contract.Result() != null); return MkSolver(MkSymbol(logic)); } @@ -3930,7 +3669,6 @@ namespace Microsoft.Z3 /// public Solver MkSimpleSolver() { - Contract.Ensures(Contract.Result() != null); return new Solver(this, Native.Z3_mk_simple_solver(nCtx)); } @@ -3944,8 +3682,7 @@ namespace Microsoft.Z3 /// public Solver MkSolver(Tactic t) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); return new Solver(this, Native.Z3_mk_solver_from_tactic(nCtx, t.NativeObject)); } @@ -3957,7 +3694,6 @@ namespace Microsoft.Z3 /// public Fixedpoint MkFixedpoint() { - Contract.Ensures(Contract.Result() != null); return new Fixedpoint(this); } @@ -3969,7 +3705,6 @@ namespace Microsoft.Z3 /// public Optimize MkOptimize() { - Contract.Ensures(Contract.Result() != null); return new Optimize(this); } @@ -3984,7 +3719,6 @@ namespace Microsoft.Z3 /// public FPRMSort MkFPRoundingModeSort() { - Contract.Ensures(Contract.Result() != null); return new FPRMSort(this); } #endregion @@ -3995,7 +3729,6 @@ namespace Microsoft.Z3 /// public FPRMExpr MkFPRoundNearestTiesToEven() { - Contract.Ensures(Contract.Result() != null); return new FPRMExpr(this, Native.Z3_mk_fpa_round_nearest_ties_to_even(nCtx)); } @@ -4004,7 +3737,6 @@ namespace Microsoft.Z3 /// public FPRMNum MkFPRNE() { - Contract.Ensures(Contract.Result() != null); return new FPRMNum(this, Native.Z3_mk_fpa_rne(nCtx)); } @@ -4013,7 +3745,6 @@ namespace Microsoft.Z3 /// public FPRMNum MkFPRoundNearestTiesToAway() { - Contract.Ensures(Contract.Result() != null); return new FPRMNum(this, Native.Z3_mk_fpa_round_nearest_ties_to_away(nCtx)); } @@ -4022,7 +3753,6 @@ namespace Microsoft.Z3 /// public FPRMNum MkFPRNA() { - Contract.Ensures(Contract.Result() != null); return new FPRMNum(this, Native.Z3_mk_fpa_rna(nCtx)); } @@ -4031,7 +3761,6 @@ namespace Microsoft.Z3 /// public FPRMNum MkFPRoundTowardPositive() { - Contract.Ensures(Contract.Result() != null); return new FPRMNum(this, Native.Z3_mk_fpa_round_toward_positive(nCtx)); } @@ -4040,7 +3769,6 @@ namespace Microsoft.Z3 /// public FPRMNum MkFPRTP() { - Contract.Ensures(Contract.Result() != null); return new FPRMNum(this, Native.Z3_mk_fpa_rtp(nCtx)); } @@ -4049,7 +3777,6 @@ namespace Microsoft.Z3 /// public FPRMNum MkFPRoundTowardNegative() { - Contract.Ensures(Contract.Result() != null); return new FPRMNum(this, Native.Z3_mk_fpa_round_toward_negative(nCtx)); } @@ -4058,7 +3785,6 @@ namespace Microsoft.Z3 /// public FPRMNum MkFPRTN() { - Contract.Ensures(Contract.Result() != null); return new FPRMNum(this, Native.Z3_mk_fpa_rtn(nCtx)); } @@ -4067,7 +3793,6 @@ namespace Microsoft.Z3 /// public FPRMNum MkFPRoundTowardZero() { - Contract.Ensures(Contract.Result() != null); return new FPRMNum(this, Native.Z3_mk_fpa_round_toward_zero(nCtx)); } @@ -4076,7 +3801,6 @@ namespace Microsoft.Z3 /// public FPRMNum MkFPRTZ() { - Contract.Ensures(Contract.Result() != null); return new FPRMNum(this, Native.Z3_mk_fpa_rtz(nCtx)); } #endregion @@ -4090,7 +3814,6 @@ namespace Microsoft.Z3 /// significand bits in the FloatingPoint sort. public FPSort MkFPSort(uint ebits, uint sbits) { - Contract.Ensures(Contract.Result() != null); return new FPSort(this, ebits, sbits); } @@ -4099,7 +3822,6 @@ namespace Microsoft.Z3 /// public FPSort MkFPSortHalf() { - Contract.Ensures(Contract.Result() != null); return new FPSort(this, Native.Z3_mk_fpa_sort_half(nCtx)); } @@ -4108,7 +3830,6 @@ namespace Microsoft.Z3 /// public FPSort MkFPSort16() { - Contract.Ensures(Contract.Result() != null); return new FPSort(this, Native.Z3_mk_fpa_sort_16(nCtx)); } @@ -4117,7 +3838,6 @@ namespace Microsoft.Z3 /// public FPSort MkFPSortSingle() { - Contract.Ensures(Contract.Result() != null); return new FPSort(this, Native.Z3_mk_fpa_sort_single(nCtx)); } @@ -4126,7 +3846,6 @@ namespace Microsoft.Z3 /// public FPSort MkFPSort32() { - Contract.Ensures(Contract.Result() != null); return new FPSort(this, Native.Z3_mk_fpa_sort_32(nCtx)); } @@ -4135,7 +3854,6 @@ namespace Microsoft.Z3 /// public FPSort MkFPSortDouble() { - Contract.Ensures(Contract.Result() != null); return new FPSort(this, Native.Z3_mk_fpa_sort_double(nCtx)); } @@ -4144,7 +3862,6 @@ namespace Microsoft.Z3 /// public FPSort MkFPSort64() { - Contract.Ensures(Contract.Result() != null); return new FPSort(this, Native.Z3_mk_fpa_sort_64(nCtx)); } @@ -4153,7 +3870,6 @@ namespace Microsoft.Z3 /// public FPSort MkFPSortQuadruple() { - Contract.Ensures(Contract.Result() != null); return new FPSort(this, Native.Z3_mk_fpa_sort_quadruple(nCtx)); } @@ -4162,7 +3878,6 @@ namespace Microsoft.Z3 /// public FPSort MkFPSort128() { - Contract.Ensures(Contract.Result() != null); return new FPSort(this, Native.Z3_mk_fpa_sort_128(nCtx)); } #endregion @@ -4174,7 +3889,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNaN(FPSort s) { - Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_nan(nCtx, s.NativeObject)); } @@ -4185,7 +3899,6 @@ namespace Microsoft.Z3 /// indicates whether the result should be negative. public FPNum MkFPInf(FPSort s, bool negative) { - Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_inf(nCtx, s.NativeObject, (byte)(negative ? 1 : 0))); } @@ -4196,7 +3909,6 @@ namespace Microsoft.Z3 /// indicates whether the result should be negative. public FPNum MkFPZero(FPSort s, bool negative) { - Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_zero(nCtx, s.NativeObject, (byte)(negative ? 1 : 0))); } @@ -4207,7 +3919,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNumeral(float v, FPSort s) { - Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_numeral_float(nCtx, v, s.NativeObject)); } @@ -4218,7 +3929,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNumeral(double v, FPSort s) { - Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_numeral_double(nCtx, v, s.NativeObject)); } @@ -4229,7 +3939,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNumeral(int v, FPSort s) { - Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_numeral_int(nCtx, v, s.NativeObject)); } @@ -4242,7 +3951,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNumeral(bool sgn, uint sig, int exp, FPSort s) { - Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_numeral_int_uint(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject)); } @@ -4255,7 +3963,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNumeral(bool sgn, Int64 exp, UInt64 sig, FPSort s) { - Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_numeral_int64_uint64(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject)); } @@ -4266,7 +3973,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFP(float v, FPSort s) { - Contract.Ensures(Contract.Result() != null); return MkFPNumeral(v, s); } @@ -4277,7 +3983,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFP(double v, FPSort s) { - Contract.Ensures(Contract.Result() != null); return MkFPNumeral(v, s); } @@ -4288,7 +3993,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFP(int v, FPSort s) { - Contract.Ensures(Contract.Result() != null); return MkFPNumeral(v, s); } @@ -4301,7 +4005,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFP(bool sgn, int exp, uint sig, FPSort s) { - Contract.Ensures(Contract.Result() != null); return MkFPNumeral(sgn, exp, sig, s); } @@ -4314,7 +4017,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFP(bool sgn, Int64 exp, UInt64 sig, FPSort s) { - Contract.Ensures(Contract.Result() != null); return MkFPNumeral(sgn, exp, sig, s); } @@ -4327,7 +4029,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPAbs(FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_abs(this.nCtx, t.NativeObject)); } @@ -4337,7 +4038,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPNeg(FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_neg(this.nCtx, t.NativeObject)); } @@ -4349,7 +4049,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPAdd(FPRMExpr rm, FPExpr t1, FPExpr t2) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_add(this.nCtx, rm.NativeObject, t1.NativeObject, t2.NativeObject)); } @@ -4361,7 +4060,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPSub(FPRMExpr rm, FPExpr t1, FPExpr t2) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_sub(this.nCtx, rm.NativeObject, t1.NativeObject, t2.NativeObject)); } @@ -4373,7 +4071,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPMul(FPRMExpr rm, FPExpr t1, FPExpr t2) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_mul(this.nCtx, rm.NativeObject, t1.NativeObject, t2.NativeObject)); } @@ -4385,7 +4082,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPDiv(FPRMExpr rm, FPExpr t1, FPExpr t2) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_div(this.nCtx, rm.NativeObject, t1.NativeObject, t2.NativeObject)); } @@ -4401,7 +4097,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPFMA(FPRMExpr rm, FPExpr t1, FPExpr t2, FPExpr t3) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_fma(this.nCtx, rm.NativeObject, t1.NativeObject, t2.NativeObject, t3.NativeObject)); } @@ -4412,7 +4107,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPSqrt(FPRMExpr rm, FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_sqrt(this.nCtx, rm.NativeObject, t.NativeObject)); } @@ -4423,7 +4117,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPRem(FPExpr t1, FPExpr t2) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_rem(this.nCtx, t1.NativeObject, t2.NativeObject)); } @@ -4435,7 +4128,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPRoundToIntegral(FPRMExpr rm, FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_round_to_integral(this.nCtx, rm.NativeObject, t.NativeObject)); } @@ -4446,7 +4138,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPMin(FPExpr t1, FPExpr t2) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_min(this.nCtx, t1.NativeObject, t2.NativeObject)); } @@ -4457,7 +4148,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPMax(FPExpr t1, FPExpr t2) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_max(this.nCtx, t1.NativeObject, t2.NativeObject)); } @@ -4468,7 +4158,6 @@ namespace Microsoft.Z3 /// floating-point term public BoolExpr MkFPLEq(FPExpr t1, FPExpr t2) { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_leq(this.nCtx, t1.NativeObject, t2.NativeObject)); } @@ -4479,7 +4168,6 @@ namespace Microsoft.Z3 /// floating-point term public BoolExpr MkFPLt(FPExpr t1, FPExpr t2) { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_lt(this.nCtx, t1.NativeObject, t2.NativeObject)); } @@ -4490,7 +4178,6 @@ namespace Microsoft.Z3 /// floating-point term public BoolExpr MkFPGEq(FPExpr t1, FPExpr t2) { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_geq(this.nCtx, t1.NativeObject, t2.NativeObject)); } @@ -4501,7 +4188,6 @@ namespace Microsoft.Z3 /// floating-point term public BoolExpr MkFPGt(FPExpr t1, FPExpr t2) { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_gt(this.nCtx, t1.NativeObject, t2.NativeObject)); } @@ -4515,7 +4201,6 @@ namespace Microsoft.Z3 /// floating-point term public BoolExpr MkFPEq(FPExpr t1, FPExpr t2) { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_eq(this.nCtx, t1.NativeObject, t2.NativeObject)); } @@ -4525,7 +4210,6 @@ namespace Microsoft.Z3 /// floating-point term public BoolExpr MkFPIsNormal(FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_is_normal(this.nCtx, t.NativeObject)); } @@ -4535,7 +4219,6 @@ namespace Microsoft.Z3 /// floating-point term public BoolExpr MkFPIsSubnormal(FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_is_subnormal(this.nCtx, t.NativeObject)); } @@ -4545,7 +4228,6 @@ namespace Microsoft.Z3 /// floating-point term public BoolExpr MkFPIsZero(FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_is_zero(this.nCtx, t.NativeObject)); } @@ -4555,7 +4237,6 @@ namespace Microsoft.Z3 /// floating-point term public BoolExpr MkFPIsInfinite(FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_is_infinite(this.nCtx, t.NativeObject)); } @@ -4565,7 +4246,6 @@ namespace Microsoft.Z3 /// floating-point term public BoolExpr MkFPIsNaN(FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_is_nan(this.nCtx, t.NativeObject)); } @@ -4575,7 +4255,6 @@ namespace Microsoft.Z3 /// floating-point term public BoolExpr MkFPIsNegative(FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_is_negative(this.nCtx, t.NativeObject)); } @@ -4585,7 +4264,6 @@ namespace Microsoft.Z3 /// floating-point term public BoolExpr MkFPIsPositive(FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_is_positive(this.nCtx, t.NativeObject)); } #endregion @@ -4606,7 +4284,6 @@ namespace Microsoft.Z3 /// bit-vector term representing the exponent. public FPExpr MkFP(BitVecExpr sgn, BitVecExpr sig, BitVecExpr exp) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_fp(this.nCtx, sgn.NativeObject, sig.NativeObject, exp.NativeObject)); } @@ -4623,7 +4300,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort (ebits+sbits == m) public FPExpr MkFPToFP(BitVecExpr bv, FPSort s) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_to_fp_bv(this.nCtx, bv.NativeObject, s.NativeObject)); } @@ -4640,7 +4316,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPExpr MkFPToFP(FPRMExpr rm, FPExpr t, FPSort s) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_to_fp_float(this.nCtx, rm.NativeObject, t.NativeObject, s.NativeObject)); } @@ -4657,7 +4332,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPExpr MkFPToFP(FPRMExpr rm, RealExpr t, FPSort s) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_to_fp_real(this.nCtx, rm.NativeObject, t.NativeObject, s.NativeObject)); } @@ -4676,7 +4350,6 @@ namespace Microsoft.Z3 /// flag indicating whether t is interpreted as signed or unsigned bit-vector. public FPExpr MkFPToFP(FPRMExpr rm, BitVecExpr t, FPSort s, bool signed) { - Contract.Ensures(Contract.Result() != null); if (signed) return new FPExpr(this, Native.Z3_mk_fpa_to_fp_signed(this.nCtx, rm.NativeObject, t.NativeObject, s.NativeObject)); else @@ -4695,7 +4368,6 @@ namespace Microsoft.Z3 /// floating-point term public FPExpr MkFPToFP(FPSort s, FPRMExpr rm, FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_to_fp_float(this.nCtx, s.NativeObject, rm.NativeObject, t.NativeObject)); } #endregion @@ -4715,7 +4387,6 @@ namespace Microsoft.Z3 /// Indicates whether the result is a signed or unsigned bit-vector. public BitVecExpr MkFPToBV(FPRMExpr rm, FPExpr t, uint sz, bool signed) { - Contract.Ensures(Contract.Result() != null); if (signed) return new BitVecExpr(this, Native.Z3_mk_fpa_to_sbv(this.nCtx, rm.NativeObject, t.NativeObject, sz)); else @@ -4733,7 +4404,6 @@ namespace Microsoft.Z3 /// FloatingPoint term public RealExpr MkFPToReal(FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new RealExpr(this, Native.Z3_mk_fpa_to_real(this.nCtx, t.NativeObject)); } #endregion @@ -4751,7 +4421,6 @@ namespace Microsoft.Z3 /// FloatingPoint term. public BitVecExpr MkFPToIEEEBV(FPExpr t) { - Contract.Ensures(Contract.Result() != null); return new BitVecExpr(this, Native.Z3_mk_fpa_to_ieee_bv(this.nCtx, t.NativeObject)); } @@ -4769,7 +4438,6 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public BitVecExpr MkFPToFP(FPRMExpr rm, IntExpr exp, RealExpr sig, FPSort s) { - Contract.Ensures(Contract.Result() != null); return new BitVecExpr(this, Native.Z3_mk_fpa_to_fp_int_real(this.nCtx, rm.NativeObject, exp.NativeObject, sig.NativeObject, s.NativeObject)); } #endregion @@ -4788,7 +4456,6 @@ namespace Microsoft.Z3 /// The native pointer to wrap. public AST WrapAST(IntPtr nativeObject) { - Contract.Ensures(Contract.Result() != null); return AST.Create(this, nativeObject); } @@ -4813,7 +4480,6 @@ namespace Microsoft.Z3 /// public string SimplifyHelp() { - Contract.Ensures(Contract.Result() != null); return Native.Z3_simplify_get_help(nCtx); } @@ -4879,84 +4545,78 @@ namespace Microsoft.Z3 GC.SuppressFinalize(this); } - [Pure] internal void CheckContextMatch(Z3Object other) { - Contract.Requires(other != null); + Debug.Assert(other != null); if (!ReferenceEquals(this, other.Context)) throw new Z3Exception("Context mismatch"); } - [Pure] internal void CheckContextMatch(Z3Object other1, Z3Object other2) { - Contract.Requires(other1 != null); - Contract.Requires(other2 != null); + Debug.Assert(other1 != null); + Debug.Assert(other2 != null); CheckContextMatch(other1); CheckContextMatch(other2); } - [Pure] internal void CheckContextMatch(Z3Object other1, Z3Object other2, Z3Object other3) { - Contract.Requires(other1 != null); - Contract.Requires(other2 != null); - Contract.Requires(other3 != null); + Debug.Assert(other1 != null); + Debug.Assert(other2 != null); + Debug.Assert(other3 != null); CheckContextMatch(other1); CheckContextMatch(other2); CheckContextMatch(other3); } - [Pure] internal void CheckContextMatch(Z3Object[] arr) { - Contract.Requires(arr == null || Contract.ForAll(arr, a => a != null)); + Debug.Assert(arr == null || arr.All(a => a != null)); if (arr != null) { foreach (Z3Object a in arr) { - Contract.Assert(a != null); // It was an assume, now we added the precondition, and we made it into an assert + Debug.Assert(a != null); // It was an assume, now we added the precondition, and we made it into an assert CheckContextMatch(a); } } } - [Pure] internal void CheckContextMatch(IEnumerable arr) where T : Z3Object { - Contract.Requires(arr == null || Contract.ForAll(arr, a => a != null)); + Debug.Assert(arr == null || arr.All(a => a != null)); if (arr != null) { foreach (Z3Object a in arr) { - Contract.Assert(a != null); // It was an assume, now we added the precondition, and we made it into an assert + Debug.Assert(a != null); // It was an assume, now we added the precondition, and we made it into an assert CheckContextMatch(a); } } } - [ContractInvariantMethod] private void ObjectInvariant() { - Contract.Invariant(m_AST_DRQ != null); - Contract.Invariant(m_ASTMap_DRQ != null); - Contract.Invariant(m_ASTVector_DRQ != null); - Contract.Invariant(m_ApplyResult_DRQ != null); - Contract.Invariant(m_FuncEntry_DRQ != null); - Contract.Invariant(m_FuncInterp_DRQ != null); - Contract.Invariant(m_Goal_DRQ != null); - Contract.Invariant(m_Model_DRQ != null); - Contract.Invariant(m_Params_DRQ != null); - Contract.Invariant(m_ParamDescrs_DRQ != null); - Contract.Invariant(m_Probe_DRQ != null); - Contract.Invariant(m_Solver_DRQ != null); - Contract.Invariant(m_Statistics_DRQ != null); - Contract.Invariant(m_Tactic_DRQ != null); - Contract.Invariant(m_Fixedpoint_DRQ != null); - Contract.Invariant(m_Optimize_DRQ != null); + Debug.Assert(m_AST_DRQ != null); + Debug.Assert(m_ASTMap_DRQ != null); + Debug.Assert(m_ASTVector_DRQ != null); + Debug.Assert(m_ApplyResult_DRQ != null); + Debug.Assert(m_FuncEntry_DRQ != null); + Debug.Assert(m_FuncInterp_DRQ != null); + Debug.Assert(m_Goal_DRQ != null); + Debug.Assert(m_Model_DRQ != null); + Debug.Assert(m_Params_DRQ != null); + Debug.Assert(m_ParamDescrs_DRQ != null); + Debug.Assert(m_Probe_DRQ != null); + Debug.Assert(m_Solver_DRQ != null); + Debug.Assert(m_Statistics_DRQ != null); + Debug.Assert(m_Tactic_DRQ != null); + Debug.Assert(m_Fixedpoint_DRQ != null); + Debug.Assert(m_Optimize_DRQ != null); } readonly private AST.DecRefQueue m_AST_DRQ = new AST.DecRefQueue(); @@ -4979,83 +4639,82 @@ namespace Microsoft.Z3 /// /// AST DRQ /// - public IDecRefQueue AST_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_AST_DRQ; } } + public IDecRefQueue AST_DRQ { get { return m_AST_DRQ; } } /// /// ASTMap DRQ /// - public IDecRefQueue ASTMap_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_ASTMap_DRQ; } } + public IDecRefQueue ASTMap_DRQ { get { return m_ASTMap_DRQ; } } /// /// ASTVector DRQ /// - public IDecRefQueue ASTVector_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_ASTVector_DRQ; } } + public IDecRefQueue ASTVector_DRQ { get { return m_ASTVector_DRQ; } } /// /// ApplyResult DRQ /// - public IDecRefQueue ApplyResult_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_ApplyResult_DRQ; } } + public IDecRefQueue ApplyResult_DRQ { get { return m_ApplyResult_DRQ; } } /// /// FuncEntry DRQ /// - public IDecRefQueue FuncEntry_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_FuncEntry_DRQ; } } + public IDecRefQueue FuncEntry_DRQ { get { return m_FuncEntry_DRQ; } } /// /// FuncInterp DRQ /// - public IDecRefQueue FuncInterp_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_FuncInterp_DRQ; } } + public IDecRefQueue FuncInterp_DRQ { get { return m_FuncInterp_DRQ; } } /// /// Goal DRQ /// - public IDecRefQueue Goal_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Goal_DRQ; } } + public IDecRefQueue Goal_DRQ { get { return m_Goal_DRQ; } } /// /// Model DRQ /// - public IDecRefQueue Model_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Model_DRQ; } } + public IDecRefQueue Model_DRQ { get { return m_Model_DRQ; } } /// /// Params DRQ /// - public IDecRefQueue Params_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Params_DRQ; } } + public IDecRefQueue Params_DRQ { get { return m_Params_DRQ; } } /// /// ParamDescrs DRQ /// - public IDecRefQueue ParamDescrs_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_ParamDescrs_DRQ; } } + public IDecRefQueue ParamDescrs_DRQ { get { return m_ParamDescrs_DRQ; } } /// /// Probe DRQ /// - public IDecRefQueue Probe_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Probe_DRQ; } } + public IDecRefQueue Probe_DRQ { get { return m_Probe_DRQ; } } /// /// Solver DRQ /// - public IDecRefQueue Solver_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Solver_DRQ; } } + public IDecRefQueue Solver_DRQ { get { return m_Solver_DRQ; } } /// /// Statistics DRQ /// - public IDecRefQueue Statistics_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Statistics_DRQ; } } + public IDecRefQueue Statistics_DRQ { get { return m_Statistics_DRQ; } } /// /// Tactic DRQ /// - public IDecRefQueue Tactic_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Tactic_DRQ; } } + public IDecRefQueue Tactic_DRQ { get { return m_Tactic_DRQ; } } /// /// FixedPoint DRQ /// - public IDecRefQueue Fixedpoint_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Fixedpoint_DRQ; } } + public IDecRefQueue Fixedpoint_DRQ { get { return m_Fixedpoint_DRQ; } } /// /// Optimize DRQ /// - public IDecRefQueue Optimize_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Fixedpoint_DRQ; } } - + public IDecRefQueue Optimize_DRQ { get { return m_Fixedpoint_DRQ; } } internal long refCount = 0; diff --git a/src/api/dotnet/DatatypeExpr.cs b/src/api/dotnet/DatatypeExpr.cs index ba3a9d478..03595c349 100644 --- a/src/api/dotnet/DatatypeExpr.cs +++ b/src/api/dotnet/DatatypeExpr.cs @@ -16,12 +16,12 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -35,7 +35,7 @@ namespace Microsoft.Z3 internal DatatypeExpr(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/DatatypeSort.cs b/src/api/dotnet/DatatypeSort.cs index e47545d68..943d3753f 100644 --- a/src/api/dotnet/DatatypeSort.cs +++ b/src/api/dotnet/DatatypeSort.cs @@ -17,15 +17,14 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// Datatype sorts. /// - [ContractVerification(true)] public class DatatypeSort : Sort { /// @@ -43,7 +42,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumConstructors; FuncDecl[] res = new FuncDecl[n]; @@ -60,7 +58,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumConstructors; FuncDecl[] res = new FuncDecl[n]; @@ -77,7 +74,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumConstructors; FuncDecl[][] res = new FuncDecl[n][]; @@ -95,14 +91,14 @@ namespace Microsoft.Z3 } #region Internal - internal DatatypeSort(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal DatatypeSort(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } internal DatatypeSort(Context ctx, Symbol name, Constructor[] constructors) : base(ctx, Native.Z3_mk_datatype(ctx.nCtx, name.NativeObject, (uint)constructors.Length, ArrayToNative(constructors))) { - Contract.Requires(ctx != null); - Contract.Requires(name != null); - Contract.Requires(constructors != null); + Debug.Assert(ctx != null); + Debug.Assert(name != null); + Debug.Assert(constructors != null); } #endregion }; diff --git a/src/api/dotnet/Deprecated.cs b/src/api/dotnet/Deprecated.cs index feb5b1555..64255cea2 100644 --- a/src/api/dotnet/Deprecated.cs +++ b/src/api/dotnet/Deprecated.cs @@ -17,17 +17,16 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Runtime.InteropServices; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// The main interaction with Z3 happens via the Context. /// - [ContractVerification(true)] public class Deprecated { diff --git a/src/api/dotnet/EnumSort.cs b/src/api/dotnet/EnumSort.cs index 62be48a2c..08c85361e 100644 --- a/src/api/dotnet/EnumSort.cs +++ b/src/api/dotnet/EnumSort.cs @@ -17,15 +17,14 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// Enumeration sorts. /// - [ContractVerification(true)] public class EnumSort : Sort { /// @@ -35,7 +34,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = Native.Z3_get_datatype_sort_num_constructors(Context.nCtx, NativeObject); FuncDecl[] t = new FuncDecl[n]; for (uint i = 0; i < n; i++) @@ -61,7 +59,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); FuncDecl[] cds = ConstDecls; Expr[] t = new Expr[cds.Length]; for (uint i = 0; i < t.Length; i++) @@ -87,7 +84,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = Native.Z3_get_datatype_sort_num_constructors(Context.nCtx, NativeObject); FuncDecl[] t = new FuncDecl[n]; for (uint i = 0; i < n; i++) @@ -110,9 +106,9 @@ namespace Microsoft.Z3 internal EnumSort(Context ctx, Symbol name, Symbol[] enumNames) : base(ctx, IntPtr.Zero) { - Contract.Requires(ctx != null); - Contract.Requires(name != null); - Contract.Requires(enumNames != null); + Debug.Assert(ctx != null); + Debug.Assert(name != null); + Debug.Assert(enumNames != null); int n = enumNames.Length; IntPtr[] n_constdecls = new IntPtr[n]; diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 5d1896221..f735401d8 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -17,15 +17,16 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; +using System.Linq; + namespace Microsoft.Z3 { /// /// Expressions are terms. /// - [ContractVerification(true)] public class Expr : AST { /// @@ -35,7 +36,6 @@ namespace Microsoft.Z3 /// public Expr Simplify(Params p = null) { - Contract.Ensures(Contract.Result() != null); if (p == null) return Expr.Create(Context, Native.Z3_simplify(Context.nCtx, NativeObject)); @@ -50,7 +50,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new FuncDecl(Context, Native.Z3_get_app_decl(Context.nCtx, NativeObject)); } } @@ -79,7 +78,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumArgs; Expr[] res = new Expr[n]; @@ -94,7 +92,6 @@ namespace Microsoft.Z3 /// public Expr Arg(uint i) { - Contract.Ensures(Contract.Result() != null); return Expr.Create(Context, Native.Z3_get_app_arg(Context.nCtx, NativeObject, i)); } @@ -104,8 +101,8 @@ namespace Microsoft.Z3 /// public void Update(Expr[] args) { - Contract.Requires(args != null); - Contract.Requires(Contract.ForAll(args, a => a != null)); + Debug.Assert(args != null); + Debug.Assert(args.All(a => a != null)); Context.CheckContextMatch(args); if (IsApp && args.Length != NumArgs) @@ -123,11 +120,10 @@ namespace Microsoft.Z3 /// public Expr Substitute(Expr[] from, Expr[] to) { - Contract.Requires(from != null); - Contract.Requires(to != null); - Contract.Requires(Contract.ForAll(from, f => f != null)); - Contract.Requires(Contract.ForAll(to, t => t != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(from != null); + Debug.Assert(to != null); + Debug.Assert(from.All(f => f != null)); + Debug.Assert(to.All(t => t != null)); Context.CheckContextMatch(from); Context.CheckContextMatch(to); @@ -142,9 +138,8 @@ namespace Microsoft.Z3 /// public Expr Substitute(Expr from, Expr to) { - Contract.Requires(from != null); - Contract.Requires(to != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(from != null); + Debug.Assert(to != null); return Substitute(new Expr[] { from }, new Expr[] { to }); } @@ -157,9 +152,8 @@ namespace Microsoft.Z3 /// public Expr SubstituteVars(Expr[] to) { - Contract.Requires(to != null); - Contract.Requires(Contract.ForAll(to, t => t != null)); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(to != null); + Debug.Assert(to.All(t => t != null)); Context.CheckContextMatch(to); return Expr.Create(Context, Native.Z3_substitute_vars(Context.nCtx, NativeObject, (uint)to.Length, Expr.ArrayToNative(to))); @@ -207,7 +201,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Sort.Create(Context, Native.Z3_get_sort(Context.nCtx, NativeObject)); } } @@ -332,7 +325,7 @@ namespace Microsoft.Z3 /// /// Retrieve bound of at-most /// - public uint AtMostBound { get { Contract.Requires(IsAtMost); return (uint)FuncDecl.Parameters[0].Int; } } + public uint AtMostBound { get { Debug.Assert(IsAtMost); return (uint)FuncDecl.Parameters[0].Int; } } /// /// Indicates whether the term is at-least @@ -342,7 +335,7 @@ namespace Microsoft.Z3 /// /// Retrieve bound of at-least /// - public uint AtLeastBound { get { Contract.Requires(IsAtLeast); return (uint)FuncDecl.Parameters[0].Int; } } + public uint AtLeastBound { get { Debug.Assert(IsAtLeast); return (uint)FuncDecl.Parameters[0].Int; } } /// /// Indicates whether the term is pbeq @@ -1816,8 +1809,6 @@ namespace Microsoft.Z3 if (!IsVar) throw new Z3Exception("Term is not a bound variable."); - Contract.EndContractBlock(); - return Native.Z3_get_index_value(Context.nCtx, NativeObject); } } @@ -1827,10 +1818,9 @@ namespace Microsoft.Z3 /// /// Constructor for Expr /// - internal protected Expr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal protected Expr(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } #if DEBUG - [Pure] internal override void CheckNativeObject(IntPtr obj) { if (Native.Z3_is_app(Context.nCtx, obj) == 0 && @@ -1841,12 +1831,10 @@ namespace Microsoft.Z3 } #endif - [Pure] internal static Expr Create(Context ctx, FuncDecl f, params Expr[] arguments) { - Contract.Requires(ctx != null); - Contract.Requires(f != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ctx != null); + Debug.Assert(f != null); IntPtr obj = Native.Z3_mk_app(ctx.nCtx, f.NativeObject, AST.ArrayLength(arguments), @@ -1854,11 +1842,9 @@ namespace Microsoft.Z3 return Create(ctx, obj); } - [Pure] new internal static Expr Create(Context ctx, IntPtr obj) { - Contract.Requires(ctx != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ctx != null); Z3_ast_kind k = (Z3_ast_kind)Native.Z3_get_ast_kind(ctx.nCtx, obj); if (k == Z3_ast_kind.Z3_QUANTIFIER_AST) diff --git a/src/api/dotnet/FPExpr.cs b/src/api/dotnet/FPExpr.cs index 85fdf2603..03ae0bff1 100644 --- a/src/api/dotnet/FPExpr.cs +++ b/src/api/dotnet/FPExpr.cs @@ -16,12 +16,12 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -45,7 +45,7 @@ namespace Microsoft.Z3 internal FPExpr(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/FPNum.cs b/src/api/dotnet/FPNum.cs index b6d349149..e21355f72 100644 --- a/src/api/dotnet/FPNum.cs +++ b/src/api/dotnet/FPNum.cs @@ -16,15 +16,14 @@ Author: Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// FloatiungPoint Numerals /// - [ContractVerification(true)] public class FPNum : FPExpr { /// @@ -175,7 +174,7 @@ namespace Microsoft.Z3 internal FPNum(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion diff --git a/src/api/dotnet/FPRMExpr.cs b/src/api/dotnet/FPRMExpr.cs index 896c3e6b9..4c4ae602f 100644 --- a/src/api/dotnet/FPRMExpr.cs +++ b/src/api/dotnet/FPRMExpr.cs @@ -16,12 +16,12 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -35,7 +35,7 @@ namespace Microsoft.Z3 internal FPRMExpr(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/FPRMNum.cs b/src/api/dotnet/FPRMNum.cs index 81cff167e..af1c8b888 100644 --- a/src/api/dotnet/FPRMNum.cs +++ b/src/api/dotnet/FPRMNum.cs @@ -16,12 +16,12 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -93,7 +93,7 @@ namespace Microsoft.Z3 internal FPRMNum(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/FPRMSort.cs b/src/api/dotnet/FPRMSort.cs index 1d8334eb5..4e04a2586 100644 --- a/src/api/dotnet/FPRMSort.cs +++ b/src/api/dotnet/FPRMSort.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -31,12 +31,12 @@ namespace Microsoft.Z3 internal FPRMSort(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal FPRMSort(Context ctx) : base(ctx, Native.Z3_mk_fpa_rounding_mode_sort(ctx.nCtx)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/FPSort.cs b/src/api/dotnet/FPSort.cs index e1ad62d49..56a738e65 100644 --- a/src/api/dotnet/FPSort.cs +++ b/src/api/dotnet/FPSort.cs @@ -16,8 +16,8 @@ Author: Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -40,12 +40,12 @@ namespace Microsoft.Z3 internal FPSort(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal FPSort(Context ctx, uint ebits, uint sbits) : base(ctx, Native.Z3_mk_fpa_sort(ctx.nCtx, ebits, sbits)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/FiniteDomainExpr.cs b/src/api/dotnet/FiniteDomainExpr.cs index 59ccb9f32..1a689d59f 100644 --- a/src/api/dotnet/FiniteDomainExpr.cs +++ b/src/api/dotnet/FiniteDomainExpr.cs @@ -16,8 +16,8 @@ Author: Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -31,7 +31,7 @@ namespace Microsoft.Z3 internal FiniteDomainExpr(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/FiniteDomainNum.cs b/src/api/dotnet/FiniteDomainNum.cs index 52c0af8bd..39d94ddbd 100644 --- a/src/api/dotnet/FiniteDomainNum.cs +++ b/src/api/dotnet/FiniteDomainNum.cs @@ -16,8 +16,8 @@ Author: Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; #if !FRAMEWORK_LT_4 using System.Numerics; @@ -28,7 +28,6 @@ namespace Microsoft.Z3 /// /// Finite-domain numerals /// - [ContractVerification(true)] public class FiniteDomainNum : FiniteDomainExpr { /// @@ -109,7 +108,7 @@ namespace Microsoft.Z3 } #region Internal - internal FiniteDomainNum(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal FiniteDomainNum(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } #endregion } } diff --git a/src/api/dotnet/FiniteDomainSort.cs b/src/api/dotnet/FiniteDomainSort.cs index 93540ff87..5392aede2 100644 --- a/src/api/dotnet/FiniteDomainSort.cs +++ b/src/api/dotnet/FiniteDomainSort.cs @@ -17,15 +17,14 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// Finite domain sorts. /// - [ContractVerification(true)] public class FiniteDomainSort : Sort { /// @@ -45,13 +44,13 @@ namespace Microsoft.Z3 internal FiniteDomainSort(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal FiniteDomainSort(Context ctx, Symbol name, ulong size) : base(ctx, Native.Z3_mk_finite_domain_sort(ctx.nCtx, name.NativeObject, size)) { - Contract.Requires(ctx != null); - Contract.Requires(name != null); + Debug.Assert(ctx != null); + Debug.Assert(name != null); } #endregion diff --git a/src/api/dotnet/Fixedpoint.cs b/src/api/dotnet/Fixedpoint.cs index 102a96ac5..51ee79b55 100644 --- a/src/api/dotnet/Fixedpoint.cs +++ b/src/api/dotnet/Fixedpoint.cs @@ -18,14 +18,14 @@ Notes: --*/ using System; -using System.Diagnostics.Contracts; +using System.Diagnostics; +using System.Linq; namespace Microsoft.Z3 { /// /// Object for managing fixedpoints /// - [ContractVerification(true)] public class Fixedpoint : Z3Object { @@ -36,7 +36,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Native.Z3_fixedpoint_get_help(Context.nCtx, NativeObject); } } @@ -48,7 +47,7 @@ namespace Microsoft.Z3 { set { - Contract.Requires(value != null); + Debug.Assert(value != null); Context.CheckContextMatch(value); Native.Z3_fixedpoint_set_params(Context.nCtx, NativeObject, value.NativeObject); } @@ -68,8 +67,8 @@ namespace Microsoft.Z3 /// public void Assert(params BoolExpr[] constraints) { - Contract.Requires(constraints != null); - Contract.Requires(Contract.ForAll(constraints, c => c != null)); + Debug.Assert(constraints != null); + Debug.Assert(constraints.All(c => c != null)); Context.CheckContextMatch(constraints); foreach (BoolExpr a in constraints) @@ -91,7 +90,7 @@ namespace Microsoft.Z3 /// public void RegisterRelation(FuncDecl f) { - Contract.Requires(f != null); + Debug.Assert(f != null); Context.CheckContextMatch(f); Native.Z3_fixedpoint_register_relation(Context.nCtx, NativeObject, f.NativeObject); @@ -102,7 +101,7 @@ namespace Microsoft.Z3 /// public void AddRule(BoolExpr rule, Symbol name = null) { - Contract.Requires(rule != null); + Debug.Assert(rule != null); Context.CheckContextMatch(rule); Native.Z3_fixedpoint_add_rule(Context.nCtx, NativeObject, rule.NativeObject, AST.GetNativeObject(name)); @@ -113,8 +112,8 @@ namespace Microsoft.Z3 /// public void AddFact(FuncDecl pred, params uint[] args) { - Contract.Requires(pred != null); - Contract.Requires(args != null); + Debug.Assert(pred != null); + Debug.Assert(args != null); Context.CheckContextMatch(pred); Native.Z3_fixedpoint_add_fact(Context.nCtx, NativeObject, pred.NativeObject, (uint)args.Length, args); @@ -128,7 +127,7 @@ namespace Microsoft.Z3 /// public Status Query(BoolExpr query) { - Contract.Requires(query != null); + Debug.Assert(query != null); Context.CheckContextMatch(query); Z3_lbool r = (Z3_lbool)Native.Z3_fixedpoint_query(Context.nCtx, NativeObject, query.NativeObject); @@ -148,8 +147,8 @@ namespace Microsoft.Z3 /// public Status Query(params FuncDecl[] relations) { - Contract.Requires(relations != null); - Contract.Requires(Contract.ForAll(0, relations.Length, i => relations[i] != null)); + Debug.Assert(relations != null); + Debug.Assert(relations.All(rel => rel != null)); Context.CheckContextMatch(relations); Z3_lbool r = (Z3_lbool)Native.Z3_fixedpoint_query_relations(Context.nCtx, NativeObject, @@ -187,7 +186,7 @@ namespace Microsoft.Z3 /// public void UpdateRule(BoolExpr rule, Symbol name) { - Contract.Requires(rule != null); + Debug.Assert(rule != null); Context.CheckContextMatch(rule); Native.Z3_fixedpoint_update_rule(Context.nCtx, NativeObject, rule.NativeObject, AST.GetNativeObject(name)); @@ -208,7 +207,6 @@ namespace Microsoft.Z3 /// public string GetReasonUnknown() { - Contract.Ensures(Contract.Result() != null); return Native.Z3_fixedpoint_get_reason_unknown(Context.nCtx, NativeObject); } @@ -252,7 +250,7 @@ namespace Microsoft.Z3 /// public void SetPredicateRepresentation(FuncDecl f, Symbol[] kinds) { - Contract.Requires(f != null); + Debug.Assert(f != null); Native.Z3_fixedpoint_set_predicate_representation(Context.nCtx, NativeObject, f.NativeObject, AST.ArrayLength(kinds), Symbol.ArrayToNative(kinds)); @@ -276,7 +274,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_rules(Context.nCtx, NativeObject)); return av.ToBoolExprArray(); @@ -290,7 +287,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_assertions(Context.nCtx, NativeObject)); return av.ToBoolExprArray(); @@ -304,7 +300,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new Statistics(Context, Native.Z3_fixedpoint_get_statistics(Context.nCtx, NativeObject)); } @@ -335,12 +330,12 @@ namespace Microsoft.Z3 internal Fixedpoint(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal Fixedpoint(Context ctx) : base(ctx, Native.Z3_mk_fixedpoint(ctx.nCtx)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/dotnet/FuncDecl.cs b/src/api/dotnet/FuncDecl.cs index 0587a2276..24ae456d8 100644 --- a/src/api/dotnet/FuncDecl.cs +++ b/src/api/dotnet/FuncDecl.cs @@ -18,14 +18,15 @@ Notes: --*/ using System; -using System.Diagnostics.Contracts; +using System.Diagnostics; +using System.Linq; + namespace Microsoft.Z3 { /// /// Function declarations. /// - [ContractVerification(true)] public class FuncDecl : AST { /// @@ -108,7 +109,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = DomainSize; @@ -126,7 +126,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Sort.Create(Context, Native.Z3_get_range(Context.nCtx, NativeObject)); } } @@ -146,7 +145,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Symbol.Create(Context, Native.Z3_get_decl_name(Context.nCtx, NativeObject)); } } @@ -166,7 +164,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint num = NumParameters; Parameter[] res = new Parameter[num]; @@ -287,22 +284,22 @@ namespace Microsoft.Z3 internal FuncDecl(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal FuncDecl(Context ctx, Symbol name, Sort[] domain, Sort range) : base(ctx, Native.Z3_mk_func_decl(ctx.nCtx, name.NativeObject, AST.ArrayLength(domain), AST.ArrayToNative(domain), range.NativeObject)) { - Contract.Requires(ctx != null); - Contract.Requires(name != null); - Contract.Requires(range != null); + Debug.Assert(ctx != null); + Debug.Assert(name != null); + Debug.Assert(range != null); } internal FuncDecl(Context ctx, string prefix, Sort[] domain, Sort range) : base(ctx, Native.Z3_mk_fresh_func_decl(ctx.nCtx, prefix, AST.ArrayLength(domain), AST.ArrayToNative(domain), range.NativeObject)) { - Contract.Requires(ctx != null); - Contract.Requires(range != null); + Debug.Assert(ctx != null); + Debug.Assert(range != null); } #if DEBUG @@ -335,7 +332,7 @@ namespace Microsoft.Z3 { get { - Contract.Requires(args == null || Contract.ForAll(args, a => a != null)); + Debug.Assert(args == null || args.All(a => a != null)); return Apply(args); } @@ -348,7 +345,7 @@ namespace Microsoft.Z3 /// public Expr Apply(params Expr[] args) { - Contract.Requires(args == null || Contract.ForAll(args, a => a != null)); + Debug.Assert(args == null || args.All(a => a != null)); Context.CheckContextMatch(args); return Expr.Create(Context, this, args); diff --git a/src/api/dotnet/FuncInterp.cs b/src/api/dotnet/FuncInterp.cs index 449d460f9..6924049d3 100644 --- a/src/api/dotnet/FuncInterp.cs +++ b/src/api/dotnet/FuncInterp.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -26,7 +26,6 @@ namespace Microsoft.Z3 /// 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 of arguments. /// - [ContractVerification(true)] public class FuncInterp : Z3Object { /// @@ -42,7 +41,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Expr.Create(Context, Native.Z3_func_entry_get_value(Context.nCtx, NativeObject)); } } @@ -62,8 +60,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.Result().Length == this.NumArgs); uint n = NumArgs; Expr[] res = new Expr[n]; @@ -87,7 +83,7 @@ namespace Microsoft.Z3 } #region Internal - internal Entry(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal Entry(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue { @@ -133,8 +129,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.ForAll(0, Contract.Result().Length, j => Contract.Result()[j] != null)); uint n = NumEntries; Entry[] res = new Entry[n]; @@ -151,7 +145,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Expr.Create(Context, Native.Z3_func_interp_get_else(Context.nCtx, NativeObject)); } @@ -194,7 +187,7 @@ namespace Microsoft.Z3 internal FuncInterp(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/dotnet/Global.cs b/src/api/dotnet/Global.cs index 17963b33d..207498760 100644 --- a/src/api/dotnet/Global.cs +++ b/src/api/dotnet/Global.cs @@ -17,9 +17,9 @@ Notes: --*/ +using System.Diagnostics; using System; using System.Runtime.InteropServices; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { diff --git a/src/api/dotnet/Goal.cs b/src/api/dotnet/Goal.cs index ef2e9a5da..4dbc78b7e 100644 --- a/src/api/dotnet/Goal.cs +++ b/src/api/dotnet/Goal.cs @@ -18,7 +18,8 @@ Notes: --*/ using System; -using System.Diagnostics.Contracts; +using System.Diagnostics; +using System.Linq; namespace Microsoft.Z3 { @@ -27,7 +28,6 @@ namespace Microsoft.Z3 /// of formulas, that can be solved and/or transformed using /// tactics and solvers. /// - [ContractVerification(true)] public class Goal : Z3Object { /// @@ -79,13 +79,13 @@ namespace Microsoft.Z3 /// public void Assert(params BoolExpr[] constraints) { - Contract.Requires(constraints != null); - Contract.Requires(Contract.ForAll(constraints, c => c != null)); + Debug.Assert(constraints != null); + Debug.Assert(constraints.All(c => c != null)); Context.CheckContextMatch(constraints); foreach (BoolExpr c in constraints) { - Contract.Assert(c != null); // It was an assume, now made an assert just to be sure we do not regress + Debug.Assert(c != null); // It was an assume, now made an assert just to be sure we do not regress Native.Z3_goal_assert(Context.nCtx, NativeObject, c.NativeObject); } } @@ -140,7 +140,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = Size; BoolExpr[] res = new BoolExpr[n]; @@ -181,7 +180,6 @@ namespace Microsoft.Z3 /// A model for g public Model ConvertModel(Model m) { - Contract.Ensures(Contract.Result() != null); if (m != null) return new Model(Context, Native.Z3_goal_convert_model(Context.nCtx, NativeObject, m.NativeObject)); else @@ -194,7 +192,7 @@ namespace Microsoft.Z3 /// public Goal Translate(Context ctx) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); return new Goal(ctx, Native.Z3_goal_translate(Context.nCtx, NativeObject, ctx.nCtx)); } @@ -248,12 +246,12 @@ namespace Microsoft.Z3 } #region Internal - internal Goal(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal Goal(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } internal Goal(Context ctx, bool models, bool unsatCores, bool proofs) : base(ctx, Native.Z3_mk_goal(ctx.nCtx, (byte)(models ? 1 : 0), (byte)(unsatCores ? 1 : 0), (byte)(proofs ? 1 : 0))) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/dotnet/IDecRefQueue.cs b/src/api/dotnet/IDecRefQueue.cs index 43506fabf..8af0973d6 100644 --- a/src/api/dotnet/IDecRefQueue.cs +++ b/src/api/dotnet/IDecRefQueue.cs @@ -17,26 +17,24 @@ Notes: --*/ +using System.Diagnostics; using System; using System.Collections; using System.Collections.Generic; using System.Threading; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// DecRefQueue interface /// - [ContractClass(typeof(DecRefQueueContracts))] public abstract class IDecRefQueue { #region Object invariant - [ContractInvariantMethod] private void ObjectInvariant() { - Contract.Invariant(this.m_queue != null); + Debug.Assert(this.m_queue != null); } #endregion @@ -61,7 +59,7 @@ namespace Microsoft.Z3 internal void IncAndClear(Context ctx, IntPtr o) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); IncRef(ctx, o); if (m_queue.Count >= m_move_limit) Clear(ctx); @@ -79,7 +77,7 @@ namespace Microsoft.Z3 internal void Clear(Context ctx) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); lock (m_lock) { @@ -90,17 +88,16 @@ namespace Microsoft.Z3 } } - [ContractClassFor(typeof(IDecRefQueue))] abstract class DecRefQueueContracts : IDecRefQueue { internal override void IncRef(Context ctx, IntPtr obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal override void DecRef(Context ctx, IntPtr obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } } } diff --git a/src/api/dotnet/IntExpr.cs b/src/api/dotnet/IntExpr.cs index 622be7bd5..3ca5398ea 100644 --- a/src/api/dotnet/IntExpr.cs +++ b/src/api/dotnet/IntExpr.cs @@ -16,12 +16,12 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -35,7 +35,7 @@ namespace Microsoft.Z3 internal IntExpr(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/IntNum.cs b/src/api/dotnet/IntNum.cs index 64fd78ad2..36f209cab 100644 --- a/src/api/dotnet/IntNum.cs +++ b/src/api/dotnet/IntNum.cs @@ -16,8 +16,8 @@ Author: Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; #if !FRAMEWORK_LT_4 using System.Numerics; @@ -28,7 +28,6 @@ namespace Microsoft.Z3 /// /// Integer Numerals /// - [ContractVerification(true)] public class IntNum : IntExpr { @@ -36,7 +35,7 @@ namespace Microsoft.Z3 internal IntNum(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion diff --git a/src/api/dotnet/IntSort.cs b/src/api/dotnet/IntSort.cs index d0c25ac79..289be4bcc 100644 --- a/src/api/dotnet/IntSort.cs +++ b/src/api/dotnet/IntSort.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -31,12 +31,12 @@ namespace Microsoft.Z3 internal IntSort(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal IntSort(Context ctx) : base(ctx, Native.Z3_mk_int_sort(ctx.nCtx)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/IntSymbol.cs b/src/api/dotnet/IntSymbol.cs index df2d9da52..1bb3b3f13 100644 --- a/src/api/dotnet/IntSymbol.cs +++ b/src/api/dotnet/IntSymbol.cs @@ -18,15 +18,14 @@ Notes: --*/ using System; +using System.Diagnostics; using System.Runtime.InteropServices; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// Numbered symbols /// - [ContractVerification(true)] public class IntSymbol : Symbol { /// @@ -47,12 +46,12 @@ namespace Microsoft.Z3 internal IntSymbol(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal IntSymbol(Context ctx, int i) : base(ctx, Native.Z3_mk_int_symbol(ctx.nCtx, i)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #if DEBUG diff --git a/src/api/dotnet/Lambda.cs b/src/api/dotnet/Lambda.cs index b3dc6c01c..35497f88f 100644 --- a/src/api/dotnet/Lambda.cs +++ b/src/api/dotnet/Lambda.cs @@ -18,14 +18,14 @@ Notes: --*/ using System; -using System.Diagnostics.Contracts; +using System.Diagnostics; +using System.Linq; namespace Microsoft.Z3 { /// /// Lambda expressions. /// - [ContractVerification(true)] public class Lambda : ArrayExpr { /// @@ -43,7 +43,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumBound; Symbol[] res = new Symbol[n]; @@ -60,7 +59,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumBound; Sort[] res = new Sort[n]; @@ -77,7 +75,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(Context, Native.Z3_get_quantifier_body(Context.nCtx, NativeObject)); } @@ -94,17 +91,16 @@ namespace Microsoft.Z3 } #region Internal - [ContractVerification(false)] // F: Clousot ForAll decompilation gets confused below. Setting verification off until I fixed the bug internal Lambda(Context ctx, Sort[] sorts, Symbol[] names, Expr body) : base(ctx, IntPtr.Zero) { - Contract.Requires(ctx != null); - Contract.Requires(sorts != null); - Contract.Requires(names != null); - Contract.Requires(body != null); - Contract.Requires(sorts.Length == names.Length); - Contract.Requires(Contract.ForAll(sorts, s => s != null)); - Contract.Requires(Contract.ForAll(names, n => n != null)); + Debug.Assert(ctx != null); + Debug.Assert(sorts != null); + Debug.Assert(names != null); + Debug.Assert(body != null); + Debug.Assert(sorts.Length == names.Length); + Debug.Assert(sorts.All(s => s != null)); + Debug.Assert(names.All(n => n != null)); Context.CheckContextMatch(sorts); Context.CheckContextMatch(names); Context.CheckContextMatch(body); @@ -119,14 +115,13 @@ namespace Microsoft.Z3 } - [ContractVerification(false)] // F: Clousot ForAll decompilation gets confused below. Setting verification off until I fixed the bug internal Lambda(Context ctx, Expr[] bound, Expr body) : base(ctx, IntPtr.Zero) { - Contract.Requires(ctx != null); - Contract.Requires(body != null); + Debug.Assert(ctx != null); + Debug.Assert(body != null); - Contract.Requires(bound != null && bound.Length > 0 && Contract.ForAll(bound, n => n != null)); + Debug.Assert(bound != null && bound.Length > 0 && bound.All(n => n != null)); Context.CheckContextMatch(bound); Context.CheckContextMatch(body); @@ -137,7 +132,7 @@ namespace Microsoft.Z3 } - internal Lambda(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal Lambda(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } #if DEBUG internal override void CheckNativeObject(IntPtr obj) diff --git a/src/api/dotnet/ListSort.cs b/src/api/dotnet/ListSort.cs index e860e4d4b..575f2a9bb 100644 --- a/src/api/dotnet/ListSort.cs +++ b/src/api/dotnet/ListSort.cs @@ -17,15 +17,14 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// List sorts. /// - [ContractVerification(true)] public class ListSort : Sort { /// @@ -35,7 +34,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, 0)); } } @@ -47,7 +45,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Context.MkApp(NilDecl); } } @@ -59,7 +56,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new FuncDecl(Context, Native.Z3_get_datatype_sort_recognizer(Context.nCtx, NativeObject, 0)); } } @@ -71,7 +67,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, 1)); } } @@ -84,7 +79,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new FuncDecl(Context, Native.Z3_get_datatype_sort_recognizer(Context.nCtx, NativeObject, 1)); } } @@ -96,7 +90,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor_accessor(Context.nCtx, NativeObject, 1, 0)); } } @@ -108,7 +101,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor_accessor(Context.nCtx, NativeObject, 1, 1)); } } @@ -117,9 +109,9 @@ namespace Microsoft.Z3 internal ListSort(Context ctx, Symbol name, Sort elemSort) : base(ctx, IntPtr.Zero) { - Contract.Requires(ctx != null); - Contract.Requires(name != null); - Contract.Requires(elemSort != null); + Debug.Assert(ctx != null); + Debug.Assert(name != null); + Debug.Assert(elemSort != null); IntPtr inil = IntPtr.Zero, iisnil = IntPtr.Zero, icons = IntPtr.Zero, iiscons = IntPtr.Zero, diff --git a/src/api/dotnet/Log.cs b/src/api/dotnet/Log.cs index f8b2ea88b..a94c29bc6 100644 --- a/src/api/dotnet/Log.cs +++ b/src/api/dotnet/Log.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -29,7 +29,6 @@ namespace Microsoft.Z3 /// Note that this is a global, static log and if multiple Context /// objects are created, it logs the interaction with all of them. /// - [ContractVerification(true)] public static class Log { private static bool m_is_open = false; @@ -59,7 +58,7 @@ namespace Microsoft.Z3 /// public static void Append(string s) { - Contract.Requires(isOpen()); + Debug.Assert(isOpen()); if (!m_is_open) throw new Z3Exception("Log cannot be closed."); @@ -70,7 +69,6 @@ namespace Microsoft.Z3 /// Checks whether the interaction log is opened. /// /// True if the interaction log is open, false otherwise. - [Pure] public static bool isOpen() { return m_is_open; diff --git a/src/api/dotnet/Model.cs b/src/api/dotnet/Model.cs index 96f62c9fb..c24516c22 100644 --- a/src/api/dotnet/Model.cs +++ b/src/api/dotnet/Model.cs @@ -18,7 +18,7 @@ Notes: --*/ using System; -using System.Diagnostics.Contracts; +using System.Diagnostics; using System.Collections.Generic; namespace Microsoft.Z3 @@ -26,7 +26,6 @@ namespace Microsoft.Z3 /// /// A Model contains interpretations (assignments) of constants and functions. /// - [ContractVerification(true)] public class Model : Z3Object { /// @@ -36,7 +35,7 @@ namespace Microsoft.Z3 /// An expression if the constant has an interpretation in the model, null otherwise. public Expr ConstInterp(Expr a) { - Contract.Requires(a != null); + Debug.Assert(a != null); Context.CheckContextMatch(a); return ConstInterp(a.FuncDecl); @@ -49,7 +48,7 @@ namespace Microsoft.Z3 /// An expression if the function has an interpretation in the model, null otherwise. public Expr ConstInterp(FuncDecl f) { - Contract.Requires(f != null); + Debug.Assert(f != null); Context.CheckContextMatch(f); if (f.Arity != 0 || @@ -70,7 +69,7 @@ namespace Microsoft.Z3 /// A FunctionInterpretation if the function has an interpretation in the model, null otherwise. public FuncInterp FuncInterp(FuncDecl f) { - Contract.Requires(f != null); + Debug.Assert(f != null); Context.CheckContextMatch(f); @@ -122,7 +121,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumConsts; FuncDecl[] res = new FuncDecl[n]; @@ -165,7 +163,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumFuncs; FuncDecl[] res = new FuncDecl[n]; @@ -182,7 +179,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint nFuncs = NumFuncs; uint nConsts = NumConsts; @@ -223,8 +219,7 @@ namespace Microsoft.Z3 /// The evaluation of in the model. public Expr Eval(Expr t, bool completion = false) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); IntPtr v = IntPtr.Zero; if (Native.Z3_model_eval(Context.nCtx, NativeObject, t.NativeObject, (byte)(completion ? 1 : 0), ref v) == (byte)0) @@ -238,8 +233,7 @@ namespace Microsoft.Z3 /// public Expr Evaluate(Expr t, bool completion = false) { - Contract.Requires(t != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(t != null); return Eval(t, completion); } @@ -263,7 +257,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumSorts; Sort[] res = new Sort[n]; @@ -281,8 +274,7 @@ namespace Microsoft.Z3 /// An array of expressions, where each is an element of the universe of public Expr[] SortUniverse(Sort s) { - Contract.Requires(s != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(s != null); ASTVector av = new ASTVector(Context, Native.Z3_model_get_sort_universe(Context.nCtx, NativeObject, s.NativeObject)); return av.ToExprArray(); @@ -301,7 +293,7 @@ namespace Microsoft.Z3 internal Model(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index ce3cc55f7..4713f414a 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -19,14 +19,14 @@ Notes: using System; using System.Collections.Generic; -using System.Diagnostics.Contracts; +using System.Diagnostics; +using System.Linq; namespace Microsoft.Z3 { /// /// Object for managing optimizization context /// - [ContractVerification(true)] public class Optimize : Z3Object { /// @@ -36,7 +36,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Native.Z3_optimize_get_help(Context.nCtx, NativeObject); } } @@ -48,7 +47,7 @@ namespace Microsoft.Z3 { set { - Contract.Requires(value != null); + Debug.Assert(value != null); Context.CheckContextMatch(value); Native.Z3_optimize_set_params(Context.nCtx, NativeObject, value.NativeObject); } @@ -99,8 +98,8 @@ namespace Microsoft.Z3 /// private void AddConstraints(IEnumerable constraints) { - Contract.Requires(constraints != null); - Contract.Requires(Contract.ForAll(constraints, c => c != null)); + Debug.Assert(constraints != null); + Debug.Assert(constraints.All(c => c != null)); Context.CheckContextMatch(constraints); foreach (BoolExpr a in constraints) @@ -248,7 +247,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); ASTVector core = new ASTVector(Context, Native.Z3_optimize_get_unsat_core(Context.nCtx, NativeObject)); return core.ToBoolExprArray(); @@ -319,7 +317,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Native.Z3_optimize_get_reason_unknown(Context.nCtx, NativeObject); } } @@ -357,7 +354,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); ASTVector assertions = new ASTVector(Context, Native.Z3_optimize_get_assertions(Context.nCtx, NativeObject)); return assertions.ToBoolExprArray(); @@ -371,7 +367,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); ASTVector objectives = new ASTVector(Context, Native.Z3_optimize_get_objectives(Context.nCtx, NativeObject)); return objectives.ToExprArray(); @@ -386,7 +381,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new Statistics(Context, Native.Z3_optimize_get_statistics(Context.nCtx, NativeObject)); } @@ -397,12 +391,12 @@ namespace Microsoft.Z3 internal Optimize(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal Optimize(Context ctx) : base(ctx, Native.Z3_mk_optimize(ctx.nCtx)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/dotnet/ParamDescrs.cs b/src/api/dotnet/ParamDescrs.cs index 1809518e1..fbfb9cd16 100644 --- a/src/api/dotnet/ParamDescrs.cs +++ b/src/api/dotnet/ParamDescrs.cs @@ -17,15 +17,14 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// A ParamDescrs describes a set of parameters. /// - [ContractVerification(true)] public class ParamDescrs : Z3Object { /// @@ -33,7 +32,7 @@ namespace Microsoft.Z3 /// public void Validate(Params p) { - Contract.Requires(p != null); + Debug.Assert(p != null); Native.Z3_params_validate(Context.nCtx, p.NativeObject, NativeObject); } @@ -42,7 +41,7 @@ namespace Microsoft.Z3 /// public Z3_param_kind GetKind(Symbol name) { - Contract.Requires(name != null); + Debug.Assert(name != null); return (Z3_param_kind)Native.Z3_param_descrs_get_kind(Context.nCtx, NativeObject, name.NativeObject); } @@ -51,7 +50,7 @@ namespace Microsoft.Z3 /// public string GetDocumentation(Symbol name) { - Contract.Requires(name != null); + Debug.Assert(name != null); return Native.Z3_param_descrs_get_documentation(Context.nCtx, NativeObject, name.NativeObject); } @@ -91,7 +90,7 @@ namespace Microsoft.Z3 internal ParamDescrs(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/dotnet/Params.cs b/src/api/dotnet/Params.cs index f0f28d8d3..e5926934a 100644 --- a/src/api/dotnet/Params.cs +++ b/src/api/dotnet/Params.cs @@ -17,15 +17,14 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// A Params objects represents a configuration in the form of Symbol/value pairs. /// - [ContractVerification(true)] public class Params : Z3Object { /// @@ -33,7 +32,7 @@ namespace Microsoft.Z3 /// public Params Add(Symbol name, bool value) { - Contract.Requires(name != null); + Debug.Assert(name != null); Native.Z3_params_set_bool(Context.nCtx, NativeObject, name.NativeObject, (byte)(value ? 1 : 0)); return this; @@ -44,7 +43,7 @@ namespace Microsoft.Z3 /// public Params Add(Symbol name, uint value) { - Contract.Requires(name != null); + Debug.Assert(name != null); Native.Z3_params_set_uint(Context.nCtx, NativeObject, name.NativeObject, value); return this; @@ -55,7 +54,7 @@ namespace Microsoft.Z3 /// public Params Add(Symbol name, double value) { - Contract.Requires(name != null); + Debug.Assert(name != null); Native.Z3_params_set_double(Context.nCtx, NativeObject, name.NativeObject, value); return this; @@ -66,7 +65,7 @@ namespace Microsoft.Z3 /// public Params Add(Symbol name, string value) { - Contract.Requires(value != null); + Debug.Assert(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, name.NativeObject, Context.MkSymbol(value).NativeObject); return this; @@ -77,8 +76,8 @@ namespace Microsoft.Z3 /// public Params Add(Symbol name, Symbol value) { - Contract.Requires(name != null); - Contract.Requires(value != null); + Debug.Assert(name != null); + Debug.Assert(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, name.NativeObject, value.NativeObject); return this; @@ -117,7 +116,7 @@ namespace Microsoft.Z3 /// public Params Add(string name, Symbol value) { - Contract.Requires(value != null); + Debug.Assert(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, value.NativeObject); return this; @@ -128,8 +127,8 @@ namespace Microsoft.Z3 /// public Params Add(string name, string value) { - Contract.Requires(name != null); - Contract.Requires(value != null); + Debug.Assert(name != null); + Debug.Assert(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, Context.MkSymbol(value).NativeObject); return this; @@ -147,7 +146,7 @@ namespace Microsoft.Z3 internal Params(Context ctx) : base(ctx, Native.Z3_mk_params(ctx.nCtx)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/dotnet/Pattern.cs b/src/api/dotnet/Pattern.cs index 1ea7bdb38..c33a38a1d 100644 --- a/src/api/dotnet/Pattern.cs +++ b/src/api/dotnet/Pattern.cs @@ -17,9 +17,9 @@ Notes: --*/ +using System.Diagnostics; using System; using System.Runtime.InteropServices; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -28,7 +28,6 @@ namespace Microsoft.Z3 /// non-empty. If the list comprises of more than one term, it is /// also called a multi-pattern. /// - [ContractVerification(true)] public class Pattern : AST { /// @@ -46,7 +45,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumTerms; Expr[] res = new Expr[n]; @@ -68,7 +66,7 @@ namespace Microsoft.Z3 internal Pattern(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/Probe.cs b/src/api/dotnet/Probe.cs index 3c5e5adc9..5cdee79a2 100644 --- a/src/api/dotnet/Probe.cs +++ b/src/api/dotnet/Probe.cs @@ -17,9 +17,9 @@ Notes: --*/ +using System.Diagnostics; using System; using System.Runtime.InteropServices; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -30,7 +30,6 @@ namespace Microsoft.Z3 /// and Context.ProbeNames. /// It may also be obtained using the command (help-tactic) in the SMT 2.0 front-end. /// - [ContractVerification(true)] public class Probe : Z3Object { /// @@ -40,7 +39,7 @@ namespace Microsoft.Z3 /// "Boolean" probes return 0.0 for false, and a value different from 0.0 for true. public double Apply(Goal g) { - Contract.Requires(g != null); + Debug.Assert(g != null); Context.CheckContextMatch(g); return Native.Z3_probe_apply(Context.nCtx, NativeObject, g.NativeObject); @@ -53,7 +52,7 @@ namespace Microsoft.Z3 { get { - Contract.Requires(g != null); + Debug.Assert(g != null); return Apply(g); } @@ -63,12 +62,12 @@ namespace Microsoft.Z3 internal Probe(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal Probe(Context ctx, string name) : base(ctx, Native.Z3_mk_probe(ctx.nCtx, name)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/dotnet/Quantifier.cs b/src/api/dotnet/Quantifier.cs index d13ca4003..f4a889092 100644 --- a/src/api/dotnet/Quantifier.cs +++ b/src/api/dotnet/Quantifier.cs @@ -18,14 +18,14 @@ Notes: --*/ using System; -using System.Diagnostics.Contracts; +using System.Diagnostics; +using System.Linq; namespace Microsoft.Z3 { /// /// Quantifier expressions. /// - [ContractVerification(true)] public class Quantifier : BoolExpr { /// @@ -67,7 +67,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumPatterns; Pattern[] res = new Pattern[n]; @@ -92,7 +91,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumNoPatterns; Pattern[] res = new Pattern[n]; @@ -117,7 +115,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumBound; Symbol[] res = new Symbol[n]; @@ -134,7 +131,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumBound; Sort[] res = new Sort[n]; @@ -151,7 +147,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new BoolExpr(Context, Native.Z3_get_quantifier_body(Context.nCtx, NativeObject)); } @@ -168,19 +163,18 @@ namespace Microsoft.Z3 } #region Internal - [ContractVerification(false)] // F: Clousot ForAll decompilation gets confused below. Setting verification off until I fixed the bug internal Quantifier(Context ctx, bool isForall, Sort[] sorts, Symbol[] names, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) : base(ctx, IntPtr.Zero) { - Contract.Requires(ctx != null); - Contract.Requires(sorts != null); - Contract.Requires(names != null); - Contract.Requires(body != null); - Contract.Requires(sorts.Length == names.Length); - Contract.Requires(Contract.ForAll(sorts, s => s != null)); - Contract.Requires(Contract.ForAll(names, n => n != null)); - Contract.Requires(patterns == null || Contract.ForAll(patterns, p => p != null)); - Contract.Requires(noPatterns == null || Contract.ForAll(noPatterns, np => np != null)); + Debug.Assert(ctx != null); + Debug.Assert(sorts != null); + Debug.Assert(names != null); + Debug.Assert(body != null); + Debug.Assert(sorts.Length == names.Length); + Debug.Assert(sorts.All(s => s != null)); + Debug.Assert(names.All(n => n != null)); + Debug.Assert(patterns == null || patterns.All(p => p != null)); + Debug.Assert(noPatterns == null || noPatterns.All(np => np != null)); Context.CheckContextMatch(patterns); Context.CheckContextMatch(noPatterns); @@ -211,16 +205,15 @@ namespace Microsoft.Z3 } } - [ContractVerification(false)] // F: Clousot ForAll decompilation gets confused below. Setting verification off until I fixed the bug internal Quantifier(Context ctx, bool isForall, Expr[] bound, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) : base(ctx, IntPtr.Zero) { - Contract.Requires(ctx != null); - Contract.Requires(body != null); + Debug.Assert(ctx != null); + Debug.Assert(body != null); - Contract.Requires(patterns == null || Contract.ForAll(patterns, p => p != null)); - Contract.Requires(noPatterns == null || Contract.ForAll(noPatterns, np => np != null)); - Contract.Requires(bound == null || Contract.ForAll(bound, n => n != null)); + Debug.Assert(patterns == null || patterns.All(p => p != null)); + Debug.Assert(noPatterns == null || noPatterns.All(np => np != null)); + Debug.Assert(bound == null || bound.All(n => n != null)); Context.CheckContextMatch(noPatterns); Context.CheckContextMatch(patterns); @@ -246,7 +239,7 @@ namespace Microsoft.Z3 } - internal Quantifier(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal Quantifier(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } #if DEBUG internal override void CheckNativeObject(IntPtr obj) diff --git a/src/api/dotnet/RatNum.cs b/src/api/dotnet/RatNum.cs index ef5f1a867..1d485a347 100644 --- a/src/api/dotnet/RatNum.cs +++ b/src/api/dotnet/RatNum.cs @@ -16,8 +16,8 @@ Author: Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; #if !FRAMEWORK_LT_4 using System.Numerics; @@ -28,7 +28,6 @@ namespace Microsoft.Z3 /// /// Rational Numerals /// - [ContractVerification(true)] public class RatNum : RealExpr { /// @@ -38,7 +37,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new IntNum(Context, Native.Z3_get_numerator(Context.nCtx, NativeObject)); } @@ -51,7 +49,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new IntNum(Context, Native.Z3_get_denominator(Context.nCtx, NativeObject)); } @@ -112,7 +109,7 @@ namespace Microsoft.Z3 internal RatNum(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/ReExpr.cs b/src/api/dotnet/ReExpr.cs index 6a10d535f..7ab9aaffc 100644 --- a/src/api/dotnet/ReExpr.cs +++ b/src/api/dotnet/ReExpr.cs @@ -16,12 +16,12 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -35,7 +35,7 @@ namespace Microsoft.Z3 internal ReExpr(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/ReSort.cs b/src/api/dotnet/ReSort.cs index bc420603d..98659c697 100644 --- a/src/api/dotnet/ReSort.cs +++ b/src/api/dotnet/ReSort.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -31,12 +31,12 @@ namespace Microsoft.Z3 internal ReSort(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal ReSort(Context ctx) : base(ctx, Native.Z3_mk_int_sort(ctx.nCtx)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/RealExpr.cs b/src/api/dotnet/RealExpr.cs index 8ee8c8e76..1c3a55189 100644 --- a/src/api/dotnet/RealExpr.cs +++ b/src/api/dotnet/RealExpr.cs @@ -16,12 +16,12 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -35,7 +35,7 @@ namespace Microsoft.Z3 internal RealExpr(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/RealSort.cs b/src/api/dotnet/RealSort.cs index 97f1cae11..38fe469ce 100644 --- a/src/api/dotnet/RealSort.cs +++ b/src/api/dotnet/RealSort.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -31,12 +31,12 @@ namespace Microsoft.Z3 internal RealSort(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal RealSort(Context ctx) : base(ctx, Native.Z3_mk_real_sort(ctx.nCtx)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/RelationSort.cs b/src/api/dotnet/RelationSort.cs index cfd7a592a..6bea5c6e1 100644 --- a/src/api/dotnet/RelationSort.cs +++ b/src/api/dotnet/RelationSort.cs @@ -17,15 +17,14 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// Relation sorts. /// - [ContractVerification(true)] public class RelationSort : Sort { /// @@ -43,7 +42,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); if (m_columnSorts != null) return m_columnSorts; @@ -62,7 +60,7 @@ namespace Microsoft.Z3 internal RelationSort(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/SeqExpr.cs b/src/api/dotnet/SeqExpr.cs index c9fdd03a8..bfab1fa36 100644 --- a/src/api/dotnet/SeqExpr.cs +++ b/src/api/dotnet/SeqExpr.cs @@ -16,12 +16,12 @@ Author: Notes: --*/ +using System.Diagnostics; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -35,7 +35,7 @@ namespace Microsoft.Z3 internal SeqExpr(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/SeqSort.cs b/src/api/dotnet/SeqSort.cs index b2be11291..2902b1e9e 100644 --- a/src/api/dotnet/SeqSort.cs +++ b/src/api/dotnet/SeqSort.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -31,12 +31,12 @@ namespace Microsoft.Z3 internal SeqSort(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal SeqSort(Context ctx) : base(ctx, Native.Z3_mk_int_sort(ctx.nCtx)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #endregion } diff --git a/src/api/dotnet/SetSort.cs b/src/api/dotnet/SetSort.cs index bdba3899f..9f55c8edb 100644 --- a/src/api/dotnet/SetSort.cs +++ b/src/api/dotnet/SetSort.cs @@ -17,28 +17,27 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// Set sorts. /// - [ContractVerification(true)] public class SetSort : Sort { #region Internal internal SetSort(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal SetSort(Context ctx, Sort ty) : base(ctx, Native.Z3_mk_set_sort(ctx.nCtx, ty.NativeObject)) { - Contract.Requires(ctx != null); - Contract.Requires(ty != null); + Debug.Assert(ctx != null); + Debug.Assert(ty != null); } #endregion } diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index a288990a2..ec53b14de 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -18,16 +18,15 @@ Notes: --*/ using System; +using System.Diagnostics; using System.Linq; using System.Collections.Generic; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// Solvers. /// - [ContractVerification(true)] public class Solver : Z3Object { /// @@ -37,7 +36,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Native.Z3_solver_get_help(Context.nCtx, NativeObject); } @@ -50,7 +48,7 @@ namespace Microsoft.Z3 { set { - Contract.Requires(value != null); + Debug.Assert(value != null); Context.CheckContextMatch(value); Native.Z3_solver_set_params(Context.nCtx, NativeObject, value.NativeObject); @@ -152,8 +150,8 @@ namespace Microsoft.Z3 /// public void Assert(params BoolExpr[] constraints) { - Contract.Requires(constraints != null); - Contract.Requires(Contract.ForAll(constraints, c => c != null)); + Debug.Assert(constraints != null); + Debug.Assert(constraints.All(c => c != null)); Context.CheckContextMatch(constraints); foreach (BoolExpr a in constraints) @@ -191,9 +189,9 @@ namespace Microsoft.Z3 /// public void AssertAndTrack(BoolExpr[] constraints, BoolExpr[] ps) { - Contract.Requires(constraints != null); - Contract.Requires(Contract.ForAll(constraints, c => c != null)); - Contract.Requires(Contract.ForAll(ps, c => c != null)); + Debug.Assert(constraints != null); + Debug.Assert(constraints.All(c => c != null)); + Debug.Assert(ps.All(c => c != null)); Context.CheckContextMatch(constraints); Context.CheckContextMatch(ps); if (constraints.Length != ps.Length) @@ -216,8 +214,8 @@ namespace Microsoft.Z3 /// public void AssertAndTrack(BoolExpr constraint, BoolExpr p) { - Contract.Requires(constraint != null); - Contract.Requires(p != null); + Debug.Assert(constraint != null); + Debug.Assert(p != null); Context.CheckContextMatch(constraint); Context.CheckContextMatch(p); @@ -259,7 +257,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)); return assertions.ToBoolExprArray(); @@ -273,7 +270,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_units(Context.nCtx, NativeObject)); return assertions.ToBoolExprArray(); @@ -394,7 +390,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); ASTVector core = new ASTVector(Context, Native.Z3_solver_get_unsat_core(Context.nCtx, NativeObject)); return core.ToBoolExprArray(); @@ -408,7 +403,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Native.Z3_solver_get_reason_unknown(Context.nCtx, NativeObject); } @@ -455,8 +449,7 @@ namespace Microsoft.Z3 /// public Solver Translate(Context ctx) { - Contract.Requires(ctx != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ctx != null); return new Solver(ctx, Native.Z3_solver_translate(Context.nCtx, NativeObject, ctx.nCtx)); } @@ -475,7 +468,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new Statistics(Context, Native.Z3_solver_get_statistics(Context.nCtx, NativeObject)); } @@ -493,7 +485,7 @@ namespace Microsoft.Z3 internal Solver(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); this.BacktrackLevel = uint.MaxValue; } diff --git a/src/api/dotnet/Sort.cs b/src/api/dotnet/Sort.cs index e32fd1eb3..cf70bbf73 100644 --- a/src/api/dotnet/Sort.cs +++ b/src/api/dotnet/Sort.cs @@ -17,15 +17,14 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// The Sort class implements type information for ASTs. /// - [ContractVerification(true)] public class Sort : AST { /// @@ -100,7 +99,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Symbol.Create(Context, Native.Z3_get_sort_name(Context.nCtx, NativeObject)); } } @@ -127,7 +125,7 @@ namespace Microsoft.Z3 /// /// Sort constructor /// - internal Sort(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } + internal Sort(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } #if DEBUG internal override void CheckNativeObject(IntPtr obj) @@ -138,11 +136,9 @@ namespace Microsoft.Z3 } #endif - [ContractVerification(true)] new internal static Sort Create(Context ctx, IntPtr obj) { - Contract.Requires(ctx != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ctx != null); switch ((Z3_sort_kind)Native.Z3_get_sort_kind(ctx.nCtx, obj)) { diff --git a/src/api/dotnet/Statistics.cs b/src/api/dotnet/Statistics.cs index c94af625c..8b664913a 100644 --- a/src/api/dotnet/Statistics.cs +++ b/src/api/dotnet/Statistics.cs @@ -18,14 +18,14 @@ Notes: --*/ using System; -using System.Diagnostics.Contracts; +using System.Diagnostics; + namespace Microsoft.Z3 { /// /// Objects of this class track statistical information about solvers. /// - [ContractVerification(true)] public class Statistics : Z3Object { /// @@ -62,7 +62,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); if (IsUInt) return m_uint.ToString(); @@ -124,9 +123,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.Result().Length == this.Size); - Contract.Ensures(Contract.ForAll(0, Contract.Result().Length, j => Contract.Result()[j] != null)); uint n = Size; Entry[] res = new Entry[n]; @@ -153,7 +149,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = Size; string[] res = new string[n]; @@ -184,7 +179,7 @@ namespace Microsoft.Z3 internal Statistics(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/dotnet/Status.cs b/src/api/dotnet/Status.cs index 5847f098b..d44cffd56 100644 --- a/src/api/dotnet/Status.cs +++ b/src/api/dotnet/Status.cs @@ -17,6 +17,7 @@ Notes: --*/ +using System.Diagnostics; using System; namespace Microsoft.Z3 diff --git a/src/api/dotnet/StringSymbol.cs b/src/api/dotnet/StringSymbol.cs index e311fb958..447e0be5f 100644 --- a/src/api/dotnet/StringSymbol.cs +++ b/src/api/dotnet/StringSymbol.cs @@ -18,8 +18,8 @@ Notes: --*/ using System; +using System.Diagnostics; using System.Runtime.InteropServices; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -27,7 +27,6 @@ namespace Microsoft.Z3 /// /// Named symbols /// - [ContractVerification(true)] public class StringSymbol : Symbol { /// @@ -38,7 +37,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); if (!IsStringSymbol()) throw new Z3Exception("String requested from non-String symbol"); @@ -50,13 +48,13 @@ namespace Microsoft.Z3 internal StringSymbol(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal StringSymbol(Context ctx, string s) : base(ctx, Native.Z3_mk_string_symbol(ctx.nCtx, s)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } #if DEBUG diff --git a/src/api/dotnet/Symbol.cs b/src/api/dotnet/Symbol.cs index 2a1fdf6c5..7df0986fe 100644 --- a/src/api/dotnet/Symbol.cs +++ b/src/api/dotnet/Symbol.cs @@ -18,15 +18,14 @@ Notes: --*/ using System; +using System.Diagnostics; using System.Runtime.InteropServices; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// /// Symbols are used to name several term and type constructors. /// - [ContractVerification(true)] public class Symbol : Z3Object { /// @@ -113,13 +112,12 @@ namespace Microsoft.Z3 /// internal protected Symbol(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal static Symbol Create(Context ctx, IntPtr obj) { - Contract.Requires(ctx != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(ctx != null); switch ((Z3_symbol_kind)Native.Z3_get_symbol_kind(ctx.nCtx, obj)) { diff --git a/src/api/dotnet/Tactic.cs b/src/api/dotnet/Tactic.cs index 0a6f79494..96b6da170 100644 --- a/src/api/dotnet/Tactic.cs +++ b/src/api/dotnet/Tactic.cs @@ -18,7 +18,7 @@ Notes: --*/ using System; -using System.Diagnostics.Contracts; +using System.Diagnostics; namespace Microsoft.Z3 { @@ -28,7 +28,6 @@ namespace Microsoft.Z3 /// and Context.TacticNames. /// It may also be obtained using the command (help-tactic) in the SMT 2.0 front-end. /// - [ContractVerification(true)] public class Tactic : Z3Object { /// @@ -38,7 +37,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Native.Z3_tactic_get_help(Context.nCtx, NativeObject); } @@ -59,8 +57,7 @@ namespace Microsoft.Z3 /// public ApplyResult Apply(Goal g, Params p = null) { - Contract.Requires(g != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(g != null); Context.CheckContextMatch(g); if (p == null) @@ -79,8 +76,7 @@ namespace Microsoft.Z3 { get { - Contract.Requires(g != null); - Contract.Ensures(Contract.Result() != null); + Debug.Assert(g != null); return Apply(g); } @@ -94,7 +90,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return Context.MkSolver(this); } @@ -104,12 +99,12 @@ namespace Microsoft.Z3 internal Tactic(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal Tactic(Context ctx, string name) : base(ctx, Native.Z3_mk_tactic(ctx.nCtx, name)) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } /// diff --git a/src/api/dotnet/TupleSort.cs b/src/api/dotnet/TupleSort.cs index ea99f3855..adbc4f904 100644 --- a/src/api/dotnet/TupleSort.cs +++ b/src/api/dotnet/TupleSort.cs @@ -18,14 +18,13 @@ Notes: --*/ using System; -using System.Diagnostics.Contracts; +using System.Diagnostics; namespace Microsoft.Z3 { /// /// Tuple sorts. /// - [ContractVerification(true)] public class TupleSort : Sort { /// @@ -35,7 +34,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return new FuncDecl(Context, Native.Z3_get_tuple_sort_mk_decl(Context.nCtx, NativeObject)); } @@ -56,7 +54,6 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); uint n = NumFields; FuncDecl[] res = new FuncDecl[n]; @@ -70,8 +67,8 @@ namespace Microsoft.Z3 internal TupleSort(Context ctx, Symbol name, uint numFields, Symbol[] fieldNames, Sort[] fieldSorts) : base(ctx, IntPtr.Zero) { - Contract.Requires(ctx != null); - Contract.Requires(name != null); + Debug.Assert(ctx != null); + Debug.Assert(name != null); IntPtr t = IntPtr.Zero; IntPtr[] f = new IntPtr[numFields]; diff --git a/src/api/dotnet/UninterpretedSort.cs b/src/api/dotnet/UninterpretedSort.cs index 154818faf..9f940468d 100644 --- a/src/api/dotnet/UninterpretedSort.cs +++ b/src/api/dotnet/UninterpretedSort.cs @@ -18,7 +18,7 @@ Notes: --*/ using System; -using System.Diagnostics.Contracts; +using System.Diagnostics; namespace Microsoft.Z3 { @@ -31,13 +31,13 @@ namespace Microsoft.Z3 internal UninterpretedSort(Context ctx, IntPtr obj) : base(ctx, obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); } internal UninterpretedSort(Context ctx, Symbol s) : base(ctx, Native.Z3_mk_uninterpreted_sort(ctx.nCtx, s.NativeObject)) { - Contract.Requires(ctx != null); - Contract.Requires(s != null); + Debug.Assert(ctx != null); + Debug.Assert(s != null); } #endregion } diff --git a/src/api/dotnet/Version.cs b/src/api/dotnet/Version.cs index 364ada781..2099959eb 100644 --- a/src/api/dotnet/Version.cs +++ b/src/api/dotnet/Version.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; namespace Microsoft.Z3 { @@ -26,7 +26,6 @@ namespace Microsoft.Z3 /// Version information. /// /// Note that this class is static. - [ContractVerification(true)] public static class Version { static Version() { } @@ -99,7 +98,6 @@ namespace Microsoft.Z3 /// new public static string ToString() { - Contract.Ensures(Contract.Result() != null); uint major = 0, minor = 0, build = 0, revision = 0; Native.Z3_get_version(ref major, ref minor, ref build, ref revision); diff --git a/src/api/dotnet/Z3Exception.cs b/src/api/dotnet/Z3Exception.cs index b0e05900c..79f6185da 100644 --- a/src/api/dotnet/Z3Exception.cs +++ b/src/api/dotnet/Z3Exception.cs @@ -17,6 +17,7 @@ Notes: --*/ +using System.Diagnostics; using System; namespace Microsoft.Z3 diff --git a/src/api/dotnet/Z3Object.cs b/src/api/dotnet/Z3Object.cs index f32ba30af..9a61a0119 100644 --- a/src/api/dotnet/Z3Object.cs +++ b/src/api/dotnet/Z3Object.cs @@ -17,8 +17,8 @@ Notes: --*/ +using System.Diagnostics; using System; -using System.Diagnostics.Contracts; using System.Threading; using System.Collections.Generic; using System.Linq; @@ -29,7 +29,6 @@ namespace Microsoft.Z3 /// Internal base class for interfacing with native Z3 objects. /// Should not be used externally. /// - [ContractVerification(true)] public class Z3Object : IDisposable { /// @@ -63,10 +62,9 @@ namespace Microsoft.Z3 #region Object Invariant - [ContractInvariantMethod] private void ObjectInvariant() { - Contract.Invariant(this.m_ctx != null); + Debug.Assert(this.m_ctx != null); } #endregion @@ -77,7 +75,7 @@ namespace Microsoft.Z3 internal Z3Object(Context ctx) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); Interlocked.Increment(ref ctx.refCount); m_ctx = ctx; @@ -85,7 +83,7 @@ namespace Microsoft.Z3 internal Z3Object(Context ctx, IntPtr obj) { - Contract.Requires(ctx != null); + Debug.Assert(ctx != null); Interlocked.Increment(ref ctx.refCount); m_ctx = ctx; @@ -119,16 +117,12 @@ namespace Microsoft.Z3 { get { - Contract.Ensures(Contract.Result() != null); return m_ctx; } } - [Pure] internal static IntPtr[] ArrayToNative(Z3Object[] a) { - Contract.Ensures(a == null || Contract.Result() != null); - Contract.Ensures(a == null || Contract.Result().Length == a.Length); if (a == null) return null; IntPtr[] an = new IntPtr[a.Length]; @@ -137,11 +131,8 @@ namespace Microsoft.Z3 return an; } - [Pure] internal static IntPtr[] EnumToNative(IEnumerable a) where T : Z3Object { - Contract.Ensures(a == null || Contract.Result() != null); - Contract.Ensures(a == null || Contract.Result().Length == a.Count()); if (a == null) return null; IntPtr[] an = new IntPtr[a.Count()]; @@ -154,7 +145,6 @@ namespace Microsoft.Z3 return an; } - [Pure] internal static uint ArrayLength(Z3Object[] a) { return (a == null)?0:(uint)a.Length; From 39d8053a5496cbd42d3cd067be7cce3068cc999b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Oct 2018 10:32:09 -0700 Subject: [PATCH 080/227] remove dummy contracts Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/core/DummyContracts.cs | 65 --------------------------- src/api/dotnet/core/README.txt | 4 ++ 2 files changed, 4 insertions(+), 65 deletions(-) delete mode 100644 src/api/dotnet/core/DummyContracts.cs diff --git a/src/api/dotnet/core/DummyContracts.cs b/src/api/dotnet/core/DummyContracts.cs deleted file mode 100644 index 103cc1288..000000000 --- a/src/api/dotnet/core/DummyContracts.cs +++ /dev/null @@ -1,65 +0,0 @@ -/*++ -Copyright () 2016 Microsoft Corporation - -Module Name: - - Contracts.cs - -Abstract: - - Z3 Managed API: Dummy Code Contracts class for .NET - frameworks that don't support them (e.g., CoreCLR). - -Author: - - Christoph Wintersteiger (cwinter) 2016-10-06 - -Notes: - ---*/ - -namespace System.Diagnostics.Contracts -{ - public class ContractClass : Attribute - { - public ContractClass(Type t) { } - } - - public class ContractClassFor : Attribute - { - public ContractClassFor(Type t) { } - } - - public class ContractInvariantMethod : Attribute - { - public ContractInvariantMethod() { } - } - - public class ContractVerification : Attribute - { - public ContractVerification(bool b) { } - } - - public class Pure : Attribute { } - - public static class Contract - { - [Conditional("false")] - public static void Ensures(bool b) { } - [Conditional("false")] - public static void Requires(bool b) { } - [Conditional("false")] - public static void Assume(bool b, string msg) { } - [Conditional("false")] - public static void Assert(bool b) { } - public static bool ForAll(bool b) { return true; } - public static bool ForAll(Object c, Func p) { return true; } - public static bool ForAll(int from, int to, Predicate p) { return true; } - [Conditional("false")] - public static void Invariant(bool b) { } - public static T[] Result() { return new T[1]; } - [Conditional("false")] - public static void EndContractBlock() { } - public static T ValueAtReturn(out T v) { T[] t = new T[1]; v = t[0]; return v; } - } -} diff --git a/src/api/dotnet/core/README.txt b/src/api/dotnet/core/README.txt index 7af9cbf2c..fa274f72b 100644 --- a/src/api/dotnet/core/README.txt +++ b/src/api/dotnet/core/README.txt @@ -8,4 +8,8 @@ checking. To build this using .NET core, run (in this directory): dotnet restore dotnet build core.csproj -c Release +If you are building with the cmake system, you should first +copy over files that are produced by the compiler into +this directory. You need to copy over Native.cs and Enumeration.cs + -- good luck! From 8f90176883eb60d62f821cbbda6564b76fd73122 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Oct 2018 13:54:55 -0700 Subject: [PATCH 081/227] fix symbol comparison Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Symbol.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/dotnet/Symbol.cs b/src/api/dotnet/Symbol.cs index 7df0986fe..afefdf3df 100644 --- a/src/api/dotnet/Symbol.cs +++ b/src/api/dotnet/Symbol.cs @@ -83,7 +83,7 @@ namespace Microsoft.Z3 /// public static bool operator !=(Symbol s1, Symbol s2) { - return !(s1.NativeObject == s2.NativeObject); + return !(s1 == s2); } /// From 3ba2aa2672f5ab6e5f7d665675a4de32fef6981d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Oct 2018 14:01:43 -0700 Subject: [PATCH 082/227] regressions in examples/dotnet/Program.cs Signed-off-by: Nikolaj Bjorner --- examples/dotnet/Program.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 230aacf6f..b6f6e8038 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -363,10 +363,10 @@ namespace test_mapi Console.WriteLine("Model = " + s.Model); - Console.WriteLine("Interpretation of MyArray:\n" + s.Model.FuncInterp(aex.FuncDecl)); + //Console.WriteLine("Interpretation of MyArray:\n" + s.Model.ConstInterp(aex.FuncDecl)); Console.WriteLine("Interpretation of x:\n" + s.Model.ConstInterp(xc)); Console.WriteLine("Interpretation of f:\n" + s.Model.FuncInterp(fd)); - Console.WriteLine("Interpretation of MyArray as Term:\n" + s.Model.FuncInterp(aex.FuncDecl)); + //Console.WriteLine("Interpretation of MyArray as Term:\n" + s.Model.ConstInterp(aex.FuncDecl)); } /// @@ -2103,7 +2103,7 @@ namespace test_mapi if (s.Check() != Status.SATISFIABLE) throw new TestFailedException(); - Console.WriteLine("OK, model: {0}", s.Model.ToString()); + // Console.WriteLine("OK, model: {0}", s.Model.ToString()); } From c802a0ac96652fc24efce7e35aa87e39c046923f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Oct 2018 14:32:59 -0700 Subject: [PATCH 083/227] fix crash exposed by examples/dotnet/Program.cs Signed-off-by: Nikolaj Bjorner --- examples/dotnet/Program.cs | 2 +- src/model/model.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index b6f6e8038..47906add4 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -2103,7 +2103,7 @@ namespace test_mapi if (s.Check() != Status.SATISFIABLE) throw new TestFailedException(); - // Console.WriteLine("OK, model: {0}", s.Model.ToString()); + Console.WriteLine("OK, model: {0}", s.Model.ToString()); } diff --git a/src/model/model.cpp b/src/model/model.cpp index a1fdfc980..60441054c 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -312,7 +312,8 @@ void model::collect_occs(top_sort& ts, func_decl* f) { func_interp* fi = get_func_interp(f); if (fi) { e = fi->get_else(); - collect_occs(ts, e); + if (e != nullptr) + collect_occs(ts, e); } } } From 21cf218a9f1853ff16255c8dd141c5e4230b9fce Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 21 Oct 2018 20:10:41 +0700 Subject: [PATCH 084/227] Remove commented out string2ostream. --- src/util/warning.cpp | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/util/warning.cpp b/src/util/warning.cpp index 6184db880..a2ebade85 100644 --- a/src/util/warning.cpp +++ b/src/util/warning.cpp @@ -25,7 +25,6 @@ Revision History: #include "util/vector.h" #ifdef _WINDOWS -#define PRF sprintf_s #define VPRF vsprintf_s void STD_CALL myInvalidParameterHandler( @@ -54,7 +53,6 @@ void STD_CALL myInvalidParameterHandler( #else -#define PRF snprintf #define VPRF vsnprintf #define BEGIN_ERR_HANDLER() {} #define END_ERR_HANDLER() {} @@ -86,23 +84,6 @@ void disable_error_msg_prefix() { g_show_error_msg_prefix = false; } -#if 0 -// [Leo]: Do we need this? -static void string2ostream(std::ostream& out, char const* msg) { - svector buff; - buff.resize(10); - BEGIN_ERR_HANDLER(); - while (true) { - int nc = PRF(buff.c_ptr(), buff.size(), msg); - if (nc >= 0 && nc < static_cast(buff.size())) - break; // success - buff.resize(buff.size()*2 + 1); - } - END_ERR_HANDLER(); - out << buff.c_ptr(); -} -#endif - void format2ostream(std::ostream & out, char const* msg, va_list args) { svector buff; #if !defined(_WINDOWS) && defined(_AMD64_) From 129353542cde46e4591827c858f5a3ff144c8768 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 21 Oct 2018 19:28:31 +0700 Subject: [PATCH 085/227] Improve format2ostream. Instead of looping to find a big enough buffer, we can call the correct function to calculate it, remembering to add an extra character for NUL termination. We also correctly do a va_copy of the args to avoid crashes on some platforms. --- src/util/warning.cpp | 46 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/src/util/warning.cpp b/src/util/warning.cpp index a2ebade85..d4de28782 100644 --- a/src/util/warning.cpp +++ b/src/util/warning.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include -#include +#include +#include #include "util/error_codes.h" #include "util/util.h" @@ -86,38 +86,22 @@ void disable_error_msg_prefix() { void format2ostream(std::ostream & out, char const* msg, va_list args) { svector buff; -#if !defined(_WINDOWS) && defined(_AMD64_) - // see comment below. - buff.resize(1024); -#else - buff.resize(128); -#endif BEGIN_ERR_HANDLER(); - while (true) { - int nc = VPRF(buff.c_ptr(), buff.size(), msg, args); -#if !defined(_WINDOWS) && defined(_AMD64_) - // For some strange reason, on Linux 64-bit version, va_list args is reset by vsnprintf. - // Z3 crashes when trying to use va_list args again. - // Hack: I truncate the message instead of expanding the buffer to make sure that - // va_list args is only used once. - END_ERR_HANDLER(); - if (nc < 0) { - // vsnprintf didn't work, so we just print the msg - out << msg; - return; - } - if (nc >= static_cast(buff.size())) { - // truncate the message - buff[buff.size() - 1] = 0; - } - out << buff.c_ptr(); - return; + + va_list args_copy; + va_copy(args_copy, args); +#ifdef _WINDOWS + size_t msg_len = _vscprintf(msg, args_copy); #else - if (nc >= 0 && nc < static_cast(buff.size())) - break; // success - buff.resize(buff.size()*2 + 1); + size_t msg_len = vsnprintf(NULL, 0, msg, args_copy); #endif - } + va_end(args_copy); + + // +1 is for NUL termination. + buff.resize(msg_len + 1); + + VPRF(buff.c_ptr(), buff.size(), msg, args); + END_ERR_HANDLER(); out << buff.c_ptr(); } From a73cf590db666f0f6adea1a42e96d58fa084e8cc Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 21 Oct 2018 20:29:01 +0700 Subject: [PATCH 086/227] Remove disable_error_msg_prefix. This wasn't used or actually implemented to do anything. --- src/util/warning.cpp | 5 ----- src/util/warning.h | 2 -- 2 files changed, 7 deletions(-) diff --git a/src/util/warning.cpp b/src/util/warning.cpp index d4de28782..10f18c21c 100644 --- a/src/util/warning.cpp +++ b/src/util/warning.cpp @@ -62,7 +62,6 @@ static bool g_warning_msgs = true; static bool g_use_std_stdout = false; static std::ostream* g_error_stream = nullptr; static std::ostream* g_warning_stream = nullptr; -static bool g_show_error_msg_prefix = true; void send_warnings_to_stdout(bool flag) { g_use_std_stdout = flag; @@ -80,10 +79,6 @@ void set_warning_stream(std::ostream* strm) { g_warning_stream = strm; } -void disable_error_msg_prefix() { - g_show_error_msg_prefix = false; -} - void format2ostream(std::ostream & out, char const* msg, va_list args) { svector buff; BEGIN_ERR_HANDLER(); diff --git a/src/util/warning.h b/src/util/warning.h index 15f1a1757..629c357fa 100644 --- a/src/util/warning.h +++ b/src/util/warning.h @@ -31,8 +31,6 @@ void set_warning_stream(std::ostream* strm); void warning_msg(const char * msg, ...); -void disable_error_msg_prefix(); - void format2ostream(std::ostream& out, char const* fmt, va_list args); class warning_displayer { From 7e35ce275a3d5860ba566d2391b7692abe58f82f Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 21 Oct 2018 20:30:07 +0700 Subject: [PATCH 087/227] Remove unused warning_displayer. --- src/util/warning.h | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/util/warning.h b/src/util/warning.h index 629c357fa..2bcc7512b 100644 --- a/src/util/warning.h +++ b/src/util/warning.h @@ -33,26 +33,5 @@ void warning_msg(const char * msg, ...); void format2ostream(std::ostream& out, char const* fmt, va_list args); -class warning_displayer { - const char * m_msg; - bool m_displayed; -public: - warning_displayer(const char * msg): - m_msg(msg), - m_displayed(false) { - } - - void sign() { - if (!m_displayed) { - warning_msg(m_msg); - m_displayed = true; - } - } - - void reset() { - m_displayed = false; - } -}; - #endif /* WARNING_H_ */ From 6e41b853f7e2dd8abcc60310d3a1237c0f61dca0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 21 Oct 2018 12:25:57 -0700 Subject: [PATCH 088/227] remove case-pred and depth-limit classes Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.cpp | 1 + src/ast/recfun_decl_plugin.cpp | 60 +++++++------------------- src/ast/recfun_decl_plugin.h | 64 ++++------------------------ src/cmd_context/cmd_context.cpp | 11 +++-- src/parsers/smt2/smt2parser.cpp | 38 ++++++++++++++--- src/smt/params/smt_params_helper.pyg | 2 +- src/smt/smt_setup.cpp | 1 + src/smt/theory_recfun.cpp | 28 ++++++------ src/smt/theory_recfun.h | 1 - 9 files changed, 81 insertions(+), 125 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index af451f9c5..868b35d00 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -517,6 +517,7 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters void array_decl_plugin::get_sort_names(svector& sort_names, symbol const & logic) { sort_names.push_back(builtin_name(ARRAY_SORT_STR, ARRAY_SORT)); + sort_names.push_back(builtin_name("=>", ARRAY_SORT)); // TBD: this could easily break users even though it is already used in CVC4: // sort_names.push_back(builtin_name("Set", _SET_SORT)); } diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 1cd9a4fb8..cdd1cec92 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -27,13 +27,7 @@ Revision History: #define VALIDATE_PARAM(m, _pred_) if (!(_pred_)) m.raise_exception("invalid parameter to recfun " #_pred_); namespace recfun { - case_pred::case_pred(ast_manager & m, family_id fid, std::string const & s, sort_ref_vector const & domain) - : m_name(), m_name_buf(s), m_domain(domain), m_decl(m) - { - m_name = symbol(m_name_buf.c_str()); - func_decl_info info(fid, OP_FUN_CASE_PRED); - m_decl = m.mk_func_decl(m_name, domain.size(), domain.c_ptr(), m.mk_bool_sort(), info); - } + case_def::case_def(ast_manager &m, family_id fid, @@ -41,21 +35,20 @@ namespace recfun { std::string & name, sort_ref_vector const & arg_sorts, unsigned num_guards, expr ** guards, expr* rhs) - : m_pred(m, fid, name, arg_sorts), m_guards(m), m_rhs(expr_ref(rhs,m)), m_def(d) { - for (unsigned i = 0; i < num_guards; ++i) { - m_guards.push_back(guards[i]); - } + : m_pred(m), + m_guards(m, num_guards, guards), + m_rhs(expr_ref(rhs,m)), + m_def(d) { + func_decl_info info(fid, OP_FUN_CASE_PRED); + m_pred = m.mk_func_decl(symbol(name.c_str()), arg_sorts.size(), arg_sorts.c_ptr(), m.mk_bool_sort(), info); } def::def(ast_manager &m, family_id fid, symbol const & s, unsigned arity, sort* const * domain, sort* range) : m(m), m_name(s), - m_domain(m), m_range(range, m), m_vars(m), m_cases(), + m_domain(m, arity, domain), m_range(range, m), m_vars(m), m_cases(), m_decl(m), m_fid(fid), m_macro(false) { - for (unsigned i = 0; i < arity; ++i) - m_domain.push_back(domain[i]); - SASSERT(arity == get_arity()); func_decl_info info(fid, OP_FUN_DEFINED); @@ -199,10 +192,11 @@ namespace recfun { void def::compute_cases(is_immediate_pred & is_i, th_rewriter & th_rw, unsigned n_vars, var *const * vars, expr* rhs0) { - if (m_cases.size() != 0) { + if (!m_cases.empty()) { TRACEFN("bug: " << m_name << " has cases already"); UNREACHABLE(); } + SASSERT(m_cases.empty()); SASSERT(n_vars == m_domain.size()); TRACEFN("compute cases " << mk_pp(rhs0, m)); @@ -343,14 +337,11 @@ namespace recfun { */ util::util(ast_manager & m, family_id id) - : m_manager(m), m_family_id(id), m_th_rw(m), m_plugin(0), m_dlimit_map() { + : m_manager(m), m_family_id(id), m_th_rw(m), m_plugin(0) { m_plugin = dynamic_cast(m.get_plugin(m_family_id)); } util::~util() { - for (auto & kv : m_dlimit_map) { - dealloc(kv.m_value); - } } def * util::decl_fun(symbol const& name, unsigned n, sort *const * domain, sort * range) { @@ -361,20 +352,11 @@ namespace recfun { d.set_definition(n_vars, vars, rhs); } - // get or create predicate for depth limit - depth_limit_pred_ref util::get_depth_limit_pred(unsigned d) { - depth_limit_pred * pred = nullptr; - if (! m_dlimit_map.find(d, pred)) { - pred = alloc(depth_limit_pred, m(), m_family_id, d); - m_dlimit_map.insert(d, pred); - } - return depth_limit_pred_ref(pred, *this); - } - app_ref util::mk_depth_limit_pred(unsigned d) { - depth_limit_pred_ref p = get_depth_limit_pred(d); - app_ref res(m().mk_const(p->get_decl()), m()); - return res; + parameter p(d); + func_decl_info info(m_family_id, OP_DEPTH_LIMIT, 1, &p); + func_decl* decl = m().mk_const_decl(symbol("recfun-depth-limit"), m().mk_bool_sort(), info); + return app_ref(m().mk_const(decl), m()); } // used to know which `app` are from this theory @@ -409,18 +391,6 @@ namespace recfun { d->compute_cases(is_i, u->get_th_rewriter(), n_vars, vars, rhs); } - depth_limit_pred::depth_limit_pred(ast_manager & m, family_id fid, unsigned d) - : m_name_buf(), m_name(""), m_depth(d), m_decl(m) { - // build name, then build decl - std::ostringstream tmpname; - tmpname << "depth_limit_" << d << std::flush; - m_name_buf.append(tmpname.str()); - m_name = symbol(m_name_buf.c_str()); - parameter params[1] = { parameter(d) }; - func_decl_info info(fid, OP_DEPTH_LIMIT, 1, params); - m_decl = m.mk_const_decl(m_name, m.mk_bool_sort(), info); - } - namespace decl { plugin::plugin() : decl_plugin(), m_defs(), m_case_defs(), m_def_block() {} plugin::~plugin() { finalize(); } diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index f2da9d053..cadbccfec 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -40,26 +40,12 @@ namespace recfun { and therefore two case predicates `C_fact_0` and `C_fact_1`, where `C_fact_0(t)=true` means `t<2` (first path) and `C_fact_1(t)=true` means `not (t<2)` (second path). */ - class case_pred { - friend class case_def; - symbol m_name; //get_name(); } + + app_ref apply_case_predicate(ptr_vector const & args) const { + ast_manager& m = m_pred.get_manager(); + return app_ref(m.mk_app(m_pred, args.size(), args.c_ptr()), m); + } + def * get_def() const { return m_def; } expr_ref_vector const & get_guards() const { return m_guards; } expr * get_guards_c_ptr() const { return *m_guards.c_ptr(); } @@ -145,27 +136,6 @@ namespace recfun { def * get_def() const { return d; } }; - // predicate for limiting unrolling depth, to be used in assumptions and conflicts - class depth_limit_pred { - friend class util; - std::string m_name_buf; - symbol m_name; - unsigned m_depth; - func_decl_ref m_decl; - unsigned m_refcount; - - void inc_ref() { m_refcount ++; } - void dec_ref() { SASSERT(m_refcount > 0); m_refcount --; } - public: - depth_limit_pred(ast_manager & m, family_id fid, unsigned d); - unsigned get_depth() const { return m_depth; } - symbol const & get_name() const { return m_name; } - func_decl * get_decl() const { return m_decl.get(); } - }; - - // A reference to `depth_limit_pred` - typedef obj_ref depth_limit_pred_ref; - namespace decl { class plugin : public decl_plugin { @@ -220,17 +190,15 @@ namespace recfun { // Varus utils for recursive functions class util { friend class decl::plugin; - - typedef map> depth_limit_map; ast_manager & m_manager; family_id m_family_id; th_rewriter m_th_rw; decl::plugin * m_plugin; - depth_limit_map m_dlimit_map; bool compute_is_immediate(expr * rhs); void set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs); + public: util(ast_manager &m, family_id); virtual ~util(); @@ -268,26 +236,12 @@ namespace recfun { app* mk_fun_defined(def const & d, ptr_vector const & args) { return mk_fun_defined(d, args.size(), args.c_ptr()); } - app* mk_case_pred(case_pred const & p, ptr_vector const & args) { - return m().mk_app(p.get_decl(), args.size(), args.c_ptr()); - } - void inc_ref(depth_limit_pred * p) { p->inc_ref(); } - void dec_ref(depth_limit_pred * p) { - p->dec_ref(); - if (p->m_refcount == 0) { - m_dlimit_map.remove(p->m_depth); - dealloc(p); - } - } - - depth_limit_pred_ref get_depth_limit_pred(unsigned d); app_ref mk_depth_limit_pred(unsigned d); }; } typedef recfun::def recfun_def; typedef recfun::case_def recfun_case_def; -typedef recfun::depth_limit_pred recfun_depth_limit_pred; typedef recfun::decl::plugin recfun_decl_plugin; typedef recfun::util recfun_util; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 18b47d012..188e2331e 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1135,14 +1135,17 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg if (num_args == 0 && range == nullptr) { if (fs.more_than_one()) - throw cmd_exception("ambiguous constant reference, more than one constant with the same sort, use a qualified expression (as ) to disumbiguate ", s); + throw cmd_exception("ambiguous constant reference, more than one constant with the same sort, use a qualified expression (as ) to disambiguate ", s); func_decl * f = fs.first(); if (f == nullptr) { throw cmd_exception("unknown constant ", s); } - if (f->get_arity() != 0) - throw cmd_exception("invalid function application, missing arguments ", s); - result = m().mk_const(f); + if (f->get_arity() != 0) { + result = array_util(m()).mk_as_array(f); + } + else { + result = m().mk_const(f); + } } else { func_decl * f = fs.find(m(), num_args, args, range); diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 7458fc578..e60608ad3 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -1439,6 +1439,12 @@ namespace smt2 { // compute match condition and substitution // t is shifted by size of subst. expr_ref bind_match(expr* t, expr* pattern, expr_ref_vector& subst) { + if (m().get_sort(t) != m().get_sort(pattern)) { + std::ostringstream str; + str << "sorts of pattern " << expr_ref(pattern, m()) << " and term " + << expr_ref(t, m()) << " are not aligned"; + throw parser_exception(str.str()); + } expr_ref tsh(m()); if (is_var(pattern)) { shifter()(t, 1, tsh); @@ -1894,13 +1900,31 @@ namespace smt2 { unsigned num_args = expr_stack().size() - fr->m_expr_spos; unsigned num_indices = m_param_stack.size() - fr->m_param_spos; expr_ref t_ref(m()); - m_ctx.mk_app(fr->m_f, - num_args, - expr_stack().c_ptr() + fr->m_expr_spos, - num_indices, - m_param_stack.c_ptr() + fr->m_param_spos, - fr->m_as_sort ? sort_stack().back() : nullptr, - t_ref); + local l; + if (m_env.find(fr->m_f, l)) { + push_local(l); + t_ref = expr_stack().back(); + for (unsigned i = 0; i < num_args; ++i) { + expr* arg = expr_stack().get(fr->m_expr_spos + i); + expr* args[2] = { t_ref.get(), arg }; + m_ctx.mk_app(symbol("select"), + 2, + args, + 0, + nullptr, + nullptr, + t_ref); + } + } + else { + m_ctx.mk_app(fr->m_f, + num_args, + expr_stack().c_ptr() + fr->m_expr_spos, + num_indices, + m_param_stack.c_ptr() + fr->m_param_spos, + fr->m_as_sort ? sort_stack().back() : nullptr, + t_ref); + } expr_stack().shrink(fr->m_expr_spos); m_param_stack.shrink(fr->m_param_spos); if (fr->m_as_sort) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 828e4f7de..c927b3214 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -97,5 +97,5 @@ def_module_params(module_name='smt', ('lemma_gc_strategy', UINT, 0, 'lemma garbage collection strategy: 0 - fixed, 1 - geometric, 2 - at restart, 3 - none'), ('dt_lazy_splits', UINT, 1, 'How lazy datatype splits are performed: 0- eager, 1- lazy for infinite types, 2- lazy'), ('recfun.native', BOOL, False, 'use native rec-fun solver'), - ('recfun.max_depth', UINT, 500, 'maximum depth of unrolling for recursive functions') + ('recfun.max_depth', UINT, 50, 'maximum depth of unrolling for recursive functions') )) diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 5b02c5bbb..99ec09d1d 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -964,6 +964,7 @@ namespace smt { setup_seq_str(st); setup_card(); setup_fpa(); + setup_recfuns(); return; } diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 059a34f29..0a91074ec 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -83,6 +83,7 @@ namespace smt { void theory_recfun::reset_queues() { m_q_case_expand.reset(); m_q_body_expand.reset(); + m_q_clauses.clear(); } void theory_recfun::reset_eh() { @@ -146,7 +147,8 @@ namespace smt { } m_q_clauses.clear(); - for (case_expansion & e : m_q_case_expand) { + for (unsigned i = 0; i < m_q_case_expand.size(); ++i) { + case_expansion & e = m_q_case_expand[i]; if (e.m_def->is_fun_macro()) { // body expand immediately assert_macro_axiom(e); @@ -159,8 +161,8 @@ namespace smt { } m_q_case_expand.clear(); - for (body_expansion & e : m_q_body_expand) { - assert_body_axiom(e); + for (unsigned i = 0; i < m_q_body_expand.size(); ++i) { + assert_body_axiom(m_q_body_expand[i]); } m_q_body_expand.clear(); } @@ -173,6 +175,8 @@ namespace smt { // first literal must be the depth limit one app_ref dlimit = m_util.mk_depth_limit_pred(get_max_depth()); c.push_back(~mk_literal(dlimit)); + enable_trace("recfun"); + TRACE("recfun", ctx().display(tout << c.back() << " " << dlimit << "\n");); SASSERT(ctx().get_assignment(c.back()) == l_false); for (expr * g : guards) { @@ -208,12 +212,7 @@ namespace smt { ctx().get_rewriter()(new_body); // simplify return new_body; } - - app_ref theory_recfun::apply_pred(recfun::case_pred const & p, - ptr_vector const & args) { - return app_ref(u().mk_case_pred(p, args), m); - } - + literal theory_recfun::mk_literal(expr* e) { ctx().internalize(e, false); literal lit = ctx().get_literal(e); @@ -246,14 +245,14 @@ namespace smt { * 2. add unit clause `f(args) = rhs` */ void theory_recfun::assert_macro_axiom(case_expansion & e) { + TRACEFN("case expansion " << pp_case_expansion(e, m) << "\n"); SASSERT(e.m_def->is_fun_macro()); auto & vars = e.m_def->get_vars(); expr_ref lhs(e.m_lhs, m); expr_ref rhs(apply_args(vars, e.m_args, e.m_def->get_macro_rhs()), m); literal lit = mk_eq_lit(lhs, rhs); ctx().mk_th_axiom(get_id(), 1, &lit); - TRACEFN("case expansion " << pp_case_expansion(e, m) << "\n" << - "macro expansion yields " << mk_pp(rhs,m) << "\n" << + TRACEFN("macro expansion yields " << mk_pp(rhs,m) << "\n" << "literal " << pp_lit(ctx(), lit)); } @@ -272,7 +271,7 @@ namespace smt { auto & vars = e.m_def->get_vars(); for (recfun::case_def const & c : e.m_def->get_cases()) { // applied predicate to `args` - app_ref pred_applied = apply_pred(c.get_pred(), e.m_args); + app_ref pred_applied = c.apply_case_predicate(e.m_args); SASSERT(u().owns_app(pred_applied)); literal concl = mk_literal(pred_applied); @@ -331,6 +330,11 @@ namespace smt { } final_check_status theory_recfun::final_check_eh() { + TRACEFN("final\n"); + if (can_propagate()) { + propagate(); + return FC_CONTINUE; + } return FC_DONE; } diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 265d8f305..f4783dcdc 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -108,7 +108,6 @@ namespace smt { void reset_queues(); expr_ref apply_args(recfun::vars const & vars, ptr_vector const & args, expr * e); //!< substitute variables by args - app_ref apply_pred(recfun::case_pred const & p, ptr_vector const & args); // Date: Sun, 21 Oct 2018 13:15:14 -0700 Subject: [PATCH 089/227] bypass warning size_t/unsigned Signed-off-by: Nikolaj Bjorner --- src/util/warning.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/warning.cpp b/src/util/warning.cpp index 10f18c21c..1e9f8a484 100644 --- a/src/util/warning.cpp +++ b/src/util/warning.cpp @@ -93,7 +93,7 @@ void format2ostream(std::ostream & out, char const* msg, va_list args) { va_end(args_copy); // +1 is for NUL termination. - buff.resize(msg_len + 1); + buff.resize(static_cast(msg_len + 1)); VPRF(buff.c_ptr(), buff.size(), msg, args); From 918a5b9e8c1c93bc32129afc2612ffa11bb2d9db Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 21 Oct 2018 13:15:51 -0700 Subject: [PATCH 090/227] updates to recfun_decl_plugin Signed-off-by: Nikolaj Bjorner --- src/ast/recfun_decl_plugin.cpp | 107 +++++++++++++-------------------- src/ast/recfun_decl_plugin.h | 6 +- 2 files changed, 44 insertions(+), 69 deletions(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index cdd1cec92..6ee0ddc39 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -33,26 +33,32 @@ namespace recfun { family_id fid, def * d, std::string & name, + unsigned case_index, sort_ref_vector const & arg_sorts, - unsigned num_guards, expr ** guards, expr* rhs) + expr_ref_vector const& guards, + expr* rhs) : m_pred(m), - m_guards(m, num_guards, guards), + m_guards(guards), m_rhs(expr_ref(rhs,m)), m_def(d) { - func_decl_info info(fid, OP_FUN_CASE_PRED); + parameter p(case_index); + func_decl_info info(fid, OP_FUN_CASE_PRED, 1, &p); m_pred = m.mk_func_decl(symbol(name.c_str()), arg_sorts.size(), arg_sorts.c_ptr(), m.mk_bool_sort(), info); } def::def(ast_manager &m, family_id fid, symbol const & s, unsigned arity, sort* const * domain, sort* range) : m(m), m_name(s), - m_domain(m, arity, domain), m_range(range, m), m_vars(m), m_cases(), - m_decl(m), m_fid(fid), m_macro(false) + m_domain(m, arity, domain), + m_range(range, m), m_vars(m), m_cases(), + m_decl(m), + m_fid(fid), + m_macro(false) { SASSERT(arity == get_arity()); func_decl_info info(fid, OP_FUN_DEFINED); - m_decl = m.mk_func_decl(m_name, arity, domain, range, info); + m_decl = m.mk_func_decl(s, arity, domain, range, info); } // does `e` contain any `ite` construct? @@ -101,6 +107,8 @@ namespace recfun { ite_lst const * to_split; // `ite` terms to make a choice on unfold_lst const * to_unfold; // terms yet to unfold + branch(unfold_lst const * to_unfold): + path(nullptr), to_split(nullptr), to_unfold(to_unfold) {} branch(choice_lst const * path, ite_lst const * to_split, unfold_lst const * to_unfold) : path(path), to_split(to_split), to_unfold(to_unfold) {} branch(branch const & from) : @@ -110,14 +118,12 @@ namespace recfun { // state for computing cases from the RHS of a functions' definition class case_state { region m_reg; - ast_manager & m_manager; vector m_branches; public: - case_state(ast_manager & m) : m_reg(), m_manager(m), m_branches() {} + case_state() : m_reg(), m_branches() {} bool empty() const { return m_branches.empty(); } - ast_manager & m() const { return m_manager; } region & reg() { return m_reg; } branch pop_branch() { @@ -128,7 +134,6 @@ namespace recfun { void push_branch(branch const & b) { m_branches.push_back(b); } - unfold_lst const * cons_unfold(expr * e, unfold_lst const * next) { return new (reg()) unfold_lst{e, next}; } @@ -149,7 +154,7 @@ namespace recfun { }; // Date: Sun, 21 Oct 2018 18:25:27 -0700 Subject: [PATCH 091/227] recfun Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 1 + src/ast/recfun_decl_plugin.cpp | 60 ++++++++++++++-------------- src/ast/recfun_decl_plugin.h | 31 ++++++-------- src/smt/params/smt_params_helper.pyg | 2 +- src/smt/smt_context.h | 5 ++- src/smt/theory_recfun.cpp | 44 +++++++++++--------- src/smt/theory_recfun.h | 5 +-- 7 files changed, 75 insertions(+), 73 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index d466d2e77..63b5a9e72 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1,4 +1,5 @@ + ############################################ # Copyright (c) 2012 Microsoft Corporation # diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 6ee0ddc39..e5796b119 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -15,6 +15,7 @@ Revision History: --*/ + #include #include #include "ast/expr_functors.h" @@ -29,14 +30,15 @@ Revision History: namespace recfun { - case_def::case_def(ast_manager &m, - family_id fid, - def * d, - std::string & name, - unsigned case_index, - sort_ref_vector const & arg_sorts, - expr_ref_vector const& guards, - expr* rhs) + case_def::case_def( + ast_manager &m, + family_id fid, + def * d, + std::string & name, + unsigned case_index, + sort_ref_vector const & arg_sorts, + expr_ref_vector const& guards, + expr* rhs) : m_pred(m), m_guards(guards), m_rhs(expr_ref(rhs,m)), @@ -52,11 +54,9 @@ namespace recfun { m_domain(m, arity, domain), m_range(range, m), m_vars(m), m_cases(), m_decl(m), - m_fid(fid), - m_macro(false) + m_fid(fid) { - SASSERT(arity == get_arity()); - + SASSERT(arity == get_arity()); func_decl_info info(fid, OP_FUN_DEFINED); m_decl = m.mk_func_decl(s, arity, domain, range, info); } @@ -124,7 +124,6 @@ namespace recfun { case_state() : m_reg(), m_branches() {} bool empty() const { return m_branches.empty(); } - region & reg() { return m_reg; } branch pop_branch() { branch res = m_branches.back(); @@ -135,7 +134,7 @@ namespace recfun { void push_branch(branch const & b) { m_branches.push_back(b); } unfold_lst const * cons_unfold(expr * e, unfold_lst const * next) { - return new (reg()) unfold_lst{e, next}; + return new (m_reg) unfold_lst{e, next}; } unfold_lst const * cons_unfold(expr * e1, expr * e2, unfold_lst const * next) { return cons_unfold(e1, cons_unfold(e2, next)); @@ -145,11 +144,11 @@ namespace recfun { } ite_lst const * cons_ite(app * ite, ite_lst const * next) { - return new (reg()) ite_lst{ite, next}; + return new (m_reg) ite_lst{ite, next}; } choice_lst const * cons_choice(app * ite, bool sign, choice_lst const * next) { - return new (reg()) choice_lst{ite, sign, next}; + return new (m_reg) choice_lst{ite, sign, next}; } }; @@ -203,21 +202,17 @@ namespace recfun { unsigned case_idx = 0; - std::string name; - name.append("case_"); + std::string name("case-"); name.append(m_name.bare_str()); - name.append("_"); m_vars.append(n_vars, vars); - // is the function a macro (unconditional body)? - m_macro = n_vars == 0 || !contains_ite(rhs); expr_ref_vector conditions(m); - if (m_macro) { + // is the function a macro (unconditional body)? + if (n_vars == 0 || !contains_ite(rhs)) { // constant function or trivial control flow, only one (dummy) case - name.append("dummy"); add_case(name, 0, conditions, rhs); return; } @@ -311,15 +306,15 @@ namespace recfun { */ util::util(ast_manager & m, family_id id) - : m_manager(m), m_family_id(id), m_th_rw(m), m_plugin(0) { - m_plugin = dynamic_cast(m.get_plugin(m_family_id)); + : m_manager(m), m_fid(id), m_th_rw(m), + m_plugin(dynamic_cast(m.get_plugin(m_fid))) { } util::~util() { } def * util::decl_fun(symbol const& name, unsigned n, sort *const * domain, sort * range) { - return alloc(def, m(), m_family_id, name, n, domain, range); + return alloc(def, m(), m_fid, name, n, domain, range); } void util::set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) { @@ -328,7 +323,7 @@ namespace recfun { app_ref util::mk_depth_limit_pred(unsigned d) { parameter p(d); - func_decl_info info(m_family_id, OP_DEPTH_LIMIT, 1, &p); + func_decl_info info(m_fid, OP_DEPTH_LIMIT, 1, &p); func_decl* decl = m().mk_const_decl(symbol("recfun-depth-limit"), m().mk_bool_sort(), info); return app_ref(m().mk_const(decl), m()); } @@ -376,13 +371,13 @@ namespace recfun { m_defs.reset(); // m_case_defs does not own its data, no need to deallocate m_case_defs.reset(); - m_util = 0; // force deletion + m_util = nullptr; // force deletion } util & plugin::u() const { SASSERT(m_manager); SASSERT(m_family_id != null_family_id); - if (m_util.get() == 0) { + if (!m_util.get()) { m_util = alloc(util, *m_manager, m_family_id); } return *(m_util.get()); @@ -398,7 +393,7 @@ namespace recfun { void plugin::set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) { u().set_definition(d, n_vars, vars, rhs); for (case_def & c : d.get_def()->get_cases()) { - m_case_defs.insert(c.get_name(), &c); + m_case_defs.insert(c.get_decl(), &c); } } @@ -434,7 +429,10 @@ namespace recfun { func_decl * plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { - switch(k) { + UNREACHABLE(); + // TBD: parameter usage seems inconsistent with other uses. + IF_VERBOSE(0, verbose_stream() << "mk-func-decl " << k << "\n"); + switch (k) { case OP_FUN_CASE_PRED: return mk_fun_pred_decl(num_parameters, parameters, arity, domain, range); case OP_FUN_DEFINED: diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index 2bfae9e4e..1e6f873e2 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -19,6 +19,7 @@ Revision History: #include "ast/ast.h" #include "ast/rewriter/th_rewriter.h" +#include "util/obj_hashtable.h" namespace recfun { class case_def; //get_name(); } + func_decl* get_decl() const { return m_pred; } app_ref apply_case_predicate(ptr_vector const & args) const { ast_manager& m = m_pred.get_manager(); @@ -97,7 +98,6 @@ namespace recfun { cases m_cases; //!< possible cases func_decl_ref m_decl; //!< generic declaration family_id m_fid; - bool m_macro; def(ast_manager &m, family_id fid, symbol const & s, unsigned arity, sort *const * domain, sort* range); @@ -115,11 +115,10 @@ namespace recfun { sort_ref const & get_range() const { return m_range; } func_decl * get_decl() const { return m_decl.get(); } - bool is_fun_macro() const { return m_macro; } + bool is_fun_macro() const { return m_cases.size() == 1; } bool is_fun_defined() const { return !is_fun_macro(); } expr * get_macro_rhs() const { - SASSERT(is_fun_macro()); return m_cases[0].get_rhs(); } }; @@ -140,7 +139,7 @@ namespace recfun { class plugin : public decl_plugin { typedef map def_map; - typedef map case_def_map; + typedef obj_map case_def_map; mutable scoped_ptr m_util; def_map m_defs; // function->def @@ -175,8 +174,8 @@ namespace recfun { def const& get_def(const symbol& s) const { return *(m_defs[s]); } promise_def get_promise_def(const symbol &s) const { return promise_def(&u(), m_defs[s]); } def& get_def(symbol const& s) { return *(m_defs[s]); } - bool has_case_def(const symbol& s) const { return m_case_defs.contains(s); } - case_def& get_case_def(symbol const& s) { SASSERT(has_case_def(s)); return *(m_case_defs[s]); } + bool has_case_def(func_decl* f) const { return m_case_defs.contains(f); } + case_def& get_case_def(func_decl* f) { SASSERT(has_case_def(f)); return *(m_case_defs[f]); } bool is_declared(symbol const& s) const { return m_defs.contains(s); } private: func_decl * mk_fun_pred_decl(unsigned num_parameters, parameter const * parameters, @@ -192,7 +191,7 @@ namespace recfun { friend class decl::plugin; ast_manager & m_manager; - family_id m_family_id; + family_id m_fid; th_rewriter m_th_rw; decl::plugin * m_plugin; @@ -205,10 +204,10 @@ namespace recfun { ast_manager & m() { return m_manager; } th_rewriter & get_th_rewriter() { return m_th_rw; } - bool is_case_pred(expr * e) const { return is_app_of(e, m_family_id, OP_FUN_CASE_PRED); } - bool is_defined(expr * e) const { return is_app_of(e, m_family_id, OP_FUN_DEFINED); } - bool is_depth_limit(expr * e) const { return is_app_of(e, m_family_id, OP_DEPTH_LIMIT); } - bool owns_app(app * e) const { return e->get_family_id() == m_family_id; } + bool is_case_pred(expr * e) const { return is_app_of(e, m_fid, OP_FUN_CASE_PRED); } + bool is_defined(expr * e) const { return is_app_of(e, m_fid, OP_FUN_DEFINED); } + bool is_depth_limit(expr * e) const { return is_app_of(e, m_fid, OP_DEPTH_LIMIT); } + bool owns_app(app * e) const { return e->get_family_id() == m_fid; } bool has_def() const { return m_plugin->has_def(); } @@ -222,17 +221,13 @@ namespace recfun { case_def& get_case_def(expr* e) { SASSERT(is_case_pred(e)); - return get_case_def(to_app(e)->get_name()); - } - - case_def& get_case_def(symbol const & s) { - SASSERT(m_plugin->has_case_def(s)); - return m_plugin->get_case_def(s); + return m_plugin->get_case_def(to_app(e)->get_decl()); } app* mk_fun_defined(def const & d, unsigned n_args, expr * const * args) { return m().mk_app(d.get_decl(), n_args, args); } + app* mk_fun_defined(def const & d, ptr_vector const & args) { return mk_fun_defined(d, args.size(), args.c_ptr()); } diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 52e8f664c..37ed061b4 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -97,5 +97,5 @@ def_module_params(module_name='smt', ('lemma_gc_strategy', UINT, 0, 'lemma garbage collection strategy: 0 - fixed, 1 - geometric, 2 - at restart, 3 - none'), ('dt_lazy_splits', UINT, 1, 'How lazy datatype splits are performed: 0- eager, 1- lazy for infinite types, 2- lazy'), ('recfun.native', BOOL, False, 'use native rec-fun solver'), - ('recfun.max_depth', UINT, 50, 'maximum depth of unrolling for recursive functions') + ('recfun.max_depth', UINT, 2, 'maximum depth of unrolling for recursive functions') )) diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 45341d368..f628b6e95 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1639,13 +1639,14 @@ namespace smt { }; inline std::ostream & operator<<(std::ostream & out, pp_lits const & pp) { - out << "clause{"; + out << "{"; bool first = true; for (unsigned i = 0; i < pp.len; ++i) { - if (first) { first = false; } else { out << " ∨ "; } + if (first) { first = false; } else { out << " or\n"; } pp.ctx.display_detailed_literal(out, pp.lits[i]); } return out << "}"; + } }; diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 0a91074ec..79060c631 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -33,7 +33,7 @@ namespace smt { m_plugin(*reinterpret_cast(m.get_plugin(get_family_id()))), m_util(m_plugin.u()), m_guard_preds(m), - m_max_depth(0), + m_max_depth(UINT_MAX), m_q_case_expand(), m_q_body_expand() { @@ -45,10 +45,12 @@ namespace smt { char const * theory_recfun::get_name() const { return "recfun"; } - void theory_recfun::init_search_eh() { - // obtain max depth via parameters - smt_params_helper p(ctx().get_params()); - set_max_depth(p.recfun_max_depth()); + unsigned theory_recfun::get_max_depth() { + if (m_max_depth == UINT_MAX) { + smt_params_helper p(ctx().get_params()); + set_max_depth(p.recfun_max_depth()); + } + return m_max_depth; } theory* theory_recfun::mk_fresh(context* new_ctx) { @@ -121,7 +123,7 @@ namespace smt { unsigned new_lim = m_guard_preds_lim.size()-num_scopes; unsigned start = m_guard_preds_lim[new_lim]; for (unsigned i = start; i < m_guard_preds.size(); ++i) { - m_guards[m_guard_preds.get(i)->get_decl()].pop_back(); + m_guards[m_guard_preds.get(i)].pop_back(); } m_guard_preds.resize(start); m_guard_preds_lim.shrink(new_lim); @@ -177,7 +179,6 @@ namespace smt { c.push_back(~mk_literal(dlimit)); enable_trace("recfun"); TRACE("recfun", ctx().display(tout << c.back() << " " << dlimit << "\n");); - SASSERT(ctx().get_assignment(c.back()) == l_false); for (expr * g : guards) { c.push_back(mk_literal(g)); @@ -194,17 +195,17 @@ namespace smt { expr* e = ctx().bool_var2expr(v); if (is_true && u().is_case_pred(e)) { TRACEFN("assign_case_pred_true " << mk_pp(e, m)); - app* a = to_app(e); // body-expand - body_expansion b_e(u(), a); + body_expansion b_e(u(), to_app(e)); push_body_expand(std::move(b_e)); } } // replace `vars` by `args` in `e` - expr_ref theory_recfun::apply_args(recfun::vars const & vars, - ptr_vector const & args, - expr * e) { + expr_ref theory_recfun::apply_args( + recfun::vars const & vars, + ptr_vector const & args, + expr * e) { SASSERT(is_standard_order(vars)); var_subst subst(m, true); expr_ref new_body(m); @@ -245,14 +246,14 @@ namespace smt { * 2. add unit clause `f(args) = rhs` */ void theory_recfun::assert_macro_axiom(case_expansion & e) { - TRACEFN("case expansion " << pp_case_expansion(e, m) << "\n"); + TRACEFN("case expansion " << pp_case_expansion(e, m) << "\n"); SASSERT(e.m_def->is_fun_macro()); auto & vars = e.m_def->get_vars(); expr_ref lhs(e.m_lhs, m); expr_ref rhs(apply_args(vars, e.m_args, e.m_def->get_macro_rhs()), m); literal lit = mk_eq_lit(lhs, rhs); ctx().mk_th_axiom(get_id(), 1, &lit); - TRACEFN("macro expansion yields " << mk_pp(rhs,m) << "\n" << + TRACEFN("macro expansion yields " << mk_pp(rhs, m) << "\n" << "literal " << pp_lit(ctx(), lit)); } @@ -291,9 +292,10 @@ namespace smt { assert_body_axiom(be); // add to set of local assumptions, for depth-limit purpose - func_decl* d = pred_applied->get_decl(); + + // func_decl* d = pred_applied->get_decl(); m_guard_preds.push_back(pred_applied); - auto& vec = m_guards.insert_if_not_there2(d, ptr_vector())->get_data().m_value; + auto& vec = m_guards.insert_if_not_there2(e.m_lhs, ptr_vector())->get_data().m_value; vec.push_back(pred_applied); if (vec.size() == get_max_depth()) { max_depth_limit(vec); @@ -322,11 +324,17 @@ namespace smt { for (auto & g : e.m_cdef->get_guards()) { expr_ref guard = apply_args(vars, args, g); clause.push_back(~mk_literal(guard)); + if (clause.back() == true_literal) { + return; + } + if (clause.back() == false_literal) { + clause.pop_back(); + } } clause.push_back(mk_eq_lit(lhs, rhs)); ctx().mk_th_axiom(get_id(), clause); TRACEFN("body " << pp_body_expansion(e,m)); - TRACEFN("clause " << pp_lits(ctx(), clause)); + TRACEFN(pp_lits(ctx(), clause)); } final_check_status theory_recfun::final_check_eh() { @@ -373,7 +381,7 @@ namespace smt { } std::ostream& operator<<(std::ostream & out, theory_recfun::pp_body_expansion const & e) { - out << "body_exp(" << e.e.m_cdef->get_name(); + out << "body_exp(" << e.e.m_cdef->get_decl()->get_name(); for (auto* t : e.e.m_args) { out << " " << mk_pp(t,e.m); } diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index f4783dcdc..68e2609d7 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -90,7 +90,7 @@ namespace smt { recfun_decl_plugin& m_plugin; recfun_util& m_util; stats m_stats; - obj_map > m_guards; + obj_map > m_guards; app_ref_vector m_guard_preds; unsigned_vector m_guard_preds_lim; unsigned m_max_depth; // for fairness and termination @@ -138,12 +138,11 @@ namespace smt { void add_theory_assumptions(expr_ref_vector & assumptions) override; void set_max_depth(unsigned n) { SASSERT(n>0); m_max_depth = n; } - unsigned get_max_depth() const { return m_max_depth; } + unsigned get_max_depth(); public: theory_recfun(ast_manager & m); ~theory_recfun() override; - void init_search_eh() override; theory * mk_fresh(context * new_ctx) override; void display(std::ostream & out) const override; void collect_statistics(::statistics & st) const override; From cd9c752834b36c033324600bdd094e62b4cda849 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 21 Oct 2018 20:46:12 -0700 Subject: [PATCH 092/227] guard Signed-off-by: Nikolaj Bjorner --- src/smt/theory_recfun.cpp | 95 +++++++++++++++++++++++++-------------- src/smt/theory_recfun.h | 48 ++++++++++++-------- 2 files changed, 91 insertions(+), 52 deletions(-) diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 79060c631..bd6f7c3fa 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -19,6 +19,7 @@ Revision History: #include "util/stats.h" #include "ast/ast_util.h" +#include "ast/for_each_expr.h" #include "smt/theory_recfun.h" #include "smt/params/smt_params_helper.hpp" @@ -32,7 +33,7 @@ namespace smt { m(m), m_plugin(*reinterpret_cast(m.get_plugin(get_family_id()))), m_util(m_plugin.u()), - m_guard_preds(m), + m_preds(m), m_max_depth(UINT_MAX), m_q_case_expand(), m_q_body_expand() @@ -111,7 +112,7 @@ namespace smt { void theory_recfun::push_scope_eh() { TRACEFN("push_scope"); theory::push_scope_eh(); - m_guard_preds_lim.push_back(m_guard_preds.size()); + m_preds_lim.push_back(m_preds.size()); } void theory_recfun::pop_scope_eh(unsigned num_scopes) { @@ -119,14 +120,14 @@ namespace smt { theory::pop_scope_eh(num_scopes); reset_queues(); - // restore guards - unsigned new_lim = m_guard_preds_lim.size()-num_scopes; - unsigned start = m_guard_preds_lim[new_lim]; - for (unsigned i = start; i < m_guard_preds.size(); ++i) { - m_guards[m_guard_preds.get(i)].pop_back(); + // restore depth book-keeping + unsigned new_lim = m_preds_lim.size()-num_scopes; + unsigned start = m_preds_lim[new_lim]; + for (unsigned i = start; i < m_preds.size(); ++i) { + m_pred_depth.remove(m_preds.get(i)); } - m_guard_preds.resize(start); - m_guard_preds_lim.shrink(new_lim); + m_preds.resize(start); + m_preds_lim.shrink(new_lim); } void theory_recfun::restart_eh() { @@ -169,24 +170,49 @@ namespace smt { m_q_body_expand.clear(); } - void theory_recfun::max_depth_limit(ptr_vector const& guards) { + /** + * make clause `depth_limit => ~guard` + * the guard appears at a depth below the current cutoff. + */ + void theory_recfun::assert_max_depth_limit(expr* guard) { TRACEFN("max-depth limit"); literal_vector c; - // make clause `depth_limit => V_{g : guards of non-recursive cases} g` - - // first literal must be the depth limit one app_ref dlimit = m_util.mk_depth_limit_pred(get_max_depth()); c.push_back(~mk_literal(dlimit)); - enable_trace("recfun"); - TRACE("recfun", ctx().display(tout << c.back() << " " << dlimit << "\n");); - - for (expr * g : guards) { - c.push_back(mk_literal(g)); - } + c.push_back(~mk_literal(guard)); TRACEFN("max-depth limit: add clause " << pp_lits(ctx(), c)); m_q_clauses.push_back(std::move(c)); } + /** + * retrieve depth associated with predicate or expression. + */ + unsigned theory_recfun::get_depth(expr* e) { + unsigned d = 0; + m_pred_depth.find(e, d); + return d; + } + + /** + * Update depth of subterms of e with respect to d. + */ + void theory_recfun::set_depth(unsigned d, expr* e) { + struct insert_c { + theory_recfun& th; + unsigned m_depth; + insert_c(theory_recfun& th, unsigned d): th(th), m_depth(d) {} + void operator()(app* e) { + if ((th.u().is_defined(e) || th.u().is_case_pred(e)) && !th.m_pred_depth.contains(e)) { + th.m_pred_depth.insert(e, m_depth); + } + } + void operator()(quantifier*) {} + void operator()(var*) {} + }; + insert_c proc(*this, d); + for_each_expr(proc, e); + } + /** * if `is_true` and `v = C_f_i(t1...tn)`, * then body-expand i-th case of `f(t1...tn)` @@ -203,6 +229,7 @@ namespace smt { // replace `vars` by `args` in `e` expr_ref theory_recfun::apply_args( + unsigned depth, recfun::vars const & vars, ptr_vector const & args, expr * e) { @@ -250,7 +277,8 @@ namespace smt { SASSERT(e.m_def->is_fun_macro()); auto & vars = e.m_def->get_vars(); expr_ref lhs(e.m_lhs, m); - expr_ref rhs(apply_args(vars, e.m_args, e.m_def->get_macro_rhs()), m); + unsigned depth = get_depth(e.m_lhs); + expr_ref rhs(apply_args(depth, vars, e.m_args, e.m_def->get_macro_rhs()), m); literal lit = mk_eq_lit(lhs, rhs); ctx().mk_th_axiom(get_id(), 1, &lit); TRACEFN("macro expansion yields " << mk_pp(rhs, m) << "\n" << @@ -273,13 +301,21 @@ namespace smt { for (recfun::case_def const & c : e.m_def->get_cases()) { // applied predicate to `args` app_ref pred_applied = c.apply_case_predicate(e.m_args); + + // cut off cases below max-depth + unsigned depth = get_depth(pred_applied); + if (depth >= get_max_depth()) { + assert_max_depth_limit(pred_applied); + continue; + } + SASSERT(u().owns_app(pred_applied)); literal concl = mk_literal(pred_applied); literal_vector guards; guards.push_back(concl); for (auto & g : c.get_guards()) { - expr_ref ga = apply_args(vars, e.m_args, g); + expr_ref ga = apply_args(depth, vars, e.m_args, g); literal guard = mk_literal(ga); guards.push_back(~guard); literal c[2] = {~concl, guard}; @@ -288,18 +324,8 @@ namespace smt { ctx().mk_th_axiom(get_id(), guards); if (c.is_immediate()) { - body_expansion be(c, e.m_args); + body_expansion be(e.m_lhs, c, e.m_args); assert_body_axiom(be); - - // add to set of local assumptions, for depth-limit purpose - - // func_decl* d = pred_applied->get_decl(); - m_guard_preds.push_back(pred_applied); - auto& vec = m_guards.insert_if_not_there2(e.m_lhs, ptr_vector())->get_data().m_value; - vec.push_back(pred_applied); - if (vec.size() == get_max_depth()) { - max_depth_limit(vec); - } } } } @@ -317,12 +343,13 @@ namespace smt { auto & vars = d.get_vars(); auto & args = e.m_args; SASSERT(is_standard_order(vars)); + unsigned depth = get_depth(e.m_lhs); expr_ref lhs(u().mk_fun_defined(d, args), m); - expr_ref rhs = apply_args(vars, args, e.m_cdef->get_rhs()); + expr_ref rhs = apply_args(depth, vars, args, e.m_cdef->get_rhs()); literal_vector clause; for (auto & g : e.m_cdef->get_guards()) { - expr_ref guard = apply_args(vars, args, g); + expr_ref guard = apply_args(depth, vars, args, g); clause.push_back(~mk_literal(guard)); if (clause.back() == true_literal) { return; diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 68e2609d7..240e595c3 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -35,11 +35,11 @@ namespace smt { // one case-expansion of `f(t1...tn)` struct case_expansion { - expr * m_lhs; // the term to expand + app * m_lhs; // the term to expand recfun_def * m_def; ptr_vector m_args; - case_expansion(recfun_util& u, app * n) : m_lhs(n), m_def(0), m_args() - { + case_expansion(recfun_util& u, app * n) : + m_lhs(n), m_def(nullptr), m_args() { SASSERT(u.is_defined(n)); func_decl * d = n->get_decl(); const symbol& name = d->get_name(); @@ -66,16 +66,20 @@ namespace smt { // one body-expansion of `f(t1...tn)` using a `C_f_i(t1...tn)` struct body_expansion { + app* m_lhs; recfun_case_def const * m_cdef; ptr_vector m_args; - body_expansion(recfun_util& u, app * n) : m_cdef(0), m_args() { + body_expansion(recfun_util& u, app * n) : m_lhs(n), m_cdef(0), m_args() { m_cdef = &u.get_case_def(n); m_args.append(n->get_num_args(), n->get_args()); } - body_expansion(recfun_case_def const & d, ptr_vector & args) : m_cdef(&d), m_args(args) {} - body_expansion(body_expansion const & from): m_cdef(from.m_cdef), m_args(from.m_args) {} - body_expansion(body_expansion && from) : m_cdef(from.m_cdef), m_args(std::move(from.m_args)) {} + body_expansion(app* lhs, recfun_case_def const & d, ptr_vector & args) : + m_lhs(lhs), m_cdef(&d), m_args(args) {} + body_expansion(body_expansion const & from): + m_lhs(from.m_lhs), m_cdef(from.m_cdef), m_args(from.m_args) {} + body_expansion(body_expansion && from) : + m_lhs(from.m_lhs), m_cdef(from.m_cdef), m_args(std::move(from.m_args)) {} }; struct pp_body_expansion { @@ -86,14 +90,16 @@ namespace smt { friend std::ostream& operator<<(std::ostream&, pp_body_expansion const &); - ast_manager& m; - recfun_decl_plugin& m_plugin; - recfun_util& m_util; - stats m_stats; - obj_map > m_guards; - app_ref_vector m_guard_preds; - unsigned_vector m_guard_preds_lim; - unsigned m_max_depth; // for fairness and termination + ast_manager& m; + recfun_decl_plugin& m_plugin; + recfun_util& m_util; + stats m_stats; + + // book-keeping for depth of predicates + obj_map m_pred_depth; + expr_ref_vector m_preds; + unsigned_vector m_preds_lim; + unsigned m_max_depth; // for fairness and termination vector m_q_case_expand; vector m_q_body_expand; @@ -107,14 +113,20 @@ namespace smt { bool is_case_pred(enode * e) const { return is_case_pred(e->get_owner()); } void reset_queues(); - expr_ref apply_args(recfun::vars const & vars, ptr_vector const & args, expr * e); //!< substitute variables by args + expr_ref apply_args(unsigned depth, recfun::vars const & vars, ptr_vector const & args, expr * e); //!< substitute variables by args void assert_macro_axiom(case_expansion & e); void assert_case_axioms(case_expansion & e); void assert_body_axiom(body_expansion & e); literal mk_literal(expr* e); - void max_depth_limit(ptr_vector const& guards); + + void assert_max_depth_limit(expr* guard); + unsigned get_depth(expr* e); + void set_depth(unsigned d, expr* e); + literal mk_eq_lit(expr* l, expr* r); - bool is_standard_order(recfun::vars const& vars) const { return vars.size() == 0 || vars[vars.size()-1]->get_idx() == 0; } + bool is_standard_order(recfun::vars const& vars) const { + return vars.size() == 0 || vars[vars.size()-1]->get_idx() == 0; + } protected: void push_case_expand(case_expansion&& e) { m_q_case_expand.push_back(e); } void push_body_expand(body_expansion&& e) { m_q_body_expand.push_back(e); } From 66f2a7636bce13b42a2073b2fc344ac34c4c6872 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Oct 2018 04:59:51 -0700 Subject: [PATCH 093/227] depth Signed-off-by: Nikolaj Bjorner --- src/smt/params/smt_params_helper.pyg | 3 +-- src/smt/theory_recfun.cpp | 26 ++++++++++---------------- src/smt/theory_recfun.h | 4 +--- 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 37ed061b4..1c96826d6 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -96,6 +96,5 @@ def_module_params(module_name='smt', ('core.extend_nonlocal_patterns', BOOL, False, 'extend unsat cores with literals that have quantifiers with patterns that contain symbols which are not in the quantifier\'s body'), ('lemma_gc_strategy', UINT, 0, 'lemma garbage collection strategy: 0 - fixed, 1 - geometric, 2 - at restart, 3 - none'), ('dt_lazy_splits', UINT, 1, 'How lazy datatype splits are performed: 0- eager, 1- lazy for infinite types, 2- lazy'), - ('recfun.native', BOOL, False, 'use native rec-fun solver'), - ('recfun.max_depth', UINT, 2, 'maximum depth of unrolling for recursive functions') + ('recfun.native', BOOL, False, 'use native rec-fun solver') )) diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index bd6f7c3fa..e642dfd85 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -34,7 +34,7 @@ namespace smt { m_plugin(*reinterpret_cast(m.get_plugin(get_family_id()))), m_util(m_plugin.u()), m_preds(m), - m_max_depth(UINT_MAX), + m_max_depth(2), m_q_case_expand(), m_q_body_expand() { @@ -46,14 +46,6 @@ namespace smt { char const * theory_recfun::get_name() const { return "recfun"; } - unsigned theory_recfun::get_max_depth() { - if (m_max_depth == UINT_MAX) { - smt_params_helper p(ctx().get_params()); - set_max_depth(p.recfun_max_depth()); - } - return m_max_depth; - } - theory* theory_recfun::mk_fresh(context* new_ctx) { return alloc(theory_recfun, new_ctx->get_manager()); } @@ -177,7 +169,7 @@ namespace smt { void theory_recfun::assert_max_depth_limit(expr* guard) { TRACEFN("max-depth limit"); literal_vector c; - app_ref dlimit = m_util.mk_depth_limit_pred(get_max_depth()); + app_ref dlimit = m_util.mk_depth_limit_pred(m_max_depth); c.push_back(~mk_literal(dlimit)); c.push_back(~mk_literal(guard)); TRACEFN("max-depth limit: add clause " << pp_lits(ctx(), c)); @@ -202,8 +194,10 @@ namespace smt { unsigned m_depth; insert_c(theory_recfun& th, unsigned d): th(th), m_depth(d) {} void operator()(app* e) { - if ((th.u().is_defined(e) || th.u().is_case_pred(e)) && !th.m_pred_depth.contains(e)) { + if (th.u().is_defined(e) && !th.m_pred_depth.contains(e)) { th.m_pred_depth.insert(e, m_depth); + th.m_preds.push_back(e); + TRACEFN("depth " << m_depth << " : " << mk_pp(e, th.m)); } } void operator()(quantifier*) {} @@ -238,6 +232,7 @@ namespace smt { expr_ref new_body(m); new_body = subst(e, args.size(), args.c_ptr()); ctx().get_rewriter()(new_body); // simplify + set_depth(depth + 1, new_body); return new_body; } @@ -303,8 +298,8 @@ namespace smt { app_ref pred_applied = c.apply_case_predicate(e.m_args); // cut off cases below max-depth - unsigned depth = get_depth(pred_applied); - if (depth >= get_max_depth()) { + unsigned depth = get_depth(e.m_lhs); + if (depth >= m_max_depth) { assert_max_depth_limit(pred_applied); continue; } @@ -375,7 +370,7 @@ namespace smt { void theory_recfun::add_theory_assumptions(expr_ref_vector & assumptions) { if (u().has_def()) { - app_ref dlimit = m_util.mk_depth_limit_pred(get_max_depth()); + app_ref dlimit = m_util.mk_depth_limit_pred(m_max_depth); TRACEFN("add_theory_assumption " << mk_pp(dlimit.get(), m)); assumptions.push_back(dlimit); } @@ -385,8 +380,7 @@ namespace smt { bool theory_recfun::should_research(expr_ref_vector & unsat_core) { for (auto & e : unsat_core) { if (u().is_depth_limit(e)) { - unsigned new_depth = (3 * (1 + get_max_depth())) / 2; - set_max_depth(new_depth); + m_max_depth = (3 * m_max_depth) / 2; return true; } } diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 240e595c3..af12853a1 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -149,13 +149,11 @@ namespace smt { void new_diseq_eh(theory_var v1, theory_var v2) override {} void add_theory_assumptions(expr_ref_vector & assumptions) override; - void set_max_depth(unsigned n) { SASSERT(n>0); m_max_depth = n; } - unsigned get_max_depth(); - public: theory_recfun(ast_manager & m); ~theory_recfun() override; theory * mk_fresh(context * new_ctx) override; + void init_search_eh() override { m_max_depth = 2; } void display(std::ostream & out) const override; void collect_statistics(::statistics & st) const override; }; From 5c80b142c5b36a72722108fa241b4b251237fa63 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Oct 2018 07:22:58 -0700 Subject: [PATCH 094/227] fix build Signed-off-by: Nikolaj Bjorner --- src/smt/params/smt_params.cpp | 1 - src/smt/params/smt_params.h | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp index 3f800455b..650afda25 100644 --- a/src/smt/params/smt_params.cpp +++ b/src/smt/params/smt_params.cpp @@ -27,7 +27,6 @@ void smt_params::updt_local_params(params_ref const & _p) { m_random_seed = p.random_seed(); m_relevancy_lvl = p.relevancy(); m_ematching = p.ematching(); - m_recfun_max_depth = p.recfun_max_depth(); m_phase_selection = static_cast(p.phase_selection()); m_restart_strategy = static_cast(p.restart_strategy()); m_restart_factor = p.restart_factor(); diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index a5923089c..8901697b7 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -108,9 +108,6 @@ struct smt_params : public preprocessor_params, bool m_new_core2th_eq; bool m_ematching; - // TODO: move into its own file? - unsigned m_recfun_max_depth; - // ----------------------------------- // // Case split strategy @@ -264,7 +261,6 @@ struct smt_params : public preprocessor_params, m_display_features(false), m_new_core2th_eq(true), m_ematching(true), - m_recfun_max_depth(50), m_case_split_strategy(CS_ACTIVITY_DELAY_NEW), m_rel_case_split_order(0), m_lookahead_diseq(false), From 81a92edb61e6438961ddaa998592c25381175d08 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Oct 2018 10:59:51 -0700 Subject: [PATCH 095/227] prepare to retool Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 1 + scripts/mk_util.py | 220 ++++++++++++++++++++++++++++- src/api/dotnet/Microsoft.Z3.csproj | 1 - src/api/dotnet/core/project.json | 22 --- 4 files changed, 220 insertions(+), 24 deletions(-) delete mode 100644 src/api/dotnet/core/project.json diff --git a/scripts/mk_project.py b/scripts/mk_project.py index d94089a9c..174b498e7 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -84,6 +84,7 @@ def init_project_def(): export_files=API_files, staging_link='python') add_dot_net_dll('dotnet', ['api_dll'], 'api/dotnet', dll_name='Microsoft.Z3', assembly_info_dir='Properties', default_key_file='src/api/dotnet/Microsoft.Z3.snk') + add_dot_net_core_dll('dotnet', ['api_dll'], 'api/dotnet', dll_name='Microsoft.Z3', assembly_info_dir='Properties', default_key_file='src/api/dotnet/Microsoft.Z3.snk') add_java_dll('java', ['api_dll'], 'api/java', dll_name='libz3java', package_name="com.microsoft.z3", manifest_file='manifest') add_ml_lib('ml', ['api_dll'], 'api/ml', lib_name='libz3ml') add_hlib('cpp', 'api/c++', includes2install=['z3++.h']) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 97e2b65f2..e5173931d 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -37,6 +37,7 @@ OCAMLOPT=getenv("OCAMLOPT", "ocamlopt") OCAML_LIB=getenv("OCAML_LIB", None) OCAMLFIND=getenv("OCAMLFIND", "ocamlfind") CSC=getenv("CSC", None) +DOTNET="dotnet" GACUTIL=getenv("GACUTIL", 'gacutil') # Standard install directories relative to PREFIX INSTALL_BIN_DIR=getenv("Z3_INSTALL_BIN_DIR", "bin") @@ -87,6 +88,7 @@ VS_PROJ = False TRACE = False PYTHON_ENABLED=False DOTNET_ENABLED=False +DOTNET_CORE_ENABLED=False DOTNET_KEY_FILE=getenv("Z3_DOTNET_KEY_FILE", None) JAVA_ENABLED=False ML_ENABLED=False @@ -690,7 +692,7 @@ def display_help(exit_code): # Parse configuration option for mk_make script def parse_options(): global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM - global DOTNET_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, JS_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED + global DOTNET_ENABLED, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, JS_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED global LINUX_X64, SLOW_OPTIMIZE, USE_OMP, LOG_SYNC global GUARD_CF, ALWAYS_DYNAMIC_BASE try: @@ -731,6 +733,9 @@ def parse_options(): TRACE = True elif opt in ('-.net', '--dotnet'): DOTNET_ENABLED = True + elif opt in ('--dotnetcore'): + DOTNET_ENABLED = True + DOTNET_CORE_ENABLED = True elif opt in ('--dotnet-key'): DOTNET_KEY_FILE = arg elif opt in ('--staticlib'): @@ -887,6 +892,9 @@ def is_js_enabled(): def is_dotnet_enabled(): return DOTNET_ENABLED +def is_dotnet_core_enabled(): + return DOTNET_CORE_ENABLED + def is_python_enabled(): return PYTHON_ENABLED @@ -1811,6 +1819,212 @@ class DotNetDLLComponent(Component): pkg_config_file = os.path.join('lib','pkgconfig','{}.pc'.format(self.gac_pkg_name())) MakeRuleCmd.remove_installed_files(out, pkg_config_file) + +# TBD: retool the following for 'dotnet build' +class DotNetCoreDLLComponent(Component): + def __init__(self, name, dll_name, path, deps, assembly_info_dir, default_key_file): + Component.__init__(self, name, path, deps) + if dll_name is None: + dll_name = name + if assembly_info_dir is None: + assembly_info_dir = "." + self.dll_name = dll_name + self.assembly_info_dir = assembly_info_dir + self.key_file = default_key_file + + def mk_pkg_config_file(self): + """ + Create pkgconfig file for the dot net bindings. These + are needed by Monodevelop. + """ + pkg_config_template = os.path.join(self.src_dir, '{}.pc.in'.format(self.gac_pkg_name())) + substitutions = { 'PREFIX': PREFIX, + 'GAC_PKG_NAME': self.gac_pkg_name(), + 'VERSION': "{}.{}.{}.{}".format( + VER_MAJOR, + VER_MINOR, + VER_BUILD, + VER_REVISION) + } + pkg_config_output = os.path.join(BUILD_DIR, + self.build_dir, + '{}.pc'.format(self.gac_pkg_name())) + + # FIXME: Why isn't the build directory available? + mk_dir(os.path.dirname(pkg_config_output)) + # Configure file that will be installed by ``make install``. + configure_file(pkg_config_template, pkg_config_output, substitutions) + + def mk_makefile(self, out): + global DOTNET_KEY_FILE + if not is_dotnet_enabled(): + return + cs_fp_files = [] + cs_files = [] + for cs_file in get_cs_files(self.src_dir): + cs_fp_files.append(os.path.join(self.to_src_dir, cs_file)) + cs_files.append(cs_file) + if self.assembly_info_dir != '.': + for cs_file in get_cs_files(os.path.join(self.src_dir, self.assembly_info_dir)): + cs_fp_files.append(os.path.join(self.to_src_dir, self.assembly_info_dir, cs_file)) + cs_files.append(os.path.join(self.assembly_info_dir, cs_file)) + dllfile = '%s.dll' % self.dll_name + out.write('%s: %s$(SO_EXT)' % (dllfile, get_component(Z3_DLL_COMPONENT).dll_name)) + for cs_file in cs_fp_files: + out.write(' ') + out.write(cs_file) + out.write('\n') + + cscCmdLine = [DOTNET] + if IS_WINDOWS: + # Using these flags under the mono compiler results in build errors. + cscCmdLine.extend( [# What is the motivation for this? + '/noconfig', + '/nostdlib+', + '/reference:mscorlib.dll', + ] + ) + + # We need to give the assembly a strong name so that it + # can be installed into the GAC with ``make install`` + if not DOTNET_KEY_FILE is None: + self.key_file = DOTNET_KEY_FILE + + if not self.key_file is None: + if os.path.isfile(self.key_file): + self.key_file = os.path.abspath(self.key_file) + elif os.path.isfile(os.path.join(self.src_dir, self.key_file)): + self.key_file = os.path.abspath(os.path.join(self.src_dir, self.key_file)) + else: + print("Keyfile '%s' could not be found; %s.dll will be unsigned." % (self.key_file, self.dll_name)) + self.key_file = None + + if not self.key_file is None: + print("%s.dll will be signed using key '%s'." % (self.dll_name, self.key_file)) + if (self.key_file.find(' ') != -1): + self.key_file = '"' + self.key_file + '"' + cscCmdLine.append('/keyfile:{}'.format(self.key_file)) + + cscCmdLine.extend( ['/unsafe+', + '/nowarn:1701,1702', + '/errorreport:prompt', + '/warn:4', + '/reference:System.Core.dll', + '/reference:System.dll', + '/reference:System.Numerics.dll', + '/filealign:512', # Why!? + '/out:{}.dll'.format(self.dll_name), + '/target:library', + '/doc:{}.xml'.format(self.dll_name), + ] + ) + if DEBUG_MODE: + cscCmdLine.extend( ['"/define:DEBUG;TRACE"', # Needs to be quoted due to ``;`` being a shell command separator + '/debug+', + '/debug:full', + '/optimize-' + ] + ) + else: + cscCmdLine.extend(['/optimize+']) + + if IS_WINDOWS: + if VS_X64: + cscCmdLine.extend(['/platform:x64']) + elif VS_ARM: + cscCmdLine.extend(['/platform:arm']) + else: + cscCmdLine.extend(['/platform:x86']) + else: + # Just use default platform for now. + # If the dlls are run using mono then it + # ignores what the platform is set to anyway. + pass + + for cs_file in cs_files: + cscCmdLine.append('{}'.format(os.path.join(self.to_src_dir, cs_file))) + + # Now emit the command line + MakeRuleCmd.write_cmd(out, ' '.join(cscCmdLine)) + + # State that the high-level "dotnet" target depends on the .NET bindings + # dll we just created the build rule for + out.write('\n') + out.write('%s: %s\n\n' % (self.name, dllfile)) + + # Create pkg-config file + self.mk_pkg_config_file() + return + + def main_component(self): + return is_dotnet_core_enabled() + + def has_assembly_info(self): + return True + + def mk_win_dist(self, build_path, dist_path): + if is_dotnet_core_enabled(): + mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR)) + shutil.copy('%s.dll' % os.path.join(build_path, self.dll_name), + '%s.dll' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) + shutil.copy('%s.xml' % os.path.join(build_path, self.dll_name), + '%s.xml' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) + if DEBUG_MODE: + shutil.copy('%s.pdb' % os.path.join(build_path, self.dll_name), + '%s.pdb' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) + + def mk_unix_dist(self, build_path, dist_path): + if is_dotnet_core_enabled(): + mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR)) + shutil.copy('%s.dll' % os.path.join(build_path, self.dll_name), + '%s.dll' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) + shutil.copy('%s.xml' % os.path.join(build_path, self.dll_name), + '%s.xml' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) + + def mk_install_deps(self, out): + if not is_dotnet_core_enabled(): + return + out.write('%s' % self.name) + + def gac_pkg_name(self): + return "{}.Sharp".format(self.dll_name) + + def _install_or_uninstall_to_gac(self, out, install): + gacUtilFlags = ['/package {}'.format(self.gac_pkg_name()), + '/root', + '{}{}'.format(MakeRuleCmd.install_root(), INSTALL_LIB_DIR) + ] + if install: + install_or_uninstall_flag = '-i' + else: + # Note need use ``-us`` here which takes an assembly file name + # rather than ``-u`` which takes an assembly display name (e.g. + # ) + install_or_uninstall_flag = '-us' + MakeRuleCmd.write_cmd(out, '{gacutil} {install_or_uninstall_flag} {assembly_name}.dll -f {flags}'.format( + gacutil=GACUTIL, + install_or_uninstall_flag=install_or_uninstall_flag, + assembly_name=self.dll_name, + flags=' '.join(gacUtilFlags))) + + def mk_install(self, out): + if not DOTNET_ENABLED: + return + self._install_or_uninstall_to_gac(out, install=True) + + # Install pkg-config file. Monodevelop needs this to find Z3 + pkg_config_output = os.path.join(self.build_dir, + '{}.pc'.format(self.gac_pkg_name())) + MakeRuleCmd.make_install_directory(out, INSTALL_PKGCONFIG_DIR) + MakeRuleCmd.install_files(out, pkg_config_output, INSTALL_PKGCONFIG_DIR) + + def mk_uninstall(self, out): + if not is_dotnet_core_enabled(): + return + self._install_or_uninstall_to_gac(out, install=False) + pkg_config_file = os.path.join('lib','pkgconfig','{}.pc'.format(self.gac_pkg_name())) + MakeRuleCmd.remove_installed_files(out, pkg_config_file) + class JavaDLLComponent(Component): def __init__(self, name, dll_name, package_name, manifest_file, path, deps): Component.__init__(self, name, path, deps) @@ -2347,6 +2561,10 @@ def add_dot_net_dll(name, deps=[], path=None, dll_name=None, assembly_info_dir=N c = DotNetDLLComponent(name, dll_name, path, deps, assembly_info_dir, default_key_file) reg_component(name, c) +def add_dot_net_core_dll(name, deps=[], path=None, dll_name=None, assembly_info_dir=None, default_key_file=None): + c = DotNetCoreDLLComponent(name, dll_name, path, deps, assembly_info_dir, default_key_file) + reg_component(name, c) + def add_java_dll(name, deps=[], path=None, dll_name=None, package_name=None, manifest_file=None): c = JavaDLLComponent(name, dll_name, package_name, manifest_file, path, deps) reg_component(name, c) diff --git a/src/api/dotnet/Microsoft.Z3.csproj b/src/api/dotnet/Microsoft.Z3.csproj index cde8b78c9..9aaa70821 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj +++ b/src/api/dotnet/Microsoft.Z3.csproj @@ -360,7 +360,6 @@ - diff --git a/src/api/dotnet/core/project.json b/src/api/dotnet/core/project.json deleted file mode 100644 index d54b6877b..000000000 --- a/src/api/dotnet/core/project.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "version": "1.0.0-*", - "buildOptions": { - "debugType": "portable", - "emitEntryPoint": false, - "outputName": "Microsoft.Z3", - "compile": [ "../*.cs", "*.cs" ], - "define": ["DOTNET_CORE"] - }, - "dependencies": { }, - "frameworks": { - "netcoreapp1.0": { - "dependencies": { - "Microsoft.NETCore.App": { - "type": "platform", - "version": "1.0.1" - } - }, - "imports": "dnxcore50" - } - } -} From 163e1e3e55bff7e839b3528676e65b79ef44a9cf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Oct 2018 11:03:41 -0700 Subject: [PATCH 096/227] avoid name clash Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 8c037f2e5..18d57e729 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -84,7 +84,7 @@ def init_project_def(): export_files=API_files, staging_link='python') add_dot_net_dll('dotnet', ['api_dll'], 'api/dotnet', dll_name='Microsoft.Z3', assembly_info_dir='Properties', default_key_file='src/api/dotnet/Microsoft.Z3.snk') - add_dot_net_core_dll('dotnet', ['api_dll'], 'api/dotnet', dll_name='Microsoft.Z3', assembly_info_dir='Properties', default_key_file='src/api/dotnet/Microsoft.Z3.snk') + add_dot_net_core_dll('dotnetcore', ['api_dll'], 'api/dotnet', dll_name='Microsoft.Z3', assembly_info_dir='Properties', default_key_file='src/api/dotnet/Microsoft.Z3.snk') add_java_dll('java', ['api_dll'], 'api/java', dll_name='libz3java', package_name="com.microsoft.z3", manifest_file='manifest') add_ml_lib('ml', ['api_dll'], 'api/ml', lib_name='libz3ml') add_hlib('cpp', 'api/c++', includes2install=['z3++.h']) From 7c043dee7de6270a9c4248750967445d6a3e1348 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Oct 2018 11:07:17 -0700 Subject: [PATCH 097/227] more prep for dotnetcore Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 5b4d31d3e..baf258c90 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -699,7 +699,7 @@ def parse_options(): options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:df:sxhmcvtnp:gj', ['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', - 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js', + 'trace', 'dotnet', 'dotnetcore', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js', 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'noomp', 'pypkgdir=', 'python', 'staticbin', 'log-sync']) except: print("ERROR: Invalid command line option") @@ -733,7 +733,7 @@ def parse_options(): TRACE = True elif opt in ('-.net', '--dotnet'): DOTNET_ENABLED = True - elif opt in ('--dotnetcore'): + elif opt in ('--dotnetcore',): DOTNET_ENABLED = True DOTNET_CORE_ENABLED = True elif opt in ('--dotnet-key'): From 4616ddf103c9688adcccaac124b5e407a0ec2933 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Oct 2018 11:50:07 -0700 Subject: [PATCH 098/227] more prep for dotnet core Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index baf258c90..b11505ad2 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -734,7 +734,6 @@ def parse_options(): elif opt in ('-.net', '--dotnet'): DOTNET_ENABLED = True elif opt in ('--dotnetcore',): - DOTNET_ENABLED = True DOTNET_CORE_ENABLED = True elif opt in ('--dotnet-key'): DOTNET_KEY_FILE = arg @@ -893,6 +892,7 @@ def is_dotnet_enabled(): return DOTNET_ENABLED def is_dotnet_core_enabled(): + print("core %s" % DOTNET_CORE_ENABLED) return DOTNET_CORE_ENABLED def is_python_enabled(): @@ -1857,7 +1857,7 @@ class DotNetCoreDLLComponent(Component): def mk_makefile(self, out): global DOTNET_KEY_FILE - if not is_dotnet_enabled(): + if not is_dotnet_core_enabled(): return cs_fp_files = [] cs_files = [] @@ -2008,7 +2008,7 @@ class DotNetCoreDLLComponent(Component): flags=' '.join(gacUtilFlags))) def mk_install(self, out): - if not DOTNET_ENABLED: + if not is_dotnet_core_enabled(): return self._install_or_uninstall_to_gac(out, install=True) @@ -2872,6 +2872,8 @@ def mk_config(): if is_dotnet_enabled(): print('C# Compiler: %s' % CSC) print('GAC utility: %s' % GACUTIL) + if is_dotnet_core_enabled(): + print('C# Compiler: %s' % DOTNET) config.close() @@ -3197,6 +3199,8 @@ def mk_bindings(api_files): dotnet_output_dir = None if is_dotnet_enabled(): dotnet_output_dir = get_component('dotnet').src_dir + elif is_dotnet_core_enabled(): + dotnet_output_dir = get_component('dotnetcore').src_dir java_output_dir = None java_package_name = None if is_java_enabled(): From 540922766d0b07fb90d0b5a2ce3a0a26ec2f1350 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Oct 2018 12:15:54 -0700 Subject: [PATCH 099/227] more dotnetcore preparation Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index b11505ad2..00bc20e29 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1875,10 +1875,10 @@ class DotNetCoreDLLComponent(Component): out.write(cs_file) out.write('\n') - cscCmdLine = [DOTNET] + dotnetCmdLine = [DOTNET] if IS_WINDOWS: # Using these flags under the mono compiler results in build errors. - cscCmdLine.extend( [# What is the motivation for this? + dotnetCmdLine.extend( [# What is the motivation for this? '/noconfig', '/nostdlib+', '/reference:mscorlib.dll', @@ -1903,9 +1903,9 @@ class DotNetCoreDLLComponent(Component): print("%s.dll will be signed using key '%s'." % (self.dll_name, self.key_file)) if (self.key_file.find(' ') != -1): self.key_file = '"' + self.key_file + '"' - cscCmdLine.append('/keyfile:{}'.format(self.key_file)) + dotnetCmdLine.append('/keyfile:{}'.format(self.key_file)) - cscCmdLine.extend( ['/unsafe+', + dotnetCmdLine.extend( ['/unsafe+', '/nowarn:1701,1702', '/errorreport:prompt', '/warn:4', @@ -1919,22 +1919,22 @@ class DotNetCoreDLLComponent(Component): ] ) if DEBUG_MODE: - cscCmdLine.extend( ['"/define:DEBUG;TRACE"', # Needs to be quoted due to ``;`` being a shell command separator + dotnetCmdLine.extend( ['"/define:DEBUG;TRACE"', # Needs to be quoted due to ``;`` being a shell command separator '/debug+', '/debug:full', '/optimize-' ] ) else: - cscCmdLine.extend(['/optimize+']) + dotnetCmdLine.extend(['/optimize+']) if IS_WINDOWS: if VS_X64: - cscCmdLine.extend(['/platform:x64']) + dotnetCmdLine.extend(['/platform:x64']) elif VS_ARM: - cscCmdLine.extend(['/platform:arm']) + dotnetCmdLine.extend(['/platform:arm']) else: - cscCmdLine.extend(['/platform:x86']) + dotnetCmdLine.extend(['/platform:x86']) else: # Just use default platform for now. # If the dlls are run using mono then it @@ -1942,10 +1942,10 @@ class DotNetCoreDLLComponent(Component): pass for cs_file in cs_files: - cscCmdLine.append('{}'.format(os.path.join(self.to_src_dir, cs_file))) + dotnetCmdLine.append('{}'.format(os.path.join(self.to_src_dir, cs_file))) # Now emit the command line - MakeRuleCmd.write_cmd(out, ' '.join(cscCmdLine)) + MakeRuleCmd.write_cmd(out, ' '.join(dotnetCmdLine)) # State that the high-level "dotnet" target depends on the .NET bindings # dll we just created the build rule for From 52801db3fdc7a39df212ec8579c92deffd6f2d01 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Oct 2018 16:28:01 -0700 Subject: [PATCH 100/227] more dotnet core prepration Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 80 +++++++------------------------------------ scripts/update_api.py | 2 +- 2 files changed, 14 insertions(+), 68 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 00bc20e29..6372e87fc 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -892,7 +892,6 @@ def is_dotnet_enabled(): return DOTNET_ENABLED def is_dotnet_core_enabled(): - print("core %s" % DOTNET_CORE_ENABLED) return DOTNET_CORE_ENABLED def is_python_enabled(): @@ -1875,75 +1874,22 @@ class DotNetCoreDLLComponent(Component): out.write(cs_file) out.write('\n') - dotnetCmdLine = [DOTNET] - if IS_WINDOWS: - # Using these flags under the mono compiler results in build errors. - dotnetCmdLine.extend( [# What is the motivation for this? - '/noconfig', - '/nostdlib+', - '/reference:mscorlib.dll', - ] - ) - - # We need to give the assembly a strong name so that it - # can be installed into the GAC with ``make install`` - if not DOTNET_KEY_FILE is None: - self.key_file = DOTNET_KEY_FILE - - if not self.key_file is None: - if os.path.isfile(self.key_file): - self.key_file = os.path.abspath(self.key_file) - elif os.path.isfile(os.path.join(self.src_dir, self.key_file)): - self.key_file = os.path.abspath(os.path.join(self.src_dir, self.key_file)) - else: - print("Keyfile '%s' could not be found; %s.dll will be unsigned." % (self.key_file, self.dll_name)) - self.key_file = None - - if not self.key_file is None: - print("%s.dll will be signed using key '%s'." % (self.dll_name, self.key_file)) - if (self.key_file.find(' ') != -1): - self.key_file = '"' + self.key_file + '"' - dotnetCmdLine.append('/keyfile:{}'.format(self.key_file)) - - dotnetCmdLine.extend( ['/unsafe+', - '/nowarn:1701,1702', - '/errorreport:prompt', - '/warn:4', - '/reference:System.Core.dll', - '/reference:System.dll', - '/reference:System.Numerics.dll', - '/filealign:512', # Why!? - '/out:{}.dll'.format(self.dll_name), - '/target:library', - '/doc:{}.xml'.format(self.dll_name), - ] - ) + # TBD: can this be replaced by running "dotnet new classlib"? + csproj = os.path.join(self.to_src_dir, "core", "core.csproj") + dotnetCmdLine = [DOTNET, "build", csproj] + + # TBD: select build configurations also based on architecture + # Debug|x86, Debug|x64, Debug|arm + # Release|x86, Release|x64, Release|arm + dotnetCmdLine.extend(['-c']) if DEBUG_MODE: - dotnetCmdLine.extend( ['"/define:DEBUG;TRACE"', # Needs to be quoted due to ``;`` being a shell command separator - '/debug+', - '/debug:full', - '/optimize-' - ] - ) + dotnetCmdLine.extend(['Debug']) else: - dotnetCmdLine.extend(['/optimize+']) - - if IS_WINDOWS: - if VS_X64: - dotnetCmdLine.extend(['/platform:x64']) - elif VS_ARM: - dotnetCmdLine.extend(['/platform:arm']) - else: - dotnetCmdLine.extend(['/platform:x86']) - else: - # Just use default platform for now. - # If the dlls are run using mono then it - # ignores what the platform is set to anyway. - pass - - for cs_file in cs_files: - dotnetCmdLine.append('{}'.format(os.path.join(self.to_src_dir, cs_file))) + dotnetCmdLine.extend(['Release']) + path = os.path.abspath(BUILD_DIR) + dotnetCmdLine.extend(['-o', path]) + # Now emit the command line MakeRuleCmd.write_cmd(out, ' '.join(dotnetCmdLine)) diff --git a/scripts/update_api.py b/scripts/update_api.py index 917df94a2..e04e37332 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1868,7 +1868,7 @@ def generate_files(api_files, mk_dotnet_wrappers(dotnet_file) if mk_util.is_verbose(): print("Generated '{}'".format(dotnet_file.name)) - + if java_output_dir: mk_java(java_output_dir, java_package_name) From aa6e1badf228405e2a574c7dc27f0ef90d302dfd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Oct 2018 08:16:26 -0700 Subject: [PATCH 101/227] recfun Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.cpp | 17 +++++++--- src/ast/ast.cpp | 18 +++++++++-- src/ast/ast.h | 13 ++++++++ src/parsers/smt2/smt2parser.cpp | 12 ++++--- src/smt/params/smt_params_helper.pyg | 3 +- src/smt/smt_context.cpp | 5 ++- src/smt/smt_context_inv.cpp | 2 +- src/smt/theory_recfun.cpp | 48 ++++++++++++++++++++-------- src/smt/theory_recfun.h | 10 +++--- 9 files changed, 95 insertions(+), 33 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 868b35d00..fa17b591d 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -253,7 +253,10 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) { if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast()) || !m_manager->compatible_sorts(domain[i+1], to_sort(parameters[i].get_ast()))) { - m_manager->raise_exception("domain sort and parameter do not match"); + std::stringstream strm; + strm << "domain sort " << sort_ref(domain[i+1], *m_manager) << " and parameter "; + strm << parameter_pp(parameters[i], *m_manager) << " do not match"; + m_manager->raise_exception(strm.str().c_str()); UNREACHABLE(); return nullptr; } @@ -292,8 +295,12 @@ func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) { m_manager->raise_exception("expecting sort parameter"); return nullptr; } - if (!m_manager->compatible_sorts(to_sort(parameters[i].get_ast()), domain[i+1])) { - m_manager->raise_exception("domain sort and parameter do not match"); + sort* srt1 = to_sort(parameters[i].get_ast()); + sort* srt2 = domain[i+1]; + if (!m_manager->compatible_sorts(srt1, srt2)) { + std::stringstream strm; + strm << "domain sort " << sort_ref(srt2, *m_manager) << " and parameter sort " << sort_ref(srt2, *m_manager) << " do not match"; + m_manager->raise_exception(strm.str()); UNREACHABLE(); return nullptr; } @@ -326,13 +333,13 @@ bool array_decl_plugin::check_set_arguments(unsigned arity, sort * const * domai if (domain[i] != domain[0]) { std::ostringstream buffer; buffer << "arguments " << 1 << " and " << (i+1) << " have different sorts"; - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); return false; } if (domain[i]->get_family_id() != m_family_id) { std::ostringstream buffer; buffer << "argument " << (i+1) << " is not of array sort"; - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); return false; } } diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 8750425a8..5f36a61ef 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include -#include +#include +#include #include "ast/ast.h" #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" @@ -1541,6 +1541,20 @@ void ast_manager::raise_exception(char const * msg) { throw ast_exception(msg); } +void ast_manager::raise_exception(std::string const& msg) { + throw ast_exception(msg.c_str()); +} + +std::ostream& ast_manager::display(std::ostream& out, parameter const& p) { + switch (p.get_kind()) { + case parameter::PARAM_AST: + return out << ast_ref(p.get_ast(), *this); + default: + return p.display(out); + } + return out; +} + void ast_manager::copy_families_plugins(ast_manager const & from) { TRACE("copy_families_plugins", diff --git a/src/ast/ast.h b/src/ast/ast.h index acef0c659..37a6126f2 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1562,6 +1562,9 @@ public: // Equivalent to throw ast_exception(msg) Z3_NORETURN void raise_exception(char const * msg); + Z3_NORETURN void raise_exception(std::string const& s); + + std::ostream& display(std::ostream& out, parameter const& p); bool is_format_manager() const { return m_format_manager == nullptr; } @@ -2498,6 +2501,16 @@ public: void mark(ast * n, bool flag) { if (flag) mark(n); else reset_mark(n); } }; +struct parameter_pp { + parameter const& p; + ast_manager& m; + parameter_pp(parameter const& p, ast_manager& m): p(p), m(m) {} +}; + +inline std::ostream& operator<<(std::ostream& out, parameter_pp const& pp) { + return pp.m.display(out, pp.p); +} + typedef ast_ref_fast_mark<1> ast_ref_fast_mark1; typedef ast_ref_fast_mark<2> ast_ref_fast_mark2; typedef ast_ref_fast_mark1 expr_ref_fast_mark1; diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 7ed90d1c8..106a77c0e 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -2277,10 +2277,14 @@ namespace smt2 { parse_expr(); if (m().get_sort(expr_stack().back()) != sort_stack().back()) throw parser_exception("invalid function/constant definition, sort mismatch"); - if (is_fun) - m_ctx.insert(id, num_vars, sort_stack().c_ptr() + sort_spos, expr_stack().back()); - else - m_ctx.model_add(id, num_vars, sort_stack().c_ptr() + sort_spos, expr_stack().back()); + sort* const* sorts = sort_stack().c_ptr() + sort_spos; + expr* t = expr_stack().back(); + if (is_fun) { + m_ctx.insert(id, num_vars, sorts, t); + } + else { + m_ctx.model_add(id, num_vars, sorts, t); + } check_rparen("invalid function/constant definition, ')' expected"); // restore stacks & env symbol_stack().shrink(sym_spos); diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 1c96826d6..2f87f24c0 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -96,5 +96,6 @@ def_module_params(module_name='smt', ('core.extend_nonlocal_patterns', BOOL, False, 'extend unsat cores with literals that have quantifiers with patterns that contain symbols which are not in the quantifier\'s body'), ('lemma_gc_strategy', UINT, 0, 'lemma garbage collection strategy: 0 - fixed, 1 - geometric, 2 - at restart, 3 - none'), ('dt_lazy_splits', UINT, 1, 'How lazy datatype splits are performed: 0- eager, 1- lazy for infinite types, 2- lazy'), - ('recfun.native', BOOL, False, 'use native rec-fun solver') + ('recfun.native', BOOL, False, 'use native rec-fun solver'), + ('recfun.depth', UINT, 2, 'initial depth for maxrec expansion') )) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index ab8707e73..a189c6be0 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1384,7 +1384,10 @@ namespace smt { SASSERT(m_manager.is_eq(n)); expr * lhs = n->get_arg(0); expr * rhs = n->get_arg(1); - if (val == l_true) { + if (m_manager.is_bool(lhs)) { + // no-op + } + else if (val == l_true) { add_eq(get_enode(lhs), get_enode(rhs), eq_justification(l)); } else { diff --git a/src/smt/smt_context_inv.cpp b/src/smt/smt_context_inv.cpp index 7f409622b..a6c4f49b4 100644 --- a/src/smt/smt_context_inv.cpp +++ b/src/smt/smt_context_inv.cpp @@ -303,7 +303,7 @@ namespace smt { for (bool_var v = 0; v < num; v++) { if (has_enode(v)) { enode * n = bool_var2enode(v); - if (n->is_eq() && is_relevant(n) && get_assignment(v) == l_false) { + if (n->is_eq() && is_relevant(n) && get_assignment(v) == l_false && !m_manager.is_iff(n->get_owner())) { TRACE("check_th_diseq_propagation", tout << "checking: #" << n->get_owner_id() << " " << mk_bounded_pp(n->get_owner(), m_manager) << "\n";); enode * lhs = n->get_arg(0)->get_root(); enode * rhs = n->get_arg(1)->get_root(); diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index e642dfd85..1fbedc63d 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -50,7 +50,14 @@ namespace smt { return alloc(theory_recfun, new_ctx->get_manager()); } + void theory_recfun::init_search_eh() { + smt_params_helper p(ctx().get_params()); + m_max_depth = p.recfun_depth(); + } + + bool theory_recfun::internalize_atom(app * atom, bool gate_ctx) { + TRACEFN(mk_pp(atom, m)); for (expr * arg : *atom) { ctx().internalize(arg, false); } @@ -76,7 +83,13 @@ namespace smt { } void theory_recfun::reset_queues() { + for (auto* e : m_q_case_expand) { + dealloc(e); + } m_q_case_expand.reset(); + for (auto* e : m_q_body_expand) { + dealloc(e); + } m_q_body_expand.reset(); m_q_clauses.clear(); } @@ -96,8 +109,7 @@ namespace smt { SASSERT(ctx().relevancy()); if (u().is_defined(n)) { TRACEFN("relevant_eh: (defined) " << mk_pp(n, m)); - case_expansion e(u(), n); - push_case_expand(std::move(e)); + push_case_expand(alloc(case_expansion, u(), n)); } } @@ -114,11 +126,13 @@ namespace smt { // restore depth book-keeping unsigned new_lim = m_preds_lim.size()-num_scopes; +#if 0 unsigned start = m_preds_lim[new_lim]; for (unsigned i = start; i < m_preds.size(); ++i) { m_pred_depth.remove(m_preds.get(i)); } m_preds.resize(start); +#endif m_preds_lim.shrink(new_lim); } @@ -141,25 +155,31 @@ namespace smt { ctx().mk_th_axiom(get_id(), c); } m_q_clauses.clear(); - + for (unsigned i = 0; i < m_q_case_expand.size(); ++i) { - case_expansion & e = m_q_case_expand[i]; - if (e.m_def->is_fun_macro()) { + case_expansion* e = m_q_case_expand[i]; + if (e->m_def->is_fun_macro()) { // body expand immediately - assert_macro_axiom(e); + assert_macro_axiom(*e); } else { // case expand - SASSERT(e.m_def->is_fun_defined()); - assert_case_axioms(e); + SASSERT(e->m_def->is_fun_defined()); + assert_case_axioms(*e); } + dealloc(e); + m_q_case_expand[i] = nullptr; } - m_q_case_expand.clear(); + m_stats.m_case_expansions += m_q_case_expand.size(); + m_q_case_expand.reset(); for (unsigned i = 0; i < m_q_body_expand.size(); ++i) { - assert_body_axiom(m_q_body_expand[i]); + assert_body_axiom(*m_q_body_expand[i]); + dealloc(m_q_body_expand[i]); + m_q_body_expand[i] = nullptr; } - m_q_body_expand.clear(); + m_stats.m_body_expansions += m_q_body_expand.size(); + m_q_body_expand.reset(); } /** @@ -167,7 +187,6 @@ namespace smt { * the guard appears at a depth below the current cutoff. */ void theory_recfun::assert_max_depth_limit(expr* guard) { - TRACEFN("max-depth limit"); literal_vector c; app_ref dlimit = m_util.mk_depth_limit_pred(m_max_depth); c.push_back(~mk_literal(dlimit)); @@ -216,8 +235,7 @@ namespace smt { if (is_true && u().is_case_pred(e)) { TRACEFN("assign_case_pred_true " << mk_pp(e, m)); // body-expand - body_expansion b_e(u(), to_app(e)); - push_body_expand(std::move(b_e)); + push_body_expand(alloc(body_expansion, u(), to_app(e))); } } @@ -268,6 +286,7 @@ namespace smt { * 2. add unit clause `f(args) = rhs` */ void theory_recfun::assert_macro_axiom(case_expansion & e) { + m_stats.m_macro_expansions++; TRACEFN("case expansion " << pp_case_expansion(e, m) << "\n"); SASSERT(e.m_def->is_fun_macro()); auto & vars = e.m_def->get_vars(); @@ -381,6 +400,7 @@ namespace smt { for (auto & e : unsat_core) { if (u().is_depth_limit(e)) { m_max_depth = (3 * m_max_depth) / 2; + IF_VERBOSE(1, verbose_stream() << "(smt.recfun :increase-depth " << m_max_depth << ")\n"); return true; } } diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index af12853a1..8249e3412 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -101,8 +101,8 @@ namespace smt { unsigned_vector m_preds_lim; unsigned m_max_depth; // for fairness and termination - vector m_q_case_expand; - vector m_q_body_expand; + ptr_vector m_q_case_expand; + ptr_vector m_q_body_expand; vector m_q_clauses; recfun_util & u() const { return m_util; } @@ -128,8 +128,8 @@ namespace smt { return vars.size() == 0 || vars[vars.size()-1]->get_idx() == 0; } protected: - void push_case_expand(case_expansion&& e) { m_q_case_expand.push_back(e); } - void push_body_expand(body_expansion&& e) { m_q_body_expand.push_back(e); } + void push_case_expand(case_expansion* e) { m_q_case_expand.push_back(e); } + void push_body_expand(body_expansion* e) { m_q_body_expand.push_back(e); } bool internalize_atom(app * atom, bool gate_ctx) override; bool internalize_term(app * term) override; @@ -153,7 +153,7 @@ namespace smt { theory_recfun(ast_manager & m); ~theory_recfun() override; theory * mk_fresh(context * new_ctx) override; - void init_search_eh() override { m_max_depth = 2; } + void init_search_eh() override; void display(std::ostream & out) const override; void collect_statistics(::statistics & st) const override; }; From 184ae7211e8f51f39f6bc9e540221684f7912cbd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Oct 2018 10:00:57 -0700 Subject: [PATCH 102/227] fix #1897 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 14 +++---- src/smt/smt_context.h | 16 ++++++++ src/smt/smt_context_pp.cpp | 12 ++++++ src/smt/theory_datatype.cpp | 77 +++++++++++++++++++------------------ src/smt/theory_lra.cpp | 16 ++++---- 5 files changed, 82 insertions(+), 53 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 17a7ce3a3..41f11dca2 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -494,7 +494,7 @@ namespace smt { try { TRACE("add_eq", tout << "assigning: #" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n";); - TRACE("add_eq_detail", tout << "assigning\n" << mk_pp(n1->get_owner(), m_manager) << "\n" << mk_pp(n2->get_owner(), m_manager) << "\n"; + TRACE("add_eq_detail", tout << "assigning\n" << enode_pp(n1, *this) << "\n" << enode_pp(n2, *this) << "\n"; tout << "kind: " << js.get_kind() << "\n";); m_stats.m_num_add_eq++; @@ -1232,7 +1232,7 @@ namespace smt { if (depth == 0) return false; if (r1->get_num_parents() < SMALL_NUM_PARENTS) { - TRACE("is_ext_diseq", tout << mk_bounded_pp(n1->get_owner(), m_manager) << " " << mk_bounded_pp(n2->get_owner(), m_manager) << " " << depth << "\n";); + TRACE("is_ext_diseq", tout << enode_pp(n1, *this) << " " << enode_pp(n2, *this) << " " << depth << "\n";); for (enode * p1 : enode::parents(r1)) { if (!is_relevant(p1)) continue; @@ -1241,7 +1241,7 @@ namespace smt { if (!p1->is_cgr()) continue; func_decl * f = p1->get_decl(); - TRACE("is_ext_diseq", tout << "p1: " << mk_bounded_pp(p1->get_owner(), m_manager) << "\n";); + TRACE("is_ext_diseq", tout << "p1: " << enode_pp(p1, *this) << "\n";); unsigned num_args = p1->get_num_args(); for (enode * p2 : enode::parents(r2)) { if (!is_relevant(p2)) @@ -1250,7 +1250,7 @@ namespace smt { continue; if (!p2->is_cgr()) continue; - TRACE("is_ext_diseq", tout << "p2: " << mk_bounded_pp(p2->get_owner(), m_manager) << "\n";); + TRACE("is_ext_diseq", tout << "p2: " << enode_pp(p2, *this) << "\n";); if (p1->get_root() != p2->get_root() && p2->get_decl() == f && p2->get_num_args() == num_args) { unsigned j = 0; for (j = 0; j < num_args; j++) { @@ -1264,7 +1264,7 @@ namespace smt { break; } if (j == num_args) { - TRACE("is_ext_diseq", tout << "found parents: " << mk_bounded_pp(p1->get_owner(), m_manager) << " " << mk_bounded_pp(p2->get_owner(), m_manager) << "\n";); + TRACE("is_ext_diseq", tout << "found parents: " << enode_pp(p1, *this) << " " << enode_pp(p2, *this) << "\n";); if (is_ext_diseq(p1, p2, depth - 1)) return true; } @@ -1770,7 +1770,7 @@ namespace smt { void context::set_conflict(const b_justification & js, literal not_l) { if (!inconsistent()) { - TRACE("set_conflict", display_literal_verbose(tout, not_l); display(tout, js); ); + TRACE("set_conflict", display_literal_verbose(tout, not_l); display(tout << " ", js); ); m_conflict = js; m_not_l = not_l; } @@ -4290,7 +4290,7 @@ namespace smt { for (enode * parent : enode::parents(n)) { family_id fid = parent->get_owner()->get_family_id(); if (fid != th_id && fid != m_manager.get_basic_family_id()) { - TRACE("is_shared", tout << mk_pp(n->get_owner(), m_manager) << "\nis shared because of:\n" << mk_pp(parent->get_owner(), m_manager) << "\n";); + TRACE("is_shared", tout << enode_pp(n, *this) << "\nis shared because of:\n" << enode_pp(parent, *this) << "\n";); return true; } } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 5733829a3..d0c9cc776 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1609,6 +1609,22 @@ namespace smt { void insert_macro(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep) { m_asserted_formulas.insert_macro(f, m, pr, dep); } }; + struct enode_eq_pp { + context const& ctx; + enode_pair const& p; + enode_eq_pp(enode_pair const& p, context const& ctx): ctx(ctx), p(p) {} + }; + + std::ostream& operator<<(std::ostream& out, enode_eq_pp const& p); + + struct enode_pp { + context const& ctx; + enode* n; + enode_pp(enode* n, context const& ctx): ctx(ctx), n(n) {} + }; + + std::ostream& operator<<(std::ostream& out, enode_pp const& p); + }; #endif /* SMT_CONTEXT_H_ */ diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index fb67d91d6..5dea80f5e 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -603,5 +603,17 @@ namespace smt { display(out, j); } + std::ostream& operator<<(std::ostream& out, enode_pp const& p) { + ast_manager& m = p.ctx.get_manager(); + enode* n = p.n; + return out << "[#" << n->get_owner_id() << " " << mk_bounded_pp(n->get_owner(), m) << "]"; + } + + std::ostream& operator<<(std::ostream& out, enode_eq_pp const& p) { + return out << enode_pp(p.p.first, p.ctx) << " = " << enode_pp(p.p.second, p.ctx) << "\n"; + } + + + }; diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 049555297..6aa49efae 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -365,7 +365,7 @@ namespace smt { if (!is_recognizer(n)) return; TRACE("datatype", tout << "assigning recognizer: #" << n->get_owner_id() << " is_true: " << is_true << "\n" - << mk_bounded_pp(n->get_owner(), get_manager()) << "\n";); + << enode_pp(n, ctx) << "\n";); SASSERT(n->get_num_args() == 1); enode * arg = n->get_arg(0); theory_var tv = arg->get_th_var(get_id()); @@ -393,11 +393,10 @@ namespace smt { } void theory_datatype::relevant_eh(app * n) { - TRACE("datatype", tout << "relevant_eh: " << mk_bounded_pp(n, get_manager()) << "\n";); context & ctx = get_context(); + TRACE("datatype", tout << "relevant_eh: " << mk_pp(n, get_manager()) << "\n";); SASSERT(ctx.relevancy()); if (is_recognizer(n)) { - TRACE("datatype", tout << "relevant_eh: #" << n->get_id() << "\n" << mk_bounded_pp(n, get_manager()) << "\n";); SASSERT(ctx.e_internalized(n)); enode * e = ctx.get_enode(n); theory_var v = e->get_arg(0)->get_th_var(get_id()); @@ -483,31 +482,41 @@ namespace smt { SASSERT(app->get_root() == root->get_root()); if (app != root) m_used_eqs.push_back(enode_pair(app, root)); + + TRACE("datatype", + tout << "occurs_check\n"; + for (enode_pair const& p : m_used_eqs) { + tout << enode_eq_pp(p, get_context()); + }); } // start exploring subgraph below `app` bool theory_datatype::occurs_check_enter(enode * app) { - oc_mark_on_stack(app); - theory_var v = app->get_root()->get_th_var(get_id()); - if (v != null_theory_var) { - v = m_find.find(v); - var_data * d = m_var_data[v]; - if (d->m_constructor) { - for (enode * arg : enode::args(d->m_constructor)) { - if (oc_cycle_free(arg)) { - continue; - } - if (oc_on_stack(arg)) { - // arg was explored before app, and is still on the stack: cycle - occurs_check_explain(app, arg); - return true; - } - // explore `arg` (with parent `app`) - if (m_util.is_datatype(get_manager().get_sort(arg->get_owner()))) { - m_parent.insert(arg->get_root(), app); - oc_push_stack(arg); - } - } + app = app->get_root(); + theory_var v = app->get_th_var(get_id()); + if (v == null_theory_var) { + return false; + } + v = m_find.find(v); + var_data * d = m_var_data[v]; + if (!d->m_constructor) { + return false; + } + enode * parent = d->m_constructor; + oc_mark_on_stack(parent); + for (enode * arg : enode::args(parent)) { + if (oc_cycle_free(arg)) { + continue; + } + if (oc_on_stack(arg)) { + // arg was explored before app, and is still on the stack: cycle + occurs_check_explain(parent, arg); + return true; + } + // explore `arg` (with paren) + if (m_util.is_datatype(get_manager().get_sort(arg->get_owner()))) { + m_parent.insert(arg->get_root(), parent); + oc_push_stack(arg); } } return false; @@ -521,7 +530,7 @@ namespace smt { a3 = cons(v3, a1) */ bool theory_datatype::occurs_check(enode * n) { - TRACE("datatype", tout << "occurs check: #" << n->get_owner_id() << " " << mk_bounded_pp(n->get_owner(), get_manager()) << "\n";); + TRACE("datatype", tout << "occurs check: " << enode_pp(n, get_context()) << "\n";); m_stats.m_occurs_check++; bool res = false; @@ -535,7 +544,7 @@ namespace smt { if (oc_cycle_free(app)) continue; - TRACE("datatype", tout << "occurs check loop: #" << app->get_owner_id() << " " << mk_bounded_pp(app->get_owner(), get_manager()) << (op==ENTER?" enter":" exit")<< "\n";); + TRACE("datatype", tout << "occurs check loop: " << enode_pp(app, get_context()) << (op==ENTER?" enter":" exit")<< "\n";); switch (op) { case ENTER: @@ -553,12 +562,6 @@ namespace smt { context & ctx = get_context(); region & r = ctx.get_region(); ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), r, 0, nullptr, m_used_eqs.size(), m_used_eqs.c_ptr()))); - TRACE("datatype", - tout << "occurs_check: true\n"; - for (enode_pair const& p : m_used_eqs) { - tout << "eq: #" << p.first->get_owner_id() << " #" << p.second->get_owner_id() << "\n"; - tout << mk_bounded_pp(p.first->get_owner(), get_manager()) << " " << mk_bounded_pp(p.second->get_owner(), get_manager()) << "\n"; - }); } return res; } @@ -613,7 +616,7 @@ namespace smt { var_data * d = m_var_data[v]; out << "v" << v << " #" << get_enode(v)->get_owner_id() << " -> v" << m_find.find(v) << " "; if (d->m_constructor) - out << mk_bounded_pp(d->m_constructor->get_owner(), get_manager()); + out << enode_pp(d->m_constructor, get_context()); else out << "(null)"; out << "\n"; @@ -778,11 +781,11 @@ namespace smt { SASSERT(!lits.empty()); region & reg = ctx.get_region(); TRACE("datatype_conflict", tout << mk_ismt2_pp(recognizer->get_owner(), get_manager()) << "\n"; - for (unsigned i = 0; i < lits.size(); i++) { - ctx.display_detailed_literal(tout, lits[i]); tout << "\n"; + for (literal l : lits) { + ctx.display_detailed_literal(tout, l); tout << "\n"; } - for (unsigned i = 0; i < eqs.size(); i++) { - tout << mk_ismt2_pp(eqs[i].first->get_owner(), get_manager()) << " = " << mk_ismt2_pp(eqs[i].second->get_owner(), get_manager()) << "\n"; + for (auto const& p : eqs) { + tout << enode_eq_pp(p, ctx); }); ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), reg, lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr()))); } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 4a04fdaaf..0b25aa626 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1361,8 +1361,7 @@ public: } enode* n2 = get_enode(other); if (n1->get_root() != n2->get_root()) { - TRACE("arith", tout << mk_pp(n1->get_owner(), m) << " = " << mk_pp(n2->get_owner(), m) << "\n"; - tout << mk_pp(n1->get_owner(), m) << " = " << mk_pp(n2->get_owner(), m) << "\n"; + TRACE("arith", tout << enode_eq_pp(enode_pair(n1, n2), ctx()); tout << "v" << v << " = " << "v" << other << "\n";); m_assume_eq_candidates.push_back(std::make_pair(v, other)); result = true; @@ -2800,15 +2799,15 @@ public: get_id(), ctx().get_region(), m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), x, y, 0, nullptr)); TRACE("arith", - for (unsigned i = 0; i < m_core.size(); ++i) { - ctx().display_detailed_literal(tout, m_core[i]); + for (literal c : m_core) { + ctx().display_detailed_literal(tout, c); tout << "\n"; } - for (unsigned i = 0; i < m_eqs.size(); ++i) { - tout << mk_pp(m_eqs[i].first->get_owner(), m) << " = " << mk_pp(m_eqs[i].second->get_owner(), m) << "\n"; + for (enode_pair const& p : m_eqs) { + tout << enode_eq_pp(p, ctx()); } tout << " ==> "; - tout << mk_pp(x->get_owner(), m) << " = " << mk_pp(y->get_owner(), m) << "\n"; + tout << enode_pp(x, ctx()) << " = " << enode_pp(y, ctx()) << "\n"; ); // parameters are TBD. @@ -3371,8 +3370,7 @@ public: break; } case equality_source: - out << mk_pp(m_equalities[idx].first->get_owner(), m) << " = " - << mk_pp(m_equalities[idx].second->get_owner(), m) << "\n"; + out << enode_eq_pp(m_equalities[idx], ctx()); break; case definition_source: { theory_var v = m_definitions[idx]; From 67077d960eb3bff9d695a099d22364156a5d24e9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Oct 2018 14:16:07 -0700 Subject: [PATCH 103/227] working with incremental depth Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 3 +- src/ast/expr_functors.cpp | 6 +- src/ast/expr_functors.h | 4 +- src/ast/recfun_decl_plugin.cpp | 45 ++++----------- src/ast/recfun_decl_plugin.h | 36 ++++++------ src/cmd_context/cmd_context.cpp | 98 +++++++++++++++++---------------- src/smt/theory_recfun.cpp | 47 ++++++++++------ src/smt/theory_recfun.h | 14 +++-- 8 files changed, 127 insertions(+), 126 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 5f36a61ef..e2ff19776 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1548,7 +1548,8 @@ void ast_manager::raise_exception(std::string const& msg) { std::ostream& ast_manager::display(std::ostream& out, parameter const& p) { switch (p.get_kind()) { case parameter::PARAM_AST: - return out << ast_ref(p.get_ast(), *this); + std::cout << "ast: " << p.get_ast() << "\n"; + return out << mk_pp(p.get_ast(), *this); default: return p.display(out); } diff --git a/src/ast/expr_functors.cpp b/src/ast/expr_functors.cpp index cada71ac9..6a2138106 100644 --- a/src/ast/expr_functors.cpp +++ b/src/ast/expr_functors.cpp @@ -69,7 +69,11 @@ void check_pred::visit(expr* e) { case AST_QUANTIFIER: { quantifier* q = to_quantifier(e); expr* arg = q->get_expr(); - if (m_visited.is_marked(arg)) { + if (!m_check_quantifiers) { + todo.pop_back(); + m_visited.mark(e, true); + } + else if (m_visited.is_marked(arg)) { todo.pop_back(); if (m_pred_holds.is_marked(arg)) { m_pred_holds.mark(e, true); diff --git a/src/ast/expr_functors.h b/src/ast/expr_functors.h index 5a4cac477..5825bea73 100644 --- a/src/ast/expr_functors.h +++ b/src/ast/expr_functors.h @@ -53,8 +53,10 @@ class check_pred { ast_mark m_pred_holds; ast_mark m_visited; expr_ref_vector m_refs; + bool m_check_quantifiers; public: - check_pred(i_expr_pred& p, ast_manager& m) : m_pred(p), m_refs(m) {} + check_pred(i_expr_pred& p, ast_manager& m, bool check_quantifiers = true) : + m_pred(p), m_refs(m), m_check_quantifiers(check_quantifiers) {} bool operator()(expr* e); diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index e5796b119..d1b9a861e 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -1,4 +1,6 @@ /*++ +Copyright (c) 2017 Microsoft Corporation, Simon Cruanes + Module Name: recfun_decl_plugin.cpp @@ -68,8 +70,11 @@ namespace recfun { ite_find_p(ast_manager & m) : m(m) {} virtual bool operator()(expr * e) { return m.is_ite(e); } }; + // ignore ites under quantifiers. + // this is redundant as the code + // that unfolds ites uses quantifier-free portion. ite_find_p p(m); - check_pred cp(p, m); + check_pred cp(p, m, false); return cp(e); } @@ -249,7 +254,9 @@ namespace recfun { else if (is_app(e)) { // explore arguments for (expr * arg : *to_app(e)) { - stack.push_back(arg); + if (contains_ite(arg)) { + stack.push_back(arg); + } } } } @@ -298,7 +305,7 @@ namespace recfun { } } - TRACEFN("done analysing " << get_name()); + TRACEFN("done analyzing " << get_name()); } /* @@ -405,42 +412,12 @@ namespace recfun { return d.get_def(); } - func_decl * plugin::mk_fun_pred_decl(unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) - { - VALIDATE_PARAM(m(), m().is_bool(range) && num_parameters == 1 && parameters[0].is_ast()); - func_decl_info info(m_family_id, OP_FUN_CASE_PRED, num_parameters, parameters); - info.m_private_parameters = true; - return m().mk_func_decl(symbol(parameters[0].get_symbol()), arity, domain, range, info); - } - - func_decl * plugin::mk_fun_defined_decl(decl_kind k, unsigned num_parameters, - parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) - { - VALIDATE_PARAM(m(), num_parameters == 1 && parameters[0].is_ast()); - func_decl_info info(m_family_id, k, num_parameters, parameters); - info.m_private_parameters = true; - return m().mk_func_decl(symbol(parameters[0].get_symbol()), arity, - domain, range, info); - } - // generic declaration of symbols func_decl * plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { UNREACHABLE(); - // TBD: parameter usage seems inconsistent with other uses. - IF_VERBOSE(0, verbose_stream() << "mk-func-decl " << k << "\n"); - switch (k) { - case OP_FUN_CASE_PRED: - return mk_fun_pred_decl(num_parameters, parameters, arity, domain, range); - case OP_FUN_DEFINED: - return mk_fun_defined_decl(k, num_parameters, parameters, arity, domain, range); - default: - UNREACHABLE(); - return nullptr; - } + return nullptr; } } } diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index 1e6f873e2..cae83584a 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -1,4 +1,6 @@ /*++ +Copyright (c) 2017 Microsoft Corporation, Simon Cruanes + Module Name: recfun_decl_plugin.h @@ -149,40 +151,36 @@ namespace recfun { ast_manager & m() { return *m_manager; } public: plugin(); - virtual ~plugin() override; - virtual void finalize() override; + ~plugin() override; + void finalize() override; util & u() const; // build or return util - virtual bool is_fully_interp(sort * s) const override { return false; } // might depend on unin sorts + bool is_fully_interp(sort * s) const override { return false; } // might depend on unin sorts - virtual decl_plugin * mk_fresh() override { return alloc(plugin); } + decl_plugin * mk_fresh() override { return alloc(plugin); } - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override { UNREACHABLE(); return 0; } + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override { + UNREACHABLE(); return nullptr; + } - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) override; - + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; + promise_def mk_def(symbol const& name, unsigned n, sort *const * params, sort * range); - + void set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs); - + def* mk_def(symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs); bool has_def(const symbol& s) const { return m_defs.contains(s); } - bool has_def() const { return !m_defs.empty(); } + bool has_defs() const { return !m_defs.empty(); } def const& get_def(const symbol& s) const { return *(m_defs[s]); } promise_def get_promise_def(const symbol &s) const { return promise_def(&u(), m_defs[s]); } def& get_def(symbol const& s) { return *(m_defs[s]); } bool has_case_def(func_decl* f) const { return m_case_defs.contains(f); } case_def& get_case_def(func_decl* f) { SASSERT(has_case_def(f)); return *(m_case_defs[f]); } bool is_declared(symbol const& s) const { return m_defs.contains(s); } - private: - func_decl * mk_fun_pred_decl(unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - func_decl * mk_fun_defined_decl(decl_kind k, - unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); }; } @@ -200,7 +198,7 @@ namespace recfun { public: util(ast_manager &m, family_id); - virtual ~util(); + ~util(); ast_manager & m() { return m_manager; } th_rewriter & get_th_rewriter() { return m_th_rw; } @@ -209,7 +207,7 @@ namespace recfun { bool is_depth_limit(expr * e) const { return is_app_of(e, m_fid, OP_DEPTH_LIMIT); } bool owns_app(app * e) const { return e->get_family_id() == m_fid; } - bool has_def() const { return m_plugin->has_def(); } + bool has_defs() const { return m_plugin->has_defs(); } //::entry * e = m_func_decls.insert_if_not_there2(s, func_decls()); func_decls & fs = e->get_data().m_value; if (!fs.insert(m(), f)) { @@ -834,9 +836,11 @@ void cmd_context::insert(symbol const & s, psort_decl * p) { void cmd_context::insert(symbol const & s, unsigned arity, sort *const* domain, expr * t) { expr_ref _t(t, m()); +#if 0 if (m_builtin_decls.contains(s)) { throw cmd_exception("invalid macro/named expression, builtin symbol ", s); } +#endif if (contains_macro(s, arity, domain)) { throw cmd_exception("named expression already defined"); } @@ -967,6 +971,15 @@ void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, s } func_decl * cmd_context::find_func_decl(symbol const & s) const { + if (contains_macro(s)) { + throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s); + } + func_decls fs; + if (m_func_decls.find(s, fs)) { + if (fs.more_than_one()) + throw cmd_exception("ambiguous function declaration reference, provide full signature to disumbiguate ( (*) ) ", s); + return fs.first(); + } builtin_decl d; if (m_builtin_decls.find(s, d)) { try { @@ -980,15 +993,6 @@ func_decl * cmd_context::find_func_decl(symbol const & s) const { } throw cmd_exception("invalid function declaration reference, must provide signature for builtin symbol ", s); } - if (contains_macro(s)) { - throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s); - } - func_decls fs; - if (m_func_decls.find(s, fs)) { - if (fs.more_than_one()) - throw cmd_exception("ambiguous function declaration reference, provide full signature to disumbiguate ( (*) ) ", s); - return fs.first(); - } throw cmd_exception("invalid function declaration reference, unknown function ", s); return nullptr; } @@ -1013,6 +1017,18 @@ static builtin_decl const & peek_builtin_decl(builtin_decl const & first, family func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices, unsigned arity, sort * const * domain, sort * range) const { + + if (domain && contains_macro(s, arity, domain)) + throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s); + + func_decl * f = nullptr; + func_decls fs; + if (num_indices == 0 && m_func_decls.find(s, fs)) { + f = fs.find(arity, domain, range); + } + if (f) { + return f; + } builtin_decl d; if (domain && m_builtin_decls.find(s, d)) { family_id fid = d.m_fid; @@ -1037,21 +1053,7 @@ func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, throw cmd_exception("invalid function declaration reference, invalid builtin reference ", s); return f; } - - if (domain && contains_macro(s, arity, domain)) - throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s); - - if (num_indices > 0) - throw cmd_exception("invalid indexed function declaration reference, unknown builtin function ", s); - - func_decl * f = nullptr; - func_decls fs; - if (m_func_decls.find(s, fs)) { - f = fs.find(arity, domain, range); - } - if (f == nullptr) - throw cmd_exception("invalid function declaration reference, unknown function ", s); - return f; + throw cmd_exception("invalid function declaration reference, unknown function ", s); } psort_decl * cmd_context::find_psort_decl(symbol const & s) const { @@ -1088,29 +1090,6 @@ void cmd_context::mk_const(symbol const & s, expr_ref & result) const { void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * args, unsigned num_indices, parameter const * indices, sort * range, expr_ref & result) const { - builtin_decl d; - if (m_builtin_decls.find(s, d)) { - family_id fid = d.m_fid; - decl_kind k = d.m_decl; - // Hack: if d.m_next != 0, we use the sort of args[0] (if available) to decide which plugin we use. - if (d.m_decl != 0 && num_args > 0) { - builtin_decl const & d2 = peek_builtin_decl(d, m().get_sort(args[0])->get_family_id()); - fid = d2.m_fid; - k = d2.m_decl; - } - if (num_indices == 0) { - result = m().mk_app(fid, k, 0, nullptr, num_args, args, range); - } - else { - result = m().mk_app(fid, k, num_indices, indices, num_args, args, range); - } - if (result.get() == nullptr) - throw cmd_exception("invalid builtin application ", s); - CHECK_SORT(result.get()); - return; - } - if (num_indices > 0) - throw cmd_exception("invalid use of indexed identifier, unknown builtin function ", s); expr* _t; if (macros_find(s, num_args, args, _t)) { TRACE("macro_bug", tout << "well_sorted_check_enabled(): " << well_sorted_check_enabled() << "\n"; @@ -1126,6 +1105,31 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg func_decls fs; if (!m_func_decls.find(s, fs)) { + + builtin_decl d; + if (m_builtin_decls.find(s, d)) { + family_id fid = d.m_fid; + decl_kind k = d.m_decl; + // Hack: if d.m_next != 0, we use the sort of args[0] (if available) to decide which plugin we use. + if (d.m_decl != 0 && num_args > 0) { + builtin_decl const & d2 = peek_builtin_decl(d, m().get_sort(args[0])->get_family_id()); + fid = d2.m_fid; + k = d2.m_decl; + } + if (num_indices == 0) { + result = m().mk_app(fid, k, 0, nullptr, num_args, args, range); + } + else { + result = m().mk_app(fid, k, num_indices, indices, num_args, args, range); + } + if (result.get() == nullptr) + throw cmd_exception("invalid builtin application ", s); + CHECK_SORT(result.get()); + return; + } + if (num_indices > 0) + throw cmd_exception("invalid use of indexed identifier, unknown builtin function ", s); + if (num_args == 0) { throw cmd_exception("unknown constant ", s); } diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 1fbedc63d..e1e741d3d 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -34,7 +34,7 @@ namespace smt { m_plugin(*reinterpret_cast(m.get_plugin(get_family_id()))), m_util(m_plugin.u()), m_preds(m), - m_max_depth(2), + m_max_depth(0), m_q_case_expand(), m_q_body_expand() { @@ -50,11 +50,15 @@ namespace smt { return alloc(theory_recfun, new_ctx->get_manager()); } - void theory_recfun::init_search_eh() { - smt_params_helper p(ctx().get_params()); + void theory_recfun::init(context* ctx) { + theory::init(ctx); + smt_params_helper p(ctx->get_params()); m_max_depth = p.recfun_depth(); + if (m_max_depth < 2) m_max_depth = 2; } + void theory_recfun::init_search_eh() { + } bool theory_recfun::internalize_atom(app * atom, bool gate_ctx) { TRACEFN(mk_pp(atom, m)); @@ -199,26 +203,22 @@ namespace smt { * retrieve depth associated with predicate or expression. */ unsigned theory_recfun::get_depth(expr* e) { + SASSERT(u().is_defined(e) || u().is_case_pred(e)); unsigned d = 0; m_pred_depth.find(e, d); + TRACEFN("depth " << d << " " << mk_pp(e, m)); return d; } /** * Update depth of subterms of e with respect to d. */ - void theory_recfun::set_depth(unsigned d, expr* e) { + void theory_recfun::set_depth_rec(unsigned d, expr* e) { struct insert_c { theory_recfun& th; unsigned m_depth; insert_c(theory_recfun& th, unsigned d): th(th), m_depth(d) {} - void operator()(app* e) { - if (th.u().is_defined(e) && !th.m_pred_depth.contains(e)) { - th.m_pred_depth.insert(e, m_depth); - th.m_preds.push_back(e); - TRACEFN("depth " << m_depth << " : " << mk_pp(e, th.m)); - } - } + void operator()(app* e) { th.set_depth(m_depth, e); } void operator()(quantifier*) {} void operator()(var*) {} }; @@ -226,6 +226,14 @@ namespace smt { for_each_expr(proc, e); } + void theory_recfun::set_depth(unsigned depth, expr* e) { + if ((u().is_defined(e) || u().is_case_pred(e)) && !m_pred_depth.contains(e)) { + m_pred_depth.insert(e, depth); + m_preds.push_back(e); + TRACEFN("depth " << depth << " : " << mk_pp(e, m)); + } + } + /** * if `is_true` and `v = C_f_i(t1...tn)`, * then body-expand i-th case of `f(t1...tn)` @@ -250,7 +258,7 @@ namespace smt { expr_ref new_body(m); new_body = subst(e, args.size(), args.c_ptr()); ctx().get_rewriter()(new_body); // simplify - set_depth(depth + 1, new_body); + set_depth_rec(depth + 1, new_body); return new_body; } @@ -312,19 +320,23 @@ namespace smt { SASSERT(e.m_def->is_fun_defined()); // add case-axioms for all case-paths auto & vars = e.m_def->get_vars(); + literal_vector preds; for (recfun::case_def const & c : e.m_def->get_cases()) { // applied predicate to `args` app_ref pred_applied = c.apply_case_predicate(e.m_args); // cut off cases below max-depth unsigned depth = get_depth(e.m_lhs); + set_depth(depth, pred_applied); + SASSERT(u().owns_app(pred_applied)); + literal concl = mk_literal(pred_applied); + preds.push_back(concl); + if (depth >= m_max_depth) { assert_max_depth_limit(pred_applied); continue; } - SASSERT(u().owns_app(pred_applied)); - literal concl = mk_literal(pred_applied); literal_vector guards; guards.push_back(concl); @@ -338,10 +350,11 @@ namespace smt { ctx().mk_th_axiom(get_id(), guards); if (c.is_immediate()) { - body_expansion be(e.m_lhs, c, e.m_args); + body_expansion be(pred_applied, c, e.m_args); assert_body_axiom(be); } } + ctx().mk_th_axiom(get_id(), preds); } /** @@ -357,7 +370,7 @@ namespace smt { auto & vars = d.get_vars(); auto & args = e.m_args; SASSERT(is_standard_order(vars)); - unsigned depth = get_depth(e.m_lhs); + unsigned depth = get_depth(e.m_pred); expr_ref lhs(u().mk_fun_defined(d, args), m); expr_ref rhs = apply_args(depth, vars, args, e.m_cdef->get_rhs()); @@ -388,7 +401,7 @@ namespace smt { } void theory_recfun::add_theory_assumptions(expr_ref_vector & assumptions) { - if (u().has_def()) { + if (u().has_defs()) { app_ref dlimit = m_util.mk_depth_limit_pred(m_max_depth); TRACEFN("add_theory_assumption " << mk_pp(dlimit.get(), m)); assumptions.push_back(dlimit); diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 8249e3412..b0d705ddc 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -66,20 +66,20 @@ namespace smt { // one body-expansion of `f(t1...tn)` using a `C_f_i(t1...tn)` struct body_expansion { - app* m_lhs; + app* m_pred; recfun_case_def const * m_cdef; ptr_vector m_args; - body_expansion(recfun_util& u, app * n) : m_lhs(n), m_cdef(0), m_args() { + body_expansion(recfun_util& u, app * n) : m_pred(n), m_cdef(0), m_args() { m_cdef = &u.get_case_def(n); m_args.append(n->get_num_args(), n->get_args()); } - body_expansion(app* lhs, recfun_case_def const & d, ptr_vector & args) : - m_lhs(lhs), m_cdef(&d), m_args(args) {} + body_expansion(app* pred, recfun_case_def const & d, ptr_vector & args) : + m_pred(pred), m_cdef(&d), m_args(args) {} body_expansion(body_expansion const & from): - m_lhs(from.m_lhs), m_cdef(from.m_cdef), m_args(from.m_args) {} + m_pred(from.m_pred), m_cdef(from.m_cdef), m_args(from.m_args) {} body_expansion(body_expansion && from) : - m_lhs(from.m_lhs), m_cdef(from.m_cdef), m_args(std::move(from.m_args)) {} + m_pred(from.m_pred), m_cdef(from.m_cdef), m_args(std::move(from.m_args)) {} }; struct pp_body_expansion { @@ -122,6 +122,7 @@ namespace smt { void assert_max_depth_limit(expr* guard); unsigned get_depth(expr* e); void set_depth(unsigned d, expr* e); + void set_depth_rec(unsigned d, expr* e); literal mk_eq_lit(expr* l, expr* r); bool is_standard_order(recfun::vars const& vars) const { @@ -148,6 +149,7 @@ namespace smt { void new_eq_eh(theory_var v1, theory_var v2) override {} void new_diseq_eh(theory_var v1, theory_var v2) override {} void add_theory_assumptions(expr_ref_vector & assumptions) override; + void init(context* ctx) override; public: theory_recfun(ast_manager & m); From 5d06fa23479d33fa81ba0751d4cd9e8aad94ea14 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 25 Oct 2018 17:29:09 -0500 Subject: [PATCH 104/227] fix #1901 Signed-off-by: Nikolaj Bjorner --- src/model/model.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/model/model.cpp b/src/model/model.cpp index 60441054c..2efc39db8 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -410,8 +410,7 @@ expr_ref model::cleanup_expr(top_sort& ts, expr* e, unsigned current_partition) } else if (f->is_skolem() && can_inline_def(ts, f) && (fi = get_func_interp(f)) && fi->get_interp() && (!ts.partition_ids().find(f, pid) || pid != current_partition)) { - var_subst vs(m); - // ? TBD args.reverse(); + var_subst vs(m, false); new_t = vs(fi->get_interp(), args.size(), args.c_ptr()); } #if 0 From c5cbf985ca245fd0f4af43bc9928115f41ed40a8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 26 Oct 2018 10:11:03 -0500 Subject: [PATCH 105/227] na Signed-off-by: Nikolaj Bjorner --- src/ast/recfun_decl_plugin.cpp | 4 ++++ src/ast/recfun_decl_plugin.h | 3 ++- src/cmd_context/cmd_context.cpp | 5 +++-- src/smt/smt_context.cpp | 2 +- src/smt/theory_recfun.cpp | 15 +++++++++++---- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index d1b9a861e..655462a1d 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -404,6 +404,10 @@ namespace recfun { } } + bool plugin::has_defs() const { + return !m_case_defs.empty(); + } + def* plugin::mk_def(symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs) { SASSERT(! m_defs.contains(name)); diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index cae83584a..d93ad50b8 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -174,7 +174,7 @@ namespace recfun { def* mk_def(symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs); bool has_def(const symbol& s) const { return m_defs.contains(s); } - bool has_defs() const { return !m_defs.empty(); } + bool has_defs() const; def const& get_def(const symbol& s) const { return *(m_defs[s]); } promise_def get_promise_def(const symbol &s) const { return promise_def(&u(), m_defs[s]); } def& get_def(symbol const& s) { return *(m_defs[s]); } @@ -207,6 +207,7 @@ namespace recfun { bool is_depth_limit(expr * e) const { return is_app_of(e, m_fid, OP_DEPTH_LIMIT); } bool owns_app(app * e) const { return e->get_family_id() == m_fid; } + //has_defs(); } //mk_def(name, arity, domain, range); @@ -950,7 +950,6 @@ void cmd_context::insert_rec_fun_as_axiom(func_decl *f, expr_ref_vector const& b void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, svector const& ids, expr* rhs) { - TRACE("recfun", tout<< "define recfun " << f->get_name() << " = " << mk_pp(rhs, m()) << "\n";); if (gparams::get_value("smt.recfun.native") != "true") { // just use an axiom @@ -958,6 +957,8 @@ void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, s return; } + TRACE("recfun", tout<< "define recfun " << f->get_name() << " = " << mk_pp(rhs, m()) << "\n";); + recfun_decl_plugin* p = get_recfun_plugin(); var_ref_vector vars(m()); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index a189c6be0..a56110bc2 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1773,7 +1773,7 @@ namespace smt { void context::set_conflict(const b_justification & js, literal not_l) { if (!inconsistent()) { - TRACE("set_conflict", display_literal_verbose(tout, not_l); display(tout, js); ); + TRACE("set_conflict", display_literal_verbose(tout, not_l); display(tout << " ", js); ); m_conflict = js; m_not_l = not_l; } diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index e1e741d3d..1c1ee964d 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -62,6 +62,9 @@ namespace smt { bool theory_recfun::internalize_atom(app * atom, bool gate_ctx) { TRACEFN(mk_pp(atom, m)); + if (!u().has_defs()) { + return false; + } for (expr * arg : *atom) { ctx().internalize(arg, false); } @@ -76,6 +79,9 @@ namespace smt { } bool theory_recfun::internalize_term(app * term) { + if (!u().has_defs()) { + return false; + } for (expr* e : *term) { ctx().internalize(e, false); } @@ -111,26 +117,26 @@ namespace smt { */ void theory_recfun::relevant_eh(app * n) { SASSERT(ctx().relevancy()); - if (u().is_defined(n)) { + if (u().is_defined(n) && u().has_defs()) { TRACEFN("relevant_eh: (defined) " << mk_pp(n, m)); push_case_expand(alloc(case_expansion, u(), n)); } } void theory_recfun::push_scope_eh() { - TRACEFN("push_scope"); theory::push_scope_eh(); m_preds_lim.push_back(m_preds.size()); } void theory_recfun::pop_scope_eh(unsigned num_scopes) { - TRACEFN("pop_scope " << num_scopes); theory::pop_scope_eh(num_scopes); reset_queues(); // restore depth book-keeping unsigned new_lim = m_preds_lim.size()-num_scopes; #if 0 + // depth tracking of recursive unfolding is + // turned off when enabling this code: unsigned start = m_preds_lim[new_lim]; for (unsigned i = start; i < m_preds.size(); ++i) { m_pred_depth.remove(m_preds.get(i)); @@ -337,7 +343,6 @@ namespace smt { continue; } - literal_vector guards; guards.push_back(concl); for (auto & g : c.get_guards()) { @@ -354,6 +359,8 @@ namespace smt { assert_body_axiom(be); } } + // the disjunction of branches is asserted + // to close the available cases. ctx().mk_th_axiom(get_id(), preds); } From 51a0022450c7d1c59e211b93dff49b239ff0636a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 27 Oct 2018 11:41:18 -0500 Subject: [PATCH 106/227] add recfun to API Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 15 ++++++++++ src/api/api_ast.cpp | 50 ++++++++++++++++++++++++++++++++ src/api/api_context.cpp | 1 + src/api/api_context.h | 3 ++ src/api/c++/z3++.h | 51 +++++++++++++++++++++++++++++++++ src/api/z3_api.h | 43 +++++++++++++++++++++++++++ src/ast/recfun_decl_plugin.cpp | 12 ++++---- src/ast/recfun_decl_plugin.h | 23 ++++++++------- src/cmd_context/cmd_context.cpp | 29 +++++-------------- src/cmd_context/cmd_context.h | 3 +- src/smt/theory_recfun.h | 3 +- 11 files changed, 191 insertions(+), 42 deletions(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 3089f5e2b..ab9c73209 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -1190,6 +1190,20 @@ void mk_model_example() { std::cout << m.eval(a + b < 2)<< std::endl; } +void recfun_example() { + std::cout << "recfun example\n"; + context c; + expr x = c.int_const("x"); + expr y = c.int_const("y"); + expr b = c.bool_const("b"); + sort I = c.int_sort(); + sort B = c.bool_sort(); + func_decl f = recfun("f", I, B, I); + expr_vector args(c); + args.push_back(x); args.push_back(b); + c.recdef(f, args, ite(b, x, f(x + 1, !b))); + prove(f(x,c.bool_val(false)) > x); +} int main() { @@ -1239,6 +1253,7 @@ int main() { consequence_example(); std::cout << "\n"; parse_example(); std::cout << "\n"; mk_model_example(); std::cout << "\n"; + recfun_example(); std::cout << "\n"; std::cout << "done\n"; } catch (exception & ex) { diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index a28315cda..cbe365c6c 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -38,6 +38,8 @@ Revision History: #include "util/cancel_eh.h" #include "util/scoped_timer.h" #include "ast/pp_params.hpp" +#include "ast/expr_abstract.h" + extern bool is_numeral_sort(Z3_context c, Z3_sort ty); @@ -110,6 +112,54 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } + Z3_func_decl Z3_API Z3_mk_rec_func_decl(Z3_context c, Z3_symbol s, unsigned domain_size, Z3_sort const* domain, + Z3_sort range) { + Z3_TRY; + LOG_Z3_mk_rec_func_decl(c, s, domain_size, domain, range); + RESET_ERROR_CODE(); + // + recfun::promise_def def = + mk_c(c)->recfun().get_plugin().mk_def(to_symbol(s), + domain_size, + to_sorts(domain), + to_sort(range)); + func_decl* d = def.get_def()->get_decl(); + mk_c(c)->save_ast_trail(d); + RETURN_Z3(of_func_decl(d)); + Z3_CATCH_RETURN(nullptr); + } + + void Z3_API Z3_add_rec_def(Z3_context c, Z3_func_decl f, unsigned n, Z3_ast args[], Z3_ast body) { + Z3_TRY; + LOG_Z3_add_rec_def(c, f, n, args, body); + func_decl* d = to_func_decl(f); + ast_manager& m = mk_c(c)->m(); + recfun::decl::plugin& p = mk_c(c)->recfun().get_plugin(); + expr_ref abs_body(m); + expr_ref_vector _args(m); + var_ref_vector _vars(m); + for (unsigned i = 0; i < n; ++i) { + _args.push_back(to_expr(args[i])); + _vars.push_back(m.mk_var(n - i - 1, m.get_sort(_args.back()))); + if (m.get_sort(_args.back()) != d->get_domain(i)) { + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); + return; + } + } + expr_abstract(m, 0, n, _args.c_ptr(), to_expr(body), abs_body); + recfun::promise_def pd = p.get_promise_def(d); + if (!pd.get_def()) { + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); + return; + } + if (m.get_sort(abs_body) != d->get_range()) { + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); + return; + } + p.set_definition(pd, n, _vars.c_ptr(), abs_body); + Z3_CATCH; + } + Z3_ast Z3_API Z3_mk_app(Z3_context c, Z3_func_decl d, unsigned num_args, Z3_ast const * args) { Z3_TRY; LOG_Z3_mk_app(c, d, num_args, args); diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index c236ba3e8..9fe13a15f 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -79,6 +79,7 @@ namespace api { m_datalog_util(m()), m_fpa_util(m()), m_sutil(m()), + m_recfun(m()), m_last_result(m()), m_ast_trail(m()), m_pmanager(m_limit) { diff --git a/src/api/api_context.h b/src/api/api_context.h index a6f55d1aa..b04768710 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -29,6 +29,7 @@ Revision History: #include "ast/datatype_decl_plugin.h" #include "ast/dl_decl_plugin.h" #include "ast/fpa_decl_plugin.h" +#include "ast/recfun_decl_plugin.h" #include "smt/smt_kernel.h" #include "smt/params/smt_params.h" #include "util/event_handler.h" @@ -62,6 +63,7 @@ namespace api { datalog::dl_decl_util m_datalog_util; fpa_util m_fpa_util; seq_util m_sutil; + recfun_util m_recfun; // Support for old solver API smt_params m_fparams; @@ -128,6 +130,7 @@ namespace api { fpa_util & fpautil() { return m_fpa_util; } datatype_util& dtutil() { return m_dt_plugin->u(); } seq_util& sutil() { return m_sutil; } + recfun_util& recfun() { return m_recfun; } family_id get_basic_fid() const { return m_basic_fid; } family_id get_array_fid() const { return m_array_fid; } family_id get_arith_fid() const { return m_arith_fid; } diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 07056746d..d360b6153 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -311,6 +311,13 @@ namespace z3 { func_decl function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & range); func_decl function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & d5, sort const & range); + func_decl recfun(symbol const & name, unsigned arity, sort const * domain, sort const & range); + func_decl recfun(char const * name, unsigned arity, sort const * domain, sort const & range); + func_decl recfun(char const * name, sort const & domain, sort const & range); + func_decl recfun(char const * name, sort const & d1, sort const & d2, sort const & range); + + void recdef(func_decl, expr_vector const& args, expr const& body); + expr constant(symbol const & name, sort const & s); expr constant(char const * name, sort const & s); expr bool_const(char const * name); @@ -2815,6 +2822,37 @@ namespace z3 { return func_decl(*this, f); } + inline func_decl context::recfun(symbol const & name, unsigned arity, sort const * domain, sort const & range) { + array args(arity); + for (unsigned i = 0; i < arity; i++) { + check_context(domain[i], range); + args[i] = domain[i]; + } + Z3_func_decl f = Z3_mk_rec_func_decl(m_ctx, name, arity, args.ptr(), range); + check_error(); + return func_decl(*this, f); + + } + + inline func_decl context::recfun(char const * name, unsigned arity, sort const * domain, sort const & range) { + return recfun(str_symbol(name), arity, domain, range); + } + + inline func_decl context::recfun(char const * name, sort const& d1, sort const & range) { + return recfun(str_symbol(name), 1, &d1, range); + } + + inline func_decl context::recfun(char const * name, sort const& d1, sort const& d2, sort const & range) { + sort dom[2] = { d1, d2 }; + return recfun(str_symbol(name), 2, dom, range); + } + + void context::recdef(func_decl f, expr_vector const& args, expr const& body) { + check_context(f, args); check_context(f, body); + array vars(args); + Z3_add_rec_def(f.ctx(), f, vars.size(), vars.ptr(), body); + } + inline expr context::constant(symbol const & name, sort const & s) { Z3_ast r = Z3_mk_const(m_ctx, name, s); check_error(); @@ -2976,6 +3014,19 @@ namespace z3 { return range.ctx().function(name.c_str(), domain, range); } + inline func_decl recfun(symbol const & name, unsigned arity, sort const * domain, sort const & range) { + return range.ctx().recfun(name, arity, domain, range); + } + inline func_decl recfun(char const * name, unsigned arity, sort const * domain, sort const & range) { + return range.ctx().recfun(name, arity, domain, range); + } + inline func_decl recfun(char const * name, sort const& d1, sort const & range) { + return range.ctx().recfun(name, d1, range); + } + inline func_decl recfun(char const * name, sort const& d1, sort const& d2, sort const & range) { + return range.ctx().recfun(name, d1, d2, range); + } + inline expr select(expr const & a, expr const & i) { check_context(a, i); Z3_ast r = Z3_mk_select(a.ctx(), a, i); diff --git a/src/api/z3_api.h b/src/api/z3_api.h index de446d9a8..a776bbe8e 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -2081,6 +2081,7 @@ extern "C" { Z3_sort range); + /** \brief Create a constant or function application. @@ -2140,6 +2141,48 @@ extern "C" { def_API('Z3_mk_fresh_const', AST, (_in(CONTEXT), _in(STRING), _in(SORT))) */ Z3_ast Z3_API Z3_mk_fresh_const(Z3_context c, Z3_string prefix, Z3_sort ty); + + + /** + \brief Declare a recursive function + + \param c logical context. + \param s name of the function. + \param domain_size number of arguments. It should be greater than 0. + \param domain array containing the sort of each argument. The array must contain domain_size elements. + \param range sort of the constant or the return sort of the function. + + After declaring recursive function, it should be associated with a recursive definition #Z3_mk_rec_def. + The function #Z3_mk_app can be used to create a constant or function + application. + + \sa Z3_mk_app + \sa Z3_mk_rec_def + + def_API('Z3_mk_rec_func_decl', FUNC_DECL, (_in(CONTEXT), _in(SYMBOL), _in(UINT), _in_array(2, SORT), _in(SORT))) + */ + Z3_func_decl Z3_API Z3_mk_rec_func_decl(Z3_context c, Z3_symbol s, + unsigned domain_size, Z3_sort const domain[], + Z3_sort range); + + /** + \brief Define the body of a recursive function. + + \param c logical context. + \param f function declaration. + \param n number of arguments to the function + \param args constants that are used as arguments to the recursive function in the definition. + \param body body of the recursive function + + After declaring a recursive function or a collection of mutually recursive functions, use + this function to provide the definition for the recursive function. + + \sa Z3_mk_rec_func_decl + + def_API('Z3_add_rec_def', VOID, (_in(CONTEXT), _in(FUNC_DECL), _in(UINT), _in_array(2, AST), _in(AST))) + */ + void Z3_API Z3_add_rec_def(Z3_context c, Z3_func_decl f, unsigned n, Z3_ast args[], Z3_ast body); + /*@}*/ /** @name Propositional Logic and Equality */ diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 655462a1d..25f545ca4 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -312,8 +312,8 @@ namespace recfun { * Main manager for defined functions */ - util::util(ast_manager & m, family_id id) - : m_manager(m), m_fid(id), m_th_rw(m), + util::util(ast_manager & m) + : m_manager(m), m_fid(m.get_family_id("recfun")), m_th_rw(m), m_plugin(dynamic_cast(m.get_plugin(m_fid))) { } @@ -385,15 +385,15 @@ namespace recfun { SASSERT(m_manager); SASSERT(m_family_id != null_family_id); if (!m_util.get()) { - m_util = alloc(util, *m_manager, m_family_id); + m_util = alloc(util, *m_manager); } return *(m_util.get()); } promise_def plugin::mk_def(symbol const& name, unsigned n, sort *const * params, sort * range) { - SASSERT(! m_defs.contains(name)); def* d = u().decl_fun(name, n, params, range); - m_defs.insert(name, d); + SASSERT(! m_defs.contains(d->get_decl())); + m_defs.insert(d->get_decl(), d); return promise_def(&u(), d); } @@ -410,8 +410,8 @@ namespace recfun { def* plugin::mk_def(symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs) { - SASSERT(! m_defs.contains(name)); promise_def d = mk_def(name, n, params, range); + SASSERT(! m_defs.contains(d.get_def()->get_decl())); set_definition(d, n_vars, vars, rhs); return d.get_def(); } diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index d93ad50b8..b516ae2bd 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -140,7 +140,7 @@ namespace recfun { namespace decl { class plugin : public decl_plugin { - typedef map def_map; + typedef obj_map def_map; typedef obj_map case_def_map; mutable scoped_ptr m_util; @@ -173,14 +173,14 @@ namespace recfun { def* mk_def(symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs); - bool has_def(const symbol& s) const { return m_defs.contains(s); } + bool has_def(func_decl* f) const { return m_defs.contains(f); } bool has_defs() const; - def const& get_def(const symbol& s) const { return *(m_defs[s]); } - promise_def get_promise_def(const symbol &s) const { return promise_def(&u(), m_defs[s]); } - def& get_def(symbol const& s) { return *(m_defs[s]); } + def const& get_def(func_decl* f) const { return *(m_defs[f]); } + promise_def get_promise_def(func_decl* f) const { return promise_def(&u(), m_defs[f]); } + def& get_def(func_decl* f) { return *(m_defs[f]); } bool has_case_def(func_decl* f) const { return m_case_defs.contains(f); } case_def& get_case_def(func_decl* f) { SASSERT(has_case_def(f)); return *(m_case_defs[f]); } - bool is_declared(symbol const& s) const { return m_defs.contains(s); } + //bool is_declared(symbol const& s) const { return m_defs.contains(s); } }; } @@ -197,7 +197,7 @@ namespace recfun { void set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs); public: - util(ast_manager &m, family_id); + util(ast_manager &m); ~util(); ast_manager & m() { return m_manager; } @@ -213,9 +213,10 @@ namespace recfun { //has_def(s)); - return m_plugin->get_def(s); + + def& get_def(func_decl* f) { + SASSERT(m_plugin->has_def(f)); + return m_plugin->get_def(f); } case_def& get_case_def(expr* e) { @@ -232,6 +233,8 @@ namespace recfun { } app_ref mk_depth_limit_pred(unsigned d); + + decl::plugin& get_plugin() { return *m_plugin; } }; } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 3031f8ed8..a4b949280 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -475,7 +475,6 @@ cmd_context::cmd_context(bool main_ctx, ast_manager * m, symbol const & l): m_manager(m), m_own_manager(m == nullptr), m_manager_initialized(false), - m_rec_fun_declared(false), m_pmanager(nullptr), m_sexpr_manager(nullptr), m_regular("stdout", std::cout), @@ -900,20 +899,15 @@ void cmd_context::model_del(func_decl* f) { } -recfun_decl_plugin * cmd_context::get_recfun_plugin() { - ast_manager & m = get_ast_manager(); - family_id id = m.get_family_id("recfun"); - recfun_decl_plugin* p = reinterpret_cast(m.get_plugin(id)); - SASSERT(p); - return p; +recfun_decl_plugin& cmd_context::get_recfun_plugin() { + recfun::util u(get_ast_manager()); + return u.get_plugin(); } recfun::promise_def cmd_context::decl_rec_fun(const symbol &name, unsigned int arity, sort *const *domain, sort *range) { SASSERT(logic_has_recfun()); - recfun_decl_plugin* p = get_recfun_plugin(); - recfun::promise_def def = p->mk_def(name, arity, domain, range); - return def; + return get_recfun_plugin().mk_def(name, arity, domain, range); } // insert a recursive function as a regular quantified axiom @@ -936,15 +930,6 @@ void cmd_context::insert_rec_fun_as_axiom(func_decl *f, expr_ref_vector const& b eq = m().mk_forall(ids.size(), f->get_domain(), ids.c_ptr(), eq, 0, m().rec_fun_qid(), symbol::null, 2, pats); } - // - // disable warning given the current way they are used - // (Z3 will here silently assume and not check the definitions to be well founded, - // and please use HSF for everything else). - // - if (false && !ids.empty() && !m_rec_fun_declared) { - warning_msg("recursive function definitions are assumed well-founded"); - m_rec_fun_declared = true; - } assert_expr(eq); } @@ -959,7 +944,7 @@ void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, s TRACE("recfun", tout<< "define recfun " << f->get_name() << " = " << mk_pp(rhs, m()) << "\n";); - recfun_decl_plugin* p = get_recfun_plugin(); + recfun_decl_plugin& p = get_recfun_plugin(); var_ref_vector vars(m()); for (expr* b : binding) { @@ -967,8 +952,8 @@ void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, s vars.push_back(to_var(b)); } - recfun::promise_def d = p->get_promise_def(f->get_name()); - p->set_definition(d, vars.size(), vars.c_ptr(), rhs); + recfun::promise_def d = p.get_promise_def(f); + p.set_definition(d, vars.size(), vars.c_ptr(), rhs); } func_decl * cmd_context::find_func_decl(symbol const & s) const { diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index acc406dfc..5e21a1bca 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -200,7 +200,6 @@ protected: ast_manager * m_manager; bool m_own_manager; bool m_manager_initialized; - bool m_rec_fun_declared; pdecl_manager * m_pmanager; sexpr_manager * m_sexpr_manager; check_logic m_check_logic; @@ -308,7 +307,7 @@ protected: void erase_macro(symbol const& s); bool macros_find(symbol const& s, unsigned n, expr*const* args, expr*& t) const; - recfun_decl_plugin * get_recfun_plugin(); + recfun_decl_plugin& get_recfun_plugin(); public: cmd_context(bool main_ctx = true, ast_manager * m = nullptr, symbol const & l = symbol::null); diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index b0d705ddc..56e738f21 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -42,8 +42,7 @@ namespace smt { m_lhs(n), m_def(nullptr), m_args() { SASSERT(u.is_defined(n)); func_decl * d = n->get_decl(); - const symbol& name = d->get_name(); - m_def = &u.get_def(name); + m_def = &u.get_def(d); m_args.append(n->get_num_args(), n->get_args()); } case_expansion(case_expansion const & from) From 80acf8ed79bb18d2cd11e49476dea73c65976b8e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 27 Oct 2018 13:26:32 -0500 Subject: [PATCH 107/227] add recfuns to model Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 3 ++- src/ast/ast.h | 2 +- src/ast/recfun_decl_plugin.cpp | 3 ++- src/ast/recfun_decl_plugin.h | 16 ++++++++++++---- src/ast/rewriter/rewriter.h | 5 +++-- src/ast/rewriter/rewriter_def.h | 6 ++---- src/smt/params/smt_params_helper.pyg | 2 +- src/smt/smt_context.cpp | 21 +++++++++++++++++++++ src/smt/theory_recfun.cpp | 2 +- 9 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index e2ff19776..9a15bc7d3 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1360,7 +1360,8 @@ ast_manager::ast_manager(ast_manager const & src, bool disable_proofs): m_proof_mode(disable_proofs ? PGM_DISABLED : src.m_proof_mode), m_trace_stream(src.m_trace_stream), m_trace_stream_owner(false), - m_rec_fun(":rec-fun") { + m_rec_fun(":rec-fun"), + m_lambda_def(":lambda-def") { SASSERT(!src.is_format_manager()); m_format_manager = alloc(ast_manager, PGM_DISABLED, m_trace_stream, true); init(); diff --git a/src/ast/ast.h b/src/ast/ast.h index 37a6126f2..9a0e223de 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1636,7 +1636,7 @@ public: bool are_distinct(expr * a, expr * b) const; bool contains(ast * a) const { return m_ast_table.contains(a); } - + bool is_rec_fun_def(quantifier* q) const { return q->get_qid() == m_rec_fun; } bool is_lambda_def(quantifier* q) const { return q->get_qid() == m_lambda_def; } func_decl* get_rec_fun_decl(quantifier* q) const; diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 25f545ca4..ca929a9d7 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -56,6 +56,7 @@ namespace recfun { m_domain(m, arity, domain), m_range(range, m), m_vars(m), m_cases(), m_decl(m), + m_rhs(m), m_fid(fid) { SASSERT(arity == get_arity()); @@ -211,7 +212,7 @@ namespace recfun { name.append(m_name.bare_str()); m_vars.append(n_vars, vars); - + m_rhs = rhs; expr_ref_vector conditions(m); diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index b516ae2bd..6bd338f54 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -99,6 +99,7 @@ namespace recfun { vars m_vars; //get_rec_funs(); + } + app_ref mk_depth_limit_pred(unsigned d); decl::plugin& get_plugin() { return *m_plugin; } diff --git a/src/ast/rewriter/rewriter.h b/src/ast/rewriter/rewriter.h index 84fef488f..4195e7de6 100644 --- a/src/ast/rewriter/rewriter.h +++ b/src/ast/rewriter/rewriter.h @@ -279,8 +279,9 @@ protected: return false; } - bool get_macro(func_decl * f, expr * & def, quantifier * & q, proof * & def_pr) { - return m_cfg.get_macro(f, def, q, def_pr); + bool get_macro(func_decl * f, expr * & def, proof * & def_pr) { + quantifier* q = nullptr; + return m_cfg.get_macro(f, def, q, def_pr); } void push_frame(expr * t, bool mcache, unsigned max_depth) { diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index ebe52f52a..3ee1e4caf 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -212,6 +212,7 @@ bool rewriter_tpl::constant_fold(app * t, frame & fr) { return false; } + template template void rewriter_tpl::process_app(app * t, frame & fr) { @@ -338,15 +339,12 @@ void rewriter_tpl::process_app(app * t, frame & fr) { // TODO: add rewrite rules support expr * def = nullptr; proof * def_pr = nullptr; - quantifier * def_q = nullptr; // When get_macro succeeds, then // we know that: // forall X. f(X) = def[X] // and def_pr is a proof for this quantifier. // - // Remark: def_q is only used for proof generation. - // It is the quantifier forall X. f(X) = def[X] - if (get_macro(f, def, def_q, def_pr)) { + if (get_macro(f, def, def_pr)) { SASSERT(!f->is_associative() || !flat_assoc(f)); SASSERT(new_num_args == t->get_num_args()); SASSERT(m().get_sort(def) == m().get_sort(t)); diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 2f87f24c0..6b4aee1c3 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -96,6 +96,6 @@ def_module_params(module_name='smt', ('core.extend_nonlocal_patterns', BOOL, False, 'extend unsat cores with literals that have quantifiers with patterns that contain symbols which are not in the quantifier\'s body'), ('lemma_gc_strategy', UINT, 0, 'lemma garbage collection strategy: 0 - fixed, 1 - geometric, 2 - at restart, 3 - none'), ('dt_lazy_splits', UINT, 1, 'How lazy datatype splits are performed: 0- eager, 1- lazy for infinite types, 2- lazy'), - ('recfun.native', BOOL, False, 'use native rec-fun solver'), + ('recfun.native', BOOL, True, 'use native rec-fun solver'), ('recfun.depth', UINT, 2, 'initial depth for maxrec expansion') )) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index a56110bc2..15887920a 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -37,6 +37,7 @@ Revision History: #include "model/model_pp.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_translation.h" +#include "ast/recfun_decl_plugin.h" namespace smt { @@ -4453,6 +4454,26 @@ namespace smt { m_model->register_decl(f, fi); } } + recfun::util u(m); + recfun::decl::plugin& p = u.get_plugin(); + func_decl_ref_vector recfuns = u.get_rec_funs(); + for (func_decl* f : recfuns) { + auto& def = u.get_def(f); + expr* rhs = def.get_rhs(); + if (!rhs) continue; + func_interp* fi = alloc(func_interp, m, f->get_arity()); + // reverse argument order so that variable 0 starts at the beginning. + expr_ref_vector subst(m); + unsigned idx = 0; + for (unsigned i = 0; i < f->get_arity(); ++i) { + subst.push_back(m.mk_var(i, f->get_domain(i))); + } + var_subst sub(m, true); + expr_ref bodyr = sub(rhs, subst.size(), subst.c_ptr()); + + fi->set_else(bodyr); + m_model->register_decl(f, fi); + } } }; diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 1c1ee964d..88354f1eb 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -306,7 +306,7 @@ namespace smt { auto & vars = e.m_def->get_vars(); expr_ref lhs(e.m_lhs, m); unsigned depth = get_depth(e.m_lhs); - expr_ref rhs(apply_args(depth, vars, e.m_args, e.m_def->get_macro_rhs()), m); + expr_ref rhs(apply_args(depth, vars, e.m_args, e.m_def->get_rhs()), m); literal lit = mk_eq_lit(lhs, rhs); ctx().mk_th_axiom(get_id(), 1, &lit); TRACEFN("macro expansion yields " << mk_pp(rhs, m) << "\n" << From 7db58be9046b4fa463c79cc9058a5aa2e4f92455 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 27 Oct 2018 16:14:20 -0500 Subject: [PATCH 108/227] add recfuns to python API Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 47 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 63b5a9e72..f68b908e2 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -800,6 +800,49 @@ def Function(name, *sig): def _to_func_decl_ref(a, ctx): return FuncDeclRef(a, ctx) +def RecFunction(name, *sig): + """Create a new Z3 recursive with the given sorts.""" + sig = _get_args(sig) + if __debug__: + _z3_assert(len(sig) > 0, "At least two arguments expected") + arity = len(sig) - 1 + rng = sig[arity] + if __debug__: + _z3_assert(is_sort(rng), "Z3 sort expected") + dom = (Sort * arity)() + for i in range(arity): + if __debug__: + _z3_assert(is_sort(sig[i]), "Z3 sort expected") + dom[i] = sig[i].ast + ctx = rng.ctx + return FuncDeclRef(Z3_mk_rec_func_decl(ctx.ref(), to_symbol(name, ctx), arity, dom, rng.ast), ctx) + +def RecAddDefinition(f, args, body): + """Set the body of a recursive function. + Recursive definitions are only unfolded during search. + >>> ctx = Context() + >>> fac = RecFunction('fac', IntSort(ctx), IntSort(ctx)) + >>> n = Int('n', ctx) + >>> RecAddDefinition(fac, n, If(n == 0, 1, n*fac(n-1))) + >>> simplify(fac(5)) + fac(5) + >>> s = Solver(ctx=ctx) + >>> s.add(fac(n) < 3) + >>> s.check() + sat + >>> s.model().eval(fac(5)) + 120 + """ + if is_app(args): + args = [args] + ctx = body.ctx + args = _get_args(args) + n = len(args) + _args = (Ast * n)() + for i in range(n): + _args[i] = args[i].ast + Z3_add_rec_def(ctx.ref(), f.ast, n, _args, body.ast) + ######################################### # # Expressions @@ -6512,8 +6555,8 @@ class Solver(Z3PPObject): >>> s.add(x > 0, x < 2) >>> s.check() sat - >>> s.model() - [x = 1] + >>> s.model().eval(x) + 1 >>> s.add(x < 1) >>> s.check() unsat From 0f0287d129e7a87e096e55c8dd15e7e224aa96c4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 28 Oct 2018 17:42:16 -0500 Subject: [PATCH 109/227] prepare release notes Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- RELEASE_NOTES | 14 +++++++++++++ scripts/mk_project.py | 2 +- src/api/api_context.h | 4 ++-- src/api/dotnet/Context.cs | 28 +++++++++++++++++++++++++ src/api/dotnet/FuncDecl.cs | 9 ++++++++ src/ast/ast_pp_util.cpp | 10 ++++++++- src/ast/ast_pp_util.h | 2 +- src/ast/ast_smt2_pp.cpp | 37 +++++++++++++++++++++++++++++++++ src/ast/ast_smt2_pp.h | 2 ++ src/ast/ast_smt_pp.cpp | 8 ------- src/ast/decl_collector.cpp | 8 ++----- src/ast/decl_collector.h | 7 +------ src/ast/recfun_decl_plugin.cpp | 2 +- src/ast/recfun_decl_plugin.h | 13 +++++------- src/ast/reg_decl_plugins.cpp | 2 +- src/cmd_context/cmd_context.cpp | 12 +++++------ src/cmd_context/cmd_context.h | 2 +- src/model/model_smt2_pp.cpp | 29 +++++++++++++------------- src/smt/theory_recfun.cpp | 2 +- src/smt/theory_recfun.h | 16 +++++++------- 21 files changed, 144 insertions(+), 67 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28ff64568..cd9c14435 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() ################################################################################ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 8) -set(Z3_VERSION_PATCH 2) +set(Z3_VERSION_PATCH 3) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified diff --git a/RELEASE_NOTES b/RELEASE_NOTES index acdb627d8..dcb8fc093 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,5 +1,19 @@ RELEASE NOTES +Version 4.8.3 +============= +- New features + - native handling of recursive function definitions + - PB rounding based option for conflict resolution when reasoning about PB constraints. + +Version 4.8.2 +============= +- Post-Release. + +Version 4.8.1 +============= +- Release. Bug-fix for 4.8.0 + Version 4.8.0 ============= diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 18d57e729..5bd96c0fc 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 8, 2, 0) + set_version(4, 8, 3, 0) add_lib('util', [], includes2install = ['z3_version.h']) add_lib('polynomial', ['util'], 'math/polynomial') add_lib('sat', ['util']) diff --git a/src/api/api_context.h b/src/api/api_context.h index b04768710..a6b8600d6 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -63,7 +63,7 @@ namespace api { datalog::dl_decl_util m_datalog_util; fpa_util m_fpa_util; seq_util m_sutil; - recfun_util m_recfun; + recfun::util m_recfun; // Support for old solver API smt_params m_fparams; @@ -130,7 +130,7 @@ namespace api { fpa_util & fpautil() { return m_fpa_util; } datatype_util& dtutil() { return m_dt_plugin->u(); } seq_util& sutil() { return m_sutil; } - recfun_util& recfun() { return m_recfun; } + recfun::util& recfun() { return m_recfun; } family_id get_basic_fid() const { return m_basic_fid; } family_id get_array_fid() const { return m_array_fid; } family_id get_arith_fid() const { return m_arith_fid; } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 97541e31f..ac11022c1 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -532,6 +532,34 @@ namespace Microsoft.Z3 return new FuncDecl(this, MkSymbol(name), domain, range); } + /// + /// Creates a new recursive function declaration. + /// + public FuncDecl MkRecFuncDecl(string name, Sort[] domain, Sort range) + { + Debug.Assert(range != null); + Debug.Assert(domain.All(d => d != null)); + + CheckContextMatch(domain); + CheckContextMatch(range); + return new FuncDecl(this, MkSymbol(name), domain, range, true); + } + + /// + /// Bind a definition to a recursive function declaration. + /// The function must have previously been created using + /// MkRecFuncDecl. The body may contain recursive uses of the function or + /// other mutually recursive functions. + /// + public void AddRecDef(FuncDecl f, Expr[] args, Expr body) + { + CheckContextMatch(f); + CheckContextMatch(args); + CheckContextMatch(body); + IntPtr[] argsNative = AST.ArrayToNative(args); + Native.Z3_add_rec_def(nCtx, f.NativeObject, (uint)args.Length, argsNative, body.NativeObject); + } + /// /// Creates a new function declaration. /// diff --git a/src/api/dotnet/FuncDecl.cs b/src/api/dotnet/FuncDecl.cs index 24ae456d8..30ed790db 100644 --- a/src/api/dotnet/FuncDecl.cs +++ b/src/api/dotnet/FuncDecl.cs @@ -302,6 +302,15 @@ namespace Microsoft.Z3 Debug.Assert(range != null); } + internal FuncDecl(Context ctx, Symbol name, Sort[] domain, Sort range, bool is_rec) + : base(ctx, Native.Z3_mk_rec_func_decl(ctx.nCtx, name.NativeObject, AST.ArrayLength(domain), AST.ArrayToNative(domain), range.NativeObject)) + { + Debug.Assert(ctx != null); + Debug.Assert(name != null); + Debug.Assert(range != null); + } + + #if DEBUG internal override void CheckNativeObject(IntPtr obj) { diff --git a/src/ast/ast_pp_util.cpp b/src/ast/ast_pp_util.cpp index 378710b36..a57ea6040 100644 --- a/src/ast/ast_pp_util.cpp +++ b/src/ast/ast_pp_util.cpp @@ -20,6 +20,7 @@ Revision History: #include "ast/ast_pp_util.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_smt_pp.h" +#include "ast/recfun_decl_plugin.h" void ast_pp_util::collect(expr* e) { coll.visit(e); @@ -49,7 +50,14 @@ void ast_pp_util::display_decls(std::ostream& out) { ast_smt2_pp(out, f, m_env) << "\n"; } } - SASSERT(coll.get_num_preds() == 0); + vector> recfuns; + recfun::util u(m); + func_decl_ref_vector funs = u.get_rec_funs(); + if (funs.empty()) return; + for (func_decl * f : funs) { + recfuns.push_back(std::make_pair(f, u.get_def(f).get_rhs())); + } + ast_smt2_pp_recdefs(out, recfuns, m_env); } void ast_pp_util::remove_decl(func_decl* f) { diff --git a/src/ast/ast_pp_util.h b/src/ast/ast_pp_util.h index c3b8aa601..e70880672 100644 --- a/src/ast/ast_pp_util.h +++ b/src/ast/ast_pp_util.h @@ -31,7 +31,7 @@ class ast_pp_util { decl_collector coll; - ast_pp_util(ast_manager& m): m(m), m_env(m), coll(m, false) {} + ast_pp_util(ast_manager& m): m(m), m_env(m), coll(m) {} void collect(expr* e); diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 3a55bbb0b..5f2d36279 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -1163,6 +1163,33 @@ public: unregister_var_names(f->get_arity()); } + // format set of mutually recursive definitions + void operator()(vector> const& funs, format_ref & r) { + format_ref_vector decls(m()), bodies(m()); + format_ref r1(m()), r2(m()); + + for (auto const& p : funs) { + unsigned len; + func_decl* f = p.first; + expr* e = p.second; + format * fname = m_env.pp_fdecl_name(f, len); + register_var_names(f->get_arity()); + format * args[3]; + args[0] = fname; + args[1] = pp_var_args(f->get_arity(), f->get_domain()); + args[2] = m_env.pp_sort(f->get_range()); + decls.push_back(mk_seq1(m(), args, args+3, f2f(), "")); + process(e, r); + bodies.push_back(r); + unregister_var_names(f->get_arity()); + } + r1 = mk_seq1(m(), decls.begin(), decls.end(), f2f(), ""); + r2 = mk_seq1(m(), bodies.begin(), bodies.end(), f2f(), ""); + format * args[2]; + args[0] = r1; + args[1] = r2; + r = mk_seq1(m(), args, args+2, f2f(), "define-rec-funs"); + } }; @@ -1275,6 +1302,16 @@ std::ostream & ast_smt2_pp(std::ostream & out, symbol const& s, bool is_skolem, return out; } +std::ostream & ast_smt2_pp_recdefs(std::ostream & out, vector> const& funs, smt2_pp_environment & env, params_ref const & p) { + ast_manager & m = env.get_manager(); + format_ref r(fm(m)); + smt2_printer pr(env, p); + pr(funs, r); + pp(out, r.get(), m, p); + return out; +} + + mk_ismt2_pp::mk_ismt2_pp(ast * t, ast_manager & m, params_ref const & p, unsigned indent, unsigned num_vars, char const * var_prefix): m_ast(t), m_manager(m), diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index 13093f138..dc306c6df 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -105,6 +105,8 @@ std::ostream & ast_smt2_pp(std::ostream & out, sort * s, smt2_pp_environment & e std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0, char const* cmd = "declare-fun"); std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, expr* e, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0, char const* cmd = "define-fun"); std::ostream & ast_smt2_pp(std::ostream & out, symbol const& s, bool is_skolem, smt2_pp_environment & env, params_ref const& p = params_ref()); +std::ostream & ast_smt2_pp_recdefs(std::ostream & out, vector> const& funs, smt2_pp_environment & env, params_ref const & p = params_ref()); + /** \brief Internal wrapper (for debugging purposes only) diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 5e2828adf..227e00419 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -980,14 +980,6 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { } } - for (unsigned i = 0; i < decls.get_num_preds(); ++i) { - func_decl* d = decls.get_pred_decls()[i]; - if (!(*m_is_declared)(d)) { - smt_printer p(strm, m, ql, rn, m_logic, true, true, m_simplify_implies, 0); - p(d); - strm << "\n"; - } - } #endif for (expr* a : m_assumptions) { diff --git a/src/ast/decl_collector.cpp b/src/ast/decl_collector.cpp index bec60e61c..bc415c461 100644 --- a/src/ast/decl_collector.cpp +++ b/src/ast/decl_collector.cpp @@ -50,18 +50,14 @@ void decl_collector::visit_func(func_decl * n) { if (!m_visited.is_marked(n)) { family_id fid = n->get_family_id(); if (fid == null_family_id) { - if (m_sep_preds && is_bool(n->get_range())) - m_preds.push_back(n); - else - m_decls.push_back(n); + m_decls.push_back(n); } m_visited.mark(n, true); } } -decl_collector::decl_collector(ast_manager & m, bool preds): +decl_collector::decl_collector(ast_manager & m): m_manager(m), - m_sep_preds(preds), m_dt_util(m) { m_basic_fid = m_manager.get_basic_family_id(); m_dt_fid = m_dt_util.get_family_id(); diff --git a/src/ast/decl_collector.h b/src/ast/decl_collector.h index 07539dbd8..8945c0bec 100644 --- a/src/ast/decl_collector.h +++ b/src/ast/decl_collector.h @@ -26,10 +26,8 @@ Revision History: class decl_collector { ast_manager & m_manager; - bool m_sep_preds; ptr_vector m_sorts; ptr_vector m_decls; - ptr_vector m_preds; ast_mark m_visited; family_id m_basic_fid; family_id m_dt_fid; @@ -46,8 +44,7 @@ class decl_collector { public: - // if preds == true, then predicates are stored in a separate collection. - decl_collector(ast_manager & m, bool preds = true); + decl_collector(ast_manager & m); ast_manager & m() { return m_manager; } void visit_func(func_decl* n); @@ -59,11 +56,9 @@ public: unsigned get_num_sorts() const { return m_sorts.size(); } unsigned get_num_decls() const { return m_decls.size(); } - unsigned get_num_preds() const { return m_preds.size(); } sort * const * get_sorts() const { return m_sorts.c_ptr(); } func_decl * const * get_func_decls() const { return m_decls.c_ptr(); } - func_decl * const * get_pred_decls() const { return m_preds.c_ptr(); } }; #endif diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index ca929a9d7..7fe7ae00b 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -369,7 +369,7 @@ namespace recfun { } namespace decl { - plugin::plugin() : decl_plugin(), m_defs(), m_case_defs(), m_def_block() {} + plugin::plugin() : decl_plugin(), m_defs(), m_case_defs() {} plugin::~plugin() { finalize(); } void plugin::finalize() { diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index 6bd338f54..347689a37 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -143,9 +143,8 @@ namespace recfun { typedef obj_map case_def_map; mutable scoped_ptr m_util; - def_map m_defs; // function->def - case_def_map m_case_defs; // case_pred->def - svector m_def_block; + def_map m_defs; // function->def + case_def_map m_case_defs; // case_pred->def ast_manager & m() { return *m_manager; } public: @@ -206,8 +205,11 @@ namespace recfun { ast_manager & m() { return m_manager; } th_rewriter & get_th_rewriter() { return m_th_rw; } + decl::plugin& get_plugin() { return *m_plugin; } + bool is_case_pred(expr * e) const { return is_app_of(e, m_fid, OP_FUN_CASE_PRED); } bool is_defined(expr * e) const { return is_app_of(e, m_fid, OP_FUN_DEFINED); } + bool is_defined(func_decl* f) const { return is_decl_of(f, m_fid, OP_FUN_DEFINED); } bool is_depth_limit(expr * e) const { return is_app_of(e, m_fid, OP_DEPTH_LIMIT); } bool owns_app(app * e) const { return e->get_family_id() == m_fid; } @@ -242,11 +244,6 @@ namespace recfun { app_ref mk_depth_limit_pred(unsigned d); - decl::plugin& get_plugin() { return *m_plugin; } }; } -typedef recfun::def recfun_def; -typedef recfun::case_def recfun_case_def; -typedef recfun::decl::plugin recfun_decl_plugin; -typedef recfun::util recfun_util; diff --git a/src/ast/reg_decl_plugins.cpp b/src/ast/reg_decl_plugins.cpp index f8abe81d8..7e121eb7f 100644 --- a/src/ast/reg_decl_plugins.cpp +++ b/src/ast/reg_decl_plugins.cpp @@ -42,7 +42,7 @@ void reg_decl_plugins(ast_manager & m) { m.register_plugin(symbol("datatype"), alloc(datatype_decl_plugin)); } if (!m.get_plugin(m.mk_family_id(symbol("recfun")))) { - m.register_plugin(symbol("recfun"), alloc(recfun_decl_plugin)); + m.register_plugin(symbol("recfun"), alloc(recfun::decl::plugin)); } if (!m.get_plugin(m.mk_family_id(symbol("datalog_relation")))) { m.register_plugin(symbol("datalog_relation"), alloc(datalog::dl_decl_plugin)); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index a4b949280..db0164445 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -693,7 +693,7 @@ void cmd_context::init_manager_core(bool new_manager) { register_plugin(symbol("bv"), alloc(bv_decl_plugin), logic_has_bv()); register_plugin(symbol("array"), alloc(array_decl_plugin), logic_has_array()); register_plugin(symbol("datatype"), alloc(datatype_decl_plugin), logic_has_datatype()); - register_plugin(symbol("recfun"), alloc(recfun_decl_plugin), logic_has_recfun()); + register_plugin(symbol("recfun"), alloc(recfun::decl::plugin), logic_has_recfun()); register_plugin(symbol("seq"), alloc(seq_decl_plugin), logic_has_seq()); register_plugin(symbol("pb"), alloc(pb_decl_plugin), logic_has_pb()); register_plugin(symbol("fpa"), alloc(fpa_decl_plugin), logic_has_fpa()); @@ -899,7 +899,7 @@ void cmd_context::model_del(func_decl* f) { } -recfun_decl_plugin& cmd_context::get_recfun_plugin() { +recfun::decl::plugin& cmd_context::get_recfun_plugin() { recfun::util u(get_ast_manager()); return u.get_plugin(); } @@ -944,7 +944,7 @@ void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, s TRACE("recfun", tout<< "define recfun " << f->get_name() << " = " << mk_pp(rhs, m()) << "\n";); - recfun_decl_plugin& p = get_recfun_plugin(); + recfun::decl::plugin& p = get_recfun_plugin(); var_ref_vector vars(m()); for (expr* b : binding) { @@ -2040,7 +2040,7 @@ void cmd_context::display_smt2_benchmark(std::ostream & out, unsigned num, expr if (logic != symbol::null) out << "(set-logic " << logic << ")" << std::endl; // collect uninterpreted function declarations - decl_collector decls(m(), false); + decl_collector decls(m()); for (unsigned i = 0; i < num; i++) { decls.visit(assertions[i]); } @@ -2071,8 +2071,8 @@ void cmd_context::slow_progress_sample() { svector labels; m_solver->get_labels(labels); regular_stream() << "(labels"; - for (unsigned i = 0; i < labels.size(); i++) { - regular_stream() << " " << labels[i]; + for (symbol const& s : labels) { + regular_stream() << " " << s; } regular_stream() << "))" << std::endl; } diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 5e21a1bca..b2ed1e5cb 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -307,7 +307,7 @@ protected: void erase_macro(symbol const& s); bool macros_find(symbol const& s, unsigned n, expr*const* args, expr*& t) const; - recfun_decl_plugin& get_recfun_plugin(); + recfun::decl::plugin& get_recfun_plugin(); public: cmd_context(bool main_ctx = true, ast_manager * m = nullptr, symbol const & l = symbol::null); diff --git a/src/model/model_smt2_pp.cpp b/src/model/model_smt2_pp.cpp index 807e2b4e7..b2a4f02aa 100644 --- a/src/model/model_smt2_pp.cpp +++ b/src/model/model_smt2_pp.cpp @@ -21,6 +21,7 @@ Revision History: #include "model/model_smt2_pp.h" #include "ast/ast_smt2_pp.h" #include "ast/func_decl_dependencies.h" +#include "ast/recfun_decl_plugin.h" #include "ast/pp.h" using namespace format_ns; @@ -60,11 +61,9 @@ static void pp_uninterp_sorts(std::ostream & out, ast_printer_context & ctx, mod ctx.display(buffer, s, 13); buffer << ":\n"; pp_indent(buffer, TAB_SZ); - ptr_vector::const_iterator it = u.begin(); - ptr_vector::const_iterator end = u.end(); - for (; it != end; ++it) { - SASSERT(is_app(*it)); - app * c = to_app(*it); + for (expr* e : u) { + SASSERT(is_app(e)); + app * c = to_app(e); pp_symbol(buffer, c->get_decl()->get_name()); buffer << " "; } @@ -87,9 +86,8 @@ static void pp_uninterp_sorts(std::ostream & out, ast_printer_context & ctx, mod out << "\n"; pp_indent(out, indent); out << ";; definitions for universe elements:\n"; - it = u.begin(); - for (; it != end; ++it) { - app * c = to_app(*it); + for (expr * e : u) { + app * c = to_app(e); pp_indent(out, indent); out << "(declare-fun "; unsigned len = pp_symbol(out, c->get_decl()->get_name()); @@ -101,9 +99,8 @@ static void pp_uninterp_sorts(std::ostream & out, ast_printer_context & ctx, mod out << ";; cardinality constraint:\n"; f_conds.reset(); format * var = mk_string(m, "x"); - it = u.begin(); - for (; it != end; ++it) { - app * c = to_app(*it); + for (expr* e : u) { + app * c = to_app(e); symbol csym = c->get_decl()->get_name(); std::string cname; if (is_smt2_quoted_symbol(csym)) @@ -170,10 +167,7 @@ void sort_fun_decls(ast_manager & m, model_core const & md, ptr_bufferget_else(), deps); - func_decl_set::iterator it2 = deps.begin(); - func_decl_set::iterator end2 = deps.end(); - for (; it2 != end2; ++it2) { - func_decl * d = *it2; + for (func_decl * d : deps) { if (d->get_arity() > 0 && md.has_interpretation(d) && !visited.contains(d)) { todo.push_back(d); visited.insert(d); @@ -189,8 +183,10 @@ void sort_fun_decls(ast_manager & m, model_core const & md, ptr_buffer var_names; ptr_buffer f_var_names; ptr_buffer f_arg_decls; @@ -200,6 +196,9 @@ static void pp_funs(std::ostream & out, ast_printer_context & ctx, model_core co sort_fun_decls(m, md, func_decls); for (unsigned i = 0; i < func_decls.size(); i++) { func_decl * f = func_decls[i]; + if (recfun_util.is_defined(f)) { + continue; + } func_interp * f_i = md.get_func_interp(f); SASSERT(f->get_arity() == f_i->get_arity()); format_ref body(fm(m)); diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 88354f1eb..c3e7c997e 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -31,7 +31,7 @@ namespace smt { theory_recfun::theory_recfun(ast_manager & m) : theory(m.mk_family_id("recfun")), m(m), - m_plugin(*reinterpret_cast(m.get_plugin(get_family_id()))), + m_plugin(*reinterpret_cast(m.get_plugin(get_family_id()))), m_util(m_plugin.u()), m_preds(m), m_max_depth(0), diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 56e738f21..46392c6d2 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -36,9 +36,9 @@ namespace smt { // one case-expansion of `f(t1...tn)` struct case_expansion { app * m_lhs; // the term to expand - recfun_def * m_def; + recfun::def * m_def; ptr_vector m_args; - case_expansion(recfun_util& u, app * n) : + case_expansion(recfun::util& u, app * n) : m_lhs(n), m_def(nullptr), m_args() { SASSERT(u.is_defined(n)); func_decl * d = n->get_decl(); @@ -66,14 +66,14 @@ namespace smt { // one body-expansion of `f(t1...tn)` using a `C_f_i(t1...tn)` struct body_expansion { app* m_pred; - recfun_case_def const * m_cdef; + recfun::case_def const * m_cdef; ptr_vector m_args; - body_expansion(recfun_util& u, app * n) : m_pred(n), m_cdef(0), m_args() { + body_expansion(recfun::util& u, app * n) : m_pred(n), m_cdef(0), m_args() { m_cdef = &u.get_case_def(n); m_args.append(n->get_num_args(), n->get_args()); } - body_expansion(app* pred, recfun_case_def const & d, ptr_vector & args) : + body_expansion(app* pred, recfun::case_def const & d, ptr_vector & args) : m_pred(pred), m_cdef(&d), m_args(args) {} body_expansion(body_expansion const & from): m_pred(from.m_pred), m_cdef(from.m_cdef), m_args(from.m_args) {} @@ -90,8 +90,8 @@ namespace smt { friend std::ostream& operator<<(std::ostream&, pp_body_expansion const &); ast_manager& m; - recfun_decl_plugin& m_plugin; - recfun_util& m_util; + recfun::decl::plugin& m_plugin; + recfun::util& m_util; stats m_stats; // book-keeping for depth of predicates @@ -104,7 +104,7 @@ namespace smt { ptr_vector m_q_body_expand; vector m_q_clauses; - recfun_util & u() const { return m_util; } + recfun::util & u() const { return m_util; } bool is_defined(app * f) const { return u().is_defined(f); } bool is_case_pred(app * f) const { return u().is_case_pred(f); } From 3c1c3d598730c28ce9fd58c34ed396f7811cc9a5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Oct 2018 14:15:29 -0500 Subject: [PATCH 110/227] fix #1908 Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.cpp | 18 +++++++++++++----- src/ast/ast.cpp | 10 ++++++++++ src/ast/ast.h | 13 +++++++++++++ src/ast/rewriter/seq_rewriter.cpp | 4 ---- src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_local_search.cpp | 18 +++++++++++++++++- src/sat/sat_local_search.h | 24 ++++++++++++++++++++++-- src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 25 +++++++++++++++---------- src/sat/sat_solver.h | 5 +++-- src/shell/dimacs_frontend.cpp | 14 +++++++------- 12 files changed, 103 insertions(+), 31 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index af451f9c5..fa17b591d 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -253,7 +253,10 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) { if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast()) || !m_manager->compatible_sorts(domain[i+1], to_sort(parameters[i].get_ast()))) { - m_manager->raise_exception("domain sort and parameter do not match"); + std::stringstream strm; + strm << "domain sort " << sort_ref(domain[i+1], *m_manager) << " and parameter "; + strm << parameter_pp(parameters[i], *m_manager) << " do not match"; + m_manager->raise_exception(strm.str().c_str()); UNREACHABLE(); return nullptr; } @@ -292,8 +295,12 @@ func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) { m_manager->raise_exception("expecting sort parameter"); return nullptr; } - if (!m_manager->compatible_sorts(to_sort(parameters[i].get_ast()), domain[i+1])) { - m_manager->raise_exception("domain sort and parameter do not match"); + sort* srt1 = to_sort(parameters[i].get_ast()); + sort* srt2 = domain[i+1]; + if (!m_manager->compatible_sorts(srt1, srt2)) { + std::stringstream strm; + strm << "domain sort " << sort_ref(srt2, *m_manager) << " and parameter sort " << sort_ref(srt2, *m_manager) << " do not match"; + m_manager->raise_exception(strm.str()); UNREACHABLE(); return nullptr; } @@ -326,13 +333,13 @@ bool array_decl_plugin::check_set_arguments(unsigned arity, sort * const * domai if (domain[i] != domain[0]) { std::ostringstream buffer; buffer << "arguments " << 1 << " and " << (i+1) << " have different sorts"; - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); return false; } if (domain[i]->get_family_id() != m_family_id) { std::ostringstream buffer; buffer << "argument " << (i+1) << " is not of array sort"; - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); return false; } } @@ -517,6 +524,7 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters void array_decl_plugin::get_sort_names(svector& sort_names, symbol const & logic) { sort_names.push_back(builtin_name(ARRAY_SORT_STR, ARRAY_SORT)); + sort_names.push_back(builtin_name("=>", ARRAY_SORT)); // TBD: this could easily break users even though it is already used in CVC4: // sort_names.push_back(builtin_name("Set", _SET_SORT)); } diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 8750425a8..99e861b16 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1542,6 +1542,16 @@ void ast_manager::raise_exception(char const * msg) { } +std::ostream& ast_manager::display(std::ostream& out, parameter const& p) { + switch (p.get_kind()) { + case parameter::PARAM_AST: + return out << mk_pp(p.get_ast(), *this); + default: + return p.display(out); + } + return out; +} + void ast_manager::copy_families_plugins(ast_manager const & from) { TRACE("copy_families_plugins", tout << "target:\n"; diff --git a/src/ast/ast.h b/src/ast/ast.h index c1193dfbd..ee39f4032 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1558,6 +1558,9 @@ public: // Equivalent to throw ast_exception(msg) Z3_NORETURN void raise_exception(char const * msg); + Z3_NORETURN void raise_exception(std::string const& msg) { raise_exception(msg.c_str()); } + + std::ostream& display(std::ostream& out, parameter const& p); bool is_format_manager() const { return m_format_manager == nullptr; } @@ -2569,6 +2572,16 @@ public: void operator()(AST * n) { m_manager.inc_ref(n); } }; +struct parameter_pp { + parameter const& p; + ast_manager& m; + parameter_pp(parameter const& p, ast_manager& m): p(p), m(m) {} +}; + +inline std::ostream& operator<<(std::ostream& out, parameter_pp const& pp) { + return pp.m.display(out, pp.p); +} + #endif /* AST_H_ */ diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 84c05d53e..e4ad3bb9d 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -859,10 +859,6 @@ br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& resu result = m_util.str.mk_concat(c, a); return BR_REWRITE1; } - if (m_util.str.is_string(a, s1) && s1.length() == 0) { - result = a; - return BR_DONE; - } return BR_FAILED; } diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index e9e6c4ee6..29221c0e8 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -86,6 +86,7 @@ namespace sat { m_local_search_mode = local_search_mode::gsat; else m_local_search_mode = local_search_mode::wsat; + m_local_search_dbg_flips = p.local_search_dbg_flips(); m_unit_walk = p.unit_walk(); m_unit_walk_threads = p.unit_walk_threads(); m_lookahead_simplify = p.lookahead_simplify(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 63e979394..ba5c9aaf3 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -105,6 +105,7 @@ namespace sat { unsigned m_local_search_threads; bool m_local_search; local_search_mode m_local_search_mode; + bool m_local_search_dbg_flips; unsigned m_unit_walk_threads; bool m_unit_walk; bool m_lookahead_simplify; diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 9b79e2964..b65abfd23 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -553,6 +553,7 @@ namespace sat { PROGRESS(tries, total_flips); for (tries = 1; !m_unsat_stack.empty() && m_limit.inc(); ++tries) { + ++m_stats.m_num_restarts; for (step = 0; step < m_max_steps && !m_unsat_stack.empty(); ++step) { pick_flip_walksat(); if (m_unsat_stack.size() < m_best_unsat) { @@ -622,7 +623,6 @@ namespace sat { break; } - // remove unit clauses from assumptions. m_constraints.shrink(num_constraints() - sz); @@ -779,8 +779,11 @@ namespace sat { } void local_search::flip_walksat(bool_var flipvar) { + ++m_stats.m_num_flips; VERIFY(!is_unit(flipvar)); m_vars[flipvar].m_value = !cur_solution(flipvar); + m_vars[flipvar].m_flips++; + m_vars[flipvar].m_slow_break.update(abs(m_vars[flipvar].m_slack_score)); bool flip_is_true = cur_solution(flipvar); coeff_vector const& truep = m_vars[flipvar].m_watch[flip_is_true]; @@ -1062,6 +1065,19 @@ namespace sat { return out << "v" << v << " := " << (vi.m_value?"true":"false") << " bias: " << vi.m_bias << "\n"; } + void local_search::collect_statistics(statistics& st) const { + if (m_config.dbg_flips()) { + unsigned i = 0; + for (var_info const& vi : m_vars) { + IF_VERBOSE(0, verbose_stream() << "flips: " << i << " " << vi.m_flips << " " << vi.m_slow_break << "\n"); + ++i; + } + } + st.update("local-search-flips", m_stats.m_num_flips); + st.update("local-search-restarts", m_stats.m_num_restarts); + } + + bool local_search::check_goodvar() { unsigned g = 0; for (unsigned v = 0; v < num_vars(); ++v) { diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index baf072419..849b4f26b 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -23,6 +23,8 @@ #include "sat/sat_types.h" #include "sat/sat_config.h" #include "util/rlimit.h" +#include "util/ema.h" +#include "util/statistics.h" namespace sat { @@ -33,18 +35,21 @@ namespace sat { int m_best_known_value; local_search_mode m_mode; bool m_phase_sticky; + bool m_dbg_flips; public: local_search_config() { m_random_seed = 0; m_best_known_value = INT_MAX; m_mode = local_search_mode::wsat; m_phase_sticky = false; + m_dbg_flips = false; } unsigned random_seed() const { return m_random_seed; } unsigned best_known_value() const { return m_best_known_value; } local_search_mode mode() const { return m_mode; } bool phase_sticky() const { return m_phase_sticky; } + bool dbg_flips() const { return m_dbg_flips; } void set_random_seed(unsigned s) { m_random_seed = s; } void set_best_known_value(unsigned v) { m_best_known_value = v; } @@ -53,6 +58,7 @@ namespace sat { m_mode = cfg.m_local_search_mode; m_random_seed = cfg.m_random_seed; m_phase_sticky = cfg.m_phase_sticky; + m_dbg_flips = cfg.m_local_search_dbg_flips; } }; @@ -74,6 +80,13 @@ namespace sat { int coefficient; // non-zero integer ob_term(bool_var v, int c): var_id(v), coefficient(c) {} }; + + struct stats { + unsigned m_num_flips; + unsigned m_num_restarts; + void reset() { memset(this, 0, sizeof(*this)); } + stats() { reset(); } + }; struct var_info { bool m_value; // current solution @@ -89,6 +102,8 @@ namespace sat { bool_var_vector m_neighbors; // neighborhood variables coeff_vector m_watch[2]; literal_vector m_bin[2]; + unsigned m_flips; + ema m_slow_break; var_info(): m_value(true), m_bias(50), @@ -97,7 +112,9 @@ namespace sat { m_in_goodvar_stack(false), m_score(0), m_slack_score(0), - m_cscc(0) + m_cscc(0), + m_flips(0), + m_slow_break(1e-5) {} }; @@ -115,6 +132,8 @@ namespace sat { literal const* end() const { return m_literals.end(); } }; + stats m_stats; + local_search_config m_config; // objective function: maximize @@ -145,7 +164,6 @@ namespace sat { inline void set_best_unsat(); /* TBD: other scores */ - vector m_constraints; @@ -293,6 +311,8 @@ namespace sat { model& get_model() { return m_model; } + void collect_statistics(statistics& st) const; + }; } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 3f0479707..2aef881ca 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -48,6 +48,7 @@ def_module_params('sat', ('local_search', BOOL, False, 'use local search instead of CDCL'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search_mode', SYMBOL, 'wsat', 'local search algorithm, either default wsat or qsat'), + ('local_search_dbg_flips', BOOL, False, 'write debug information for number of flips'), ('unit_walk', BOOL, False, 'use unit-walk search instead of CDCL'), ('unit_walk_threads', UINT, 0, 'number of unit-walk search threads to find satisfiable solution'), ('lookahead.cube.cutoff', SYMBOL, 'depth', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 2032445ed..fea45c07b 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -68,6 +68,7 @@ namespace sat { m_simplifications = 0; m_ext = nullptr; m_cuber = nullptr; + m_local_search = nullptr; m_mc.set_solver(this); } @@ -764,9 +765,9 @@ namespace sat { m_not_l = not_l; } - void solver::assign_core(literal l, justification j) { + void solver::assign_core(literal l, unsigned lvl, justification j) { SASSERT(value(l) == l_undef); - TRACE("sat_assign_core", tout << l << " " << j << " level: " << scope_lvl() << "\n";); + TRACE("sat_assign_core", tout << l << " " << j << " level: " << lvl << "\n";); if (at_base_lvl()) { if (m_config.m_drat) m_drat.add(l, !j.is_none()); j = justification(); // erase justification for level 0 @@ -774,7 +775,7 @@ namespace sat { m_assignment[l.index()] = l_true; m_assignment[(~l).index()] = l_false; bool_var v = l.var(); - m_level[v] = scope_lvl(); + m_level[v] = lvl; m_justification[v] = j; m_phase[v] = static_cast(l.sign()); m_assigned_since_gc[v] = true; @@ -882,7 +883,7 @@ namespace sat { return false; case l_undef: m_stats.m_bin_propagate++; - assign_core(l1, justification(not_l)); + assign_core(l1, scope_lvl(), justification(not_l)); break; case l_true: break; // skip @@ -897,11 +898,11 @@ namespace sat { val2 = value(l2); if (val1 == l_false && val2 == l_undef) { m_stats.m_ter_propagate++; - assign_core(l2, justification(l1, not_l)); + assign_core(l2, scope_lvl(), justification(l1, not_l)); } else if (val1 == l_undef && val2 == l_false) { m_stats.m_ter_propagate++; - assign_core(l1, justification(l2, not_l)); + assign_core(l1, scope_lvl(), justification(l2, not_l)); } else if (val1 == l_false && val2 == l_false) { CONFLICT_CLEANUP(); @@ -964,7 +965,7 @@ namespace sat { it2++; m_stats.m_propagate++; c.mark_used(); - assign_core(c[0], justification(cls_off)); + assign_core(c[0], scope_lvl(), justification(cls_off)); #ifdef UPDATE_GLUE if (update && c.is_learned() && c.glue() > 2) { unsigned glue; @@ -1042,7 +1043,7 @@ namespace sat { literal l(v, false); if (mdl[v] != l_true) l.neg(); push(); - assign_core(l, justification()); + assign_core(l, scope_lvl(), justification()); } mk_model(); break; @@ -1160,13 +1161,16 @@ namespace sat { lbool solver::do_local_search(unsigned num_lits, literal const* lits) { scoped_limits scoped_rl(rlimit()); - local_search srch; + SASSERT(!m_local_search); + m_local_search = alloc(local_search); + local_search& srch = *m_local_search; srch.config().set_config(m_config); srch.import(*this, false); scoped_rl.push_child(&srch.rlimit()); lbool r = srch.check(num_lits, lits, nullptr); m_model = srch.get_model(); - // srch.collect_statistics(m_aux_stats); + m_local_search = nullptr; + dealloc(&srch); return r; } @@ -3379,6 +3383,7 @@ namespace sat { m_asymm_branch.collect_statistics(st); m_probing.collect_statistics(st); if (m_ext) m_ext->collect_statistics(st); + if (m_local_search) m_local_search->collect_statistics(st); st.copy(m_aux_stats); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index a9a9fcee0..27c2e123c 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -163,6 +163,7 @@ namespace sat { bool m_par_syncing_clauses; class lookahead* m_cuber; + class local_search* m_local_search; statistics m_aux_stats; @@ -305,11 +306,11 @@ namespace sat { TRACE("sat_assign", tout << l << " previous value: " << value(l) << "\n";); switch (value(l)) { case l_false: set_conflict(j, ~l); break; - case l_undef: assign_core(l, j); break; + case l_undef: assign_core(l, scope_lvl(), j); break; case l_true: return; } } - void assign_core(literal l, justification jst); + void assign_core(literal l, unsigned lvl, justification jst); void set_conflict(justification c, literal not_l); void set_conflict(justification c) { set_conflict(c, null_literal); } lbool status(clause const & c) const; diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 3a2af72cf..d0fce359f 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -178,21 +178,21 @@ unsigned read_dimacs(char const * file_name) { std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; exit(ERR_OPEN_FILE); } - parse_dimacs(in, solver); + parse_dimacs(in, *g_solver); } else { - parse_dimacs(std::cin, solver); + parse_dimacs(std::cin, *g_solver); } - IF_VERBOSE(20, solver.display_status(verbose_stream());); + IF_VERBOSE(20, g_solver->display_status(verbose_stream());); lbool r; vector tracking_clauses; - sat::solver solver2(p, limit); - if (p.get_bool("dimacs.core", false)) { - g_solver = &solver2; + sat::solver solver2( p, limit); + if (p.get_bool("dimacs.core", false)) { sat::literal_vector assumptions; track_clauses(solver, solver2, assumptions, tracking_clauses); - r = g_solver->check(assumptions.size(), assumptions.c_ptr()); + g_solver = &solver2; + r = solver2.check(assumptions.size(), assumptions.c_ptr()); } else { r = g_solver->check(); From 2b14ec215b738b027c74d411f32fc549574d98b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Oct 2018 17:22:55 -0500 Subject: [PATCH 111/227] na Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 9a15bc7d3..cc9605fc9 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1549,7 +1549,6 @@ void ast_manager::raise_exception(std::string const& msg) { std::ostream& ast_manager::display(std::ostream& out, parameter const& p) { switch (p.get_kind()) { case parameter::PARAM_AST: - std::cout << "ast: " << p.get_ast() << "\n"; return out << mk_pp(p.get_ast(), *this); default: return p.display(out); From 22d2458c93d4822be81d9ba1cb3cbe2c76782211 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Oct 2018 18:23:10 -0500 Subject: [PATCH 112/227] na Signed-off-by: Nikolaj Bjorner --- src/ast/ast.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index efe452619..4054b32dc 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -2501,15 +2501,6 @@ public: void mark(ast * n, bool flag) { if (flag) mark(n); else reset_mark(n); } }; -struct parameter_pp { - parameter const& p; - ast_manager& m; - parameter_pp(parameter const& p, ast_manager& m): p(p), m(m) {} -}; - -inline std::ostream& operator<<(std::ostream& out, parameter_pp const& pp) { - return pp.m.display(out, pp.p); -} typedef ast_ref_fast_mark<1> ast_ref_fast_mark1; typedef ast_ref_fast_mark<2> ast_ref_fast_mark2; From bcf896bd0359e75bd46ac5fbb090f7bd708c10da Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Oct 2018 18:25:03 -0500 Subject: [PATCH 113/227] display' Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index d72bcbe82..9a5e1de9c 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1546,16 +1546,6 @@ void ast_manager::raise_exception(std::string const& msg) { throw ast_exception(msg.c_str()); } -std::ostream& ast_manager::display(std::ostream& out, parameter const& p) { - switch (p.get_kind()) { - case parameter::PARAM_AST: - return out << mk_pp(p.get_ast(), *this); - default: - return p.display(out); - } - return out; -} - std::ostream& ast_manager::display(std::ostream& out, parameter const& p) { switch (p.get_kind()) { From a775d1f5189f9fa7f10f51ba6fbdfaade1367da1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Oct 2018 14:40:13 -0500 Subject: [PATCH 114/227] newline Signed-off-by: Nikolaj Bjorner --- src/util/uint_set.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/uint_set.h b/src/util/uint_set.h index e6518b435..202df1039 100644 --- a/src/util/uint_set.h +++ b/src/util/uint_set.h @@ -270,7 +270,8 @@ public: if (contains(v)) { m_in_set[v] = false; unsigned i = m_set.size(); - for (; i > 0 && m_set[--i] != v; ) ; + for (; i > 0 && m_set[--i] != v; ) + ; SASSERT(m_set[i] == v); m_set[i] = m_set.back(); m_set.pop_back(); From 2a6fa4af3930b9f00aa875e1be9b244291ea604b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Oct 2018 16:30:42 -0500 Subject: [PATCH 115/227] deal with compiler warnings Signed-off-by: Nikolaj Bjorner --- src/ast/csp_decl_plugin.h | 2 +- src/sat/ba_solver.cpp | 10 +++++----- src/shell/dimacs_frontend.cpp | 14 +++++++------- src/smt/smt_context.cpp | 2 -- src/smt/theory_jobscheduler.cpp | 5 +++-- src/smt/theory_jobscheduler.h | 2 +- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/ast/csp_decl_plugin.h b/src/ast/csp_decl_plugin.h index f6f15d70a..7c10bbfe9 100644 --- a/src/ast/csp_decl_plugin.h +++ b/src/ast/csp_decl_plugin.h @@ -63,7 +63,7 @@ Revision History: --*/ -#pragma once; +#pragma once #include "ast/ast.h" enum js_sort_kind { diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index e939072e1..dd690a6a9 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1060,9 +1060,9 @@ namespace sat { uint64_t ba_solver::get_coeff(literal lit) const { int64_t c1 = get_coeff(lit.var()); SASSERT(c1 < 0 == lit.sign()); - uint64_t c = static_cast(std::abs(c1)); - m_overflow |= c != c1; - return c; + int64_t c = std::abs(c1); + m_overflow |= (c != c1); + return static_cast(c); } ba_solver::wliteral ba_solver::get_wliteral(bool_var v) { @@ -1630,7 +1630,7 @@ namespace sat { mark_visited(v); if (s().is_marked(v)) { int64_t c = get_coeff(v); - if (c == 0 || (c < 0 == consequent.sign())) { + if (c == 0 || ((c < 0) == consequent.sign())) { s().reset_mark(v); --m_num_marks; } @@ -3538,7 +3538,7 @@ namespace sat { } ++m_stats.m_num_big_strengthenings; p.set_removed(); - constraint* c = add_pb_ge(null_literal, wlits, b, p.learned()); + add_pb_ge(null_literal, wlits, b, p.learned()); return; } } diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index d0fce359f..3a2af72cf 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -178,21 +178,21 @@ unsigned read_dimacs(char const * file_name) { std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; exit(ERR_OPEN_FILE); } - parse_dimacs(in, *g_solver); + parse_dimacs(in, solver); } else { - parse_dimacs(std::cin, *g_solver); + parse_dimacs(std::cin, solver); } - IF_VERBOSE(20, g_solver->display_status(verbose_stream());); + IF_VERBOSE(20, solver.display_status(verbose_stream());); lbool r; vector tracking_clauses; - sat::solver solver2( p, limit); - if (p.get_bool("dimacs.core", false)) { + sat::solver solver2(p, limit); + if (p.get_bool("dimacs.core", false)) { + g_solver = &solver2; sat::literal_vector assumptions; track_clauses(solver, solver2, assumptions, tracking_clauses); - g_solver = &solver2; - r = solver2.check(assumptions.size(), assumptions.c_ptr()); + r = g_solver->check(assumptions.size(), assumptions.c_ptr()); } else { r = g_solver->check(); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 21af24b32..83ff79d3c 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4455,7 +4455,6 @@ namespace smt { } } recfun::util u(m); - recfun::decl::plugin& p = u.get_plugin(); func_decl_ref_vector recfuns = u.get_rec_funs(); for (func_decl* f : recfuns) { auto& def = u.get_def(f); @@ -4464,7 +4463,6 @@ namespace smt { func_interp* fi = alloc(func_interp, m, f->get_arity()); // reverse argument order so that variable 0 starts at the beginning. expr_ref_vector subst(m); - unsigned idx = 0; for (unsigned i = 0; i < f->get_arity(); ++i) { subst.push_back(m.mk_var(i, f->get_domain(i))); } diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index 880d75d24..847ea7f5e 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -130,7 +130,6 @@ namespace smt { void theory_jobscheduler::new_eq_eh(theory_var v1, theory_var v2) { enode* e1 = get_enode(v1); - enode* e2 = get_enode(v2); enode* root = e1->get_root(); unsigned r; if (u.is_resource(root->get_owner(), r)) { @@ -712,7 +711,7 @@ namespace smt { time_t start_lb = std::numeric_limits::max(); time_t runtime_lb = std::numeric_limits::max(); - time_t end_ub = 0, runtime_ub = 0; + time_t end_ub = 0; // , runtime_ub = 0; for (job_resource const& jr : ji.m_resources) { unsigned r = jr.m_resource_id; res_info const& ri = m_resources[r]; @@ -784,6 +783,7 @@ namespace smt { // resource(j) = r => start(j) <= end[idx] || start[idx+1] <= start(j); void theory_jobscheduler::assert_job_not_in_gap(unsigned j, unsigned r, unsigned idx, unsigned idx1, literal eq) { job_resource const& jr = get_job_resource(j, r); + (void) jr; vector& available = m_resources[r].m_available; SASSERT(resource_available(jr, available[idx])); literal l2 = mk_ge(m_jobs[j].m_start, available[idx1].m_start); @@ -795,6 +795,7 @@ namespace smt { void theory_jobscheduler::assert_job_non_preemptable(unsigned j, unsigned r, unsigned idx, unsigned idx1, literal eq) { vector& available = m_resources[r].m_available; job_resource const& jr = get_job_resource(j, r); + (void) jr; SASSERT(resource_available(jr, available[idx])); literal l2 = mk_le(m_jobs[j].m_end, available[idx].m_end); literal l3 = mk_ge(m_jobs[j].m_start, available[idx1].m_start); diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index 59c3b975d..3b9a42595 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -18,7 +18,7 @@ Author: Revision History: --*/ -#pragma once; +#pragma once #include "util/uint_set.h" #include "ast/csp_decl_plugin.h" From b02fec91cc10147e81eceeb1c1333245dc1ae4fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Nov 2018 09:34:42 -0500 Subject: [PATCH 116/227] fixing python build errors Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 4 ++- src/ast/recfun_decl_plugin.cpp | 40 ++++++++++--------------- src/ast/recfun_decl_plugin.h | 20 ++++++++----- src/ast/rewriter/expr_safe_replace.cpp | 1 - src/ast/rewriter/expr_safe_replace.h | 1 + src/ast/rewriter/recfun_replace.h | 41 ++++++++++++++++++++++++++ src/cmd_context/cmd_context.cpp | 4 ++- 7 files changed, 76 insertions(+), 35 deletions(-) create mode 100644 src/ast/rewriter/recfun_replace.h diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index cbe365c6c..bf5a79bdf 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -33,6 +33,7 @@ Revision History: #include "ast/rewriter/th_rewriter.h" #include "ast/rewriter/var_subst.h" #include "ast/rewriter/expr_safe_replace.h" +#include "ast/rewriter/recfun_replace.h" #include "ast/pp.h" #include "util/scoped_ctrl_c.h" #include "util/cancel_eh.h" @@ -156,7 +157,8 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return; } - p.set_definition(pd, n, _vars.c_ptr(), abs_body); + recfun_replace replace(m); + p.set_definition(replace, pd, n, _vars.c_ptr(), abs_body); Z3_CATCH; } diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 7fe7ae00b..1ac44067f 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -21,7 +21,6 @@ Revision History: #include #include #include "ast/expr_functors.h" -#include "ast/expr_substitution.h" #include "ast/recfun_decl_plugin.h" #include "ast/ast_pp.h" #include "util/scoped_ptr_vector.h" @@ -162,7 +161,7 @@ namespace recfun { static void convert_path(ast_manager & m, choice_lst const * choices, expr_ref_vector & conditions /* out */, - expr_substitution & subst /* out */) + replace & subst /* out */) { for (; choices != nullptr; choices = choices->next) { app * ite = choices->ite; @@ -177,15 +176,6 @@ namespace recfun { } } - // substitute `subst` in `e` - static expr_ref replace_subst(th_rewriter & th_rw, ast_manager & m, - expr_substitution & subst, expr * e) { - th_rw.reset(); - th_rw.set_substitution(&subst); - expr_ref res(m); - th_rw(e, res); - return res; - } void def::add_case(std::string & name, unsigned case_index, expr_ref_vector const& conditions, expr * rhs, bool is_imm) { case_def c(m, m_fid, this, name, case_index, get_domain(), conditions, rhs); @@ -198,7 +188,8 @@ namespace recfun { // Compute a set of cases, given the RHS - void def::compute_cases(is_immediate_pred & is_i, th_rewriter & th_rw, + void def::compute_cases(replace& subst, + is_immediate_pred & is_i, unsigned n_vars, var *const * vars, expr* rhs) { VERIFY(m_cases.empty() && "cases cannot already be computed"); @@ -291,13 +282,13 @@ namespace recfun { // leaf of the search tree conditions.reset(); - expr_substitution subst(m); + subst.reset(); convert_path(m, b.path, conditions, subst); // substitute, to get rid of `ite` terms - expr_ref case_rhs = replace_subst(th_rw, m, subst, rhs); + expr_ref case_rhs = subst(rhs); for (unsigned i = 0; i < conditions.size(); ++i) { - conditions[i] = replace_subst(th_rw, m, subst, conditions.get(i)); + conditions[i] = subst(conditions.get(i)); } // yield new case @@ -314,7 +305,7 @@ namespace recfun { */ util::util(ast_manager & m) - : m_manager(m), m_fid(m.get_family_id("recfun")), m_th_rw(m), + : m_manager(m), m_fid(m.get_family_id("recfun")), m_plugin(dynamic_cast(m.get_plugin(m_fid))) { } @@ -325,8 +316,8 @@ namespace recfun { return alloc(def, m(), m_fid, name, n, domain, range); } - void util::set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) { - d.set_definition(n_vars, vars, rhs); + void util::set_definition(replace& subst, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) { + d.set_definition(subst, n_vars, vars, rhs); } app_ref util::mk_depth_limit_pred(unsigned d) { @@ -361,11 +352,11 @@ namespace recfun { }; // set definition - void promise_def::set_definition(unsigned n_vars, var * const * vars, expr * rhs) { + void promise_def::set_definition(replace& r, unsigned n_vars, var * const * vars, expr * rhs) { SASSERT(n_vars == d->get_arity()); is_imm_pred is_i(*u); - d->compute_cases(is_i, u->get_th_rewriter(), n_vars, vars, rhs); + d->compute_cases(r, is_i, n_vars, vars, rhs); } namespace decl { @@ -398,8 +389,8 @@ namespace recfun { return promise_def(&u(), d); } - void plugin::set_definition(promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) { - u().set_definition(d, n_vars, vars, rhs); + void plugin::set_definition(replace& r, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) { + u().set_definition(r, d, n_vars, vars, rhs); for (case_def & c : d.get_def()->get_cases()) { m_case_defs.insert(c.get_decl(), &c); } @@ -409,11 +400,12 @@ namespace recfun { return !m_case_defs.empty(); } - def* plugin::mk_def(symbol const& name, unsigned n, sort ** params, sort * range, + def* plugin::mk_def(replace& subst, + symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs) { promise_def d = mk_def(name, n, params, range); SASSERT(! m_defs.contains(d.get_def()->get_decl())); - set_definition(d, n_vars, vars, rhs); + set_definition(subst, d, n_vars, vars, rhs); return d.get_def(); } diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index 347689a37..0247335e8 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -20,7 +20,6 @@ Revision History: #pragma once #include "ast/ast.h" -#include "ast/rewriter/th_rewriter.h" #include "util/obj_hashtable.h" namespace recfun { @@ -46,6 +45,13 @@ namespace recfun { typedef var_ref_vector vars; + class replace { + public: + virtual void reset() = 0; + virtual void insert(expr* d, expr* r) = 0; + virtual expr_ref operator()(expr* e) = 0; + }; + class case_def { friend class def; func_decl_ref m_pred; // Date: Thu, 1 Nov 2018 09:40:19 -0500 Subject: [PATCH 117/227] add missing override Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/expr_safe_replace.cpp | 1 + src/ast/rewriter/expr_safe_replace.h | 1 - src/ast/rewriter/recfun_replace.h | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index e99568961..c2efb520d 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -19,6 +19,7 @@ Revision History: --*/ #include "ast/rewriter/expr_safe_replace.h" +#include "ast/rewriter/var_subst.h" #include "ast/ast_pp.h" diff --git a/src/ast/rewriter/expr_safe_replace.h b/src/ast/rewriter/expr_safe_replace.h index 3c7be4742..fb66661af 100644 --- a/src/ast/rewriter/expr_safe_replace.h +++ b/src/ast/rewriter/expr_safe_replace.h @@ -23,7 +23,6 @@ Revision History: #define EXPR_SAFE_REPLACE_H_ #include "ast/ast.h" -#include "ast/rewriter/var_subst.h" class expr_safe_replace { ast_manager& m; diff --git a/src/ast/rewriter/recfun_replace.h b/src/ast/rewriter/recfun_replace.h index 78dd0ee56..5a24e8513 100644 --- a/src/ast/rewriter/recfun_replace.h +++ b/src/ast/rewriter/recfun_replace.h @@ -34,8 +34,8 @@ class recfun_replace : public recfun::replace { public: recfun_replace(ast_manager& m): m(m), m_replace(m) {} void reset() override { m_replace.reset(); } - void insert(expr* s, expr* t) { m_replace.insert(s, t); } - expr_ref operator()(expr* e) { expr_ref r(m); m_replace(e, r); return r; } + void insert(expr* s, expr* t) override { m_replace.insert(s, t); } + expr_ref operator()(expr* e) override { expr_ref r(m); m_replace(e, r); return r; } }; #endif /* RECFUN_REPLACE_H_ */ From d9e77ba443aae56a60d0f2d6e7ea33ff032dd7b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Nov 2018 09:55:27 -0500 Subject: [PATCH 118/227] fix model extraction for 0-ary recursive function declarations Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 83ff79d3c..6e132ff71 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4460,6 +4460,11 @@ namespace smt { auto& def = u.get_def(f); expr* rhs = def.get_rhs(); if (!rhs) continue; + if (f->get_arity() == 0) { + m_model->register_decl(f, rhs); + continue; + } + func_interp* fi = alloc(func_interp, m, f->get_arity()); // reverse argument order so that variable 0 starts at the beginning. expr_ref_vector subst(m); From cf4bf7b591b6657e3d361b6175b4c9a4b4ced4ae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Nov 2018 18:44:53 -0500 Subject: [PATCH 119/227] more consistent use of parallel mode when enabled, takes care of example test from #1898 that didn't trigger parallel mode Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/sat_tactic.cpp | 4 +-- src/smt/tactic/smt_tactic.cpp | 31 ++++++++++--------- src/smt/tactic/smt_tactic.h | 8 ++--- src/tactic/fd_solver/fd_solver.cpp | 13 ++++++-- src/tactic/fpa/qffp_tactic.cpp | 4 +-- src/tactic/portfolio/default_tactic.cpp | 2 +- src/tactic/portfolio/smt_strategic_solver.cpp | 6 +++- src/tactic/smtlogics/nra_tactic.cpp | 2 +- src/tactic/smtlogics/qfaufbv_tactic.cpp | 2 +- src/tactic/smtlogics/qfauflia_tactic.cpp | 2 +- src/tactic/smtlogics/qfbv_tactic.cpp | 4 +-- src/tactic/smtlogics/qfidl_tactic.cpp | 4 +-- src/tactic/smtlogics/qflia_tactic.cpp | 20 ++++++------ src/tactic/smtlogics/qflra_tactic.cpp | 4 +-- src/tactic/smtlogics/qfnia_tactic.cpp | 2 +- src/tactic/smtlogics/qfnra_tactic.cpp | 4 +-- src/tactic/smtlogics/qfuf_tactic.cpp | 2 +- src/tactic/smtlogics/qfufbv_tactic.cpp | 4 +-- src/tactic/smtlogics/quant_tactics.cpp | 18 +++++------ src/tactic/ufbv/ufbv_tactic.cpp | 2 +- 20 files changed, 73 insertions(+), 65 deletions(-) diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 149a4e853..ef8a9e77e 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -17,12 +17,10 @@ Notes: --*/ #include "ast/ast_pp.h" +#include "model/model_v2_pp.h" #include "tactic/tactical.h" #include "sat/tactic/goal2sat.h" #include "sat/sat_solver.h" -#include "solver/parallel_tactic.h" -#include "solver/parallel_params.hpp" -#include "model/model_v2_pp.h" class sat_tactic : public tactic { diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 6aa365383..730061c8b 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -289,30 +289,31 @@ public: } }; -tactic * mk_smt_tactic(params_ref const & p) { +static tactic * mk_seq_smt_tactic(params_ref const & p) { return alloc(smt_tactic, p); } -tactic * mk_smt_tactic_using(bool auto_config, params_ref const & _p) { +static tactic * mk_seq_smt_tactic_using(bool auto_config, params_ref const & _p) { params_ref p = _p; p.set_bool("auto_config", auto_config); - tactic * r = mk_smt_tactic(p); + tactic * r = mk_seq_smt_tactic(p); TRACE("smt_tactic", tout << "auto_config: " << auto_config << "\nr: " << r << "\np: " << p << "\n";); return using_params(r, p); } -tactic * mk_psmt_tactic(ast_manager& m, params_ref const& p, symbol const& logic) { - parallel_params pp(p); - return pp.enable() ? mk_parallel_tactic(mk_smt_solver(m, p, logic), p) : mk_smt_tactic(p); -} - -tactic * mk_psmt_tactic_using(ast_manager& m, bool auto_config, params_ref const& _p, symbol const& logic) { - parallel_params pp(_p); - params_ref p = _p; - p.set_bool("auto_config", auto_config); - return using_params(pp.enable() ? mk_parallel_tactic(mk_smt_solver(m, p, logic), p) : mk_smt_tactic(p), p); -} - tactic * mk_parallel_smt_tactic(ast_manager& m, params_ref const& p) { return mk_parallel_tactic(mk_smt_solver(m, p, symbol::null), p); } + +tactic * mk_smt_tactic(ast_manager& m, params_ref const& p, symbol const& logic) { + parallel_params pp(p); + return pp.enable() ? mk_parallel_tactic(mk_smt_solver(m, p, logic), p) : mk_seq_smt_tactic(p); +} + +tactic * mk_smt_tactic_using(ast_manager& m, bool auto_config, params_ref const& _p) { + parallel_params pp(_p); + params_ref p = _p; + p.set_bool("auto_config", auto_config); + return using_params(pp.enable() ? mk_parallel_smt_tactic(m, p) : mk_seq_smt_tactic(p), p); +} + diff --git a/src/smt/tactic/smt_tactic.h b/src/smt/tactic/smt_tactic.h index fbee950c2..733413bb2 100644 --- a/src/smt/tactic/smt_tactic.h +++ b/src/smt/tactic/smt_tactic.h @@ -27,17 +27,15 @@ Notes: class tactic; class filter_model_converter; -tactic * mk_smt_tactic(params_ref const & p = params_ref()); +tactic * mk_smt_tactic(ast_manager& m, params_ref const & p = params_ref(), symbol const& logic = symbol::null); // syntax sugar for using_params(mk_smt_tactic(), p) where p = (:auto_config, auto_config) -tactic * mk_smt_tactic_using(bool auto_config = true, params_ref const & p = params_ref()); +tactic * mk_smt_tactic_using(ast_manager& m, bool auto_config = true, params_ref const & p = params_ref()); -tactic * mk_psmt_tactic(ast_manager& m, params_ref const& p, symbol const& logic = symbol::null); -tactic * mk_psmt_tactic_using(ast_manager& m, bool auto_config, params_ref const& p, symbol const& logic = symbol::null); tactic * mk_parallel_smt_tactic(ast_manager& m, params_ref const& p); /* - ADD_TACTIC("smt", "apply a SAT based SMT solver.", "mk_smt_tactic(p)") + ADD_TACTIC("smt", "apply a SAT based SMT solver.", "mk_smt_tactic(m, p)") ADD_TACTIC("psmt", "builtin strategy for SMT tactic in parallel.", "mk_parallel_smt_tactic(m, p)") */ #endif diff --git a/src/tactic/fd_solver/fd_solver.cpp b/src/tactic/fd_solver/fd_solver.cpp index 2af30b089..8e32b74d0 100644 --- a/src/tactic/fd_solver/fd_solver.cpp +++ b/src/tactic/fd_solver/fd_solver.cpp @@ -35,11 +35,18 @@ solver * mk_fd_solver(ast_manager & m, params_ref const & p, bool incremental_mo return s; } -tactic * mk_fd_tactic(ast_manager & m, params_ref const& p) { +static tactic * mk_seq_fd_tactic(ast_manager & m, params_ref const& p) { return mk_solver2tactic(mk_fd_solver(m, p, false)); } tactic * mk_parallel_qffd_tactic(ast_manager& m, params_ref const& p) { - solver* s = mk_fd_solver(m, p); - return mk_parallel_tactic(s, p); + return mk_parallel_tactic(mk_fd_solver(m, p), p); } + + +tactic * mk_fd_tactic(ast_manager & m, params_ref const& _p) { + parallel_params pp(_p); + params_ref p = _p; + return pp.enable() ? mk_parallel_qffd_tactic(m, p) : mk_seq_fd_tactic(m, p); +} + diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp index 1c48fef38..9f4f1b604 100644 --- a/src/tactic/fpa/qffp_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -94,11 +94,11 @@ tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { using_params(mk_simplify_tactic(m, p), simp_p), cond(mk_is_propositional_probe(), cond(mk_produce_proofs_probe(), - mk_smt_tactic(p), // `sat' does not support proofs. + mk_smt_tactic(m, p), // `sat' does not support proofs. mk_sat_tactic(m, p)), cond(mk_is_fp_qfnra_probe(), mk_qfnra_tactic(m, p), - mk_smt_tactic(p)))); + mk_smt_tactic(m, p)))); st->updt_params(p); return st; diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 3e479524e..23334bf07 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -48,7 +48,7 @@ tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { cond(mk_is_qffp_probe(), mk_qffp_tactic(m, p), cond(mk_is_qffplra_probe(), mk_qffplra_tactic(m, p), //cond(mk_is_qfufnra_probe(), mk_qfufnra_tactic(m, p), - mk_smt_tactic()))))))))))))), + mk_smt_tactic(m)))))))))))))), p); return st; } diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 6718eb13f..fee3bed77 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -41,6 +41,9 @@ Notes: #include "sat/sat_solver/inc_sat_solver.h" #include "ast/rewriter/bv_rewriter.h" #include "solver/solver2tactic.h" +#include "solver/parallel_tactic.h" +#include "solver/parallel_params.hpp" + tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const & logic) { @@ -99,7 +102,8 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const } static solver* mk_special_solver_for_logic(ast_manager & m, params_ref const & p, symbol const& logic) { - if ((logic == "QF_FD" || logic == "SAT") && !m.proofs_enabled()) + parallel_params pp(p); + if ((logic == "QF_FD" || logic == "SAT") && !m.proofs_enabled() && !pp.enable()) return mk_fd_solver(m, p); return nullptr; } diff --git a/src/tactic/smtlogics/nra_tactic.cpp b/src/tactic/smtlogics/nra_tactic.cpp index a9b32e5a8..8aefad0a0 100644 --- a/src/tactic/smtlogics/nra_tactic.cpp +++ b/src/tactic/smtlogics/nra_tactic.cpp @@ -44,7 +44,7 @@ tactic * mk_nra_tactic(ast_manager & m, params_ref const& p) { try_for(mk_qfnra_nlsat_tactic(m, p1), 10000), mk_qfnra_nlsat_tactic(m, p2)), or_else(mk_nlqsat_tactic(m, p), - mk_smt_tactic(p)) + mk_smt_tactic(m, p)) )); } diff --git a/src/tactic/smtlogics/qfaufbv_tactic.cpp b/src/tactic/smtlogics/qfaufbv_tactic.cpp index 601f872aa..b35bc1f20 100644 --- a/src/tactic/smtlogics/qfaufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfaufbv_tactic.cpp @@ -57,7 +57,7 @@ tactic * mk_qfaufbv_tactic(ast_manager & m, params_ref const & p) { ); tactic * st = using_params(and_then(preamble_st, - using_params(mk_smt_tactic(), solver_p)), + using_params(mk_smt_tactic(m), solver_p)), main_p); st->updt_params(p); diff --git a/src/tactic/smtlogics/qfauflia_tactic.cpp b/src/tactic/smtlogics/qfauflia_tactic.cpp index 4a0e9eb34..206914a0f 100644 --- a/src/tactic/smtlogics/qfauflia_tactic.cpp +++ b/src/tactic/smtlogics/qfauflia_tactic.cpp @@ -45,7 +45,7 @@ tactic * mk_qfauflia_tactic(ast_manager & m, params_ref const & p) { ); tactic * st = and_then(using_params(preamble_st, main_p), - using_params(mk_smt_tactic(), solver_p)); + using_params(mk_smt_tactic(m), solver_p)); st->updt_params(p); return st; diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index 7c410e721..11d05cde6 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -121,9 +121,9 @@ static tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { tactic * new_sat = cond(mk_produce_proofs_probe(), - and_then(mk_simplify_tactic(m), mk_smt_tactic()), + and_then(mk_simplify_tactic(m), mk_smt_tactic(m)), mk_psat_tactic(m, p)); - return mk_qfbv_tactic(m, p, new_sat, mk_psmt_tactic(m, p)); + return mk_qfbv_tactic(m, p, new_sat, mk_smt_tactic(m, p)); } diff --git a/src/tactic/smtlogics/qfidl_tactic.cpp b/src/tactic/smtlogics/qfidl_tactic.cpp index a34a25e67..109089c2e 100644 --- a/src/tactic/smtlogics/qfidl_tactic.cpp +++ b/src/tactic/smtlogics/qfidl_tactic.cpp @@ -101,9 +101,9 @@ tactic * mk_qfidl_tactic(ast_manager & m, params_ref const & p) { using_params(and_then(preamble_st, or_else(using_params(mk_diff_neq_tactic(m), diff_neq_p), try2bv, - mk_smt_tactic())), + mk_smt_tactic(m))), main_p), - mk_smt_tactic()); + mk_smt_tactic(m)); st->updt_params(p); diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index eed4e4425..d2fcc922d 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -58,21 +58,21 @@ probe * mk_is_quasi_pb_probe() { } // Create SMT solver that does not use cuts -static tactic * mk_no_cut_smt_tactic(unsigned rs) { +static tactic * mk_no_cut_smt_tactic(ast_manager& m, unsigned rs) { params_ref solver_p; solver_p.set_sym(symbol("smt.logic"), symbol("QF_LIA")); // force smt_setup to use the new solver solver_p.set_uint("arith.branch_cut_ratio", 10000000); solver_p.set_uint("random_seed", rs); - return annotate_tactic("no-cut-smt-tactic", using_params(mk_smt_tactic_using(false), solver_p)); + return annotate_tactic("no-cut-smt-tactic", using_params(mk_smt_tactic_using(m, false), solver_p)); } // Create SMT solver that does not use cuts -static tactic * mk_no_cut_no_relevancy_smt_tactic(unsigned rs) { +static tactic * mk_no_cut_no_relevancy_smt_tactic(ast_manager& m, unsigned rs) { params_ref solver_p; solver_p.set_uint("arith.branch_cut_ratio", 10000000); solver_p.set_uint("random_seed", rs); solver_p.set_uint("relevancy", 0); - return annotate_tactic("no-cut-relevancy-tactic", using_params(mk_smt_tactic_using(false), solver_p)); + return annotate_tactic("no-cut-relevancy-tactic", using_params(mk_smt_tactic_using(m, false), solver_p)); } static tactic * mk_bv2sat_tactic(ast_manager & m) { @@ -155,10 +155,10 @@ static tactic * mk_ilp_model_finder_tactic(ast_manager & m) { fail_if(mk_produce_unsat_cores_probe()), mk_propagate_ineqs_tactic(m), or_else(// try_for(mk_mip_tactic(m), 5000), - try_for(mk_no_cut_smt_tactic(100), 2000), + try_for(mk_no_cut_smt_tactic(m, 100), 2000), and_then(using_params(mk_add_bounds_tactic(m), add_bounds_p1), try_for(mk_lia2sat_tactic(m), 5000)), - try_for(mk_no_cut_smt_tactic(200), 5000), + try_for(mk_no_cut_smt_tactic(m, 200), 5000), and_then(using_params(mk_add_bounds_tactic(m), add_bounds_p2), try_for(mk_lia2sat_tactic(m), 10000)) // , mk_mip_tactic(m) @@ -170,9 +170,9 @@ static tactic * mk_bounded_tactic(ast_manager & m) { return annotate_tactic( "bounded-tactic", and_then(fail_if(mk_is_unbounded_probe()), - or_else(try_for(mk_no_cut_smt_tactic(100), 5000), - try_for(mk_no_cut_no_relevancy_smt_tactic(200), 5000), - try_for(mk_no_cut_smt_tactic(300), 15000) + or_else(try_for(mk_no_cut_smt_tactic(m, 100), 5000), + try_for(mk_no_cut_no_relevancy_smt_tactic(m, 200), 5000), + try_for(mk_no_cut_smt_tactic(m, 300), 15000) ), mk_fail_if_undecided_tactic())); } @@ -218,7 +218,7 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) { using_params(mk_lia2sat_tactic(m), quasi_pb_p), mk_fail_if_undecided_tactic()), mk_bounded_tactic(m), - mk_smt_tactic())), + mk_smt_tactic(m))), main_p); diff --git a/src/tactic/smtlogics/qflra_tactic.cpp b/src/tactic/smtlogics/qflra_tactic.cpp index b44ace7b1..90532cef6 100644 --- a/src/tactic/smtlogics/qflra_tactic.cpp +++ b/src/tactic/smtlogics/qflra_tactic.cpp @@ -68,7 +68,7 @@ tactic * mk_qflra_tactic(ast_manager & m, params_ref const & p) { #endif // return using_params(or_else(mip, - // using_params(mk_smt_tactic(), pivot_p)), + // using_params(mk_smt_tactic(m), pivot_p)), // p); #if 0 @@ -82,7 +82,7 @@ tactic * mk_qflra_tactic(ast_manager & m, params_ref const & p) { using_params(mk_smt_tactic(), simplex_1), using_params(mk_smt_tactic(), simplex_2)); #else - return using_params(using_params(mk_smt_tactic(), pivot_p), p); + return using_params(using_params(mk_smt_tactic(m), pivot_p), p); #endif } diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index b92e08006..02e3349aa 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -105,7 +105,7 @@ static tactic * mk_qfnia_nlsat_solver(ast_manager & m, params_ref const & p) { static tactic * mk_qfnia_smt_solver(ast_manager& m, params_ref const& p) { params_ref simp_p = p; simp_p.set_bool("som", true); // expand into sums of monomials - return and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic()); + return and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic(m)); } tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { diff --git a/src/tactic/smtlogics/qfnra_tactic.cpp b/src/tactic/smtlogics/qfnra_tactic.cpp index cc01950a2..7d93abe25 100644 --- a/src/tactic/smtlogics/qfnra_tactic.cpp +++ b/src/tactic/smtlogics/qfnra_tactic.cpp @@ -28,7 +28,7 @@ static tactic * mk_qfnra_sat_solver(ast_manager& m, params_ref const& p, unsigne nra2sat_p.set_uint("nla2bv_max_bv_size", p.get_uint("nla2bv_max_bv_size", bv_size)); return and_then(mk_nla2bv_tactic(m, nra2sat_p), - mk_smt_tactic(), + mk_smt_tactic(m), mk_fail_if_undecided_tactic()); } @@ -47,7 +47,7 @@ tactic * mk_qfnra_tactic(ast_manager & m, params_ref const& p) { or_else(try_for(mk_qfnra_nlsat_tactic(m, p0), 5000), try_for(mk_qfnra_nlsat_tactic(m, p1), 10000), mk_qfnra_sat_solver(m, p, 4), - and_then(try_for(mk_smt_tactic(), 5000), mk_fail_if_undecided_tactic()), + and_then(try_for(mk_smt_tactic(m), 5000), mk_fail_if_undecided_tactic()), mk_qfnra_sat_solver(m, p, 6), mk_qfnra_nlsat_tactic(m, p2))); } diff --git a/src/tactic/smtlogics/qfuf_tactic.cpp b/src/tactic/smtlogics/qfuf_tactic.cpp index 2de9612c6..6af75b13f 100644 --- a/src/tactic/smtlogics/qfuf_tactic.cpp +++ b/src/tactic/smtlogics/qfuf_tactic.cpp @@ -34,7 +34,7 @@ tactic * mk_qfuf_tactic(ast_manager & m, params_ref const & p) { mk_solve_eqs_tactic(m, p), using_params(mk_simplify_tactic(m, p), s2_p), if_no_proofs(if_no_unsat_cores(mk_symmetry_reduce_tactic(m, p))), - mk_smt_tactic(p)); + mk_smt_tactic(m, p)); } diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index a4e169856..38eaa25fb 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -176,7 +176,7 @@ tactic * mk_qfufbv_tactic(ast_manager & m, params_ref const & p) { tactic * const preamble_st = mk_qfufbv_preamble(m, p); tactic * st = using_params(and_then(preamble_st, - cond(mk_is_qfbv_probe(), mk_qfbv_tactic(m), mk_smt_tactic())), + cond(mk_is_qfbv_probe(), mk_qfbv_tactic(m), mk_smt_tactic(m))), main_p); st->updt_params(p); @@ -188,5 +188,5 @@ tactic * mk_qfufbv_ackr_tactic(ast_manager & m, params_ref const & p) { tactic * const actual_tactic = alloc(qfufbv_ackr_tactic, m, p); return and_then(preamble_t, - cond(mk_is_qfufbv_probe(), actual_tactic, mk_smt_tactic())); + cond(mk_is_qfufbv_probe(), actual_tactic, mk_smt_tactic(m))); } diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index 8438d1a32..910a5d53c 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -64,14 +64,14 @@ static tactic * mk_no_solve_eq_preprocessor(ast_manager & m) { tactic * mk_ufnia_tactic(ast_manager & m, params_ref const & p) { tactic * st = and_then(mk_no_solve_eq_preprocessor(m), mk_qe_lite_tactic(m, p), - mk_smt_tactic()); + mk_smt_tactic(m)); st->updt_params(p); return st; } tactic * mk_uflra_tactic(ast_manager & m, params_ref const & p) { tactic * st = and_then(mk_quant_preprocessor(m), - mk_smt_tactic()); + mk_smt_tactic(m)); st->updt_params(p); return st; } @@ -82,23 +82,23 @@ tactic * mk_auflia_tactic(ast_manager & m, params_ref const & p) { TRACE("qi_cost", qi_p.display(tout); tout << "\n" << qi_p.get_str("qi.cost", "") << "\n";); tactic * st = and_then(mk_no_solve_eq_preprocessor(m), or_else(and_then(fail_if(mk_gt(mk_num_exprs_probe(), mk_const_probe(static_cast(128)))), - using_params(mk_smt_tactic(), qi_p), + using_params(mk_smt_tactic(m), qi_p), mk_fail_if_undecided_tactic()), - mk_smt_tactic())); + mk_smt_tactic(m))); st->updt_params(p); return st; } tactic * mk_auflira_tactic(ast_manager & m, params_ref const & p) { tactic * st = and_then(mk_quant_preprocessor(m), - mk_smt_tactic()); + mk_smt_tactic(m)); st->updt_params(p); return st; } tactic * mk_aufnira_tactic(ast_manager & m, params_ref const & p) { tactic * st = and_then(mk_quant_preprocessor(m), - mk_smt_tactic()); + mk_smt_tactic(m)); st->updt_params(p); return st; } @@ -109,9 +109,9 @@ tactic * mk_lra_tactic(ast_manager & m, params_ref const & p) { cond(mk_has_quantifier_probe(), cond(mk_is_lira_probe(), or_else(mk_qsat_tactic(m, p), - and_then(mk_qe_tactic(m), mk_smt_tactic())), - mk_smt_tactic()), - mk_smt_tactic())); + and_then(mk_qe_tactic(m), mk_smt_tactic(m))), + mk_smt_tactic(m)), + mk_smt_tactic(m))); st->updt_params(p); return st; } diff --git a/src/tactic/ufbv/ufbv_tactic.cpp b/src/tactic/ufbv/ufbv_tactic.cpp index 1fb4486ec..09b2bd00c 100644 --- a/src/tactic/ufbv/ufbv_tactic.cpp +++ b/src/tactic/ufbv/ufbv_tactic.cpp @@ -67,7 +67,7 @@ tactic * mk_ufbv_tactic(ast_manager & m, params_ref const & p) { main_p.set_bool("elim_and", true); tactic * t = and_then(repeat(mk_ufbv_preprocessor_tactic(m, main_p), 2), - mk_smt_tactic_using(false, main_p)); + mk_smt_tactic_using(m, false, main_p)); t->updt_params(p); From f699ac0353a57cdd0622b0071babfbfad7b8463a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Nov 2018 13:54:23 -0800 Subject: [PATCH 120/227] fixing bugs uncovered by repro in #1914 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 6 +++--- src/smt/theory_arith_aux.h | 12 ++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 70ce6b397..384b44de7 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -541,9 +541,9 @@ namespace smt { bool process_atoms() const; unsigned get_num_conflicts() const { return m_num_conflicts; } var_kind get_var_kind(theory_var v) const { return m_data[v].kind(); } - bool is_base(theory_var v) const { return get_var_kind(v) == BASE; } - bool is_quasi_base(theory_var v) const { return get_var_kind(v) == QUASI_BASE; } - bool is_non_base(theory_var v) const { return get_var_kind(v) == NON_BASE; } + bool is_base(theory_var v) const { return v != null_theory_var && get_var_kind(v) == BASE; } + bool is_quasi_base(theory_var v) const { return v != null_theory_var && get_var_kind(v) == QUASI_BASE; } + bool is_non_base(theory_var v) const { return v != null_theory_var && get_var_kind(v) == NON_BASE; } void set_var_kind(theory_var v, var_kind k) { m_data[v].m_kind = k; } unsigned get_var_row(theory_var v) const { SASSERT(!is_non_base(v)); return m_data[v].m_row_id; } void set_var_row(theory_var v, unsigned r_id) { m_data[v].m_row_id = r_id; } diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 9561aa089..f70e50ece 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -491,13 +491,21 @@ namespace smt { if (!it->is_dead()) { unsigned rid = it->m_row_id; row & r = m_rows[rid]; - if (is_base(r.get_base_var())) + theory_var v = r.get_base_var(); + if (v == null_theory_var) { + // skip + } + else if (is_base(v)) { return it; + } else if (quasi_base_rid == -1) quasi_base_rid = rid; } } - SASSERT(quasi_base_rid != -1); // since c.size() != 0 + if (quasi_base_rid == -1) { + return nullptr; + } + quasi_base_row2base_row(quasi_base_rid); // There is no guarantee that v is still a variable of row quasi_base_rid. From 4c4ca7d3b8222f3f061ef38591d384f3d189efca Mon Sep 17 00:00:00 2001 From: Andrei Sebastian BURUIANA Date: Tue, 6 Nov 2018 13:41:18 +0200 Subject: [PATCH 121/227] fixed documentation of Z3_param_descrs_get_name --- src/api/z3_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index a776bbe8e..a903ba9cb 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1715,7 +1715,7 @@ extern "C" { unsigned Z3_API Z3_param_descrs_size(Z3_context c, Z3_param_descrs p); /** - \brief Return the number of parameters in the given parameter description set. + \brief Return the name of the parameter at index \c i. \pre i < Z3_param_descrs_size(c, p) From 83aa2ab39d6126b85d202b3dab2f9bfe33b3600d Mon Sep 17 00:00:00 2001 From: Andrei Sebastian BURUIANA Date: Tue, 6 Nov 2018 13:50:52 +0200 Subject: [PATCH 122/227] fixed documentation of Z3_param_descrs_get_name --- src/api/z3_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index a903ba9cb..e1359949d 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1715,7 +1715,7 @@ extern "C" { unsigned Z3_API Z3_param_descrs_size(Z3_context c, Z3_param_descrs p); /** - \brief Return the name of the parameter at index \c i. + \brief Return the name of the parameter at given index \c i. \pre i < Z3_param_descrs_size(c, p) From 1a030bb7229d5ac8772b3daa9bb91a1afc56a4cb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Nov 2018 07:50:05 -0800 Subject: [PATCH 123/227] add missing inline fix #1917 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index d360b6153..edc724160 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2847,7 +2847,7 @@ namespace z3 { return recfun(str_symbol(name), 2, dom, range); } - void context::recdef(func_decl f, expr_vector const& args, expr const& body) { + inline void context::recdef(func_decl f, expr_vector const& args, expr const& body) { check_context(f, args); check_context(f, body); array vars(args); Z3_add_rec_def(f.ctx(), f, vars.size(), vars.ptr(), body); From 9121c74c9fd8e0832fec72498d53673a157ac2b0 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 6 Nov 2018 13:44:57 -0600 Subject: [PATCH 124/227] feat(api/ml): release runtime lock on some long-running functions --- scripts/update_api.py | 15 +++++++++++++++ src/api/ml/META.in | 2 +- src/api/ml/z3native_stubs.c.pre | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 917df94a2..87bdd3551 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1328,6 +1328,13 @@ def mk_ml(ml_src_dir, ml_output_dir): mk_z3native_stubs_c(ml_src_dir, ml_output_dir) +z3_long_funs = frozenset([ + 'Z3_solver_check', + 'Z3_solver_check_assumptions', + 'Z3_simplify', + 'Z3_simplify_ex', + ]) + def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface ml_wrapperf = os.path.join(ml_output_dir, 'z3native_stubs.c') ml_wrapper = open(ml_wrapperf, 'w') @@ -1491,6 +1498,10 @@ def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface ml_wrapper.write(' assert(_iter == Val_emptylist);\n\n') i = i + 1 + release_caml_gc= name in z3_long_funs + if release_caml_gc: + ml_wrapper.write('\n caml_release_runtime_system();\n') + ml_wrapper.write('\n /* invoke Z3 function */\n ') if result != VOID: ts = type2str(result) @@ -1499,6 +1510,7 @@ def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface else: ml_wrapper.write('z3rv = ') + # invoke procedure ml_wrapper.write('%s(' % name) i = 0 @@ -1516,6 +1528,9 @@ def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface i = i + 1 ml_wrapper.write(');\n') + if release_caml_gc: + ml_wrapper.write('\n caml_acquire_runtime_system();\n') + if have_context and name not in Unwrapped: ml_wrapper.write(' ec = Z3_get_error_code(ctx_p->ctx);\n') ml_wrapper.write(' if (ec != Z3_OK) {\n') diff --git a/src/api/ml/META.in b/src/api/ml/META.in index 1951e60b3..e58ebf722 100644 --- a/src/api/ml/META.in +++ b/src/api/ml/META.in @@ -1,7 +1,7 @@ # META file for the "z3" package: version = "@VERSION@" description = "Z3 Theorem Prover (OCaml API)" -requires = "num" +requires = "num threads" archive(byte) = "z3ml.cma" archive(native) = "z3ml.cmxa" archive(byte,plugin) = "z3ml.cma" diff --git a/src/api/ml/z3native_stubs.c.pre b/src/api/ml/z3native_stubs.c.pre index c1c772c85..71ee18ce9 100644 --- a/src/api/ml/z3native_stubs.c.pre +++ b/src/api/ml/z3native_stubs.c.pre @@ -11,6 +11,7 @@ extern "C" { #include #include #include +#include #ifdef Custom_tag #include From b02c69828419e792c67876f7beecfabe73196aac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Nov 2018 16:52:10 -0800 Subject: [PATCH 125/227] align variable names with dimacs input Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 4 ---- src/api/api_solver.cpp | 3 +++ src/ast/rewriter/seq_rewriter.cpp | 6 +++++- src/tactic/fpa/qffp_tactic.cpp | 13 +++++++------ 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 6372e87fc..08ff771e7 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1859,14 +1859,11 @@ class DotNetCoreDLLComponent(Component): if not is_dotnet_core_enabled(): return cs_fp_files = [] - cs_files = [] for cs_file in get_cs_files(self.src_dir): cs_fp_files.append(os.path.join(self.to_src_dir, cs_file)) - cs_files.append(cs_file) if self.assembly_info_dir != '.': for cs_file in get_cs_files(os.path.join(self.src_dir, self.assembly_info_dir)): cs_fp_files.append(os.path.join(self.to_src_dir, self.assembly_info_dir, cs_file)) - cs_files.append(os.path.join(self.assembly_info_dir, cs_file)) dllfile = '%s.dll' % self.dll_name out.write('%s: %s$(SO_EXT)' % (dllfile, get_component(Z3_DLL_COMPONENT).dll_name)) for cs_file in cs_fp_files: @@ -1874,7 +1871,6 @@ class DotNetCoreDLLComponent(Component): out.write(cs_file) out.write('\n') - # TBD: can this be replaced by running "dotnet new classlib"? csproj = os.path.join(self.to_src_dir, "core", "core.csproj") dotnetCmdLine = [DOTNET, "build", csproj] diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 204370346..cb4ae19db 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -188,6 +188,9 @@ extern "C" { sat2goal s2g; ref mc; atom2bool_var a2b(m); + for (unsigned v = 0; v < solver.num_vars(); ++v) { + a2b.insert(m.mk_const(symbol(v), m.mk_bool_sort()), v); + } goal g(m); s2g(solver, a2b, to_solver_ref(s)->get_params(), g, mc); for (unsigned i = 0; i < g.size(); ++i) { diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index e4ad3bb9d..dad485d94 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -844,6 +844,10 @@ br_status seq_rewriter::mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result return BR_FAILED; } +// (str.replace s t t') is the string obtained by replacing the first occurrence +// of t in s, if any, by t'. Note that if t is empty, the result is to prepend +// t' to s; also, if t does not occur in s then the result is s. + br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& result) { zstring s1, s2, s3; if (m_util.str.is_string(a, s1) && m_util.str.is_string(b, s2) && @@ -855,7 +859,7 @@ br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& resu result = a; return BR_DONE; } - if (m_util.str.is_string(b, s2) && s2.length() == 0) { + if (m_util.str.is_empty(b)) { result = m_util.str.mk_concat(c, a); return BR_REWRITE1; } diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp index 9f4f1b604..97f05c17b 100644 --- a/src/tactic/fpa/qffp_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -17,15 +17,16 @@ Notes: --*/ #include "tactic/tactical.h" -#include "tactic/core/simplify_tactic.h" -#include "tactic/bv/bit_blaster_tactic.h" -#include "sat/tactic/sat_tactic.h" #include "tactic/fpa/fpa2bv_tactic.h" -#include "smt/tactic/smt_tactic.h" +#include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" -#include "ackermannization/ackermannize_bv_tactic.h" #include "tactic/arith/probe_arith.h" +#include "tactic/bv/bit_blaster_tactic.h" #include "tactic/smtlogics/qfnra_tactic.h" +#include "sat/tactic/sat_tactic.h" +#include "sat/sat_solver/inc_sat_solver.h" +#include "smt/tactic/smt_tactic.h" +#include "ackermannization/ackermannize_bv_tactic.h" #include "tactic/fpa/qffp_tactic.h" @@ -95,7 +96,7 @@ tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { cond(mk_is_propositional_probe(), cond(mk_produce_proofs_probe(), mk_smt_tactic(m, p), // `sat' does not support proofs. - mk_sat_tactic(m, p)), + mk_psat_tactic(m, p)), cond(mk_is_fp_qfnra_probe(), mk_qfnra_tactic(m, p), mk_smt_tactic(m, p)))); From 2c8d9425686b32c73c28573cc3612a7e9a5c27b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Nov 2018 18:05:40 -0800 Subject: [PATCH 126/227] add error if library is not included #1924 Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 384e1d080..e226a275e 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -258,7 +258,7 @@ def cp_vs_runtime(x64): platform = "x86" vcdir = os.environ['VCINSTALLDIR'] path = '%sredist\\%s' % (vcdir, platform) - VS_RUNTIME_FILES = [] + vs_runtime_files = [] for root, dirs, files in os.walk(path): for filename in files: if fnmatch(filename, '*.dll'): @@ -266,10 +266,11 @@ def cp_vs_runtime(x64): if pat.match(filename): fname = os.path.join(root, filename) if not os.path.isdir(fname): - VS_RUNTIME_FILES.append(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(x64), 'bin') - for f in VS_RUNTIME_FILES: + for f in vs_runtime_files: shutil.copy(f, bin_dist_path) if is_verbose(): print("Copied '%s' to '%s'" % (f, bin_dist_path)) From d7ecaa2ebbb790cbe19bb8d57d2b0358e5ba7532 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Nov 2018 09:56:19 -0800 Subject: [PATCH 127/227] add stub for certificate #1926 --- src/muz/spacer/spacer_context.cpp | 4 ++++ src/muz/spacer/spacer_context.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 9a9043f2f..308b07d1a 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2366,6 +2366,10 @@ void context::updt_params() { } } +void context::display_certificate(std::ostream& out) const { + proof_ref pr = get_proof(); + out << pr; +} void context::reset() { diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 0d8b2daf6..8dd13cf63 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -1092,7 +1092,7 @@ public: void reset(); std::ostream& display(std::ostream& out) const; - void display_certificate(std::ostream& out) const {NOT_IMPLEMENTED_YET();} + void display_certificate(std::ostream& out) const; pob& get_root() const {return m_pob_queue.get_root();} void set_query(func_decl* q) {m_query_pred = q;} From 82e60ab17ad68d70eb3cdd5f6896dd5e9ecf68be Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Nov 2018 10:07:42 -0800 Subject: [PATCH 128/227] add exception handler for debugging #1925 Signed-off-by: Nikolaj Bjorner --- scripts/mk_genfile_common.py | 50 +++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index 7fa6d4041..4d32d9788 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -692,31 +692,35 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path): fout.write('#include "cmd_context/tactic_cmds.h"\n') fout.write('#include "cmd_context/cmd_context.h"\n') tactic_pat = re.compile('[ \t]*ADD_TACTIC\(.*\)') - probe_pat = re.compile('[ \t]*ADD_PROBE\(.*\)') + probe_pat = re.compile('[ \t]*ADD_PROBE\(.*\)') for h_file in sorted_headers_by_component(h_files_full_path): added_include = False - with open(h_file, 'r') as fin: - for line in fin: - if tactic_pat.match(line): - if not added_include: - added_include = True - fout.write('#include "%s"\n' % path_after_src(h_file)) - try: - eval(line.strip('\n '), eval_globals, None) - except Exception as e: - _logger.error("Failed processing ADD_TACTIC command at '{}'\n{}".format( - fullname, line)) - raise e - if probe_pat.match(line): - if not added_include: - added_include = True - fout.write('#include "%s"\n' % path_after_src(h_file)) - try: - eval(line.strip('\n '), eval_globals, None) - except Exception as e: - _logger.error("Failed processing ADD_PROBE command at '{}'\n{}".format( - fullname, line)) - raise e + try: + with open(h_file, 'r') as fin: + for line in fin: + if tactic_pat.match(line): + if not added_include: + added_include = True + fout.write('#include "%s"\n' % path_after_src(h_file)) + try: + eval(line.strip('\n '), eval_globals, None) + except Exception as e: + _logger.error("Failed processing ADD_TACTIC command at '{}'\n{}".format( + fullname, line)) + raise e + if probe_pat.match(line): + if not added_include: + added_include = True + fout.write('#include "%s"\n' % path_after_src(h_file)) + try: + eval(line.strip('\n '), eval_globals, None) + except Exception as e: + _logger.error("Failed processing ADD_PROBE command at '{}'\n{}".format( + fullname, line)) + raise e + except e: + _loggeer.error("Failed to read file {}\n".format(fullname)) + raise e # First pass will just generate the tactic factories fout.write('#define ADD_TACTIC_CMD(NAME, DESCR, CODE) ctx.insert(alloc(tactic_cmd, symbol(NAME), DESCR, [](ast_manager &m, const params_ref &p) { return CODE; }))\n') fout.write('#define ADD_PROBE(NAME, DESCR, PROBE) ctx.insert(alloc(probe_info, symbol(NAME), DESCR, PROBE))\n') From cea15c878050bc3fbff0118ed9268ca1911db111 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Nov 2018 10:13:05 -0800 Subject: [PATCH 129/227] use h_file not fullname in error message Signed-off-by: Nikolaj Bjorner --- scripts/mk_genfile_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index 4d32d9788..cc2550e44 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -719,7 +719,7 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path): fullname, line)) raise e except e: - _loggeer.error("Failed to read file {}\n".format(fullname)) + _loggeer.error("Failed to read file {}\n".format(h_file)) raise e # First pass will just generate the tactic factories fout.write('#define ADD_TACTIC_CMD(NAME, DESCR, CODE) ctx.insert(alloc(tactic_cmd, symbol(NAME), DESCR, [](ast_manager &m, const params_ref &p) { return CODE; }))\n') From a0007476051943b04034880516a36278f117929e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Nov 2018 14:13:43 -0800 Subject: [PATCH 130/227] fixing mk-win-dist to include redist #1924 Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index e226a275e..10bb5a6ef 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -257,11 +257,21 @@ def cp_vs_runtime(x64): else: platform = "x86" vcdir = os.environ['VCINSTALLDIR'] - path = '%sredist\\%s' % (vcdir, platform) + 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 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'): + 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) From 58d93d8907da066eefc6ff0fbd282c8de7594149 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 5 Sep 2018 10:36:25 -0400 Subject: [PATCH 131/227] Fix add external lemmas to solver even if use_bg_invs=false spacer.use_bg_invs controls how user-supplied invariants are used. However, the user expects them to be used independent of the option. --- src/muz/spacer/spacer_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 308b07d1a..fd16e99f6 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2507,7 +2507,7 @@ void context::add_cover(int level, func_decl* p, expr* property, bool bg) } void context::add_invariant (func_decl *p, expr *property) -{add_cover (infty_level(), p, property, true);} +{add_cover (infty_level(), p, property, use_bg_invs());} expr_ref context::get_reachable(func_decl *p) { pred_transformer* pt = nullptr; From 6cc6ffcde22d6894956b5adcb9e17d1ffdc49169 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sun, 11 Nov 2018 08:26:00 -0500 Subject: [PATCH 132/227] Fix display_certificate in spacer This is expected to work now (query q1 :print-certificate true) --- src/muz/spacer/spacer_context.cpp | 28 ++++++++++++++++------------ src/muz/spacer/spacer_context.h | 7 +++++-- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index fd16e99f6..bbb06f719 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2366,11 +2366,6 @@ void context::updt_params() { } } -void context::display_certificate(std::ostream& out) const { - proof_ref pr = get_proof(); - out << pr; -} - void context::reset() { TRACE("spacer", tout << "\n";); @@ -2747,7 +2742,7 @@ lbool context::solve(unsigned from_lvl) if (m_last_result == l_true) { m_stats.m_cex_depth = get_cex_depth (); } - + if (m_params.print_statistics ()) { statistics st; collect_statistics (st); @@ -2931,10 +2926,6 @@ expr_ref context::get_answer() } } -/** - \brief Retrieve satisfying assignment with explanation. -*/ -expr_ref context::mk_sat_answer() {return get_ground_sat_answer();} expr_ref context::mk_unsat_answer() const @@ -2957,8 +2948,7 @@ proof_ref context::get_ground_refutation() { ground_sat_answer_op op(*this); return op(*m_query); } -expr_ref context::get_ground_sat_answer() -{ +expr_ref context::get_ground_sat_answer() const { if (m_last_result != l_true) { IF_VERBOSE(0, verbose_stream() << "Sat answer unavailable when result is false\n";); @@ -3086,6 +3076,20 @@ expr_ref context::get_ground_sat_answer() return expr_ref(m.mk_and(cex.size(), cex.c_ptr()), m); } +void context::display_certificate(std::ostream &out) const { + switch(m_last_result) { + case l_false: + out << mk_pp(mk_unsat_answer(), m); + break; + case l_true: + out << mk_pp(mk_sat_answer(), m); + break; + case l_undef: + out << "unknown"; + break; + } +} + ///this is where everything starts lbool context::solve_core (unsigned from_lvl) { diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 8dd13cf63..494de1c23 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -1007,7 +1007,10 @@ class context { const vector& reach_pred_used, pob_ref_buffer &out); - expr_ref mk_sat_answer(); + /** + \brief Retrieve satisfying assignment with explanation. + */ + expr_ref mk_sat_answer() const {return get_ground_sat_answer();} expr_ref mk_unsat_answer() const; unsigned get_cex_depth (); @@ -1083,7 +1086,7 @@ public: * get bottom-up (from query) sequence of ground predicate instances * (for e.g. P(0,1,0,0,3)) that together form a ground derivation to query */ - expr_ref get_ground_sat_answer (); + expr_ref get_ground_sat_answer () const; proof_ref get_ground_refutation(); void get_rules_along_trace (datalog::rule_ref_vector& rules); From d4e476d764692927929a3c98d4b03236f82bc62d Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sun, 11 Nov 2018 09:06:36 -0500 Subject: [PATCH 133/227] Work around unexpected behaviour in generalizer --- src/muz/spacer/spacer_generalizers.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 6f9758337..9d2c00c33 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -107,8 +107,7 @@ void lemma_bool_inductive_generalizer::operator()(lemma_ref &lemma) { expand_literals(m, extra_lits); SASSERT(extra_lits.size() > 0); bool found = false; - if (extra_lits.get(0) != lit) { - SASSERT(extra_lits.size() > 1); + if (extra_lits.get(0) != lit && extra_lits.size() > 1) { for (unsigned j = 0, sz = extra_lits.size(); !found && j < sz; ++j) { cube[i] = extra_lits.get(j); if (pt.check_inductive(lemma->level(), cube, uses_level, weakness)) { From 1082fad27a5fb5e369902b049481664195af0c09 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 11 Nov 2018 22:21:43 +0700 Subject: [PATCH 134/227] Fix typos. --- src/ast/csp_decl_plugin.cpp | 4 ++-- src/muz/rel/dl_relation_manager.h | 4 ++-- src/smt/theory_jobscheduler.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ast/csp_decl_plugin.cpp b/src/ast/csp_decl_plugin.cpp index 21cd798b2..154bbfbc3 100644 --- a/src/ast/csp_decl_plugin.cpp +++ b/src/ast/csp_decl_plugin.cpp @@ -104,7 +104,7 @@ func_decl * csp_decl_plugin::mk_func_decl( if (domain[2] != m_int_sort) m_manager->raise_exception("3rd argument of add-job-resource expects should be an integer"); if (domain[3] != m_int_sort) m_manager->raise_exception("4th argument of add-job-resource expects should be an integer"); if (domain[4] != m_int_sort) m_manager->raise_exception("5th argument of add-job-resource expects should be an integer"); - if (domain[5] != m_alist_sort) m_manager->raise_exception("6th argument of add-job-resource should be an a list of properties"); + if (domain[5] != m_alist_sort) m_manager->raise_exception("6th argument of add-job-resource should be a list of properties"); name = symbol("add-job-resource"); rng = m_alist_sort; break; @@ -115,7 +115,7 @@ func_decl * csp_decl_plugin::mk_func_decl( if (domain[2] != m_int_sort) m_manager->raise_exception("3rd argument of add-resource-available expects should be an integer"); if (domain[3] != m_int_sort) m_manager->raise_exception("4th argument of add-resource-available expects should be an integer"); if (domain[4] != m_int_sort) m_manager->raise_exception("5th argument of add-resource-available expects should be an integer"); - if (domain[5] != m_alist_sort) m_manager->raise_exception("6th argument of add-resource-available should be an a list of properties"); + if (domain[5] != m_alist_sort) m_manager->raise_exception("6th argument of add-resource-available should be a list of properties"); name = symbol("add-resource-available"); rng = m_alist_sort; break; diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index 5fb468ef5..f81785332 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -263,7 +263,7 @@ namespace datalog { } /** - \brief Return an operation that is a composition of a join an a project operation. + \brief Return an operation that is a composition of a join and a project operation. */ relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, @@ -433,7 +433,7 @@ namespace datalog { } /** - \brief Return an operation that is a composition of a join an a project operation. + \brief Return an operation that is a composition of a join and a project operation. This operation is equivalent to the two operations performed separately, unless functional columns are involved. diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index 847ea7f5e..3b218f56d 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -315,7 +315,7 @@ namespace smt { /** * For time interval [t0, t1] the end-time can be computed as a function - * of start time based on reource load availability. + * of start time based on resource load availability. * * r = resource(j) & t1 >= start(j) >= t0 => end(j) = start(j) + ect(j, r, t0) - t0 */ @@ -672,7 +672,7 @@ namespace smt { } /* - * Initialze the state based on the set of jobs and resources added. + * Initialize the state based on the set of jobs and resources added. * Ensure that the availability slots for each resource is sorted by time. * * For each resource j: From 69e2f33ecf1ae574366a6242cb0e42e2e3bd6040 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Nov 2018 09:50:52 -0800 Subject: [PATCH 135/227] undefine min/max #1927 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 51 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index edc724160..dcb929385 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -28,6 +28,9 @@ Notes: #include #include +#undef min +#undef max + /** \defgroup cppapi C++ API @@ -1478,9 +1481,51 @@ namespace z3 { inline expr nand(expr const& a, expr const& b) { check_context(a, b); Z3_ast r = Z3_mk_bvnand(a.ctx(), a, b); return expr(a.ctx(), r); } inline expr nor(expr const& a, expr const& b) { check_context(a, b); Z3_ast r = Z3_mk_bvnor(a.ctx(), a, b); return expr(a.ctx(), r); } inline expr xnor(expr const& a, expr const& b) { check_context(a, b); Z3_ast r = Z3_mk_bvxnor(a.ctx(), a, b); return expr(a.ctx(), r); } - inline expr min(expr const& a, expr const& b) { check_context(a, b); Z3_ast r = Z3_mk_fpa_min(a.ctx(), a, b); return expr(a.ctx(), r); } - inline expr max(expr const& a, expr const& b) { check_context(a, b); Z3_ast r = Z3_mk_fpa_max(a.ctx(), a, b); return expr(a.ctx(), r); } - inline expr abs(expr const & a) { Z3_ast r = Z3_mk_fpa_abs(a.ctx(), a); return expr(a.ctx(), r); } + inline expr min(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r; + if (a.is_arith()) { + r = Z3_mk_ite(a.ctx(), Z3_mk_ge(a.ctx(), a, b), b, a); + } + else if (a.is_bv()) { + r = Z3_mk_ite(a.ctx(), Z3_mk_bvuge(a.ctx(), a, b), b, a); + } + else { + assert(a.is_fpa()); + r = Z3_mk_fpa_min(a.ctx(), a, b); + } + return expr(a.ctx(), r); + } + inline expr max(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r; + if (a.is_arith()) { + r = Z3_mk_ite(a.ctx(), Z3_mk_ge(a.ctx(), a, b), a, b); + } + else if (a.is_bv()) { + r = Z3_mk_ite(a.ctx(), Z3_mk_bvuge(a.ctx(), a, b), a, b); + } + else { + assert(a.is_fpa()); + r = Z3_mk_fpa_max(a.ctx(), a, b); + } + return expr(a.ctx(), r); + } + inline expr abs(expr const & a) { + Z3_ast r; + if (a.is_int()) { + expr zero = a.ctx().int_val(0); + r = Z3_mk_ite(a.ctx(), Z3_mk_ge(a.ctx(), a, zero), a, zero); + } + else if (a.is_real()) { + expr zero = a.ctx().real_val(0); + r = Z3_mk_ite(a.ctx(), Z3_mk_ge(a.ctx(), a, zero), a, zero); + } + else { + r = Z3_mk_fpa_abs(a.ctx(), a); + } + return expr(a.ctx(), r); + } inline expr sqrt(expr const & a, expr const& rm) { check_context(a, rm); assert(a.is_fpa()); From 4d0bc8c8b35e16d9510f0e886458311d7e627083 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Nov 2018 15:10:44 -0800 Subject: [PATCH 136/227] ignore propagation on units Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist.py | 2 +- src/sat/sat_solver.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 10bb5a6ef..9e0374192 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -267,7 +267,7 @@ def cp_vs_runtime(x64): # we use a "check_root" filter to find some hopefully suitable # redistributable. def check_root(root): - return platform in root and "CRT" in root and "onecore" not in root and "debug" not in 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): diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f38da472f..1881d0375 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -920,7 +920,7 @@ namespace sat { if (c[0] == not_l) std::swap(c[0], c[1]); CTRACE("propagate_bug", c[1] != not_l, tout << "l: " << l << " " << c << "\n";); - if (c.was_removed() || c[1] != not_l) { + if (c.was_removed() || c.size() == 1 || c[1] != not_l) { // Remark: this method may be invoked when the watch lists are not in a consistent state, // and may contain dead/removed clauses, or clauses with removed literals. // See: method propagate_unit at sat_simplifier.cpp From 72400f186901e4e3e542ffc0749c017d528a6cef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Nov 2018 03:43:04 -0800 Subject: [PATCH 137/227] fix #1927 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 4 ++-- src/muz/spacer/spacer_context.cpp | 2 +- src/qe/qe_datatypes.cpp | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index dcb929385..edac9a828 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1515,11 +1515,11 @@ namespace z3 { Z3_ast r; if (a.is_int()) { expr zero = a.ctx().int_val(0); - r = Z3_mk_ite(a.ctx(), Z3_mk_ge(a.ctx(), a, zero), a, zero); + r = Z3_mk_ite(a.ctx(), Z3_mk_ge(a.ctx(), a, zero), a, -a); } else if (a.is_real()) { expr zero = a.ctx().real_val(0); - r = Z3_mk_ite(a.ctx(), Z3_mk_ge(a.ctx(), a, zero), a, zero); + r = Z3_mk_ite(a.ctx(), Z3_mk_ge(a.ctx(), a, zero), a, -a); } else { r = Z3_mk_fpa_abs(a.ctx(), a); diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index bbb06f719..bad25ef71 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1210,7 +1210,7 @@ expr_ref pred_transformer::get_origin_summary (model &mdl, if (!is_quantifier(s) && !mdl.is_true(s)) { TRACE("spacer", tout << "Summary not true in the model: " << mk_pp(s, m) << "\n";); - return expr_ref(m); + // return expr_ref(m); } } diff --git a/src/qe/qe_datatypes.cpp b/src/qe/qe_datatypes.cpp index 7ade47458..4109d7fd9 100644 --- a/src/qe/qe_datatypes.cpp +++ b/src/qe/qe_datatypes.cpp @@ -77,6 +77,7 @@ namespace qe { ptr_vector const& acc = *dt.get_constructor_accessors(f); for (unsigned i = 0; i < acc.size(); ++i) { arg = m.mk_fresh_const(acc[i]->get_name().str().c_str(), acc[i]->get_range()); + vars.push_back(arg); model.register_decl(arg->get_decl(), m_val->get_arg(i)); args.push_back(arg); } From 8847898a7d6ab78502a7b8990fe3d0b1701b55d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Nov 2018 08:52:51 -0800 Subject: [PATCH 138/227] add multiline lisp style comments #1932 Signed-off-by: Nikolaj Bjorner --- src/parsers/smt2/smt2scanner.cpp | 30 +++++++++++++++++++++++++++++- src/parsers/smt2/smt2scanner.h | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/parsers/smt2/smt2scanner.cpp b/src/parsers/smt2/smt2scanner.cpp index 9a9e69b67..e1725dada 100644 --- a/src/parsers/smt2/smt2scanner.cpp +++ b/src/parsers/smt2/smt2scanner.cpp @@ -64,6 +64,26 @@ namespace smt2 { next(); } } + + void scanner::read_multiline_comment() { + SASSERT(curr() == '|'); + next(); + while (true) { + char c = curr(); + if (m_at_eof) + return; + if (c == '\n') { + new_line(); + next(); + continue; + } + next(); + if (c == '|' && curr() == '#') { + next(); + return; + } + } + } scanner::token scanner::read_quoted_symbol() { SASSERT(curr() == '|'); @@ -235,6 +255,10 @@ namespace smt2 { throw scanner_exception("invalid empty bit-vector literal", m_line, m_spos); return BV_TOKEN; } + else if ('|') { + read_multiline_comment(); + return NULL_TOKEN; + } else { throw scanner_exception("invalid bit-vector literal, expecting 'x' or 'b'", m_line, m_spos); } @@ -295,6 +319,8 @@ namespace smt2 { scanner::token scanner::scan() { while (true) { signed char c = curr(); + token t; + m_pos = m_spos; if (m_at_eof) @@ -329,7 +355,9 @@ namespace smt2 { case '0': return read_number(); case '#': - return read_bv_literal(); + t = read_bv_literal(); + if (t == NULL_TOKEN) break; + return t; case '-': if (m_smtlib2_compliant) return read_symbol(); diff --git a/src/parsers/smt2/smt2scanner.h b/src/parsers/smt2/smt2scanner.h index 5283c57cf..5fad416b0 100644 --- a/src/parsers/smt2/smt2scanner.h +++ b/src/parsers/smt2/smt2scanner.h @@ -92,6 +92,7 @@ namespace smt2 { token read_symbol(); token read_quoted_symbol(); void read_comment(); + void read_multiline_comment(); token read_number(); token read_signed_number(); token read_string(); From ef9b46b2e59a5672436e4bd9c453f7ba94d9a5ab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Nov 2018 09:21:51 -0800 Subject: [PATCH 139/227] fix #1922 - incorrect pretty printing of datatypes Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt_pp.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 227e00419..0def08094 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -811,8 +811,6 @@ public: m_out << ")"; } m_out << "("; - m_out << m_renaming.get_symbol(d->name(), false); - m_out << " "; bool first_constr = true; for (datatype::constructor* f : *d) { if (!first_constr) m_out << " "; else first_constr = false; From 9b4cf1559dd431a716b351b4d14105ea27efb263 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Nov 2018 15:33:46 -0800 Subject: [PATCH 140/227] recover error stream from dimacs Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 6 ++++- src/sat/dimacs.cpp | 47 ++++++++++++++++++++--------------- src/sat/dimacs.h | 2 +- src/shell/dimacs_frontend.cpp | 6 ++--- 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index cb4ae19db..a5ad7b525 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -183,8 +183,12 @@ extern "C" { } else if (ext && std::string("dimacs") == ext) { ast_manager& m = to_solver_ref(s)->get_manager(); + std::stringstream err; sat::solver solver(to_solver_ref(s)->get_params(), m.limit()); - parse_dimacs(is, solver); + if (!parse_dimacs(is, err, solver)) { + SET_ERROR_CODE(Z3_PARSER_ERROR, err.str().c_str()); + return; + } sat2goal s2g; ref mc; atom2bool_var a2b(m); diff --git a/src/sat/dimacs.cpp b/src/sat/dimacs.cpp index 463418b23..970e682b3 100644 --- a/src/sat/dimacs.cpp +++ b/src/sat/dimacs.cpp @@ -21,6 +21,8 @@ Revision History: #undef min #include "sat/sat_solver.h" +struct lex_error {}; + class stream_buffer { std::istream & m_stream; int m_val; @@ -67,7 +69,7 @@ void skip_line(Buffer & in) { } template -int parse_int(Buffer & in) { +int parse_int(Buffer & in, std::ostream& err) { int val = 0; bool neg = false; skip_whitespace(in); @@ -81,9 +83,8 @@ int parse_int(Buffer & in) { } if (*in < '0' || *in > '9') { - std::cerr << "(error, \"unexpected char: " << *in << " line: " << in.line() << "\")\n"; - exit(3); - exit(ERR_PARSER); + err << "(error, \"unexpected char: " << *in << " line: " << in.line() << "\")\n"; + throw lex_error(); } while (*in >= '0' && *in <= '9') { @@ -95,14 +96,14 @@ int parse_int(Buffer & in) { } template -void read_clause(Buffer & in, sat::solver & solver, sat::literal_vector & lits) { +void read_clause(Buffer & in, std::ostream& err, sat::solver & solver, sat::literal_vector & lits) { int parsed_lit; int var; lits.reset(); while (true) { - parsed_lit = parse_int(in); + parsed_lit = parse_int(in, err); if (parsed_lit == 0) break; var = abs(parsed_lit); @@ -114,24 +115,30 @@ void read_clause(Buffer & in, sat::solver & solver, sat::literal_vector & lits) } template -void parse_dimacs_core(Buffer & in, sat::solver & solver) { +bool parse_dimacs_core(Buffer & in, std::ostream& err, sat::solver & solver) { sat::literal_vector lits; - while (true) { - skip_whitespace(in); - if (*in == EOF) { - break; - } - else if (*in == 'c' || *in == 'p') { - skip_line(in); - } - else { - read_clause(in, solver, lits); - solver.mk_clause(lits.size(), lits.c_ptr()); + try { + while (true) { + skip_whitespace(in); + if (*in == EOF) { + break; + } + else if (*in == 'c' || *in == 'p') { + skip_line(in); + } + else { + read_clause(in, err, solver, lits); + solver.mk_clause(lits.size(), lits.c_ptr()); + } } } + catch (lex_error) { + return false; + } + return true; } -void parse_dimacs(std::istream & in, sat::solver & solver) { +bool parse_dimacs(std::istream & in, std::ostream& err, sat::solver & solver) { stream_buffer _in(in); - parse_dimacs_core(_in, solver); + return parse_dimacs_core(_in, err, solver); } diff --git a/src/sat/dimacs.h b/src/sat/dimacs.h index 50ebec0c8..4c5d51502 100644 --- a/src/sat/dimacs.h +++ b/src/sat/dimacs.h @@ -21,7 +21,7 @@ Revision History: #include "sat/sat_types.h" -void parse_dimacs(std::istream & s, sat::solver & solver); +bool parse_dimacs(std::istream & s, std::ostream& err, sat::solver & solver); #endif /* DIMACS_PARSER_H_ */ diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 3a2af72cf..738566ce2 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -136,7 +136,7 @@ void verify_solution(char const * file_name) { std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; exit(ERR_OPEN_FILE); } - parse_dimacs(in, solver); + parse_dimacs(in, std::cerr, solver); sat::model const & m = g_solver->get_model(); for (unsigned i = 1; i < m.size(); i++) { @@ -178,10 +178,10 @@ unsigned read_dimacs(char const * file_name) { std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; exit(ERR_OPEN_FILE); } - parse_dimacs(in, solver); + parse_dimacs(in, std::cerr, solver); } else { - parse_dimacs(std::cin, solver); + parse_dimacs(std::cin, std::cerr, solver); } IF_VERBOSE(20, solver.display_status(verbose_stream());); From c59b331c1f4c960e444940c5effc1fdb1a4557cc Mon Sep 17 00:00:00 2001 From: Andrew Helwer Date: Tue, 13 Nov 2018 12:19:20 -0800 Subject: [PATCH 141/227] Updated nuget package spec and directions --- package/Microsoft.Z3.x64.nuspec | 30 ++++++++++++++-------------- package/PackageCreationDirections.md | 6 ++---- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/package/Microsoft.Z3.x64.nuspec b/package/Microsoft.Z3.x64.nuspec index 95d594dfb..506e5f9c7 100644 --- a/package/Microsoft.Z3.x64.nuspec +++ b/package/Microsoft.Z3.x64.nuspec @@ -3,20 +3,20 @@ Microsoft.Z3.x64 $(releaseVersion) - © Microsoft Corporation. All rights reserved. - Microsoft - Microsoft,Z3Prover - $(iconUrlFromReleaseCommit) - https://github.com/Z3Prover/z3 - $(licenseUrlFromReleaseCommit) - - true - Z3 is a constraint/SMT solver and theorem prover from Microsoft Research. - smt constraint solver theorem prover + © Microsoft Corporation. All rights reserved. + Microsoft + https://raw.githubusercontent.com/Z3Prover/z3/$(releaseCommitHash)/package/icon.jpg + https://github.com/Z3Prover/z3 + https://raw.githubusercontent.com/Z3Prover/z3/$(releaseCommitHash)/LICENSE.txt + + true + Z3 is a satisfiability modulo theories solver from Microsoft Research. + smt constraint solver theorem prover + en diff --git a/package/PackageCreationDirections.md b/package/PackageCreationDirections.md index 930ba14f7..6aaee5a1d 100644 --- a/package/PackageCreationDirections.md +++ b/package/PackageCreationDirections.md @@ -15,11 +15,9 @@ | +-- Microsoft.Z3.x64.targets | +-- libz3.dll ``` - 4. Open the nuspec file and fill in the appropriate macro values (note that for all URLs, preserve link integrity by linking to a specific commit): + 4. Open the nuspec file and fill in the appropriate macro values: * $(releaseVersion) - the Z3 version being released in this package - * $(iconUrlFromReleaseCommit) - URL for the Z3 icon file - * $(licenseUrlFromReleaseCommit) - URL for the Z3 repo license - * $(releaseCommitHash) - hash of the release commit + * $(releaseCommitHash) - hash of the release commit (there are several of these) 5. Run `nuget pack Microsoft.Z3.x64\Microsoft.Z3.x64.nuspec` 6. Test the resulting nupkg file (described below) then submit the package for signing before uploading to NuGet.org From 225fb82d9656b17b5c36266b05cc1b0ab051116e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Nov 2018 15:54:37 -0800 Subject: [PATCH 142/227] add TBD for dotnet example Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 08ff771e7..c73e1f1d1 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2357,7 +2357,7 @@ class DotNetExampleComponent(ExampleComponent): ExampleComponent.__init__(self, name, path) def is_example(self): - return is_dotnet_enabled() + return is_dotnet_enabled() or is_dotnet_core_enabled() def mk_makefile(self, out): if is_dotnet_enabled(): @@ -2385,6 +2385,8 @@ class DotNetExampleComponent(ExampleComponent): out.write(os.path.join(relative_path, csfile)) out.write('\n') out.write('_ex_%s: %s\n\n' % (self.name, exefile)) + if is_dotnet_core_enabled(): + print("TBD: build script for dotnet_example on core") class JavaExampleComponent(ExampleComponent): def __init__(self, name, path): From bd78558826da01d612847c999866d20f1392742e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Nov 2018 19:51:57 -0800 Subject: [PATCH 143/227] adding dotnetcore handling Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index c73e1f1d1..01c1ea9a2 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -61,6 +61,7 @@ PATTERN_COMPONENT='pattern' UTIL_COMPONENT='util' API_COMPONENT='api' DOTNET_COMPONENT='dotnet' +DOTNET_CORE_COMPONENT='dotnetcore' JAVA_COMPONENT='java' ML_COMPONENT='ml' CPP_COMPONENT='cpp' @@ -3192,6 +3193,8 @@ def mk_z3consts_py(api_files): # Extract enumeration types from z3_api.h, and add .Net definitions def mk_z3consts_dotnet(api_files): dotnet = get_component(DOTNET_COMPONENT) + if not dotnet: + dotnet = get_component(DOTNET_CORE_COMPONENT) full_path_api_files = [] for api_file in api_files: api_file_c = dotnet.find_file(api_file, dotnet.name) From dbd5ef45261dc259d808864d06513b511f92eca4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Nov 2018 19:58:09 -0800 Subject: [PATCH 144/227] more dotnet core Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 01c1ea9a2..c0b2c5fc4 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -455,6 +455,10 @@ def check_dotnet(): if r != 0: raise MKException('Failed testing gacutil. Set environment variable GACUTIL with the path to gacutil.') +def check_dotnet_core(): + # TBD: check DOTNET + pass + def check_ml(): t = TempFile('hello.ml') t.add('print_string "Hello world!\n";;') @@ -3172,9 +3176,12 @@ def mk_bindings(api_files): if is_ml_enabled(): check_ml() mk_z3consts_ml(api_files) - if is_dotnet_enabled(): + if is_dotnet_enabled() check_dotnet() mk_z3consts_dotnet(api_files) + if is_dotnetcore_enabled(): + check_dotnet_core() + mk_z3consts_dotnet(api_files) # Extract enumeration types from API files, and add python definitions. def mk_z3consts_py(api_files): From 37ec933c664a9ce86be573bb63ad09ffc4a6adf2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Nov 2018 19:58:42 -0800 Subject: [PATCH 145/227] more dotnet core Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index c0b2c5fc4..674e75f3c 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -3176,7 +3176,7 @@ def mk_bindings(api_files): if is_ml_enabled(): check_ml() mk_z3consts_ml(api_files) - if is_dotnet_enabled() + if is_dotnet_enabled(): check_dotnet() mk_z3consts_dotnet(api_files) if is_dotnetcore_enabled(): From ccf6ca310ed26137cbbd2fb133c7016601de6fdb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Nov 2018 19:59:46 -0800 Subject: [PATCH 146/227] more dotnet core Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 674e75f3c..88d7d7246 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -3179,7 +3179,7 @@ def mk_bindings(api_files): if is_dotnet_enabled(): check_dotnet() mk_z3consts_dotnet(api_files) - if is_dotnetcore_enabled(): + if is_dotnet_core_enabled(): check_dotnet_core() mk_z3consts_dotnet(api_files) From 2fbaad15d7324b4b67a968a6c3831416f384393b Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 14 Nov 2018 09:57:47 -0800 Subject: [PATCH 147/227] Build example for dotnetcore. --- scripts/mk_util.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 88d7d7246..cfcf78538 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2391,7 +2391,41 @@ class DotNetExampleComponent(ExampleComponent): out.write('\n') out.write('_ex_%s: %s\n\n' % (self.name, exefile)) if is_dotnet_core_enabled(): - print("TBD: build script for dotnet_example on core") + proj_name = 'dotnet_example.csproj' + out.write('_ex_%s:' % self.name) + for csfile in get_cs_files(self.ex_dir): + out.write(' ') + out.write(os.path.join(self.to_ex_dir, csfile)) + out.write('\n') + out.write('\t@echo "" > %s\n' % proj_name) + out.write('\t@echo " " >> %s\n' % proj_name) + out.write('\t@echo " Exe" >> %s\n' % proj_name) + out.write('\t@echo " netcoreapp2.0" >> %s\n' % proj_name) + out.write('\t@echo " ') + if VS_X64: + out.write('x64') + elif VS_ARM: + out.write('ARM') + else: + out.write('x86') + out.write('" >> %s\n' % proj_name) + out.write('\t@echo " " >> %s\n' % proj_name) + out.write('\t@echo " " >> %s\n' % proj_name) + out.write('\t@echo " " >> %s\n' % (self.to_ex_dir, proj_name)) + out.write('\t@echo " " >> %s\n' % proj_name) + out.write('\t@echo " Microsoft.Z3.dll" >> %s\n' % proj_name) + out.write('\t@echo " " >> %s\n' % proj_name) + out.write('\t@echo " " >> %s\n' % proj_name) + out.write('\t@echo "" >> %s\n' % proj_name) + + dotnetCmdLine = [DOTNET, "build", proj_name] + dotnetCmdLine.extend(['-c']) + if DEBUG_MODE: + dotnetCmdLine.extend(['Debug']) + else: + dotnetCmdLine.extend(['Release']) + MakeRuleCmd.write_cmd(out, ' '.join(dotnetCmdLine)) + out.write('\n') class JavaExampleComponent(ExampleComponent): def __init__(self, name, path): From d4567a125588160d7bf0517d27000b26788580ad Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 14 Nov 2018 11:11:25 -0800 Subject: [PATCH 148/227] Fix `echo` command for Windows. --- scripts/mk_util.py | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index cfcf78538..472da8595 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2396,27 +2396,35 @@ class DotNetExampleComponent(ExampleComponent): for csfile in get_cs_files(self.ex_dir): out.write(' ') out.write(os.path.join(self.to_ex_dir, csfile)) + + def mk_echo(msg): + echo_ex_qu = '' if IS_WINDOWS else '"' + echo_in_qu = '"' if IS_WINDOWS else '\\"' + echo_esc = '^' if IS_WINDOWS else '' + + msg = msg.replace('"', echo_in_qu).replace('<', echo_esc + '<').replace('>', echo_esc + '>') + out.write('\t@echo %s%s%s > %s\n' % (echo_ex_qu, msg, echo_ex_qu, proj_name)) + out.write('\n') - out.write('\t@echo "" > %s\n' % proj_name) - out.write('\t@echo " " >> %s\n' % proj_name) - out.write('\t@echo " Exe" >> %s\n' % proj_name) - out.write('\t@echo " netcoreapp2.0" >> %s\n' % proj_name) - out.write('\t@echo " ') + mk_echo('') + mk_echo(' ') + mk_echo(' Exe') + mk_echo(' netcoreapp2.0') if VS_X64: - out.write('x64') + platform = 'x64' elif VS_ARM: - out.write('ARM') + platform = 'ARM' else: - out.write('x86') - out.write('" >> %s\n' % proj_name) - out.write('\t@echo " " >> %s\n' % proj_name) - out.write('\t@echo " " >> %s\n' % proj_name) - out.write('\t@echo " " >> %s\n' % (self.to_ex_dir, proj_name)) - out.write('\t@echo " " >> %s\n' % proj_name) - out.write('\t@echo " Microsoft.Z3.dll" >> %s\n' % proj_name) - out.write('\t@echo " " >> %s\n' % proj_name) - out.write('\t@echo " " >> %s\n' % proj_name) - out.write('\t@echo "" >> %s\n' % proj_name) + platform = 'x86' + mk_echo(' %s' % platform) + mk_echo(' ') + mk_echo(' ') + mk_echo(' ' % self.to_ex_dir) + mk_echo(' ') + mk_echo(' Microsoft.Z3.dll') + mk_echo(' ') + mk_echo('') dotnetCmdLine = [DOTNET, "build", proj_name] dotnetCmdLine.extend(['-c']) From e39907c4810ce51dec97936965d64e8c109915ee Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 14 Nov 2018 11:25:18 -0800 Subject: [PATCH 149/227] Fix some problems in `mk_echo`. --- scripts/mk_util.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 472da8595..b6afaf897 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2397,13 +2397,14 @@ class DotNetExampleComponent(ExampleComponent): out.write(' ') out.write(os.path.join(self.to_ex_dir, csfile)) - def mk_echo(msg): + def mk_echo(msg, first = False): echo_ex_qu = '' if IS_WINDOWS else '"' echo_in_qu = '"' if IS_WINDOWS else '\\"' echo_esc = '^' if IS_WINDOWS else '' + echo_dir = '>' if first else '>>' msg = msg.replace('"', echo_in_qu).replace('<', echo_esc + '<').replace('>', echo_esc + '>') - out.write('\t@echo %s%s%s > %s\n' % (echo_ex_qu, msg, echo_ex_qu, proj_name)) + out.write('\t@echo %s%s%s %s %s\n' % (echo_ex_qu, msg, echo_ex_qu, echo_dir, proj_name)) out.write('\n') mk_echo('') @@ -2421,7 +2422,7 @@ class DotNetExampleComponent(ExampleComponent): mk_echo(' ') mk_echo(' ' % self.to_ex_dir) mk_echo(' ') - mk_echo(' Microsoft.Z3.dllMicrosoft.Z3.dll') mk_echo(' ') mk_echo(' ') mk_echo('') From 33363aeb58ab641c8e9b3c3a9ffaaf33e8c24f5e Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 14 Nov 2018 11:27:55 -0800 Subject: [PATCH 150/227] Fix problem in `mk_echo`. --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index b6afaf897..aaeed1dea 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2407,7 +2407,7 @@ class DotNetExampleComponent(ExampleComponent): out.write('\t@echo %s%s%s %s %s\n' % (echo_ex_qu, msg, echo_ex_qu, echo_dir, proj_name)) out.write('\n') - mk_echo('') + mk_echo('', True) mk_echo(' ') mk_echo(' Exe') mk_echo(' netcoreapp2.0') From 52910fa465e8a839e2a20dfaf682e89e84a899b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Nov 2018 11:31:39 -0800 Subject: [PATCH 151/227] fix #1937 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 12 +++++++++++- src/parsers/smt2/smt2parser.cpp | 11 +++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index dad485d94..82607452f 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -561,6 +561,7 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu zstring s; rational pos, len; + TRACE("seq", tout << mk_pp(a, m()) << " " << mk_pp(b, m()) << " " << mk_pp(c, m()) << "\n";); bool constantBase = m_util.str.is_string(a, s); bool constantPos = m_autil.is_numeral(b, pos); bool constantLen = m_autil.is_numeral(c, len); @@ -599,6 +600,10 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu SASSERT(_len > 0); expr_ref_vector as(m()), bs(m()); m_util.str.get_concat(a, as); + if (as.empty()) { + result = a; + return BR_DONE; + } for (unsigned i = 0; i < as.size() && _len > 0; ++i) { if (m_util.str.is_unit(as[i].get())) { if (_pos == 0) { @@ -613,7 +618,12 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu return BR_FAILED; } } - result = m_util.str.mk_concat(bs); + if (bs.empty()) { + result = m_util.str.mk_empty(m().get_sort(a)); + } + else { + result = m_util.str.mk_concat(bs); + } return BR_DONE; } diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 106a77c0e..64f9c36fd 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -346,7 +346,8 @@ namespace smt2 { // consume garbage // return true if managed to recover from the error... bool sync_after_error() { - while (true) { + unsigned num_errors = 0; + while (num_errors < 100) { try { while (curr_is_rparen()) next(); @@ -374,8 +375,10 @@ namespace smt2 { catch (scanner_exception & ex) { SASSERT(ex.has_pos()); error(ex.line(), ex.pos(), ex.msg()); + ++num_errors; } } + return false; } void check_next(scanner::token t, char const * msg) { @@ -3117,7 +3120,7 @@ namespace smt2 { bool operator()() { m_num_bindings = 0; - bool found_errors = false; + unsigned found_errors = 0; try { scan_core(); @@ -3126,7 +3129,7 @@ namespace smt2 { error(ex.msg()); if (!sync_after_error()) return false; - found_errors = true; + found_errors++; } while (true) { @@ -3138,7 +3141,7 @@ namespace smt2 { parse_cmd(); break; case scanner::EOF_TOKEN: - return !found_errors; + return found_errors == 0; default: throw parser_exception("invalid command, '(' expected"); break; From 139d8b85f018dc392f85af989af62a920e7c7e48 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Nov 2018 11:43:41 -0800 Subject: [PATCH 152/227] core Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 88d7d7246..6d3ad3d4b 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -456,7 +456,9 @@ def check_dotnet(): raise MKException('Failed testing gacutil. Set environment variable GACUTIL with the path to gacutil.') def check_dotnet_core(): - # TBD: check DOTNET + r = exec_cmd([DOTNET, '--help']) + if r != 0: + raise MKException('Failed testing dotnet. Make sure to install and configure dotnet core utilities') pass def check_ml(): From 727929c9af003d71eab1f0d90cc8e01761943491 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Nov 2018 12:04:31 -0800 Subject: [PATCH 153/227] fix test build Signed-off-by: Nikolaj Bjorner --- src/test/cnf_backbones.cpp | 4 ++-- src/test/sat_lookahead.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/test/cnf_backbones.cpp b/src/test/cnf_backbones.cpp index 50584c90c..10f3e56a7 100644 --- a/src/test/cnf_backbones.cpp +++ b/src/test/cnf_backbones.cpp @@ -238,10 +238,10 @@ static void cnf_backbones(bool use_chunk, char const* file_name) { std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; exit(ERR_OPEN_FILE); } - parse_dimacs(in, solver); + if (!parse_dimacs(in, std::cerr, solver)) return; } else { - parse_dimacs(std::cin, solver); + if (!parse_dimacs(std::cin, std::cerr, solver)) return; } IF_VERBOSE(20, solver.display_status(verbose_stream());); diff --git a/src/test/sat_lookahead.cpp b/src/test/sat_lookahead.cpp index fccbe8eed..23c4a4738 100644 --- a/src/test/sat_lookahead.cpp +++ b/src/test/sat_lookahead.cpp @@ -34,7 +34,8 @@ void tst_sat_lookahead(char ** argv, int argc, int& i) { std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; exit(ERR_OPEN_FILE); } - parse_dimacs(in, solver); + if (!parse_dimacs(in, std::cerr, solver)) + return; } sat::lookahead lh(solver); From 2501a875efcaa5d837601b40eafdcdeb7f351505 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Nov 2018 13:44:40 -0800 Subject: [PATCH 154/227] update script to generate file directly instead of from makefile Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 12ccc538c..63938caf9 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2399,36 +2399,32 @@ class DotNetExampleComponent(ExampleComponent): out.write(' ') out.write(os.path.join(self.to_ex_dir, csfile)) - def mk_echo(msg, first = False): - echo_ex_qu = '' if IS_WINDOWS else '"' - echo_in_qu = '"' if IS_WINDOWS else '\\"' - echo_esc = '^' if IS_WINDOWS else '' - echo_dir = '>' if first else '>>' - - msg = msg.replace('"', echo_in_qu).replace('<', echo_esc + '<').replace('>', echo_esc + '>') - out.write('\t@echo %s%s%s %s %s\n' % (echo_ex_qu, msg, echo_ex_qu, echo_dir, proj_name)) - - out.write('\n') - mk_echo('', True) - mk_echo(' ') - mk_echo(' Exe') - mk_echo(' netcoreapp2.0') + proj_path = os.path.join(BUILD_DIR, proj_name) if VS_X64: platform = 'x64' elif VS_ARM: platform = 'ARM' else: platform = 'x86' - mk_echo(' %s' % platform) - mk_echo(' ') - mk_echo(' ') - mk_echo(' ' % self.to_ex_dir) - mk_echo(' ') - mk_echo(' Microsoft.Z3.dll') - mk_echo(' ') - mk_echo(' ') - mk_echo('') + dotnet_proj_str = """xemacs + + Exe + netcoreapp2.0 + %s + + + + + Microsoft.Z3.dll + + +""" % (platform, self.to_ex_dir) + + with open(proj_path, 'w') as ous: + ous.write(dotnet_proj_str) + + out.write('\n') dotnetCmdLine = [DOTNET, "build", proj_name] dotnetCmdLine.extend(['-c']) if DEBUG_MODE: From 690bd8502ab66ccae28a3d7538b7933930197e91 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 14 Nov 2018 13:47:46 -0800 Subject: [PATCH 155/227] Choose runtime for .NET core DLL. --- scripts/mk_util.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index aaeed1dea..c84b1c3a4 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1888,6 +1888,15 @@ class DotNetCoreDLLComponent(Component): else: dotnetCmdLine.extend(['Release']) + if IS_WINDOWS: + runtime = "win-" + ("x64" if VS_X64 else "x86") + elif IS_LINUX: + runtime = "linux-x64" if LINUX_X64 else "" + elif IS_OSX: + runtime = "osx-x64" if LINUX_X64 else "" + if runtime != "": + dotnetCmdLine.extend(['-r', runtime]) + path = os.path.abspath(BUILD_DIR) dotnetCmdLine.extend(['-o', path]) From 1cc2cc01431e17e46be7b7bd89127dcbdd05e089 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Nov 2018 14:07:14 -0800 Subject: [PATCH 156/227] add TBD marker Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 63938caf9..be7132b75 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1839,6 +1839,7 @@ class DotNetCoreDLLComponent(Component): self.key_file = default_key_file def mk_pkg_config_file(self): + # TBD revise """ Create pkgconfig file for the dot net bindings. These are needed by Monodevelop. From c3725000182ef974e1e120c299adaa0377284dc9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Nov 2018 14:51:58 -0800 Subject: [PATCH 157/227] update for nuget/core Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 103 ++++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 43 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 4037b3996..bd455b95e 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -562,6 +562,11 @@ def set_version(major, minor, build, revision): def get_version(): return (VER_MAJOR, VER_MINOR, VER_BUILD, VER_REVISION) +def get_version_string(n): + if n == 3: + return "{}.{}.{}".format(VER_MAJOR,VER_MINOR,VER_BUILD) + return "{}.{}.{}.{}".format(VER_MAJOR,VER_MINOR,VER_BUILD,VER_REVISION) + def build_static_lib(): return STATIC_LIB @@ -1639,11 +1644,7 @@ class DotNetDLLComponent(Component): pkg_config_template = os.path.join(self.src_dir, '{}.pc.in'.format(self.gac_pkg_name())) substitutions = { 'PREFIX': PREFIX, 'GAC_PKG_NAME': self.gac_pkg_name(), - 'VERSION': "{}.{}.{}.{}".format( - VER_MAJOR, - VER_MINOR, - VER_BUILD, - VER_REVISION) + 'VERSION': get_version_string(4) } pkg_config_output = os.path.join(BUILD_DIR, self.build_dir, @@ -1838,30 +1839,14 @@ class DotNetCoreDLLComponent(Component): self.assembly_info_dir = assembly_info_dir self.key_file = default_key_file - def mk_pkg_config_file(self): + def mk_nuget_config_file(self): # TBD revise """ - Create pkgconfig file for the dot net bindings. These + Create nuget file for the dot net bindings. These are needed by Monodevelop. """ - pkg_config_template = os.path.join(self.src_dir, '{}.pc.in'.format(self.gac_pkg_name())) - substitutions = { 'PREFIX': PREFIX, - 'GAC_PKG_NAME': self.gac_pkg_name(), - 'VERSION': "{}.{}.{}.{}".format( - VER_MAJOR, - VER_MINOR, - VER_BUILD, - VER_REVISION) - } - pkg_config_output = os.path.join(BUILD_DIR, - self.build_dir, - '{}.pc'.format(self.gac_pkg_name())) - - # FIXME: Why isn't the build directory available? - mk_dir(os.path.dirname(pkg_config_output)) - # Configure file that will be installed by ``make install``. - configure_file(pkg_config_template, pkg_config_output, substitutions) - + return + def mk_makefile(self, out): global DOTNET_KEY_FILE if not is_dotnet_core_enabled(): @@ -1879,26 +1864,55 @@ class DotNetCoreDLLComponent(Component): out.write(cs_file) out.write('\n') - csproj = os.path.join(self.to_src_dir, "core", "core.csproj") + if VS_X64: + platform = 'x64' + elif VS_ARM: + platform = 'ARM' + else: + platform = 'x86' + + version = get_version_string(3) + + core_csproj_str = """ + + + netcoreapp1.0 + %s + $(DefineConstants);DOTNET_CORE + portable + Microsoft.Z3 + Library + Microsoft.Z3 + $(PackageTargetFallback);dnxcore50 + 1.0.4 + %s + true + Microsoft + Microsoft + Z3 is a satisfiability modulo theories solver from Microsoft Research. + © Microsoft Corporation. All rights reserved. + smt constraint solver theorem prover + + + + + + +""" % (platform, version, self.to_src_dir) + + mk_dir(os.path.join(BUILD_DIR, 'dotnet')) + csproj = os.path.join('dotnet', 'z3.csproj') + with open(os.path.join(BUILD_DIR, csproj), 'w') as ous: + ous.write(core_csproj_str) + dotnetCmdLine = [DOTNET, "build", csproj] - # TBD: select build configurations also based on architecture - # Debug|x86, Debug|x64, Debug|arm - # Release|x86, Release|x64, Release|arm dotnetCmdLine.extend(['-c']) if DEBUG_MODE: dotnetCmdLine.extend(['Debug']) else: dotnetCmdLine.extend(['Release']) - if IS_WINDOWS: - runtime = "win-" + ("x64" if VS_X64 else "x86") - elif IS_LINUX: - runtime = "linux-x64" if LINUX_X64 else "" - elif IS_OSX: - runtime = "osx-x64" if LINUX_X64 else "" - if runtime != "": - dotnetCmdLine.extend(['-r', runtime]) path = os.path.abspath(BUILD_DIR) dotnetCmdLine.extend(['-o', path]) @@ -1911,8 +1925,8 @@ class DotNetCoreDLLComponent(Component): out.write('\n') out.write('%s: %s\n\n' % (self.name, dllfile)) - # Create pkg-config file - self.mk_pkg_config_file() + # Create nuget file + self.mk_nuget_config_file() return def main_component(self): @@ -1926,8 +1940,8 @@ class DotNetCoreDLLComponent(Component): mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR)) shutil.copy('%s.dll' % os.path.join(build_path, self.dll_name), '%s.dll' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) - shutil.copy('%s.xml' % os.path.join(build_path, self.dll_name), - '%s.xml' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) + shutil.copy('%s.deps.json' % os.path.join(build_path, self.dll_name), + '%s.deps.json' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) if DEBUG_MODE: shutil.copy('%s.pdb' % os.path.join(build_path, self.dll_name), '%s.pdb' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) @@ -1937,8 +1951,8 @@ class DotNetCoreDLLComponent(Component): mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR)) shutil.copy('%s.dll' % os.path.join(build_path, self.dll_name), '%s.dll' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) - shutil.copy('%s.xml' % os.path.join(build_path, self.dll_name), - '%s.xml' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) + shutil.copy('%s.deps.json' % os.path.join(build_path, self.dll_name), + '%s.deps.json' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) def mk_install_deps(self, out): if not is_dotnet_core_enabled(): @@ -1949,6 +1963,7 @@ class DotNetCoreDLLComponent(Component): return "{}.Sharp".format(self.dll_name) def _install_or_uninstall_to_gac(self, out, install): + # TBD revise for nuget gacUtilFlags = ['/package {}'.format(self.gac_pkg_name()), '/root', '{}{}'.format(MakeRuleCmd.install_root(), INSTALL_LIB_DIR) @@ -1967,6 +1982,7 @@ class DotNetCoreDLLComponent(Component): flags=' '.join(gacUtilFlags))) def mk_install(self, out): + # TBD revise for nuget if not is_dotnet_core_enabled(): return self._install_or_uninstall_to_gac(out, install=True) @@ -1978,6 +1994,7 @@ class DotNetCoreDLLComponent(Component): MakeRuleCmd.install_files(out, pkg_config_output, INSTALL_PKGCONFIG_DIR) def mk_uninstall(self, out): + # TBD revise for nuget if not is_dotnet_core_enabled(): return self._install_or_uninstall_to_gac(out, install=False) From 13d1ccfeaf9463f73740a964a9ab0ee042897ee9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Nov 2018 14:59:53 -0800 Subject: [PATCH 158/227] update for nuget/core Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index bd455b95e..2662d0933 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1890,7 +1890,7 @@ class DotNetCoreDLLComponent(Component): Microsoft Microsoft Z3 is a satisfiability modulo theories solver from Microsoft Research. - © Microsoft Corporation. All rights reserved. + Copyright Microsoft Corporation. All rights reserved. smt constraint solver theorem prover From 4f4463b2b71e58268a57a127a8fb8b0204b4ab2e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Nov 2018 15:06:24 -0800 Subject: [PATCH 159/227] update for nuget/core Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 2662d0933..1ac9abd0f 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -456,6 +456,8 @@ def check_dotnet(): raise MKException('Failed testing gacutil. Set environment variable GACUTIL with the path to gacutil.') def check_dotnet_core(): + if not IS_WINDOWS: + return r = exec_cmd([DOTNET, '--help']) if r != 0: raise MKException('Failed testing dotnet. Make sure to install and configure dotnet core utilities') From c6c4dc456379aa5c9fdede19226686444e579292 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Nov 2018 16:57:47 -0800 Subject: [PATCH 160/227] start script on assembling platform binaries to wrap with nuget install Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_release.py | 62 +++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 scripts/mk_nuget_release.py diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py new file mode 100644 index 000000000..98a7c6362 --- /dev/null +++ b/scripts/mk_nuget_release.py @@ -0,0 +1,62 @@ +# +# Copyright (c) 2018 Microsoft Corporation +# + +# 1. download releases from github +# 2. copy over libz3.dll for the different architectures +# 3. copy over Microsoft.Z3.dll from suitable distribution +# 4. copy nuspec file from packages +# 5. call nuget pack + +import json +import os +import urllib.request +import zipfile +import sys +import os.path + +data = json.loads(urllib.request.urlopen("https://api.github.com/repos/Z3Prover/z3/releases/latest").read().decode()) + +version_str = data['tag_name'] + +def mk_dir(d): + if not os.path.exists(d): + os.makedirs(d) + +def download_installs(): + for asset in data['assets']: + url = asset['browser_download_url'] + name = asset['name'] + print("Downloading ", url) + sys.stdout.flush() + urllib.request.urlretrieve(url, "packages/%s" % name) + +os_names = ["ubuntu-14", "ubuntu-16", "win", "debian", "osx"] + +def unpack(): + for f in os.listdir("packages"): + if f.endswith("zip") and "x64" in f: + print(f) + # determine os from os_names + # instead of this string manipulation. + + name = os.path.splitext(f)[0] + os_name = name[name.find("x64")+4:] + os_name = os_name[:os_name.find("-")] + print(os_name) + + zip_ref = zipfile.ZipFile("packages/%s" % f, 'r') + path = "out/%s" % os_name + zip_ref.extract("%s/bin/libz3.so" % name) + + # unzip files in packages + pass + +def main(): + mk_dir("packages") +# download_installs() +# create_nuget_dir() + unpack() +# create_nuget_package() + +main() From 6a9c8a8999449439ec589ff9f6ee781151ee9d59 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Nov 2018 19:40:56 -0800 Subject: [PATCH 161/227] remove spurious string Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 1ac9abd0f..9c5b0c9a9 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2436,7 +2436,7 @@ class DotNetExampleComponent(ExampleComponent): else: platform = 'x86' - dotnet_proj_str = """xemacs + dotnet_proj_str = """ Exe netcoreapp2.0 From 03bb5a085facc26b4503d7dbc7c0efc289cab8a5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Nov 2018 09:21:03 -0800 Subject: [PATCH 162/227] fix #1940 Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 06f30cbdf..737213477 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -899,7 +899,7 @@ bool seq_decl_plugin::are_distinct(app* a, app* b) const { } if (is_app_of(a, m_family_id, OP_SEQ_UNIT) && is_app_of(b, m_family_id, OP_SEQ_UNIT)) { - return true; + return m_manager->are_distinct(a->get_arg(0), b->get_arg(0)); } if (is_app_of(a, m_family_id, OP_SEQ_EMPTY) && is_app_of(b, m_family_id, OP_SEQ_UNIT)) { From a85a612bae9e09e40981df809c06d97669b16073 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Nov 2018 10:03:43 -0800 Subject: [PATCH 163/227] use old-fashined C for test_capi Signed-off-by: Nikolaj Bjorner --- examples/c/test_capi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 14e403826..dbcd0e82a 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -379,6 +379,7 @@ void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f) Z3_sort t; Z3_symbol f_name, t_name; Z3_ast_vector q; + unsigned i; t = Z3_get_range(ctx, f); @@ -399,7 +400,7 @@ void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f) 1, &t_name, &t, 1, &f_name, &f); printf("assert axiom:\n%s\n", Z3_ast_vector_to_string(ctx, q)); - for (unsigned i = 0; i < Z3_ast_vector_size(ctx, q); ++i) { + for (i = 0; i < Z3_ast_vector_size(ctx, q); ++i) { Z3_solver_assert(ctx, s, Z3_ast_vector_get(ctx, q, i)); } } @@ -1644,6 +1645,7 @@ void parser_example2() Z3_symbol names[2]; Z3_func_decl decls[2]; Z3_ast_vector f; + unsigned i; printf("\nparser_example2\n"); LOG_MSG("parser_example2"); @@ -1668,7 +1670,7 @@ void parser_example2() 2, names, decls); printf("formula: %s\n", Z3_ast_vector_to_string(ctx, f)); printf("assert axiom:\n%s\n", Z3_ast_vector_to_string(ctx, f)); - for (unsigned i = 0; i < Z3_ast_vector_size(ctx, f); ++i) { + for (i = 0; i < Z3_ast_vector_size(ctx, f); ++i) { Z3_solver_assert(ctx, s, Z3_ast_vector_get(ctx, f, i)); } check(ctx, s, Z3_L_TRUE); From 8bfeca063d45a8bcefa9157b28a69bcd66d62b02 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Nov 2018 10:36:27 -0800 Subject: [PATCH 164/227] update example build for dotnet core Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 9c5b0c9a9..ced57ab77 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2428,7 +2428,8 @@ class DotNetExampleComponent(ExampleComponent): out.write(' ') out.write(os.path.join(self.to_ex_dir, csfile)) - proj_path = os.path.join(BUILD_DIR, proj_name) + mk_dir(os.path.join(BUILD_DIR, 'dotnet_example')) + csproj = os.path.join('dotnet_example', proj_name) if VS_X64: platform = 'x64' elif VS_ARM: @@ -2443,18 +2444,18 @@ class DotNetExampleComponent(ExampleComponent): %s - + - Microsoft.Z3.dll + ..\Microsoft.Z3.dll """ % (platform, self.to_ex_dir) - with open(proj_path, 'w') as ous: + with open(os.path.join(BUILD_DIR, csproj), 'w') as ous: ous.write(dotnet_proj_str) out.write('\n') - dotnetCmdLine = [DOTNET, "build", proj_name] + dotnetCmdLine = [DOTNET, "build", csproj] dotnetCmdLine.extend(['-c']) if DEBUG_MODE: dotnetCmdLine.extend(['Debug']) From bb5837791a21f9f7bd8e85b381e3dc36ec8c03ab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Nov 2018 11:02:49 -0800 Subject: [PATCH 165/227] clean up dotnet core component Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 62 +++++----------------------------------------- 1 file changed, 6 insertions(+), 56 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index ced57ab77..5bba2420a 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1829,7 +1829,7 @@ class DotNetDLLComponent(Component): MakeRuleCmd.remove_installed_files(out, pkg_config_file) -# TBD: retool the following for 'dotnet build' +# build for dotnet core class DotNetCoreDLLComponent(Component): def __init__(self, name, dll_name, path, deps, assembly_info_dir, default_key_file): Component.__init__(self, name, path, deps) @@ -1841,15 +1841,9 @@ class DotNetCoreDLLComponent(Component): self.assembly_info_dir = assembly_info_dir self.key_file = default_key_file - def mk_nuget_config_file(self): - # TBD revise - """ - Create nuget file for the dot net bindings. These - are needed by Monodevelop. - """ - return def mk_makefile(self, out): + # TBD: handle keyfile global DOTNET_KEY_FILE if not is_dotnet_core_enabled(): return @@ -1915,26 +1909,20 @@ class DotNetCoreDLLComponent(Component): else: dotnetCmdLine.extend(['Release']) - path = os.path.abspath(BUILD_DIR) dotnetCmdLine.extend(['-o', path]) - # Now emit the command line MakeRuleCmd.write_cmd(out, ' '.join(dotnetCmdLine)) - # State that the high-level "dotnet" target depends on the .NET bindings - # dll we just created the build rule for out.write('\n') out.write('%s: %s\n\n' % (self.name, dllfile)) - # Create nuget file - self.mk_nuget_config_file() - return def main_component(self): return is_dotnet_core_enabled() def has_assembly_info(self): + # TBD: is this required for dotnet core given that version numbers are in z3.csproj file? return True def mk_win_dist(self, build_path, dist_path): @@ -1957,51 +1945,13 @@ class DotNetCoreDLLComponent(Component): '%s.deps.json' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) def mk_install_deps(self, out): - if not is_dotnet_core_enabled(): - return - out.write('%s' % self.name) - - def gac_pkg_name(self): - return "{}.Sharp".format(self.dll_name) - - def _install_or_uninstall_to_gac(self, out, install): - # TBD revise for nuget - gacUtilFlags = ['/package {}'.format(self.gac_pkg_name()), - '/root', - '{}{}'.format(MakeRuleCmd.install_root(), INSTALL_LIB_DIR) - ] - if install: - install_or_uninstall_flag = '-i' - else: - # Note need use ``-us`` here which takes an assembly file name - # rather than ``-u`` which takes an assembly display name (e.g. - # ) - install_or_uninstall_flag = '-us' - MakeRuleCmd.write_cmd(out, '{gacutil} {install_or_uninstall_flag} {assembly_name}.dll -f {flags}'.format( - gacutil=GACUTIL, - install_or_uninstall_flag=install_or_uninstall_flag, - assembly_name=self.dll_name, - flags=' '.join(gacUtilFlags))) + pass def mk_install(self, out): - # TBD revise for nuget - if not is_dotnet_core_enabled(): - return - self._install_or_uninstall_to_gac(out, install=True) - - # Install pkg-config file. Monodevelop needs this to find Z3 - pkg_config_output = os.path.join(self.build_dir, - '{}.pc'.format(self.gac_pkg_name())) - MakeRuleCmd.make_install_directory(out, INSTALL_PKGCONFIG_DIR) - MakeRuleCmd.install_files(out, pkg_config_output, INSTALL_PKGCONFIG_DIR) + pass def mk_uninstall(self, out): - # TBD revise for nuget - if not is_dotnet_core_enabled(): - return - self._install_or_uninstall_to_gac(out, install=False) - pkg_config_file = os.path.join('lib','pkgconfig','{}.pc'.format(self.gac_pkg_name())) - MakeRuleCmd.remove_installed_files(out, pkg_config_file) + pass class JavaDLLComponent(Component): def __init__(self, name, dll_name, package_name, manifest_file, path, deps): From becf5de8720b44c286e504050a018ef6c9b0efe9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Nov 2018 16:16:15 -0800 Subject: [PATCH 166/227] with Mathias on nuget package generation Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_release.py | 93 ++++++++++++++++++++++++++++--------- scripts/mk_project.py | 5 +- 2 files changed, 76 insertions(+), 22 deletions(-) diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index 98a7c6362..1db75cd69 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -14,6 +14,10 @@ import urllib.request import zipfile import sys import os.path +import shutil +import subprocess +import mk_util +import mk_project data = json.loads(urllib.request.urlopen("https://api.github.com/repos/Z3Prover/z3/releases/latest").read().decode()) @@ -27,36 +31,83 @@ def download_installs(): for asset in data['assets']: url = asset['browser_download_url'] name = asset['name'] + if "x64" not in name: + continue print("Downloading ", url) sys.stdout.flush() urllib.request.urlretrieve(url, "packages/%s" % name) -os_names = ["ubuntu-14", "ubuntu-16", "win", "debian", "osx"] +os_info = {"ubuntu-14" : ('so', 'ubuntu.14.04-x64'), + 'ubuntu-16' : ('so', 'ubuntu.16.04-x64'), + 'win' : ('dll', 'win-x64'), + 'debian' : ('so', 'debian.8-x64') } +def classify_package(f): + for os_name in os_info: + if os_name in f: + ext, dst = os_info[os_name] + return os_name, f[:-4], ext, dst + return None + def unpack(): - for f in os.listdir("packages"): - if f.endswith("zip") and "x64" in f: - print(f) - # determine os from os_names - # instead of this string manipulation. - - name = os.path.splitext(f)[0] - os_name = name[name.find("x64")+4:] - os_name = os_name[:os_name.find("-")] - print(os_name) - - zip_ref = zipfile.ZipFile("packages/%s" % f, 'r') - path = "out/%s" % os_name - zip_ref.extract("%s/bin/libz3.so" % name) - # unzip files in packages - pass + # out + # +- runtimes + # +- win-x64 + # +- ubuntu.16.04-x64 + # +- ubuntu.14.04-x64 + # +- debian.8-x64 + # + + for f in os.listdir("packages"): + if f.endswith("zip") and "x64" in f and classify_package(f): + print(f) + os_name, package_dir, ext, dst = classify_package(f) + zip_ref = zipfile.ZipFile("packages/%s" % f, 'r') + zip_ref.extract("%s/bin/libz3.%s" % (package_dir, ext), "tmp") + mk_dir("out/runtimes/%s" % dst) + shutil.move("tmp/%s/bin/libz3.%s" % (package_dir, ext), "out/runtimes/%s/." % dst) + if "win" in f: + mk_dir("out/lib/netstandard1.0/") + for b in ["Microsoft.Z3.dll"]: + zip_ref.extract("%s/bin/%s" % (package_dir, b), "tmp") + shutil.move("tmp/%s/bin/%s" % (package_dir, b), "out/lib/netstandard1.0/%s" % b) + +def create_nuget_spec(): + mk_project.init_version() + contents = """ + + + Microsoft.Z3.x64 + %s + Microsoft + Z3 is a satisfiability modulo theories solver from Microsoft Research. + Copyright Microsoft Corporation. All rights reserved. + smt constraint solver theorem prover + https://raw.githubusercontent.com/Z3Prover/z3/master/package/icon.jpg + https://github.com/Z3Prover/z3 + https://raw.githubusercontent.com/Z3Prover/z3/master/LICENSE.txt + + true + en + +""" + + with open("out/Microsoft.Z3.x64.nuspec", 'w') as f: + f.write(contents % mk_util.get_version_string(3)) + +def create_nuget_package(): + subprocess.call(["nuget", "pack"], cwd="out") def main(): mk_dir("packages") -# download_installs() -# create_nuget_dir() + #download_installs() unpack() -# create_nuget_package() - + create_nuget_spec() + create_nuget_package() + + main() diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 5bd96c0fc..e70a094a0 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -7,9 +7,12 @@ ############################################ from mk_util import * +def init_version(): + set_version(4, 8, 3, 0) + # Z3 Project definition def init_project_def(): - set_version(4, 8, 3, 0) + init_version() add_lib('util', [], includes2install = ['z3_version.h']) add_lib('polynomial', ['util'], 'math/polynomial') add_lib('sat', ['util']) From 60d7444c965fa2c2481120dd25c29c1257f96f89 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Nov 2018 16:16:38 -0800 Subject: [PATCH 167/227] build generated files outside of src Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_release.py | 2 +- scripts/mk_util.py | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index 98a7c6362..2b7734fe0 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -54,7 +54,7 @@ def unpack(): def main(): mk_dir("packages") -# download_installs() + download_installs() # create_nuget_dir() unpack() # create_nuget_package() diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 5bba2420a..7e405f42f 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1909,7 +1909,7 @@ class DotNetCoreDLLComponent(Component): else: dotnetCmdLine.extend(['Release']) - path = os.path.abspath(BUILD_DIR) + path = os.path.join(os.path.abspath(BUILD_DIR), ".") dotnetCmdLine.extend(['-o', path]) MakeRuleCmd.write_cmd(out, ' '.join(dotnetCmdLine)) @@ -3170,7 +3170,8 @@ def mk_bindings(api_files): if is_dotnet_enabled(): dotnet_output_dir = get_component('dotnet').src_dir elif is_dotnet_core_enabled(): - dotnet_output_dir = get_component('dotnetcore').src_dir + dotnet_output_dir = os.path.join(BUILD_DIR, 'dotnet') + mk_dir(dotnet_output_dir) java_output_dir = None java_package_name = None if is_java_enabled(): @@ -3199,10 +3200,10 @@ def mk_bindings(api_files): mk_z3consts_ml(api_files) if is_dotnet_enabled(): check_dotnet() - mk_z3consts_dotnet(api_files) + mk_z3consts_dotnet(api_files, dotnet_output_dir) if is_dotnet_core_enabled(): check_dotnet_core() - mk_z3consts_dotnet(api_files) + mk_z3consts_dotnet(api_files, dotnet_output_dir) # Extract enumeration types from API files, and add python definitions. def mk_z3consts_py(api_files): @@ -3219,7 +3220,7 @@ def mk_z3consts_py(api_files): print("Generated '{}".format(generated_file)) # Extract enumeration types from z3_api.h, and add .Net definitions -def mk_z3consts_dotnet(api_files): +def mk_z3consts_dotnet(api_files, output_dir): dotnet = get_component(DOTNET_COMPONENT) if not dotnet: dotnet = get_component(DOTNET_CORE_COMPONENT) @@ -3228,7 +3229,7 @@ def mk_z3consts_dotnet(api_files): api_file_c = dotnet.find_file(api_file, dotnet.name) api_file = os.path.join(api_file_c.src_dir, api_file) full_path_api_files.append(api_file) - generated_file = mk_genfile_common.mk_z3consts_dotnet_internal(full_path_api_files, dotnet.src_dir) + generated_file = mk_genfile_common.mk_z3consts_dotnet_internal(full_path_api_files, output_dir) if VERBOSE: print("Generated '{}".format(generated_file)) From f4ced3c1647d1288d3dd0df8cf9e95b0d92c5f2c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Nov 2018 16:40:35 -0800 Subject: [PATCH 168/227] use netstandard1.4 Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_release.py | 4 ++-- scripts/mk_util.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index 2847f2884..09cfd2b7a 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -67,10 +67,10 @@ def unpack(): mk_dir("out/runtimes/%s" % dst) shutil.move("tmp/%s/bin/libz3.%s" % (package_dir, ext), "out/runtimes/%s/." % dst) if "win" in f: - mk_dir("out/lib/netstandard1.0/") + mk_dir("out/lib/netstandard1.4/") for b in ["Microsoft.Z3.dll"]: zip_ref.extract("%s/bin/%s" % (package_dir, b), "tmp") - shutil.move("tmp/%s/bin/%s" % (package_dir, b), "out/lib/netstandard1.0/%s" % b) + shutil.move("tmp/%s/bin/%s" % (package_dir, b), "out/lib/netstandard1.4/%s" % b) def create_nuget_spec(): mk_project.init_version() diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 7e405f42f..790de530d 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1872,14 +1872,13 @@ class DotNetCoreDLLComponent(Component): core_csproj_str = """ - netcoreapp1.0 + netstandard1.4 %s $(DefineConstants);DOTNET_CORE portable Microsoft.Z3 Library Microsoft.Z3 - $(PackageTargetFallback);dnxcore50 1.0.4 %s true From 5ebe342da14995fe8f89c99dd9cbbae008af5591 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Nov 2018 13:27:58 -0800 Subject: [PATCH 169/227] add support for keyfiles Signed-off-by: Nikolaj Bjorner --- scripts/mk_unix_dist.py | 6 +++++- scripts/mk_util.py | 42 +++++++++++++++++++++++++---------------- scripts/mk_win_dist.py | 2 +- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 00cf3c706..06d87cd63 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -186,7 +186,11 @@ def mk_dist_dir(): build_path = BUILD_DIR dist_path = os.path.join(DIST_DIR, get_z3_name()) mk_dir(dist_path) - mk_util.DOTNET_ENABLED = DOTNET_ENABLED + name = get_z3_name() + if "x64" in name or "mac" in name: + mk_util.DOTNET_CORE_ENABLED = DOTNET_ENABLED + else: + mk_util.DOTNET_ENABLED = DOTNET_ENABLED mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE mk_util.JAVA_ENABLED = JAVA_ENABLED mk_util.PYTHON_ENABLED = PYTHON_ENABLED diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 790de530d..bb91df59b 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -668,6 +668,7 @@ def display_help(exit_code): if IS_WINDOWS: print(" -v, --vsproj generate Visual Studio Project Files.") print(" --optimize generate optimized code during linking.") + print(" --dotnetcore generate .NET platform bindings.") print(" --dotnet generate .NET bindings.") print(" --dotnet-key= sign the .NET assembly using the private key in .") print(" --java generate Java bindings.") @@ -1627,6 +1628,23 @@ class PythonInstallComponent(Component): def mk_makefile(self, out): return +def set_key_file(self): + global DOTNET_KEY_FILE + # We need to give the assembly a strong name so that it + # can be installed into the GAC with ``make install`` + if not DOTNET_KEY_FILE is None: + self.key_file = DOTNET_KEY_FILE + + if not self.key_file is None: + if os.path.isfile(self.key_file): + self.key_file = os.path.abspath(self.key_file) + elif os.path.isfile(os.path.join(self.src_dir, self.key_file)): + self.key_file = os.path.abspath(os.path.join(self.src_dir, self.key_file)) + else: + print("Keyfile '%s' could not be found; %s.dll will be unsigned." % (self.key_file, self.dll_name)) + self.key_file = None + + class DotNetDLLComponent(Component): def __init__(self, name, dll_name, path, deps, assembly_info_dir, default_key_file): Component.__init__(self, name, path, deps) @@ -1688,19 +1706,7 @@ class DotNetDLLComponent(Component): ] ) - # We need to give the assembly a strong name so that it - # can be installed into the GAC with ``make install`` - if not DOTNET_KEY_FILE is None: - self.key_file = DOTNET_KEY_FILE - - if not self.key_file is None: - if os.path.isfile(self.key_file): - self.key_file = os.path.abspath(self.key_file) - elif os.path.isfile(os.path.join(self.src_dir, self.key_file)): - self.key_file = os.path.abspath(os.path.join(self.src_dir, self.key_file)) - else: - print("Keyfile '%s' could not be found; %s.dll will be unsigned." % (self.key_file, self.dll_name)) - self.key_file = None + set_key_file(self) if not self.key_file is None: print("%s.dll will be signed using key '%s'." % (self.dll_name, self.key_file)) @@ -1843,8 +1849,6 @@ class DotNetCoreDLLComponent(Component): def mk_makefile(self, out): - # TBD: handle keyfile - global DOTNET_KEY_FILE if not is_dotnet_core_enabled(): return cs_fp_files = [] @@ -1859,6 +1863,11 @@ class DotNetCoreDLLComponent(Component): out.write(' ') out.write(cs_file) out.write('\n') + + set_key_file(self) + key = "" + if not self.key_file is None: + key = "%s" % self.key_file if VS_X64: platform = 'x64' @@ -1887,13 +1896,14 @@ class DotNetCoreDLLComponent(Component): Z3 is a satisfiability modulo theories solver from Microsoft Research. Copyright Microsoft Corporation. All rights reserved. smt constraint solver theorem prover + %s -""" % (platform, version, self.to_src_dir) +""" % (platform, version, key, self.to_src_dir) mk_dir(os.path.join(BUILD_DIR, 'dotnet')) csproj = os.path.join('dotnet', 'z3.csproj') diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 9e0374192..10865676d 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -208,7 +208,7 @@ def mk_dist_dir(x64): build_path = BUILD_X86_DIR dist_path = os.path.join(DIST_DIR, get_z3_name(x64)) mk_dir(dist_path) - mk_util.DOTNET_ENABLED = DOTNET_ENABLED + mk_util.DOTNET_CORE_ENABLED = DOTNET_ENABLED mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE mk_util.JAVA_ENABLED = JAVA_ENABLED mk_util.PYTHON_ENABLED = PYTHON_ENABLED From cfb14c879a4cd063a17b06ca0d5ffe6a864bb5d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Nov 2018 13:59:00 -0800 Subject: [PATCH 170/227] make dotnet core dist optional Signed-off-by: Nikolaj Bjorner --- scripts/mk_unix_dist.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 06d87cd63..8e5336f67 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -23,6 +23,7 @@ VERBOSE=True DIST_DIR='dist' FORCE_MK=False DOTNET_ENABLED=True +DOTNET_CORE_ENABLED=False DOTNET_KEY_FILE=None JAVA_ENABLED=True GIT_HASH=False @@ -55,6 +56,7 @@ def display_help(): 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(" --nodotnet do not include .NET bindings in the binary distribution files.") + print(" --dotnetcore build for dotnet core.") print(" --dotnet-key= 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.") @@ -88,6 +90,8 @@ def parse_options(): FORCE_MK = True elif opt == '--nodotnet': DOTNET_ENABLED = False + elif opt == '--dotnetcore': + DOTNET_CORE_ENABLED = True elif opt == '--nopython': PYTHON_ENABLED = False elif opt == '--dotnet-key': @@ -108,7 +112,11 @@ def check_build_dir(path): def mk_build_dir(path): if not check_build_dir(path) or FORCE_MK: opts = ["python", os.path.join('scripts', 'mk_make.py'), "-b", path, "--staticlib"] - if DOTNET_ENABLED: + if DOTNET_CORE_ENABLED: + opts.append('--dotnetcore') + if not DOTNET_KEY_FILE is None: + opts.append('--dotnet-key=' + DOTNET_KEY_FILE) + elif DOTNET_ENABLED: opts.append('--dotnet') if not DOTNET_KEY_FILE is None: opts.append('--dotnet-key=' + DOTNET_KEY_FILE) @@ -187,7 +195,7 @@ def mk_dist_dir(): dist_path = os.path.join(DIST_DIR, get_z3_name()) mk_dir(dist_path) name = get_z3_name() - if "x64" in name or "mac" in name: + if DOTNET_CORE_ENABLED: mk_util.DOTNET_CORE_ENABLED = DOTNET_ENABLED else: mk_util.DOTNET_ENABLED = DOTNET_ENABLED From 1a5be0f25e0c8eb5c11e32eec979376fa03af214 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Nov 2018 15:14:43 -0800 Subject: [PATCH 171/227] make dotnet core dist optional Signed-off-by: Nikolaj Bjorner --- scripts/mk_unix_dist.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 8e5336f67..3e4456676 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -73,6 +73,7 @@ def parse_options(): 'force', 'nojava', 'nodotnet', + 'dotnetcore', 'dotnet-key=', 'githash', 'nopython' @@ -194,9 +195,8 @@ def mk_dist_dir(): build_path = BUILD_DIR dist_path = os.path.join(DIST_DIR, get_z3_name()) mk_dir(dist_path) - name = get_z3_name() if DOTNET_CORE_ENABLED: - mk_util.DOTNET_CORE_ENABLED = DOTNET_ENABLED + mk_util.DOTNET_CORE_ENABLED = True else: mk_util.DOTNET_ENABLED = DOTNET_ENABLED mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE From 69dc74923908206f0a568ee89fd6cc1c8392802c Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sat, 17 Nov 2018 21:02:00 +0700 Subject: [PATCH 172/227] Fix missing word in doc comment. --- src/api/z3_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index e1359949d..be463b1b0 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5579,7 +5579,7 @@ extern "C" { \brief Convert a goal into a DIMACS formatted string. The goal must be in CNF. You can convert a goal to CNF by applying the tseitin-cnf tactic. Bit-vectors are not automatically - converted to Booleans either, so the caller intends to + converted to Booleans either, so if the caller intends to preserve satisfiability, it should apply bit-blasting tactics. Quantifiers and theory atoms will not be encoded. From 9ec59fdb9338bd91ac0487d6b2fea8d6ba402ae7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Nov 2018 15:04:25 -0800 Subject: [PATCH 173/227] fix #1934 Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 4 +- src/opt/maxres.cpp | 117 +++++++++++++++++++------------- src/opt/opt_context.cpp | 14 ++-- src/solver/check_sat_result.cpp | 1 + 4 files changed, 83 insertions(+), 53 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 88d7d7246..261890922 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -456,7 +456,9 @@ def check_dotnet(): raise MKException('Failed testing gacutil. Set environment variable GACUTIL with the path to gacutil.') def check_dotnet_core(): - # TBD: check DOTNET + # r = exec_cmd([DOTNET]) + # if r != 0: + # raise ... pass def check_ml(): diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 0b5f20db8..7f8b8ba91 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -108,6 +108,7 @@ private: bool m_pivot_on_cs; // prefer smaller correction set to core. bool m_dump_benchmarks; // display benchmarks (into wcnf format) + std::string m_trace_id; typedef ptr_vector exprs; @@ -152,6 +153,14 @@ public: (m.is_not(l, l) && is_uninterp_const(l)); } + void add(expr_ref_vector const& es) { + for (expr* e : es) add(e); + } + + void add(expr* e) { + s().assert_expr(e); + } + void add_soft(expr* e, rational const& w) { TRACE("opt", tout << mk_pp(e, m) << " |-> " << w << "\n";); expr_ref asum(m), fml(m); @@ -168,7 +177,7 @@ public: else { asum = mk_fresh_bool("soft"); fml = m.mk_iff(asum, e); - s().assert_expr(fml); + add(fml); } new_assumption(asum, w); } @@ -194,11 +203,8 @@ public: if (is_sat != l_true) return is_sat; while (m_lower < m_upper) { TRACE("opt_verbose", - display_vec(tout, m_asms); - s().display(tout); - tout << "\n"; - display(tout); - ); + s().display(tout << m_asms << "\n") << "\n"; + display(tout);); is_sat = check_sat_hill_climb(m_asms); if (m.canceled()) { return l_undef; @@ -206,8 +212,7 @@ public: switch (is_sat) { case l_true: CTRACE("opt", !m_model->is_true(m_asms), - tout << *m_model; - tout << "assumptions: "; + tout << *m_model << "assumptions: "; for (expr* a : m_asms) tout << mk_pp(a, m) << " -> " << (*m_model)(a) << " "; tout << "\n";); SASSERT(m_model->is_true(m_asms)); @@ -320,6 +325,7 @@ public: void found_optimum() { IF_VERBOSE(1, verbose_stream() << "found optimum\n";); + verify_assumptions(); m_lower.reset(); for (soft& s : m_soft) { s.is_true = m_model->is_true(s.s); @@ -348,7 +354,14 @@ public: st.update("maxres-correction-sets", m_stats.m_num_cs); } - lbool get_cores(vector& cores) { + struct weighted_core { + exprs m_core; + rational m_weight; + weighted_core(exprs const& c, rational const& w): + m_core(c), m_weight(w) {} + }; + + lbool get_cores(vector& cores) { // assume m_s is unsat. lbool is_sat = l_false; cores.reset(); @@ -361,7 +374,7 @@ public: get_mus_model(mdl); is_sat = minimize_core(_core); core.append(_core.size(), _core.c_ptr()); - // verify_core(core); + verify_core(core); ++m_stats.m_num_cores; if (is_sat != l_true) { IF_VERBOSE(100, verbose_stream() << "(opt.maxres minimization failed)\n";); @@ -373,13 +386,16 @@ public: m_lower = m_upper; return l_true; } + + // 1. remove all core literals from m_asms // 2. re-add literals of higher weight than min-weight. // 3. 'core' stores the core literals that are // re-encoded as assumptions, afterwards + cores.push_back(weighted_core(core, core_weight(core))); + remove_soft(core, m_asms); - split_core(core); - cores.push_back(core); + split_core(core); if (core.size() >= m_max_core_size) break; if (cores.size() >= m_max_num_cores) break; @@ -456,7 +472,7 @@ public: } lbool process_unsat() { - vector cores; + vector cores; lbool is_sat = get_cores(cores); if (is_sat != l_true) { return is_sat; @@ -478,9 +494,9 @@ public: return result; } - void process_unsat(vector const& cores) { + void process_unsat(vector const& cores) { for (auto const & c : cores) { - process_unsat(c); + process_unsat(c.m_core, c.m_weight); } } @@ -491,16 +507,15 @@ public: } } - void process_unsat(exprs const& core) { + void process_unsat(exprs const& core, rational w) { IF_VERBOSE(3, verbose_stream() << "(maxres cs model valid: " << (m_csmodel.get() != nullptr) << " cs size:" << m_correction_set_size << " core: " << core.size() << ")\n";); expr_ref fml(m); SASSERT(!core.empty()); - rational w = core_weight(core); TRACE("opt", display_vec(tout << "minimized core: ", core);); - IF_VERBOSE(10, display_vec(verbose_stream() << "core: ", core);); + IF_VERBOSE(10, display_vec(verbose_stream() << "core: ", core);); max_resolve(core, w); fml = mk_not(m, mk_and(m, core.size(), core.c_ptr())); - s().assert_expr(fml); + add(fml); m_lower += w; if (m_st == s_primal_dual) { m_lower = std::min(m_lower, m_upper); @@ -636,10 +651,10 @@ public: else { dd = mk_fresh_bool("d"); fml = m.mk_implies(dd, d); - s().assert_expr(fml); + add(fml); m_defs.push_back(fml); fml = m.mk_implies(dd, b_i); - s().assert_expr(fml); + add(fml); m_defs.push_back(fml); fml = m.mk_and(d, b_i); update_model(dd, fml); @@ -650,7 +665,7 @@ public: fml = m.mk_implies(asum, cls); update_model(asum, cls); new_assumption(asum, w); - s().assert_expr(fml); + add(fml); m_defs.push_back(fml); } } @@ -682,7 +697,7 @@ public: d = mk_fresh_bool("d"); fml = m.mk_implies(d, cls); update_model(d, cls); - s().assert_expr(fml); + add(fml); m_defs.push_back(fml); } @@ -691,10 +706,10 @@ public: } asum = mk_fresh_bool("a"); fml = m.mk_implies(asum, b_i1); - s().assert_expr(fml); + add(fml); m_defs.push_back(fml); fml = m.mk_implies(asum, cls); - s().assert_expr(fml); + add(fml); m_defs.push_back(fml); new_assumption(asum, w); @@ -702,7 +717,7 @@ public: update_model(asum, fml); } fml = m.mk_or(cs.size(), cs.c_ptr()); - s().assert_expr(fml); + add(fml); } void update_assignment(model_ref & mdl) { @@ -747,7 +762,7 @@ public: s.is_true = m_model->is_true(s.s); } - // DEBUG_CODE(verify_assignment();); + verify_assignment(); m_upper = upper; @@ -768,7 +783,7 @@ public: } fml = u.mk_lt(nsoft.size(), weights.c_ptr(), nsoft.c_ptr(), m_upper); TRACE("opt", tout << "block upper bound " << fml << "\n";);; - s().assert_expr(fml); + add(fml); } void remove_soft(exprs const& core, expr_ref_vector& asms) { @@ -819,40 +834,50 @@ public: void commit_assignment() override { if (m_found_feasible_optimum) { TRACE("opt", tout << "Committing feasible solution\n" << m_defs << " " << m_asms;); - s().assert_expr(m_defs); - s().assert_expr(m_asms); + add(m_defs); + add(m_asms); } // else: there is only a single assignment to these soft constraints. } void verify_core(exprs const& core) { - IF_VERBOSE(3, verbose_stream() << "verify core\n";); - ref smt_solver = mk_smt_solver(m, m_params, symbol()); - smt_solver->assert_expr(s().get_assertions()); - smt_solver->assert_expr(core); - lbool is_sat = smt_solver->check_sat(0, nullptr); - if (is_sat == l_true) { - IF_VERBOSE(0, verbose_stream() << "not a core\n";); - } + if (!gparams::get_ref().get_bool("model_validate", false)) return; + IF_VERBOSE(3, verbose_stream() << "verify core " << s().check_sat(core.size(), core.c_ptr()) << "\n";); + ref _solver = mk_smt_solver(m, m_params, symbol()); + _solver->assert_expr(s().get_assertions()); + _solver->assert_expr(core); + lbool is_sat = _solver->check_sat(0, nullptr); + IF_VERBOSE(0, verbose_stream() << "core status (l_false:) " << is_sat << "\n"); + VERIFY(is_sat == l_false); + } + + void verify_assumptions() { + if (!gparams::get_ref().get_bool("model_validate", false)) return; + IF_VERBOSE(1, verbose_stream() << "verify assumptions\n";); + ref _solver = mk_smt_solver(m, m_params, symbol()); + _solver->assert_expr(s().get_assertions()); + _solver->assert_expr(m_asms); + lbool is_sat = _solver->check_sat(0, nullptr); + IF_VERBOSE(1, verbose_stream() << "assignment status (l_true) " << is_sat << "\n";); + VERIFY(is_sat == l_true); } void verify_assignment() { + if (!gparams::get_ref().get_bool("model_validate", false)) return; IF_VERBOSE(1, verbose_stream() << "verify assignment\n";); - ref smt_solver = mk_smt_solver(m, m_params, symbol()); - smt_solver->assert_expr(s().get_assertions()); + ref _solver = mk_smt_solver(m, m_params, symbol()); + _solver->assert_expr(s().get_assertions()); expr_ref n(m); for (soft& s : m_soft) { n = s.s; if (!s.is_true) { n = mk_not(m, n); } - smt_solver->assert_expr(n); + _solver->assert_expr(n); } - lbool is_sat = smt_solver->check_sat(0, nullptr); - if (is_sat == l_false) { - IF_VERBOSE(0, verbose_stream() << "assignment is infeasible\n";); - } - IF_VERBOSE(1, verbose_stream() << "verified\n";); + lbool is_sat = _solver->check_sat(0, nullptr); + IF_VERBOSE(1, verbose_stream() << "assignment status (l_true) " << is_sat << "\n"); + VERIFY(is_sat == l_true); } }; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index d9c3457fa..29246c6f5 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -284,7 +284,9 @@ namespace opt { symbol pri = optp.priority(); IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n"); + lbool is_sat = s.check_sat(asms.size(),asms.c_ptr()); + TRACE("opt", s.display(tout << "initial search result: " << is_sat << "\n");); if (is_sat != l_false) { s.get_model(m_model); @@ -1555,7 +1557,6 @@ namespace opt { } void context::validate_model() { - return; if (!gparams::get_ref().get_bool("model_validate", false)) return; expr_ref_vector fmls(m); get_hard_constraints(fmls); @@ -1565,11 +1566,12 @@ namespace opt { mdl->set_model_completion(true); for (expr * f : fmls) { if (!mdl->is_true(f)) { - //IF_VERBOSE(0, m_fm->display(verbose_stream() << "fm\n")); - IF_VERBOSE(0, m_model_converter->display(verbose_stream() << "mc\n")); - IF_VERBOSE(0, verbose_stream() << "Failed to validate " << mk_pp(f, m) << "\n" << tmp << "\n"); - IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *mdl, 0)); - IF_VERBOSE(11, verbose_stream() << to_string_internal() << "\n"); + IF_VERBOSE(0, + verbose_stream() << "Failed to validate " << mk_pp(f, m) << "\n" << tmp << "\n"; + m_fm->display(verbose_stream() << "fm\n"); + m_model_converter->display(verbose_stream() << "mc\n"); + model_smt2_pp(verbose_stream(), m, *mdl, 0); + verbose_stream() << to_string_internal() << "\n"); exit(0); } } diff --git a/src/solver/check_sat_result.cpp b/src/solver/check_sat_result.cpp index 28e6afeca..7431618df 100644 --- a/src/solver/check_sat_result.cpp +++ b/src/solver/check_sat_result.cpp @@ -36,6 +36,7 @@ void check_sat_result::set_reason_unknown(event_handler& eh) { } } + simple_check_sat_result::simple_check_sat_result(ast_manager & m): m_core(m), m_proof(m) { From e98da4320b6febeac1a38c435f8d03d35fea69f0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Nov 2018 15:08:52 -0800 Subject: [PATCH 174/227] make dotnet core optional for mk_win_dist Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 10865676d..41229e438 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -25,6 +25,7 @@ VERBOSE=True DIST_DIR='dist' FORCE_MK=False DOTNET_ENABLED=True +DOTNET_CORE_ENABLED=False DOTNET_KEY_FILE=None JAVA_ENABLED=True GIT_HASH=False @@ -62,6 +63,7 @@ def display_help(): 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(" --nodotnet do not include .NET bindings in the binary distribution files.") + print(" --dotnetcore build for dotnet core.") print(" --dotnet-key= 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.") @@ -72,7 +74,7 @@ def display_help(): # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_KEY_FILE, PYTHON_ENABLED, X86ONLY, X64ONLY + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, PYTHON_ENABLED, X86ONLY, X64ONLY path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', @@ -80,6 +82,7 @@ def parse_options(): 'force', 'nojava', 'nodotnet', + 'dotnetcore', 'dotnet-key=', 'githash', 'nopython', @@ -99,6 +102,8 @@ def parse_options(): FORCE_MK = True elif opt == '--nodotnet': DOTNET_ENABLED = False + elif opt == '--dotnetcore': + DOTNET_CORE_ENABLED = True elif opt == '--nopython': PYTHON_ENABLED = False elif opt == '--dotnet-key': @@ -124,7 +129,11 @@ def mk_build_dir(path, x64): if not check_build_dir(path) or FORCE_MK: parallel = '--parallel=' + MAKEJOBS opts = ["python", os.path.join('scripts', 'mk_make.py'), parallel, "-b", path] - if DOTNET_ENABLED: + if DOTNET_CORE_ENABLED: + opts.append('--dotnetcore') + if not DOTNET_KEY_FILE is None: + opts.append('--dotnet-key=' + DOTNET_KEY_FILE) + elif DOTNET_ENABLED: opts.append('--dotnet') if not DOTNET_KEY_FILE is None: opts.append('--dotnet-key=' + DOTNET_KEY_FILE) @@ -208,7 +217,10 @@ def mk_dist_dir(x64): build_path = BUILD_X86_DIR dist_path = os.path.join(DIST_DIR, get_z3_name(x64)) mk_dir(dist_path) - mk_util.DOTNET_CORE_ENABLED = DOTNET_ENABLED + if DOTNET_CORE_ENABLED: + mk_util.DOTNET_CORE_ENABLED = True + else: + mk_util.DOTNET_CORE_ENABLED = DOTNET_ENABLED mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE mk_util.JAVA_ENABLED = JAVA_ENABLED mk_util.PYTHON_ENABLED = PYTHON_ENABLED From d45b8a3ac83ef49d5b46f32b26bac1f3dd1acfbf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Nov 2018 15:24:54 -0800 Subject: [PATCH 175/227] fix debug build, add access to numerics from model Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 20 ++++++++++++++++++++ src/api/dotnet/Model.cs | 8 ++++++++ src/opt/maxres.cpp | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index ac11022c1..a941f8e86 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -931,6 +931,26 @@ namespace Microsoft.Z3 return new BoolExpr(this, Native.Z3_mk_xor(nCtx, t1.NativeObject, t2.NativeObject)); } + /// + /// Create an expression representing t1 xor t2 xor t3 ... . + /// + public BoolExpr MkXor(IEnumerable ts) + { + Debug.Assert(ts != null); + Debug.Assert(ts.All(a => a != null)); + CheckContextMatch(ts); + BoolExpr r = null; + foreach (var t in ts) { + if (r == null) + r = t; + else + r = MkXor(r, t); + } + if (r == null) + r = MkTrue(); + return r; + } + /// /// Create an expression representing t[0] and t[1] and .... /// diff --git a/src/api/dotnet/Model.cs b/src/api/dotnet/Model.cs index c24516c22..c0cb091b0 100644 --- a/src/api/dotnet/Model.cs +++ b/src/api/dotnet/Model.cs @@ -238,6 +238,14 @@ namespace Microsoft.Z3 return Eval(t, completion); } + /// + /// Evaluate expression to a double, assuming it is a numeral already. + /// + public double Double(Expr t) { + var r = Eval(t, true); + return Native.Z3_get_numeral_double(Context.nCtx, r.NativeObject); + } + /// /// The number of uninterpreted sorts that the model has an interpretation for. /// diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 7f8b8ba91..98e6531ea 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -405,7 +405,7 @@ public: TRACE("opt", tout << "sat: " << is_sat << " num cores: " << cores.size() << "\n"; - for (auto const& c : cores) display_vec(tout, c); + for (auto const& c : cores) display_vec(tout, c.m_core); tout << "num assumptions: " << m_asms.size() << "\n";); return is_sat; From 141cd687ffe36f3f94b4de6b7e56eb2f07cbcb03 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Nov 2018 15:37:36 -0800 Subject: [PATCH 176/227] disable validation in builds Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 6 +++--- src/opt/opt_context.cpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 98e6531ea..75a42886c 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -841,7 +841,7 @@ public: } void verify_core(exprs const& core) { - if (!gparams::get_ref().get_bool("model_validate", false)) return; + return; IF_VERBOSE(3, verbose_stream() << "verify core " << s().check_sat(core.size(), core.c_ptr()) << "\n";); ref _solver = mk_smt_solver(m, m_params, symbol()); _solver->assert_expr(s().get_assertions()); @@ -852,7 +852,7 @@ public: } void verify_assumptions() { - if (!gparams::get_ref().get_bool("model_validate", false)) return; + return; IF_VERBOSE(1, verbose_stream() << "verify assumptions\n";); ref _solver = mk_smt_solver(m, m_params, symbol()); _solver->assert_expr(s().get_assertions()); @@ -863,7 +863,7 @@ public: } void verify_assignment() { - if (!gparams::get_ref().get_bool("model_validate", false)) return; + return; IF_VERBOSE(1, verbose_stream() << "verify assignment\n";); ref _solver = mk_smt_solver(m, m_params, symbol()); _solver->assert_expr(s().get_assertions()); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 29246c6f5..a6f3d8152 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1557,6 +1557,7 @@ namespace opt { } void context::validate_model() { + return; if (!gparams::get_ref().get_bool("model_validate", false)) return; expr_ref_vector fmls(m); get_hard_constraints(fmls); From 1603075189b2298dfbad2db8271663f898c49f6c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Nov 2018 15:46:06 -0800 Subject: [PATCH 177/227] add empty/full to java #1944 Signed-off-by: Nikolaj Bjorner --- src/api/java/Context.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 08d20dfb2..ede494598 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2173,6 +2173,22 @@ public class Context implements AutoCloseable { { checkContextMatch(t); return (ReExpr) Expr.create(this, Native.mkReIntersect(nCtx(), t.length, AST.arrayToNative(t))); + } + + /** + * Create the empty regular expression. + */ + public ReExpr mkEmptyRe(Sort s) + { + return (ReExpr) Expr.create(this, Native.mkReEmpty(nCtx(), s.getNativeObject())); + } + + /** + * Create the full regular expression. + */ + public ReExpr mkFullRe(Sort s) + { + return (ReExpr) Expr.create(this, Native.mkReFull(nCtx(), s.getNativeObject())); } /** From d400929d9a05423f7ed06c7d75fb4e55e3f13eec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Nov 2018 08:56:30 -0800 Subject: [PATCH 178/227] fix #1945 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 4ca4928d0..f3a3e9238 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -503,7 +503,7 @@ namespace smt { tout << "lower: " << lower << "\n"; tout << "upper: " << upper << "\n";); - mk_axiom(eqz, eq, true); + mk_axiom(eqz, eq, false); mk_axiom(eqz, lower, false); mk_axiom(eqz, upper, !m_util.is_numeral(abs_divisor)); rational k; From fb1287155e28a675d0783e4a24d1483126cd80b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Nov 2018 08:59:27 -0800 Subject: [PATCH 179/227] fix windows build_dist setting Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 41229e438..e61a7714c 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -220,7 +220,7 @@ def mk_dist_dir(x64): if DOTNET_CORE_ENABLED: mk_util.DOTNET_CORE_ENABLED = True else: - mk_util.DOTNET_CORE_ENABLED = DOTNET_ENABLED + mk_util.DOTNET_ENABLED = DOTNET_ENABLED mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE mk_util.JAVA_ENABLED = JAVA_ENABLED mk_util.PYTHON_ENABLED = PYTHON_ENABLED From 6ef2557e2a96657c85dee84397e4fdfa5027fe0d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Nov 2018 09:34:33 -0800 Subject: [PATCH 180/227] investigate #1946 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 4 + src/tactic/bv/bit_blaster_model_converter.cpp | 6 +- src/util/params.cpp | 101 ++++++++---------- 3 files changed, 50 insertions(+), 61 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index f68b908e2..70dcb158e 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6164,6 +6164,10 @@ class ModelRef(Z3PPObject): def __deepcopy__(self): return self.translate(self.ctx) +def Model(ctx = None): + ctx = _get_ctx(ctx) + return ModelRef(Z3_mk_model(ctx.ref()), ctx) + def is_as_array(n): """Return true if n is a Z3 expression of the form (_ as-array f).""" return isinstance(n, ExprRef) and Z3_is_as_array(n.ctx.ref(), n.as_ast()) diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index 5474700c3..be6ea8b7a 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -72,10 +72,8 @@ struct bit_blaster_model_converter : public model_converter { } TRACE("blaster_mc", tout << "bits that should not be included in the model:\n"; - obj_hashtable::iterator it = bits.begin(); - obj_hashtable::iterator end = bits.end(); - for (; it != end; ++it) { - tout << (*it)->get_name() << " "; + for (func_decl* f : bits) { + tout << f->get_name() << " "; } tout << "\n";); diff --git a/src/util/params.cpp b/src/util/params.cpp index d7e05cb00..43f53514a 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -161,19 +161,15 @@ struct param_descrs::imp { void display(std::ostream & out, unsigned indent, bool smt2_style, bool include_descr) const { svector names; - dictionary::iterator it = m_info.begin(); - dictionary::iterator end = m_info.end(); - for (; it != end; ++it) { - names.push_back(it->m_key); + for (auto const& kv : m_info) { + names.push_back(kv.m_key); } std::sort(names.begin(), names.end(), lt()); - svector::iterator it2 = names.begin(); - svector::iterator end2 = names.end(); - for (; it2 != end2; ++it2) { + for (symbol const& name : names) { for (unsigned i = 0; i < indent; i++) out << " "; if (smt2_style) out << ':'; - char const * s = it2->bare_str(); + char const * s = name.bare_str(); unsigned n = static_cast(strlen(s)); for (unsigned i = 0; i < n; i++) { if (smt2_style && s[i] == '_') @@ -186,7 +182,7 @@ struct param_descrs::imp { out << s[i]; } info d; - m_info.find(*it2, d); + m_info.find(name, d); SASSERT(d.m_descr); out << " (" << d.m_kind << ")"; if (include_descr) @@ -198,10 +194,8 @@ struct param_descrs::imp { } void copy(param_descrs & other) { - dictionary::iterator it = other.m_imp->m_info.begin(); - dictionary::iterator end = other.m_imp->m_info.end(); - for (; it != end; ++it) { - insert(it->m_key, it->m_value.m_kind, it->m_value.m_descr, it->m_value.m_default, it->m_value.m_module); + for (auto const& kv : other.m_imp->m_info) { + insert(kv.m_key, kv.m_value.m_kind, kv.m_value.m_descr, kv.m_value.m_default, kv.m_value.m_module); } } @@ -346,24 +340,22 @@ public: void reset(symbol const & k); void reset(char const * k); - void validate(param_descrs const & p) { - svector::iterator it = m_entries.begin(); - svector::iterator end = m_entries.end(); + void validate(param_descrs const & p) { symbol suffix, prefix; - for (; it != end; ++it) { - param_kind expected = p.get_kind_in_module(it->first); + for (params::entry& e : m_entries) { + param_kind expected = p.get_kind_in_module(e.first); if (expected == CPK_INVALID) { std::stringstream strm; - strm << "unknown parameter '" << it->first.str() << "'\n"; + strm << "unknown parameter '" << e.first.str() << "'\n"; strm << "Legal parameters are:\n"; p.display(strm, 2, false, false); throw default_exception(strm.str()); } - if (it->second.m_kind != expected && - !(it->second.m_kind == CPK_UINT && expected == CPK_NUMERAL)) { + if (e.second.m_kind != expected && + !(e.second.m_kind == CPK_UINT && expected == CPK_NUMERAL)) { std::stringstream strm; - strm << "Parameter " << it->first.str() << " was given argument of type "; - strm << it->second.m_kind << ", expected " << expected; + strm << "Parameter " << e.first.str() << " was given argument of type "; + strm << e.second.m_kind << ", expected " << expected; throw default_exception(strm.str()); } } @@ -405,28 +397,26 @@ public: void display(std::ostream & out) const { out << "(params"; - svector::const_iterator it = m_entries.begin(); - svector::const_iterator end = m_entries.end(); - for (; it != end; ++it) { - out << " " << it->first; - switch (it->second.m_kind) { + for (params::entry const& e : m_entries) { + out << " " << e.first; + switch (e.second.m_kind) { case CPK_BOOL: - out << " " << (it->second.m_bool_value?"true":"false"); + out << " " << (e.second.m_bool_value?"true":"false"); break; case CPK_UINT: - out << " " <second.m_uint_value; + out << " " <second.m_double_value; + out << " " << e.second.m_double_value; break; case CPK_NUMERAL: - out << " " << *(it->second.m_rat_value); + out << " " << *(e.second.m_rat_value); break; case CPK_SYMBOL: - out << " " << symbol::mk_symbol_from_c_ptr(it->second.m_sym_value); + out << " " << symbol::mk_symbol_from_c_ptr(e.second.m_sym_value); break; case CPK_STRING: - out << " " << it->second.m_str_value; + out << " " << e.second.m_str_value; break; default: UNREACHABLE(); @@ -437,31 +427,29 @@ public: } void display_smt2(std::ostream & out, char const* module, param_descrs& descrs) const { - svector::const_iterator it = m_entries.begin(); - svector::const_iterator end = m_entries.end(); - for (; it != end; ++it) { - if (!descrs.contains(it->first)) continue; + for (params::entry const& e : m_entries) { + if (!descrs.contains(e.first)) continue; out << "(set-option :"; out << module << "."; - out << it->first; - switch (it->second.m_kind) { + out << e.first; + switch (e.second.m_kind) { case CPK_BOOL: - out << " " << (it->second.m_bool_value?"true":"false"); + out << " " << (e.second.m_bool_value?"true":"false"); break; case CPK_UINT: - out << " " <second.m_uint_value; + out << " " <second.m_double_value; + out << " " << e.second.m_double_value; break; case CPK_NUMERAL: - out << " " << *(it->second.m_rat_value); + out << " " << *(e.second.m_rat_value); break; case CPK_SYMBOL: - out << " " << symbol::mk_symbol_from_c_ptr(it->second.m_sym_value); + out << " " << symbol::mk_symbol_from_c_ptr(e.second.m_sym_value); break; case CPK_STRING: - out << " " << it->second.m_str_value; + out << " " << e.second.m_str_value; break; default: UNREACHABLE(); @@ -472,29 +460,27 @@ public: } void display(std::ostream & out, symbol const & k) const { - svector::const_iterator it = m_entries.begin(); - svector::const_iterator end = m_entries.end(); - for (; it != end; ++it) { - if (it->first != k) + for (params::entry const& e : m_entries) { + if (e.first != k) continue; - switch (it->second.m_kind) { + switch (e.second.m_kind) { case CPK_BOOL: - out << (it->second.m_bool_value?"true":"false"); + out << (e.second.m_bool_value?"true":"false"); return; case CPK_UINT: - out << it->second.m_uint_value; + out << e.second.m_uint_value; return; case CPK_DOUBLE: - out << it->second.m_double_value; + out << e.second.m_double_value; return; case CPK_NUMERAL: - out << *(it->second.m_rat_value); + out << *(e.second.m_rat_value); return; case CPK_SYMBOL: - out << symbol::mk_symbol_from_c_ptr(it->second.m_sym_value); + out << symbol::mk_symbol_from_c_ptr(e.second.m_sym_value); return; case CPK_STRING: - out << it->second.m_str_value; + out << e.second.m_str_value; return; default: out << "internal"; @@ -786,6 +772,7 @@ void params::del_values() { return false; \ } + bool params::contains(symbol const & k) const { CONTAINS(k); } From a9e6d83c6e746480811b80467a33281a2e554e21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Nov 2018 10:40:08 -0800 Subject: [PATCH 181/227] std::cout -> out Signed-off-by: Nikolaj Bjorner --- src/solver/solver.h | 2 ++ src/util/gparams.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/solver/solver.h b/src/solver/solver.h index 5329161cd..7437a5a08 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -146,6 +146,8 @@ public: lbool check_sat(app_ref_vector const& asms) { return check_sat(asms.size(), (expr* const*)asms.c_ptr()); } + lbool check_sat() { return check_sat(0, nullptr); } + /** \brief Check satisfiability modulo a cube and a clause. diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 4ba3b3b5c..9ab3123a2 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -520,7 +520,7 @@ public: try { symbol m, p; normalize(name, m, p); - std::cout << name << " " << m << " " << p << "\n"; + out << name << " " << m << " " << p << "\n"; param_descrs * d; if (m == symbol::null) { d = &get_param_descrs(); From ddf6d48b3e731cd3a7bd79cab7ef73985c8824f1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Nov 2018 10:48:45 -0800 Subject: [PATCH 182/227] update unix-dist Signed-off-by: Nikolaj Bjorner --- scripts/mk_unix_dist.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 3e4456676..5b019f17b 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -93,6 +93,7 @@ def parse_options(): DOTNET_ENABLED = False elif opt == '--dotnetcore': DOTNET_CORE_ENABLED = True + DOTNET_ENABLED = False elif opt == '--nopython': PYTHON_ENABLED = False elif opt == '--dotnet-key': @@ -195,10 +196,8 @@ def mk_dist_dir(): build_path = BUILD_DIR dist_path = os.path.join(DIST_DIR, get_z3_name()) mk_dir(dist_path) - if DOTNET_CORE_ENABLED: - mk_util.DOTNET_CORE_ENABLED = True - else: - mk_util.DOTNET_ENABLED = DOTNET_ENABLED + mk_util.DOTNET_CORE_ENABLED = DOTNET_CORE_ENABLED + mk_util.DOTNET_ENABLED = DOTNET_ENABLED mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE mk_util.JAVA_ENABLED = JAVA_ENABLED mk_util.PYTHON_ENABLED = PYTHON_ENABLED From 5188f4d82e9c1a71eae1332470c2f11e3e4d9c18 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Nov 2018 10:55:59 -0800 Subject: [PATCH 183/227] update dist scripts Signed-off-by: Nikolaj Bjorner --- scripts/mk_unix_dist.py | 2 +- scripts/mk_win_dist.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 5b019f17b..bad51528f 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -65,7 +65,7 @@ def display_help(): # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_KEY_FILE + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index e61a7714c..bd3cad18a 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -104,6 +104,7 @@ def parse_options(): DOTNET_ENABLED = False elif opt == '--dotnetcore': DOTNET_CORE_ENABLED = True + DOTNET_ENABLED = False elif opt == '--nopython': PYTHON_ENABLED = False elif opt == '--dotnet-key': From 93835eab05da592efaffd6f3ddd82cee135f8c4d Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 19 Nov 2018 13:04:07 +0700 Subject: [PATCH 184/227] Correct Z3_(fixedpoint|optimize)_from_file param doc. --- src/api/z3_fixedpoint.h | 2 +- src/api/z3_optimization.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/z3_fixedpoint.h b/src/api/z3_fixedpoint.h index b4c3eee49..df1f1461f 100644 --- a/src/api/z3_fixedpoint.h +++ b/src/api/z3_fixedpoint.h @@ -308,7 +308,7 @@ extern "C" { \param c - context. \param f - fixedpoint context. - \param s - string containing SMT2 specification. + \param s - path to file containing SMT2 specification. def_API('Z3_fixedpoint_from_file', AST_VECTOR, (_in(CONTEXT), _in(FIXEDPOINT), _in(STRING))) */ diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h index f15d8ff9c..b1c01a386 100644 --- a/src/api/z3_optimization.h +++ b/src/api/z3_optimization.h @@ -252,7 +252,7 @@ extern "C" { \param c - context. \param o - optimize context. - \param s - string containing SMT2 specification. + \param s - path to file containing SMT2 specification. def_API('Z3_optimize_from_file', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(STRING))) */ From 529e62e01ee90eb7e48f0eb65ea8efb62165e823 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Nov 2018 00:48:33 -0800 Subject: [PATCH 185/227] remove unsound rewrite Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.cpp | 2 +- src/util/ref_vector.h | 26 ++++++++++++++++++++++++++ src/util/vector.h | 16 ++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 72ce9c761..a19074c51 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -1209,7 +1209,7 @@ br_status arith_rewriter::mk_to_int_core(expr * arg, expr_ref & result) { result = m().mk_app(get_fid(), to_app(arg)->get_decl()->get_decl_kind(), int_args.size(), int_args.c_ptr()); return BR_REWRITE1; } - if (!int_args.empty() && (m_util.is_add(arg) || m_util.is_mul(arg))) { + if (!int_args.empty() && m_util.is_add(arg)) { decl_kind k = to_app(arg)->get_decl()->get_decl_kind(); expr_ref t1(m().mk_app(get_fid(), k, int_args.size(), int_args.c_ptr()), m()); expr_ref t2(m().mk_app(get_fid(), k, real_args.size(), real_args.c_ptr()), m()); diff --git a/src/util/ref_vector.h b/src/util/ref_vector.h index 1e6525a06..491f1515f 100644 --- a/src/util/ref_vector.h +++ b/src/util/ref_vector.h @@ -186,6 +186,7 @@ public: std::swap(m_nodes[i], m_nodes[sz-i-1]); } } + }; template @@ -304,6 +305,31 @@ public: // prevent abuse: ref_vector & operator=(ref_vector const & other) = delete; + + ref_vector&& filter(std::function& predicate) { + ref_vector result(m()); + for (auto& t : *this) + if (predicate(t)) result.push_back(t); + return result; + } + + template + vector&& map(std::function& f) { + vector result; + for (auto& t : *this) + result.push_back(f(t)); + return result; + } + + ref_vector&& map(std::function& f) { + ref_vector result(m()); + for (auto& t : *this) + result.push_back(f(t)); + return result; + } + + + }; template diff --git a/src/util/vector.h b/src/util/vector.h index edcee7449..7724841c1 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -28,6 +28,7 @@ Revision History: #include #include #include +#include #include "util/memory_manager.h" #include "util/hash.h" #include "util/z3_exception.h" @@ -230,6 +231,21 @@ public: return *this; } + vector&& filter(std::function& predicate) { + vector result; + for (auto& t : *this) + if (predicate(t)) result.push_back(t); + return result; + } + + template + vector&& map(std::function& f) { + vector result; + for (auto& t : *this) + result.push_back(f(t)); + return result; + } + void reset() { if (m_data) { if (CallDestructors) { From e1388a838c21f9b0a87495376ab8ca99a87c90e6 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 19 Nov 2018 18:58:09 +0700 Subject: [PATCH 186/227] Fix precondition in Z3_get_symbol_string doc comment. --- src/api/z3_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index be463b1b0..a153f674b 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3889,7 +3889,7 @@ extern "C" { /** \brief Return the symbol name. - \pre Z3_get_symbol_string(s) == Z3_STRING_SYMBOL + \pre Z3_get_symbol_kind(s) == Z3_STRING_SYMBOL \warning The returned buffer is statically allocated by Z3. It will be automatically deallocated when #Z3_del_context is invoked. From 115256e353e26080fd8aaf6ec4db673453d4f7a9 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 19 Nov 2018 20:32:00 +0700 Subject: [PATCH 187/227] Improve intra-doc linking. --- src/api/z3_api.h | 14 +++++++++----- src/api/z3_fixedpoint.h | 2 +- src/api/z3_fpa.h | 4 ++-- src/api/z3_optimization.h | 9 +++++++++ 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index be463b1b0..1abde8074 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1751,6 +1751,7 @@ extern "C" { NB. Not all integers can be passed to this function. The legal range of unsigned integers is 0 to 2^30-1. + \sa Z3_get_symbol_int \sa Z3_mk_string_symbol def_API('Z3_mk_int_symbol', SYMBOL, (_in(CONTEXT), _in(INT))) @@ -1762,6 +1763,7 @@ extern "C" { Symbols are used to name several term and type constructors. + \sa Z3_get_symbol_string \sa Z3_mk_int_symbol def_API('Z3_mk_string_symbol', SYMBOL, (_in(CONTEXT), _in(STRING))) @@ -5950,9 +5952,9 @@ extern "C" { on how it is used and how its parameters are set. If the solver is used in a non incremental way (i.e. no calls to - `Z3_solver_push()` or `Z3_solver_pop()`, and no calls to - `Z3_solver_assert()` or `Z3_solver_assert_and_track()` after checking - satisfiability without an intervening `Z3_solver_reset()`) then solver1 + #Z3_solver_push() or #Z3_solver_pop(), and no calls to + #Z3_solver_assert() or #Z3_solver_assert_and_track() after checking + satisfiability without an intervening #Z3_solver_reset()) then solver1 will be used. This solver will apply Z3's "default" tactic. The "default" tactic will attempt to probe the logic used by the @@ -5986,13 +5988,13 @@ extern "C" { This is equivalent to applying the "smt" tactic. - Unlike `Z3_mk_solver()` this solver + Unlike #Z3_mk_solver() this solver - Does not attempt to apply any logic specific tactics. - Does not change its behaviour based on whether it used incrementally/non-incrementally. Note that these differences can result in very different performance - compared to `Z3_mk_solver()`. + compared to #Z3_mk_solver(). The function #Z3_solver_get_model retrieves a model if the assertions is satisfiable (i.e., the result is \c @@ -6195,6 +6197,8 @@ extern "C" { generation was enabled when the context was created, and the assertions are unsatisfiable (i.e., the result is \c Z3_L_FALSE). + \sa Z3_solver_check_assumptions + def_API('Z3_solver_check', INT, (_in(CONTEXT), _in(SOLVER))) */ Z3_lbool Z3_API Z3_solver_check(Z3_context c, Z3_solver s); diff --git a/src/api/z3_fixedpoint.h b/src/api/z3_fixedpoint.h index df1f1461f..246228ae6 100644 --- a/src/api/z3_fixedpoint.h +++ b/src/api/z3_fixedpoint.h @@ -138,7 +138,7 @@ extern "C" { Each conjunct encodes values of the bound variables of the query that are satisfied. In PDR mode, the returned answer is a single conjunction. - When used in Datalog mode the previous call to Z3_fixedpoint_query must have returned Z3_L_TRUE. + When used in Datalog mode the previous call to #Z3_fixedpoint_query must have returned Z3_L_TRUE. When used with the PDR engine, the previous call must have been either Z3_L_TRUE or Z3_L_FALSE. def_API('Z3_fixedpoint_get_answer', AST, (_in(CONTEXT), _in(FIXEDPOINT))) diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index f6001e87d..544d9372b 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -229,7 +229,7 @@ extern "C" { \param s target sort \param negative indicates whether the result should be negative - When \c negative is true, -oo will be generated instead of +oo. + When \c negative is \c true, -oo will be generated instead of +oo. def_API('Z3_mk_fpa_inf', AST, (_in(CONTEXT),_in(SORT),_in(BOOL))) */ @@ -242,7 +242,7 @@ extern "C" { \param s target sort \param negative indicates whether the result should be negative - When \c negative is true, -zero will be generated instead of +zero. + When \c negative is \c true, -zero will be generated instead of +zero. def_API('Z3_mk_fpa_zero', AST, (_in(CONTEXT),_in(SORT),_in(BOOL))) */ diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h index b1c01a386..fffaac212 100644 --- a/src/api/z3_optimization.h +++ b/src/api/z3_optimization.h @@ -55,6 +55,8 @@ extern "C" { /** \brief Assert hard constraint to the optimization context. + \sa Z3_optimize_assert_soft + def_API('Z3_optimize_assert', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(AST))) */ void Z3_API Z3_optimize_assert(Z3_context c, Z3_optimize o, Z3_ast a); @@ -67,6 +69,8 @@ extern "C" { \param weight - a positive weight, penalty for violating soft constraint \param id - optional identifier to group soft constraints + \sa Z3_optimize_assert + def_API('Z3_optimize_assert_soft', UINT, (_in(CONTEXT), _in(OPTIMIZE), _in(AST), _in(STRING), _in(SYMBOL))) */ unsigned Z3_API Z3_optimize_assert_soft(Z3_context c, Z3_optimize o, Z3_ast a, Z3_string weight, Z3_symbol id); @@ -76,6 +80,9 @@ extern "C" { \param c - context \param o - optimization context \param t - arithmetical term + + \sa Z3_optimize_minimize + def_API('Z3_optimize_maximize', UINT, (_in(CONTEXT), _in(OPTIMIZE), _in(AST))) */ unsigned Z3_API Z3_optimize_maximize(Z3_context c, Z3_optimize o, Z3_ast t); @@ -86,6 +93,8 @@ extern "C" { \param o - optimization context \param t - arithmetical term + \sa Z3_optimize_maximize + def_API('Z3_optimize_minimize', UINT, (_in(CONTEXT), _in(OPTIMIZE), _in(AST))) */ unsigned Z3_API Z3_optimize_minimize(Z3_context c, Z3_optimize o, Z3_ast t); From 5eefa9c34b5246059484a9dc89f31787557fd4b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Nov 2018 08:42:18 -0800 Subject: [PATCH 188/227] fix combinator signatures Signed-off-by: Nikolaj Bjorner --- src/cmd_context/pdecl.h | 8 ++++---- src/util/ref_vector.h | 32 ++++++++++++++++++++++++++++---- src/util/vector.h | 36 +++++++++++++++++++++++++++++++++--- 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/cmd_context/pdecl.h b/src/cmd_context/pdecl.h index d994a1e8f..8742424c3 100644 --- a/src/cmd_context/pdecl.h +++ b/src/cmd_context/pdecl.h @@ -36,7 +36,7 @@ protected: void inc_ref() { m_ref_count++; } void dec_ref() { SASSERT(m_ref_count > 0); --m_ref_count; } virtual bool is_psort() const { return false; } - virtual size_t obj_size() const = 0; + virtual size_t obj_size() const { UNREACHABLE(); return sizeof(*this); } pdecl(unsigned id, unsigned num_params):m_id(id), m_num_params(num_params), m_ref_count(0) {} virtual void finalize(pdecl_manager & m) {} virtual ~pdecl() {} @@ -74,9 +74,9 @@ public: virtual bool is_sort_wrapper() const { return false; } virtual sort * instantiate(pdecl_manager & m, sort * const * s) { return nullptr; } // we use hash-consing for psorts. - virtual char const * hcons_kind() const = 0; - virtual unsigned hcons_hash() const = 0; - virtual bool hcons_eq(psort const * other) const = 0; + virtual char const * hcons_kind() const { UNREACHABLE(); return nullptr; } + virtual unsigned hcons_hash() const { UNREACHABLE(); return 0; } + virtual bool hcons_eq(psort const * other) const { UNREACHABLE(); return false; } void reset_cache(pdecl_manager& m) override; }; diff --git a/src/util/ref_vector.h b/src/util/ref_vector.h index 491f1515f..f45b44dae 100644 --- a/src/util/ref_vector.h +++ b/src/util/ref_vector.h @@ -306,28 +306,52 @@ public: // prevent abuse: ref_vector & operator=(ref_vector const & other) = delete; - ref_vector&& filter(std::function& predicate) { + bool containsp(std::function& predicate) const { + for (auto const& t : *this) + if (predicate(t)) + return true; + return false; + } + + ref_vector filter_pure(std::function& predicate) const { ref_vector result(m()); for (auto& t : *this) - if (predicate(t)) result.push_back(t); + if (predicate(t)) + result.push_back(t); return result; } + ref_vector& filter_update(std::function& predicate) { + unsigned j = 0; + for (auto& t : *this) + if (predicate(t)) + set(j++, t); + shrink(j); + return *this; + } + template - vector&& map(std::function& f) { + vector mapv_pure(std::function& f) const { vector result; for (auto& t : *this) result.push_back(f(t)); return result; } - ref_vector&& map(std::function& f) { + ref_vector map_pure(std::function& f) const { ref_vector result(m()); for (auto& t : *this) result.push_back(f(t)); return result; } + ref_vector& map_update(std::function& f) { + unsigned j = 0; + for (auto& t : *this) + set(j++, f(t)); + return *this; + } + }; diff --git a/src/util/vector.h b/src/util/vector.h index 7724841c1..acbcd1357 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -231,21 +231,51 @@ public: return *this; } - vector&& filter(std::function& predicate) { + bool containsp(std::function& predicate) const { + for (auto const& t : *this) + if (predicate(t)) + return true; + return false; + } + + /** + * retain elements that satisfy predicate. aka 'where'. + */ + vector filter_pure(std::function& predicate) const { vector result; for (auto& t : *this) - if (predicate(t)) result.push_back(t); + if (predicate(t)) + result.push_back(t); return result; } + vector& filter_update(std::function& predicate) { + unsigned j = 0; + for (auto& t : *this) + if (predicate(t)) + set(j++, t); + shrink(j); + return *this; + } + + /** + * update elements using f, aka 'select' + */ template - vector&& map(std::function& f) { + vector map_pure(std::function& f) const { vector result; for (auto& t : *this) result.push_back(f(t)); return result; } + vector& map_update(std::function& f) { + unsigned j = 0; + for (auto& t : *this) + set(j++, f(t)); + return *this; + } + void reset() { if (m_data) { if (CallDestructors) { From 56bbed173e183004f11d3efe60d8787963a3ab63 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 20 Nov 2018 00:25:37 +0700 Subject: [PATCH 189/227] Remove usages of Z3_TRUE / Z3_FALSE. Now that this is all using stdbool.h, we can just use true/false. For now, we leave the aliases in place in z3_api.h. --- examples/c/test_capi.c | 116 +++++++++++++++++----------------- examples/maxsat/maxsat.c | 2 +- src/api/api_algebraic.cpp | 8 +-- src/api/api_arith.cpp | 2 +- src/api/api_ast.cpp | 2 +- src/api/api_ast_map.cpp | 2 +- src/api/api_config_params.cpp | 4 +- src/api/api_datalog.cpp | 8 +-- src/api/api_fpa.cpp | 14 ++-- src/api/api_goal.cpp | 6 +- src/api/api_log.cpp | 4 +- src/api/api_model.cpp | 16 ++--- src/api/api_numeral.cpp | 82 ++++++++++++------------ src/api/api_quant.cpp | 12 ++-- src/api/api_rcf.cpp | 12 ++-- src/api/api_seq.cpp | 16 ++--- src/api/api_stats.cpp | 6 +- src/api/c++/z3++.h | 2 +- src/api/z3_algebraic.h | 20 +++--- src/api/z3_api.h | 28 ++++---- src/api/z3_rcf.h | 12 ++-- src/smt/theory_str.cpp | 1 - src/test/no_overflow.cpp | 2 +- 23 files changed, 188 insertions(+), 189 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index dbcd0e82a..ea0cd8528 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -899,7 +899,7 @@ void prove_example1() /* prove g(x) = g(y) */ f = Z3_mk_eq(ctx, gx, gy); printf("prove: x = y implies g(x) = g(y)\n"); - prove(ctx, s, f, Z3_TRUE); + prove(ctx, s, f, true); /* create g(g(x)) */ ggx = mk_unary_app(ctx, g, gx); @@ -907,7 +907,7 @@ void prove_example1() /* disprove g(g(x)) = g(y) */ f = Z3_mk_eq(ctx, ggx, gy); printf("disprove: x = y implies g(g(x)) = g(y)\n"); - prove(ctx, s, f, Z3_FALSE); + prove(ctx, s, f, false); del_solver(ctx, s); Z3_del_context(ctx); @@ -979,13 +979,13 @@ void prove_example2() /* prove z < 0 */ f = Z3_mk_lt(ctx, z, zero); printf("prove: not(g(g(x) - g(y)) = g(z)), x + z <= y <= x implies z < 0\n"); - prove(ctx, s, f, Z3_TRUE); + prove(ctx, s, f, true); /* disprove z < -1 */ minus_one = mk_int(ctx, -1); f = Z3_mk_lt(ctx, z, minus_one); printf("disprove: not(g(g(x) - g(y)) = g(z)), x + z <= y <= x implies z < -1\n"); - prove(ctx, s, f, Z3_FALSE); + prove(ctx, s, f, false); del_solver(ctx, s); Z3_del_context(ctx); @@ -1131,7 +1131,7 @@ void quantifier_example1() /* prove f(x, y) = f(w, v) implies y = v */ p2 = Z3_mk_eq(ctx, y, v); printf("prove: f(x, y) = f(w, v) implies y = v\n"); - prove(ctx, s, p2, Z3_TRUE); + prove(ctx, s, p2, true); /* disprove f(x, y) = f(w, v) implies x = w */ /* using check2 instead of prove */ @@ -1198,7 +1198,7 @@ void array_example1() thm = Z3_mk_implies(ctx, antecedent, consequent); printf("prove: store(a1, i1, v1) = store(a2, i2, v2) implies (i1 = i3 or i2 = i3 or select(a1, i3) = select(a2, i3))\n"); printf("%s\n", Z3_ast_to_string(ctx, thm)); - prove(ctx, s, thm, Z3_TRUE); + prove(ctx, s, thm, true); del_solver(ctx, s); Z3_del_context(ctx); @@ -1339,13 +1339,13 @@ void tuple_example1() eq2 = Z3_mk_eq(ctx, x, one); thm = Z3_mk_implies(ctx, eq1, eq2); printf("prove: get_x(mk_pair(x, y)) = 1 implies x = 1\n"); - prove(ctx, s, thm, Z3_TRUE); + prove(ctx, s, thm, true); /* disprove that get_x(mk_pair(x,y)) == 1 implies y = 1*/ eq3 = Z3_mk_eq(ctx, y, one); thm = Z3_mk_implies(ctx, eq1, eq3); printf("disprove: get_x(mk_pair(x, y)) = 1 implies y = 1\n"); - prove(ctx, s, thm, Z3_FALSE); + prove(ctx, s, thm, false); } { @@ -1366,12 +1366,12 @@ void tuple_example1() consequent = Z3_mk_eq(ctx, p1, p2); thm = Z3_mk_implies(ctx, antecedent, consequent); printf("prove: get_x(p1) = get_x(p2) and get_y(p1) = get_y(p2) implies p1 = p2\n"); - prove(ctx, s, thm, Z3_TRUE); + prove(ctx, s, thm, true); /* disprove that get_x(p1) = get_x(p2) implies p1 = p2 */ thm = Z3_mk_implies(ctx, antecedents[0], consequent); printf("disprove: get_x(p1) = get_x(p2) implies p1 = p2\n"); - prove(ctx, s, thm, Z3_FALSE); + prove(ctx, s, thm, false); } { @@ -1390,14 +1390,14 @@ void tuple_example1() consequent = Z3_mk_eq(ctx, x, ten); thm = Z3_mk_implies(ctx, antecedent, consequent); printf("prove: p2 = update(p1, 0, 10) implies get_x(p2) = 10\n"); - prove(ctx, s, thm, Z3_TRUE); + prove(ctx, s, thm, true); /* disprove that p2 = update(p1, 0, 10) implies get_y(p2) = 10 */ y = mk_unary_app(ctx, get_y_decl, p2); consequent = Z3_mk_eq(ctx, y, ten); thm = Z3_mk_implies(ctx, antecedent, consequent); printf("disprove: p2 = update(p1, 0, 10) implies get_y(p2) = 10\n"); - prove(ctx, s, thm, Z3_FALSE); + prove(ctx, s, thm, false); } del_solver(ctx, s); @@ -1429,7 +1429,7 @@ void bitvector_example1() c2 = Z3_mk_bvsle(ctx, x_minus_ten, zero); thm = Z3_mk_iff(ctx, c1, c2); printf("disprove: x - 10 <= 0 IFF x <= 10 for (32-bit) machine integers\n"); - prove(ctx, s, thm, Z3_FALSE); + prove(ctx, s, thm, false); del_solver(ctx, s); Z3_del_context(ctx); @@ -1717,7 +1717,7 @@ void parser_example3() 0, 0, 0, 1, &g_name, &g); printf("formula: %s\n", Z3_ast_vector_to_string(ctx, thm)); - prove(ctx, s, Z3_ast_vector_get(ctx, thm, 0), Z3_TRUE); + prove(ctx, s, Z3_ast_vector_get(ctx, thm, 0), true); del_solver(ctx, s); Z3_del_context(ctx); @@ -1781,13 +1781,13 @@ void numeral_example() { n2 = Z3_mk_numeral(ctx, "0.5", real_ty); printf("Numerals n1:%s", Z3_ast_to_string(ctx, n1)); printf(" n2:%s\n", Z3_ast_to_string(ctx, n2)); - prove(ctx, s, Z3_mk_eq(ctx, n1, n2), Z3_TRUE); + prove(ctx, s, Z3_mk_eq(ctx, n1, n2), true); n1 = Z3_mk_numeral(ctx, "-1/3", real_ty); n2 = Z3_mk_numeral(ctx, "-0.33333333333333333333333333333333333333333333333333", real_ty); printf("Numerals n1:%s", Z3_ast_to_string(ctx, n1)); printf(" n2:%s\n", Z3_ast_to_string(ctx, n2)); - prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, n1, n2)), Z3_TRUE); + prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, n1, n2)), true); del_solver(ctx, s); Z3_del_context(ctx); } @@ -1852,14 +1852,14 @@ void enum_example() { orange = Z3_mk_app(ctx, enum_consts[2], 0, 0); /* Apples are different from oranges */ - prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, apple, orange)), Z3_TRUE); + prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, apple, orange)), true); /* Apples pass the apple test */ - prove(ctx, s, Z3_mk_app(ctx, enum_testers[0], 1, &apple), Z3_TRUE); + prove(ctx, s, Z3_mk_app(ctx, enum_testers[0], 1, &apple), true); /* Oranges fail the apple test */ - prove(ctx, s, Z3_mk_app(ctx, enum_testers[0], 1, &orange), Z3_FALSE); - prove(ctx, s, Z3_mk_not(ctx, Z3_mk_app(ctx, enum_testers[0], 1, &orange)), Z3_TRUE); + prove(ctx, s, Z3_mk_app(ctx, enum_testers[0], 1, &orange), false); + prove(ctx, s, Z3_mk_not(ctx, Z3_mk_app(ctx, enum_testers[0], 1, &orange)), true); fruity = mk_var(ctx, "fruity", fruit); @@ -1868,7 +1868,7 @@ void enum_example() { ors[1] = Z3_mk_eq(ctx, fruity, banana); ors[2] = Z3_mk_eq(ctx, fruity, orange); - prove(ctx, s, Z3_mk_or(ctx, 3, ors), Z3_TRUE); + prove(ctx, s, Z3_mk_or(ctx, 3, ors), true); /* delete logical context */ del_solver(ctx, s); @@ -1900,41 +1900,41 @@ void list_example() { l2 = mk_binary_app(ctx, cons_decl, mk_int(ctx, 2), nil); /* nil != cons(1, nil) */ - prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, nil, l1)), Z3_TRUE); + prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, nil, l1)), true); /* cons(2,nil) != cons(1, nil) */ - prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, l1, l2)), Z3_TRUE); + prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, l1, l2)), true); /* cons(x,nil) = cons(y, nil) => x = y */ x = mk_var(ctx, "x", int_ty); y = mk_var(ctx, "y", int_ty); l1 = mk_binary_app(ctx, cons_decl, x, nil); l2 = mk_binary_app(ctx, cons_decl, y, nil); - prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, x, y)), Z3_TRUE); + prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, x, y)), true); /* cons(x,u) = cons(x, v) => u = v */ u = mk_var(ctx, "u", int_list); v = mk_var(ctx, "v", int_list); l1 = mk_binary_app(ctx, cons_decl, x, u); l2 = mk_binary_app(ctx, cons_decl, y, v); - prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, u, v)), Z3_TRUE); - prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, x, y)), Z3_TRUE); + prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, u, v)), true); + prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, x, y)), true); /* is_nil(u) or is_cons(u) */ ors[0] = Z3_mk_app(ctx, is_nil_decl, 1, &u); ors[1] = Z3_mk_app(ctx, is_cons_decl, 1, &u); - prove(ctx, s, Z3_mk_or(ctx, 2, ors), Z3_TRUE); + prove(ctx, s, Z3_mk_or(ctx, 2, ors), true); /* occurs check u != cons(x,u) */ - prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, u, l1)), Z3_TRUE); + prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, u, l1)), true); /* destructors: is_cons(u) => u = cons(head(u),tail(u)) */ fml1 = Z3_mk_eq(ctx, u, mk_binary_app(ctx, cons_decl, mk_unary_app(ctx, head_decl, u), mk_unary_app(ctx, tail_decl, u))); fml = Z3_mk_implies(ctx, Z3_mk_app(ctx, is_cons_decl, 1, &u), fml1); printf("Formula %s\n", Z3_ast_to_string(ctx, fml)); - prove(ctx, s, fml, Z3_TRUE); + prove(ctx, s, fml, true); - prove(ctx, s, fml1, Z3_FALSE); + prove(ctx, s, fml1, false); /* delete logical context */ del_solver(ctx, s); @@ -1982,7 +1982,7 @@ void tree_example() { l2 = mk_binary_app(ctx, cons_decl, l1, nil); /* nil != cons(nil, nil) */ - prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, nil, l1)), Z3_TRUE); + prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, nil, l1)), true); /* cons(x,u) = cons(x, v) => u = v */ u = mk_var(ctx, "u", cell); @@ -1991,24 +1991,24 @@ void tree_example() { y = mk_var(ctx, "y", cell); l1 = mk_binary_app(ctx, cons_decl, x, u); l2 = mk_binary_app(ctx, cons_decl, y, v); - prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, u, v)), Z3_TRUE); - prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, x, y)), Z3_TRUE); + prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, u, v)), true); + prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, x, y)), true); /* is_nil(u) or is_cons(u) */ ors[0] = Z3_mk_app(ctx, is_nil_decl, 1, &u); ors[1] = Z3_mk_app(ctx, is_cons_decl, 1, &u); - prove(ctx, s, Z3_mk_or(ctx, 2, ors), Z3_TRUE); + prove(ctx, s, Z3_mk_or(ctx, 2, ors), true); /* occurs check u != cons(x,u) */ - prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, u, l1)), Z3_TRUE); + prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, u, l1)), true); /* destructors: is_cons(u) => u = cons(car(u),cdr(u)) */ fml1 = Z3_mk_eq(ctx, u, mk_binary_app(ctx, cons_decl, mk_unary_app(ctx, car_decl, u), mk_unary_app(ctx, cdr_decl, u))); fml = Z3_mk_implies(ctx, Z3_mk_app(ctx, is_cons_decl, 1, &u), fml1); printf("Formula %s\n", Z3_ast_to_string(ctx, fml)); - prove(ctx, s, fml, Z3_TRUE); + prove(ctx, s, fml, true); - prove(ctx, s, fml1, Z3_FALSE); + prove(ctx, s, fml1, false); /* delete logical context */ del_solver(ctx, s); @@ -2100,8 +2100,8 @@ void forest_example() { /* nil != cons(nil,nil) */ - prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, nil1, f1)), Z3_TRUE); - prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, nil2, t1)), Z3_TRUE); + prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, nil1, f1)), true); + prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, nil2, t1)), true); /* cons(x,u) = cons(x, v) => u = v */ @@ -2111,16 +2111,16 @@ void forest_example() { y = mk_var(ctx, "y", tree); l1 = mk_binary_app(ctx, cons1_decl, x, u); l2 = mk_binary_app(ctx, cons1_decl, y, v); - prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, u, v)), Z3_TRUE); - prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, x, y)), Z3_TRUE); + prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, u, v)), true); + prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, x, y)), true); /* is_nil(u) or is_cons(u) */ ors[0] = Z3_mk_app(ctx, is_nil1_decl, 1, &u); ors[1] = Z3_mk_app(ctx, is_cons1_decl, 1, &u); - prove(ctx, s, Z3_mk_or(ctx, 2, ors), Z3_TRUE); + prove(ctx, s, Z3_mk_or(ctx, 2, ors), true); /* occurs check u != cons(x,u) */ - prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, u, l1)), Z3_TRUE); + prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, u, l1)), true); /* delete logical context */ del_solver(ctx, s); @@ -2193,19 +2193,19 @@ void binary_tree_example() { Z3_ast node3 = Z3_mk_app(ctx, node_decl, 3, args3); /* prove that nil != node1 */ - prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, nil, node1)), Z3_TRUE); + prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, nil, node1)), true); /* prove that nil = left(node1) */ - prove(ctx, s, Z3_mk_eq(ctx, nil, mk_unary_app(ctx, left_decl, node1)), Z3_TRUE); + prove(ctx, s, Z3_mk_eq(ctx, nil, mk_unary_app(ctx, left_decl, node1)), true); /* prove that node1 = right(node3) */ - prove(ctx, s, Z3_mk_eq(ctx, node1, mk_unary_app(ctx, right_decl, node3)), Z3_TRUE); + prove(ctx, s, Z3_mk_eq(ctx, node1, mk_unary_app(ctx, right_decl, node3)), true); /* prove that !is-nil(node2) */ - prove(ctx, s, Z3_mk_not(ctx, mk_unary_app(ctx, is_nil_decl, node2)), Z3_TRUE); + prove(ctx, s, Z3_mk_not(ctx, mk_unary_app(ctx, is_nil_decl, node2)), true); /* prove that value(node2) >= 0 */ - prove(ctx, s, Z3_mk_ge(ctx, mk_unary_app(ctx, value_decl, node2), mk_int(ctx, 0)), Z3_TRUE); + prove(ctx, s, Z3_mk_ge(ctx, mk_unary_app(ctx, value_decl, node2), mk_int(ctx, 0)), true); } /* delete logical context */ @@ -2347,7 +2347,7 @@ unsigned assert_retractable_cnstr(Z3_ext_context ctx, Z3_ast c) { ans_lit = Z3_mk_fresh_const(ctx->m_context, "k", ty); result = ctx->m_num_answer_literals; ctx->m_answer_literals[result] = ans_lit; - ctx->m_retracted[result] = Z3_FALSE; + ctx->m_retracted[result] = false; ctx->m_num_answer_literals++; // assert: c OR (not ans_lit) args[0] = c; @@ -2363,7 +2363,7 @@ void retract_cnstr(Z3_ext_context ctx, unsigned id) { if (id >= ctx->m_num_answer_literals) { exitf("invalid constraint id."); } - ctx->m_retracted[id] = Z3_TRUE; + ctx->m_retracted[id] = true; } /** @@ -2373,7 +2373,7 @@ void reassert_cnstr(Z3_ext_context ctx, unsigned id) { if (id >= ctx->m_num_answer_literals) { exitf("invalid constraint id."); } - ctx->m_retracted[id] = Z3_FALSE; + ctx->m_retracted[id] = false; } /** @@ -2387,7 +2387,7 @@ Z3_lbool ext_check(Z3_ext_context ctx) { unsigned core_size; unsigned i; for (i = 0; i < ctx->m_num_answer_literals; i++) { - if (ctx->m_retracted[i] == Z3_FALSE) { + if (ctx->m_retracted[i] == false) { // Since the answer literal was not retracted, we added it as an assumption. // Recall that we assert (C \/ (not ans_lit)). Therefore, adding ans_lit as an assumption has the effect of "asserting" C. // If the constraint was "retracted" (ctx->m_retracted[i] == Z3_true), then we don't really need to add (not ans_lit) as an assumption. @@ -2874,8 +2874,8 @@ void mk_model_example() { Z3_ast aPlusBEval = NULL; Z3_bool aPlusBEvalSuccess = Z3_model_eval(ctx, m, aPlusB, - /*model_completion=*/Z3_FALSE, &aPlusBEval); - if (aPlusBEvalSuccess != Z3_TRUE) { + /*model_completion=*/false, &aPlusBEval); + if (aPlusBEvalSuccess != true) { printf("Failed to evaluate model\n"); exit(1); } @@ -2884,7 +2884,7 @@ void mk_model_example() { int aPlusBValue = 0; Z3_bool getAPlusBValueSuccess = Z3_get_numeral_int(ctx, aPlusBEval, &aPlusBValue); - if (getAPlusBValueSuccess != Z3_TRUE) { + if (getAPlusBValueSuccess != true) { printf("Failed to get integer value for a+b\n"); exit(1); } @@ -2908,8 +2908,8 @@ void mk_model_example() { Z3_ast arrayAddEval = NULL; Z3_bool arrayAddEvalSuccess = Z3_model_eval(ctx, m, arrayAdd, - /*model_completion=*/Z3_FALSE, &arrayAddEval); - if (arrayAddEvalSuccess != Z3_TRUE) { + /*model_completion=*/false, &arrayAddEval); + if (arrayAddEvalSuccess != true) { printf("Failed to evaluate model\n"); exit(1); } @@ -2917,7 +2917,7 @@ void mk_model_example() { int arrayAddValue = 0; Z3_bool getArrayAddValueSuccess = Z3_get_numeral_int(ctx, arrayAddEval, &arrayAddValue); - if (getArrayAddValueSuccess != Z3_TRUE) { + if (getArrayAddValueSuccess != true) { printf("Failed to get integer value for c[0] + c[1] + c[2]\n"); exit(1); } diff --git a/examples/maxsat/maxsat.c b/examples/maxsat/maxsat.c index 50550106e..1f9ae165f 100644 --- a/examples/maxsat/maxsat.c +++ b/examples/maxsat/maxsat.c @@ -382,7 +382,7 @@ unsigned get_num_disabled_soft_constraints(Z3_context ctx, Z3_model m, unsigned Z3_ast t = Z3_mk_true(ctx); for (i = 0; i < num_soft_cnstrs; i++) { Z3_ast val; - if (Z3_model_eval(ctx, m, aux_vars[i], 1, &val) == Z3_TRUE) { + if (Z3_model_eval(ctx, m, aux_vars[i], 1, &val) == true) { // printf("%s", Z3_ast_to_string(ctx, aux_vars[i])); // printf(" -> %s\n", Z3_ast_to_string(ctx, val)); if (Z3_is_eq_ast(ctx, val, t)) { diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index 1bb1b6a51..c6d0b179b 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -83,8 +83,8 @@ extern "C" { Z3_TRY; LOG_Z3_algebraic_is_value(c, a); RESET_ERROR_CODE(); - return Z3_algebraic_is_value_core(c, a) ? Z3_TRUE : Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return Z3_algebraic_is_value_core(c, a) ? true : false; + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_algebraic_is_pos(Z3_context c, Z3_ast a) { @@ -283,7 +283,7 @@ extern "C" { r = _am.IRAT_PRED(av, bv); \ } \ } \ - return r ? Z3_TRUE : Z3_FALSE; + return r ? true : false; Z3_bool Z3_API Z3_algebraic_lt(Z3_context c, Z3_ast a, Z3_ast b) { @@ -293,7 +293,7 @@ extern "C" { CHECK_IS_ALGEBRAIC(a, 0); CHECK_IS_ALGEBRAIC(b, 0); BIN_PRED(<,lt); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_algebraic_gt(Z3_context c, Z3_ast a, Z3_ast b) { diff --git a/src/api/api_arith.cpp b/src/api/api_arith.cpp index f46f56ef2..214a95a73 100644 --- a/src/api/api_arith.cpp +++ b/src/api/api_arith.cpp @@ -121,7 +121,7 @@ extern "C" { Z3_bool Z3_API Z3_is_algebraic_number(Z3_context c, Z3_ast a) { LOG_Z3_is_algebraic_number(c, a); - return mk_c(c)->autil().is_irrational_algebraic_numeral(to_expr(a)) ? Z3_TRUE : Z3_FALSE; + return mk_c(c)->autil().is_irrational_algebraic_numeral(to_expr(a)) ? true : false; } Z3_ast Z3_API Z3_get_algebraic_number_lower(Z3_context c, Z3_ast a, unsigned precision) { diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index bf5a79bdf..277715950 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -313,7 +313,7 @@ extern "C" { LOG_Z3_is_well_sorted(c, t); RESET_ERROR_CODE(); return is_well_sorted(mk_c(c)->m(), to_expr(t)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_symbol_kind Z3_API Z3_get_symbol_kind(Z3_context c, Z3_symbol s) { diff --git a/src/api/api_ast_map.cpp b/src/api/api_ast_map.cpp index 44cadc691..524bd113d 100644 --- a/src/api/api_ast_map.cpp +++ b/src/api/api_ast_map.cpp @@ -62,7 +62,7 @@ extern "C" { LOG_Z3_ast_map_contains(c, m, k); RESET_ERROR_CODE(); return to_ast_map_ref(m).contains(to_ast(k)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_ast Z3_API Z3_ast_map_find(Z3_context c, Z3_ast_map m, Z3_ast k) { diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp index 604177561..54b3c5795 100644 --- a/src/api/api_config_params.cpp +++ b/src/api/api_config_params.cpp @@ -57,13 +57,13 @@ extern "C" { try { g_Z3_global_param_get_buffer = gparams::get_value(param_id); *param_value = g_Z3_global_param_get_buffer.c_str(); - return Z3_TRUE; + return true; } catch (z3_exception & ex) { // The error handler is only available for contexts // Just throw a warning. warning_msg("%s", ex.msg()); - return Z3_FALSE; + return false; } } diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index ae21885a9..0f6bd49cc 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -205,17 +205,17 @@ extern "C" { *out = 0; } if (Z3_get_sort_kind(c, s) != Z3_FINITE_DOMAIN_SORT) { - return Z3_FALSE; + return false; } if (!out) { - return Z3_FALSE; + return false; } // must start logging here, since function uses Z3_get_sort_kind above LOG_Z3_get_finite_domain_sort_size(c, s, out); RESET_ERROR_CODE(); VERIFY(mk_c(c)->datalog_util().try_get_size(to_sort(s), *out)); - return Z3_TRUE; - Z3_CATCH_RETURN(Z3_FALSE); + return true; + Z3_CATCH_RETURN(false); } Z3_fixedpoint Z3_API Z3_mk_fixedpoint(Z3_context c) { diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 604267536..c8a2690c6 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -1243,7 +1243,7 @@ extern "C" { return false; } return fu.is_nan(to_expr(t)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_fpa_is_numeral_inf(Z3_context c, Z3_ast t) { @@ -1257,7 +1257,7 @@ extern "C" { return false; } return fu.is_inf(to_expr(t)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_fpa_is_numeral_zero(Z3_context c, Z3_ast t) { @@ -1271,7 +1271,7 @@ extern "C" { return false; } return fu.is_zero(to_expr(t)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_fpa_is_numeral_normal(Z3_context c, Z3_ast t) { @@ -1285,7 +1285,7 @@ extern "C" { return false; } return fu.is_normal(to_expr(t)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_fpa_is_numeral_subnormal(Z3_context c, Z3_ast t) { @@ -1299,7 +1299,7 @@ extern "C" { return false; } return fu.is_subnormal(to_expr(t)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_fpa_is_numeral_positive(Z3_context c, Z3_ast t) { @@ -1313,7 +1313,7 @@ extern "C" { return false; } return fu.is_positive(to_expr(t)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_fpa_is_numeral_negative(Z3_context c, Z3_ast t) { @@ -1327,7 +1327,7 @@ extern "C" { return false; } return fu.is_negative(to_expr(t)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } }; diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index 3d75c3dba..1a67e1061 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -87,7 +87,7 @@ extern "C" { LOG_Z3_goal_inconsistent(c, g); RESET_ERROR_CODE(); return to_goal_ref(g)->inconsistent(); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } unsigned Z3_API Z3_goal_depth(Z3_context c, Z3_goal g) { @@ -141,7 +141,7 @@ extern "C" { LOG_Z3_goal_is_decided_sat(c, g); RESET_ERROR_CODE(); return to_goal_ref(g)->is_decided_sat(); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_goal_is_decided_unsat(Z3_context c, Z3_goal g) { @@ -149,7 +149,7 @@ extern "C" { LOG_Z3_goal_is_decided_unsat(c, g); RESET_ERROR_CODE(); return to_goal_ref(g)->is_decided_unsat(); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_model Z3_API Z3_goal_convert_model(Z3_context c, Z3_goal g, Z3_model m) { diff --git a/src/api/api_log.cpp b/src/api/api_log.cpp index 0f531b98e..dd517c82f 100644 --- a/src/api/api_log.cpp +++ b/src/api/api_log.cpp @@ -34,7 +34,7 @@ extern "C" { } Z3_bool Z3_API Z3_open_log(Z3_string filename) { - Z3_bool res = Z3_TRUE; + Z3_bool res = true; #ifdef Z3_LOG_SYNC #pragma omp critical (z3_log) @@ -46,7 +46,7 @@ extern "C" { if (g_z3_log->bad() || g_z3_log->fail()) { dealloc(g_z3_log); g_z3_log = nullptr; - res = Z3_FALSE; + res = false; } else { *g_z3_log << "V \"" << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER << "." << Z3_REVISION_NUMBER << " " << __DATE__ << "\"\n"; diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 939cccdca..0cc555d3c 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -80,11 +80,11 @@ extern "C" { LOG_Z3_model_has_interp(c, m, a); CHECK_NON_NULL(m, 0); if (to_model_ref(m)->has_interpretation(to_func_decl(a))) { - return Z3_TRUE; + return true; } else { - return Z3_FALSE; + return false; } - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_func_interp Z3_API Z3_model_get_func_interp(Z3_context c, Z3_model m, Z3_func_decl f) { @@ -162,15 +162,15 @@ extern "C" { LOG_Z3_model_eval(c, m, t, model_completion, v); if (v) *v = nullptr; RESET_ERROR_CODE(); - CHECK_NON_NULL(m, Z3_FALSE); - CHECK_IS_EXPR(t, Z3_FALSE); + CHECK_NON_NULL(m, false); + CHECK_IS_EXPR(t, false); model * _m = to_model_ref(m); expr_ref result(mk_c(c)->m()); - model::scoped_model_completion _scm(*_m, model_completion == Z3_TRUE); + model::scoped_model_completion _scm(*_m, model_completion == true); result = (*_m)(to_expr(t)); mk_c(c)->save_ast_trail(result.get()); *v = of_ast(result.get()); - RETURN_Z3_model_eval Z3_TRUE; + RETURN_Z3_model_eval true; Z3_CATCH_RETURN(0); } @@ -230,7 +230,7 @@ extern "C" { LOG_Z3_is_as_array(c, a); RESET_ERROR_CODE(); return a && is_expr(to_ast(a)) && is_app_of(to_expr(a), mk_c(c)->get_array_fid(), OP_AS_ARRAY); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_func_decl Z3_API Z3_get_as_array_func_decl(Z3_context c, Z3_ast a) { diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 11afed82e..f90c0b4f1 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -146,7 +146,7 @@ extern "C" { Z3_TRY; LOG_Z3_is_numeral_ast(c, a); RESET_ERROR_CODE(); - CHECK_IS_EXPR(a, Z3_FALSE); + CHECK_IS_EXPR(a, false); expr* e = to_expr(a); return mk_c(c)->autil().is_numeral(e) || @@ -154,29 +154,29 @@ extern "C" { mk_c(c)->fpautil().is_numeral(e) || mk_c(c)->fpautil().is_rm_numeral(e) || mk_c(c)->datalog_util().is_numeral_ext(e); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_get_numeral_rational(Z3_context c, Z3_ast a, rational& r) { Z3_TRY; // This function is not part of the public API RESET_ERROR_CODE(); - CHECK_IS_EXPR(a, Z3_FALSE); + CHECK_IS_EXPR(a, false); expr* e = to_expr(a); if (mk_c(c)->autil().is_numeral(e, r)) { - return Z3_TRUE; + return true; } unsigned bv_size; if (mk_c(c)->bvutil().is_numeral(e, r, bv_size)) { - return Z3_TRUE; + return true; } uint64_t v; if (mk_c(c)->datalog_util().is_numeral(e, v)) { r = rational(v, rational::ui64()); - return Z3_TRUE; + return true; } - return Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return false; + Z3_CATCH_RETURN(false); } @@ -188,7 +188,7 @@ extern "C" { CHECK_IS_EXPR(a, ""); rational r; Z3_bool ok = Z3_get_numeral_rational(c, a, r); - if (ok == Z3_TRUE) { + if (ok == true) { return mk_c(c)->mk_external_string(r.to_string()); } else { @@ -253,7 +253,7 @@ extern "C" { return mk_c(c)->mk_external_string(buffer.str()); } Z3_bool ok = Z3_get_numeral_rational(c, a, r); - if (ok == Z3_TRUE) { + if (ok == true) { return mk_c(c)->mk_external_string(r.to_string()); } else { @@ -268,24 +268,24 @@ extern "C" { // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_small(c, a, num, den); RESET_ERROR_CODE(); - CHECK_IS_EXPR(a, Z3_FALSE); + CHECK_IS_EXPR(a, false); rational r; Z3_bool ok = Z3_get_numeral_rational(c, a, r); - if (ok == Z3_TRUE) { + if (ok == true) { rational n = numerator(r); rational d = denominator(r); if (n.is_int64() && d.is_int64()) { *num = n.get_int64(); *den = d.get_int64(); - return Z3_TRUE; + return true; } else { - return Z3_FALSE; + return false; } } SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return false; + Z3_CATCH_RETURN(false); } @@ -294,18 +294,18 @@ extern "C" { // This function invokes Z3_get_numeral_int64, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_int(c, v, i); RESET_ERROR_CODE(); - CHECK_IS_EXPR(v, Z3_FALSE); + CHECK_IS_EXPR(v, false); if (!i) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return Z3_FALSE; + return false; } int64_t l; if (Z3_get_numeral_int64(c, v, &l) && l >= INT_MIN && l <= INT_MAX) { *i = static_cast(l); - return Z3_TRUE; + return true; } - return Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return false; + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_get_numeral_uint(Z3_context c, Z3_ast v, unsigned* u) { @@ -313,18 +313,18 @@ extern "C" { // This function invokes Z3_get_numeral_uint64, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_uint(c, v, u); RESET_ERROR_CODE(); - CHECK_IS_EXPR(v, Z3_FALSE); + CHECK_IS_EXPR(v, false); if (!u) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return Z3_FALSE; + return false; } uint64_t l; if (Z3_get_numeral_uint64(c, v, &l) && (l <= 0xFFFFFFFF)) { *u = static_cast(l); - return Z3_TRUE; + return true; } - return Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return false; + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, uint64_t* u) { @@ -332,20 +332,20 @@ extern "C" { // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_uint64(c, v, u); RESET_ERROR_CODE(); - CHECK_IS_EXPR(v, Z3_FALSE); + CHECK_IS_EXPR(v, false); if (!u) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return Z3_FALSE; + return false; } rational r; Z3_bool ok = Z3_get_numeral_rational(c, v, r); SASSERT(u); - if (ok == Z3_TRUE && r.is_uint64()) { + if (ok == true && r.is_uint64()) { *u = r.get_uint64(); return ok; } - return Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return false; + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_get_numeral_int64(Z3_context c, Z3_ast v, int64_t* i) { @@ -353,19 +353,19 @@ extern "C" { // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_int64(c, v, i); RESET_ERROR_CODE(); - CHECK_IS_EXPR(v, Z3_FALSE); + CHECK_IS_EXPR(v, false); if (!i) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return Z3_FALSE; + return false; } rational r; Z3_bool ok = Z3_get_numeral_rational(c, v, r); - if (ok == Z3_TRUE && r.is_int64()) { + if (ok == true && r.is_int64()) { *i = r.get_int64(); return ok; } - return Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return false; + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_get_numeral_rational_int64(Z3_context c, Z3_ast v, int64_t* num, int64_t* den) { @@ -373,14 +373,14 @@ extern "C" { // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_rational_int64(c, v, num, den); RESET_ERROR_CODE(); - CHECK_IS_EXPR(v, Z3_FALSE); + CHECK_IS_EXPR(v, false); if (!num || !den) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - return Z3_FALSE; + return false; } rational r; Z3_bool ok = Z3_get_numeral_rational(c, v, r); - if (ok != Z3_TRUE) { + if (ok != true) { return ok; } rational n = numerator(r); @@ -390,8 +390,8 @@ extern "C" { *den = d.get_int64(); return ok; } - return Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return false; + Z3_CATCH_RETURN(false); } Z3_ast Z3_API Z3_mk_bv_numeral(Z3_context c, unsigned sz, Z3_bool const* bits) { diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index fe9faa2a5..3e639f93d 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -347,24 +347,24 @@ extern "C" { Z3_TRY; LOG_Z3_is_quantifier_forall(c, a); RESET_ERROR_CODE(); - return ::is_forall(to_ast(a)) ? Z3_TRUE : Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return ::is_forall(to_ast(a)) ? true : false; + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_is_quantifier_exists(Z3_context c, Z3_ast a) { Z3_TRY; LOG_Z3_is_quantifier_exists(c, a); RESET_ERROR_CODE(); - return ::is_exists(to_ast(a)) ? Z3_TRUE : Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return ::is_exists(to_ast(a)) ? true : false; + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_is_lambda(Z3_context c, Z3_ast a) { Z3_TRY; LOG_Z3_is_lambda(c, a); RESET_ERROR_CODE(); - return ::is_lambda(to_ast(a)) ? Z3_TRUE : Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return ::is_lambda(to_ast(a)) ? true : false; + Z3_CATCH_RETURN(false); } diff --git a/src/api/api_rcf.cpp b/src/api/api_rcf.cpp index d92ff155b..0bcabf0c4 100644 --- a/src/api/api_rcf.cpp +++ b/src/api/api_rcf.cpp @@ -220,7 +220,7 @@ extern "C" { RESET_ERROR_CODE(); reset_rcf_cancel(c); return rcfm(c).lt(to_rcnumeral(a), to_rcnumeral(b)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_rcf_gt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { @@ -229,7 +229,7 @@ extern "C" { RESET_ERROR_CODE(); reset_rcf_cancel(c); return rcfm(c).gt(to_rcnumeral(a), to_rcnumeral(b)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_rcf_le(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { @@ -238,7 +238,7 @@ extern "C" { RESET_ERROR_CODE(); reset_rcf_cancel(c); return rcfm(c).le(to_rcnumeral(a), to_rcnumeral(b)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_rcf_ge(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { @@ -247,7 +247,7 @@ extern "C" { RESET_ERROR_CODE(); reset_rcf_cancel(c); return rcfm(c).ge(to_rcnumeral(a), to_rcnumeral(b)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_rcf_eq(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { @@ -256,7 +256,7 @@ extern "C" { RESET_ERROR_CODE(); reset_rcf_cancel(c); return rcfm(c).eq(to_rcnumeral(a), to_rcnumeral(b)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_rcf_neq(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { @@ -265,7 +265,7 @@ extern "C" { RESET_ERROR_CODE(); reset_rcf_cancel(c); return rcfm(c).neq(to_rcnumeral(a), to_rcnumeral(b)); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } Z3_string Z3_API Z3_rcf_num_to_string(Z3_context c, Z3_rcf_num a, Z3_bool compact, Z3_bool html) { diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 42979d1ed..1e9e7f277 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -70,8 +70,8 @@ extern "C" { LOG_Z3_is_seq_sort(c, s); RESET_ERROR_CODE(); bool result = mk_c(c)->sutil().is_seq(to_sort(s)); - return result?Z3_TRUE:Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return result?true:false; + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_is_re_sort(Z3_context c, Z3_sort s) { @@ -79,8 +79,8 @@ extern "C" { LOG_Z3_is_re_sort(c, s); RESET_ERROR_CODE(); bool result = mk_c(c)->sutil().is_re(to_sort(s)); - return result?Z3_TRUE:Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return result?true:false; + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_is_string_sort(Z3_context c, Z3_sort s) { @@ -88,8 +88,8 @@ extern "C" { LOG_Z3_is_string_sort(c, s); RESET_ERROR_CODE(); bool result = mk_c(c)->sutil().is_string(to_sort(s)); - return result?Z3_TRUE:Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return result?true:false; + Z3_CATCH_RETURN(false); } Z3_bool Z3_API Z3_is_string(Z3_context c, Z3_ast s) { @@ -97,8 +97,8 @@ extern "C" { LOG_Z3_is_string(c, s); RESET_ERROR_CODE(); bool result = mk_c(c)->sutil().str.is_string(to_expr(s)); - return result?Z3_TRUE:Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return result?true:false; + Z3_CATCH_RETURN(false); } Z3_string Z3_API Z3_get_string(Z3_context c, Z3_ast s) { diff --git a/src/api/api_stats.cpp b/src/api/api_stats.cpp index 2014d57b8..6ab18c214 100644 --- a/src/api/api_stats.cpp +++ b/src/api/api_stats.cpp @@ -80,7 +80,7 @@ extern "C" { RESET_ERROR_CODE(); if (idx >= to_stats_ref(s).size()) { SET_ERROR_CODE(Z3_IOB, nullptr); - return Z3_FALSE; + return false; } return to_stats_ref(s).is_uint(idx); Z3_CATCH_RETURN(0); @@ -92,10 +92,10 @@ extern "C" { RESET_ERROR_CODE(); if (idx >= to_stats_ref(s).size()) { SET_ERROR_CODE(Z3_IOB, nullptr); - return Z3_FALSE; + return false; } return !to_stats_ref(s).is_uint(idx); - Z3_CATCH_RETURN(Z3_FALSE); + Z3_CATCH_RETURN(false); } unsigned Z3_API Z3_stats_get_uint_value(Z3_context c, Z3_stats s, unsigned idx) { diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index edac9a828..f2cb149cb 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2038,7 +2038,7 @@ namespace z3 { Z3_ast r = 0; Z3_bool status = Z3_model_eval(ctx(), m_model, n, model_completion, &r); check_error(); - if (status == Z3_FALSE && ctx().enable_exceptions()) + if (status == false && ctx().enable_exceptions()) Z3_THROW(exception("failed to evaluate expression")); return expr(ctx(), r); } diff --git a/src/api/z3_algebraic.h b/src/api/z3_algebraic.h index 49c61afef..c3f5337c2 100644 --- a/src/api/z3_algebraic.h +++ b/src/api/z3_algebraic.h @@ -31,7 +31,7 @@ extern "C" { /** @name Algebraic Numbers */ /*@{*/ /** - \brief Return Z3_TRUE if \c a can be used as value in the Z3 real algebraic + \brief Return \c true if \c a can be used as value in the Z3 real algebraic number package. def_API('Z3_algebraic_is_value', BOOL, (_in(CONTEXT), _in(AST))) @@ -39,7 +39,7 @@ extern "C" { Z3_bool Z3_API Z3_algebraic_is_value(Z3_context c, Z3_ast a); /** - \brief Return the Z3_TRUE if \c a is positive, and Z3_FALSE otherwise. + \brief Return \c true if \c a is positive, and \c false otherwise. \pre Z3_algebraic_is_value(c, a) @@ -48,7 +48,7 @@ extern "C" { Z3_bool Z3_API Z3_algebraic_is_pos(Z3_context c, Z3_ast a); /** - \brief Return the Z3_TRUE if \c a is negative, and Z3_FALSE otherwise. + \brief Return \c true if \c a is negative, and \c false otherwise. \pre Z3_algebraic_is_value(c, a) @@ -57,7 +57,7 @@ extern "C" { Z3_bool Z3_API Z3_algebraic_is_neg(Z3_context c, Z3_ast a); /** - \brief Return the Z3_TRUE if \c a is zero, and Z3_FALSE otherwise. + \brief Return \c true if \c a is zero, and \c false otherwise. \pre Z3_algebraic_is_value(c, a) @@ -141,7 +141,7 @@ extern "C" { Z3_ast Z3_API Z3_algebraic_power(Z3_context c, Z3_ast a, unsigned k); /** - \brief Return Z3_TRUE if a < b, and Z3_FALSE otherwise. + \brief Return \c true if a < b, and \c false otherwise. \pre Z3_algebraic_is_value(c, a) \pre Z3_algebraic_is_value(c, b) @@ -151,7 +151,7 @@ extern "C" { Z3_bool Z3_API Z3_algebraic_lt(Z3_context c, Z3_ast a, Z3_ast b); /** - \brief Return Z3_TRUE if a > b, and Z3_FALSE otherwise. + \brief Return \c true if a > b, and \c false otherwise. \pre Z3_algebraic_is_value(c, a) \pre Z3_algebraic_is_value(c, b) @@ -161,7 +161,7 @@ extern "C" { Z3_bool Z3_API Z3_algebraic_gt(Z3_context c, Z3_ast a, Z3_ast b); /** - \brief Return Z3_TRUE if a <= b, and Z3_FALSE otherwise. + \brief Return \c true if a <= b, and \c false otherwise. \pre Z3_algebraic_is_value(c, a) \pre Z3_algebraic_is_value(c, b) @@ -171,7 +171,7 @@ extern "C" { Z3_bool Z3_API Z3_algebraic_le(Z3_context c, Z3_ast a, Z3_ast b); /** - \brief Return Z3_TRUE if a >= b, and Z3_FALSE otherwise. + \brief Return \c true if a >= b, and \c false otherwise. \pre Z3_algebraic_is_value(c, a) \pre Z3_algebraic_is_value(c, b) @@ -181,7 +181,7 @@ extern "C" { Z3_bool Z3_API Z3_algebraic_ge(Z3_context c, Z3_ast a, Z3_ast b); /** - \brief Return Z3_TRUE if a == b, and Z3_FALSE otherwise. + \brief Return \c true if a == b, and \c false otherwise. \pre Z3_algebraic_is_value(c, a) \pre Z3_algebraic_is_value(c, b) @@ -191,7 +191,7 @@ extern "C" { Z3_bool Z3_API Z3_algebraic_eq(Z3_context c, Z3_ast a, Z3_ast b); /** - \brief Return Z3_TRUE if a != b, and Z3_FALSE otherwise. + \brief Return \c true if a != b, and \c false otherwise. \pre Z3_algebraic_is_value(c, a) \pre Z3_algebraic_is_value(c, b) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 87750fa83..a94030d22 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1435,7 +1435,7 @@ extern "C" { /** \brief Get a global (or module) parameter. - Returns \c Z3_FALSE if the parameter value does not exist. + Returns \c false if the parameter value does not exist. \sa Z3_global_param_set @@ -3953,7 +3953,7 @@ extern "C" { unsigned Z3_API Z3_get_bv_sort_size(Z3_context c, Z3_sort t); /** - \brief Store the size of the sort in \c r. Return Z3_FALSE if the call failed. + \brief Store the size of the sort in \c r. Return \c false if the call failed. That is, Z3_get_sort_kind(s) == Z3_FINITE_DOMAIN_SORT def_API('Z3_get_finite_domain_sort_size', BOOL, (_in(CONTEXT), _in(SORT), _out(UINT64))) @@ -4518,7 +4518,7 @@ extern "C" { \param num numerator. \param den denominator. - Return \c Z3_TRUE if the numeral value fits in 64 bit numerals, \c Z3_FALSE otherwise. + Return \c true if the numeral value fits in 64 bit numerals, \c false otherwise. \pre Z3_get_ast_kind(a) == Z3_NUMERAL_AST @@ -4528,7 +4528,7 @@ extern "C" { /** \brief Similar to #Z3_get_numeral_string, but only succeeds if - the value can fit in a machine int. Return Z3_TRUE if the call succeeded. + the value can fit in a machine int. Return \c true if the call succeeded. \pre Z3_get_ast_kind(c, v) == Z3_NUMERAL_AST @@ -4540,7 +4540,7 @@ extern "C" { /** \brief Similar to #Z3_get_numeral_string, but only succeeds if - the value can fit in a machine unsigned int. Return Z3_TRUE if the call succeeded. + the value can fit in a machine unsigned int. Return \c true if the call succeeded. \pre Z3_get_ast_kind(c, v) == Z3_NUMERAL_AST @@ -4552,7 +4552,7 @@ extern "C" { /** \brief Similar to #Z3_get_numeral_string, but only succeeds if - the value can fit in a machine \c uint64_t int. Return Z3_TRUE if the call succeeded. + the value can fit in a machine \c uint64_t int. Return \c true if the call succeeded. \pre Z3_get_ast_kind(c, v) == Z3_NUMERAL_AST @@ -4564,7 +4564,7 @@ extern "C" { /** \brief Similar to #Z3_get_numeral_string, but only succeeds if - the value can fit in a machine \c int64_t int. Return Z3_TRUE if the call succeeded. + the value can fit in a machine \c int64_t int. Return \c true if the call succeeded. \pre Z3_get_ast_kind(c, v) == Z3_NUMERAL_AST @@ -4576,7 +4576,7 @@ extern "C" { /** \brief Similar to #Z3_get_numeral_string, but only succeeds if - the value can fit as a rational number as machine \c int64_t int. Return Z3_TRUE if the call succeeded. + the value can fit as a rational number as machine \c int64_t int. Return \c true if the call succeeded. \pre Z3_get_ast_kind(c, v) == Z3_NUMERAL_AST @@ -4853,12 +4853,12 @@ extern "C" { /** \brief Evaluate the AST node \c t in the given model. - Return \c Z3_TRUE if succeeded, and store the result in \c v. + Return \c true if succeeded, and store the result in \c v. - If \c model_completion is Z3_TRUE, then Z3 will assign an interpretation for any constant or function that does + If \c model_completion is \c true, then Z3 will assign an interpretation for any constant or function that does not have an interpretation in \c m. These constants and functions were essentially don't cares. - If \c model_completion is Z3_FALSE, then Z3 will not assign interpretations to constants for functions that do + If \c model_completion is \c false, then Z3 will not assign interpretations to constants for functions that do not have interpretations in \c m. Evaluation behaves as the identify function in this case. The evaluation may fail for the following reasons: @@ -4995,7 +4995,7 @@ extern "C" { /** \brief The \ccode{(_ as-array f)} AST node is a construct for assigning interpretations for arrays in Z3. It is the array such that forall indices \c i we have that \ccode{(select (_ as-array f) i)} is equal to \ccode{(f i)}. - This procedure returns Z3_TRUE if the \c a is an \c as-array AST node. + This procedure returns \c true if the \c a is an \c as-array AST node. Z3 current solvers have minimal support for \c as_array nodes. @@ -6370,7 +6370,7 @@ extern "C" { Z3_string Z3_API Z3_stats_get_key(Z3_context c, Z3_stats s, unsigned idx); /** - \brief Return Z3_TRUE if the given statistical data is a unsigned integer. + \brief Return \c true if the given statistical data is a unsigned integer. \pre idx < Z3_stats_size(c, s) @@ -6379,7 +6379,7 @@ extern "C" { Z3_bool Z3_API Z3_stats_is_uint(Z3_context c, Z3_stats s, unsigned idx); /** - \brief Return Z3_TRUE if the given statistical data is a double. + \brief Return \c true if the given statistical data is a double. \pre idx < Z3_stats_size(c, s) diff --git a/src/api/z3_rcf.h b/src/api/z3_rcf.h index 779c3ff88..cc8e5a525 100644 --- a/src/api/z3_rcf.h +++ b/src/api/z3_rcf.h @@ -134,42 +134,42 @@ extern "C" { Z3_rcf_num Z3_API Z3_rcf_power(Z3_context c, Z3_rcf_num a, unsigned k); /** - \brief Return Z3_TRUE if a < b + \brief Return \c true if a < b def_API('Z3_rcf_lt', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM))) */ Z3_bool Z3_API Z3_rcf_lt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); /** - \brief Return Z3_TRUE if a > b + \brief Return \c true if a > b def_API('Z3_rcf_gt', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM))) */ Z3_bool Z3_API Z3_rcf_gt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); /** - \brief Return Z3_TRUE if a <= b + \brief Return \c true if a <= b def_API('Z3_rcf_le', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM))) */ Z3_bool Z3_API Z3_rcf_le(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); /** - \brief Return Z3_TRUE if a >= b + \brief Return \c true if a >= b def_API('Z3_rcf_ge', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM))) */ Z3_bool Z3_API Z3_rcf_ge(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); /** - \brief Return Z3_TRUE if a == b + \brief Return \c true if a == b def_API('Z3_rcf_eq', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM))) */ Z3_bool Z3_API Z3_rcf_eq(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); /** - \brief Return Z3_TRUE if a != b + \brief Return \c true if a != b def_API('Z3_rcf_neq', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM))) */ diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 856ba728e..f0e11c248 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -10608,7 +10608,6 @@ namespace smt { std::map > var_eq_concat_map; int conflictInDep = ctx_dep_analysis(varAppearInAssign, freeVar_map, unrollGroup_map, var_eq_concat_map); if (conflictInDep == -1) { - // return Z3_TRUE; return FC_DONE; } diff --git a/src/test/no_overflow.cpp b/src/test/no_overflow.cpp index bb87b1d30..9ad629383 100644 --- a/src/test/no_overflow.cpp +++ b/src/test/no_overflow.cpp @@ -662,7 +662,7 @@ void test_equiv(Equivalence_params params, unsigned bvsize, bool is_signed) { // Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, t2, Z3_mk_numeral(ctx, "1", bv))); // //TEST_NO_UNDERFLOW; // Z3_solver_assert(ctx, s, test_udfl); -// ENSURE(Z3_check(ctx) == Z3_TRUE); +// ENSURE(Z3_check(ctx) == true); // Z3_solver_pop(ctx, s, 1); // // Z3_del_config(cfg); From 5a825d7ac35288ddd11c43dff4691ec14e880595 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Nov 2018 09:37:23 -0800 Subject: [PATCH 190/227] true is true, false is not true, it is false Signed-off-by: Nikolaj Bjorner --- src/api/api_algebraic.cpp | 4 ++-- src/api/api_arith.cpp | 2 +- src/api/api_model.cpp | 2 +- src/api/api_numeral.cpp | 12 ++++++------ src/api/api_quant.cpp | 6 +++--- src/api/api_seq.cpp | 12 ++++-------- 6 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index c6d0b179b..4ea046f1c 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -83,7 +83,7 @@ extern "C" { Z3_TRY; LOG_Z3_algebraic_is_value(c, a); RESET_ERROR_CODE(); - return Z3_algebraic_is_value_core(c, a) ? true : false; + return Z3_algebraic_is_value_core(c, a); Z3_CATCH_RETURN(false); } @@ -283,7 +283,7 @@ extern "C" { r = _am.IRAT_PRED(av, bv); \ } \ } \ - return r ? true : false; + return r; Z3_bool Z3_API Z3_algebraic_lt(Z3_context c, Z3_ast a, Z3_ast b) { diff --git a/src/api/api_arith.cpp b/src/api/api_arith.cpp index 214a95a73..0827fd911 100644 --- a/src/api/api_arith.cpp +++ b/src/api/api_arith.cpp @@ -121,7 +121,7 @@ extern "C" { Z3_bool Z3_API Z3_is_algebraic_number(Z3_context c, Z3_ast a) { LOG_Z3_is_algebraic_number(c, a); - return mk_c(c)->autil().is_irrational_algebraic_numeral(to_expr(a)) ? true : false; + return mk_c(c)->autil().is_irrational_algebraic_numeral(to_expr(a)); } Z3_ast Z3_API Z3_get_algebraic_number_lower(Z3_context c, Z3_ast a, unsigned precision) { diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 0cc555d3c..279cef673 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -166,7 +166,7 @@ extern "C" { CHECK_IS_EXPR(t, false); model * _m = to_model_ref(m); expr_ref result(mk_c(c)->m()); - model::scoped_model_completion _scm(*_m, model_completion == true); + model::scoped_model_completion _scm(*_m, model_completion); result = (*_m)(to_expr(t)); mk_c(c)->save_ast_trail(result.get()); *v = of_ast(result.get()); diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index f90c0b4f1..718712d61 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -188,7 +188,7 @@ extern "C" { CHECK_IS_EXPR(a, ""); rational r; Z3_bool ok = Z3_get_numeral_rational(c, a, r); - if (ok == true) { + if (ok) { return mk_c(c)->mk_external_string(r.to_string()); } else { @@ -252,8 +252,8 @@ extern "C" { am.display_decimal(buffer, n, precision); return mk_c(c)->mk_external_string(buffer.str()); } - Z3_bool ok = Z3_get_numeral_rational(c, a, r); - if (ok == true) { + bool ok = Z3_get_numeral_rational(c, a, r); + if (ok) { return mk_c(c)->mk_external_string(r.to_string()); } else { @@ -271,7 +271,7 @@ extern "C" { CHECK_IS_EXPR(a, false); rational r; Z3_bool ok = Z3_get_numeral_rational(c, a, r); - if (ok == true) { + if (ok) { rational n = numerator(r); rational d = denominator(r); if (n.is_int64() && d.is_int64()) { @@ -340,7 +340,7 @@ extern "C" { rational r; Z3_bool ok = Z3_get_numeral_rational(c, v, r); SASSERT(u); - if (ok == true && r.is_uint64()) { + if (ok && r.is_uint64()) { *u = r.get_uint64(); return ok; } @@ -360,7 +360,7 @@ extern "C" { } rational r; Z3_bool ok = Z3_get_numeral_rational(c, v, r); - if (ok == true && r.is_int64()) { + if (ok && r.is_int64()) { *i = r.get_int64(); return ok; } diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index 3e639f93d..306b422f1 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -347,7 +347,7 @@ extern "C" { Z3_TRY; LOG_Z3_is_quantifier_forall(c, a); RESET_ERROR_CODE(); - return ::is_forall(to_ast(a)) ? true : false; + return ::is_forall(to_ast(a)); Z3_CATCH_RETURN(false); } @@ -355,7 +355,7 @@ extern "C" { Z3_TRY; LOG_Z3_is_quantifier_exists(c, a); RESET_ERROR_CODE(); - return ::is_exists(to_ast(a)) ? true : false; + return ::is_exists(to_ast(a)); Z3_CATCH_RETURN(false); } @@ -363,7 +363,7 @@ extern "C" { Z3_TRY; LOG_Z3_is_lambda(c, a); RESET_ERROR_CODE(); - return ::is_lambda(to_ast(a)) ? true : false; + return ::is_lambda(to_ast(a)); Z3_CATCH_RETURN(false); } diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 1e9e7f277..7a9ca80a7 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -69,8 +69,7 @@ extern "C" { Z3_TRY; LOG_Z3_is_seq_sort(c, s); RESET_ERROR_CODE(); - bool result = mk_c(c)->sutil().is_seq(to_sort(s)); - return result?true:false; + return mk_c(c)->sutil().is_seq(to_sort(s)); Z3_CATCH_RETURN(false); } @@ -78,8 +77,7 @@ extern "C" { Z3_TRY; LOG_Z3_is_re_sort(c, s); RESET_ERROR_CODE(); - bool result = mk_c(c)->sutil().is_re(to_sort(s)); - return result?true:false; + return mk_c(c)->sutil().is_re(to_sort(s)); Z3_CATCH_RETURN(false); } @@ -87,8 +85,7 @@ extern "C" { Z3_TRY; LOG_Z3_is_string_sort(c, s); RESET_ERROR_CODE(); - bool result = mk_c(c)->sutil().is_string(to_sort(s)); - return result?true:false; + return mk_c(c)->sutil().is_string(to_sort(s)); Z3_CATCH_RETURN(false); } @@ -96,8 +93,7 @@ extern "C" { Z3_TRY; LOG_Z3_is_string(c, s); RESET_ERROR_CODE(); - bool result = mk_c(c)->sutil().str.is_string(to_expr(s)); - return result?true:false; + return mk_c(c)->sutil().str.is_string(to_expr(s)); Z3_CATCH_RETURN(false); } From 04d709dae147542fee24656c8548259f9cd5dd92 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Nov 2018 09:42:10 -0800 Subject: [PATCH 191/227] build errors on shrink Signed-off-by: Nikolaj Bjorner --- src/util/ref_vector.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/ref_vector.h b/src/util/ref_vector.h index f45b44dae..d0a17116a 100644 --- a/src/util/ref_vector.h +++ b/src/util/ref_vector.h @@ -321,6 +321,8 @@ public: return result; } +#if 0 + // TBD: not sure why some compilers complain here. ref_vector& filter_update(std::function& predicate) { unsigned j = 0; for (auto& t : *this) @@ -329,6 +331,7 @@ public: shrink(j); return *this; } +#endif template vector mapv_pure(std::function& f) const { From 7d0d7e6343b6b428ed4ac7947b2f6724a7578b22 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Nov 2018 10:59:12 -0800 Subject: [PATCH 192/227] have replayer handle oom natively Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 1 - src/api/z3_replayer.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 9fe13a15f..c61fa9c4d 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -440,7 +440,6 @@ extern "C" { void Z3_API Z3_set_error_handler(Z3_context c, Z3_error_handler h) { RESET_ERROR_CODE(); mk_c(c)->set_error_handler(h); - // [Leo]: using exception handling, we don't need global error handlers anymore } void Z3_API Z3_set_error(Z3_context c, Z3_error_code e) { diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 8ebac8068..97b88c9d7 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -401,6 +401,7 @@ struct z3_replayer::imp { #define TICK_FREQUENCY 100000 void parse() { + memory::exit_when_out_of_memory(false, nullptr); uint64_t counter = 0; unsigned tick = 0; while (true) { From 7f5d66c3c299cefbf334c24afaf40cbb6761eda3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Nov 2018 12:21:17 -0800 Subject: [PATCH 193/227] updated release notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index dcb8fc093..06618a8f2 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -3,8 +3,12 @@ RELEASE NOTES Version 4.8.3 ============= - New features - - native handling of recursive function definitions + - Native handling of recursive function definitions, thanks to Simon Cruanes - PB rounding based option for conflict resolution when reasoning about PB constraints. + - Access to numeral constants as a double from the native API. + +- Notes + - fixes several bugs discovered since the 4.8.1 release. Version 4.8.2 ============= From e83e9b02dfd977653491f9c76ab05411335a9511 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Nov 2018 15:17:55 -0800 Subject: [PATCH 194/227] increment version number to 4.8.4 Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_nuget_release.py | 18 ++++++++++-------- scripts/mk_project.py | 2 +- src/sat/sat_parallel.cpp | 11 ----------- src/sat/sat_parallel.h | 2 -- 5 files changed, 12 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd9c14435..bc5eecdef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() ################################################################################ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 8) -set(Z3_VERSION_PATCH 3) +set(Z3_VERSION_PATCH 4) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index 09cfd2b7a..7d2f23998 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -31,8 +31,6 @@ def download_installs(): for asset in data['assets']: url = asset['browser_download_url'] name = asset['name'] - if "x64" not in name: - continue print("Downloading ", url) sys.stdout.flush() urllib.request.urlretrieve(url, "packages/%s" % name) @@ -40,6 +38,8 @@ def download_installs(): os_info = {"ubuntu-14" : ('so', 'ubuntu.14.04-x64'), 'ubuntu-16' : ('so', 'ubuntu.16.04-x64'), 'win' : ('dll', 'win-x64'), + 'win' : ('dll', 'win-x86'), + 'osx' : ('dylib', 'macos'), 'debian' : ('so', 'debian.8-x64') } def classify_package(f): @@ -54,18 +54,20 @@ def unpack(): # out # +- runtimes # +- win-x64 + # +- win-x86 # +- ubuntu.16.04-x64 # +- ubuntu.14.04-x64 # +- debian.8-x64 + # +- macos # + - for f in os.listdir("packages"): - if f.endswith("zip") and "x64" in f and classify_package(f): - print(f) + for f in os.listdir("packages"): + print(f) + if f.endswith("zip") and classify_package(f): os_name, package_dir, ext, dst = classify_package(f) zip_ref = zipfile.ZipFile("packages/%s" % f, 'r') zip_ref.extract("%s/bin/libz3.%s" % (package_dir, ext), "tmp") mk_dir("out/runtimes/%s" % dst) - shutil.move("tmp/%s/bin/libz3.%s" % (package_dir, ext), "out/runtimes/%s/." % dst) + shutil.move("tmp/%s/bin/libz3.%s" % (package_dir, ext), "out/runtimes/%s/." % dst, "/y") if "win" in f: mk_dir("out/lib/netstandard1.4/") for b in ["Microsoft.Z3.dll"]: @@ -77,7 +79,7 @@ def create_nuget_spec(): contents = """ - Microsoft.Z3.x64 + Microsoft.Z3 %s Microsoft Z3 is a satisfiability modulo theories solver from Microsoft Research. @@ -96,7 +98,7 @@ def create_nuget_spec(): """ - with open("out/Microsoft.Z3.x64.nuspec", 'w') as f: + with open("out/Microsoft.Z3.nuspec", 'w') as f: f.write(contents % mk_util.get_version_string(3)) def create_nuget_package(): diff --git a/scripts/mk_project.py b/scripts/mk_project.py index e70a094a0..8cf60ab62 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, 8, 3, 0) + set_version(4, 8, 4, 0) # Z3 Project definition def init_project_def(): diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 33cb02a87..ce2080f8c 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -285,17 +285,6 @@ namespace sat { return copied; } - void parallel::set_phase(local_search& s) { - #pragma omp critical (par_solver) - { - m_consumer_ready = true; - m_phase.reserve(s.num_vars(), l_undef); - for (unsigned i = 0; i < s.num_vars(); ++i) { - m_phase[i] = s.get_phase(i) ? l_true : l_false; - } - m_num_clauses = s.num_non_binary_clauses(); - } - } bool parallel::copy_solver(solver& s) { bool copied = false; diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h index 256623380..afb148ed4 100644 --- a/src/sat/sat_parallel.h +++ b/src/sat/sat_parallel.h @@ -104,8 +104,6 @@ namespace sat { void get_phase(solver& s); - void set_phase(local_search& s); - bool get_phase(local_search& s); bool copy_solver(solver& s); From 76d0a5a6ed300e765251f416d6b84fbeee00c051 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Nov 2018 15:35:42 -0800 Subject: [PATCH 195/227] tweaks to mk_nuget_release Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_release.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index 7d2f23998..265968b7e 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -23,6 +23,8 @@ data = json.loads(urllib.request.urlopen("https://api.github.com/repos/Z3Prover/ version_str = data['tag_name'] +print(version_str) + def mk_dir(d): if not os.path.exists(d): os.makedirs(d) @@ -33,12 +35,13 @@ def download_installs(): name = asset['name'] print("Downloading ", url) sys.stdout.flush() + continue urllib.request.urlretrieve(url, "packages/%s" % name) -os_info = {"ubuntu-14" : ('so', 'ubuntu.14.04-x64'), +os_info = {"z64-ubuntu-14" : ('so', 'ubuntu.14.04-x64'), 'ubuntu-16' : ('so', 'ubuntu.16.04-x64'), - 'win' : ('dll', 'win-x64'), - 'win' : ('dll', 'win-x86'), + 'x64-win' : ('dll', 'win-x64'), + 'x86-win' : ('dll', 'win-x86'), 'osx' : ('dylib', 'macos'), 'debian' : ('so', 'debian.8-x64') } @@ -50,6 +53,7 @@ def classify_package(f): return None def unpack(): + shutil.rmtree("out") # unzip files in packages # out # +- runtimes @@ -62,9 +66,10 @@ def unpack(): # + for f in os.listdir("packages"): print(f) - if f.endswith("zip") and classify_package(f): - os_name, package_dir, ext, dst = classify_package(f) - zip_ref = zipfile.ZipFile("packages/%s" % f, 'r') + if f.endswith(".zip") and classify_package(f): + os_name, package_dir, ext, dst = classify_package(f) + path = os.path.abspath(os.path.join("packages", f)) + zip_ref = zipfile.ZipFile(path, 'r') zip_ref.extract("%s/bin/libz3.%s" % (package_dir, ext), "tmp") mk_dir("out/runtimes/%s" % dst) shutil.move("tmp/%s/bin/libz3.%s" % (package_dir, ext), "out/runtimes/%s/." % dst, "/y") @@ -75,7 +80,6 @@ def unpack(): shutil.move("tmp/%s/bin/%s" % (package_dir, b), "out/lib/netstandard1.4/%s" % b) def create_nuget_spec(): - mk_project.init_version() contents = """ @@ -99,8 +103,8 @@ def create_nuget_spec(): """ with open("out/Microsoft.Z3.nuspec", 'w') as f: - f.write(contents % mk_util.get_version_string(3)) - + f.write(contents % version_str[3:]) + def create_nuget_package(): subprocess.call(["nuget", "pack"], cwd="out") From a076e330372c1ae2a5cea1c0c1c8809e0c1b889e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Nov 2018 15:35:49 -0800 Subject: [PATCH 196/227] tweaks to mk_nuget_release Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_release.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index 265968b7e..7ce14bf5d 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -35,7 +35,6 @@ def download_installs(): name = asset['name'] print("Downloading ", url) sys.stdout.flush() - continue urllib.request.urlretrieve(url, "packages/%s" % name) os_info = {"z64-ubuntu-14" : ('so', 'ubuntu.14.04-x64'), From edf8ba44d1c9d68e636639184a77c1528f07940d Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 20 Nov 2018 11:27:09 +0700 Subject: [PATCH 197/227] Switch from using Z3_bool to using bool. This is a continuation of the work started by using stdbool and continued by switching from Z3_TRUE|FALSE to true|false. --- examples/c/test_capi.c | 14 +++---- examples/tptp/tptp5.cpp | 2 +- scripts/update_api.py | 8 ++-- src/api/api_algebraic.cpp | 20 ++++----- src/api/api_arith.cpp | 2 +- src/api/api_ast.cpp | 10 ++--- src/api/api_ast_map.cpp | 2 +- src/api/api_bv.cpp | 8 ++-- src/api/api_context.cpp | 2 +- src/api/api_datalog.cpp | 2 +- src/api/api_fpa.cpp | 32 +++++++-------- src/api/api_goal.cpp | 8 ++-- src/api/api_log.cpp | 4 +- src/api/api_model.cpp | 6 +-- src/api/api_numeral.cpp | 28 ++++++------- src/api/api_params.cpp | 2 +- src/api/api_quant.cpp | 16 ++++---- src/api/api_rcf.cpp | 14 +++---- src/api/api_seq.cpp | 8 ++-- src/api/api_stats.cpp | 4 +- src/api/c++/z3++.h | 8 ++-- src/api/z3_algebraic.h | 20 ++++----- src/api/z3_api.h | 82 ++++++++++++++++++------------------- src/api/z3_ast_containers.h | 2 +- src/api/z3_fpa.h | 32 +++++++-------- src/api/z3_private.h | 2 +- src/api/z3_rcf.h | 14 +++---- src/test/no_overflow.cpp | 12 +++--- 28 files changed, 182 insertions(+), 182 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index ea0cd8528..980592f25 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -241,7 +241,7 @@ void check(Z3_context ctx, Z3_solver s, Z3_lbool expected_result) The context \c ctx is not modified by this function. */ -void prove(Z3_context ctx, Z3_solver s, Z3_ast f, Z3_bool is_valid) +void prove(Z3_context ctx, Z3_solver s, Z3_ast f, bool is_valid) { Z3_model m = 0; Z3_ast not_f; @@ -639,7 +639,7 @@ void display_model(Z3_context c, FILE * out, Z3_model m) Z3_symbol name; Z3_func_decl cnst = Z3_model_get_const_decl(c, m, i); Z3_ast a, v; - Z3_bool ok; + bool ok; name = Z3_get_decl_name(c, cnst); display_symbol(c, out, name); fprintf(out, " = "); @@ -2304,7 +2304,7 @@ typedef struct { // IMPORTANT: the fields m_answer_literals, m_retracted and m_num_answer_literals must be saved/restored // if push/pop operations are performed on m_context. Z3_ast m_answer_literals[MAX_RETRACTABLE_ASSERTIONS]; - Z3_bool m_retracted[MAX_RETRACTABLE_ASSERTIONS]; // true if the assertion was retracted. + bool m_retracted[MAX_RETRACTABLE_ASSERTIONS]; // true if the assertion was retracted. unsigned m_num_answer_literals; } Z3_ext_context_struct; @@ -2872,7 +2872,7 @@ void mk_model_example() { /*num_args=*/2, /*args=*/addArgs); Z3_ast aPlusBEval = NULL; - Z3_bool aPlusBEvalSuccess = + bool aPlusBEvalSuccess = Z3_model_eval(ctx, m, aPlusB, /*model_completion=*/false, &aPlusBEval); if (aPlusBEvalSuccess != true) { @@ -2882,7 +2882,7 @@ void mk_model_example() { { int aPlusBValue = 0; - Z3_bool getAPlusBValueSuccess = + bool getAPlusBValueSuccess = Z3_get_numeral_int(ctx, aPlusBEval, &aPlusBValue); if (getAPlusBValueSuccess != true) { printf("Failed to get integer value for a+b\n"); @@ -2906,7 +2906,7 @@ void mk_model_example() { /*num_args=*/3, /*args=*/arrayAddArgs); Z3_ast arrayAddEval = NULL; - Z3_bool arrayAddEvalSuccess = + bool arrayAddEvalSuccess = Z3_model_eval(ctx, m, arrayAdd, /*model_completion=*/false, &arrayAddEval); if (arrayAddEvalSuccess != true) { @@ -2915,7 +2915,7 @@ void mk_model_example() { } { int arrayAddValue = 0; - Z3_bool getArrayAddValueSuccess = + bool getArrayAddValueSuccess = Z3_get_numeral_int(ctx, arrayAddEval, &arrayAddValue); if (getArrayAddValueSuccess != true) { printf("Failed to get integer value for c[0] + c[1] + c[2]\n"); diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index 882c2bbe2..1a1e31f0a 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -1337,7 +1337,7 @@ public: } } else if (e.is_quantifier()) { - Z3_bool is_forall = Z3_is_quantifier_forall(ctx, e); + bool is_forall = Z3_is_quantifier_forall(ctx, e); unsigned nb = Z3_get_quantifier_num_bound(ctx, e); out << (is_forall?"!":"?") << "["; diff --git a/scripts/update_api.py b/scripts/update_api.py index 227d02dd2..901ea4fda 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -61,7 +61,7 @@ def is_obj(ty): return ty >= FIRST_OBJ_ID Type2Str = { VOID : 'void', VOID_PTR : 'void*', INT : 'int', UINT : 'unsigned', INT64 : 'int64_t', UINT64 : 'uint64_t', DOUBLE : 'double', - FLOAT : 'float', STRING : 'Z3_string', STRING_PTR : 'Z3_string_ptr', BOOL : 'Z3_bool', SYMBOL : 'Z3_symbol', + FLOAT : 'float', STRING : 'Z3_string', STRING_PTR : 'Z3_string_ptr', BOOL : 'bool', SYMBOL : 'Z3_symbol', PRINT_MODE : 'Z3_ast_print_mode', ERROR_CODE : 'Z3_error_code' } @@ -1227,7 +1227,7 @@ def ml_has_plus_type(ts): def ml_unwrap(t, ts, s): if t == STRING: return '(' + ts + ') String_val(' + s + ')' - elif t == BOOL or (type2str(t) == 'Z3_bool'): + elif t == BOOL or (type2str(t) == 'bool'): return '(' + ts + ') Bool_val(' + s + ')' elif t == INT or t == PRINT_MODE or t == ERROR_CODE: return '(' + ts + ') Int_val(' + s + ')' @@ -1248,7 +1248,7 @@ def ml_unwrap(t, ts, s): def ml_set_wrap(t, d, n): if t == VOID: return d + ' = Val_unit;' - elif t == BOOL or (type2str(t) == 'Z3_bool'): + elif t == BOOL or (type2str(t) == 'bool'): return d + ' = Val_bool(' + n + ');' elif t == INT or t == UINT or t == PRINT_MODE or t == ERROR_CODE: return d + ' = Val_int(' + n + ');' @@ -1263,7 +1263,7 @@ def ml_set_wrap(t, d, n): return '*(' + pts + '*)Data_custom_val(' + d + ') = ' + n + ';' def ml_alloc_and_store(t, lhs, rhs): - if t == VOID or t == BOOL or t == INT or t == UINT or t == PRINT_MODE or t == ERROR_CODE or t == INT64 or t == UINT64 or t == DOUBLE or t == STRING or (type2str(t) == 'Z3_bool'): + if t == VOID or t == BOOL or t == INT or t == UINT or t == PRINT_MODE or t == ERROR_CODE or t == INT64 or t == UINT64 or t == DOUBLE or t == STRING or (type2str(t) == 'bool'): return ml_set_wrap(t, lhs, rhs) else: pts = ml_plus_type(type2str(t)) diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index 4ea046f1c..7d08ade35 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -79,7 +79,7 @@ extern "C" { _c->autil().is_irrational_algebraic_numeral(to_expr(a))); } - Z3_bool Z3_API Z3_algebraic_is_value(Z3_context c, Z3_ast a) { + bool Z3_API Z3_algebraic_is_value(Z3_context c, Z3_ast a) { Z3_TRY; LOG_Z3_algebraic_is_value(c, a); RESET_ERROR_CODE(); @@ -87,15 +87,15 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_algebraic_is_pos(Z3_context c, Z3_ast a) { + bool Z3_API Z3_algebraic_is_pos(Z3_context c, Z3_ast a) { return Z3_algebraic_sign(c, a) > 0; } - Z3_bool Z3_API Z3_algebraic_is_neg(Z3_context c, Z3_ast a) { + bool Z3_API Z3_algebraic_is_neg(Z3_context c, Z3_ast a) { return Z3_algebraic_sign(c, a) < 0; } - Z3_bool Z3_API Z3_algebraic_is_zero(Z3_context c, Z3_ast a) { + bool Z3_API Z3_algebraic_is_zero(Z3_context c, Z3_ast a) { return Z3_algebraic_sign(c, a) == 0; } @@ -286,7 +286,7 @@ extern "C" { return r; - Z3_bool Z3_API Z3_algebraic_lt(Z3_context c, Z3_ast a, Z3_ast b) { + bool Z3_API Z3_algebraic_lt(Z3_context c, Z3_ast a, Z3_ast b) { Z3_TRY; LOG_Z3_algebraic_lt(c, a, b); RESET_ERROR_CODE(); @@ -296,19 +296,19 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_algebraic_gt(Z3_context c, Z3_ast a, Z3_ast b) { + bool Z3_API Z3_algebraic_gt(Z3_context c, Z3_ast a, Z3_ast b) { return Z3_algebraic_lt(c, b, a); } - Z3_bool Z3_API Z3_algebraic_le(Z3_context c, Z3_ast a, Z3_ast b) { + bool Z3_API Z3_algebraic_le(Z3_context c, Z3_ast a, Z3_ast b) { return !Z3_algebraic_lt(c, b, a); } - Z3_bool Z3_API Z3_algebraic_ge(Z3_context c, Z3_ast a, Z3_ast b) { + bool Z3_API Z3_algebraic_ge(Z3_context c, Z3_ast a, Z3_ast b) { return !Z3_algebraic_lt(c, a, b); } - Z3_bool Z3_API Z3_algebraic_eq(Z3_context c, Z3_ast a, Z3_ast b) { + bool Z3_API Z3_algebraic_eq(Z3_context c, Z3_ast a, Z3_ast b) { Z3_TRY; LOG_Z3_algebraic_eq(c, a, b); RESET_ERROR_CODE(); @@ -318,7 +318,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_bool Z3_API Z3_algebraic_neq(Z3_context c, Z3_ast a, Z3_ast b) { + bool Z3_API Z3_algebraic_neq(Z3_context c, Z3_ast a, Z3_ast b) { return !Z3_algebraic_eq(c, a, b); } diff --git a/src/api/api_arith.cpp b/src/api/api_arith.cpp index 0827fd911..69fde33a7 100644 --- a/src/api/api_arith.cpp +++ b/src/api/api_arith.cpp @@ -119,7 +119,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_is_algebraic_number(Z3_context c, Z3_ast a) { + bool Z3_API Z3_is_algebraic_number(Z3_context c, Z3_ast a) { LOG_Z3_is_algebraic_number(c, a); return mk_c(c)->autil().is_irrational_algebraic_numeral(to_expr(a)); } diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 277715950..d10da60db 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -73,7 +73,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_is_eq_sort(Z3_context c, Z3_sort s1, Z3_sort s2) { + bool Z3_API Z3_is_eq_sort(Z3_context c, Z3_sort s1, Z3_sort s2) { RESET_ERROR_CODE(); return s1 == s2; } @@ -88,12 +88,12 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_is_eq_ast(Z3_context c, Z3_ast s1, Z3_ast s2) { + bool Z3_API Z3_is_eq_ast(Z3_context c, Z3_ast s1, Z3_ast s2) { RESET_ERROR_CODE(); return s1 == s2; } - Z3_bool Z3_API Z3_is_eq_func_decl(Z3_context c, Z3_func_decl s1, Z3_func_decl s2) { + bool Z3_API Z3_is_eq_func_decl(Z3_context c, Z3_func_decl s1, Z3_func_decl s2) { RESET_ERROR_CODE(); return s1 == s2; } @@ -308,7 +308,7 @@ extern "C" { return to_sort(s)->get_id(); } - Z3_bool Z3_API Z3_is_well_sorted(Z3_context c, Z3_ast t) { + bool Z3_API Z3_is_well_sorted(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_is_well_sorted(c, t); RESET_ERROR_CODE(); @@ -383,7 +383,7 @@ extern "C" { return to_ast(a)->hash(); } - Z3_bool Z3_API Z3_is_app(Z3_context c, Z3_ast a) { + bool Z3_API Z3_is_app(Z3_context c, Z3_ast a) { LOG_Z3_is_app(c, a); RESET_ERROR_CODE(); return a != nullptr && is_app(reinterpret_cast(a)); diff --git a/src/api/api_ast_map.cpp b/src/api/api_ast_map.cpp index 524bd113d..aaece1621 100644 --- a/src/api/api_ast_map.cpp +++ b/src/api/api_ast_map.cpp @@ -57,7 +57,7 @@ extern "C" { Z3_CATCH; } - Z3_bool Z3_API Z3_ast_map_contains(Z3_context c, Z3_ast_map m, Z3_ast k) { + bool Z3_API Z3_ast_map_contains(Z3_context c, Z3_ast_map m, Z3_ast k) { Z3_TRY; LOG_Z3_ast_map_contains(c, m, k); RESET_ERROR_CODE(); diff --git a/src/api/api_bv.cpp b/src/api/api_bv.cpp index bd603aa6d..e56371bb5 100644 --- a/src/api/api_bv.cpp +++ b/src/api/api_bv.cpp @@ -106,7 +106,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ MK_BV_PUNARY(Z3_mk_rotate_right, OP_ROTATE_RIGHT); MK_BV_PUNARY(Z3_mk_int2bv, OP_INT2BV); - Z3_ast Z3_API Z3_mk_bv2int(Z3_context c, Z3_ast n, Z3_bool is_signed) { + Z3_ast Z3_API Z3_mk_bv2int(Z3_context c, Z3_ast n, bool is_signed) { Z3_TRY; LOG_Z3_mk_bv2int(c, n, is_signed); RESET_ERROR_CODE(); @@ -186,7 +186,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ return Z3_mk_int(c, -1, s); } - Z3_ast Z3_API Z3_mk_bvadd_no_overflow(Z3_context c, Z3_ast t1, Z3_ast t2, Z3_bool is_signed) { + Z3_ast Z3_API Z3_mk_bvadd_no_overflow(Z3_context c, Z3_ast t1, Z3_ast t2, bool is_signed) { Z3_TRY; RESET_ERROR_CODE(); if (is_signed) { @@ -286,7 +286,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_CATCH_RETURN(nullptr); } - Z3_ast Z3_API Z3_mk_bvsub_no_underflow(Z3_context c, Z3_ast t1, Z3_ast t2, Z3_bool is_signed) { + Z3_ast Z3_API Z3_mk_bvsub_no_underflow(Z3_context c, Z3_ast t1, Z3_ast t2, bool is_signed) { Z3_TRY; RESET_ERROR_CODE(); if (is_signed) { @@ -311,7 +311,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_CATCH_RETURN(nullptr); } - Z3_ast Z3_API Z3_mk_bvmul_no_overflow(Z3_context c, Z3_ast n1, Z3_ast n2, Z3_bool is_signed) { + Z3_ast Z3_API Z3_mk_bvmul_no_overflow(Z3_context c, Z3_ast n1, Z3_ast n2, bool is_signed) { LOG_Z3_mk_bvmul_no_overflow(c, n1, n2, is_signed); RESET_ERROR_CODE(); if (is_signed) { diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index c61fa9c4d..0b1bf4490 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -363,7 +363,7 @@ extern "C" { Z3_CATCH; } - void Z3_API Z3_toggle_warning_messages(Z3_bool enabled) { + void Z3_API Z3_toggle_warning_messages(bool enabled) { LOG_Z3_toggle_warning_messages(enabled); enable_warning_messages(enabled != 0); } diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 0f6bd49cc..790470275 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -199,7 +199,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, uint64_t * out) { + bool Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, uint64_t * out) { Z3_TRY; if (out) { *out = 0; diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index c8a2690c6..9728cbc00 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -232,7 +232,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_ast Z3_API Z3_mk_fpa_inf(Z3_context c, Z3_sort s, Z3_bool negative) { + Z3_ast Z3_API Z3_mk_fpa_inf(Z3_context c, Z3_sort s, bool negative) { Z3_TRY; LOG_Z3_mk_fpa_inf(c, s, negative); RESET_ERROR_CODE(); @@ -249,7 +249,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_ast Z3_API Z3_mk_fpa_zero(Z3_context c, Z3_sort s, Z3_bool negative) { + Z3_ast Z3_API Z3_mk_fpa_zero(Z3_context c, Z3_sort s, bool negative) { Z3_TRY; LOG_Z3_mk_fpa_inf(c, s, negative); RESET_ERROR_CODE(); @@ -338,7 +338,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_ast Z3_API Z3_mk_fpa_numeral_int_uint(Z3_context c, Z3_bool sgn, signed exp, unsigned sig, Z3_sort ty) { + Z3_ast Z3_API Z3_mk_fpa_numeral_int_uint(Z3_context c, bool sgn, signed exp, unsigned sig, Z3_sort ty) { Z3_TRY; LOG_Z3_mk_fpa_numeral_int64_uint64(c, sgn, exp, sig, ty); RESET_ERROR_CODE(); @@ -358,7 +358,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_ast Z3_API Z3_mk_fpa_numeral_int64_uint64(Z3_context c, Z3_bool sgn, int64_t exp, uint64_t sig, Z3_sort ty) { + Z3_ast Z3_API Z3_mk_fpa_numeral_int64_uint64(Z3_context c, bool sgn, int64_t exp, uint64_t sig, Z3_sort ty) { Z3_TRY; LOG_Z3_mk_fpa_numeral_int64_uint64(c, sgn, exp, sig, ty); RESET_ERROR_CODE(); @@ -905,7 +905,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_bool Z3_API Z3_fpa_get_numeral_sign(Z3_context c, Z3_ast t, int * sgn) { + bool Z3_API Z3_fpa_get_numeral_sign(Z3_context c, Z3_ast t, int * sgn) { Z3_TRY; LOG_Z3_fpa_get_numeral_sign(c, t, sgn); RESET_ERROR_CODE(); @@ -1035,7 +1035,7 @@ extern "C" { Z3_CATCH_RETURN(""); } - Z3_bool Z3_API Z3_fpa_get_numeral_significand_uint64(Z3_context c, Z3_ast t, uint64_t * n) { + bool Z3_API Z3_fpa_get_numeral_significand_uint64(Z3_context c, Z3_ast t, uint64_t * n) { Z3_TRY; LOG_Z3_fpa_get_numeral_significand_uint64(c, t, n); RESET_ERROR_CODE(); @@ -1072,7 +1072,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_string Z3_API Z3_fpa_get_numeral_exponent_string(Z3_context c, Z3_ast t, Z3_bool biased) { + Z3_string Z3_API Z3_fpa_get_numeral_exponent_string(Z3_context c, Z3_ast t, bool biased) { Z3_TRY; LOG_Z3_fpa_get_numeral_exponent_string(c, t, biased); RESET_ERROR_CODE(); @@ -1113,7 +1113,7 @@ extern "C" { Z3_CATCH_RETURN(""); } - Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(Z3_context c, Z3_ast t, int64_t * n, Z3_bool biased) { + bool Z3_API Z3_fpa_get_numeral_exponent_int64(Z3_context c, Z3_ast t, int64_t * n, bool biased) { Z3_TRY; LOG_Z3_fpa_get_numeral_exponent_int64(c, t, n, biased); RESET_ERROR_CODE(); @@ -1157,7 +1157,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_fpa_get_numeral_exponent_bv(Z3_context c, Z3_ast t, Z3_bool biased) { + Z3_ast Z3_API Z3_fpa_get_numeral_exponent_bv(Z3_context c, Z3_ast t, bool biased) { Z3_TRY; LOG_Z3_fpa_get_numeral_exponent_bv(c, t, biased); RESET_ERROR_CODE(); @@ -1232,7 +1232,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_fpa_is_numeral_nan(Z3_context c, Z3_ast t) { + bool Z3_API Z3_fpa_is_numeral_nan(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_fpa_is_numeral_nan(c, t); RESET_ERROR_CODE(); @@ -1246,7 +1246,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_fpa_is_numeral_inf(Z3_context c, Z3_ast t) { + bool Z3_API Z3_fpa_is_numeral_inf(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_fpa_is_numeral_inf(c, t); RESET_ERROR_CODE(); @@ -1260,7 +1260,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_fpa_is_numeral_zero(Z3_context c, Z3_ast t) { + bool Z3_API Z3_fpa_is_numeral_zero(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_fpa_is_numeral_zero(c, t); RESET_ERROR_CODE(); @@ -1274,7 +1274,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_fpa_is_numeral_normal(Z3_context c, Z3_ast t) { + bool Z3_API Z3_fpa_is_numeral_normal(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_fpa_is_numeral_normal(c, t); RESET_ERROR_CODE(); @@ -1288,7 +1288,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_fpa_is_numeral_subnormal(Z3_context c, Z3_ast t) { + bool Z3_API Z3_fpa_is_numeral_subnormal(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_fpa_is_numeral_subnormal(c, t); RESET_ERROR_CODE(); @@ -1302,7 +1302,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_fpa_is_numeral_positive(Z3_context c, Z3_ast t) { + bool Z3_API Z3_fpa_is_numeral_positive(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_fpa_is_numeral_positive(c, t); RESET_ERROR_CODE(); @@ -1316,7 +1316,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_fpa_is_numeral_negative(Z3_context c, Z3_ast t) { + bool Z3_API Z3_fpa_is_numeral_negative(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_fpa_is_numeral_negative(c, t); RESET_ERROR_CODE(); diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index 1a67e1061..c70d241e0 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -25,7 +25,7 @@ Revision History: extern "C" { - Z3_goal Z3_API Z3_mk_goal(Z3_context c, Z3_bool models, Z3_bool unsat_cores, Z3_bool proofs) { + Z3_goal Z3_API Z3_mk_goal(Z3_context c, bool models, bool unsat_cores, bool proofs) { Z3_TRY; LOG_Z3_mk_goal(c, models, unsat_cores, proofs); RESET_ERROR_CODE(); @@ -82,7 +82,7 @@ extern "C" { Z3_CATCH; } - Z3_bool Z3_API Z3_goal_inconsistent(Z3_context c, Z3_goal g) { + bool Z3_API Z3_goal_inconsistent(Z3_context c, Z3_goal g) { Z3_TRY; LOG_Z3_goal_inconsistent(c, g); RESET_ERROR_CODE(); @@ -136,7 +136,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_bool Z3_API Z3_goal_is_decided_sat(Z3_context c, Z3_goal g) { + bool Z3_API Z3_goal_is_decided_sat(Z3_context c, Z3_goal g) { Z3_TRY; LOG_Z3_goal_is_decided_sat(c, g); RESET_ERROR_CODE(); @@ -144,7 +144,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_goal_is_decided_unsat(Z3_context c, Z3_goal g) { + bool Z3_API Z3_goal_is_decided_unsat(Z3_context c, Z3_goal g) { Z3_TRY; LOG_Z3_goal_is_decided_unsat(c, g); RESET_ERROR_CODE(); diff --git a/src/api/api_log.cpp b/src/api/api_log.cpp index dd517c82f..d338407bf 100644 --- a/src/api/api_log.cpp +++ b/src/api/api_log.cpp @@ -33,8 +33,8 @@ extern "C" { } } - Z3_bool Z3_API Z3_open_log(Z3_string filename) { - Z3_bool res = true; + bool Z3_API Z3_open_log(Z3_string filename) { + bool res = true; #ifdef Z3_LOG_SYNC #pragma omp critical (z3_log) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 279cef673..c7347f299 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -75,7 +75,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_model_has_interp(Z3_context c, Z3_model m, Z3_func_decl a) { + bool Z3_API Z3_model_has_interp(Z3_context c, Z3_model m, Z3_func_decl a) { Z3_TRY; LOG_Z3_model_has_interp(c, m, a); CHECK_NON_NULL(m, 0); @@ -157,7 +157,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_model_eval(Z3_context c, Z3_model m, Z3_ast t, Z3_bool model_completion, Z3_ast * v) { + bool Z3_API Z3_model_eval(Z3_context c, Z3_model m, Z3_ast t, bool model_completion, Z3_ast * v) { Z3_TRY; LOG_Z3_model_eval(c, m, t, model_completion, v); if (v) *v = nullptr; @@ -225,7 +225,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_is_as_array(Z3_context c, Z3_ast a) { + bool Z3_API Z3_is_as_array(Z3_context c, Z3_ast a) { Z3_TRY; LOG_Z3_is_as_array(c, a); RESET_ERROR_CODE(); diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 718712d61..cfa64e2c3 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -142,7 +142,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_is_numeral_ast(Z3_context c, Z3_ast a) { + bool Z3_API Z3_is_numeral_ast(Z3_context c, Z3_ast a) { Z3_TRY; LOG_Z3_is_numeral_ast(c, a); RESET_ERROR_CODE(); @@ -157,7 +157,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_get_numeral_rational(Z3_context c, Z3_ast a, rational& r) { + bool Z3_API Z3_get_numeral_rational(Z3_context c, Z3_ast a, rational& r) { Z3_TRY; // This function is not part of the public API RESET_ERROR_CODE(); @@ -187,7 +187,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_IS_EXPR(a, ""); rational r; - Z3_bool ok = Z3_get_numeral_rational(c, a, r); + bool ok = Z3_get_numeral_rational(c, a, r); if (ok) { return mk_c(c)->mk_external_string(r.to_string()); } @@ -263,14 +263,14 @@ extern "C" { Z3_CATCH_RETURN(""); } - Z3_bool Z3_API Z3_get_numeral_small(Z3_context c, Z3_ast a, int64_t* num, int64_t* den) { + bool Z3_API Z3_get_numeral_small(Z3_context c, Z3_ast a, int64_t* num, int64_t* den) { Z3_TRY; // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_small(c, a, num, den); RESET_ERROR_CODE(); CHECK_IS_EXPR(a, false); rational r; - Z3_bool ok = Z3_get_numeral_rational(c, a, r); + bool ok = Z3_get_numeral_rational(c, a, r); if (ok) { rational n = numerator(r); rational d = denominator(r); @@ -289,7 +289,7 @@ extern "C" { } - Z3_bool Z3_API Z3_get_numeral_int(Z3_context c, Z3_ast v, int* i) { + bool Z3_API Z3_get_numeral_int(Z3_context c, Z3_ast v, int* i) { Z3_TRY; // This function invokes Z3_get_numeral_int64, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_int(c, v, i); @@ -308,7 +308,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_get_numeral_uint(Z3_context c, Z3_ast v, unsigned* u) { + bool Z3_API Z3_get_numeral_uint(Z3_context c, Z3_ast v, unsigned* u) { Z3_TRY; // This function invokes Z3_get_numeral_uint64, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_uint(c, v, u); @@ -327,7 +327,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, uint64_t* u) { + bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, uint64_t* u) { Z3_TRY; // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_uint64(c, v, u); @@ -338,7 +338,7 @@ extern "C" { return false; } rational r; - Z3_bool ok = Z3_get_numeral_rational(c, v, r); + bool ok = Z3_get_numeral_rational(c, v, r); SASSERT(u); if (ok && r.is_uint64()) { *u = r.get_uint64(); @@ -348,7 +348,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_get_numeral_int64(Z3_context c, Z3_ast v, int64_t* i) { + bool Z3_API Z3_get_numeral_int64(Z3_context c, Z3_ast v, int64_t* i) { Z3_TRY; // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_int64(c, v, i); @@ -359,7 +359,7 @@ extern "C" { return false; } rational r; - Z3_bool ok = Z3_get_numeral_rational(c, v, r); + bool ok = Z3_get_numeral_rational(c, v, r); if (ok && r.is_int64()) { *i = r.get_int64(); return ok; @@ -368,7 +368,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_get_numeral_rational_int64(Z3_context c, Z3_ast v, int64_t* num, int64_t* den) { + bool Z3_API Z3_get_numeral_rational_int64(Z3_context c, Z3_ast v, int64_t* num, int64_t* den) { Z3_TRY; // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_rational_int64(c, v, num, den); @@ -379,7 +379,7 @@ extern "C" { return false; } rational r; - Z3_bool ok = Z3_get_numeral_rational(c, v, r); + bool ok = Z3_get_numeral_rational(c, v, r); if (ok != true) { return ok; } @@ -394,7 +394,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_ast Z3_API Z3_mk_bv_numeral(Z3_context c, unsigned sz, Z3_bool const* bits) { + Z3_ast Z3_API Z3_mk_bv_numeral(Z3_context c, unsigned sz, bool const* bits) { Z3_TRY; LOG_Z3_mk_bv_numeral(c, sz, bits); RESET_ERROR_CODE(); diff --git a/src/api/api_params.cpp b/src/api/api_params.cpp index 9d9f5157c..31a196f96 100644 --- a/src/api/api_params.cpp +++ b/src/api/api_params.cpp @@ -62,7 +62,7 @@ extern "C" { /** \brief Add a Boolean parameter \c k with value \c v to the parameter set \c p. */ - void Z3_API Z3_params_set_bool(Z3_context c, Z3_params p, Z3_symbol k, Z3_bool v) { + void Z3_API Z3_params_set_bool(Z3_context c, Z3_params p, Z3_symbol k, bool v) { Z3_TRY; LOG_Z3_params_set_bool(c, p, k, v); RESET_ERROR_CODE(); diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index 306b422f1..546f4174a 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -26,7 +26,7 @@ extern "C" { Z3_ast Z3_API Z3_mk_quantifier( Z3_context c, - Z3_bool is_forall, + bool is_forall, unsigned weight, unsigned num_patterns, Z3_pattern const patterns[], unsigned num_decls, Z3_sort const sorts[], @@ -50,7 +50,7 @@ extern "C" { Z3_ast mk_quantifier_ex_core( Z3_context c, - Z3_bool is_forall, + bool is_forall, unsigned weight, Z3_symbol quantifier_id, Z3_symbol skolem_id, @@ -109,7 +109,7 @@ extern "C" { Z3_ast Z3_API Z3_mk_quantifier_ex( Z3_context c, - Z3_bool is_forall, + bool is_forall, unsigned weight, Z3_symbol quantifier_id, Z3_symbol skolem_id, @@ -201,7 +201,7 @@ extern "C" { Z3_ast Z3_API Z3_mk_quantifier_const_ex(Z3_context c, - Z3_bool is_forall, + bool is_forall, unsigned weight, Z3_symbol quantifier_id, Z3_symbol skolem_id, @@ -283,7 +283,7 @@ extern "C" { } Z3_ast Z3_API Z3_mk_quantifier_const(Z3_context c, - Z3_bool is_forall, + bool is_forall, unsigned weight, unsigned num_bound, Z3_app const bound[], @@ -343,7 +343,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_is_quantifier_forall(Z3_context c, Z3_ast a) { + bool Z3_API Z3_is_quantifier_forall(Z3_context c, Z3_ast a) { Z3_TRY; LOG_Z3_is_quantifier_forall(c, a); RESET_ERROR_CODE(); @@ -351,7 +351,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_is_quantifier_exists(Z3_context c, Z3_ast a) { + bool Z3_API Z3_is_quantifier_exists(Z3_context c, Z3_ast a) { Z3_TRY; LOG_Z3_is_quantifier_exists(c, a); RESET_ERROR_CODE(); @@ -359,7 +359,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_is_lambda(Z3_context c, Z3_ast a) { + bool Z3_API Z3_is_lambda(Z3_context c, Z3_ast a) { Z3_TRY; LOG_Z3_is_lambda(c, a); RESET_ERROR_CODE(); diff --git a/src/api/api_rcf.cpp b/src/api/api_rcf.cpp index 0bcabf0c4..bcaf0869f 100644 --- a/src/api/api_rcf.cpp +++ b/src/api/api_rcf.cpp @@ -214,7 +214,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_rcf_lt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { + bool Z3_API Z3_rcf_lt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { Z3_TRY; LOG_Z3_rcf_lt(c, a, b); RESET_ERROR_CODE(); @@ -223,7 +223,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_rcf_gt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { + bool Z3_API Z3_rcf_gt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { Z3_TRY; LOG_Z3_rcf_gt(c, a, b); RESET_ERROR_CODE(); @@ -232,7 +232,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_rcf_le(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { + bool Z3_API Z3_rcf_le(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { Z3_TRY; LOG_Z3_rcf_le(c, a, b); RESET_ERROR_CODE(); @@ -241,7 +241,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_rcf_ge(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { + bool Z3_API Z3_rcf_ge(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { Z3_TRY; LOG_Z3_rcf_ge(c, a, b); RESET_ERROR_CODE(); @@ -250,7 +250,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_rcf_eq(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { + bool Z3_API Z3_rcf_eq(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { Z3_TRY; LOG_Z3_rcf_eq(c, a, b); RESET_ERROR_CODE(); @@ -259,7 +259,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_rcf_neq(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { + bool Z3_API Z3_rcf_neq(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { Z3_TRY; LOG_Z3_rcf_neq(c, a, b); RESET_ERROR_CODE(); @@ -268,7 +268,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_string Z3_API Z3_rcf_num_to_string(Z3_context c, Z3_rcf_num a, Z3_bool compact, Z3_bool html) { + Z3_string Z3_API Z3_rcf_num_to_string(Z3_context c, Z3_rcf_num a, bool compact, bool html) { Z3_TRY; LOG_Z3_rcf_num_to_string(c, a, compact, html); RESET_ERROR_CODE(); diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 7a9ca80a7..6b48360a3 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -65,7 +65,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_is_seq_sort(Z3_context c, Z3_sort s) { + bool Z3_API Z3_is_seq_sort(Z3_context c, Z3_sort s) { Z3_TRY; LOG_Z3_is_seq_sort(c, s); RESET_ERROR_CODE(); @@ -73,7 +73,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_is_re_sort(Z3_context c, Z3_sort s) { + bool Z3_API Z3_is_re_sort(Z3_context c, Z3_sort s) { Z3_TRY; LOG_Z3_is_re_sort(c, s); RESET_ERROR_CODE(); @@ -81,7 +81,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_is_string_sort(Z3_context c, Z3_sort s) { + bool Z3_API Z3_is_string_sort(Z3_context c, Z3_sort s) { Z3_TRY; LOG_Z3_is_string_sort(c, s); RESET_ERROR_CODE(); @@ -89,7 +89,7 @@ extern "C" { Z3_CATCH_RETURN(false); } - Z3_bool Z3_API Z3_is_string(Z3_context c, Z3_ast s) { + bool Z3_API Z3_is_string(Z3_context c, Z3_ast s) { Z3_TRY; LOG_Z3_is_string(c, s); RESET_ERROR_CODE(); diff --git a/src/api/api_stats.cpp b/src/api/api_stats.cpp index 6ab18c214..3ff87039f 100644 --- a/src/api/api_stats.cpp +++ b/src/api/api_stats.cpp @@ -74,7 +74,7 @@ extern "C" { Z3_CATCH_RETURN(""); } - Z3_bool Z3_API Z3_stats_is_uint(Z3_context c, Z3_stats s, unsigned idx) { + bool Z3_API Z3_stats_is_uint(Z3_context c, Z3_stats s, unsigned idx) { Z3_TRY; LOG_Z3_stats_is_uint(c, s, idx); RESET_ERROR_CODE(); @@ -86,7 +86,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_bool Z3_API Z3_stats_is_double(Z3_context c, Z3_stats s, unsigned idx) { + bool Z3_API Z3_stats_is_double(Z3_context c, Z3_stats s, unsigned idx) { Z3_TRY; LOG_Z3_stats_is_double(c, s, idx); RESET_ERROR_CODE(); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index f2cb149cb..d5d3bc1ff 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2036,7 +2036,7 @@ namespace z3 { expr eval(expr const & n, bool model_completion=false) const { check_context(*this, n); Z3_ast r = 0; - Z3_bool status = Z3_model_eval(ctx(), m_model, n, model_completion, &r); + bool status = Z3_model_eval(ctx(), m_model, n, model_completion, &r); check_error(); if (status == false && ctx().enable_exceptions()) Z3_THROW(exception("failed to evaluate expression")); @@ -2112,8 +2112,8 @@ namespace z3 { } unsigned size() const { return Z3_stats_size(ctx(), m_stats); } std::string key(unsigned i) const { Z3_string s = Z3_stats_get_key(ctx(), m_stats, i); check_error(); return s; } - bool is_uint(unsigned i) const { Z3_bool r = Z3_stats_is_uint(ctx(), m_stats, i); check_error(); return r != 0; } - bool is_double(unsigned i) const { Z3_bool r = Z3_stats_is_double(ctx(), m_stats, i); check_error(); return r != 0; } + bool is_uint(unsigned i) const { bool r = Z3_stats_is_uint(ctx(), m_stats, i); check_error(); return r != 0; } + bool is_double(unsigned i) const { bool r = Z3_stats_is_double(ctx(), m_stats, i); check_error(); return r != 0; } unsigned uint_value(unsigned i) const { unsigned r = Z3_stats_get_uint_value(ctx(), m_stats, i); check_error(); return r; } double double_value(unsigned i) const { double r = Z3_stats_get_double_value(ctx(), m_stats, i); check_error(); return r; } friend std::ostream & operator<<(std::ostream & out, stats const & s); @@ -2934,7 +2934,7 @@ namespace z3 { inline expr context::bv_val(uint64_t n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, s); check_error(); return expr(*this, r); } inline expr context::bv_val(char const * n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_numeral(m_ctx, n, s); check_error(); return expr(*this, r); } inline expr context::bv_val(unsigned n, bool const* bits) { - array _bits(n); + array _bits(n); for (unsigned i = 0; i < n; ++i) _bits[i] = bits[i] ? 1 : 0; Z3_ast r = Z3_mk_bv_numeral(m_ctx, n, _bits.ptr()); check_error(); return expr(*this, r); } diff --git a/src/api/z3_algebraic.h b/src/api/z3_algebraic.h index c3f5337c2..1ebc1ad8f 100644 --- a/src/api/z3_algebraic.h +++ b/src/api/z3_algebraic.h @@ -36,7 +36,7 @@ extern "C" { def_API('Z3_algebraic_is_value', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_algebraic_is_value(Z3_context c, Z3_ast a); + bool Z3_API Z3_algebraic_is_value(Z3_context c, Z3_ast a); /** \brief Return \c true if \c a is positive, and \c false otherwise. @@ -45,7 +45,7 @@ extern "C" { def_API('Z3_algebraic_is_pos', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_algebraic_is_pos(Z3_context c, Z3_ast a); + bool Z3_API Z3_algebraic_is_pos(Z3_context c, Z3_ast a); /** \brief Return \c true if \c a is negative, and \c false otherwise. @@ -54,7 +54,7 @@ extern "C" { def_API('Z3_algebraic_is_neg', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_algebraic_is_neg(Z3_context c, Z3_ast a); + bool Z3_API Z3_algebraic_is_neg(Z3_context c, Z3_ast a); /** \brief Return \c true if \c a is zero, and \c false otherwise. @@ -63,7 +63,7 @@ extern "C" { def_API('Z3_algebraic_is_zero', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_algebraic_is_zero(Z3_context c, Z3_ast a); + bool Z3_API Z3_algebraic_is_zero(Z3_context c, Z3_ast a); /** \brief Return 1 if \c a is positive, 0 if \c a is zero, and -1 if \c a is negative. @@ -148,7 +148,7 @@ extern "C" { def_API('Z3_algebraic_lt', BOOL, (_in(CONTEXT), _in(AST), _in(AST))) */ - Z3_bool Z3_API Z3_algebraic_lt(Z3_context c, Z3_ast a, Z3_ast b); + bool Z3_API Z3_algebraic_lt(Z3_context c, Z3_ast a, Z3_ast b); /** \brief Return \c true if a > b, and \c false otherwise. @@ -158,7 +158,7 @@ extern "C" { def_API('Z3_algebraic_gt', BOOL, (_in(CONTEXT), _in(AST), _in(AST))) */ - Z3_bool Z3_API Z3_algebraic_gt(Z3_context c, Z3_ast a, Z3_ast b); + bool Z3_API Z3_algebraic_gt(Z3_context c, Z3_ast a, Z3_ast b); /** \brief Return \c true if a <= b, and \c false otherwise. @@ -168,7 +168,7 @@ extern "C" { def_API('Z3_algebraic_le', BOOL, (_in(CONTEXT), _in(AST), _in(AST))) */ - Z3_bool Z3_API Z3_algebraic_le(Z3_context c, Z3_ast a, Z3_ast b); + bool Z3_API Z3_algebraic_le(Z3_context c, Z3_ast a, Z3_ast b); /** \brief Return \c true if a >= b, and \c false otherwise. @@ -178,7 +178,7 @@ extern "C" { def_API('Z3_algebraic_ge', BOOL, (_in(CONTEXT), _in(AST), _in(AST))) */ - Z3_bool Z3_API Z3_algebraic_ge(Z3_context c, Z3_ast a, Z3_ast b); + bool Z3_API Z3_algebraic_ge(Z3_context c, Z3_ast a, Z3_ast b); /** \brief Return \c true if a == b, and \c false otherwise. @@ -188,7 +188,7 @@ extern "C" { def_API('Z3_algebraic_eq', BOOL, (_in(CONTEXT), _in(AST), _in(AST))) */ - Z3_bool Z3_API Z3_algebraic_eq(Z3_context c, Z3_ast a, Z3_ast b); + bool Z3_API Z3_algebraic_eq(Z3_context c, Z3_ast a, Z3_ast b); /** \brief Return \c true if a != b, and \c false otherwise. @@ -198,7 +198,7 @@ extern "C" { def_API('Z3_algebraic_neq', BOOL, (_in(CONTEXT), _in(AST), _in(AST))) */ - Z3_bool Z3_API Z3_algebraic_neq(Z3_context c, Z3_ast a, Z3_ast b); + bool Z3_API Z3_algebraic_neq(Z3_context c, Z3_ast a, Z3_ast b); /** \brief Given a multivariate polynomial p(x_0, ..., x_{n-1}, x_n), returns the diff --git a/src/api/z3_api.h b/src/api/z3_api.h index a94030d22..a85413491 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1641,7 +1641,7 @@ extern "C" { def_API('Z3_params_set_bool', VOID, (_in(CONTEXT), _in(PARAMS), _in(SYMBOL), _in(BOOL))) */ - void Z3_API Z3_params_set_bool(Z3_context c, Z3_params p, Z3_symbol k, Z3_bool v); + void Z3_API Z3_params_set_bool(Z3_context c, Z3_params p, Z3_symbol k, bool v); /** \brief Add a unsigned parameter \c k with value \c v to the parameter set \c p. @@ -2895,7 +2895,7 @@ extern "C" { def_API('Z3_mk_bv2int', AST, (_in(CONTEXT), _in(AST), _in(BOOL))) */ - Z3_ast Z3_API Z3_mk_bv2int(Z3_context c,Z3_ast t1, Z3_bool is_signed); + Z3_ast Z3_API Z3_mk_bv2int(Z3_context c,Z3_ast t1, bool is_signed); /** \brief Create a predicate that checks that the bit-wise addition @@ -2905,7 +2905,7 @@ extern "C" { def_API('Z3_mk_bvadd_no_overflow', AST, (_in(CONTEXT), _in(AST), _in(AST), _in(BOOL))) */ - Z3_ast Z3_API Z3_mk_bvadd_no_overflow(Z3_context c, Z3_ast t1, Z3_ast t2, Z3_bool is_signed); + Z3_ast Z3_API Z3_mk_bvadd_no_overflow(Z3_context c, Z3_ast t1, Z3_ast t2, bool is_signed); /** \brief Create a predicate that checks that the bit-wise signed addition @@ -2935,7 +2935,7 @@ extern "C" { def_API('Z3_mk_bvsub_no_underflow', AST, (_in(CONTEXT), _in(AST), _in(AST), _in(BOOL))) */ - Z3_ast Z3_API Z3_mk_bvsub_no_underflow(Z3_context c, Z3_ast t1, Z3_ast t2, Z3_bool is_signed); + Z3_ast Z3_API Z3_mk_bvsub_no_underflow(Z3_context c, Z3_ast t1, Z3_ast t2, bool is_signed); /** \brief Create a predicate that checks that the bit-wise signed division @@ -2965,7 +2965,7 @@ extern "C" { def_API('Z3_mk_bvmul_no_overflow', AST, (_in(CONTEXT), _in(AST), _in(AST), _in(BOOL))) */ - Z3_ast Z3_API Z3_mk_bvmul_no_overflow(Z3_context c, Z3_ast t1, Z3_ast t2, Z3_bool is_signed); + Z3_ast Z3_API Z3_mk_bvmul_no_overflow(Z3_context c, Z3_ast t1, Z3_ast t2, bool is_signed); /** \brief Create a predicate that checks that the bit-wise signed multiplication @@ -3269,7 +3269,7 @@ extern "C" { \sa Z3_mk_numeral def_API('Z3_mk_bv_numeral', AST, (_in(CONTEXT), _in(UINT), _in_array(1, BOOL))) */ - Z3_ast Z3_API Z3_mk_bv_numeral(Z3_context c, unsigned sz, Z3_bool const* bits); + Z3_ast Z3_API Z3_mk_bv_numeral(Z3_context c, unsigned sz, bool const* bits); /*@}*/ @@ -3288,7 +3288,7 @@ extern "C" { def_API('Z3_is_seq_sort', BOOL, (_in(CONTEXT), _in(SORT))) */ - Z3_bool Z3_API Z3_is_seq_sort(Z3_context c, Z3_sort s); + bool Z3_API Z3_is_seq_sort(Z3_context c, Z3_sort s); /** \brief Create a regular expression sort out of a sequence sort. @@ -3302,7 +3302,7 @@ extern "C" { def_API('Z3_is_re_sort', BOOL, (_in(CONTEXT), _in(SORT))) */ - Z3_bool Z3_API Z3_is_re_sort(Z3_context c, Z3_sort s); + bool Z3_API Z3_is_re_sort(Z3_context c, Z3_sort s); /** \brief Create a sort for 8 bit strings. @@ -3319,7 +3319,7 @@ extern "C" { def_API('Z3_is_string_sort', BOOL, (_in(CONTEXT), _in(SORT))) */ - Z3_bool Z3_API Z3_is_string_sort(Z3_context c, Z3_sort s); + bool Z3_API Z3_is_string_sort(Z3_context c, Z3_sort s); /** \brief Create a string constant out of the string that is passed in @@ -3332,7 +3332,7 @@ extern "C" { def_API('Z3_is_string', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_is_string(Z3_context c, Z3_ast s); + bool Z3_API Z3_is_string(Z3_context c, Z3_ast s); /** \brief Retrieve the string constant stored in \c s. @@ -3681,7 +3681,7 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_quantifier( Z3_context c, - Z3_bool is_forall, + bool is_forall, unsigned weight, unsigned num_patterns, Z3_pattern const patterns[], unsigned num_decls, Z3_sort const sorts[], @@ -3715,7 +3715,7 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_quantifier_ex( Z3_context c, - Z3_bool is_forall, + bool is_forall, unsigned weight, Z3_symbol quantifier_id, Z3_symbol skolem_id, @@ -3791,7 +3791,7 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_quantifier_const( Z3_context c, - Z3_bool is_forall, + bool is_forall, unsigned weight, unsigned num_bound, Z3_app const bound[], unsigned num_patterns, Z3_pattern const patterns[], @@ -3806,7 +3806,7 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_quantifier_const_ex( Z3_context c, - Z3_bool is_forall, + bool is_forall, unsigned weight, Z3_symbol quantifier_id, Z3_symbol skolem_id, @@ -3929,7 +3929,7 @@ extern "C" { def_API('Z3_is_eq_sort', BOOL, (_in(CONTEXT), _in(SORT), _in(SORT))) */ - Z3_bool Z3_API Z3_is_eq_sort(Z3_context c, Z3_sort s1, Z3_sort s2); + bool Z3_API Z3_is_eq_sort(Z3_context c, Z3_sort s1, Z3_sort s2); /** \brief Return the sort kind (e.g., array, tuple, int, bool, etc). @@ -4196,7 +4196,7 @@ extern "C" { def_API('Z3_is_eq_func_decl', BOOL, (_in(CONTEXT), _in(FUNC_DECL), _in(FUNC_DECL))) */ - Z3_bool Z3_API Z3_is_eq_func_decl(Z3_context c, Z3_func_decl f1, Z3_func_decl f2); + bool Z3_API Z3_is_eq_func_decl(Z3_context c, Z3_func_decl f1, Z3_func_decl f2); /** \brief Return a unique identifier for \c f. @@ -4375,7 +4375,7 @@ extern "C" { def_API('Z3_is_eq_ast', BOOL, (_in(CONTEXT), _in(AST), _in(AST))) */ - Z3_bool Z3_API Z3_is_eq_ast(Z3_context c, Z3_ast t1, Z3_ast t2); + bool Z3_API Z3_is_eq_ast(Z3_context c, Z3_ast t1, Z3_ast t2); /** \brief Return a unique identifier for \c t. @@ -4413,7 +4413,7 @@ extern "C" { def_API('Z3_is_well_sorted', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_is_well_sorted(Z3_context c, Z3_ast t); + bool Z3_API Z3_is_well_sorted(Z3_context c, Z3_ast t); /** \brief Return Z3_L_TRUE if \c a is true, Z3_L_FALSE if it is false, and Z3_L_UNDEF otherwise. @@ -4432,19 +4432,19 @@ extern "C" { /** def_API('Z3_is_app', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_is_app(Z3_context c, Z3_ast a); + bool Z3_API Z3_is_app(Z3_context c, Z3_ast a); /** def_API('Z3_is_numeral_ast', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_is_numeral_ast(Z3_context c, Z3_ast a); + bool Z3_API Z3_is_numeral_ast(Z3_context c, Z3_ast a); /** \brief Return true if the given AST is a real algebraic number. def_API('Z3_is_algebraic_number', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_is_algebraic_number(Z3_context c, Z3_ast a); + bool Z3_API Z3_is_algebraic_number(Z3_context c, Z3_ast a); /** \brief Convert an \c ast into an \c APP_AST. This is just type casting. @@ -4524,7 +4524,7 @@ extern "C" { def_API('Z3_get_numeral_small', BOOL, (_in(CONTEXT), _in(AST), _out(INT64), _out(INT64))) */ - Z3_bool Z3_API Z3_get_numeral_small(Z3_context c, Z3_ast a, int64_t* num, int64_t* den); + bool Z3_API Z3_get_numeral_small(Z3_context c, Z3_ast a, int64_t* num, int64_t* den); /** \brief Similar to #Z3_get_numeral_string, but only succeeds if @@ -4536,7 +4536,7 @@ extern "C" { def_API('Z3_get_numeral_int', BOOL, (_in(CONTEXT), _in(AST), _out(INT))) */ - Z3_bool Z3_API Z3_get_numeral_int(Z3_context c, Z3_ast v, int* i); + bool Z3_API Z3_get_numeral_int(Z3_context c, Z3_ast v, int* i); /** \brief Similar to #Z3_get_numeral_string, but only succeeds if @@ -4548,7 +4548,7 @@ extern "C" { def_API('Z3_get_numeral_uint', BOOL, (_in(CONTEXT), _in(AST), _out(UINT))) */ - Z3_bool Z3_API Z3_get_numeral_uint(Z3_context c, Z3_ast v, unsigned* u); + bool Z3_API Z3_get_numeral_uint(Z3_context c, Z3_ast v, unsigned* u); /** \brief Similar to #Z3_get_numeral_string, but only succeeds if @@ -4560,7 +4560,7 @@ extern "C" { def_API('Z3_get_numeral_uint64', BOOL, (_in(CONTEXT), _in(AST), _out(UINT64))) */ - Z3_bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, uint64_t* u); + bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, uint64_t* u); /** \brief Similar to #Z3_get_numeral_string, but only succeeds if @@ -4572,7 +4572,7 @@ extern "C" { def_API('Z3_get_numeral_int64', BOOL, (_in(CONTEXT), _in(AST), _out(INT64))) */ - Z3_bool Z3_API Z3_get_numeral_int64(Z3_context c, Z3_ast v, int64_t* i); + bool Z3_API Z3_get_numeral_int64(Z3_context c, Z3_ast v, int64_t* i); /** \brief Similar to #Z3_get_numeral_string, but only succeeds if @@ -4584,7 +4584,7 @@ extern "C" { def_API('Z3_get_numeral_rational_int64', BOOL, (_in(CONTEXT), _in(AST), _out(INT64), _out(INT64))) */ - Z3_bool Z3_API Z3_get_numeral_rational_int64(Z3_context c, Z3_ast v, int64_t* num, int64_t* den); + bool Z3_API Z3_get_numeral_rational_int64(Z3_context c, Z3_ast v, int64_t* num, int64_t* den); /** \brief Return a lower bound for the given real algebraic number. @@ -4643,7 +4643,7 @@ extern "C" { def_API('Z3_is_quantifier_forall', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_is_quantifier_forall(Z3_context c, Z3_ast a); + bool Z3_API Z3_is_quantifier_forall(Z3_context c, Z3_ast a); /** \brief Determine if ast is an existential quantifier. @@ -4651,7 +4651,7 @@ extern "C" { def_API('Z3_is_quantifier_exists', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_is_quantifier_exists(Z3_context c, Z3_ast a); + bool Z3_API Z3_is_quantifier_exists(Z3_context c, Z3_ast a); /** \brief Determine if ast is a lambda expression. @@ -4660,7 +4660,7 @@ extern "C" { def_API('Z3_is_lambda', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_is_lambda(Z3_context c, Z3_ast a); + bool Z3_API Z3_is_lambda(Z3_context c, Z3_ast a); /** \brief Obtain weight of quantifier. @@ -4874,7 +4874,7 @@ extern "C" { def_API('Z3_model_eval', BOOL, (_in(CONTEXT), _in(MODEL), _in(AST), _in(BOOL), _out(AST))) */ - Z3_bool_opt Z3_API Z3_model_eval(Z3_context c, Z3_model m, Z3_ast t, Z3_bool model_completion, Z3_ast * v); + Z3_bool_opt Z3_API Z3_model_eval(Z3_context c, Z3_model m, Z3_ast t, bool model_completion, Z3_ast * v); /** \brief Return the interpretation (i.e., assignment) of constant \c a in the model \c m. @@ -4892,7 +4892,7 @@ extern "C" { def_API('Z3_model_has_interp', BOOL, (_in(CONTEXT), _in(MODEL), _in(FUNC_DECL))) */ - Z3_bool Z3_API Z3_model_has_interp(Z3_context c, Z3_model m, Z3_func_decl a); + bool Z3_API Z3_model_has_interp(Z3_context c, Z3_model m, Z3_func_decl a); /** \brief Return the interpretation of the function \c f in the model \c m. @@ -5003,7 +5003,7 @@ extern "C" { def_API('Z3_is_as_array', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_is_as_array(Z3_context c, Z3_ast a); + bool Z3_API Z3_is_as_array(Z3_context c, Z3_ast a); /** \brief Return the function declaration \c f associated with a \ccode{(_ as_array f)} node. @@ -5168,7 +5168,7 @@ extern "C" { extra_API('Z3_open_log', INT, (_in(STRING),)) */ - Z3_bool Z3_API Z3_open_log(Z3_string filename); + bool Z3_API Z3_open_log(Z3_string filename); /** \brief Append user-defined string to interaction log. @@ -5196,7 +5196,7 @@ extern "C" { def_API('Z3_toggle_warning_messages', VOID, (_in(BOOL),)) */ - void Z3_API Z3_toggle_warning_messages(Z3_bool enabled); + void Z3_API Z3_toggle_warning_messages(bool enabled); /*@}*/ /** @name String conversion */ @@ -5457,7 +5457,7 @@ extern "C" { def_API('Z3_mk_goal', GOAL, (_in(CONTEXT), _in(BOOL), _in(BOOL), _in(BOOL))) */ - Z3_goal Z3_API Z3_mk_goal(Z3_context c, Z3_bool models, Z3_bool unsat_cores, Z3_bool proofs); + Z3_goal Z3_API Z3_mk_goal(Z3_context c, bool models, bool unsat_cores, bool proofs); /** \brief Increment the reference counter of the given goal. @@ -5501,7 +5501,7 @@ extern "C" { def_API('Z3_goal_inconsistent', BOOL, (_in(CONTEXT), _in(GOAL))) */ - Z3_bool Z3_API Z3_goal_inconsistent(Z3_context c, Z3_goal g); + bool Z3_API Z3_goal_inconsistent(Z3_context c, Z3_goal g); /** \brief Return the depth of the given goal. It tracks how many transformations were applied to it. @@ -5545,14 +5545,14 @@ extern "C" { def_API('Z3_goal_is_decided_sat', BOOL, (_in(CONTEXT), _in(GOAL))) */ - Z3_bool Z3_API Z3_goal_is_decided_sat(Z3_context c, Z3_goal g); + bool Z3_API Z3_goal_is_decided_sat(Z3_context c, Z3_goal g); /** \brief Return true if the goal contains false, and it is precise or the product of an over approximation. def_API('Z3_goal_is_decided_unsat', BOOL, (_in(CONTEXT), _in(GOAL))) */ - Z3_bool Z3_API Z3_goal_is_decided_unsat(Z3_context c, Z3_goal g); + bool Z3_API Z3_goal_is_decided_unsat(Z3_context c, Z3_goal g); /** \brief Copy a goal \c g from the context \c source to the context \c target. @@ -6376,7 +6376,7 @@ extern "C" { def_API('Z3_stats_is_uint', BOOL, (_in(CONTEXT), _in(STATS), _in(UINT))) */ - Z3_bool Z3_API Z3_stats_is_uint(Z3_context c, Z3_stats s, unsigned idx); + bool Z3_API Z3_stats_is_uint(Z3_context c, Z3_stats s, unsigned idx); /** \brief Return \c true if the given statistical data is a double. @@ -6385,7 +6385,7 @@ extern "C" { def_API('Z3_stats_is_double', BOOL, (_in(CONTEXT), _in(STATS), _in(UINT))) */ - Z3_bool Z3_API Z3_stats_is_double(Z3_context c, Z3_stats s, unsigned idx); + bool Z3_API Z3_stats_is_double(Z3_context c, Z3_stats s, unsigned idx); /** \brief Return the unsigned value of the given statistical data. diff --git a/src/api/z3_ast_containers.h b/src/api/z3_ast_containers.h index c423a3286..c8438a2ad 100644 --- a/src/api/z3_ast_containers.h +++ b/src/api/z3_ast_containers.h @@ -138,7 +138,7 @@ extern "C" { def_API('Z3_ast_map_contains', BOOL, (_in(CONTEXT), _in(AST_MAP), _in(AST))) */ - Z3_bool Z3_API Z3_ast_map_contains(Z3_context c, Z3_ast_map m, Z3_ast k); + bool Z3_API Z3_ast_map_contains(Z3_context c, Z3_ast_map m, Z3_ast k); /** \brief Return the value associated with the key \c k. diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 544d9372b..cc2091caa 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -233,7 +233,7 @@ extern "C" { def_API('Z3_mk_fpa_inf', AST, (_in(CONTEXT),_in(SORT),_in(BOOL))) */ - Z3_ast Z3_API Z3_mk_fpa_inf(Z3_context c, Z3_sort s, Z3_bool negative); + Z3_ast Z3_API Z3_mk_fpa_inf(Z3_context c, Z3_sort s, bool negative); /** \brief Create a floating-point zero of sort s. @@ -246,7 +246,7 @@ extern "C" { def_API('Z3_mk_fpa_zero', AST, (_in(CONTEXT),_in(SORT),_in(BOOL))) */ - Z3_ast Z3_API Z3_mk_fpa_zero(Z3_context c, Z3_sort s, Z3_bool negative); + Z3_ast Z3_API Z3_mk_fpa_zero(Z3_context c, Z3_sort s, bool negative); /** \brief Create an expression of FloatingPoint sort from three bit-vector expressions. @@ -332,7 +332,7 @@ extern "C" { def_API('Z3_mk_fpa_numeral_int_uint', AST, (_in(CONTEXT), _in(BOOL), _in(INT), _in(UINT), _in(SORT))) */ - Z3_ast Z3_API Z3_mk_fpa_numeral_int_uint(Z3_context c, Z3_bool sgn, signed exp, unsigned sig, Z3_sort ty); + Z3_ast Z3_API Z3_mk_fpa_numeral_int_uint(Z3_context c, bool sgn, signed exp, unsigned sig, Z3_sort ty); /** \brief Create a numeral of FloatingPoint sort from a sign bit and two 64-bit integers. @@ -349,7 +349,7 @@ extern "C" { def_API('Z3_mk_fpa_numeral_int64_uint64', AST, (_in(CONTEXT), _in(BOOL), _in(INT64), _in(UINT64), _in(SORT))) */ - Z3_ast Z3_API Z3_mk_fpa_numeral_int64_uint64(Z3_context c, Z3_bool sgn, int64_t exp, uint64_t sig, Z3_sort ty); + Z3_ast Z3_API Z3_mk_fpa_numeral_int64_uint64(Z3_context c, bool sgn, int64_t exp, uint64_t sig, Z3_sort ty); /** \brief Floating-point absolute value @@ -830,7 +830,7 @@ extern "C" { def_API('Z3_fpa_is_numeral_nan', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_fpa_is_numeral_nan(Z3_context c, Z3_ast t); + bool Z3_API Z3_fpa_is_numeral_nan(Z3_context c, Z3_ast t); /** \brief Checks whether a given floating-point numeral is a +oo or -oo. @@ -840,7 +840,7 @@ extern "C" { def_API('Z3_fpa_is_numeral_inf', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_fpa_is_numeral_inf(Z3_context c, Z3_ast t); + bool Z3_API Z3_fpa_is_numeral_inf(Z3_context c, Z3_ast t); /** \brief Checks whether a given floating-point numeral is +zero or -zero. @@ -850,7 +850,7 @@ extern "C" { def_API('Z3_fpa_is_numeral_zero', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_fpa_is_numeral_zero(Z3_context c, Z3_ast t); + bool Z3_API Z3_fpa_is_numeral_zero(Z3_context c, Z3_ast t); /** \brief Checks whether a given floating-point numeral is normal. @@ -860,7 +860,7 @@ extern "C" { def_API('Z3_fpa_is_numeral_normal', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_fpa_is_numeral_normal(Z3_context c, Z3_ast t); + bool Z3_API Z3_fpa_is_numeral_normal(Z3_context c, Z3_ast t); /** \brief Checks whether a given floating-point numeral is subnormal. @@ -870,7 +870,7 @@ extern "C" { def_API('Z3_fpa_is_numeral_subnormal', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_fpa_is_numeral_subnormal(Z3_context c, Z3_ast t); + bool Z3_API Z3_fpa_is_numeral_subnormal(Z3_context c, Z3_ast t); /** \brief Checks whether a given floating-point numeral is positive. @@ -880,7 +880,7 @@ extern "C" { def_API('Z3_fpa_is_numeral_positive', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_fpa_is_numeral_positive(Z3_context c, Z3_ast t); + bool Z3_API Z3_fpa_is_numeral_positive(Z3_context c, Z3_ast t); /** \brief Checks whether a given floating-point numeral is negative. @@ -890,7 +890,7 @@ extern "C" { def_API('Z3_fpa_is_numeral_negative', BOOL, (_in(CONTEXT), _in(AST))) */ - Z3_bool Z3_API Z3_fpa_is_numeral_negative(Z3_context c, Z3_ast t); + bool Z3_API Z3_fpa_is_numeral_negative(Z3_context c, Z3_ast t); /** \brief Retrieves the sign of a floating-point literal as a bit-vector expression. @@ -928,7 +928,7 @@ extern "C" { def_API('Z3_fpa_get_numeral_sign', BOOL, (_in(CONTEXT), _in(AST), _out(INT))) */ - Z3_bool Z3_API Z3_fpa_get_numeral_sign(Z3_context c, Z3_ast t, int * sgn); + bool Z3_API Z3_fpa_get_numeral_sign(Z3_context c, Z3_ast t, int * sgn); /** \brief Return the significand value of a floating-point numeral as a string. @@ -956,7 +956,7 @@ extern "C" { def_API('Z3_fpa_get_numeral_significand_uint64', BOOL, (_in(CONTEXT), _in(AST), _out(UINT64))) */ - Z3_bool Z3_API Z3_fpa_get_numeral_significand_uint64(Z3_context c, Z3_ast t, uint64_t * n); + bool Z3_API Z3_fpa_get_numeral_significand_uint64(Z3_context c, Z3_ast t, uint64_t * n); /** \brief Return the exponent value of a floating-point numeral as a string. @@ -970,7 +970,7 @@ extern "C" { def_API('Z3_fpa_get_numeral_exponent_string', STRING, (_in(CONTEXT), _in(AST), _in(BOOL))) */ - Z3_string Z3_API Z3_fpa_get_numeral_exponent_string(Z3_context c, Z3_ast t, Z3_bool biased); + Z3_string Z3_API Z3_fpa_get_numeral_exponent_string(Z3_context c, Z3_ast t, bool biased); /** \brief Return the exponent value of a floating-point numeral as a signed 64-bit integer @@ -985,7 +985,7 @@ extern "C" { def_API('Z3_fpa_get_numeral_exponent_int64', BOOL, (_in(CONTEXT), _in(AST), _out(INT64), _in(BOOL))) */ - Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(Z3_context c, Z3_ast t, int64_t * n, Z3_bool biased); + bool Z3_API Z3_fpa_get_numeral_exponent_int64(Z3_context c, Z3_ast t, int64_t * n, bool biased); /** \brief Retrieves the exponent of a floating-point literal as a bit-vector expression. @@ -999,7 +999,7 @@ extern "C" { def_API('Z3_fpa_get_numeral_exponent_bv', AST, (_in(CONTEXT), _in(AST), _in(BOOL))) */ - Z3_ast Z3_API Z3_fpa_get_numeral_exponent_bv(Z3_context c, Z3_ast t, Z3_bool biased); + Z3_ast Z3_API Z3_fpa_get_numeral_exponent_bv(Z3_context c, Z3_ast t, bool biased); /** \brief Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format. diff --git a/src/api/z3_private.h b/src/api/z3_private.h index 7b60a6ab9..4d5e2d3bd 100644 --- a/src/api/z3_private.h +++ b/src/api/z3_private.h @@ -29,7 +29,7 @@ Notes: extern "C" { #endif // __cplusplus - Z3_bool Z3_API Z3_get_numeral_rational(Z3_context c, Z3_ast a, rational& r); + bool Z3_API Z3_get_numeral_rational(Z3_context c, Z3_ast a, rational& r); #ifdef __cplusplus }; diff --git a/src/api/z3_rcf.h b/src/api/z3_rcf.h index cc8e5a525..dc025bddd 100644 --- a/src/api/z3_rcf.h +++ b/src/api/z3_rcf.h @@ -138,49 +138,49 @@ extern "C" { def_API('Z3_rcf_lt', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM))) */ - Z3_bool Z3_API Z3_rcf_lt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); + bool Z3_API Z3_rcf_lt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); /** \brief Return \c true if a > b def_API('Z3_rcf_gt', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM))) */ - Z3_bool Z3_API Z3_rcf_gt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); + bool Z3_API Z3_rcf_gt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); /** \brief Return \c true if a <= b def_API('Z3_rcf_le', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM))) */ - Z3_bool Z3_API Z3_rcf_le(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); + bool Z3_API Z3_rcf_le(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); /** \brief Return \c true if a >= b def_API('Z3_rcf_ge', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM))) */ - Z3_bool Z3_API Z3_rcf_ge(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); + bool Z3_API Z3_rcf_ge(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); /** \brief Return \c true if a == b def_API('Z3_rcf_eq', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM))) */ - Z3_bool Z3_API Z3_rcf_eq(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); + bool Z3_API Z3_rcf_eq(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); /** \brief Return \c true if a != b def_API('Z3_rcf_neq', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM))) */ - Z3_bool Z3_API Z3_rcf_neq(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); + bool Z3_API Z3_rcf_neq(Z3_context c, Z3_rcf_num a, Z3_rcf_num b); /** \brief Convert the RCF numeral into a string. def_API('Z3_rcf_num_to_string', STRING, (_in(CONTEXT), _in(RCF_NUM), _in(BOOL), _in(BOOL))) */ - Z3_string Z3_API Z3_rcf_num_to_string(Z3_context c, Z3_rcf_num a, Z3_bool compact, Z3_bool html); + Z3_string Z3_API Z3_rcf_num_to_string(Z3_context c, Z3_rcf_num a, bool compact, bool html); /** \brief Convert the RCF numeral into a string in decimal notation. diff --git a/src/test/no_overflow.cpp b/src/test/no_overflow.cpp index 9ad629383..eb26866a5 100644 --- a/src/test/no_overflow.cpp +++ b/src/test/no_overflow.cpp @@ -530,7 +530,7 @@ void test_div(unsigned bvsize) { Z3_del_context(ctx); } -typedef Z3_ast (Z3_API *NO_OVFL_ARITH_FUNC)(Z3_context ctx, Z3_ast t1, Z3_ast t2, Z3_bool is_signed); +typedef Z3_ast (Z3_API *NO_OVFL_ARITH_FUNC)(Z3_context ctx, Z3_ast t1, Z3_ast t2, bool is_signed); typedef Z3_ast (Z3_API *ARITH_FUNC)(Z3_context ctx, Z3_ast t1, Z3_ast t2); typedef enum { OVFL_FUNC, UDFL_FUNC } overflow_type; @@ -546,11 +546,11 @@ typedef struct { bool sign_compar; // whether signed comparison should be used even for unsigned operation } Equivalence_params; -Z3_ast Z3_API Z3_mk_bvsdiv_no_overflow_wrapper(Z3_context ctx, Z3_ast t1, Z3_ast t2, Z3_bool is_signed) { +Z3_ast Z3_API Z3_mk_bvsdiv_no_overflow_wrapper(Z3_context ctx, Z3_ast t1, Z3_ast t2, bool is_signed) { return Z3_mk_bvsdiv_no_overflow(ctx, t1, t2); } -Z3_ast Z3_API Z3_mk_bvneg_no_overflow_wrapper(Z3_context ctx, Z3_ast t1, Z3_ast t2, Z3_bool is_signed) { +Z3_ast Z3_API Z3_mk_bvneg_no_overflow_wrapper(Z3_context ctx, Z3_ast t1, Z3_ast t2, bool is_signed) { return Z3_mk_bvneg_no_overflow(ctx, t1); } @@ -558,15 +558,15 @@ Z3_ast Z3_API Z3_mk_bvneg_wrapper(Z3_context ctx, Z3_ast t1, Z3_ast t2) { return Z3_mk_bvneg(ctx, t1); } -Z3_ast Z3_API Z3_mk_bvadd_no_underflow_wrapper(Z3_context ctx, Z3_ast t1, Z3_ast t2, Z3_bool is_signed) { +Z3_ast Z3_API Z3_mk_bvadd_no_underflow_wrapper(Z3_context ctx, Z3_ast t1, Z3_ast t2, bool is_signed) { return Z3_mk_bvadd_no_underflow(ctx, t1, t2); } -Z3_ast Z3_API Z3_mk_bvsub_no_overflow_wrapper(Z3_context ctx, Z3_ast t1, Z3_ast t2, Z3_bool is_signed) { +Z3_ast Z3_API Z3_mk_bvsub_no_overflow_wrapper(Z3_context ctx, Z3_ast t1, Z3_ast t2, bool is_signed) { return Z3_mk_bvsub_no_overflow(ctx, t1, t2); } -Z3_ast Z3_API Z3_mk_bvmul_no_underflow_wrapper(Z3_context ctx, Z3_ast t1, Z3_ast t2, Z3_bool is_signed) { +Z3_ast Z3_API Z3_mk_bvmul_no_underflow_wrapper(Z3_context ctx, Z3_ast t1, Z3_ast t2, bool is_signed) { return Z3_mk_bvmul_no_underflow(ctx, t1, t2); } From b93ffe676be77fe0ac2846d79b9e1a00c7837ba1 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 20 Nov 2018 11:34:32 +0700 Subject: [PATCH 198/227] Fix broken link. It is Z3_add_rec_def, not Z3_mk_rec_def. --- src/api/z3_api.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index a94030d22..e78dacbcb 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -2154,12 +2154,12 @@ extern "C" { \param domain array containing the sort of each argument. The array must contain domain_size elements. \param range sort of the constant or the return sort of the function. - After declaring recursive function, it should be associated with a recursive definition #Z3_mk_rec_def. + After declaring recursive function, it should be associated with a recursive definition #Z3_add_rec_def. The function #Z3_mk_app can be used to create a constant or function application. \sa Z3_mk_app - \sa Z3_mk_rec_def + \sa Z3_add_rec_def def_API('Z3_mk_rec_func_decl', FUNC_DECL, (_in(CONTEXT), _in(SYMBOL), _in(UINT), _in_array(2, SORT), _in(SORT))) */ From 67ea2a2c88ae804b4a276cddf65d123f401c833b Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 20 Nov 2018 09:52:43 -0800 Subject: [PATCH 199/227] test Signed-off-by: Lev Nachmanson --- src/util/lp/gomory.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/util/lp/gomory.h b/src/util/lp/gomory.h index b7946d6b0..acb5f04fd 100644 --- a/src/util/lp/gomory.h +++ b/src/util/lp/gomory.h @@ -14,8 +14,6 @@ Author: Lev Nachmanson (levnach) Revision History: - - --*/ #pragma once #include "util/lp/lar_term.h" From 5a94cece2ea566f1152702492a2822f04b90526e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Nov 2018 10:29:00 -0800 Subject: [PATCH 200/227] add macz3 status Signed-off-by: Nikolaj Bjorner --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fef293fac..cd3615608 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z | Windows x64 | Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | macOS | TravisCI | | ----------- | ----------- | ----------- | ---------- | ---------- | ----- | -------- | -[![win64-badge](https://z3build.visualstudio.com/_apis/public/build/definitions/2e0aa542-a22c-4b1a-8dcd-3ebae8e12db4/4/badge)](https://z3build.visualstudio.com/Z3Build/_build/index?definitionId=4) | [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) +[![win64-badge](https://z3build.visualstudio.com/_apis/public/build/definitions/2e0aa542-a22c-4b1a-8dcd-3ebae8e12db4/4/badge)](https://z3build.visualstudio.com/Z3Build/_build/index?definitionId=4) | [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build status](https://cz3.visualstudio.com/Z3/_apis/build/status/OSX)](https://cz3.visualstudio.com/Z3/_build/latest?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang From 9615974e768b9034dcae0f771ee46981e5b417b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Nov 2018 10:30:00 -0800 Subject: [PATCH 201/227] add macz3 status Signed-off-by: Nikolaj Bjorner --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cd3615608..808b24034 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z | Windows x64 | Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | macOS | TravisCI | | ----------- | ----------- | ----------- | ---------- | ---------- | ----- | -------- | -[![win64-badge](https://z3build.visualstudio.com/_apis/public/build/definitions/2e0aa542-a22c-4b1a-8dcd-3ebae8e12db4/4/badge)](https://z3build.visualstudio.com/Z3Build/_build/index?definitionId=4) | [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build status](https://cz3.visualstudio.com/Z3/_apis/build/status/OSX)](https://cz3.visualstudio.com/Z3/_build/latest?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) +[![win64-badge](https://z3build.visualstudio.com/_apis/public/build/definitions/2e0aa542-a22c-4b1a-8dcd-3ebae8e12db4/4/badge)](https://z3build.visualstudio.com/Z3Build/_build/index?definitionId=4) | [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![Build status](https://cz3.visualstudio.com/Z3/_apis/build/status/OSX)](https://cz3.visualstudio.com/Z3/_build/latest?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang From 7016d94d59300b53740ea1c3b4f68a8b27ba3bef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Nov 2018 11:30:44 -0800 Subject: [PATCH 202/227] fix #1956 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_recfun.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index c3e7c997e..303bf5155 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -338,7 +338,11 @@ namespace smt { literal concl = mk_literal(pred_applied); preds.push_back(concl); - if (depth >= m_max_depth) { + if (c.is_immediate()) { + body_expansion be(pred_applied, c, e.m_args); + assert_body_axiom(be); + } + else if (depth >= m_max_depth) { assert_max_depth_limit(pred_applied); continue; } @@ -354,10 +358,6 @@ namespace smt { } ctx().mk_th_axiom(get_id(), guards); - if (c.is_immediate()) { - body_expansion be(pred_applied, c, e.m_args); - assert_body_axiom(be); - } } // the disjunction of branches is asserted // to close the available cases. @@ -386,6 +386,7 @@ namespace smt { expr_ref guard = apply_args(depth, vars, args, g); clause.push_back(~mk_literal(guard)); if (clause.back() == true_literal) { + TRACEFN("body " << pp_body_expansion(e,m) << "\n" << clause << "\n" << guard); return; } if (clause.back() == false_literal) { From 37ef3cbeb2cae5bc43f9a42bad91ba5ba3df099d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Nov 2018 14:32:01 -0800 Subject: [PATCH 203/227] add rc2 sample Signed-off-by: Nikolaj Bjorner --- examples/python/rc2.py | 84 +++++++++++++++++++++++++++++++++++++++++ src/api/python/z3/z3.py | 8 +++- 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 examples/python/rc2.py diff --git a/examples/python/rc2.py b/examples/python/rc2.py new file mode 100644 index 000000000..a68e41b46 --- /dev/null +++ b/examples/python/rc2.py @@ -0,0 +1,84 @@ +# RC2 algorithm +# basic version without optimizations +# See also https://github.com/pysathq/pysat and papers in CP 2014, JSAT 2015. + +from z3 import * + +def tt(s, f): + return is_true(s.model().eval(f)) + + +def add(Ws, f, w): + Ws[f] = w + (Ws[f] if f in Ws else 0) + +def sub(Ws, f, w): + w1 = Ws[f] + if w1 > w: + Ws[f] = w1 - w + else: + del(Ws[f]) + +class RC2: + def __init__(self, s): + self.bounds = {} + self.solver = s + self.solver.set("sat.cardinality.solver", True) + self.solver.set("sat.core.minimize", True) + self.solver.set("sat.core.minimize_partial", True) + + def at_most(self, S, k): + fml = AtMost(S + [k]) + name = Bool("%s" % fml) + self.solver.add(Implies(name, fml)) + self.bounds[name] = (S, k) + return name + + # Ws are weighted soft constraints + # Whenever there is an unsatisfiable core over ws + # increase the limit of each soft constraint from a bound + # and create a soft constraint that limits the number of + # increased bounds to be at most one. + def maxsat(self, Ws): + cost = 0 + Ws0 = Ws.copy() + while unsat == self.solver.check([f for f in Ws]): + core = list(self.solver.unsat_core()) + print (self.solver.statistics()) + print("Core", core) + if not core: + return unsat + w = min([Ws[c] for c in core]) + cost += w + for f in core: + sub(Ws, f, w) + for f in core: + if f in self.bounds: + S, k = self.bounds[f] + if k + 1 < len(S): + add(Ws, self.at_most(S, k + 1), w) + add(Ws, self.at_most([mk_not(f) for f in core], 1), w) + + return cost, { f for f in Ws0 if tt(self.solver, f) } + + def from_file(self, file): + opt = Optimize() + opt.from_file(file) + self.solver.add(opt.assertions()) + obj = opt.objectives()[0] + Ws = {} + for f in obj.children(): + assert(f.arg(1).as_long() == 0) + add(Ws, f.arg(0), f.arg(2).as_long()) + return self.maxsat(Ws) + + +def main(file): + s = SolverFor("QF_FD") + rc2 = RC2(s) + set_param(verbose=0) + cost, trues = rc2.from_file(file) + print(cost) + print(s.statistics()) + +# main() + diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 70dcb158e..ffd9c27a1 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1645,6 +1645,12 @@ def Not(a, ctx=None): a = s.cast(a) return BoolRef(Z3_mk_not(ctx.ref(), a.as_ast()), ctx) +def mk_not(a): + if is_not(a): + return a.arg(0) + else: + return Not(a) + def _has_probe(args): """Return `True` if one of the elements of the given collection is a Z3 probe.""" for arg in args: @@ -2800,7 +2806,7 @@ class RatNumRef(ArithRef): return self.denominator().is_int() and self.denominator_as_long() == 1 def as_long(self): - _z3_assert(self.is_int(), "Expected integer fraction") + _z3_assert(self.is_int_value(), "Expected integer fraction") return self.numerator_as_long() def as_decimal(self, prec): From c95dbb47a3aab5e30fd0413585620a6955113b57 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Nov 2018 16:43:37 -0800 Subject: [PATCH 204/227] fix #1958 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 2fb95e676..a4537837b 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -4822,6 +4822,7 @@ void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) { /* 0 <= i <= len(s) => s = xe & i = len(x) + i < 0 => len(e) = 0 */ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) { expr_ref x(mk_skolem(m_pre, s, i), m); @@ -4833,6 +4834,7 @@ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) { literal i_le_s = mk_simplified_literal(m_autil.mk_le(mk_sub(i, ls), zero)); add_axiom(~i_ge_0, ~i_le_s, mk_seq_eq(s, xe)); add_axiom(~i_ge_0, ~i_le_s, mk_eq(i, lx, false)); + add_axiom(i_ge_0, mk_eq(zero, m_util.str.mk_length(e), false)); } From 90070fda959c5bd17291abebf7dc768735969cbb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Nov 2018 20:17:09 -0800 Subject: [PATCH 205/227] fix #1959 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index a4537837b..ccebe0358 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -4823,6 +4823,7 @@ void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) { /* 0 <= i <= len(s) => s = xe & i = len(x) i < 0 => len(e) = 0 + i > len(s) => len(e) = 0 */ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) { expr_ref x(mk_skolem(m_pre, s, i), m); @@ -4830,11 +4831,13 @@ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) { expr_ref ls(m_util.str.mk_length(s), m); expr_ref zero(m_autil.mk_int(0), m); expr_ref xe = mk_concat(x, e); + literal le_is_0 = mk_eq(zero, m_util.str.mk_length(e), false); literal i_ge_0 = mk_simplified_literal(m_autil.mk_ge(i, zero)); literal i_le_s = mk_simplified_literal(m_autil.mk_le(mk_sub(i, ls), zero)); add_axiom(~i_ge_0, ~i_le_s, mk_seq_eq(s, xe)); add_axiom(~i_ge_0, ~i_le_s, mk_eq(i, lx, false)); - add_axiom(i_ge_0, mk_eq(zero, m_util.str.mk_length(e), false)); + add_axiom(i_ge_0, le_is_0); + add_axiom(i_le_s, le_is_0); } From 236f85d82bde5c4f3ab0829af8d16a4e1246d59c Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 21 Nov 2018 06:55:47 +0700 Subject: [PATCH 206/227] Improve intra-doc linking. --- src/api/z3_api.h | 41 +++++++++++++++++++++++++++++++++++++++ src/api/z3_fixedpoint.h | 18 +++++++++++++++++ src/api/z3_optimization.h | 39 +++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 92dd399c5..6e3ce57a1 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4751,6 +4751,8 @@ extern "C" { The returned AST is simplified using algebraic simplification rules, such as constant propagation (propagating true/false over logical connectives). + \sa Z3_simplify_ex + def_API('Z3_simplify', AST, (_in(CONTEXT), _in(AST))) */ Z3_ast Z3_API Z3_simplify(Z3_context c, Z3_ast a); @@ -4762,6 +4764,10 @@ extern "C" { This procedure is similar to #Z3_simplify, but the behavior of the simplifier can be configured using the given parameter set. + \sa Z3_simplify + \sa Z3_simplify_get_help + \sa Z3_simplify_get_param_descrs + def_API('Z3_simplify_ex', AST, (_in(CONTEXT), _in(AST), _in(PARAMS))) */ Z3_ast Z3_API Z3_simplify_ex(Z3_context c, Z3_ast a, Z3_params p); @@ -4769,6 +4775,9 @@ extern "C" { /** \brief Return a string describing all available parameters. + \sa Z3_simplify_ex + \sa Z3_simplify_get_param_descrs + def_API('Z3_simplify_get_help', STRING, (_in(CONTEXT),)) */ Z3_string Z3_API Z3_simplify_get_help(Z3_context c); @@ -4776,6 +4785,9 @@ extern "C" { /** \brief Return the parameter description set for the simplify procedure. + \sa Z3_simplify_ex + \sa Z3_simplify_get_help + def_API('Z3_simplify_get_param_descrs', PARAM_DESCRS, (_in(CONTEXT),)) */ Z3_param_descrs Z3_API Z3_simplify_get_param_descrs(Z3_context c); @@ -6050,6 +6062,9 @@ extern "C" { /** \brief Return a string describing all solver available parameters. + \sa Z3_solver_get_param_descrs + \sa Z3_solver_set_params + def_API('Z3_solver_get_help', STRING, (_in(CONTEXT), _in(SOLVER))) */ Z3_string Z3_API Z3_solver_get_help(Z3_context c, Z3_solver s); @@ -6057,6 +6072,9 @@ extern "C" { /** \brief Return the parameter description set for the given solver object. + \sa Z3_solver_get_help + \sa Z3_solver_set_params + def_API('Z3_solver_get_param_descrs', PARAM_DESCRS, (_in(CONTEXT), _in(SOLVER))) */ Z3_param_descrs Z3_API Z3_solver_get_param_descrs(Z3_context c, Z3_solver s); @@ -6064,6 +6082,9 @@ extern "C" { /** \brief Set the given solver using the given parameters. + \sa Z3_solver_get_help + \sa Z3_solver_get_param_descrs + def_API('Z3_solver_set_params', VOID, (_in(CONTEXT), _in(SOLVER), _in(PARAMS))) */ void Z3_API Z3_solver_set_params(Z3_context c, Z3_solver s, Z3_params p); @@ -6087,6 +6108,7 @@ extern "C" { The solver contains a stack of assertions. + \sa Z3_solver_get_num_scopes \sa Z3_solver_pop def_API('Z3_solver_push', VOID, (_in(CONTEXT), _in(SOLVER))) @@ -6096,6 +6118,7 @@ extern "C" { /** \brief Backtrack \c n backtracking points. + \sa Z3_solver_get_num_scopes \sa Z3_solver_push \pre n <= Z3_solver_get_num_scopes(c, s) @@ -6107,6 +6130,9 @@ extern "C" { /** \brief Remove all assertions from the solver. + \sa Z3_solver_assert + \sa Z3_solver_assert_and_track + def_API('Z3_solver_reset', VOID, (_in(CONTEXT), _in(SOLVER))) */ void Z3_API Z3_solver_reset(Z3_context c, Z3_solver s); @@ -6127,6 +6153,9 @@ extern "C" { The functions #Z3_solver_check and #Z3_solver_check_assumptions should be used to check whether the logical context is consistent or not. + \sa Z3_solver_assert_and_track + \sa Z3_solver_reset + def_API('Z3_solver_assert', VOID, (_in(CONTEXT), _in(SOLVER), _in(AST))) */ void Z3_API Z3_solver_assert(Z3_context c, Z3_solver s, Z3_ast a); @@ -6143,6 +6172,9 @@ extern "C" { \pre \c a must be a Boolean expression \pre \c p must be a Boolean constant (aka variable). + \sa Z3_solver_assert + \sa Z3_solver_reset + def_API('Z3_solver_assert_and_track', VOID, (_in(CONTEXT), _in(SOLVER), _in(AST), _in(AST))) */ void Z3_API Z3_solver_assert_and_track(Z3_context c, Z3_solver s, Z3_ast a, Z3_ast p); @@ -6150,6 +6182,9 @@ extern "C" { /** \brief load solver assertions from a file. + \sa Z3_solver_from_string + \sa Z3_solver_to_string + def_API('Z3_solver_from_file', VOID, (_in(CONTEXT), _in(SOLVER), _in(STRING))) */ void Z3_API Z3_solver_from_file(Z3_context c, Z3_solver s, Z3_string file_name); @@ -6157,6 +6192,9 @@ extern "C" { /** \brief load solver assertions from a string. + \sa Z3_solver_from_file + \sa Z3_solver_to_string + def_API('Z3_solver_from_string', VOID, (_in(CONTEXT), _in(SOLVER), _in(STRING))) */ void Z3_API Z3_solver_from_string(Z3_context c, Z3_solver s, Z3_string file_name); @@ -6323,6 +6361,9 @@ extern "C" { /** \brief Convert a solver into a string. + \sa Z3_solver_from_file + \sa Z3_solver_from_string + def_API('Z3_solver_to_string', STRING, (_in(CONTEXT), _in(SOLVER))) */ Z3_string Z3_API Z3_solver_to_string(Z3_context c, Z3_solver s); diff --git a/src/api/z3_fixedpoint.h b/src/api/z3_fixedpoint.h index 246228ae6..393cba224 100644 --- a/src/api/z3_fixedpoint.h +++ b/src/api/z3_fixedpoint.h @@ -253,6 +253,9 @@ extern "C" { /** \brief Set parameters on fixedpoint context. + \sa Z3_fixedpoint_get_help + \sa Z3_fixedpoint_get_param_descrs + def_API('Z3_fixedpoint_set_params', VOID, (_in(CONTEXT), _in(FIXEDPOINT), _in(PARAMS))) */ void Z3_API Z3_fixedpoint_set_params(Z3_context c, Z3_fixedpoint f, Z3_params p); @@ -260,6 +263,9 @@ extern "C" { /** \brief Return a string describing all fixedpoint available parameters. + \sa Z3_fixedpoint_get_param_descrs + \sa Z3_fixedpoint_set_params + def_API('Z3_fixedpoint_get_help', STRING, (_in(CONTEXT), _in(FIXEDPOINT))) */ Z3_string Z3_API Z3_fixedpoint_get_help(Z3_context c, Z3_fixedpoint f); @@ -267,6 +273,9 @@ extern "C" { /** \brief Return the parameter description set for the given fixedpoint object. + \sa Z3_fixedpoint_get_help + \sa Z3_fixedpoint_set_params + def_API('Z3_fixedpoint_get_param_descrs', PARAM_DESCRS, (_in(CONTEXT), _in(FIXEDPOINT))) */ Z3_param_descrs Z3_API Z3_fixedpoint_get_param_descrs(Z3_context c, Z3_fixedpoint f); @@ -278,6 +287,9 @@ extern "C" { \param num_queries - number of additional queries to print. \param queries - additional queries. + \sa Z3_fixedpoint_from_file + \sa Z3_fixedpoint_from_string + def_API('Z3_fixedpoint_to_string', STRING, (_in(CONTEXT), _in(FIXEDPOINT), _in(UINT), _in_array(2, AST))) */ Z3_string Z3_API Z3_fixedpoint_to_string( @@ -295,6 +307,9 @@ extern "C" { \param f - fixedpoint context. \param s - string containing SMT2 specification. + \sa Z3_fixedpoint_from_file + \sa Z3_fixedpoint_to_string + def_API('Z3_fixedpoint_from_string', AST_VECTOR, (_in(CONTEXT), _in(FIXEDPOINT), _in(STRING))) */ Z3_ast_vector Z3_API Z3_fixedpoint_from_string(Z3_context c, @@ -310,6 +325,9 @@ extern "C" { \param f - fixedpoint context. \param s - path to file containing SMT2 specification. + \sa Z3_fixedpoint_from_string + \sa Z3_fixedpoint_to_string + def_API('Z3_fixedpoint_from_file', AST_VECTOR, (_in(CONTEXT), _in(FIXEDPOINT), _in(STRING))) */ Z3_ast_vector Z3_API Z3_fixedpoint_from_file(Z3_context c, diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h index fffaac212..750f286a5 100644 --- a/src/api/z3_optimization.h +++ b/src/api/z3_optimization.h @@ -129,6 +129,11 @@ extern "C" { \param num_assumptions - number of additional assumptions \param assumptions - the additional assumptions + \sa Z3_optimize_get_reason_unknown + \sa Z3_optimize_get_model + \sa Z3_optimize_get_statistics + \sa Z3_optimize_get_unsat_core + def_API('Z3_optimize_check', INT, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT), _in_array(2, AST))) */ Z3_lbool Z3_API Z3_optimize_check(Z3_context c, Z3_optimize o, unsigned num_assumptions, Z3_ast const assumptions[]); @@ -169,6 +174,9 @@ extern "C" { \param o - optimization context \param p - parameters + \sa Z3_optimize_get_help + \sa Z3_optimize_get_param_descrs + def_API('Z3_optimize_set_params', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(PARAMS))) */ void Z3_API Z3_optimize_set_params(Z3_context c, Z3_optimize o, Z3_params p); @@ -179,6 +187,9 @@ extern "C" { \param c - context \param o - optimization context + \sa Z3_optimize_get_help + \sa Z3_optimize_set_params + def_API('Z3_optimize_get_param_descrs', PARAM_DESCRS, (_in(CONTEXT), _in(OPTIMIZE))) */ Z3_param_descrs Z3_API Z3_optimize_get_param_descrs(Z3_context c, Z3_optimize o); @@ -190,6 +201,10 @@ extern "C" { \param o - optimization context \param idx - index of optimization objective + \sa Z3_optimize_get_upper + \sa Z3_optimize_get_lower_as_vector + \sa Z3_optimize_get_upper_as_vector + def_API('Z3_optimize_get_lower', AST, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT))) */ Z3_ast Z3_API Z3_optimize_get_lower(Z3_context c, Z3_optimize o, unsigned idx); @@ -201,6 +216,10 @@ extern "C" { \param o - optimization context \param idx - index of optimization objective + \sa Z3_optimize_get_lower + \sa Z3_optimize_get_lower_as_vector + \sa Z3_optimize_get_upper_as_vector + def_API('Z3_optimize_get_upper', AST, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT))) */ Z3_ast Z3_API Z3_optimize_get_upper(Z3_context c, Z3_optimize o, unsigned idx); @@ -216,6 +235,10 @@ extern "C" { \param o - optimization context \param idx - index of optimization objective + \sa Z3_optimize_get_lower + \sa Z3_optimize_get_upper + \sa Z3_optimize_get_upper_as_vector + def_API('Z3_optimize_get_lower_as_vector', AST_VECTOR, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT))) */ Z3_ast_vector Z3_API Z3_optimize_get_lower_as_vector(Z3_context c, Z3_optimize o, unsigned idx); @@ -227,6 +250,10 @@ extern "C" { \param o - optimization context \param idx - index of optimization objective + \sa Z3_optimize_get_lower + \sa Z3_optimize_get_upper + \sa Z3_optimize_get_lower_as_vector + def_API('Z3_optimize_get_upper_as_vector', AST_VECTOR, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT))) */ Z3_ast_vector Z3_API Z3_optimize_get_upper_as_vector(Z3_context c, Z3_optimize o, unsigned idx); @@ -237,6 +264,9 @@ extern "C" { \param c - context. \param o - optimization context. + \sa Z3_optimize_from_file + \sa Z3_optimize_from_string + def_API('Z3_optimize_to_string', STRING, (_in(CONTEXT), _in(OPTIMIZE))) */ Z3_string Z3_API Z3_optimize_to_string(Z3_context c, Z3_optimize o); @@ -250,6 +280,9 @@ extern "C" { \param o - optimize context. \param s - string containing SMT2 specification. + \sa Z3_optimize_from_file + \sa Z3_optimize_to_string + def_API('Z3_optimize_from_string', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(STRING))) */ void Z3_API Z3_optimize_from_string(Z3_context c, Z3_optimize o, Z3_string s); @@ -263,6 +296,9 @@ extern "C" { \param o - optimize context. \param s - path to file containing SMT2 specification. + \sa Z3_optimize_from_string + \sa Z3_optimize_to_string + def_API('Z3_optimize_from_file', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(STRING))) */ void Z3_API Z3_optimize_from_file(Z3_context c, Z3_optimize o, Z3_string s); @@ -270,6 +306,9 @@ extern "C" { /** \brief Return a string containing a description of parameters accepted by optimize. + \sa Z3_optimize_get_param_descrs + \sa Z3_optimize_set_params + def_API('Z3_optimize_get_help', STRING, (_in(CONTEXT), _in(OPTIMIZE))) */ Z3_string Z3_API Z3_optimize_get_help(Z3_context c, Z3_optimize t); From 0c1408b30ecce3b3108b27b81633c092bbec548b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Nov 2018 13:48:48 -0800 Subject: [PATCH 207/227] fixing #1948 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 86 +++++++++++++++++---------- src/ast/ast.h | 11 ++-- src/tactic/smtlogics/qfnia_tactic.cpp | 3 +- src/util/chashtable.h | 15 ++++- src/util/memory_manager.cpp | 16 +++-- 5 files changed, 88 insertions(+), 43 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 9a5e1de9c..067c4d127 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -595,8 +595,7 @@ unsigned get_node_hash(ast const * n) { return 0; } -void ast_table::erase(ast * n) { - // Customized erase method +void ast_table::push_erase(ast * n) { // It uses two important properties: // 1. n is known to be in the table. // 2. operator== can be used instead of compare_nodes (big savings) @@ -604,36 +603,59 @@ void ast_table::erase(ast * n) { unsigned h = n->hash(); unsigned idx = h & mask; cell * c = m_table + idx; - SASSERT(!c->is_free()); cell * prev = nullptr; while (true) { + SASSERT(!c->is_free()); + cell * next = c->m_next; if (c->m_data == n) { m_size--; if (prev == nullptr) { - cell * next = c->m_next; if (next == nullptr) { m_used_slots--; + push_recycle_cell(c); c->mark_free(); SASSERT(c->is_free()); } else { *c = *next; - recycle_cell(next); + next->m_data = n; + push_recycle_cell(next); } } else { - prev->m_next = c->m_next; - recycle_cell(c); + prev->m_next = next; + push_recycle_cell(c); } return; } CHS_CODE(m_collisions++;); prev = c; - c = c->m_next; + c = next; SASSERT(c); } } +ast* ast_table::pop_erase() { + cell* c = m_tofree_cell; + if (c == nullptr) { + return nullptr; + } + if (c->is_free()) { + // cell was marked free, should not be recycled. + c->unmark_free(); + m_tofree_cell = c->m_next; + c->mark_free(); + } + else { + // cell should be recycled with m_free_cell + m_tofree_cell = c->m_next; + recycle_cell(c); + } + return c->m_data; +} + + + // ----------------------------------- // // decl_plugin @@ -1827,21 +1849,17 @@ ast * ast_manager::register_node_core(ast * n) { void ast_manager::delete_node(ast * n) { TRACE("delete_node_bug", tout << mk_ll_pp(n, *this) << "\n";); - ptr_buffer worklist; - worklist.push_back(n); - while (!worklist.empty()) { - n = worklist.back(); - worklist.pop_back(); + SASSERT(m_ast_table.contains(n)); + m_ast_table.push_erase(n); + + while ((n = m_ast_table.pop_erase())) { TRACE("ast", tout << "Deleting object " << n->m_id << " " << n << "\n";); CTRACE("del_quantifier", is_quantifier(n), tout << "deleting quantifier " << n->m_id << " " << n << "\n";); TRACE("mk_var_bug", tout << "del_ast: " << n->m_id << "\n";); TRACE("ast_delete_node", tout << mk_bounded_pp(n, *this) << "\n";); - SASSERT(m_ast_table.contains(n)); - m_ast_table.erase(n); - SASSERT(!m_ast_table.contains(n)); SASSERT(!m_debug_ref_count || !m_debug_free_indices.contains(n->m_id)); #ifdef RECYCLE_FREE_AST_INDICES @@ -1860,29 +1878,35 @@ void ast_manager::delete_node(ast * n) { dealloc(info); } break; - case AST_FUNC_DECL: - if (to_func_decl(n)->m_info != nullptr && !m_debug_ref_count) { - func_decl_info * info = to_func_decl(n)->get_info(); + case AST_FUNC_DECL: { + func_decl* f = to_func_decl(n); + if (f->m_info != nullptr && !m_debug_ref_count) { + func_decl_info * info = f->get_info(); info->del_eh(*this); dealloc(info); } - dec_array_ref(worklist, to_func_decl(n)->get_arity(), to_func_decl(n)->get_domain()); - dec_ref(worklist, to_func_decl(n)->get_range()); + push_dec_array_ref(f->get_arity(), f->get_domain()); + push_dec_ref(f->get_range()); break; - case AST_APP: - dec_ref(worklist, to_app(n)->get_decl()); - dec_array_ref(worklist, to_app(n)->get_num_args(), to_app(n)->get_args()); + } + case AST_APP: { + app* a = to_app(n); + push_dec_ref(a->get_decl()); + push_dec_array_ref(a->get_num_args(), a->get_args()); break; + } case AST_VAR: - dec_ref(worklist, to_var(n)->get_sort()); + push_dec_ref(to_var(n)->get_sort()); break; - case AST_QUANTIFIER: - dec_array_ref(worklist, to_quantifier(n)->get_num_decls(), to_quantifier(n)->get_decl_sorts()); - dec_ref(worklist, to_quantifier(n)->get_expr()); - dec_ref(worklist, to_quantifier(n)->get_sort()); - dec_array_ref(worklist, to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns()); - dec_array_ref(worklist, to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns()); + case AST_QUANTIFIER: { + quantifier* q = to_quantifier(n); + push_dec_array_ref(q->get_num_decls(), q->get_decl_sorts()); + push_dec_ref(q->get_expr()); + push_dec_ref(q->get_sort()); + push_dec_array_ref(q->get_num_patterns(), q->get_patterns()); + push_dec_array_ref(q->get_num_no_patterns(), q->get_no_patterns()); break; + } default: break; } diff --git a/src/ast/ast.h b/src/ast/ast.h index 4054b32dc..b81db5196 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -962,7 +962,8 @@ class ast_translation; class ast_table : public chashtable, ast_eq_proc> { public: - void erase(ast * n); + void push_erase(ast * n); + ast* pop_erase(); }; // ----------------------------------- @@ -2297,17 +2298,17 @@ protected: bool check_nnf_proof_parents(unsigned num_proofs, proof * const * proofs) const; private: - void dec_ref(ptr_buffer & worklist, ast * n) { + void push_dec_ref(ast * n) { n->dec_ref(); if (n->get_ref_count() == 0) { - worklist.push_back(n); + m_ast_table.push_erase(n); } } template - void dec_array_ref(ptr_buffer & worklist, unsigned sz, T * const * a) { + void push_dec_array_ref(unsigned sz, T * const * a) { for(unsigned i = 0; i < sz; i++) { - dec_ref(worklist, a[i]); + push_dec_ref(a[i]); } } }; diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 02e3349aa..d28034a1d 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -116,5 +116,6 @@ tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { or_else(mk_qfnia_sat_solver(m, p), try_for(mk_qfnia_smt_solver(m, p), 2000), mk_qfnia_nlsat_solver(m, p), - mk_qfnia_smt_solver(m, p))); + mk_qfnia_smt_solver(m, p)) + ); } diff --git a/src/util/chashtable.h b/src/util/chashtable.h index 9bc5988e5..e49ac3bd4 100644 --- a/src/util/chashtable.h +++ b/src/util/chashtable.h @@ -31,6 +31,7 @@ Revision History: #include "util/memory_manager.h" #include "util/debug.h" #include "util/trace.h" +#include "util/tptr.h" #ifdef Z3DEBUG #include "util/hashtable.h" #endif @@ -54,8 +55,9 @@ protected: cell * m_next; T m_data; cell():m_next(reinterpret_cast(1)) {} - bool is_free() const { return m_next == reinterpret_cast(1); } - void mark_free() { m_next = reinterpret_cast(1); } + bool is_free() const { return GET_TAG(m_next) == 1; } + void mark_free() { m_next = TAG(cell*, m_next, 1); } + void unmark_free() { m_next = UNTAG(cell*, m_next); } }; cell * m_table; // array of cells. @@ -70,6 +72,7 @@ protected: #endif cell * m_next_cell; cell * m_free_cell; + cell * m_tofree_cell; unsigned get_hash(T const & d) const { return HashProc::operator()(d); } bool equals(T const & e1, T const & e2) const { return EqProc::operator()(e1, e2); } @@ -171,6 +174,7 @@ protected: m_slots = new_slots; m_next_cell = next_cell; m_free_cell = nullptr; + m_tofree_cell = nullptr; CASSERT("chashtable", check_invariant()); return; } @@ -204,6 +208,12 @@ protected: m_free_cell = c; } + void push_recycle_cell(cell* c) { + SASSERT(c < m_table + m_capacity); + c->m_next = m_tofree_cell; + m_tofree_cell = c; + } + void init(unsigned slots, unsigned cellar) { m_capacity = slots + cellar; m_table = alloc_table(m_capacity); @@ -212,6 +222,7 @@ protected: m_size = 0; m_next_cell = m_table + slots; m_free_cell = nullptr; + m_tofree_cell = nullptr; } public: diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 0a1d360c8..148306fbd 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -292,8 +292,10 @@ void memory::deallocate(void * p) { void * memory::allocate(size_t s) { s = s + sizeof(size_t); // we allocate an extra field! void * r = malloc(s); - if (r == 0) + if (r == 0) { throw_out_of_memory(); + return nullptr; + } *(static_cast(r)) = s; g_memory_thread_alloc_size += s; g_memory_thread_alloc_count += 1; @@ -317,8 +319,10 @@ void* memory::reallocate(void *p, size_t s) { } void *r = realloc(real_p, s); - if (r == 0) + if (r == 0) { throw_out_of_memory(); + return nullptr; + } *(static_cast(r)) = s; return static_cast(r) + 1; // we return a pointer to the location after the extra field } @@ -361,8 +365,10 @@ void * memory::allocate(size_t s) { if (counts_exceeded) throw_alloc_counts_exceeded(); void * r = malloc(s); - if (r == nullptr) + if (r == nullptr) { throw_out_of_memory(); + return nullptr; + } *(static_cast(r)) = s; return static_cast(r) + 1; // we return a pointer to the location after the extra field } @@ -389,8 +395,10 @@ void* memory::reallocate(void *p, size_t s) { if (counts_exceeded) throw_alloc_counts_exceeded(); void *r = realloc(real_p, s); - if (r == nullptr) + if (r == nullptr) { throw_out_of_memory(); + return nullptr; + } *(static_cast(r)) = s; return static_cast(r) + 1; // we return a pointer to the location after the extra field } From 7b2590c026a4fb3ec4f7be541e22d6cf78434e99 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Nov 2018 17:08:33 -0800 Subject: [PATCH 208/227] fix is-unit test in seq rewriter Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 32 ++++++++++++++++++++----------- src/util/ref_vector.h | 31 ++++++++++++++++++------------ 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 82607452f..75b0c38e9 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -677,8 +677,22 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { } // check if subsequence of a is in b. expr_ref_vector as(m()), bs(m()); - m_util.str.get_concat(a, as); - m_util.str.get_concat(b, bs); + if (m_util.str.is_string(a, c)) { + for (unsigned i = 0; i < c.length(); ++i) { + as.push_back(m_util.str.mk_unit(m_util.str.mk_char(c, i))); + } + } + else { + m_util.str.get_concat(a, as); + } + if (m_util.str.is_string(b, d)) { + for (unsigned i = 0; i < d.length(); ++i) { + bs.push_back(m_util.str.mk_unit(m_util.str.mk_char(d, i))); + } + } + else { + m_util.str.get_concat(b, bs); + } bool all_values = true; TRACE("seq", tout << mk_pp(a, m()) << " contains " << mk_pp(b, m()) << "\n";); @@ -719,7 +733,6 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { } } - if (as.empty()) { result = m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b))); return BR_REWRITE2; @@ -755,14 +768,10 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { result = m().mk_true(); return BR_DONE; } - bool all_units = true; - for (unsigned i = 0; i < bs.size(); ++i) { - all_units = m_util.str.is_unit(bs[i].get()); - } - for (unsigned i = 0; i < as.size(); ++i) { - all_units = m_util.str.is_unit(as[i].get()); - } - if (all_units) { + + std::function is_unit = [&](expr *e) { return m_util.str.is_unit(e); }; + + if (bs.forall(is_unit) && as.forall(is_unit)) { if (as.size() < bs.size()) { result = m().mk_false(); return BR_DONE; @@ -1595,6 +1604,7 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) { return BR_REWRITE3; } + bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs, bool& change) { expr* a, *b; zstring s; diff --git a/src/util/ref_vector.h b/src/util/ref_vector.h index d0a17116a..02803a514 100644 --- a/src/util/ref_vector.h +++ b/src/util/ref_vector.h @@ -306,24 +306,31 @@ public: // prevent abuse: ref_vector & operator=(ref_vector const & other) = delete; - bool containsp(std::function& predicate) const { - for (auto const& t : *this) + bool forall(std::function& predicate) const { + for (T* t : *this) + if (!predicate(t)) + return false; + return true; + } + + bool exists(std::function& predicate) const { + for (T* t : *this) if (predicate(t)) return true; return false; } - ref_vector filter_pure(std::function& predicate) const { + ref_vector filter_pure(std::function& predicate) const { ref_vector result(m()); - for (auto& t : *this) + for (T* t : *this) if (predicate(t)) result.push_back(t); return result; } #if 0 - // TBD: not sure why some compilers complain here. - ref_vector& filter_update(std::function& predicate) { + // TBD: + ref_vector& filter_update(std::function& predicate) { unsigned j = 0; for (auto& t : *this) if (predicate(t)) @@ -334,23 +341,23 @@ public: #endif template - vector mapv_pure(std::function& f) const { + vector mapv_pure(std::function& f) const { vector result; - for (auto& t : *this) + for (T* t : *this) result.push_back(f(t)); return result; } - ref_vector map_pure(std::function& f) const { + ref_vector map_pure(std::function& f) const { ref_vector result(m()); - for (auto& t : *this) + for (T* t : *this) result.push_back(f(t)); return result; } - ref_vector& map_update(std::function& f) { + ref_vector& map_update(std::function& f) { unsigned j = 0; - for (auto& t : *this) + for (T* t : *this) set(j++, f(t)); return *this; } From 498fa879934e5e5eccb386a488f8076b59ea93e2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Nov 2018 10:48:49 -0800 Subject: [PATCH 209/227] seq rewriting fixes Signed-off-by: Nikolaj Bjorner --- examples/python/rc2.py | 112 ++++++++++++++++----- src/ast/rewriter/seq_rewriter.cpp | 157 +++++++++++------------------- src/ast/seq_decl_plugin.cpp | 28 +++++- src/ast/seq_decl_plugin.h | 29 +++--- 4 files changed, 184 insertions(+), 142 deletions(-) diff --git a/examples/python/rc2.py b/examples/python/rc2.py index a68e41b46..5ccbbaca8 100644 --- a/examples/python/rc2.py +++ b/examples/python/rc2.py @@ -1,5 +1,9 @@ # RC2 algorithm -# basic version without optimizations +# basic version with some optimizations +# - process soft constraints in order of highest values first. +# - extract multiple cores, not just one +# - use built-in cardinality constraints, cheap core minimization. +# # See also https://github.com/pysathq/pysat and papers in CP 2014, JSAT 2015. from z3 import * @@ -7,7 +11,6 @@ from z3 import * def tt(s, f): return is_true(s.model().eval(f)) - def add(Ws, f, w): Ws[f] = w + (Ws[f] if f in Ws else 0) @@ -19,46 +22,106 @@ def sub(Ws, f, w): del(Ws[f]) class RC2: + def __init__(self, s): self.bounds = {} + self.names = {} self.solver = s self.solver.set("sat.cardinality.solver", True) self.solver.set("sat.core.minimize", True) self.solver.set("sat.core.minimize_partial", True) def at_most(self, S, k): - fml = AtMost(S + [k]) + fml = simplify(AtMost(S + [k])) + if fml in self.names: + return self.names[fml] name = Bool("%s" % fml) self.solver.add(Implies(name, fml)) self.bounds[name] = (S, k) + sel.names[fml] = name return name + def print_cost(self): + print("max cost", self.max_cost, "min cost", self.min_cost) + + def update_max_cost(self): + self.max_cost = min(self.max_cost, self.get_cost()) + self.print_cost() + + # sort W, and incrementally add elements of W + # in sorted order to prefer cores with high weight. + def check(self, Ws): + ws = sorted(list(Ws), lambda f,w : -w) + # print(ws) + i = 0 + while i < len(ws): + j = i + # increment j until making 5% progress or exhausting equal weight entries + while (j < len(ws) and ws[j][1] == ws[i][1]) or (i > 0 and (i - j)*20 < len(ws)): + j += 1 + i = j + r = self.solver.check(ws[j][0] for j in range(i)) + if r == sat: + self.update_max_cost() + else: + return r + return sat + + def get_cost(self): + return sum(self.Ws0[c] for c in self.Ws0 if not tt(self.solver, c)) + + # Retrieve independendent cores from Ws + def get_cores(self, Ws): + cores = [] + while unsat == self.check(Ws): + core = list(self.solver.unsat_core()) + print (self.solver.statistics()) + if not core: + return unsat + w = min([Ws[c] for c in core]) + for f in core: + sub(Ws, f, w) + cores += [(core, w)] + self.update_max_cost() + return cores + + # Add new soft constraints to replace core + # with weight w. Allow to weaken at most + # one element of core. Elements that are + # cardinality constraints are weakened by + # increasing their bounds. Non-cardinality + # constraints are weakened to "true". They + # correspond to the constraint Not(s) <= 0, + # so weakening produces Not(s) <= 1, which + # is a tautology. + def update_bounds(self, Ws, core, w): + for f in core: + if f in self.bounds: + S, k = self.bounds[f] + if k + 1 < len(S): + add(Ws, self.at_most(S, k + 1), w) + add(Ws, self.at_most([mk_not(f) for f in core], 1), w) + # Ws are weighted soft constraints # Whenever there is an unsatisfiable core over ws # increase the limit of each soft constraint from a bound # and create a soft constraint that limits the number of # increased bounds to be at most one. def maxsat(self, Ws): - cost = 0 - Ws0 = Ws.copy() - while unsat == self.solver.check([f for f in Ws]): - core = list(self.solver.unsat_core()) - print (self.solver.statistics()) - print("Core", core) - if not core: - return unsat - w = min([Ws[c] for c in core]) - cost += w - for f in core: - sub(Ws, f, w) - for f in core: - if f in self.bounds: - S, k = self.bounds[f] - if k + 1 < len(S): - add(Ws, self.at_most(S, k + 1), w) - add(Ws, self.at_most([mk_not(f) for f in core], 1), w) - - return cost, { f for f in Ws0 if tt(self.solver, f) } + self.min_cost = 0 + self.max_cost = sum(Ws[c] for c in Ws) + self.Ws0 = Ws.copy() + while True: + cores = self.get_cores(Ws) + if not cores: + break + if cores == unsat: + return unsat + for (core, w) in cores: + self.min_cost += w + self.print_cost() + self.update_bounds(Ws, core, w) + return sel.min_cost, { f for f in self.Ws0 if not tt(self.solver, f) } def from_file(self, file): opt = Optimize() @@ -71,12 +134,11 @@ class RC2: add(Ws, f.arg(0), f.arg(2).as_long()) return self.maxsat(Ws) - def main(file): s = SolverFor("QF_FD") rc2 = RC2(s) set_param(verbose=0) - cost, trues = rc2.from_file(file) + cost, falses = rc2.from_file(file) print(cost) print(s.statistics()) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 75b0c38e9..6503bdcb9 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -675,25 +675,17 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { result = m().mk_bool_val(c.contains(d)); return BR_DONE; } + expr* x = nullptr, *y, *z; + if (m_util.str.is_extract(b, x, y, z) && x == a) { + result = m().mk_true(); + return BR_DONE; + } + // check if subsequence of a is in b. expr_ref_vector as(m()), bs(m()); - if (m_util.str.is_string(a, c)) { - for (unsigned i = 0; i < c.length(); ++i) { - as.push_back(m_util.str.mk_unit(m_util.str.mk_char(c, i))); - } - } - else { - m_util.str.get_concat(a, as); - } - if (m_util.str.is_string(b, d)) { - for (unsigned i = 0; i < d.length(); ++i) { - bs.push_back(m_util.str.mk_unit(m_util.str.mk_char(d, i))); - } - } - else { - m_util.str.get_concat(b, bs); - } - bool all_values = true; + m_util.str.get_concat_units(a, as); + m_util.str.get_concat_units(b, bs); + TRACE("seq", tout << mk_pp(a, m()) << " contains " << mk_pp(b, m()) << "\n";); if (bs.empty()) { @@ -701,24 +693,21 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { return BR_DONE; } - for (unsigned i = 0; all_values && i < bs.size(); ++i) { - all_values = m().is_value(bs[i].get()); + if (as.empty()) { + result = m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b))); + return BR_REWRITE2; } - bool found = false; - for (unsigned i = 0; !found && i < as.size(); ++i) { - all_values &= m().is_value(as[i].get()); - if (bs.size() <= as.size() - i) { - unsigned j = 0; - for (; j < bs.size() && as[j+i].get() == bs[j].get(); ++j) {}; - found = j == bs.size(); + for (unsigned i = 0; bs.size() + i <= as.size(); ++i) { + unsigned j = 0; + for (; j < bs.size() && as.get(j+i) == bs.get(j); ++j) {}; + if (j == bs.size()) { + result = m().mk_true(); + return BR_DONE; } } - if (found) { - result = m().mk_true(); - return BR_DONE; - } - if (all_values) { + std::function is_value = [&](expr* e) { return m().is_value(e); }; + if (bs.forall(is_value) && as.forall(is_value)) { result = m().mk_false(); return BR_DONE; } @@ -733,26 +722,12 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { } } - if (as.empty()) { - result = m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b))); - return BR_REWRITE2; - } - - if (bs.size() == 1 && m_util.str.is_string(bs[0].get(), c)) { - for (auto a_i : as) { - if (m_util.str.is_string(a_i, d) && d.contains(c)) { - result = m().mk_true(); - return BR_DONE; - } - } - } - unsigned offs = 0; unsigned sz = as.size(); - expr* b0 = bs[0].get(); - expr* bL = bs[bs.size()-1].get(); + expr* b0 = bs.get(0); + expr* bL = bs.get(bs.size()-1); for (; offs < as.size() && cannot_contain_prefix(as[offs].get(), b0); ++offs) {} - for (; sz > offs && cannot_contain_suffix(as[sz-1].get(), bL); --sz) {} + for (; sz > offs && cannot_contain_suffix(as.get(sz-1), bL); --sz) {} if (offs == sz) { result = m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b))); return BR_REWRITE2; @@ -763,24 +738,15 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { return BR_REWRITE2; } - expr* x, *y, *z; - if (m_util.str.is_extract(b, x, y, z) && x == a) { - result = m().mk_true(); - return BR_DONE; - } std::function is_unit = [&](expr *e) { return m_util.str.is_unit(e); }; if (bs.forall(is_unit) && as.forall(is_unit)) { - if (as.size() < bs.size()) { - result = m().mk_false(); - return BR_DONE; - } expr_ref_vector ors(m()); - for (unsigned i = 0; i < as.size() - bs.size() + 1; ++i) { + for (unsigned i = 0; i + bs.size() <= as.size(); ++i) { expr_ref_vector ands(m()); for (unsigned j = 0; j < bs.size(); ++j) { - ands.push_back(m().mk_eq(as[i + j].get(), bs[j].get())); + ands.push_back(m().mk_eq(as.get(i + j), bs.get(j))); } ors.push_back(::mk_and(ands)); } @@ -797,46 +763,41 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { br_status seq_rewriter::mk_seq_at(expr* a, expr* b, expr_ref& result) { zstring c; rational r; - if (m_autil.is_numeral(b, r)) { - if (r.is_neg()) { - result = m_util.str.mk_empty(m().get_sort(a)); - return BR_DONE; - } - unsigned len = 0; - bool bounded = min_length(1, &a, len); - if (bounded && r >= rational(len)) { - result = m_util.str.mk_empty(m().get_sort(a)); - return BR_DONE; - } - if (m_util.str.is_string(a, c)) { - if (r.is_unsigned() && r < rational(c.length())) { - result = m_util.str.mk_string(c.extract(r.get_unsigned(), 1)); - } - else { - result = m_util.str.mk_empty(m().get_sort(a)); - } - return BR_DONE; - } - if (r.is_unsigned()) { - len = r.get_unsigned(); - expr_ref_vector as(m()); - m_util.str.get_concat(a, as); - for (unsigned i = 0; i < as.size(); ++i) { - if (m_util.str.is_unit(as[i].get())) { - if (len == 0) { - result = as[i].get(); - return BR_DONE; - } - --len; - } - else { - return BR_FAILED; - } - } - } - + if (!m_autil.is_numeral(b, r)) { + return BR_FAILED; } - return BR_FAILED; + if (r.is_neg()) { + result = m_util.str.mk_empty(m().get_sort(a)); + return BR_DONE; + } + if (!r.is_unsigned()) { + return BR_FAILED; + } + unsigned len = r.get_unsigned(); + + expr_ref_vector as(m()); + m_util.str.get_concat_units(a, as); + + for (unsigned i = 0; i < as.size(); ++i) { + expr* a = as.get(i); + if (m_util.str.is_unit(a)) { + if (len == i) { + result = a; + return BR_REWRITE1; + } + } + else if (i > 0) { + SASSERT(len >= i); + result = m_util.str.mk_concat(as.size() - i, as.c_ptr() + i); + result = m().mk_app(m_util.get_family_id(), OP_SEQ_AT, result, m_autil.mk_int(len - i)); + return BR_REWRITE2; + } + else { + return BR_FAILED; + } + } + result = m_util.str.mk_empty(m().get_sort(a)); + return BR_DONE; } br_status seq_rewriter::mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result) { diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 737213477..5a01b63bb 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -933,16 +933,16 @@ app* seq_util::mk_skolem(symbol const& name, unsigned n, expr* const* args, sort return m.mk_app(f, n, args); } -app* seq_util::str::mk_string(zstring const& s) { return u.seq.mk_string(s); } +app* seq_util::str::mk_string(zstring const& s) const { + return u.seq.mk_string(s); +} - - -app* seq_util::str::mk_char(zstring const& s, unsigned idx) { +app* seq_util::str::mk_char(zstring const& s, unsigned idx) const { bv_util bvu(m); return bvu.mk_numeral(s[idx], s.num_bits()); } -app* seq_util::str::mk_char(char ch) { +app* seq_util::str::mk_char(char ch) const { zstring s(ch, zstring::ascii); return mk_char(s, 0); } @@ -969,6 +969,24 @@ void seq_util::str::get_concat(expr* e, expr_ref_vector& es) const { } } +void seq_util::str::get_concat_units(expr* e, expr_ref_vector& es) const { + expr* e1, *e2; + while (is_concat(e, e1, e2)) { + get_concat_units(e1, es); + e = e2; + } + zstring s; + if (is_string(e, s)) { + unsigned sz = s.length(); + for (unsigned j = 0; j < sz; ++j) { + es.push_back(mk_unit(mk_char(s, j))); + } + } + else if (!is_empty(e)) { + es.push_back(e); + } +} + app* seq_util::re::mk_loop(expr* r, unsigned lo) { parameter param(lo); return m.mk_app(m_fid, OP_RE_LOOP, 1, ¶m, 1, &r); diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 8bd4d2807..80b432f3e 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -232,26 +232,26 @@ public: public: str(seq_util& u): u(u), m(u.m), m_fid(u.m_fid) {} - sort* mk_seq(sort* s) { parameter param(s); return m.mk_sort(m_fid, SEQ_SORT, 1, ¶m); } + sort* mk_seq(sort* s) const { parameter param(s); return m.mk_sort(m_fid, SEQ_SORT, 1, ¶m); } sort* mk_string_sort() const { return m.mk_sort(m_fid, _STRING_SORT, 0, nullptr); } app* mk_empty(sort* s) const { return m.mk_const(m.mk_func_decl(m_fid, OP_SEQ_EMPTY, 0, nullptr, 0, (expr*const*)nullptr, s)); } - app* mk_string(zstring const& s); - app* mk_string(symbol const& s) { return u.seq.mk_string(s); } - app* mk_char(char ch); + app* mk_string(zstring const& s) const; + app* mk_string(symbol const& s) const { return u.seq.mk_string(s); } + app* mk_char(char ch) const; app* mk_concat(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONCAT, 2, es); } - app* mk_concat(expr* a, expr* b, expr* c) { return mk_concat(a, mk_concat(b, c)); } + app* mk_concat(expr* a, expr* b, expr* c) const { return mk_concat(a, mk_concat(b, c)); } expr* mk_concat(unsigned n, expr* const* es) const { if (n == 1) return es[0]; SASSERT(n > 1); return m.mk_app(m_fid, OP_SEQ_CONCAT, n, es); } expr* mk_concat(expr_ref_vector const& es) const { return mk_concat(es.size(), es.c_ptr()); } app* mk_length(expr* a) const { return m.mk_app(m_fid, OP_SEQ_LENGTH, 1, &a); } - app* mk_substr(expr* a, expr* b, expr* c) { expr* es[3] = { a, b, c }; return m.mk_app(m_fid, OP_SEQ_EXTRACT, 3, es); } - app* mk_contains(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONTAINS, 2, es); } - app* mk_prefix(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_PREFIX, 2, es); } - app* mk_suffix(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_SUFFIX, 2, es); } - app* mk_index(expr* a, expr* b, expr* i) { expr* es[3] = { a, b, i}; return m.mk_app(m_fid, OP_SEQ_INDEX, 3, es); } - app* mk_unit(expr* u) { return m.mk_app(m_fid, OP_SEQ_UNIT, 1, &u); } - app* mk_char(zstring const& s, unsigned idx); - app* mk_itos(expr* i) { return m.mk_app(m_fid, OP_STRING_ITOS, 1, &i); } - app* mk_stoi(expr* s) { return m.mk_app(m_fid, OP_STRING_STOI, 1, &s); } + app* mk_substr(expr* a, expr* b, expr* c) const { expr* es[3] = { a, b, c }; return m.mk_app(m_fid, OP_SEQ_EXTRACT, 3, es); } + app* mk_contains(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONTAINS, 2, es); } + app* mk_prefix(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_PREFIX, 2, es); } + app* mk_suffix(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_SUFFIX, 2, es); } + app* mk_index(expr* a, expr* b, expr* i) const { expr* es[3] = { a, b, i}; return m.mk_app(m_fid, OP_SEQ_INDEX, 3, es); } + app* mk_unit(expr* u) const { return m.mk_app(m_fid, OP_SEQ_UNIT, 1, &u); } + app* mk_char(zstring const& s, unsigned idx) const; + app* mk_itos(expr* i) const { return m.mk_app(m_fid, OP_STRING_ITOS, 1, &i); } + app* mk_stoi(expr* s) const { return m.mk_app(m_fid, OP_STRING_STOI, 1, &s); } bool is_string(expr const * n) const { return is_app_of(n, m_fid, OP_STRING_CONST); } @@ -304,6 +304,7 @@ public: MATCH_UNARY(is_unit); void get_concat(expr* e, expr_ref_vector& es) const; + void get_concat_units(expr* e, expr_ref_vector& es) const; expr* get_leftmost_concat(expr* e) const { expr* e1, *e2; while (is_concat(e, e1, e2)) e = e1; return e; } expr* get_rightmost_concat(expr* e) const { expr* e1, *e2; while (is_concat(e, e1, e2)) e = e2; return e; } }; From aeb4d1864dc3583585c6bb87eeb3431c3a17cefb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Nov 2018 11:39:34 -0800 Subject: [PATCH 210/227] clean up suffix/prefix rewriting Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 108 ++++++++++++++++-------------- src/ast/seq_decl_plugin.cpp | 5 ++ src/ast/seq_decl_plugin.h | 1 + 3 files changed, 65 insertions(+), 49 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 6503bdcb9..04ab51538 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -694,7 +694,7 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { } if (as.empty()) { - result = m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b))); + result = m_util.str.mk_is_empty(b); return BR_REWRITE2; } @@ -729,7 +729,7 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { for (; offs < as.size() && cannot_contain_prefix(as[offs].get(), b0); ++offs) {} for (; sz > offs && cannot_contain_suffix(as.get(sz-1), bL); --sz) {} if (offs == sz) { - result = m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b))); + result = m_util.str.mk_is_empty(b); return BR_REWRITE2; } if (offs > 0 || sz < as.size()) { @@ -914,25 +914,23 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { } } } - m_util.str.get_concat(a, as); - m_util.str.get_concat(b, bs); + m_util.str.get_concat_units(a, as); + m_util.str.get_concat_units(b, bs); unsigned i = 0; expr_ref_vector eqs(m()); for (; i < as.size() && i < bs.size(); ++i) { - expr* a = as[i].get(), *b = bs[i].get(); - if (a == b) { + expr* ai = as.get(i), *bi = bs.get(i); + if (m().are_equal(ai, bi)) { continue; } - if (m_util.str.is_unit(a) && m_util.str.is_unit(b)) { - eqs.push_back(m().mk_eq(a, b)); - continue; - } - if (m().is_value(a) && m().is_value(b) && m_util.str.is_string(a) && m_util.str.is_string(b)) { - TRACE("seq", tout << mk_pp(a, m()) << " != " << mk_pp(b, m()) << "\n";); + if (m().are_distinct(ai, bi)) { result = m().mk_false(); return BR_DONE; } - + if (m_util.str.is_unit(ai) && m_util.str.is_unit(bi)) { + eqs.push_back(m().mk_eq(ai, bi)); + continue; + } break; } if (i == as.size()) { @@ -943,7 +941,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { SASSERT(i < as.size()); if (i == bs.size()) { for (unsigned j = i; j < as.size(); ++j) { - eqs.push_back(m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), as[j].get())); + eqs.push_back(m_util.str.mk_is_empty(as.get(j))); } result = mk_and(eqs); TRACE("seq", tout << result << "\n";); @@ -953,13 +951,13 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { SASSERT(i < as.size() && i < bs.size()); a = m_util.str.mk_concat(as.size() - i, as.c_ptr() + i); b = m_util.str.mk_concat(bs.size() - i, bs.c_ptr() + i); - result = m_util.str.mk_prefix(a, b); + eqs.push_back(m_util.str.mk_prefix(a, b)); + result = mk_and(eqs); TRACE("seq", tout << result << "\n";); - return BR_DONE; - } - else { - return BR_FAILED; + return BR_REWRITE3; } + + return BR_FAILED; } br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { @@ -973,7 +971,7 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { return BR_DONE; } if (m_util.str.is_empty(b)) { - result = m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), a); + result = m_util.str.mk_is_empty(a); return BR_REWRITE3; } @@ -1039,36 +1037,48 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { } } } - expr_ref_vector as(m()), bs(m()); - m_util.str.get_concat(a, as); - m_util.str.get_concat(b, bs); - bool change = false; - while (as.size() > 0 && bs.size() > 0 && as.back() == bs.back()) { - as.pop_back(); - bs.pop_back(); - change = true; - } - if (as.size() > 0 && bs.size() > 0 && m().is_value(as.back()) && m().is_value(bs.back())) { - result = m().mk_false(); - return BR_DONE; - } - if (change) { - // suffix("", bs) <- true - if (as.empty()) { - result = m().mk_true(); + expr_ref_vector as(m()), bs(m()), eqs(m()); + m_util.str.get_concat_units(a, as); + m_util.str.get_concat_units(b, bs); + unsigned i = 1, sza = as.size(), szb = bs.size(); + for (; i <= sza && i <= szb; ++i) { + expr* ai = as.get(sza-i), *bi = bs.get(szb-i); + if (m().are_equal(ai, bi)) { + continue; + } + if (m().are_distinct(ai, bi)) { + result = m().mk_false(); return BR_DONE; } - // suffix(as, "") iff as = "" - if (bs.empty()) { - for (unsigned j = 0; j < as.size(); ++j) { - bs.push_back(m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), as[j].get())); - } - result = mk_and(bs); - return BR_REWRITE3; + if (m_util.str.is_unit(ai) && m_util.str.is_unit(bi)) { + eqs.push_back(m().mk_eq(ai, bi)); + continue; } - result = m_util.str.mk_suffix(m_util.str.mk_concat(as.size(), as.c_ptr()), - m_util.str.mk_concat(bs.size(), bs.c_ptr())); - return BR_DONE; + break; + } + if (i > sza) { + result = mk_and(eqs); + TRACE("seq", tout << result << "\n";); + return BR_REWRITE3; + } + if (i > szb) { + for (unsigned j = i; j <= sza; ++j) { + expr* aj = as.get(sza-j); + eqs.push_back(m_util.str.mk_is_empty(aj)); + } + result = mk_and(eqs); + TRACE("seq", tout << result << "\n";); + return BR_REWRITE3; + } + + if (i > 1) { + SASSERT(i <= sza && i <= szb); + a = m_util.str.mk_concat(sza - i + 1, as.c_ptr()); + b = m_util.str.mk_concat(szb - i + 1, bs.c_ptr()); + eqs.push_back(m_util.str.mk_suffix(a, b)); + result = mk_and(eqs); + TRACE("seq", tout << result << "\n";); + return BR_REWRITE3; } return BR_FAILED; @@ -1226,7 +1236,7 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) { TRACE("seq", tout << seq << "\n";); if (seq.empty()) { - result = m().mk_eq(a, m_util.str.mk_empty(m().get_sort(a))); + result = m_util.str.mk_is_empty(a); } else { result = m().mk_eq(a, m_util.str.mk_concat(seq)); @@ -1888,7 +1898,7 @@ bool seq_rewriter::reduce_contains(expr* a, expr* b, expr_ref_vector& disj) { disj.push_back(m_util.str.mk_contains(m_util.str.mk_concat(m_lhs.size() - i, m_lhs.c_ptr() + i), b)); return true; } - disj.push_back(m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b)))); + disj.push_back(m_util.str.mk_is_empty(b)); return true; } diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 5a01b63bb..4bcc664a4 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -987,6 +987,11 @@ void seq_util::str::get_concat_units(expr* e, expr_ref_vector& es) const { } } +app* seq_util::str::mk_is_empty(expr* s) const { + return m.mk_eq(mk_empty(get_sort(s)), s); +} + + app* seq_util::re::mk_loop(expr* r, unsigned lo) { parameter param(lo); return m.mk_app(m_fid, OP_RE_LOOP, 1, ¶m, 1, &r); diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 80b432f3e..52a764dde 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -252,6 +252,7 @@ public: app* mk_char(zstring const& s, unsigned idx) const; app* mk_itos(expr* i) const { return m.mk_app(m_fid, OP_STRING_ITOS, 1, &i); } app* mk_stoi(expr* s) const { return m.mk_app(m_fid, OP_STRING_STOI, 1, &s); } + app* mk_is_empty(expr* s) const; bool is_string(expr const * n) const { return is_app_of(n, m_fid, OP_STRING_CONST); } From ec36a9c495746551c6187cfe2662b5475fc9e6dc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Nov 2018 12:40:23 -0800 Subject: [PATCH 211/227] fix user push/pop with ba constraints Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 17 ++++++++++++ src/sat/ba_solver.h | 2 ++ src/sat/sat_extension.h | 1 + src/sat/sat_solver.cpp | 22 ++++++++------- src/sat/sat_solver.h | 1 + src/sat/tactic/goal2sat.cpp | 54 ++++++++++++++++++------------------- 6 files changed, 59 insertions(+), 38 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index dd690a6a9..762939b74 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -64,6 +64,13 @@ namespace sat { return static_cast(*this); } + unsigned ba_solver::constraint::fold_max_var(unsigned w) const { + if (lit() != null_literal) w = std::max(w, lit().var()); + for (unsigned i = 0; i < size(); ++i) w = std::max(w, get_lit(i).var()); + return w; + } + + std::ostream& operator<<(std::ostream& out, ba_solver::constraint const& cnstr) { if (cnstr.lit() != null_literal) out << cnstr.lit() << " == "; switch (cnstr.tag()) { @@ -2660,6 +2667,16 @@ namespace sat { } c.set_psm(r); } + + unsigned ba_solver::max_var(unsigned w) const { + for (constraint* cp : m_constraints) { + w = cp->fold_max_var(w); + } + for (constraint* cp : m_learned) { + w = cp->fold_max_var(w); + } + return w; + } void ba_solver::gc() { if (m_learned.size() >= 2 * m_constraints.size() && diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 558b22bf3..141ca0887 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -101,6 +101,7 @@ namespace sat { bool is_clear() const { return m_watch == null_literal && m_lit != null_literal; } bool is_pure() const { return m_pure; } void set_pure() { m_pure = true; } + unsigned fold_max_var(unsigned w) const; size_t obj_size() const { return m_obj_size; } card& to_card(); @@ -552,6 +553,7 @@ namespace sat { void find_mutexes(literal_vector& lits, vector & mutexes) override; void pop_reinit() override; void gc() override; + unsigned max_var(unsigned w) const override; double get_reward(literal l, ext_justification_idx idx, literal_occs_fun& occs) const override; bool is_extended_binary(ext_justification_idx idx, literal_vector & r) override; void init_use_list(ext_use_list& ul) override; diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index e687ab2b0..41aebb97e 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -80,6 +80,7 @@ namespace sat { virtual void init_use_list(ext_use_list& ul) = 0; virtual bool is_blocked(literal l, ext_constraint_idx) = 0; virtual bool check_model(model const& m) const = 0; + virtual unsigned max_var(unsigned w) const = 0; }; }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1881d0375..ee3bc7880 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3274,17 +3274,19 @@ namespace sat { } void solver::gc_var(bool_var v) { - if (v > 0) { - bool_var w = max_var(m_learned, v-1); - w = max_var(m_clauses, w); - w = max_var(true, w); - w = max_var(false, w); - v = m_mc.max_var(w); - for (literal lit : m_trail) { - if (lit.var() > w) w = lit.var(); - } - v = std::max(v, w + 1); + bool_var w = max_var(m_learned, v); + w = max_var(m_clauses, w); + w = max_var(true, w); + w = max_var(false, w); + v = m_mc.max_var(w); + for (literal lit : m_trail) { + w = std::max(w, lit.var()); } + if (m_ext) { + w = m_ext->max_var(w); + } + v = w + 1; + // v is an index of a variable that does not occur in solver state. if (v < m_level.size()) { for (bool_var i = v; i < m_level.size(); ++i) { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 27c2e123c..8402fc898 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -543,6 +543,7 @@ namespace sat { void user_push(); void user_pop(unsigned num_scopes); void pop_to_base_level(); + unsigned num_user_scopes() const { return m_user_scope_literals.size(); } reslimit& rlimit() { return m_rlimit; } // ----------------------- // diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 645ef8a3f..d484ecda4 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -444,13 +444,24 @@ struct goal2sat::imp { convert_to_wlits(t, lits, wlits); } + void push_result(bool root, sat::literal lit, unsigned num_args) { + if (root) { + m_result_stack.reset(); + mk_clause(lit); + } + else { + m_result_stack.shrink(m_result_stack.size() - num_args); + m_result_stack.push_back(lit); + } + } + void convert_pb_ge(app* t, bool root, bool sign) { rational k = pb.get_k(t); check_unsigned(k); svector wlits; convert_pb_args(t, wlits); unsigned sz = m_result_stack.size(); - if (root) { + if (root && m_solver.num_user_scopes() == 0) { m_result_stack.reset(); unsigned k1 = k.get_unsigned(); if (sign) { @@ -467,8 +478,7 @@ struct goal2sat::imp { sat::literal lit(v, sign); m_ext->add_pb_ge(v, wlits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); - m_result_stack.shrink(sz - t->get_num_args()); - m_result_stack.push_back(lit); + push_result(root, lit, t->get_num_args()); } } @@ -483,7 +493,7 @@ struct goal2sat::imp { } check_unsigned(k); unsigned sz = m_result_stack.size(); - if (root) { + if (root && m_solver.num_user_scopes() == 0) { m_result_stack.reset(); unsigned k1 = k.get_unsigned(); if (sign) { @@ -500,19 +510,19 @@ struct goal2sat::imp { sat::literal lit(v, sign); m_ext->add_pb_ge(v, wlits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); - m_result_stack.shrink(sz - t->get_num_args()); - m_result_stack.push_back(lit); + push_result(root, lit, t->get_num_args()); } } void convert_pb_eq(app* t, bool root, bool sign) { - IF_VERBOSE(0, verbose_stream() << "pbeq: " << mk_pp(t, m) << "\n";); + //IF_VERBOSE(0, verbose_stream() << "pbeq: " << mk_pp(t, m) << "\n";); rational k = pb.get_k(t); SASSERT(k.is_unsigned()); svector wlits; convert_pb_args(t, wlits); - sat::bool_var v1 = (root && !sign) ? sat::null_bool_var : m_solver.mk_var(true); - sat::bool_var v2 = (root && !sign) ? sat::null_bool_var : m_solver.mk_var(true); + bool base_assert = (root && !sign && m_solver.num_user_scopes() == 0); + sat::bool_var v1 = base_assert ? sat::null_bool_var : m_solver.mk_var(true); + sat::bool_var v2 = base_assert ? sat::null_bool_var : m_solver.mk_var(true); m_ext->add_pb_ge(v1, wlits, k.get_unsigned()); k.neg(); for (wliteral& wl : wlits) { @@ -521,7 +531,7 @@ struct goal2sat::imp { } check_unsigned(k); m_ext->add_pb_ge(v2, wlits, k.get_unsigned()); - if (root && !sign) { + if (base_assert) { m_result_stack.reset(); } else { @@ -532,13 +542,8 @@ struct goal2sat::imp { mk_clause(~l, l2); mk_clause(~l1, ~l2, l); m_cache.insert(t, l); - m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); if (sign) l.neg(); - m_result_stack.push_back(l); - if (root) { - m_result_stack.reset(); - mk_clause(l); - } + push_result(root, l, t->get_num_args()); } } @@ -547,7 +552,7 @@ struct goal2sat::imp { sat::literal_vector lits; unsigned sz = m_result_stack.size(); convert_pb_args(t->get_num_args(), lits); - if (root) { + if (root && m_solver.num_user_scopes() == 0) { m_result_stack.reset(); m_ext->add_at_least(sat::null_bool_var, lits, k.get_unsigned()); } @@ -558,8 +563,7 @@ struct goal2sat::imp { m_cache.insert(t, lit); if (sign) lit.neg(); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); - m_result_stack.shrink(sz - t->get_num_args()); - m_result_stack.push_back(lit); + push_result(root, lit, t->get_num_args()); } } @@ -571,7 +575,7 @@ struct goal2sat::imp { for (sat::literal& l : lits) { l.neg(); } - if (root) { + if (root && m_solver.num_user_scopes() == 0) { m_result_stack.reset(); m_ext->add_at_least(sat::null_bool_var, lits, lits.size() - k.get_unsigned()); } @@ -580,9 +584,8 @@ struct goal2sat::imp { sat::literal lit(v, false); m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned()); m_cache.insert(t, lit); - m_result_stack.shrink(sz - t->get_num_args()); if (sign) lit.neg(); - m_result_stack.push_back(lit); + push_result(root, lit, t->get_num_args()); } } @@ -610,13 +613,8 @@ struct goal2sat::imp { mk_clause(~l, l2); mk_clause(~l1, ~l2, l); m_cache.insert(t, l); - m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); if (sign) l.neg(); - m_result_stack.push_back(l); - if (root) { - mk_clause(l); - m_result_stack.reset(); - } + push_result(root, l, t->get_num_args()); } } From 7bc3b4e3810c81dff9ad677cd3a1d63bced7ee63 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Nov 2018 13:03:55 -0800 Subject: [PATCH 212/227] swap order in equality for emptiness check to deal with rewriter Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 4 ++-- src/ast/seq_decl_plugin.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 04ab51538..00debef6a 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -1241,7 +1241,7 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) { else { result = m().mk_eq(a, m_util.str.mk_concat(seq)); } - return BR_REWRITE_FULL; + return BR_REWRITE3; } if (!is_sequence(a, seq)) { @@ -1569,7 +1569,7 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) { return BR_FAILED; } for (unsigned i = 0; i < lhs.size(); ++i) { - res.push_back(m().mk_eq(lhs[i].get(), rhs[i].get())); + res.push_back(m().mk_eq(lhs.get(i), rhs.get(i))); } result = mk_and(res); return BR_REWRITE3; diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 4bcc664a4..98c79abe8 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -988,7 +988,7 @@ void seq_util::str::get_concat_units(expr* e, expr_ref_vector& es) const { } app* seq_util::str::mk_is_empty(expr* s) const { - return m.mk_eq(mk_empty(get_sort(s)), s); + return m.mk_eq(s, mk_empty(get_sort(s))); } From f591e0948aea9c49f470ef1bca5bb40d7f854b99 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Nov 2018 15:28:33 -0800 Subject: [PATCH 213/227] fix #1841 Signed-off-by: Nikolaj Bjorner --- examples/python/rc2.py | 5 +- src/ast/arith_decl_plugin.h | 5 + src/ast/rewriter/seq_rewriter.cpp | 43 +++- src/ast/rewriter/seq_rewriter.h | 2 + src/ast/seq_decl_plugin.cpp | 15 ++ src/ast/seq_decl_plugin.h | 7 + src/smt/theory_seq.cpp | 330 ++++++++++++------------------ src/smt/theory_seq.h | 12 +- 8 files changed, 209 insertions(+), 210 deletions(-) diff --git a/examples/python/rc2.py b/examples/python/rc2.py index 5ccbbaca8..10bd83469 100644 --- a/examples/python/rc2.py +++ b/examples/python/rc2.py @@ -42,7 +42,7 @@ class RC2: return name def print_cost(self): - print("max cost", self.max_cost, "min cost", self.min_cost) + print("cost [", self.min_cost, ":", self.max_cost, "]") def update_max_cost(self): self.max_cost = min(self.max_cost, self.get_cost()) @@ -142,5 +142,8 @@ def main(file): print(cost) print(s.statistics()) +if len(sys.argv) > 1: + main(sys.argv[1]) + # main() diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index aea8863af..00c7e694f 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -231,6 +231,11 @@ public: bool is_arith_expr(expr const * n) const { return is_app(n) && to_app(n)->get_family_id() == m_afid; } bool is_irrational_algebraic_numeral(expr const * n) const; + bool is_unsigned(expr const * n, unsigned& u) const { + rational val; + bool is_int = true; + return is_numeral(n, val, is_int) && is_int && val.is_unsigned(), u = val.get_unsigned(), true; + } bool is_numeral(expr const * n, rational & val, bool & is_int) const; bool is_numeral(expr const * n, rational & val) const { bool is_int; return is_numeral(n, val, is_int); } bool is_numeral(expr const * n) const { return is_app_of(n, m_afid, OP_NUM); } diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 00debef6a..abcf2d205 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -738,7 +738,6 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { return BR_REWRITE2; } - std::function is_unit = [&](expr *e) { return m_util.str.is_unit(e); }; if (bs.forall(is_unit) && as.forall(is_unit)) { @@ -754,6 +753,16 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { return BR_REWRITE_FULL; } + if (bs.size() == 1 && bs.forall(is_unit) && as.size() > 1) { + expr_ref_vector ors(m()); + for (expr* ai : as) { + ors.push_back(m_util.str.mk_contains(ai, bs.get(0))); + } + result = ::mk_or(ors); + return BR_REWRITE_FULL; + } + + return BR_FAILED; } @@ -1575,6 +1584,34 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) { return BR_REWRITE3; } +/** + * t = (concat (unit (nth t 0)) (unit (nth t 1)) (unit (nth t 2)) .. (unit (nth t k-1))) + * -> + * (length t) = k + */ +bool seq_rewriter::reduce_nth_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs) { + if (ls.size() == 1 && !rs.empty()) { + expr* l = ls.get(0); + for (unsigned i = 0; i < rs.size(); ++i) { + unsigned k = 0; + expr* ru = nullptr, *r = nullptr; + if (m_util.str.is_unit(rs.get(i), ru) && m_util.str.is_nth(ru, r, k) && k == i && r == l) { + continue; + } + return false; + } + arith_util a(m()); + lhs.push_back(m_util.str.mk_length(l)); + rhs.push_back(a.mk_int(rs.size())); + ls.reset(); + rs.reset(); + return true; + } + else if (rs.size() == 1 && !ls.empty()) { + return reduce_nth_eq(rs, ls, rhs, lhs); + } + return false; +} bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs, bool& change) { expr* a, *b; @@ -1582,6 +1619,10 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_ bool lchange = false; SASSERT(lhs.empty()); TRACE("seq", tout << ls << "\n"; tout << rs << "\n";); + if (reduce_nth_eq(ls, rs, lhs, rhs)) { + change = true; + return true; + } // solve from back while (true) { while (!rs.empty() && m_util.str.is_empty(rs.back())) { diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index f5878b2c2..e6f280033 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -170,6 +170,8 @@ public: bool reduce_contains(expr* a, expr* b, expr_ref_vector& disj); + bool reduce_nth_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs); + void add_seqs(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_vector& lhs, expr_ref_vector& rhs); diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 98c79abe8..85f5c1b1c 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -537,6 +537,7 @@ void seq_decl_plugin::init() { m_sigs[OP_SEQ_REPLACE] = alloc(psig, m, "seq.replace", 1, 3, seq3A, seqA); m_sigs[OP_SEQ_INDEX] = alloc(psig, m, "seq.indexof", 1, 3, seq2AintT, intT); m_sigs[OP_SEQ_AT] = alloc(psig, m, "seq.at", 1, 2, seqAintT, seqA); + m_sigs[OP_SEQ_NTH] = alloc(psig, m, "seq.nth", 1, 2, seqAintT, A); m_sigs[OP_SEQ_LENGTH] = alloc(psig, m, "seq.len", 1, 1, &seqA, intT); m_sigs[OP_RE_PLUS] = alloc(psig, m, "re.+", 1, 1, &reA, reA); m_sigs[OP_RE_STAR] = alloc(psig, m, "re.*", 1, 1, &reA, reA); @@ -805,6 +806,10 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case _OP_STRING_CHARAT: return mk_str_fun(k, arity, domain, range, OP_SEQ_AT); + case OP_SEQ_NTH: + match(*m_sigs[k], arity, domain, range, rng); + return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k)); + case OP_SEQ_EXTRACT: return mk_seq_fun(k, arity, domain, range, _OP_STRING_SUBSTR); case _OP_STRING_SUBSTR: @@ -957,6 +962,16 @@ bool seq_util::str::is_string(expr const* n, zstring& s) const { } } +bool seq_util::str::is_nth(expr const* n, expr*& s, unsigned& idx) const { + expr* i = nullptr; + if (!is_nth(n, s, i)) return false; + return arith_util(m).is_unsigned(i, idx); +} + +app* seq_util::str::mk_nth(expr* s, unsigned i) const { + return mk_nth(s, arith_util(m).mk_int(i)); +} + void seq_util::str::get_concat(expr* e, expr_ref_vector& es) const { expr* e1, *e2; diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 52a764dde..b4f38fc46 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -41,6 +41,7 @@ enum seq_op_kind { OP_SEQ_EXTRACT, OP_SEQ_REPLACE, OP_SEQ_AT, + OP_SEQ_NTH, OP_SEQ_LENGTH, OP_SEQ_INDEX, OP_SEQ_TO_RE, @@ -243,6 +244,9 @@ public: expr* mk_concat(unsigned n, expr* const* es) const { if (n == 1) return es[0]; SASSERT(n > 1); return m.mk_app(m_fid, OP_SEQ_CONCAT, n, es); } expr* mk_concat(expr_ref_vector const& es) const { return mk_concat(es.size(), es.c_ptr()); } app* mk_length(expr* a) const { return m.mk_app(m_fid, OP_SEQ_LENGTH, 1, &a); } + app* mk_nth(expr* s, expr* i) const { expr* es[2] = { s, i }; return m.mk_app(m_fid, OP_SEQ_NTH, 2, es); } + app* mk_nth(expr* s, unsigned i) const; + app* mk_substr(expr* a, expr* b, expr* c) const { expr* es[3] = { a, b, c }; return m.mk_app(m_fid, OP_SEQ_EXTRACT, 3, es); } app* mk_contains(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONTAINS, 2, es); } app* mk_prefix(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_PREFIX, 2, es); } @@ -270,6 +274,8 @@ public: bool is_extract(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_EXTRACT); } bool is_contains(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_CONTAINS); } bool is_at(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_AT); } + bool is_nth(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_NTH); } + bool is_nth(expr const* n, expr*& s, unsigned& idx) const; bool is_index(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_INDEX); } bool is_replace(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_REPLACE); } bool is_prefix(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_PREFIX); } @@ -294,6 +300,7 @@ public: MATCH_TERNARY(is_extract); MATCH_BINARY(is_contains); MATCH_BINARY(is_at); + MATCH_BINARY(is_nth); MATCH_BINARY(is_index); MATCH_TERNARY(is_index); MATCH_TERNARY(is_replace); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index ccebe0358..3ea9ca368 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -389,11 +389,11 @@ bool theory_seq::branch_binary_variable(eq const& e) { return true; } if (!get_length(x, lenX)) { - enforce_length(ensure_enode(x)); + enforce_length(x); return true; } if (!get_length(y, lenY)) { - enforce_length(ensure_enode(y)); + enforce_length(y); return true; } if (lenX + rational(xs.size()) != lenY + rational(ys.size())) { @@ -469,7 +469,7 @@ void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector rational lenX; if (!get_length(X, lenX)) { TRACE("seq", tout << "enforce length on " << mk_pp(X, m) << "\n";); - enforce_length(ensure_enode(X)); + enforce_length(X); return; } if (lenX > rational(units.size())) { @@ -642,13 +642,13 @@ bool theory_seq::branch_ternary_variable(eq const& e, bool flag1) { rational lenX, lenY1, lenY2; context& ctx = get_context(); if (!get_length(x, lenX)) { - enforce_length(ensure_enode(x)); + enforce_length(x); } if (!get_length(y1, lenY1)) { - enforce_length(ensure_enode(y1)); + enforce_length(y1); } if (!get_length(y2, lenY2)) { - enforce_length(ensure_enode(y2)); + enforce_length(y2); } SASSERT(!xs.empty() && !ys.empty()); @@ -758,13 +758,13 @@ bool theory_seq::branch_ternary_variable2(eq const& e, bool flag1) { rational lenX, lenY1, lenY2; context& ctx = get_context(); if (!get_length(x, lenX)) { - enforce_length(ensure_enode(x)); + enforce_length(x); } if (!get_length(y1, lenY1)) { - enforce_length(ensure_enode(y1)); + enforce_length(y1); } if (!get_length(y2, lenY2)) { - enforce_length(ensure_enode(y2)); + enforce_length(y2); } SASSERT(!xs.empty() && !ys.empty()); unsigned_vector indexes = overlap2(xs, ys); @@ -832,16 +832,16 @@ bool theory_seq::branch_quat_variable(eq const& e) { rational lenX1, lenX2, lenY1, lenY2; context& ctx = get_context(); if (!get_length(x1_l, lenX1)) { - enforce_length(ensure_enode(x1_l)); + enforce_length(x1_l); } if (!get_length(y1_l, lenY1)) { - enforce_length(ensure_enode(y1_l)); + enforce_length(y1_l); } if (!get_length(x2, lenX2)) { - enforce_length(ensure_enode(x2)); + enforce_length(x2); } if (!get_length(y2, lenY2)) { - enforce_length(ensure_enode(y2)); + enforce_length(y2); } SASSERT(!xs.empty() && !ys.empty()); @@ -1304,31 +1304,33 @@ bool theory_seq::len_based_split(eq const& e) { y12 = mk_concat(Z, y12); } } - else { - lenY11 = m_util.str.mk_length(y11); - } + else { + lenY11 = m_util.str.mk_length(y11); + } dependency* dep = e.dep(); literal_vector lits; literal lit1 = mk_eq(lenX11, lenY11, false); - if (ctx.get_assignment(lit1) != l_true) { - return false; - } + if (ctx.get_assignment(lit1) != l_true) { + return false; + } lits.push_back(lit1); if (ls.size() >= 2 && rs.size() >= 2 && (ls.size() > 2 || rs.size() > 2)) { expr_ref len1(m_autil.mk_int(0),m), len2(m_autil.mk_int(0),m); - for (unsigned i = 2; i < ls.size(); ++i) + for (unsigned i = 2; i < ls.size(); ++i) { len1 = mk_add(len1, m_util.str.mk_length(ls[i])); - for (unsigned i = 2; i < rs.size(); ++i) + } + for (unsigned i = 2; i < rs.size(); ++i) { len2 = mk_add(len2, m_util.str.mk_length(rs[i])); - literal lit2; + } + literal lit2; if (!m_autil.is_numeral(len1) && !m_autil.is_numeral(len2)) { lit2 = mk_eq(len1, len2, false); } else { expr_ref eq_len(m.mk_eq(len1, len2), m); - lit2 = mk_literal(eq_len); + lit2 = mk_literal(eq_len); } if (ctx.get_assignment(lit2) == l_true) { @@ -1530,7 +1532,7 @@ bool theory_seq::enforce_length(expr_ref_vector const& es, vector & le len.push_back(val); } else { - enforce_length(ensure_enode(e)); + enforce_length(e); all_have_length = false; } } @@ -1553,10 +1555,10 @@ bool theory_seq::branch_variable() { #if 0 if (!has_length(e.ls())) { - enforce_length(ensure_enode(e.ls())); + enforce_length(e.ls()); } if (!has_length(e.rs())) { - enforce_length(ensure_enode(e.rs())); + enforce_length(e.rs()); } #endif } @@ -1926,7 +1928,8 @@ bool theory_seq::is_unit_nth(expr* e) const { } bool theory_seq::is_nth(expr* e) const { - return is_skolem(m_nth, e); + return m_util.str.is_nth(e); +// return is_skolem(m_nth, e); } bool theory_seq::is_nth(expr* e, expr*& e1, expr*& e2) const { @@ -1964,9 +1967,7 @@ bool theory_seq::is_post(expr* e, expr*& s, expr*& i) { expr_ref theory_seq::mk_nth(expr* s, expr* idx) { - sort* char_sort = nullptr; - VERIFY(m_util.is_seq(m.get_sort(s), char_sort)); - return mk_skolem(m_nth, s, idx, nullptr, nullptr, char_sort); + return expr_ref(m_util.str.mk_nth(s, idx), m); } expr_ref theory_seq::mk_sk_ite(expr* c, expr* t, expr* e) { @@ -2166,9 +2167,8 @@ void theory_seq::propagate_lit(dependency* dep, unsigned n, literal const* _lits if (!linearize(dep, eqs, lits)) return; TRACE("seq", - tout << "assert:"; - ctx.display_detailed_literal(tout, lit); - tout << " <- "; ctx.display_literals_verbose(tout, lits); + ctx.display_detailed_literal(tout << "assert:", lit); + ctx.display_literals_verbose(tout << " <- ", lits); if (!lits.empty()) tout << "\n"; display_deps(tout, dep);); justification* js = ctx.mk_justification( @@ -2235,10 +2235,10 @@ void theory_seq::enforce_length_coherence(enode* n1, enode* n2) { return; } if (has_length(o1) && !has_length(o2)) { - enforce_length(n2); + enforce_length(o2); } else if (has_length(o2) && !has_length(o1)) { - enforce_length(n1); + enforce_length(o1); } } @@ -3059,41 +3059,73 @@ bool theory_seq::solve_ne(unsigned idx) { bool theory_seq::solve_nc(unsigned idx) { nc const& n = m_ncs[idx]; - dependency* deps = n.deps(); + literal len_gt = n.len_gt(); + context& ctx = get_context(); expr_ref c = canonize(n.contains(), deps); + expr* a = nullptr, *b = nullptr; CTRACE("seq", c != n.contains(), tout << n.contains() << " => " << c << "\n";); + if (m.is_true(c)) { literal_vector lits; set_conflict(deps, lits); return true; } + if (m.is_false(c)) { return true; } - if (c != n.contains()) { - m_ncs.push_back(nc(c, deps)); - m_new_propagation = true; + + if (ctx.get_assignment(len_gt) == l_true) { + TRACE("seq", tout << len_gt << " is true\n";); return true; } - expr* e1 = nullptr, *e2 = nullptr; - if (m.is_eq(c, e1, e2)) { - literal eq = mk_eq(e1, e2, false); + if (m.is_eq(c, a, b)) { + literal eq = mk_eq(a, b, false); propagate_lit(deps, 0, nullptr, ~eq); return true; } if (m.is_or(c)) { - for (unsigned i = 0; i < to_app(c)->get_num_args(); ++i) { - expr_ref ci(to_app(c)->get_arg(i), m); - m_ncs.push_back(nc(ci, deps)); + for (expr* arg : *to_app(c)) { + expr_ref ci(arg, m); + m_ncs.push_back(nc(ci, len_gt, deps)); } m_new_propagation = true; return true; } + + if (m.is_and(c)) { + enode_pair_vector eqs; + literal_vector lits; + if (!linearize(deps, eqs, lits)) { + return false; + } + for (enode_pair const& p : eqs) { + lits.push_back(~mk_eq(p.first->get_owner(), p.second->get_owner(), false)); + } + for (expr* arg : *to_app(c)) { + if (m.is_eq(arg, a, b)) { + lits.push_back(~mk_eq(a, b, false)); + } + else { + lits.push_back(~mk_literal(arg)); + } + } + TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()) << "\n";); + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + return true; + } + + if (c != n.contains()) { + m_ncs.push_back(nc(c, len_gt, deps)); + m_new_propagation = true; + return true; + } + return false; } @@ -3310,7 +3342,8 @@ void theory_seq::add_length(expr* e) { /* ensure that all elements in equivalence class occur under an application of 'length' */ -void theory_seq::enforce_length(enode* n) { +void theory_seq::enforce_length(expr* e) { + enode* n = ensure_enode(e); enode* n1 = n; do { expr* o = n->get_owner(); @@ -3377,12 +3410,10 @@ bool theory_seq::add_stoi_val_axiom(expr* e) { if (!val.is_minus_one()) { app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m); expr_ref n1(arith_util(m).mk_numeral(val, true), m); - literal eq1 = mk_eq(e, n1, false); - literal eq2 = mk_eq(n, e1, false); + literal eq1 = mk_preferred_eq(e, n1); + literal eq2 = mk_preferred_eq(n, e1); add_axiom(~eq1, eq2); add_axiom(~eq2, eq1); - ctx.force_phase(eq1); - ctx.force_phase(eq2); m_trail_stack.push(insert_map(m_stoi_axioms, val)); m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); return true; @@ -3411,7 +3442,7 @@ bool theory_seq::add_stoi_val_axiom(expr* e) { } num = m_autil.mk_add(nums.size(), nums.c_ptr()); ctx.get_rewriter()(num); - lits.push_back(mk_eq(e, num, false)); + lits.push_back(mk_preferred_eq(e, num)); ++m_stats.m_add_axiom; m_new_propagation = true; for (literal lit : lits) { @@ -3439,9 +3470,16 @@ literal theory_seq::is_digit(expr* ch) { add_axiom(~lo, ~hi, isd); add_axiom(~isd, lo); add_axiom(~isd, hi); +#if 1 for (unsigned i = 0; i < 10; ++i) { - add_axiom(~mk_eq(ch, bv.mk_numeral(rational('0'+i), bv.mk_sort(8)), false), mk_eq(d2i, m_autil.mk_int(i), false)); + expr_ref cnst(bv.mk_numeral(rational('0'+i), bv.mk_sort(8)), m); + add_axiom(mk_eq(digit2int(cnst), m_autil.mk_int(i), false)); } +#else + for (unsigned i = 0; i < 10; ++i) { + add_axiom(~mk_eq(ch, bv.mk_numeral(rational('0'+i), bv.mk_sort(8)), false), mk_preferred_eq(d2i, m_autil.mk_int(i))); + } +#endif return isd; } @@ -3450,6 +3488,7 @@ expr_ref theory_seq::digit2int(expr* ch) { } void theory_seq::add_itos_axiom(expr* e) { + context& ctx = get_context(); rational val; expr* n = nullptr; TRACE("seq", tout << mk_pp(e, m) << "\n";); @@ -3467,7 +3506,7 @@ void theory_seq::add_itos_axiom(expr* e) { // n >= 0 => stoi(itos(n)) = n app_ref stoi(m_util.str.mk_stoi(e), m); - add_axiom(~ge0, mk_eq(stoi, n, false)); + add_axiom(~ge0, mk_preferred_eq(stoi, n)); // n >= 0 => itos(n) in (0-9)+ expr_ref num_re(m); @@ -3556,8 +3595,8 @@ void theory_seq::display(std::ostream & out) const { if (!m_ncs.empty()) { out << "Non contains:\n"; - for (unsigned i = 0; i < m_ncs.size(); ++i) { - display_nc(out, m_ncs[i]); + for (auto const& nc : m_ncs) { + display_nc(out, nc); } } @@ -3607,15 +3646,14 @@ void theory_seq::display_deps(std::ostream& out, literal_vector const& lits, eno context& ctx = get_context(); smt2_pp_environment_dbg env(m); params_ref p; - for (unsigned i = 0; i < eqs.size(); ++i) { + for (auto const& eq : eqs) { out << " (= "; - ast_smt2_pp(out, eqs[i].first->get_owner(), env, p, 5); + ast_smt2_pp(out, eq.first->get_owner(), env, p, 5); out << "\n "; - ast_smt2_pp(out, eqs[i].second->get_owner(), env, p, 5); + ast_smt2_pp(out, eq.second->get_owner(), env, p, 5); out << ")\n"; } - for (unsigned i = 0; i < lits.size(); ++i) { - literal l = lits[i]; + for (literal l : lits) { if (l == true_literal) { out << " true"; } @@ -3724,9 +3762,9 @@ public: } void add_buffer(svector& sbuffer, zstring const& zs) { - for (unsigned l = 0; l < zs.length(); ++l) { - sbuffer.push_back(zs[l]); - } + for (unsigned i = 0; i < zs.length(); ++i) { + sbuffer.push_back(zs[i]); + } } app * mk_value(model_generator & mg, ptr_vector & values) override { @@ -3922,9 +3960,9 @@ bool theory_seq::canonize(expr* e, expr_ref_vector& es, dependency*& eqs) { bool theory_seq::canonize(expr_ref_vector const& es, expr_ref_vector& result, dependency*& eqs) { bool change = false; - for (unsigned i = 0; i < es.size(); ++i) { - change = canonize(es[i], result, eqs) || change; - SASSERT(!m_util.str.is_concat(es[i]) || change); + for (expr* e : es) { + change = canonize(e, result, eqs) || change; + SASSERT(!m_util.str.is_concat(e) || change); } return change; } @@ -4075,9 +4113,12 @@ expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) { deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(n1, n2))); } else { - TRACE("seq", tout << "add axiom\n";); - add_axiom(~mk_eq(num, e1, false), mk_eq(e, res, false)); - add_axiom(mk_eq(num, e1, false), ~mk_eq(e, res, false)); + TRACE("seq", tout << "mk equalities\n";); + literal l1 = mk_preferred_eq(num, e1); + literal l2 = mk_preferred_eq(e, res); + TRACE("seq", tout << "add axiom " << l1 << " " << l2 << "\n";); + add_axiom(l1, ~l2); + add_axiom(~l1, l2); result = e; } #else @@ -4148,8 +4189,7 @@ void theory_seq::deque_axiom(expr* n) { add_length_axiom(n); } else if (m_util.str.is_empty(n) && !has_length(n) && !m_length.empty()) { - ensure_enode(n); - enforce_length(get_context().get_enode(n)); + enforce_length(n); } else if (m_util.str.is_index(n)) { add_indexof_axiom(n); @@ -4931,12 +4971,19 @@ literal theory_seq::mk_literal(expr* _e) { return ctx.get_literal(e); } - literal theory_seq::mk_seq_eq(expr* a, expr* b) { SASSERT(m_util.is_seq(a)); return mk_literal(mk_skolem(m_eq, a, b, nullptr, nullptr, m.mk_bool_sort())); } +literal theory_seq::mk_preferred_eq(expr* a, expr* b) { + context& ctx = get_context(); + ctx.assume_eq(ensure_enode(a), ensure_enode(b)); + literal lit = mk_eq(a, b, false); + ctx.force_phase(lit); + return lit; +} + literal theory_seq::mk_eq_empty(expr* _e, bool phase) { context& ctx = get_context(); expr_ref e(_e, m); @@ -5042,8 +5089,8 @@ expr_ref theory_seq::mk_skolem(symbol const& name, expr* e1, expr* e2, expr* e3, } if (name == m_seq_align) { for (unsigned i = 0; i < len; ++i) { - es[i] = coalesce_chars(es[i]); - TRACE("seq", tout << mk_pp(es[i], m) << "\n";); + es[i] = coalesce_chars(es[i]); + TRACE("seq", tout << mk_pp(es[i], m) << "\n";); } } return expr_ref(m_util.mk_skolem(name, len, es, range), m); @@ -5135,24 +5182,7 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { propagate_eq(lit, f, e2, true); } else { -#if 1 propagate_not_suffix(e); - -#else - // lit => e1 != empty - propagate_non_empty(lit, e1); - - // lit => e1 = first ++ (unit last) - expr_ref f1 = mk_first(e1); - expr_ref f2 = mk_last(e1); - f = mk_concat(f1, m_util.str.mk_unit(f2)); - propagate_eq(lit, e1, f, true); - - TRACE("seq", tout << "suffix: " << f << " = " << mk_pp(e1, m) << "\n";); - if (add_suffix2suffix(e, change)) { - add_atom(e); - } -#endif } } else if (m_util.str.is_contains(e, e1, e2)) { @@ -5179,15 +5209,11 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { } else if (!canonizes(false, e)) { propagate_non_empty(lit, e2); -#if 1 dependency* dep = m_dm.mk_leaf(assumption(lit)); - m_ncs.push_back(nc(expr_ref(e, m), dep)); -#else - propagate_lit(0, 1, &lit, ~mk_literal(m_util.str.mk_prefix(e2, e1))); - if (add_contains2contains(e, change)) { - add_atom(e); - } -#endif + literal len_gt = mk_simplified_literal(m_autil.mk_le(m_autil.mk_sub(m_util.str.mk_length(e1), m_util.str.mk_length(e2)), + m_autil.mk_int(-1))); + ctx.force_phase(len_gt); + m_ncs.push_back(nc(expr_ref(e, m), len_gt, dep)); } } else if (is_accept(e)) { @@ -5350,7 +5376,7 @@ void theory_seq::relevant_eh(app* n) { expr* arg; if (m_util.str.is_length(n, arg) && !has_length(arg) && get_context().e_internalized(arg)) { - enforce_length(get_context().get_enode(arg)); + enforce_length(arg); } } @@ -5814,69 +5840,6 @@ bool theory_seq::add_prefix2prefix(expr* e, bool& change) { return false; } -/* - !suffix(e1, e2) -> e2 = emp \/ last(e1) != last(e2) \/ !suffix(first(e1), first(e2)) - */ -bool theory_seq::add_suffix2suffix(expr* e, bool& change) { - context& ctx = get_context(); - expr* e1 = nullptr, *e2 = nullptr; - VERIFY(m_util.str.is_suffix(e, e1, e2)); - SASSERT(ctx.get_assignment(e) == l_false); - if (canonizes(false, e)) { - return false; - } - - literal e2_is_emp = mk_eq_empty(e2); - switch (ctx.get_assignment(e2_is_emp)) { - case l_true: - return false; // done - case l_undef: - ctx.force_phase(e2_is_emp); - return true; // retry - case l_false: - break; - } - expr_ref first2 = mk_first(e2); - expr_ref last2 = mk_last(e2); - expr_ref conc2 = mk_concat(first2, m_util.str.mk_unit(last2)); - propagate_eq(~e2_is_emp, e2, conc2, true); - - literal e1_is_emp = mk_eq_empty(e1); - switch (ctx.get_assignment(e1_is_emp)) { - case l_true: - return false; // done - case l_undef: - ctx.force_phase(e1_is_emp); - return true; // retry - case l_false: - break; - } - expr_ref first1 = mk_first(e1); - expr_ref last1 = mk_last(e1); - expr_ref conc1 = mk_concat(first1, m_util.str.mk_unit(last1)); - propagate_eq(~e1_is_emp, e1, conc1, true); - - - literal last_eq = mk_eq(last1, last2, false); - switch (ctx.get_assignment(last_eq)) { - case l_false: - return false; // done - case l_undef: - ctx.force_phase(~last_eq); - return true; - case l_true: - break; - } - - change = true; - literal_vector lits; - lits.push_back(~ctx.get_literal(e)); - lits.push_back(~e2_is_emp); - lits.push_back(last_eq); - propagate_lit(nullptr, lits.size(), lits.c_ptr(), ~mk_literal(m_util.str.mk_suffix(first1, first2))); - TRACE("seq", tout << mk_pp(e, m) << " saturate\n";); - return false; -} bool theory_seq::canonizes(bool sign, expr* e) { context& ctx = get_context(); @@ -5898,41 +5861,6 @@ bool theory_seq::canonizes(bool sign, expr* e) { return false; } -/* - !contains(e1, e2) -> !prefix(e2, e1) - !contains(e1, e2) -> e1 = emp \/ !contains(tail(e1), e2) - */ - -bool theory_seq::add_contains2contains(expr* e, bool& change) { - context& ctx = get_context(); - expr* e1 = nullptr, *e2 = nullptr; - VERIFY(m_util.str.is_contains(e, e1, e2)); - SASSERT(ctx.get_assignment(e) == l_false); - if (canonizes(false, e)) { - return false; - } - - literal e1_is_emp = mk_eq_empty(e1); - switch (ctx.get_assignment(e1_is_emp)) { - case l_true: - return false; // done - case l_undef: - ctx.force_phase(e1_is_emp); - return true; // retry - default: - break; - } - change = true; - expr_ref head(m), tail(m), conc(m); - mk_decompose(e1, head, tail); - - conc = mk_concat(head, tail); - propagate_eq(~e1_is_emp, e1, conc, true); - - literal lits[2] = { ~ctx.get_literal(e), ~e1_is_emp }; - propagate_lit(nullptr, 2, lits, ~mk_literal(m_util.str.mk_contains(tail, e2))); - return false; -} bool theory_seq::propagate_automata() { context& ctx = get_context(); @@ -5958,12 +5886,6 @@ bool theory_seq::propagate_automata() { else if (m_util.str.is_prefix(e)) { reQ = add_prefix2prefix(e, change); } - else if (m_util.str.is_suffix(e)) { - reQ = add_suffix2suffix(e, change); - } - else if (m_util.str.is_contains(e)) { - reQ = add_contains2contains(e, change); - } if (reQ) { re_add.push_back(e); change = true; diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index fbefaede2..4cd2bb2b2 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -196,23 +196,28 @@ namespace smt { class nc { expr_ref m_contains; + literal m_len_gt; dependency* m_dep; public: - nc(expr_ref const& c, dependency* dep): + nc(expr_ref const& c, literal len_gt, dependency* dep): m_contains(c), + m_len_gt(len_gt), m_dep(dep) {} nc(nc const& other): m_contains(other.m_contains), + m_len_gt(other.m_len_gt), m_dep(other.m_dep) {} nc& operator=(nc const& other) { if (this != &other) { m_contains = other.m_contains; m_dep = other.m_dep; + m_len_gt = other.m_len_gt; } return *this; } dependency* deps() const { return m_dep; } expr_ref const& contains() const { return m_contains; } + literal len_gt() const { return m_len_gt; } }; class apply { @@ -530,7 +535,7 @@ namespace smt { bool has_length(expr *e) const { return m_length.contains(e); } void add_length(expr* e); - void enforce_length(enode* n); + void enforce_length(expr* n); bool enforce_length(expr_ref_vector const& es, vector& len); void enforce_length_coherence(enode* n1, enode* n2); @@ -552,6 +557,7 @@ namespace smt { literal mk_simplified_literal(expr* n); literal mk_eq_empty(expr* n, bool phase = true); literal mk_seq_eq(expr* a, expr* b); + literal mk_preferred_eq(expr* a, expr* b); void tightest_prefix(expr* s, expr* x); expr_ref mk_sub(expr* a, expr* b); expr_ref mk_add(expr* a, expr* b); @@ -599,8 +605,6 @@ namespace smt { bool add_accept2step(expr* acc, bool& change); bool add_step2accept(expr* step, bool& change); bool add_prefix2prefix(expr* e, bool& change); - bool add_suffix2suffix(expr* e, bool& change); - bool add_contains2contains(expr* e, bool& change); void propagate_not_prefix(expr* e); void propagate_not_prefix2(expr* e); void propagate_not_suffix(expr* e); From f5455ce2acd9bd2f32a08b05b0db36a84871cc4e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Nov 2018 15:40:08 -0800 Subject: [PATCH 214/227] fix exception handling for #1959 Signed-off-by: Nikolaj Bjorner --- scripts/mk_genfile_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index cc2550e44..c42eaf86d 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -718,7 +718,7 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path): _logger.error("Failed processing ADD_PROBE command at '{}'\n{}".format( fullname, line)) raise e - except e: + except Exception as e: _loggeer.error("Failed to read file {}\n".format(h_file)) raise e # First pass will just generate the tactic factories From 8d940f64b88774877f8cc64a74c09bbedcc7b0fe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Nov 2018 10:57:07 -0800 Subject: [PATCH 215/227] fix build regression Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 33 ------------------------------- src/ast/rewriter/seq_rewriter.h | 2 -- src/smt/theory_seq.cpp | 26 ++++++++++++++++++++++++ src/smt/theory_seq.h | 1 + 4 files changed, 27 insertions(+), 35 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index abcf2d205..b67163f7c 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -1584,45 +1584,12 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) { return BR_REWRITE3; } -/** - * t = (concat (unit (nth t 0)) (unit (nth t 1)) (unit (nth t 2)) .. (unit (nth t k-1))) - * -> - * (length t) = k - */ -bool seq_rewriter::reduce_nth_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs) { - if (ls.size() == 1 && !rs.empty()) { - expr* l = ls.get(0); - for (unsigned i = 0; i < rs.size(); ++i) { - unsigned k = 0; - expr* ru = nullptr, *r = nullptr; - if (m_util.str.is_unit(rs.get(i), ru) && m_util.str.is_nth(ru, r, k) && k == i && r == l) { - continue; - } - return false; - } - arith_util a(m()); - lhs.push_back(m_util.str.mk_length(l)); - rhs.push_back(a.mk_int(rs.size())); - ls.reset(); - rs.reset(); - return true; - } - else if (rs.size() == 1 && !ls.empty()) { - return reduce_nth_eq(rs, ls, rhs, lhs); - } - return false; -} - bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs, bool& change) { expr* a, *b; zstring s; bool lchange = false; SASSERT(lhs.empty()); TRACE("seq", tout << ls << "\n"; tout << rs << "\n";); - if (reduce_nth_eq(ls, rs, lhs, rhs)) { - change = true; - return true; - } // solve from back while (true) { while (!rs.empty() && m_util.str.is_empty(rs.back())) { diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index e6f280033..f5878b2c2 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -170,8 +170,6 @@ public: bool reduce_contains(expr* a, expr* b, expr_ref_vector& disj); - bool reduce_nth_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs); - void add_seqs(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_vector& lhs, expr_ref_vector& rhs); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 3ea9ca368..beaba3947 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2292,6 +2292,26 @@ bool theory_seq::simplify_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependenc return true; } +bool theory_seq::solve_nth_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependency* deps) { + if (ls.size() != 1) return false; + expr_ref l(ls.get(0), m); + for (unsigned i = 0; i < rs.size(); ++i) { + unsigned k = 0; + expr* ru = nullptr, *r = nullptr; + if (m_util.str.is_unit(rs.get(i), ru) && m_util.str.is_nth(ru, r, k) && k == i && r == l) { + continue; + } + return false; + } + add_solution(l, mk_concat(rs, m.get_sort(l)), deps); + expr_ref r(m_autil.mk_int(rs.size()), m); + ls.reset(); + rs.reset(); + ls.push_back(m_util.str.mk_length(l)); + rs.push_back(r); + return true; +} + bool theory_seq::solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* deps) { if (l.size() == 1 && is_var(l[0]) && !occurs(l[0], r) && add_solution(l[0], mk_concat(r, m.get_sort(l[0])), deps)) { return true; @@ -2446,6 +2466,12 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de TRACE("seq", tout << "binary\n";); return true; } + if (!ctx.inconsistent() && solve_nth_eq(ls, rs, deps)) { + change = true; + } + if (!ctx.inconsistent() && solve_nth_eq(rs, ls, deps)) { + change = true; + } if (!ctx.inconsistent() && change) { // The propagation step from arithmetic state (e.g. length offset) to length constraints if (get_context().get_scope_level() == 0) { diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 4cd2bb2b2..4aa90d53b 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -432,6 +432,7 @@ namespace smt { bool simplify_eq(expr_ref_vector& l, expr_ref_vector& r, dependency* dep); bool solve_unit_eq(expr* l, expr* r, dependency* dep); bool solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep); + bool solve_nth_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependency* dep); bool is_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, expr_ref& x, ptr_vector& xunits, ptr_vector& yunits, expr_ref& y); bool is_quat_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x1, expr_ref_vector& xs, expr_ref& x2, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2); bool is_ternary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x, expr_ref_vector& xs, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2, bool flag1); From 801026937d1b3b141b8dfdcfca2182570eec6ebb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Nov 2018 13:49:09 -0800 Subject: [PATCH 216/227] fix #1846 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 43 ++++++++++++++++++++++++++++++------------ src/smt/theory_seq.h | 3 ++- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index beaba3947..4830e56fe 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2292,9 +2292,30 @@ bool theory_seq::simplify_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependenc return true; } -bool theory_seq::solve_nth_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependency* deps) { - if (ls.size() != 1) return false; - expr_ref l(ls.get(0), m); +bool theory_seq::solve_itos(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep) { + expr* e = nullptr; + if (ls.size() == 1 && rs.empty() && m_util.str.is_itos(ls[0], e)) { + literal lit = mk_simplified_literal(m_autil.mk_le(e, m_autil.mk_int(-1))); + propagate_lit(dep, 0, nullptr, lit); + return true; + } + if (rs.size() == 1 && ls.empty() && m_util.str.is_itos(rs[0], e)) { + literal lit = mk_simplified_literal(m_autil.mk_le(e, m_autil.mk_int(-1))); + propagate_lit(dep, 0, nullptr, lit); + return true; + } + return false; +} + +bool theory_seq::solve_nth_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep) { + if (ls.size() != 1 || rs.size() <= 1) { + return false; + } + expr* l = ls.get(0); + rational val; + if (!get_length(l, val) || val != rational(rs.size())) { + return false; + } for (unsigned i = 0; i < rs.size(); ++i) { unsigned k = 0; expr* ru = nullptr, *r = nullptr; @@ -2303,12 +2324,7 @@ bool theory_seq::solve_nth_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependen } return false; } - add_solution(l, mk_concat(rs, m.get_sort(l)), deps); - expr_ref r(m_autil.mk_int(rs.size()), m); - ls.reset(); - rs.reset(); - ls.push_back(m_util.str.mk_length(l)); - rs.push_back(r); + add_solution(l, mk_concat(rs, m.get_sort(l)), dep); return true; } @@ -2467,10 +2483,13 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de return true; } if (!ctx.inconsistent() && solve_nth_eq(ls, rs, deps)) { - change = true; + return true; } if (!ctx.inconsistent() && solve_nth_eq(rs, ls, deps)) { - change = true; + return true; + } + if (!ctx.inconsistent() && solve_itos(rs, ls, deps)) { + return true; } if (!ctx.inconsistent() && change) { // The propagation step from arithmetic state (e.g. length offset) to length constraints @@ -3433,7 +3452,7 @@ bool theory_seq::add_stoi_val_axiom(expr* e) { } if (!m_stoi_axioms.contains(val)) { m_stoi_axioms.insert(val); - if (!val.is_minus_one()) { + if (!val.is_neg()) { app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m); expr_ref n1(arith_util(m).mk_numeral(val, true), m); literal eq1 = mk_preferred_eq(e, n1); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 4aa90d53b..ac3c4052b 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -432,7 +432,8 @@ namespace smt { bool simplify_eq(expr_ref_vector& l, expr_ref_vector& r, dependency* dep); bool solve_unit_eq(expr* l, expr* r, dependency* dep); bool solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep); - bool solve_nth_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependency* dep); + bool solve_nth_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep); + bool solve_itos(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep); bool is_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, expr_ref& x, ptr_vector& xunits, ptr_vector& yunits, expr_ref& y); bool is_quat_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x1, expr_ref_vector& xs, expr_ref& x2, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2); bool is_ternary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x, expr_ref_vector& xs, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2, bool flag1); From 88fb826a0301ad19edbc44a87b7f0d00c3e581d9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Nov 2018 18:50:20 -0800 Subject: [PATCH 217/227] overhaul stoi and itos to fix #1957 and related Signed-off-by: Nikolaj Bjorner --- src/math/automata/automaton.h | 14 ++- src/smt/theory_seq.cpp | 187 +++++++++++++++++----------------- src/smt/theory_seq.h | 2 + 3 files changed, 106 insertions(+), 97 deletions(-) diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index de72d6b2d..d642d2379 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -428,7 +428,18 @@ public: add(mv); } } + else if (1 == out_degree(src) && (is_final_state(src) || !is_final_state(dst))) { + moves const& mvs = m_delta[dst]; + moves mvs1; + for (move const& mv : mvs) { + mvs1.push_back(move(m, src, mv.dst(), mv.t())); + } + for (move const& mv : mvs1) { + add(mv); + } + } else { + TRACE("seq", tout << "epsilon not removed " << out_degree(src) << " " << is_final_state(src) << " " << is_final_state(dst) << "\n";); continue; } remove(src, dst, nullptr); @@ -600,13 +611,14 @@ private: } } +#if 0 void remove_dead_states() { unsigned_vector remap; for (unsigned i = 0; i < m_delta.size(); ++i) { } } - +#endif void add(move const& mv) { if (!is_duplicate_cheap(mv)) { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 4830e56fe..194da2913 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3431,14 +3431,17 @@ void theory_seq::add_stoi_axiom(expr* e) { literal l = mk_simplified_literal(m_autil.mk_ge(e, m_autil.mk_int(-1))); add_axiom(l); - // stoi(s) >= 0 <=> s in (0-9)+ - expr_ref num_re(m); - num_re = m_util.re.mk_range(m_util.str.mk_string(symbol("0")), m_util.str.mk_string(symbol("9"))); - num_re = m_util.re.mk_plus(num_re); - app_ref in_re(m_util.re.mk_in_re(s, num_re), m); - literal ge0 = mk_simplified_literal(m_autil.mk_ge(e, m_autil.mk_int(0))); - add_axiom(~ge0, mk_literal(in_re)); - add_axiom(ge0, ~mk_literal(in_re)); +} + +void theory_seq::ensure_digit_axiom() { + + if (m_stoi_axioms.empty() && m_itos_axioms.empty()) { + bv_util bv(m); + for (unsigned i = 0; i < 10; ++i) { + expr_ref cnst(bv.mk_numeral(rational('0'+i), bv.mk_sort(8)), m); + add_axiom(mk_eq(digit2int(cnst), m_autil.mk_int(i), false)); + } + } } bool theory_seq::add_stoi_val_axiom(expr* e) { @@ -3447,54 +3450,16 @@ bool theory_seq::add_stoi_val_axiom(expr* e) { rational val; TRACE("seq", tout << mk_pp(e, m) << "\n";); VERIFY(m_util.str.is_stoi(e, n)); - if (!get_num_value(e, val)) { + + if (m_util.str.is_itos(n)) { return false; } - if (!m_stoi_axioms.contains(val)) { - m_stoi_axioms.insert(val); - if (!val.is_neg()) { - app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m); - expr_ref n1(arith_util(m).mk_numeral(val, true), m); - literal eq1 = mk_preferred_eq(e, n1); - literal eq2 = mk_preferred_eq(n, e1); - add_axiom(~eq1, eq2); - add_axiom(~eq2, eq1); - m_trail_stack.push(insert_map(m_stoi_axioms, val)); - m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); - return true; - } - } - if (upper_bound(n, val) && get_length(n, val) && val.is_pos() && !m_stoi_axioms.contains(val)) { - zstring s; - SASSERT(val.is_unsigned()); - unsigned sz = val.get_unsigned(); - expr_ref len1(m), len2(m), ith_char(m), num(m), coeff(m); - expr_ref_vector nums(m); - len1 = m_util.str.mk_length(n); - len2 = m_autil.mk_int(sz); - literal lit = mk_eq(len1, len2, false); - literal_vector lits; - lits.push_back(~lit); - for (unsigned i = 0; i < sz; ++i) { - ith_char = mk_nth(n, m_autil.mk_int(i)); - lits.push_back(~is_digit(ith_char)); - nums.push_back(digit2int(ith_char)); - } - rational c(1); - for (unsigned i = sz; i-- > 0; c *= rational(10)) { - coeff = m_autil.mk_numeral(c, true); - nums[i] = m_autil.mk_mul(coeff, nums[i].get()); - } - num = m_autil.mk_add(nums.size(), nums.c_ptr()); - ctx.get_rewriter()(num); - lits.push_back(mk_preferred_eq(e, num)); - ++m_stats.m_add_axiom; - m_new_propagation = true; - for (literal lit : lits) { - ctx.mark_as_relevant(lit); - } - TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";); - ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + + enforce_length(n); + + if (get_length(n, val) && val.is_pos() && val.is_unsigned() && !m_stoi_axioms.contains(val)) { + ensure_digit_axiom(); + add_si_axiom(n, e, val.get_unsigned()); m_stoi_axioms.insert(val); m_trail_stack.push(insert_map(m_stoi_axioms, val)); m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); @@ -3515,16 +3480,6 @@ literal theory_seq::is_digit(expr* ch) { add_axiom(~lo, ~hi, isd); add_axiom(~isd, lo); add_axiom(~isd, hi); -#if 1 - for (unsigned i = 0; i < 10; ++i) { - expr_ref cnst(bv.mk_numeral(rational('0'+i), bv.mk_sort(8)), m); - add_axiom(mk_eq(digit2int(cnst), m_autil.mk_int(i), false)); - } -#else - for (unsigned i = 0; i < 10; ++i) { - add_axiom(~mk_eq(ch, bv.mk_numeral(rational('0'+i), bv.mk_sort(8)), false), mk_preferred_eq(d2i, m_autil.mk_int(i))); - } -#endif return isd; } @@ -3553,14 +3508,46 @@ void theory_seq::add_itos_axiom(expr* e) { app_ref stoi(m_util.str.mk_stoi(e), m); add_axiom(~ge0, mk_preferred_eq(stoi, n)); - // n >= 0 => itos(n) in (0-9)+ - expr_ref num_re(m); - num_re = m_util.re.mk_range(m_util.str.mk_string(symbol("0")), m_util.str.mk_string(symbol("9"))); - num_re = m_util.re.mk_plus(num_re); - app_ref in_re(m_util.re.mk_in_re(e, num_re), m); - add_axiom(~ge0, mk_literal(in_re)); } + +// n >= 0 & len(e) = k => is_digit(e_i) for i = 0..k-1 +// n >= 0 & len(e) = k => n = sum 10^i*digit(e_i) +// n < 0 & len(e) = k => \/_i ~is_digit(e_i) for i = 0..k-1 + +void theory_seq::add_si_axiom(expr* e, expr* n, unsigned k) { + context& ctx = get_context(); + zstring s; + expr_ref ith_char(m), num(m), coeff(m); + expr_ref_vector nums(m), chars(m); + literal len_eq_k = mk_preferred_eq(m_util.str.mk_length(e), m_autil.mk_int(k)); + literal ge0 = mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0))); + literal_vector digits; + digits.push_back(~len_eq_k); + digits.push_back(ge0); + for (unsigned i = 0; i < k; ++i) { + ith_char = mk_nth(e, m_autil.mk_int(i)); + literal isd = is_digit(ith_char); + add_axiom(~len_eq_k, ~ge0, isd); + chars.push_back(m_util.str.mk_unit(ith_char)); + nums.push_back(digit2int(ith_char)); + } + ++m_stats.m_add_axiom; + ctx.mk_th_axiom(get_id(), digits.size(), digits.c_ptr()); + rational c(1); + for (unsigned i = k; i-- > 0; c *= rational(10)) { + coeff = m_autil.mk_int(c); + nums[i] = m_autil.mk_mul(coeff, nums.get(i)); + } + num = m_autil.mk_add(nums.size(), nums.c_ptr()); + ctx.get_rewriter()(num); + m_new_propagation = true; + add_axiom(~len_eq_k, ~ge0, mk_preferred_eq(n, num)); + + add_axiom(~len_eq_k, ~ge0, mk_preferred_eq(e, m_util.str.mk_concat(chars))); +} + + bool theory_seq::add_itos_val_axiom(expr* e) { context& ctx = get_context(); rational val; @@ -3569,24 +3556,21 @@ bool theory_seq::add_itos_val_axiom(expr* e) { VERIFY(m_util.str.is_itos(e, n)); bool change = false; - if (get_num_value(n, val) && !val.is_neg() && !m_itos_axioms.contains(val)) { - m_itos_axioms.insert(val); - app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m); - expr_ref n1(arith_util(m).mk_numeral(val, true), m); - - // itos(n) = "25" <=> n = 25 - literal eq1 = mk_eq(n1, n , false); - literal eq2 = mk_eq(e, e1, false); - add_axiom(~eq1, eq2); - add_axiom(~eq2, eq1); - ctx.force_phase(eq1); - ctx.force_phase(eq2); - - m_trail_stack.push(insert_map(m_itos_axioms, val)); - m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); - change = true; + if (m_util.str.is_stoi(n)) { + return false; } - return change; + enforce_length(e); + + if (get_length(e, val) && val.is_pos() && !m_itos_axioms.contains(val) && val.is_unsigned()) { + add_si_axiom(e, n, val.get_unsigned()); + ensure_digit_axiom(); + m_itos_axioms.insert(val); + m_trail_stack.push(insert_map(m_itos_axioms, val)); + m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); + return true; + } + + return false; } void theory_seq::apply_sort_cnstr(enode* n, sort* s) { @@ -5553,8 +5537,6 @@ bool theory_seq::add_accept2step(expr* acc, bool& change) { return false; } SASSERT(m_autil.is_numeral(idx)); - eautomaton::moves mvs; - aut->get_moves_from(src, mvs); expr_ref len(m_util.str.mk_length(e), m); literal_vector lits; @@ -5572,29 +5554,40 @@ bool theory_seq::add_accept2step(expr* acc, bool& change) { break; } } + + eautomaton::moves mvs; + aut->get_moves_from(src, mvs); bool has_undef = false; int start = ctx.get_random_value(); + TRACE("seq", tout << mvs.size() << "\n";); for (unsigned i = 0; i < mvs.size(); ++i) { unsigned j = (i + start) % mvs.size(); eautomaton::move mv = mvs[j]; expr_ref nth = mk_nth(e, idx); expr_ref acc = mv.t()->accept(nth); + TRACE("seq", tout << j << ": " << acc << "\n";); step = mk_step(e, idx, re, src, mv.dst(), acc); - lits.push_back(mk_literal(step)); - switch (ctx.get_assignment(lits.back())) { + literal slit = mk_literal(step); + literal tlit = mk_literal(acc); + add_axiom(~slit, tlit); + lits.push_back(slit); + switch (ctx.get_assignment(slit)) { case l_true: return false; case l_undef: - //ctx.force_phase(lits.back()); - //return true; + ctx.mark_as_relevant(slit); + // ctx.force_phase(slit); + // return true; + // std::cout << mk_pp(step, m) << " is undef\n"; has_undef = true; - break; + break; default: break; } } change = true; if (has_undef && mvs.size() == 1) { + TRACE("seq", tout << "has single move\n";); literal lit = lits.back(); lits.pop_back(); for (unsigned i = 0; i < lits.size(); ++i) { @@ -5604,6 +5597,7 @@ bool theory_seq::add_accept2step(expr* acc, bool& change) { return false; } if (has_undef) { + TRACE("seq", tout << "has undef\n";); return true; } TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";); @@ -5617,14 +5611,15 @@ bool theory_seq::add_accept2step(expr* acc, bool& change) { /** + step(s, idx, re, i, j, t) => t acc(s, idx, re, i) & step(s, idx, re, i, j, t) => acc(s, idx + 1, re, j) */ bool theory_seq::add_step2accept(expr* step, bool& change) { context& ctx = get_context(); SASSERT(ctx.get_assignment(step) == l_true); - expr* re = nullptr, *_acc = nullptr, *s = nullptr, *idx = nullptr, *i = nullptr, *j = nullptr; - VERIFY(is_step(step, s, idx, re, i, j, _acc)); + expr* re = nullptr, *t = nullptr, *s = nullptr, *idx = nullptr, *i = nullptr, *j = nullptr; + VERIFY(is_step(step, s, idx, re, i, j, t)); literal acc1 = mk_accept(s, idx, re, i); switch (ctx.get_assignment(acc1)) { case l_false: diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index ac3c4052b..2c99d8fd1 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -552,6 +552,8 @@ namespace smt { void add_stoi_axiom(expr* n); bool add_stoi_val_axiom(expr* n); bool add_itos_val_axiom(expr* n); + void add_si_axiom(expr* s, expr* i, unsigned sz); + void ensure_digit_axiom(); literal is_digit(expr* ch); expr_ref digit2int(expr* ch); void add_itos_length_axiom(expr* n); From d55af419554ec7c36d1c9cf93d79cc3b6c2479ba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Nov 2018 19:54:34 -0800 Subject: [PATCH 218/227] constrain lengths Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 194da2913..9b79786fd 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3514,13 +3514,15 @@ void theory_seq::add_itos_axiom(expr* e) { // n >= 0 & len(e) = k => is_digit(e_i) for i = 0..k-1 // n >= 0 & len(e) = k => n = sum 10^i*digit(e_i) // n < 0 & len(e) = k => \/_i ~is_digit(e_i) for i = 0..k-1 +// 10^k <= n < 10^{k+1}-1 => len(e) = k void theory_seq::add_si_axiom(expr* e, expr* n, unsigned k) { context& ctx = get_context(); zstring s; expr_ref ith_char(m), num(m), coeff(m); expr_ref_vector nums(m), chars(m); - literal len_eq_k = mk_preferred_eq(m_util.str.mk_length(e), m_autil.mk_int(k)); + expr_ref len(m_util.str.mk_length(e), m); + literal len_eq_k = mk_preferred_eq(len, m_autil.mk_int(k)); literal ge0 = mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0))); literal_vector digits; digits.push_back(~len_eq_k); @@ -3545,6 +3547,21 @@ void theory_seq::add_si_axiom(expr* e, expr* n, unsigned k) { add_axiom(~len_eq_k, ~ge0, mk_preferred_eq(n, num)); add_axiom(~len_eq_k, ~ge0, mk_preferred_eq(e, m_util.str.mk_concat(chars))); + + SASSERT(k > 0); + rational lb = power(rational(10), k - 1); + rational ub = power(rational(10), k) - 1; + arith_util a (m); + literal lbl = mk_literal(a.mk_ge(n, a.mk_int(lb))); + literal ubl = mk_literal(a.mk_le(n, a.mk_int(ub))); + literal ge_k = mk_literal(a.mk_ge(len, a.mk_int(k))); + literal le_k = mk_literal(a.mk_le(len, a.mk_int(k))); + // n >= lb => len(s) >= k + // n >= 0 & len(s) >= k => n >= lb + // 0 <= n <= ub => len(s) <= k + add_axiom(~lbl, ge_k); + add_axiom(~ge0, lbl, ~ge_k); + add_axiom(~ge0, ~ubl, le_k); } @@ -3570,6 +3587,7 @@ bool theory_seq::add_itos_val_axiom(expr* e) { return true; } + return false; } From 20a28af2255641293a7ea8e0974316fd88746c9a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Nov 2018 21:42:48 -0800 Subject: [PATCH 219/227] fix stoi/itos axiom replay Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 80 +++++++++++++++++++++--------------------- src/smt/theory_seq.h | 16 +++++++-- 2 files changed, 54 insertions(+), 42 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 9b79786fd..fb6a95790 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3411,17 +3411,20 @@ void theory_seq::add_int_string(expr* e) { bool theory_seq::check_int_string() { bool change = false; for (expr * e : m_int_string) { - expr* n = nullptr; - if (m_util.str.is_itos(e) && add_itos_val_axiom(e)) { - change = true; - } - else if (m_util.str.is_stoi(e, n) && add_stoi_val_axiom(e)) { + if (check_int_string(e)) { change = true; } } return change; } +bool theory_seq::check_int_string(expr* e) { + return + (m_util.str.is_itos(e) && add_itos_val_axiom(e)) || + (m_util.str.is_stoi(e) && add_stoi_val_axiom(e)); +} + + void theory_seq::add_stoi_axiom(expr* e) { TRACE("seq", tout << mk_pp(e, m) << "\n";); expr* s = nullptr; @@ -3435,7 +3438,7 @@ void theory_seq::add_stoi_axiom(expr* e) { void theory_seq::ensure_digit_axiom() { - if (m_stoi_axioms.empty() && m_itos_axioms.empty()) { + if (m_si_axioms.empty()) { bv_util bv(m); for (unsigned i = 0; i < 10; ++i) { expr_ref cnst(bv.mk_numeral(rational('0'+i), bv.mk_sort(8)), m); @@ -3444,25 +3447,46 @@ void theory_seq::ensure_digit_axiom() { } } +bool theory_seq::add_itos_val_axiom(expr* e) { + context& ctx = get_context(); + rational val; + expr* n = nullptr; + TRACE("seq", tout << mk_pp(e, m) << "\n";); + VERIFY(m_util.str.is_itos(e, n)); + + if (m_util.str.is_stoi(n)) { + return false; + } + enforce_length(e); + + if (get_length(e, val) && val.is_pos() && val.is_unsigned() && !m_si_axioms.contains(e)) { + add_si_axiom(e, n, val.get_unsigned()); + m_si_axioms.insert(e); + m_trail_stack.push(push_replay(alloc(replay_is_axiom, m, e))); + m_trail_stack.push(insert_map, expr*>(m_si_axioms, e)); + return true; + } + + return false; +} + bool theory_seq::add_stoi_val_axiom(expr* e) { context& ctx = get_context(); expr* n = nullptr; rational val; - TRACE("seq", tout << mk_pp(e, m) << "\n";); + TRACE("seq", tout << mk_pp(e, m) << " " << ctx.get_scope_level () << "\n";); VERIFY(m_util.str.is_stoi(e, n)); if (m_util.str.is_itos(n)) { return false; } - enforce_length(n); - if (get_length(n, val) && val.is_pos() && val.is_unsigned() && !m_stoi_axioms.contains(val)) { - ensure_digit_axiom(); + if (get_length(n, val) && val.is_pos() && val.is_unsigned() && !m_si_axioms.contains(e)) { add_si_axiom(n, e, val.get_unsigned()); - m_stoi_axioms.insert(val); - m_trail_stack.push(insert_map(m_stoi_axioms, val)); - m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); + m_si_axioms.insert(e); + m_trail_stack.push(push_replay(alloc(replay_is_axiom, m, e))); + m_trail_stack.push(insert_map, expr*>(m_si_axioms, e)); return true; } @@ -3527,6 +3551,7 @@ void theory_seq::add_si_axiom(expr* e, expr* n, unsigned k) { literal_vector digits; digits.push_back(~len_eq_k); digits.push_back(ge0); + ensure_digit_axiom(); for (unsigned i = 0; i < k; ++i) { ith_char = mk_nth(e, m_autil.mk_int(i)); literal isd = is_digit(ith_char); @@ -3565,31 +3590,6 @@ void theory_seq::add_si_axiom(expr* e, expr* n, unsigned k) { } -bool theory_seq::add_itos_val_axiom(expr* e) { - context& ctx = get_context(); - rational val; - expr* n = nullptr; - TRACE("seq", tout << mk_pp(e, m) << "\n";); - VERIFY(m_util.str.is_itos(e, n)); - bool change = false; - - if (m_util.str.is_stoi(n)) { - return false; - } - enforce_length(e); - - if (get_length(e, val) && val.is_pos() && !m_itos_axioms.contains(val) && val.is_unsigned()) { - add_si_axiom(e, n, val.get_unsigned()); - ensure_digit_axiom(); - m_itos_axioms.insert(val); - m_trail_stack.push(insert_map(m_itos_axioms, val)); - m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); - return true; - } - - - return false; -} void theory_seq::apply_sort_cnstr(enode* n, sort* s) { mk_var(n); @@ -4209,8 +4209,8 @@ void theory_seq::propagate() { ++m_axioms_head; } while (!m_replay.empty() && !ctx.inconsistent()) { - TRACE("seq", tout << "replay at level: " << ctx.get_scope_level() << "\n";); apply* app = m_replay[m_replay.size() - 1]; + TRACE("seq", tout << "replay at level: " << ctx.get_scope_level() << "\n";); (*app)(*this); m_replay.pop_back(); } @@ -4221,6 +4221,7 @@ void theory_seq::propagate() { } void theory_seq::enque_axiom(expr* e) { + TRACE("seq", tout << "enqueue_axiom " << mk_pp(e, m) << " " << m_axiom_set.contains(e) << "\n";); if (!m_axiom_set.contains(e)) { TRACE("seq", tout << "add axiom " << mk_pp(e, m) << "\n";); m_axioms.push_back(e); @@ -5596,7 +5597,6 @@ bool theory_seq::add_accept2step(expr* acc, bool& change) { ctx.mark_as_relevant(slit); // ctx.force_phase(slit); // return true; - // std::cout << mk_pp(step, m) << " is undef\n"; has_undef = true; break; default: diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 2c99d8fd1..2f1767ba7 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -259,6 +259,18 @@ namespace smt { } }; + + class replay_is_axiom : public apply { + expr_ref m_e; + public: + replay_is_axiom(ast_manager& m, expr* e) : m_e(e, m) {} + ~replay_is_axiom() override {} + void operator()(theory_seq& th) override { + th.check_int_string(m_e); + m_e.reset(); + } + }; + class push_replay : public trail { apply* m_apply; public: @@ -321,8 +333,7 @@ namespace smt { unsigned m_axioms_head; // index of first axiom to add. bool m_incomplete; // is the solver (clearly) incomplete for the fragment. expr_ref_vector m_int_string; - rational_set m_itos_axioms; - rational_set m_stoi_axioms; + obj_hashtable m_si_axioms; obj_hashtable m_length; // is length applied scoped_ptr_vector m_replay; // set of actions to replay model_generator* m_mg; @@ -544,6 +555,7 @@ namespace smt { // model-check the functions that convert integers to strings and the other way. void add_int_string(expr* e); bool check_int_string(); + bool check_int_string(expr* e); expr_ref add_elim_string_axiom(expr* n); void add_at_axiom(expr* n); From 069949a5766abcd416c65dd0139e72b57a976e3d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Nov 2018 22:30:13 -0800 Subject: [PATCH 220/227] fix model construction for semantics of itos Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index fb6a95790..965fdd6a5 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3519,9 +3519,8 @@ void theory_seq::add_itos_axiom(expr* e) { VERIFY(m_util.str.is_itos(e, n)); // itos(n) = "" <=> n < 0 - app_ref e1(m_util.str.mk_empty(m.get_sort(e)), m); expr_ref zero(arith_util(m).mk_int(0), m); - literal eq1 = mk_eq(e1, e, false); + literal eq1 = mk_literal(m_util.str.mk_is_empty(e)); literal ge0 = mk_literal(m_autil.mk_ge(n, zero)); // n >= 0 => itos(n) != "" // itos(n) = "" or n >= 0 @@ -3849,8 +3848,13 @@ public: std::ostringstream strm; arith_util arith(th.m); VERIFY(arith.is_numeral(values[j++], val)); - if (val.is_neg()) strm << "-"; - strm << abs(val); + + if (val.is_neg()) { + strm << ""; + } + else { + strm << val; + } zstring zs(strm.str().c_str()); add_buffer(sbuffer, zs); break; From 33eb82c25aefbe107b1ca76c4e2a2b6c883b2264 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Nov 2018 23:36:47 -0800 Subject: [PATCH 221/227] remove prefix2prefix, fix #1566 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 145 ++++------------------------------------- src/smt/theory_seq.h | 2 - 2 files changed, 12 insertions(+), 135 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 965fdd6a5..59f9b4ea7 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -4039,9 +4039,6 @@ expr_ref theory_seq::try_expand(expr* e, dependency*& eqs){ } result = ed.first; } - else if (false && m_util.str.is_string(e)) { - result = add_elim_string_axiom(e); - } else { m_expand_todo.push_back(e); } @@ -4113,13 +4110,6 @@ expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) { } else { literal lit(mk_literal(e1)); -#if 0 - expr_ref sk_ite = mk_sk_ite(e1, e2, e3); - add_axiom(~lit, mk_eq(e2, sk_ite, false)); - add_axiom( lit, mk_eq(e3, sk_ite, false)); - result = sk_ite; - -#else switch (ctx.get_assignment(lit)) { case l_true: deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(lit))); @@ -4132,13 +4122,12 @@ expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) { if (!result) return result; break; case l_undef: - result = e; + result = e; m_reset_cache = true; TRACE("seq", tout << "undef: " << result << "\n"; tout << lit << "@ level: " << ctx.get_scope_level() << "\n";); break; } -#endif } } else if (m_util.str.is_itos(e, e1)) { @@ -5217,14 +5206,7 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { propagate_eq(lit, f, e2, true); } else { -#if 0 - propagate_not_prefix2(e); -#else - propagate_non_empty(lit, e1); - if (add_prefix2prefix(e, change)) { - add_atom(e); - } -#endif + propagate_not_prefix(e); } } else if (m_util.str.is_suffix(e, e1, e2)) { @@ -5745,7 +5727,7 @@ bool theory_seq::add_reject2reject(expr* rej, bool& change) { /* !prefix(e1,e2) => e1 != "" - !prefix(e1,e2) => e2 = "" or e1 = xcy & (e2 = xdz & c != d or x = e2) + !prefix(e1,e2) => len(e1) > len(e2) or e1 = xcy & e2 = xdz & c != d */ void theory_seq::propagate_not_prefix(expr* e) { @@ -5758,8 +5740,7 @@ void theory_seq::propagate_not_prefix(expr* e) { return; } propagate_non_empty(~lit, e1); - expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m); - literal e2_is_emp = mk_seq_eq(e2, emp); + literal e1_gt_e2 = mk_simplified_literal(m_autil.mk_ge(m_autil.mk_sub(m_util.str.mk_length(e1), m_util.str.mk_length(e2)), m_autil.mk_int(1))); sort* char_sort = nullptr; VERIFY(m_util.is_seq(m.get_sort(e1), char_sort)); expr_ref x = mk_skolem(symbol("seq.prefix.x"), e1, e2); @@ -5767,40 +5748,15 @@ void theory_seq::propagate_not_prefix(expr* e) { expr_ref z = mk_skolem(symbol("seq.prefix.z"), e1, e2); expr_ref c = mk_skolem(symbol("seq.prefix.c"), e1, e2, nullptr, nullptr, char_sort); expr_ref d = mk_skolem(symbol("seq.prefix.d"), e1, e2, nullptr, nullptr, char_sort); - add_axiom(lit, e2_is_emp, mk_seq_eq(e1, mk_concat(x, m_util.str.mk_unit(c), y))); - add_axiom(lit, e2_is_emp, mk_seq_eq(e2, mk_concat(x, m_util.str.mk_unit(d), z)), mk_seq_eq(e2, x)); - add_axiom(lit, e2_is_emp, ~mk_eq(c, d, false), mk_seq_eq(e2, x)); + add_axiom(lit, e1_gt_e2, mk_seq_eq(e1, mk_concat(x, m_util.str.mk_unit(c), y))); + add_axiom(lit, e1_gt_e2, mk_seq_eq(e2, mk_concat(x, m_util.str.mk_unit(d), z)), mk_seq_eq(e2, x)); + add_axiom(lit, e1_gt_e2, ~mk_eq(c, d, false)); } -/* - !prefix(e1,e2) => len(e1) > 0 - !prefix(e1,e2) => len(e1) > len(e2) or e2 = pre(e2,len(e1))post(e2,len(e2)-len(e1)) & pre(e2, len(e1)) != e1 -*/ - -void theory_seq::propagate_not_prefix2(expr* e) { - context& ctx = get_context(); - expr* e1 = nullptr, *e2 = nullptr; - VERIFY(m_util.str.is_prefix(e, e1, e2)); - literal lit = ctx.get_literal(e); - SASSERT(ctx.get_assignment(lit) == l_false); - if (canonizes(false, e)) { - return; - } - propagate_non_empty(~lit, e1); - expr_ref len_e1(m_util.str.mk_length(e1), m); - expr_ref len_e2(m_util.str.mk_length(e2), m); - expr_ref len_e2_e1(mk_sub(len_e2, len_e1), m); - expr_ref x = mk_skolem(m_pre, e2, len_e1); - expr_ref y = mk_skolem(m_post, e2, len_e2_e1); - literal e2_ge_e1 = mk_literal(m_autil.mk_ge(len_e2_e1, m_autil.mk_int(0))); - add_axiom(lit, ~e2_ge_e1, mk_seq_eq(e2, mk_concat(x, y))); - add_axiom(lit, ~e2_ge_e1, mk_eq(m_util.str.mk_length(x), len_e1, false)); - add_axiom(lit, ~e2_ge_e1, ~mk_eq(e1, x, false)); -} /* !suffix(e1,e2) => e1 != "" - !suffix(e1,e2) => e2 = "" or e1 = ycx & (e2 = zdx & c != d or x = e2) + !suffix(e1,e2) => len(e1) > len(e2) or e1 = ycx & e2 = zdx & c != d */ @@ -5814,9 +5770,7 @@ void theory_seq::propagate_not_suffix(expr* e) { return; } propagate_non_empty(~lit, e1); - - expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m); - literal e2_is_emp = mk_seq_eq(e2, emp); + literal e1_gt_e2 = mk_simplified_literal(m_autil.mk_ge(m_autil.mk_sub(m_util.str.mk_length(e1), m_util.str.mk_length(e2)), m_autil.mk_int(1))); sort* char_sort = nullptr; VERIFY(m_util.is_seq(m.get_sort(e1), char_sort)); expr_ref x = mk_skolem(symbol("seq.suffix.x"), e1, e2); @@ -5824,84 +5778,12 @@ void theory_seq::propagate_not_suffix(expr* e) { expr_ref z = mk_skolem(symbol("seq.suffix.z"), e1, e2); expr_ref c = mk_skolem(symbol("seq.suffix.c"), e1, e2, nullptr, nullptr, char_sort); expr_ref d = mk_skolem(symbol("seq.suffix.d"), e1, e2, nullptr, nullptr, char_sort); - add_axiom(lit, e2_is_emp, mk_seq_eq(e1, mk_concat(y, m_util.str.mk_unit(c), x))); - add_axiom(lit, e2_is_emp, mk_seq_eq(e2, mk_concat(z, m_util.str.mk_unit(d), x)), mk_seq_eq(e2, x)); - add_axiom(lit, e2_is_emp, ~mk_eq(c, d, false), mk_seq_eq(e2, x)); + add_axiom(lit, e1_gt_e2, mk_seq_eq(e1, mk_concat(y, m_util.str.mk_unit(c), x))); + add_axiom(lit, e1_gt_e2, mk_seq_eq(e2, mk_concat(z, m_util.str.mk_unit(d), x))); + add_axiom(lit, e1_gt_e2, ~mk_eq(c, d, false)); } -/* - !prefix -> e2 = emp \/ nth(e1,0) != nth(e2,0) \/ !prefix(tail(e1),tail(e2)) -*/ -bool theory_seq::add_prefix2prefix(expr* e, bool& change) { - context& ctx = get_context(); - expr* e1 = nullptr, *e2 = nullptr; - VERIFY(m_util.str.is_prefix(e, e1, e2)); - SASSERT(ctx.get_assignment(e) == l_false); - if (canonizes(false, e)) { - TRACE("seq", tout << mk_pp(e, m) << " is false\n";); - return false; - } - expr_ref head1(m), tail1(m), head2(m), tail2(m), conc(m); - - literal e2_is_emp = mk_eq_empty(e2); - switch (ctx.get_assignment(e2_is_emp)) { - case l_true: - TRACE("seq", tout << mk_pp(e, m) << ": " << mk_pp(e2, m) << " = empty\n"; - ctx.display_literal_verbose(tout, e2_is_emp); tout << "\n"; ); - return false; // done - case l_undef: - // ctx.force_phase(e2_is_emp); - TRACE("seq", tout << mk_pp(e, m) << ": " << mk_pp(e2, m) << " ~ empty\n";); - return true; // retry - default: - break; - } - - mk_decompose(e2, head2, tail2); - conc = mk_concat(head2, tail2); - propagate_eq(~e2_is_emp, e2, conc, true); - - literal e1_is_emp = mk_eq_empty(e1, false); - switch (ctx.get_assignment(e1_is_emp)) { - case l_true: - TRACE("seq", tout << mk_pp(e, m) << ": " << mk_pp(e1, m) << " != empty\n";); - add_axiom(ctx.get_literal(e), ~e1_is_emp); - return false; // done - case l_undef: - TRACE("seq", tout << mk_pp(e, m) << ": " << mk_pp(e1, m) << " ~ empty\n";); - return true; // retry - default: - break; - } - - mk_decompose(e1, head1, tail1); - conc = mk_concat(head1, tail1); - propagate_eq(~e1_is_emp, e1, conc, true); - - - literal lit = mk_eq(head1, head2, false); - switch (ctx.get_assignment(lit)) { - case l_true: - break; - case l_false: - TRACE("seq", tout << mk_pp(e, m) << ": " << head1 << " != " << head2 << "\n";); - return false; - case l_undef: - ctx.force_phase(~lit); - TRACE("seq", tout << mk_pp(e, m) << ": " << head1 << " ~ " << head2 << "\n";); - return true; - } - change = true; - literal_vector lits; - lits.push_back(~ctx.get_literal(e)); - lits.push_back(~e2_is_emp); - lits.push_back(lit); - propagate_lit(nullptr, lits.size(), lits.c_ptr(), ~mk_literal(m_util.str.mk_prefix(tail1, tail2))); - TRACE("seq", tout << mk_pp(e, m) << " saturate: " << tail1 << " = " << tail2 << "\n";); - return false; -} - bool theory_seq::canonizes(bool sign, expr* e) { context& ctx = get_context(); @@ -5945,9 +5827,6 @@ bool theory_seq::propagate_automata() { else if (is_step(e)) { reQ = add_step2accept(e, change); } - else if (m_util.str.is_prefix(e)) { - reQ = add_prefix2prefix(e, change); - } if (reQ) { re_add.push_back(e); change = true; diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 2f1767ba7..0452bf560 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -620,9 +620,7 @@ namespace smt { bool add_reject2reject(expr* rej, bool& change); bool add_accept2step(expr* acc, bool& change); bool add_step2accept(expr* step, bool& change); - bool add_prefix2prefix(expr* e, bool& change); void propagate_not_prefix(expr* e); - void propagate_not_prefix2(expr* e); void propagate_not_suffix(expr* e); void ensure_nth(literal lit, expr* s, expr* idx); bool canonizes(bool sign, expr* e); From d61d9d4ce345db25a36126cf20173dfbb044bdda Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Nov 2018 11:06:51 -0800 Subject: [PATCH 222/227] remove reject states Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 313 ++++++++++++++++------------------------- src/smt/theory_seq.h | 22 ++- 2 files changed, 126 insertions(+), 209 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 59f9b4ea7..865af665f 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -224,7 +224,6 @@ theory_seq::theory_seq(ast_manager& m, theory_seq_params const & params): m_prefix = "seq.p.suffix"; m_suffix = "seq.s.prefix"; m_accept = "aut.accept"; - m_reject = "aut.reject"; m_tail = "seq.tail"; m_nth = "seq.nth"; m_seq_first = "seq.first"; @@ -398,7 +397,7 @@ bool theory_seq::branch_binary_variable(eq const& e) { } if (lenX + rational(xs.size()) != lenY + rational(ys.size())) { // |x| - |y| = |ys| - |xs| - expr_ref a(mk_sub(m_util.str.mk_length(x), m_util.str.mk_length(y)), m); + expr_ref a(mk_sub(mk_len(x), mk_len(y)), m); expr_ref b(m_autil.mk_int(ys.size()-xs.size()), m); propagate_lit(e.dep(), 0, nullptr, mk_eq(a, b, false)); return true; @@ -409,7 +408,7 @@ bool theory_seq::branch_binary_variable(eq const& e) { branch_unit_variable(e.dep(), x, Ys); return true; } - expr_ref le(m_autil.mk_le(m_util.str.mk_length(x), m_autil.mk_int(ys.size())), m); + expr_ref le(m_autil.mk_le(mk_len(x), m_autil.mk_int(ys.size())), m); literal lit = mk_literal(le); if (l_false == ctx.get_assignment(lit)) { // |x| > |ys| => x = ys ++ y1, y = y1 ++ y2, y2 = xs @@ -473,7 +472,7 @@ void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector return; } if (lenX > rational(units.size())) { - expr_ref le(m_autil.mk_le(m_util.str.mk_length(X), m_autil.mk_int(units.size())), m); + expr_ref le(m_autil.mk_le(mk_len(X), m_autil.mk_int(units.size())), m); TRACE("seq", tout << "propagate length on " << mk_pp(X, m) << "\n";); propagate_lit(dep, 0, nullptr, mk_literal(le)); return; @@ -485,7 +484,7 @@ void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector set_empty(X); } else { - literal lit = mk_eq(m_autil.mk_int(lX), m_util.str.mk_length(X), false); + literal lit = mk_eq(m_autil.mk_int(lX), mk_len(X), false); if (l_true == ctx.get_assignment(lit)) { expr_ref R(m_util.str.mk_concat(lX, units.c_ptr()), m); propagate_eq(dep, lit, X, R); @@ -591,7 +590,7 @@ bool theory_seq::branch_ternary_variable_base( else { xs2E = m_util.str.mk_empty(m.get_sort(x)); } - literal lit1 = mk_literal(m_autil.mk_le(m_util.str.mk_length(y2), m_autil.mk_int(xs.size()-ind))); + literal lit1 = mk_literal(m_autil.mk_le(mk_len(y2), m_autil.mk_int(xs.size()-ind))); if (ctx.get_assignment(lit1) == l_undef) { TRACE("seq", tout << "base case init\n";); ctx.mark_as_relevant(lit1); @@ -672,7 +671,7 @@ bool theory_seq::branch_ternary_variable(eq const& e, bool flag1) { propagate_eq(dep, lits, y2, ZxsE, true); } else { - expr_ref ge(m_autil.mk_ge(m_util.str.mk_length(y2), m_autil.mk_int(xs.size())), m); + expr_ref ge(m_autil.mk_ge(mk_len(y2), m_autil.mk_int(xs.size())), m); literal lit2 = mk_literal(ge); if (ctx.get_assignment(lit2) == l_undef) { TRACE("seq", tout << "rec case init\n";); @@ -707,7 +706,7 @@ bool theory_seq::branch_ternary_variable_base2(dependency* dep, unsigned_vector else { xs1E = m_util.str.mk_empty(m.get_sort(x)); } - literal lit1 = mk_literal(m_autil.mk_le(m_util.str.mk_length(y1), m_autil.mk_int(ind))); + literal lit1 = mk_literal(m_autil.mk_le(mk_len(y1), m_autil.mk_int(ind))); if (ctx.get_assignment(lit1) == l_undef) { TRACE("seq", tout << "base case init\n";); ctx.mark_as_relevant(lit1); @@ -787,7 +786,7 @@ bool theory_seq::branch_ternary_variable2(eq const& e, bool flag1) { propagate_eq(dep, lits, y1, xsZ, true); } else { - expr_ref ge(m_autil.mk_ge(m_util.str.mk_length(y1), m_autil.mk_int(xs.size())), m); + expr_ref ge(m_autil.mk_ge(mk_len(y1), m_autil.mk_int(xs.size())), m); literal lit2 = mk_literal(ge); if (ctx.get_assignment(lit2) == l_undef) { TRACE("seq", tout << "rec case init\n";); @@ -851,7 +850,7 @@ bool theory_seq::branch_quat_variable(eq const& e) { expr_ref ysy2 = mk_concat(ys); expr_ref x1(x1_l, m); expr_ref y1(y1_l, m); - expr_ref sub(mk_sub(m_util.str.mk_length(x1_l), m_util.str.mk_length(y1_l)), m); + expr_ref sub(mk_sub(mk_len(x1_l), mk_len(y1_l)), m); expr_ref le(m_autil.mk_le(sub, m_autil.mk_int(0)), m); literal lit2 = mk_literal(le); if (ctx.get_assignment(lit2) == l_undef) { @@ -952,7 +951,7 @@ int theory_seq::find_fst_non_empty_idx(expr_ref_vector const& xs) const { for (unsigned i = 0; i < xs.size(); ++i) { expr* x = xs[i]; if (!is_var(x)) return -1; - expr_ref e(m_util.str.mk_length(x), m); + expr_ref e = mk_len(x); if (ctx.e_internalized(e)) { enode* root = ctx.get_enode(e)->get_root(); rational val; @@ -1011,7 +1010,7 @@ void theory_seq::find_max_eq_len(expr_ref_vector const& ls, expr_ref_vector cons else { hi1 = rational(-2); } - len1 = mk_add(len1, m_util.str.mk_length(ls.get(j))); + len1 = mk_add(len1, mk_len(ls.get(j))); j++; } j = 2 + r_fst; @@ -1044,7 +1043,7 @@ void theory_seq::find_max_eq_len(expr_ref_vector const& ls, expr_ref_vector cons else { hi2 = rational(-2); } - len2 = mk_add(len2, m_util.str.mk_length(rs.get(j))); + len2 = mk_add(len2, mk_len(rs.get(j))); j++; } if (m_autil.is_numeral(len1) && m_autil.is_numeral(len2)) @@ -1089,7 +1088,7 @@ bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector cons expr* l_fst = find_fst_non_empty_var(ls); expr* r_fst = find_fst_non_empty_var(rs); if (!r_fst) return false; - expr_ref len_r_fst(m_util.str.mk_length(r_fst), m); + expr_ref len_r_fst = mk_len(r_fst); enode * root2; if (!ctx.e_internalized(len_r_fst)) return false; @@ -1098,7 +1097,7 @@ bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector cons // Offset = 0, No change if (l_fst) { - expr_ref len_l_fst(m_util.str.mk_length(l_fst), m); + expr_ref len_l_fst = mk_len(l_fst); if (ctx.e_internalized(len_l_fst)) { enode * root1 = ctx.get_enode(len_l_fst)->get_root(); if (root1 == root2) { @@ -1124,7 +1123,7 @@ bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector cons if (e.rs().size()>1 && is_var(e.rs().get(0))) nl_fst = e.rs().get(0); if (nl_fst && nl_fst != r_fst) { - expr_ref len_nl_fst(m_util.str.mk_length(nl_fst), m); + expr_ref len_nl_fst = mk_len(nl_fst); if (ctx.e_internalized(len_nl_fst)) { enode * root1 = ctx.get_enode(len_nl_fst)->get_root(); if (root1 == root2) { @@ -1141,7 +1140,7 @@ bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector cons } // Offset != 0, No change if (l_fst) { - expr_ref len_l_fst(m_util.str.mk_length(l_fst), m); + expr_ref len_l_fst = mk_len(l_fst); if (ctx.e_internalized(len_l_fst)) { enode * root1 = ctx.get_enode(len_l_fst)->get_root(); obj_map tmp; @@ -1178,7 +1177,7 @@ bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector cons nl_fst = e.rs().get(0); if (nl_fst && nl_fst != r_fst) { int offset; - expr_ref len_nl_fst(m_util.str.mk_length(nl_fst), m); + expr_ref len_nl_fst = mk_len(nl_fst); if (ctx.e_internalized(len_nl_fst)) { enode * root1 = ctx.get_enode(len_nl_fst)->get_root(); if (!m_autil.is_numeral(root1->get_owner()) && tmp.find(root1, offset)) { @@ -1207,14 +1206,14 @@ bool theory_seq::has_len_offset(expr_ref_vector const& ls, expr_ref_vector const if (!is_var(l_fst) || !is_var(r_fst)) return false; - expr_ref len_r_fst(m_util.str.mk_length(r_fst), m); + expr_ref len_r_fst = mk_len(r_fst); enode * root2; if (!ctx.e_internalized(len_r_fst)) return false; else root2 = ctx.get_enode(len_r_fst)->get_root(); - expr_ref len_l_fst(m_util.str.mk_length(l_fst), m); + expr_ref len_l_fst = mk_len(l_fst); if (ctx.e_internalized(len_l_fst)) { enode * root1 = ctx.get_enode(len_l_fst)->get_root(); if (root1 == root2) { @@ -1285,12 +1284,12 @@ bool theory_seq::len_based_split(eq const& e) { expr_ref y11(m_util.str.mk_concat(1, rs.c_ptr()), m); expr_ref y12(m_util.str.mk_concat(rs.size()-1, rs.c_ptr()+1), m); - expr_ref lenX11(m_util.str.mk_length(x11),m); + expr_ref lenX11 = mk_len(x11); expr_ref lenY11(m); expr_ref Z(m); int offset = 0; if (offset_orig != 0) { - lenY11 = m_autil.mk_add(m_util.str.mk_length(y11), m_autil.mk_int(offset_orig)); + lenY11 = m_autil.mk_add(mk_len(y11), m_autil.mk_int(offset_orig)); if (offset_orig > 0) { offset = offset_orig; Z = mk_skolem(m_seq_align, y12, x12, x11, y11); @@ -1305,7 +1304,7 @@ bool theory_seq::len_based_split(eq const& e) { } } else { - lenY11 = m_util.str.mk_length(y11); + lenY11 = mk_len(y11); } dependency* dep = e.dep(); @@ -1319,10 +1318,10 @@ bool theory_seq::len_based_split(eq const& e) { if (ls.size() >= 2 && rs.size() >= 2 && (ls.size() > 2 || rs.size() > 2)) { expr_ref len1(m_autil.mk_int(0),m), len2(m_autil.mk_int(0),m); for (unsigned i = 2; i < ls.size(); ++i) { - len1 = mk_add(len1, m_util.str.mk_length(ls[i])); + len1 = mk_add(len1, mk_len(ls[i])); } for (unsigned i = 2; i < rs.size(); ++i) { - len2 = mk_add(len2, m_util.str.mk_length(rs[i])); + len2 = mk_add(len2, mk_len(rs[i])); } literal lit2; if (!m_autil.is_numeral(len1) && !m_autil.is_numeral(len2)) { @@ -1351,7 +1350,7 @@ bool theory_seq::len_based_split(eq const& e) { } if (offset != 0) { - expr_ref lenZ(m_util.str.mk_length(Z), m); + expr_ref lenZ = mk_len(Z); propagate_eq(dep, lits, lenZ, m_autil.mk_int(offset), false); } propagate_eq(dep, lits, y11, x11, true); @@ -1383,7 +1382,7 @@ bool theory_seq::branch_variable_mb() { TRACE("seq", tout << "lengths are not compatible\n";); expr_ref l = mk_concat(e.ls()); expr_ref r = mk_concat(e.rs()); - expr_ref lnl(m_util.str.mk_length(l), m), lnr(m_util.str.mk_length(r), m); + expr_ref lnl = mk_len(l), lnr = mk_len(r); propagate_eq(e.dep(), lnl, lnr, false); change = true; continue; @@ -1473,9 +1472,9 @@ bool theory_seq::split_lengths(dependency* dep, // |b| < |X| <= |b| + |Y| => x = bY1, Y = Y1Y2 - expr_ref lenXE(m_util.str.mk_length(X), m); - expr_ref lenYE(m_util.str.mk_length(Y), m); - expr_ref lenb(m_util.str.mk_length(b), m); + expr_ref lenXE = mk_len(X); + expr_ref lenYE = mk_len(Y); + expr_ref lenb = mk_len(b); expr_ref le1(m_autil.mk_le(mk_sub(lenXE, lenb), m_autil.mk_int(0)), m); expr_ref le2(m_autil.mk_le(mk_sub(mk_sub(lenXE, lenb), lenYE), m_autil.mk_int(0)), m); @@ -1509,7 +1508,7 @@ bool theory_seq::split_lengths(dependency* dep, } bool theory_seq::set_empty(expr* x) { - add_axiom(~mk_eq(m_autil.mk_int(0), m_util.str.mk_length(x), false), mk_eq_empty(x)); + add_axiom(~mk_eq(m_autil.mk_int(0), mk_len(x), false), mk_eq_empty(x)); return true; } @@ -1679,10 +1678,8 @@ bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_re TRACE("seq", tout << "start: " << start << "\n"; for (literal lit : lits) { - ctx.display_literal_verbose(tout << lit << ": ", lit); - tout << "\n"; - ctx.display(tout, ctx.get_justification(lit.var())); - tout << "\n"; + ctx.display_literal_verbose(tout << lit << ": ", lit) << "\n"; + ctx.display(tout, ctx.get_justification(lit.var())); tout << "\n"; }); return true; } @@ -1778,16 +1775,16 @@ bool theory_seq::propagate_length_coherence(expr* e) { elems.push_back(seq); tail = mk_concat(elems.size(), elems.c_ptr()); // len(e) >= low => e = tail; - literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)))); + literal low(mk_literal(m_autil.mk_ge(mk_len(e), m_autil.mk_numeral(lo, true)))); add_axiom(~low, mk_seq_eq(e, tail)); if (upper_bound(e, hi)) { // len(e) <= hi => len(tail) <= hi - lo - expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m); + expr_ref high1(m_autil.mk_le(mk_len(e), m_autil.mk_numeral(hi, true)), m); if (hi == lo) { add_axiom(~mk_literal(high1), mk_seq_eq(seq, emp)); } else { - expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); + expr_ref high2(m_autil.mk_le(mk_len(seq), m_autil.mk_numeral(hi-lo, true)), m); add_axiom(~mk_literal(high1), mk_literal(high2)); } } @@ -1859,7 +1856,7 @@ bool theory_seq::fixed_length(bool is_zero) { bool theory_seq::fixed_length(expr* e, bool is_zero) { rational lo, hi; if (!(is_var(e) && lower_bound(e, lo) && upper_bound(e, hi) && lo == hi - && ((is_zero && lo.is_zero()) || (!is_zero && lo.is_unsigned())))) { + && ((is_zero && lo.is_zero()) || (!is_zero && lo.is_unsigned())))) { return false; } if (is_skolem(m_tail, e) || is_skolem(m_seq_first, e) || @@ -1891,7 +1888,7 @@ bool theory_seq::fixed_length(expr* e, bool is_zero) { seq = mk_concat(elems.size(), elems.c_ptr()); } TRACE("seq", tout << "Fixed: " << mk_pp(e, m) << " " << lo << "\n";); - add_axiom(~mk_eq(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true), false), mk_seq_eq(seq, e)); + add_axiom(~mk_eq(mk_len(e), m_autil.mk_numeral(lo, true), false), mk_seq_eq(seq, e)); if (!ctx.at_base_level()) { m_trail_stack.push(push_replay(alloc(replay_fixed_length, m, e))); } @@ -1996,6 +1993,7 @@ expr_ref theory_seq::mk_first(expr* s) { void theory_seq::mk_decompose(expr* e, expr_ref& head, expr_ref& tail) { expr* e1 = nullptr, *e2 = nullptr; zstring s; + rational r; if (m_util.str.is_empty(e)) { head = m_util.str.mk_unit(mk_nth(e, m_autil.mk_int(0))); tail = e; @@ -2012,11 +2010,9 @@ void theory_seq::mk_decompose(expr* e, expr_ref& head, expr_ref& tail) { head = e1; tail = e2; } - else if (is_skolem(m_tail, e)) { - rational r; + else if (is_skolem(m_tail, e) && m_autil.is_numeral(to_app(e)->get_arg(1), r)) { app* a = to_app(e); - expr* s = a->get_arg(0); - VERIFY (m_autil.is_numeral(a->get_arg(1), r)); + expr* s = a->get_arg(0); expr* idx = m_autil.mk_int(r.get_unsigned() + 1); head = m_util.str.mk_unit(mk_nth(s, idx)); tail = mk_skolem(m_tail, s, idx); @@ -2526,7 +2522,7 @@ bool theory_seq::propagate_max_length(expr* l, expr* r, dependency* deps) { } rational hi; if (is_tail(l, s, idx) && has_length(s) && m_util.str.is_empty(r) && !upper_bound(s, hi)) { - propagate_lit(deps, 0, nullptr, mk_literal(m_autil.mk_le(m_util.str.mk_length(s), m_autil.mk_int(idx+1)))); + propagate_lit(deps, 0, nullptr, mk_literal(m_autil.mk_le(mk_len(s), m_autil.mk_int(idx+1)))); return true; } return false; @@ -2770,8 +2766,8 @@ bool theory_seq::reduce_length(unsigned i, unsigned j, bool front, expr_ref_vect SASSERT(0 < r1 && r1 < rs.size()); expr_ref l = mk_concat(l1, ls1); expr_ref r = mk_concat(r1, rs1); - expr_ref lenl(m_util.str.mk_length(l), m); - expr_ref lenr(m_util.str.mk_length(r), m); + expr_ref lenl = mk_len(l); + expr_ref lenr = mk_len(r); literal lit = mk_eq(lenl, lenr, false); if (ctx.get_assignment(lit) == l_true) { // expr_ref len_eq(m.mk_eq(lenl, lenr), m); @@ -2859,7 +2855,7 @@ bool theory_seq::get_length(expr* e, expr_ref& len, literal_vector& lits) { if (m_util.str.is_extract(e, s, i, l)) { // 0 <= i <= len(s), 0 <= l, i + l <= len(s) expr_ref zero(m_autil.mk_int(0), m); - expr_ref ls(m_util.str.mk_length(s), m); + expr_ref ls = mk_len(s); expr_ref ls_minus_i_l(mk_sub(mk_sub(ls, i),l), m); bool i_is_zero = m_autil.is_numeral(i, r) && r.is_zero(); literal i_ge_0 = i_is_zero?true_literal:mk_simplified_literal(m_autil.mk_ge(i, zero)); @@ -2883,7 +2879,7 @@ bool theory_seq::get_length(expr* e, expr_ref& len, literal_vector& lits) { expr_ref zero(m_autil.mk_int(0), m); bool i_is_zero = m_autil.is_numeral(i, r) && r.is_zero(); literal i_ge_0 = i_is_zero?true_literal:mk_simplified_literal(m_autil.mk_ge(i, zero)); - literal i_lt_len_s = ~mk_simplified_literal(m_autil.mk_ge(mk_sub(i, m_util.str.mk_length(s)), zero)); + literal i_lt_len_s = ~mk_simplified_literal(m_autil.mk_ge(mk_sub(i, mk_len(s)), zero)); literal _lits[2] = { i_ge_0, i_lt_len_s}; if (ctx.get_assignment(i_ge_0) == l_true && ctx.get_assignment(i_lt_len_s) == l_true) { @@ -2897,7 +2893,7 @@ bool theory_seq::get_length(expr* e, expr_ref& len, literal_vector& lits) { expr_ref zero(m_autil.mk_int(0), m); bool i_is_zero = m_autil.is_numeral(i, r) && r.is_zero(); literal i_ge_0 = i_is_zero?true_literal:mk_simplified_literal(m_autil.mk_ge(i, zero)); - literal i_lt_len_s = ~mk_simplified_literal(m_autil.mk_ge(mk_sub(i, m_util.str.mk_length(s)), zero)); + literal i_lt_len_s = ~mk_simplified_literal(m_autil.mk_ge(mk_sub(i, mk_len(s)), zero)); literal _lits[2] = { i_ge_0, i_lt_len_s }; if (ctx.get_assignment(i_ge_0) == l_true && ctx.get_assignment(i_lt_len_s) == l_true) { @@ -2910,7 +2906,7 @@ bool theory_seq::get_length(expr* e, expr_ref& len, literal_vector& lits) { else if (is_post(e, s, l)) { expr_ref zero(m_autil.mk_int(0), m); literal l_ge_0 = mk_simplified_literal(m_autil.mk_ge(l, zero)); - literal l_le_len_s = mk_simplified_literal(m_autil.mk_ge(mk_sub(m_util.str.mk_length(s), l), zero)); + literal l_le_len_s = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(s), l), zero)); literal _lits[2] = { l_ge_0, l_le_len_s }; if (ctx.get_assignment(l_ge_0) == l_true && ctx.get_assignment(l_le_len_s) == l_true) { @@ -2920,6 +2916,17 @@ bool theory_seq::get_length(expr* e, expr_ref& len, literal_vector& lits) { } TRACE("seq", ctx.display_literals_verbose(tout, 2, _lits); tout << "\n";); } + else if (is_skolem(m_tail, e)) { + s = to_app(e)->get_arg(0); + l = to_app(e)->get_arg(1); + expr_ref len_s = mk_len(s); + literal len_s_ge_l = mk_simplified_literal(m_autil.mk_ge(mk_sub(len_s, l), m_autil.mk_int(0))); + if (ctx.get_assignment(len_s_ge_l) == l_true) { + len = mk_sub(len_s, l); + lits.push_back(len_s_ge_l); + return true; + } + } else if (m_util.str.is_unit(e)) { len = m_autil.mk_int(1); return true; @@ -3393,7 +3400,7 @@ void theory_seq::enforce_length(expr* e) { do { expr* o = n->get_owner(); if (!has_length(o)) { - expr_ref len(m_util.str.mk_length(o), m); + expr_ref len = mk_len(o); enque_axiom(len); add_length(o); } @@ -3544,7 +3551,7 @@ void theory_seq::add_si_axiom(expr* e, expr* n, unsigned k) { zstring s; expr_ref ith_char(m), num(m), coeff(m); expr_ref_vector nums(m), chars(m); - expr_ref len(m_util.str.mk_length(e), m); + expr_ref len = mk_len(e); literal len_eq_k = mk_preferred_eq(len, m_autil.mk_int(k)); literal ge0 = mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0))); literal_vector digits; @@ -3648,32 +3655,35 @@ void theory_seq::display(std::ostream & out) const { } -void theory_seq::display_nc(std::ostream& out, nc const& nc) const { +std::ostream& theory_seq::display_nc(std::ostream& out, nc const& nc) const { out << "not " << mk_pp(nc.contains(), m) << "\n"; - display_deps(out << " <- ", nc.deps()); out << "\n"; + display_deps(out << " <- ", nc.deps()) << "\n"; + return out; } -void theory_seq::display_equations(std::ostream& out) const { +std::ostream& theory_seq::display_equations(std::ostream& out) const { for (auto const& e : m_eqs) { display_equation(out, e); } + return out; } -void theory_seq::display_equation(std::ostream& out, eq const& e) const { +std::ostream& theory_seq::display_equation(std::ostream& out, eq const& e) const { out << e.ls() << " = " << e.rs() << " <- \n"; - display_deps(out, e.dep()); + return display_deps(out, e.dep()); } -void theory_seq::display_disequations(std::ostream& out) const { +std::ostream& theory_seq::display_disequations(std::ostream& out) const { bool first = true; for (ne const& n : m_nqs) { if (first) out << "Disequations:\n"; first = false; display_disequation(out, n); } + return out; } -void theory_seq::display_disequation(std::ostream& out, ne const& e) const { +std::ostream& theory_seq::display_disequation(std::ostream& out, ne const& e) const { for (literal lit : e.lits()) { out << lit << " "; } @@ -3686,9 +3696,10 @@ void theory_seq::display_disequation(std::ostream& out, ne const& e) const { if (e.dep()) { display_deps(out, e.dep()); } + return out; } -void theory_seq::display_deps(std::ostream& out, literal_vector const& lits, enode_pair_vector const& eqs) const { +std::ostream& theory_seq::display_deps(std::ostream& out, literal_vector const& lits, enode_pair_vector const& eqs) const { context& ctx = get_context(); smt2_pp_environment_dbg env(m); params_ref p; @@ -3718,13 +3729,15 @@ void theory_seq::display_deps(std::ostream& out, literal_vector const& lits, eno } out << "\n"; } + return out; } -void theory_seq::display_deps(std::ostream& out, dependency* dep) const { +std::ostream& theory_seq::display_deps(std::ostream& out, dependency* dep) const { literal_vector lits; enode_pair_vector eqs; linearize(dep, eqs, lits); display_deps(out, lits, eqs); + return out; } void theory_seq::collect_statistics(::statistics & st) const { @@ -4335,7 +4348,7 @@ void theory_seq::add_indexof_axiom(expr* i) { expr_ref x = mk_skolem(m_indexof_left, t, s); expr_ref y = mk_skolem(m_indexof_right, t, s); xsy = mk_concat(x, s, y); - expr_ref lenx(m_util.str.mk_length(x), m); + expr_ref lenx = mk_len(x); // |s| = 0 => indexof(t,s,0) = 0 // contains(t,s) & |s| != 0 => t = xsy & indexof(t,s,0) = |x| add_axiom(~s_eq_empty, i_eq_0); @@ -4348,9 +4361,9 @@ void theory_seq::add_indexof_axiom(expr* i) { // offset >= len(t) => |s| = 0 or indexof(t, s, offset) = -1 // offset > len(t) => indexof(t, s, offset) = -1 // offset = len(t) & |s| = 0 => indexof(t, s, offset) = offset - expr_ref len_t(m_util.str.mk_length(t), m); - literal offset_ge_len = mk_simplified_literal(m_autil.mk_ge(m_autil.mk_sub(offset, len_t), zero)); - literal offset_le_len = mk_simplified_literal(m_autil.mk_le(m_autil.mk_sub(offset, len_t), zero)); + expr_ref len_t = mk_len(t); + literal offset_ge_len = mk_simplified_literal(m_autil.mk_ge(mk_sub(offset, len_t), zero)); + literal offset_le_len = mk_simplified_literal(m_autil.mk_le(mk_sub(offset, len_t), zero)); literal i_eq_offset = mk_eq(i, offset, false); add_axiom(~offset_ge_len, s_eq_empty, i_eq_m1); add_axiom(offset_le_len, i_eq_m1); @@ -4369,7 +4382,7 @@ void theory_seq::add_indexof_axiom(expr* i) { // -1 = indexof(y,s,0) + offset = indexof(t, s, offset) add_axiom(~offset_ge_0, offset_ge_len, mk_seq_eq(t, mk_concat(x, y))); - add_axiom(~offset_ge_0, offset_ge_len, mk_eq(m_util.str.mk_length(x), offset, false)); + add_axiom(~offset_ge_0, offset_ge_len, mk_eq(mk_len(x), offset, false)); add_axiom(~offset_ge_0, offset_ge_len, ~mk_eq(indexof0, minus_one, false), i_eq_m1); add_axiom(~offset_ge_0, offset_ge_len, @@ -4553,12 +4566,10 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { if (!a) return; - expr_ref len(m_util.str.mk_length(s), m); + expr_ref len = mk_len(s); for (unsigned i = 0; i < a->num_states(); ++i) { literal acc = mk_accept(s, len, e3, i); - literal rej = mk_reject(s, len, e3, i); add_axiom(a->is_final_state(i)?acc:~acc); - add_axiom(a->is_final_state(i)?~rej:rej); } expr_ref zero(m_autil.mk_int(0), m); @@ -4574,7 +4585,7 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { propagate_lit(nullptr, 1, &lit, lits[1]); } else { - TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";); + TRACE("seq", ctx.display_literals_verbose(tout, lits) << "\n";); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } } @@ -4643,7 +4654,7 @@ bool theory_seq::get_num_value(expr* e, rational& val) const { bool theory_seq::lower_bound(expr* _e, rational& lo) const { context& ctx = get_context(); - expr_ref e(m_util.str.mk_length(_e), m); + expr_ref e = mk_len(_e); expr_ref _lo(m); family_id afid = m_autil.get_family_id(); do { @@ -4664,7 +4675,7 @@ bool theory_seq::lower_bound(expr* _e, rational& lo) const { // we have to traverse the eqc to query for the better lower bound. bool theory_seq::lower_bound2(expr* _e, rational& lo) { context& ctx = get_context(); - expr_ref e(m_util.str.mk_length(_e), m); + expr_ref e = mk_len(_e); expr_ref _lo(m); theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); if (!tha) { @@ -4700,7 +4711,7 @@ bool theory_seq::lower_bound2(expr* _e, rational& lo) { bool theory_seq::upper_bound(expr* _e, rational& hi) const { context& ctx = get_context(); - expr_ref e(m_util.str.mk_length(_e), m); + expr_ref e = mk_len(_e); family_id afid = m_autil.get_family_id(); expr_ref _hi(m); do { @@ -4746,7 +4757,7 @@ bool theory_seq::get_length(expr* e, rational& val) const { return false; } else { - len = m_util.str.mk_length(c); + len = mk_len(c); if (ctx.e_internalized(len) && get_arith_value(ctx, m_autil.get_family_id(), len, len_val) && m_autil.is_numeral(len_val, val1)) { @@ -4811,9 +4822,9 @@ void theory_seq::add_extract_axiom(expr* e) { return; } expr_ref x(mk_skolem(m_pre, s, i), m); - expr_ref ls(m_util.str.mk_length(s), m); - expr_ref lx(m_util.str.mk_length(x), m); - expr_ref le(m_util.str.mk_length(e), m); + expr_ref ls = mk_len(s); + expr_ref lx = mk_len(x); + expr_ref le = mk_len(e); expr_ref ls_minus_i_l(mk_sub(mk_sub(ls, i), l), m); expr_ref y(mk_skolem(m_post, s, ls_minus_i_l), m); expr_ref xe = mk_concat(x, e); @@ -4852,7 +4863,7 @@ bool theory_seq::is_drop_last(expr* s, expr* i, expr* l) { return false; } expr_ref l2(m), l1(l, m); - l2 = m_autil.mk_sub(m_util.str.mk_length(s), m_autil.mk_int(1)); + l2 = mk_sub(mk_len(s), m_autil.mk_int(1)); m_rewrite(l1); m_rewrite(l2); return l1 == l2; @@ -4864,7 +4875,7 @@ bool theory_seq::is_tail(expr* s, expr* i, expr* l) { return false; } expr_ref l2(m), l1(l, m); - l2 = m_autil.mk_sub(m_util.str.mk_length(s), m_autil.mk_int(1)); + l2 = mk_sub(mk_len(s), m_autil.mk_int(1)); m_rewrite(l1); m_rewrite(l2); return l1 == l2; @@ -4887,8 +4898,8 @@ bool theory_seq::is_extract_suffix(expr* s, expr* i, expr* l) { */ void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) { TRACE("seq", tout << mk_pp(e, m) << " " << mk_pp(s, m) << " " << mk_pp(l, m) << "\n";); - expr_ref le(m_util.str.mk_length(e), m); - expr_ref ls(m_util.str.mk_length(s), m); + expr_ref le = mk_len(e); + expr_ref ls = mk_len(s); expr_ref ls_minus_l(mk_sub(ls, l), m); expr_ref y(mk_skolem(m_post, s, ls_minus_l), m); expr_ref zero(m_autil.mk_int(0), m); @@ -4897,7 +4908,7 @@ void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) { literal l_le_s = mk_simplified_literal(m_autil.mk_le(mk_sub(l, ls), zero)); add_axiom(~l_ge_0, ~l_le_s, mk_seq_eq(s, ey)); add_axiom(~l_ge_0, ~l_le_s, mk_eq(l, le, false)); - add_axiom(~l_ge_0, ~l_le_s, mk_eq(ls_minus_l, m_util.str.mk_length(y), false)); + add_axiom(~l_ge_0, ~l_le_s, mk_eq(ls_minus_l, mk_len(y), false)); add_axiom(l_le_s, mk_eq(e, s, false)); } @@ -4908,11 +4919,11 @@ void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) { */ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) { expr_ref x(mk_skolem(m_pre, s, i), m); - expr_ref lx(m_util.str.mk_length(x), m); - expr_ref ls(m_util.str.mk_length(s), m); + expr_ref lx = mk_len(x); + expr_ref ls = mk_len(s); expr_ref zero(m_autil.mk_int(0), m); expr_ref xe = mk_concat(x, e); - literal le_is_0 = mk_eq(zero, m_util.str.mk_length(e), false); + literal le_is_0 = mk_eq(zero, mk_len(e), false); literal i_ge_0 = mk_simplified_literal(m_autil.mk_ge(i, zero)); literal i_le_s = mk_simplified_literal(m_autil.mk_le(mk_sub(i, ls), zero)); add_axiom(~i_ge_0, ~i_le_s, mk_seq_eq(s, xe)); @@ -4932,18 +4943,19 @@ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) { void theory_seq::add_at_axiom(expr* e) { expr* s = nullptr, *i = nullptr; VERIFY(m_util.str.is_at(e, s, i)); - expr_ref len_e(m_util.str.mk_length(e), m); - expr_ref len_s(m_util.str.mk_length(s), m); + expr_ref len_e = mk_len(e); + expr_ref len_s = mk_len(s); expr_ref zero(m_autil.mk_int(0), m); expr_ref one(m_autil.mk_int(1), m); expr_ref x = mk_skolem(m_pre, s, i); - expr_ref y = mk_skolem(m_post, s, mk_sub(mk_sub(len_s, i), one)); + //expr_ref y = mk_skolem(m_post, s, mk_sub(mk_sub(len_s, i), one)); + expr_ref y = mk_skolem(m_tail, s, i); expr_ref xey = mk_concat(x, e, y); - expr_ref len_x(m_util.str.mk_length(x), m); + expr_ref len_x = mk_len(x); expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); literal i_ge_0 = mk_simplified_literal(m_autil.mk_ge(i, zero)); - literal i_ge_len_s = mk_simplified_literal(m_autil.mk_ge(mk_sub(i, m_util.str.mk_length(s)), zero)); + literal i_ge_len_s = mk_simplified_literal(m_autil.mk_ge(mk_sub(i, mk_len(s)), zero)); add_axiom(~i_ge_0, i_ge_len_s, mk_seq_eq(s, xey)); @@ -4969,7 +4981,7 @@ void theory_seq::propagate_step(literal lit, expr* step) { // skip } else { - propagate_lit(nullptr, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx))); + propagate_lit(nullptr, 1, &lit, ~mk_literal(m_autil.mk_le(mk_len(s), idx))); } ensure_nth(lit, s, idx); } @@ -4989,8 +5001,8 @@ void theory_seq::ensure_nth(literal lit, expr* s, expr* idx) { for (unsigned j = 0; j <= _idx; ++j) { mk_decompose(s2, head, tail); elems.push_back(head); - len1 = m_util.str.mk_length(s2); - len2 = m_autil.mk_add(m_autil.mk_int(1), m_util.str.mk_length(tail)); + len1 = mk_len(s2); + len2 = m_autil.mk_add(m_autil.mk_int(1), mk_len(tail)); propagate_eq(lit, len1, len2, false); s2 = tail; } @@ -5061,7 +5073,7 @@ void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4, liter if (l3 != null_literal && l3 != false_literal) { ctx.mark_as_relevant(l3); lits.push_back(l3); } if (l4 != null_literal && l4 != false_literal) { ctx.mark_as_relevant(l4); lits.push_back(l4); } if (l5 != null_literal && l5 != false_literal) { ctx.mark_as_relevant(l5); lits.push_back(l5); } - TRACE("seq", ctx.display_literals_verbose(tout << "assert:\n", lits); tout << "\n";); + TRACE("seq", ctx.display_literals_verbose(tout << "assert:\n", lits) << "\n";); m_new_propagation = true; ++m_stats.m_add_axiom; ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); @@ -5180,7 +5192,7 @@ void theory_seq::propagate_eq(dependency* deps, literal_vector const& _lits, exp } TRACE("seq", tout << "assert: " << mk_pp(e1, m) << " = " << mk_pp(e2, m) << " <- \n"; - if (!lits.empty()) { ctx.display_literals_verbose(tout, lits); tout << "\n"; }); + if (!lits.empty()) { ctx.display_literals_verbose(tout, lits) << "\n"; }); justification* js = ctx.mk_justification( ext_theory_eq_propagation_justification( @@ -5244,7 +5256,7 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { else if (!canonizes(false, e)) { propagate_non_empty(lit, e2); dependency* dep = m_dm.mk_leaf(assumption(lit)); - literal len_gt = mk_simplified_literal(m_autil.mk_le(m_autil.mk_sub(m_util.str.mk_length(e1), m_util.str.mk_length(e2)), + literal len_gt = mk_simplified_literal(m_autil.mk_le(mk_sub(mk_len(e1), mk_len(e2)), m_autil.mk_int(-1))); ctx.force_phase(len_gt); m_ncs.push_back(nc(expr_ref(e, m), len_gt, dep)); @@ -5258,12 +5270,6 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { } } } - else if (is_reject(e)) { - if (is_true) { - propagate_acc_rej_length(lit, e); - add_atom(e); - } - } else if (is_step(e)) { if (is_true) { propagate_step(lit, e); @@ -5439,11 +5445,6 @@ literal theory_seq::mk_accept(expr* s, expr* idx, expr* re, expr* state) { args.push_back(s).push_back(idx).push_back(re).push_back(state); return mk_literal(m_util.mk_skolem(m_accept, args.size(), args.c_ptr(), m.mk_bool_sort())); } -literal theory_seq::mk_reject(expr* s, expr* idx, expr* re, expr* state) { - expr_ref_vector args(m); - args.push_back(s).push_back(idx).push_back(re).push_back(state); - return mk_literal(m_util.mk_skolem(m_reject, args.size(), args.c_ptr(), m.mk_bool_sort())); -} bool theory_seq::is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut) { if (is_skolem(ar, e)) { @@ -5494,33 +5495,25 @@ expr_ref theory_seq::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned /* acc(s, idx, re, i) -> len(s) >= idx if i is final - rej(s, idx, re, i) -> len(s) >= idx if i is non-final acc(s, idx, re, i) -> len(s) > idx if i is non-final - rej(s, idx, re, i) -> len(s) > idx if i is final */ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { expr *s = nullptr, *idx = nullptr, *re = nullptr; - unsigned src; eautomaton* aut = nullptr; - bool is_acc; - is_acc = is_accept(e, s, idx, re, src, aut); - if (!is_acc) { - VERIFY(is_reject(e, s, idx, re, src, aut)); - } + unsigned src = 0; + VERIFY(is_accept(e, s, idx, re, src, aut)); if (m_util.str.is_length(idx)) return; SASSERT(m_autil.is_numeral(idx)); SASSERT(get_context().get_assignment(lit) == l_true); if (aut->is_sink_state(src)) { propagate_lit(nullptr, 1, &lit, false_literal); - return; } - bool is_final = aut->is_final_state(src); - if (is_final == is_acc) { - propagate_lit(nullptr, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); + else if (aut->is_final_state(src)) { + propagate_lit(nullptr, 1, &lit, mk_literal(m_autil.mk_ge(mk_len(s), idx))); } else { - propagate_lit(nullptr, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx))); + propagate_lit(nullptr, 1, &lit, ~mk_literal(m_autil.mk_le(mk_len(s), idx))); } } @@ -5543,7 +5536,7 @@ bool theory_seq::add_accept2step(expr* acc, bool& change) { } SASSERT(m_autil.is_numeral(idx)); - expr_ref len(m_util.str.mk_length(e), m); + expr_ref len = mk_len(e); literal_vector lits; lits.push_back(~ctx.get_literal(acc)); if (aut->is_final_state(src)) { @@ -5604,7 +5597,7 @@ bool theory_seq::add_accept2step(expr* acc, bool& change) { TRACE("seq", tout << "has undef\n";); return true; } - TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";); + TRACE("seq", ctx.display_literals_verbose(tout, lits) << "\n";); for (unsigned i = 0; i < lits.size(); ++i) { SASSERT(ctx.get_assignment(lits[i]) == l_false); lits[i].neg(); @@ -5658,73 +5651,6 @@ bool theory_seq::add_step2accept(expr* step, bool& change) { } -/* - rej(s, idx, re, i) & nth(s, idx) = t & idx < len(s) => rej(s, idx + 1, re, j) - - len(s) > idx -> s = (nth 0 s) ++ .. ++ (nth idx s) ++ (tail idx s) - -Recall we also have: - rej(s, idx, re, i) -> len(s) >= idx if i is non-final - rej(s, idx, re, i) -> len(s) > idx if i is final - -*/ -bool theory_seq::add_reject2reject(expr* rej, bool& change) { - context& ctx = get_context(); - SASSERT(ctx.get_assignment(rej) == l_true); - expr* s = nullptr, *idx = nullptr, *re = nullptr; - unsigned src; - rational r; - eautomaton* aut = nullptr; - VERIFY(is_reject(rej, s, idx, re, src, aut)); - if (!aut || m_util.str.is_length(idx)) return false; - VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); - expr_ref idx1(m_autil.mk_int(r.get_unsigned() + 1), m); - eautomaton::moves mvs; - aut->get_moves_from(src, mvs); - literal rej1 = ctx.get_literal(rej); - expr_ref len(m_util.str.mk_length(s), m); - literal len_le_idx = mk_literal(m_autil.mk_le(len, idx)); - switch (ctx.get_assignment(len_le_idx)) { - case l_true: - return false; - case l_undef: - ctx.force_phase(len_le_idx); - return true; - default: - break; - } - expr_ref nth = mk_nth(s, idx); - ensure_nth(~len_le_idx, s, idx); - literal_vector eqs; - bool has_undef = false; - for (eautomaton::move const& mv : mvs) { - literal eq = mk_literal(mv.t()->accept(nth)); - switch (ctx.get_assignment(eq)) { - case l_false: - case l_true: - break; - case l_undef: - ctx.force_phase(~eq); - has_undef = true; - break; - } - eqs.push_back(eq); - } - change = true; - if (has_undef) { - return true; - } - for (unsigned i = 0; i < mvs.size(); ++i) { - eautomaton::move const& mv = mvs[i]; - literal eq = eqs[i]; - if (ctx.get_assignment(eq) == l_true) { - literal rej2 = mk_reject(s, idx1, re, m_autil.mk_int(mv.dst())); - add_axiom(~rej1, ~eq, len_le_idx, rej2); - } - } - return false; -} - /* !prefix(e1,e2) => e1 != "" !prefix(e1,e2) => len(e1) > len(e2) or e1 = xcy & e2 = xdz & c != d @@ -5740,7 +5666,7 @@ void theory_seq::propagate_not_prefix(expr* e) { return; } propagate_non_empty(~lit, e1); - literal e1_gt_e2 = mk_simplified_literal(m_autil.mk_ge(m_autil.mk_sub(m_util.str.mk_length(e1), m_util.str.mk_length(e2)), m_autil.mk_int(1))); + literal e1_gt_e2 = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(e1), mk_len(e2)), m_autil.mk_int(1))); sort* char_sort = nullptr; VERIFY(m_util.is_seq(m.get_sort(e1), char_sort)); expr_ref x = mk_skolem(symbol("seq.prefix.x"), e1, e2); @@ -5770,7 +5696,7 @@ void theory_seq::propagate_not_suffix(expr* e) { return; } propagate_non_empty(~lit, e1); - literal e1_gt_e2 = mk_simplified_literal(m_autil.mk_ge(m_autil.mk_sub(m_util.str.mk_length(e1), m_util.str.mk_length(e2)), m_autil.mk_int(1))); + literal e1_gt_e2 = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(e1), mk_len(e2)), m_autil.mk_int(1))); sort* char_sort = nullptr; VERIFY(m_util.is_seq(m.get_sort(e1), char_sort)); expr_ref x = mk_skolem(symbol("seq.suffix.x"), e1, e2); @@ -5821,9 +5747,6 @@ bool theory_seq::propagate_automata() { if (is_accept(e)) { reQ = add_accept2step(e, change); } - else if (is_reject(e)) { - reQ = add_reject2reject(e, change); - } else if (is_step(e)) { reQ = add_step2accept(e, change); } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 0452bf560..ef26f78cc 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -577,6 +577,7 @@ namespace smt { void tightest_prefix(expr* s, expr* x); expr_ref mk_sub(expr* a, expr* b); expr_ref mk_add(expr* a, expr* b); + expr_ref mk_len(expr* s) const { return expr_ref(m_util.str.mk_length(s), m); } enode* ensure_enode(expr* a); dependency* mk_join(dependency* deps, literal lit); @@ -606,18 +607,11 @@ namespace smt { bool is_accept(expr* acc, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut) { return is_acc_rej(m_accept, acc, s, idx, re, i, aut); } - literal mk_reject(expr* s, expr* idx, expr* re, expr* state); - literal mk_reject(expr* s, expr* idx, expr* re, unsigned i) { return mk_reject(s, idx, re, m_autil.mk_int(i)); } - bool is_reject(expr* rej) const { return is_skolem(m_reject, rej); } - bool is_reject(expr* rej, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut) { - return is_acc_rej(m_reject, rej, s, idx, re, i, aut); - } bool is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut); expr_ref mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned j, expr* acc); bool is_step(expr* e, expr*& s, expr*& tail, expr*& re, expr*& i, expr*& j, expr*& t) const; bool is_step(expr* e) const; void propagate_step(literal lit, expr* n); - bool add_reject2reject(expr* rej, bool& change); bool add_accept2step(expr* acc, bool& change); bool add_step2accept(expr* step, bool& change); void propagate_not_prefix(expr* e); @@ -632,13 +626,13 @@ namespace smt { void new_eq_eh(dependency* dep, enode* n1, enode* n2); // diagnostics - void display_equations(std::ostream& out) const; - void display_equation(std::ostream& out, eq const& e) const; - void display_disequations(std::ostream& out) const; - void display_disequation(std::ostream& out, ne const& e) const; - void display_deps(std::ostream& out, dependency* deps) const; - void display_deps(std::ostream& out, literal_vector const& lits, enode_pair_vector const& eqs) const; - void display_nc(std::ostream& out, nc const& nc) const; + std::ostream& display_equations(std::ostream& out) const; + std::ostream& display_equation(std::ostream& out, eq const& e) const; + std::ostream& display_disequations(std::ostream& out) const; + std::ostream& display_disequation(std::ostream& out, ne const& e) const; + std::ostream& display_deps(std::ostream& out, dependency* deps) const; + std::ostream& display_deps(std::ostream& out, literal_vector const& lits, enode_pair_vector const& eqs) const; + std::ostream& display_nc(std::ostream& out, nc const& nc) const; public: theory_seq(ast_manager& m, theory_seq_params const & params); ~theory_seq() override; From 6ddbc9cd38738454c30c5000f119b2838dfccebf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Nov 2018 15:26:39 -0800 Subject: [PATCH 223/227] overhaul of regular expression membership solving. Use iterative deepening and propagation, coallesce intersections Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 18 +- src/ast/seq_decl_plugin.h | 5 + src/cmd_context/cmd_context.cpp | 21 +- src/smt/theory_seq.cpp | 366 ++++++++++++-------------------- src/smt/theory_seq.h | 42 ++-- 5 files changed, 200 insertions(+), 252 deletions(-) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 85f5c1b1c..93a8956df 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -663,24 +663,28 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, info); } - case OP_SEQ_UNIT: case OP_RE_PLUS: case OP_RE_STAR: case OP_RE_OPTION: case OP_RE_RANGE: case OP_RE_OF_PRED: + case OP_RE_COMPLEMENT: + m_has_re = true; + // fall-through + case OP_SEQ_UNIT: case OP_STRING_ITOS: case OP_STRING_STOI: - case OP_RE_COMPLEMENT: match(*m_sigs[k], arity, domain, range, rng); return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k)); case _OP_REGEXP_FULL_CHAR: + m_has_re = true; if (!range) range = m_re; match(*m_sigs[k], arity, domain, range, rng); return m.mk_func_decl(symbol("re.allchar"), arity, domain, rng, func_decl_info(m_family_id, OP_RE_FULL_CHAR_SET)); case OP_RE_FULL_CHAR_SET: + m_has_re = true; if (!range) range = m_re; if (range == m_re) { match(*m_sigs[k], arity, domain, range, rng); @@ -689,15 +693,18 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, range, func_decl_info(m_family_id, k)); case OP_RE_FULL_SEQ_SET: + m_has_re = true; if (!range) range = m_re; return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, range, func_decl_info(m_family_id, k)); case _OP_REGEXP_EMPTY: + m_has_re = true; if (!range) range = m_re; match(*m_sigs[k], arity, domain, range, rng); return m.mk_func_decl(symbol("re.nostr"), arity, domain, rng, func_decl_info(m_family_id, OP_RE_EMPTY_SET)); case OP_RE_EMPTY_SET: + m_has_re = true; if (!range) range = m_re; if (range == m_re) { match(*m_sigs[k], arity, domain, range, rng); @@ -706,6 +713,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, range, func_decl_info(m_family_id, k)); case OP_RE_LOOP: + m_has_re = true; switch (arity) { case 1: match(*m_sigs[k], arity, domain, range, rng); @@ -728,6 +736,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, } case _OP_RE_UNROLL: + m_has_re = true; match(*m_sigs[k], arity, domain, range, rng); return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k)); @@ -741,6 +750,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_RE_UNION: case OP_RE_CONCAT: case OP_RE_INTERSECT: + m_has_re = true; return mk_assoc_fun(k, arity, domain, range, k, k); case OP_SEQ_CONCAT: @@ -792,13 +802,17 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, return mk_str_fun(k, arity, domain, range, OP_SEQ_CONTAINS); case OP_SEQ_TO_RE: + m_has_re = true; return mk_seq_fun(k, arity, domain, range, _OP_STRING_TO_REGEXP); case _OP_STRING_TO_REGEXP: + m_has_re = true; return mk_str_fun(k, arity, domain, range, OP_SEQ_TO_RE); case OP_SEQ_IN_RE: + m_has_re = true; return mk_seq_fun(k, arity, domain, range, _OP_STRING_IN_REGEXP); case _OP_STRING_IN_REGEXP: + m_has_re = true; return mk_str_fun(k, arity, domain, range, OP_SEQ_IN_RE); case OP_SEQ_AT: diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index b4f38fc46..f8107f1e0 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -146,6 +146,7 @@ class seq_decl_plugin : public decl_plugin { sort* m_string; sort* m_char; sort* m_re; + bool m_has_re; void match(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng); @@ -197,6 +198,8 @@ public: app* mk_string(symbol const& s); app* mk_string(zstring const& s); + bool has_re() const { return m_has_re; } + }; class seq_util { @@ -221,6 +224,8 @@ public: app* mk_skolem(symbol const& name, unsigned n, expr* const* args, sort* range); bool is_skolem(expr const* e) const { return is_app_of(e, m_fid, _OP_SEQ_SKOLEM); } + bool has_re() const { return seq.has_re(); } + class str { seq_util& u; ast_manager& m; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 250dbea08..fb81c673e 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1750,20 +1750,25 @@ struct contains_underspecified_op_proc { struct found {}; family_id m_array_fid; datatype_util m_dt; + seq_util m_seq; + family_id m_seq_id; - contains_underspecified_op_proc(ast_manager & m):m_array_fid(m.mk_family_id("array")), m_dt(m) {} + contains_underspecified_op_proc(ast_manager & m):m_array_fid(m.mk_family_id("array")), m_dt(m), m_seq(m), m_seq_id(m_seq.get_family_id()) {} void operator()(var * n) {} void operator()(app * n) { if (m_dt.is_accessor(n->get_decl())) throw found(); - if (n->get_family_id() != m_array_fid) - return; - decl_kind k = n->get_decl_kind(); - if (k == OP_AS_ARRAY || - k == OP_STORE || - k == OP_ARRAY_MAP || - k == OP_CONST_ARRAY) + if (n->get_family_id() == m_array_fid) { + decl_kind k = n->get_decl_kind(); + if (k == OP_AS_ARRAY || + k == OP_STORE || + k == OP_ARRAY_MAP || + k == OP_CONST_ARRAY) + throw found(); + } + if (n->get_family_id() == m_seq_id && m_seq.is_re(n)) { throw found(); + } } void operator()(quantifier * n) {} }; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 865af665f..3799ff082 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -217,7 +217,8 @@ theory_seq::theory_seq(ast_manager& m, theory_seq_params const & params): m_ls(m), m_rs(m), m_lhs(m), m_rhs(m), m_res(m), - m_atoms_qhead(0), + m_max_unfolding_depth(1), + m_max_unfolding_lit(null_literal), m_new_solution(false), m_new_propagation(false), m_mk_aut(m) { @@ -324,11 +325,6 @@ final_check_status theory_seq::final_check_eh() { TRACE("seq", tout << ">>extensionality\n";); return FC_CONTINUE; } - if (propagate_automata()) { - ++m_stats.m_propagate_automata; - TRACE("seq", tout << ">>propagate_automata\n";); - return FC_CONTINUE; - } if (is_solved()) { TRACE("seq", tout << ">>is_solved\n";); return FC_DONE; @@ -895,8 +891,8 @@ void theory_seq::len_offset(expr* e, rational val) { if (m_autil.is_add(e, l1, l2) && m_autil.is_mul(l2, l21, l22) && m_autil.is_numeral(l21, fact) && fact.is_minus_one()) { if (ctx.e_internalized(l1) && ctx.e_internalized(l22)) { - enode* r1 = ctx.get_enode(l1)->get_root(), *n1 = r1; - enode* r2 = ctx.get_enode(l22)->get_root(), *n2 = r2; + enode* r1 = get_root(l1), *n1 = r1; + enode* r2 = get_root(l22), *n2 = r2; expr *e1 = nullptr, *e2 = nullptr; do { if (m_util.str.is_length(n1->get_owner(), e1)) @@ -1093,13 +1089,13 @@ bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector cons if (!ctx.e_internalized(len_r_fst)) return false; else - root2 = ctx.get_enode(len_r_fst)->get_root(); + root2 = get_root(len_r_fst); // Offset = 0, No change if (l_fst) { expr_ref len_l_fst = mk_len(l_fst); if (ctx.e_internalized(len_l_fst)) { - enode * root1 = ctx.get_enode(len_l_fst)->get_root(); + enode * root1 = get_root(len_l_fst); if (root1 == root2) { TRACE("seq", tout << "(" << mk_pp(l_fst, m) << ", " << mk_pp(r_fst,m) << ")\n";); return false; @@ -1125,7 +1121,7 @@ bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector cons if (nl_fst && nl_fst != r_fst) { expr_ref len_nl_fst = mk_len(nl_fst); if (ctx.e_internalized(len_nl_fst)) { - enode * root1 = ctx.get_enode(len_nl_fst)->get_root(); + enode * root1 = get_root(len_nl_fst); if (root1 == root2) { res.reset(); res.append(e.rs().size(), e.rs().c_ptr()); @@ -1142,7 +1138,7 @@ bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector cons if (l_fst) { expr_ref len_l_fst = mk_len(l_fst); if (ctx.e_internalized(len_l_fst)) { - enode * root1 = ctx.get_enode(len_l_fst)->get_root(); + enode * root1 = get_root(len_l_fst); obj_map tmp; int offset; if (!m_autil.is_numeral(root1->get_owner()) && !m_autil.is_numeral(root2->get_owner())) { @@ -3363,7 +3359,6 @@ bool theory_seq::internalize_term(app* term) { mk_var(e); return true; } - TRACE("seq_verbose", tout << mk_pp(term, m) << "\n";); for (auto arg : *term) { mk_var(ensure_enode(arg)); } @@ -3743,7 +3738,6 @@ std::ostream& theory_seq::display_deps(std::ostream& out, dependency* dep) const void theory_seq::collect_statistics(::statistics & st) const { st.update("seq num splits", m_stats.m_num_splits); st.update("seq num reductions", m_stats.m_num_reductions); - st.update("seq unfold def", m_stats.m_propagate_automata); st.update("seq length coherence", m_stats.m_check_length_coherence); st.update("seq branch", m_stats.m_branch_variable); st.update("seq solve !=", m_stats.m_solve_nqs); @@ -3905,8 +3899,8 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { context& ctx = get_context(); expr* e1, *e2, *e3; if (m.is_ite(e, e1, e2, e3) && ctx.e_internalized(e2) && ctx.e_internalized(e3) && - (ctx.get_enode(e2)->get_root() == n->get_root() || - ctx.get_enode(e3)->get_root() == n->get_root())) { + (get_root(e2) == n->get_root() || + get_root(e3) == n->get_root())) { if (ctx.get_enode(e2)->get_root() == n->get_root()) { return mk_value(ctx.get_enode(e2), mg); } @@ -4562,20 +4556,43 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { e3 = m_util.re.mk_complement(re); lit.neg(); } + + literal_vector lits; + + enode_pair_vector eqs; + for (unsigned i = 0; i < m_s_in_re.size(); ++i) { + auto const& entry = m_s_in_re[i]; + if (entry.m_active && get_root(entry.m_s) == get_root(s)) { + m_trail_stack.push(vector_value_trail(m_s_in_re, i)); + m_s_in_re[i].m_active = false; + e3 = m_util.re.mk_inter(entry.m_re, e3); + lits.push_back(entry.m_lit); + eqs.push_back(enode_pair(ensure_enode(entry.m_s), ensure_enode(s))); + } + } + if (!lits.empty()) { + TRACE("seq", tout << "creating intersection " << e3 << "\n";); + lits.push_back(lit); + literal inter = mk_literal(m_util.re.mk_in_re(s, e3)); + justification* js = + ctx.mk_justification( + ext_theory_propagation_justification( + get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), inter)); + ctx.assign(inter, js); + return; + } + eautomaton* a = get_automaton(e3); if (!a) return; + m_s_in_re.push_back(s_in_re(lit, s, e3, a)); + m_trail_stack.push(push_back_vector>(m_s_in_re)); expr_ref len = mk_len(s); - for (unsigned i = 0; i < a->num_states(); ++i) { - literal acc = mk_accept(s, len, e3, i); - add_axiom(a->is_final_state(i)?acc:~acc); - } expr_ref zero(m_autil.mk_int(0), m); unsigned_vector states; a->get_epsilon_closure(a->init(), states); - literal_vector lits; lits.push_back(~lit); for (unsigned st : states) { @@ -4966,25 +4983,6 @@ void theory_seq::add_at_axiom(expr* e) { add_axiom(~i_ge_len_s, mk_eq(e, emp, false)); } -/** - step(s, idx, re, i, j, t) -> nth(s, idx) == t & len(s) > idx -*/ -void theory_seq::propagate_step(literal lit, expr* step) { - SASSERT(get_context().get_assignment(lit) == l_true); - expr* re = nullptr, *acc = nullptr, *s = nullptr, *idx = nullptr, *i = nullptr, *j = nullptr; - VERIFY(is_step(step, s, idx, re, i, j, acc)); - TRACE("seq", tout << mk_pp(step, m) << " -> " << mk_pp(acc, m) << "\n";); - propagate_lit(nullptr, 1, &lit, mk_simplified_literal(acc)); - rational lo; - rational _idx; - if (lower_bound(s, lo) && lo.is_unsigned() && m_autil.is_numeral(idx, _idx) && lo >= _idx) { - // skip - } - else { - propagate_lit(nullptr, 1, &lit, ~mk_literal(m_autil.mk_le(mk_len(s), idx))); - } - ensure_nth(lit, s, idx); -} /* lit => s = (nth s 0) ++ (nth s 1) ++ ... ++ (nth s idx) ++ (tail s idx) @@ -5264,18 +5262,12 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { } else if (is_accept(e)) { if (is_true) { - propagate_acc_rej_length(lit, e); - if (add_accept2step(e, change)) { - add_atom(e); - } + propagate_accept(lit, e); } } else if (is_step(e)) { if (is_true) { propagate_step(lit, e); - if (add_step2accept(e, change)) { - add_atom(e); - } } } else if (is_eq(e, e1, e2)) { @@ -5290,6 +5282,10 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { // propagate equalities } else if (is_skolem(symbol("seq.is_digit"), e)) { + // no-op + } + else if (is_max_unfolding(e)) { + // no-op } else { TRACE("seq", tout << mk_pp(e, m) << "\n";); @@ -5297,11 +5293,6 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { } } -void theory_seq::add_atom(expr* e) { - m_trail_stack.push(push_back_vector >(m_atoms)); - m_atoms.push_back(e); -} - void theory_seq::new_eq_eh(theory_var v1, theory_var v2) { enode* n1 = get_enode(v1); enode* n2 = get_enode(v2); @@ -5326,13 +5317,31 @@ void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) { enforce_length_coherence(n1, n2); } else if (n1 != n2 && m_util.is_re(n1->get_owner())) { - // ignore - // eautomaton* a1 = get_automaton(n1->get_owner()); - // eautomaton* a2 = get_automaton(n2->get_owner()); - // eautomaton* b1 = mk_difference(*a1, *a2); - // eautomaton* b2 = mk_difference(*a2, *a1); - // eautomaton* c = mk_union(*b1, *b2); - // then some emptiness check. + // create an expression for the symmetric difference and imply it is empty. + enode_pair_vector eqs; + literal_vector lits; + if (!linearize(deps, eqs, lits)) + return; + context& ctx = get_context(); + eqs.push_back(enode_pair(n1, n2)); + expr_ref r1(n1->get_owner(), m); + expr_ref r2(n2->get_owner(), m); + ctx.get_rewriter()(r1); + ctx.get_rewriter()(r2); + if (r1 == r2) { + return; + } +#if 0 + expr* d1 = m_util.re.mk_inter(r1, m_util.re.mk_complement(r2)); + expr* d2 = m_util.re.mk_inter(r2, m_util.re.mk_complement(r1)); + expr_ref diff(m_util.re.mk_union(d1, d2), m); + lit = mk_literal(m_util.re.mk_is_empty(diff)); + justification* js = + ctx.mk_justification( + ext_theory_propagation_justification( + get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), lit)); + ctx.assign(lit, js); +#endif } } @@ -5369,7 +5378,6 @@ void theory_seq::push_scope_eh() { m_eqs.push_scope(); m_nqs.push_scope(); m_ncs.push_scope(); - m_atoms_lim.push_back(m_atoms.size()); } void theory_seq::pop_scope_eh(unsigned num_scopes) { @@ -5382,8 +5390,6 @@ void theory_seq::pop_scope_eh(unsigned num_scopes) { m_eqs.pop_scope(num_scopes); m_nqs.pop_scope(num_scopes); m_ncs.pop_scope(num_scopes); - m_atoms.resize(m_atoms_lim[m_atoms_lim.size()-num_scopes]); - m_atoms_lim.shrink(m_atoms_lim.size()-num_scopes); m_rewrite.reset(); if (ctx.get_base_level() > ctx.get_scope_level() - num_scopes) { m_replay.reset(); @@ -5430,10 +5436,7 @@ eautomaton* theory_seq::get_automaton(expr* re) { m_mk_aut.set_solver(alloc(seq_expr_solver, m, get_context().get_fparams())); } result = m_mk_aut(re); - if (result) { - display_expr disp(m); - TRACE("seq", result->display(tout, disp);); - } + CTRACE("seq", result, result->display(tout, display_expr(m));); m_automata.push_back(result); m_re2aut.insert(re, result); m_res.push_back(re); @@ -5446,8 +5449,8 @@ literal theory_seq::mk_accept(expr* s, expr* idx, expr* re, expr* state) { return mk_literal(m_util.mk_skolem(m_accept, args.size(), args.c_ptr(), m.mk_bool_sort())); } -bool theory_seq::is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut) { - if (is_skolem(ar, e)) { +bool theory_seq::is_accept(expr* e, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut) { + if (is_accept(e)) { rational r; s = to_app(e)->get_arg(0); idx = to_app(e)->get_arg(1); @@ -5483,169 +5486,109 @@ bool theory_seq::is_step(expr* e, expr*& s, expr*& idx, expr*& re, expr*& i, exp } } -expr_ref theory_seq::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned j, expr* acc) { - SASSERT(m.is_bool(acc)); +expr_ref theory_seq::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned j, expr* t) { expr_ref_vector args(m); args.push_back(s).push_back(idx).push_back(re); args.push_back(m_autil.mk_int(i)); args.push_back(m_autil.mk_int(j)); - args.push_back(acc); + args.push_back(t); return expr_ref(m_util.mk_skolem(m_aut_step, args.size(), args.c_ptr(), m.mk_bool_sort()), m); } -/* - acc(s, idx, re, i) -> len(s) >= idx if i is final - - acc(s, idx, re, i) -> len(s) > idx if i is non-final +/** + step(s, idx, re, i, j, t) -> nth(s, idx) == t & len(s) > idx + step(s, idx, re, i, j, t) -> accept(s, idx + 1, re, j) */ -void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { - expr *s = nullptr, *idx = nullptr, *re = nullptr; - eautomaton* aut = nullptr; - unsigned src = 0; - VERIFY(is_accept(e, s, idx, re, src, aut)); - if (m_util.str.is_length(idx)) return; - SASSERT(m_autil.is_numeral(idx)); +void theory_seq::propagate_step(literal lit, expr* step) { SASSERT(get_context().get_assignment(lit) == l_true); - if (aut->is_sink_state(src)) { - propagate_lit(nullptr, 1, &lit, false_literal); - } - else if (aut->is_final_state(src)) { - propagate_lit(nullptr, 1, &lit, mk_literal(m_autil.mk_ge(mk_len(s), idx))); + expr* re = nullptr, *s = nullptr, *t = nullptr, *idx = nullptr, *i = nullptr, *j = nullptr; + VERIFY(is_step(step, s, idx, re, i, j, t)); + + TRACE("seq", tout << mk_pp(step, m) << " -> " << mk_pp(t, m) << "\n";); + propagate_lit(nullptr, 1, &lit, mk_literal(t)); + + rational lo; + rational _idx; + if (lower_bound(s, lo) && lo.is_unsigned() && m_autil.is_numeral(idx, _idx) && lo >= _idx) { + // skip } else { propagate_lit(nullptr, 1, &lit, ~mk_literal(m_autil.mk_le(mk_len(s), idx))); } + ensure_nth(lit, s, idx); + + expr_ref idx1(m_autil.mk_int(_idx + 1), m); + propagate_lit(nullptr, 1, &lit, mk_accept(s, idx1, re, j)); } /** acc(s, idx, re, i) -> \/ step(s, idx, re, i, j, t) if i is non-final - acc(s, idx, re, i) -> len(s) <= idx \/ step(s, idx, re, i, j, t) if i is final -*/ -bool theory_seq::add_accept2step(expr* acc, bool& change) { - context& ctx = get_context(); - - TRACE("seq", tout << mk_pp(acc, m) << "\n";); - SASSERT(ctx.get_assignment(acc) == l_true); + acc(s, idx, re, i) -> len(s) <= idx \/ step(s, idx, re, i, j, t) if i is final + acc(s, idx, re, i) -> len(s) >= idx if i is final + acc(s, idx, re, i) -> len(s) > idx if i is non-final + acc(s, idx, re, i) -> idx < max_unfolding + */ +void theory_seq::propagate_accept(literal lit, expr* acc) { expr *e = nullptr, *idx = nullptr, *re = nullptr; - expr_ref step(m); - unsigned src; + unsigned src = 0; + rational _idx; eautomaton* aut = nullptr; VERIFY(is_accept(acc, e, idx, re, src, aut)); - if (!aut || m_util.str.is_length(idx)) { - return false; + VERIFY(aut); + if (aut->is_sink_state(src)) { + propagate_lit(nullptr, 1, &lit, false_literal); + return; + } + VERIFY(m_autil.is_numeral(idx, _idx)); + if (_idx.get_unsigned() > m_max_unfolding_depth && m_max_unfolding_lit != null_literal) { + propagate_lit(nullptr, 1, &lit, ~m_max_unfolding_lit); + return; } - SASSERT(m_autil.is_numeral(idx)); expr_ref len = mk_len(e); + literal_vector lits; - lits.push_back(~ctx.get_literal(acc)); + lits.push_back(~lit); if (aut->is_final_state(src)) { lits.push_back(mk_literal(m_autil.mk_le(len, idx))); - switch (ctx.get_assignment(lits.back())) { - case l_true: - return false; - case l_undef: - change = true; - ctx.force_phase(lits.back()); - return true; - default: - break; - } + propagate_lit(nullptr, 1, &lit, mk_literal(m_autil.mk_ge(len, idx))); + } + else { + propagate_lit(nullptr, 1, &lit, ~mk_literal(m_autil.mk_le(len, idx))); } - eautomaton::moves mvs; aut->get_moves_from(src, mvs); - bool has_undef = false; - int start = ctx.get_random_value(); TRACE("seq", tout << mvs.size() << "\n";); - for (unsigned i = 0; i < mvs.size(); ++i) { - unsigned j = (i + start) % mvs.size(); - eautomaton::move mv = mvs[j]; + for (auto const& mv : mvs) { expr_ref nth = mk_nth(e, idx); - expr_ref acc = mv.t()->accept(nth); - TRACE("seq", tout << j << ": " << acc << "\n";); - step = mk_step(e, idx, re, src, mv.dst(), acc); - literal slit = mk_literal(step); - literal tlit = mk_literal(acc); - add_axiom(~slit, tlit); - lits.push_back(slit); - switch (ctx.get_assignment(slit)) { - case l_true: - return false; - case l_undef: - ctx.mark_as_relevant(slit); - // ctx.force_phase(slit); - // return true; - has_undef = true; - break; - default: - break; - } + expr_ref t = mv.t()->accept(nth); + get_context().get_rewriter()(t); + literal step = mk_literal(mk_step(e, idx, re, src, mv.dst(), t)); + lits.push_back(step); } - change = true; - if (has_undef && mvs.size() == 1) { - TRACE("seq", tout << "has single move\n";); - literal lit = lits.back(); - lits.pop_back(); - for (unsigned i = 0; i < lits.size(); ++i) { - lits[i].neg(); - } - propagate_lit(nullptr, lits.size(), lits.c_ptr(), lit); - return false; - } - if (has_undef) { - TRACE("seq", tout << "has undef\n";); - return true; - } - TRACE("seq", ctx.display_literals_verbose(tout, lits) << "\n";); - for (unsigned i = 0; i < lits.size(); ++i) { - SASSERT(ctx.get_assignment(lits[i]) == l_false); - lits[i].neg(); - } - set_conflict(nullptr, lits); - return false; + get_context().mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } - -/** - step(s, idx, re, i, j, t) => t - acc(s, idx, re, i) & step(s, idx, re, i, j, t) => acc(s, idx + 1, re, j) -*/ - -bool theory_seq::add_step2accept(expr* step, bool& change) { - context& ctx = get_context(); - SASSERT(ctx.get_assignment(step) == l_true); - expr* re = nullptr, *t = nullptr, *s = nullptr, *idx = nullptr, *i = nullptr, *j = nullptr; - VERIFY(is_step(step, s, idx, re, i, j, t)); - literal acc1 = mk_accept(s, idx, re, i); - switch (ctx.get_assignment(acc1)) { - case l_false: - break; - case l_undef: - change = true; - return true; - case l_true: { - change = true; - rational r; - VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); - expr_ref idx1(m_autil.mk_int(r.get_unsigned() + 1), m); - literal acc2 = mk_accept(s, idx1, re, j); - literal_vector lits; - lits.push_back(acc1); - lits.push_back(ctx.get_literal(step)); - lits.push_back(~acc2); - switch (ctx.get_assignment(acc2)) { - case l_undef: - propagate_lit(nullptr, 2, lits.c_ptr(), acc2); - break; - case l_true: - break; - case l_false: - set_conflict(nullptr, lits); - break; - } - break; +void theory_seq::add_theory_assumptions(expr_ref_vector & assumptions) { + TRACE("seq", tout << "add_theory_assumption " << m_util.has_re() << "\n";); + if (m_util.has_re()) { + expr_ref dlimit = mk_max_unfolding_depth(); + m_max_unfolding_lit = mk_literal(dlimit); + TRACE("seq", tout << "add_theory_assumption " << dlimit << " " << assumptions << "\n";); + assumptions.push_back(dlimit); } +} + +bool theory_seq::should_research(expr_ref_vector & unsat_core) { + if (!m_util.has_re()) { + return false; + } + for (auto & e : unsat_core) { + if (is_max_unfolding(e)) { + m_max_unfolding_depth = (3 * m_max_unfolding_depth) / 2 + 1; + IF_VERBOSE(1, verbose_stream() << "(smt.seq :increase-depth " << m_max_unfolding_depth << ")\n"); + return true; + } } return false; } @@ -5683,8 +5626,7 @@ void theory_seq::propagate_not_prefix(expr* e) { /* !suffix(e1,e2) => e1 != "" !suffix(e1,e2) => len(e1) > len(e2) or e1 = ycx & e2 = zdx & c != d - */ - +*/ void theory_seq::propagate_not_suffix(expr* e) { context& ctx = get_context(); @@ -5732,34 +5674,6 @@ bool theory_seq::canonizes(bool sign, expr* e) { } -bool theory_seq::propagate_automata() { - context& ctx = get_context(); - if (m_atoms_qhead == m_atoms.size()) { - return false; - } - m_trail_stack.push(value_trail(m_atoms_qhead)); - ptr_vector re_add; - bool change = false; - while (m_atoms_qhead < m_atoms.size() && !ctx.inconsistent()) { - expr* e = m_atoms[m_atoms_qhead]; - TRACE("seq", tout << mk_pp(e, m) << "\n";); - bool reQ = false; - if (is_accept(e)) { - reQ = add_accept2step(e, change); - } - else if (is_step(e)) { - reQ = add_step2accept(e, change); - } - if (reQ) { - re_add.push_back(e); - change = true; - } - ++m_atoms_qhead; - } - m_atoms.append(re_add); - return change || get_context().inconsistent(); -} - void theory_seq::get_concat(expr* e, ptr_vector& concats) { expr* e1 = nullptr, *e2 = nullptr; while (true) { diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index ef26f78cc..aa278e972 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -289,6 +289,16 @@ namespace smt { } }; + struct s_in_re { + literal m_lit; + expr* m_s; + expr* m_re; + eautomaton* m_aut; + bool m_active; + s_in_re(literal l, expr*s, expr* re, eautomaton* aut): + m_lit(l), m_s(s), m_re(re), m_aut(aut), m_active(true) {} + }; + void erase_index(unsigned idx, unsigned i); struct stats { @@ -353,11 +363,10 @@ namespace smt { scoped_ptr_vector m_automata; obj_map m_re2aut; expr_ref_vector m_res; + unsigned m_max_unfolding_depth; + literal m_max_unfolding_lit; + vector m_s_in_re; - // queue of asserted atoms - ptr_vector m_atoms; - unsigned_vector m_atoms_lim; - unsigned m_atoms_qhead; bool m_new_solution; // new solution added bool m_new_propagation; // new propagation to core re2automaton m_mk_aut; @@ -378,6 +387,8 @@ namespace smt { void pop_scope_eh(unsigned num_scopes) override; void restart_eh() override; void relevant_eh(app* n) override; + bool should_research(expr_ref_vector &) override; + void add_theory_assumptions(expr_ref_vector & assumptions) override; theory* mk_fresh(context* new_ctx) override { return alloc(theory_seq, new_ctx->get_manager(), m_params); } char const * get_name() const override { return "seq"; } theory_var mk_var(enode* n) override; @@ -579,7 +590,7 @@ namespace smt { expr_ref mk_add(expr* a, expr* b); expr_ref mk_len(expr* s) const { return expr_ref(m_util.str.mk_length(s), m); } enode* ensure_enode(expr* a); - + enode* get_root(expr* a) { return ensure_enode(a)->get_root(); } dependency* mk_join(dependency* deps, literal lit); dependency* mk_join(dependency* deps, literal_vector const& lits); @@ -604,25 +615,24 @@ namespace smt { literal mk_accept(expr* s, expr* idx, expr* re, expr* state); literal mk_accept(expr* s, expr* idx, expr* re, unsigned i) { return mk_accept(s, idx, re, m_autil.mk_int(i)); } bool is_accept(expr* acc) const { return is_skolem(m_accept, acc); } - bool is_accept(expr* acc, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut) { - return is_acc_rej(m_accept, acc, s, idx, re, i, aut); - } - bool is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut); - expr_ref mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned j, expr* acc); + bool is_accept(expr* acc, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut); + expr_ref mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned j, expr* t); bool is_step(expr* e, expr*& s, expr*& tail, expr*& re, expr*& i, expr*& j, expr*& t) const; bool is_step(expr* e) const; - void propagate_step(literal lit, expr* n); - bool add_accept2step(expr* acc, bool& change); - bool add_step2accept(expr* step, bool& change); + bool is_max_unfolding(expr* e) const { return is_skolem(symbol("seq.max_unfolding_depth"), e); } + expr_ref mk_max_unfolding_depth() { + return mk_skolem(symbol("seq.max_unfolding_depth"), + m_autil.mk_int(m_max_unfolding_depth), + nullptr, nullptr, nullptr, m.mk_bool_sort()); + } void propagate_not_prefix(expr* e); void propagate_not_suffix(expr* e); void ensure_nth(literal lit, expr* s, expr* idx); bool canonizes(bool sign, expr* e); void propagate_non_empty(literal lit, expr* s); bool propagate_is_conc(expr* e, expr* conc); - void propagate_acc_rej_length(literal lit, expr* acc_rej); - bool propagate_automata(); - void add_atom(expr* e); + void propagate_step(literal lit, expr* n); + void propagate_accept(literal lit, expr* e); void new_eq_eh(dependency* dep, enode* n1, enode* n2); // diagnostics From 96043216e576e3b6d005ce5407cdc022befcaaf5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Nov 2018 17:25:56 -0800 Subject: [PATCH 224/227] fix unsound unfolding Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 3799ff082..ac417aa76 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -5509,7 +5509,8 @@ void theory_seq::propagate_step(literal lit, expr* step) { rational lo; rational _idx; - if (lower_bound(s, lo) && lo.is_unsigned() && m_autil.is_numeral(idx, _idx) && lo >= _idx) { + VERIFY(m_autil.is_numeral(idx, _idx)); + if (lower_bound(s, lo) && lo.is_unsigned() && lo >= _idx) { // skip } else { @@ -5580,6 +5581,7 @@ void theory_seq::add_theory_assumptions(expr_ref_vector & assumptions) { } bool theory_seq::should_research(expr_ref_vector & unsat_core) { + TRACE("seq", tout << unsat_core << " " << m_util.has_re() << "\n";); if (!m_util.has_re()) { return false; } From 32df9b1155dba9ccdee8b8fdea031d2041def140 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Nov 2018 17:34:53 -0800 Subject: [PATCH 225/227] mac build errors Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index ac417aa76..2bce6cf56 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3450,7 +3450,6 @@ void theory_seq::ensure_digit_axiom() { } bool theory_seq::add_itos_val_axiom(expr* e) { - context& ctx = get_context(); rational val; expr* n = nullptr; TRACE("seq", tout << mk_pp(e, m) << "\n";); @@ -3514,7 +3513,6 @@ expr_ref theory_seq::digit2int(expr* ch) { } void theory_seq::add_itos_axiom(expr* e) { - context& ctx = get_context(); rational val; expr* n = nullptr; TRACE("seq", tout << mk_pp(e, m) << "\n";); @@ -5206,7 +5204,6 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { expr* e = ctx.bool_var2expr(v); expr* e1 = nullptr, *e2 = nullptr; expr_ref f(m); - bool change = false; literal lit(v, !is_true); if (m_util.str.is_prefix(e, e1, e2)) { @@ -5436,7 +5433,7 @@ eautomaton* theory_seq::get_automaton(expr* re) { m_mk_aut.set_solver(alloc(seq_expr_solver, m, get_context().get_fparams())); } result = m_mk_aut(re); - CTRACE("seq", result, result->display(tout, display_expr(m));); + CTRACE("seq", result, { display_expr d(m); result->display(tout, d); }); m_automata.push_back(result); m_re2aut.insert(re, result); m_res.push_back(re); From 074ed0d874b2740a66af999f40d8469b2d87004c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Nov 2018 17:39:19 -0800 Subject: [PATCH 226/227] fix warnings Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/goal2sat.cpp | 4 ---- src/smt/tactic/smt_tactic.cpp | 7 ------- 2 files changed, 11 deletions(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index d484ecda4..68e18375f 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -460,7 +460,6 @@ struct goal2sat::imp { check_unsigned(k); svector wlits; convert_pb_args(t, wlits); - unsigned sz = m_result_stack.size(); if (root && m_solver.num_user_scopes() == 0) { m_result_stack.reset(); unsigned k1 = k.get_unsigned(); @@ -492,7 +491,6 @@ struct goal2sat::imp { k += rational(wl.first); } check_unsigned(k); - unsigned sz = m_result_stack.size(); if (root && m_solver.num_user_scopes() == 0) { m_result_stack.reset(); unsigned k1 = k.get_unsigned(); @@ -550,7 +548,6 @@ struct goal2sat::imp { void convert_at_least_k(app* t, rational const& k, bool root, bool sign) { SASSERT(k.is_unsigned()); sat::literal_vector lits; - unsigned sz = m_result_stack.size(); convert_pb_args(t->get_num_args(), lits); if (root && m_solver.num_user_scopes() == 0) { m_result_stack.reset(); @@ -570,7 +567,6 @@ struct goal2sat::imp { void convert_at_most_k(app* t, rational const& k, bool root, bool sign) { SASSERT(k.is_unsigned()); sat::literal_vector lits; - unsigned sz = m_result_stack.size(); convert_pb_args(t->get_num_args(), lits); for (sat::literal& l : lits) { l.neg(); diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 730061c8b..2d894d3ee 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -293,13 +293,6 @@ static tactic * mk_seq_smt_tactic(params_ref const & p) { return alloc(smt_tactic, p); } -static tactic * mk_seq_smt_tactic_using(bool auto_config, params_ref const & _p) { - params_ref p = _p; - p.set_bool("auto_config", auto_config); - tactic * r = mk_seq_smt_tactic(p); - TRACE("smt_tactic", tout << "auto_config: " << auto_config << "\nr: " << r << "\np: " << p << "\n";); - return using_params(r, p); -} tactic * mk_parallel_smt_tactic(ast_manager& m, params_ref const& p) { return mk_parallel_tactic(mk_smt_solver(m, p, symbol::null), p); From aa723f1eeeb6bc8963ebf19f2adbaee24a668e71 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Nov 2018 18:13:35 -0800 Subject: [PATCH 227/227] fix uninitialized variable Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 93a8956df..8fc130ef1 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -345,7 +345,8 @@ seq_decl_plugin::seq_decl_plugin(): m_init(false), m_charc_sym("Char"), m_string(nullptr), m_char(nullptr), - m_re(nullptr) {} + m_re(nullptr), + m_has_re(false) {} void seq_decl_plugin::finalize() { for (unsigned i = 0; i < m_sigs.size(); ++i)