From a2dcf87e10ad4119bfb1aa740cb4701a163c7372 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Feb 2019 14:43:39 -0800 Subject: [PATCH 001/156] add ESRP signing of nuget packages Signed-off-by: Nikolaj Bjorner --- scripts/authorization.json | 15 ++++++++++ scripts/mk_nuget_release.py | 57 +++++++++++++++++++++++++++++++++++-- scripts/policy.json | 8 ++++++ 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 scripts/authorization.json create mode 100644 scripts/policy.json diff --git a/scripts/authorization.json b/scripts/authorization.json new file mode 100644 index 000000000..97fb21dfa --- /dev/null +++ b/scripts/authorization.json @@ -0,0 +1,15 @@ +{ + "Version": "1.0.0", + "AuthenticationType": "AAD_CERT", + "ClientId": "1c614a83-2dbe-4d3c-853b-effaefd4fb20", + "AuthCert": { + "SubjectName": "1c614a83-2dbe-4d3c-853b-effaefd4fb20.microsoft.com", + "StoreLocation": "LocalMachine", + "StoreName": "My" + }, + "RequestSigningCert": { + "SubjectName": "1c614a83-2dbe-4d3c-853b-effaefd4fb20", + "StoreLocation": "LocalMachine", + "StoreName": "My" + } +} diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index db7a1af64..ebd0e0ba7 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -7,6 +7,7 @@ # 3. copy over Microsoft.Z3.dll from suitable distribution # 4. copy nuspec file from packages # 5. call nuget pack +# 6. sign package import json import os @@ -22,6 +23,7 @@ import mk_project data = json.loads(urllib.request.urlopen("https://api.github.com/repos/Z3Prover/z3/releases/latest").read().decode()) version_str = data['tag_name'] +version_num = version_str[3:] print(version_str) @@ -50,7 +52,8 @@ def classify_package(f): ext, dst = os_info[os_name] return os_name, f[:-4], ext, dst return None - + + def unpack(): shutil.rmtree("out", ignore_errors=True) # unzip files in packages @@ -103,17 +106,67 @@ Linux Dependencies: """ with open("out/Microsoft.Z3.nuspec", 'w') as f: - f.write(contents % version_str[3:]) + f.write(contents % version_num) def create_nuget_package(): subprocess.call(["nuget", "pack"], cwd="out") +nuget_sign_input = """ +{ + "Version": "1.0.0", + "SignBatches" + : + [ + { + "SourceLocationType": "UNC", + "SourceRootDirectory": "%s", + "DestinationLocationType": "UNC", + "DestinationRootDirectory": "%s", + "SignRequestFiles": [ + { + "CustomerCorrelationId": "42fc9577-af9e-4ac9-995d-1788d8721d17", + "SourceLocation": "Microsoft.Z3.%s.nupkg", + "DestinationLocation": "Microsoft.Z3.%s.nupkg" + } + ], + "SigningInfo": { + "Operations": [ + { + "KeyCode" : "CP-401405", + "OperationCode" : "NuGetSign", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + }, + { + "KeyCode" : "CP-401405", + "OperationCode" : "NuGetVerify", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + } + ] + } + } + ] +}""" + +def sign_nuget_package(): + package_name = "Microsoft.Z3.%s.nupkg" % version_num + input_file = "out/nuget_sign_input.json" + output_path = os.path.abspath("out").replace("\\","\\\\") + with open(input_file, 'w') as f: + f.write(nuget_sign_input % (output_path, output_path, version_num, version_num)) + subprocess.call(["EsrpClient.exe", "sign", "-a", "authorization.json", "-p", "policy.json", "-i", input_file, "-o", "out\\diagnostics.json"]) + + def main(): mk_dir("packages") download_installs() unpack() create_nuget_spec() create_nuget_package() + sign_nuget_package() main() diff --git a/scripts/policy.json b/scripts/policy.json new file mode 100644 index 000000000..badebe683 --- /dev/null +++ b/scripts/policy.json @@ -0,0 +1,8 @@ +{ + "Version": "1.0.0", + "Intent": "ProductRelease", + "ContentType": "Binaries", + "ContentOrigin": "1stParty", + "ProductState": "Next", + "Audience": "ExternalBroad" +} From 6a0c409b0f0deab89cfc242b5b42629638d78c66 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 28 Feb 2019 10:53:27 +0000 Subject: [PATCH 002/156] move a few strings instead of copying --- src/ast/array_decl_plugin.cpp | 16 ++++++++-------- src/ast/ast.cpp | 4 ++-- src/ast/ast.h | 2 +- src/ast/ast_smt_pp.cpp | 2 +- src/ast/bv_decl_plugin.cpp | 2 +- src/ast/datatype_decl_plugin.cpp | 2 +- src/ast/dl_decl_plugin.cpp | 4 ++-- src/ast/rewriter/enum2bv_rewriter.cpp | 2 +- src/ast/rewriter/rewriter_types.h | 2 +- src/ast/seq_decl_plugin.cpp | 10 +++++----- src/cmd_context/cmd_context.cpp | 4 ++-- src/parsers/smt2/smt2parser.cpp | 6 +++--- src/smt/smt_quantifier.cpp | 2 +- src/util/gparams.cpp | 2 +- 14 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 44c423c09..211c67953 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -141,7 +141,7 @@ func_decl * array_decl_plugin::mk_map(func_decl* f, unsigned arity, sort* const* std::ostringstream buffer; buffer << "map expects to take as many arguments as the function being mapped, " << "it was given " << arity << " but expects " << f->get_arity(); - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); return nullptr; } if (arity == 0) { @@ -158,14 +158,14 @@ func_decl * array_decl_plugin::mk_map(func_decl* f, unsigned arity, sort* const* if (!is_array_sort(domain[i])) { std::ostringstream buffer; buffer << "map expects an array sort as argument at position " << i; - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); return nullptr; } if (get_array_arity(domain[i]) != dom_arity) { std::ostringstream buffer; buffer << "map expects all arguments to have the same array domain, " << "this is not the case for argument " << i; - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); return nullptr; } for (unsigned j = 0; j < dom_arity; ++j) { @@ -173,7 +173,7 @@ func_decl * array_decl_plugin::mk_map(func_decl* f, unsigned arity, sort* const* std::ostringstream buffer; buffer << "map expects all arguments to have the same array domain, " << "this is not the case for argument " << i; - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); return nullptr; } } @@ -181,7 +181,7 @@ func_decl * array_decl_plugin::mk_map(func_decl* f, unsigned arity, sort* const* std::ostringstream buffer; buffer << "map expects the argument at position " << i << " to have the array range the same as the function"; - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); return nullptr; } } @@ -244,7 +244,7 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) { if (num_parameters != arity) { std::stringstream strm; strm << "select requires " << num_parameters << " arguments, but was provided with " << arity << " arguments"; - m_manager->raise_exception(strm.str().c_str()); + m_manager->raise_exception(strm.str()); return nullptr; } ptr_buffer new_domain; // we need this because of coercions. @@ -256,7 +256,7 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) { 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()); + m_manager->raise_exception(strm.str()); UNREACHABLE(); return nullptr; } @@ -284,7 +284,7 @@ func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) { std::ostringstream buffer; buffer << "store expects the first argument to be an array taking " << num_parameters+1 << ", instead it was passed " << (arity - 1) << "arguments"; - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); UNREACHABLE(); return nullptr; } diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index b84dac136..c73e2f1d8 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1584,8 +1584,8 @@ 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()); +void ast_manager::raise_exception(std::string && msg) { + throw ast_exception(std::move(msg)); } diff --git a/src/ast/ast.h b/src/ast/ast.h index 9c6c811b0..1c25ff9ec 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1574,7 +1574,7 @@ public: // Equivalent to throw ast_exception(msg) Z3_NORETURN void raise_exception(char const * msg); - Z3_NORETURN void raise_exception(std::string const& s); + Z3_NORETURN void raise_exception(std::string && s); std::ostream& display(std::ostream& out, parameter const& p); diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index ea220f7e7..48daf6988 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -951,7 +951,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { strm << "(set-logic " << m_logic << ")\n"; } if (!m_attributes.empty()) { - strm << "; " << m_attributes.c_str(); + strm << "; " << m_attributes; } #if 0 diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 738444b3b..4ffd7d6cb 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -624,7 +624,7 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p if (m.get_sort(args[i]) != r->get_domain(i)) { std::ostringstream buffer; buffer << "Argument " << mk_pp(args[i], m) << " at position " << i << " does not match declaration " << mk_pp(r, m); - m.raise_exception(buffer.str().c_str()); + m.raise_exception(buffer.str()); return nullptr; } } diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 8bf0abbb3..146c7359f 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -342,7 +342,7 @@ namespace datatype { std::ostringstream buffer; buffer << "second argument to field update should be " << mk_ismt2_pp(rng, m) << " instead of " << mk_ismt2_pp(domain[1], m); - m.raise_exception(buffer.str().c_str()); + m.raise_exception(buffer.str()); return nullptr; } range = domain[0]; diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index 01b06518e..43cf50662 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -54,7 +54,7 @@ namespace datalog { } std::ostringstream buffer; buffer << msg << ", value is not within bound " << low << " <= " << val << " <= " << up; - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); return false; } @@ -676,7 +676,7 @@ namespace datalog { } std::stringstream strm; strm << "sort '" << mk_pp(s, m) << "' is not recognized as a sort that contains numeric values.\nUse Bool, BitVec, Int, Real, or a Finite domain sort"; - m.raise_exception(strm.str().c_str()); + m.raise_exception(strm.str()); return nullptr; } diff --git a/src/ast/rewriter/enum2bv_rewriter.cpp b/src/ast/rewriter/enum2bv_rewriter.cpp index 65250282c..f6f2d6f85 100644 --- a/src/ast/rewriter/enum2bv_rewriter.cpp +++ b/src/ast/rewriter/enum2bv_rewriter.cpp @@ -86,7 +86,7 @@ struct enum2bv_rewriter::imp { void throw_non_fd(expr* e) { std::stringstream strm; strm << "unable to handle nested data-type expression " << mk_pp(e, m); - throw rewriter_exception(strm.str().c_str()); + throw rewriter_exception(strm.str()); } void check_for_fd(unsigned n, expr* const* args) { diff --git a/src/ast/rewriter/rewriter_types.h b/src/ast/rewriter/rewriter_types.h index 094357fed..77ab42b2a 100644 --- a/src/ast/rewriter/rewriter_types.h +++ b/src/ast/rewriter/rewriter_types.h @@ -46,7 +46,7 @@ inline br_status unsigned2br_status(unsigned u) { class rewriter_exception : public default_exception { public: - rewriter_exception(char const * msg):default_exception(msg) {} + rewriter_exception(std::string && msg) : default_exception(std::move(msg)) {} }; #endif diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 20e1fb36c..7576e43c0 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -400,7 +400,7 @@ void seq_decl_plugin::match_right_assoc(psig& sig, unsigned dsz, sort *const* do std::ostringstream strm; strm << "Unexpected number of arguments to '" << sig.m_name << "' "; strm << "at least one argument expected " << dsz << " given"; - m.raise_exception(strm.str().c_str()); + m.raise_exception(strm.str()); } bool is_match = true; for (unsigned i = 0; is_match && i < dsz; ++i) { @@ -420,7 +420,7 @@ void seq_decl_plugin::match_right_assoc(psig& sig, unsigned dsz, sort *const* do if (range) { strm << " and range: " << mk_pp(range, m); } - m.raise_exception(strm.str().c_str()); + m.raise_exception(strm.str()); } range_out = apply_binding(binding, sig.m_range); SASSERT(range_out); @@ -434,7 +434,7 @@ void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* ran std::ostringstream strm; strm << "Unexpected number of arguments to '" << sig.m_name << "' "; strm << sig.m_dom.size() << " arguments expected " << dsz << " given"; - m.raise_exception(strm.str().c_str()); + m.raise_exception(strm.str()); } bool is_match = true; for (unsigned i = 0; is_match && i < dsz; ++i) { @@ -459,13 +459,13 @@ void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* ran strm << mk_pp(sig.m_dom[i].get(), m) << " "; } - m.raise_exception(strm.str().c_str()); + m.raise_exception(strm.str()); } if (!range && dsz == 0) { std::ostringstream strm; strm << "Sort of polymorphic function '" << sig.m_name << "' "; strm << "is ambiguous. Function takes no arguments and sort of range has not been constrained"; - m.raise_exception(strm.str().c_str()); + m.raise_exception(strm.str()); } range_out = apply_binding(m_binding, sig.m_range); SASSERT(range_out); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index c58453460..9de183ca8 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -797,7 +797,7 @@ void cmd_context::insert(symbol const & s, func_decl * f) { msg += " '"; msg += s.str(); msg += "' (with the given signature) already declared"; - throw cmd_exception(msg.c_str()); + throw cmd_exception(std::move(msg)); } if (s != f->get_name()) { TRACE("func_decl_alias", tout << "adding alias for: " << f->get_name() << ", alias: " << s << "\n";); @@ -1142,7 +1142,7 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg for (unsigned i = 0; i < fs.get_num_entries(); ++i) { buffer << "\ndeclared: " << mk_pp(fs.get_entry(i), m()) << " "; } - throw cmd_exception(buffer.str().c_str()); + throw cmd_exception(buffer.str()); } if (well_sorted_check_enabled()) m().check_sort(f, num_args, args); diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index bf1e25e57..c103b0276 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -482,7 +482,7 @@ namespace smt2 { if (context[0]) msg += ": "; msg += "unknown sort '"; msg += id.str() + "'"; - throw parser_exception(msg.c_str()); + throw parser_exception(std::move(msg)); } void consume_sexpr() { @@ -1633,7 +1633,7 @@ namespace smt2 { void unknown_var_const_name(symbol id) { std::string msg = "unknown constant/variable '"; msg += id.str() + "'"; - throw parser_exception(msg.c_str()); + throw parser_exception(std::move(msg)); } rational m_last_bv_numeral; // for bv, bvbin, bvhex @@ -2431,7 +2431,7 @@ namespace smt2 { buffer << "invalid function definition, sort mismatch. Expcected " << mk_pp(f->get_range(), m()) << " but function body has sort " << mk_pp(m().get_sort(body), m()); - throw parser_exception(buffer.str().c_str()); + throw parser_exception(buffer.str()); } m_ctx.insert_rec_fun(f, bindings, ids, body); } diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 008da06ec..d0ca05ff9 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -173,7 +173,7 @@ namespace smt { if (num_instances > 0) { out << "[quantifier_instances] "; out.width(10); - out << q->get_qid().str().c_str() << " : "; + out << q->get_qid().str() << " : "; out.width(6); out << num_instances << " : "; out.width(3); diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 9ab3123a2..6b5919f8e 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -172,7 +172,7 @@ public: } for (unsigned i = 0; i < n; i++) { if (tmp[i] == '.') { - param_name = tmp.substr(i+1).c_str(); + param_name = tmp.c_str() + i + 1; tmp.resize(i); mod_name = tmp.c_str(); return; From 4c76d43670f5307287506680de6c8eb24e263923 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Feb 2019 08:35:22 -0800 Subject: [PATCH 003/156] add binary_merge encoding option Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 37 +++++++- src/sat/sat_params.pyg | 2 +- src/smt/smt_kernel.cpp | 3 +- src/smt/smt_kernel.h | 2 +- src/test/sorting_network.cpp | 137 ++++++++++++++++++++++++++++ src/util/sorting_network.h | 106 +++++++++++++++++++++ 6 files changed, 283 insertions(+), 4 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 0faf08515..015372933 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -161,7 +161,6 @@ struct pb2bv_rewriter::imp { } if (m_pb_solver == "segmented") { - expr_ref result(m); switch (is_le) { case l_true: return mk_seg_le(k); case l_false: return mk_seg_ge(k); @@ -169,6 +168,11 @@ struct pb2bv_rewriter::imp { } } + if (m_pb_solver == "binary_merge") { + expr_ref result = binary_merge(is_le, k); + if (result) return result; + } + // fall back to divide and conquer encoding. SASSERT(k.is_pos()); expr_ref zero(m), bound(m); @@ -494,6 +498,37 @@ struct pb2bv_rewriter::imp { return true; } + /** + \brief binary merge encoding. + */ + expr_ref binary_merge(lbool is_le, rational const& k) { + expr_ref result(m); + unsigned_vector coeffs; + for (rational const& c : m_coeffs) { + if (c.is_unsigned()) { + coeffs.push_back(c.get_unsigned()); + } + else { + return result; + } + } + if (!k.is_unsigned()) { + return result; + } + switch (is_le) { + case l_true: + result = m_sort.le(k.get_unsigned(), coeffs.size(), coeffs.c_ptr(), m_args.c_ptr()); + break; + case l_false: + result = m_sort.ge(k.get_unsigned(), coeffs.size(), coeffs.c_ptr(), m_args.c_ptr()); + break; + case l_undef: + result = m_sort.eq(k.get_unsigned(), coeffs.size(), coeffs.c_ptr(), m_args.c_ptr()); + break; + } + return result; + } + /** \brief Segment based encoding. The PB terms are partitoned into segments, such that each segment contains arguments with the same cofficient. diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 88b196d04..178132f63 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -43,7 +43,7 @@ def_module_params('sat', ('drat.check_unsat', BOOL, False, 'build up internal proof and check'), ('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)'), + ('pb.solver', SYMBOL, 'solver', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), binary_merge, segmented, solver (use native 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'), diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index adcda3979..6c5bad479 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -383,8 +383,9 @@ namespace smt { return m_imp->next_decision(); } - void kernel::display(std::ostream & out) const { + std::ostream& kernel::display(std::ostream & out) const { m_imp->display(out); + return out; } void kernel::collect_statistics(::statistics & st) const { diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index a46195e02..e21a49dc4 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -237,7 +237,7 @@ namespace smt { /** \brief (For debubbing purposes) Prints the state of the kernel */ - void display(std::ostream & out) const; + std::ostream& display(std::ostream & out) const; /** \brief Collect runtime statistics. diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 2470df528..9a143c012 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -522,7 +522,144 @@ static void tst_sorting_network(sorting_network_encoding enc) { test_sorting5(enc); } +static void test_pb(unsigned max_w, unsigned sz, unsigned_vector& ws) { + if (ws.empty()) { + for (unsigned w = 1; w <= max_w; ++w) { + ws.push_back(w); + test_pb(max_w, sz, ws); + ws.pop_back(); + } + } + else if (ws.size() < sz) { + for (unsigned w = ws.back(); w <= max_w; ++w) { + ws.push_back(w); + test_pb(max_w, sz, ws); + ws.pop_back(); + } + } + else { + SASSERT(ws.size() == sz); + ast_manager m; + reg_decl_plugins(m); + expr_ref_vector xs(m), nxs(m); + expr_ref ge(m), eq(m); + smt_params fp; + smt::kernel solver(m, fp); + for (unsigned i = 0; i < sz; ++i) { + xs.push_back(m.mk_const(symbol(i), m.mk_bool_sort())); + nxs.push_back(m.mk_not(xs.back())); + } + std::cout << ws << " " << "\n"; + for (unsigned k = max_w + 1; k < ws.size()*max_w; ++k) { + + ast_ext2 ext(m); + psort_nw sn(ext); + solver.push(); + //std::cout << "bound: " << k << "\n"; + //std::cout << ws << " " << xs << "\n"; + ge = sn.ge(k, sz, ws.c_ptr(), xs.c_ptr()); + //std::cout << "ge: " << ge << "\n"; + for (expr* cls : ext.m_clauses) { + solver.assert_expr(cls); + } + // solver.display(std::cout); + // for each truth assignment to xs, validate + // that circuit computes the right value for ge + for (unsigned i = 0; i < (1ul << sz); ++i) { + solver.push(); + unsigned sum = 0; + for (unsigned j = 0; j < sz; ++j) { + if (0 == ((1 << j) & i)) { + solver.assert_expr(xs.get(j)); + sum += ws[j]; + } + else { + solver.assert_expr(nxs.get(j)); + } + } + // std::cout << "bound: " << k << "\n"; + // std::cout << ws << " " << xs << "\n"; + // std::cout << sum << " >= " << k << " : " << (sum >= k) << " "; + solver.push(); + if (sum < k) { + solver.assert_expr(m.mk_not(ge)); + } + else { + solver.assert_expr(ge); + } + // solver.display(std::cout) << "\n"; + VERIFY(solver.check() == l_true); + solver.pop(1); + + solver.push(); + if (sum >= k) { + solver.assert_expr(m.mk_not(ge)); + } + else { + solver.assert_expr(ge); + } + // solver.display(std::cout) << "\n"; + VERIFY(l_false == solver.check()); + solver.pop(1); + solver.pop(1); + } + solver.pop(1); + + solver.push(); + eq = sn.eq(k, sz, ws.c_ptr(), xs.c_ptr()); + + for (expr* cls : ext.m_clauses) { + solver.assert_expr(cls); + } + // for each truth assignment to xs, validate + // that circuit computes the right value for ge + for (unsigned i = 0; i < (1ul << sz); ++i) { + solver.push(); + unsigned sum = 0; + for (unsigned j = 0; j < sz; ++j) { + if (0 == ((1 << j) & i)) { + solver.assert_expr(xs.get(j)); + sum += ws[j]; + } + else { + solver.assert_expr(nxs.get(j)); + } + } + solver.push(); + if (sum != k) { + solver.assert_expr(m.mk_not(eq)); + } + else { + solver.assert_expr(eq); + } + // solver.display(std::cout) << "\n"; + VERIFY(solver.check() == l_true); + solver.pop(1); + + solver.push(); + if (sum == k) { + solver.assert_expr(m.mk_not(eq)); + } + else { + solver.assert_expr(eq); + } + VERIFY(l_false == solver.check()); + solver.pop(1); + solver.pop(1); + } + + solver.pop(1); + } + } +} + +static void tst_pb() { + unsigned_vector ws; + test_pb(3, 3, ws); +} + void tst_sorting_network() { + tst_pb(); tst_sorting_network(sorting_network_encoding::unate_at_most); tst_sorting_network(sorting_network_encoding::circuit_at_most); tst_sorting_network(sorting_network_encoding::ordered_at_most); diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index b094a5b66..b7358b58c 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -357,6 +357,112 @@ Notes: } } + /** + \brief encode clauses for ws*xs >= k + + - normalize inequality to ws'*xs' >= a*2^(bits-1) + - for each binary digit, sort contributions + - merge with even digits from lower layer - creating 2*n vector + - for last layer return that index a is on. + */ + + literal le(unsigned k, unsigned n, unsigned const* ws, literal const* xs) { + unsigned sum = 0; + literal_vector Xs; + for (unsigned i = 0; i < n; ++i) { + sum += ws[i]; + Xs.push_back(mk_not(xs[i])); + } + if (k >= sum) { + return ctx.mk_true(); + } + return ge(sum - k, n, ws, Xs.begin()); + } + + literal ge(unsigned k, unsigned n, unsigned const* ws, literal const* xs) { + m_t = GE_FULL; + return cmp(k, n, ws, xs); + } + + literal eq(unsigned k, unsigned n, unsigned const* ws, literal const* xs) { + return mk_and(ge(k, n, ws, xs), le(k, n, ws, xs)); +#if 0 + m_t = EQ; + return cmp(k, n, ws, xs); +#endif + } + + literal cmp(unsigned k, unsigned n, unsigned const* ws, literal const* xs) { + unsigned w_max = 0, sum = 0; + literal_vector Xs; + unsigned_vector Ws; + for (unsigned i = 0; i < n; ++i) { + sum += ws[i]; + w_max = std::max(ws[i], w_max); + Xs.push_back(xs[i]); + Ws.push_back(ws[i]); + } + if (sum < k) { + return ctx.mk_false(); + } + + // Normalize to form Ws*Xs ~ a*2^{q-1} + SASSERT(w_max > 0); + unsigned bits = 0; + while (w_max > 0) { + bits++; + w_max >>= 1; + } + unsigned pow = (1ul << (bits-1)); + unsigned a = (k + pow - 1) / pow; // a*pow >= k + SASSERT(a*pow >= k); + SASSERT((a-1)*pow < k); + if (a*pow > k) { + Ws.push_back(a*pow - k); + Xs.push_back(ctx.mk_true()); + ++n; + k = a*pow; + } + literal_vector W, We, B, S, E; + for (unsigned i = 0; i < bits; ++i) { + + // B is digits from Xs that are set at bit position i + B.reset(); + for (unsigned j = 0; j < n; ++j) { + if (0 != ((1 << i) & Ws[j])) { + B.push_back(Xs[j]); + } + } + + // We is every second position of W + We.reset(); + for (unsigned j = 0; j + 2 <= W.size(); j += 2) { + We.push_back(W[j+1]); + } + // if we test for equality, then what is not included has to be false. + if (m_t == EQ && W.size() % 2 == 1) { + E.push_back(mk_not(W.back())); + } + + // B is the sorted (from largest to smallest bit) version of S + S.reset(); + sorting(B.size(), B.begin(), S); + + // W is the merge of S and We + W.reset(); + merge(S.size(), S.begin(), We.size(), We.begin(), W); + } + + if (m_t == EQ) { + E.push_back(W[a - 1]); + if (a < W.size()) E.push_back(mk_not(W[a])); + return mk_and(E); + } + SASSERT(m_t == GE_FULL); + return W[a - 1]; + } + + private: From 5fa5719c6fcd3d169d2714b78ad433a76e84ca20 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Feb 2019 08:58:58 -0800 Subject: [PATCH 004/156] fix #2159 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index f8651ab90..2a3348ed9 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10147,7 +10147,7 @@ def IndexOf(s, substr, offset): substr = _coerce_seq(substr, ctx) if _is_int(offset): offset = IntVal(offset, ctx) - return SeqRef(Z3_mk_seq_index(s.ctx_ref(), s.as_ast(), substr.as_ast(), offset.as_ast()), s.ctx) + return ArithRef(Z3_mk_seq_index(s.ctx_ref(), s.as_ast(), substr.as_ast(), offset.as_ast()), s.ctx) def Length(s): """Obtain the length of a sequence 's' From 69d7d8ff877971bf8d47d67cd2ab098b70d39e3b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Feb 2019 11:42:17 -0800 Subject: [PATCH 005/156] local Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 4 +++- src/sat/sat_config.h | 8 ++++++-- src/sat/sat_solver/inc_sat_solver.cpp | 5 ----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 08336b1e4..6b8181886 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -201,8 +201,10 @@ namespace sat { m_pb_solver = PB_SOLVER; else if (s == symbol("segmented")) m_pb_solver = PB_SEGMENTED; + else if (s == symbol("binary_merge")) + m_pb_solver == PB_BINARY_MERGE; else - throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting, segmented"); + throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting, segmented, binary_merge"); s = p.pb_resolve(); if (s == "cardinality") diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index b8d0ca0f5..e9895a051 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -57,7 +57,8 @@ namespace sat { PB_CIRCUIT, PB_SORTING, PB_TOTALIZER, - PB_SEGMENTED + PB_SEGMENTED, + PB_BINARY_MERGE }; enum pb_resolve { @@ -162,7 +163,6 @@ namespace sat { bool m_drat_check_unsat; bool m_drat_check_sat; - pb_solver m_pb_solver; bool m_card_solver; pb_resolve m_pb_resolve; pb_lemma_format m_pb_lemma_format; @@ -182,6 +182,10 @@ namespace sat { config(params_ref const & p); void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); + + private: + pb_solver m_pb_solver; + }; }; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 9ca1150a9..0cc829379 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -300,11 +300,6 @@ public: sat_params p1(p); m_params.set_bool("keep_cardinality_constraints", p1.cardinality_solver()); m_params.set_sym("pb.solver", p1.pb_solver()); - - m_params.set_bool("keep_pb_constraints", m_solver.get_config().m_pb_solver == sat::PB_SOLVER); - m_params.set_bool("pb_num_system", m_solver.get_config().m_pb_solver == sat::PB_SORTING); - m_params.set_bool("pb_totalizer", m_solver.get_config().m_pb_solver == sat::PB_TOTALIZER); - m_params.set_bool("xor_solver", p1.xor_solver()); m_solver.updt_params(m_params); m_solver.set_incremental(is_incremental() && !override_incremental()); From 69f03952a70130111e28b47a8662506f2841d237 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 28 Feb 2019 12:11:34 -1000 Subject: [PATCH 006/156] enable lar_solver::constraint_holds Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 31e9d2654..db81ad403 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -945,7 +945,6 @@ bool lar_solver::all_constraints_hold() const { } bool lar_solver::constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const { - return true; mpq left_side_val = get_left_side_val(constr, var_map); switch (constr.m_kind) { case LE: return left_side_val <= constr.m_right_side; From a2dddbd7a549e6529b089714210fdf7477367204 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Feb 2019 14:28:03 -0800 Subject: [PATCH 007/156] check pb solver Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 20 +++++++------------- src/sat/sat_config.h | 12 ------------ src/sat/sat_model_converter.cpp | 7 +------ 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 6b8181886..78d93880c 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -191,20 +191,14 @@ namespace sat { // PB parameters s = p.pb_solver(); - if (s == symbol("circuit")) - m_pb_solver = PB_CIRCUIT; - else if (s == symbol("sorting")) - m_pb_solver = PB_SORTING; - else if (s == symbol("totalizer")) - m_pb_solver = PB_TOTALIZER; - else if (s == symbol("solver")) - m_pb_solver = PB_SOLVER; - else if (s == symbol("segmented")) - m_pb_solver = PB_SEGMENTED; - else if (s == symbol("binary_merge")) - m_pb_solver == PB_BINARY_MERGE; - else + if (s != symbol("circuit") && + s != symbol("sorting") && + s != symbol("totalizer") && + s != symbol("solver") && + s != symbol("segmented") && + s != symbol("binary_merge")) { throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting, segmented, binary_merge"); + } s = p.pb_resolve(); if (s == "cardinality") diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index e9895a051..5203b0838 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -52,15 +52,6 @@ namespace sat { BH_LRB }; - enum pb_solver { - PB_SOLVER, - PB_CIRCUIT, - PB_SORTING, - PB_TOTALIZER, - PB_SEGMENTED, - PB_BINARY_MERGE - }; - enum pb_resolve { PB_CARDINALITY, PB_ROUNDING @@ -183,9 +174,6 @@ namespace sat { void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); - private: - pb_solver m_pb_solver; - }; }; diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 577588305..60b758fec 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -221,12 +221,7 @@ namespace sat { void model_converter::add_elim_stack(entry & e) { e.m_elim_stack.push_back(stackv().empty() ? nullptr : alloc(elim_stack, stackv())); -#if 0 - if (!stackv().empty() && e.get_kind() == ATE) { - IF_VERBOSE(0, display(verbose_stream(), e) << "\n"); - } -#endif - for (auto const& s : stackv()) VERIFY(legal_to_flip(s.second.var())); + VERIFY(for (auto const& s : stackv()) VERIFY(legal_to_flip(s.second.var()))); stackv().reset(); } From 006590f32932c3b3c832c8428d5b54f537933f75 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Feb 2019 14:29:20 -0800 Subject: [PATCH 008/156] na Signed-off-by: Nikolaj Bjorner --- src/sat/sat_model_converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 60b758fec..fb8c48866 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -221,7 +221,7 @@ namespace sat { void model_converter::add_elim_stack(entry & e) { e.m_elim_stack.push_back(stackv().empty() ? nullptr : alloc(elim_stack, stackv())); - VERIFY(for (auto const& s : stackv()) VERIFY(legal_to_flip(s.second.var()))); + // VERIFY(for (auto const& s : stackv()) VERIFY(legal_to_flip(s.second.var()));); stackv().reset(); } From ccc170a06e9f5b8dfae559d8640e908155b23fc1 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sat, 2 Mar 2019 16:42:18 +0000 Subject: [PATCH 009/156] model evaluator: cleanup cache when model_eval param changes --- src/api/api_model.cpp | 1 - src/model/model_evaluator.cpp | 27 +++++++++++++++------------ src/model/model_evaluator_params.pyg | 1 - 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 0937e668e..8fba5e9f6 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include "api/z3.h" #include "api/api_log_macros.h" #include "api/api_context.h" diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 968aca51f..eb8f718fb 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -36,7 +36,7 @@ Revision History: #include "model/model_smt2_pp.h" #include "ast/rewriter/var_subst.h" - +namespace { struct evaluator_cfg : public default_rewriter_cfg { ast_manager & m; model_core & m_model; @@ -53,7 +53,6 @@ struct evaluator_cfg : public default_rewriter_cfg { unsigned long long m_max_memory; unsigned m_max_steps; bool m_model_completion; - bool m_cache; bool m_array_equalities; bool m_array_as_stores; obj_map m_def_cache; @@ -91,7 +90,6 @@ struct evaluator_cfg : public default_rewriter_cfg { model_evaluator_params p(_p); m_max_memory = megabytes_to_bytes(p.max_memory()); m_max_steps = p.max_steps(); - m_cache = p.cache(); m_model_completion = p.completion(); m_array_equalities = p.array_equalities(); m_array_as_stores = p.array_as_stores(); @@ -328,8 +326,6 @@ struct evaluator_cfg : public default_rewriter_cfg { return num_steps > m_max_steps; } - bool cache_results() const { return m_cache; } - br_status mk_array_eq(expr* a, expr* b, expr_ref& result) { TRACE("model_evaluator", tout << "mk_array_eq " << m_array_equalities << "\n";); if (a == b) { @@ -544,8 +540,7 @@ struct evaluator_cfg : public default_rewriter_cfg { return true; } }; - -template class rewriter_tpl; +} struct model_evaluator::imp : public rewriter_tpl { evaluator_cfg m_cfg; @@ -557,6 +552,11 @@ struct model_evaluator::imp : public rewriter_tpl { set_cancel_check(false); } void expand_stores(expr_ref &val) {m_cfg.expand_stores(val);} + void reset() { + rewriter_tpl::reset(); + m_cfg.reset(); + m_cfg.m_def_cache.reset(); + } }; model_evaluator::model_evaluator(model_core & md, params_ref const & p) { @@ -580,7 +580,10 @@ void model_evaluator::get_param_descrs(param_descrs & r) { } void model_evaluator::set_model_completion(bool f) { - m_imp->cfg().m_model_completion = f; + if (m_imp->cfg().m_model_completion != f) { + reset(); + m_imp->cfg().m_model_completion = f; + } } bool model_evaluator::get_model_completion() const { @@ -597,8 +600,8 @@ unsigned model_evaluator::get_num_steps() const { void model_evaluator::cleanup(params_ref const & p) { model_core & md = m_imp->cfg().m_model; - dealloc(m_imp); - m_imp = alloc(imp, md, p); + m_imp->~imp(); + new (m_imp) imp(md, p); } void model_evaluator::reset(params_ref const & p) { @@ -607,8 +610,8 @@ void model_evaluator::reset(params_ref const & p) { } void model_evaluator::reset(model_core &model, params_ref const& p) { - dealloc(m_imp); - m_imp = alloc(imp, model, p); + m_imp->~imp(); + new (m_imp) imp(model, p); } diff --git a/src/model/model_evaluator_params.pyg b/src/model/model_evaluator_params.pyg index 509b3e7c7..890e19cfe 100644 --- a/src/model/model_evaluator_params.pyg +++ b/src/model/model_evaluator_params.pyg @@ -3,7 +3,6 @@ def_module_params('model_evaluator', params=(max_memory_param(), max_steps_param(), ('completion', BOOL, False, 'assigns an interptetation to symbols that do not have one in the current model, when evaluating expressions in the current model'), - ('cache', BOOL, True, 'cache intermediate results in the model evaluator'), ('array_equalities', BOOL, True, 'evaluate array equalities'), ('array_as_stores', BOOL, True, 'return array as a set of stores'), )) From 3ee5c0e7d9d6b5cca9567631533f0e9569c6218b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 11:33:44 -0800 Subject: [PATCH 010/156] fix #2164 address some of simplification shortcommings from #2151 #2152 #2153 Signed-off-by: Nikolaj Bjorner --- src/api/api_tactic.cpp | 4 +- src/api/c++/z3++.h | 2 +- src/ast/array_decl_plugin.cpp | 4 + src/ast/array_decl_plugin.h | 7 ++ src/ast/rewriter/array_rewriter.cpp | 161 +++++++++++++--------------- src/cmd_context/eval_cmd.cpp | 1 + src/parsers/smt2/smt2parser.cpp | 1 + src/smt/theory_lra.cpp | 5 +- src/util/lp/lar_solver.cpp | 39 ++++--- src/util/lp/lar_solver.h | 1 + src/util/mpz.cpp | 2 +- 11 files changed, 120 insertions(+), 107 deletions(-) diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index 7c0143201..491fb8354 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -52,7 +52,9 @@ extern "C" { RESET_ERROR_CODE(); tactic_cmd * t = mk_c(c)->find_tactic_cmd(symbol(name)); if (t == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); + std::stringstream err; + err << "unknown tactic " << name; + SET_ERROR_CODE(Z3_INVALID_ARG, err.str().c_str()); RETURN_Z3(nullptr); } tactic * new_t = t->mk(mk_c(c)->m()); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 6113fdbe9..cbb12ea99 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2387,7 +2387,7 @@ namespace z3 { return *this; } void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } - // void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } + void add(expr_vector const& v) { check_context(*this, v); for (unsigned i = 0; i < v.size(); ++i) add(v[i]); } unsigned size() const { return Z3_goal_size(ctx(), m_goal); } expr operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); } diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 211c67953..7975a4d61 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -576,6 +576,10 @@ func_decl * array_recognizers::get_as_array_func_decl(func_decl * f) const { return to_func_decl(f->get_parameter(0).get_ast()); } +bool array_recognizers::is_const(expr* e, expr*& v) const { + return is_const(e) && (v = to_app(e)->get_arg(0), true); +} + array_util::array_util(ast_manager& m): array_recognizers(m.mk_family_id("array")), m_manager(m) { diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index c735fb811..1ae0c9593 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -152,6 +152,8 @@ public: bool is_as_array(func_decl* f, func_decl*& g) const { return is_decl_of(f, m_fid, OP_AS_ARRAY) && (g = get_as_array_func_decl(f), true); } func_decl * get_as_array_func_decl(expr * n) const; func_decl * get_as_array_func_decl(func_decl* f) const; + + bool is_const(expr* e, expr*& v) const; }; class array_util : public array_recognizers { @@ -178,6 +180,11 @@ public: parameter param(s); return m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, ¶m, 1, &v); } + app * mk_const_array(unsigned n, sort * const* s, expr * v) { + vector ps; + for (unsigned i = 0; i < n; ++i) ps.push_back(parameter(s[i])); + return m_manager.mk_app(m_fid, OP_CONST_ARRAY, n, ps.c_ptr(), 1, &v); + } app * mk_empty_set(sort * s) { return mk_const_array(s, m_manager.mk_false()); } diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 56e094dab..8ff6dd654 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -230,105 +230,92 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, } br_status array_rewriter::mk_map_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args >= 0); - bool is_store0 = m_util.is_store(args[0]); - bool is_const0 = m_util.is_const(args[0]); - if (num_args == 1) { - // - // map_f (store a j v) = (store (map_f a) j (f v)) - // - if (is_store0) { - app * store_expr = to_app(args[0]); - unsigned num_args = store_expr->get_num_args(); - SASSERT(num_args >= 3); - expr * a = store_expr->get_arg(0); - expr * v = store_expr->get_arg(num_args-1); - - ptr_buffer new_args; - - new_args.push_back(m_util.mk_map(f, 1, &a)); // (map_f a) - new_args.append(num_args - 2, store_expr->get_args() + 1); // j - new_args.push_back(m().mk_app(f, v)); // (f v) - - result = m().mk_app(get_fid(), OP_STORE, new_args.size(), new_args.c_ptr()); - return BR_REWRITE2; - } - - // - // map_f (const v) = (const (f v)) - // - if (is_const0) { - expr * fv = m().mk_app(f, to_app(args[0])->get_arg(0)); - result = m_util.mk_const_array(m().get_sort(args[0]), fv); - return BR_REWRITE2; - } - return BR_FAILED; - } - SASSERT(num_args > 1); - - if (is_store0) { - unsigned num_indices = to_app(args[0])->get_num_args() - 2; - unsigned i; - for (i = 1; i < num_args; i++) { - if (!m_util.is_store(args[i])) - break; - unsigned j; - for (j = 1; j < num_indices+1; j++) { - if (to_app(args[0])->get_arg(j) != to_app(args[i])->get_arg(j)) - break; - } - if (j < num_indices+1) - break; + app* store_expr = nullptr; + unsigned num_indices = 0; + bool same_store = true; + for (unsigned i = 0; same_store && i < num_args; i++) { + expr* a = args[i]; + if (m_util.is_const(a)) { + continue; } - // - // map_f (store a_1 j v_1) ... (store a_n j v_n) --> (store (map_f a_1 ... a_n) j (f v_1 ... v_n)) - // - if (i == num_args) { - ptr_buffer arrays; - ptr_buffer values; - for (unsigned i = 0; i < num_args; i++) { - arrays.push_back(to_app(args[i])->get_arg(0)); - values.push_back(to_app(args[i])->get_arg(num_indices+1)); + else if (!m_util.is_store(a)) { + same_store = false; + } + else if (!store_expr) { + num_indices = to_app(a)->get_num_args() - 2; + store_expr = to_app(a); + } + else { + for (unsigned j = 1; same_store && j < num_indices + 1; j++) { + same_store = (store_expr->get_arg(j) == to_app(a)->get_arg(j)); } - ptr_buffer new_args; - new_args.push_back(m_util.mk_map(f, arrays.size(), arrays.c_ptr())); + } + } + + // + // map_f (store a_1 j v_1) ... (store a_n j v_n) --> (store (map_f a_1 ... a_n) j (f v_1 ... v_n)) + // + if (same_store) { + ptr_buffer arrays; + ptr_buffer values; + for (unsigned i = 0; i < num_args; i++) { + expr* a = args[i]; + if (m_util.is_const(a)) { + arrays.push_back(a); + values.push_back(to_app(a)->get_arg(0)); + } + else { + arrays.push_back(to_app(a)->get_arg(0)); + values.push_back(to_app(a)->get_arg(num_indices+1)); + } + } + ptr_buffer new_args; + new_args.push_back(m_util.mk_map(f, arrays.size(), arrays.c_ptr())); + if (store_expr) { new_args.append(num_indices, to_app(args[0])->get_args() + 1); new_args.push_back(m().mk_app(f, values.size(), values.c_ptr())); result = m().mk_app(get_fid(), OP_STORE, new_args.size(), new_args.c_ptr()); - return BR_REWRITE2; } - return BR_FAILED; + else { + result = m_util.mk_const_array(m().get_sort(args[0]), new_args.back()); + } + return BR_REWRITE2; } - if (is_const0) { - unsigned i; - for (i = 1; i < num_args; i++) { - if (!m_util.is_const(args[i])) - break; + // + // map_f (lambda x1 b1) ... (lambda x1 bn) -> lambda x1 (f b1 .. bn) + // + quantifier* lam = nullptr; + for (unsigned i = 0; i < num_args; ++i) { + if (is_lambda(args[i])) { + lam = to_quantifier(args[i]); } - if (i == num_args) { - // - // map_f (const v_1) ... (const v_n) = (const (f v_1 ... v_n)) - // - ptr_buffer values; - for (unsigned i = 0; i < num_args; i++) { - values.push_back(to_app(args[i])->get_arg(0)); + } + if (lam) { + expr_ref_vector args1(m()); + for (unsigned i = 0; i < num_args; ++i) { + expr* a = args[i]; + if (m_util.is_const(a)) { + args1.push_back(to_app(a)->get_arg(0)); + } + else if (is_lambda(a)) { + lam = to_quantifier(a); + args1.push_back(lam->get_expr()); + } + else { + expr_ref_vector sel(m()); + sel.push_back(a); + unsigned n = lam->get_num_decls(); + for (unsigned i = 0; i < n; ++i) { + sel.push_back(m().mk_var(n - i - 1, lam->get_decl_sort(i))); + } + args1.push_back(m_util.mk_select(sel.size(), sel.c_ptr())); } - - expr * fv = m().mk_app(f, values.size(), values.c_ptr()); - sort * in_s = get_sort(args[0]); - ptr_vector domain; - unsigned domain_sz = get_array_arity(in_s); - for (unsigned i = 0; i < domain_sz; i++) - domain.push_back(get_array_domain(in_s, i)); - sort_ref out_s(m()); - out_s = m_util.mk_array_sort(domain_sz, domain.c_ptr(), f->get_range()); - parameter p(out_s.get()); - result = m().mk_app(get_fid(), OP_CONST_ARRAY, 1, &p, 1, &fv); - return BR_REWRITE2; } - return BR_FAILED; + result = m().mk_app(f, args1.size(), args1.c_ptr()); + result = m().update_quantifier(lam, result); + return BR_REWRITE3; } return BR_FAILED; diff --git a/src/cmd_context/eval_cmd.cpp b/src/cmd_context/eval_cmd.cpp index a599cfa4a..e6980583a 100644 --- a/src/cmd_context/eval_cmd.cpp +++ b/src/cmd_context/eval_cmd.cpp @@ -71,6 +71,7 @@ public: expr_ref r(ctx.m()); unsigned timeout = m_params.get_uint("timeout", UINT_MAX); unsigned rlimit = m_params.get_uint("rlimit", 0); + md->compress(); model_evaluator ev(*(md.get()), m_params); ev.set_solver(alloc(th_solver, ctx)); cancel_eh eh(ctx.m().limit()); diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index c103b0276..b3b8082fe 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -2677,6 +2677,7 @@ namespace smt2 { m_ctx.regular_stream() << "("; expr ** expr_it = expr_stack().c_ptr() + spos; expr ** expr_end = expr_it + m_cached_strings.size(); + md->compress(); for (unsigned i = 0; expr_it < expr_end; expr_it++, i++) { model::scoped_model_completion _scm(md, true); expr_ref v = (*md)(*expr_it); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 81edb2c67..605498e53 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -3329,13 +3329,12 @@ public: st = lp::lp_status::UNBOUNDED; } else { - vi = m_theory_var2var_index[v]; - st = m_solver->maximize_term(vi, term_max); + st = m_solver->maximize_term(v, term_max); } - TRACE("arith", display(tout << st << " v" << v << " vi: " << vi << "\n");); switch (st) { case lp::lp_status::OPTIMAL: { init_variable_values(); + TRACE("arith", display(tout << st << " v" << v << " vi: " << vi << "\n");); inf_rational val = get_value(v); // inf_rational val(term_max.x, term_max.y); blocker = mk_gt(v); diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index db81ad403..2daedc045 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -85,6 +85,15 @@ std::ostream& lar_solver::print_implied_bound(const implied_bound& be, std::ostr out << "end of implied bound" << std::endl; return out; } + +std::ostream& lar_solver::print_values(std::ostream& out) const { + for (unsigned i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { + const numeric_pair & rp = m_mpq_lar_core_solver.m_r_x[i]; + out << this->get_column_name(i) << " -> " << rp << "\n"; + } + return out; +} + bool lar_solver::implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const { std::unordered_map coeff_map; @@ -463,29 +472,28 @@ void lar_solver::prepare_costs_for_r_solver(const lar_term & term) { bool lar_solver::maximize_term_on_corrected_r_solver(lar_term & term, impq &term_max) { settings().backup_costs = false; + bool ret = false; switch (settings().simplex_strategy()) { case simplex_strategy_enum::tableau_rows: prepare_costs_for_r_solver(term); settings().simplex_strategy() = simplex_strategy_enum::tableau_costs; - { - bool ret = maximize_term_on_tableau(term, term_max); - settings().simplex_strategy() = simplex_strategy_enum::tableau_rows; - set_costs_to_zero(term); - m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::OPTIMAL); - return ret; - } + ret = maximize_term_on_tableau(term, term_max); + settings().simplex_strategy() = simplex_strategy_enum::tableau_rows; + set_costs_to_zero(term); + m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::OPTIMAL); + return ret; + case simplex_strategy_enum::tableau_costs: prepare_costs_for_r_solver(term); - { - bool ret = maximize_term_on_tableau(term, term_max); - set_costs_to_zero(term); - m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::OPTIMAL); - return ret; - } - + ret = maximize_term_on_tableau(term, term_max); + set_costs_to_zero(term); + m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::OPTIMAL); + return ret; + case simplex_strategy_enum::lu: lp_assert(false); // not implemented return false; + default: lp_unreachable(); // wrong mode } @@ -511,6 +519,7 @@ lar_term lar_solver::get_term_to_maximize(unsigned ext_j) const { lp_status lar_solver::maximize_term(unsigned ext_j, impq &term_max) { + TRACE("lar_solver", print_values(tout);); bool was_feasible = m_mpq_lar_core_solver.m_r_solver.calc_current_x_is_feasible_include_non_basis(); impq prev_value; lar_term term = get_term_to_maximize(ext_j); @@ -559,6 +568,7 @@ lp_status lar_solver::maximize_term(unsigned ext_j, term_max = prev_value; m_mpq_lar_core_solver.m_r_x = backup; } + TRACE("lar_solver", print_values(tout);); return term_max == opt_val? lp_status::OPTIMAL :lp_status::FEASIBLE; } @@ -1185,6 +1195,7 @@ void lar_solver::get_model(std::unordered_map & variable_values) break; } + TRACE("get_model", tout << get_column_name(i) << " := " << x << "\n";); variable_values[i] = x; } } while (i != m_mpq_lar_core_solver.m_r_x.size()); diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 7af9cfacb..1dce8524e 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -457,6 +457,7 @@ public: std::ostream& print_implied_bound(const implied_bound& be, std::ostream & out) const; + std::ostream& print_values(std::ostream& out) const; mpq get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const; diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 6776acf65..178d5042d 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -1784,7 +1784,7 @@ void display_binary_data(std::ostream &out, unsigned val, unsigned numBits) { template void mpz_manager::display_bin(std::ostream & out, mpz const & a, unsigned num_bits) const { if (is_small(a)) { - display_binary_data(out, get_uint64(a), num_bits); + display_binary_data(out, static_cast(get_uint64(a)), num_bits); } else { #ifndef _MP_GMP digit_t *ds = digits(a); From 7399f78dfd2c38fc50170f3560811bc54b917859 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 12:40:59 -0800 Subject: [PATCH 011/156] disable model compression for regressions Signed-off-by: Nikolaj Bjorner --- src/parsers/smt2/smt2parser.cpp | 2 +- src/qe/qe_lite.cpp | 1 - src/sat/sat_solver.cpp | 2 +- src/util/lp/int_solver.cpp | 4 +++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index b3b8082fe..e09ea0f3c 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -2677,7 +2677,7 @@ namespace smt2 { m_ctx.regular_stream() << "("; expr ** expr_it = expr_stack().c_ptr() + spos; expr ** expr_end = expr_it + m_cached_strings.size(); - md->compress(); + // md->compress(); for (unsigned i = 0; expr_it < expr_end; expr_it++, i++) { model::scoped_model_completion _scm(md, true); expr_ref v = (*md)(*expr_it); diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 1f8f78aaa..4e2d8413a 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -2430,7 +2430,6 @@ class qe_lite_tactic : public tactic { tactic_report report("qe-lite", *g); proof_ref new_pr(m); expr_ref new_f(m); - bool produce_proofs = g->proofs_enabled(); unsigned sz = g->size(); for (unsigned i = 0; i < sz; i++) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c6b04cfd8..427077804 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -42,8 +42,8 @@ namespace sat { m_checkpoint_enabled(true), m_config(p), m_par(nullptr), - m_cls_allocator_idx(false), m_drat(*this), + m_cls_allocator_idx(false), m_cleaner(*this), m_simplifier(*this, p), m_scc(*this, p), diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 0967c6cc6..6af668506 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -282,6 +282,7 @@ void int_solver::find_feasible_solution() { lia_move int_solver::run_gcd_test() { if (settings().m_int_run_gcd_test) { settings().st().m_gcd_calls++; + TRACE("int_solver", tout << "gcd-test " << settings().st().m_gcd_calls << "\n";); if (!gcd_test()) { settings().st().m_gcd_conflicts++; return lia_move::conflict; @@ -291,6 +292,7 @@ lia_move int_solver::run_gcd_test() { } lia_move int_solver::gomory_cut() { + TRACE("int_solver", tout << "gomory " << m_number_of_calls << "\n";); if ((m_number_of_calls) % settings().m_int_gomory_cut_period != 0) return lia_move::undef; @@ -1052,7 +1054,7 @@ lia_move int_solver::create_branch_on_column(int j) { m_k = m_upper? floor(get_value(j)) : ceil(get_value(j)); } - TRACE("arith_int", tout << "branching v" << j << " = " << get_value(j) << "\n"; + TRACE("int_solver", tout << "branching v" << j << " = " << get_value(j) << "\n"; display_column(tout, j); tout << "k = " << m_k << std::endl; ); From 8e812ea239ead910eafc2f6db96fad6fcde8dc07 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 12:51:26 -0800 Subject: [PATCH 012/156] revert fix for #2164 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 605498e53..bb329fbf1 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -3329,7 +3329,8 @@ public: st = lp::lp_status::UNBOUNDED; } else { - st = m_solver->maximize_term(v, term_max); + vi = m_theory_var2var_index[v]; + st = m_solver->maximize_term(vi, term_max); } switch (st) { case lp::lp_status::OPTIMAL: { @@ -3342,11 +3343,13 @@ public: } case lp::lp_status::FEASIBLE: { inf_rational val = get_value(v); + TRACE("arith", display(tout << st << " v" << v << " vi: " << vi << "\n");); blocker = mk_gt(v); return inf_eps(rational::zero(), val); } default: SASSERT(st == lp::lp_status::UNBOUNDED); + TRACE("arith", display(tout << st << " v" << v << " vi: " << vi << "\n");); has_shared = false; blocker = m.mk_false(); return inf_eps(rational::one(), inf_rational()); From 06725de4773746812e5249f613d69052a4a3e665 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 3 Mar 2019 10:57:25 -1000 Subject: [PATCH 013/156] fixes in indices in lar_solver::maximize_term() Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 3 ++- src/util/lp/lar_solver.cpp | 19 +++++++++---------- src/util/lp/lar_solver.h | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 605498e53..babafe129 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -3329,7 +3329,8 @@ public: st = lp::lp_status::UNBOUNDED; } else { - st = m_solver->maximize_term(v, term_max); + vi = m_theory_var2var_index[v]; + st = m_solver->maximize_term(vi, term_max); } switch (st) { case lp::lp_status::OPTIMAL: { diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 2daedc045..879dfd32f 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -505,24 +505,23 @@ bool lar_solver::remove_from_basis(unsigned j) { return m_mpq_lar_core_solver.m_r_solver.remove_from_basis(j); } -lar_term lar_solver::get_term_to_maximize(unsigned ext_j) const { - unsigned local_j; - if (m_var_register.external_is_used(ext_j, local_j)) { +lar_term lar_solver::get_term_to_maximize(unsigned j_or_term) const { + if (is_term(j_or_term)) + return get_term(j_or_term); + if (j_or_term < m_mpq_lar_core_solver.m_r_x.size()) { lar_term r; - r. add_monomial(one_of_type(), local_j); + r.add_monomial(one_of_type(), j_or_term); return r; - } - if (!is_term(ext_j) || adjust_term_index(ext_j) >= m_terms.size()) - return lar_term(); // return an empty term - return get_term(ext_j); + } + return lar_term(); // return an empty term } -lp_status lar_solver::maximize_term(unsigned ext_j, +lp_status lar_solver::maximize_term(unsigned j_or_term, impq &term_max) { TRACE("lar_solver", print_values(tout);); bool was_feasible = m_mpq_lar_core_solver.m_r_solver.calc_current_x_is_feasible_include_non_basis(); impq prev_value; - lar_term term = get_term_to_maximize(ext_j); + lar_term term = get_term_to_maximize(j_or_term); if (term.is_empty()) { return lp_status::UNBOUNDED; } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 1dce8524e..39adbd86f 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -310,7 +310,7 @@ public: impq &term_max); // starting from a given feasible state look for the maximum of the term // return true if found and false if unbounded - lp_status maximize_term(unsigned ext_j , + lp_status maximize_term(unsigned j_or_term, impq &term_max); From e51b5fd99c10319584230d13e57f9bbe6e0fbd18 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 13:10:11 -0800 Subject: [PATCH 014/156] fix t154 regression Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.cpp | 1 + src/ast/rewriter/array_rewriter.cpp | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 7975a4d61..396f93973 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -127,6 +127,7 @@ func_decl * array_decl_plugin::mk_const(sort * s, unsigned arity, sort * const * return nullptr; } if (!m_manager->compatible_sorts(get_array_range(s), domain[0])) { + SASSERT(false); m_manager->raise_exception("invalid const array definition, sort mismatch between array range and argument"); return nullptr; } diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 8ff6dd654..f5798dede 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -270,15 +270,21 @@ br_status array_rewriter::mk_map_core(func_decl * f, unsigned num_args, expr * c values.push_back(to_app(a)->get_arg(num_indices+1)); } } - ptr_buffer new_args; - new_args.push_back(m_util.mk_map(f, arrays.size(), arrays.c_ptr())); if (store_expr) { + ptr_buffer new_args; + new_args.push_back(m_util.mk_map(f, arrays.size(), arrays.c_ptr())); new_args.append(num_indices, to_app(args[0])->get_args() + 1); new_args.push_back(m().mk_app(f, values.size(), values.c_ptr())); result = m().mk_app(get_fid(), OP_STORE, new_args.size(), new_args.c_ptr()); } else { - result = m_util.mk_const_array(m().get_sort(args[0]), new_args.back()); + expr_ref value(m().mk_app(f, values.size(), values.c_ptr()), m()); + sort* s0 = m().get_sort(args[0]); + unsigned sz = get_array_arity(s0); + ptr_vector domain; + for (unsigned i = 0; i < sz; ++i) domain.push_back(get_array_domain(s0, i)); + sort_ref s(m_util.mk_array_sort(sz, domain.c_ptr(), m().get_sort(value)), m()); + result = m_util.mk_const_array(s, value); } return BR_REWRITE2; } From 6c331279ae3eb7d0b9c6346ab5a221d90c0dd3ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 13:22:12 -0800 Subject: [PATCH 015/156] fix array regressions Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.cpp | 1 - src/ast/array_decl_plugin.h | 5 ----- src/cmd_context/eval_cmd.cpp | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 396f93973..7975a4d61 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -127,7 +127,6 @@ func_decl * array_decl_plugin::mk_const(sort * s, unsigned arity, sort * const * return nullptr; } if (!m_manager->compatible_sorts(get_array_range(s), domain[0])) { - SASSERT(false); m_manager->raise_exception("invalid const array definition, sort mismatch between array range and argument"); return nullptr; } diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 1ae0c9593..e0342ad72 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -180,11 +180,6 @@ public: parameter param(s); return m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, ¶m, 1, &v); } - app * mk_const_array(unsigned n, sort * const* s, expr * v) { - vector ps; - for (unsigned i = 0; i < n; ++i) ps.push_back(parameter(s[i])); - return m_manager.mk_app(m_fid, OP_CONST_ARRAY, n, ps.c_ptr(), 1, &v); - } app * mk_empty_set(sort * s) { return mk_const_array(s, m_manager.mk_false()); } diff --git a/src/cmd_context/eval_cmd.cpp b/src/cmd_context/eval_cmd.cpp index e6980583a..8819eb584 100644 --- a/src/cmd_context/eval_cmd.cpp +++ b/src/cmd_context/eval_cmd.cpp @@ -71,7 +71,7 @@ public: expr_ref r(ctx.m()); unsigned timeout = m_params.get_uint("timeout", UINT_MAX); unsigned rlimit = m_params.get_uint("rlimit", 0); - md->compress(); + // md->compress(); model_evaluator ev(*(md.get()), m_params); ev.set_solver(alloc(th_solver, ctx)); cancel_eh eh(ctx.m().limit()); From 7b4c919fcf5db8b7f58e92675648ad019dc0507a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 14:11:05 -0800 Subject: [PATCH 016/156] stubs for stronger array equality rewriting Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.cpp | 17 +++++ src/ast/array_decl_plugin.h | 2 + src/ast/rewriter/array_rewriter.cpp | 108 +++++++++++++++++++++++----- src/ast/rewriter/array_rewriter.h | 2 + 4 files changed, 110 insertions(+), 19 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 7975a4d61..d2d1039fa 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -580,6 +580,23 @@ bool array_recognizers::is_const(expr* e, expr*& v) const { return is_const(e) && (v = to_app(e)->get_arg(0), true); } +bool array_recognizers::is_store_ext(expr* _e, expr_ref& a, expr_ref_vector& args, expr_ref& value) { + ast_manager& m = a.m(); + if (is_store(_e)) { + app* e = to_app(_e); + a = e->get_arg(0); + unsigned sz = e->get_num_args(); + args.reset(); + for (unsigned i = 1; i < sz-1; ++i) { + args.push_back(e->get_arg(i)); + } + value = e->get_arg(sz-1); + return true; + } + return false; +} + + array_util::array_util(ast_manager& m): array_recognizers(m.mk_family_id("array")), m_manager(m) { diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index e0342ad72..5b44d31c9 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -154,6 +154,8 @@ public: func_decl * get_as_array_func_decl(func_decl* f) const; bool is_const(expr* e, expr*& v) const; + + bool is_store_ext(expr* e, expr_ref& a, expr_ref_vector& args, expr_ref& value); }; class array_util : public array_recognizers { diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index f5798dede..6ad9c3654 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -389,10 +389,96 @@ br_status array_rewriter::mk_set_subset(expr * arg1, expr * arg2, expr_ref & res return BR_REWRITE3; } +void array_rewriter::mk_eq(expr* e, expr* lhs, expr* rhs, expr_ref_vector& fmls) { + expr_ref tmp1(m()), tmp2(m()); + expr_ref a(m()), v(m()); + expr_ref_vector args0(m()), args(m()); + while (m_util.is_store_ext(e, a, args0, v)) { + args.reset(); + args.push_back(lhs); + args.append(args0); + mk_select(args.size(), args.c_ptr(), tmp1); + args[0] = rhs; + mk_select(args.size(), args.c_ptr(), tmp2); + fmls.push_back(m().mk_eq(tmp1, tmp2)); + e = a; + } +} + +bool array_rewriter::has_index_set(expr* e, expr_ref& e0, vector& indices) { + expr_ref_vector args(m()); + expr_ref a(m()), v(m()); + a = e; + while (m_util.is_store_ext(e, a, args, v)) { + indices.push_back(args); + e = a; + } + e0 = e; + if (is_lambda(e0)) { + quantifier* q = to_quantifier(e0); + e = q->get_expr(); + unsigned num_idxs = q->get_num_decls(); + expr* e1, *e2, *e3; + ptr_vector eqs; + while (!is_ground(e) && m().is_ite(e, e1, e2, e3) && is_ground(e2)) { + args.reset(); + args.resize(num_idxs, nullptr); + eqs.reset(); + eqs.push_back(e1); + for (unsigned i = 0; i < eqs.size(); ++i) { + expr* e = eqs[i]; + if (m().is_and(e)) { + eqs.append(to_app(e)->get_num_args(), to_app(e)->get_args()); + } + else if (m().is_eq(e, e1, e2)) { + if (is_var(e2)) { + std::swap(e1, e2); + } + if (is_var(e1) && is_ground(e2)) { + unsigned idx = to_var(e1)->get_idx(); + args[num_idxs - idx - 1] = e2; + } + else { + return false; + } + } + } + for (unsigned i = 0; i < num_idxs; ++i) { + if (!args.get(i)) return false; + } + indices.push_back(args); + e = e3; + } + e0 = e; + return is_ground(e); + } + return true; +} + br_status array_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { if (!m_expand_store_eq) { return BR_FAILED; } + expr_ref_vector fmls(m()); + +#if 0 + // lambda friendly version of array equality rewriting. + vector indices; + expr_ref lhs0(m()), rhs0(m()); + expr_ref tmp1(m()), tmp2(m()); + if (has_index_set(lhs, lhs0, indices) && has_index_set(rhs, rhs0, indices) && lhs0 == rhs0) { + expr_ref_vector args(m()); + for (auto const& idxs : indices) { + args.reset(); + args.push_back(lhs); + args.append(idxs); + mk_select(args.size(), args.c_ptr(), tmp1); + args[0] = rhs; + mk_select(args.size(), args.c_ptr(), tmp2); + fmls.push_back(m().mk_eq(tmp1, tmp2)); + } + } +#endif expr* lhs1 = lhs; while (m_util.is_store(lhs1)) { lhs1 = to_app(lhs1)->get_arg(0); @@ -404,25 +490,9 @@ br_status array_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) if (lhs1 != rhs1) { return BR_FAILED; } - ptr_buffer fmls, args; - expr* e; - expr_ref tmp1(m()), tmp2(m()); -#define MK_EQ() \ - while (m_util.is_store(e)) { \ - args.push_back(lhs); \ - args.append(to_app(e)->get_num_args()-2,to_app(e)->get_args()+1); \ - mk_select(args.size(), args.c_ptr(), tmp1); \ - args[0] = rhs; \ - mk_select(args.size(), args.c_ptr(), tmp2); \ - fmls.push_back(m().mk_eq(tmp1, tmp2)); \ - e = to_app(e)->get_arg(0); \ - args.reset(); \ - } \ - - e = lhs; - MK_EQ(); - e = rhs; - MK_EQ(); + + mk_eq(lhs, lhs, rhs, fmls); + mk_eq(rhs, lhs, rhs, fmls); result = m().mk_and(fmls.size(), fmls.c_ptr()); return BR_REWRITE_FULL; } diff --git a/src/ast/rewriter/array_rewriter.h b/src/ast/rewriter/array_rewriter.h index 90b3b6f34..a951db725 100644 --- a/src/ast/rewriter/array_rewriter.h +++ b/src/ast/rewriter/array_rewriter.h @@ -35,6 +35,8 @@ class array_rewriter { bool m_expand_select_ite; template lbool compare_args(unsigned num_args, expr * const * args1, expr * const * args2); + bool has_index_set(expr* e, expr_ref& e0, vector& indices); + void mk_eq(expr* e, expr* lhs, expr* rhs, expr_ref_vector& fmls); public: array_rewriter(ast_manager & m, params_ref const & p = params_ref()): m_util(m) { From 752ac09fee0cca13d1d78acd09ef68816ab15681 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 14:30:59 -0800 Subject: [PATCH 017/156] fix #2161 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 53 +++++------------------------------------- 1 file changed, 6 insertions(+), 47 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index bb329fbf1..1a63b97fb 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -236,6 +236,7 @@ class theory_lra::imp { expr* m_not_handled; ptr_vector m_underspecified; ptr_vector m_idiv_terms; + unsigned m_idiv_bound_calls; unsigned_vector m_var_trail; vector > m_use_list; // bounds where variables are used. @@ -307,6 +308,7 @@ class theory_lra::imp { if (m_solver) return; reset_variable_values(); + m_idiv_bound_calls; m_theory_var2var_index.reset(); m_solver = alloc(lp::lar_solver); lp_params lp(ctx().get_params()); @@ -1683,6 +1685,10 @@ public: if (m_idiv_terms.empty()) { return true; } + ++m_idiv_bound_calls; + if ((m_idiv_bound_calls % 10) != 0) { + return true; + } bool all_divs_valid = true; init_variable_values(); for (expr* n : m_idiv_terms) { @@ -1753,53 +1759,6 @@ public: ctx().display_literals_verbose(tout, lits) << "\n";); continue; } -#if 0 - - // TBD similar for non-linear division. - // better to deal with in nla_solver: - - all_divs_valid = false; - - - // - // p/q <= r1/r2 => n <= div(r1, r2) - // <=> - // p*r2 <= q*r1 => n <= div(r1, r2) - // - // p/q >= r1/r2 => n >= div(r1, r2) - // <=> - // p*r2 >= r1*q => n >= div(r1, r2) - // - expr_ref zero(a.mk_int(0), m); - expr_ref divc(a.mk_numeral(div(r1, r2), true), m); - expr_ref pqr(a.mk_sub(a.mk_mul(a.mk_numeral(r2, true), p), a.mk_mul(a.mk_numeral(r1, true), q)), m); - literal pq_lhs = ~mk_literal(a.mk_le(pqr, zero)); - literal pq_rhs = ~mk_literal(a.mk_ge(pqr, zero)); - literal n_le_div = mk_literal(a.mk_le(n, divc)); - literal n_ge_div = mk_literal(a.mk_ge(n, divc)); - if (m.has_trace_stream()) { - app_ref body(m); - body = m.mk_implies(ctx().bool_var2expr(pq_lhs.var()), ctx().bool_var2expr(n_le_div.var())); - th.log_axiom_instantiation(body); - } - mk_axiom(pq_lhs, n_le_div); - if (m.has_trace_stream()) m.trace_stream() << "[end-of-instance]\n"; - if (m.has_trace_stream()) { - app_ref body(m); - body = m.mk_implies(ctx().bool_var2expr(pq_rhs.var()), ctx().bool_var2expr(n_ge_div.var())); - th.log_axiom_instantiation(body); - } - mk_axiom(pq_rhs, n_ge_div); - if (m.has_trace_stream()) m.trace_stream() << "[end-of-instance]\n"; - TRACE("arith", - literal_vector lits; - lits.push_back(pq_lhs); - lits.push_back(n_le_div); - ctx().display_literals_verbose(tout, lits) << "\n"; - lits[0] = pq_rhs; - lits[1] = n_ge_div; - ctx().display_literals_verbose(tout, lits) << "\n";); -#endif } return all_divs_valid; From 7aa8b4ac2ac4c70d7fa3c85ac32d9629f2be2c2e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 19:11:22 -0800 Subject: [PATCH 018/156] restrict idiv-bound checks to bounded terms Signed-off-by: Nikolaj Bjorner --- src/ast/expr_substitution.cpp | 8 +-- src/muz/spacer/spacer_iuc_solver.cpp | 2 +- src/opt/opt_solver.cpp | 3 +- src/opt/optsmt.cpp | 2 +- src/smt/theory_lra.cpp | 76 +++++++++++++++------------- src/util/lp/lar_solver.cpp | 8 +-- src/util/stopwatch.h | 2 +- 7 files changed, 54 insertions(+), 47 deletions(-) diff --git a/src/ast/expr_substitution.cpp b/src/ast/expr_substitution.cpp index e8d75f461..61bd9370c 100644 --- a/src/ast/expr_substitution.cpp +++ b/src/ast/expr_substitution.cpp @@ -65,8 +65,8 @@ std::ostream& expr_substitution::display(std::ostream& out) { } void expr_substitution::insert(expr * c, expr * def, proof * def_pr, expr_dependency * def_dep) { - obj_map::obj_map_entry * entry = m_subst.insert_if_not_there2(c, 0); - if (entry->get_data().m_value == 0) { + obj_map::obj_map_entry * entry = m_subst.insert_if_not_there2(c, nullptr); + if (entry->get_data().m_value == nullptr) { // new entry m_manager.inc_ref(c); m_manager.inc_ref(def); @@ -89,14 +89,14 @@ void expr_substitution::insert(expr * c, expr * def, proof * def_pr, expr_depend entry->get_data().m_value = def; if (proofs_enabled()) { obj_map::obj_map_entry * entry_pr = m_subst_pr->find_core(c); - SASSERT(entry_pr != 0); + SASSERT(entry_pr != nullptr); m_manager.inc_ref(def_pr); m_manager.dec_ref(entry_pr->get_data().m_value); entry_pr->get_data().m_value = def_pr; } if (unsat_core_enabled()) { obj_map::obj_map_entry * entry_dep = m_subst_dep->find_core(c); - SASSERT(entry_dep != 0); + SASSERT(entry_dep != nullptr); m_manager.inc_ref(def_dep); m_manager.dec_ref(entry_dep->get_data().m_value); entry_dep->get_data().m_value = def_dep; diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index f28864e27..114bc69b9 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -342,7 +342,7 @@ namespace spacer { proof_ref pr2(m); { - scoped_watch _t_ (m_hyp_reduce2_sw); + // scoped_watch _t_ (m_hyp_reduce2_sw); hypothesis_reducer hyp_reducer(m); pr2 = hyp_reducer.reduce(pr1); } diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 80a81ba3a..eb766a1ba 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -233,7 +233,8 @@ namespace opt { get_model(m_model); inf_eps val2; m_valid_objectives[i] = true; - TRACE("opt", tout << (has_shared?"has shared":"non-shared") << " " << val << "\n";); + has_shared = true; + TRACE("opt", tout << (has_shared?"has shared":"non-shared") << " " << val << " " << blocker << "\n";); if (!m_models[i]) { set_model(i); } diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 4a35acd02..462c9855a 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -215,7 +215,7 @@ namespace opt { ++num_scopes; bound = m_s->mk_ge(obj_index, obj + inf_eps(delta_per_step)); } - TRACE("opt", tout << delta_per_step << " " << bound << "\n";); + TRACE("opt", tout << "delta: " << delta_per_step << " " << bound << "\n";); m_s->assert_expr(bound); } else if (is_sat == l_false && delta_per_step > rational::one()) { diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 1a63b97fb..774dc09f3 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -236,7 +236,6 @@ class theory_lra::imp { expr* m_not_handled; ptr_vector m_underspecified; ptr_vector m_idiv_terms; - unsigned m_idiv_bound_calls; unsigned_vector m_var_trail; vector > m_use_list; // bounds where variables are used. @@ -308,7 +307,6 @@ class theory_lra::imp { if (m_solver) return; reset_variable_values(); - m_idiv_bound_calls; m_theory_var2var_index.reset(); m_solver = alloc(lp::lar_solver); lp_params lp(ctx().get_params()); @@ -1103,24 +1101,6 @@ public: if (m.has_trace_stream()) m.trace_stream() << "[end-of-instance]\n"; } - // create axiom for - // u = v + r*w, - /// abs(r) > r >= 0 - void assert_idiv_mod_axioms(theory_var u, theory_var v, theory_var w, rational const& r) { - app_ref term(m); - term = a.mk_sub(get_enode(u)->get_owner(), - a.mk_add(get_enode(v)->get_owner(), - a.mk_mul(a.mk_numeral(r, true), - get_enode(w)->get_owner()))); - theory_var z = internalize_def(term); - lp::var_index vi = get_var_index(z); - add_def_constraint(m_solver->add_var_bound(vi, lp::GE, rational::zero())); - add_def_constraint(m_solver->add_var_bound(vi, lp::LE, rational::zero())); - add_def_constraint(m_solver->add_var_bound(get_var_index(v), lp::GE, rational::zero())); - add_def_constraint(m_solver->add_var_bound(get_var_index(v), lp::LT, abs(r))); - TRACE("arith", m_solver->print_constraints(tout << term << "\n");); - } - void mk_idiv_mod_axioms(expr * p, expr * q) { if (a.is_zero(q)) { return; @@ -1681,16 +1661,31 @@ public: * 0 < q => (v(p)/v(q) <= p/q => v(p)/v(q) - 1 < n) * */ + + bool is_bounded(expr* n) { + expr* x = nullptr, *y = nullptr; + while (true) { + if (a.is_idiv(n, x, y) && a.is_numeral(y)) { + n = x; + } + else if (a.is_mod(n, x, y) && a.is_numeral(y)) { + return true; + } + else if (a.is_numeral(n)) { + return true; + } + else { + return false; + } + } + } + bool check_idiv_bounds() { if (m_idiv_terms.empty()) { return true; } - ++m_idiv_bound_calls; - if ((m_idiv_bound_calls % 10) != 0) { - return true; - } - bool all_divs_valid = true; init_variable_values(); + bool all_divs_valid = true; for (expr* n : m_idiv_terms) { expr* p = nullptr, *q = nullptr; VERIFY(a.is_idiv(n, p, q)); @@ -1709,9 +1704,11 @@ public: continue; } - if (a.is_numeral(q, r2) && r2.is_pos()) { - if (get_value(v) == div(r1, r2)) continue; + if (a.is_numeral(q, r2) && r2.is_pos() && is_bounded(n)) { + rational val_v = get_value(v); + if (val_v == div(r1, r2)) continue; + TRACE("arith", tout << get_value(v) << " != " << r1 << " div " << r2 << "\n";); rational div_r = div(r1, r2); // p <= q * div(r1, q) + q - 1 => div(p, q) <= div(r1, r2) // p >= q * div(r1, q) => div(r1, q) <= div(p, q) @@ -1853,14 +1850,17 @@ public: TRACE("arith", tout << "canceled\n";); return l_undef; } + + lbool lia_check = l_undef; if (!check_idiv_bounds()) { - TRACE("arith", tout << "idiv bounds check\n";); return l_false; } m_explanation.reset(); switch (m_lia->check()) { case lp::lia_move::sat: - return l_true; + lia_check = l_true; + break; + case lp::lia_move::branch: { TRACE("arith", tout << "branch\n";); app_ref b = mk_bound(m_lia->get_term(), m_lia->get_offset(), !m_lia->is_upper()); @@ -1876,7 +1876,8 @@ public: // TBD: ctx().force_phase(ctx().get_literal(b)); // at this point we have a new unassigned atom that the // SAT core assigns a value to - return l_false; + lia_check = l_false; + break; } case lp::lia_move::cut: { TRACE("arith", tout << "cut\n";); @@ -1902,24 +1903,27 @@ public: ctx().display_lemma_as_smt_problem(tout << "new cut:\n", m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit); display(tout);); assign(lit); - return l_false; + lia_check = l_false; + break; } case lp::lia_move::conflict: TRACE("arith", tout << "conflict\n";); // ex contains unsat core m_explanation = m_lia->get_explanation().m_explanation; set_conflict1(); - return l_false; + lia_check = l_false; + break; case lp::lia_move::undef: TRACE("arith", tout << "lia undef\n";); - return l_undef; + lia_check = l_undef; + break; case lp::lia_move::continue_with_check: - return l_undef; + lia_check = l_undef; + break; default: UNREACHABLE(); } - UNREACHABLE(); - return l_undef; + return lia_check; } lbool check_nra() { diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 879dfd32f..5db041218 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -346,13 +346,12 @@ void lar_solver::shrink_inf_set_after_pop(unsigned n, int_set & set) { void lar_solver::pop(unsigned k) { - TRACE("arith_int", tout << "pop" << std::endl;); + TRACE("int_solver", tout << "pop" << std::endl;); TRACE("lar_solver", tout << "k = " << k << std::endl;); m_infeasible_column_index.pop(k); unsigned n = m_columns_to_ul_pairs.peek_size(k); m_var_register.shrink(n); - TRACE("arith_int", tout << "pop" << std::endl;); if (m_settings.use_tableau()) { pop_tableau(); } @@ -453,6 +452,7 @@ void lar_solver::set_costs_to_zero(const lar_term& term) { void lar_solver::prepare_costs_for_r_solver(const lar_term & term) { + TRACE("lar_solver", print_term(term, tout << "prepare: ");); auto & rslv = m_mpq_lar_core_solver.m_r_solver; rslv.m_using_infeas_costs = false; lp_assert(costs_are_zeros_for_r_solver()); @@ -473,6 +473,7 @@ bool lar_solver::maximize_term_on_corrected_r_solver(lar_term & term, impq &term_max) { settings().backup_costs = false; bool ret = false; + TRACE("lar_solver", print_term(term, tout << "maximize: ") << "\n"; print_constraints(tout);); switch (settings().simplex_strategy()) { case simplex_strategy_enum::tableau_rows: prepare_costs_for_r_solver(term); @@ -506,8 +507,9 @@ bool lar_solver::remove_from_basis(unsigned j) { } lar_term lar_solver::get_term_to_maximize(unsigned j_or_term) const { - if (is_term(j_or_term)) + if (is_term(j_or_term)) { return get_term(j_or_term); + } if (j_or_term < m_mpq_lar_core_solver.m_r_x.size()) { lar_term r; r.add_monomial(one_of_type(), j_or_term); diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index 1135c893e..da1a3deaa 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -60,7 +60,7 @@ public: } void stop() { - SASSERT(m_running); + // SASSERT(m_running); DEBUG_CODE(m_running = false;); m_elapsed += get() - m_start; } From 19e7b75536aa1dc311147f6677aab5efb016f867 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 19:31:51 -0800 Subject: [PATCH 019/156] set status optimal also on object Signed-off-by: Nikolaj Bjorner --- src/util/lp/lar_solver.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 5db041218..8e0ee89c6 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -570,7 +570,11 @@ lp_status lar_solver::maximize_term(unsigned j_or_term, m_mpq_lar_core_solver.m_r_x = backup; } TRACE("lar_solver", print_values(tout);); - return term_max == opt_val? lp_status::OPTIMAL :lp_status::FEASIBLE; + if (term_max == opt_val) { + set_status(lp_status::OPTIMAL); + return lp_status::OPTIMAL; + } + return lp_status::FEASIBLE; } From 0c0e79a937c5dcd6d8bee66e2a640aaeeeef0f40 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 20:33:12 -0800 Subject: [PATCH 020/156] add logging to lar-solver to capture state for unbounded optimization Signed-off-by: Nikolaj Bjorner --- src/util/lp/lar_core_solver_def.h | 8 ++++++-- src/util/lp/lar_solver.cpp | 15 +++++++++------ src/util/lp/lp_core_solver_base.h | 2 -- src/util/lp/lp_primal_core_solver_def.h | 6 ++++-- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/util/lp/lar_core_solver_def.h b/src/util/lp/lar_core_solver_def.h index b945b0e51..ca7915c7d 100644 --- a/src/util/lp/lar_core_solver_def.h +++ b/src/util/lp/lar_core_solver_def.h @@ -265,12 +265,14 @@ unsigned lar_core_solver::get_number_of_non_ints() const { } void lar_core_solver::solve() { + TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";); lp_assert(m_r_solver.non_basic_columns_are_set_correctly()); lp_assert(m_r_solver.inf_set_is_correct()); TRACE("find_feas_stats", tout << "infeasibles = " << m_r_solver.m_inf_set.size() << ", int_infs = " << get_number_of_non_ints() << std::endl;); if (m_r_solver.current_x_is_feasible() && m_r_solver.m_look_for_feasible_solution_only) { - m_r_solver.set_status(lp_status::OPTIMAL); - return; + m_r_solver.set_status(lp_status::OPTIMAL); + TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";); + return; } ++settings().st().m_need_to_solve_inf; CASSERT("A_off", !m_r_solver.A_mult_x_is_off()); @@ -310,6 +312,8 @@ void lar_core_solver::solve() { lp_assert(r_basis_is_OK()); lp_assert(m_r_solver.non_basic_columns_are_set_correctly()); lp_assert(m_r_solver.inf_set_is_correct()); + + TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";); } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 8e0ee89c6..48b08a215 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -403,12 +403,15 @@ bool lar_solver::maximize_term_on_tableau(const lar_term & term, m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::FEASIBLE); m_mpq_lar_core_solver.solve(); - if (m_mpq_lar_core_solver.m_r_solver.get_status() == lp_status::UNBOUNDED) + lp_status st = m_mpq_lar_core_solver.m_r_solver.get_status(); + TRACE("lar_solver", tout << st << "\n";); + if (st == lp_status::UNBOUNDED) { return false; - - term_max = term.apply(m_mpq_lar_core_solver.m_r_x); - - return true; + } + else { + term_max = term.apply(m_mpq_lar_core_solver.m_r_x); + return true; + } } bool lar_solver::costs_are_zeros_for_r_solver() const { @@ -452,7 +455,7 @@ void lar_solver::set_costs_to_zero(const lar_term& term) { void lar_solver::prepare_costs_for_r_solver(const lar_term & term) { - TRACE("lar_solver", print_term(term, tout << "prepare: ");); + TRACE("lar_solver", print_term(term, tout << "prepare: ") << "\n";); auto & rslv = m_mpq_lar_core_solver.m_r_solver; rslv.m_using_infeas_costs = false; lp_assert(costs_are_zeros_for_r_solver()); diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index 9a6549917..c1b8aa987 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -136,8 +136,6 @@ public: } const vector & non_basis() const { return m_nbasis; } - - void set_status(lp_status status) { m_status = status; diff --git a/src/util/lp/lp_primal_core_solver_def.h b/src/util/lp/lp_primal_core_solver_def.h index a43764172..a91491313 100644 --- a/src/util/lp/lp_primal_core_solver_def.h +++ b/src/util/lp/lp_primal_core_solver_def.h @@ -775,6 +775,7 @@ template void lp_primal_core_solver::advance_on_e X t; int leaving = find_leaving_and_t_precise(entering, t); if (leaving == -1) { + TRACE("lar_solver", tout << "non-leaving\n";); this->set_status(lp_status::UNBOUNDED); return; } @@ -828,6 +829,7 @@ template void lp_primal_core_solver::advance_on_e } else { this->set_status(lp_status::TENTATIVE_UNBOUNDED); } + TRACE("lar_solver", tout << this->get_status() << "\n";); return; } advance_on_entering_and_leaving(entering, leaving, t); @@ -857,11 +859,11 @@ template void lp_primal_core_solver::print_column out << this->m_column_norms[j] << " "; } out << std::endl; - out << std::endl; -} + } // returns the number of iterations template unsigned lp_primal_core_solver::solve() { + TRACE("lar_solver", pretty_print(tout);); if (numeric_traits::precise() && this->m_settings.use_tableau()) return solve_with_tableau(); From 5c13acbf9fc23ed8de15a1ca003e65a2045ba665 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 20:48:13 -0800 Subject: [PATCH 021/156] remove print directive that doesn't compile Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 6 +++++- src/util/lp/lp_primal_core_solver_def.h | 27 ++++++++++++------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 774dc09f3..ceeb1617f 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1704,9 +1704,13 @@ public: continue; } - if (a.is_numeral(q, r2) && r2.is_pos() && is_bounded(n)) { + if (a.is_numeral(q, r2) && r2.is_pos()) { rational val_v = get_value(v); if (val_v == div(r1, r2)) continue; + if (!is_bounded(n)) { + TRACE("arith", tout << "unbounded " << expr_ref(n, m) << "\n";); + continue; + } TRACE("arith", tout << get_value(v) << " != " << r1 << " div " << r2 << "\n";); rational div_r = div(r1, r2); diff --git a/src/util/lp/lp_primal_core_solver_def.h b/src/util/lp/lp_primal_core_solver_def.h index a91491313..ad861cc7a 100644 --- a/src/util/lp/lp_primal_core_solver_def.h +++ b/src/util/lp/lp_primal_core_solver_def.h @@ -357,20 +357,20 @@ template bool lp_primal_core_solver::try_jump_to_ bool & unlimited) { switch(this->m_column_types[entering]){ case column_type::boxed: - if (m_sign_of_entering_delta > 0) { - t = this->m_upper_bounds[entering] - this->m_x[entering]; - if (unlimited || t <= theta){ - lp_assert(t >= zero_of_type()); - return true; - } - } else { // m_sign_of_entering_delta == -1 - t = this->m_x[entering] - this->m_lower_bounds[entering]; - if (unlimited || t <= theta) { - lp_assert(t >= zero_of_type()); - return true; - } + if (m_sign_of_entering_delta > 0) { + t = this->m_upper_bounds[entering] - this->m_x[entering]; + if (unlimited || t <= theta){ + lp_assert(t >= zero_of_type()); + return true; } - return false; + } else { // m_sign_of_entering_delta == -1 + t = this->m_x[entering] - this->m_lower_bounds[entering]; + if (unlimited || t <= theta) { + lp_assert(t >= zero_of_type()); + return true; + } + } + return false; case column_type::upper_bound: if (m_sign_of_entering_delta > 0) { t = this->m_upper_bounds[entering] - this->m_x[entering]; @@ -863,7 +863,6 @@ template void lp_primal_core_solver::print_column // returns the number of iterations template unsigned lp_primal_core_solver::solve() { - TRACE("lar_solver", pretty_print(tout);); if (numeric_traits::precise() && this->m_settings.use_tableau()) return solve_with_tableau(); From 26921d1c9cccf05f6cc3c5cc8d9448809bef7cf2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 22:32:50 -0800 Subject: [PATCH 022/156] fix #2155 Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_context.cpp | 22 +++++++++++++++++++--- src/muz/spacer/spacer_context.h | 6 +++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 76e7e24c6..a2fb70e63 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2948,7 +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() const { +expr_ref context::get_ground_sat_answer() { if (m_last_result != l_true) { IF_VERBOSE(0, verbose_stream() << "Sat answer unavailable when result is false\n";); @@ -2994,6 +2994,7 @@ expr_ref context::get_ground_sat_answer() const { ref cex_ctx = mk_smt_solver(m, params_ref::get_empty(), symbol::null); + bool first = true; // preorder traversal of the query derivation tree for (unsigned curr = 0; curr < pts.size (); curr++) { // pick next pt, fact, and cex_fact @@ -3032,6 +3033,7 @@ expr_ref context::get_ground_sat_answer() const { } cex_ctx->assert_expr(pt->transition()); cex_ctx->assert_expr(pt->rule2tag(r)); + TRACE("cex", cex_ctx->display(tout);); lbool res = cex_ctx->check_sat(0, nullptr); CTRACE("cex", res == l_false, tout << "Cex fact: " << mk_pp(cex_fact, m) << "\n"; @@ -3046,6 +3048,20 @@ expr_ref context::get_ground_sat_answer() const { cex_ctx->get_model (local_mdl); cex_ctx->pop (1); local_mdl->set_model_completion(true); + if (first) { + unsigned sig_size = pt->sig_size(); + expr_ref_vector ground_fact_conjs(m); + expr_ref_vector ground_arg_vals(m); + for (unsigned j = 0; j < sig_size; j++) { + expr_ref sig_arg(m), sig_val(m); + sig_arg = m.mk_const (m_pm.o2n(pt->sig(j), 0)); + std::cout << sig_arg << "\n"; + sig_val = (*local_mdl)(sig_arg); + ground_arg_vals.push_back(sig_val); + } + cex.push_back(m.mk_app(pt->head(), sig_size, ground_arg_vals.c_ptr())); + first = false; + } for (unsigned i = 0; i < child_pts.size(); i++) { pred_transformer& ch_pt = *(child_pts.get(i)); unsigned sig_size = ch_pt.sig_size(); @@ -3073,10 +3089,10 @@ expr_ref context::get_ground_sat_answer() const { TRACE ("spacer", tout << "ground cex\n" << cex << "\n";); - return expr_ref(m.mk_and(cex.size(), cex.c_ptr()), m); + return mk_and(cex); } -void context::display_certificate(std::ostream &out) const { +void context::display_certificate(std::ostream &out) { switch(m_last_result) { case l_false: out << mk_pp(mk_unsat_answer(), m); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 494de1c23..54eb1befa 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -1010,7 +1010,7 @@ class context { /** \brief Retrieve satisfying assignment with explanation. */ - expr_ref mk_sat_answer() const {return get_ground_sat_answer();} + expr_ref mk_sat_answer() {return get_ground_sat_answer();} expr_ref mk_unsat_answer() const; unsigned get_cex_depth (); @@ -1086,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 () const; + expr_ref get_ground_sat_answer (); proof_ref get_ground_refutation(); void get_rules_along_trace (datalog::rule_ref_vector& rules); @@ -1095,7 +1095,7 @@ public: void reset(); std::ostream& display(std::ostream& out) const; - void display_certificate(std::ostream& out) const; + void display_certificate(std::ostream& out); pob& get_root() const {return m_pob_queue.get_root();} void set_query(func_decl* q) {m_query_pred = q;} From f00697cf95b8b025c4769217554243a14e1a581b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2019 22:33:28 -0800 Subject: [PATCH 023/156] fix #2155 Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_context.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index a2fb70e63..04f5834aa 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -3055,7 +3055,6 @@ expr_ref context::get_ground_sat_answer() { for (unsigned j = 0; j < sig_size; j++) { expr_ref sig_arg(m), sig_val(m); sig_arg = m.mk_const (m_pm.o2n(pt->sig(j), 0)); - std::cout << sig_arg << "\n"; sig_val = (*local_mdl)(sig_arg); ground_arg_vals.push_back(sig_val); } From 21be4e6d16bf35c3e83a1bdffa4639eebac6158b Mon Sep 17 00:00:00 2001 From: Egor Bredikhin <32983915+Egor18@users.noreply.github.com> Date: Tue, 5 Mar 2019 17:09:27 -0500 Subject: [PATCH 024/156] Fix misprint --- src/ast/array_decl_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index d2d1039fa..d361815b2 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -299,7 +299,7 @@ func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) { 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"; + strm << "domain sort " << sort_ref(srt2, *m_manager) << " and parameter sort " << sort_ref(srt1, *m_manager) << " do not match"; m_manager->raise_exception(strm.str()); UNREACHABLE(); return nullptr; From c4d9754eefc63637ac05f902b6f1fd985201afd8 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 6 Mar 2019 11:12:18 +0000 Subject: [PATCH 025/156] cmake: remove old directive --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 188d8dfde..600314b7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,7 +189,6 @@ endif() # Note for some reason we have to leave off ``-D`` here otherwise # we get ``-D-DZ3DEBUG`` passed to the compiler list(APPEND Z3_COMPONENT_CXX_DEFINES $<$:Z3DEBUG>) -list(APPEND Z3_COMPONENT_CXX_DEFINES $<$:LEAN_DEBUG>) list(APPEND Z3_COMPONENT_CXX_DEFINES $<$:_EXTERNAL_RELEASE>) list(APPEND Z3_COMPONENT_CXX_DEFINES $<$:_EXTERNAL_RELEASE>) From 7ad4ced12f8624f8ecfaf6a0e49c507ff420de2d Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 6 Mar 2019 12:16:48 +0000 Subject: [PATCH 026/156] librt no longer needed(?) --- CMakeLists.txt | 39 --------------------------------------- scripts/mk_util.py | 6 ------ 2 files changed, 45 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 600314b7e..e5619ddc5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -271,45 +271,6 @@ list(APPEND Z3_COMPONENT_EXTRA_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/src" ) -################################################################################ -# Linux specific configuration -################################################################################ -if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - # Try to detect if it is necessary to link against librt. - # Note that glibc < 2.17 required librt to be linked to use clock_gettime() - # and friends. - set(CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE - " - #include - int main() { - timespec res; - int result = clock_gettime(CLOCK_REALTIME, &res); - return result == 0; - } - " - ) - check_cxx_source_compiles( - "${CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE}" - CLOCK_GETTIME_NO_REQUIRE_LIBRT - ) - if (NOT CLOCK_GETTIME_NO_REQUIRE_LIBRT) - # Try again with librt - message(STATUS "Failed to link against clock_gettime(), trying with librt") - set(CMAKE_REQUIRED_LIBRARIES_OLD "${CMAKE_REQUIRED_LIBRARIES}") - set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} rt") - check_cxx_source_compiles( - "${CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE}" - CLOCK_GETTIME_REQUIRES_LIBRT - ) - set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_OLD}") - if (CLOCK_GETTIME_REQUIRES_LIBRT) - list(APPEND Z3_DEPENDENT_LIBS "rt") - else() - message(FATAL_ERROR "Failed to link against clock_gettime()") - endif() - endif() -endif() - ################################################################################ # GNU multiple precision library support ################################################################################ diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 2e827a7f3..ffbf13010 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2832,24 +2832,18 @@ def mk_config(): CXXFLAGS = '%s -D_LINUX_' % CXXFLAGS OS_DEFINES = '-D_LINUX_' SO_EXT = '.so' - LDFLAGS = '%s -lrt' % LDFLAGS SLIBFLAGS = '-shared' - SLIBEXTRAFLAGS = '%s -lrt' % SLIBEXTRAFLAGS SLIBEXTRAFLAGS = '%s -Wl,-soname,libz3.so' % SLIBEXTRAFLAGS elif sysname == 'FreeBSD': CXXFLAGS = '%s -D_FREEBSD_' % CXXFLAGS OS_DEFINES = '-D_FREEBSD_' SO_EXT = '.so' - LDFLAGS = '%s -lrt' % LDFLAGS SLIBFLAGS = '-shared' - SLIBEXTRAFLAGS = '%s -lrt' % SLIBEXTRAFLAGS elif sysname == 'NetBSD': CXXFLAGS = '%s -D_NETBSD_' % CXXFLAGS OS_DEFINES = '-D_NETBSD_' SO_EXT = '.so' - LDFLAGS = '%s -lrt' % LDFLAGS SLIBFLAGS = '-shared' - SLIBEXTRAFLAGS = '%s -lrt' % SLIBEXTRAFLAGS elif sysname == 'OpenBSD': CXXFLAGS = '%s -D_OPENBSD_' % CXXFLAGS OS_DEFINES = '-D_OPENBSD_' From e05596e7e564d5009d1843fa28f62487596be4db Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 6 Mar 2019 11:41:56 -0500 Subject: [PATCH 027/156] z3str3: fix str.indexof with offset (issue #2092) --- src/smt/theory_str.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 50e666c70..37c5b6237 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1427,7 +1427,7 @@ namespace smt { // 0 < i < len(H) --> // H = hd ++ tl // len(hd) = i - // str.indexof(tl, N, 0) + // i + str.indexof(tl, N, 0) expr * H = nullptr; // "haystack" expr * N = nullptr; // "needle" @@ -1463,12 +1463,19 @@ namespace smt { expr_ref conclusion(ctx.mk_eq_atom(e, minus_one), m); assert_implication(premise, conclusion); } - // case 4: 0 < i < len(H) + // case 3.5: H doesn't contain N + { + expr_ref premise(m.mk_not(u.str.mk_contains(H, N)), m); + expr_ref conclusion(ctx.mk_eq_atom(e, minus_one), m); + assert_implication(premise, conclusion); + } + // case 4: 0 < i < len(H) and H contains N { expr_ref premise1(m_autil.mk_gt(i, zero), m); //expr_ref premise2(m_autil.mk_lt(i, mk_strlen(H)), m); expr_ref premise2(m.mk_not(m_autil.mk_ge(m_autil.mk_add(i, m_autil.mk_mul(minus_one, mk_strlen(H))), zero)), m); - expr_ref _premise(m.mk_and(premise1, premise2), m); + expr_ref premise3(u.str.mk_contains(H, N), m); + expr_ref _premise(m.mk_and(premise1, premise2, premise3), m); expr_ref premise(_premise); th_rewriter rw(m); rw(premise); @@ -1479,7 +1486,8 @@ namespace smt { expr_ref_vector conclusion_terms(m); conclusion_terms.push_back(ctx.mk_eq_atom(H, mk_concat(hd, tl))); conclusion_terms.push_back(ctx.mk_eq_atom(mk_strlen(hd), i)); - conclusion_terms.push_back(ctx.mk_eq_atom(e, mk_indexof(tl, N))); + conclusion_terms.push_back(u.str.mk_contains(tl, N)); + conclusion_terms.push_back(ctx.mk_eq_atom(e, m_autil.mk_add(i, mk_indexof(tl, N)))); expr_ref conclusion(mk_and(conclusion_terms), m); assert_implication(premise, conclusion); From 5a02edc8cd7e7bc99cd30b714c05af055dcf149b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Mar 2019 10:18:29 -0800 Subject: [PATCH 028/156] add recognizer for distinct Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index cbb12ea99..fb0657aa2 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -996,6 +996,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(); } + bool is_distinct() const { return is_app() && Z3_OP_DISTINCT == decl().decl_kind(); } friend expr distinct(expr_vector const& args); friend expr concat(expr const& a, expr const& b); From 5abc4a6d68d57bffeed98bf5c77394dfada32f75 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Mar 2019 22:03:57 -0800 Subject: [PATCH 029/156] rewrite quantifiers in model evaluator #2171 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/th_rewriter.cpp | 10 ++++++++++ src/ast/rewriter/th_rewriter.h | 9 ++++++++- src/model/model_evaluator.cpp | 12 ++++++++++++ src/smt/theory_lra.cpp | 2 +- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 4fa8c4074..4c81ab665 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -839,3 +839,13 @@ expr_ref th_rewriter::mk_app(func_decl* f, unsigned num_args, expr* const* args) void th_rewriter::set_solver(expr_solver* solver) { m_imp->set_solver(solver); } + + +bool th_rewriter::reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + return m_imp->cfg().reduce_quantifier(old_q, new_body, new_patterns, new_no_patterns, result, result_pr); +} diff --git a/src/ast/rewriter/th_rewriter.h b/src/ast/rewriter/th_rewriter.h index 19a99f4d3..281c685f2 100644 --- a/src/ast/rewriter/th_rewriter.h +++ b/src/ast/rewriter/th_rewriter.h @@ -41,7 +41,7 @@ public: static void get_param_descrs(param_descrs & r); unsigned get_cache_size() const; unsigned get_num_steps() const; - + void operator()(expr_ref& term); void operator()(expr * t, expr_ref & result); void operator()(expr * t, expr_ref & result, proof_ref & result_pr); @@ -49,6 +49,13 @@ public: expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args); + bool reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr); + void cleanup(); void reset(); diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 968aca51f..d2f14d9b4 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -30,6 +30,7 @@ Revision History: #include "ast/rewriter/datatype_rewriter.h" #include "ast/rewriter/array_rewriter.h" #include "ast/rewriter/fpa_rewriter.h" +#include "ast/rewriter/th_rewriter.h" #include "ast/rewriter/rewriter_def.h" #include "ast/ast_pp.h" #include "ast/ast_util.h" @@ -126,6 +127,17 @@ struct evaluator_cfg : public default_rewriter_cfg { return false; } + bool reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + th_rewriter th(m); + return th.reduce_quantifier(old_q, new_body, new_patterns, new_no_patterns, result, result_pr); + } + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { result_pr = nullptr; family_id fid = f->get_family_id(); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 81edb2c67..45ade8b46 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -3332,7 +3332,7 @@ public: vi = m_theory_var2var_index[v]; st = m_solver->maximize_term(vi, term_max); } - TRACE("arith", display(tout << st << " v" << v << " vi: " << vi << "\n");); + TRACE("arith", display(tout << st << " v" << v << " vi: " << vi << " " << term_max << "\n");); switch (st) { case lp::lp_status::OPTIMAL: { init_variable_values(); From 9d2a1068381f5057db6f61ed4ce067054856dfd3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Mar 2019 00:07:48 -0800 Subject: [PATCH 030/156] unused variable warning Signed-off-by: Nikolaj Bjorner --- src/smt/smt_theory.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index ebce8df6f..f1f304fa6 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -373,9 +373,8 @@ namespace smt { if (used_enodes.size() > 0) { m.trace_stream() << " ;"; for (auto n : used_enodes) { - enode *orig = std::get<0>(n); enode *substituted = std::get<1>(n); - SASSERT(orig == nullptr); + SASSERT(std::get<0>(n) == nullptr); m.trace_stream() << " #" << substituted->get_owner_id(); } } From c0f7afacc497e7e2e1a2a28bcebf1173933f5bab Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 7 Mar 2019 09:58:36 +0000 Subject: [PATCH 031/156] bump cmake minimum version to 3.4 as it was released 3+ years ago some misc compiler flags cleanup --- CMakeLists.txt | 39 +++++----------------------------- cmake/compiler_lto.cmake | 3 +-- cmake/compiler_warnings.cmake | 9 +++----- cmake/msvc_legacy_quirks.cmake | 13 ------------ scripts/mk_util.py | 8 +++---- 5 files changed, 13 insertions(+), 59 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5619ddc5..64efaf72d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,8 @@ # Enforce some CMake policies -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.4) + if (POLICY CMP0054) - # FIXME: This is horrible. With the old behaviour, - # quoted strings like "MSVC" in if() conditionals - # get implicitly dereferenced. The NEW behaviour - # doesn't do this but CMP0054 was only introduced - # in CMake 3.1 and we support lower versions as the - # minimum. We could set NEW here but it would be very - # confusing to use NEW for some builds and OLD for others - # which could lead to some subtle bugs. Instead when the - # minimum version is 3.1 change this policy to NEW and remove - # the hacks in place to work around it. - cmake_policy(SET CMP0054 OLD) + cmake_policy(SET CMP0054 NEW) endif() if (POLICY CMP0042) @@ -22,13 +13,6 @@ endif() set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake") project(Z3 CXX) -if ("${CMAKE_VERSION}" VERSION_LESS "3.4") - # FIXME: Drop this when we upgrade to newer CMake versions. - # HACK: Although we don't need C language support if it is not - # enabled CMake's `FindThreads` module fails in old CMake versions. - enable_language(C) -endif() - ################################################################################ # Project version ################################################################################ @@ -352,12 +336,11 @@ if (("${TARGET_ARCHITECTURE}" STREQUAL "x86_64") OR ("${TARGET_ARCHITECTURE}" ST list(APPEND Z3_DEPENDENT_LIBS "iomp5") endif() set(SSE_FLAGS "-mfpmath=sse" "-msse" "-msse2") - # FIXME: Remove "x.." when CMP0054 is set to NEW elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel") set(SSE_FLAGS "-mfpmath=sse" "-msse" "-msse2") # Intel's compiler requires linking with libiomp5 list(APPEND Z3_DEPENDENT_LIBS "iomp5") - elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set(SSE_FLAGS "/arch:SSE2") else() message(FATAL_ERROR "Unknown compiler ${CMAKE_CXX_COMPILER_ID}") @@ -369,17 +352,6 @@ if (("${TARGET_ARCHITECTURE}" STREQUAL "x86_64") OR ("${TARGET_ARCHITECTURE}" ST unset(SSE_FLAGS) endif() - - -# FIXME: Remove "x.." when CMP0054 is set to NEW -if ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") - # This is the default for MSVC already but to replicate the - # python/Makefile build system behaviour this flag is set - # explicitly. - z3_add_cxx_flag("/fp:precise" REQUIRED) -endif() -# There doesn't seem to be an equivalent for clang/gcc - ################################################################################ # Threading support ################################################################################ @@ -493,8 +465,7 @@ endif() ################################################################################ # MSVC specific flags inherited from old build system ################################################################################ -# FIXME: Remove "x.." when CMP0054 is set to NEW -if ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") include(${CMAKE_SOURCE_DIR}/cmake/msvc_legacy_quirks.cmake) endif() diff --git a/cmake/compiler_lto.cmake b/cmake/compiler_lto.cmake index b90890f59..b4eb83e18 100644 --- a/cmake/compiler_lto.cmake +++ b/cmake/compiler_lto.cmake @@ -22,8 +22,7 @@ if (LINK_TIME_OPTIMIZATION) ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")) set(_lto_compiler_flag "-flto") set(_lto_linker_flag "-flto") - # FIXME: Remove "x.." when CMP0054 is set to NEW - elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set(_lto_compiler_flag "/GL") set(_lto_linker_flag "/LTCG") else() diff --git a/cmake/compiler_warnings.cmake b/cmake/compiler_warnings.cmake index 183f490dd..983325796 100644 --- a/cmake/compiler_warnings.cmake +++ b/cmake/compiler_warnings.cmake @@ -56,8 +56,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") list(APPEND WARNING_FLAGS_TO_CHECK ${CLANG_ONLY_WARNINGS}) list(APPEND WARNING_AS_ERROR_FLAGS_TO_CHECK ${GCC_AND_CLANG_WARNINGS_AS_ERRORS}) list(APPEND WARNING_AS_ERROR_FLAGS_TO_CHECK ${CLANG_WARNINGS_AS_ERRORS}) - # FIXME: Remove "x.." when CMP0054 is set to NEW -elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") list(APPEND WARNING_FLAGS_TO_CHECK ${MSVC_WARNINGS}) # CMake's default flags include /W3 already so remove them if @@ -111,8 +110,7 @@ if ("${WARNINGS_AS_ERRORS}" STREQUAL "ON") message(STATUS "Treating compiler warnings as errors") if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")) list(APPEND Z3_COMPONENT_CXX_FLAGS "-Werror") - # FIXME: Remove "x.." when CMP0054 is set to NEW - elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") list(APPEND Z3_COMPONENT_CXX_FLAGS "/WX") else() message(AUTHOR_WARNING "Unknown compiler") @@ -126,8 +124,7 @@ elseif ("${WARNINGS_AS_ERRORS}" STREQUAL "SERIOUS_ONLY") endforeach() elseif ("${WARNINGS_AS_ERRORS}" STREQUAL "OFF") message(STATUS "Not treating compiler warnings as errors") - # FIXME: Remove "x.." when CMP0054 is set to NEW - if ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # Warnings as errors is off by default for MSVC so setting this # is not necessary but this duplicates the behaviour of the old # build system. diff --git a/cmake/msvc_legacy_quirks.cmake b/cmake/msvc_legacy_quirks.cmake index a8006e2d3..d34351c1d 100644 --- a/cmake/msvc_legacy_quirks.cmake +++ b/cmake/msvc_legacy_quirks.cmake @@ -69,14 +69,6 @@ list(APPEND Z3_COMPONENT_CXX_DEFINES ${Z3_MSVC_LEGACY_DEFINES}) ################################################################################ # Compiler flags ################################################################################ -# By default in MSVC this is on but the old build system set this explicitly so -# for completeness set it too. -# See https://msdn.microsoft.com/en-us/library/dh8che7s.aspx -z3_add_cxx_flag("/Zc:wchar_t" REQUIRED) -# By default in MSVC this on but the old build system set this explicitly so -# for completeness set it too. -z3_add_cxx_flag("/Zc:forScope" REQUIRED) - # FIXME: We might want to move this out somewhere else if we decide # we want to set `-fno-omit-frame-pointer` for gcc/clang. # No omit frame pointer @@ -106,11 +98,6 @@ if (("${TARGET_ARCHITECTURE}" STREQUAL "x86_64") OR ("${TARGET_ARCHITECTURE}" ST z3_add_cxx_flag("/Gd" REQUIRED) endif() -# FIXME: The old build system explicitly disables code analysis. -# I don't know why. Duplicate this behaviour for now. -# See https://msdn.microsoft.com/en-us/library/ms173498.aspx -z3_add_cxx_flag("/analyze-" REQUIRED) - ################################################################################ # Linker flags ################################################################################ diff --git a/scripts/mk_util.py b/scripts/mk_util.py index ffbf13010..5397bd80f 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2725,7 +2725,7 @@ def mk_config(): 'SLINK_FLAGS=/nologo /LDd\n' % static_opt) if VS_X64: config.write( - 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- %s %s\n' % (extra_opt, static_opt)) + 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /GS /Gd %s %s\n' % (extra_opt, static_opt)) config.write( 'LINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT %s\n' 'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 %s %s\n' % (link_extra_opt, maybe_disable_dynamic_base, link_extra_opt)) @@ -2734,7 +2734,7 @@ def mk_config(): exit(1) else: config.write( - 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- /arch:SSE2 %s %s\n' % (extra_opt, static_opt)) + 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /GS /Gd /arch:SSE2 %s %s\n' % (extra_opt, static_opt)) config.write( 'LINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT %s\n' 'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 %s %s\n' % (link_extra_opt, maybe_disable_dynamic_base, link_extra_opt)) @@ -2750,7 +2750,7 @@ def mk_config(): extra_opt = '%s /D _TRACE ' % extra_opt if VS_X64: config.write( - 'CXXFLAGS=/c%s /Zi /nologo /W3 /WX- /O2 /D _EXTERNAL_RELEASE /D WIN32 /D NDEBUG /D _LIB /D _WINDOWS /D _UNICODE /D UNICODE /Gm- /EHsc /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TP %s %s\n' % (GL, extra_opt, static_opt)) + 'CXXFLAGS=/c%s /Zi /nologo /W3 /WX- /O2 /D _EXTERNAL_RELEASE /D WIN32 /D NDEBUG /D _LIB /D _WINDOWS /D _UNICODE /D UNICODE /Gm- /EHsc /GS /Gd /TP %s %s\n' % (GL, extra_opt, static_opt)) config.write( 'LINK_EXTRA_FLAGS=/link%s /MACHINE:X64 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 %s\n' 'SLINK_EXTRA_FLAGS=/link%s /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 %s\n' % (LTCG, link_extra_opt, LTCG, link_extra_opt)) @@ -2759,7 +2759,7 @@ def mk_config(): exit(1) else: config.write( - 'CXXFLAGS=/nologo /c%s /Zi /W3 /WX- /O2 /Oy- /D _EXTERNAL_RELEASE /D WIN32 /D NDEBUG /D _CONSOLE /D _WINDOWS /D ASYNC_COMMANDS /Gm- /EHsc /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- /arch:SSE2 %s %s\n' % (GL, extra_opt, static_opt)) + 'CXXFLAGS=/nologo /c%s /Zi /W3 /WX- /O2 /Oy- /D _EXTERNAL_RELEASE /D WIN32 /D NDEBUG /D _CONSOLE /D _WINDOWS /D ASYNC_COMMANDS /Gm- /EHsc /GS /Gd /arch:SSE2 %s %s\n' % (GL, extra_opt, static_opt)) config.write( 'LINK_EXTRA_FLAGS=/link%s /DEBUG /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT %s\n' 'SLINK_EXTRA_FLAGS=/link%s /DEBUG /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 %s %s\n' % (LTCG, link_extra_opt, LTCG, maybe_disable_dynamic_base, link_extra_opt)) From deb2deb4ad9c9aae6bf6428af9dfdc7ab31e0762 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 7 Mar 2019 10:04:06 +0000 Subject: [PATCH 032/156] fix linking of .so on old build system --- 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 5397bd80f..18ed0f74e 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2903,7 +2903,7 @@ def mk_config(): config.write('SO_EXT=%s\n' % SO_EXT) config.write('SLINK=%s\n' % CXX) config.write('SLINK_FLAGS=%s\n' % SLIBFLAGS) - config.write('SLINK_EXTRA_FLAGS=%s\n' % SLIBEXTRAFLAGS) + config.write('SLINK_EXTRA_FLAGS=-lpthread %s\n' % SLIBEXTRAFLAGS) config.write('SLINK_OUT_FLAG=-o \n') config.write('OS_DEFINES=%s\n' % OS_DEFINES) if is_verbose(): From 70ada9919e1c8f6d6d8cb3c6af64c71a6cad9791 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 7 Mar 2019 11:09:25 +0000 Subject: [PATCH 033/156] cmake: fix windows build with long absolute directory names --- cmake/z3_add_component.cmake | 8 +++++--- scripts/mk_install_tactic_cpp.py | 15 +++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/cmake/z3_add_component.cmake b/cmake/z3_add_component.cmake index 8ab6e045d..ac6d1ec06 100644 --- a/cmake/z3_add_component.cmake +++ b/cmake/z3_add_component.cmake @@ -262,18 +262,20 @@ macro(z3_add_install_tactic_rule) GLOBAL PROPERTY Z3_${dependency}_TACTIC_HEADERS ) - list(APPEND _tactic_header_files ${_component_tactic_header_files}) + list(APPEND _tactic_header_files "${_component_tactic_header_files}") endforeach() unset(_component_tactic_header_files) + string(REPLACE ";" "\n" _tactic_header_files "${_tactic_header_files}") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/install_tactic.deps" ${_tactic_header_files}) add_custom_command(OUTPUT "install_tactic.cpp" COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/scripts/mk_install_tactic_cpp.py" "${CMAKE_CURRENT_BINARY_DIR}" - ${_tactic_header_files} + "${CMAKE_CURRENT_BINARY_DIR}/install_tactic.deps" DEPENDS "${CMAKE_SOURCE_DIR}/scripts/mk_install_tactic_cpp.py" ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} - ${_tactic_header_files} + "${CMAKE_CURRENT_BINARY_DIR}/install_tactic.deps" COMMENT "Generating \"${CMAKE_CURRENT_BINARY_DIR}/install_tactic.cpp\"" ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} VERBATIM diff --git a/scripts/mk_install_tactic_cpp.py b/scripts/mk_install_tactic_cpp.py index a152eff14..b82e71354 100755 --- a/scripts/mk_install_tactic_cpp.py +++ b/scripts/mk_install_tactic_cpp.py @@ -14,19 +14,22 @@ def main(args): logging.basicConfig(level=logging.INFO) parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("destination_dir", help="destination directory") - parser.add_argument("header_files", nargs="+", - help="One or more header files to parse") + parser.add_argument("deps", help="file with header file names to parse") pargs = parser.parse_args(args) if not mk_genfile_common.check_dir_exists(pargs.destination_dir): return 1 - if not mk_genfile_common.check_files_exist(pargs.header_files): + if not mk_genfile_common.check_files_exist([pargs.deps]): return 1 - h_files_full_path = [] - for header_file in pargs.header_files: - h_files_full_path.append(os.path.abspath(header_file)) + with open(pargs.deps, 'r') as f: + lines = f.read().split('\n') + h_files_full_path = [os.path.abspath(header_file) + for header_file in lines if header_file] + + if not mk_genfile_common.check_files_exist(h_files_full_path): + return 1 output = mk_genfile_common.mk_install_tactic_cpp_internal( h_files_full_path, From cd4b53500c6e49e9f1de0259dd6ebab4a45946ff Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 8 Mar 2019 10:13:46 +0000 Subject: [PATCH 034/156] avoid a few str copies + symbol hiding --- src/api/api_config_params.cpp | 2 +- src/api/api_context.cpp | 12 ++---------- src/api/api_context.h | 2 +- src/api/api_goal.cpp | 4 ++-- src/api/api_model.cpp | 2 +- src/api/api_seq.cpp | 3 +-- src/api/api_stats.cpp | 2 +- src/ast/rewriter/pb2bv_rewriter.cpp | 2 +- src/shell/main.cpp | 14 +++++++------- src/util/gparams.cpp | 4 ++-- src/util/prime_generator.cpp | 2 +- src/util/scoped_ctrl_c.cpp | 4 ++-- src/util/scoped_ctrl_c.h | 2 -- 13 files changed, 22 insertions(+), 33 deletions(-) diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp index 60d5fa556..1682fb707 100644 --- a/src/api/api_config_params.cpp +++ b/src/api/api_config_params.cpp @@ -48,7 +48,7 @@ extern "C" { env_params::updt_params(); } - std::string g_Z3_global_param_get_buffer; + static std::string g_Z3_global_param_get_buffer; Z3_bool_opt Z3_API Z3_global_param_get(Z3_string param_id, Z3_string_ptr param_value) { memory::initialize(UINT_MAX); diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index a2492cb1a..71bebef73 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -155,8 +155,6 @@ namespace api { m_error_code = Z3_OK; } - - void context::check_searching() { if (m_searching) { set_error_code(Z3_INVALID_USAGE, "cannot use function while searching"); // TBD: error code could be fixed. @@ -168,8 +166,8 @@ namespace api { return const_cast(m_string_buffer.c_str()); } - char * context::mk_external_string(std::string const & str) { - m_string_buffer = str; + char * context::mk_external_string(std::string && str) { + m_string_buffer = std::move(str); return const_cast(m_string_buffer.c_str()); } @@ -466,17 +464,11 @@ extern "C" { } } - Z3_API char const * Z3_get_error_msg(Z3_context c, Z3_error_code err) { LOG_Z3_get_error_msg(c, err); return _get_error_msg(c, err); } - Z3_API char const * Z3_get_error_msg_ex(Z3_context c, Z3_error_code err) { - return Z3_get_error_msg(c, err); - } - - void Z3_API Z3_set_ast_print_mode(Z3_context c, Z3_ast_print_mode mode) { Z3_TRY; LOG_Z3_set_ast_print_mode(c, mode); diff --git a/src/api/api_context.h b/src/api/api_context.h index aacd4edd3..8bd75aaa0 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -179,7 +179,7 @@ namespace api { // Store a copy of str in m_string_buffer, and return a reference to it. // This method is used to communicate local/internal strings with the "external world" char * mk_external_string(char const * str); - char * mk_external_string(std::string const & str); + char * mk_external_string(std::string && str); // Create a numeral of the given sort expr * mk_numeral_core(rational const & n, sort * s); diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index c70d241e0..04c2945a9 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -189,7 +189,7 @@ extern "C" { std::string result = buffer.str(); SASSERT(result.size() > 0); result.resize(result.size()-1); - return mk_c(c)->mk_external_string(result); + return mk_c(c)->mk_external_string(std::move(result)); Z3_CATCH_RETURN(""); } @@ -207,7 +207,7 @@ extern "C" { std::string result = buffer.str(); SASSERT(result.size() > 0); result.resize(result.size()-1); - return mk_c(c)->mk_external_string(result); + return mk_c(c)->mk_external_string(std::move(result)); Z3_CATCH_RETURN(""); } diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 8fba5e9f6..812d80b23 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -478,7 +478,7 @@ extern "C" { model_v2_pp(buffer, *(to_model_ref(m)), p.partial()); result = buffer.str(); } - return mk_c(c)->mk_external_string(result); + return mk_c(c)->mk_external_string(std::move(result)); Z3_CATCH_RETURN(nullptr); } diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 19e298ee8..17264ad77 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -106,8 +106,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG, "expression is not a string literal"); return ""; } - std::string s = str.encode(); - return mk_c(c)->mk_external_string(s); + return mk_c(c)->mk_external_string(str.encode()); Z3_CATCH_RETURN(""); } diff --git a/src/api/api_stats.cpp b/src/api/api_stats.cpp index 3ff87039f..410118c9d 100644 --- a/src/api/api_stats.cpp +++ b/src/api/api_stats.cpp @@ -34,7 +34,7 @@ extern "C" { result = buffer.str(); SASSERT(result.size() > 0); result.resize(result.size()-1); - return mk_c(c)->mk_external_string(result); + return mk_c(c)->mk_external_string(std::move(result)); Z3_CATCH_RETURN(""); } diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 015372933..2a8681383 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -28,7 +28,7 @@ Notes: #include "util/uint_set.h" #include "util/gparams.h" -const unsigned g_primes[7] = { 2, 3, 5, 7, 11, 13, 17}; +static const unsigned g_primes[7] = { 2, 3, 5, 7, 11, 13, 17}; struct pb2bv_rewriter::imp { diff --git a/src/shell/main.cpp b/src/shell/main.cpp index 260cf8a79..1d22ce9b6 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -41,14 +41,14 @@ Revision History: typedef enum { IN_UNSPECIFIED, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_LP, IN_Z3_LOG, IN_MPS } input_kind; -std::string g_aux_input_file; -char const * g_input_file = nullptr; -bool g_standard_input = false; -input_kind g_input_kind = IN_UNSPECIFIED; +static std::string g_aux_input_file; +static char const * g_input_file = nullptr; +static bool g_standard_input = false; +static input_kind g_input_kind = IN_UNSPECIFIED; bool g_display_statistics = false; -bool g_display_istatistics = false; +static bool g_display_istatistics = false; -void error(const char * msg) { +static void error(const char * msg) { std::cerr << "Error: " << msg << "\n"; std::cerr << "For usage information: z3 -h\n"; exit(ERR_CMD_LINE); @@ -114,7 +114,7 @@ void display_usage() { std::cout << "Use 'z3 -p' for the complete list of global and module parameters.\n"; } -void parse_cmd_line_args(int argc, char ** argv) { +static void parse_cmd_line_args(int argc, char ** argv) { long timeout = 0; int i = 1; char * eq_pos = nullptr; diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 6b5919f8e..ea9b3603c 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -25,7 +25,7 @@ extern void gparams_register_modules(); static char const * g_old_params_names[] = { "arith_adaptive","arith_adaptive_assertion_threshold","arith_adaptive_gcd","arith_adaptive_propagation_threshold","arith_add_binary_bounds","arith_blands_rule_threshold","arith_branch_cut_ratio","arith_dump_lemmas","arith_eager_eq_axioms","arith_eager_gcd","arith_eq_bounds","arith_euclidean_solver","arith_expand_eqs","arith_force_simplex","arith_gcd_test","arith_ignore_int","arith_lazy_adapter","arith_lazy_pivoting","arith_max_lemma_size","arith_process_all_eqs","arith_propagate_eqs","arith_propagation_mode","arith_propagation_threshold","arith_prop_strategy","arith_random_initial_value","arith_random_lower","arith_random_seed","arith_random_upper","arith_reflect","arith_skip_big_coeffs","arith_small_lemma_size","arith_solver","arith_stronger_lemmas","array_always_prop_upward","array_canonize","array_cg","array_delay_exp_axiom","array_extensional","array_laziness","array_lazy_ieq","array_lazy_ieq_delay","array_solver","array_weak","async_commands","at_labels_cex","auto_config","bb_eager","bb_ext_gates","bb_quantifiers","bin_clauses","bit2int","bv2int_distribute","bv_blast_max_size","bv_cc","bv_enable_int2bv_propagation","bv_lazy_le","bv_max_sharing","bv_reflect","bv_solver","case_split","check_at_labels","check_proof","cnf_factor","cnf_mode","context_simplifier","dack","dack_eq","dack_factor","dack_gc","dack_gc_inv_decay","dack_threshold","default_qid","default_table","default_table_checked","delay_units","delay_units_threshold","der","display_config","display_dot_proof","display_error_for_visual_studio","display_features","display_proof","display_unsat_core","distribute_forall","dt_lazy_splits","dump_goal_as_smt","elim_and","elim_bounds","elim_nlarith_quantifiers","elim_quantifiers","elim_term_ite","ematching","engine","eq_propagation","hi_div0","ignore_bad_patterns","ignore_setparameter","instruction_max","inst_gen","interactive","internalizer_nnf","lemma_gc_factor","lemma_gc_half","lemma_gc_initial","lemma_gc_new_clause_activity","lemma_gc_new_clause_relevancy","lemma_gc_new_old_ratio","lemma_gc_old_clause_activity","lemma_gc_old_clause_relevancy","lemma_gc_strategy","lift_ite","lookahead_diseq","macro_finder","max_conflicts","max_counterexamples","mbqi","mbqi_force_template","mbqi_max_cexs","mbqi_max_cexs_incr","mbqi_max_iterations","mbqi_trace","minimize_lemmas","model","model_compact","model_completion","model_display_arg_sort","model_hide_unused_partitions","model_on_final_check","model_on_timeout","model_partial","model_v1","model_v2","model_validate","new_core2th_eq","ng_lift_ite","nl_arith","nl_arith_branching","nl_arith_gb","nl_arith_gb_eqs","nl_arith_gb_perturbate","nl_arith_gb_threshold","nl_arith_max_degree","nl_arith_rounds","nnf_factor","nnf_ignore_labels","nnf_mode","nnf_sk_hack","order","order_var_weight","order_weights","phase_selection","pi_arith","pi_arith_weight","pi_avoid_skolems","pi_block_looop_patterns","pi_max_multi_patterns","pi_non_nested_arith_weight","pi_nopat_weight","pi_pull_quantifiers","pi_use_database","pi_warnings","pp_bounded","pp_bv_literals","pp_bv_neg","pp_decimal","pp_decimal_precision","pp_fixed_indent","pp_flat_assoc","pp_max_depth","pp_max_indent","pp_max_num_lines","pp_max_ribbon","pp_max_width","pp_min_alias_size","pp_simplify_implies","pp_single_line","precedence","precedence_gen","pre_demodulator","pre_simplifier","pre_simplify_expr","profile_res_sub","progress_sampling_freq","proof_mode","propagate_booleans","propagate_values","pull_cheap_ite_trees","pull_nested_quantifiers","qi_conservative_final_check","qi_cost","qi_eager_threshold","qi_lazy_instantiation","qi_lazy_quick_checker","qi_lazy_threshold","qi_max_eager_multi_patterns","qi_max_instances","qi_max_lazy_multi_pattern_matching","qi_new_gen","qi_profile","qi_profile_freq","qi_promote_unsat","qi_quick_checker","quasi_macros","random_case_split_freq","random_initial_activity","random_seed","recent_lemma_threshold","reduce_args","refine_inj_axiom","relevancy","relevancy_lemma","rel_case_split_order","restart_adaptive","restart_agility_threshold","restart_factor","restart_initial","restart_strategy","restricted_quasi_macros","simplify_clauses","smtlib2_compliant","smtlib_category","smtlib_dump_lemmas","smtlib_logic","smtlib_source_info","smtlib_trace_path","soft_timeout","solver","spc_bs","spc_es","spc_factor_subsumption_index_opt","spc_initial_subsumption_index_opt","spc_max_subsumption_index_features","spc_min_func_freq_subsumption_index","spc_num_iterations","spc_trace","statistics","strong_context_simplifier","tick","trace","trace_file_name","type_check","user_theory_persist_axioms","user_theory_preprocess_axioms","verbose","warning","well_sorted_check","z3_solver_ll_pp","z3_solver_smt_pp", nullptr }; -bool is_old_param_name(symbol const & name) { +static bool is_old_param_name(symbol const & name) { char const * const * it = g_old_params_names; while (*it) { if (name == *it) @@ -66,7 +66,7 @@ static char const * g_params_renames[] = { "pp_min_alias_size", "pp.min_alias_size", nullptr }; -char const * get_new_param_name(symbol const & p) { +static char const * get_new_param_name(symbol const & p) { char const * const * it = g_params_renames; while (*it) { if (p == *it) { diff --git a/src/util/prime_generator.cpp b/src/util/prime_generator.cpp index 6c0376e52..9d3936edf 100644 --- a/src/util/prime_generator.cpp +++ b/src/util/prime_generator.cpp @@ -96,7 +96,7 @@ uint64_t prime_generator::operator()(unsigned idx) { return m_primes[idx]; } -prime_generator g_prime_generator; +static prime_generator g_prime_generator; prime_iterator::prime_iterator(prime_generator * g):m_idx(0) { if (g == nullptr) { diff --git a/src/util/scoped_ctrl_c.cpp b/src/util/scoped_ctrl_c.cpp index 2dbbaec9b..e6214cfab 100644 --- a/src/util/scoped_ctrl_c.cpp +++ b/src/util/scoped_ctrl_c.cpp @@ -20,9 +20,9 @@ Revision History: #include #include "util/scoped_ctrl_c.h" -scoped_ctrl_c * scoped_ctrl_c::g_obj = nullptr; +static scoped_ctrl_c * g_obj = nullptr; -void scoped_ctrl_c::on_ctrl_c(int) { +static void on_ctrl_c(int) { if (g_obj->m_first) { g_obj->m_cancel_eh(CTRL_C_EH_CALLER); if (g_obj->m_once) { diff --git a/src/util/scoped_ctrl_c.h b/src/util/scoped_ctrl_c.h index b3abf0e26..654938bfc 100644 --- a/src/util/scoped_ctrl_c.h +++ b/src/util/scoped_ctrl_c.h @@ -29,8 +29,6 @@ struct scoped_ctrl_c { bool m_enabled; void (STD_CALL *m_old_handler)(int); scoped_ctrl_c * m_old_scoped_ctrl_c; - static scoped_ctrl_c * g_obj; - static void STD_CALL on_ctrl_c(int); public: // If once == true, then the cancel_eh is invoked only at the first Ctrl-C. // The next time, the old signal handler will take over. From 9736c4637587bcfedacf614fd494d0826090f564 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 8 Mar 2019 11:16:10 +0000 Subject: [PATCH 035/156] constify is_threaded if MT is disabled --- src/util/util.cpp | 2 ++ src/util/util.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/util/util.cpp b/src/util/util.cpp index 59d6d752c..4fb361475 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -39,6 +39,7 @@ void set_verbose_stream(std::ostream& str) { g_verbose_stream = &str; } +#ifndef _NO_OMP_ #ifdef _WINDOWS static int g_thread_id = 0; #else @@ -57,6 +58,7 @@ bool is_threaded() { #endif return g_is_threaded; } +#endif std::ostream& verbose_stream() { return *g_verbose_stream; diff --git a/src/util/util.h b/src/util/util.h index 0ca02bc84..9bc4f8a41 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -174,7 +174,11 @@ void set_verbosity_level(unsigned lvl); unsigned get_verbosity_level(); std::ostream& verbose_stream(); void set_verbose_stream(std::ostream& str); +#ifdef _NO_OMP_ +# define is_threaded() false +#else bool is_threaded(); +#endif #define IF_VERBOSE(LVL, CODE) { \ From 5bc0fb47a837e53cab7994345f4435e55dade2fb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Mar 2019 19:31:30 -0800 Subject: [PATCH 036/156] fix #2169 Signed-off-by: Nikolaj Bjorner --- src/api/api_seq.cpp | 14 ++++++++++++++ src/api/python/z3/z3.py | 2 +- src/api/z3_api.h | 9 +++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 19e298ee8..0b4bd4348 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -55,6 +55,20 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } + + Z3_ast Z3_API Z3_mk_lstring(Z3_context c, unsigned sz, Z3_string str) { + Z3_TRY; + LOG_Z3_mk_string(c, str); + RESET_ERROR_CODE(); + unsigned_vector chs; + for (unsigned i = 0; i < sz; ++i) chs.push_back(str[i]); + zstring s(sz, chs.c_ptr(), zstring::ascii); + app* a = mk_c(c)->sutil().str.mk_string(s); + mk_c(c)->save_ast_trail(a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(nullptr); + } + Z3_sort Z3_API Z3_mk_string_sort(Z3_context c) { Z3_TRY; LOG_Z3_mk_string_sort(c); diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 2a3348ed9..f31df5a4f 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10006,7 +10006,7 @@ def is_string_value(a): def StringVal(s, ctx=None): """create a string expression""" ctx = _get_ctx(ctx) - return SeqRef(Z3_mk_string(ctx.ref(), s), ctx) + return SeqRef(Z3_mk_lstring(ctx.ref(), len(s), s), ctx) def String(name, ctx=None): """Return a string constant named `name`. If `ctx=None`, then the global context is used. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index e1710b499..ce59210f1 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3327,6 +3327,15 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_string(Z3_context c, Z3_string s); + /** + \brief Create a string constant out of the string that is passed in + It takes the length of the string as well to take into account + 0 characters. + + def_API('Z3_mk_lstring' ,AST ,(_in(CONTEXT), _in(UINT), _in(STRING))) + */ + Z3_ast Z3_API Z3_mk_lstring(Z3_context c, unsigned len, Z3_string s); + /** \brief Determine if \c s is a string constant. From 05663592ee7cad232e94274a9fe20721ec1cbd81 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 Mar 2019 14:42:00 -0700 Subject: [PATCH 037/156] fix #2173 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_rewriter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index f6b760f9c..24f23ea45 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -500,12 +500,14 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref // (bvsle (- x (srem x c1)) c2) -> (bvsle x (+ c1 c2 - 1)) // (bvsle (+ x (* -1 (srem_i x c1))) c2) // pre: (and (> c1 0) (> c2 0) (= c2 % c1 0) (<= (+ c1 c2 -1) max_int)) - if (is_signed && is_num2 && m_util.is_bv_add(a, a1, a2) && + if (is_signed && is_num2 && + m_util.is_bv_add(a, a1, a2) && m_util.is_bv_mul(a2, a3, a4) && is_numeral(a3, r1, sz) && m_util.norm(r1, sz, is_signed).is_minus_one() && m_util.is_bv_sremi(a4, a5, a6) && is_numeral(a6, r1, sz) && (r1 = m_util.norm(r1, sz, is_signed), r1.is_pos()) && r2.is_pos() && + (a1 == a5) && (r2 % r1).is_zero() && r1 + r2 - rational::one() < rational::power_of_two(sz-1)) { result = m_util.mk_sle(a1, m_util.mk_numeral(r1 + r2 - rational::one(), sz)); return BR_REWRITE2; From 8f1c5239beabd29bfc13216e4c9cc5f6ae9d0bcd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Mar 2019 13:39:57 -0700 Subject: [PATCH 038/156] updates for #2151 #2152 Signed-off-by: Nikolaj Bjorner --- src/ast/normal_forms/defined_names.cpp | 10 ++--- src/ast/rewriter/array_rewriter.h | 1 + src/ast/rewriter/rewriter.h | 2 +- src/ast/rewriter/rewriter_def.h | 53 +++++++++++++++++--------- src/ast/rewriter/th_rewriter.cpp | 9 ++++- src/model/model_evaluator.cpp | 19 +++++---- src/smt/smt_model_generator.cpp | 2 - 7 files changed, 61 insertions(+), 35 deletions(-) diff --git a/src/ast/normal_forms/defined_names.cpp b/src/ast/normal_forms/defined_names.cpp index 88ded842f..0dcdd9597 100644 --- a/src/ast/normal_forms/defined_names.cpp +++ b/src/ast/normal_forms/defined_names.cpp @@ -159,11 +159,11 @@ void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer - void process_const(app * t); + bool process_const(app * t); template bool visit(expr * t, unsigned max_depth); diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 0eeb1f52f..f628c2225 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -80,27 +80,42 @@ void rewriter_tpl::process_var(var * v) { template template -void rewriter_tpl::process_const(app * t) { +bool rewriter_tpl::process_const(app * t0) { + app_ref t(t0, m()); + bool rounds = 0; + retry: SASSERT(t->get_num_args() == 0); br_status st = m_cfg.reduce_app(t->get_decl(), 0, nullptr, m_r, m_pr); SASSERT(st != BR_DONE || m().get_sort(m_r) == m().get_sort(t)); - SASSERT(st == BR_FAILED || st == BR_DONE); - if (st == BR_DONE) { + switch (st) { + case BR_FAILED: + if (rounds == 0) { + result_stack().push_back(t); + if (ProofGen) + result_pr_stack().push_back(nullptr); // implicit reflexivity + return true; + } + m_r = t; + // fall through + case BR_DONE: result_stack().push_back(m_r.get()); if (ProofGen) { if (m_pr) result_pr_stack().push_back(m_pr); else - result_pr_stack().push_back(m().mk_rewrite(t, m_r)); + result_pr_stack().push_back(m().mk_rewrite(t0, m_r)); m_pr = nullptr; } m_r = nullptr; - set_new_child_flag(t); - } - else { - result_stack().push_back(t); - if (ProofGen) - result_pr_stack().push_back(nullptr); // implicit reflexivity + set_new_child_flag(t0); + return true; + default: + if (is_app(m_r) && to_app(m_r)->get_num_args() == 0) { + t = to_app(m_r); + rounds++; + goto retry; + } + return false; } } @@ -115,6 +130,7 @@ void rewriter_tpl::process_const(app * t) { template template bool rewriter_tpl::visit(expr * t, unsigned max_depth) { + // retry: TRACE("rewriter_visit", tout << "visiting\n" << mk_ismt2_pp(t, m()) << "\n";); expr * new_t = nullptr; proof * new_t_pr = nullptr; @@ -164,15 +180,14 @@ bool rewriter_tpl::visit(expr * t, unsigned max_depth) { switch (t->get_kind()) { case AST_APP: if (to_app(t)->get_num_args() == 0) { - process_const(to_app(t)); - return true; - } - else { - if (max_depth != RW_UNBOUNDED_DEPTH) - max_depth--; - push_frame(t, c, max_depth); - return false; + if (process_const(to_app(t))) + return true; + t = m_r; } + if (max_depth != RW_UNBOUNDED_DEPTH) + max_depth--; + push_frame(t, c, max_depth); + return false; case AST_VAR: process_var(to_var(t)); return true; @@ -224,7 +239,7 @@ bool rewriter_tpl::constant_fold(app * t, frame & fr) { template template void rewriter_tpl::process_app(app * t, frame & fr) { - SASSERT(t->get_num_args() > 0); + // SASSERT(t->get_num_args() > 0); SASSERT(!frame_stack().empty()); switch (fr.m_state) { case PROCESS_CHILDREN: { diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 4c81ab665..6a64eaa82 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -661,6 +661,13 @@ struct th_rewriter_cfg : public default_rewriter_cfg { p1 = m().mk_pull_quant(old_q, q1); } } + else if ( + old_q->get_kind() == lambda_k && + is_ground(new_body)) { + result = m_ar_rw.util().mk_const_array(old_q->get_sort(), new_body); + result_pr = nullptr; + return true; + } else { ptr_buffer new_patterns_buf; ptr_buffer new_no_patterns_buf; @@ -677,10 +684,10 @@ struct th_rewriter_cfg : public default_rewriter_cfg { TRACE("reduce_quantifier", tout << mk_ismt2_pp(old_q, m()) << "\n----->\n" << mk_ismt2_pp(q1, m()) << "\n";); SASSERT(is_well_sorted(m(), q1)); } - SASSERT(m().get_sort(old_q) == m().get_sort(q1)); result = elim_unused_vars(m(), q1, params_ref()); + TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << result << "\n";); result_pr = nullptr; diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index b2b927faf..35cbfe9c7 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -140,24 +140,25 @@ struct evaluator_cfg : public default_rewriter_cfg { result_pr = nullptr; family_id fid = f->get_family_id(); bool is_uninterp = fid != null_family_id && m.get_plugin(fid)->is_considered_uninterpreted(f); + br_status st = BR_FAILED; if (num == 0 && (fid == null_family_id || is_uninterp)) { expr * val = m_model.get_const_interp(f); if (val != nullptr) { result = val; - return BR_DONE; + return m_ar.is_as_array(val)? BR_REWRITE1 : BR_DONE; } - - if (m_model_completion) { + else if (m_model_completion) { sort * s = f->get_range(); expr * val = m_model.get_some_value(s); m_model.register_decl(f, val); result = val; return BR_DONE; } - return BR_FAILED; + else { + return BR_FAILED; + } } - br_status st = BR_FAILED; if (fid == m_b_rw.get_fid()) { decl_kind k = f->get_decl_kind(); @@ -205,17 +206,18 @@ struct evaluator_cfg : public default_rewriter_cfg { TRACE("model_evaluator", tout << "reduce_app " << f->get_name() << "\n"; for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m) << "\n"; tout << "---->\n" << mk_ismt2_pp(result, m) << "\n";); - return BR_REWRITE1; + st = BR_REWRITE1; } if (st == BR_FAILED && !m.is_builtin_family_id(fid)) st = evaluate_partial_theory_func(f, num, args, result, result_pr); if (st == BR_DONE && is_app(result)) { app* a = to_app(result); if (evaluate(a->get_decl(), a->get_num_args(), a->get_args(), result)) { - return BR_REWRITE1; + st = BR_REWRITE1; } } #if 1 + TRACE("model_evaluator", tout << st << " " << num << " " << m_ar.is_as_array(f) << " " << m_model_completion << "\n";); if (st == BR_FAILED && num == 0 && m_ar.is_as_array(f) && m_model_completion) { func_decl* g = nullptr; VERIFY(m_ar.is_as_array(f, g)); @@ -253,6 +255,7 @@ struct evaluator_cfg : public default_rewriter_cfg { } void expand_stores(expr_ref& val) { + TRACE("model_evaluator", tout << val << "\n";); vector stores; expr_ref else_case(m); bool _unused; @@ -503,6 +506,7 @@ struct evaluator_cfg : public default_rewriter_cfg { if (!m_ar.is_as_array(a)) { TRACE("model_evaluator", tout << "no translation: " << mk_pp(a, m) << "\n";); + TRACE("model_evaluator", tout << m_model << "\n";); return false; } @@ -630,6 +634,7 @@ void model_evaluator::reset(model_core &model, params_ref const& p) { void model_evaluator::operator()(expr * t, expr_ref & result) { TRACE("model_evaluator", tout << mk_ismt2_pp(t, m()) << "\n";); m_imp->operator()(t, result); + TRACE("model_evaluator", tout << result << "\n";); m_imp->expand_stores(result); } diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index c27845ff6..065e5d952 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -380,11 +380,9 @@ namespace smt { */ bool model_generator::include_func_interp(func_decl * f) const { family_id fid = f->get_family_id(); - TRACE("model", tout << f->get_name() << " " << fid << "\n";); if (fid == null_family_id) return !m_hidden_ufs.contains(f); if (fid == m_manager.get_basic_family_id()) return false; theory * th = m_context->get_theory(fid); - TRACE("model", tout << th << "\n";); if (!th) return true; return th->include_func_interp(f); } From 75b1e8fe27ed35d235b691c5258cf9502d8e4fc5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Mar 2019 20:12:17 -0700 Subject: [PATCH 039/156] add tracing for 2157 Signed-off-by: Nikolaj Bjorner --- src/opt/optsmt.cpp | 7 ++++++- src/smt/theory_lra.cpp | 2 ++ src/util/lp/lar_core_solver_def.h | 6 +++++- src/util/lp/lp_primal_core_solver_def.h | 2 ++ src/util/lp/lp_primal_core_solver_tableau_def.h | 2 ++ 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 462c9855a..46491bc23 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -191,7 +191,10 @@ namespace opt { SASSERT(delta_per_step.is_int()); SASSERT(delta_per_step.is_pos()); is_sat = m_s->check_sat(0, nullptr); - TRACE("opt", tout << "check " << is_sat << "\n";); + TRACE("opt", tout << "check " << is_sat << "\n"; + tout << "lower: " << m_lower[obj_index] << "\n"; + tout << "upper: " << m_upper[obj_index] << "\n"; + ); if (is_sat == l_true) { m_s->maximize_objective(obj_index, bound); m_s->get_model(m_model); @@ -232,6 +235,8 @@ namespace opt { } m_s->pop(num_scopes); + TRACE("opt", tout << is_sat << " " << num_scopes << "\n";); + if (is_sat == l_false && !m_model) { return l_false; } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index ceeb1617f..27362fc77 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -955,6 +955,7 @@ public: } void push_scope_eh() { + TRACE("arith", tout << "push\n";); m_scopes.push_back(scope()); scope& s = m_scopes.back(); s.m_bounds_lim = m_bounds_trail.size(); @@ -969,6 +970,7 @@ public: } void pop_scope_eh(unsigned num_scopes) { + TRACE("arith", tout << "pop " << num_scopes << "\n";); if (num_scopes == 0) { return; } diff --git a/src/util/lp/lar_core_solver_def.h b/src/util/lp/lar_core_solver_def.h index ca7915c7d..476e11698 100644 --- a/src/util/lp/lar_core_solver_def.h +++ b/src/util/lp/lar_core_solver_def.h @@ -278,6 +278,7 @@ void lar_core_solver::solve() { CASSERT("A_off", !m_r_solver.A_mult_x_is_off()); lp_assert((!settings().use_tableau()) || r_basis_is_OK()); if (need_to_presolve_with_double_solver()) { + TRACE("lar_solver", tout << "presolving\n";); prefix_d(); lar_solution_signature solution_signature; vector changes_of_basis = find_solution_signature_with_doubles(solution_signature); @@ -293,6 +294,7 @@ void lar_core_solver::solve() { lp_assert(!settings().use_tableau() || r_basis_is_OK()); } else { if (!settings().use_tableau()) { + TRACE("lar_solver", tout << "no tablau\n";); bool snapped = m_r_solver.snap_non_basic_x_to_bound(); lp_assert(m_r_solver.non_basic_columns_are_set_correctly()); if (snapped) @@ -300,8 +302,10 @@ void lar_core_solver::solve() { } if (m_r_solver.m_look_for_feasible_solution_only) m_r_solver.find_feasible_solution(); - else + else { + TRACE("lar_solver", tout << "solve\n";); m_r_solver.solve(); + } lp_assert(!settings().use_tableau() || r_basis_is_OK()); } if (m_r_solver.get_status() == lp_status::INFEASIBLE) { diff --git a/src/util/lp/lp_primal_core_solver_def.h b/src/util/lp/lp_primal_core_solver_def.h index ad861cc7a..bc3ccc055 100644 --- a/src/util/lp/lp_primal_core_solver_def.h +++ b/src/util/lp/lp_primal_core_solver_def.h @@ -863,6 +863,7 @@ template void lp_primal_core_solver::print_column // returns the number of iterations template unsigned lp_primal_core_solver::solve() { + TRACE("lar_solver", tout << "solve " << this->get_status() << "\n";); if (numeric_traits::precise() && this->m_settings.use_tableau()) return solve_with_tableau(); @@ -882,6 +883,7 @@ template unsigned lp_primal_core_solver::solve() } one_iteration(); + TRACE("lar_solver", tout << "one iteration: " << this->get_status() << "\n";); lp_assert(!this->m_using_infeas_costs || this->costs_on_nbasis_are_zeros()); switch (this->get_status()) { case lp_status::OPTIMAL: // double check that we are at optimum diff --git a/src/util/lp/lp_primal_core_solver_tableau_def.h b/src/util/lp/lp_primal_core_solver_tableau_def.h index 8f9cf7ff1..0d6f7ac92 100644 --- a/src/util/lp/lp_primal_core_solver_tableau_def.h +++ b/src/util/lp/lp_primal_core_solver_tableau_def.h @@ -35,6 +35,7 @@ template void lp_primal_core_solver::advance_on_e X t; int leaving = find_leaving_and_t_tableau(entering, t); if (leaving == -1) { + TRACE("lar_solver", tout << "nothing leaving " << entering << "\n";); this->set_status(lp_status::UNBOUNDED); return; } @@ -117,6 +118,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { } else one_iteration_tableau(); + TRACE("lar_solver", tout << "one iteration tableau " << this->get_status() << "\n";); switch (this->get_status()) { case lp_status::OPTIMAL: // double check that we are at optimum case lp_status::INFEASIBLE: From f336039da3a919c45a49f16134e140f1a155731d Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 13 Mar 2019 15:28:50 -0700 Subject: [PATCH 040/156] snap variables to bounds when maximizing terms Signed-off-by: Lev Nachmanson --- src/util/lp/int_solver.cpp | 64 ++--------------------- src/util/lp/int_solver.h | 3 -- src/util/lp/lar_solver.cpp | 69 +++++++++++++++++++++++-- src/util/lp/lar_solver.h | 7 +++ src/util/lp/lp_primal_core_solver.h | 3 +- src/util/lp/lp_primal_core_solver_def.h | 3 +- 6 files changed, 80 insertions(+), 69 deletions(-) diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 6af668506..ad6766f64 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -263,7 +263,7 @@ lia_move int_solver::find_cube() { if (st != lp_status::FEASIBLE && st != lp_status::OPTIMAL) { TRACE("cube", tout << "cannot find a feasiblie solution";); _sp.pop(); - move_non_basic_columns_to_bounds(); + m_lar_solver->move_non_basic_columns_to_bounds(); find_feasible_solution(); // it can happen that we found an integer solution here return !m_lar_solver->r_basis_has_inf_int()? lia_move::sat: lia_move::undef; @@ -296,7 +296,7 @@ lia_move int_solver::gomory_cut() { if ((m_number_of_calls) % settings().m_int_gomory_cut_period != 0) return lia_move::undef; - if (move_non_basic_columns_to_bounds()) { + if (m_lar_solver->move_non_basic_columns_to_bounds()) { #if Z3DEBUG lp_status st = #endif @@ -441,53 +441,6 @@ int int_solver::find_any_inf_int_column_basis_first() { return find_inf_int_nbasis_column(); } -bool int_solver::move_non_basic_column_to_bounds(unsigned j) { - auto & lcs = m_lar_solver->m_mpq_lar_core_solver; - auto & val = lcs.m_r_x[j]; - switch (lcs.m_column_types()[j]) { - case column_type::boxed: - if (val != lcs.m_r_lower_bounds()[j] && val != lcs.m_r_upper_bounds()[j]) { - if (random() % 2 == 0) - set_value_for_nbasic_column(j, lcs.m_r_lower_bounds()[j]); - else - set_value_for_nbasic_column(j, lcs.m_r_upper_bounds()[j]); - return true; - } - break; - case column_type::lower_bound: - if (val != lcs.m_r_lower_bounds()[j]) { - set_value_for_nbasic_column(j, lcs.m_r_lower_bounds()[j]); - return true; - } - break; - case column_type::upper_bound: - if (val != lcs.m_r_upper_bounds()[j]) { - set_value_for_nbasic_column(j, lcs.m_r_upper_bounds()[j]); - return true; - } - break; - default: - if (is_int(j) && !val.is_int()) { - set_value_for_nbasic_column(j, impq(floor(val))); - return true; - } - break; - } - return false; -} - -bool int_solver::move_non_basic_columns_to_bounds() { - auto & lcs = m_lar_solver->m_mpq_lar_core_solver; - bool change = false; - for (unsigned j : lcs.m_r_nbasis) { - if (move_non_basic_column_to_bounds(j)) - change = true; - } - - if (settings().simplex_strategy() == simplex_strategy_enum::tableau_costs) - m_lar_solver->update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); - return change; -} void int_solver::set_value_for_nbasic_column_ignore_old_values(unsigned j, const impq & new_val) { lp_assert(!is_base(j)); @@ -498,13 +451,6 @@ void int_solver::set_value_for_nbasic_column_ignore_old_values(unsigned j, const } -void int_solver::set_value_for_nbasic_column(unsigned j, const impq & new_val) { - lp_assert(!is_base(j)); - auto & x = m_lar_solver->m_mpq_lar_core_solver.m_r_x[j]; - auto delta = new_val - x; - x = new_val; - m_lar_solver->change_basic_columns_dependend_on_a_given_nb_column(j, delta); -} void int_solver::patch_nbasic_column(unsigned j, bool patch_only_int_vals) { auto & lcs = m_lar_solver->m_mpq_lar_core_solver; @@ -537,7 +483,7 @@ void int_solver::patch_nbasic_column(unsigned j, bool patch_only_int_vals) { if (inf_u || l <= u) { TRACE("patch_int", tout << "patching with l: " << l << '\n';); - set_value_for_nbasic_column(j, l); + m_lar_solver->set_value_for_nbasic_column(j, l); } else { TRACE("patch_int", @@ -546,12 +492,12 @@ void int_solver::patch_nbasic_column(unsigned j, bool patch_only_int_vals) { } else if (!inf_u) { u = m_is_one ? floor(u) : m * floor(u / m); - set_value_for_nbasic_column(j, u); + m_lar_solver->set_value_for_nbasic_column(j, u); TRACE("patch_int", tout << "patching with u: " << u << '\n';); } else { - set_value_for_nbasic_column(j, impq(0)); + m_lar_solver->set_value_for_nbasic_column(j, impq(0)); TRACE("patch_int", tout << "patching with 0\n";); } diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index 17ce20481..9fb6aa066 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -55,7 +55,6 @@ public: explanation const& get_explanation() const { return m_ex; } bool is_upper() const { return m_upper; } - bool move_non_basic_column_to_bounds(unsigned j); bool is_base(unsigned j) const; bool is_real(unsigned j) const; const impq & lower_bound(unsigned j) const; @@ -95,7 +94,6 @@ private: bool is_fixed(unsigned j) const; bool is_free(unsigned j) const; bool value_is_int(unsigned j) const; - void set_value_for_nbasic_column(unsigned j, const impq & new_val); void set_value_for_nbasic_column_ignore_old_values(unsigned j, const impq & new_val); bool non_basic_columns_are_at_bounds() const; bool is_feasible() const; @@ -108,7 +106,6 @@ private: int get_kth_inf_int(unsigned) const; lp_settings& settings(); const lp_settings& settings() const; - bool move_non_basic_columns_to_bounds(); void branch_infeasible_int_var(unsigned); lia_move mk_gomory_cut(unsigned inf_col, const row_strip& row); lia_move proceed_with_gomory_cut(unsigned j); diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 48b08a215..28d06f65d 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -270,9 +270,9 @@ void lar_solver::propagate_bounds_for_touched_rows(bound_propagator & bp) { } } -lp_status lar_solver::get_status() const { return m_status;} +lp_status lar_solver::get_status() const { return m_status; } -void lar_solver::set_status(lp_status s) {m_status = s;} +void lar_solver::set_status(lp_status s) { m_status = s; } lp_status lar_solver::find_feasible_solution() { m_settings.st().m_make_feasible++; @@ -453,9 +453,10 @@ void lar_solver::set_costs_to_zero(const lar_term& term) { lp_assert(costs_are_zeros_for_r_solver()); } -void lar_solver::prepare_costs_for_r_solver(const lar_term & term) { - +void lar_solver::prepare_costs_for_r_solver(const lar_term & term) { TRACE("lar_solver", print_term(term, tout << "prepare: ") << "\n";); + if (move_non_basic_columns_to_bounds()) + find_feasible_solution(); auto & rslv = m_mpq_lar_core_solver.m_r_solver; rslv.m_using_infeas_costs = false; lp_assert(costs_are_zeros_for_r_solver()); @@ -471,13 +472,71 @@ void lar_solver::prepare_costs_for_r_solver(const lar_term & term) { } lp_assert(rslv.reduced_costs_are_correct_tableau()); } + +bool lar_solver::move_non_basic_columns_to_bounds() { + auto & lcs = m_mpq_lar_core_solver; + bool change = false; + for (unsigned j : lcs.m_r_nbasis) { + if (move_non_basic_column_to_bounds(j)) + change = true; + } + + if (settings().simplex_strategy() == simplex_strategy_enum::tableau_costs) + update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); + return change; +} + +bool lar_solver::move_non_basic_column_to_bounds(unsigned j) { + auto & lcs = m_mpq_lar_core_solver; + auto & val = lcs.m_r_x[j]; + switch (lcs.m_column_types()[j]) { + case column_type::boxed: + if (val != lcs.m_r_lower_bounds()[j] && val != lcs.m_r_upper_bounds()[j]) { + if (random() % 2 == 0) + set_value_for_nbasic_column(j, lcs.m_r_lower_bounds()[j]); + else + set_value_for_nbasic_column(j, lcs.m_r_upper_bounds()[j]); + return true; + } + break; + case column_type::lower_bound: + if (val != lcs.m_r_lower_bounds()[j]) { + set_value_for_nbasic_column(j, lcs.m_r_lower_bounds()[j]); + return true; + } + break; + case column_type::upper_bound: + if (val != lcs.m_r_upper_bounds()[j]) { + set_value_for_nbasic_column(j, lcs.m_r_upper_bounds()[j]); + return true; + } + break; + default: + if (is_int(j) && !val.is_int()) { + set_value_for_nbasic_column(j, impq(floor(val))); + return true; + } + break; + } + return false; +} + +void lar_solver::set_value_for_nbasic_column(unsigned j, const impq & new_val) { + lp_assert(!is_base(j)); + auto & x = m_mpq_lar_core_solver.m_r_x[j]; + auto delta = new_val - x; + x = new_val; + change_basic_columns_dependend_on_a_given_nb_column(j, delta); +} + bool lar_solver::maximize_term_on_corrected_r_solver(lar_term & term, impq &term_max) { settings().backup_costs = false; bool ret = false; - TRACE("lar_solver", print_term(term, tout << "maximize: ") << "\n"; print_constraints(tout);); + TRACE("lar_solver", print_term(term, tout << "maximize: ") << "\n"; print_constraints(tout); tout << ", strategy = " << (int)settings().simplex_strategy() << "\n";); switch (settings().simplex_strategy()) { + case simplex_strategy_enum::tableau_rows: prepare_costs_for_r_solver(term); settings().simplex_strategy() = simplex_strategy_enum::tableau_costs; diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 39adbd86f..2b506abd0 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -359,7 +359,14 @@ public: void detect_rows_with_changed_bounds_for_column(unsigned j); void detect_rows_with_changed_bounds(); + inline bool is_base(unsigned j) const { + return m_mpq_lar_core_solver.m_r_heading[j] >= 0; + } + bool move_non_basic_columns_to_bounds(); + + bool move_non_basic_column_to_bounds(unsigned j); + void set_value_for_nbasic_column(unsigned j, const impq & new_val); void update_x_and_inf_costs_for_columns_with_changed_bounds(); void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); diff --git a/src/util/lp/lp_primal_core_solver.h b/src/util/lp/lp_primal_core_solver.h index db92edb05..c3d262e91 100644 --- a/src/util/lp/lp_primal_core_solver.h +++ b/src/util/lp/lp_primal_core_solver.h @@ -869,7 +869,8 @@ public: for (unsigned j : this->m_basis) if(!basis_column_is_set_correctly(j)) return false; - return true; + + return this->m_basis_heading.size() == this->m_A.column_count() && this->m_basis.size() == this->m_A.row_count(); } void init_run_tableau(); diff --git a/src/util/lp/lp_primal_core_solver_def.h b/src/util/lp/lp_primal_core_solver_def.h index bc3ccc055..588e67756 100644 --- a/src/util/lp/lp_primal_core_solver_def.h +++ b/src/util/lp/lp_primal_core_solver_def.h @@ -151,8 +151,9 @@ template bool lp_primal_core_solver::column_is_benefitial_for_entering_basis_precise(unsigned j) const { lp_assert (numeric_traits::precise()); if (this->m_using_infeas_costs && this->m_settings.use_breakpoints_in_feasibility_search) - return column_is_benefitial_for_entering_on_breakpoints(j); + return column_is_benefitial_for_entering_on_breakpoints(j); const T& dj = this->m_d[j]; + TRACE("lar_solver", tout << "dj=" << dj << "\n";); switch (this->m_column_types[j]) { case column_type::fixed: break; case column_type::free_column: From d642ed559155d97639cc522740acff39231d0f47 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Mar 2019 18:03:18 -0700 Subject: [PATCH 041/156] adding targets Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_release.py | 4 ++++ src/api/dotnet/Microsoft.Z3.targets.in | 10 ++++++++++ 2 files changed, 14 insertions(+) create mode 100644 src/api/dotnet/Microsoft.Z3.targets.in diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index ebd0e0ba7..d1033ae58 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -81,6 +81,9 @@ def unpack(): zip_ref.extract("%s/bin/%s" % (package_dir, b), "tmp") shutil.move("tmp/%s/bin/%s" % (package_dir, b), "out/lib/netstandard1.4/%s" % b) +def mk_targets(): + shutil.copy("../src/api/dotnet/Microsoft.Z3.targets.in", "out/Microsoft.Z3.targets") + def create_nuget_spec(): contents = """ @@ -164,6 +167,7 @@ def main(): mk_dir("packages") download_installs() unpack() + mk_targets() create_nuget_spec() create_nuget_package() sign_nuget_package() diff --git a/src/api/dotnet/Microsoft.Z3.targets.in b/src/api/dotnet/Microsoft.Z3.targets.in new file mode 100644 index 000000000..a5ff7b8aa --- /dev/null +++ b/src/api/dotnet/Microsoft.Z3.targets.in @@ -0,0 +1,10 @@ + + + + + false + libz3.dll + PreserveNewest + + + \ No newline at end of file From 90b78eb64a2eacb2f36cd08cfa959239df1dca0d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Mar 2019 19:59:05 -0700 Subject: [PATCH 042/156] use random_next instead of library random Signed-off-by: Nikolaj Bjorner --- src/util/lp/lar_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 28d06f65d..503624a6e 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -492,7 +492,7 @@ bool lar_solver::move_non_basic_column_to_bounds(unsigned j) { switch (lcs.m_column_types()[j]) { case column_type::boxed: if (val != lcs.m_r_lower_bounds()[j] && val != lcs.m_r_upper_bounds()[j]) { - if (random() % 2 == 0) + if (m_settings.random_next() % 2 == 0) set_value_for_nbasic_column(j, lcs.m_r_lower_bounds()[j]); else set_value_for_nbasic_column(j, lcs.m_r_upper_bounds()[j]); From 038f992ff485d0bf93f962dc9e45330ff1e2e47d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Mar 2019 12:48:27 -0700 Subject: [PATCH 043/156] remove platformtarget for dotnetcore spec Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 10 +--------- src/smt/theory_lra.cpp | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 18ed0f74e..f57394f3e 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1889,20 +1889,12 @@ class DotNetCoreDLLComponent(Component): key = "%s" % self.key_file key += "\ntrue" - if VS_X64: - platform = 'x64' - elif VS_ARM: - platform = 'ARM' - else: - platform = 'x86' - version = get_version_string(3) core_csproj_str = """ netstandard1.4 - %s $(DefineConstants);DOTNET_CORE portable Microsoft.Z3 @@ -1923,7 +1915,7 @@ class DotNetCoreDLLComponent(Component): -""" % (platform, version, key, self.to_src_dir) +""" % (version, key, self.to_src_dir) mk_dir(os.path.join(BUILD_DIR, 'dotnet')) csproj = os.path.join('dotnet', 'z3.csproj') diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 27362fc77..11a9fa6f7 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1517,7 +1517,7 @@ public: } final_check_status final_check_eh() { - IF_VERBOSE(2, verbose_stream() << "final-check " << m_solver->get_status() << "\n"); + IF_VERBOSE(12, verbose_stream() << "final-check " << m_solver->get_status() << "\n"); m_use_nra_model = false; lbool is_sat = l_true; if (m_solver->get_status() != lp::lp_status::OPTIMAL) { From 001c120169a06da94f04cd4231614f8098a24e3f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Mar 2019 15:35:33 -0700 Subject: [PATCH 044/156] x64 Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_release.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index d1033ae58..fe31dc16c 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -42,7 +42,8 @@ def download_installs(): os_info = {"z64-ubuntu-14" : ('so', 'ubuntu.14.04-x64'), 'ubuntu-16' : ('so', 'ubuntu-x64'), 'x64-win' : ('dll', 'win-x64'), - 'x86-win' : ('dll', 'win-x86'), +# Skip x86 as I can't get dotnet build to produce AnyCPU TargetPlatform +# 'x86-win' : ('dll', 'win-x86'), 'osx' : ('dylib', 'macos'), 'debian' : ('so', 'debian.8-x64') } @@ -82,13 +83,19 @@ def unpack(): shutil.move("tmp/%s/bin/%s" % (package_dir, b), "out/lib/netstandard1.4/%s" % b) def mk_targets(): - shutil.copy("../src/api/dotnet/Microsoft.Z3.targets.in", "out/Microsoft.Z3.targets") + mk_dir("out/build") + shutil.copy("../src/api/dotnet/Microsoft.Z3.targets.in", "out/build/Microsoft.Z3.targets") + +def mk_license(): + mk_dir("out/license") + shutil.copy("../LICENSE.txt", "out/license/LICENSE.txt") def create_nuget_spec(): + mk_license() contents = """ - Microsoft.Z3 + Microsoft.Z3.x64 %s Microsoft @@ -108,7 +115,7 @@ Linux Dependencies: """ - with open("out/Microsoft.Z3.nuspec", 'w') as f: + with open("out/Microsoft.Z3.x64.nuspec", 'w') as f: f.write(contents % version_num) def create_nuget_package(): @@ -128,8 +135,8 @@ nuget_sign_input = """ "SignRequestFiles": [ { "CustomerCorrelationId": "42fc9577-af9e-4ac9-995d-1788d8721d17", - "SourceLocation": "Microsoft.Z3.%s.nupkg", - "DestinationLocation": "Microsoft.Z3.%s.nupkg" + "SourceLocation": "Microsoft.Z3.x64.%s.nupkg", + "DestinationLocation": "Microsoft.Z3.x64.%s.nupkg" } ], "SigningInfo": { @@ -155,7 +162,7 @@ nuget_sign_input = """ }""" def sign_nuget_package(): - package_name = "Microsoft.Z3.%s.nupkg" % version_num + package_name = "Microsoft.Z3.x64.%s.nupkg" % version_num input_file = "out/nuget_sign_input.json" output_path = os.path.abspath("out").replace("\\","\\\\") with open(input_file, 'w') as f: From e19c1194963e896683074dd738df8e3b40893922 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Mar 2019 15:41:52 -0700 Subject: [PATCH 045/156] copyright Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index fe31dc16c..0b6f130b1 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -104,7 +104,7 @@ Z3 is a satisfiability modulo theories solver from Microsoft Research. Linux Dependencies: libgomp.so.1 installed - Copyright Microsoft Corporation. All rights reserved. + © 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 From 0a477a0a93bd6bf5ebac8be9998fbe53ad6ff431 Mon Sep 17 00:00:00 2001 From: Andrew Helwer Date: Thu, 14 Mar 2019 15:46:03 -0700 Subject: [PATCH 046/156] Remove dependency on TargetPlatform macro Unnecessary, since dropping support for x86 --- src/api/dotnet/Microsoft.Z3.targets.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/Microsoft.Z3.targets.in b/src/api/dotnet/Microsoft.Z3.targets.in index a5ff7b8aa..bf2ca2dc7 100644 --- a/src/api/dotnet/Microsoft.Z3.targets.in +++ b/src/api/dotnet/Microsoft.Z3.targets.in @@ -1,10 +1,10 @@ - + false libz3.dll PreserveNewest - \ No newline at end of file + From 7b50fca02c1399efe115e1d1efaa08f8529d71e0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Mar 2019 18:22:42 -0700 Subject: [PATCH 047/156] display dimacs Signed-off-by: Nikolaj Bjorner --- src/ast/display_dimacs.cpp | 60 +++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/src/ast/display_dimacs.cpp b/src/ast/display_dimacs.cpp index da39538d9..a1375dff8 100644 --- a/src/ast/display_dimacs.cpp +++ b/src/ast/display_dimacs.cpp @@ -26,6 +26,7 @@ std::ostream& display_dimacs(std::ostream& out, expr_ref_vector const& fmls) { ptr_vector exprs; unsigned num_vars = 0; unsigned num_cls = fmls.size(); + bool is_from_dimacs = true; for (expr * f : fmls) { unsigned num_lits; expr * const * lits; @@ -41,10 +42,51 @@ std::ostream& display_dimacs(std::ostream& out, expr_ref_vector const& fmls) { expr * l = lits[j]; if (m.is_not(l)) l = to_app(l)->get_arg(0); - if (expr2var.get(l->get_id(), UINT_MAX) == UINT_MAX) { - num_vars++; - expr2var.setx(l->get_id(), num_vars, UINT_MAX); - exprs.setx(l->get_id(), l, nullptr); + if (!is_uninterp_const(l)) { + is_from_dimacs = false; + break; + } + symbol const& s = to_app(l)->get_decl()->get_name(); + if (s.is_numerical() && s.get_num() > 0) { + if (expr2var.get(l->get_id(), UINT_MAX) == UINT_MAX) { + ++num_vars; + expr2var.setx(l->get_id(), s.get_num(), UINT_MAX); + exprs.setx(l->get_id(), l, nullptr); + } + continue; + } + is_from_dimacs = false; + break; + } + if (!is_from_dimacs) { + num_vars = 0; + expr2var.reset(); + exprs.reset(); + break; + } + } + + if (!is_from_dimacs) { + for (expr * f : fmls) { + unsigned num_lits; + expr * const * lits; + if (m.is_or(f)) { + num_lits = to_app(f)->get_num_args(); + lits = to_app(f)->get_args(); + } + else { + num_lits = 1; + lits = &f; + } + for (unsigned j = 0; j < num_lits; j++) { + expr * l = lits[j]; + if (m.is_not(l)) + l = to_app(l)->get_arg(0); + if (expr2var.get(l->get_id(), UINT_MAX) == UINT_MAX) { + num_vars++; + expr2var.setx(l->get_id(), num_vars, UINT_MAX); + exprs.setx(l->get_id(), l, nullptr); + } } } } @@ -71,10 +113,12 @@ std::ostream& display_dimacs(std::ostream& out, expr_ref_vector const& fmls) { } out << "0\n"; } - for (expr* e : exprs) { - if (e && is_app(e)) { - symbol const& n = to_app(e)->get_decl()->get_name(); - out << "c " << expr2var[e->get_id()] << " " << n << "\n"; + if (!is_from_dimacs) { + for (expr* e : exprs) { + if (e && is_app(e)) { + symbol const& n = to_app(e)->get_decl()->get_name(); + out << "c " << expr2var[e->get_id()] << " " << n << "\n"; + } } } return out; From f0aebb1600ac1660c43f155f81b6747891e2e4b4 Mon Sep 17 00:00:00 2001 From: Andrew Helwer Date: Fri, 15 Mar 2019 15:20:32 -0700 Subject: [PATCH 048/156] Fixed nuget package spec generation code --- scripts/mk_nuget_release.py | 40 ++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index 0b6f130b1..4a2bfd98e 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -20,19 +20,23 @@ 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()) +release_data = json.loads(urllib.request.urlopen("https://api.github.com/repos/Z3Prover/z3/releases/latest").read().decode()) +release_tag_name = release_data['tag_name'] +release_tag_ref_data = json.loads(urllib.request.urlopen("https://api.github.com/repos/Z3Prover/z3/git/refs/tags/%s" % release_tag_name).read().decode()) +release_tag_sha = release_tag_ref_data['object']['sha'] +release_tag_data = json.loads(urllib.request.urlopen("https://api.github.com/repos/Z3Prover/z3/git/tags/%s" % release_tag_sha).read().decode()) -version_str = data['tag_name'] -version_num = version_str[3:] +release_version = release_tag_name[3:] +release_commit = release_tag_data['object']['sha'] -print(version_str) +print(release_version) def mk_dir(d): if not os.path.exists(d): os.makedirs(d) def download_installs(): - for asset in data['assets']: + for asset in latest_release_data['assets']: url = asset['browser_download_url'] name = asset['name'] print("Downloading ", url) @@ -85,18 +89,13 @@ def unpack(): def mk_targets(): mk_dir("out/build") shutil.copy("../src/api/dotnet/Microsoft.Z3.targets.in", "out/build/Microsoft.Z3.targets") - -def mk_license(): - mk_dir("out/license") - shutil.copy("../LICENSE.txt", "out/license/LICENSE.txt") def create_nuget_spec(): - mk_license() contents = """ Microsoft.Z3.x64 - %s + {0} Microsoft Z3 is a satisfiability modulo theories solver from Microsoft Research. @@ -106,17 +105,22 @@ Linux Dependencies: © Microsoft Corporation. All rights reserved. smt constraint solver theorem prover - https://raw.githubusercontent.com/Z3Prover/z3/master/package/icon.jpg + https://raw.githubusercontent.com/Z3Prover/z3/{1}/package/icon.jpg https://github.com/Z3Prover/z3 - https://raw.githubusercontent.com/Z3Prover/z3/master/LICENSE.txt - + https://raw.githubusercontent.com/Z3Prover/z3/{1}/LICENSE.txt + true en -""" +""".format(release_version, release_commit) with open("out/Microsoft.Z3.x64.nuspec", 'w') as f: - f.write(contents % version_num) + f.write(contents) def create_nuget_package(): subprocess.call(["nuget", "pack"], cwd="out") @@ -162,11 +166,11 @@ nuget_sign_input = """ }""" def sign_nuget_package(): - package_name = "Microsoft.Z3.x64.%s.nupkg" % version_num + package_name = "Microsoft.Z3.x64.%s.nupkg" % release_version input_file = "out/nuget_sign_input.json" output_path = os.path.abspath("out").replace("\\","\\\\") with open(input_file, 'w') as f: - f.write(nuget_sign_input % (output_path, output_path, version_num, version_num)) + f.write(nuget_sign_input % (output_path, output_path, release_version, release_version)) subprocess.call(["EsrpClient.exe", "sign", "-a", "authorization.json", "-p", "policy.json", "-i", input_file, "-o", "out\\diagnostics.json"]) From a492eb020901a394fc9b13bda30fbd5d7f630995 Mon Sep 17 00:00:00 2001 From: Andrew Helwer Date: Fri, 15 Mar 2019 15:23:33 -0700 Subject: [PATCH 049/156] Fixed missed renamed variable --- scripts/mk_nuget_release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index 4a2bfd98e..0b418f48d 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -36,7 +36,7 @@ def mk_dir(d): os.makedirs(d) def download_installs(): - for asset in latest_release_data['assets']: + for asset in release_data['assets']: url = asset['browser_download_url'] name = asset['name'] print("Downloading ", url) From 869cb66736b075726246ea151aa21a144acb3f22 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Mar 2019 11:52:55 -0700 Subject: [PATCH 050/156] step 1 in aligning version tweaks for #2184 Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index f57394f3e..b8fbf9a45 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -102,7 +102,7 @@ STATIC_BIN=False VER_MAJOR=None VER_MINOR=None VER_BUILD=None -VER_REVISION=None +VER_TWEAK=None PREFIX=sys.prefix GMP=False VS_PAR=False @@ -553,22 +553,22 @@ def find_c_compiler(): raise MKException('C compiler was not found. Try to set the environment variable CC with the C compiler available in your system.') def set_version(major, minor, build, revision): - global VER_MAJOR, VER_MINOR, VER_BUILD, VER_REVISION, GIT_DESCRIBE + global VER_MAJOR, VER_MINOR, VER_BUILD, VER_TWEAK, GIT_DESCRIBE VER_MAJOR = major VER_MINOR = minor VER_BUILD = build - VER_REVISION = revision + VER_TWEAK = revision if GIT_DESCRIBE: branch = check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']) - VER_REVISION = int(check_output(['git', 'rev-list', '--count', 'HEAD'])) + VER_TWEAK = int(check_output(['git', 'rev-list', '--count', 'HEAD'])) def get_version(): - return (VER_MAJOR, VER_MINOR, VER_BUILD, VER_REVISION) + return (VER_MAJOR, VER_MINOR, VER_BUILD, VER_TWEAK) 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) + return "{}.{}.{}.{}".format(VER_MAJOR,VER_MINOR,VER_BUILD,VER_TWEAK) def build_static_lib(): return STATIC_LIB @@ -1783,7 +1783,7 @@ class DotNetDLLComponent(Component): { 'VER_MAJOR': str(major), 'VER_MINOR': str(minor), 'VER_BUILD': str(build), - 'VER_REVISION': str(revision), + 'VER_TWEAK': str(revision), } ) else: @@ -2222,7 +2222,7 @@ class MLComponent(Component): else: prefix_lib = '-L' + PREFIX + '/lib' substitutions = { 'LEXTRA': prefix_lib, - 'VERSION': "{}.{}.{}.{}".format(VER_MAJOR, VER_MINOR, VER_BUILD, VER_REVISION) } + 'VERSION': "{}.{}.{}.{}".format(VER_MAJOR, VER_MINOR, VER_BUILD, VER_TWEAK) } configure_file(os.path.join(self.src_dir, 'META.in'), os.path.join(BUILD_DIR, self.sub_dir, 'META'), @@ -3054,7 +3054,7 @@ def update_version(): major = VER_MAJOR minor = VER_MINOR build = VER_BUILD - revision = VER_REVISION + revision = VER_TWEAK if major is None or minor is None or build is None or revision is None: raise MKException("set_version(major, minor, build, revision) must be used before invoking update_version()") if not ONLY_MAKEFILES: From 36a2052cca96e3b681af179e4387dc0f818885de Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Mar 2019 15:46:48 -0700 Subject: [PATCH 051/156] update to TWEAK Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/CMakeLists.txt | 2 +- src/api/dotnet/Microsoft.Z3.csproj.in | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 3ff1a484a..8792f825e 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -4,7 +4,7 @@ find_package(Dotnet REQUIRED) set(VER_MAJOR "${Z3_VERSION_MAJOR}") set(VER_MINOR "${Z3_VERSION_MINOR}") set(VER_BUILD "${Z3_VERSION_PATCH}") -set(VER_REVISION "${Z3_VERSION_TWEAK}") +set(VER_TWEAK "${Z3_VERSION_TWEAK}") # Generate Native.cs set(Z3_DOTNET_NATIVE_FILE "${CMAKE_CURRENT_BINARY_DIR}/Native.cs") diff --git a/src/api/dotnet/Microsoft.Z3.csproj.in b/src/api/dotnet/Microsoft.Z3.csproj.in index fc6d6a978..fb8aa4da5 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj.in +++ b/src/api/dotnet/Microsoft.Z3.csproj.in @@ -21,11 +21,11 @@ Microsoft Corporation Microsoft Corporation - @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@ - @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@ + @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_TWEAK@ + @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_TWEAK@ - @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@ - @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@ + @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_TWEAK@ + @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_TWEAK@ ${DOTNET_PACKAGE_VERSION} smt constraint solver theorem prover From 957c3be02fb7307d2eb544064dcbb84186563d09 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Mar 2019 16:52:18 -0700 Subject: [PATCH 052/156] build errors/warnings Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Properties/AssemblyInfo.cs.in | 4 ++-- src/ast/rewriter/rewriter_def.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/dotnet/Properties/AssemblyInfo.cs.in b/src/api/dotnet/Properties/AssemblyInfo.cs.in index e5a85f16f..5c3f02cfd 100644 --- a/src/api/dotnet/Properties/AssemblyInfo.cs.in +++ b/src/api/dotnet/Properties/AssemblyInfo.cs.in @@ -34,5 +34,5 @@ using System.Security.Permissions; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("4.2.0.0")] -[assembly: AssemblyVersion("@VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@")] -[assembly: AssemblyFileVersion("@VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@")] +[assembly: AssemblyVersion("@VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_TWEAK@")] +[assembly: AssemblyFileVersion("@VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_TWEAK@")] diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index f628c2225..2f0d9c659 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -82,14 +82,14 @@ template template bool rewriter_tpl::process_const(app * t0) { app_ref t(t0, m()); - bool rounds = 0; + bool retried = false; retry: SASSERT(t->get_num_args() == 0); br_status st = m_cfg.reduce_app(t->get_decl(), 0, nullptr, m_r, m_pr); SASSERT(st != BR_DONE || m().get_sort(m_r) == m().get_sort(t)); switch (st) { case BR_FAILED: - if (rounds == 0) { + if (!retried) { result_stack().push_back(t); if (ProofGen) result_pr_stack().push_back(nullptr); // implicit reflexivity @@ -112,7 +112,7 @@ bool rewriter_tpl::process_const(app * t0) { default: if (is_app(m_r) && to_app(m_r)->get_num_args() == 0) { t = to_app(m_r); - rounds++; + retried = true; goto retry; } return false; From f534f79a21f86c03a68e4af237d27ee394521cb3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Mar 2019 18:16:09 -0700 Subject: [PATCH 053/156] include all sorts from declarations, and include sorts from datatypes #2185 Signed-off-by: Nikolaj Bjorner --- src/api/api_parsers.cpp | 62 ++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 32c133d2b..76100fcbc 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -34,28 +34,58 @@ extern "C" { // Support for SMTLIB2 Z3_ast_vector parse_smtlib2_stream(bool exec, Z3_context c, std::istream& is, - unsigned num_sorts, - Z3_symbol const sort_names[], - Z3_sort const sorts[], - unsigned num_decls, - Z3_symbol const decl_names[], - Z3_func_decl const decls[]) { + unsigned num_sorts, + Z3_symbol const _sort_names[], + Z3_sort const _sorts[], + unsigned num_decls, + Z3_symbol const decl_names[], + Z3_func_decl const decls[]) { Z3_TRY; - scoped_ptr ctx = alloc(cmd_context, false, &(mk_c(c)->m())); + ast_manager& m = mk_c(c)->m(); + scoped_ptr ctx = alloc(cmd_context, false, &(m)); ctx->set_ignore_check(true); - Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), m); + + vector sort_names; + ptr_vector sorts; + for (unsigned i = 0; i < num_sorts; ++i) { + sorts.push_back(to_sort(_sorts[i])); + sort_names.push_back(to_symbol(_sort_names[i])); + } + mk_c(c)->save_object(v); for (unsigned i = 0; i < num_decls; ++i) { - ctx->insert(to_symbol(decl_names[i]), to_func_decl(decls[i])); - } - for (unsigned i = 0; i < num_sorts; ++i) { - sort* srt = to_sort(sorts[i]); - symbol name(to_symbol(sort_names[i])); - if (!ctx->find_psort_decl(name)) { - psort* ps = ctx->pm().mk_psort_cnst(srt); - ctx->insert(ctx->pm().mk_psort_user_decl(0, name, ps)); + func_decl* d = to_func_decl(decls[i]); + ctx->insert(to_symbol(decl_names[i]), d); + sort_names.push_back(d->get_range()->get_name()); + sorts.push_back(d->get_range()); + for (sort* s : *d) { + sort_names.push_back(s->get_name()); + sorts.push_back(s); } } + datatype_util dt(m); + for (unsigned i = 0; i < num_sorts; ++i) { + sort* srt = sorts[i]; + symbol name = sort_names[i]; + if (ctx->find_psort_decl(name)) { + continue; + } + psort* ps = ctx->pm().mk_psort_cnst(srt); + ctx->insert(ctx->pm().mk_psort_user_decl(0, name, ps)); + if (!dt.is_datatype(srt)) { + continue; + } + + for (func_decl * c : *dt.get_datatype_constructors(srt)) { + ctx->insert(c->get_name(), c); + func_decl * r = dt.get_constructor_recognizer(c); + ctx->insert(r->get_name(), r); + for (func_decl * a : *dt.get_constructor_accessors(c)) { + ctx->insert(a->get_name(), a); + } + } + } std::stringstream errstrm; ctx->set_regular_stream(errstrm); try { From 834cf962a1849ffce77bf8fe9e6b74fbed26c3ae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Mar 2019 11:23:01 -0700 Subject: [PATCH 054/156] expose nth over API, change _getitem_ in python bindings to use nth instead of at, add 'at' operator for the purpose of the previous semantics Signed-off-by: Nikolaj Bjorner --- src/api/api_seq.cpp | 1 + src/api/c++/z3++.h | 27 +++++++++++++++++++++++++++ src/api/dotnet/ArrayExpr.cs | 6 ++++++ src/api/dotnet/Context.cs | 13 ++++++++++++- src/api/dotnet/SeqExpr.cs | 5 +++++ src/api/python/z3/z3.py | 5 +++++ src/api/z3_api.h | 10 ++++++++++ 7 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 08307c0bc..b06a63507 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -145,6 +145,7 @@ extern "C" { MK_TERNARY(Z3_mk_seq_extract, mk_c(c)->get_seq_fid(), OP_SEQ_EXTRACT, SKIP); MK_TERNARY(Z3_mk_seq_replace, mk_c(c)->get_seq_fid(), OP_SEQ_REPLACE, SKIP); MK_BINARY(Z3_mk_seq_at, mk_c(c)->get_seq_fid(), OP_SEQ_AT, SKIP); + MK_BINARY(Z3_mk_seq_nth, mk_c(c)->get_seq_fid(), OP_SEQ_AT, SKIP); MK_UNARY(Z3_mk_seq_length, mk_c(c)->get_seq_fid(), OP_SEQ_LENGTH, SKIP); MK_TERNARY(Z3_mk_seq_index, mk_c(c)->get_seq_fid(), OP_SEQ_INDEX, SKIP); MK_UNARY(Z3_mk_seq_to_re, mk_c(c)->get_seq_fid(), OP_SEQ_TO_RE, SKIP); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index fb0657aa2..c8aac77d3 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -648,10 +648,17 @@ namespace z3 { expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4, expr const & a5) const; }; + /** + \brief forward declarations + */ + expr select(expr const & a, expr const& i); + expr select(expr const & a, expr_vector const & i); + /** \brief A Z3 expression is used to represent formulas and terms. For Z3, a formula is any expression of sort Boolean. Every expression has a sort. */ + class expr : public ast { public: expr(context & c):ast(c) {} @@ -1136,6 +1143,12 @@ namespace z3 { check_error(); return expr(ctx(), r); } + expr nth(expr const& index) const { + check_context(*this, index); + Z3_ast r = Z3_mk_seq_nth(ctx(), *this, index); + check_error(); + return expr(ctx(), r); + } expr length() const { Z3_ast r = Z3_mk_seq_length(ctx(), *this); check_error(); @@ -1167,6 +1180,20 @@ namespace z3 { return expr(ctx(), r); } + /** + * index operator defined on arrays and sequences. + */ + expr operator[](expr const& index) const { + assert(is_array() || is_seq()); + if (is_array()) { + return select(*this, index); + } + return nth(index); + } + + expr operator[](expr_vector const& index) const { + return select(*this, index); + } /** \brief Return a simplified version of this expression. diff --git a/src/api/dotnet/ArrayExpr.cs b/src/api/dotnet/ArrayExpr.cs index c53763886..d0e45561d 100644 --- a/src/api/dotnet/ArrayExpr.cs +++ b/src/api/dotnet/ArrayExpr.cs @@ -38,5 +38,11 @@ namespace Microsoft.Z3 Debug.Assert(ctx != null); } #endregion + + public Expr this[Expr index] + { + get { return Context.MkSelect(this, index); } + } + } } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index cdaae332b..150283ea5 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2454,7 +2454,7 @@ namespace Microsoft.Z3 /// /// Retrieve sequence of length one at index. /// - public SeqExpr MkAt(SeqExpr s, IntExpr index) + public SeqExpr MkAt(SeqExpr s, Expr index) { Debug.Assert(s != null); Debug.Assert(index != null); @@ -2462,6 +2462,17 @@ namespace Microsoft.Z3 return new SeqExpr(this, Native.Z3_mk_seq_at(nCtx, s.NativeObject, index.NativeObject)); } + /// + /// Retrieve element at index. + /// + public SeqExpr MkNth(SeqExpr s, Expr index) + { + Debug.Assert(s != null); + Debug.Assert(index != null); + CheckContextMatch(s, index); + return new SeqExpr(this, Native.Z3_mk_seq_nth(nCtx, s.NativeObject, index.NativeObject)); + } + /// /// Extract subsequence. /// diff --git a/src/api/dotnet/SeqExpr.cs b/src/api/dotnet/SeqExpr.cs index bfab1fa36..1544d630f 100644 --- a/src/api/dotnet/SeqExpr.cs +++ b/src/api/dotnet/SeqExpr.cs @@ -38,5 +38,10 @@ namespace Microsoft.Z3 Debug.Assert(ctx != null); } #endregion + + public Expr this[Expr index] + { + get { return Context.MkNth(this, index); } + } } } diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index f31df5a4f..880bf009f 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -9941,6 +9941,11 @@ class SeqRef(ExprRef): return Concat(other, self) def __getitem__(self, i): + if _is_int(i): + i = IntVal(i, self.ctx) + return SeqRef(Z3_mk_seq_nth(self.ctx_ref(), self.as_ast(), i.as_ast()), self.ctx) + + def at(self, i): if _is_int(i): i = IntVal(i, self.ctx) return SeqRef(Z3_mk_seq_at(self.ctx_ref(), self.as_ast(), i.as_ast()), self.ctx) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index ce59210f1..2ca2c14d9 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1168,6 +1168,7 @@ typedef enum { Z3_OP_SEQ_EXTRACT, Z3_OP_SEQ_REPLACE, Z3_OP_SEQ_AT, + Z3_OP_SEQ_NTH, Z3_OP_SEQ_LENGTH, Z3_OP_SEQ_INDEX, Z3_OP_SEQ_TO_RE, @@ -3420,11 +3421,20 @@ extern "C" { /** \brief Retrieve from \c s the unit sequence positioned at position \c index. + The sequence is empty if the index is out of bounds. def_API('Z3_mk_seq_at' ,AST ,(_in(CONTEXT), _in(AST), _in(AST))) */ Z3_ast Z3_API Z3_mk_seq_at(Z3_context c, Z3_ast s, Z3_ast index); + /** + \brief Retrieve from \c s the element positioned at position \c index. + The function is under-specified if the index is out of bounds. + + def_API('Z3_mk_seq_nth' ,AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_nth(Z3_context c, Z3_ast s, Z3_ast index); + /** \brief Return the length of the sequence \c s. From 9bc49142689e23f0881465920ce1d4e5e1b6dc2d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Mar 2019 11:32:28 -0700 Subject: [PATCH 055/156] add nth remapping Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index eeb85687d..4893cbe10 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1162,6 +1162,7 @@ extern "C" { case OP_SEQ_EXTRACT: return Z3_OP_SEQ_EXTRACT; case OP_SEQ_REPLACE: return Z3_OP_SEQ_REPLACE; case OP_SEQ_AT: return Z3_OP_SEQ_AT; + case OP_SEQ_NTH: return Z3_OP_SEQ_NTH; case OP_SEQ_LENGTH: return Z3_OP_SEQ_LENGTH; case OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX; case OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE; From d953bdd2e4f6e51a971a2ae0eb17b1629fd73d7c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Mar 2019 11:35:03 -0700 Subject: [PATCH 056/156] add multi-argument select for C# Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/ArrayExpr.cs | 5 +++++ src/api/dotnet/Context.cs | 1 + 2 files changed, 6 insertions(+) diff --git a/src/api/dotnet/ArrayExpr.cs b/src/api/dotnet/ArrayExpr.cs index d0e45561d..5fc27d253 100644 --- a/src/api/dotnet/ArrayExpr.cs +++ b/src/api/dotnet/ArrayExpr.cs @@ -44,5 +44,10 @@ namespace Microsoft.Z3 get { return Context.MkSelect(this, index); } } + public Expr this[IEnumerable index] + { + get { return Context.MkSelect(this, index.ToArray()); } + } + } } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 150283ea5..c5222d340 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2079,6 +2079,7 @@ namespace Microsoft.Z3 return Expr.Create(this, Native.Z3_mk_select_n(nCtx, a.NativeObject, AST.ArrayLength(args), AST.ArrayToNative(args))); } + /// /// Array update. /// From 93a4afe5d22885fb5f0c8149ba588048663571ea Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Mar 2019 11:36:29 -0700 Subject: [PATCH 057/156] add multi-argument select for C# Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/ArrayExpr.cs | 2 ++ src/api/dotnet/SeqExpr.cs | 1 + 2 files changed, 3 insertions(+) diff --git a/src/api/dotnet/ArrayExpr.cs b/src/api/dotnet/ArrayExpr.cs index 5fc27d253..513696f12 100644 --- a/src/api/dotnet/ArrayExpr.cs +++ b/src/api/dotnet/ArrayExpr.cs @@ -39,11 +39,13 @@ namespace Microsoft.Z3 } #endregion + /// Single argument select public Expr this[Expr index] { get { return Context.MkSelect(this, index); } } + /// Multi argument select public Expr this[IEnumerable index] { get { return Context.MkSelect(this, index.ToArray()); } diff --git a/src/api/dotnet/SeqExpr.cs b/src/api/dotnet/SeqExpr.cs index 1544d630f..227556391 100644 --- a/src/api/dotnet/SeqExpr.cs +++ b/src/api/dotnet/SeqExpr.cs @@ -39,6 +39,7 @@ namespace Microsoft.Z3 } #endregion + /// Access the nth element of a sequence public Expr this[Expr index] { get { return Context.MkNth(this, index); } From 057151c7a80dac44d610f5286799ad7b727b5d2c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Mar 2019 07:56:25 -0700 Subject: [PATCH 058/156] fix #2188 Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/goal2sat.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index b9adba7cf..19e7d6ba2 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -1002,7 +1002,6 @@ void sat2goal::mc::operator()(model_ref & md) { // create a SAT model using md sat::model sat_md; expr_ref val(m); - VERIFY(!m_var2expr.empty()); for (expr * atom : m_var2expr) { if (!atom) { sat_md.push_back(l_undef); From 885d640301b9687d30c7e569cd8dd9d64eb9762b Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 19 Mar 2019 14:58:23 -0700 Subject: [PATCH 059/156] make explicit rational(double)constructor Signed-off-by: Lev Nachmanson --- src/util/lp/lp_core_solver_base.h | 2 +- src/util/lp/lp_solver_def.h | 2 +- src/util/lp/scaler_def.h | 16 ++++++++-------- src/util/rational.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index c1b8aa987..46f683c91 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -214,7 +214,7 @@ public: if (m_A.m_columns[bj].size() > 1) return true; for (const auto & c : m_A.m_columns[bj]) { - if (m_A.get_val(c) != one_of_type()) + if (m_A.get_val(c) != one_of_type()) return true; else break; diff --git a/src/util/lp/lp_solver_def.h b/src/util/lp/lp_solver_def.h index 21a86efba..d18333161 100644 --- a/src/util/lp/lp_solver_def.h +++ b/src/util/lp/lp_solver_def.h @@ -561,7 +561,7 @@ template void lp_solver::set_scaled_cost(unsigned column_info * ci = this->m_map_from_var_index_to_column_info[this->m_core_solver_columns_to_external_columns[j]]; T cost = ci->get_cost(); if (ci->is_flipped()){ - cost *= -1; + cost *= T(-1); } lp_assert(ci->is_fixed() == false); this->m_costs[j] = cost * this->m_column_scale[j]; diff --git a/src/util/lp/scaler_def.h b/src/util/lp/scaler_def.h index 4c9784a43..489f42c56 100644 --- a/src/util/lp/scaler_def.h +++ b/src/util/lp/scaler_def.h @@ -221,15 +221,15 @@ template void scaler::scale_row(unsigned i) { } if (row_max < m_scaling_minimum) { do { - alpha *= 2; - row_max *= 2; + alpha *= T(2); + row_max *= T(2); } while (row_max < m_scaling_minimum); m_A.multiply_row(i, alpha); m_b[i] *= alpha; } else if (row_max > m_scaling_maximum) { do { - alpha /= 2; - row_max /= 2; + alpha /= T(2); + row_max /= T(2); } while (row_max > m_scaling_maximum); m_A.multiply_row(i, alpha); m_b[i] *= alpha; @@ -245,13 +245,13 @@ template void scaler::scale_column(unsigned i) } if (column_max < m_scaling_minimum) { do { - alpha *= 2; - column_max *= 2; + alpha *= T(2); + column_max *= T(2); } while (column_max < m_scaling_minimum); } else if (column_max > m_scaling_maximum) { do { - alpha /= 2; - column_max /= 2; + alpha /= T(2); + column_max /= T(2); } while (column_max > m_scaling_maximum); } else { return; diff --git a/src/util/rational.h b/src/util/rational.h index bf68c0bf6..f343ee019 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -53,7 +53,7 @@ public: rational(mpz const & z) { m().set(m_val, z); } - rational(double z) { UNREACHABLE(); } + explicit rational(double z) { UNREACHABLE(); } explicit rational(char const * v) { m().set(m_val, v); } From eae4fd6afd29bddcfea4e7fa05a7a87788528883 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 19 Mar 2019 15:56:09 -0700 Subject: [PATCH 060/156] fix the build lp.cpp in test Signed-off-by: Lev Nachmanson --- src/test/lp/lp.cpp | 87 +++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index f43aff668..0c243c9c8 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -2673,25 +2673,25 @@ void test_term() { var_index one = solver.add_var(_one, false); vector> term_one; - term_one.push_back(std::make_pair((int)1, one)); + term_one.push_back(std::make_pair(mpq(1), one)); solver.add_constraint(term_one, lconstraint_kind::EQ, mpq(0)); vector> term_ls; - term_ls.push_back(std::pair((int)1, x)); - term_ls.push_back(std::pair((int)1, y)); - term_ls.push_back(std::make_pair((int)3, one)); + term_ls.push_back(std::pair(mpq(1), x)); + term_ls.push_back(std::pair(mpq(1), y)); + term_ls.push_back(std::make_pair(mpq(3), one)); var_index z = solver.add_term(term_ls); vector> ls; - ls.push_back(std::pair((int)1, x)); - ls.push_back(std::pair((int)1, y)); - ls.push_back(std::pair((int)1, z)); + ls.push_back(std::pair(mpq(1), x)); + ls.push_back(std::pair(mpq(1), y)); + ls.push_back(std::pair(mpq(1), z)); solver.add_constraint(ls, lconstraint_kind::EQ, mpq(0)); ls.clear(); - ls.push_back(std::pair((int)1, x)); + ls.push_back(std::pair(mpq(1), x)); solver.add_constraint(ls, lconstraint_kind::LT, mpq(0)); - ls.push_back(std::pair((int)2, y)); + ls.push_back(std::pair(mpq(2), y)); solver.add_constraint(ls, lconstraint_kind::GT, mpq(0)); auto status = solver.solve(); std::cout << lp_status_to_string(status) << std::endl; @@ -2711,15 +2711,15 @@ void test_evidence_for_total_inf_simple(argument_parser & args_parser) { lar_solver solver; var_index x = solver.add_var(0, false); var_index y = solver.add_var(1, false); - solver.add_var_bound(x, LE, -mpq(1)); + solver.add_var_bound(x, LE, mpq(-1)); solver.add_var_bound(y, GE, mpq(0)); vector> ls; - ls.push_back(std::pair((int)1, x)); - ls.push_back(std::pair((int)1, y)); + ls.push_back(std::pair(mpq(1), x)); + ls.push_back(std::pair(mpq(1), y)); solver.add_constraint(ls, GE, mpq(1)); ls.pop_back(); - ls.push_back(std::pair(-(int)1, y)); + ls.push_back(std::pair(- mpq(1), y)); solver.add_constraint(ls, lconstraint_kind::GE, mpq(0)); auto status = solver.solve(); std::cout << lp_status_to_string(status) << std::endl; @@ -2748,19 +2748,20 @@ void test_bound_propagation_one_small_sample1() { unsigned b = ls.add_var(1, false); unsigned c = ls.add_var(2, false); vector> coeffs; - coeffs.push_back(std::pair(1, a)); - coeffs.push_back(std::pair(-1, c)); + coeffs.push_back(std::pair(mpq(1), a)); + coeffs.push_back(std::pair(mpq(-1), c)); + ls.add_term(coeffs); coeffs.pop_back(); - coeffs.push_back(std::pair(-1, b)); + coeffs.push_back(std::pair(mpq(-1), b)); ls.add_term(coeffs); coeffs.clear(); - coeffs.push_back(std::pair(1, a)); - coeffs.push_back(std::pair(-1, b)); + coeffs.push_back(std::pair(mpq(1), a)); + coeffs.push_back(std::pair(mpq(-1), b)); ls.add_constraint(coeffs, LE, zero_of_type()); coeffs.clear(); - coeffs.push_back(std::pair(1, b)); - coeffs.push_back(std::pair(-1, c)); + coeffs.push_back(std::pair(mpq(1), b)); + coeffs.push_back(std::pair(mpq(-1), c)); ls.add_constraint(coeffs, LE, zero_of_type()); vector ev; ls.add_var_bound(a, LE, mpq(1)); @@ -2812,8 +2813,8 @@ void test_bound_propagation_one_row() { unsigned x0 = ls.add_var(0, false); unsigned x1 = ls.add_var(1, false); vector> c; - c.push_back(std::pair(1, x0)); - c.push_back(std::pair(-1, x1)); + c.push_back(std::pair(mpq(1), x0)); + c.push_back(std::pair(mpq(-1), x1)); ls.add_constraint(c, EQ, one_of_type()); vector ev; ls.add_var_bound(x0, LE, mpq(1)); @@ -2826,8 +2827,8 @@ void test_bound_propagation_one_row_with_bounded_vars() { unsigned x0 = ls.add_var(0, false); unsigned x1 = ls.add_var(1, false); vector> c; - c.push_back(std::pair(1, x0)); - c.push_back(std::pair(-1, x1)); + c.push_back(std::pair(mpq(1), x0)); + c.push_back(std::pair(mpq(-1), x1)); ls.add_constraint(c, EQ, one_of_type()); vector ev; ls.add_var_bound(x0, GE, mpq(-3)); @@ -2842,8 +2843,8 @@ void test_bound_propagation_one_row_mixed() { unsigned x0 = ls.add_var(0, false); unsigned x1 = ls.add_var(1, false); vector> c; - c.push_back(std::pair(1, x0)); - c.push_back(std::pair(-1, x1)); + c.push_back(std::pair(mpq(1), x0)); + c.push_back(std::pair(mpq(-1), x1)); ls.add_constraint(c, EQ, one_of_type()); vector ev; ls.add_var_bound(x1, LE, mpq(1)); @@ -2858,14 +2859,14 @@ void test_bound_propagation_two_rows() { unsigned y = ls.add_var(1, false); unsigned z = ls.add_var(2, false); vector> c; - c.push_back(std::pair(1, x)); - c.push_back(std::pair(2, y)); - c.push_back(std::pair(3, z)); + c.push_back(std::pair(mpq(1), x)); + c.push_back(std::pair(mpq(2), y)); + c.push_back(std::pair(mpq(3), z)); ls.add_constraint(c, GE, one_of_type()); c.clear(); - c.push_back(std::pair(3, x)); - c.push_back(std::pair(2, y)); - c.push_back(std::pair(1, z)); + c.push_back(std::pair(mpq(3), x)); + c.push_back(std::pair(mpq(2), y)); + c.push_back(std::pair(mpq(y), z)); ls.add_constraint(c, GE, one_of_type()); ls.add_var_bound(x, LE, mpq(2)); vector ev; @@ -2882,9 +2883,9 @@ void test_total_case_u() { unsigned y = ls.add_var(1, false); unsigned z = ls.add_var(2, false); vector> c; - c.push_back(std::pair(1, x)); - c.push_back(std::pair(2, y)); - c.push_back(std::pair(3, z)); + c.push_back(std::pair(mpq(1), x)); + c.push_back(std::pair(mpq(2), y)); + c.push_back(std::pair(mpq(3), z)); ls.add_constraint(c, LE, one_of_type()); ls.add_var_bound(x, GE, zero_of_type()); ls.add_var_bound(y, GE, zero_of_type()); @@ -2908,9 +2909,9 @@ void test_total_case_l(){ unsigned y = ls.add_var(1, false); unsigned z = ls.add_var(2, false); vector> c; - c.push_back(std::pair(1, x)); - c.push_back(std::pair(2, y)); - c.push_back(std::pair(3, z)); + c.push_back(std::pair(mpq(1), x)); + c.push_back(std::pair(mpq(2), y)); + c.push_back(std::pair(mpq(3), z)); ls.add_constraint(c, GE, one_of_type()); ls.add_var_bound(x, LE, one_of_type()); ls.add_var_bound(y, LE, one_of_type()); @@ -3490,16 +3491,16 @@ void test_maximize_term() { var_index x = solver.add_var(_x, false); var_index y = solver.add_var(_y, true); vector> term_ls; - term_ls.push_back(std::pair((int)1, x)); - term_ls.push_back(std::pair((int)-1, y)); + term_ls.push_back(std::pair(mpq(1), x)); + term_ls.push_back(std::pair(mpq(-1), y)); unsigned term_x_min_y = solver.add_term(term_ls); term_ls.clear(); - term_ls.push_back(std::pair((int)2, x)); - term_ls.push_back(std::pair((int)2, y)); + term_ls.push_back(std::pair(mpq(2), x)); + term_ls.push_back(std::pair(mpq(2), y)); unsigned term_2x_pl_2y = solver.add_term(term_ls); solver.add_var_bound(term_x_min_y, LE, zero_of_type()); - solver.add_var_bound(term_2x_pl_2y, LE, mpq((int)5)); + solver.add_var_bound(term_2x_pl_2y, LE, mpq(5)); solver.find_feasible_solution(); lp_assert(solver.get_status() == lp_status::OPTIMAL); solver.print_constraints(std::cout); From 6e5d0b759401d5f20da9d73ed8e59536bbcff765 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 22 Mar 2019 09:43:34 -0700 Subject: [PATCH 061/156] Remove unnecessary null pointer checks --- src/util/lp/lar_core_solver.h | 5 +++-- src/util/lp/lp_core_solver_base.h | 5 ++--- src/util/lp/lp_dual_simplex.h | 4 +--- src/util/lp/lp_primal_simplex_def.h | 4 +--- src/util/lp/lp_solver_def.h | 4 +--- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/util/lp/lar_core_solver.h b/src/util/lp/lar_core_solver.h index 52290c69a..9dec5aa70 100644 --- a/src/util/lp/lar_core_solver.h +++ b/src/util/lp/lar_core_solver.h @@ -421,9 +421,10 @@ public: unsigned leaving = trace_of_basis_change[i+1]; cs.change_basis_unconditionally(entering, leaving); } - if (cs.m_factorization != nullptr) + if (cs.m_factorization != nullptr) { delete cs.m_factorization; - cs.m_factorization = nullptr; + cs.m_factorization = nullptr; + } } else { indexed_vector w(cs.m_A.row_count()); // the queues of delayed indices diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index 46f683c91..4c17df29c 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -127,9 +127,8 @@ public: void init(); virtual ~lp_core_solver_base() { - if (m_factorization != nullptr) - delete m_factorization; - } + delete m_factorization; + } vector & non_basis() { return m_nbasis; diff --git a/src/util/lp/lp_dual_simplex.h b/src/util/lp/lp_dual_simplex.h index 59b1bc24c..c33b55031 100644 --- a/src/util/lp/lp_dual_simplex.h +++ b/src/util/lp/lp_dual_simplex.h @@ -34,9 +34,7 @@ class lp_dual_simplex: public lp_solver { vector m_can_enter_basis; public: ~lp_dual_simplex() override { - if (m_core_solver != nullptr) { - delete m_core_solver; - } + delete m_core_solver; } lp_dual_simplex() : m_core_solver(nullptr) {} diff --git a/src/util/lp/lp_primal_simplex_def.h b/src/util/lp/lp_primal_simplex_def.h index 722e4bd79..ad644838f 100644 --- a/src/util/lp/lp_primal_simplex_def.h +++ b/src/util/lp/lp_primal_simplex_def.h @@ -263,9 +263,7 @@ template void lp_primal_simplex::solve_with_total template lp_primal_simplex::~lp_primal_simplex() { - if (m_core_solver != nullptr) { - delete m_core_solver; - } + delete m_core_solver; } template bool lp_primal_simplex::bounds_hold(std::unordered_map const & solution) { diff --git a/src/util/lp/lp_solver_def.h b/src/util/lp/lp_solver_def.h index d18333161..04603f4a7 100644 --- a/src/util/lp/lp_solver_def.h +++ b/src/util/lp/lp_solver_def.h @@ -86,9 +86,7 @@ template int lp_solver::get_column_index_by_name( template lp_solver::~lp_solver(){ - if (m_A != nullptr) { - delete m_A; - } + delete m_A; for (auto t : m_map_from_var_index_to_column_info) { delete t.second; } From 61ac006cbe2730efed5942916952980c207c9857 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 22 Mar 2019 10:32:33 -0700 Subject: [PATCH 062/156] Remove unnecessary null pointer checks --- src/util/lp/mps_reader.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/util/lp/mps_reader.h b/src/util/lp/mps_reader.h index 2ef07af6e..bc2a8432e 100644 --- a/src/util/lp/mps_reader.h +++ b/src/util/lp/mps_reader.h @@ -754,10 +754,7 @@ public: } for (auto s : m_columns) { auto col = s.second; - auto b = col->m_bound; - if (b != nullptr) { - delete b; - } + delete col->m_bound; delete col; } } From e59d60fbbe44876f878233d6487ed4f28d46af68 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 22 Mar 2019 10:47:11 -0700 Subject: [PATCH 063/156] Remove unnecessary null pointer checks --- src/util/lp/lar_core_solver.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/util/lp/lar_core_solver.h b/src/util/lp/lar_core_solver.h index 9dec5aa70..98d0912bc 100644 --- a/src/util/lp/lar_core_solver.h +++ b/src/util/lp/lar_core_solver.h @@ -235,20 +235,17 @@ public: m_r_upper_bounds.pop(k); m_column_types.pop(k); - if (m_r_solver.m_factorization != nullptr) { - delete m_r_solver.m_factorization; - m_r_solver.m_factorization = nullptr; - } + delete m_r_solver.m_factorization; + m_r_solver.m_factorization = nullptr; m_r_x.resize(m_r_A.column_count()); m_r_solver.m_costs.resize(m_r_A.column_count()); m_r_solver.m_d.resize(m_r_A.column_count()); if(!settings().use_tableau()) pop_markowitz_counts(k); m_d_A.pop(k); - if (m_d_solver.m_factorization != nullptr) { - delete m_d_solver.m_factorization; - m_d_solver.m_factorization = nullptr; - } + // doubles + delete m_d_solver.m_factorization; + m_d_solver.m_factorization = nullptr; m_d_x.resize(m_d_A.column_count()); pop_basis(k); From 62ec02e50fff5bdee46808eaedb0e49b31bfbe4d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Mar 2019 23:34:56 -0700 Subject: [PATCH 064/156] extend rewriting features for arrays, #2151 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/array_rewriter.cpp | 47 +++++++++++++++++++++-------- src/ast/rewriter/th_rewriter.cpp | 2 +- src/model/model_evaluator.cpp | 11 +++++-- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 6ad9c3654..61860ec4b 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -36,36 +36,48 @@ void array_rewriter::get_param_descrs(param_descrs & r) { br_status array_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { SASSERT(f->get_family_id() == get_fid()); - TRACE("array_rewriter", tout << mk_pp(f, m()) << "\n"; - for (unsigned i = 0; i < num_args; ++i) { - tout << mk_pp(args[i], m()) << "\n"; - }); + br_status st; switch (f->get_decl_kind()) { case OP_SELECT: - return mk_select_core(num_args, args, result); + st = mk_select_core(num_args, args, result); + break; case OP_STORE: - return mk_store_core(num_args, args, result); + st = mk_store_core(num_args, args, result); + break; case OP_ARRAY_MAP: SASSERT(f->get_num_parameters() == 1); SASSERT(f->get_parameter(0).is_ast()); SASSERT(is_func_decl(f->get_parameter(0).get_ast())); - return mk_map_core(to_func_decl(f->get_parameter(0).get_ast()), num_args, args, result); + st = mk_map_core(to_func_decl(f->get_parameter(0).get_ast()), num_args, args, result); + break; case OP_SET_UNION: - return mk_set_union(num_args, args, result); + st = mk_set_union(num_args, args, result); + break; case OP_SET_INTERSECT: - return mk_set_intersect(num_args, args, result); + st = mk_set_intersect(num_args, args, result); + break; case OP_SET_SUBSET: SASSERT(num_args == 2); - return mk_set_subset(args[0], args[1], result); + st = mk_set_subset(args[0], args[1], result); + break; case OP_SET_COMPLEMENT: SASSERT(num_args == 1); - return mk_set_complement(args[0], result); + st = mk_set_complement(args[0], result); + break; case OP_SET_DIFFERENCE: SASSERT(num_args == 2); - return mk_set_difference(args[0], args[1], result); + st = mk_set_difference(args[0], args[1], result); + break; default: return BR_FAILED; } + TRACE("array_rewriter", tout << mk_pp(f, m()) << "\n"; + for (unsigned i = 0; i < num_args; ++i) { + tout << mk_pp(args[i], m()) << "\n"; + } + tout << "\n --> " << result << "\n"; + ); + return st; } // l_true -- all equal @@ -456,6 +468,17 @@ bool array_rewriter::has_index_set(expr* e, expr_ref& e0, vectorget_expr(), v), m()); + result = m().update_quantifier(lam, quantifier_kind::forall_k, e); + return BR_REWRITE2; + } if (!m_expand_store_eq) { return BR_FAILED; } diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 6a64eaa82..1b586b4b6 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -32,6 +32,7 @@ Notes: #include "ast/rewriter/var_subst.h" #include "ast/expr_substitution.h" #include "ast/ast_smt2_pp.h" +#include "ast/ast_pp.h" #include "ast/ast_util.h" #include "ast/well_sorted.h" @@ -184,7 +185,6 @@ struct th_rewriter_cfg : public default_rewriter_cfg { st = m_ar_rw.mk_eq_core(args[0], args[1], result); else if (s_fid == m_seq_rw.get_fid()) st = m_seq_rw.mk_eq_core(args[0], args[1], result); - if (st != BR_FAILED) return st; } diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 35cbfe9c7..229ed875e 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -38,6 +38,7 @@ Revision History: #include "ast/rewriter/var_subst.h" namespace { + struct evaluator_cfg : public default_rewriter_cfg { ast_manager & m; model_core & m_model; @@ -165,7 +166,8 @@ struct evaluator_cfg : public default_rewriter_cfg { if (k == OP_EQ) { // theory dispatch for = SASSERT(num == 2); - family_id s_fid = m.get_sort(args[0])->get_family_id(); + sort* s = m.get_sort(args[0]); + family_id s_fid = s->get_family_id(); if (s_fid == m_a_rw.get_fid()) st = m_a_rw.mk_eq_core(args[0], args[1], result); else if (s_fid == m_bv_rw.get_fid()) @@ -178,6 +180,9 @@ struct evaluator_cfg : public default_rewriter_cfg { st = m_seq_rw.mk_eq_core(args[0], args[1], result); else if (s_fid == m_ar_rw.get_fid()) st = mk_array_eq(args[0], args[1], result); + TRACE("model_evaluator", + tout << st << " " << mk_pp(s, m) << " " << s_fid << " " << m_ar_rw.get_fid() << " " + << mk_pp(args[0], m) << " " << mk_pp(args[1], m) << " " << result << "\n";); if (st != BR_FAILED) return st; } @@ -348,7 +353,7 @@ struct evaluator_cfg : public default_rewriter_cfg { return BR_DONE; } if (!m_array_equalities) { - return BR_FAILED; + return m_ar_rw.mk_eq_core(a, b, result); } vector stores1, stores2; @@ -389,7 +394,7 @@ struct evaluator_cfg : public default_rewriter_cfg { ); return BR_REWRITE_FULL; } - return BR_FAILED; + return m_ar_rw.mk_eq_core(a, b, result); } struct args_eq { From 3c8fd83c9768a0943544505905f045e87dc4e1e1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Mar 2019 12:29:34 -0700 Subject: [PATCH 065/156] implementing last-index-of #2089 Signed-off-by: Nikolaj Bjorner --- src/api/api_seq.cpp | 1 + src/api/c++/z3++.h | 6 ++ src/api/python/z3/z3.py | 9 +++ src/api/z3_api.h | 10 ++- src/ast/rewriter/seq_rewriter.cpp | 103 +++++++++++++++++++++--------- src/ast/rewriter/seq_rewriter.h | 1 + src/ast/seq_decl_plugin.cpp | 24 ++++++- src/ast/seq_decl_plugin.h | 5 ++ src/smt/theory_seq.cpp | 45 +++++++++++++ src/smt/theory_seq.h | 1 + 10 files changed, 174 insertions(+), 31 deletions(-) diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index b06a63507..b621dcebe 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -148,6 +148,7 @@ extern "C" { MK_BINARY(Z3_mk_seq_nth, mk_c(c)->get_seq_fid(), OP_SEQ_AT, SKIP); MK_UNARY(Z3_mk_seq_length, mk_c(c)->get_seq_fid(), OP_SEQ_LENGTH, SKIP); MK_TERNARY(Z3_mk_seq_index, mk_c(c)->get_seq_fid(), OP_SEQ_INDEX, SKIP); + MK_BINARY(Z3_mk_seq_last_index, mk_c(c)->get_seq_fid(), OP_SEQ_LAST_INDEX, SKIP); MK_UNARY(Z3_mk_seq_to_re, mk_c(c)->get_seq_fid(), OP_SEQ_TO_RE, SKIP); MK_BINARY(Z3_mk_seq_in_re, mk_c(c)->get_seq_fid(), OP_SEQ_IN_RE, SKIP); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index c8aac77d3..4992015de 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -3276,6 +3276,12 @@ namespace z3 { s.check_error(); return expr(s.ctx(), r); } + inline expr last_indexof(expr const& s, expr const& substr) { + check_context(s, substr); + Z3_ast r = Z3_mk_seq_last_index(s.ctx(), s, substr); + s.check_error(); + return expr(s.ctx(), r); + } inline expr to_re(expr const& s) { MK_EXPR1(Z3_mk_seq_to_re, s); } diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 880bf009f..69c90c3f6 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10154,6 +10154,15 @@ def IndexOf(s, substr, offset): offset = IntVal(offset, ctx) return ArithRef(Z3_mk_seq_index(s.ctx_ref(), s.as_ast(), substr.as_ast(), offset.as_ast()), s.ctx) +def LastIndexOf(s, substr): + """Retrieve the last index of substring within a string""" + ctx = None + ctx = _get_ctx2(s, substr, ctx) + s = _coerce_seq(s, ctx) + substr = _coerce_seq(substr, ctx) + return ArithRef(Z3_mk_seq_last_index(s.ctx_ref(), s.as_ast(), substr.as_ast()), s.ctx) + + def Length(s): """Obtain the length of a sequence 's' >>> l = Length(StringVal("abc")) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 2ca2c14d9..7f1a1c70c 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1171,6 +1171,7 @@ typedef enum { Z3_OP_SEQ_NTH, Z3_OP_SEQ_LENGTH, Z3_OP_SEQ_INDEX, + Z3_OP_SEQ_LAST_INDEX, Z3_OP_SEQ_TO_RE, Z3_OP_SEQ_IN_RE, @@ -3446,12 +3447,19 @@ extern "C" { /** \brief Return index of first occurrence of \c substr in \c s starting from offset \c offset. If \c s does not contain \c substr, then the value is -1, if \c offset is the length of \c s, then the value is -1 as well. - The function is under-specified if \c offset is negative or larger than the length of \c s. + The value is -1 if \c offset is negative or larger than the length of \c s. def_API('Z3_mk_seq_index' ,AST ,(_in(CONTEXT), _in(AST), _in(AST), _in(AST))) */ Z3_ast Z3_API Z3_mk_seq_index(Z3_context c, Z3_ast s, Z3_ast substr, Z3_ast offset); + /** + \brief Return the last occurrence of \c substr in \c s. + If \c s does not contain \c substr, then the value is -1, + def_API('Z3_mk_seq_last_index', AST, (_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_last_index(Z3_context c, Z3_ast, Z3_ast substr); + /** \brief Convert string to integer. diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index cb915d86b..5aef06531 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -391,44 +391,57 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con case OP_SEQ_UNIT: SASSERT(num_args == 1); - return mk_seq_unit(args[0], result); + st = mk_seq_unit(args[0], result); + break; case OP_SEQ_EMPTY: return BR_FAILED; case OP_RE_PLUS: SASSERT(num_args == 1); - return mk_re_plus(args[0], result); + st = mk_re_plus(args[0], result); + break; case OP_RE_STAR: SASSERT(num_args == 1); st = mk_re_star(args[0], result); break; case OP_RE_OPTION: SASSERT(num_args == 1); - return mk_re_opt(args[0], result); + st = mk_re_opt(args[0], result); + break; case OP_RE_CONCAT: if (num_args == 1) { result = args[0]; - return BR_DONE; + st = BR_DONE; + } + else { + SASSERT(num_args == 2); + st = mk_re_concat(args[0], args[1], result); } - SASSERT(num_args == 2); - st = mk_re_concat(args[0], args[1], result); break; case OP_RE_UNION: if (num_args == 1) { - result = args[0]; return BR_DONE; + result = args[0]; + st = BR_DONE; } - SASSERT(num_args == 2); - return mk_re_union(args[0], args[1], result); + else { + SASSERT(num_args == 2); + st = mk_re_union(args[0], args[1], result); + } + break; case OP_RE_RANGE: SASSERT(num_args == 2); - return mk_re_range(args[0], args[1], result); + st = mk_re_range(args[0], args[1], result); + break; case OP_RE_INTERSECT: SASSERT(num_args == 2); - return mk_re_inter(args[0], args[1], result); + st = mk_re_inter(args[0], args[1], result); + break; case OP_RE_COMPLEMENT: SASSERT(num_args == 1); - return mk_re_complement(args[0], result); + st = mk_re_complement(args[0], result); + break; case OP_RE_LOOP: - return mk_re_loop(num_args, args, result); + st = mk_re_loop(num_args, args, result); + break; case OP_RE_EMPTY_SET: return BR_FAILED; case OP_RE_FULL_SEQ_SET: @@ -442,23 +455,29 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con case OP_SEQ_CONCAT: if (num_args == 1) { result = args[0]; - return BR_DONE; + st = BR_DONE; } - SASSERT(num_args == 2); - return mk_seq_concat(args[0], args[1], result); + else { + SASSERT(num_args == 2); + st = mk_seq_concat(args[0], args[1], result); + } + break; case OP_SEQ_LENGTH: SASSERT(num_args == 1); - return mk_seq_length(args[0], result); + st = mk_seq_length(args[0], result); + break; case OP_SEQ_EXTRACT: SASSERT(num_args == 3); st = mk_seq_extract(args[0], args[1], args[2], result); break; case OP_SEQ_CONTAINS: SASSERT(num_args == 2); - return mk_seq_contains(args[0], args[1], result); + st = mk_seq_contains(args[0], args[1], result); + break; case OP_SEQ_AT: SASSERT(num_args == 2); - return mk_seq_at(args[0], args[1], result); + st = mk_seq_at(args[0], args[1], result); + break; #if 0 case OP_SEQ_NTH: SASSERT(num_args == 2); @@ -466,35 +485,49 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con #endif case OP_SEQ_PREFIX: SASSERT(num_args == 2); - return mk_seq_prefix(args[0], args[1], result); + st = mk_seq_prefix(args[0], args[1], result); + break; case OP_SEQ_SUFFIX: SASSERT(num_args == 2); - return mk_seq_suffix(args[0], args[1], result); + st = mk_seq_suffix(args[0], args[1], result); + break; case OP_SEQ_INDEX: if (num_args == 2) { expr_ref arg3(m_autil.mk_int(0), m()); result = m_util.str.mk_index(args[0], args[1], arg3); - return BR_REWRITE1; + st = BR_REWRITE1; } - SASSERT(num_args == 3); - return mk_seq_index(args[0], args[1], args[2], result); + else { + SASSERT(num_args == 3); + st = mk_seq_index(args[0], args[1], args[2], result); + } + break; + case OP_SEQ_LAST_INDEX: + SASSERT(num_args == 2); + st = mk_seq_last_index(args[0], args[1], result); + break; case OP_SEQ_REPLACE: SASSERT(num_args == 3); - return mk_seq_replace(args[0], args[1], args[2], result); + st = mk_seq_replace(args[0], args[1], args[2], result); + break; case OP_SEQ_TO_RE: SASSERT(num_args == 1); - return mk_str_to_regexp(args[0], result); + st = mk_str_to_regexp(args[0], result); + break; case OP_SEQ_IN_RE: SASSERT(num_args == 2); - return mk_str_in_regexp(args[0], args[1], result); + st = mk_str_in_regexp(args[0], args[1], result); + break; case OP_STRING_CONST: return BR_FAILED; case OP_STRING_ITOS: SASSERT(num_args == 1); - return mk_str_itos(args[0], result); + st = mk_str_itos(args[0], result); + break; case OP_STRING_STOI: SASSERT(num_args == 1); - return mk_str_stoi(args[0], result); + st = mk_str_stoi(args[0], result); + break; case _OP_STRING_CONCAT: case _OP_STRING_PREFIX: case _OP_STRING_SUFFIX: @@ -908,6 +941,18 @@ br_status seq_rewriter::mk_seq_nth(expr* a, expr* b, expr_ref& result) { return BR_FAILED; } +br_status seq_rewriter::mk_seq_last_index(expr* a, expr* b, expr_ref& result) { + zstring s1, s2; + bool isc1 = m_util.str.is_string(a, s1); + bool isc2 = m_util.str.is_string(b, s2); + if (isc1 && isc2) { + int idx = s1.last_indexof(s2); + result = m_autil.mk_numeral(rational(idx), true); + return BR_DONE; + } + return BR_FAILED; +} + br_status seq_rewriter::mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result) { zstring s1, s2; rational r; diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 25b8979fc..73ab26591 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -116,6 +116,7 @@ class seq_rewriter { br_status mk_seq_at(expr* a, expr* b, expr_ref& result); br_status mk_seq_nth(expr* a, expr* b, expr_ref& result); br_status mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result); + br_status mk_seq_last_index(expr* a, expr* b, expr_ref& result); br_status mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& result); br_status mk_seq_prefix(expr* a, expr* b, expr_ref& result); br_status mk_seq_suffix(expr* a, expr* b, expr_ref& result); diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 7576e43c0..0fd27302a 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -273,6 +273,21 @@ int zstring::indexof(zstring const& other, int offset) const { return -1; } +int zstring::last_indexof(zstring const& other) const { + if (other.length() == 0) return length(); + if (other.length() > length()) return -1; + for (unsigned last = length() - other.length(); last-- > 0; ) { + bool suffix = true; + for (unsigned j = 0; suffix && j < other.length(); ++j) { + suffix = m_buffer[last + j] == other[j]; + } + if (suffix) { + return static_cast(last); + } + } + return -1; +} + zstring zstring::extract(int offset, int len) const { zstring result(m_encoding); SASSERT(0 <= offset && 0 <= len); @@ -530,6 +545,7 @@ void seq_decl_plugin::init() { m_sigs[OP_SEQ_EXTRACT] = alloc(psig, m, "seq.extract", 1, 3, seqAint2T, seqA); 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_LAST_INDEX] = alloc(psig, m, "seq.last_indexof", 1, 2, seqAseqA, 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); @@ -774,7 +790,13 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, OP_SEQ_INDEX)); } return mk_str_fun(k, arity, domain, range, OP_SEQ_INDEX); - + case OP_SEQ_LAST_INDEX: + if (arity != 2) { + m.raise_exception("two arguments expected tin last_indexof"); + } + else { + return mk_seq_fun(k, arity, domain, range, OP_SEQ_LAST_INDEX); + } case OP_SEQ_PREFIX: return mk_seq_fun(k, arity, domain, range, _OP_STRING_PREFIX); case _OP_STRING_PREFIX: diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 1148c8411..0185e473c 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -43,6 +43,7 @@ enum seq_op_kind { OP_SEQ_NTH, OP_SEQ_LENGTH, OP_SEQ_INDEX, + OP_SEQ_LAST_INDEX, OP_SEQ_TO_RE, OP_SEQ_IN_RE, @@ -113,6 +114,7 @@ public: bool prefixof(zstring const& other) const; bool contains(zstring const& other) const; int indexof(zstring const& other, int offset) const; + int last_indexof(zstring const& other) const; zstring extract(int lo, int hi) const; zstring operator+(zstring const& other) const; bool operator==(const zstring& other) const; @@ -260,6 +262,7 @@ public: 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_last_index(expr* a, expr* b) const { expr* es[2] = { a, b}; return m.mk_app(m_fid, OP_SEQ_LAST_INDEX, 2, 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); } @@ -285,6 +288,7 @@ public: 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_last_index(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_LAST_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); } bool is_suffix(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_SUFFIX); } @@ -311,6 +315,7 @@ public: MATCH_BINARY(is_nth); MATCH_BINARY(is_index); MATCH_TERNARY(is_index); + MATCH_BINARY(is_last_index); MATCH_TERNARY(is_replace); MATCH_BINARY(is_prefix); MATCH_BINARY(is_suffix); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 9a3f47757..7a899d5ae 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -4150,6 +4150,12 @@ expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) { if (!arg1 || !arg2) return result; result = m_util.str.mk_index(arg1, arg2, e3); } + else if (m_util.str.is_last_index(e, e1, e2)) { + arg1 = try_expand(e1, deps); + arg2 = try_expand(e2, deps); + if (!arg1 || !arg2) return result; + result = m_util.str.mk_last_index(arg1, arg2); + } else if (m.is_ite(e, e1, e2, e3)) { if (ctx.e_internalized(e) && ctx.e_internalized(e2) && ctx.get_enode(e)->get_root() == ctx.get_enode(e2)->get_root()) { result = try_expand(e2, deps); @@ -4288,6 +4294,9 @@ void theory_seq::deque_axiom(expr* n) { else if (m_util.str.is_index(n)) { add_indexof_axiom(n); } + else if (m_util.str.is_last_index(n)) { + add_last_indexof_axiom(n); + } else if (m_util.str.is_replace(n)) { add_replace_axiom(n); } @@ -4437,6 +4446,42 @@ void theory_seq::add_indexof_axiom(expr* i) { } } +/** + + !contains(t, s) => i = -1 + |t| = 0 => |s| = 0 or i = -1 + |t| = 0 & |s| = 0 => i = 0 + |t| != 0 & contains(t, s) => t = xsy & i = len(x) + |s| = 0 or s = s_head*s_tail + |s| = 0 or !contains(s_tail*y, s) + + */ +void theory_seq::add_last_indexof_axiom(expr* i) { + expr* s = nullptr, *t = nullptr; + VERIFY(m_util.str.is_last_index(i, t, s)); + expr_ref minus_one(m_autil.mk_int(-1), m); + expr_ref zero(m_autil.mk_int(0), m); + expr_ref s_head(m), s_tail(m); + expr_ref x = mk_skolem(symbol("seq.last_indexof_left"), t, s); + expr_ref y = mk_skolem(symbol("seq.last_indexof_right"), t, s); + mk_decompose(s, s_head, s_tail); + literal cnt = mk_literal(m_util.str.mk_contains(t, s)); + literal cnt2 = mk_literal(m_util.str.mk_contains(mk_concat(s_tail, y), s)); + literal i_eq_m1 = mk_eq(i, minus_one, false); + literal i_eq_0 = mk_eq(i, zero, false); + literal s_eq_empty = mk_eq_empty(s); + literal t_eq_empty = mk_eq_empty(t); + expr_ref xsy = mk_concat(x, s, y); + + add_axiom(cnt, i_eq_m1); + add_axiom(~t_eq_empty, s_eq_empty, i_eq_m1); + add_axiom(~t_eq_empty, ~s_eq_empty, i_eq_0); + add_axiom(t_eq_empty, ~cnt, mk_seq_eq(t, xsy)); + add_axiom(t_eq_empty, ~cnt, mk_eq(i, mk_len(x), false)); + add_axiom(s_eq_empty, mk_eq(s, mk_concat(s_head, s_tail), false)); + add_axiom(s_eq_empty, ~cnt2); +} + /* let r = replace(a, s, t) diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 166c8774e..f0d7fa15b 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -550,6 +550,7 @@ namespace smt { void push_lit_as_expr(literal l, expr_ref_vector& buf); void add_axiom(literal l1, literal l2 = null_literal, literal l3 = null_literal, literal l4 = null_literal, literal l5 = null_literal); void add_indexof_axiom(expr* e); + void add_last_indexof_axiom(expr* e); void add_replace_axiom(expr* e); void add_extract_axiom(expr* e); void add_length_axiom(expr* n); From a74ac93bcc3dfec5429861fef95eafeac439f03a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Mar 2019 13:34:31 -0700 Subject: [PATCH 066/156] fix #2196 Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/goal2sat.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 19e7d6ba2..b329cb06e 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -549,9 +549,14 @@ struct goal2sat::imp { SASSERT(k.is_unsigned()); sat::literal_vector lits; convert_pb_args(t->get_num_args(), lits); + unsigned k2 = k.get_unsigned(); 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()); + if (sign) { + for (sat::literal& l : lits) l.neg(); + k2 = lits.size() + 1 - k2; + } + m_ext->add_at_least(sat::null_bool_var, lits, k2); } else { sat::bool_var v = m_solver.add_var(true); @@ -571,14 +576,19 @@ struct goal2sat::imp { for (sat::literal& l : lits) { l.neg(); } + unsigned k2 = lits.size() - k.get_unsigned(); 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()); + if (sign) { + for (sat::literal& l : lits) l.neg(); + k2 = lits.size() + 1 - k2; + } + m_ext->add_at_least(sat::null_bool_var, lits, k2); } else { sat::bool_var v = m_solver.add_var(true); sat::literal lit(v, false); - m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned()); + m_ext->add_at_least(v, lits, k2); m_cache.insert(t, lit); if (sign) lit.neg(); push_result(root, lit, t->get_num_args()); From 604c9d38dca36cdd598487960c17c28913a2b50d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Mar 2019 12:54:18 -0700 Subject: [PATCH 067/156] don't overwrite last search failure, #2198 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 6b15501ea..5715e067d 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3749,7 +3749,6 @@ namespace smt { } if (resource_limits_exceeded() && !inconsistent()) { - m_last_search_failure = RESOURCE_LIMIT; return l_undef; } } From fca8ffd9480a743209e7038041b1d26182c77361 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Mar 2019 16:37:50 -0700 Subject: [PATCH 068/156] fix #2199 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 69c90c3f6..e5ab83187 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10316,3 +10316,15 @@ def Loop(re, lo, hi=0): False """ return ReRef(Z3_mk_re_loop(re.ctx_ref(), re.as_ast(), lo, hi), re.ctx) + +def Range(lo, hi, ctx = None): + """Create the range regular expression over two sequences of length 1 + >>> range = Range("a","z") + >>> print(simplify(InRe("b", range))) + True + >>> print(simplify(InRe("bb", range))) + False + """ + lo = _coerce_seq(lo, ctx) + hi = _coerce_seq(hi, ctx) + return ReRef(Z3_mk_re_range(lo.ctx_ref(), lo.ast, hi.ast), lo.ctx) From dc0e9c1919295cb0ad9cb0798741de6e536d5eb1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 11:46:36 -0700 Subject: [PATCH 069/156] completing user print experience with seq/re #2200 Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 4 +-- src/api/api_seq.cpp | 26 +++++++++++++++++ src/api/python/z3/z3.py | 30 ++++++++++++++++++-- src/api/python/z3/z3printer.py | 40 +++++++++++++++++++++++++-- src/api/z3_api.h | 14 ++++++++++ src/sat/sat_model_converter.cpp | 6 +++- src/sat/sat_solver.cpp | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 3 +- src/sat/tactic/goal2sat.h | 2 +- 9 files changed, 115 insertions(+), 11 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 4893cbe10..cabfdb101 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1192,8 +1192,8 @@ extern "C" { case OP_RE_UNION: return Z3_OP_RE_UNION; case OP_RE_INTERSECT: return Z3_OP_RE_INTERSECT; case OP_RE_LOOP: return Z3_OP_RE_LOOP; - // case OP_RE_FULL_SEQ_SET: return Z3_OP_RE_FULL_SET; - case OP_RE_FULL_CHAR_SET: return Z3_OP_RE_FULL_SET; + case OP_RE_FULL_SEQ_SET: return Z3_OP_RE_FULL_SET; + //case OP_RE_FULL_CHAR_SET: return Z3_OP_RE_FULL_SET; case OP_RE_EMPTY_SET: return Z3_OP_RE_EMPTY_SET; default: return Z3_OP_INTERNAL; diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index b621dcebe..7554fff8a 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -95,6 +95,32 @@ extern "C" { Z3_CATCH_RETURN(false); } + Z3_sort Z3_API Z3_get_seq_sort_basis(Z3_context c, Z3_sort s) { + Z3_TRY; + LOG_Z3_get_seq_sort_basis(c, s); + RESET_ERROR_CODE(); + sort* r = nullptr; + if (!mk_c(c)->sutil().is_seq(to_sort(s), r)) { + SET_ERROR_CODE(Z3_INVALID_ARG, "expected sequence sort"); + RETURN_Z3(nullptr); + } + RETURN_Z3(of_sort(r)); + Z3_CATCH_RETURN(nullptr); + } + + Z3_sort Z3_API Z3_get_re_sort_basis(Z3_context c, Z3_sort s) { + Z3_TRY; + LOG_Z3_get_re_sort_basis(c, s); + RESET_ERROR_CODE(); + sort* r = nullptr; + if (!mk_c(c)->sutil().is_re(to_sort(s), r)) { + SET_ERROR_CODE(Z3_INVALID_ARG, "expected regex sort"); + RETURN_Z3(nullptr); + } + RETURN_Z3(of_sort(r)); + Z3_CATCH_RETURN(nullptr); + } + bool Z3_API Z3_is_string_sort(Z3_context c, Z3_sort s) { Z3_TRY; LOG_Z3_is_string_sort(c, s); diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index e5ab83187..8a7053deb 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -609,6 +609,10 @@ def _to_sort_ref(s, ctx): return FPSortRef(s, ctx) elif k == Z3_ROUNDING_MODE_SORT: return FPRMSortRef(s, ctx) + elif k == Z3_RE_SORT: + return ReSortRef(s, ctx) + elif k == Z3_SEQ_SORT: + return SeqSortRef(s, ctx) return SortRef(s, ctx) def _sort(ctx, a): @@ -9908,6 +9912,9 @@ class SeqSortRef(SortRef): False """ return Z3_is_string_sort(self.ctx_ref(), self.ast) + + def basis(self): + return _to_sort_ref(Z3_get_seq_sort_basis(self.ctx_ref(), self.ast), self.ctx) def StringSort(ctx=None): @@ -10062,7 +10069,7 @@ def Full(s): re.all >>> e1 = Full(ReSort(StringSort())) >>> print(e1) - re.all + rel.all """ if isinstance(s, ReSortRef): return ReRef(Z3_mk_re_full(s.ctx_ref(), s.ast), s.ctx) @@ -10212,6 +10219,8 @@ def Re(s, ctx=None): class ReSortRef(SortRef): """Regular expression sort.""" + def basis(self): + return _to_sort_ref(Z3_get_re_sort_basis(self.ctx_ref(), self.ast), self.ctx) def ReSort(s): if is_ast(s): @@ -10228,7 +10237,6 @@ class ReRef(ExprRef): def __add__(self, other): return Union(self, other) - def is_re(s): return isinstance(s, ReRef) @@ -10265,6 +10273,24 @@ def Union(*args): v[i] = args[i].as_ast() return ReRef(Z3_mk_re_union(ctx.ref(), sz, v), ctx) +def Intersect(*args): + """Create intersection of regular expressions. + >>> re = Intersect(Re("a"), Re("b"), Re("c")) + Intersect(Re("a"), Re("b"), Re("c")) + """ + args = _get_args(args) + sz = len(args) + if __debug__: + _z3_assert(sz > 0, "At least one argument expected.") + _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.") + if sz == 1: + return args[0] + ctx = args[0].ctx + v = (Ast * sz)() + for i in range(sz): + v[i] = args[i].as_ast() + return ReRef(Z3_mk_re_intersect(ctx.ref(), sz, v), ctx) + def Plus(re): """Create the regular expression accepting one or more repetitions of argument. >>> re = Plus(Re("a")) diff --git a/src/api/python/z3/z3printer.py b/src/api/python/z3/z3printer.py index 76614910f..5640ebcac 100644 --- a/src/api/python/z3/z3printer.py +++ b/src/api/python/z3/z3printer.py @@ -36,7 +36,15 @@ _z3_op_to_str = { Z3_OP_CONCAT : 'Concat', Z3_OP_EXTRACT : 'Extract', Z3_OP_BV2INT : 'BV2Int', Z3_OP_ARRAY_MAP : 'Map', Z3_OP_SELECT : 'Select', Z3_OP_STORE : 'Store', Z3_OP_CONST_ARRAY : 'K', Z3_OP_ARRAY_EXT : 'Ext', - Z3_OP_PB_AT_MOST : 'AtMost', Z3_OP_PB_LE : 'PbLe', Z3_OP_PB_GE : 'PbGe', Z3_OP_PB_EQ : 'PbEq' + Z3_OP_PB_AT_MOST : 'AtMost', Z3_OP_PB_LE : 'PbLe', Z3_OP_PB_GE : 'PbGe', Z3_OP_PB_EQ : 'PbEq', + Z3_OP_SEQ_CONCAT : 'Concat', Z3_OP_SEQ_PREFIX : 'PrefixOf', Z3_OP_SEQ_SUFFIX : 'SuffixOf', + Z3_OP_SEQ_UNIT : 'Unit', Z3_OP_SEQ_CONTAINS : 'Contains' , Z3_OP_SEQ_REPLACE : 'Replace', + Z3_OP_SEQ_AT : 'At', Z3_OP_SEQ_NTH : 'Nth', Z3_OP_SEQ_INDEX : 'IndexOf', + Z3_OP_SEQ_LAST_INDEX : 'LastIndexOf', Z3_OP_SEQ_LENGTH : 'Length', Z3_OP_STR_TO_INT : 'StrToInt', Z3_OP_INT_TO_STR : 'IntToStr', + Z3_OP_SEQ_IN_RE : 'InRe', Z3_OP_SEQ_TO_RE : 'Re', + Z3_OP_RE_PLUS : 'Plus', Z3_OP_RE_STAR : 'Star', Z3_OP_RE_OPTION : 'Option', Z3_OP_RE_UNION : 'Union', Z3_OP_RE_RANGE : 'Range', + Z3_OP_RE_INTERSECT : 'Intersect', Z3_OP_RE_COMPLEMENT : 'Complement', + } # List of infix operators @@ -486,7 +494,7 @@ class PP: def pp(self, f, indent): if isinstance(f, str): - sef.pp_string(f, indent) + self.pp_string(f, indent) elif f.is_string(): self.pp_string(f, indent) elif f.is_indent(): @@ -558,10 +566,23 @@ class Formatter: return seq1('BitVec', (to_format(s.size()), )) elif isinstance(s, z3.FPSortRef): return seq1('FPSort', (to_format(s.ebits()), to_format(s.sbits()))) + elif isinstance(s, z3.ReSortRef): + return seq1('ReSort', (self.pp_sort(s.basis()), )) + elif isinstance(s, z3.SeqSortRef): + if s.is_string(): + return to_format("String") + return seq1('Seq', (self.pp_sort(s.basis()), )) else: return to_format(s.name()) def pp_const(self, a): + k = a.decl().kind() + if k == Z3_OP_RE_EMPTY_SET: + return self.pp_set("Empty", a) + elif k == Z3_OP_SEQ_EMPTY: + return self.pp_set("Empty", a) + elif k == Z3_OP_RE_FULL_SET: + return self.pp_set("Full", a) return self.pp_name(a) def pp_int(self, a): @@ -577,7 +598,7 @@ class Formatter: return to_format(a.as_decimal(self.precision)) def pp_string(self, a): - return to_format(a.as_string()) + return to_format("\"" + a.as_string() + "\"") def pp_bv(self, a): return to_format(a.as_string()) @@ -842,6 +863,17 @@ class Formatter: arg = self.pp_expr(a.arg(0), d+1, xs) return seq1(self.pp_name(a), [ to_format(h), to_format(l), arg ]) + def pp_loop(self, a, d, xs): + l = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0) + arg = self.pp_expr(a.arg(0), d+1, xs) + if Z3_get_decl_num_parameters(a.ctx_ref(), a.decl().ast) > 1: + h = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 1) + return seq1("Loop", [ arg, to_format(l), to_format(h) ]) + return seq1("Loop", [ arg, to_format(l) ]) + + def pp_set(self, id, a): + return seq1(id, [self.pp_sort(a.sort())]) + def pp_pattern(self, a, d, xs): if a.num_args() == 1: return self.pp_expr(a.arg(0), d, xs) @@ -918,6 +950,8 @@ class Formatter: return self.pp_unary_param(a, d, xs) elif k == Z3_OP_EXTRACT: return self.pp_extract(a, d, xs) + elif k == Z3_OP_RE_LOOP: + return self.pp_loop(a, d, xs) elif k == Z3_OP_DT_IS: return self.pp_is(a, d, xs) elif k == Z3_OP_ARRAY_MAP: diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 7f1a1c70c..e17378d94 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3292,6 +3292,13 @@ extern "C" { */ bool Z3_API Z3_is_seq_sort(Z3_context c, Z3_sort s); + /** + \brief Retrieve basis sort for sequence sort. + + def_API('Z3_get_seq_sort_basis', SORT, (_in(CONTEXT), _in(SORT))) + */ + Z3_sort Z3_API Z3_get_seq_sort_basis(Z3_context c, Z3_sort s); + /** \brief Create a regular expression sort out of a sequence sort. @@ -3306,6 +3313,13 @@ extern "C" { */ bool Z3_API Z3_is_re_sort(Z3_context c, Z3_sort s); + /** + \brief Retrieve basis sort for regex sort. + + def_API('Z3_get_re_sort_basis', SORT, (_in(CONTEXT), _in(SORT))) + */ + Z3_sort Z3_API Z3_get_re_sort_basis(Z3_context c, Z3_sort s); + /** \brief Create a sort for 8 bit strings. diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index fb8c48866..fab3be418 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -75,7 +75,7 @@ namespace sat { void model_converter::operator()(model & m) const { vector::const_iterator begin = m_entries.begin(); vector::const_iterator it = m_entries.end(); - bool first = false; // true; // false; // // true; + bool first = false; //SASSERT(!m_solver || m_solver->check_clauses(m)); while (it != begin) { --it; @@ -146,6 +146,10 @@ namespace sat { bool sat = false; for (literal l : it->m_clauses) { if (l == null_literal) { + CTRACE("sat", !sat, + display(tout); + for (unsigned v = 0; v < m.size(); ++v) tout << v << ": " << m[v] << "\n"; + ); SASSERT(sat); sat = false; continue; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 427077804..a0bd94303 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1608,6 +1608,7 @@ namespace sat { if (inconsistent()) break; assign_scoped(lit); } + propagate(false); TRACE("sat", for (literal a : m_assumptions) { index_set s; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 0cc829379..bd8a19044 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -879,6 +879,7 @@ private: mdl = nullptr; return; } + TRACE("sat", m_solver.display_model(tout);); sat::model const & ll_m = m_solver.get_model(); mdl = alloc(model, m); for (sat::bool_var v = 0; v < ll_m.size(); ++v) { @@ -899,11 +900,9 @@ private: } if (m_sat_mc) { - // IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "satmc\n");); (*m_sat_mc)(mdl); } if (m_mcs.back()) { - //IF_VERBOSE(0, m_mc0->display(verbose_stream() << "mc0\n");); (*m_mcs.back())(mdl); } TRACE("sat", model_smt2_pp(tout, m, *mdl, 0);); diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index 78884051e..2177ca34d 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -88,7 +88,7 @@ public: mc(ast_manager& m); ~mc() override {} // flush model converter from SAT solver to this structure. - void flush_smc(sat::solver_core& s, atom2bool_var const& map); + void flush_smc(sat::solver_core& s, atom2bool_var const& map); void operator()(model_ref& md) override; void operator()(expr_ref& fml) override; model_converter* translate(ast_translation& translator) override; From cdc89b6193ef219e53cf9293528a8b083f95135d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 12:57:08 -0700 Subject: [PATCH 070/156] add get-info :rlimit option to cmd-context to facilitate timeout based repros Signed-off-by: Nikolaj Bjorner --- src/cmd_context/basic_cmds.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 80cd6373e..8ba830287 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -629,6 +629,7 @@ class get_info_cmd : public cmd { symbol m_reason_unknown; symbol m_all_statistics; symbol m_assertion_stack_levels; + symbol m_rlimit; public: get_info_cmd(): cmd("get-info"), @@ -639,7 +640,8 @@ public: m_status(":status"), m_reason_unknown(":reason-unknown"), m_all_statistics(":all-statistics"), - m_assertion_stack_levels(":assertion-stack-levels") { + m_assertion_stack_levels(":assertion-stack-levels"), + m_rlimit(":rlimit") { } char const * get_usage() const override { return ""; } char const * get_descr(cmd_context & ctx) const override { return "get information."; } @@ -671,6 +673,9 @@ public: else if (opt == m_reason_unknown) { ctx.regular_stream() << "(:reason-unknown \"" << escaped(ctx.reason_unknown().c_str()) << "\")" << std::endl; } + else if (opt == m_rlimit) { + ctx.regular_stream() << "(:rlimit " << ctx.m().limit().count() << ")" << std::endl; + } else if (opt == m_all_statistics) { ctx.display_statistics(); } From 32164b6c7f307b93118fa257bebbd0db6ea3ee56 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 13:10:11 -0700 Subject: [PATCH 071/156] fix python doc regressions Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 8a7053deb..173119011 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -3841,7 +3841,7 @@ def Extract(high, low, a): >>> Extract(6, 2, x).sort() BitVec(5) >>> simplify(Extract(StringVal("abcd"),2,1)) - c + "c" """ if isinstance(high, str): high = StringVal(high) @@ -10051,10 +10051,10 @@ def Empty(s): True >>> e3 = Empty(SeqSort(IntSort())) >>> print(e3) - seq.empty + Empty(Seq(Int)) >>> e4 = Empty(ReSort(SeqSort(IntSort()))) >>> print(e4) - re.empty + Empty(ReSort(Seq(Int))) """ if isinstance(s, SeqSortRef): return SeqRef(Z3_mk_seq_empty(s.ctx_ref(), s.ast), s.ctx) @@ -10066,10 +10066,10 @@ def Full(s): """Create the regular expression that accepts the universal language >>> e = Full(ReSort(SeqSort(IntSort()))) >>> print(e) - re.all + Full(ReSort(Int)) >>> e1 = Full(ReSort(StringSort())) >>> print(e1) - rel.all + Full(ReSort(String)) """ if isinstance(s, ReSortRef): return ReRef(Z3_mk_re_full(s.ctx_ref(), s.ast), s.ctx) @@ -10131,7 +10131,7 @@ def Replace(s, src, dst): """Replace the first occurrence of 'src' by 'dst' in 's' >>> r = Replace("aaa", "a", "b") >>> simplify(r) - baa + "baa" """ ctx = _get_ctx2(dst, s) if ctx is None and is_expr(src): @@ -10276,7 +10276,6 @@ def Union(*args): def Intersect(*args): """Create intersection of regular expressions. >>> re = Intersect(Re("a"), Re("b"), Re("c")) - Intersect(Re("a"), Re("b"), Re("c")) """ args = _get_args(args) sz = len(args) From 0a0b0a5cc016d37eeb1111ce9b0d05d93b8a25ba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 13:22:35 -0700 Subject: [PATCH 072/156] fix python doc regressions Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 173119011..e3995ddb5 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10066,7 +10066,7 @@ def Full(s): """Create the regular expression that accepts the universal language >>> e = Full(ReSort(SeqSort(IntSort()))) >>> print(e) - Full(ReSort(Int)) + Full(ReSort(Seq(Int))) >>> e1 = Full(ReSort(StringSort())) >>> print(e1) Full(ReSort(String)) From 5c67c9d907ca196c7efb1e757ced48707a1e9b35 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 17:08:31 -0700 Subject: [PATCH 073/156] print certificate for #2202, enable CTL-C for API fix #2203 Signed-off-by: Nikolaj Bjorner --- src/api/api_datalog.cpp | 3 +++ src/api/api_opt.cpp | 3 +++ src/api/api_solver.cpp | 9 +++------ src/muz/base/dl_context.cpp | 10 ++++++++-- src/muz/base/dl_context.h | 2 +- src/opt/opt_context.cpp | 2 ++ src/sat/sat_model_converter.cpp | 18 ++++++++++++++---- src/solver/solver.cpp | 3 --- src/util/params.cpp | 3 +++ src/util/params.h | 1 + 10 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 790470275..57037f1a8 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -24,6 +24,7 @@ Revision History: #include "api/api_stats.h" #include "muz/fp/datalog_parser.h" #include "util/cancel_eh.h" +#include "util/scoped_ctrl_c.h" #include "util/scoped_timer.h" #include "muz/fp/dl_cmds.h" #include "cmd_context/cmd_context.h" @@ -280,11 +281,13 @@ extern "C" { 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()); + bool use_ctrl_c = to_fixedpoint(d)->m_params.get_bool("ctrl_c", true); { 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); + scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); try { r = to_fixedpoint_ref(d)->ctx().query(to_expr(q)); } diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 5d35b23b0..ad2c75764 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -18,6 +18,7 @@ Revision History: #include #include "util/cancel_eh.h" #include "util/scoped_timer.h" +#include "util/scoped_ctrl_c.h" #include "util/file_path.h" #include "parsers/smt2/smt2parser.h" #include "opt/opt_context.h" @@ -148,8 +149,10 @@ extern "C" { cancel_eh eh(mk_c(c)->m().limit()); unsigned timeout = to_optimize_ptr(o)->get_params().get_uint("timeout", mk_c(c)->get_timeout()); unsigned rlimit = to_optimize_ptr(o)->get_params().get_uint("rlimit", mk_c(c)->get_rlimit()); + bool use_ctrl_c = to_optimize_ptr(o)->get_params().get_bool("ctrl_c", true); api::context::set_interruptable si(*(mk_c(c)), eh); { + scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); scoped_timer timer(timeout, &eh); scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); try { diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index cafbfb9ff..fb7a937cc 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -31,9 +31,6 @@ Revision History: #include "api/api_stats.h" #include "api/api_ast_vector.h" #include "solver/tactic2solver.h" -#include "util/scoped_ctrl_c.h" -#include "util/cancel_eh.h" -#include "util/scoped_timer.h" #include "util/file_path.h" #include "tactic/portfolio/smt_strategic_solver.h" #include "smt/smt_solver.h" @@ -465,7 +462,7 @@ extern "C" { expr * const * _assumptions = to_exprs(assumptions); unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); - bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false); + bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", true); cancel_eh eh(mk_c(c)->m().limit()); api::context::set_interruptable si(*(mk_c(c)), eh); lbool result; @@ -656,7 +653,7 @@ extern "C" { lbool result = l_undef; unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); - bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false); + bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", true); cancel_eh eh(mk_c(c)->m().limit()); api::context::set_interruptable si(*(mk_c(c)), eh); { @@ -698,7 +695,7 @@ extern "C" { } unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); - bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false); + bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", true); cancel_eh eh(mk_c(c)->m().limit()); api::context::set_interruptable si(*(mk_c(c)), eh); { diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index e8578f327..d4af4693a 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -730,6 +730,7 @@ namespace datalog { void context::collect_params(param_descrs& p) { fp_params::collect_param_descrs(p); insert_timeout(p); + insert_ctrl_c(p); } void context::updt_params(params_ref const& p) { @@ -854,7 +855,11 @@ namespace datalog { UNREACHABLE(); } ensure_engine(); - return m_engine->query(query); + lbool r = m_engine->query(query); + if (r != l_undef && get_params().print_certificate()) { + display_certificate(std::cout) << "\n"; + } + return r; } lbool context::query_from_lvl (expr* query, unsigned lvl) { @@ -951,9 +956,10 @@ namespace datalog { } } - void context::display_certificate(std::ostream& out) { + std::ostream& context::display_certificate(std::ostream& out) { ensure_engine(); m_engine->display_certificate(out); + return out; } void context::display(std::ostream & out) const { diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index a14ef163f..b20e2813e 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -581,7 +581,7 @@ namespace datalog { /** \brief Display a certificate for reachability and/or unreachability. */ - void display_certificate(std::ostream& out); + std::ostream& display_certificate(std::ostream& out); /** \brief query result if it contains fact. diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index e7c9e72ea..b43147c33 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1487,6 +1487,8 @@ namespace opt { void context::collect_param_descrs(param_descrs & r) { opt_params::collect_param_descrs(r); + insert_timeout(r); + insert_ctrl_c(r); } void context::updt_params(params_ref const& p) { diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index fab3be418..ddb7df74b 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -144,20 +144,30 @@ namespace sat { DEBUG_CODE({ // all clauses must be satisfied bool sat = false; - for (literal l : it->m_clauses) { + bool undef = false; + for (literal const& l : it->m_clauses) { if (l == null_literal) { CTRACE("sat", !sat, + if (m_solver) m_solver->display(tout); display(tout); for (unsigned v = 0; v < m.size(); ++v) tout << v << ": " << m[v] << "\n"; + for (literal const& l2 : it->m_clauses) { + if (l2 == null_literal) tout << "\n"; else tout << l2 << " "; + if (&l == &l2) break; + } ); - SASSERT(sat); + SASSERT(sat || undef); sat = false; + undef = false; continue; } if (sat) continue; - if (value_at(l, m) == l_true) - sat = true; + switch (value_at(l, m)) { + case l_undef: undef = true; break; + case l_true: sat = true; break; + default: break; + } } }); } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 89421f079..20c2166a2 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -223,9 +223,6 @@ void solver::assert_expr(expr* f, expr* t) { assert_expr_core2(fml, a); } -static void insert_ctrl_c(param_descrs & r) { - r.insert("ctrl_c", CPK_BOOL, "enable interrupts from ctrl-c", "false"); -} void solver::collect_param_descrs(param_descrs & r) { diff --git a/src/util/params.cpp b/src/util/params.cpp index bfb6095d6..dd98dd958 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -305,6 +305,9 @@ void insert_rlimit(param_descrs & r) { r.insert("rlimit", CPK_UINT, "default resource limit used for solvers. Unrestricted when set to 0.", "0"); } +void insert_ctrl_c(param_descrs & r) { + r.insert("ctrl_c", CPK_BOOL, "enable interrupts from ctrl-c", "true"); +} class params { friend class params_ref; diff --git a/src/util/params.h b/src/util/params.h index 5330993c1..8d036456d 100644 --- a/src/util/params.h +++ b/src/util/params.h @@ -140,5 +140,6 @@ void insert_produce_models(param_descrs & r); void insert_produce_proofs(param_descrs & r); void insert_timeout(param_descrs & r); void insert_rlimit(param_descrs & r); +void insert_ctrl_c(param_descrs & r); #endif From 3125c19049d441de58943fa4556aca55bc52bcc5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 18:44:46 -0700 Subject: [PATCH 074/156] add sr Signed-off-by: Nikolaj Bjorner --- src/ast/CMakeLists.txt | 1 + src/ast/special_relations_decl_plugin.cpp | 79 ++ src/ast/special_relations_decl_plugin.h | 97 +++ src/smt/CMakeLists.txt | 1 + src/smt/diff_logic.h | 148 +++- src/smt/theory_special_relations.cpp | 905 ++++++++++++++++++++++ src/smt/theory_special_relations.h | 198 +++++ 7 files changed, 1413 insertions(+), 16 deletions(-) create mode 100644 src/ast/special_relations_decl_plugin.cpp create mode 100644 src/ast/special_relations_decl_plugin.h create mode 100644 src/smt/theory_special_relations.cpp create mode 100644 src/smt/theory_special_relations.h diff --git a/src/ast/CMakeLists.txt b/src/ast/CMakeLists.txt index 56ab78b8a..0bcc4d847 100644 --- a/src/ast/CMakeLists.txt +++ b/src/ast/CMakeLists.txt @@ -41,6 +41,7 @@ z3_add_component(ast reg_decl_plugins.cpp seq_decl_plugin.cpp shared_occs.cpp + special_relations_decl_plugin.cpp static_features.cpp used_vars.cpp well_sorted.cpp diff --git a/src/ast/special_relations_decl_plugin.cpp b/src/ast/special_relations_decl_plugin.cpp new file mode 100644 index 000000000..6bb5734e5 --- /dev/null +++ b/src/ast/special_relations_decl_plugin.cpp @@ -0,0 +1,79 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + special_relations_decl_plugin.cpp + +Abstract: + + + +Author: + + Nikolaj Bjorner (nbjorner) 2015-15-9. + +Revision History: + +--*/ + +#include +#include"ast.h" +#include"special_relations_decl_plugin.h" + + + +special_relations_decl_plugin::special_relations_decl_plugin(): + m_lo("linear-order"), + m_po("partial-order"), + m_po_ao("partial-order-already-ordered"), + m_plo("piecewise-linear-order"), + m_to("tree-order") +{} + +func_decl * special_relations_decl_plugin::mk_func_decl( + decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) +{ + if (arity != 2) { + m_manager->raise_exception("special relations should have arity 2"); + return 0; + } + if (domain[0] != domain[1]) { + m_manager->raise_exception("argument sort missmatch"); + return 0; + } + func_decl_info info(m_family_id, k, num_parameters, parameters); + symbol name; + switch(k) { + case OP_SPECIAL_RELATION_PO: name = m_po; break; + case OP_SPECIAL_RELATION_PO_AO: name = m_po_ao; break; + case OP_SPECIAL_RELATION_LO: name = m_lo; break; + case OP_SPECIAL_RELATION_PLO: name = m_plo; break; + case OP_SPECIAL_RELATION_TO: name = m_to; break; + } + return m_manager->mk_func_decl(name, arity, domain, m_manager->mk_bool_sort(), info); +} + +void special_relations_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { + if (logic == symbol::null) { + op_names.push_back(builtin_name(m_po.bare_str(), OP_SPECIAL_RELATION_PO)); + op_names.push_back(builtin_name(m_po_ao.bare_str(), OP_SPECIAL_RELATION_PO_AO)); + op_names.push_back(builtin_name(m_lo.bare_str(), OP_SPECIAL_RELATION_LO)); + op_names.push_back(builtin_name(m_plo.bare_str(), OP_SPECIAL_RELATION_PLO)); + op_names.push_back(builtin_name(m_to.bare_str(), OP_SPECIAL_RELATION_TO)); + } +} + +sr_property special_relations_util::get_property(func_decl* f) const { + switch (f->get_decl_kind()) { + case OP_SPECIAL_RELATION_PO: return sr_po; + case OP_SPECIAL_RELATION_PO_AO: return sr_po; // still partial ordered + case OP_SPECIAL_RELATION_LO: return sr_lo; + case OP_SPECIAL_RELATION_PLO: return sr_plo; + case OP_SPECIAL_RELATION_TO: return sr_to; + default: + UNREACHABLE(); + return sr_po; + } +} diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h new file mode 100644 index 000000000..068382b23 --- /dev/null +++ b/src/ast/special_relations_decl_plugin.h @@ -0,0 +1,97 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + special_relations_decl_plugin.h + +Abstract: + + + +Author: + + Nikolaj Bjorner (nbjorner) 2015-15-9. + Ashutosh Gupta 2016 + +Revision History: + +--*/ +#ifndef SPECIAL_RELATIONS_DECL_PLUGIN_H_ +#define SPECIAL_RELATIONS_DECL_PLUGIN_H_ + +#include"ast.h" + + + +enum special_relations_op_kind { + OP_SPECIAL_RELATION_LO, + OP_SPECIAL_RELATION_PO, + OP_SPECIAL_RELATION_PO_AO, + OP_SPECIAL_RELATION_PLO, + OP_SPECIAL_RELATION_TO, + LAST_SPECIAL_RELATIONS_OP +}; + +class special_relations_decl_plugin : public decl_plugin { + symbol m_lo; + symbol m_po; + symbol m_po_ao; + symbol m_plo; + symbol m_to; +public: + special_relations_decl_plugin(); + virtual ~special_relations_decl_plugin() {} + + virtual decl_plugin * mk_fresh() { + return alloc(special_relations_decl_plugin); + } + + virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + virtual void get_op_names(svector & op_names, symbol const & logic); + + + virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { return 0; } +}; + +enum sr_property { + sr_transitive = 0x01, // Rxy & Ryz -> Rxz + sr_reflexive = 0x02, // Rxx + sr_antisymmetric = 0x04, // Rxy & Ryx -> x = y + sr_lefttree = 0x08, // Ryx & Rzx -> Ryz | Rzy + sr_righttree = 0x10, // Rxy & Rxz -> Ryx | Rzy + sr_po = 0x01 | 0x02 | 0x04, // partial order + sr_lo = 0x01 | 0x02 | 0x04 | 0x08 | 0x10, // linear order + sr_plo = 0x01 | 0x02 | 0x04 | 0x20, // piecewise linear order + sr_to = 0x01 | 0x02 | 0x04 | 0x10, // right-tree +}; + +class special_relations_util { + ast_manager& m; + family_id m_fid; +public: + special_relations_util(ast_manager& m) : m(m), m_fid(m.get_family_id("special_relations")) {} + + bool is_special_relation(func_decl* f) const { return f->get_family_id() == m_fid; } + bool is_special_relation(app* e) const { return is_special_relation(e->get_decl()); } + sr_property get_property(func_decl* f) const; + sr_property get_property(app* e) const { return get_property(e->get_decl()); } + + bool is_lo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_LO); } + bool is_po(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO); } + bool is_po_ao(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO_AO); } + bool is_plo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PLO); } + bool is_to(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TO); } + + app * mk_lo (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_LO, arg1, arg2); } + app * mk_po (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO, arg1, arg2); } + app * mk_po_ao (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO_AO, arg1, arg2); } + app * mk_plo(expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PLO, arg1, arg2); } + app * mk_to (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_TO, arg1, arg2); } + +}; + + +#endif /* SPECIAL_RELATIONS_DECL_PLUGIN_H_ */ diff --git a/src/smt/CMakeLists.txt b/src/smt/CMakeLists.txt index 52d3a5943..adc348633 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -62,6 +62,7 @@ z3_add_component(smt theory_pb.cpp theory_recfun.cpp theory_seq.cpp + theory_special_relations.cpp theory_str.cpp theory_utvpi.cpp theory_wmaxsat.cpp diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 44e858219..f3ce7fb13 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -296,6 +296,9 @@ public: numeral const& get_weight(edge_id id) const { return m_edges[id].get_weight(); } + edge_id_vector const& get_out_edges(dl_var v) const { return m_out_edges[v]; } + + edge_id_vector const& get_in_edges(dl_var v) const { return m_in_edges[v]; } private: // An assignment is almost feasible if all but edge with idt edge are feasible. @@ -661,6 +664,113 @@ public: } } + bool can_reach(dl_var src, dl_var dst) { + uint_set target, visited; + target.insert(dst); + return reachable(src, target, visited, dst); + } + + bool reachable(dl_var start, uint_set const& target, uint_set& visited, dl_var& dst) { + visited.reset(); + svector nodes; + nodes.push_back(start); + for (dl_var n : nodes) { + if (visited.contains(n)) continue; + visited.insert(n); + edge_id_vector & edges = m_out_edges[n]; + for (edge_id e_id : edges) { + edge & e = m_edges[e_id]; + if (e.is_enabled()) { + dst = e.get_target(); + if (target.contains(dst)) { + return true; + } + nodes.push_back(dst); + } + } + } + return false; + } + +private: + svector m_freq_hybrid; + int m_total_count = 0; + int m_run_counter = -1; + svector m_hybrid_visited, m_hybrid_parent; +public: + + template + bool find_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { + auto zero_edge = true; + unsigned bfs_head = 0; + int_vector bfs_todo; + int_vector dfs_todo; + m_hybrid_visited.resize(m_assignment.size(), m_run_counter++); + m_hybrid_parent.resize(m_assignment.size(), -1); + bfs_todo.push_back(source); + m_hybrid_parent[source] = -1; + m_hybrid_visited[source] = m_run_counter; + numeral gamma; + while (bfs_head < bfs_todo.size() || !dfs_todo.empty()) { + m_total_count++; + dl_var v; + if (!dfs_todo.empty()) { + v = dfs_todo.back(); + dfs_todo.pop_back(); + } + else { + v = bfs_todo[bfs_head++]; + } + + edge_id_vector & edges = m_out_edges[v]; + for (edge_id e_id : edges) { + edge & e = m_edges[e_id]; + SASSERT(e.get_source() == v); + if (!e.is_enabled()) { + continue; + } + set_gamma(e, gamma); + if ((gamma.is_one() || (!zero_edge && gamma.is_neg())) + && e.get_timestamp() < timestamp) { + dl_var curr_target = e.get_target(); + if (curr_target == target) { + f(e.get_explanation()); + m_freq_hybrid[e_id]++; + for (;;) { + int p = m_hybrid_parent[v]; + if (p == -1) + return true; + + edge_id eid; + bool ret = get_edge_id(p, v, eid); + if (eid == null_edge_id || !ret) { + return true; + } + else { + edge & e = m_edges[eid]; + f(e.get_explanation()); + m_freq_hybrid[eid]++; + v = p; + } + } + } + else if (m_hybrid_visited[curr_target] != m_run_counter) { + if (m_freq_hybrid[e_id] > 1) { + dfs_todo.push_back(curr_target); + } + else { + bfs_todo.push_back(curr_target); + } + m_hybrid_visited[curr_target] = m_run_counter; + m_hybrid_parent[curr_target] = v; + } + } + } + } + return false; + + } + // // Create fresh literals obtained by resolving a pair (or more) // literals associated with the edges. @@ -1274,8 +1384,22 @@ public: // Find the shortest path from source to target using (normalized) zero edges with timestamp less than the given timestamp. // The functor f is applied on every explanation attached to the edges in the shortest path. // Return true if the path exists, false otherwise. + + + // Return true if the path exists, false otherwise. + template + bool find_shortest_zero_edge_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { + return find_shortest_path_aux(source, target, timestamp, f, true); + } + template - bool find_shortest_zero_edge_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { + bool find_shortest_reachable_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { + return find_shortest_path_aux(source, target, timestamp, f, false); + } + + + template + bool find_shortest_path_aux(dl_var source, dl_var target, unsigned timestamp, Functor & f, bool zero_edge) { svector bfs_todo; svector bfs_mark; bfs_mark.resize(m_assignment.size(), false); @@ -1292,10 +1416,7 @@ public: dl_var v = curr.m_var; TRACE("dl_bfs", tout << "processing: " << v << "\n";); edge_id_vector & edges = m_out_edges[v]; - typename edge_id_vector::iterator it = edges.begin(); - typename edge_id_vector::iterator end = edges.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges) { edge & e = m_edges[e_id]; SASSERT(e.get_source() == v); if (!e.is_enabled()) { @@ -1303,7 +1424,8 @@ public: } set_gamma(e, gamma); TRACE("dl_bfs", tout << "processing edge: "; display_edge(tout, e); tout << "gamma: " << gamma << "\n";); - if (gamma.is_zero() && e.get_timestamp() < timestamp) { + if ((gamma.is_one() || (!zero_edge && gamma.is_neg())) && e.get_timestamp() < timestamp) { + // if (gamma.is_zero() && e.get_timestamp() < timestamp) dl_var curr_target = e.get_target(); TRACE("dl_bfs", tout << "curr_target: " << curr_target << ", mark: " << static_cast(bfs_mark[curr_target]) << "\n";); @@ -1477,11 +1599,7 @@ private: } TRACE("diff_logic", tout << "source: " << source << "\n";); - typename edge_id_vector::const_iterator it = edges[source].begin(); - typename edge_id_vector::const_iterator end = edges[source].end(); - - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges[source]) { edge const& e = m_edges[e_id]; if (&e == &e_init) { @@ -1569,11 +1687,9 @@ private: tout << "\n"; }); - typename heap::const_iterator it = state.m_heap.begin(); - typename heap::const_iterator end = state.m_heap.end(); - for (; it != end; ++it) { - SASSERT(m_mark[*it] != DL_PROP_UNMARKED); - m_mark[*it] = DL_PROP_UNMARKED;; + for (auto & s : state.m_heap) { + SASSERT(m_mark[s] != DL_PROP_UNMARKED); + m_mark[s] = DL_PROP_UNMARKED;; } state.m_heap.reset(); SASSERT(marks_are_clear()); diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp new file mode 100644 index 000000000..c58ffb24a --- /dev/null +++ b/src/smt/theory_special_relations.cpp @@ -0,0 +1,905 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + theory_special_relations.cpp + +Abstract: + + Special Relations theory plugin. + +Author: + + Nikolaj Bjorner (nbjorner) 2015-9-16 + Ashutosh Gupta 2016 + +Notes: + +--*/ + +#include + +#include "smt/smt_context.h" +#include "smt/theory_arith.h" +#include "smt/theory_special_relations.h" +#include "smt/smt_solver.h" +#include "solver/solver.h" +#include "ast/reg_decl_plugins.h" +#include "ast/ast_pp.h" + +static constexpr bool KVEC = false; +static constexpr bool HYBRID_SEARCH = false; + +namespace smt { + + void theory_special_relations::relation::push() { + m_scopes.push_back(scope()); + scope& s = m_scopes.back(); + s.m_asserted_atoms_lim = m_asserted_atoms.size(); + s.m_asserted_qhead_old = m_asserted_qhead; + if (!KVEC) { + m_graph.push(); + } + m_ufctx.get_trail_stack().push_scope(); + } + + void theory_special_relations::relation::pop(unsigned num_scopes) { + unsigned new_lvl = m_scopes.size() - num_scopes; + scope& s = m_scopes[new_lvl]; + m_asserted_atoms.shrink(s.m_asserted_atoms_lim); + m_asserted_qhead = s.m_asserted_qhead_old; + m_scopes.shrink(new_lvl); + if (!KVEC) { + m_graph.pop(num_scopes); + } + m_ufctx.get_trail_stack().pop_scope(num_scopes); + } + + void theory_special_relations::relation::ensure_var(theory_var v) { + while ((unsigned)v > m_uf.mk_var()); + if ((unsigned)v >= m_graph.get_num_nodes()) { + m_graph.init_var(v); + } + } + + bool theory_special_relations::relation::new_eq_eh(literal l, theory_var v1, theory_var v2) { + ensure_var(v1); + ensure_var(v2); + literal_vector ls; + ls.push_back(l); + return + m_graph.enable_edge(m_graph.add_edge(v1, v2, s_integer(1), ls)) && + m_graph.enable_edge(m_graph.add_edge(v2, v1, s_integer(1), ls)); + } + + theory_special_relations::theory_special_relations(ast_manager& m): + theory(m.mk_family_id("special_relations")), + m_util(m), m_autil(m) { + params_ref params; + params.set_bool("model", true); + params.set_bool("unsat_core", true); + m_nested_solver = mk_smt_solver(m, params, symbol("QF_LRA")); + m_int_sort = m_autil.mk_real(); + } + + theory_special_relations::~theory_special_relations() { + reset_eh(); + m_nested_solver = nullptr; + } + + theory * theory_special_relations::mk_fresh(context * new_ctx) { + return alloc(theory_special_relations, new_ctx->get_manager()); + } + + static void populate_k_vars(int v, int k, u_map>& map, int& curr_id, ast_manager& m, sort** int_sort) { + int need = !map.contains(v) ? k : k - map[v].size(); + for (auto i = 0; i < need; ++i) { + auto *fd = m.mk_func_decl(symbol(curr_id++), 0, int_sort, *int_sort); + map[v].push_back(m.mk_app(fd, unsigned(0), nullptr)); + } + } + + bool theory_special_relations::internalize_atom(app * atm, bool gate_ctx) { + TRACE("special_relations", tout << mk_pp(atm, get_manager()) << "\n";); + SASSERT(m_util.is_special_relation(atm)); + relation* r = 0; + if (!m_relations.find(atm->get_decl(), r)) { + //todo: push pop may get misaligned if the following alloc happens after push + r = alloc(relation, m_util.get_property(atm), atm->get_decl()); + m_relations.insert(atm->get_decl(), r); + } + context& ctx = get_context(); + expr* arg0 = atm->get_arg(0); + expr* arg1 = atm->get_arg(1); + theory_var v0 = mk_var(arg0); + theory_var v1 = mk_var(arg1); + bool_var v = ctx.mk_bool_var(atm); + ctx.set_var_theory(v, get_id()); + atom* a = alloc(atom, v, *r, v0, v1); + m_atoms.push_back(a); + //std::cerr << "INTER : " << a->v1() << ' ' << a->v2() << ' ' << gate_ctx << "\n"; + m_bool_var2atom.insert(v, a); + return true; + } + + theory_var theory_special_relations::mk_var(expr* e) { + context& ctx = get_context(); + if (!ctx.e_internalized(e)) { + ctx.internalize(e, false); + } + enode * n = ctx.get_enode(e); + theory_var v = n->get_th_var(get_id()); + if (null_theory_var == v) { + v = theory::mk_var(n); + ctx.attach_th_var(n, this, v); + } + return v; + } + + void theory_special_relations::new_eq_eh(theory_var v1, theory_var v2) { + context& ctx = get_context(); + app_ref eq(get_manager()); + app* t1 = get_enode(v1)->get_owner(); + app* t2 = get_enode(v2)->get_owner(); + eq = get_manager().mk_eq(t1, t2); + VERIFY(internalize_atom(eq, false)); + literal l(ctx.get_literal(eq)); + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; !ctx.inconsistent() && it != end; ++it) { + relation& r = *it->m_value; + if (!r.new_eq_eh(l, v1, v2)) { + set_neg_cycle_conflict(r); + break; + } + } + } + + final_check_status theory_special_relations::final_check_eh() { + TRACE("special_relations", tout << "\n";); + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + lbool r = l_true; + for (; it != end && r == l_true; ++it) { + r = final_check(*it->m_value); + } + switch (r) { + case l_undef: + return FC_GIVEUP; + case l_false: + return FC_CONTINUE; + default: + break; + } + it = m_relations.begin(); + bool new_equality = false; + for (; it != end; ++it) { + if (extract_equalities(*it->m_value)) { + new_equality = true; + } + } + if (new_equality) { + return FC_CONTINUE; + } + else { + return FC_DONE; + } + } + + lbool theory_special_relations::final_check_lo(relation& r) { + // all constraints are saturated by propagation. + return l_true; + } + + enode* theory_special_relations::ensure_enode(expr* e) { + context& ctx = get_context(); + if (!ctx.e_internalized(e)) { + ctx.internalize(e, false); + } + enode* n = ctx.get_enode(e); + ctx.mark_as_relevant(n); + return n; + } + + literal theory_special_relations::mk_literal(expr* _e) { + expr_ref e(_e, get_manager()); + context& ctx = get_context(); + ensure_enode(e); + return ctx.get_literal(e); + } + + theory_var theory_special_relations::mk_var(enode* n) { + if (is_attached_to_var(n)) { + return n->get_th_var(get_id()); + } + else { + theory_var v = theory::mk_var(n); + get_context().attach_th_var(n, this, v); + get_context().mark_as_relevant(n); + return v; + } + } + + lbool theory_special_relations::final_check_plo(relation& r) { + // + // ensure that !Rxy -> Ryx between connected components + // (where Rzx & Rzy or Rxz & Ryz for some z) + // + lbool res = l_true; + for (unsigned i = 0; res == l_true && i < r.m_asserted_atoms.size(); ++i) { + atom& a = *r.m_asserted_atoms[i]; + if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { + res = enable(a); + } + } + return res; + } + + lbool theory_special_relations::final_check_to(relation& r) { + uint_set visited, target; + lbool res = l_true; + for (unsigned i = 0; res == l_true && i < r.m_asserted_atoms.size(); ++i) { + atom& a = *r.m_asserted_atoms[i]; + if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { + target.reset(); + theory_var w; + // v2 !<= v1 is asserted + target.insert(a.v2()); + if (r.m_graph.reachable(a.v1(), visited, target, w)) { + // we already have v1 <= v2 + continue; + } + target.reset(); + if (r.m_graph.reachable(a.v2(), target, visited, w)) { + // there is a common successor + // v1 <= w + // v2 <= w + // v1 !<= v2 + // -> v1 <= w & v2 <= w & v1 !<= v2 -> v2 <= v1 + unsigned timestamp = r.m_graph.get_timestamp(); + r.m_explanation.reset(); + r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r); + r.m_graph.find_shortest_reachable_path(a.v2(), w, timestamp, r); + r.m_explanation.push_back(a.explanation()); + literal_vector const& lits = r.m_explanation; + if (!r.m_graph.enable_edge(r.m_graph.add_edge(a.v2(), a.v1(), s_integer(0), lits))) { + set_neg_cycle_conflict(r); + res = l_false; + } + } + // TODO: check if algorithm correctly produces all constraints. + // e.g., if we add an edge, do we have to repeat the loop? + // + } + } + return res; + } + + lbool theory_special_relations::enable(atom& a) { + if (!a.enable()) { + relation& r = a.get_relation(); + set_neg_cycle_conflict(r); + return l_false; + } + else { + return l_true; + } + } + + void theory_special_relations::set_neg_cycle_conflict(relation& r) { + r.m_explanation.reset(); + r.m_graph.traverse_neg_cycle2(false, r); + set_conflict(r); + } + + void theory_special_relations::set_conflict(relation& r) { + literal_vector const& lits = r.m_explanation; + context & ctx = get_context(); + vector params; + ctx.set_conflict( + ctx.mk_justification( + ext_theory_conflict_justification( + get_id(), ctx.get_region(), + lits.size(), lits.c_ptr(), 0, 0, params.size(), params.c_ptr()))); + } + + lbool theory_special_relations::final_check(relation& r) { + // timer m_timer_fc; //for debugging + // static unsigned call_count = 0; + // static double total_call_times = 0.0; + // m_timer_fc.start(); + // call_count++; + + lbool res = propagate(r); + if (res != l_true) return res; + switch (r.m_property) { + case sr_lo: + res = final_check_lo(r); + break; + case sr_po: + res = final_check_po(r); + break; + case sr_plo: + res = final_check_plo(r); + break; + case sr_to: + res = final_check_to(r); + break; + default: + UNREACHABLE(); + res = l_undef; + } + + return res; + } + + bool theory_special_relations::extract_equalities(relation& r) { + bool new_eq = false; + int_vector scc_id; + u_map roots; + context& ctx = get_context(); + r.m_graph.compute_zero_edge_scc(scc_id); + for (unsigned i = 0, j = 0; i < scc_id.size(); ++i) { + if (scc_id[i] == -1) { + continue; + } + enode* n = get_enode(i); + if (roots.find(scc_id[i], j)) { + enode* m = get_enode(j); + if (n->get_root() != m->get_root()) { + new_eq = true; + unsigned timestamp = r.m_graph.get_timestamp(); + r.m_explanation.reset(); + r.m_graph.find_shortest_zero_edge_path(i, j, timestamp, r); + r.m_graph.find_shortest_zero_edge_path(j, i, timestamp, r); + eq_justification js(ctx.mk_justification(theory_axiom_justification(get_id(), ctx.get_region(), r.m_explanation.size(), r.m_explanation.c_ptr()))); + ctx.assign_eq(n, m, js); + } + } + else { + roots.insert(scc_id[i], i); + } + } + return new_eq; + } + + /* + \brief Propagation for piecewise linear orders + */ + lbool theory_special_relations::propagate_plo(atom& a) { + lbool res = l_true; + relation& r = a.get_relation(); + if (a.phase()) { + r.m_uf.merge(a.v1(), a.v2()); + res = enable(a); + } + else if (r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { + res = enable(a); + } + return res; + } + + lbool theory_special_relations::propagate_po(atom& a) { + lbool res = l_true; + relation& r = a.get_relation(); + if (a.phase()) { + r.m_uf.merge(a.v1(), a.v2()); + res = enable(a); + } + return res; + } + + lbool theory_special_relations::final_check_po(relation& r) { + if (!KVEC) { + lbool res = l_true; + for (unsigned i = 0; res == l_true && i < r.m_asserted_atoms.size(); ++i) { + atom& a = *r.m_asserted_atoms[i]; + if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { + // v1 !-> v2 + // find v1 -> v3 -> v4 -> v2 path + r.m_explanation.reset(); + unsigned timestamp = r.m_graph.get_timestamp(); + auto found_path = HYBRID_SEARCH ? + r.m_graph.find_path(a.v1(), a.v2(), timestamp, r) : + r.m_graph.find_shortest_reachable_path(a.v1(), a.v2(), timestamp, r); + if (found_path) { + r.m_explanation.push_back(a.explanation()); + set_conflict(r); + res = l_false; + } + } + } + return res; + } + context& ctx = get_context(); + ast_manager& m = ctx.get_manager(); + + ptr_vector assumptions; + ptr_vector literals; + + int k = 1; + static int curr_id = 100000; + + u_map> map; + lbool res = l_true; + for (atom * ap : r.m_asserted_atoms) { + if (res != l_true) break; + atom a = *ap; + if (a.phase()) { + continue; + // assumptions.push_back(b); + r.m_uf.merge(a.v1(), a.v2()); + } + } + for (atom * ap : r.m_asserted_atoms) { + if (res != l_true) break; + atom a = *ap; + if (a.phase()) + continue; + if (r.m_uf.find(a.v1()) != r.m_uf.find(a.v2())) { + continue; + } + populate_k_vars(a.v1(), k, map, curr_id, m, &m_int_sort); + populate_k_vars(a.v2(), k, map, curr_id, m, &m_int_sort); + + literals.push_back(m_autil.mk_lt(map[a.v1()][0], map[a.v2()][0])); + + auto bool_sort = m.mk_bool_sort(); + auto b_func = m.mk_func_decl(symbol(curr_id++), 0, &bool_sort, bool_sort); + auto b = m.mk_app(b_func, unsigned(0), nullptr); + + auto f = m.mk_implies( b, m.mk_not(literals.back()) ); + m_nested_solver->assert_expr(f); + atom_cache.insert(b->get_id(), &a); + assumptions.push_back(b); + r.m_explanation.reset(); + if (m_nested_solver->check_sat(assumptions.size(), assumptions.c_ptr()) == l_false) { + expr_ref_vector unsat_core(m); + m_nested_solver->get_unsat_core(unsat_core); + for (expr* e : unsat_core) { + atom& a = *atom_cache[e->get_id()]; + r.m_explanation.push_back(a.explanation()); + } + for (auto e : r.m_explanation) { + std::cerr << "EX " << e.hash() << "\n"; + } + set_conflict(r); + res = l_false; + } + assumptions.pop_back(); + } + return res; + } + + lbool theory_special_relations::propagate(relation& r) { + lbool res = l_true; + while (res == l_true && r.m_asserted_qhead < r.m_asserted_atoms.size()) { + atom& a = *r.m_asserted_atoms[r.m_asserted_qhead]; + switch (r.m_property) { + case sr_lo: + res = enable(a); + break; + case sr_plo: + res = propagate_plo(a); + break; + case sr_po: + res = propagate_po(a); + break; + default: + if (a.phase()) { + res = enable(a); + } + break; + } + ++r.m_asserted_qhead; + } + return res; + } + + void theory_special_relations::reset_eh() { + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + m_relations.reset(); + del_atoms(0); + } + + void theory_special_relations::assign_eh(bool_var v, bool is_true) { + TRACE("special_relations", tout << "assign bv" << v << " " << (is_true?" <- true":" <- false") << "\n";); + atom* a = 0; + VERIFY(m_bool_var2atom.find(v, a)); + a->set_phase(is_true); + a->get_relation().m_asserted_atoms.push_back(a); + //std::cerr << "ASSIGN: " << a->v1() << ' ' << a->v2() << "\n"; + } + + void theory_special_relations::push_scope_eh() { + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + it->m_value->push(); + } + m_atoms_lim.push_back(m_atoms.size()); + } + + void theory_special_relations::pop_scope_eh(unsigned num_scopes) { + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + it->m_value->pop(num_scopes); + } + unsigned new_lvl = m_atoms_lim.size() - num_scopes; + del_atoms(m_atoms_lim[new_lvl]); + } + + void theory_special_relations::del_atoms(unsigned old_size) { + atoms::iterator begin = m_atoms.begin() + old_size; + atoms::iterator it = m_atoms.end(); + while (it != begin) { + --it; + atom * a = *it; + m_bool_var2atom.erase(a->var()); + dealloc(a); + } + m_atoms.shrink(old_size); + } + + + void theory_special_relations::collect_statistics(::statistics & st) const { + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + it->m_value->m_graph.collect_statistics(st); + } + } + + model_value_proc * theory_special_relations::mk_value(enode * n, model_generator & mg) { + UNREACHABLE(); + return 0; + } + + void theory_special_relations::ensure_strict(graph& g) { + unsigned sz = g.get_num_edges(); + for (unsigned i = 0; i < sz; ++i) { + if (!g.is_enabled(i)) continue; + if (g.get_weight(i) != s_integer(0)) continue; + dl_var src = g.get_source(i); + dl_var dst = g.get_target(i); + if (get_enode(src)->get_root() == get_enode(dst)->get_root()) continue; + VERIFY(g.enable_edge(g.add_edge(src, dst, s_integer(-2), literal_vector()))); + } + TRACE("special_relations", g.display(tout);); + } + + void theory_special_relations::ensure_tree(graph& g) { + unsigned sz = g.get_num_nodes(); + for (unsigned i = 0; i < sz; ++i) { + int_vector const& edges = g.get_in_edges(i); + for (unsigned j = 0; j < edges.size(); ++j) { + edge_id e1 = edges[j]; + if (g.is_enabled(e1)) { + SASSERT (i == g.get_target(e1)); + dl_var src1 = g.get_source(e1); + for (unsigned k = j + 1; k < edges.size(); ++k) { + edge_id e2 = edges[k]; + if (g.is_enabled(e2)) { + dl_var src2 = g.get_source(e2); + if (get_enode(src1)->get_root() == get_enode(src2)->get_root()) continue; + if (!disconnected(g, src1, src2)) continue; + VERIFY(g.enable_edge(g.add_edge(src1, src2, s_integer(-2), literal_vector()))); + } + } + } + } + } + TRACE("special_relations", g.display(tout);); + } + + bool theory_special_relations::disconnected(graph const& g, dl_var u, dl_var v) const { + s_integer val_u = g.get_assignment(u); + s_integer val_v = g.get_assignment(v); + if (val_u == val_v) return u != v; + if (val_u < val_v) { + std::swap(u, v); + std::swap(val_u, val_v); + } + SASSERT(val_u > val_v); + svector todo; + todo.push_back(u); + while (!todo.empty()) { + u = todo.back(); + todo.pop_back(); + if (u == v) { + return false; + } + SASSERT(g.get_assignment(u) <= val_u); + if (g.get_assignment(u) <= val_v) { + continue; + } + int_vector const& edges = g.get_out_edges(u); + for (unsigned i = 0; i < edges.size(); ++i) { + edge_id e = edges[i]; + if (is_strict_neighbour_edge(g, e)) { + todo.push_back(g.get_target(e)); + } + } + } + return true; + } + + expr_ref theory_special_relations::mk_inj(relation& r, model_generator& mg) { + // context& ctx = get_context(); + ast_manager& m = get_manager(); + r.push(); + ensure_strict(r.m_graph); + func_decl_ref fn(m); + expr_ref result(m); + arith_util arith(m); + sort* const* ty = r.decl()->get_domain(); + fn = m.mk_fresh_func_decl("inj", 1, ty, arith.mk_int()); + unsigned sz = r.m_graph.get_num_nodes(); + func_interp* fi = alloc(func_interp, m, 1); + for (unsigned i = 0; i < sz; ++i) { + s_integer val = r.m_graph.get_assignment(i); + expr* arg = get_enode(i)->get_owner(); + fi->insert_new_entry(&arg, arith.mk_numeral(val.to_rational(), true)); + } + TRACE("special_relations", r.m_graph.display(tout);); + r.pop(1); + fi->set_else(arith.mk_numeral(rational(0), true)); + mg.get_model().register_decl(fn, fi); + result = arith.mk_le(m.mk_app(fn,m.mk_var(0, *ty)), m.mk_app(fn, m.mk_var(1, *ty))); + return result; + } + + expr_ref theory_special_relations::mk_class(relation& r, model_generator& mg) { + //context& ctx = get_context(); + ast_manager& m = get_manager(); + expr_ref result(m); + func_decl_ref fn(m); + arith_util arith(m); + func_interp* fi = alloc(func_interp, m, 1); + sort* const* ty = r.decl()->get_domain(); + fn = m.mk_fresh_func_decl("class", 1, ty, arith.mk_int()); + unsigned sz = r.m_graph.get_num_nodes(); + for (unsigned i = 0; i < sz; ++i) { + unsigned val = r.m_uf.find(i); + expr* arg = get_enode(i)->get_owner(); + fi->insert_new_entry(&arg, arith.mk_numeral(rational(val), true)); + } + fi->set_else(arith.mk_numeral(rational(0), true)); + mg.get_model().register_decl(fn, fi); + result = m.mk_eq(m.mk_app(fn, m.mk_var(0, *ty)), m.mk_app(fn, m.mk_var(1, *ty))); + return result; + } + + expr_ref theory_special_relations::mk_interval(relation& r, model_generator& mg, unsigned_vector & lo, unsigned_vector& hi) { + graph const& g = r.m_graph; + //context& ctx = get_context(); + ast_manager& m = get_manager(); + expr_ref result(m); + func_decl_ref lofn(m), hifn(m); + arith_util arith(m); + func_interp* lofi = alloc(func_interp, m, 1); + func_interp* hifi = alloc(func_interp, m, 1); + sort* const* ty = r.decl()->get_domain(); + lofn = m.mk_fresh_func_decl("lo", 1, ty, arith.mk_int()); + hifn = m.mk_fresh_func_decl("hi", 1, ty, arith.mk_int()); + unsigned sz = g.get_num_nodes(); + for (unsigned i = 0; i < sz; ++i) { + expr* arg = get_enode(i)->get_owner(); + lofi->insert_new_entry(&arg, arith.mk_numeral(rational(lo[i]), true)); + hifi->insert_new_entry(&arg, arith.mk_numeral(rational(hi[i]), true)); + } + lofi->set_else(arith.mk_numeral(rational(0), true)); + hifi->set_else(arith.mk_numeral(rational(0), true)); + mg.get_model().register_decl(lofn, lofi); + mg.get_model().register_decl(hifn, hifi); + result = m.mk_and(arith.mk_le(m.mk_app(lofn, m.mk_var(0, *ty)), m.mk_app(lofn, m.mk_var(1, *ty))), + arith.mk_le(m.mk_app(hifn, m.mk_var(1, *ty)), m.mk_app(hifn, m.mk_var(0, *ty)))); + return result; + } + + void theory_special_relations::init_model_lo(relation& r, model_generator& m) { + expr_ref inj = mk_inj(r, m); + func_interp* fi = alloc(func_interp, get_manager(), 2); + fi->set_else(inj); + m.get_model().register_decl(r.decl(), fi); + } + + void theory_special_relations::init_model_plo(relation& r, model_generator& m) { + expr_ref inj = mk_inj(r, m); + expr_ref cls = mk_class(r, m); + func_interp* fi = alloc(func_interp, get_manager(), 2); + fi->set_else(get_manager().mk_and(inj, cls)); + m.get_model().register_decl(r.decl(), fi); + } + + void theory_special_relations::init_model_po(relation& r, model_generator& mg) { + // NOT_IMPLEMENTED_YET(); + } + + /** + \brief map each node to an interval of numbers, such that + the children are proper sub-intervals. + Then the <= relation becomes interval containment. + + 1. For each vertex, count the number of nodes below it in the transitive closure. + Store the result in num_children. + 2. Identify each root. + 3. Process children, assigning unique (and disjoint) intervals. + 4. Extract interpretation. + + + */ + + void theory_special_relations::init_model_to(relation& r, model_generator& mg) { + unsigned_vector num_children, lo, hi; + graph const& g = r.m_graph; + r.push(); + ensure_strict(r.m_graph); + ensure_tree(r.m_graph); + count_children(g, num_children); + assign_interval(g, num_children, lo, hi); + expr_ref iv = mk_interval(r, mg, lo, hi); + r.pop(1); + func_interp* fi = alloc(func_interp, get_manager(), 2); + fi->set_else(iv); + mg.get_model().register_decl(r.decl(), fi); + } + + bool theory_special_relations::is_neighbour_edge(graph const& g, edge_id edge) const { + CTRACE("special_relations_verbose", g.is_enabled(edge), + tout << edge << ": " << g.get_source(edge) << " " << g.get_target(edge) << " "; + tout << (g.get_assignment(g.get_source(edge)) - g.get_assignment(g.get_target(edge))) << "\n";); + + return + g.is_enabled(edge) && + g.get_assignment(g.get_source(edge)) - g.get_assignment(g.get_target(edge)) == s_integer(1); + } + + bool theory_special_relations::is_strict_neighbour_edge(graph const& g, edge_id e) const { + return is_neighbour_edge(g, e) && g.get_weight(e) != s_integer(0); + } + + void theory_special_relations::count_children(graph const& g, unsigned_vector& num_children) { + unsigned sz = g.get_num_nodes(); + svector nodes; + num_children.resize(sz, 0); + svector processed(sz, false); + for (unsigned i = 0; i < sz; ++i) nodes.push_back(i); + while (!nodes.empty()) { + dl_var v = nodes.back(); + if (processed[v]) { + nodes.pop_back(); + continue; + } + unsigned nc = 1; + bool all_p = true; + int_vector const& edges = g.get_out_edges(v); + for (unsigned i = 0; i < edges.size(); ++i) { + edge_id e = edges[i]; + if (is_strict_neighbour_edge(g, e)) { + dl_var dst = g.get_target(e); + TRACE("special_relations", tout << v << " -> " << dst << "\n";); + if (!processed[dst]) { + all_p = false; + nodes.push_back(dst); + } + nc += num_children[dst]; + } + } + if (all_p) { + nodes.pop_back(); + num_children[v] = nc; + processed[v] = true; + } + } + TRACE("special_relations", + for (unsigned i = 0; i < sz; ++i) { + tout << i << ": " << num_children[i] << "\n"; + }); + } + + void theory_special_relations::assign_interval(graph const& g, unsigned_vector const& num_children, unsigned_vector& lo, unsigned_vector& hi) { + svector nodes; + unsigned sz = g.get_num_nodes(); + lo.resize(sz, 0); + hi.resize(sz, 0); + unsigned offset = 0; + for (unsigned i = 0; i < sz; ++i) { + bool is_root = true; + int_vector const& edges = g.get_in_edges(i); + for (unsigned j = 0; is_root && j < edges.size(); ++j) { + is_root = !g.is_enabled(edges[j]); + } + if (is_root) { + lo[i] = offset; + hi[i] = offset + num_children[i] - 1; + offset = hi[i] + 1; + nodes.push_back(i); + } + } + while (!nodes.empty()) { + dl_var v = nodes.back(); + int_vector const& edges = g.get_out_edges(v); + unsigned l = lo[v]; + unsigned h = hi[v]; + (void)h; + nodes.pop_back(); + for (unsigned i = 0; i < edges.size(); ++i) { + SASSERT(l <= h); + if (is_strict_neighbour_edge(g, edges[i])) { + dl_var dst = g.get_target(edges[i]); + lo[dst] = l; + hi[dst] = l + num_children[dst] - 1; + l = hi[dst] + 1; + nodes.push_back(dst); + } + } + SASSERT(l == h); + } + } + + void theory_special_relations::init_model(model_generator & m) { + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + switch (it->m_value->m_property) { + case sr_lo: + init_model_lo(*it->m_value, m); + break; + case sr_plo: + init_model_plo(*it->m_value, m); + break; + case sr_to: + init_model_to(*it->m_value, m); + break; + case sr_po: + init_model_po(*it->m_value, m); + break; + default: + UNREACHABLE(); //ASHU: added to remove warning! Should be supported! + } + } + } + + void theory_special_relations::display(std::ostream & out) const { + if (m_relations.empty()) return; + out << "Theory Special Relations\n"; + display_var2enode(out); + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + out << mk_pp(it->m_value->decl(), get_manager()) << ":\n"; + it->m_value->m_graph.display(out); + it->m_value->m_uf.display(out); + for (unsigned i = 0; i < it->m_value->m_asserted_atoms.size(); ++i){ + atom& a = *it->m_value->m_asserted_atoms[i]; + display_atom( out, a ); + } + } + } + + void theory_special_relations::collect_asserted_po_atoms( vector< std::pair >& atoms) const { + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + relation& r = *(it->m_value ); + if( r.m_property != sr_po ) continue; + // SASSERT( r.m_asserted_qhead == r.m_asserted_atoms.size() ); + for (unsigned i = 0; i < r.m_asserted_atoms.size(); ++i) { + atom& a = *r.m_asserted_atoms[i]; + atoms.push_back( std::make_pair(a.var(),a.phase()) ); + } + } + } + + void theory_special_relations::display_atom( std::ostream & out, atom& a ) const { + context& ctx = get_context(); + expr* e = ctx.bool_var2expr( a.var() ); + if( !a.phase() ) out << "(not "; + out << mk_pp( e, get_manager()); + if( !a.phase() ) out << ")"; + out << "\n"; + } + + void theory_special_relations::display_atom( atom& a) const { + display_atom( std::cerr, a); + } + +} diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h new file mode 100644 index 000000000..dbb339d3c --- /dev/null +++ b/src/smt/theory_special_relations.h @@ -0,0 +1,198 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + theory_special_relations.h + +Abstract: + + Special Relations theory plugin. + +Author: + + Nikolaj Bjorner (nbjorner) 2015-9-16 + +Notes: + +--*/ + +#include "ast/special_relations_decl_plugin.h" +#include "smt/smt_theory.h" +#include "smt/theory_diff_logic.h" +#include "util/union_find.h" +#include "solver/solver.h" + +#ifndef THEORY_SPECIAL_RELATIONS_H_ +#define THEORY_SPECIAL_RELATIONS_H_ + +namespace smt { + class theory_special_relations : public theory { + + + struct relation; + + class atom { + bool_var m_bvar; + relation& m_relation; + bool m_phase; + theory_var m_v1; + theory_var m_v2; + edge_id m_pos; + edge_id m_neg; + public: + atom(bool_var b, relation& r, theory_var v1, theory_var v2): + m_bvar(b), + m_relation(r), + m_phase(true), + m_v1(v1), + m_v2(v2) + { + r.ensure_var(v1); + r.ensure_var(v2); + literal_vector ls; + ls.push_back(literal(b, false)); + m_pos = r.m_graph.add_edge(v1, v2, s_integer(1), ls); // v2 <= v1 + ls[0] = literal(b, true); + m_neg = r.m_graph.add_edge(v2, v1, s_integer(-2), ls); // v1 <= v2 - 1 + } + bool_var var() const { return m_bvar;} + relation& get_relation() const { return m_relation; } + bool phase() { return m_phase; } + void set_phase(bool b) { m_phase = b; } + theory_var v1() { return m_v1; } + theory_var v2() { return m_v2; } + literal explanation() { return literal(m_bvar, !m_phase); } + bool enable() { + edge_id edge = m_phase?m_pos:m_neg; + return m_relation.m_graph.enable_edge(edge); + } + }; + typedef ptr_vector atoms; + + struct scope { + unsigned m_asserted_atoms_lim; + unsigned m_asserted_qhead_old; + }; + + struct int_ext : public sidl_ext { + typedef literal_vector explanation; + }; + typedef dl_graph graph; + + typedef union_find union_find_t; + + struct relation { + sr_property m_property; + func_decl* m_decl; + atoms m_asserted_atoms; // set of asserted atoms + unsigned m_asserted_qhead; + svector m_scopes; + graph m_graph; + union_find_default_ctx m_ufctx; + union_find_t m_uf; + literal_vector m_explanation; + + relation(sr_property p, func_decl* d): m_property(p), m_decl(d), m_asserted_qhead(0), m_uf(m_ufctx) {} + + func_decl* decl() { return m_decl; } + void push(); + void pop(unsigned num_scopes); + void ensure_var(theory_var v); + bool new_eq_eh(literal l, theory_var v1, theory_var v2); + void operator()(literal_vector const & ex) { + m_explanation.append(ex); + } + void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {} + }; + + + + + typedef u_map bool_var2atom; + + special_relations_util m_util; + arith_util m_autil; + + atoms m_atoms; + unsigned_vector m_atoms_lim; + obj_map m_relations; + bool_var2atom m_bool_var2atom; + + scoped_ptr m_nested_solver; + struct atom_hash { + size_t operator()(atom a) const { + return std::hash()(a.v1()) ^ std::hash()(a.v2()) ^ std::hash()(a.phase()); + } + }; + u_map expr_cache; + u_map atom_cache; + sort* m_int_sort; + + void del_atoms(unsigned old_size); + lbool final_check(relation& r); + lbool final_check_po(relation& r); + lbool final_check_lo(relation& r); + lbool final_check_plo(relation& r); + lbool final_check_to(relation& r); + lbool propagate(relation& r); + lbool enable(atom& a); + bool extract_equalities(relation& r); + void set_neg_cycle_conflict(relation& r); + void set_conflict(relation& r); + lbool propagate_plo(atom& a); + lbool propagate_po(atom& a); //ASHU: added to modify po solving + theory_var mk_var(expr* e); + void count_children(graph const& g, unsigned_vector& num_children); + void ensure_strict(graph& g); + void ensure_tree(graph& g); + void assign_interval(graph const& g, unsigned_vector const& num_children, unsigned_vector& lo, unsigned_vector& hi); + expr_ref mk_inj(relation& r, model_generator& m); + expr_ref mk_class(relation& r, model_generator& m); + expr_ref mk_interval(relation& r, model_generator& mg, unsigned_vector & lo, unsigned_vector& hi); + void init_model_lo(relation& r, model_generator& m); + void init_model_to(relation& r, model_generator& m); + void init_model_po(relation& r, model_generator& m); + void init_model_plo(relation& r, model_generator& m); + bool is_neighbour_edge(graph const& g, edge_id id) const; + bool is_strict_neighbour_edge(graph const& g, edge_id id) const; + bool disconnected(graph const& g, dl_var u, dl_var v) const; + + public: + theory_special_relations(ast_manager& m); + virtual ~theory_special_relations(); + + virtual theory * mk_fresh(context * new_ctx); + virtual bool internalize_atom(app * atom, bool gate_ctx); + virtual bool internalize_term(app * term) { UNREACHABLE(); return false; } + virtual void new_eq_eh(theory_var v1, theory_var v2); + virtual void new_diseq_eh(theory_var v1, theory_var v2) {} + virtual bool use_diseqs() const { return false; } + virtual bool build_models() const { return true; } + virtual final_check_status final_check_eh(); + virtual void reset_eh(); + virtual void assign_eh(bool_var v, bool is_true); + virtual void init_search_eh() {} + virtual void push_scope_eh(); + virtual void pop_scope_eh(unsigned num_scopes); + virtual void restart_eh() {} + virtual void collect_statistics(::statistics & st) const; + virtual model_value_proc * mk_value(enode * n, model_generator & mg); + virtual void init_model(model_generator & m); + virtual bool can_propagate() { return false; } + virtual void propagate() {} + virtual void display(std::ostream & out) const; + + literal mk_literal(expr* _e); + enode* ensure_enode(expr* e); + theory_var mk_var(enode* n); + + //BEGIN: ASHU + void collect_asserted_po_atoms( vector< std::pair >& atoms) const; + void display_atom( std::ostream & out, atom& a) const; + void display_atom( atom& a) const; + //END: ASHU + }; +} + +#endif From 0fa4aaa62526da0bd49e3e92fdb043b2399486f6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 19:10:30 -0700 Subject: [PATCH 075/156] use for pattern Signed-off-by: Nikolaj Bjorner --- src/smt/diff_logic.h | 127 ++++++--------------------- src/smt/theory_special_relations.cpp | 10 +-- 2 files changed, 34 insertions(+), 103 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index f3ce7fb13..5ea27d4c9 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -228,10 +228,7 @@ class dl_graph { int n = m_out_edges.size(); for (dl_var id = 0; id < n; id++) { const edge_id_vector & e_ids = m_out_edges[id]; - edge_id_vector::const_iterator it = e_ids.begin(); - edge_id_vector::const_iterator end = e_ids.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : e_ids) { SASSERT(static_cast(e_id) <= m_edges.size()); const edge & e = m_edges[e_id]; SASSERT(e.get_source() == id); @@ -239,10 +236,7 @@ class dl_graph { } for (dl_var id = 0; id < n; id++) { const edge_id_vector & e_ids = m_in_edges[id]; - edge_id_vector::const_iterator it = e_ids.begin(); - edge_id_vector::const_iterator end = e_ids.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : e_ids) { SASSERT(static_cast(e_id) <= m_edges.size()); const edge & e = m_edges[e_id]; SASSERT(e.get_target() == id); @@ -337,10 +331,8 @@ private: } void reset_marks() { - dl_var_vector::iterator it = m_visited.begin(); - dl_var_vector::iterator end = m_visited.end(); - for (; it != end; ++it) { - m_mark[*it] = DL_UNMARKED; + for (dl_var v : m_visited) { + m_mark[v] = DL_UNMARKED; } m_visited.reset(); } @@ -392,10 +384,7 @@ private: return false; } - typename edge_id_vector::iterator it = m_out_edges[source].begin(); - typename edge_id_vector::iterator end = m_out_edges[source].end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : m_out_edges[source]) { edge & e = m_edges[e_id]; SASSERT(e.get_source() == source); if (!e.is_enabled()) { @@ -445,10 +434,7 @@ private: dl_var src = e->get_source(); dl_var dst = e->get_target(); numeral w = e->get_weight(); - typename edge_id_vector::iterator it = m_out_edges[src].begin(); - typename edge_id_vector::iterator end = m_out_edges[src].end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : m_out_edges[src]) { edge const& e2 = m_edges[e_id]; if (e2.get_target() == dst && e2.is_enabled() && // or at least not be inconsistent with current choices @@ -598,10 +584,7 @@ public: // // search for edges that can reduce size of negative cycle. // - typename edge_id_vector::iterator it = m_out_edges[src].begin(); - typename edge_id_vector::iterator end = m_out_edges[src].end(); - for (; it != end; ++it) { - edge_id e_id2 = *it; + for (edge_id e_id2 : m_out_edges[src]) { edge const& e2 = m_edges[e_id2]; dl_var src2 = e2.get_target(); if (e_id2 == e_id || !e2.is_enabled()) { @@ -905,10 +888,8 @@ public: SASSERT(is_feasible()); if (!m_assignment[v].is_zero()) { numeral k = m_assignment[v]; - typename assignment::iterator it = m_assignment.begin(); - typename assignment::iterator end = m_assignment.end(); - for (; it != end; ++it) { - *it -= k; + for (auto& a : m_assignment) { + a -= k; } SASSERT(is_feasible()); } @@ -963,10 +944,7 @@ public: void display_agl(std::ostream & out) const { uint_set vars; - typename edges::const_iterator it = m_edges.begin(); - typename edges::const_iterator end = m_edges.end(); - for (; it != end; ++it) { - edge const& e = *it; + for (edge const& e : m_edges) { if (e.is_enabled()) { vars.insert(e.get_source()); vars.insert(e.get_target()); @@ -980,9 +958,7 @@ public: out << "\"" << v << "\" [label=\"" << v << ":" << m_assignment[v] << "\"]\n"; } } - it = m_edges.begin(); - for (; it != end; ++it) { - edge const& e = *it; + for (edge const& e : m_edges) { if (e.is_enabled()) { out << "\"" << e.get_source() << "\"->\"" << e.get_target() << "\"[label=\"" << e.get_weight() << "\"]\n"; } @@ -998,10 +974,7 @@ public: } void display_edges(std::ostream & out) const { - typename edges::const_iterator it = m_edges.begin(); - typename edges::const_iterator end = m_edges.end(); - for (; it != end; ++it) { - edge const& e = *it; + for (edge const& e : m_edges) { if (e.is_enabled()) { display_edge(out, e); } @@ -1030,11 +1003,8 @@ public: // If there is such edge, then the weight is stored in w and the explanation in ex. bool get_edge_weight(dl_var source, dl_var target, numeral & w, explanation & ex) { edge_id_vector & edges = m_out_edges[source]; - typename edge_id_vector::iterator it = edges.begin(); - typename edge_id_vector::iterator end = edges.end(); bool found = false; - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges) { edge & e = m_edges[e_id]; if (e.is_enabled() && e.get_target() == target && (!found || e.get_weight() < w)) { w = e.get_weight(); @@ -1049,12 +1019,10 @@ public: // If there is such edge, return its edge_id in parameter id. bool get_edge_id(dl_var source, dl_var target, edge_id & id) const { edge_id_vector const & edges = m_out_edges[source]; - typename edge_id_vector::const_iterator it = edges.begin(); - typename edge_id_vector::const_iterator end = edges.end(); - for (; it != end; ++it) { - id = *it; - edge const & e = m_edges[id]; + for (edge_id e_id : edges) { + edge const & e = m_edges[e_id]; if (e.get_target() == target) { + id = e_id; return true; } } @@ -1068,18 +1036,14 @@ public: void get_neighbours_undirected(dl_var current, svector & neighbours) { neighbours.reset(); edge_id_vector & out_edges = m_out_edges[current]; - typename edge_id_vector::iterator it = out_edges.begin(), end = out_edges.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : out_edges) { edge & e = m_edges[e_id]; SASSERT(e.get_source() == current); dl_var neighbour = e.get_target(); neighbours.push_back(neighbour); } edge_id_vector & in_edges = m_in_edges[current]; - typename edge_id_vector::iterator it2 = in_edges.begin(), end2 = in_edges.end(); - for (; it2 != end2; ++it2) { - edge_id e_id = *it2; + for (edge_id e_id : in_edges) { edge & e = m_edges[e_id]; SASSERT(e.get_target() == current); dl_var neighbour = e.get_source(); @@ -1162,10 +1126,7 @@ public: template void enumerate_edges(dl_var source, dl_var target, Functor& f) { edge_id_vector & edges = m_out_edges[source]; - typename edge_id_vector::iterator it = edges.begin(); - typename edge_id_vector::iterator end = edges.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges) { edge const& e = m_edges[e_id]; if (e.get_target() == target) { f(e.get_weight(), e.get_explanation()); @@ -1222,10 +1183,7 @@ public: m_roots.push_back(v); numeral gamma; edge_id_vector & edges = m_out_edges[v]; - typename edge_id_vector::iterator it = edges.begin(); - typename edge_id_vector::iterator end = edges.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges) { edge & e = m_edges[e_id]; if (!e.is_enabled()) { continue; @@ -1278,10 +1236,7 @@ public: for (unsigned i = 0; i < succ.size(); ++i) { v = succ[i]; edge_id_vector & edges = m_out_edges[v]; - typename edge_id_vector::iterator it = edges.begin(); - typename edge_id_vector::iterator end = edges.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges) { edge & e = m_edges[e_id]; if (!e.is_enabled()) { continue; @@ -1708,11 +1663,8 @@ private: for (unsigned i = 0; i < src.m_visited.size(); ++i) { dl_var c = src.m_visited[i]; - typename edge_id_vector::const_iterator it = edges[c].begin(); - typename edge_id_vector::const_iterator end = edges[c].end(); numeral n1 = n0 + src.m_delta[c] - m_assignment[c]; - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges[c]) { edge const& e1 = m_edges[e_id]; SASSERT(c == e1.get_source()); if (e1.is_enabled()) { @@ -1760,13 +1712,10 @@ public: edge_id_vector& out_edges = m_out_edges[src]; edge_id_vector& in_edges = m_in_edges[dst]; numeral w = e1.get_weight(); - typename edge_id_vector::const_iterator it, end; if (out_edges.size() < in_edges.size()) { - end = out_edges.end(); - for (it = out_edges.begin(); it != end; ++it) { + for (edge_id e_id : out_edges) { ++m_stats.m_implied_literal_cost; - edge_id e_id = *it; edge const& e2 = m_edges[e_id]; if (e_id != id && !e2.is_enabled() && e2.get_target() == dst && e2.get_weight() >= w) { subsumed.push_back(e_id); @@ -1775,10 +1724,8 @@ public: } } else { - end = in_edges.end(); - for (it = in_edges.begin(); it != end; ++it) { + for (edge_id e_id : in_edges) { ++m_stats.m_implied_literal_cost; - edge_id e_id = *it; edge const& e2 = m_edges[e_id]; if (e_id != id && !e2.is_enabled() && e2.get_source() == src && e2.get_weight() >= w) { subsumed.push_back(e_id); @@ -1812,20 +1759,14 @@ public: find_subsumed1(id, subsumed); typename edge_id_vector::const_iterator it, end, it3, end3; - it = m_in_edges[src].begin(); - end = m_in_edges[src].end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : m_in_edges[src]) { edge const& e2 = m_edges[e_id]; if (!e2.is_enabled() || e2.get_source() == dst) { continue; } w2 = e2.get_weight() + w; - it3 = m_out_edges[e2.get_source()].begin(); - end3 = m_out_edges[e2.get_source()].end(); - for (; it3 != end3; ++it3) { + for (edge_id e_id3 : m_out_edges[e2.get_source()]) { ++m_stats.m_implied_literal_cost; - edge_id e_id3 = *it3; edge const& e3 = m_edges[e_id3]; if (e3.is_enabled() || e3.get_target() != dst) { continue; @@ -1836,21 +1777,15 @@ public: } } } - it = m_out_edges[dst].begin(); - end = m_out_edges[dst].end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : m_out_edges[dst]) { edge const& e2 = m_edges[e_id]; if (!e2.is_enabled() || e2.get_target() == src) { continue; } w2 = e2.get_weight() + w; - it3 = m_in_edges[e2.get_target()].begin(); - end3 = m_in_edges[e2.get_target()].end(); - for (; it3 != end3; ++it3) { + for (edge_id e_id2 : m_in_edges[e2.get_target()]) { ++m_stats.m_implied_literal_cost; - edge_id e_id3 = *it3; edge const& e3 = m_edges[e_id3]; if (e3.is_enabled() || e3.get_source() != src) { continue; @@ -1899,11 +1834,7 @@ public: m_mark[v] = DL_PROCESSED; TRACE("diff_logic", tout << v << "\n";); - typename edge_id_vector::iterator it = m_out_edges[v].begin(); - typename edge_id_vector::iterator end = m_out_edges[v].end(); - - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : m_out_edges[v]) { edge const& e = m_edges[e_id]; if (!e.is_enabled() || e.get_timestamp() > timestamp) { continue; diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index c58ffb24a..a5a6ce13a 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -92,10 +92,10 @@ namespace smt { return alloc(theory_special_relations, new_ctx->get_manager()); } - static void populate_k_vars(int v, int k, u_map>& map, int& curr_id, ast_manager& m, sort** int_sort) { + static void populate_k_vars(int v, int k, u_map>& map, int& curr_id, ast_manager& m, sort* int_sort) { int need = !map.contains(v) ? k : k - map[v].size(); for (auto i = 0; i < need; ++i) { - auto *fd = m.mk_func_decl(symbol(curr_id++), 0, int_sort, *int_sort); + auto *fd = m.mk_const_decl(symbol(curr_id++), int_sort); map[v].push_back(m.mk_app(fd, unsigned(0), nullptr)); } } @@ -438,13 +438,13 @@ namespace smt { if (r.m_uf.find(a.v1()) != r.m_uf.find(a.v2())) { continue; } - populate_k_vars(a.v1(), k, map, curr_id, m, &m_int_sort); - populate_k_vars(a.v2(), k, map, curr_id, m, &m_int_sort); + populate_k_vars(a.v1(), k, map, curr_id, m, m_int_sort); + populate_k_vars(a.v2(), k, map, curr_id, m, m_int_sort); literals.push_back(m_autil.mk_lt(map[a.v1()][0], map[a.v2()][0])); auto bool_sort = m.mk_bool_sort(); - auto b_func = m.mk_func_decl(symbol(curr_id++), 0, &bool_sort, bool_sort); + auto b_func = m.mk_const_decl(symbol(curr_id++), bool_sort); auto b = m.mk_app(b_func, unsigned(0), nullptr); auto f = m.mk_implies( b, m.mk_not(literals.back()) ); From 4603c647a7bbf2d9dfa8bf3f02093a2de4a31a20 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 19:21:54 -0700 Subject: [PATCH 076/156] use override Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 4 --- src/smt/theory_special_relations.h | 50 +++++++++++++--------------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index a5a6ce13a..e1a42403d 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -898,8 +898,4 @@ namespace smt { out << "\n"; } - void theory_special_relations::display_atom( atom& a) const { - display_atom( std::cerr, a); - } - } diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index dbb339d3c..90b6a7bbf 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -160,38 +160,36 @@ namespace smt { public: theory_special_relations(ast_manager& m); - virtual ~theory_special_relations(); + ~theory_special_relations() override; - virtual theory * mk_fresh(context * new_ctx); - virtual bool internalize_atom(app * atom, bool gate_ctx); - virtual bool internalize_term(app * term) { UNREACHABLE(); return false; } - virtual void new_eq_eh(theory_var v1, theory_var v2); - virtual void new_diseq_eh(theory_var v1, theory_var v2) {} - virtual bool use_diseqs() const { return false; } - virtual bool build_models() const { return true; } - virtual final_check_status final_check_eh(); - virtual void reset_eh(); - virtual void assign_eh(bool_var v, bool is_true); - virtual void init_search_eh() {} - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); - virtual void restart_eh() {} - virtual void collect_statistics(::statistics & st) const; - virtual model_value_proc * mk_value(enode * n, model_generator & mg); - virtual void init_model(model_generator & m); - virtual bool can_propagate() { return false; } - virtual void propagate() {} - virtual void display(std::ostream & out) const; + theory * mk_fresh(context * new_ctx) override; + bool internalize_atom(app * atom, bool gate_ctx) override; + bool internalize_term(app * term) override { UNREACHABLE(); return false; } + void new_eq_eh(theory_var v1, theory_var v2) override; + void new_diseq_eh(theory_var v1, theory_var v2) override {} + bool use_diseqs() const override { return false; } + bool build_models() const override { return true; } + final_check_status final_check_eh() override; + void reset_eh() override; + void assign_eh(bool_var v, bool is_true) override; + void init_search_eh() override {} + void push_scope_eh() override; + void pop_scope_eh(unsigned num_scopes) override; + void restart_eh() override {} + void collect_statistics(::statistics & st) const override; + model_value_proc * mk_value(enode * n, model_generator & mg) override; + void init_model(model_generator & m) override; + bool can_propagate() override { return false; } + void propagate() override {} + void display(std::ostream & out) const override; literal mk_literal(expr* _e); enode* ensure_enode(expr* e); theory_var mk_var(enode* n); - //BEGIN: ASHU - void collect_asserted_po_atoms( vector< std::pair >& atoms) const; - void display_atom( std::ostream & out, atom& a) const; - void display_atom( atom& a) const; - //END: ASHU + void collect_asserted_po_atoms( vector< std::pair >& atoms) const; + void display_atom( std::ostream & out, atom& a) const; + }; } From ceb4c985bfdf2372860f27868262417cf5182a05 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 20:21:22 -0700 Subject: [PATCH 077/156] tidy Signed-off-by: Nikolaj Bjorner --- src/smt/diff_logic.h | 91 ++++++++++++++---------------- src/smt/theory_special_relations.h | 28 ++++----- 2 files changed, 55 insertions(+), 64 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 5ea27d4c9..29b1050df 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -324,10 +324,11 @@ private: // Store in gamma the normalized weight. The normalized weight is given // by the formula // m_assignment[e.get_source()] - m_assignment[e.get_target()] + e.get_weight() - void set_gamma(const edge & e, numeral & gamma) { + numeral& set_gamma(const edge & e, numeral & gamma) { gamma = m_assignment[e.get_source()]; gamma -= m_assignment[e.get_target()]; gamma += e.get_weight(); + return gamma; } void reset_marks() { @@ -373,7 +374,7 @@ private: TRACE("arith", tout << id << "\n";); dl_var source = target; - for(;;) { + while (true) { ++m_stats.m_propagation_cost; if (m_mark[root] != DL_UNMARKED) { // negative cycle was found @@ -680,8 +681,14 @@ private: int m_total_count = 0; int m_run_counter = -1; svector m_hybrid_visited, m_hybrid_parent; + + bool is_connected(numeral const& gamma, bool zero_edge, edge const& e, unsigned timestamp) const { + return (gamma.is_one() || (!zero_edge && gamma.is_neg())) && e.get_timestamp() < timestamp; + } + public: + template bool find_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { auto zero_edge = true; @@ -713,13 +720,12 @@ public: continue; } set_gamma(e, gamma); - if ((gamma.is_one() || (!zero_edge && gamma.is_neg())) - && e.get_timestamp() < timestamp) { + if (is_connected(gamma, zero_edge, e, timestamp)) { dl_var curr_target = e.get_target(); if (curr_target == target) { f(e.get_explanation()); m_freq_hybrid[e_id]++; - for (;;) { + while (true) { int p = m_hybrid_parent[v]; if (p == -1) return true; @@ -981,12 +987,12 @@ public: } } - void display_edge(std::ostream & out, edge_id id) const { - display_edge(out, m_edges[id]); + std::ostream& display_edge(std::ostream & out, edge_id id) const { + return display_edge(out, m_edges[id]); } - void display_edge(std::ostream & out, const edge & e) const { - out << e.get_explanation() << " (<= (- $" << e.get_target() << " $" << e.get_source() << ") " << e.get_weight() << ") " << e.get_timestamp() << "\n"; + std::ostream& display_edge(std::ostream & out, const edge & e) const { + return out << e.get_explanation() << " (<= (- $" << e.get_target() << " $" << e.get_source() << ") " << e.get_weight() << ") " << e.get_timestamp() << "\n"; } template @@ -1233,17 +1239,11 @@ public: m_dfs_time[v] = 0; succ.push_back(v); numeral gamma; - for (unsigned i = 0; i < succ.size(); ++i) { - v = succ[i]; - edge_id_vector & edges = m_out_edges[v]; - for (edge_id e_id : edges) { - edge & e = m_edges[e_id]; - if (!e.is_enabled()) { - continue; - } - SASSERT(e.get_source() == v); - set_gamma(e, gamma); - if (gamma.is_zero()) { + for (dl_var w : succ) { + for (edge_id e_id : m_out_edges[w]) { + edge & e = m_edges[e_id]; + if (e.is_enabled() && set_gamma(e, gamma).is_zero()) { + SASSERT(e.get_source() == w); dl_var target = e.get_target(); if (m_dfs_time[target] == -1) { succ.push_back(target); @@ -1334,40 +1334,37 @@ private: m_edge_id(e) { } }; - + public: // Find the shortest path from source to target using (normalized) zero edges with timestamp less than the given timestamp. // The functor f is applied on every explanation attached to the edges in the shortest path. // Return true if the path exists, false otherwise. - - - // Return true if the path exists, false otherwise. - template - bool find_shortest_zero_edge_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { - return find_shortest_path_aux(source, target, timestamp, f, true); - } + + + // Return true if the path exists, false otherwise. + template + bool find_shortest_zero_edge_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { + return find_shortest_path_aux(source, target, timestamp, f, true); + } template bool find_shortest_reachable_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { return find_shortest_path_aux(source, target, timestamp, f, false); } - template bool find_shortest_path_aux(dl_var source, dl_var target, unsigned timestamp, Functor & f, bool zero_edge) { svector bfs_todo; - svector bfs_mark; + svector bfs_mark; bfs_mark.resize(m_assignment.size(), false); bfs_todo.push_back(bfs_elem(source, -1, null_edge_id)); bfs_mark[source] = true; - unsigned m_head = 0; numeral gamma; - while (m_head < bfs_todo.size()) { - bfs_elem & curr = bfs_todo[m_head]; - int parent_idx = m_head; - m_head++; + for (unsigned head = 0; head < bfs_todo.size(); ++head) { + bfs_elem & curr = bfs_todo[head]; + int parent_idx = head; dl_var v = curr.m_var; TRACE("dl_bfs", tout << "processing: " << v << "\n";); edge_id_vector & edges = m_out_edges[v]; @@ -1378,18 +1375,16 @@ public: continue; } set_gamma(e, gamma); - TRACE("dl_bfs", tout << "processing edge: "; display_edge(tout, e); tout << "gamma: " << gamma << "\n";); - if ((gamma.is_one() || (!zero_edge && gamma.is_neg())) && e.get_timestamp() < timestamp) { - // if (gamma.is_zero() && e.get_timestamp() < timestamp) + TRACE("dl_bfs", display_edge(tout << "processing edge: ", e) << " gamma: " << gamma << "\n";); + if (is_connected(gamma, zero_edge, e, timestamp)) { dl_var curr_target = e.get_target(); - TRACE("dl_bfs", tout << "curr_target: " << curr_target << - ", mark: " << static_cast(bfs_mark[curr_target]) << "\n";); + TRACE("dl_bfs", tout << "curr_target: " << curr_target << ", mark: " << bfs_mark[curr_target] << "\n";); if (curr_target == target) { TRACE("dl_bfs", tout << "found path\n";); TRACE("dl_eq_bug", tout << "path: " << source << " --> " << target << "\n"; display_edge(tout, e); int tmp_parent_idx = parent_idx; - for (;;) { + while (true) { bfs_elem & curr = bfs_todo[tmp_parent_idx]; if (curr.m_edge_id == null_edge_id) { break; @@ -1399,11 +1394,10 @@ public: display_edge(tout, e); tmp_parent_idx = curr.m_parent_idx; } - tout.flush(); }); TRACE("dl_eq_bug", display_edge(tout, e);); f(e.get_explanation()); - for (;;) { + while (true) { SASSERT(parent_idx >= 0); bfs_elem & curr = bfs_todo[parent_idx]; if (curr.m_edge_id == null_edge_id) { @@ -1417,11 +1411,9 @@ public: } } } - else { - if (!bfs_mark[curr_target]) { - bfs_todo.push_back(bfs_elem(curr_target, parent_idx, e_id)); - bfs_mark[curr_target] = true; - } + else if (!bfs_mark[curr_target]) { + bfs_todo.push_back(bfs_elem(curr_target, parent_idx, e_id)); + bfs_mark[curr_target] = true; } } } @@ -1507,8 +1499,7 @@ private: numeral get_reduced_weight(dfs_state& state, dl_var n, edge const& e) { numeral gamma; - set_gamma(e, gamma); - return state.m_delta[n] + gamma; + return state.m_delta[n] + set_gamma(e, gamma); } template diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 90b6a7bbf..74e9d38bf 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -58,11 +58,11 @@ namespace smt { } bool_var var() const { return m_bvar;} relation& get_relation() const { return m_relation; } - bool phase() { return m_phase; } + bool phase() const { return m_phase; } void set_phase(bool b) { m_phase = b; } - theory_var v1() { return m_v1; } - theory_var v2() { return m_v2; } - literal explanation() { return literal(m_bvar, !m_phase); } + theory_var v1() const { return m_v1; } + theory_var v2() const { return m_v2; } + literal explanation() const { return literal(m_bvar, !m_phase); } bool enable() { edge_id edge = m_phase?m_pos:m_neg; return m_relation.m_graph.enable_edge(edge); @@ -112,16 +112,16 @@ namespace smt { typedef u_map bool_var2atom; special_relations_util m_util; - arith_util m_autil; - + arith_util m_autil; atoms m_atoms; unsigned_vector m_atoms_lim; obj_map m_relations; bool_var2atom m_bool_var2atom; scoped_ptr m_nested_solver; + struct atom_hash { - size_t operator()(atom a) const { + size_t operator()(atom const& a) const { return std::hash()(a.v1()) ^ std::hash()(a.v2()) ^ std::hash()(a.phase()); } }; @@ -158,6 +158,13 @@ namespace smt { bool is_strict_neighbour_edge(graph const& g, edge_id id) const; bool disconnected(graph const& g, dl_var u, dl_var v) const; + literal mk_literal(expr* _e); + enode* ensure_enode(expr* e); + theory_var mk_var(enode* n); + + void collect_asserted_po_atoms(vector< std::pair >& atoms) const; + void display_atom(std::ostream & out, atom& a) const; + public: theory_special_relations(ast_manager& m); ~theory_special_relations() override; @@ -182,13 +189,6 @@ namespace smt { bool can_propagate() override { return false; } void propagate() override {} void display(std::ostream & out) const override; - - literal mk_literal(expr* _e); - enode* ensure_enode(expr* e); - theory_var mk_var(enode* n); - - void collect_asserted_po_atoms( vector< std::pair >& atoms) const; - void display_atom( std::ostream & out, atom& a) const; }; } From e4bf1663b62bd4d8024e96d9eeecad66eae011b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 20:47:02 -0700 Subject: [PATCH 078/156] na Signed-off-by: Nikolaj Bjorner --- src/smt/diff_logic.h | 2 +- src/smt/theory_special_relations.cpp | 110 +++++++++++---------------- 2 files changed, 46 insertions(+), 66 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 29b1050df..8544a2384 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -1365,7 +1365,7 @@ public: for (unsigned head = 0; head < bfs_todo.size(); ++head) { bfs_elem & curr = bfs_todo[head]; int parent_idx = head; - dl_var v = curr.m_var; + dl_var v = curr.m_var; TRACE("dl_bfs", tout << "processing: " << v << "\n";); edge_id_vector & edges = m_out_edges[v]; for (edge_id e_id : edges) { diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index e1a42403d..e0201c25c 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -157,23 +157,20 @@ namespace smt { final_check_status theory_special_relations::final_check_eh() { TRACE("special_relations", tout << "\n";); - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - lbool r = l_true; - for (; it != end && r == l_true; ++it) { - r = final_check(*it->m_value); + for (auto const& kv : m_relations) { + lbool r = final_check(*kv.m_value); + switch (r) { + case l_undef: + return FC_GIVEUP; + case l_false: + return FC_CONTINUE; + default: + break; + } } - switch (r) { - case l_undef: - return FC_GIVEUP; - case l_false: - return FC_CONTINUE; - default: - break; - } - it = m_relations.begin(); bool new_equality = false; - for (; it != end; ++it) { - if (extract_equalities(*it->m_value)) { + for (auto const& kv : m_relations) { + if (extract_equalities(*kv.m_value)) { new_equality = true; } } @@ -421,6 +418,7 @@ namespace smt { u_map> map; lbool res = l_true; + // TBD: non-functional code? for (atom * ap : r.m_asserted_atoms) { if (res != l_true) break; atom a = *ap; @@ -449,7 +447,7 @@ namespace smt { auto f = m.mk_implies( b, m.mk_not(literals.back()) ); m_nested_solver->assert_expr(f); - atom_cache.insert(b->get_id(), &a); + atom_cache.insert(b->get_id(), ap); assumptions.push_back(b); r.m_explanation.reset(); if (m_nested_solver->check_sat(assumptions.size(), assumptions.c_ptr()) == l_false) { @@ -496,9 +494,8 @@ namespace smt { } void theory_special_relations::reset_eh() { - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - dealloc(it->m_value); + for (auto const& kv : m_relations) { + dealloc(kv.m_value); } m_relations.reset(); del_atoms(0); @@ -510,21 +507,18 @@ namespace smt { VERIFY(m_bool_var2atom.find(v, a)); a->set_phase(is_true); a->get_relation().m_asserted_atoms.push_back(a); - //std::cerr << "ASSIGN: " << a->v1() << ' ' << a->v2() << "\n"; } void theory_special_relations::push_scope_eh() { - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - it->m_value->push(); + for (auto const& kv : m_relations) { + kv.m_value->push(); } m_atoms_lim.push_back(m_atoms.size()); } void theory_special_relations::pop_scope_eh(unsigned num_scopes) { - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - it->m_value->pop(num_scopes); + for (auto const& kv : m_relations) { + kv.m_value->pop(num_scopes); } unsigned new_lvl = m_atoms_lim.size() - num_scopes; del_atoms(m_atoms_lim[new_lvl]); @@ -544,9 +538,8 @@ namespace smt { void theory_special_relations::collect_statistics(::statistics & st) const { - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - it->m_value->m_graph.collect_statistics(st); + for (auto const& kv : m_relations) { + kv.m_value->m_graph.collect_statistics(st); } } @@ -613,9 +606,7 @@ namespace smt { if (g.get_assignment(u) <= val_v) { continue; } - int_vector const& edges = g.get_out_edges(u); - for (unsigned i = 0; i < edges.size(); ++i) { - edge_id e = edges[i]; + for (edge_id e : g.get_out_edges(u)) { if (is_strict_neighbour_edge(g, e)) { todo.push_back(g.get_target(e)); } @@ -773,9 +764,7 @@ namespace smt { } unsigned nc = 1; bool all_p = true; - int_vector const& edges = g.get_out_edges(v); - for (unsigned i = 0; i < edges.size(); ++i) { - edge_id e = edges[i]; + for (edge_id e : g.get_out_edges(v)) { if (is_strict_neighbour_edge(g, e)) { dl_var dst = g.get_target(e); TRACE("special_relations", tout << v << " -> " << dst << "\n";); @@ -839,23 +828,22 @@ namespace smt { } void theory_special_relations::init_model(model_generator & m) { - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - switch (it->m_value->m_property) { + for (auto const& kv : m_relations) { + switch (kv.m_value->m_property) { case sr_lo: - init_model_lo(*it->m_value, m); + init_model_lo(*kv.m_value, m); break; case sr_plo: - init_model_plo(*it->m_value, m); + init_model_plo(*kv.m_value, m); break; case sr_to: - init_model_to(*it->m_value, m); + init_model_to(*kv.m_value, m); break; case sr_po: - init_model_po(*it->m_value, m); + init_model_po(*kv.m_value, m); break; default: - UNREACHABLE(); //ASHU: added to remove warning! Should be supported! + UNREACHABLE(); //ASHU: added to remove warning! Should be supported! } } } @@ -864,38 +852,30 @@ namespace smt { if (m_relations.empty()) return; out << "Theory Special Relations\n"; display_var2enode(out); - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - out << mk_pp(it->m_value->decl(), get_manager()) << ":\n"; - it->m_value->m_graph.display(out); - it->m_value->m_uf.display(out); - for (unsigned i = 0; i < it->m_value->m_asserted_atoms.size(); ++i){ - atom& a = *it->m_value->m_asserted_atoms[i]; - display_atom( out, a ); + for (auto const& kv : m_relations) { + out << mk_pp(kv.m_value->decl(), get_manager()) << ":\n"; + kv.m_value->m_graph.display(out); + kv.m_value->m_uf.display(out); + for (atom* ap : kv.m_value->m_asserted_atoms) { + display_atom(out, *ap); } } } - void theory_special_relations::collect_asserted_po_atoms( vector< std::pair >& atoms) const { - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - relation& r = *(it->m_value ); - if( r.m_property != sr_po ) continue; - // SASSERT( r.m_asserted_qhead == r.m_asserted_atoms.size() ); - for (unsigned i = 0; i < r.m_asserted_atoms.size(); ++i) { - atom& a = *r.m_asserted_atoms[i]; - atoms.push_back( std::make_pair(a.var(),a.phase()) ); + void theory_special_relations::collect_asserted_po_atoms(vector>& atoms) const { + for (auto const& kv : m_relations) { + relation& r = *kv.m_value; + if (r.m_property != sr_po) continue; + for (atom* ap : r.m_asserted_atoms) { + atoms.push_back(std::make_pair(ap->var(), ap->phase())); } } } - void theory_special_relations::display_atom( std::ostream & out, atom& a ) const { + void theory_special_relations::display_atom(std::ostream & out, atom& a) const { context& ctx = get_context(); expr* e = ctx.bool_var2expr( a.var() ); - if( !a.phase() ) out << "(not "; - out << mk_pp( e, get_manager()); - if( !a.phase() ) out << ")"; - out << "\n"; + out << (a.phase() ? "" : "(not ") << mk_pp(e, get_manager()) << (a.phase() ? "" : ")") << "\n"; } } From f83b32e6c3879e780555f119b60ba211db3f39c6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 03:36:30 -0700 Subject: [PATCH 079/156] remove unused code Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 110 +++++---------------------- src/smt/theory_special_relations.h | 12 --- 2 files changed, 17 insertions(+), 105 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index e0201c25c..9e1579570 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -28,7 +28,6 @@ Notes: #include "ast/reg_decl_plugins.h" #include "ast/ast_pp.h" -static constexpr bool KVEC = false; static constexpr bool HYBRID_SEARCH = false; namespace smt { @@ -38,9 +37,7 @@ namespace smt { scope& s = m_scopes.back(); s.m_asserted_atoms_lim = m_asserted_atoms.size(); s.m_asserted_qhead_old = m_asserted_qhead; - if (!KVEC) { - m_graph.push(); - } + m_graph.push(); m_ufctx.get_trail_stack().push_scope(); } @@ -50,9 +47,7 @@ namespace smt { m_asserted_atoms.shrink(s.m_asserted_atoms_lim); m_asserted_qhead = s.m_asserted_qhead_old; m_scopes.shrink(new_lvl); - if (!KVEC) { - m_graph.pop(num_scopes); - } + m_graph.pop(num_scopes); m_ufctx.get_trail_stack().pop_scope(num_scopes); } @@ -75,17 +70,11 @@ namespace smt { theory_special_relations::theory_special_relations(ast_manager& m): theory(m.mk_family_id("special_relations")), - m_util(m), m_autil(m) { - params_ref params; - params.set_bool("model", true); - params.set_bool("unsat_core", true); - m_nested_solver = mk_smt_solver(m, params, symbol("QF_LRA")); - m_int_sort = m_autil.mk_real(); + m_util(m) { } theory_special_relations::~theory_special_relations() { reset_eh(); - m_nested_solver = nullptr; } theory * theory_special_relations::mk_fresh(context * new_ctx) { @@ -118,7 +107,7 @@ namespace smt { ctx.set_var_theory(v, get_id()); atom* a = alloc(atom, v, *r, v0, v1); m_atoms.push_back(a); - //std::cerr << "INTER : " << a->v1() << ' ' << a->v2() << ' ' << gate_ctx << "\n"; + TRACE("sr", tout << "INTER : " << a->v1() << ' ' << a->v2() << ' ' << gate_ctx << "\n";); m_bool_var2atom.insert(v, a); return true; } @@ -386,86 +375,22 @@ namespace smt { } lbool theory_special_relations::final_check_po(relation& r) { - if (!KVEC) { - lbool res = l_true; - for (unsigned i = 0; res == l_true && i < r.m_asserted_atoms.size(); ++i) { - atom& a = *r.m_asserted_atoms[i]; - if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { - // v1 !-> v2 - // find v1 -> v3 -> v4 -> v2 path - r.m_explanation.reset(); - unsigned timestamp = r.m_graph.get_timestamp(); - auto found_path = HYBRID_SEARCH ? - r.m_graph.find_path(a.v1(), a.v2(), timestamp, r) : - r.m_graph.find_shortest_reachable_path(a.v1(), a.v2(), timestamp, r); - if (found_path) { - r.m_explanation.push_back(a.explanation()); - set_conflict(r); - res = l_false; - } - } - } - return res; - } - context& ctx = get_context(); - ast_manager& m = ctx.get_manager(); - - ptr_vector assumptions; - ptr_vector literals; - - int k = 1; - static int curr_id = 100000; - - u_map> map; - lbool res = l_true; - // TBD: non-functional code? - for (atom * ap : r.m_asserted_atoms) { - if (res != l_true) break; - atom a = *ap; - if (a.phase()) { - continue; - // assumptions.push_back(b); - r.m_uf.merge(a.v1(), a.v2()); - } - } - for (atom * ap : r.m_asserted_atoms) { - if (res != l_true) break; - atom a = *ap; - if (a.phase()) - continue; - if (r.m_uf.find(a.v1()) != r.m_uf.find(a.v2())) { - continue; - } - populate_k_vars(a.v1(), k, map, curr_id, m, m_int_sort); - populate_k_vars(a.v2(), k, map, curr_id, m, m_int_sort); - - literals.push_back(m_autil.mk_lt(map[a.v1()][0], map[a.v2()][0])); - - auto bool_sort = m.mk_bool_sort(); - auto b_func = m.mk_const_decl(symbol(curr_id++), bool_sort); - auto b = m.mk_app(b_func, unsigned(0), nullptr); - - auto f = m.mk_implies( b, m.mk_not(literals.back()) ); - m_nested_solver->assert_expr(f); - atom_cache.insert(b->get_id(), ap); - assumptions.push_back(b); - r.m_explanation.reset(); - if (m_nested_solver->check_sat(assumptions.size(), assumptions.c_ptr()) == l_false) { - expr_ref_vector unsat_core(m); - m_nested_solver->get_unsat_core(unsat_core); - for (expr* e : unsat_core) { - atom& a = *atom_cache[e->get_id()]; + for (atom* ap : r.m_asserted_atoms) { + atom& a = *ap; + if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { + // v1 !-> v2 + // find v1 -> v3 -> v4 -> v2 path + r.m_explanation.reset(); + unsigned timestamp = r.m_graph.get_timestamp(); + bool found_path = r.m_graph.find_shortest_reachable_path(a.v1(), a.v2(), timestamp, r); + if (found_path) { r.m_explanation.push_back(a.explanation()); + set_conflict(r); + return l_false; } - for (auto e : r.m_explanation) { - std::cerr << "EX " << e.hash() << "\n"; - } - set_conflict(r); - res = l_false; } - assumptions.pop_back(); } - return res; + return l_true; } lbool theory_special_relations::propagate(relation& r) { @@ -503,8 +428,7 @@ namespace smt { void theory_special_relations::assign_eh(bool_var v, bool is_true) { TRACE("special_relations", tout << "assign bv" << v << " " << (is_true?" <- true":" <- false") << "\n";); - atom* a = 0; - VERIFY(m_bool_var2atom.find(v, a)); + atom* a = m_bool_var2atom[v]; a->set_phase(is_true); a->get_relation().m_asserted_atoms.push_back(a); } diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 74e9d38bf..e9e5668f3 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -112,22 +112,10 @@ namespace smt { typedef u_map bool_var2atom; special_relations_util m_util; - arith_util m_autil; atoms m_atoms; unsigned_vector m_atoms_lim; obj_map m_relations; bool_var2atom m_bool_var2atom; - - scoped_ptr m_nested_solver; - - struct atom_hash { - size_t operator()(atom const& a) const { - return std::hash()(a.v1()) ^ std::hash()(a.v2()) ^ std::hash()(a.phase()); - } - }; - u_map expr_cache; - u_map atom_cache; - sort* m_int_sort; void del_atoms(unsigned old_size); lbool final_check(relation& r); From 31969b503729f12b15ef070f6e9101f187c8da7b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 04:43:47 -0700 Subject: [PATCH 080/156] tidy Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 103 +++++++++++---------------- src/smt/theory_special_relations.h | 13 +++- 2 files changed, 53 insertions(+), 63 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 9e1579570..95cfb410e 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -28,8 +28,6 @@ Notes: #include "ast/reg_decl_plugins.h" #include "ast/ast_pp.h" -static constexpr bool HYBRID_SEARCH = false; - namespace smt { void theory_special_relations::relation::push() { @@ -63,9 +61,7 @@ namespace smt { ensure_var(v2); literal_vector ls; ls.push_back(l); - return - m_graph.enable_edge(m_graph.add_edge(v1, v2, s_integer(1), ls)) && - m_graph.enable_edge(m_graph.add_edge(v2, v1, s_integer(1), ls)); + return m_graph.add_non_strict_edge(v1, v2, ls) && m_graph.add_non_strict_edge(v2, v1, ls); } theory_special_relations::theory_special_relations(ast_manager& m): @@ -81,22 +77,13 @@ namespace smt { return alloc(theory_special_relations, new_ctx->get_manager()); } - static void populate_k_vars(int v, int k, u_map>& map, int& curr_id, ast_manager& m, sort* int_sort) { - int need = !map.contains(v) ? k : k - map[v].size(); - for (auto i = 0; i < need; ++i) { - auto *fd = m.mk_const_decl(symbol(curr_id++), int_sort); - map[v].push_back(m.mk_app(fd, unsigned(0), nullptr)); - } - } - bool theory_special_relations::internalize_atom(app * atm, bool gate_ctx) { - TRACE("special_relations", tout << mk_pp(atm, get_manager()) << "\n";); SASSERT(m_util.is_special_relation(atm)); relation* r = 0; if (!m_relations.find(atm->get_decl(), r)) { - //todo: push pop may get misaligned if the following alloc happens after push r = alloc(relation, m_util.get_property(atm), atm->get_decl()); m_relations.insert(atm->get_decl(), r); + for (unsigned i = 0; i < m_atoms_lim.size(); ++i) r->push(); } context& ctx = get_context(); expr* arg0 = atm->get_arg(0); @@ -107,7 +94,7 @@ namespace smt { ctx.set_var_theory(v, get_id()); atom* a = alloc(atom, v, *r, v0, v1); m_atoms.push_back(a); - TRACE("sr", tout << "INTER : " << a->v1() << ' ' << a->v2() << ' ' << gate_ctx << "\n";); + TRACE("special_relations", tout << mk_pp(atm, get_manager()) << " : " << a->v1() << ' ' << a->v2() << ' ' << gate_ctx << "\n";); m_bool_var2atom.insert(v, a); return true; } @@ -222,42 +209,39 @@ namespace smt { lbool theory_special_relations::final_check_to(relation& r) { uint_set visited, target; - lbool res = l_true; - for (unsigned i = 0; res == l_true && i < r.m_asserted_atoms.size(); ++i) { - atom& a = *r.m_asserted_atoms[i]; - if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { - target.reset(); - theory_var w; - // v2 !<= v1 is asserted - target.insert(a.v2()); - if (r.m_graph.reachable(a.v1(), visited, target, w)) { - // we already have v1 <= v2 - continue; + for (atom* ap : r.m_asserted_atoms) { + atom& a = *ap; + if (a.phase() || r.m_uf.find(a.v1()) != r.m_uf.find(a.v2())) { + continue; + } + target.reset(); + theory_var w; + // v2 !<= v1 is asserted + target.insert(a.v2()); + if (r.m_graph.reachable(a.v1(), visited, target, w)) { + // we already have v1 <= v2 + continue; + } + target.reset(); + if (r.m_graph.reachable(a.v2(), target, visited, w)) { + // there is a common successor + // v1 <= w + // v2 <= w + // v1 !<= v2 + // -> v1 <= w & v2 <= w & v1 !<= v2 -> v2 <= v1 + unsigned timestamp = r.m_graph.get_timestamp(); + r.m_explanation.reset(); + r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r); + r.m_graph.find_shortest_reachable_path(a.v2(), w, timestamp, r); + r.m_explanation.push_back(a.explanation()); + literal_vector const& lits = r.m_explanation; + if (!r.m_graph.add_non_strict_edge(a.v2(), a.v1(), lits)) { + set_neg_cycle_conflict(r); + return l_false; } - target.reset(); - if (r.m_graph.reachable(a.v2(), target, visited, w)) { - // there is a common successor - // v1 <= w - // v2 <= w - // v1 !<= v2 - // -> v1 <= w & v2 <= w & v1 !<= v2 -> v2 <= v1 - unsigned timestamp = r.m_graph.get_timestamp(); - r.m_explanation.reset(); - r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r); - r.m_graph.find_shortest_reachable_path(a.v2(), w, timestamp, r); - r.m_explanation.push_back(a.explanation()); - literal_vector const& lits = r.m_explanation; - if (!r.m_graph.enable_edge(r.m_graph.add_edge(a.v2(), a.v1(), s_integer(0), lits))) { - set_neg_cycle_conflict(r); - res = l_false; - } - } - // TODO: check if algorithm correctly produces all constraints. - // e.g., if we add an edge, do we have to repeat the loop? - // } } - return res; + return l_true; } lbool theory_special_relations::enable(atom& a) { @@ -289,12 +273,6 @@ namespace smt { } lbool theory_special_relations::final_check(relation& r) { - // timer m_timer_fc; //for debugging - // static unsigned call_count = 0; - // static double total_call_times = 0.0; - // m_timer_fc.start(); - // call_count++; - lbool res = propagate(r); if (res != l_true) return res; switch (r.m_property) { @@ -446,6 +424,7 @@ namespace smt { } unsigned new_lvl = m_atoms_lim.size() - num_scopes; del_atoms(m_atoms_lim[new_lvl]); + m_atoms_lim.shrink(new_lvl); } void theory_special_relations::del_atoms(unsigned old_size) { @@ -453,7 +432,7 @@ namespace smt { atoms::iterator it = m_atoms.end(); while (it != begin) { --it; - atom * a = *it; + atom* a = *it; m_bool_var2atom.erase(a->var()); dealloc(a); } @@ -469,7 +448,7 @@ namespace smt { model_value_proc * theory_special_relations::mk_value(enode * n, model_generator & mg) { UNREACHABLE(); - return 0; + return nullptr; } void theory_special_relations::ensure_strict(graph& g) { @@ -480,7 +459,7 @@ namespace smt { dl_var src = g.get_source(i); dl_var dst = g.get_target(i); if (get_enode(src)->get_root() == get_enode(dst)->get_root()) continue; - VERIFY(g.enable_edge(g.add_edge(src, dst, s_integer(-2), literal_vector()))); + VERIFY(g.add_strict_edge(src, dst, literal_vector())); } TRACE("special_relations", g.display(tout);); } @@ -498,9 +477,10 @@ namespace smt { edge_id e2 = edges[k]; if (g.is_enabled(e2)) { dl_var src2 = g.get_source(e2); - if (get_enode(src1)->get_root() == get_enode(src2)->get_root()) continue; - if (!disconnected(g, src1, src2)) continue; - VERIFY(g.enable_edge(g.add_edge(src1, src2, s_integer(-2), literal_vector()))); + if (get_enode(src1)->get_root() != get_enode(src2)->get_root() && + disconnected(g, src1, src2)) { + VERIFY(g.add_strict_edge(src1, src2, literal_vector())); + } } } } @@ -587,7 +567,6 @@ namespace smt { expr_ref theory_special_relations::mk_interval(relation& r, model_generator& mg, unsigned_vector & lo, unsigned_vector& hi) { graph const& g = r.m_graph; - //context& ctx = get_context(); ast_manager& m = get_manager(); expr_ref result(m); func_decl_ref lofn(m), hifn(m); diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index e9e5668f3..7c243dee0 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -78,7 +78,14 @@ namespace smt { struct int_ext : public sidl_ext { typedef literal_vector explanation; }; - typedef dl_graph graph; + struct graph : public dl_graph { + bool add_strict_edge(theory_var v1, theory_var v2, literal_vector const& j) { + return enable_edge(add_edge(v1, v2, s_integer(1), j)); + } + bool add_non_strict_edge(theory_var v1, theory_var v2, literal_vector const& j) { + return enable_edge(add_edge(v1, v2, s_integer(-2), j)); + } + }; typedef union_find union_find_t; @@ -104,6 +111,9 @@ namespace smt { m_explanation.append(ex); } void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {} + + bool add_strict_edge(theory_var v1, theory_var v2, literal_vector const& j); + bool add_non_strict_edge(theory_var v1, theory_var v2, literal_vector const& j); }; @@ -117,6 +127,7 @@ namespace smt { obj_map m_relations; bool_var2atom m_bool_var2atom; + void del_atoms(unsigned old_size); lbool final_check(relation& r); lbool final_check_po(relation& r); From dd9aec55527413182da1f3a4d31e129d02fdb88d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 10:40:08 -0700 Subject: [PATCH 081/156] nits Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 15 ++++----------- src/smt/theory_special_relations.h | 10 +++++----- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 95cfb410e..03066f766 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -115,15 +115,11 @@ namespace smt { void theory_special_relations::new_eq_eh(theory_var v1, theory_var v2) { context& ctx = get_context(); - app_ref eq(get_manager()); app* t1 = get_enode(v1)->get_owner(); app* t2 = get_enode(v2)->get_owner(); - eq = get_manager().mk_eq(t1, t2); - VERIFY(internalize_atom(eq, false)); - literal l(ctx.get_literal(eq)); - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; !ctx.inconsistent() && it != end; ++it) { - relation& r = *it->m_value; + literal eq = mk_eq(t1, t2, false); + for (auto const& kv : m_relations) { + relation& r = *kv.m_value; if (!r.new_eq_eh(l, v1, v2)) { set_neg_cycle_conflict(r); break; @@ -175,9 +171,8 @@ namespace smt { literal theory_special_relations::mk_literal(expr* _e) { expr_ref e(_e, get_manager()); - context& ctx = get_context(); ensure_enode(e); - return ctx.get_literal(e); + return get_context().get_literal(e); } theory_var theory_special_relations::mk_var(enode* n) { @@ -520,7 +515,6 @@ namespace smt { } expr_ref theory_special_relations::mk_inj(relation& r, model_generator& mg) { - // context& ctx = get_context(); ast_manager& m = get_manager(); r.push(); ensure_strict(r.m_graph); @@ -545,7 +539,6 @@ namespace smt { } expr_ref theory_special_relations::mk_class(relation& r, model_generator& mg) { - //context& ctx = get_context(); ast_manager& m = get_manager(); expr_ref result(m); func_decl_ref fn(m); diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 7c243dee0..01314b362 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -17,14 +17,14 @@ Notes: --*/ +#ifndef THEORY_SPECIAL_RELATIONS_H_ +#define THEORY_SPECIAL_RELATIONS_H_ + #include "ast/special_relations_decl_plugin.h" #include "smt/smt_theory.h" #include "smt/theory_diff_logic.h" #include "util/union_find.h" -#include "solver/solver.h" - -#ifndef THEORY_SPECIAL_RELATIONS_H_ -#define THEORY_SPECIAL_RELATIONS_H_ +#include "util/rational.h" namespace smt { class theory_special_relations : public theory { @@ -140,7 +140,7 @@ namespace smt { void set_neg_cycle_conflict(relation& r); void set_conflict(relation& r); lbool propagate_plo(atom& a); - lbool propagate_po(atom& a); //ASHU: added to modify po solving + lbool propagate_po(atom& a); theory_var mk_var(expr* e); void count_children(graph const& g, unsigned_vector& num_children); void ensure_strict(graph& g); From 1634a21e75e9c2f7414dc9f9a979b695ac24bf07 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 10:43:29 -0700 Subject: [PATCH 082/156] l -> eq Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 03066f766..3750ce967 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -120,7 +120,7 @@ namespace smt { literal eq = mk_eq(t1, t2, false); for (auto const& kv : m_relations) { relation& r = *kv.m_value; - if (!r.new_eq_eh(l, v1, v2)) { + if (!r.new_eq_eh(eq, v1, v2)) { set_neg_cycle_conflict(r); break; } From c4b4744ae90322f537a6d933a61affab4e9088e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 13:13:50 -0700 Subject: [PATCH 083/156] e_id3 Signed-off-by: Nikolaj Bjorner --- src/smt/diff_logic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 8544a2384..8332baaf4 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -1775,7 +1775,7 @@ public: continue; } w2 = e2.get_weight() + w; - for (edge_id e_id2 : m_in_edges[e2.get_target()]) { + for (edge_id e_id3 : m_in_edges[e2.get_target()]) { ++m_stats.m_implied_literal_cost; edge const& e3 = m_edges[e_id3]; if (e3.is_enabled() || e3.get_source() != src) { From 48e0626ffebc97e0bcacd08b07deb1a22051b302 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 17:42:27 -0700 Subject: [PATCH 084/156] add API Signed-off-by: Nikolaj Bjorner --- src/api/CMakeLists.txt | 1 + src/api/api_ast.cpp | 12 +++++ src/api/api_context.cpp | 1 + src/api/api_context.h | 3 ++ src/api/api_special_relations.cpp | 78 ++++++++++++++++++++++++++++ src/api/c++/z3++.h | 36 +++++++++++++ src/api/z3_api.h | 57 +++++++++++++++++++- src/smt/diff_logic.h | 9 ++-- src/smt/theory_special_relations.cpp | 31 ++++++----- src/smt/theory_special_relations.h | 22 ++++---- 10 files changed, 223 insertions(+), 27 deletions(-) create mode 100644 src/api/api_special_relations.cpp diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt index 4a5514a7b..247d0a14c 100644 --- a/src/api/CMakeLists.txt +++ b/src/api/CMakeLists.txt @@ -61,6 +61,7 @@ z3_add_component(api api_rcf.cpp api_seq.cpp api_solver.cpp + api_special_relations.cpp api_stats.cpp api_tactic.cpp z3_replayer.cpp diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index cabfdb101..a8f62572a 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1052,6 +1052,18 @@ extern "C" { } } + if (mk_c(c)->get_special_relations_fid() == _d->get_family_id()) { + switch(_d->get_decl_kind()) { + case OP_SPECIAL_RELATION_LO : return Z3_OP_SPECIAL_RELATION_LO; + case OP_SPECIAL_RELATION_PO : return Z3_OP_SPECIAL_RELATION_PO; + case OP_SPECIAL_RELATION_PO_AO : return Z3_OP_SPECIAL_RELATION_PO_AO; + case OP_SPECIAL_RELATION_PLO: return Z3_OP_SPECIAL_RELATION_PLO; + case OP_SPECIAL_RELATION_TO : return Z3_OP_SPECIAL_RELATION_TO; + default: UNREACHABLE(); + } + } + + if (mk_c(c)->get_bv_fid() == _d->get_family_id()) { switch(_d->get_decl_kind()) { case OP_BV_NUM: return Z3_OP_BNUM; diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 71bebef73..811cb30ee 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -101,6 +101,7 @@ namespace api { m_datalog_fid = m().mk_family_id("datalog_relation"); m_fpa_fid = m().mk_family_id("fpa"); m_seq_fid = m().mk_family_id("seq"); + m_special_relations_fid = m().mk_family_id("special_relations"); m_dt_plugin = static_cast(m().get_plugin(m_dt_fid)); install_tactics(*this); diff --git a/src/api/api_context.h b/src/api/api_context.h index 8bd75aaa0..1c4145810 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -30,6 +30,7 @@ Revision History: #include "ast/dl_decl_plugin.h" #include "ast/fpa_decl_plugin.h" #include "ast/recfun_decl_plugin.h" +#include "ast/special_relations_decl_plugin.h" #include "smt/smt_kernel.h" #include "smt/params/smt_params.h" #include "util/event_handler.h" @@ -106,6 +107,7 @@ namespace api { family_id m_pb_fid; family_id m_fpa_fid; family_id m_seq_fid; + family_id m_special_relations_fid; datatype_decl_plugin * m_dt_plugin; std::string m_string_buffer; // temporary buffer used to cache strings sent to the "external" world. @@ -162,6 +164,7 @@ namespace api { family_id get_fpa_fid() const { return m_fpa_fid; } family_id get_seq_fid() const { return m_seq_fid; } datatype_decl_plugin * get_dt_plugin() const { return m_dt_plugin; } + family_id get_special_relations_fid() const { return m_special_relations_fid; } Z3_error_code get_error_code() const { return m_error_code; } void reset_error_code(); diff --git a/src/api/api_special_relations.cpp b/src/api/api_special_relations.cpp new file mode 100644 index 000000000..40fde5083 --- /dev/null +++ b/src/api/api_special_relations.cpp @@ -0,0 +1,78 @@ +/*++ +Copyright (c) 2019 Microsoft Corporation + +Module Name: + + api_special_relations.cpp + +Abstract: + Basic API for Special relations + +Author: + + Nikolaj Bjorner (nbjorner) 2019-03-25 + Ashutosh Gupta 2016 + +Revision History: + +--*/ + +#include +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "ast/ast_pp.h" +#include "ast/special_relations_decl_plugin.h" + +extern "C" { + +#if 0 + bool Z3_API Z3_is_sr_lo(Z3_context c, Z3_ast s) { + Z3_TRY; + LOG_Z3_is_sr_lo(c, s); + RESET_ERROR_CODE(); + RETURN_Z3(mk_c(c)->sr_util().is_lo( to_expr(s) )); + Z3_CATCH_RETURN(false); + } + + bool Z3_API Z3_is_sr_po(Z3_context c, Z3_ast s) { + Z3_TRY; + LOG_Z3_is_sr_po(c, s); + RESET_ERROR_CODE(); + RETURN_Z3(mk_c(c)->sr_util().is_po( to_expr(s) )); + Z3_CATCH_RETURN(false); + } + + bool Z3_API Z3_is_sr_po_ao(Z3_context c, Z3_ast s) { + Z3_TRY; + LOG_Z3_is_sr_po_ao(c, s); + RESET_ERROR_CODE(); + RETURN_Z3(mk_c(c)->sr_util().is_po_ao( to_expr(s) )); + Z3_CATCH_RETURN(false); + } + + bool Z3_API Z3_is_sr_plo(Z3_context c, Z3_ast s) { + Z3_TRY; + LOG_Z3_is_sr_plo(c, s); + RESET_ERROR_CODE(); + RETURN_Z3(mk_c(c)->sr_util().is_plo( to_expr(s) )); + Z3_CATCH_RETURN(false); + } + + bool Z3_API Z3_is_sr_to(Z3_context c, Z3_ast s) { + Z3_TRY; + LOG_Z3_is_sr_to(c, s); + RESET_ERROR_CODE(); + RETURN_Z3(mk_c(c)->sr_util().is_to( to_expr(s) )); + Z3_CATCH_RETURN(false); + } +#endif + + MK_BINARY(Z3_mk_sr_lo , mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_LO, SKIP); + MK_BINARY(Z3_mk_sr_po , mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_PO, SKIP); + MK_BINARY(Z3_mk_sr_po_ao,mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_PO_AO,SKIP); + MK_BINARY(Z3_mk_sr_plo, mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_PLO, SKIP); + MK_BINARY(Z3_mk_sr_to , mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_TO, SKIP); + +}; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 4992015de..e18ca9204 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1707,6 +1707,42 @@ namespace z3 { */ inline expr sext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_sign_ext(a.ctx(), i, a)); } + inline expr sr_lo(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r = Z3_mk_sr_lo(a.ctx(), a, b); + a.check_error(); + return expr(a.ctx(), r); + } + + inline expr sr_po(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r = Z3_mk_sr_po(a.ctx(), a, b); + a.check_error(); + return expr(a.ctx(), r); + } + + inline expr sr_po_ao(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r = Z3_mk_sr_po_ao(a.ctx(), a, b); + a.check_error(); + return expr(a.ctx(), r); + } + + inline expr sr_plo(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r = Z3_mk_sr_plo(a.ctx(), a, b); + a.check_error(); + return expr(a.ctx(), r); + } + + inline expr sr_to(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r = Z3_mk_sr_to(a.ctx(), a, b); + a.check_error(); + return expr(a.ctx(), r); + } + + template class cast_ast; template<> class cast_ast { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index e17378d94..6d1db22b3 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1101,6 +1101,13 @@ typedef enum { Z3_OP_BUREM_I, Z3_OP_BSMOD_I, + // Special relations + Z3_OP_SPECIAL_RELATION_LO, + Z3_OP_SPECIAL_RELATION_PO, + Z3_OP_SPECIAL_RELATION_PO_AO, + Z3_OP_SPECIAL_RELATION_PLO, + Z3_OP_SPECIAL_RELATION_TO, + // Proofs Z3_OP_PR_UNDEF = 0x500, Z3_OP_PR_TRUE, @@ -3595,10 +3602,58 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_re_full(Z3_context c, Z3_sort re); - /*@}*/ + /** @name Special relations */ + /*@{*/ + /** + \brief declare \c a and \c b are in linear order. + + \pre a and b are of same type. + + def_API('Z3_mk_sr_lo', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_sr_lo(Z3_context c, Z3_ast a, Z3_ast b); + + /** + \brief declare \c a and \c b are in partial order. + + \pre a and b are of same type. + + def_API('Z3_mk_sr_po', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_sr_po(Z3_context c, Z3_ast a, Z3_ast b); + + /** + \brief declare \c a and \c b are already partial ordered. + + \pre a and b are of same type. + + def_API('Z3_mk_sr_po_ao', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_sr_po_ao(Z3_context c, Z3_ast a, Z3_ast b); + + /** + \brief declare \c a and \c b are in piecewise linear order. + + \pre a and b are of same type. + + def_API('Z3_mk_sr_plo', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_sr_plo(Z3_context c, Z3_ast a, Z3_ast b); + + /** + \brief declare \c a and \c b are in total order. + + \pre a and b are of same type. + + def_API('Z3_mk_sr_to', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_sr_to(Z3_context c, Z3_ast a, Z3_ast b); + + /*@}*/ + /** @name Quantifiers */ /*@{*/ /** diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 8332baaf4..605390cf1 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -683,9 +683,12 @@ private: svector m_hybrid_visited, m_hybrid_parent; bool is_connected(numeral const& gamma, bool zero_edge, edge const& e, unsigned timestamp) const { - return (gamma.is_one() || (!zero_edge && gamma.is_neg())) && e.get_timestamp() < timestamp; + return (gamma.is_zero() || (!zero_edge && gamma.is_neg())) && e.get_timestamp() < timestamp; } + int_vector bfs_todo; + int_vector dfs_todo; + public: @@ -693,8 +696,8 @@ public: bool find_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { auto zero_edge = true; unsigned bfs_head = 0; - int_vector bfs_todo; - int_vector dfs_todo; + bfs_todo.reset(); + dfs_todo.reset(); m_hybrid_visited.resize(m_assignment.size(), m_run_counter++); m_hybrid_parent.resize(m_assignment.size(), -1); bfs_todo.push_back(source); diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 3750ce967..a4c73028e 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -213,17 +213,21 @@ namespace smt { theory_var w; // v2 !<= v1 is asserted target.insert(a.v2()); - if (r.m_graph.reachable(a.v1(), visited, target, w)) { + if (r.m_graph.reachable(a.v1(), target, visited, w)) { // we already have v1 <= v2 continue; } - target.reset(); - if (r.m_graph.reachable(a.v2(), target, visited, w)) { - // there is a common successor + // the nodes visited from v1 become target for v2 + if (r.m_graph.reachable(a.v2(), visited, target, w)) { + // we have the following: // v1 <= w // v2 <= w // v1 !<= v2 - // -> v1 <= w & v2 <= w & v1 !<= v2 -> v2 <= v1 + // + // enforce the assertion + // + // v1 <= w & v2 <= w & v1 !<= v2 -> v2 <= v1 + // unsigned timestamp = r.m_graph.get_timestamp(); r.m_explanation.reset(); r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r); @@ -297,7 +301,7 @@ namespace smt { u_map roots; context& ctx = get_context(); r.m_graph.compute_zero_edge_scc(scc_id); - for (unsigned i = 0, j = 0; i < scc_id.size(); ++i) { + for (unsigned i = 0, j = 0; !ctx.inconsistent() && i < scc_id.size(); ++i) { if (scc_id[i] == -1) { continue; } @@ -635,11 +639,11 @@ namespace smt { bool theory_special_relations::is_neighbour_edge(graph const& g, edge_id edge) const { CTRACE("special_relations_verbose", g.is_enabled(edge), tout << edge << ": " << g.get_source(edge) << " " << g.get_target(edge) << " "; - tout << (g.get_assignment(g.get_source(edge)) - g.get_assignment(g.get_target(edge))) << "\n";); + tout << (g.get_assignment(g.get_target(edge)) - g.get_assignment(g.get_source(edge))) << "\n";); return g.is_enabled(edge) && - g.get_assignment(g.get_source(edge)) - g.get_assignment(g.get_target(edge)) == s_integer(1); + g.get_assignment(g.get_source(edge)) + s_integer(1) == g.get_assignment(g.get_target(edge)); } bool theory_special_relations::is_strict_neighbour_edge(graph const& g, edge_id e) const { @@ -650,7 +654,7 @@ namespace smt { unsigned sz = g.get_num_nodes(); svector nodes; num_children.resize(sz, 0); - svector processed(sz, false); + svector processed(sz, false); for (unsigned i = 0; i < sz; ++i) nodes.push_back(i); while (!nodes.empty()) { dl_var v = nodes.back(); @@ -692,8 +696,8 @@ namespace smt { for (unsigned i = 0; i < sz; ++i) { bool is_root = true; int_vector const& edges = g.get_in_edges(i); - for (unsigned j = 0; is_root && j < edges.size(); ++j) { - is_root = !g.is_enabled(edges[j]); + for (edge_id e_id : edges) { + is_root &= !g.is_enabled(e_id); } if (is_root) { lo[i] = offset; @@ -739,7 +743,8 @@ namespace smt { init_model_po(*kv.m_value, m); break; default: - UNREACHABLE(); //ASHU: added to remove warning! Should be supported! + // other 28 combinations of 0x1F + NOT_IMPLEMENTED_YET(); } } } @@ -770,7 +775,7 @@ namespace smt { void theory_special_relations::display_atom(std::ostream & out, atom& a) const { context& ctx = get_context(); - expr* e = ctx.bool_var2expr( a.var() ); + expr* e = ctx.bool_var2expr(a.var()); out << (a.phase() ? "" : "(not ") << mk_pp(e, get_manager()) << (a.phase() ? "" : ")") << "\n"; } diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 01314b362..312d0d20b 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -52,9 +52,9 @@ namespace smt { r.ensure_var(v2); literal_vector ls; ls.push_back(literal(b, false)); - m_pos = r.m_graph.add_edge(v1, v2, s_integer(1), ls); // v2 <= v1 + m_pos = r.m_graph.add_edge(v1, v2, s_integer(0), ls); // v1 <= v2 ls[0] = literal(b, true); - m_neg = r.m_graph.add_edge(v2, v1, s_integer(-2), ls); // v1 <= v2 - 1 + m_neg = r.m_graph.add_edge(v2, v1, s_integer(-1), ls); // v2 + 1 <= v1 } bool_var var() const { return m_bvar;} relation& get_relation() const { return m_relation; } @@ -80,22 +80,24 @@ namespace smt { }; struct graph : public dl_graph { bool add_strict_edge(theory_var v1, theory_var v2, literal_vector const& j) { - return enable_edge(add_edge(v1, v2, s_integer(1), j)); + // v1 + 1 <= v2 + return enable_edge(add_edge(v1, v2, s_integer(-1), j)); } bool add_non_strict_edge(theory_var v1, theory_var v2, literal_vector const& j) { - return enable_edge(add_edge(v1, v2, s_integer(-2), j)); + // v1 <= v2 + return enable_edge(add_edge(v1, v2, s_integer(0), j)); } }; typedef union_find union_find_t; struct relation { - sr_property m_property; - func_decl* m_decl; - atoms m_asserted_atoms; // set of asserted atoms - unsigned m_asserted_qhead; - svector m_scopes; - graph m_graph; + sr_property m_property; + func_decl* m_decl; + atoms m_asserted_atoms; // set of asserted atoms + unsigned m_asserted_qhead; + svector m_scopes; + graph m_graph; union_find_default_ctx m_ufctx; union_find_t m_uf; literal_vector m_explanation; From 76cd8367dcdea9dafe7e9a0c1661a41210cf20ca Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 17:51:15 -0700 Subject: [PATCH 085/156] adding cmd_context Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 3 +++ src/cmd_context/cmd_context.cpp | 3 +++ src/smt/smt_setup.cpp | 6 ++++++ src/smt/smt_setup.h | 1 + 4 files changed, 13 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index e3995ddb5..267a24a20 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10353,3 +10353,6 @@ def Range(lo, hi, ctx = None): lo = _coerce_seq(lo, ctx) hi = _coerce_seq(hi, ctx) return ReRef(Z3_mk_re_range(lo.ctx_ref(), lo.ast, hi.ast), lo.ctx) + +# Special Relations + diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 9de183ca8..9fbeced71 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -31,6 +31,7 @@ Notes: #include "ast/pb_decl_plugin.h" #include "ast/fpa_decl_plugin.h" #include "ast/csp_decl_plugin.h" +#include "ast/special_relations_decl_plugin.h" #include "ast/ast_pp.h" #include "ast/rewriter/var_subst.h" #include "ast/pp.h" @@ -687,6 +688,7 @@ void cmd_context::init_manager_core(bool new_manager) { 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(csp_decl_plugin), smt_logics::logic_is_csp(m_logic)); + register_plugin(symbol("special_relations"), alloc(special_relations_decl_plugin), !has_logic()); } else { // the manager was created by an external module @@ -703,6 +705,7 @@ void cmd_context::init_manager_core(bool new_manager) { 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/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 731034921..89213c86d 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -33,6 +33,7 @@ Revision History: #include "smt/theory_dl.h" #include "smt/theory_seq_empty.h" #include "smt/theory_seq.h" +#include "smt/theory_special_relations.h" #include "smt/theory_pb.h" #include "smt/theory_fpa.h" #include "smt/theory_str.h" @@ -935,6 +936,10 @@ namespace smt { m_context.register_plugin(alloc(smt::theory_jobscheduler, m_manager)); } + void setup::setup_special_relations() { + m_context.register_plugin(alloc(smt::theory_special_relations, m_manager)); + } + void setup::setup_unknown() { static_features st(m_manager); ptr_vector fmls; @@ -950,6 +955,7 @@ namespace smt { setup_seq_str(st); setup_card(); setup_fpa(); + setup_special_relations(); } void setup::setup_unknown(static_features & st) { diff --git a/src/smt/smt_setup.h b/src/smt/smt_setup.h index 01a143301..53186f91c 100644 --- a/src/smt/smt_setup.h +++ b/src/smt/smt_setup.h @@ -82,6 +82,7 @@ namespace smt { void setup_QF_S(); void setup_LRA(); void setup_CSP(); + void setup_special_relations(); void setup_AUFLIA(bool simple_array = true); void setup_AUFLIA(static_features const & st); void setup_AUFLIRA(bool simple_array = true); From 63c63606ee772be3378fd881c600cac34b020d89 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 17:53:43 -0700 Subject: [PATCH 086/156] include path Signed-off-by: Nikolaj Bjorner --- src/ast/special_relations_decl_plugin.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ast/special_relations_decl_plugin.cpp b/src/ast/special_relations_decl_plugin.cpp index 6bb5734e5..b5a55cbb4 100644 --- a/src/ast/special_relations_decl_plugin.cpp +++ b/src/ast/special_relations_decl_plugin.cpp @@ -17,9 +17,9 @@ Revision History: --*/ -#include -#include"ast.h" -#include"special_relations_decl_plugin.h" +#include +#include "ast/ast.h" +#include "ast/special_relations_decl_plugin.h" @@ -37,11 +37,11 @@ func_decl * special_relations_decl_plugin::mk_func_decl( { if (arity != 2) { m_manager->raise_exception("special relations should have arity 2"); - return 0; + return nullptr; } if (domain[0] != domain[1]) { m_manager->raise_exception("argument sort missmatch"); - return 0; + return nullptr; } func_decl_info info(m_family_id, k, num_parameters, parameters); symbol name; From 6c96f855db0bbbb0ac31d17b20089cb57ee55dc2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 17:54:05 -0700 Subject: [PATCH 087/156] include path Signed-off-by: Nikolaj Bjorner --- src/ast/special_relations_decl_plugin.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index 068382b23..ef432dbcc 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -20,8 +20,7 @@ Revision History: #ifndef SPECIAL_RELATIONS_DECL_PLUGIN_H_ #define SPECIAL_RELATIONS_DECL_PLUGIN_H_ -#include"ast.h" - +#include "ast/ast.h" enum special_relations_op_kind { From 0ae3de99162ac52c79c77fcae7c9dec23285d1ba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 17:57:06 -0700 Subject: [PATCH 088/156] virtual -> override Signed-off-by: Nikolaj Bjorner --- src/ast/special_relations_decl_plugin.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index ef432dbcc..e8260e154 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -40,19 +40,19 @@ class special_relations_decl_plugin : public decl_plugin { symbol m_to; public: special_relations_decl_plugin(); - virtual ~special_relations_decl_plugin() {} - virtual decl_plugin * mk_fresh() { + ~special_relations_decl_plugin() override {} + + decl_plugin * mk_fresh() override { return alloc(special_relations_decl_plugin); } - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; - virtual void get_op_names(svector & op_names, symbol const & logic); - - - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { return 0; } + void get_op_names(svector & op_names, symbol const & logic) override; + + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override { return nullptr; } }; enum sr_property { From 8da1b024b7fc2352839b7783d498517d8b11106e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Mar 2019 04:30:29 -0700 Subject: [PATCH 089/156] fix #2205 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 1 - src/ast/datatype_decl_plugin.cpp | 19 ++++++----- src/ast/rewriter/th_rewriter.cpp | 1 + src/smt/smt_theory.cpp | 51 +++++++++++++++++++++++++++++ src/smt/smt_theory.h | 56 +++++--------------------------- src/smt/theory_datatype.cpp | 2 +- 6 files changed, 71 insertions(+), 59 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index c73e2f1d8..68d24d0a9 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1875,7 +1875,6 @@ void ast_manager::delete_node(ast * 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";); diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 146c7359f..71b35f914 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -454,23 +454,24 @@ namespace datatype { } void plugin::log_axiom_definitions(symbol const& s, sort * new_sort) { + std::ostream& out = m_manager->trace_stream(); symbol const& family_name = m_manager->get_family_name(get_family_id()); for (constructor const* c : *m_defs[s]) { func_decl_ref f = c->instantiate(new_sort); const unsigned num_args = f->get_arity(); if (num_args == 0) continue; for (unsigned i = 0; i < num_args; ++i) { - m_manager->trace_stream() << "[mk-var] " << family_name << "#" << m_id_counter << " " << i << "\n"; + out << "[mk-var] " << family_name << "#" << m_id_counter << " " << i << "\n"; ++m_id_counter; } const unsigned constructor_id = m_id_counter; - m_manager->trace_stream() << "[mk-app] " << family_name << "#" << constructor_id << " " << f->get_name(); + out << "[mk-app] " << family_name << "#" << constructor_id << " " << f->get_name(); for (unsigned i = 0; i < num_args; ++i) { - m_manager->trace_stream() << " " << family_name << "#" << constructor_id - num_args + i; + out << " " << family_name << "#" << constructor_id - num_args + i; } - m_manager->trace_stream() << "\n"; + out << "\n"; ++m_id_counter; - m_manager->trace_stream() << "[mk-app] " << family_name << "#" << m_id_counter << " pattern " << family_name << "#" << constructor_id << "\n"; + out << "[mk-app] " << family_name << "#" << m_id_counter << " pattern " << family_name << "#" << constructor_id << "\n"; ++m_id_counter; m_axiom_bases.insert(f->get_name(), constructor_id + 4); std::ostringstream var_sorts; @@ -481,14 +482,14 @@ namespace datatype { unsigned i = 0; for (accessor const* a : *c) { func_decl_ref acc = a->instantiate(new_sort); - m_manager->trace_stream() << "[mk-app] " << family_name << "#" << m_id_counter << " " << acc->get_name() << " " << family_name << "#" << constructor_id << "\n"; + out << "[mk-app] " << family_name << "#" << m_id_counter << " " << acc->get_name() << " " << family_name << "#" << constructor_id << "\n"; ++m_id_counter; - m_manager->trace_stream() << "[mk-app] " << family_name << "#" << m_id_counter << " = " << family_name << "#" << constructor_id - num_args + i + out << "[mk-app] " << family_name << "#" << m_id_counter << " = " << family_name << "#" << constructor_id - num_args + i << " " << family_name << "#" << m_id_counter - 1 << "\n"; ++m_id_counter; - m_manager->trace_stream() << "[mk-quant] " << family_name << "#" << m_id_counter << " constructor_accessor_axiom " << family_name << "#" << constructor_id + 1 + out << "[mk-quant] " << family_name << "#" << m_id_counter << " constructor_accessor_axiom " << family_name << "#" << constructor_id + 1 << " " << family_name << "#" << m_id_counter - 1 << "\n"; - m_manager->trace_stream() << "[attach-var-names] " << family_name << "#" << m_id_counter << var_description << "\n"; + out << "[attach-var-names] " << family_name << "#" << m_id_counter << var_description << "\n"; ++m_id_counter; ++i; } diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 1b586b4b6..9390e21ee 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -583,6 +583,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { m().trace_stream() << "[instance] " << static_cast(nullptr) << " #" << tmp->get_id() << "\n"; m().trace_stream() << "[attach-enode] #" << tmp->get_id() << " 0\n"; m().trace_stream() << "[end-of-instance]\n"; + m().trace_stream().flush(); } if (st != BR_DONE && st != BR_FAILED) { diff --git a/src/smt/smt_theory.cpp b/src/smt/smt_theory.cpp index 63c6d7417..b791991f2 100644 --- a/src/smt/smt_theory.cpp +++ b/src/smt/smt_theory.cpp @@ -137,5 +137,56 @@ namespace smt { theory::~theory() { } + + void theory::log_axiom_instantiation(app * r, unsigned axiom_id, unsigned num_bindings, app * const * bindings, unsigned pattern_id, const vector> & used_enodes) { + ast_manager & m = get_manager(); + std::ostream& out = m.trace_stream(); + symbol const & family_name = m.get_family_name(get_family_id()); + if (pattern_id == UINT_MAX) { + out << "[inst-discovered] theory-solving " << static_cast(nullptr) << " " << family_name << "#"; + if (axiom_id != UINT_MAX) + out << axiom_id; + for (unsigned i = 0; i < num_bindings; ++i) { + out << " #" << bindings[i]->get_id(); + } + if (used_enodes.size() > 0) { + out << " ;"; + for (auto n : used_enodes) { + enode *substituted = std::get<1>(n); + SASSERT(std::get<0>(n) == nullptr); + out << " #" << substituted->get_owner_id(); + } + } + } else { + SASSERT(axiom_id != UINT_MAX); + obj_hashtable already_visited; + for (auto n : used_enodes) { + enode *orig = std::get<0>(n); + enode *substituted = std::get<1>(n); + if (orig != nullptr) { + quantifier_manager::log_justification_to_root(out, orig, already_visited, get_context(), get_manager()); + quantifier_manager::log_justification_to_root(out, substituted, already_visited, get_context(), get_manager()); + } + } + out << "[new-match] " << static_cast(nullptr) << " " << family_name << "#" << axiom_id << " " << family_name << "#" << pattern_id; + for (unsigned i = 0; i < num_bindings; ++i) { + out << " #" << bindings[i]->get_id(); + } + out << " ;"; + for (auto n : used_enodes) { + enode *orig = std::get<0>(n); + enode *substituted = std::get<1>(n); + if (orig == nullptr) { + out << " #" << substituted->get_owner_id(); + } else { + out << " (#" << orig->get_owner_id() << " #" << substituted->get_owner_id() << ")"; + } + } + } + out << "\n"; + out << "[instance] " << static_cast(nullptr) << " #" << r->get_id() << "\n"; + out.flush(); + } + }; diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index f1f304fa6..92aa87163 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -360,55 +360,15 @@ namespace smt { std::ostream& display_var_flat_def(std::ostream & out, theory_var v) const { return display_flat_app(out, get_enode(v)->get_owner()); } protected: - void log_axiom_instantiation(app * r, unsigned axiom_id = UINT_MAX, unsigned num_bindings = 0, app * const * bindings = nullptr, unsigned pattern_id = UINT_MAX, const vector> & used_enodes = vector>()) { - ast_manager & m = get_manager(); - symbol const & family_name = m.get_family_name(get_family_id()); - if (pattern_id == UINT_MAX) { - m.trace_stream() << "[inst-discovered] theory-solving " << static_cast(nullptr) << " " << family_name << "#"; - if (axiom_id != UINT_MAX) - m.trace_stream() << axiom_id; - for (unsigned i = 0; i < num_bindings; ++i) { - m.trace_stream() << " #" << bindings[i]->get_id(); - } - if (used_enodes.size() > 0) { - m.trace_stream() << " ;"; - for (auto n : used_enodes) { - enode *substituted = std::get<1>(n); - SASSERT(std::get<0>(n) == nullptr); - m.trace_stream() << " #" << substituted->get_owner_id(); - } - } - } else { - SASSERT(axiom_id != UINT_MAX); - obj_hashtable already_visited; - for (auto n : used_enodes) { - enode *orig = std::get<0>(n); - enode *substituted = std::get<1>(n); - if (orig != nullptr) { - quantifier_manager::log_justification_to_root(m.trace_stream(), orig, already_visited, get_context(), get_manager()); - quantifier_manager::log_justification_to_root(m.trace_stream(), substituted, already_visited, get_context(), get_manager()); - } - } - m.trace_stream() << "[new-match] " << static_cast(nullptr) << " " << family_name << "#" << axiom_id << " " << family_name << "#" << pattern_id; - for (unsigned i = 0; i < num_bindings; ++i) { - m.trace_stream() << " #" << bindings[i]->get_id(); - } - m.trace_stream() << " ;"; - for (auto n : used_enodes) { - enode *orig = std::get<0>(n); - enode *substituted = std::get<1>(n); - if (orig == nullptr) { - m.trace_stream() << " #" << substituted->get_owner_id(); - } else { - m.trace_stream() << " (#" << orig->get_owner_id() << " #" << substituted->get_owner_id() << ")"; - } - } - } - m.trace_stream() << "\n"; - m.trace_stream() << "[instance] " << static_cast(nullptr) << " #" << r->get_id() << "\n"; - } + void log_axiom_instantiation(app * r, unsigned axiom_id = UINT_MAX, unsigned num_bindings = 0, + app * const * bindings = nullptr, unsigned pattern_id = UINT_MAX, + const vector> & used_enodes = vector>()); - void log_axiom_instantiation(expr * r, unsigned axiom_id = UINT_MAX, unsigned num_bindings = 0, app * const * bindings = nullptr, unsigned pattern_id = UINT_MAX, const vector> & used_enodes = vector>()) { log_axiom_instantiation(to_app(r), axiom_id, num_bindings, bindings, pattern_id, used_enodes); } + void log_axiom_instantiation(expr * r, unsigned axiom_id = UINT_MAX, unsigned num_bindings = 0, + app * const * bindings = nullptr, unsigned pattern_id = UINT_MAX, + const vector> & used_enodes = vector>()) { + log_axiom_instantiation(to_app(r), axiom_id, num_bindings, bindings, pattern_id, used_enodes); + } void log_axiom_instantiation(app * r, unsigned num_blamed_enodes, enode ** blamed_enodes) { vector> used_enodes; diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index f26791639..9e941fcd5 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -139,7 +139,7 @@ namespace smt { expr * acc = m.mk_app(d, n->get_owner()); args.push_back(acc); } - expr * mk = m.mk_app(c, args.size(), args.c_ptr()); + expr_ref mk(m.mk_app(c, args.size(), args.c_ptr()), m); if (m.has_trace_stream()) { app_ref body(m); body = m.mk_eq(n->get_owner(), mk); From fa97f4a62620f8758d74c5d678e674d4e5ae3d41 Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Tue, 26 Mar 2019 14:16:31 +0000 Subject: [PATCH 090/156] fix name clash in ocaml api --- src/api/ml/z3.ml | 2 +- src/api/ml/z3.mli | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 5fb87bf64..50735a57c 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -717,7 +717,7 @@ struct else mk_exists ctx sorts names body weight patterns nopatterns quantifier_id skolem_id - let mk_quantifier (ctx:context) (universal:bool) (bound_constants:expr list) (body:expr) (weight:int option) (patterns:Pattern.pattern list) (nopatterns:expr list) (quantifier_id:Symbol.symbol option) (skolem_id:Symbol.symbol option) = + let mk_quantifier_const (ctx:context) (universal:bool) (bound_constants:expr list) (body:expr) (weight:int option) (patterns:Pattern.pattern list) (nopatterns:expr list) (quantifier_id:Symbol.symbol option) (skolem_id:Symbol.symbol option) = if universal then mk_forall_const ctx bound_constants body weight patterns nopatterns quantifier_id skolem_id else diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 4b6d8bc25..f93769731 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -746,7 +746,7 @@ sig 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 (** Create a Quantifier. *) - val mk_quantifier : context -> bool -> Expr.expr list -> Expr.expr -> int option -> Pattern.pattern list -> Expr.expr list -> Symbol.symbol option -> Symbol.symbol option -> quantifier + val mk_quantifier_const : context -> bool -> Expr.expr list -> Expr.expr -> int option -> Pattern.pattern list -> Expr.expr list -> Symbol.symbol option -> Symbol.symbol option -> quantifier (** A string representation of the quantifier. *) val to_string : quantifier -> string From 9008beeb01e6450068937ce1f89053e4e670674f Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Tue, 26 Mar 2019 14:33:20 +0000 Subject: [PATCH 091/156] fix mk_quantifier signature --- src/api/ml/z3.mli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index f93769731..69dbfa23d 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -743,7 +743,7 @@ sig 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 + val mk_quantifier : context -> bool -> Sort.sort list -> Symbol.symbol list -> Expr.expr -> int option -> Pattern.pattern list -> Expr.expr list -> Symbol.symbol option -> Symbol.symbol option -> quantifier (** Create a Quantifier. *) val mk_quantifier_const : context -> bool -> Expr.expr list -> Expr.expr -> int option -> Pattern.pattern list -> Expr.expr list -> Symbol.symbol option -> Symbol.symbol option -> quantifier From b89cd9aea6052711852b8dc090c5e8e21eab9e99 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Mar 2019 08:15:26 -0700 Subject: [PATCH 092/156] display methods Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 22 ++++++++++++++-------- src/smt/theory_special_relations.h | 2 ++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index a4c73028e..d56844ad9 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -64,6 +64,17 @@ namespace smt { return m_graph.add_non_strict_edge(v1, v2, ls) && m_graph.add_non_strict_edge(v2, v1, ls); } + std::ostream& theory_special_relations::relation::display(theory_special_relations const& th, std::ostream& out) const { + out << m_decl->get_name() << ":\n"; + m_graph.display(out); + out << "explanation: " << m_explanation << "\n"; + m_uf.display(out); + for (atom* ap : m_asserted_atoms) { + th.display_atom(out, *ap); + } + return out; + } + theory_special_relations::theory_special_relations(ast_manager& m): theory(m.mk_family_id("special_relations")), m_util(m) { @@ -94,7 +105,7 @@ namespace smt { ctx.set_var_theory(v, get_id()); atom* a = alloc(atom, v, *r, v0, v1); m_atoms.push_back(a); - TRACE("special_relations", tout << mk_pp(atm, get_manager()) << " : " << a->v1() << ' ' << a->v2() << ' ' << gate_ctx << "\n";); + TRACE("special_relations", tout << mk_pp(atm, get_manager()) << " : bv" << v << " v" << a->v1() << " v" << a->v2() << ' ' << gate_ctx << "\n";); m_bool_var2atom.insert(v, a); return true; } @@ -291,7 +302,7 @@ namespace smt { UNREACHABLE(); res = l_undef; } - + TRACE("special_relations", r.display(*this, tout);); return res; } @@ -754,12 +765,7 @@ namespace smt { out << "Theory Special Relations\n"; display_var2enode(out); for (auto const& kv : m_relations) { - out << mk_pp(kv.m_value->decl(), get_manager()) << ":\n"; - kv.m_value->m_graph.display(out); - kv.m_value->m_uf.display(out); - for (atom* ap : kv.m_value->m_asserted_atoms) { - display_atom(out, *ap); - } + kv.m_value->display(*this, out); } } diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 312d0d20b..81a968e54 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -116,6 +116,8 @@ namespace smt { bool add_strict_edge(theory_var v1, theory_var v2, literal_vector const& j); bool add_non_strict_edge(theory_var v1, theory_var v2, literal_vector const& j); + + std::ostream& display(theory_special_relations const& sr, std::ostream& out) const; }; From fde7283bb9e496b88c072196655e3b54efaf9ae6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Mar 2019 08:39:56 -0700 Subject: [PATCH 093/156] support indexed relations Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 1 - src/api/api_special_relations.cpp | 20 +++++++++--- src/api/c++/z3++.h | 39 +++++++---------------- src/api/z3_api.h | 34 ++++++++------------ src/ast/special_relations_decl_plugin.cpp | 4 --- src/ast/special_relations_decl_plugin.h | 4 --- src/smt/theory_special_relations.cpp | 6 +++- 7 files changed, 45 insertions(+), 63 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index a8f62572a..999ebab6b 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1056,7 +1056,6 @@ extern "C" { switch(_d->get_decl_kind()) { case OP_SPECIAL_RELATION_LO : return Z3_OP_SPECIAL_RELATION_LO; case OP_SPECIAL_RELATION_PO : return Z3_OP_SPECIAL_RELATION_PO; - case OP_SPECIAL_RELATION_PO_AO : return Z3_OP_SPECIAL_RELATION_PO_AO; case OP_SPECIAL_RELATION_PLO: return Z3_OP_SPECIAL_RELATION_PLO; case OP_SPECIAL_RELATION_TO : return Z3_OP_SPECIAL_RELATION_TO; default: UNREACHABLE(); diff --git a/src/api/api_special_relations.cpp b/src/api/api_special_relations.cpp index 40fde5083..e852c2b34 100644 --- a/src/api/api_special_relations.cpp +++ b/src/api/api_special_relations.cpp @@ -68,11 +68,21 @@ extern "C" { Z3_CATCH_RETURN(false); } #endif +#define MK_TERN(NAME, FID) \ + Z3_ast Z3_API NAME(Z3_context c, unsigned index, Z3_ast a, Z3_ast b) { \ + LOG_ ##NAME(c, index, a, b); \ + Z3_TRY; \ + expr* args[2] = { to_expr(a), to_expr(b) }; \ + parameter p(index); \ + ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_special_relations_fid(), FID, 1, &p, 2, args); \ + mk_c(c)->save_ast_trail(a); \ + RETURN_Z3(of_ast(a)); \ + Z3_CATCH_RETURN(nullptr); \ +} - MK_BINARY(Z3_mk_sr_lo , mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_LO, SKIP); - MK_BINARY(Z3_mk_sr_po , mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_PO, SKIP); - MK_BINARY(Z3_mk_sr_po_ao,mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_PO_AO,SKIP); - MK_BINARY(Z3_mk_sr_plo, mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_PLO, SKIP); - MK_BINARY(Z3_mk_sr_to , mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_TO, SKIP); + MK_TERN(Z3_mk_linear_order, OP_SPECIAL_RELATION_LO); + MK_TERN(Z3_mk_partial_order, OP_SPECIAL_RELATION_PO); + MK_TERN(Z3_mk_piecewise_linear_order, OP_SPECIAL_RELATION_PLO); + MK_TERN(Z3_mk_tree_order, OP_SPECIAL_RELATION_TO); }; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index e18ca9204..8df43d477 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1707,42 +1707,27 @@ namespace z3 { */ inline expr sext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_sign_ext(a.ctx(), i, a)); } - inline expr sr_lo(expr const& a, expr const& b) { + typedef Z3_ast Z3_apply_order(Z3_context, unsigned, Z3_ast, Z3_ast); + + inline expr apply_order(Z3_apply_order app, unsigned index, expr const& a, expr const& b) { check_context(a, b); - Z3_ast r = Z3_mk_sr_lo(a.ctx(), a, b); + Z3_ast r = app(a.ctx(), index, a, b); a.check_error(); return expr(a.ctx(), r); } - - inline expr sr_po(expr const& a, expr const& b) { - check_context(a, b); - Z3_ast r = Z3_mk_sr_po(a.ctx(), a, b); - a.check_error(); - return expr(a.ctx(), r); + inline expr linear_order(unsigned index, expr const& a, expr const& b) { + return apply_order(Z3_mk_linear_order, index, a, b); } - - inline expr sr_po_ao(expr const& a, expr const& b) { - check_context(a, b); - Z3_ast r = Z3_mk_sr_po_ao(a.ctx(), a, b); - a.check_error(); - return expr(a.ctx(), r); + inline expr partial_order(unsigned index, expr const& a, expr const& b) { + return apply_order(Z3_mk_partial_order, index, a, b); } - - inline expr sr_plo(expr const& a, expr const& b) { - check_context(a, b); - Z3_ast r = Z3_mk_sr_plo(a.ctx(), a, b); - a.check_error(); - return expr(a.ctx(), r); + inline expr piecewise_linear_order(unsigned index, expr const& a, expr const& b) { + return apply_order(Z3_mk_piecewise_linear_order, index, a, b); } - - inline expr sr_to(expr const& a, expr const& b) { - check_context(a, b); - Z3_ast r = Z3_mk_sr_to(a.ctx(), a, b); - a.check_error(); - return expr(a.ctx(), r); + inline expr tree_order(unsigned index, expr const& a, expr const& b) { + return apply_order(Z3_mk_tree_order, index, a, b); } - template class cast_ast; template<> class cast_ast { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 6d1db22b3..7ba33a61d 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3608,49 +3608,41 @@ extern "C" { /** @name Special relations */ /*@{*/ /** - \brief declare \c a and \c b are in linear order. + \brief declare \c a and \c b are in linear order over a relation indexed by \c id. \pre a and b are of same type. + - def_API('Z3_mk_sr_lo', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + def_API('Z3_mk_linear_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) */ - Z3_ast Z3_API Z3_mk_sr_lo(Z3_context c, Z3_ast a, Z3_ast b); + Z3_ast Z3_API Z3_mk_linear_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); /** - \brief declare \c a and \c b are in partial order. + \brief declare \c a and \c b are in partial order over a relation indexed by \c id. \pre a and b are of same type. - def_API('Z3_mk_sr_po', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + def_API('Z3_mk_partial_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) */ - Z3_ast Z3_API Z3_mk_sr_po(Z3_context c, Z3_ast a, Z3_ast b); + Z3_ast Z3_API Z3_mk_partial_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); /** - \brief declare \c a and \c b are already partial ordered. + \brief declare \c a and \c b are in piecewise linear order indexed by relation \c id. \pre a and b are of same type. - def_API('Z3_mk_sr_po_ao', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + def_API('Z3_mk_piecewise_linear_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) */ - Z3_ast Z3_API Z3_mk_sr_po_ao(Z3_context c, Z3_ast a, Z3_ast b); + Z3_ast Z3_API Z3_mk_piecewise_linear_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); /** - \brief declare \c a and \c b are in piecewise linear order. + \brief declare \c a and \c b are in tree order indexed by \c id. \pre a and b are of same type. - def_API('Z3_mk_sr_plo', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + def_API('Z3_mk_tree_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) */ - Z3_ast Z3_API Z3_mk_sr_plo(Z3_context c, Z3_ast a, Z3_ast b); - - /** - \brief declare \c a and \c b are in total order. - - \pre a and b are of same type. - - def_API('Z3_mk_sr_to', AST ,(_in(CONTEXT), _in(AST), _in(AST))) - */ - Z3_ast Z3_API Z3_mk_sr_to(Z3_context c, Z3_ast a, Z3_ast b); + Z3_ast Z3_API Z3_mk_tree_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); /*@}*/ diff --git a/src/ast/special_relations_decl_plugin.cpp b/src/ast/special_relations_decl_plugin.cpp index b5a55cbb4..6dd0af1b4 100644 --- a/src/ast/special_relations_decl_plugin.cpp +++ b/src/ast/special_relations_decl_plugin.cpp @@ -26,7 +26,6 @@ Revision History: special_relations_decl_plugin::special_relations_decl_plugin(): m_lo("linear-order"), m_po("partial-order"), - m_po_ao("partial-order-already-ordered"), m_plo("piecewise-linear-order"), m_to("tree-order") {} @@ -47,7 +46,6 @@ func_decl * special_relations_decl_plugin::mk_func_decl( symbol name; switch(k) { case OP_SPECIAL_RELATION_PO: name = m_po; break; - case OP_SPECIAL_RELATION_PO_AO: name = m_po_ao; break; case OP_SPECIAL_RELATION_LO: name = m_lo; break; case OP_SPECIAL_RELATION_PLO: name = m_plo; break; case OP_SPECIAL_RELATION_TO: name = m_to; break; @@ -58,7 +56,6 @@ func_decl * special_relations_decl_plugin::mk_func_decl( void special_relations_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { if (logic == symbol::null) { op_names.push_back(builtin_name(m_po.bare_str(), OP_SPECIAL_RELATION_PO)); - op_names.push_back(builtin_name(m_po_ao.bare_str(), OP_SPECIAL_RELATION_PO_AO)); op_names.push_back(builtin_name(m_lo.bare_str(), OP_SPECIAL_RELATION_LO)); op_names.push_back(builtin_name(m_plo.bare_str(), OP_SPECIAL_RELATION_PLO)); op_names.push_back(builtin_name(m_to.bare_str(), OP_SPECIAL_RELATION_TO)); @@ -68,7 +65,6 @@ void special_relations_decl_plugin::get_op_names(svector & op_name sr_property special_relations_util::get_property(func_decl* f) const { switch (f->get_decl_kind()) { case OP_SPECIAL_RELATION_PO: return sr_po; - case OP_SPECIAL_RELATION_PO_AO: return sr_po; // still partial ordered case OP_SPECIAL_RELATION_LO: return sr_lo; case OP_SPECIAL_RELATION_PLO: return sr_plo; case OP_SPECIAL_RELATION_TO: return sr_to; diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index e8260e154..dbdd61805 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -26,7 +26,6 @@ Revision History: enum special_relations_op_kind { OP_SPECIAL_RELATION_LO, OP_SPECIAL_RELATION_PO, - OP_SPECIAL_RELATION_PO_AO, OP_SPECIAL_RELATION_PLO, OP_SPECIAL_RELATION_TO, LAST_SPECIAL_RELATIONS_OP @@ -35,7 +34,6 @@ enum special_relations_op_kind { class special_relations_decl_plugin : public decl_plugin { symbol m_lo; symbol m_po; - symbol m_po_ao; symbol m_plo; symbol m_to; public: @@ -80,13 +78,11 @@ public: bool is_lo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_LO); } bool is_po(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO); } - bool is_po_ao(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO_AO); } bool is_plo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PLO); } bool is_to(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TO); } app * mk_lo (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_LO, arg1, arg2); } app * mk_po (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO, arg1, arg2); } - app * mk_po_ao (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO_AO, arg1, arg2); } app * mk_plo(expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PLO, arg1, arg2); } app * mk_to (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_TO, arg1, arg2); } diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index d56844ad9..65d30cea6 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -65,7 +65,11 @@ namespace smt { } std::ostream& theory_special_relations::relation::display(theory_special_relations const& th, std::ostream& out) const { - out << m_decl->get_name() << ":\n"; + out << mk_pp(m_decl, th.get_manager()); + for (unsigned i = 0; i < m_decl->get_num_parameters(); ++i) { + th.get_manager().display(out << " ", m_decl->get_parameter(i)); + } + out << ":\n"; m_graph.display(out); out << "explanation: " << m_explanation << "\n"; m_uf.display(out); From 5478955199e7b8996f10f91a35710b1f5c0d30b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Mar 2019 16:19:36 -0700 Subject: [PATCH 094/156] disable cancelation during propagation at base level Signed-off-by: Nikolaj Bjorner --- src/model/func_interp.cpp | 2 +- src/smt/smt_cg_table.cpp | 181 ++++++++++++++++++-------------- src/smt/smt_cg_table.h | 155 ++------------------------- src/smt/smt_context.cpp | 89 ++++++---------- src/smt/smt_context.h | 1 + src/smt/smt_model_generator.cpp | 8 +- src/util/trace.cpp | 1 + 7 files changed, 149 insertions(+), 288 deletions(-) diff --git a/src/model/func_interp.cpp b/src/model/func_interp.cpp index f981270b6..e1d90516c 100644 --- a/src/model/func_interp.cpp +++ b/src/model/func_interp.cpp @@ -203,7 +203,7 @@ void func_interp::insert_new_entry(expr * const * args, expr * r) { } tout << "Old: " << mk_ismt2_pp(get_entry(args)->get_result(), m_manager) << "\n"; ); - SASSERT(get_entry(args) == 0); + SASSERT(get_entry(args) == nullptr); func_entry * new_entry = func_entry::mk(m_manager, m_arity, args, r); if (!new_entry->args_are_values()) m_args_are_values = false; diff --git a/src/smt/smt_cg_table.cpp b/src/smt/smt_cg_table.cpp index b85fed02d..c969cc559 100644 --- a/src/smt/smt_cg_table.cpp +++ b/src/smt/smt_cg_table.cpp @@ -22,81 +22,6 @@ Revision History: namespace smt { -#if 0 - unsigned cg_table::cg_hash::operator()(enode * n) const { - if (n->is_commutative()) { - return combine_hash(n->get_decl_id(), - n->get_arg(0)->get_root()->hash() * - n->get_arg(1)->get_root()->hash()); - } - else { - unsigned num = n->get_num_args(); - switch (num) { - case 0: UNREACHABLE(); return 0; - case 1: - return combine_hash(n->get_decl_id(), n->get_arg(0)->get_root()->hash()); - case 2: { - unsigned a = n->get_decl_id(); - unsigned b = n->get_arg(0)->get_root()->hash(); - unsigned c = n->get_arg(1)->get_root()->hash(); - mix(a,b,c); - return c; - } - default: - return get_composite_hash(n, n->get_num_args(), m_khasher, m_chasher); - } - } - } - - bool cg_table::cg_eq::operator()(enode * n1, enode * n2) const { -#if 0 - static unsigned counter = 0; - static unsigned failed = 0; - bool r = congruent(n1, n2, m_commutativity); - if (!r) - failed++; - counter++; - if (counter % 100000 == 0) - std::cout << "cg_eq: " << counter << " " << failed << "\n"; - return r; -#else - return congruent(n1, n2, m_commutativity); -#endif - } - - cg_table::cg_table(ast_manager & m): - m_manager(m), - m_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY, cg_hash(), cg_eq(m_commutativity)) { - } - - void cg_table::display(std::ostream & out) const { - out << "congruence table:\n"; - for (enode * n : m_table) { - out << mk_pp(n->get_owner(), m_manager) << "\n"; - } - } - - void cg_table::display_compact(std::ostream & out) const { - if (!m_table.empty()) { - out << "congruence table:\n"; - for (enode * n : m_table) { - out << "#" << n->get_owner()->get_id() << " "; - } - out << "\n"; - } - } - -#ifdef Z3DEBUG - bool cg_table::check_invariant() const { - for (enode * n : m_table) { - CTRACE("cg_table", !contains_ptr(n), tout << "#" << n->get_owner_id() << "\n";); - SASSERT(contains_ptr(n)); - } - return true; - } -#endif - -#else // one table per func_decl implementation unsigned cg_table::cg_hash::operator()(enode * n) const { SASSERT(n->get_decl()->is_flat_associative() || n->get_num_args() >= 3); @@ -222,18 +147,116 @@ namespace smt { } void cg_table::display(std::ostream & out) const { + for (auto const& kv : m_func_decl2id) { + void * t = m_tables[kv.m_value]; + out << mk_pp(kv.m_key, m_manager) << ": "; + switch (GET_TAG(t)) { + case UNARY: + display_unary(out, t); + break; + case BINARY: + display_binary(out, t); + break; + case BINARY_COMM: + display_binary_comm(out, t); + break; + case NARY: + display_nary(out, t); + break; + } + } } + void cg_table::display_binary(std::ostream& out, void* t) const { + binary_table* tb = UNTAG(binary_table*, t); + out << "b "; + for (enode* n : *tb) { + out << n->get_owner_id() << " " << cg_binary_hash()(n) << " "; + } + out << "\n"; + } + + void cg_table::display_binary_comm(std::ostream& out, void* t) const { + comm_table* tb = UNTAG(comm_table*, t); + out << "bc "; + for (enode* n : *tb) { + out << n->get_owner_id() << " "; + } + out << "\n"; + } + + void cg_table::display_unary(std::ostream& out, void* t) const { + unary_table* tb = UNTAG(unary_table*, t); + out << "un "; + for (enode* n : *tb) { + out << n->get_owner_id() << " "; + } + out << "\n"; + } + + void cg_table::display_nary(std::ostream& out, void* t) const { + table* tb = UNTAG(table*, t); + out << "nary "; + for (enode* n : *tb) { + out << n->get_owner_id() << " "; + } + out << "\n"; + } + + + enode_bool_pair cg_table::insert(enode * n) { + // it doesn't make sense to insert a constant. + SASSERT(n->get_num_args() > 0); + SASSERT(!m_manager.is_and(n->get_owner())); + SASSERT(!m_manager.is_or(n->get_owner())); + enode * n_prime; + void * t = get_table(n); + switch (static_cast(GET_TAG(t))) { + case UNARY: + n_prime = UNTAG(unary_table*, t)->insert_if_not_there(n); + return enode_bool_pair(n_prime, false); + case BINARY: + n_prime = UNTAG(binary_table*, t)->insert_if_not_there(n); + TRACE("cg_table", tout << "insert: " << n->get_owner_id() << " " << cg_binary_hash()(n) << " inserted: " << (n == n_prime) << " " << n_prime->get_owner_id() << "\n"; + display_binary(tout, t); tout << "contains_ptr: " << contains_ptr(n) << "\n";); + return enode_bool_pair(n_prime, false); + case BINARY_COMM: + m_commutativity = false; + n_prime = UNTAG(comm_table*, t)->insert_if_not_there(n); + return enode_bool_pair(n_prime, m_commutativity); + default: + n_prime = UNTAG(table*, t)->insert_if_not_there(n); + return enode_bool_pair(n_prime, false); + } + } + + void cg_table::erase(enode * n) { + SASSERT(n->get_num_args() > 0); + void * t = get_table(n); + switch (static_cast(GET_TAG(t))) { + case UNARY: + UNTAG(unary_table*, t)->erase(n); + break; + case BINARY: + TRACE("cg_table", tout << "erase: " << n->get_owner_id() << " " << cg_binary_hash()(n) << " contains: " << contains_ptr(n) << "\n";); + UNTAG(binary_table*, t)->erase(n); + break; + case BINARY_COMM: + UNTAG(comm_table*, t)->erase(n); + break; + default: + UNTAG(table*, t)->erase(n); + break; + } + } + + void cg_table::display_compact(std::ostream & out) const { } -#ifdef Z3DEBUG bool cg_table::check_invariant() const { return true; } -#endif - -#endif }; diff --git a/src/smt/smt_cg_table.h b/src/smt/smt_cg_table.h index 4085ccc5f..78babf3b3 100644 --- a/src/smt/smt_cg_table.h +++ b/src/smt/smt_cg_table.h @@ -27,89 +27,6 @@ namespace smt { typedef std::pair enode_bool_pair; -#if 0 - /** - \brief Congruence table. - */ - class cg_table { - struct cg_khasher { - unsigned operator()(enode const * n) const { return n->get_decl_id(); } - }; - - struct cg_chasher { - unsigned operator()(enode const * n, unsigned idx) const { - return n->get_arg(idx)->get_root()->hash(); - } - }; - - struct cg_hash { - cg_khasher m_khasher; - cg_chasher m_chasher; - public: - unsigned operator()(enode * n) const; - }; - - struct cg_eq { - bool & m_commutativity; - cg_eq(bool & comm):m_commutativity(comm) {} - bool operator()(enode * n1, enode * n2) const; - }; - - typedef ptr_hashtable table; - - ast_manager & m_manager; - bool m_commutativity; //!< true if the last found congruence used commutativity - table m_table; - public: - cg_table(ast_manager & m); - - /** - \brief Try to insert n into the table. If the table already - contains an element n' congruent to n, then do nothing and - return n' and a boolean indicating whether n and n' are congruence - modulo commutativity, otherwise insert n and return (n,false). - */ - enode_bool_pair insert(enode * n) { - // it doesn't make sense to insert a constant. - SASSERT(n->get_num_args() > 0); - m_commutativity = false; - enode * n_prime = m_table.insert_if_not_there(n); - SASSERT(contains(n)); - return enode_bool_pair(n_prime, m_commutativity); - } - - void erase(enode * n) { - SASSERT(n->get_num_args() > 0); - m_table.erase(n); - SASSERT(!contains(n)); - } - - bool contains(enode * n) const { - return m_table.contains(n); - } - - enode * find(enode * n) const { - enode * r = 0; - return m_table.find(n, r) ? r : 0; - } - - bool contains_ptr(enode * n) const { - enode * n_prime; - return m_table.find(n, n_prime) && n == n_prime; - } - - void reset() { - m_table.reset(); - } - - void display(std::ostream & out) const; - - void display_compact(std::ostream & out) const; -#ifdef Z3DEBUG - bool check_invariant() const; -#endif - }; -#else // one table per function symbol /** @@ -137,9 +54,6 @@ namespace smt { struct cg_binary_hash { unsigned operator()(enode * n) const { SASSERT(n->get_num_args() == 2); - // too many collisions - // unsigned r = 17 + n->get_arg(0)->get_root()->hash(); - // return r * 31 + n->get_arg(1)->get_root()->hash(); return combine_hash(n->get_arg(0)->get_root()->hash(), n->get_arg(1)->get_root()->hash()); } }; @@ -149,23 +63,9 @@ namespace smt { SASSERT(n1->get_num_args() == 2); SASSERT(n2->get_num_args() == 2); SASSERT(n1->get_decl() == n2->get_decl()); -#if 1 return n1->get_arg(0)->get_root() == n2->get_arg(0)->get_root() && n1->get_arg(1)->get_root() == n2->get_arg(1)->get_root(); -#else - bool r = - n1->get_arg(0)->get_root() == n2->get_arg(0)->get_root() && - n1->get_arg(1)->get_root() == n2->get_arg(1)->get_root(); - static unsigned counter = 0; - static unsigned failed = 0; - if (!r) - failed++; - counter++; - if (counter % 100000 == 0) - std::cerr << "[cg_eq] " << counter << " " << failed << "\n"; - return r; -#endif } }; @@ -249,48 +149,9 @@ namespace smt { return n' and a boolean indicating whether n and n' are congruence modulo commutativity, otherwise insert n and return (n,false). */ - enode_bool_pair insert(enode * n) { - // it doesn't make sense to insert a constant. - SASSERT(n->get_num_args() > 0); - SASSERT(!m_manager.is_and(n->get_owner())); - SASSERT(!m_manager.is_or(n->get_owner())); - enode * n_prime; - void * t = get_table(n); - switch (static_cast(GET_TAG(t))) { - case UNARY: - n_prime = UNTAG(unary_table*, t)->insert_if_not_there(n); - return enode_bool_pair(n_prime, false); - case BINARY: - n_prime = UNTAG(binary_table*, t)->insert_if_not_there(n); - return enode_bool_pair(n_prime, false); - case BINARY_COMM: - m_commutativity = false; - n_prime = UNTAG(comm_table*, t)->insert_if_not_there(n); - return enode_bool_pair(n_prime, m_commutativity); - default: - n_prime = UNTAG(table*, t)->insert_if_not_there(n); - return enode_bool_pair(n_prime, false); - } - } + enode_bool_pair insert(enode * n); - void erase(enode * n) { - SASSERT(n->get_num_args() > 0); - void * t = get_table(n); - switch (static_cast(GET_TAG(t))) { - case UNARY: - UNTAG(unary_table*, t)->erase(n); - break; - case BINARY: - UNTAG(binary_table*, t)->erase(n); - break; - case BINARY_COMM: - UNTAG(comm_table*, t)->erase(n); - break; - default: - UNTAG(table*, t)->erase(n); - break; - } - } + void erase(enode * n); bool contains(enode * n) const { SASSERT(n->get_num_args() > 0); @@ -343,13 +204,19 @@ namespace smt { void display(std::ostream & out) const; + void display_binary(std::ostream& out, void* t) const; + + void display_binary_comm(std::ostream& out, void* t) const; + + void display_unary(std::ostream& out, void* t) const; + + void display_nary(std::ostream& out, void* t) const; + void display_compact(std::ostream & out) const; -#ifdef Z3DEBUG + bool check_invariant() const; -#endif }; -#endif }; #endif /* SMT_CG_TABLE_H_ */ diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 5715e067d..63979e657 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -86,7 +86,8 @@ namespace smt { m_generation(0), m_last_search_result(l_undef), m_last_search_failure(UNKNOWN), - m_searching(false) { + m_searching(false), + m_propagating(false) { SASSERT(m_scope_lvl == 0); SASSERT(m_base_lvl == 0); @@ -131,8 +132,13 @@ namespace smt { return literal(v, lit.sign()); } + /** + \brief retrieve flag for when cancelation is possible. + Cancelation is not safe during propagation at base level because + congruences cannot be retracted to a consistent state. + */ bool context::get_cancel_flag() { - return !m_manager.limit().inc(); + return !m_manager.limit().inc() && !(at_base_level() && m_propagating); } void context::updt_params(params_ref const& p) { @@ -548,14 +554,10 @@ namespace smt { mark_as_relevant(r1); } - TRACE("add_eq", tout << "to trail\n";); - push_trail(add_eq_trail(r1, n1, r2->get_num_parents())); - TRACE("add_eq", tout << "qmanager add_eq\n";); m_qmanager->add_eq_eh(r1, r2); - TRACE("add_eq", tout << "merge theory_vars\n";); merge_theory_vars(n2, n1, js); // 'Proof' tree @@ -571,25 +573,6 @@ namespace smt { // r1 -> .. -> n1 -> n2 -> ... -> r2 -#if 0 - { - static unsigned counter = 0; - static unsigned num_adds = 0; - static unsigned num_bad_adds = 0; - num_adds++; - if (r1->get_class_size() <= r2->get_class_size() && - r1->m_parents.size() > r2->m_parents.size()) { - num_bad_adds++; - } - if (num_adds % 100000 == 0) { - verbose_stream() << "[add-eq]: " << num_bad_adds << " " << num_adds << " " - << static_cast(num_bad_adds)/static_cast(num_adds) << "\n"; - } - } -#endif - - - TRACE("add_eq", tout << "remove_parents_from_cg_table\n";); remove_parents_from_cg_table(r1); enode * curr = r1; @@ -600,11 +583,8 @@ namespace smt { while(curr != r1); SASSERT(r1->get_root() == r2); - - TRACE("add_eq", tout << "reinsert_parents_into_cg_table\n";); reinsert_parents_into_cg_table(r1, r2, n1, n2, js); - TRACE("add_eq", tout << "propagate_bool_enode_assignment\n";); if (n2->is_bool()) propagate_bool_enode_assignment(r1, r2, n1, n2); @@ -632,25 +612,21 @@ namespace smt { void context::remove_parents_from_cg_table(enode * r1) { // Remove parents from the congruence table for (enode * parent : enode::parents(r1)) { -#if 0 - { - static unsigned num_eqs = 0; - static unsigned num_parents = 0; - static unsigned counter = 0; - if (parent->is_eq()) - num_eqs++; - num_parents++; - if (num_parents % 100000 == 0) { - verbose_stream() << "[remove-cg] " << num_eqs << " " << num_parents << " " - << static_cast(num_eqs)/static_cast(num_parents) << "\n"; - } - } -#endif - SASSERT(parent->is_marked() || !parent->is_cgc_enabled() || - (!parent->is_true_eq() && parent->is_cgr() == m_cg_table.contains_ptr(parent)) || - (parent->is_true_eq() && !m_cg_table.contains_ptr(parent))); + CTRACE("add_eq", !parent->is_marked() && parent->is_cgc_enabled() && parent->is_true_eq() && m_cg_table.contains_ptr(parent), tout << parent->get_owner_id() << "\n";); + CTRACE("add_eq", !parent->is_marked() && parent->is_cgc_enabled() && !parent->is_true_eq() && parent->is_cgr() && !m_cg_table.contains_ptr(parent), + tout << "cgr !contains " << parent->get_owner_id() << " " << mk_pp(parent->get_decl(), m_manager) << "\n"; + for (enode* n : enode::args(parent)) tout << n->get_root()->get_owner_id() << " " << n->get_root()->hash() << " "; + tout << "\n"; + tout << "contains: " << m_cg_table.contains(parent) << "\n"; + if (m_cg_table.contains(parent)) { + tout << "owner: " << m_cg_table.find(parent)->get_owner_id() << "\n"; + } + m_cg_table.display(tout); + ); + CTRACE("add_eq", !parent->is_marked() && parent->is_cgc_enabled() && !parent->is_true_eq() && !parent->is_cgr() && m_cg_table.contains_ptr(parent), tout << "!cgr contains " << parent->get_owner_id() << "\n";); + SASSERT(parent->is_marked() || !parent->is_cgc_enabled() || parent->is_true_eq() || parent->is_cgr() == m_cg_table.contains_ptr(parent)); + SASSERT(parent->is_marked() || !parent->is_cgc_enabled() || !parent->is_true_eq() || !m_cg_table.contains_ptr(parent)); if (!parent->is_marked() && parent->is_cgr() && !parent->is_true_eq()) { - TRACE("add_eq_parents", tout << "add_eq removing: #" << parent->get_owner_id() << "\n";); SASSERT(!parent->is_cgc_enabled() || m_cg_table.contains_ptr(parent)); parent->set_mark(); if (parent->is_cgc_enabled()) { @@ -704,7 +680,6 @@ namespace smt { enode_bool_pair pair = m_cg_table.insert(parent); enode * parent_prime = pair.first; if (parent_prime == parent) { - TRACE("add_eq_parents", tout << "add_eq reinserting: #" << parent->get_owner_id() << "\n";); SASSERT(parent); SASSERT(parent->is_cgr()); SASSERT(m_cg_table.contains_ptr(parent)); @@ -983,7 +958,6 @@ namespace smt { for (; it != end; ++it) { enode * parent = *it; if (parent->is_cgc_enabled()) { - TRACE("add_eq_parents", tout << "removing: #" << parent->get_owner_id() << "\n";); CTRACE("add_eq", !parent->is_cgr() || !m_cg_table.contains_ptr(parent), tout << "old num_parents: " << r2_num_parents << ", num_parents: " << r2->m_parents.size() << ", parent: #" << parent->get_owner_id() << ", parents: \n"; @@ -1011,14 +985,13 @@ namespace smt { for (enode * parent : enode::parents(r1)) { TRACE("add_eq_parents", tout << "visiting: #" << parent->get_owner_id() << "\n";); if (parent->is_cgc_enabled()) { - enode * cg = parent->m_cg; + enode * cg = parent->m_cg; if (!parent->is_true_eq() && - (parent == cg || // parent was root of the congruence class before and after the merge - !congruent(parent, cg) // parent was root of the congruence class before but not after the merge + (parent == cg || // parent was root of the congruence class before and after the merge + !congruent(parent, cg) // parent was root of the congruence class before but not after the merge )) { - TRACE("add_eq_parents", tout << "trying to reinsert\n";); - m_cg_table.insert(parent); - parent->m_cg = parent; + enode_bool_pair p = m_cg_table.insert(parent); + parent->m_cg = p.first; } } } @@ -1353,13 +1326,14 @@ namespace smt { \remark The method assign_eq adds a new entry on this queue. */ bool context::propagate_eqs() { - TRACE("add_eq", tout << m_eq_propagation_queue.size() << "\n";); - for (unsigned i = 0; i < m_eq_propagation_queue.size() && !get_cancel_flag(); i++) { + unsigned i = 0; + for (; i < m_eq_propagation_queue.size() && !get_cancel_flag(); i++) { new_eq & entry = m_eq_propagation_queue[i]; add_eq(entry.m_lhs, entry.m_rhs, entry.m_justification); if (inconsistent()) return false; } + TRACE("add_eq", tout << m_eq_propagation_queue.size() << " " << i << "\n";); m_eq_propagation_queue.reset(); return true; } @@ -1728,6 +1702,7 @@ namespace smt { } bool context::propagate() { + flet _prop(m_propagating, true); TRACE("propagate", tout << "propagating... " << m_qhead << ":" << m_assigned_literals.size() << "\n";); while (true) { if (inconsistent()) @@ -4449,7 +4424,7 @@ namespace smt { void context::add_rec_funs_to_model() { ast_manager& m = m_manager; - SASSERT(m_model); + if (!m_model) return; for (unsigned i = 0; !get_cancel_flag() && i < m_asserted_formulas.get_num_formulas(); ++i) { expr* e = m_asserted_formulas.get_formula(i); if (is_quantifier(e)) { diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index d4d4ec6fb..42111c591 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -923,6 +923,7 @@ namespace smt { failure m_last_search_failure; ptr_vector m_incomplete_theories; //!< theories that failed to produce a model bool m_searching; + bool m_propagating; unsigned m_num_conflicts; unsigned m_num_conflicts_since_restart; unsigned m_num_conflicts_since_lemma_gc; diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 065e5d952..767b9e06e 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -427,14 +427,8 @@ namespace smt { } tout << "\n"; tout << "value: #" << n->get_owner_id() << "\n" << mk_ismt2_pp(result, m_manager) << "\n";); - if (m_context->get_last_search_failure() == smt::THEORY) { - // if the theory solvers are incomplete, then we cannot assume the e-graph is close under congruence - if (fi->get_entry(args.c_ptr()) == nullptr) - fi->insert_new_entry(args.c_ptr(), result); - } - else { + if (fi->get_entry(args.c_ptr()) == nullptr) fi->insert_new_entry(args.c_ptr(), result); - } } } } diff --git a/src/util/trace.cpp b/src/util/trace.cpp index e4b210021..5e2930999 100644 --- a/src/util/trace.cpp +++ b/src/util/trace.cpp @@ -20,6 +20,7 @@ Revision History: #include "util/str_hashtable.h" #ifdef _TRACE + std::ofstream tout(".z3-trace"); static bool g_enable_all_trace_tags = false; From 51a26ceb9eba71faf52f3a81f0b0ccb2410a5a68 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Mar 2019 09:50:13 -0700 Subject: [PATCH 095/156] more segfault sources #2205, examining bit2bool internalization for #2282 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_bv.cpp | 32 ++++++++------------------------ src/smt/theory_datatype.cpp | 7 +++---- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 736218bc4..b2207199c 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -97,30 +97,6 @@ namespace smt { // This will also force the creation of all bits for x. enode * first_arg_enode = ctx.get_enode(first_arg); get_var(first_arg_enode); -#if 0 - // constant axiomatization moved to catch all case in the end of function. - - // numerals are not blasted into bit2bool, so we do this directly. - rational val; - unsigned sz; - if (!ctx.b_internalized(n) && m_util.is_numeral(first_arg, val, sz)) { - - TRACE("bv", tout << "bit2bool constants\n";); - theory_var v = first_arg_enode->get_th_var(get_id()); - app* owner = first_arg_enode->get_owner(); - for (unsigned i = 0; i < sz; ++i) { - app* e = mk_bit2bool(owner, i); - ctx.internalize(e, true); - } - m_bits[v].reset(); - rational bit; - for (unsigned i = 0; i < sz; ++i) { - div(val, rational::power_of_two(i), bit); - mod(bit, rational(2), bit); - m_bits[v].push_back(bit.is_zero()?false_literal:true_literal); - } - } -#endif } enode * arg = ctx.get_enode(first_arg); @@ -144,6 +120,13 @@ namespace smt { unsigned idx = n->get_decl()->get_parameter(0).get_int(); SASSERT(a->m_occs == 0); a->m_occs = new (get_region()) var_pos_occ(v_arg, idx); +#if 0 + // possible fix for #2162, but effect of fix needs to be checked. + if (idx < m_bits[v_arg].size()) { + ctx.mk_th_axiom(get_id(), m_bits[v_arg][idx], literal(bv, true)); + ctx.mk_th_axiom(get_id(), ~m_bits[v_arg][idx], literal(bv, false)); + } +#endif } // axiomatize bit2bool on constants. rational val; @@ -782,6 +765,7 @@ namespace smt { bits.swap(new_bits); \ } \ init_bits(e, bits); \ + TRACE("bv", tout << arg_bits << " " << bits << " " << new_bits << "\n";); \ } diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 9e941fcd5..dd1b302e1 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -175,7 +175,7 @@ namespace smt { unsigned base_id = get_manager().has_trace_stream() && accessors.size() > 0 ? m_util.get_plugin()->get_axiom_base_id(d->get_name()) : 0; unsigned i = 0; for (func_decl * acc : accessors) { - app * acc_app = m.mk_app(acc, n->get_owner()); + app_ref acc_app(m.mk_app(acc, n->get_owner()), m); enode * arg = n->get_arg(i); if (m.has_trace_stream()) { app_ref body(m); @@ -239,7 +239,7 @@ namespace smt { ctx.internalize(acc_app, false); arg = ctx.get_enode(acc_app); } - app * acc_own = m.mk_app(acc1, own); + app_ref acc_own(m.mk_app(acc1, own), m); if (m.has_trace_stream()) { app_ref body(m); body = m.mk_implies(rec_app, m.mk_eq(arg->get_owner(), acc_own)); @@ -249,8 +249,7 @@ namespace smt { if (m.has_trace_stream()) m.trace_stream() << "[end-of-instance]\n"; } // update_field is identity if 'n' is not created by a matching constructor. - app_ref imp(m); - imp = m.mk_implies(m.mk_not(rec_app), m.mk_eq(n->get_owner(), arg1)); + app_ref imp(m.mk_implies(m.mk_not(rec_app), m.mk_eq(n->get_owner(), arg1)), m); if (m.has_trace_stream()) log_axiom_instantiation(imp, 1, &n); assert_eq_axiom(n, arg1, ~is_con); if (m.has_trace_stream()) m.trace_stream() << "[end-of-instance]\n"; From d1d49ef3a974ea9c86b15df4b32843f7fdfdca87 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 27 Mar 2019 17:13:00 +0000 Subject: [PATCH 096/156] Fix BV-conversion of fp.roundToIntegral. Fixes #2191. --- src/ast/fpa/fpa2bv_converter.cpp | 41 ++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index eef2452db..f8879d6a1 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1986,15 +1986,17 @@ void fpa2bv_converter::mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & SASSERT(is_well_sorted(m, v4)); - // exponent >= sbits-1 + // exponent >= sbits-1 -> x expr_ref exp_is_large(m); - exp_is_large = m_bv_util.mk_sle(m_bv_util.mk_numeral(sbits-1, ebits), a_exp); + exp_is_large = log2(sbits-1)+1 <= ebits-1 ? + m_bv_util.mk_sle(m_bv_util.mk_numeral(sbits-1, ebits), a_exp) : + m.mk_false(); dbg_decouple("fpa2bv_r2i_exp_is_large", exp_is_large); c5 = exp_is_large; v5 = x; // Actual conversion with rounding. - // x.exponent >= 0 && x.exponent < x.sbits - 1 + // exponent >= 0 && exponent < sbits - 1 expr_ref res_sgn(m), res_sig(m), res_exp(m); res_sgn = a_sgn; @@ -2070,7 +2072,6 @@ void fpa2bv_converter::mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & m_simp.mk_ite(c53, v53, res_sig, res_sig); m_simp.mk_ite(c52, v52, res_sig, res_sig); m_simp.mk_ite(c51, v51, res_sig, res_sig); - res_sig = m_bv_util.mk_zero_extend(1, m_bv_util.mk_concat(res_sig, m_bv_util.mk_numeral(0, 3))); // rounding bits are all 0. SASSERT(m_bv_util.get_bv_size(res_exp) == ebits); SASSERT(m_bv_util.get_bv_size(shift) == sbits); @@ -2082,11 +2083,37 @@ void fpa2bv_converter::mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & res_exp = m_bv_util.mk_bv_add(m_bv_util.mk_zero_extend(2, res_exp), e_shift); SASSERT(m_bv_util.get_bv_size(res_sgn) == 1); - SASSERT(m_bv_util.get_bv_size(res_sig) == sbits + 4); + SASSERT(m_bv_util.get_bv_size(res_sig) == sbits); SASSERT(m_bv_util.get_bv_size(res_exp) == ebits + 2); - // CMW: We use the rounder for normalization. - round(s, rm, res_sgn, res_sig, res_exp, v6); + // Renormalize + expr_ref zero_e2(m), min_exp(m), sig_lz(m), max_exp_delta(m), sig_lz_capped(m), renorm_delta(m); + zero_e2 = m_bv_util.mk_numeral(0, ebits+2); + mk_min_exp(ebits, min_exp); + min_exp = m_bv_util.mk_sign_extend(2, min_exp); + mk_leading_zeros(res_sig, ebits+2, sig_lz); + max_exp_delta = m_bv_util.mk_bv_sub(res_exp, min_exp); + sig_lz_capped = m.mk_ite(m_bv_util.mk_sle(sig_lz, max_exp_delta), sig_lz, max_exp_delta); + renorm_delta = m.mk_ite(m_bv_util.mk_sle(zero_e2, sig_lz_capped), sig_lz_capped, zero_e2); + SASSERT(m_bv_util.get_bv_size(renorm_delta) == ebits + 2); + res_exp = m_bv_util.mk_bv_sub(res_exp, renorm_delta); + res_sig = m_bv_util.mk_bv_shl(res_sig, m_bv_util.mk_zero_extend(sbits-ebits-2, renorm_delta)); + dbg_decouple("fpa2bv_r2i_renorm_delta", renorm_delta); + + res_exp = m_bv_util.mk_extract(ebits-1, 0, res_exp); + mk_bias(res_exp, res_exp); + res_sig = m_bv_util.mk_extract(sbits-2, 0, res_sig); + v6 = m_util.mk_fp(res_sgn, res_exp, res_sig); + + dbg_decouple("fpa2bv_r2i_res_sgn", res_sgn); + dbg_decouple("fpa2bv_r2i_res_sig", res_sig); + dbg_decouple("fpa2bv_r2i_res_exp", res_exp); + + dbg_decouple("fpa2bv_r2i_c1", c1); + dbg_decouple("fpa2bv_r2i_c2", c2); + dbg_decouple("fpa2bv_r2i_c3", c3); + dbg_decouple("fpa2bv_r2i_c4", c4); + dbg_decouple("fpa2bv_r2i_c5", c5); // And finally, we tie them together. mk_ite(c5, v5, v6, result); From deb48bffe138ca01f0af5fe403e905b23548d1d6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Mar 2019 10:32:42 -0700 Subject: [PATCH 097/156] possible fix for #2182 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_bv.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index b2207199c..89b211af6 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -120,8 +120,8 @@ namespace smt { unsigned idx = n->get_decl()->get_parameter(0).get_int(); SASSERT(a->m_occs == 0); a->m_occs = new (get_region()) var_pos_occ(v_arg, idx); -#if 0 - // possible fix for #2162, but effect of fix needs to be checked. +#if 1 + // possible fix for #2182, but effect of fix needs to be checked. if (idx < m_bits[v_arg].size()) { ctx.mk_th_axiom(get_id(), m_bits[v_arg][idx], literal(bv, true)); ctx.mk_th_axiom(get_id(), ~m_bits[v_arg][idx], literal(bv, false)); From c69e911a7990fab39b8fb9bb93d1e439ce3064d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Mar 2019 16:59:13 -0700 Subject: [PATCH 098/156] adding po evaluator Signed-off-by: Nikolaj Bjorner --- src/api/api_datatype.cpp | 65 ++++-------- src/ast/datatype_decl_plugin.cpp | 79 +++++++++++++++ src/ast/datatype_decl_plugin.h | 6 ++ src/ast/special_relations_decl_plugin.h | 4 + src/model/model.cpp | 1 + src/model/model_core.cpp | 1 + src/smt/smt_context.cpp | 1 + src/smt/theory_special_relations.cpp | 128 +++++++++++++++++++++++- 8 files changed, 233 insertions(+), 52 deletions(-) diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 0c2544643..d48ce76e2 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -160,69 +160,40 @@ extern "C" { LOG_Z3_mk_list_sort(c, name, elem_sort, nil_decl, is_nil_decl, cons_decl, is_cons_decl, head_decl, tail_decl); RESET_ERROR_CODE(); ast_manager& m = mk_c(c)->m(); + func_decl_ref nil(m), is_nil(m), cons(m), is_cons(m), head(m), tail(m); datatype_util& dt_util = mk_c(c)->dtutil(); mk_c(c)->reset_last_result(); - datatype_util data_util(m); - accessor_decl* head_tail[2] = { - mk_accessor_decl(m, symbol("head"), type_ref(to_sort(elem_sort))), - mk_accessor_decl(m, symbol("tail"), type_ref(0)) - }; - constructor_decl* constrs[2] = { - mk_constructor_decl(symbol("nil"), symbol("is_nil"), 0, nullptr), - // Leo: SMT 2.0 document uses 'insert' instead of cons - mk_constructor_decl(symbol("cons"), symbol("is_cons"), 2, head_tail) - }; - - sort_ref_vector sorts(m); - { - datatype_decl * decl = mk_datatype_decl(dt_util, to_symbol(name), 0, nullptr, 2, constrs); - bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &decl, 0, nullptr, sorts); - del_datatype_decl(decl); - - if (!is_ok) { - SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - RETURN_Z3(nullptr); - } + sort_ref s = dt_util.mk_list_datatype(to_sort(elem_sort), to_symbol(name), cons, is_cons, head, tail, nil, is_nil); + + if (!s) { + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); + RETURN_Z3(nullptr); } - sort * s = sorts.get(0); mk_c(c)->save_multiple_ast_trail(s); - ptr_vector const& cnstrs = *data_util.get_datatype_constructors(s); - SASSERT(cnstrs.size() == 2); - func_decl* f; if (nil_decl) { - f = cnstrs[0]; - mk_c(c)->save_multiple_ast_trail(f); - *nil_decl = of_func_decl(f); + mk_c(c)->save_multiple_ast_trail(nil); + *nil_decl = of_func_decl(nil); } if (is_nil_decl) { - f = data_util.get_constructor_is(cnstrs[0]); - mk_c(c)->save_multiple_ast_trail(f); - *is_nil_decl = of_func_decl(f); + mk_c(c)->save_multiple_ast_trail(is_nil); + *is_nil_decl = of_func_decl(is_nil); } if (cons_decl) { - f = cnstrs[1]; - mk_c(c)->save_multiple_ast_trail(f); - *cons_decl = of_func_decl(f); + mk_c(c)->save_multiple_ast_trail(cons); + *cons_decl = of_func_decl(cons); } if (is_cons_decl) { - f = data_util.get_constructor_is(cnstrs[1]); - mk_c(c)->save_multiple_ast_trail(f); - *is_cons_decl = of_func_decl(f); + mk_c(c)->save_multiple_ast_trail(is_cons); + *is_cons_decl = of_func_decl(is_cons); } if (head_decl) { - ptr_vector const& acc = *data_util.get_constructor_accessors(cnstrs[1]); - SASSERT(acc.size() == 2); - f = (acc)[0]; - mk_c(c)->save_multiple_ast_trail(f); - *head_decl = of_func_decl(f); + mk_c(c)->save_multiple_ast_trail(head); + *head_decl = of_func_decl(head); } if (tail_decl) { - ptr_vector const& acc = *data_util.get_constructor_accessors(cnstrs[1]); - SASSERT(acc.size() == 2); - f = (acc)[1]; - mk_c(c)->save_multiple_ast_trail(f); - *tail_decl = of_func_decl(f); + mk_c(c)->save_multiple_ast_trail(tail); + *tail_decl = of_func_decl(tail); } RETURN_Z3_mk_list_sort(of_sort(s)); Z3_CATCH_RETURN(nullptr); diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 146c7359f..e7a5506a8 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -1187,6 +1187,85 @@ namespace datatype { } } } + + sort_ref util::mk_list_datatype(sort* elem, symbol const& name, + func_decl_ref& cons, func_decl_ref& is_cons, + func_decl_ref& hd, func_decl_ref& tl, + func_decl_ref& nil, func_decl_ref& is_nil) { + + accessor_decl* head_tail[2] = { + mk_accessor_decl(m, symbol("head"), type_ref(elem)), + mk_accessor_decl(m, symbol("tail"), type_ref(0)) + }; + constructor_decl* constrs[2] = { + mk_constructor_decl(symbol("nil"), symbol("is_nil"), 0, nullptr), + mk_constructor_decl(symbol("cons"), symbol("is_cons"), 2, head_tail) + }; + decl::plugin& p = *get_plugin(); + + sort_ref_vector sorts(m); + datatype_decl * decl = mk_datatype_decl(*this, name, 0, nullptr, 2, constrs); + bool is_ok = p.mk_datatypes(1, &decl, 0, nullptr, sorts); + del_datatype_decl(decl); + + if (!is_ok) { + return sort_ref(m); + } + sort* s = sorts.get(0); + ptr_vector const& cnstrs = *get_datatype_constructors(s); + SASSERT(cnstrs.size() == 2); + nil = cnstrs[0]; + is_nil = get_constructor_is(cnstrs[0]); + cons = cnstrs[1]; + is_cons = get_constructor_is(cnstrs[1]); + ptr_vector const& acc = *get_constructor_accessors(cnstrs[1]); + SASSERT(acc.size() == 2); + hd = acc[0]; + tl = acc[1]; + return sort_ref(s, m); + } + + sort_ref util::mk_pair_datatype(sort* a, sort* b, func_decl_ref& fst, func_decl_ref& snd, func_decl_ref& pair) { + type_ref t1(a), t2(b); + accessor_decl* fstd = mk_accessor_decl(m, symbol("fst"), t1); + accessor_decl* sndd = mk_accessor_decl(m, symbol("snd"), t2); + accessor_decl* accd[2] = { fstd, sndd }; + auto * p = mk_constructor_decl(symbol("pair"), symbol("is-pair"), 2, accd); + auto* dt = mk_datatype_decl(*this, symbol("pair"), 0, nullptr, 1, &p); + sort_ref_vector sorts(m); + VERIFY(get_plugin()->mk_datatypes(1, &dt, 0, nullptr, sorts)); + del_datatype_decl(dt); + sort* s = sorts.get(0); + ptr_vector const& cnstrs = *get_datatype_constructors(s); + SASSERT(cnstrs.size() == 1); + ptr_vector const& acc = *get_constructor_accessors(cnstrs[0]); + SASSERT(acc.size() == 2); + fst = acc[0]; + snd = acc[1]; + pair = cnstrs[0]; + return sort_ref(s, m); + } + + sort_ref util::mk_tuple_datatype(svector> const& elems, symbol const& name, symbol const& test, func_decl_ref& tup, func_decl_ref_vector& accs) { + ptr_vector accd; + for (auto const& e : elems) { + type_ref t(e.second); + accd.push_back(mk_accessor_decl(m, e.first, t)); + } + auto* tuple = mk_constructor_decl(name, test, accd.size(), accd.c_ptr()); + auto* dt = mk_datatype_decl(*this, name, 0, nullptr, 1, &tuple); + sort_ref_vector sorts(m); + VERIFY(get_plugin()->mk_datatypes(1, &dt, 0, nullptr, sorts)); + del_datatype_decl(dt); + sort* s = sorts.get(0); + ptr_vector const& cnstrs = *get_datatype_constructors(s); + SASSERT(cnstrs.size() == 1); + ptr_vector const& acc = *get_constructor_accessors(cnstrs[0]); + for (auto* f : acc) accs.push_back(f); + tup = cnstrs[0]; + return sort_ref(s, m); + } + } datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort*const* params, unsigned num_constructors, constructor_decl * const * cs) { diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index e9734ac0b..5292ab6b9 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -364,6 +364,12 @@ namespace datatype { decl::plugin* get_plugin() { return m_plugin; } void get_defs(sort* s, ptr_vector& defs); def const& get_def(sort* s) const; + sort_ref mk_list_datatype(sort* elem, symbol const& name, + func_decl_ref& cons, func_decl_ref& is_cons, + func_decl_ref& hd, func_decl_ref& tl, + func_decl_ref& nil, func_decl_ref& is_nil); + sort_ref mk_pair_datatype(sort* a, sort* b, func_decl_ref& fst, func_decl_ref& snd, func_decl_ref& pair); + sort_ref mk_tuple_datatype(svector> const& elems, symbol const& name, symbol const& test, func_decl_ref& tup, func_decl_ref_vector& accs); }; }; diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index dbdd61805..e8260e154 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -26,6 +26,7 @@ Revision History: enum special_relations_op_kind { OP_SPECIAL_RELATION_LO, OP_SPECIAL_RELATION_PO, + OP_SPECIAL_RELATION_PO_AO, OP_SPECIAL_RELATION_PLO, OP_SPECIAL_RELATION_TO, LAST_SPECIAL_RELATIONS_OP @@ -34,6 +35,7 @@ enum special_relations_op_kind { class special_relations_decl_plugin : public decl_plugin { symbol m_lo; symbol m_po; + symbol m_po_ao; symbol m_plo; symbol m_to; public: @@ -78,11 +80,13 @@ public: bool is_lo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_LO); } bool is_po(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO); } + bool is_po_ao(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO_AO); } bool is_plo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PLO); } bool is_to(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TO); } app * mk_lo (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_LO, arg1, arg2); } app * mk_po (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO, arg1, arg2); } + app * mk_po_ao (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO_AO, arg1, arg2); } app * mk_plo(expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PLO, arg1, arg2); } app * mk_to (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_TO, arg1, arg2); } diff --git a/src/model/model.cpp b/src/model/model.cpp index e6a3ffedf..aa3976cb9 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -217,6 +217,7 @@ void model::compress() { } } if (removed.empty()) break; + TRACE("model", tout << "remove\n"; for (func_decl* f : removed) tout << f->get_name() << "\n";); remove_decls(m_decls, removed); remove_decls(m_func_decls, removed); remove_decls(m_const_decls, removed); diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index d92e81421..0f811034a 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -66,6 +66,7 @@ void model_core::register_decl(func_decl * d, expr * v) { } void model_core::register_decl(func_decl * d, func_interp * fi) { + TRACE("model", tout << "register " << d->get_name() << "\n";); SASSERT(d->get_arity() > 0); SASSERT(&fi->m() == &m); decl2finterp::obj_map_entry * entry = m_finterp.insert_if_not_there2(d, nullptr); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 5715e067d..fc5c7e917 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4478,6 +4478,7 @@ namespace smt { } recfun::util u(m); func_decl_ref_vector recfuns = u.get_rec_funs(); + std::cout << recfuns << "\n"; for (func_decl* f : recfuns) { auto& def = u.get_def(f); expr* rhs = def.get_rhs(); diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 65d30cea6..8339c658e 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -26,7 +26,11 @@ Notes: #include "smt/smt_solver.h" #include "solver/solver.h" #include "ast/reg_decl_plugins.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/recfun_decl_plugin.h" #include "ast/ast_pp.h" +#include "ast/rewriter/recfun_replace.h" + namespace smt { @@ -610,16 +614,130 @@ namespace smt { m.get_model().register_decl(r.decl(), fi); } - void theory_special_relations::init_model_plo(relation& r, model_generator& m) { - expr_ref inj = mk_inj(r, m); - expr_ref cls = mk_class(r, m); + void theory_special_relations::init_model_plo(relation& r, model_generator& mg) { + expr_ref inj = mk_inj(r, mg); + expr_ref cls = mk_class(r, mg); func_interp* fi = alloc(func_interp, get_manager(), 2); fi->set_else(get_manager().mk_and(inj, cls)); - m.get_model().register_decl(r.decl(), fi); + mg.get_model().register_decl(r.decl(), fi); } + /** + \brief model for a partial order, + is a recursive function that evaluates membership in partial order over + a fixed set of edges. It runs in O(e*n^2) where n is the number of vertices and e + number of edges. + + connected1(x, y, v, w, S) = + if x = v then + if y = w then (S, true) else + if w in S then (S, false) else + connected2(w, y, S u { w }, edges) + else (S, false) + + connected2(x, y, S, []) = (S, false) + connected2(x, y, S, (u,w)::edges) = + let (S, c) = connected1(x, y, u, w, S) + if c then (S, true) else connected2(x, y, S, edges) + + */ + + void theory_special_relations::init_model_po(relation& r, model_generator& mg) { - // NOT_IMPLEMENTED_YET(); + ast_manager& m = get_manager(); + sort* s = r.m_decl->get_domain(0); + context& ctx = get_context(); + datatype_util dt(m); + recfun::util rf(m); + recfun::decl::plugin& p = rf.get_plugin(); + func_decl_ref nil(m), is_nil(m), cons(m), is_cons(m), hd(m), tl(m); + sort_ref listS(dt.mk_list_datatype(s, symbol("List"), cons, is_cons, hd, tl, nil, is_nil), m); + func_decl_ref fst(m), snd(m), pair(m); + sort_ref tup(dt.mk_pair_datatype(listS, m.mk_bool_sort(), fst, snd, pair), m); + sort* dom1[5] = { s, s, listS, s, s }; + recfun::promise_def c1 = p.mk_def(symbol("connected1"), 5, dom1, tup); + sort* dom2[3] = { s, s, listS }; + recfun::promise_def c2 = p.mk_def(symbol("connected2"), 3, dom2, tup); + sort* dom3[2] = { s, listS }; + recfun::promise_def mem = p.mk_def(symbol("member"), 2, dom3, m.mk_bool_sort()); + var_ref xV(m.mk_var(1, s), m); + var_ref SV(m.mk_var(0, listS), m); + var_ref yV(m), vV(m), wV(m); + + expr* x = xV, *S = SV; + expr* T = m.mk_true(); + expr* F = m.mk_false(); + func_decl* memf = mem.get_def()->get_decl(); + func_decl* conn1 = c1.get_def()->get_decl(); + func_decl* conn2 = c2.get_def()->get_decl(); + expr_ref mem_body(m); + mem_body = m.mk_ite(m.mk_app(is_nil, S), + F, + m.mk_ite(m.mk_eq(m.mk_app(hd, S), x), + T, + m.mk_app(memf, x, m.mk_app(tl, S)))); + recfun_replace rep(m); + var* vars[2] = { xV, SV }; + p.set_definition(rep, mem, 2, vars, mem_body); + + xV = m.mk_var(4, s); + yV = m.mk_var(3, s); + SV = m.mk_var(2, listS); + vV = m.mk_var(1, s); + wV = m.mk_var(0, s); + expr* y = yV, *v = vV, *w = wV; + x = xV, S = SV; + + expr_ref ST(m.mk_app(pair, S, T), m); + expr_ref SF(m.mk_app(pair, S, F), m); + + expr_ref connected_body(m); + connected_body = + m.mk_ite(m.mk_not(m.mk_eq(x, v)), + SF, + m.mk_ite(m.mk_eq(y, w), + ST, + m.mk_ite(m.mk_app(memf, w, S), + SF, + m.mk_app(conn2, w, y, m.mk_app(cons, w, S))))); + var* vars2[5] = { xV, yV, SV, vV, wV }; + p.set_definition(rep, c1, 5, vars2, connected_body); + + xV = m.mk_var(2, s); + yV = m.mk_var(1, s); + SV = m.mk_var(0, listS); + x = xV, y = yV, S = SV; + ST = m.mk_app(pair, S, T); + SF = m.mk_app(pair, S, F); + expr_ref connected_rec_body(m); + connected_rec_body = SF; + + for (atom* ap : r.m_asserted_atoms) { + atom& a = *ap; + if (!a.phase()) continue; + SASSERT(ctx.get_assignment(a.var()) == l_true); + expr* n1 = get_enode(a.v1())->get_root()->get_owner(); + expr* n2 = get_enode(a.v2())->get_root()->get_owner(); + + expr* Sr = connected_rec_body; + expr* args[5] = { x, y, m.mk_app(fst, Sr), n1, n2}; + expr* Sc = m.mk_app(conn1, 5, args); + connected_rec_body = m.mk_ite(m.mk_app(snd, Sr), ST, Sc); + } + var* vars3[3] = { xV, yV, SV }; + p.set_definition(rep, c2, 3, vars3, connected_rec_body); + +#if 0 + // TBD: doesn't terminate with model_evaluator/rewriter + + // r.m_decl(x,y) -> snd(connected2(x,y,nil)) + + func_interp* fi = alloc(func_interp, m, 2); + fi->set_else(m.mk_app(snd, m.mk_app(conn2, x, y, m.mk_const(nil)))); + mg.get_model().register_decl(r.decl(), fi); +#endif + + } /** From 4e38e90e2b25c42be81781f8c8e4e55c88f457f9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Mar 2019 07:03:04 -0700 Subject: [PATCH 099/156] fix po model Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 2 +- src/smt/theory_special_relations.cpp | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index fc5c7e917..5b18613b6 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4478,7 +4478,6 @@ namespace smt { } recfun::util u(m); func_decl_ref_vector recfuns = u.get_rec_funs(); - std::cout << recfuns << "\n"; for (func_decl* f : recfuns) { auto& def = u.get_def(f); expr* rhs = def.get_rhs(); @@ -4500,6 +4499,7 @@ namespace smt { fi->set_else(bodyr); m_model->register_decl(f, fi); } + TRACE("model", tout << *m_model << "\n";); } }; diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 8339c658e..6e8c04a97 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -727,16 +727,14 @@ namespace smt { var* vars3[3] = { xV, yV, SV }; p.set_definition(rep, c2, 3, vars3, connected_rec_body); -#if 0 - // TBD: doesn't terminate with model_evaluator/rewriter - // r.m_decl(x,y) -> snd(connected2(x,y,nil)) + xV = m.mk_var(0, s); + yV = m.mk_var(1, s); + x = xV, y = yV; func_interp* fi = alloc(func_interp, m, 2); - fi->set_else(m.mk_app(snd, m.mk_app(conn2, x, y, m.mk_const(nil)))); + fi->set_else(m.mk_app(snd, m.mk_app(conn2, x, y, m.mk_app(cons, x, m.mk_const(nil))))); mg.get_model().register_decl(r.decl(), fi); -#endif - } From 876aa01167fd8c58652442001e40376ee611664d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 18:44:46 -0700 Subject: [PATCH 100/156] add sr Signed-off-by: Nikolaj Bjorner --- src/ast/CMakeLists.txt | 1 + src/ast/special_relations_decl_plugin.cpp | 79 ++ src/ast/special_relations_decl_plugin.h | 97 +++ src/smt/CMakeLists.txt | 1 + src/smt/diff_logic.h | 148 +++- src/smt/theory_special_relations.cpp | 905 ++++++++++++++++++++++ src/smt/theory_special_relations.h | 198 +++++ 7 files changed, 1413 insertions(+), 16 deletions(-) create mode 100644 src/ast/special_relations_decl_plugin.cpp create mode 100644 src/ast/special_relations_decl_plugin.h create mode 100644 src/smt/theory_special_relations.cpp create mode 100644 src/smt/theory_special_relations.h diff --git a/src/ast/CMakeLists.txt b/src/ast/CMakeLists.txt index 56ab78b8a..0bcc4d847 100644 --- a/src/ast/CMakeLists.txt +++ b/src/ast/CMakeLists.txt @@ -41,6 +41,7 @@ z3_add_component(ast reg_decl_plugins.cpp seq_decl_plugin.cpp shared_occs.cpp + special_relations_decl_plugin.cpp static_features.cpp used_vars.cpp well_sorted.cpp diff --git a/src/ast/special_relations_decl_plugin.cpp b/src/ast/special_relations_decl_plugin.cpp new file mode 100644 index 000000000..6bb5734e5 --- /dev/null +++ b/src/ast/special_relations_decl_plugin.cpp @@ -0,0 +1,79 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + special_relations_decl_plugin.cpp + +Abstract: + + + +Author: + + Nikolaj Bjorner (nbjorner) 2015-15-9. + +Revision History: + +--*/ + +#include +#include"ast.h" +#include"special_relations_decl_plugin.h" + + + +special_relations_decl_plugin::special_relations_decl_plugin(): + m_lo("linear-order"), + m_po("partial-order"), + m_po_ao("partial-order-already-ordered"), + m_plo("piecewise-linear-order"), + m_to("tree-order") +{} + +func_decl * special_relations_decl_plugin::mk_func_decl( + decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) +{ + if (arity != 2) { + m_manager->raise_exception("special relations should have arity 2"); + return 0; + } + if (domain[0] != domain[1]) { + m_manager->raise_exception("argument sort missmatch"); + return 0; + } + func_decl_info info(m_family_id, k, num_parameters, parameters); + symbol name; + switch(k) { + case OP_SPECIAL_RELATION_PO: name = m_po; break; + case OP_SPECIAL_RELATION_PO_AO: name = m_po_ao; break; + case OP_SPECIAL_RELATION_LO: name = m_lo; break; + case OP_SPECIAL_RELATION_PLO: name = m_plo; break; + case OP_SPECIAL_RELATION_TO: name = m_to; break; + } + return m_manager->mk_func_decl(name, arity, domain, m_manager->mk_bool_sort(), info); +} + +void special_relations_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { + if (logic == symbol::null) { + op_names.push_back(builtin_name(m_po.bare_str(), OP_SPECIAL_RELATION_PO)); + op_names.push_back(builtin_name(m_po_ao.bare_str(), OP_SPECIAL_RELATION_PO_AO)); + op_names.push_back(builtin_name(m_lo.bare_str(), OP_SPECIAL_RELATION_LO)); + op_names.push_back(builtin_name(m_plo.bare_str(), OP_SPECIAL_RELATION_PLO)); + op_names.push_back(builtin_name(m_to.bare_str(), OP_SPECIAL_RELATION_TO)); + } +} + +sr_property special_relations_util::get_property(func_decl* f) const { + switch (f->get_decl_kind()) { + case OP_SPECIAL_RELATION_PO: return sr_po; + case OP_SPECIAL_RELATION_PO_AO: return sr_po; // still partial ordered + case OP_SPECIAL_RELATION_LO: return sr_lo; + case OP_SPECIAL_RELATION_PLO: return sr_plo; + case OP_SPECIAL_RELATION_TO: return sr_to; + default: + UNREACHABLE(); + return sr_po; + } +} diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h new file mode 100644 index 000000000..068382b23 --- /dev/null +++ b/src/ast/special_relations_decl_plugin.h @@ -0,0 +1,97 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + special_relations_decl_plugin.h + +Abstract: + + + +Author: + + Nikolaj Bjorner (nbjorner) 2015-15-9. + Ashutosh Gupta 2016 + +Revision History: + +--*/ +#ifndef SPECIAL_RELATIONS_DECL_PLUGIN_H_ +#define SPECIAL_RELATIONS_DECL_PLUGIN_H_ + +#include"ast.h" + + + +enum special_relations_op_kind { + OP_SPECIAL_RELATION_LO, + OP_SPECIAL_RELATION_PO, + OP_SPECIAL_RELATION_PO_AO, + OP_SPECIAL_RELATION_PLO, + OP_SPECIAL_RELATION_TO, + LAST_SPECIAL_RELATIONS_OP +}; + +class special_relations_decl_plugin : public decl_plugin { + symbol m_lo; + symbol m_po; + symbol m_po_ao; + symbol m_plo; + symbol m_to; +public: + special_relations_decl_plugin(); + virtual ~special_relations_decl_plugin() {} + + virtual decl_plugin * mk_fresh() { + return alloc(special_relations_decl_plugin); + } + + virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + virtual void get_op_names(svector & op_names, symbol const & logic); + + + virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { return 0; } +}; + +enum sr_property { + sr_transitive = 0x01, // Rxy & Ryz -> Rxz + sr_reflexive = 0x02, // Rxx + sr_antisymmetric = 0x04, // Rxy & Ryx -> x = y + sr_lefttree = 0x08, // Ryx & Rzx -> Ryz | Rzy + sr_righttree = 0x10, // Rxy & Rxz -> Ryx | Rzy + sr_po = 0x01 | 0x02 | 0x04, // partial order + sr_lo = 0x01 | 0x02 | 0x04 | 0x08 | 0x10, // linear order + sr_plo = 0x01 | 0x02 | 0x04 | 0x20, // piecewise linear order + sr_to = 0x01 | 0x02 | 0x04 | 0x10, // right-tree +}; + +class special_relations_util { + ast_manager& m; + family_id m_fid; +public: + special_relations_util(ast_manager& m) : m(m), m_fid(m.get_family_id("special_relations")) {} + + bool is_special_relation(func_decl* f) const { return f->get_family_id() == m_fid; } + bool is_special_relation(app* e) const { return is_special_relation(e->get_decl()); } + sr_property get_property(func_decl* f) const; + sr_property get_property(app* e) const { return get_property(e->get_decl()); } + + bool is_lo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_LO); } + bool is_po(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO); } + bool is_po_ao(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO_AO); } + bool is_plo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PLO); } + bool is_to(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TO); } + + app * mk_lo (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_LO, arg1, arg2); } + app * mk_po (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO, arg1, arg2); } + app * mk_po_ao (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO_AO, arg1, arg2); } + app * mk_plo(expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PLO, arg1, arg2); } + app * mk_to (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_TO, arg1, arg2); } + +}; + + +#endif /* SPECIAL_RELATIONS_DECL_PLUGIN_H_ */ diff --git a/src/smt/CMakeLists.txt b/src/smt/CMakeLists.txt index 52d3a5943..adc348633 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -62,6 +62,7 @@ z3_add_component(smt theory_pb.cpp theory_recfun.cpp theory_seq.cpp + theory_special_relations.cpp theory_str.cpp theory_utvpi.cpp theory_wmaxsat.cpp diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 44e858219..f3ce7fb13 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -296,6 +296,9 @@ public: numeral const& get_weight(edge_id id) const { return m_edges[id].get_weight(); } + edge_id_vector const& get_out_edges(dl_var v) const { return m_out_edges[v]; } + + edge_id_vector const& get_in_edges(dl_var v) const { return m_in_edges[v]; } private: // An assignment is almost feasible if all but edge with idt edge are feasible. @@ -661,6 +664,113 @@ public: } } + bool can_reach(dl_var src, dl_var dst) { + uint_set target, visited; + target.insert(dst); + return reachable(src, target, visited, dst); + } + + bool reachable(dl_var start, uint_set const& target, uint_set& visited, dl_var& dst) { + visited.reset(); + svector nodes; + nodes.push_back(start); + for (dl_var n : nodes) { + if (visited.contains(n)) continue; + visited.insert(n); + edge_id_vector & edges = m_out_edges[n]; + for (edge_id e_id : edges) { + edge & e = m_edges[e_id]; + if (e.is_enabled()) { + dst = e.get_target(); + if (target.contains(dst)) { + return true; + } + nodes.push_back(dst); + } + } + } + return false; + } + +private: + svector m_freq_hybrid; + int m_total_count = 0; + int m_run_counter = -1; + svector m_hybrid_visited, m_hybrid_parent; +public: + + template + bool find_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { + auto zero_edge = true; + unsigned bfs_head = 0; + int_vector bfs_todo; + int_vector dfs_todo; + m_hybrid_visited.resize(m_assignment.size(), m_run_counter++); + m_hybrid_parent.resize(m_assignment.size(), -1); + bfs_todo.push_back(source); + m_hybrid_parent[source] = -1; + m_hybrid_visited[source] = m_run_counter; + numeral gamma; + while (bfs_head < bfs_todo.size() || !dfs_todo.empty()) { + m_total_count++; + dl_var v; + if (!dfs_todo.empty()) { + v = dfs_todo.back(); + dfs_todo.pop_back(); + } + else { + v = bfs_todo[bfs_head++]; + } + + edge_id_vector & edges = m_out_edges[v]; + for (edge_id e_id : edges) { + edge & e = m_edges[e_id]; + SASSERT(e.get_source() == v); + if (!e.is_enabled()) { + continue; + } + set_gamma(e, gamma); + if ((gamma.is_one() || (!zero_edge && gamma.is_neg())) + && e.get_timestamp() < timestamp) { + dl_var curr_target = e.get_target(); + if (curr_target == target) { + f(e.get_explanation()); + m_freq_hybrid[e_id]++; + for (;;) { + int p = m_hybrid_parent[v]; + if (p == -1) + return true; + + edge_id eid; + bool ret = get_edge_id(p, v, eid); + if (eid == null_edge_id || !ret) { + return true; + } + else { + edge & e = m_edges[eid]; + f(e.get_explanation()); + m_freq_hybrid[eid]++; + v = p; + } + } + } + else if (m_hybrid_visited[curr_target] != m_run_counter) { + if (m_freq_hybrid[e_id] > 1) { + dfs_todo.push_back(curr_target); + } + else { + bfs_todo.push_back(curr_target); + } + m_hybrid_visited[curr_target] = m_run_counter; + m_hybrid_parent[curr_target] = v; + } + } + } + } + return false; + + } + // // Create fresh literals obtained by resolving a pair (or more) // literals associated with the edges. @@ -1274,8 +1384,22 @@ public: // Find the shortest path from source to target using (normalized) zero edges with timestamp less than the given timestamp. // The functor f is applied on every explanation attached to the edges in the shortest path. // Return true if the path exists, false otherwise. + + + // Return true if the path exists, false otherwise. + template + bool find_shortest_zero_edge_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { + return find_shortest_path_aux(source, target, timestamp, f, true); + } + template - bool find_shortest_zero_edge_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { + bool find_shortest_reachable_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { + return find_shortest_path_aux(source, target, timestamp, f, false); + } + + + template + bool find_shortest_path_aux(dl_var source, dl_var target, unsigned timestamp, Functor & f, bool zero_edge) { svector bfs_todo; svector bfs_mark; bfs_mark.resize(m_assignment.size(), false); @@ -1292,10 +1416,7 @@ public: dl_var v = curr.m_var; TRACE("dl_bfs", tout << "processing: " << v << "\n";); edge_id_vector & edges = m_out_edges[v]; - typename edge_id_vector::iterator it = edges.begin(); - typename edge_id_vector::iterator end = edges.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges) { edge & e = m_edges[e_id]; SASSERT(e.get_source() == v); if (!e.is_enabled()) { @@ -1303,7 +1424,8 @@ public: } set_gamma(e, gamma); TRACE("dl_bfs", tout << "processing edge: "; display_edge(tout, e); tout << "gamma: " << gamma << "\n";); - if (gamma.is_zero() && e.get_timestamp() < timestamp) { + if ((gamma.is_one() || (!zero_edge && gamma.is_neg())) && e.get_timestamp() < timestamp) { + // if (gamma.is_zero() && e.get_timestamp() < timestamp) dl_var curr_target = e.get_target(); TRACE("dl_bfs", tout << "curr_target: " << curr_target << ", mark: " << static_cast(bfs_mark[curr_target]) << "\n";); @@ -1477,11 +1599,7 @@ private: } TRACE("diff_logic", tout << "source: " << source << "\n";); - typename edge_id_vector::const_iterator it = edges[source].begin(); - typename edge_id_vector::const_iterator end = edges[source].end(); - - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges[source]) { edge const& e = m_edges[e_id]; if (&e == &e_init) { @@ -1569,11 +1687,9 @@ private: tout << "\n"; }); - typename heap::const_iterator it = state.m_heap.begin(); - typename heap::const_iterator end = state.m_heap.end(); - for (; it != end; ++it) { - SASSERT(m_mark[*it] != DL_PROP_UNMARKED); - m_mark[*it] = DL_PROP_UNMARKED;; + for (auto & s : state.m_heap) { + SASSERT(m_mark[s] != DL_PROP_UNMARKED); + m_mark[s] = DL_PROP_UNMARKED;; } state.m_heap.reset(); SASSERT(marks_are_clear()); diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp new file mode 100644 index 000000000..c58ffb24a --- /dev/null +++ b/src/smt/theory_special_relations.cpp @@ -0,0 +1,905 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + theory_special_relations.cpp + +Abstract: + + Special Relations theory plugin. + +Author: + + Nikolaj Bjorner (nbjorner) 2015-9-16 + Ashutosh Gupta 2016 + +Notes: + +--*/ + +#include + +#include "smt/smt_context.h" +#include "smt/theory_arith.h" +#include "smt/theory_special_relations.h" +#include "smt/smt_solver.h" +#include "solver/solver.h" +#include "ast/reg_decl_plugins.h" +#include "ast/ast_pp.h" + +static constexpr bool KVEC = false; +static constexpr bool HYBRID_SEARCH = false; + +namespace smt { + + void theory_special_relations::relation::push() { + m_scopes.push_back(scope()); + scope& s = m_scopes.back(); + s.m_asserted_atoms_lim = m_asserted_atoms.size(); + s.m_asserted_qhead_old = m_asserted_qhead; + if (!KVEC) { + m_graph.push(); + } + m_ufctx.get_trail_stack().push_scope(); + } + + void theory_special_relations::relation::pop(unsigned num_scopes) { + unsigned new_lvl = m_scopes.size() - num_scopes; + scope& s = m_scopes[new_lvl]; + m_asserted_atoms.shrink(s.m_asserted_atoms_lim); + m_asserted_qhead = s.m_asserted_qhead_old; + m_scopes.shrink(new_lvl); + if (!KVEC) { + m_graph.pop(num_scopes); + } + m_ufctx.get_trail_stack().pop_scope(num_scopes); + } + + void theory_special_relations::relation::ensure_var(theory_var v) { + while ((unsigned)v > m_uf.mk_var()); + if ((unsigned)v >= m_graph.get_num_nodes()) { + m_graph.init_var(v); + } + } + + bool theory_special_relations::relation::new_eq_eh(literal l, theory_var v1, theory_var v2) { + ensure_var(v1); + ensure_var(v2); + literal_vector ls; + ls.push_back(l); + return + m_graph.enable_edge(m_graph.add_edge(v1, v2, s_integer(1), ls)) && + m_graph.enable_edge(m_graph.add_edge(v2, v1, s_integer(1), ls)); + } + + theory_special_relations::theory_special_relations(ast_manager& m): + theory(m.mk_family_id("special_relations")), + m_util(m), m_autil(m) { + params_ref params; + params.set_bool("model", true); + params.set_bool("unsat_core", true); + m_nested_solver = mk_smt_solver(m, params, symbol("QF_LRA")); + m_int_sort = m_autil.mk_real(); + } + + theory_special_relations::~theory_special_relations() { + reset_eh(); + m_nested_solver = nullptr; + } + + theory * theory_special_relations::mk_fresh(context * new_ctx) { + return alloc(theory_special_relations, new_ctx->get_manager()); + } + + static void populate_k_vars(int v, int k, u_map>& map, int& curr_id, ast_manager& m, sort** int_sort) { + int need = !map.contains(v) ? k : k - map[v].size(); + for (auto i = 0; i < need; ++i) { + auto *fd = m.mk_func_decl(symbol(curr_id++), 0, int_sort, *int_sort); + map[v].push_back(m.mk_app(fd, unsigned(0), nullptr)); + } + } + + bool theory_special_relations::internalize_atom(app * atm, bool gate_ctx) { + TRACE("special_relations", tout << mk_pp(atm, get_manager()) << "\n";); + SASSERT(m_util.is_special_relation(atm)); + relation* r = 0; + if (!m_relations.find(atm->get_decl(), r)) { + //todo: push pop may get misaligned if the following alloc happens after push + r = alloc(relation, m_util.get_property(atm), atm->get_decl()); + m_relations.insert(atm->get_decl(), r); + } + context& ctx = get_context(); + expr* arg0 = atm->get_arg(0); + expr* arg1 = atm->get_arg(1); + theory_var v0 = mk_var(arg0); + theory_var v1 = mk_var(arg1); + bool_var v = ctx.mk_bool_var(atm); + ctx.set_var_theory(v, get_id()); + atom* a = alloc(atom, v, *r, v0, v1); + m_atoms.push_back(a); + //std::cerr << "INTER : " << a->v1() << ' ' << a->v2() << ' ' << gate_ctx << "\n"; + m_bool_var2atom.insert(v, a); + return true; + } + + theory_var theory_special_relations::mk_var(expr* e) { + context& ctx = get_context(); + if (!ctx.e_internalized(e)) { + ctx.internalize(e, false); + } + enode * n = ctx.get_enode(e); + theory_var v = n->get_th_var(get_id()); + if (null_theory_var == v) { + v = theory::mk_var(n); + ctx.attach_th_var(n, this, v); + } + return v; + } + + void theory_special_relations::new_eq_eh(theory_var v1, theory_var v2) { + context& ctx = get_context(); + app_ref eq(get_manager()); + app* t1 = get_enode(v1)->get_owner(); + app* t2 = get_enode(v2)->get_owner(); + eq = get_manager().mk_eq(t1, t2); + VERIFY(internalize_atom(eq, false)); + literal l(ctx.get_literal(eq)); + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; !ctx.inconsistent() && it != end; ++it) { + relation& r = *it->m_value; + if (!r.new_eq_eh(l, v1, v2)) { + set_neg_cycle_conflict(r); + break; + } + } + } + + final_check_status theory_special_relations::final_check_eh() { + TRACE("special_relations", tout << "\n";); + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + lbool r = l_true; + for (; it != end && r == l_true; ++it) { + r = final_check(*it->m_value); + } + switch (r) { + case l_undef: + return FC_GIVEUP; + case l_false: + return FC_CONTINUE; + default: + break; + } + it = m_relations.begin(); + bool new_equality = false; + for (; it != end; ++it) { + if (extract_equalities(*it->m_value)) { + new_equality = true; + } + } + if (new_equality) { + return FC_CONTINUE; + } + else { + return FC_DONE; + } + } + + lbool theory_special_relations::final_check_lo(relation& r) { + // all constraints are saturated by propagation. + return l_true; + } + + enode* theory_special_relations::ensure_enode(expr* e) { + context& ctx = get_context(); + if (!ctx.e_internalized(e)) { + ctx.internalize(e, false); + } + enode* n = ctx.get_enode(e); + ctx.mark_as_relevant(n); + return n; + } + + literal theory_special_relations::mk_literal(expr* _e) { + expr_ref e(_e, get_manager()); + context& ctx = get_context(); + ensure_enode(e); + return ctx.get_literal(e); + } + + theory_var theory_special_relations::mk_var(enode* n) { + if (is_attached_to_var(n)) { + return n->get_th_var(get_id()); + } + else { + theory_var v = theory::mk_var(n); + get_context().attach_th_var(n, this, v); + get_context().mark_as_relevant(n); + return v; + } + } + + lbool theory_special_relations::final_check_plo(relation& r) { + // + // ensure that !Rxy -> Ryx between connected components + // (where Rzx & Rzy or Rxz & Ryz for some z) + // + lbool res = l_true; + for (unsigned i = 0; res == l_true && i < r.m_asserted_atoms.size(); ++i) { + atom& a = *r.m_asserted_atoms[i]; + if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { + res = enable(a); + } + } + return res; + } + + lbool theory_special_relations::final_check_to(relation& r) { + uint_set visited, target; + lbool res = l_true; + for (unsigned i = 0; res == l_true && i < r.m_asserted_atoms.size(); ++i) { + atom& a = *r.m_asserted_atoms[i]; + if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { + target.reset(); + theory_var w; + // v2 !<= v1 is asserted + target.insert(a.v2()); + if (r.m_graph.reachable(a.v1(), visited, target, w)) { + // we already have v1 <= v2 + continue; + } + target.reset(); + if (r.m_graph.reachable(a.v2(), target, visited, w)) { + // there is a common successor + // v1 <= w + // v2 <= w + // v1 !<= v2 + // -> v1 <= w & v2 <= w & v1 !<= v2 -> v2 <= v1 + unsigned timestamp = r.m_graph.get_timestamp(); + r.m_explanation.reset(); + r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r); + r.m_graph.find_shortest_reachable_path(a.v2(), w, timestamp, r); + r.m_explanation.push_back(a.explanation()); + literal_vector const& lits = r.m_explanation; + if (!r.m_graph.enable_edge(r.m_graph.add_edge(a.v2(), a.v1(), s_integer(0), lits))) { + set_neg_cycle_conflict(r); + res = l_false; + } + } + // TODO: check if algorithm correctly produces all constraints. + // e.g., if we add an edge, do we have to repeat the loop? + // + } + } + return res; + } + + lbool theory_special_relations::enable(atom& a) { + if (!a.enable()) { + relation& r = a.get_relation(); + set_neg_cycle_conflict(r); + return l_false; + } + else { + return l_true; + } + } + + void theory_special_relations::set_neg_cycle_conflict(relation& r) { + r.m_explanation.reset(); + r.m_graph.traverse_neg_cycle2(false, r); + set_conflict(r); + } + + void theory_special_relations::set_conflict(relation& r) { + literal_vector const& lits = r.m_explanation; + context & ctx = get_context(); + vector params; + ctx.set_conflict( + ctx.mk_justification( + ext_theory_conflict_justification( + get_id(), ctx.get_region(), + lits.size(), lits.c_ptr(), 0, 0, params.size(), params.c_ptr()))); + } + + lbool theory_special_relations::final_check(relation& r) { + // timer m_timer_fc; //for debugging + // static unsigned call_count = 0; + // static double total_call_times = 0.0; + // m_timer_fc.start(); + // call_count++; + + lbool res = propagate(r); + if (res != l_true) return res; + switch (r.m_property) { + case sr_lo: + res = final_check_lo(r); + break; + case sr_po: + res = final_check_po(r); + break; + case sr_plo: + res = final_check_plo(r); + break; + case sr_to: + res = final_check_to(r); + break; + default: + UNREACHABLE(); + res = l_undef; + } + + return res; + } + + bool theory_special_relations::extract_equalities(relation& r) { + bool new_eq = false; + int_vector scc_id; + u_map roots; + context& ctx = get_context(); + r.m_graph.compute_zero_edge_scc(scc_id); + for (unsigned i = 0, j = 0; i < scc_id.size(); ++i) { + if (scc_id[i] == -1) { + continue; + } + enode* n = get_enode(i); + if (roots.find(scc_id[i], j)) { + enode* m = get_enode(j); + if (n->get_root() != m->get_root()) { + new_eq = true; + unsigned timestamp = r.m_graph.get_timestamp(); + r.m_explanation.reset(); + r.m_graph.find_shortest_zero_edge_path(i, j, timestamp, r); + r.m_graph.find_shortest_zero_edge_path(j, i, timestamp, r); + eq_justification js(ctx.mk_justification(theory_axiom_justification(get_id(), ctx.get_region(), r.m_explanation.size(), r.m_explanation.c_ptr()))); + ctx.assign_eq(n, m, js); + } + } + else { + roots.insert(scc_id[i], i); + } + } + return new_eq; + } + + /* + \brief Propagation for piecewise linear orders + */ + lbool theory_special_relations::propagate_plo(atom& a) { + lbool res = l_true; + relation& r = a.get_relation(); + if (a.phase()) { + r.m_uf.merge(a.v1(), a.v2()); + res = enable(a); + } + else if (r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { + res = enable(a); + } + return res; + } + + lbool theory_special_relations::propagate_po(atom& a) { + lbool res = l_true; + relation& r = a.get_relation(); + if (a.phase()) { + r.m_uf.merge(a.v1(), a.v2()); + res = enable(a); + } + return res; + } + + lbool theory_special_relations::final_check_po(relation& r) { + if (!KVEC) { + lbool res = l_true; + for (unsigned i = 0; res == l_true && i < r.m_asserted_atoms.size(); ++i) { + atom& a = *r.m_asserted_atoms[i]; + if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { + // v1 !-> v2 + // find v1 -> v3 -> v4 -> v2 path + r.m_explanation.reset(); + unsigned timestamp = r.m_graph.get_timestamp(); + auto found_path = HYBRID_SEARCH ? + r.m_graph.find_path(a.v1(), a.v2(), timestamp, r) : + r.m_graph.find_shortest_reachable_path(a.v1(), a.v2(), timestamp, r); + if (found_path) { + r.m_explanation.push_back(a.explanation()); + set_conflict(r); + res = l_false; + } + } + } + return res; + } + context& ctx = get_context(); + ast_manager& m = ctx.get_manager(); + + ptr_vector assumptions; + ptr_vector literals; + + int k = 1; + static int curr_id = 100000; + + u_map> map; + lbool res = l_true; + for (atom * ap : r.m_asserted_atoms) { + if (res != l_true) break; + atom a = *ap; + if (a.phase()) { + continue; + // assumptions.push_back(b); + r.m_uf.merge(a.v1(), a.v2()); + } + } + for (atom * ap : r.m_asserted_atoms) { + if (res != l_true) break; + atom a = *ap; + if (a.phase()) + continue; + if (r.m_uf.find(a.v1()) != r.m_uf.find(a.v2())) { + continue; + } + populate_k_vars(a.v1(), k, map, curr_id, m, &m_int_sort); + populate_k_vars(a.v2(), k, map, curr_id, m, &m_int_sort); + + literals.push_back(m_autil.mk_lt(map[a.v1()][0], map[a.v2()][0])); + + auto bool_sort = m.mk_bool_sort(); + auto b_func = m.mk_func_decl(symbol(curr_id++), 0, &bool_sort, bool_sort); + auto b = m.mk_app(b_func, unsigned(0), nullptr); + + auto f = m.mk_implies( b, m.mk_not(literals.back()) ); + m_nested_solver->assert_expr(f); + atom_cache.insert(b->get_id(), &a); + assumptions.push_back(b); + r.m_explanation.reset(); + if (m_nested_solver->check_sat(assumptions.size(), assumptions.c_ptr()) == l_false) { + expr_ref_vector unsat_core(m); + m_nested_solver->get_unsat_core(unsat_core); + for (expr* e : unsat_core) { + atom& a = *atom_cache[e->get_id()]; + r.m_explanation.push_back(a.explanation()); + } + for (auto e : r.m_explanation) { + std::cerr << "EX " << e.hash() << "\n"; + } + set_conflict(r); + res = l_false; + } + assumptions.pop_back(); + } + return res; + } + + lbool theory_special_relations::propagate(relation& r) { + lbool res = l_true; + while (res == l_true && r.m_asserted_qhead < r.m_asserted_atoms.size()) { + atom& a = *r.m_asserted_atoms[r.m_asserted_qhead]; + switch (r.m_property) { + case sr_lo: + res = enable(a); + break; + case sr_plo: + res = propagate_plo(a); + break; + case sr_po: + res = propagate_po(a); + break; + default: + if (a.phase()) { + res = enable(a); + } + break; + } + ++r.m_asserted_qhead; + } + return res; + } + + void theory_special_relations::reset_eh() { + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + m_relations.reset(); + del_atoms(0); + } + + void theory_special_relations::assign_eh(bool_var v, bool is_true) { + TRACE("special_relations", tout << "assign bv" << v << " " << (is_true?" <- true":" <- false") << "\n";); + atom* a = 0; + VERIFY(m_bool_var2atom.find(v, a)); + a->set_phase(is_true); + a->get_relation().m_asserted_atoms.push_back(a); + //std::cerr << "ASSIGN: " << a->v1() << ' ' << a->v2() << "\n"; + } + + void theory_special_relations::push_scope_eh() { + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + it->m_value->push(); + } + m_atoms_lim.push_back(m_atoms.size()); + } + + void theory_special_relations::pop_scope_eh(unsigned num_scopes) { + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + it->m_value->pop(num_scopes); + } + unsigned new_lvl = m_atoms_lim.size() - num_scopes; + del_atoms(m_atoms_lim[new_lvl]); + } + + void theory_special_relations::del_atoms(unsigned old_size) { + atoms::iterator begin = m_atoms.begin() + old_size; + atoms::iterator it = m_atoms.end(); + while (it != begin) { + --it; + atom * a = *it; + m_bool_var2atom.erase(a->var()); + dealloc(a); + } + m_atoms.shrink(old_size); + } + + + void theory_special_relations::collect_statistics(::statistics & st) const { + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + it->m_value->m_graph.collect_statistics(st); + } + } + + model_value_proc * theory_special_relations::mk_value(enode * n, model_generator & mg) { + UNREACHABLE(); + return 0; + } + + void theory_special_relations::ensure_strict(graph& g) { + unsigned sz = g.get_num_edges(); + for (unsigned i = 0; i < sz; ++i) { + if (!g.is_enabled(i)) continue; + if (g.get_weight(i) != s_integer(0)) continue; + dl_var src = g.get_source(i); + dl_var dst = g.get_target(i); + if (get_enode(src)->get_root() == get_enode(dst)->get_root()) continue; + VERIFY(g.enable_edge(g.add_edge(src, dst, s_integer(-2), literal_vector()))); + } + TRACE("special_relations", g.display(tout);); + } + + void theory_special_relations::ensure_tree(graph& g) { + unsigned sz = g.get_num_nodes(); + for (unsigned i = 0; i < sz; ++i) { + int_vector const& edges = g.get_in_edges(i); + for (unsigned j = 0; j < edges.size(); ++j) { + edge_id e1 = edges[j]; + if (g.is_enabled(e1)) { + SASSERT (i == g.get_target(e1)); + dl_var src1 = g.get_source(e1); + for (unsigned k = j + 1; k < edges.size(); ++k) { + edge_id e2 = edges[k]; + if (g.is_enabled(e2)) { + dl_var src2 = g.get_source(e2); + if (get_enode(src1)->get_root() == get_enode(src2)->get_root()) continue; + if (!disconnected(g, src1, src2)) continue; + VERIFY(g.enable_edge(g.add_edge(src1, src2, s_integer(-2), literal_vector()))); + } + } + } + } + } + TRACE("special_relations", g.display(tout);); + } + + bool theory_special_relations::disconnected(graph const& g, dl_var u, dl_var v) const { + s_integer val_u = g.get_assignment(u); + s_integer val_v = g.get_assignment(v); + if (val_u == val_v) return u != v; + if (val_u < val_v) { + std::swap(u, v); + std::swap(val_u, val_v); + } + SASSERT(val_u > val_v); + svector todo; + todo.push_back(u); + while (!todo.empty()) { + u = todo.back(); + todo.pop_back(); + if (u == v) { + return false; + } + SASSERT(g.get_assignment(u) <= val_u); + if (g.get_assignment(u) <= val_v) { + continue; + } + int_vector const& edges = g.get_out_edges(u); + for (unsigned i = 0; i < edges.size(); ++i) { + edge_id e = edges[i]; + if (is_strict_neighbour_edge(g, e)) { + todo.push_back(g.get_target(e)); + } + } + } + return true; + } + + expr_ref theory_special_relations::mk_inj(relation& r, model_generator& mg) { + // context& ctx = get_context(); + ast_manager& m = get_manager(); + r.push(); + ensure_strict(r.m_graph); + func_decl_ref fn(m); + expr_ref result(m); + arith_util arith(m); + sort* const* ty = r.decl()->get_domain(); + fn = m.mk_fresh_func_decl("inj", 1, ty, arith.mk_int()); + unsigned sz = r.m_graph.get_num_nodes(); + func_interp* fi = alloc(func_interp, m, 1); + for (unsigned i = 0; i < sz; ++i) { + s_integer val = r.m_graph.get_assignment(i); + expr* arg = get_enode(i)->get_owner(); + fi->insert_new_entry(&arg, arith.mk_numeral(val.to_rational(), true)); + } + TRACE("special_relations", r.m_graph.display(tout);); + r.pop(1); + fi->set_else(arith.mk_numeral(rational(0), true)); + mg.get_model().register_decl(fn, fi); + result = arith.mk_le(m.mk_app(fn,m.mk_var(0, *ty)), m.mk_app(fn, m.mk_var(1, *ty))); + return result; + } + + expr_ref theory_special_relations::mk_class(relation& r, model_generator& mg) { + //context& ctx = get_context(); + ast_manager& m = get_manager(); + expr_ref result(m); + func_decl_ref fn(m); + arith_util arith(m); + func_interp* fi = alloc(func_interp, m, 1); + sort* const* ty = r.decl()->get_domain(); + fn = m.mk_fresh_func_decl("class", 1, ty, arith.mk_int()); + unsigned sz = r.m_graph.get_num_nodes(); + for (unsigned i = 0; i < sz; ++i) { + unsigned val = r.m_uf.find(i); + expr* arg = get_enode(i)->get_owner(); + fi->insert_new_entry(&arg, arith.mk_numeral(rational(val), true)); + } + fi->set_else(arith.mk_numeral(rational(0), true)); + mg.get_model().register_decl(fn, fi); + result = m.mk_eq(m.mk_app(fn, m.mk_var(0, *ty)), m.mk_app(fn, m.mk_var(1, *ty))); + return result; + } + + expr_ref theory_special_relations::mk_interval(relation& r, model_generator& mg, unsigned_vector & lo, unsigned_vector& hi) { + graph const& g = r.m_graph; + //context& ctx = get_context(); + ast_manager& m = get_manager(); + expr_ref result(m); + func_decl_ref lofn(m), hifn(m); + arith_util arith(m); + func_interp* lofi = alloc(func_interp, m, 1); + func_interp* hifi = alloc(func_interp, m, 1); + sort* const* ty = r.decl()->get_domain(); + lofn = m.mk_fresh_func_decl("lo", 1, ty, arith.mk_int()); + hifn = m.mk_fresh_func_decl("hi", 1, ty, arith.mk_int()); + unsigned sz = g.get_num_nodes(); + for (unsigned i = 0; i < sz; ++i) { + expr* arg = get_enode(i)->get_owner(); + lofi->insert_new_entry(&arg, arith.mk_numeral(rational(lo[i]), true)); + hifi->insert_new_entry(&arg, arith.mk_numeral(rational(hi[i]), true)); + } + lofi->set_else(arith.mk_numeral(rational(0), true)); + hifi->set_else(arith.mk_numeral(rational(0), true)); + mg.get_model().register_decl(lofn, lofi); + mg.get_model().register_decl(hifn, hifi); + result = m.mk_and(arith.mk_le(m.mk_app(lofn, m.mk_var(0, *ty)), m.mk_app(lofn, m.mk_var(1, *ty))), + arith.mk_le(m.mk_app(hifn, m.mk_var(1, *ty)), m.mk_app(hifn, m.mk_var(0, *ty)))); + return result; + } + + void theory_special_relations::init_model_lo(relation& r, model_generator& m) { + expr_ref inj = mk_inj(r, m); + func_interp* fi = alloc(func_interp, get_manager(), 2); + fi->set_else(inj); + m.get_model().register_decl(r.decl(), fi); + } + + void theory_special_relations::init_model_plo(relation& r, model_generator& m) { + expr_ref inj = mk_inj(r, m); + expr_ref cls = mk_class(r, m); + func_interp* fi = alloc(func_interp, get_manager(), 2); + fi->set_else(get_manager().mk_and(inj, cls)); + m.get_model().register_decl(r.decl(), fi); + } + + void theory_special_relations::init_model_po(relation& r, model_generator& mg) { + // NOT_IMPLEMENTED_YET(); + } + + /** + \brief map each node to an interval of numbers, such that + the children are proper sub-intervals. + Then the <= relation becomes interval containment. + + 1. For each vertex, count the number of nodes below it in the transitive closure. + Store the result in num_children. + 2. Identify each root. + 3. Process children, assigning unique (and disjoint) intervals. + 4. Extract interpretation. + + + */ + + void theory_special_relations::init_model_to(relation& r, model_generator& mg) { + unsigned_vector num_children, lo, hi; + graph const& g = r.m_graph; + r.push(); + ensure_strict(r.m_graph); + ensure_tree(r.m_graph); + count_children(g, num_children); + assign_interval(g, num_children, lo, hi); + expr_ref iv = mk_interval(r, mg, lo, hi); + r.pop(1); + func_interp* fi = alloc(func_interp, get_manager(), 2); + fi->set_else(iv); + mg.get_model().register_decl(r.decl(), fi); + } + + bool theory_special_relations::is_neighbour_edge(graph const& g, edge_id edge) const { + CTRACE("special_relations_verbose", g.is_enabled(edge), + tout << edge << ": " << g.get_source(edge) << " " << g.get_target(edge) << " "; + tout << (g.get_assignment(g.get_source(edge)) - g.get_assignment(g.get_target(edge))) << "\n";); + + return + g.is_enabled(edge) && + g.get_assignment(g.get_source(edge)) - g.get_assignment(g.get_target(edge)) == s_integer(1); + } + + bool theory_special_relations::is_strict_neighbour_edge(graph const& g, edge_id e) const { + return is_neighbour_edge(g, e) && g.get_weight(e) != s_integer(0); + } + + void theory_special_relations::count_children(graph const& g, unsigned_vector& num_children) { + unsigned sz = g.get_num_nodes(); + svector nodes; + num_children.resize(sz, 0); + svector processed(sz, false); + for (unsigned i = 0; i < sz; ++i) nodes.push_back(i); + while (!nodes.empty()) { + dl_var v = nodes.back(); + if (processed[v]) { + nodes.pop_back(); + continue; + } + unsigned nc = 1; + bool all_p = true; + int_vector const& edges = g.get_out_edges(v); + for (unsigned i = 0; i < edges.size(); ++i) { + edge_id e = edges[i]; + if (is_strict_neighbour_edge(g, e)) { + dl_var dst = g.get_target(e); + TRACE("special_relations", tout << v << " -> " << dst << "\n";); + if (!processed[dst]) { + all_p = false; + nodes.push_back(dst); + } + nc += num_children[dst]; + } + } + if (all_p) { + nodes.pop_back(); + num_children[v] = nc; + processed[v] = true; + } + } + TRACE("special_relations", + for (unsigned i = 0; i < sz; ++i) { + tout << i << ": " << num_children[i] << "\n"; + }); + } + + void theory_special_relations::assign_interval(graph const& g, unsigned_vector const& num_children, unsigned_vector& lo, unsigned_vector& hi) { + svector nodes; + unsigned sz = g.get_num_nodes(); + lo.resize(sz, 0); + hi.resize(sz, 0); + unsigned offset = 0; + for (unsigned i = 0; i < sz; ++i) { + bool is_root = true; + int_vector const& edges = g.get_in_edges(i); + for (unsigned j = 0; is_root && j < edges.size(); ++j) { + is_root = !g.is_enabled(edges[j]); + } + if (is_root) { + lo[i] = offset; + hi[i] = offset + num_children[i] - 1; + offset = hi[i] + 1; + nodes.push_back(i); + } + } + while (!nodes.empty()) { + dl_var v = nodes.back(); + int_vector const& edges = g.get_out_edges(v); + unsigned l = lo[v]; + unsigned h = hi[v]; + (void)h; + nodes.pop_back(); + for (unsigned i = 0; i < edges.size(); ++i) { + SASSERT(l <= h); + if (is_strict_neighbour_edge(g, edges[i])) { + dl_var dst = g.get_target(edges[i]); + lo[dst] = l; + hi[dst] = l + num_children[dst] - 1; + l = hi[dst] + 1; + nodes.push_back(dst); + } + } + SASSERT(l == h); + } + } + + void theory_special_relations::init_model(model_generator & m) { + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + switch (it->m_value->m_property) { + case sr_lo: + init_model_lo(*it->m_value, m); + break; + case sr_plo: + init_model_plo(*it->m_value, m); + break; + case sr_to: + init_model_to(*it->m_value, m); + break; + case sr_po: + init_model_po(*it->m_value, m); + break; + default: + UNREACHABLE(); //ASHU: added to remove warning! Should be supported! + } + } + } + + void theory_special_relations::display(std::ostream & out) const { + if (m_relations.empty()) return; + out << "Theory Special Relations\n"; + display_var2enode(out); + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + out << mk_pp(it->m_value->decl(), get_manager()) << ":\n"; + it->m_value->m_graph.display(out); + it->m_value->m_uf.display(out); + for (unsigned i = 0; i < it->m_value->m_asserted_atoms.size(); ++i){ + atom& a = *it->m_value->m_asserted_atoms[i]; + display_atom( out, a ); + } + } + } + + void theory_special_relations::collect_asserted_po_atoms( vector< std::pair >& atoms) const { + obj_map::iterator it = m_relations.begin(), end = m_relations.end(); + for (; it != end; ++it) { + relation& r = *(it->m_value ); + if( r.m_property != sr_po ) continue; + // SASSERT( r.m_asserted_qhead == r.m_asserted_atoms.size() ); + for (unsigned i = 0; i < r.m_asserted_atoms.size(); ++i) { + atom& a = *r.m_asserted_atoms[i]; + atoms.push_back( std::make_pair(a.var(),a.phase()) ); + } + } + } + + void theory_special_relations::display_atom( std::ostream & out, atom& a ) const { + context& ctx = get_context(); + expr* e = ctx.bool_var2expr( a.var() ); + if( !a.phase() ) out << "(not "; + out << mk_pp( e, get_manager()); + if( !a.phase() ) out << ")"; + out << "\n"; + } + + void theory_special_relations::display_atom( atom& a) const { + display_atom( std::cerr, a); + } + +} diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h new file mode 100644 index 000000000..dbb339d3c --- /dev/null +++ b/src/smt/theory_special_relations.h @@ -0,0 +1,198 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + theory_special_relations.h + +Abstract: + + Special Relations theory plugin. + +Author: + + Nikolaj Bjorner (nbjorner) 2015-9-16 + +Notes: + +--*/ + +#include "ast/special_relations_decl_plugin.h" +#include "smt/smt_theory.h" +#include "smt/theory_diff_logic.h" +#include "util/union_find.h" +#include "solver/solver.h" + +#ifndef THEORY_SPECIAL_RELATIONS_H_ +#define THEORY_SPECIAL_RELATIONS_H_ + +namespace smt { + class theory_special_relations : public theory { + + + struct relation; + + class atom { + bool_var m_bvar; + relation& m_relation; + bool m_phase; + theory_var m_v1; + theory_var m_v2; + edge_id m_pos; + edge_id m_neg; + public: + atom(bool_var b, relation& r, theory_var v1, theory_var v2): + m_bvar(b), + m_relation(r), + m_phase(true), + m_v1(v1), + m_v2(v2) + { + r.ensure_var(v1); + r.ensure_var(v2); + literal_vector ls; + ls.push_back(literal(b, false)); + m_pos = r.m_graph.add_edge(v1, v2, s_integer(1), ls); // v2 <= v1 + ls[0] = literal(b, true); + m_neg = r.m_graph.add_edge(v2, v1, s_integer(-2), ls); // v1 <= v2 - 1 + } + bool_var var() const { return m_bvar;} + relation& get_relation() const { return m_relation; } + bool phase() { return m_phase; } + void set_phase(bool b) { m_phase = b; } + theory_var v1() { return m_v1; } + theory_var v2() { return m_v2; } + literal explanation() { return literal(m_bvar, !m_phase); } + bool enable() { + edge_id edge = m_phase?m_pos:m_neg; + return m_relation.m_graph.enable_edge(edge); + } + }; + typedef ptr_vector atoms; + + struct scope { + unsigned m_asserted_atoms_lim; + unsigned m_asserted_qhead_old; + }; + + struct int_ext : public sidl_ext { + typedef literal_vector explanation; + }; + typedef dl_graph graph; + + typedef union_find union_find_t; + + struct relation { + sr_property m_property; + func_decl* m_decl; + atoms m_asserted_atoms; // set of asserted atoms + unsigned m_asserted_qhead; + svector m_scopes; + graph m_graph; + union_find_default_ctx m_ufctx; + union_find_t m_uf; + literal_vector m_explanation; + + relation(sr_property p, func_decl* d): m_property(p), m_decl(d), m_asserted_qhead(0), m_uf(m_ufctx) {} + + func_decl* decl() { return m_decl; } + void push(); + void pop(unsigned num_scopes); + void ensure_var(theory_var v); + bool new_eq_eh(literal l, theory_var v1, theory_var v2); + void operator()(literal_vector const & ex) { + m_explanation.append(ex); + } + void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {} + }; + + + + + typedef u_map bool_var2atom; + + special_relations_util m_util; + arith_util m_autil; + + atoms m_atoms; + unsigned_vector m_atoms_lim; + obj_map m_relations; + bool_var2atom m_bool_var2atom; + + scoped_ptr m_nested_solver; + struct atom_hash { + size_t operator()(atom a) const { + return std::hash()(a.v1()) ^ std::hash()(a.v2()) ^ std::hash()(a.phase()); + } + }; + u_map expr_cache; + u_map atom_cache; + sort* m_int_sort; + + void del_atoms(unsigned old_size); + lbool final_check(relation& r); + lbool final_check_po(relation& r); + lbool final_check_lo(relation& r); + lbool final_check_plo(relation& r); + lbool final_check_to(relation& r); + lbool propagate(relation& r); + lbool enable(atom& a); + bool extract_equalities(relation& r); + void set_neg_cycle_conflict(relation& r); + void set_conflict(relation& r); + lbool propagate_plo(atom& a); + lbool propagate_po(atom& a); //ASHU: added to modify po solving + theory_var mk_var(expr* e); + void count_children(graph const& g, unsigned_vector& num_children); + void ensure_strict(graph& g); + void ensure_tree(graph& g); + void assign_interval(graph const& g, unsigned_vector const& num_children, unsigned_vector& lo, unsigned_vector& hi); + expr_ref mk_inj(relation& r, model_generator& m); + expr_ref mk_class(relation& r, model_generator& m); + expr_ref mk_interval(relation& r, model_generator& mg, unsigned_vector & lo, unsigned_vector& hi); + void init_model_lo(relation& r, model_generator& m); + void init_model_to(relation& r, model_generator& m); + void init_model_po(relation& r, model_generator& m); + void init_model_plo(relation& r, model_generator& m); + bool is_neighbour_edge(graph const& g, edge_id id) const; + bool is_strict_neighbour_edge(graph const& g, edge_id id) const; + bool disconnected(graph const& g, dl_var u, dl_var v) const; + + public: + theory_special_relations(ast_manager& m); + virtual ~theory_special_relations(); + + virtual theory * mk_fresh(context * new_ctx); + virtual bool internalize_atom(app * atom, bool gate_ctx); + virtual bool internalize_term(app * term) { UNREACHABLE(); return false; } + virtual void new_eq_eh(theory_var v1, theory_var v2); + virtual void new_diseq_eh(theory_var v1, theory_var v2) {} + virtual bool use_diseqs() const { return false; } + virtual bool build_models() const { return true; } + virtual final_check_status final_check_eh(); + virtual void reset_eh(); + virtual void assign_eh(bool_var v, bool is_true); + virtual void init_search_eh() {} + virtual void push_scope_eh(); + virtual void pop_scope_eh(unsigned num_scopes); + virtual void restart_eh() {} + virtual void collect_statistics(::statistics & st) const; + virtual model_value_proc * mk_value(enode * n, model_generator & mg); + virtual void init_model(model_generator & m); + virtual bool can_propagate() { return false; } + virtual void propagate() {} + virtual void display(std::ostream & out) const; + + literal mk_literal(expr* _e); + enode* ensure_enode(expr* e); + theory_var mk_var(enode* n); + + //BEGIN: ASHU + void collect_asserted_po_atoms( vector< std::pair >& atoms) const; + void display_atom( std::ostream & out, atom& a) const; + void display_atom( atom& a) const; + //END: ASHU + }; +} + +#endif From 5baef8bcf3b01a981245ee81813edd5550595786 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 19:10:30 -0700 Subject: [PATCH 101/156] use for pattern Signed-off-by: Nikolaj Bjorner --- src/smt/diff_logic.h | 127 ++++++--------------------- src/smt/theory_special_relations.cpp | 10 +-- 2 files changed, 34 insertions(+), 103 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index f3ce7fb13..5ea27d4c9 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -228,10 +228,7 @@ class dl_graph { int n = m_out_edges.size(); for (dl_var id = 0; id < n; id++) { const edge_id_vector & e_ids = m_out_edges[id]; - edge_id_vector::const_iterator it = e_ids.begin(); - edge_id_vector::const_iterator end = e_ids.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : e_ids) { SASSERT(static_cast(e_id) <= m_edges.size()); const edge & e = m_edges[e_id]; SASSERT(e.get_source() == id); @@ -239,10 +236,7 @@ class dl_graph { } for (dl_var id = 0; id < n; id++) { const edge_id_vector & e_ids = m_in_edges[id]; - edge_id_vector::const_iterator it = e_ids.begin(); - edge_id_vector::const_iterator end = e_ids.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : e_ids) { SASSERT(static_cast(e_id) <= m_edges.size()); const edge & e = m_edges[e_id]; SASSERT(e.get_target() == id); @@ -337,10 +331,8 @@ private: } void reset_marks() { - dl_var_vector::iterator it = m_visited.begin(); - dl_var_vector::iterator end = m_visited.end(); - for (; it != end; ++it) { - m_mark[*it] = DL_UNMARKED; + for (dl_var v : m_visited) { + m_mark[v] = DL_UNMARKED; } m_visited.reset(); } @@ -392,10 +384,7 @@ private: return false; } - typename edge_id_vector::iterator it = m_out_edges[source].begin(); - typename edge_id_vector::iterator end = m_out_edges[source].end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : m_out_edges[source]) { edge & e = m_edges[e_id]; SASSERT(e.get_source() == source); if (!e.is_enabled()) { @@ -445,10 +434,7 @@ private: dl_var src = e->get_source(); dl_var dst = e->get_target(); numeral w = e->get_weight(); - typename edge_id_vector::iterator it = m_out_edges[src].begin(); - typename edge_id_vector::iterator end = m_out_edges[src].end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : m_out_edges[src]) { edge const& e2 = m_edges[e_id]; if (e2.get_target() == dst && e2.is_enabled() && // or at least not be inconsistent with current choices @@ -598,10 +584,7 @@ public: // // search for edges that can reduce size of negative cycle. // - typename edge_id_vector::iterator it = m_out_edges[src].begin(); - typename edge_id_vector::iterator end = m_out_edges[src].end(); - for (; it != end; ++it) { - edge_id e_id2 = *it; + for (edge_id e_id2 : m_out_edges[src]) { edge const& e2 = m_edges[e_id2]; dl_var src2 = e2.get_target(); if (e_id2 == e_id || !e2.is_enabled()) { @@ -905,10 +888,8 @@ public: SASSERT(is_feasible()); if (!m_assignment[v].is_zero()) { numeral k = m_assignment[v]; - typename assignment::iterator it = m_assignment.begin(); - typename assignment::iterator end = m_assignment.end(); - for (; it != end; ++it) { - *it -= k; + for (auto& a : m_assignment) { + a -= k; } SASSERT(is_feasible()); } @@ -963,10 +944,7 @@ public: void display_agl(std::ostream & out) const { uint_set vars; - typename edges::const_iterator it = m_edges.begin(); - typename edges::const_iterator end = m_edges.end(); - for (; it != end; ++it) { - edge const& e = *it; + for (edge const& e : m_edges) { if (e.is_enabled()) { vars.insert(e.get_source()); vars.insert(e.get_target()); @@ -980,9 +958,7 @@ public: out << "\"" << v << "\" [label=\"" << v << ":" << m_assignment[v] << "\"]\n"; } } - it = m_edges.begin(); - for (; it != end; ++it) { - edge const& e = *it; + for (edge const& e : m_edges) { if (e.is_enabled()) { out << "\"" << e.get_source() << "\"->\"" << e.get_target() << "\"[label=\"" << e.get_weight() << "\"]\n"; } @@ -998,10 +974,7 @@ public: } void display_edges(std::ostream & out) const { - typename edges::const_iterator it = m_edges.begin(); - typename edges::const_iterator end = m_edges.end(); - for (; it != end; ++it) { - edge const& e = *it; + for (edge const& e : m_edges) { if (e.is_enabled()) { display_edge(out, e); } @@ -1030,11 +1003,8 @@ public: // If there is such edge, then the weight is stored in w and the explanation in ex. bool get_edge_weight(dl_var source, dl_var target, numeral & w, explanation & ex) { edge_id_vector & edges = m_out_edges[source]; - typename edge_id_vector::iterator it = edges.begin(); - typename edge_id_vector::iterator end = edges.end(); bool found = false; - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges) { edge & e = m_edges[e_id]; if (e.is_enabled() && e.get_target() == target && (!found || e.get_weight() < w)) { w = e.get_weight(); @@ -1049,12 +1019,10 @@ public: // If there is such edge, return its edge_id in parameter id. bool get_edge_id(dl_var source, dl_var target, edge_id & id) const { edge_id_vector const & edges = m_out_edges[source]; - typename edge_id_vector::const_iterator it = edges.begin(); - typename edge_id_vector::const_iterator end = edges.end(); - for (; it != end; ++it) { - id = *it; - edge const & e = m_edges[id]; + for (edge_id e_id : edges) { + edge const & e = m_edges[e_id]; if (e.get_target() == target) { + id = e_id; return true; } } @@ -1068,18 +1036,14 @@ public: void get_neighbours_undirected(dl_var current, svector & neighbours) { neighbours.reset(); edge_id_vector & out_edges = m_out_edges[current]; - typename edge_id_vector::iterator it = out_edges.begin(), end = out_edges.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : out_edges) { edge & e = m_edges[e_id]; SASSERT(e.get_source() == current); dl_var neighbour = e.get_target(); neighbours.push_back(neighbour); } edge_id_vector & in_edges = m_in_edges[current]; - typename edge_id_vector::iterator it2 = in_edges.begin(), end2 = in_edges.end(); - for (; it2 != end2; ++it2) { - edge_id e_id = *it2; + for (edge_id e_id : in_edges) { edge & e = m_edges[e_id]; SASSERT(e.get_target() == current); dl_var neighbour = e.get_source(); @@ -1162,10 +1126,7 @@ public: template void enumerate_edges(dl_var source, dl_var target, Functor& f) { edge_id_vector & edges = m_out_edges[source]; - typename edge_id_vector::iterator it = edges.begin(); - typename edge_id_vector::iterator end = edges.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges) { edge const& e = m_edges[e_id]; if (e.get_target() == target) { f(e.get_weight(), e.get_explanation()); @@ -1222,10 +1183,7 @@ public: m_roots.push_back(v); numeral gamma; edge_id_vector & edges = m_out_edges[v]; - typename edge_id_vector::iterator it = edges.begin(); - typename edge_id_vector::iterator end = edges.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges) { edge & e = m_edges[e_id]; if (!e.is_enabled()) { continue; @@ -1278,10 +1236,7 @@ public: for (unsigned i = 0; i < succ.size(); ++i) { v = succ[i]; edge_id_vector & edges = m_out_edges[v]; - typename edge_id_vector::iterator it = edges.begin(); - typename edge_id_vector::iterator end = edges.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges) { edge & e = m_edges[e_id]; if (!e.is_enabled()) { continue; @@ -1708,11 +1663,8 @@ private: for (unsigned i = 0; i < src.m_visited.size(); ++i) { dl_var c = src.m_visited[i]; - typename edge_id_vector::const_iterator it = edges[c].begin(); - typename edge_id_vector::const_iterator end = edges[c].end(); numeral n1 = n0 + src.m_delta[c] - m_assignment[c]; - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : edges[c]) { edge const& e1 = m_edges[e_id]; SASSERT(c == e1.get_source()); if (e1.is_enabled()) { @@ -1760,13 +1712,10 @@ public: edge_id_vector& out_edges = m_out_edges[src]; edge_id_vector& in_edges = m_in_edges[dst]; numeral w = e1.get_weight(); - typename edge_id_vector::const_iterator it, end; if (out_edges.size() < in_edges.size()) { - end = out_edges.end(); - for (it = out_edges.begin(); it != end; ++it) { + for (edge_id e_id : out_edges) { ++m_stats.m_implied_literal_cost; - edge_id e_id = *it; edge const& e2 = m_edges[e_id]; if (e_id != id && !e2.is_enabled() && e2.get_target() == dst && e2.get_weight() >= w) { subsumed.push_back(e_id); @@ -1775,10 +1724,8 @@ public: } } else { - end = in_edges.end(); - for (it = in_edges.begin(); it != end; ++it) { + for (edge_id e_id : in_edges) { ++m_stats.m_implied_literal_cost; - edge_id e_id = *it; edge const& e2 = m_edges[e_id]; if (e_id != id && !e2.is_enabled() && e2.get_source() == src && e2.get_weight() >= w) { subsumed.push_back(e_id); @@ -1812,20 +1759,14 @@ public: find_subsumed1(id, subsumed); typename edge_id_vector::const_iterator it, end, it3, end3; - it = m_in_edges[src].begin(); - end = m_in_edges[src].end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : m_in_edges[src]) { edge const& e2 = m_edges[e_id]; if (!e2.is_enabled() || e2.get_source() == dst) { continue; } w2 = e2.get_weight() + w; - it3 = m_out_edges[e2.get_source()].begin(); - end3 = m_out_edges[e2.get_source()].end(); - for (; it3 != end3; ++it3) { + for (edge_id e_id3 : m_out_edges[e2.get_source()]) { ++m_stats.m_implied_literal_cost; - edge_id e_id3 = *it3; edge const& e3 = m_edges[e_id3]; if (e3.is_enabled() || e3.get_target() != dst) { continue; @@ -1836,21 +1777,15 @@ public: } } } - it = m_out_edges[dst].begin(); - end = m_out_edges[dst].end(); - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : m_out_edges[dst]) { edge const& e2 = m_edges[e_id]; if (!e2.is_enabled() || e2.get_target() == src) { continue; } w2 = e2.get_weight() + w; - it3 = m_in_edges[e2.get_target()].begin(); - end3 = m_in_edges[e2.get_target()].end(); - for (; it3 != end3; ++it3) { + for (edge_id e_id2 : m_in_edges[e2.get_target()]) { ++m_stats.m_implied_literal_cost; - edge_id e_id3 = *it3; edge const& e3 = m_edges[e_id3]; if (e3.is_enabled() || e3.get_source() != src) { continue; @@ -1899,11 +1834,7 @@ public: m_mark[v] = DL_PROCESSED; TRACE("diff_logic", tout << v << "\n";); - typename edge_id_vector::iterator it = m_out_edges[v].begin(); - typename edge_id_vector::iterator end = m_out_edges[v].end(); - - for (; it != end; ++it) { - edge_id e_id = *it; + for (edge_id e_id : m_out_edges[v]) { edge const& e = m_edges[e_id]; if (!e.is_enabled() || e.get_timestamp() > timestamp) { continue; diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index c58ffb24a..a5a6ce13a 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -92,10 +92,10 @@ namespace smt { return alloc(theory_special_relations, new_ctx->get_manager()); } - static void populate_k_vars(int v, int k, u_map>& map, int& curr_id, ast_manager& m, sort** int_sort) { + static void populate_k_vars(int v, int k, u_map>& map, int& curr_id, ast_manager& m, sort* int_sort) { int need = !map.contains(v) ? k : k - map[v].size(); for (auto i = 0; i < need; ++i) { - auto *fd = m.mk_func_decl(symbol(curr_id++), 0, int_sort, *int_sort); + auto *fd = m.mk_const_decl(symbol(curr_id++), int_sort); map[v].push_back(m.mk_app(fd, unsigned(0), nullptr)); } } @@ -438,13 +438,13 @@ namespace smt { if (r.m_uf.find(a.v1()) != r.m_uf.find(a.v2())) { continue; } - populate_k_vars(a.v1(), k, map, curr_id, m, &m_int_sort); - populate_k_vars(a.v2(), k, map, curr_id, m, &m_int_sort); + populate_k_vars(a.v1(), k, map, curr_id, m, m_int_sort); + populate_k_vars(a.v2(), k, map, curr_id, m, m_int_sort); literals.push_back(m_autil.mk_lt(map[a.v1()][0], map[a.v2()][0])); auto bool_sort = m.mk_bool_sort(); - auto b_func = m.mk_func_decl(symbol(curr_id++), 0, &bool_sort, bool_sort); + auto b_func = m.mk_const_decl(symbol(curr_id++), bool_sort); auto b = m.mk_app(b_func, unsigned(0), nullptr); auto f = m.mk_implies( b, m.mk_not(literals.back()) ); From c714abbff2844a28f954f43744d3f38e37d46f3b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 19:21:54 -0700 Subject: [PATCH 102/156] use override Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 4 --- src/smt/theory_special_relations.h | 50 +++++++++++++--------------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index a5a6ce13a..e1a42403d 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -898,8 +898,4 @@ namespace smt { out << "\n"; } - void theory_special_relations::display_atom( atom& a) const { - display_atom( std::cerr, a); - } - } diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index dbb339d3c..90b6a7bbf 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -160,38 +160,36 @@ namespace smt { public: theory_special_relations(ast_manager& m); - virtual ~theory_special_relations(); + ~theory_special_relations() override; - virtual theory * mk_fresh(context * new_ctx); - virtual bool internalize_atom(app * atom, bool gate_ctx); - virtual bool internalize_term(app * term) { UNREACHABLE(); return false; } - virtual void new_eq_eh(theory_var v1, theory_var v2); - virtual void new_diseq_eh(theory_var v1, theory_var v2) {} - virtual bool use_diseqs() const { return false; } - virtual bool build_models() const { return true; } - virtual final_check_status final_check_eh(); - virtual void reset_eh(); - virtual void assign_eh(bool_var v, bool is_true); - virtual void init_search_eh() {} - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); - virtual void restart_eh() {} - virtual void collect_statistics(::statistics & st) const; - virtual model_value_proc * mk_value(enode * n, model_generator & mg); - virtual void init_model(model_generator & m); - virtual bool can_propagate() { return false; } - virtual void propagate() {} - virtual void display(std::ostream & out) const; + theory * mk_fresh(context * new_ctx) override; + bool internalize_atom(app * atom, bool gate_ctx) override; + bool internalize_term(app * term) override { UNREACHABLE(); return false; } + void new_eq_eh(theory_var v1, theory_var v2) override; + void new_diseq_eh(theory_var v1, theory_var v2) override {} + bool use_diseqs() const override { return false; } + bool build_models() const override { return true; } + final_check_status final_check_eh() override; + void reset_eh() override; + void assign_eh(bool_var v, bool is_true) override; + void init_search_eh() override {} + void push_scope_eh() override; + void pop_scope_eh(unsigned num_scopes) override; + void restart_eh() override {} + void collect_statistics(::statistics & st) const override; + model_value_proc * mk_value(enode * n, model_generator & mg) override; + void init_model(model_generator & m) override; + bool can_propagate() override { return false; } + void propagate() override {} + void display(std::ostream & out) const override; literal mk_literal(expr* _e); enode* ensure_enode(expr* e); theory_var mk_var(enode* n); - //BEGIN: ASHU - void collect_asserted_po_atoms( vector< std::pair >& atoms) const; - void display_atom( std::ostream & out, atom& a) const; - void display_atom( atom& a) const; - //END: ASHU + void collect_asserted_po_atoms( vector< std::pair >& atoms) const; + void display_atom( std::ostream & out, atom& a) const; + }; } From 10ba7316972f99705fed0fb7330cf981d0d9eb98 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 20:21:22 -0700 Subject: [PATCH 103/156] tidy Signed-off-by: Nikolaj Bjorner --- src/smt/diff_logic.h | 91 ++++++++++++++---------------- src/smt/theory_special_relations.h | 28 ++++----- 2 files changed, 55 insertions(+), 64 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 5ea27d4c9..29b1050df 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -324,10 +324,11 @@ private: // Store in gamma the normalized weight. The normalized weight is given // by the formula // m_assignment[e.get_source()] - m_assignment[e.get_target()] + e.get_weight() - void set_gamma(const edge & e, numeral & gamma) { + numeral& set_gamma(const edge & e, numeral & gamma) { gamma = m_assignment[e.get_source()]; gamma -= m_assignment[e.get_target()]; gamma += e.get_weight(); + return gamma; } void reset_marks() { @@ -373,7 +374,7 @@ private: TRACE("arith", tout << id << "\n";); dl_var source = target; - for(;;) { + while (true) { ++m_stats.m_propagation_cost; if (m_mark[root] != DL_UNMARKED) { // negative cycle was found @@ -680,8 +681,14 @@ private: int m_total_count = 0; int m_run_counter = -1; svector m_hybrid_visited, m_hybrid_parent; + + bool is_connected(numeral const& gamma, bool zero_edge, edge const& e, unsigned timestamp) const { + return (gamma.is_one() || (!zero_edge && gamma.is_neg())) && e.get_timestamp() < timestamp; + } + public: + template bool find_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { auto zero_edge = true; @@ -713,13 +720,12 @@ public: continue; } set_gamma(e, gamma); - if ((gamma.is_one() || (!zero_edge && gamma.is_neg())) - && e.get_timestamp() < timestamp) { + if (is_connected(gamma, zero_edge, e, timestamp)) { dl_var curr_target = e.get_target(); if (curr_target == target) { f(e.get_explanation()); m_freq_hybrid[e_id]++; - for (;;) { + while (true) { int p = m_hybrid_parent[v]; if (p == -1) return true; @@ -981,12 +987,12 @@ public: } } - void display_edge(std::ostream & out, edge_id id) const { - display_edge(out, m_edges[id]); + std::ostream& display_edge(std::ostream & out, edge_id id) const { + return display_edge(out, m_edges[id]); } - void display_edge(std::ostream & out, const edge & e) const { - out << e.get_explanation() << " (<= (- $" << e.get_target() << " $" << e.get_source() << ") " << e.get_weight() << ") " << e.get_timestamp() << "\n"; + std::ostream& display_edge(std::ostream & out, const edge & e) const { + return out << e.get_explanation() << " (<= (- $" << e.get_target() << " $" << e.get_source() << ") " << e.get_weight() << ") " << e.get_timestamp() << "\n"; } template @@ -1233,17 +1239,11 @@ public: m_dfs_time[v] = 0; succ.push_back(v); numeral gamma; - for (unsigned i = 0; i < succ.size(); ++i) { - v = succ[i]; - edge_id_vector & edges = m_out_edges[v]; - for (edge_id e_id : edges) { - edge & e = m_edges[e_id]; - if (!e.is_enabled()) { - continue; - } - SASSERT(e.get_source() == v); - set_gamma(e, gamma); - if (gamma.is_zero()) { + for (dl_var w : succ) { + for (edge_id e_id : m_out_edges[w]) { + edge & e = m_edges[e_id]; + if (e.is_enabled() && set_gamma(e, gamma).is_zero()) { + SASSERT(e.get_source() == w); dl_var target = e.get_target(); if (m_dfs_time[target] == -1) { succ.push_back(target); @@ -1334,40 +1334,37 @@ private: m_edge_id(e) { } }; - + public: // Find the shortest path from source to target using (normalized) zero edges with timestamp less than the given timestamp. // The functor f is applied on every explanation attached to the edges in the shortest path. // Return true if the path exists, false otherwise. - - - // Return true if the path exists, false otherwise. - template - bool find_shortest_zero_edge_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { - return find_shortest_path_aux(source, target, timestamp, f, true); - } + + + // Return true if the path exists, false otherwise. + template + bool find_shortest_zero_edge_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { + return find_shortest_path_aux(source, target, timestamp, f, true); + } template bool find_shortest_reachable_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { return find_shortest_path_aux(source, target, timestamp, f, false); } - template bool find_shortest_path_aux(dl_var source, dl_var target, unsigned timestamp, Functor & f, bool zero_edge) { svector bfs_todo; - svector bfs_mark; + svector bfs_mark; bfs_mark.resize(m_assignment.size(), false); bfs_todo.push_back(bfs_elem(source, -1, null_edge_id)); bfs_mark[source] = true; - unsigned m_head = 0; numeral gamma; - while (m_head < bfs_todo.size()) { - bfs_elem & curr = bfs_todo[m_head]; - int parent_idx = m_head; - m_head++; + for (unsigned head = 0; head < bfs_todo.size(); ++head) { + bfs_elem & curr = bfs_todo[head]; + int parent_idx = head; dl_var v = curr.m_var; TRACE("dl_bfs", tout << "processing: " << v << "\n";); edge_id_vector & edges = m_out_edges[v]; @@ -1378,18 +1375,16 @@ public: continue; } set_gamma(e, gamma); - TRACE("dl_bfs", tout << "processing edge: "; display_edge(tout, e); tout << "gamma: " << gamma << "\n";); - if ((gamma.is_one() || (!zero_edge && gamma.is_neg())) && e.get_timestamp() < timestamp) { - // if (gamma.is_zero() && e.get_timestamp() < timestamp) + TRACE("dl_bfs", display_edge(tout << "processing edge: ", e) << " gamma: " << gamma << "\n";); + if (is_connected(gamma, zero_edge, e, timestamp)) { dl_var curr_target = e.get_target(); - TRACE("dl_bfs", tout << "curr_target: " << curr_target << - ", mark: " << static_cast(bfs_mark[curr_target]) << "\n";); + TRACE("dl_bfs", tout << "curr_target: " << curr_target << ", mark: " << bfs_mark[curr_target] << "\n";); if (curr_target == target) { TRACE("dl_bfs", tout << "found path\n";); TRACE("dl_eq_bug", tout << "path: " << source << " --> " << target << "\n"; display_edge(tout, e); int tmp_parent_idx = parent_idx; - for (;;) { + while (true) { bfs_elem & curr = bfs_todo[tmp_parent_idx]; if (curr.m_edge_id == null_edge_id) { break; @@ -1399,11 +1394,10 @@ public: display_edge(tout, e); tmp_parent_idx = curr.m_parent_idx; } - tout.flush(); }); TRACE("dl_eq_bug", display_edge(tout, e);); f(e.get_explanation()); - for (;;) { + while (true) { SASSERT(parent_idx >= 0); bfs_elem & curr = bfs_todo[parent_idx]; if (curr.m_edge_id == null_edge_id) { @@ -1417,11 +1411,9 @@ public: } } } - else { - if (!bfs_mark[curr_target]) { - bfs_todo.push_back(bfs_elem(curr_target, parent_idx, e_id)); - bfs_mark[curr_target] = true; - } + else if (!bfs_mark[curr_target]) { + bfs_todo.push_back(bfs_elem(curr_target, parent_idx, e_id)); + bfs_mark[curr_target] = true; } } } @@ -1507,8 +1499,7 @@ private: numeral get_reduced_weight(dfs_state& state, dl_var n, edge const& e) { numeral gamma; - set_gamma(e, gamma); - return state.m_delta[n] + gamma; + return state.m_delta[n] + set_gamma(e, gamma); } template diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 90b6a7bbf..74e9d38bf 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -58,11 +58,11 @@ namespace smt { } bool_var var() const { return m_bvar;} relation& get_relation() const { return m_relation; } - bool phase() { return m_phase; } + bool phase() const { return m_phase; } void set_phase(bool b) { m_phase = b; } - theory_var v1() { return m_v1; } - theory_var v2() { return m_v2; } - literal explanation() { return literal(m_bvar, !m_phase); } + theory_var v1() const { return m_v1; } + theory_var v2() const { return m_v2; } + literal explanation() const { return literal(m_bvar, !m_phase); } bool enable() { edge_id edge = m_phase?m_pos:m_neg; return m_relation.m_graph.enable_edge(edge); @@ -112,16 +112,16 @@ namespace smt { typedef u_map bool_var2atom; special_relations_util m_util; - arith_util m_autil; - + arith_util m_autil; atoms m_atoms; unsigned_vector m_atoms_lim; obj_map m_relations; bool_var2atom m_bool_var2atom; scoped_ptr m_nested_solver; + struct atom_hash { - size_t operator()(atom a) const { + size_t operator()(atom const& a) const { return std::hash()(a.v1()) ^ std::hash()(a.v2()) ^ std::hash()(a.phase()); } }; @@ -158,6 +158,13 @@ namespace smt { bool is_strict_neighbour_edge(graph const& g, edge_id id) const; bool disconnected(graph const& g, dl_var u, dl_var v) const; + literal mk_literal(expr* _e); + enode* ensure_enode(expr* e); + theory_var mk_var(enode* n); + + void collect_asserted_po_atoms(vector< std::pair >& atoms) const; + void display_atom(std::ostream & out, atom& a) const; + public: theory_special_relations(ast_manager& m); ~theory_special_relations() override; @@ -182,13 +189,6 @@ namespace smt { bool can_propagate() override { return false; } void propagate() override {} void display(std::ostream & out) const override; - - literal mk_literal(expr* _e); - enode* ensure_enode(expr* e); - theory_var mk_var(enode* n); - - void collect_asserted_po_atoms( vector< std::pair >& atoms) const; - void display_atom( std::ostream & out, atom& a) const; }; } From f8b8d5b8704495202cd52043d0a3142392f8d8fe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2019 20:47:02 -0700 Subject: [PATCH 104/156] na Signed-off-by: Nikolaj Bjorner --- src/smt/diff_logic.h | 2 +- src/smt/theory_special_relations.cpp | 110 +++++++++++---------------- 2 files changed, 46 insertions(+), 66 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 29b1050df..8544a2384 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -1365,7 +1365,7 @@ public: for (unsigned head = 0; head < bfs_todo.size(); ++head) { bfs_elem & curr = bfs_todo[head]; int parent_idx = head; - dl_var v = curr.m_var; + dl_var v = curr.m_var; TRACE("dl_bfs", tout << "processing: " << v << "\n";); edge_id_vector & edges = m_out_edges[v]; for (edge_id e_id : edges) { diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index e1a42403d..e0201c25c 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -157,23 +157,20 @@ namespace smt { final_check_status theory_special_relations::final_check_eh() { TRACE("special_relations", tout << "\n";); - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - lbool r = l_true; - for (; it != end && r == l_true; ++it) { - r = final_check(*it->m_value); + for (auto const& kv : m_relations) { + lbool r = final_check(*kv.m_value); + switch (r) { + case l_undef: + return FC_GIVEUP; + case l_false: + return FC_CONTINUE; + default: + break; + } } - switch (r) { - case l_undef: - return FC_GIVEUP; - case l_false: - return FC_CONTINUE; - default: - break; - } - it = m_relations.begin(); bool new_equality = false; - for (; it != end; ++it) { - if (extract_equalities(*it->m_value)) { + for (auto const& kv : m_relations) { + if (extract_equalities(*kv.m_value)) { new_equality = true; } } @@ -421,6 +418,7 @@ namespace smt { u_map> map; lbool res = l_true; + // TBD: non-functional code? for (atom * ap : r.m_asserted_atoms) { if (res != l_true) break; atom a = *ap; @@ -449,7 +447,7 @@ namespace smt { auto f = m.mk_implies( b, m.mk_not(literals.back()) ); m_nested_solver->assert_expr(f); - atom_cache.insert(b->get_id(), &a); + atom_cache.insert(b->get_id(), ap); assumptions.push_back(b); r.m_explanation.reset(); if (m_nested_solver->check_sat(assumptions.size(), assumptions.c_ptr()) == l_false) { @@ -496,9 +494,8 @@ namespace smt { } void theory_special_relations::reset_eh() { - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - dealloc(it->m_value); + for (auto const& kv : m_relations) { + dealloc(kv.m_value); } m_relations.reset(); del_atoms(0); @@ -510,21 +507,18 @@ namespace smt { VERIFY(m_bool_var2atom.find(v, a)); a->set_phase(is_true); a->get_relation().m_asserted_atoms.push_back(a); - //std::cerr << "ASSIGN: " << a->v1() << ' ' << a->v2() << "\n"; } void theory_special_relations::push_scope_eh() { - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - it->m_value->push(); + for (auto const& kv : m_relations) { + kv.m_value->push(); } m_atoms_lim.push_back(m_atoms.size()); } void theory_special_relations::pop_scope_eh(unsigned num_scopes) { - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - it->m_value->pop(num_scopes); + for (auto const& kv : m_relations) { + kv.m_value->pop(num_scopes); } unsigned new_lvl = m_atoms_lim.size() - num_scopes; del_atoms(m_atoms_lim[new_lvl]); @@ -544,9 +538,8 @@ namespace smt { void theory_special_relations::collect_statistics(::statistics & st) const { - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - it->m_value->m_graph.collect_statistics(st); + for (auto const& kv : m_relations) { + kv.m_value->m_graph.collect_statistics(st); } } @@ -613,9 +606,7 @@ namespace smt { if (g.get_assignment(u) <= val_v) { continue; } - int_vector const& edges = g.get_out_edges(u); - for (unsigned i = 0; i < edges.size(); ++i) { - edge_id e = edges[i]; + for (edge_id e : g.get_out_edges(u)) { if (is_strict_neighbour_edge(g, e)) { todo.push_back(g.get_target(e)); } @@ -773,9 +764,7 @@ namespace smt { } unsigned nc = 1; bool all_p = true; - int_vector const& edges = g.get_out_edges(v); - for (unsigned i = 0; i < edges.size(); ++i) { - edge_id e = edges[i]; + for (edge_id e : g.get_out_edges(v)) { if (is_strict_neighbour_edge(g, e)) { dl_var dst = g.get_target(e); TRACE("special_relations", tout << v << " -> " << dst << "\n";); @@ -839,23 +828,22 @@ namespace smt { } void theory_special_relations::init_model(model_generator & m) { - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - switch (it->m_value->m_property) { + for (auto const& kv : m_relations) { + switch (kv.m_value->m_property) { case sr_lo: - init_model_lo(*it->m_value, m); + init_model_lo(*kv.m_value, m); break; case sr_plo: - init_model_plo(*it->m_value, m); + init_model_plo(*kv.m_value, m); break; case sr_to: - init_model_to(*it->m_value, m); + init_model_to(*kv.m_value, m); break; case sr_po: - init_model_po(*it->m_value, m); + init_model_po(*kv.m_value, m); break; default: - UNREACHABLE(); //ASHU: added to remove warning! Should be supported! + UNREACHABLE(); //ASHU: added to remove warning! Should be supported! } } } @@ -864,38 +852,30 @@ namespace smt { if (m_relations.empty()) return; out << "Theory Special Relations\n"; display_var2enode(out); - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - out << mk_pp(it->m_value->decl(), get_manager()) << ":\n"; - it->m_value->m_graph.display(out); - it->m_value->m_uf.display(out); - for (unsigned i = 0; i < it->m_value->m_asserted_atoms.size(); ++i){ - atom& a = *it->m_value->m_asserted_atoms[i]; - display_atom( out, a ); + for (auto const& kv : m_relations) { + out << mk_pp(kv.m_value->decl(), get_manager()) << ":\n"; + kv.m_value->m_graph.display(out); + kv.m_value->m_uf.display(out); + for (atom* ap : kv.m_value->m_asserted_atoms) { + display_atom(out, *ap); } } } - void theory_special_relations::collect_asserted_po_atoms( vector< std::pair >& atoms) const { - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; it != end; ++it) { - relation& r = *(it->m_value ); - if( r.m_property != sr_po ) continue; - // SASSERT( r.m_asserted_qhead == r.m_asserted_atoms.size() ); - for (unsigned i = 0; i < r.m_asserted_atoms.size(); ++i) { - atom& a = *r.m_asserted_atoms[i]; - atoms.push_back( std::make_pair(a.var(),a.phase()) ); + void theory_special_relations::collect_asserted_po_atoms(vector>& atoms) const { + for (auto const& kv : m_relations) { + relation& r = *kv.m_value; + if (r.m_property != sr_po) continue; + for (atom* ap : r.m_asserted_atoms) { + atoms.push_back(std::make_pair(ap->var(), ap->phase())); } } } - void theory_special_relations::display_atom( std::ostream & out, atom& a ) const { + void theory_special_relations::display_atom(std::ostream & out, atom& a) const { context& ctx = get_context(); expr* e = ctx.bool_var2expr( a.var() ); - if( !a.phase() ) out << "(not "; - out << mk_pp( e, get_manager()); - if( !a.phase() ) out << ")"; - out << "\n"; + out << (a.phase() ? "" : "(not ") << mk_pp(e, get_manager()) << (a.phase() ? "" : ")") << "\n"; } } From 1e751422e18ee73f1ecc0cc3c049a465344b4d18 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 03:36:30 -0700 Subject: [PATCH 105/156] remove unused code Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 110 +++++---------------------- src/smt/theory_special_relations.h | 12 --- 2 files changed, 17 insertions(+), 105 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index e0201c25c..9e1579570 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -28,7 +28,6 @@ Notes: #include "ast/reg_decl_plugins.h" #include "ast/ast_pp.h" -static constexpr bool KVEC = false; static constexpr bool HYBRID_SEARCH = false; namespace smt { @@ -38,9 +37,7 @@ namespace smt { scope& s = m_scopes.back(); s.m_asserted_atoms_lim = m_asserted_atoms.size(); s.m_asserted_qhead_old = m_asserted_qhead; - if (!KVEC) { - m_graph.push(); - } + m_graph.push(); m_ufctx.get_trail_stack().push_scope(); } @@ -50,9 +47,7 @@ namespace smt { m_asserted_atoms.shrink(s.m_asserted_atoms_lim); m_asserted_qhead = s.m_asserted_qhead_old; m_scopes.shrink(new_lvl); - if (!KVEC) { - m_graph.pop(num_scopes); - } + m_graph.pop(num_scopes); m_ufctx.get_trail_stack().pop_scope(num_scopes); } @@ -75,17 +70,11 @@ namespace smt { theory_special_relations::theory_special_relations(ast_manager& m): theory(m.mk_family_id("special_relations")), - m_util(m), m_autil(m) { - params_ref params; - params.set_bool("model", true); - params.set_bool("unsat_core", true); - m_nested_solver = mk_smt_solver(m, params, symbol("QF_LRA")); - m_int_sort = m_autil.mk_real(); + m_util(m) { } theory_special_relations::~theory_special_relations() { reset_eh(); - m_nested_solver = nullptr; } theory * theory_special_relations::mk_fresh(context * new_ctx) { @@ -118,7 +107,7 @@ namespace smt { ctx.set_var_theory(v, get_id()); atom* a = alloc(atom, v, *r, v0, v1); m_atoms.push_back(a); - //std::cerr << "INTER : " << a->v1() << ' ' << a->v2() << ' ' << gate_ctx << "\n"; + TRACE("sr", tout << "INTER : " << a->v1() << ' ' << a->v2() << ' ' << gate_ctx << "\n";); m_bool_var2atom.insert(v, a); return true; } @@ -386,86 +375,22 @@ namespace smt { } lbool theory_special_relations::final_check_po(relation& r) { - if (!KVEC) { - lbool res = l_true; - for (unsigned i = 0; res == l_true && i < r.m_asserted_atoms.size(); ++i) { - atom& a = *r.m_asserted_atoms[i]; - if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { - // v1 !-> v2 - // find v1 -> v3 -> v4 -> v2 path - r.m_explanation.reset(); - unsigned timestamp = r.m_graph.get_timestamp(); - auto found_path = HYBRID_SEARCH ? - r.m_graph.find_path(a.v1(), a.v2(), timestamp, r) : - r.m_graph.find_shortest_reachable_path(a.v1(), a.v2(), timestamp, r); - if (found_path) { - r.m_explanation.push_back(a.explanation()); - set_conflict(r); - res = l_false; - } - } - } - return res; - } - context& ctx = get_context(); - ast_manager& m = ctx.get_manager(); - - ptr_vector assumptions; - ptr_vector literals; - - int k = 1; - static int curr_id = 100000; - - u_map> map; - lbool res = l_true; - // TBD: non-functional code? - for (atom * ap : r.m_asserted_atoms) { - if (res != l_true) break; - atom a = *ap; - if (a.phase()) { - continue; - // assumptions.push_back(b); - r.m_uf.merge(a.v1(), a.v2()); - } - } - for (atom * ap : r.m_asserted_atoms) { - if (res != l_true) break; - atom a = *ap; - if (a.phase()) - continue; - if (r.m_uf.find(a.v1()) != r.m_uf.find(a.v2())) { - continue; - } - populate_k_vars(a.v1(), k, map, curr_id, m, m_int_sort); - populate_k_vars(a.v2(), k, map, curr_id, m, m_int_sort); - - literals.push_back(m_autil.mk_lt(map[a.v1()][0], map[a.v2()][0])); - - auto bool_sort = m.mk_bool_sort(); - auto b_func = m.mk_const_decl(symbol(curr_id++), bool_sort); - auto b = m.mk_app(b_func, unsigned(0), nullptr); - - auto f = m.mk_implies( b, m.mk_not(literals.back()) ); - m_nested_solver->assert_expr(f); - atom_cache.insert(b->get_id(), ap); - assumptions.push_back(b); - r.m_explanation.reset(); - if (m_nested_solver->check_sat(assumptions.size(), assumptions.c_ptr()) == l_false) { - expr_ref_vector unsat_core(m); - m_nested_solver->get_unsat_core(unsat_core); - for (expr* e : unsat_core) { - atom& a = *atom_cache[e->get_id()]; + for (atom* ap : r.m_asserted_atoms) { + atom& a = *ap; + if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { + // v1 !-> v2 + // find v1 -> v3 -> v4 -> v2 path + r.m_explanation.reset(); + unsigned timestamp = r.m_graph.get_timestamp(); + bool found_path = r.m_graph.find_shortest_reachable_path(a.v1(), a.v2(), timestamp, r); + if (found_path) { r.m_explanation.push_back(a.explanation()); + set_conflict(r); + return l_false; } - for (auto e : r.m_explanation) { - std::cerr << "EX " << e.hash() << "\n"; - } - set_conflict(r); - res = l_false; } - assumptions.pop_back(); } - return res; + return l_true; } lbool theory_special_relations::propagate(relation& r) { @@ -503,8 +428,7 @@ namespace smt { void theory_special_relations::assign_eh(bool_var v, bool is_true) { TRACE("special_relations", tout << "assign bv" << v << " " << (is_true?" <- true":" <- false") << "\n";); - atom* a = 0; - VERIFY(m_bool_var2atom.find(v, a)); + atom* a = m_bool_var2atom[v]; a->set_phase(is_true); a->get_relation().m_asserted_atoms.push_back(a); } diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 74e9d38bf..e9e5668f3 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -112,22 +112,10 @@ namespace smt { typedef u_map bool_var2atom; special_relations_util m_util; - arith_util m_autil; atoms m_atoms; unsigned_vector m_atoms_lim; obj_map m_relations; bool_var2atom m_bool_var2atom; - - scoped_ptr m_nested_solver; - - struct atom_hash { - size_t operator()(atom const& a) const { - return std::hash()(a.v1()) ^ std::hash()(a.v2()) ^ std::hash()(a.phase()); - } - }; - u_map expr_cache; - u_map atom_cache; - sort* m_int_sort; void del_atoms(unsigned old_size); lbool final_check(relation& r); From 168b0bcc4474300744ec92b6c6617c07beb84e46 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 04:43:47 -0700 Subject: [PATCH 106/156] tidy Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 103 +++++++++++---------------- src/smt/theory_special_relations.h | 13 +++- 2 files changed, 53 insertions(+), 63 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 9e1579570..95cfb410e 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -28,8 +28,6 @@ Notes: #include "ast/reg_decl_plugins.h" #include "ast/ast_pp.h" -static constexpr bool HYBRID_SEARCH = false; - namespace smt { void theory_special_relations::relation::push() { @@ -63,9 +61,7 @@ namespace smt { ensure_var(v2); literal_vector ls; ls.push_back(l); - return - m_graph.enable_edge(m_graph.add_edge(v1, v2, s_integer(1), ls)) && - m_graph.enable_edge(m_graph.add_edge(v2, v1, s_integer(1), ls)); + return m_graph.add_non_strict_edge(v1, v2, ls) && m_graph.add_non_strict_edge(v2, v1, ls); } theory_special_relations::theory_special_relations(ast_manager& m): @@ -81,22 +77,13 @@ namespace smt { return alloc(theory_special_relations, new_ctx->get_manager()); } - static void populate_k_vars(int v, int k, u_map>& map, int& curr_id, ast_manager& m, sort* int_sort) { - int need = !map.contains(v) ? k : k - map[v].size(); - for (auto i = 0; i < need; ++i) { - auto *fd = m.mk_const_decl(symbol(curr_id++), int_sort); - map[v].push_back(m.mk_app(fd, unsigned(0), nullptr)); - } - } - bool theory_special_relations::internalize_atom(app * atm, bool gate_ctx) { - TRACE("special_relations", tout << mk_pp(atm, get_manager()) << "\n";); SASSERT(m_util.is_special_relation(atm)); relation* r = 0; if (!m_relations.find(atm->get_decl(), r)) { - //todo: push pop may get misaligned if the following alloc happens after push r = alloc(relation, m_util.get_property(atm), atm->get_decl()); m_relations.insert(atm->get_decl(), r); + for (unsigned i = 0; i < m_atoms_lim.size(); ++i) r->push(); } context& ctx = get_context(); expr* arg0 = atm->get_arg(0); @@ -107,7 +94,7 @@ namespace smt { ctx.set_var_theory(v, get_id()); atom* a = alloc(atom, v, *r, v0, v1); m_atoms.push_back(a); - TRACE("sr", tout << "INTER : " << a->v1() << ' ' << a->v2() << ' ' << gate_ctx << "\n";); + TRACE("special_relations", tout << mk_pp(atm, get_manager()) << " : " << a->v1() << ' ' << a->v2() << ' ' << gate_ctx << "\n";); m_bool_var2atom.insert(v, a); return true; } @@ -222,42 +209,39 @@ namespace smt { lbool theory_special_relations::final_check_to(relation& r) { uint_set visited, target; - lbool res = l_true; - for (unsigned i = 0; res == l_true && i < r.m_asserted_atoms.size(); ++i) { - atom& a = *r.m_asserted_atoms[i]; - if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { - target.reset(); - theory_var w; - // v2 !<= v1 is asserted - target.insert(a.v2()); - if (r.m_graph.reachable(a.v1(), visited, target, w)) { - // we already have v1 <= v2 - continue; + for (atom* ap : r.m_asserted_atoms) { + atom& a = *ap; + if (a.phase() || r.m_uf.find(a.v1()) != r.m_uf.find(a.v2())) { + continue; + } + target.reset(); + theory_var w; + // v2 !<= v1 is asserted + target.insert(a.v2()); + if (r.m_graph.reachable(a.v1(), visited, target, w)) { + // we already have v1 <= v2 + continue; + } + target.reset(); + if (r.m_graph.reachable(a.v2(), target, visited, w)) { + // there is a common successor + // v1 <= w + // v2 <= w + // v1 !<= v2 + // -> v1 <= w & v2 <= w & v1 !<= v2 -> v2 <= v1 + unsigned timestamp = r.m_graph.get_timestamp(); + r.m_explanation.reset(); + r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r); + r.m_graph.find_shortest_reachable_path(a.v2(), w, timestamp, r); + r.m_explanation.push_back(a.explanation()); + literal_vector const& lits = r.m_explanation; + if (!r.m_graph.add_non_strict_edge(a.v2(), a.v1(), lits)) { + set_neg_cycle_conflict(r); + return l_false; } - target.reset(); - if (r.m_graph.reachable(a.v2(), target, visited, w)) { - // there is a common successor - // v1 <= w - // v2 <= w - // v1 !<= v2 - // -> v1 <= w & v2 <= w & v1 !<= v2 -> v2 <= v1 - unsigned timestamp = r.m_graph.get_timestamp(); - r.m_explanation.reset(); - r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r); - r.m_graph.find_shortest_reachable_path(a.v2(), w, timestamp, r); - r.m_explanation.push_back(a.explanation()); - literal_vector const& lits = r.m_explanation; - if (!r.m_graph.enable_edge(r.m_graph.add_edge(a.v2(), a.v1(), s_integer(0), lits))) { - set_neg_cycle_conflict(r); - res = l_false; - } - } - // TODO: check if algorithm correctly produces all constraints. - // e.g., if we add an edge, do we have to repeat the loop? - // } } - return res; + return l_true; } lbool theory_special_relations::enable(atom& a) { @@ -289,12 +273,6 @@ namespace smt { } lbool theory_special_relations::final_check(relation& r) { - // timer m_timer_fc; //for debugging - // static unsigned call_count = 0; - // static double total_call_times = 0.0; - // m_timer_fc.start(); - // call_count++; - lbool res = propagate(r); if (res != l_true) return res; switch (r.m_property) { @@ -446,6 +424,7 @@ namespace smt { } unsigned new_lvl = m_atoms_lim.size() - num_scopes; del_atoms(m_atoms_lim[new_lvl]); + m_atoms_lim.shrink(new_lvl); } void theory_special_relations::del_atoms(unsigned old_size) { @@ -453,7 +432,7 @@ namespace smt { atoms::iterator it = m_atoms.end(); while (it != begin) { --it; - atom * a = *it; + atom* a = *it; m_bool_var2atom.erase(a->var()); dealloc(a); } @@ -469,7 +448,7 @@ namespace smt { model_value_proc * theory_special_relations::mk_value(enode * n, model_generator & mg) { UNREACHABLE(); - return 0; + return nullptr; } void theory_special_relations::ensure_strict(graph& g) { @@ -480,7 +459,7 @@ namespace smt { dl_var src = g.get_source(i); dl_var dst = g.get_target(i); if (get_enode(src)->get_root() == get_enode(dst)->get_root()) continue; - VERIFY(g.enable_edge(g.add_edge(src, dst, s_integer(-2), literal_vector()))); + VERIFY(g.add_strict_edge(src, dst, literal_vector())); } TRACE("special_relations", g.display(tout);); } @@ -498,9 +477,10 @@ namespace smt { edge_id e2 = edges[k]; if (g.is_enabled(e2)) { dl_var src2 = g.get_source(e2); - if (get_enode(src1)->get_root() == get_enode(src2)->get_root()) continue; - if (!disconnected(g, src1, src2)) continue; - VERIFY(g.enable_edge(g.add_edge(src1, src2, s_integer(-2), literal_vector()))); + if (get_enode(src1)->get_root() != get_enode(src2)->get_root() && + disconnected(g, src1, src2)) { + VERIFY(g.add_strict_edge(src1, src2, literal_vector())); + } } } } @@ -587,7 +567,6 @@ namespace smt { expr_ref theory_special_relations::mk_interval(relation& r, model_generator& mg, unsigned_vector & lo, unsigned_vector& hi) { graph const& g = r.m_graph; - //context& ctx = get_context(); ast_manager& m = get_manager(); expr_ref result(m); func_decl_ref lofn(m), hifn(m); diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index e9e5668f3..7c243dee0 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -78,7 +78,14 @@ namespace smt { struct int_ext : public sidl_ext { typedef literal_vector explanation; }; - typedef dl_graph graph; + struct graph : public dl_graph { + bool add_strict_edge(theory_var v1, theory_var v2, literal_vector const& j) { + return enable_edge(add_edge(v1, v2, s_integer(1), j)); + } + bool add_non_strict_edge(theory_var v1, theory_var v2, literal_vector const& j) { + return enable_edge(add_edge(v1, v2, s_integer(-2), j)); + } + }; typedef union_find union_find_t; @@ -104,6 +111,9 @@ namespace smt { m_explanation.append(ex); } void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {} + + bool add_strict_edge(theory_var v1, theory_var v2, literal_vector const& j); + bool add_non_strict_edge(theory_var v1, theory_var v2, literal_vector const& j); }; @@ -117,6 +127,7 @@ namespace smt { obj_map m_relations; bool_var2atom m_bool_var2atom; + void del_atoms(unsigned old_size); lbool final_check(relation& r); lbool final_check_po(relation& r); From 892be69d5142e4c889ad60f3dfa36e8166f6f245 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 10:40:08 -0700 Subject: [PATCH 107/156] nits Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 15 ++++----------- src/smt/theory_special_relations.h | 10 +++++----- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 95cfb410e..03066f766 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -115,15 +115,11 @@ namespace smt { void theory_special_relations::new_eq_eh(theory_var v1, theory_var v2) { context& ctx = get_context(); - app_ref eq(get_manager()); app* t1 = get_enode(v1)->get_owner(); app* t2 = get_enode(v2)->get_owner(); - eq = get_manager().mk_eq(t1, t2); - VERIFY(internalize_atom(eq, false)); - literal l(ctx.get_literal(eq)); - obj_map::iterator it = m_relations.begin(), end = m_relations.end(); - for (; !ctx.inconsistent() && it != end; ++it) { - relation& r = *it->m_value; + literal eq = mk_eq(t1, t2, false); + for (auto const& kv : m_relations) { + relation& r = *kv.m_value; if (!r.new_eq_eh(l, v1, v2)) { set_neg_cycle_conflict(r); break; @@ -175,9 +171,8 @@ namespace smt { literal theory_special_relations::mk_literal(expr* _e) { expr_ref e(_e, get_manager()); - context& ctx = get_context(); ensure_enode(e); - return ctx.get_literal(e); + return get_context().get_literal(e); } theory_var theory_special_relations::mk_var(enode* n) { @@ -520,7 +515,6 @@ namespace smt { } expr_ref theory_special_relations::mk_inj(relation& r, model_generator& mg) { - // context& ctx = get_context(); ast_manager& m = get_manager(); r.push(); ensure_strict(r.m_graph); @@ -545,7 +539,6 @@ namespace smt { } expr_ref theory_special_relations::mk_class(relation& r, model_generator& mg) { - //context& ctx = get_context(); ast_manager& m = get_manager(); expr_ref result(m); func_decl_ref fn(m); diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 7c243dee0..01314b362 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -17,14 +17,14 @@ Notes: --*/ +#ifndef THEORY_SPECIAL_RELATIONS_H_ +#define THEORY_SPECIAL_RELATIONS_H_ + #include "ast/special_relations_decl_plugin.h" #include "smt/smt_theory.h" #include "smt/theory_diff_logic.h" #include "util/union_find.h" -#include "solver/solver.h" - -#ifndef THEORY_SPECIAL_RELATIONS_H_ -#define THEORY_SPECIAL_RELATIONS_H_ +#include "util/rational.h" namespace smt { class theory_special_relations : public theory { @@ -140,7 +140,7 @@ namespace smt { void set_neg_cycle_conflict(relation& r); void set_conflict(relation& r); lbool propagate_plo(atom& a); - lbool propagate_po(atom& a); //ASHU: added to modify po solving + lbool propagate_po(atom& a); theory_var mk_var(expr* e); void count_children(graph const& g, unsigned_vector& num_children); void ensure_strict(graph& g); From 6a9cbe146169c4b02460f5bbc63a4c0fb6b83c68 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 10:43:29 -0700 Subject: [PATCH 108/156] l -> eq Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 03066f766..3750ce967 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -120,7 +120,7 @@ namespace smt { literal eq = mk_eq(t1, t2, false); for (auto const& kv : m_relations) { relation& r = *kv.m_value; - if (!r.new_eq_eh(l, v1, v2)) { + if (!r.new_eq_eh(eq, v1, v2)) { set_neg_cycle_conflict(r); break; } From e3a2168a20ace02a06e15d9bba6740e5fb4ed650 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 13:13:50 -0700 Subject: [PATCH 109/156] e_id3 Signed-off-by: Nikolaj Bjorner --- src/smt/diff_logic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 8544a2384..8332baaf4 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -1775,7 +1775,7 @@ public: continue; } w2 = e2.get_weight() + w; - for (edge_id e_id2 : m_in_edges[e2.get_target()]) { + for (edge_id e_id3 : m_in_edges[e2.get_target()]) { ++m_stats.m_implied_literal_cost; edge const& e3 = m_edges[e_id3]; if (e3.is_enabled() || e3.get_source() != src) { From 5536834019ec6fb61b5e410ef4d97c59e04f386c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 17:42:27 -0700 Subject: [PATCH 110/156] add API Signed-off-by: Nikolaj Bjorner --- src/api/CMakeLists.txt | 1 + src/api/api_ast.cpp | 12 +++++ src/api/api_context.cpp | 1 + src/api/api_context.h | 3 ++ src/api/api_special_relations.cpp | 78 ++++++++++++++++++++++++++++ src/api/c++/z3++.h | 36 +++++++++++++ src/api/z3_api.h | 57 +++++++++++++++++++- src/smt/diff_logic.h | 9 ++-- src/smt/theory_special_relations.cpp | 31 ++++++----- src/smt/theory_special_relations.h | 22 ++++---- 10 files changed, 223 insertions(+), 27 deletions(-) create mode 100644 src/api/api_special_relations.cpp diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt index 4a5514a7b..247d0a14c 100644 --- a/src/api/CMakeLists.txt +++ b/src/api/CMakeLists.txt @@ -61,6 +61,7 @@ z3_add_component(api api_rcf.cpp api_seq.cpp api_solver.cpp + api_special_relations.cpp api_stats.cpp api_tactic.cpp z3_replayer.cpp diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index cabfdb101..a8f62572a 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1052,6 +1052,18 @@ extern "C" { } } + if (mk_c(c)->get_special_relations_fid() == _d->get_family_id()) { + switch(_d->get_decl_kind()) { + case OP_SPECIAL_RELATION_LO : return Z3_OP_SPECIAL_RELATION_LO; + case OP_SPECIAL_RELATION_PO : return Z3_OP_SPECIAL_RELATION_PO; + case OP_SPECIAL_RELATION_PO_AO : return Z3_OP_SPECIAL_RELATION_PO_AO; + case OP_SPECIAL_RELATION_PLO: return Z3_OP_SPECIAL_RELATION_PLO; + case OP_SPECIAL_RELATION_TO : return Z3_OP_SPECIAL_RELATION_TO; + default: UNREACHABLE(); + } + } + + if (mk_c(c)->get_bv_fid() == _d->get_family_id()) { switch(_d->get_decl_kind()) { case OP_BV_NUM: return Z3_OP_BNUM; diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 71bebef73..811cb30ee 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -101,6 +101,7 @@ namespace api { m_datalog_fid = m().mk_family_id("datalog_relation"); m_fpa_fid = m().mk_family_id("fpa"); m_seq_fid = m().mk_family_id("seq"); + m_special_relations_fid = m().mk_family_id("special_relations"); m_dt_plugin = static_cast(m().get_plugin(m_dt_fid)); install_tactics(*this); diff --git a/src/api/api_context.h b/src/api/api_context.h index 8bd75aaa0..1c4145810 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -30,6 +30,7 @@ Revision History: #include "ast/dl_decl_plugin.h" #include "ast/fpa_decl_plugin.h" #include "ast/recfun_decl_plugin.h" +#include "ast/special_relations_decl_plugin.h" #include "smt/smt_kernel.h" #include "smt/params/smt_params.h" #include "util/event_handler.h" @@ -106,6 +107,7 @@ namespace api { family_id m_pb_fid; family_id m_fpa_fid; family_id m_seq_fid; + family_id m_special_relations_fid; datatype_decl_plugin * m_dt_plugin; std::string m_string_buffer; // temporary buffer used to cache strings sent to the "external" world. @@ -162,6 +164,7 @@ namespace api { family_id get_fpa_fid() const { return m_fpa_fid; } family_id get_seq_fid() const { return m_seq_fid; } datatype_decl_plugin * get_dt_plugin() const { return m_dt_plugin; } + family_id get_special_relations_fid() const { return m_special_relations_fid; } Z3_error_code get_error_code() const { return m_error_code; } void reset_error_code(); diff --git a/src/api/api_special_relations.cpp b/src/api/api_special_relations.cpp new file mode 100644 index 000000000..40fde5083 --- /dev/null +++ b/src/api/api_special_relations.cpp @@ -0,0 +1,78 @@ +/*++ +Copyright (c) 2019 Microsoft Corporation + +Module Name: + + api_special_relations.cpp + +Abstract: + Basic API for Special relations + +Author: + + Nikolaj Bjorner (nbjorner) 2019-03-25 + Ashutosh Gupta 2016 + +Revision History: + +--*/ + +#include +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "ast/ast_pp.h" +#include "ast/special_relations_decl_plugin.h" + +extern "C" { + +#if 0 + bool Z3_API Z3_is_sr_lo(Z3_context c, Z3_ast s) { + Z3_TRY; + LOG_Z3_is_sr_lo(c, s); + RESET_ERROR_CODE(); + RETURN_Z3(mk_c(c)->sr_util().is_lo( to_expr(s) )); + Z3_CATCH_RETURN(false); + } + + bool Z3_API Z3_is_sr_po(Z3_context c, Z3_ast s) { + Z3_TRY; + LOG_Z3_is_sr_po(c, s); + RESET_ERROR_CODE(); + RETURN_Z3(mk_c(c)->sr_util().is_po( to_expr(s) )); + Z3_CATCH_RETURN(false); + } + + bool Z3_API Z3_is_sr_po_ao(Z3_context c, Z3_ast s) { + Z3_TRY; + LOG_Z3_is_sr_po_ao(c, s); + RESET_ERROR_CODE(); + RETURN_Z3(mk_c(c)->sr_util().is_po_ao( to_expr(s) )); + Z3_CATCH_RETURN(false); + } + + bool Z3_API Z3_is_sr_plo(Z3_context c, Z3_ast s) { + Z3_TRY; + LOG_Z3_is_sr_plo(c, s); + RESET_ERROR_CODE(); + RETURN_Z3(mk_c(c)->sr_util().is_plo( to_expr(s) )); + Z3_CATCH_RETURN(false); + } + + bool Z3_API Z3_is_sr_to(Z3_context c, Z3_ast s) { + Z3_TRY; + LOG_Z3_is_sr_to(c, s); + RESET_ERROR_CODE(); + RETURN_Z3(mk_c(c)->sr_util().is_to( to_expr(s) )); + Z3_CATCH_RETURN(false); + } +#endif + + MK_BINARY(Z3_mk_sr_lo , mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_LO, SKIP); + MK_BINARY(Z3_mk_sr_po , mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_PO, SKIP); + MK_BINARY(Z3_mk_sr_po_ao,mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_PO_AO,SKIP); + MK_BINARY(Z3_mk_sr_plo, mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_PLO, SKIP); + MK_BINARY(Z3_mk_sr_to , mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_TO, SKIP); + +}; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 4992015de..e18ca9204 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1707,6 +1707,42 @@ namespace z3 { */ inline expr sext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_sign_ext(a.ctx(), i, a)); } + inline expr sr_lo(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r = Z3_mk_sr_lo(a.ctx(), a, b); + a.check_error(); + return expr(a.ctx(), r); + } + + inline expr sr_po(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r = Z3_mk_sr_po(a.ctx(), a, b); + a.check_error(); + return expr(a.ctx(), r); + } + + inline expr sr_po_ao(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r = Z3_mk_sr_po_ao(a.ctx(), a, b); + a.check_error(); + return expr(a.ctx(), r); + } + + inline expr sr_plo(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r = Z3_mk_sr_plo(a.ctx(), a, b); + a.check_error(); + return expr(a.ctx(), r); + } + + inline expr sr_to(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r = Z3_mk_sr_to(a.ctx(), a, b); + a.check_error(); + return expr(a.ctx(), r); + } + + template class cast_ast; template<> class cast_ast { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index e17378d94..6d1db22b3 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1101,6 +1101,13 @@ typedef enum { Z3_OP_BUREM_I, Z3_OP_BSMOD_I, + // Special relations + Z3_OP_SPECIAL_RELATION_LO, + Z3_OP_SPECIAL_RELATION_PO, + Z3_OP_SPECIAL_RELATION_PO_AO, + Z3_OP_SPECIAL_RELATION_PLO, + Z3_OP_SPECIAL_RELATION_TO, + // Proofs Z3_OP_PR_UNDEF = 0x500, Z3_OP_PR_TRUE, @@ -3595,10 +3602,58 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_re_full(Z3_context c, Z3_sort re); - /*@}*/ + /** @name Special relations */ + /*@{*/ + /** + \brief declare \c a and \c b are in linear order. + + \pre a and b are of same type. + + def_API('Z3_mk_sr_lo', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_sr_lo(Z3_context c, Z3_ast a, Z3_ast b); + + /** + \brief declare \c a and \c b are in partial order. + + \pre a and b are of same type. + + def_API('Z3_mk_sr_po', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_sr_po(Z3_context c, Z3_ast a, Z3_ast b); + + /** + \brief declare \c a and \c b are already partial ordered. + + \pre a and b are of same type. + + def_API('Z3_mk_sr_po_ao', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_sr_po_ao(Z3_context c, Z3_ast a, Z3_ast b); + + /** + \brief declare \c a and \c b are in piecewise linear order. + + \pre a and b are of same type. + + def_API('Z3_mk_sr_plo', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_sr_plo(Z3_context c, Z3_ast a, Z3_ast b); + + /** + \brief declare \c a and \c b are in total order. + + \pre a and b are of same type. + + def_API('Z3_mk_sr_to', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_sr_to(Z3_context c, Z3_ast a, Z3_ast b); + + /*@}*/ + /** @name Quantifiers */ /*@{*/ /** diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 8332baaf4..605390cf1 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -683,9 +683,12 @@ private: svector m_hybrid_visited, m_hybrid_parent; bool is_connected(numeral const& gamma, bool zero_edge, edge const& e, unsigned timestamp) const { - return (gamma.is_one() || (!zero_edge && gamma.is_neg())) && e.get_timestamp() < timestamp; + return (gamma.is_zero() || (!zero_edge && gamma.is_neg())) && e.get_timestamp() < timestamp; } + int_vector bfs_todo; + int_vector dfs_todo; + public: @@ -693,8 +696,8 @@ public: bool find_path(dl_var source, dl_var target, unsigned timestamp, Functor & f) { auto zero_edge = true; unsigned bfs_head = 0; - int_vector bfs_todo; - int_vector dfs_todo; + bfs_todo.reset(); + dfs_todo.reset(); m_hybrid_visited.resize(m_assignment.size(), m_run_counter++); m_hybrid_parent.resize(m_assignment.size(), -1); bfs_todo.push_back(source); diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 3750ce967..a4c73028e 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -213,17 +213,21 @@ namespace smt { theory_var w; // v2 !<= v1 is asserted target.insert(a.v2()); - if (r.m_graph.reachable(a.v1(), visited, target, w)) { + if (r.m_graph.reachable(a.v1(), target, visited, w)) { // we already have v1 <= v2 continue; } - target.reset(); - if (r.m_graph.reachable(a.v2(), target, visited, w)) { - // there is a common successor + // the nodes visited from v1 become target for v2 + if (r.m_graph.reachable(a.v2(), visited, target, w)) { + // we have the following: // v1 <= w // v2 <= w // v1 !<= v2 - // -> v1 <= w & v2 <= w & v1 !<= v2 -> v2 <= v1 + // + // enforce the assertion + // + // v1 <= w & v2 <= w & v1 !<= v2 -> v2 <= v1 + // unsigned timestamp = r.m_graph.get_timestamp(); r.m_explanation.reset(); r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r); @@ -297,7 +301,7 @@ namespace smt { u_map roots; context& ctx = get_context(); r.m_graph.compute_zero_edge_scc(scc_id); - for (unsigned i = 0, j = 0; i < scc_id.size(); ++i) { + for (unsigned i = 0, j = 0; !ctx.inconsistent() && i < scc_id.size(); ++i) { if (scc_id[i] == -1) { continue; } @@ -635,11 +639,11 @@ namespace smt { bool theory_special_relations::is_neighbour_edge(graph const& g, edge_id edge) const { CTRACE("special_relations_verbose", g.is_enabled(edge), tout << edge << ": " << g.get_source(edge) << " " << g.get_target(edge) << " "; - tout << (g.get_assignment(g.get_source(edge)) - g.get_assignment(g.get_target(edge))) << "\n";); + tout << (g.get_assignment(g.get_target(edge)) - g.get_assignment(g.get_source(edge))) << "\n";); return g.is_enabled(edge) && - g.get_assignment(g.get_source(edge)) - g.get_assignment(g.get_target(edge)) == s_integer(1); + g.get_assignment(g.get_source(edge)) + s_integer(1) == g.get_assignment(g.get_target(edge)); } bool theory_special_relations::is_strict_neighbour_edge(graph const& g, edge_id e) const { @@ -650,7 +654,7 @@ namespace smt { unsigned sz = g.get_num_nodes(); svector nodes; num_children.resize(sz, 0); - svector processed(sz, false); + svector processed(sz, false); for (unsigned i = 0; i < sz; ++i) nodes.push_back(i); while (!nodes.empty()) { dl_var v = nodes.back(); @@ -692,8 +696,8 @@ namespace smt { for (unsigned i = 0; i < sz; ++i) { bool is_root = true; int_vector const& edges = g.get_in_edges(i); - for (unsigned j = 0; is_root && j < edges.size(); ++j) { - is_root = !g.is_enabled(edges[j]); + for (edge_id e_id : edges) { + is_root &= !g.is_enabled(e_id); } if (is_root) { lo[i] = offset; @@ -739,7 +743,8 @@ namespace smt { init_model_po(*kv.m_value, m); break; default: - UNREACHABLE(); //ASHU: added to remove warning! Should be supported! + // other 28 combinations of 0x1F + NOT_IMPLEMENTED_YET(); } } } @@ -770,7 +775,7 @@ namespace smt { void theory_special_relations::display_atom(std::ostream & out, atom& a) const { context& ctx = get_context(); - expr* e = ctx.bool_var2expr( a.var() ); + expr* e = ctx.bool_var2expr(a.var()); out << (a.phase() ? "" : "(not ") << mk_pp(e, get_manager()) << (a.phase() ? "" : ")") << "\n"; } diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 01314b362..312d0d20b 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -52,9 +52,9 @@ namespace smt { r.ensure_var(v2); literal_vector ls; ls.push_back(literal(b, false)); - m_pos = r.m_graph.add_edge(v1, v2, s_integer(1), ls); // v2 <= v1 + m_pos = r.m_graph.add_edge(v1, v2, s_integer(0), ls); // v1 <= v2 ls[0] = literal(b, true); - m_neg = r.m_graph.add_edge(v2, v1, s_integer(-2), ls); // v1 <= v2 - 1 + m_neg = r.m_graph.add_edge(v2, v1, s_integer(-1), ls); // v2 + 1 <= v1 } bool_var var() const { return m_bvar;} relation& get_relation() const { return m_relation; } @@ -80,22 +80,24 @@ namespace smt { }; struct graph : public dl_graph { bool add_strict_edge(theory_var v1, theory_var v2, literal_vector const& j) { - return enable_edge(add_edge(v1, v2, s_integer(1), j)); + // v1 + 1 <= v2 + return enable_edge(add_edge(v1, v2, s_integer(-1), j)); } bool add_non_strict_edge(theory_var v1, theory_var v2, literal_vector const& j) { - return enable_edge(add_edge(v1, v2, s_integer(-2), j)); + // v1 <= v2 + return enable_edge(add_edge(v1, v2, s_integer(0), j)); } }; typedef union_find union_find_t; struct relation { - sr_property m_property; - func_decl* m_decl; - atoms m_asserted_atoms; // set of asserted atoms - unsigned m_asserted_qhead; - svector m_scopes; - graph m_graph; + sr_property m_property; + func_decl* m_decl; + atoms m_asserted_atoms; // set of asserted atoms + unsigned m_asserted_qhead; + svector m_scopes; + graph m_graph; union_find_default_ctx m_ufctx; union_find_t m_uf; literal_vector m_explanation; From 8d5507008e2c52b15104eebe1062a6f8591fa6c1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 17:51:15 -0700 Subject: [PATCH 111/156] adding cmd_context Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 3 +++ src/cmd_context/cmd_context.cpp | 3 +++ src/smt/smt_setup.cpp | 6 ++++++ src/smt/smt_setup.h | 1 + 4 files changed, 13 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index e3995ddb5..267a24a20 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10353,3 +10353,6 @@ def Range(lo, hi, ctx = None): lo = _coerce_seq(lo, ctx) hi = _coerce_seq(hi, ctx) return ReRef(Z3_mk_re_range(lo.ctx_ref(), lo.ast, hi.ast), lo.ctx) + +# Special Relations + diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 9de183ca8..9fbeced71 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -31,6 +31,7 @@ Notes: #include "ast/pb_decl_plugin.h" #include "ast/fpa_decl_plugin.h" #include "ast/csp_decl_plugin.h" +#include "ast/special_relations_decl_plugin.h" #include "ast/ast_pp.h" #include "ast/rewriter/var_subst.h" #include "ast/pp.h" @@ -687,6 +688,7 @@ void cmd_context::init_manager_core(bool new_manager) { 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(csp_decl_plugin), smt_logics::logic_is_csp(m_logic)); + register_plugin(symbol("special_relations"), alloc(special_relations_decl_plugin), !has_logic()); } else { // the manager was created by an external module @@ -703,6 +705,7 @@ void cmd_context::init_manager_core(bool new_manager) { 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/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 731034921..89213c86d 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -33,6 +33,7 @@ Revision History: #include "smt/theory_dl.h" #include "smt/theory_seq_empty.h" #include "smt/theory_seq.h" +#include "smt/theory_special_relations.h" #include "smt/theory_pb.h" #include "smt/theory_fpa.h" #include "smt/theory_str.h" @@ -935,6 +936,10 @@ namespace smt { m_context.register_plugin(alloc(smt::theory_jobscheduler, m_manager)); } + void setup::setup_special_relations() { + m_context.register_plugin(alloc(smt::theory_special_relations, m_manager)); + } + void setup::setup_unknown() { static_features st(m_manager); ptr_vector fmls; @@ -950,6 +955,7 @@ namespace smt { setup_seq_str(st); setup_card(); setup_fpa(); + setup_special_relations(); } void setup::setup_unknown(static_features & st) { diff --git a/src/smt/smt_setup.h b/src/smt/smt_setup.h index 01a143301..53186f91c 100644 --- a/src/smt/smt_setup.h +++ b/src/smt/smt_setup.h @@ -82,6 +82,7 @@ namespace smt { void setup_QF_S(); void setup_LRA(); void setup_CSP(); + void setup_special_relations(); void setup_AUFLIA(bool simple_array = true); void setup_AUFLIA(static_features const & st); void setup_AUFLIRA(bool simple_array = true); From b46cedf64776d9e55e83c662a690e81f961b204f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 17:53:43 -0700 Subject: [PATCH 112/156] include path Signed-off-by: Nikolaj Bjorner --- src/ast/special_relations_decl_plugin.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ast/special_relations_decl_plugin.cpp b/src/ast/special_relations_decl_plugin.cpp index 6bb5734e5..b5a55cbb4 100644 --- a/src/ast/special_relations_decl_plugin.cpp +++ b/src/ast/special_relations_decl_plugin.cpp @@ -17,9 +17,9 @@ Revision History: --*/ -#include -#include"ast.h" -#include"special_relations_decl_plugin.h" +#include +#include "ast/ast.h" +#include "ast/special_relations_decl_plugin.h" @@ -37,11 +37,11 @@ func_decl * special_relations_decl_plugin::mk_func_decl( { if (arity != 2) { m_manager->raise_exception("special relations should have arity 2"); - return 0; + return nullptr; } if (domain[0] != domain[1]) { m_manager->raise_exception("argument sort missmatch"); - return 0; + return nullptr; } func_decl_info info(m_family_id, k, num_parameters, parameters); symbol name; From 57609e57f555eba84fe68f6b4d7d07bcd223070a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 17:54:05 -0700 Subject: [PATCH 113/156] include path Signed-off-by: Nikolaj Bjorner --- src/ast/special_relations_decl_plugin.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index 068382b23..ef432dbcc 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -20,8 +20,7 @@ Revision History: #ifndef SPECIAL_RELATIONS_DECL_PLUGIN_H_ #define SPECIAL_RELATIONS_DECL_PLUGIN_H_ -#include"ast.h" - +#include "ast/ast.h" enum special_relations_op_kind { From 87bc4cf693550520746fef51a353ad3bf318376d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Mar 2019 17:57:06 -0700 Subject: [PATCH 114/156] virtual -> override Signed-off-by: Nikolaj Bjorner --- src/ast/special_relations_decl_plugin.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index ef432dbcc..e8260e154 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -40,19 +40,19 @@ class special_relations_decl_plugin : public decl_plugin { symbol m_to; public: special_relations_decl_plugin(); - virtual ~special_relations_decl_plugin() {} - virtual decl_plugin * mk_fresh() { + ~special_relations_decl_plugin() override {} + + decl_plugin * mk_fresh() override { return alloc(special_relations_decl_plugin); } - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; - virtual void get_op_names(svector & op_names, symbol const & logic); - - - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { return 0; } + void get_op_names(svector & op_names, symbol const & logic) override; + + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override { return nullptr; } }; enum sr_property { From 81b1338af69d37dbc38eb93d4465b5fb8adbb7fb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Mar 2019 08:15:26 -0700 Subject: [PATCH 115/156] display methods Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 22 ++++++++++++++-------- src/smt/theory_special_relations.h | 2 ++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index a4c73028e..d56844ad9 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -64,6 +64,17 @@ namespace smt { return m_graph.add_non_strict_edge(v1, v2, ls) && m_graph.add_non_strict_edge(v2, v1, ls); } + std::ostream& theory_special_relations::relation::display(theory_special_relations const& th, std::ostream& out) const { + out << m_decl->get_name() << ":\n"; + m_graph.display(out); + out << "explanation: " << m_explanation << "\n"; + m_uf.display(out); + for (atom* ap : m_asserted_atoms) { + th.display_atom(out, *ap); + } + return out; + } + theory_special_relations::theory_special_relations(ast_manager& m): theory(m.mk_family_id("special_relations")), m_util(m) { @@ -94,7 +105,7 @@ namespace smt { ctx.set_var_theory(v, get_id()); atom* a = alloc(atom, v, *r, v0, v1); m_atoms.push_back(a); - TRACE("special_relations", tout << mk_pp(atm, get_manager()) << " : " << a->v1() << ' ' << a->v2() << ' ' << gate_ctx << "\n";); + TRACE("special_relations", tout << mk_pp(atm, get_manager()) << " : bv" << v << " v" << a->v1() << " v" << a->v2() << ' ' << gate_ctx << "\n";); m_bool_var2atom.insert(v, a); return true; } @@ -291,7 +302,7 @@ namespace smt { UNREACHABLE(); res = l_undef; } - + TRACE("special_relations", r.display(*this, tout);); return res; } @@ -754,12 +765,7 @@ namespace smt { out << "Theory Special Relations\n"; display_var2enode(out); for (auto const& kv : m_relations) { - out << mk_pp(kv.m_value->decl(), get_manager()) << ":\n"; - kv.m_value->m_graph.display(out); - kv.m_value->m_uf.display(out); - for (atom* ap : kv.m_value->m_asserted_atoms) { - display_atom(out, *ap); - } + kv.m_value->display(*this, out); } } diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 312d0d20b..81a968e54 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -116,6 +116,8 @@ namespace smt { bool add_strict_edge(theory_var v1, theory_var v2, literal_vector const& j); bool add_non_strict_edge(theory_var v1, theory_var v2, literal_vector const& j); + + std::ostream& display(theory_special_relations const& sr, std::ostream& out) const; }; From f55e4ccc412bbc57b49fe897bbbae815599e2da3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Mar 2019 08:39:56 -0700 Subject: [PATCH 116/156] support indexed relations Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 1 - src/api/api_special_relations.cpp | 20 +++++++++--- src/api/c++/z3++.h | 39 +++++++---------------- src/api/z3_api.h | 34 ++++++++------------ src/ast/special_relations_decl_plugin.cpp | 4 --- src/ast/special_relations_decl_plugin.h | 4 --- src/smt/theory_special_relations.cpp | 6 +++- 7 files changed, 45 insertions(+), 63 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index a8f62572a..999ebab6b 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1056,7 +1056,6 @@ extern "C" { switch(_d->get_decl_kind()) { case OP_SPECIAL_RELATION_LO : return Z3_OP_SPECIAL_RELATION_LO; case OP_SPECIAL_RELATION_PO : return Z3_OP_SPECIAL_RELATION_PO; - case OP_SPECIAL_RELATION_PO_AO : return Z3_OP_SPECIAL_RELATION_PO_AO; case OP_SPECIAL_RELATION_PLO: return Z3_OP_SPECIAL_RELATION_PLO; case OP_SPECIAL_RELATION_TO : return Z3_OP_SPECIAL_RELATION_TO; default: UNREACHABLE(); diff --git a/src/api/api_special_relations.cpp b/src/api/api_special_relations.cpp index 40fde5083..e852c2b34 100644 --- a/src/api/api_special_relations.cpp +++ b/src/api/api_special_relations.cpp @@ -68,11 +68,21 @@ extern "C" { Z3_CATCH_RETURN(false); } #endif +#define MK_TERN(NAME, FID) \ + Z3_ast Z3_API NAME(Z3_context c, unsigned index, Z3_ast a, Z3_ast b) { \ + LOG_ ##NAME(c, index, a, b); \ + Z3_TRY; \ + expr* args[2] = { to_expr(a), to_expr(b) }; \ + parameter p(index); \ + ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_special_relations_fid(), FID, 1, &p, 2, args); \ + mk_c(c)->save_ast_trail(a); \ + RETURN_Z3(of_ast(a)); \ + Z3_CATCH_RETURN(nullptr); \ +} - MK_BINARY(Z3_mk_sr_lo , mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_LO, SKIP); - MK_BINARY(Z3_mk_sr_po , mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_PO, SKIP); - MK_BINARY(Z3_mk_sr_po_ao,mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_PO_AO,SKIP); - MK_BINARY(Z3_mk_sr_plo, mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_PLO, SKIP); - MK_BINARY(Z3_mk_sr_to , mk_c(c)->get_special_relations_fid(), OP_SPECIAL_RELATION_TO, SKIP); + MK_TERN(Z3_mk_linear_order, OP_SPECIAL_RELATION_LO); + MK_TERN(Z3_mk_partial_order, OP_SPECIAL_RELATION_PO); + MK_TERN(Z3_mk_piecewise_linear_order, OP_SPECIAL_RELATION_PLO); + MK_TERN(Z3_mk_tree_order, OP_SPECIAL_RELATION_TO); }; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index e18ca9204..8df43d477 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1707,42 +1707,27 @@ namespace z3 { */ inline expr sext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_sign_ext(a.ctx(), i, a)); } - inline expr sr_lo(expr const& a, expr const& b) { + typedef Z3_ast Z3_apply_order(Z3_context, unsigned, Z3_ast, Z3_ast); + + inline expr apply_order(Z3_apply_order app, unsigned index, expr const& a, expr const& b) { check_context(a, b); - Z3_ast r = Z3_mk_sr_lo(a.ctx(), a, b); + Z3_ast r = app(a.ctx(), index, a, b); a.check_error(); return expr(a.ctx(), r); } - - inline expr sr_po(expr const& a, expr const& b) { - check_context(a, b); - Z3_ast r = Z3_mk_sr_po(a.ctx(), a, b); - a.check_error(); - return expr(a.ctx(), r); + inline expr linear_order(unsigned index, expr const& a, expr const& b) { + return apply_order(Z3_mk_linear_order, index, a, b); } - - inline expr sr_po_ao(expr const& a, expr const& b) { - check_context(a, b); - Z3_ast r = Z3_mk_sr_po_ao(a.ctx(), a, b); - a.check_error(); - return expr(a.ctx(), r); + inline expr partial_order(unsigned index, expr const& a, expr const& b) { + return apply_order(Z3_mk_partial_order, index, a, b); } - - inline expr sr_plo(expr const& a, expr const& b) { - check_context(a, b); - Z3_ast r = Z3_mk_sr_plo(a.ctx(), a, b); - a.check_error(); - return expr(a.ctx(), r); + inline expr piecewise_linear_order(unsigned index, expr const& a, expr const& b) { + return apply_order(Z3_mk_piecewise_linear_order, index, a, b); } - - inline expr sr_to(expr const& a, expr const& b) { - check_context(a, b); - Z3_ast r = Z3_mk_sr_to(a.ctx(), a, b); - a.check_error(); - return expr(a.ctx(), r); + inline expr tree_order(unsigned index, expr const& a, expr const& b) { + return apply_order(Z3_mk_tree_order, index, a, b); } - template class cast_ast; template<> class cast_ast { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 6d1db22b3..7ba33a61d 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3608,49 +3608,41 @@ extern "C" { /** @name Special relations */ /*@{*/ /** - \brief declare \c a and \c b are in linear order. + \brief declare \c a and \c b are in linear order over a relation indexed by \c id. \pre a and b are of same type. + - def_API('Z3_mk_sr_lo', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + def_API('Z3_mk_linear_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) */ - Z3_ast Z3_API Z3_mk_sr_lo(Z3_context c, Z3_ast a, Z3_ast b); + Z3_ast Z3_API Z3_mk_linear_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); /** - \brief declare \c a and \c b are in partial order. + \brief declare \c a and \c b are in partial order over a relation indexed by \c id. \pre a and b are of same type. - def_API('Z3_mk_sr_po', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + def_API('Z3_mk_partial_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) */ - Z3_ast Z3_API Z3_mk_sr_po(Z3_context c, Z3_ast a, Z3_ast b); + Z3_ast Z3_API Z3_mk_partial_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); /** - \brief declare \c a and \c b are already partial ordered. + \brief declare \c a and \c b are in piecewise linear order indexed by relation \c id. \pre a and b are of same type. - def_API('Z3_mk_sr_po_ao', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + def_API('Z3_mk_piecewise_linear_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) */ - Z3_ast Z3_API Z3_mk_sr_po_ao(Z3_context c, Z3_ast a, Z3_ast b); + Z3_ast Z3_API Z3_mk_piecewise_linear_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); /** - \brief declare \c a and \c b are in piecewise linear order. + \brief declare \c a and \c b are in tree order indexed by \c id. \pre a and b are of same type. - def_API('Z3_mk_sr_plo', AST ,(_in(CONTEXT), _in(AST), _in(AST))) + def_API('Z3_mk_tree_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) */ - Z3_ast Z3_API Z3_mk_sr_plo(Z3_context c, Z3_ast a, Z3_ast b); - - /** - \brief declare \c a and \c b are in total order. - - \pre a and b are of same type. - - def_API('Z3_mk_sr_to', AST ,(_in(CONTEXT), _in(AST), _in(AST))) - */ - Z3_ast Z3_API Z3_mk_sr_to(Z3_context c, Z3_ast a, Z3_ast b); + Z3_ast Z3_API Z3_mk_tree_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); /*@}*/ diff --git a/src/ast/special_relations_decl_plugin.cpp b/src/ast/special_relations_decl_plugin.cpp index b5a55cbb4..6dd0af1b4 100644 --- a/src/ast/special_relations_decl_plugin.cpp +++ b/src/ast/special_relations_decl_plugin.cpp @@ -26,7 +26,6 @@ Revision History: special_relations_decl_plugin::special_relations_decl_plugin(): m_lo("linear-order"), m_po("partial-order"), - m_po_ao("partial-order-already-ordered"), m_plo("piecewise-linear-order"), m_to("tree-order") {} @@ -47,7 +46,6 @@ func_decl * special_relations_decl_plugin::mk_func_decl( symbol name; switch(k) { case OP_SPECIAL_RELATION_PO: name = m_po; break; - case OP_SPECIAL_RELATION_PO_AO: name = m_po_ao; break; case OP_SPECIAL_RELATION_LO: name = m_lo; break; case OP_SPECIAL_RELATION_PLO: name = m_plo; break; case OP_SPECIAL_RELATION_TO: name = m_to; break; @@ -58,7 +56,6 @@ func_decl * special_relations_decl_plugin::mk_func_decl( void special_relations_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { if (logic == symbol::null) { op_names.push_back(builtin_name(m_po.bare_str(), OP_SPECIAL_RELATION_PO)); - op_names.push_back(builtin_name(m_po_ao.bare_str(), OP_SPECIAL_RELATION_PO_AO)); op_names.push_back(builtin_name(m_lo.bare_str(), OP_SPECIAL_RELATION_LO)); op_names.push_back(builtin_name(m_plo.bare_str(), OP_SPECIAL_RELATION_PLO)); op_names.push_back(builtin_name(m_to.bare_str(), OP_SPECIAL_RELATION_TO)); @@ -68,7 +65,6 @@ void special_relations_decl_plugin::get_op_names(svector & op_name sr_property special_relations_util::get_property(func_decl* f) const { switch (f->get_decl_kind()) { case OP_SPECIAL_RELATION_PO: return sr_po; - case OP_SPECIAL_RELATION_PO_AO: return sr_po; // still partial ordered case OP_SPECIAL_RELATION_LO: return sr_lo; case OP_SPECIAL_RELATION_PLO: return sr_plo; case OP_SPECIAL_RELATION_TO: return sr_to; diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index e8260e154..dbdd61805 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -26,7 +26,6 @@ Revision History: enum special_relations_op_kind { OP_SPECIAL_RELATION_LO, OP_SPECIAL_RELATION_PO, - OP_SPECIAL_RELATION_PO_AO, OP_SPECIAL_RELATION_PLO, OP_SPECIAL_RELATION_TO, LAST_SPECIAL_RELATIONS_OP @@ -35,7 +34,6 @@ enum special_relations_op_kind { class special_relations_decl_plugin : public decl_plugin { symbol m_lo; symbol m_po; - symbol m_po_ao; symbol m_plo; symbol m_to; public: @@ -80,13 +78,11 @@ public: bool is_lo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_LO); } bool is_po(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO); } - bool is_po_ao(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO_AO); } bool is_plo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PLO); } bool is_to(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TO); } app * mk_lo (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_LO, arg1, arg2); } app * mk_po (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO, arg1, arg2); } - app * mk_po_ao (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO_AO, arg1, arg2); } app * mk_plo(expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PLO, arg1, arg2); } app * mk_to (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_TO, arg1, arg2); } diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index d56844ad9..65d30cea6 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -65,7 +65,11 @@ namespace smt { } std::ostream& theory_special_relations::relation::display(theory_special_relations const& th, std::ostream& out) const { - out << m_decl->get_name() << ":\n"; + out << mk_pp(m_decl, th.get_manager()); + for (unsigned i = 0; i < m_decl->get_num_parameters(); ++i) { + th.get_manager().display(out << " ", m_decl->get_parameter(i)); + } + out << ":\n"; m_graph.display(out); out << "explanation: " << m_explanation << "\n"; m_uf.display(out); From 175008a6c6081107fa9309f3e34a008770ce24b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Mar 2019 16:59:13 -0700 Subject: [PATCH 117/156] adding po evaluator Signed-off-by: Nikolaj Bjorner --- src/api/api_datatype.cpp | 65 ++++-------- src/ast/datatype_decl_plugin.cpp | 79 +++++++++++++++ src/ast/datatype_decl_plugin.h | 6 ++ src/ast/special_relations_decl_plugin.h | 4 + src/model/model.cpp | 1 + src/model/model_core.cpp | 1 + src/smt/smt_context.cpp | 1 + src/smt/theory_special_relations.cpp | 128 +++++++++++++++++++++++- 8 files changed, 233 insertions(+), 52 deletions(-) diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 0c2544643..d48ce76e2 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -160,69 +160,40 @@ extern "C" { LOG_Z3_mk_list_sort(c, name, elem_sort, nil_decl, is_nil_decl, cons_decl, is_cons_decl, head_decl, tail_decl); RESET_ERROR_CODE(); ast_manager& m = mk_c(c)->m(); + func_decl_ref nil(m), is_nil(m), cons(m), is_cons(m), head(m), tail(m); datatype_util& dt_util = mk_c(c)->dtutil(); mk_c(c)->reset_last_result(); - datatype_util data_util(m); - accessor_decl* head_tail[2] = { - mk_accessor_decl(m, symbol("head"), type_ref(to_sort(elem_sort))), - mk_accessor_decl(m, symbol("tail"), type_ref(0)) - }; - constructor_decl* constrs[2] = { - mk_constructor_decl(symbol("nil"), symbol("is_nil"), 0, nullptr), - // Leo: SMT 2.0 document uses 'insert' instead of cons - mk_constructor_decl(symbol("cons"), symbol("is_cons"), 2, head_tail) - }; - - sort_ref_vector sorts(m); - { - datatype_decl * decl = mk_datatype_decl(dt_util, to_symbol(name), 0, nullptr, 2, constrs); - bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &decl, 0, nullptr, sorts); - del_datatype_decl(decl); - - if (!is_ok) { - SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); - RETURN_Z3(nullptr); - } + sort_ref s = dt_util.mk_list_datatype(to_sort(elem_sort), to_symbol(name), cons, is_cons, head, tail, nil, is_nil); + + if (!s) { + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); + RETURN_Z3(nullptr); } - sort * s = sorts.get(0); mk_c(c)->save_multiple_ast_trail(s); - ptr_vector const& cnstrs = *data_util.get_datatype_constructors(s); - SASSERT(cnstrs.size() == 2); - func_decl* f; if (nil_decl) { - f = cnstrs[0]; - mk_c(c)->save_multiple_ast_trail(f); - *nil_decl = of_func_decl(f); + mk_c(c)->save_multiple_ast_trail(nil); + *nil_decl = of_func_decl(nil); } if (is_nil_decl) { - f = data_util.get_constructor_is(cnstrs[0]); - mk_c(c)->save_multiple_ast_trail(f); - *is_nil_decl = of_func_decl(f); + mk_c(c)->save_multiple_ast_trail(is_nil); + *is_nil_decl = of_func_decl(is_nil); } if (cons_decl) { - f = cnstrs[1]; - mk_c(c)->save_multiple_ast_trail(f); - *cons_decl = of_func_decl(f); + mk_c(c)->save_multiple_ast_trail(cons); + *cons_decl = of_func_decl(cons); } if (is_cons_decl) { - f = data_util.get_constructor_is(cnstrs[1]); - mk_c(c)->save_multiple_ast_trail(f); - *is_cons_decl = of_func_decl(f); + mk_c(c)->save_multiple_ast_trail(is_cons); + *is_cons_decl = of_func_decl(is_cons); } if (head_decl) { - ptr_vector const& acc = *data_util.get_constructor_accessors(cnstrs[1]); - SASSERT(acc.size() == 2); - f = (acc)[0]; - mk_c(c)->save_multiple_ast_trail(f); - *head_decl = of_func_decl(f); + mk_c(c)->save_multiple_ast_trail(head); + *head_decl = of_func_decl(head); } if (tail_decl) { - ptr_vector const& acc = *data_util.get_constructor_accessors(cnstrs[1]); - SASSERT(acc.size() == 2); - f = (acc)[1]; - mk_c(c)->save_multiple_ast_trail(f); - *tail_decl = of_func_decl(f); + mk_c(c)->save_multiple_ast_trail(tail); + *tail_decl = of_func_decl(tail); } RETURN_Z3_mk_list_sort(of_sort(s)); Z3_CATCH_RETURN(nullptr); diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 71b35f914..e8f276aa8 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -1188,6 +1188,85 @@ namespace datatype { } } } + + sort_ref util::mk_list_datatype(sort* elem, symbol const& name, + func_decl_ref& cons, func_decl_ref& is_cons, + func_decl_ref& hd, func_decl_ref& tl, + func_decl_ref& nil, func_decl_ref& is_nil) { + + accessor_decl* head_tail[2] = { + mk_accessor_decl(m, symbol("head"), type_ref(elem)), + mk_accessor_decl(m, symbol("tail"), type_ref(0)) + }; + constructor_decl* constrs[2] = { + mk_constructor_decl(symbol("nil"), symbol("is_nil"), 0, nullptr), + mk_constructor_decl(symbol("cons"), symbol("is_cons"), 2, head_tail) + }; + decl::plugin& p = *get_plugin(); + + sort_ref_vector sorts(m); + datatype_decl * decl = mk_datatype_decl(*this, name, 0, nullptr, 2, constrs); + bool is_ok = p.mk_datatypes(1, &decl, 0, nullptr, sorts); + del_datatype_decl(decl); + + if (!is_ok) { + return sort_ref(m); + } + sort* s = sorts.get(0); + ptr_vector const& cnstrs = *get_datatype_constructors(s); + SASSERT(cnstrs.size() == 2); + nil = cnstrs[0]; + is_nil = get_constructor_is(cnstrs[0]); + cons = cnstrs[1]; + is_cons = get_constructor_is(cnstrs[1]); + ptr_vector const& acc = *get_constructor_accessors(cnstrs[1]); + SASSERT(acc.size() == 2); + hd = acc[0]; + tl = acc[1]; + return sort_ref(s, m); + } + + sort_ref util::mk_pair_datatype(sort* a, sort* b, func_decl_ref& fst, func_decl_ref& snd, func_decl_ref& pair) { + type_ref t1(a), t2(b); + accessor_decl* fstd = mk_accessor_decl(m, symbol("fst"), t1); + accessor_decl* sndd = mk_accessor_decl(m, symbol("snd"), t2); + accessor_decl* accd[2] = { fstd, sndd }; + auto * p = mk_constructor_decl(symbol("pair"), symbol("is-pair"), 2, accd); + auto* dt = mk_datatype_decl(*this, symbol("pair"), 0, nullptr, 1, &p); + sort_ref_vector sorts(m); + VERIFY(get_plugin()->mk_datatypes(1, &dt, 0, nullptr, sorts)); + del_datatype_decl(dt); + sort* s = sorts.get(0); + ptr_vector const& cnstrs = *get_datatype_constructors(s); + SASSERT(cnstrs.size() == 1); + ptr_vector const& acc = *get_constructor_accessors(cnstrs[0]); + SASSERT(acc.size() == 2); + fst = acc[0]; + snd = acc[1]; + pair = cnstrs[0]; + return sort_ref(s, m); + } + + sort_ref util::mk_tuple_datatype(svector> const& elems, symbol const& name, symbol const& test, func_decl_ref& tup, func_decl_ref_vector& accs) { + ptr_vector accd; + for (auto const& e : elems) { + type_ref t(e.second); + accd.push_back(mk_accessor_decl(m, e.first, t)); + } + auto* tuple = mk_constructor_decl(name, test, accd.size(), accd.c_ptr()); + auto* dt = mk_datatype_decl(*this, name, 0, nullptr, 1, &tuple); + sort_ref_vector sorts(m); + VERIFY(get_plugin()->mk_datatypes(1, &dt, 0, nullptr, sorts)); + del_datatype_decl(dt); + sort* s = sorts.get(0); + ptr_vector const& cnstrs = *get_datatype_constructors(s); + SASSERT(cnstrs.size() == 1); + ptr_vector const& acc = *get_constructor_accessors(cnstrs[0]); + for (auto* f : acc) accs.push_back(f); + tup = cnstrs[0]; + return sort_ref(s, m); + } + } datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort*const* params, unsigned num_constructors, constructor_decl * const * cs) { diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index e9734ac0b..5292ab6b9 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -364,6 +364,12 @@ namespace datatype { decl::plugin* get_plugin() { return m_plugin; } void get_defs(sort* s, ptr_vector& defs); def const& get_def(sort* s) const; + sort_ref mk_list_datatype(sort* elem, symbol const& name, + func_decl_ref& cons, func_decl_ref& is_cons, + func_decl_ref& hd, func_decl_ref& tl, + func_decl_ref& nil, func_decl_ref& is_nil); + sort_ref mk_pair_datatype(sort* a, sort* b, func_decl_ref& fst, func_decl_ref& snd, func_decl_ref& pair); + sort_ref mk_tuple_datatype(svector> const& elems, symbol const& name, symbol const& test, func_decl_ref& tup, func_decl_ref_vector& accs); }; }; diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index dbdd61805..e8260e154 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -26,6 +26,7 @@ Revision History: enum special_relations_op_kind { OP_SPECIAL_RELATION_LO, OP_SPECIAL_RELATION_PO, + OP_SPECIAL_RELATION_PO_AO, OP_SPECIAL_RELATION_PLO, OP_SPECIAL_RELATION_TO, LAST_SPECIAL_RELATIONS_OP @@ -34,6 +35,7 @@ enum special_relations_op_kind { class special_relations_decl_plugin : public decl_plugin { symbol m_lo; symbol m_po; + symbol m_po_ao; symbol m_plo; symbol m_to; public: @@ -78,11 +80,13 @@ public: bool is_lo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_LO); } bool is_po(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO); } + bool is_po_ao(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO_AO); } bool is_plo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PLO); } bool is_to(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TO); } app * mk_lo (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_LO, arg1, arg2); } app * mk_po (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO, arg1, arg2); } + app * mk_po_ao (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO_AO, arg1, arg2); } app * mk_plo(expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PLO, arg1, arg2); } app * mk_to (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_TO, arg1, arg2); } diff --git a/src/model/model.cpp b/src/model/model.cpp index e6a3ffedf..aa3976cb9 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -217,6 +217,7 @@ void model::compress() { } } if (removed.empty()) break; + TRACE("model", tout << "remove\n"; for (func_decl* f : removed) tout << f->get_name() << "\n";); remove_decls(m_decls, removed); remove_decls(m_func_decls, removed); remove_decls(m_const_decls, removed); diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index d92e81421..0f811034a 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -66,6 +66,7 @@ void model_core::register_decl(func_decl * d, expr * v) { } void model_core::register_decl(func_decl * d, func_interp * fi) { + TRACE("model", tout << "register " << d->get_name() << "\n";); SASSERT(d->get_arity() > 0); SASSERT(&fi->m() == &m); decl2finterp::obj_map_entry * entry = m_finterp.insert_if_not_there2(d, nullptr); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 63979e657..0012f1433 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4453,6 +4453,7 @@ namespace smt { } recfun::util u(m); func_decl_ref_vector recfuns = u.get_rec_funs(); + std::cout << recfuns << "\n"; for (func_decl* f : recfuns) { auto& def = u.get_def(f); expr* rhs = def.get_rhs(); diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 65d30cea6..8339c658e 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -26,7 +26,11 @@ Notes: #include "smt/smt_solver.h" #include "solver/solver.h" #include "ast/reg_decl_plugins.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/recfun_decl_plugin.h" #include "ast/ast_pp.h" +#include "ast/rewriter/recfun_replace.h" + namespace smt { @@ -610,16 +614,130 @@ namespace smt { m.get_model().register_decl(r.decl(), fi); } - void theory_special_relations::init_model_plo(relation& r, model_generator& m) { - expr_ref inj = mk_inj(r, m); - expr_ref cls = mk_class(r, m); + void theory_special_relations::init_model_plo(relation& r, model_generator& mg) { + expr_ref inj = mk_inj(r, mg); + expr_ref cls = mk_class(r, mg); func_interp* fi = alloc(func_interp, get_manager(), 2); fi->set_else(get_manager().mk_and(inj, cls)); - m.get_model().register_decl(r.decl(), fi); + mg.get_model().register_decl(r.decl(), fi); } + /** + \brief model for a partial order, + is a recursive function that evaluates membership in partial order over + a fixed set of edges. It runs in O(e*n^2) where n is the number of vertices and e + number of edges. + + connected1(x, y, v, w, S) = + if x = v then + if y = w then (S, true) else + if w in S then (S, false) else + connected2(w, y, S u { w }, edges) + else (S, false) + + connected2(x, y, S, []) = (S, false) + connected2(x, y, S, (u,w)::edges) = + let (S, c) = connected1(x, y, u, w, S) + if c then (S, true) else connected2(x, y, S, edges) + + */ + + void theory_special_relations::init_model_po(relation& r, model_generator& mg) { - // NOT_IMPLEMENTED_YET(); + ast_manager& m = get_manager(); + sort* s = r.m_decl->get_domain(0); + context& ctx = get_context(); + datatype_util dt(m); + recfun::util rf(m); + recfun::decl::plugin& p = rf.get_plugin(); + func_decl_ref nil(m), is_nil(m), cons(m), is_cons(m), hd(m), tl(m); + sort_ref listS(dt.mk_list_datatype(s, symbol("List"), cons, is_cons, hd, tl, nil, is_nil), m); + func_decl_ref fst(m), snd(m), pair(m); + sort_ref tup(dt.mk_pair_datatype(listS, m.mk_bool_sort(), fst, snd, pair), m); + sort* dom1[5] = { s, s, listS, s, s }; + recfun::promise_def c1 = p.mk_def(symbol("connected1"), 5, dom1, tup); + sort* dom2[3] = { s, s, listS }; + recfun::promise_def c2 = p.mk_def(symbol("connected2"), 3, dom2, tup); + sort* dom3[2] = { s, listS }; + recfun::promise_def mem = p.mk_def(symbol("member"), 2, dom3, m.mk_bool_sort()); + var_ref xV(m.mk_var(1, s), m); + var_ref SV(m.mk_var(0, listS), m); + var_ref yV(m), vV(m), wV(m); + + expr* x = xV, *S = SV; + expr* T = m.mk_true(); + expr* F = m.mk_false(); + func_decl* memf = mem.get_def()->get_decl(); + func_decl* conn1 = c1.get_def()->get_decl(); + func_decl* conn2 = c2.get_def()->get_decl(); + expr_ref mem_body(m); + mem_body = m.mk_ite(m.mk_app(is_nil, S), + F, + m.mk_ite(m.mk_eq(m.mk_app(hd, S), x), + T, + m.mk_app(memf, x, m.mk_app(tl, S)))); + recfun_replace rep(m); + var* vars[2] = { xV, SV }; + p.set_definition(rep, mem, 2, vars, mem_body); + + xV = m.mk_var(4, s); + yV = m.mk_var(3, s); + SV = m.mk_var(2, listS); + vV = m.mk_var(1, s); + wV = m.mk_var(0, s); + expr* y = yV, *v = vV, *w = wV; + x = xV, S = SV; + + expr_ref ST(m.mk_app(pair, S, T), m); + expr_ref SF(m.mk_app(pair, S, F), m); + + expr_ref connected_body(m); + connected_body = + m.mk_ite(m.mk_not(m.mk_eq(x, v)), + SF, + m.mk_ite(m.mk_eq(y, w), + ST, + m.mk_ite(m.mk_app(memf, w, S), + SF, + m.mk_app(conn2, w, y, m.mk_app(cons, w, S))))); + var* vars2[5] = { xV, yV, SV, vV, wV }; + p.set_definition(rep, c1, 5, vars2, connected_body); + + xV = m.mk_var(2, s); + yV = m.mk_var(1, s); + SV = m.mk_var(0, listS); + x = xV, y = yV, S = SV; + ST = m.mk_app(pair, S, T); + SF = m.mk_app(pair, S, F); + expr_ref connected_rec_body(m); + connected_rec_body = SF; + + for (atom* ap : r.m_asserted_atoms) { + atom& a = *ap; + if (!a.phase()) continue; + SASSERT(ctx.get_assignment(a.var()) == l_true); + expr* n1 = get_enode(a.v1())->get_root()->get_owner(); + expr* n2 = get_enode(a.v2())->get_root()->get_owner(); + + expr* Sr = connected_rec_body; + expr* args[5] = { x, y, m.mk_app(fst, Sr), n1, n2}; + expr* Sc = m.mk_app(conn1, 5, args); + connected_rec_body = m.mk_ite(m.mk_app(snd, Sr), ST, Sc); + } + var* vars3[3] = { xV, yV, SV }; + p.set_definition(rep, c2, 3, vars3, connected_rec_body); + +#if 0 + // TBD: doesn't terminate with model_evaluator/rewriter + + // r.m_decl(x,y) -> snd(connected2(x,y,nil)) + + func_interp* fi = alloc(func_interp, m, 2); + fi->set_else(m.mk_app(snd, m.mk_app(conn2, x, y, m.mk_const(nil)))); + mg.get_model().register_decl(r.decl(), fi); +#endif + + } /** From e4eca577f6746af778fa66200127704bad80e1ab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Mar 2019 07:03:04 -0700 Subject: [PATCH 118/156] fix po model Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 2 +- src/smt/theory_special_relations.cpp | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 0012f1433..a40efe228 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4453,7 +4453,6 @@ namespace smt { } recfun::util u(m); func_decl_ref_vector recfuns = u.get_rec_funs(); - std::cout << recfuns << "\n"; for (func_decl* f : recfuns) { auto& def = u.get_def(f); expr* rhs = def.get_rhs(); @@ -4475,6 +4474,7 @@ namespace smt { fi->set_else(bodyr); m_model->register_decl(f, fi); } + TRACE("model", tout << *m_model << "\n";); } }; diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 8339c658e..6e8c04a97 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -727,16 +727,14 @@ namespace smt { var* vars3[3] = { xV, yV, SV }; p.set_definition(rep, c2, 3, vars3, connected_rec_body); -#if 0 - // TBD: doesn't terminate with model_evaluator/rewriter - // r.m_decl(x,y) -> snd(connected2(x,y,nil)) + xV = m.mk_var(0, s); + yV = m.mk_var(1, s); + x = xV, y = yV; func_interp* fi = alloc(func_interp, m, 2); - fi->set_else(m.mk_app(snd, m.mk_app(conn2, x, y, m.mk_const(nil)))); + fi->set_else(m.mk_app(snd, m.mk_app(conn2, x, y, m.mk_app(cons, x, m.mk_const(nil))))); mg.get_model().register_decl(r.decl(), fi); -#endif - } From bce1ee6d393954e04228a7cd4fa94689e500c6c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Mar 2019 09:21:34 -0700 Subject: [PATCH 119/156] new files Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/func_decl_replace.cpp | 96 ++++++++++++++++++++ src/ast/rewriter/func_decl_replace.h | 45 +++++++++ src/tactic/core/special_relations_tactic.cpp | 72 +++++++++++++++ src/tactic/core/special_relations_tactic.h | 69 ++++++++++++++ 4 files changed, 282 insertions(+) create mode 100644 src/ast/rewriter/func_decl_replace.cpp create mode 100644 src/ast/rewriter/func_decl_replace.h create mode 100644 src/tactic/core/special_relations_tactic.cpp create mode 100644 src/tactic/core/special_relations_tactic.h diff --git a/src/ast/rewriter/func_decl_replace.cpp b/src/ast/rewriter/func_decl_replace.cpp new file mode 100644 index 000000000..6e64dd568 --- /dev/null +++ b/src/ast/rewriter/func_decl_replace.cpp @@ -0,0 +1,96 @@ +/*++ +Copyright (c) 2019 Microsoft Corporation + +Module Name: + + func_decl_replace.cpp + +Abstract: + + Replace functions in expressions. + +Author: + + Nikolaj Bjorner (nbjorner) 2019-03-28 + +Revision History: + + +--*/ + + +#include "ast/rewriter/func_decl_replace.h" + +expr_ref func_decl_replace::operator()(expr* e) { + m_todo.push_back(e); + + while (!m_todo.empty()) { + expr* a = m_todo.back(), *b; + if (m_cache.contains(a)) { + m_todo.pop_back(); + } + else if (is_var(a)) { + m_cache.insert(a, a); + m_todo.pop_back(); + } + else if (is_app(a)) { + app* c = to_app(a); + unsigned n = c->get_num_args(); + m_args.reset(); + bool arg_differs = false; + for (unsigned i = 0; i < n; ++i) { + expr* d = nullptr, *arg = c->get_arg(i); + if (m_cache.find(arg, d)) { + m_args.push_back(d); + arg_differs |= arg != d; + SASSERT(m.get_sort(arg) == m.get_sort(d)); + } + else { + m_todo.push_back(arg); + } + } + if (m_args.size() == n) { + if (arg_differs) { + b = m.mk_app(c->get_decl(), m_args.size(), m_args.c_ptr()); + m_refs.push_back(b); + SASSERT(m.get_sort(a) == m.get_sort(b)); + } else { + b = a; + } + func_decl* f = nullptr; + if (m_subst.find(c->get_decl(), f)) { + b = m.mk_app(f, m_args.size(), m_args.c_ptr()); + m_refs.push_back(b); + } + m_cache.insert(a, b); + m_todo.pop_back(); + } + } + else { + quantifier* q = to_quantifier(a); + SASSERT(is_quantifier(a)); + expr* body = q->get_expr(), *new_body; + if (m_cache.find(body, new_body)) { + if (new_body == body) { + b = a; + } + else { + b = m.update_quantifier(q, new_body); + m_refs.push_back(b); + } + m_cache.insert(a, b); + m_todo.pop_back(); + } + else { + m_todo.push_back(body); + } + } + } + return expr_ref(cache.find(e), m); +} + +void func_decl_replace::reset() { + m_cache.reset(); + m_subst.reset(); + m_refs.reset(); +} diff --git a/src/ast/rewriter/func_decl_replace.h b/src/ast/rewriter/func_decl_replace.h new file mode 100644 index 000000000..a553ed999 --- /dev/null +++ b/src/ast/rewriter/func_decl_replace.h @@ -0,0 +1,45 @@ +/*++ +Copyright (c) 2019 Microsoft Corporation + +Module Name: + + func_decl_replace.h + +Abstract: + + Replace functions in expressions. + +Author: + + Nikolaj Bjorner (nbjorner) 2019-03-28 + +Revision History: + + +--*/ + +#ifndef FUNC_DECL_REPLACE_H_ +#define FUNC_DECL_REPLACE_H_ + +#include "ast/ast.h" + +class func_decl_replace { + ast_manager& m; + obj_map m_subst; + obj_map m_cache; + ptr_vector m_todo, m_args; + expr_ref_vector m_refs; + +public: + func_decl_replace(ast_manager& m): m(m), m_refs(m) {} + + void insert(func_decl* src, func_decl* dst) { m_subst.insert(src, dst); } + + expr_ref operator()(expr* e); + + void reset(); + + bool empty() const { return m_subst.empty(); } +}; + +#endif /* FUNC_DECL_REPLACE_H_ */ diff --git a/src/tactic/core/special_relations_tactic.cpp b/src/tactic/core/special_relations_tactic.cpp new file mode 100644 index 000000000..cb0533e81 --- /dev/null +++ b/src/tactic/core/special_relations_tactic.cpp @@ -0,0 +1,72 @@ +/*++ +Copyright (c) 2019 Microsoft Corporation + +Module Name: + + special_relations_tactic.cpp + +Abstract: + + Detect special relations in an axiomatization, + rewrite goal using special relations. + +Author: + + Nikolaj Bjorner (nbjorner) 2019-03-28 + +Notes: + +--*/ +#include "tactic/core/special_relations.h" + +void special_relations_tactic::collect_feature(goal const& g, unsigned idx, + obj_map& goal_features) { + expr* f = g.form(idx); + func_decl_ref p(m); + if (is_transitivity(f, p)) { + insert(goal_features, p, idx, sr_transitive); + } +} + +void specia_relations_tactic::insert(obj_map& goal_features, func_decl* p, unsigned idx, sr_property p) { + +} + + +bool special_relations_tactic::is_transitivity(expr* fml, func_decl_ref& p) { + return false; +} +bool special_relations_tactic::is_anti_symmetry(expr* fml, func_decl_ref& p) { + return false; +} +bool special_relations_tactic::is_left_tree(expr* fml, func_decl_ref& p) { + return false; +} +bool special_relations_tactic::is_right_tree(expr* fml, func_decl_ref& p) { + return false; +} +bool special_relations_tactic::is_reflexivity(expr* fml, func_decl_ref& p) { + return false; +} +bool special_relations_tactic::is_total(expr* fml, func_decl_ref& p) { + return false; +} +bool special_relations_tactic::is_symmetric(expr* fml, func_decl_ref& p) { + return false; +} + + +void special_relations_tactic::operator()(goal_ref const & g, goal_ref_buffer & result) { + tactic_report report("special_relations", g); + obj_map goal_features; + unsigned size = g.size(); + for (unsigned idx = 0; idx < size; idx++) { + collect_feature(g, idx, goal_features); + } + if (!goal_features.empty()) { + + } + g->inc_depth(); + result.push_back(g.get()); +} + diff --git a/src/tactic/core/special_relations_tactic.h b/src/tactic/core/special_relations_tactic.h new file mode 100644 index 000000000..88bd94843 --- /dev/null +++ b/src/tactic/core/special_relations_tactic.h @@ -0,0 +1,69 @@ +/*++ +Copyright (c) 2019 Microsoft Corporation + +Module Name: + + special_relations_tactic.h + +Abstract: + + Detect special relations in an axiomatization, + rewrite goal using special relations. + +Author: + + Nikolaj Bjorner (nbjorner) 2019-03-28 + +Notes: + +--*/ +#ifndef SPECIAL_RELATIONS_TACTIC_H_ +#define SPECIAL_RELATIONS_TACTIC_H_ + +#include "tactic/tactic.h" +#include "tactic/tactical.h" + +class special_relations_tactic : public tactic { + params_ref m_params; + + struct sp_axioms { + unsigned_vector m_goal_indices; + unsigned m_sp_features; + }; + + void collect_feature(goal const& g, unsigned idx, obj_map& goal_features); + void insert(obj_map& goal_features, func_decl* p, unsigned idx, sr_property p); + + bool is_transitivity(expr* fml, func_decl_ref& p); + bool is_anti_symmetry(expr* fml, func_decl_ref& p); + bool is_left_tree(expr* fml, func_decl_ref& p); + bool is_right_tree(expr* fml, func_decl_ref& p); + bool is_reflexivity(expr* fml, func_decl_ref& p); + bool is_total(expr* fml, func_decl_ref& p); + bool is_symmetric(expr* fml, func_decl_ref& p); + +public: + + special_relations_tactic(ast_manager & m, params_ref const & ref = params_ref()) {} + + ~special_relations_tactic() override {} + + void updt_params(params_ref const & p) override { m_params = p; } + + void collect_param_descrs(param_descrs & r) override { } + + void operator()(goal_ref const & in, goal_ref_buffer & result) override; + + void cleanup() override {} + + tactic * translate(ast_manager & m) override { return alloc(special_relations_tactic, m, m_params); } + +}; + +tactic * mk_special_relations_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("special_relations", "detect and replace by special relations.", "mk_special_relations_tactic(m, p)") +*/ + +#endif From 7a6823aef1f2ad9266fdc7fd2930c7bf3c683096 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Mar 2019 10:07:50 -0700 Subject: [PATCH 120/156] add special relations tactic Signed-off-by: Nikolaj Bjorner --- src/api/z3_api.h | 1 - src/ast/rewriter/CMakeLists.txt | 1 + src/ast/rewriter/func_decl_replace.cpp | 2 +- src/ast/special_relations_decl_plugin.h | 15 ++-- src/tactic/core/CMakeLists.txt | 2 + src/tactic/core/special_relations_tactic.cpp | 81 +++++++++++++++++--- src/tactic/core/special_relations_tactic.h | 11 ++- 7 files changed, 92 insertions(+), 21 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 7ba33a61d..e1fe76175 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1104,7 +1104,6 @@ typedef enum { // Special relations Z3_OP_SPECIAL_RELATION_LO, Z3_OP_SPECIAL_RELATION_PO, - Z3_OP_SPECIAL_RELATION_PO_AO, Z3_OP_SPECIAL_RELATION_PLO, Z3_OP_SPECIAL_RELATION_TO, diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index 9f98ff0ed..d506c75b3 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -19,6 +19,7 @@ z3_add_component(rewriter factor_equivs.cpp factor_rewriter.cpp fpa_rewriter.cpp + func_decl_replace.cpp hoist_rewriter.cpp inj_axiom.cpp label_rewriter.cpp diff --git a/src/ast/rewriter/func_decl_replace.cpp b/src/ast/rewriter/func_decl_replace.cpp index 6e64dd568..dcde9044f 100644 --- a/src/ast/rewriter/func_decl_replace.cpp +++ b/src/ast/rewriter/func_decl_replace.cpp @@ -86,7 +86,7 @@ expr_ref func_decl_replace::operator()(expr* e) { } } } - return expr_ref(cache.find(e), m); + return expr_ref(m_cache.find(e), m); } void func_decl_replace::reset() { diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index e8260e154..5926057f5 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -26,7 +26,6 @@ Revision History: enum special_relations_op_kind { OP_SPECIAL_RELATION_LO, OP_SPECIAL_RELATION_PO, - OP_SPECIAL_RELATION_PO_AO, OP_SPECIAL_RELATION_PLO, OP_SPECIAL_RELATION_TO, LAST_SPECIAL_RELATIONS_OP @@ -35,7 +34,6 @@ enum special_relations_op_kind { class special_relations_decl_plugin : public decl_plugin { symbol m_lo; symbol m_po; - symbol m_po_ao; symbol m_plo; symbol m_to; public: @@ -56,15 +54,17 @@ public: }; enum sr_property { + sr_none = 0x00, sr_transitive = 0x01, // Rxy & Ryz -> Rxz sr_reflexive = 0x02, // Rxx sr_antisymmetric = 0x04, // Rxy & Ryx -> x = y sr_lefttree = 0x08, // Ryx & Rzx -> Ryz | Rzy sr_righttree = 0x10, // Rxy & Rxz -> Ryx | Rzy + sr_total = 0x20, // Rxy | Ryx sr_po = 0x01 | 0x02 | 0x04, // partial order - sr_lo = 0x01 | 0x02 | 0x04 | 0x08 | 0x10, // linear order - sr_plo = 0x01 | 0x02 | 0x04 | 0x20, // piecewise linear order sr_to = 0x01 | 0x02 | 0x04 | 0x10, // right-tree + sr_plo = 0x01 | 0x02 | 0x04 | 0x08 | 0x10, // piecewise linear order + sr_lo = 0x01 | 0x02 | 0x04 | 0x20, // linear order }; class special_relations_util { @@ -78,15 +78,18 @@ public: sr_property get_property(func_decl* f) const; sr_property get_property(app* e) const { return get_property(e->get_decl()); } + func_decl* mk_to_decl(func_decl* f) { parameter p(f); SASSERT(f->get_arity() == 2); return m.mk_func_decl(m_fid, OP_SPECIAL_RELATION_TO, 1, &p, 2, f->get_domain(), f->get_range()); } + func_decl* mk_po_decl(func_decl* f) { parameter p(f); SASSERT(f->get_arity() == 2); return m.mk_func_decl(m_fid, OP_SPECIAL_RELATION_PO, 1, &p, 2, f->get_domain(), f->get_range()); } + func_decl* mk_plo_decl(func_decl* f) { parameter p(f); SASSERT(f->get_arity() == 2); return m.mk_func_decl(m_fid, OP_SPECIAL_RELATION_PLO, 1, &p, 2, f->get_domain(), f->get_range()); } + func_decl* mk_lo_decl(func_decl* f) { parameter p(f); SASSERT(f->get_arity() == 2); return m.mk_func_decl(m_fid, OP_SPECIAL_RELATION_LO, 1, &p, 2, f->get_domain(), f->get_range()); } + bool is_lo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_LO); } bool is_po(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO); } - bool is_po_ao(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO_AO); } bool is_plo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PLO); } bool is_to(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TO); } app * mk_lo (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_LO, arg1, arg2); } app * mk_po (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO, arg1, arg2); } - app * mk_po_ao (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO_AO, arg1, arg2); } app * mk_plo(expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PLO, arg1, arg2); } app * mk_to (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_TO, arg1, arg2); } diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index 44284b625..a247c7b20 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -19,6 +19,7 @@ z3_add_component(core_tactics reduce_invertible_tactic.cpp simplify_tactic.cpp solve_eqs_tactic.cpp + special_relations_tactic.cpp split_clause_tactic.cpp symmetry_reduce_tactic.cpp tseitin_cnf_tactic.cpp @@ -46,6 +47,7 @@ z3_add_component(core_tactics reduce_invertible_tactic.h simplify_tactic.h solve_eqs_tactic.h + special_relations_tactic.h split_clause_tactic.h symmetry_reduce_tactic.h tseitin_cnf_tactic.h diff --git a/src/tactic/core/special_relations_tactic.cpp b/src/tactic/core/special_relations_tactic.cpp index cb0533e81..f256bdbef 100644 --- a/src/tactic/core/special_relations_tactic.cpp +++ b/src/tactic/core/special_relations_tactic.cpp @@ -17,7 +17,8 @@ Author: Notes: --*/ -#include "tactic/core/special_relations.h" +#include "tactic/core/special_relations_tactic.h" +#include "ast/rewriter/func_decl_replace.h" void special_relations_tactic::collect_feature(goal const& g, unsigned idx, obj_map& goal_features) { @@ -26,14 +27,34 @@ void special_relations_tactic::collect_feature(goal const& g, unsigned idx, if (is_transitivity(f, p)) { insert(goal_features, p, idx, sr_transitive); } + else if (is_anti_symmetry(f, p)) { + insert(goal_features, p, idx, sr_antisymmetric); + } + else if (is_left_tree(f, p)) { + insert(goal_features, p, idx, sr_lefttree); + } + else if (is_right_tree(f, p)) { + insert(goal_features, p, idx, sr_righttree); + } + else if (is_reflexive(f, p)) { + insert(goal_features, p, idx, sr_reflexive); + } + else if (is_total(f, p)) { + insert(goal_features, p, idx, sr_total); + } } -void specia_relations_tactic::insert(obj_map& goal_features, func_decl* p, unsigned idx, sr_property p) { - +void special_relations_tactic::insert(obj_map& goal_features, func_decl* f, unsigned idx, sr_property p) { + sp_axioms ax; + goal_features.find(f, ax); + ax.m_goal_indices.push_back(idx); + ax.m_sp_features = (sr_property)(p | ax.m_sp_features); + goal_features.insert(f, ax); } bool special_relations_tactic::is_transitivity(expr* fml, func_decl_ref& p) { + // match Forall x, y, z . p(x,y) & p(y,z) -> p(x,z) return false; } bool special_relations_tactic::is_anti_symmetry(expr* fml, func_decl_ref& p) { @@ -45,7 +66,7 @@ bool special_relations_tactic::is_left_tree(expr* fml, func_decl_ref& p) { bool special_relations_tactic::is_right_tree(expr* fml, func_decl_ref& p) { return false; } -bool special_relations_tactic::is_reflexivity(expr* fml, func_decl_ref& p) { +bool special_relations_tactic::is_reflexive(expr* fml, func_decl_ref& p) { return false; } bool special_relations_tactic::is_total(expr* fml, func_decl_ref& p) { @@ -57,16 +78,58 @@ bool special_relations_tactic::is_symmetric(expr* fml, func_decl_ref& p) { void special_relations_tactic::operator()(goal_ref const & g, goal_ref_buffer & result) { - tactic_report report("special_relations", g); + tactic_report report("special_relations", *g); obj_map goal_features; - unsigned size = g.size(); + unsigned size = g->size(); for (unsigned idx = 0; idx < size; idx++) { - collect_feature(g, idx, goal_features); + collect_feature(*g, idx, goal_features); } - if (!goal_features.empty()) { - + special_relations_util u(m); + func_decl_replace replace(m); + unsigned_vector to_delete; + for(auto const& kv : goal_features) { + func_decl* sp = nullptr; + sr_property feature = kv.m_value.m_sp_features; + switch (feature) { + case sr_po: + replace.insert(kv.m_key, u.mk_po_decl(kv.m_key)); + to_delete.append(kv.m_value.m_goal_indices); + break; + case sr_to: + replace.insert(kv.m_key, u.mk_to_decl(kv.m_key)); + to_delete.append(kv.m_value.m_goal_indices); + break; + case sr_plo: + replace.insert(kv.m_key, u.mk_plo_decl(kv.m_key)); + to_delete.append(kv.m_value.m_goal_indices); + break; + case sr_lo: + replace.insert(kv.m_key, u.mk_lo_decl(kv.m_key)); + to_delete.append(kv.m_value.m_goal_indices); + break; + default: + TRACE("special_relations", tout << "unprocessed feature " << feature << "\n";); + break; + } } + if (!replace.empty()) { + for (unsigned idx = 0; idx < size; idx++) { + if (to_delete.contains(idx)) { + g->update(idx, m.mk_true()); + } + else { + expr_ref new_f = replace(g->form(idx)); + g->update(idx, new_f); + } + } + g->elim_true(); + } + g->inc_depth(); result.push_back(g.get()); } +tactic * mk_special_relations_tactic(ast_manager & m, params_ref const & p) { + return alloc(special_relations_tactic, m, p); +} + diff --git a/src/tactic/core/special_relations_tactic.h b/src/tactic/core/special_relations_tactic.h index 88bd94843..9d7be3717 100644 --- a/src/tactic/core/special_relations_tactic.h +++ b/src/tactic/core/special_relations_tactic.h @@ -22,29 +22,32 @@ Notes: #include "tactic/tactic.h" #include "tactic/tactical.h" +#include "ast/special_relations_decl_plugin.h" class special_relations_tactic : public tactic { + ast_manager& m; params_ref m_params; struct sp_axioms { unsigned_vector m_goal_indices; - unsigned m_sp_features; + sr_property m_sp_features; + sp_axioms():m_sp_features(sr_none) {} }; void collect_feature(goal const& g, unsigned idx, obj_map& goal_features); - void insert(obj_map& goal_features, func_decl* p, unsigned idx, sr_property p); + void insert(obj_map& goal_features, func_decl* f, unsigned idx, sr_property p); bool is_transitivity(expr* fml, func_decl_ref& p); bool is_anti_symmetry(expr* fml, func_decl_ref& p); bool is_left_tree(expr* fml, func_decl_ref& p); bool is_right_tree(expr* fml, func_decl_ref& p); - bool is_reflexivity(expr* fml, func_decl_ref& p); + bool is_reflexive(expr* fml, func_decl_ref& p); bool is_total(expr* fml, func_decl_ref& p); bool is_symmetric(expr* fml, func_decl_ref& p); public: - special_relations_tactic(ast_manager & m, params_ref const & ref = params_ref()) {} + special_relations_tactic(ast_manager & m, params_ref const & ref = params_ref()): m(m), m_params(ref) {} ~special_relations_tactic() override {} From 1c694fd42fda6b7008f699524445efbffdb5e0b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Mar 2019 16:11:16 -0700 Subject: [PATCH 121/156] sr Signed-off-by: Nikolaj Bjorner --- src/ast/ast.h | 1 + src/ast/pattern/expr_pattern_match.cpp | 68 ++++++++++---- src/ast/pattern/expr_pattern_match.h | 7 +- src/ast/rewriter/func_decl_replace.cpp | 1 + src/ast/rewriter/func_decl_replace.h | 9 +- src/tactic/core/special_relations_tactic.cpp | 99 ++++++++++++-------- src/tactic/core/special_relations_tactic.h | 8 +- 7 files changed, 130 insertions(+), 63 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index 1c25ff9ec..baefc4685 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -2122,6 +2122,7 @@ public: app * mk_or(expr * arg1, expr * arg2) { return mk_app(m_basic_family_id, OP_OR, arg1, arg2); } app * mk_and(expr * arg1, expr * arg2) { return mk_app(m_basic_family_id, OP_AND, arg1, arg2); } app * mk_or(expr * arg1, expr * arg2, expr * arg3) { return mk_app(m_basic_family_id, OP_OR, arg1, arg2, arg3); } + app * mk_or(expr* a, expr* b, expr* c, expr* d) { expr* args[4] = { a, b, c, d }; return mk_app(m_basic_family_id, OP_OR, 4, args); } app * mk_and(expr * arg1, expr * arg2, expr * arg3) { return mk_app(m_basic_family_id, OP_AND, arg1, arg2, arg3); } app * mk_implies(expr * arg1, expr * arg2) { return mk_app(m_basic_family_id, OP_IMPLIES, arg1, arg2); } app * mk_not(expr * n) { return mk_app(m_basic_family_id, OP_NOT, n); } diff --git a/src/ast/pattern/expr_pattern_match.cpp b/src/ast/pattern/expr_pattern_match.cpp index 5cd3542df..5a1f20c3b 100644 --- a/src/ast/pattern/expr_pattern_match.cpp +++ b/src/ast/pattern/expr_pattern_match.cpp @@ -52,28 +52,50 @@ expr_pattern_match::match_quantifier(quantifier* qf, app_ref_vector& patterns, u } m_regs[0] = qf->get_expr(); for (unsigned i = 0; i < m_precompiled.size(); ++i) { - quantifier* qf2 = m_precompiled[i].get(); - if (qf2->get_kind() != qf->get_kind() || is_lambda(qf)) { - continue; - } - if (qf2->get_num_decls() != qf->get_num_decls()) { - continue; - } - subst s; - if (match(qf->get_expr(), m_first_instrs[i], s)) { - for (unsigned j = 0; j < qf2->get_num_patterns(); ++j) { - app* p = static_cast(qf2->get_pattern(j)); - expr_ref p_result(m_manager); - instantiate(p, qf->get_num_decls(), s, p_result); - patterns.push_back(to_app(p_result.get())); - } - weight = qf2->get_weight(); - return true; + if (match_quantifier(i, qf, patterns, weight)) + return true; + } + return false; +} + +bool +expr_pattern_match::match_quantifier(unsigned i, quantifier* qf, app_ref_vector& patterns, unsigned& weight) { + quantifier* qf2 = m_precompiled[i].get(); + if (qf2->get_kind() != qf->get_kind() || is_lambda(qf)) { + return false; + } + if (qf2->get_num_decls() != qf->get_num_decls()) { + return false; + } + subst s; + if (match(qf->get_expr(), m_first_instrs[i], s)) { + for (unsigned j = 0; j < qf2->get_num_patterns(); ++j) { + app* p = static_cast(qf2->get_pattern(j)); + expr_ref p_result(m_manager); + instantiate(p, qf->get_num_decls(), s, p_result); + patterns.push_back(to_app(p_result.get())); } + weight = qf2->get_weight(); + return true; } return false; } +bool expr_pattern_match::match_quantifier_index(quantifier* qf, app_ref_vector& patterns, unsigned& index) { + if (m_regs.empty()) return false; + m_regs[0] = qf->get_expr(); + + for (unsigned i = 0; i < m_precompiled.size(); ++i) { + unsigned weight = 0; + if (match_quantifier(i, qf, patterns, weight)) { + index = i; + return true; + } + } + return false; +} + + void expr_pattern_match::instantiate(expr* a, unsigned num_bound, subst& s, expr_ref& result) { bound b; @@ -399,8 +421,16 @@ expr_pattern_match::initialize(char const * spec_string) { TRACE("expr_pattern_match", display(tout); ); } -void -expr_pattern_match::display(std::ostream& out) const { +unsigned expr_pattern_match::initialize(quantifier* q) { + if (m_instrs.empty()) { + m_instrs.push_back(instr(BACKTRACK)); + } + compile(q); + return m_precompiled.size() - 1; +} + + +void expr_pattern_match::display(std::ostream& out) const { for (unsigned i = 0; i < m_instrs.size(); ++i) { display(out, m_instrs[i]); } diff --git a/src/ast/pattern/expr_pattern_match.h b/src/ast/pattern/expr_pattern_match.h index d1388b43f..679d69fbb 100644 --- a/src/ast/pattern/expr_pattern_match.h +++ b/src/ast/pattern/expr_pattern_match.h @@ -131,11 +131,14 @@ class expr_pattern_match { public: expr_pattern_match(ast_manager & manager); ~expr_pattern_match(); - virtual bool match_quantifier(quantifier * qf, app_ref_vector & patterns, unsigned & weight); - virtual void initialize(char const * database); + bool match_quantifier(quantifier * qf, app_ref_vector & patterns, unsigned & weight); + bool match_quantifier_index(quantifier* qf, app_ref_vector & patterns, unsigned& index); + unsigned initialize(quantifier* qf); + void initialize(char const * database); void display(std::ostream& out) const; private: + bool match_quantifier(unsigned i, quantifier * qf, app_ref_vector & patterns, unsigned & weight); void instantiate(expr* a, unsigned num_bound, subst& s, expr_ref& result); void compile(expr* q); bool match(expr* a, unsigned init, subst& s); diff --git a/src/ast/rewriter/func_decl_replace.cpp b/src/ast/rewriter/func_decl_replace.cpp index dcde9044f..97451cb58 100644 --- a/src/ast/rewriter/func_decl_replace.cpp +++ b/src/ast/rewriter/func_decl_replace.cpp @@ -93,4 +93,5 @@ void func_decl_replace::reset() { m_cache.reset(); m_subst.reset(); m_refs.reset(); + m_funs.reset(); } diff --git a/src/ast/rewriter/func_decl_replace.h b/src/ast/rewriter/func_decl_replace.h index a553ed999..7f37e8753 100644 --- a/src/ast/rewriter/func_decl_replace.h +++ b/src/ast/rewriter/func_decl_replace.h @@ -27,13 +27,14 @@ class func_decl_replace { ast_manager& m; obj_map m_subst; obj_map m_cache; - ptr_vector m_todo, m_args; - expr_ref_vector m_refs; + ptr_vector m_todo, m_args; + expr_ref_vector m_refs; + func_decl_ref_vector m_funs; public: - func_decl_replace(ast_manager& m): m(m), m_refs(m) {} + func_decl_replace(ast_manager& m): m(m), m_refs(m), m_funs(m) {} - void insert(func_decl* src, func_decl* dst) { m_subst.insert(src, dst); } + void insert(func_decl* src, func_decl* dst) { m_subst.insert(src, dst); m_funs.push_back(src), m_funs.push_back(dst); } expr_ref operator()(expr* e); diff --git a/src/tactic/core/special_relations_tactic.cpp b/src/tactic/core/special_relations_tactic.cpp index f256bdbef..be0706c5c 100644 --- a/src/tactic/core/special_relations_tactic.cpp +++ b/src/tactic/core/special_relations_tactic.cpp @@ -24,23 +24,12 @@ void special_relations_tactic::collect_feature(goal const& g, unsigned idx, obj_map& goal_features) { expr* f = g.form(idx); func_decl_ref p(m); - if (is_transitivity(f, p)) { - insert(goal_features, p, idx, sr_transitive); - } - else if (is_anti_symmetry(f, p)) { - insert(goal_features, p, idx, sr_antisymmetric); - } - else if (is_left_tree(f, p)) { - insert(goal_features, p, idx, sr_lefttree); - } - else if (is_right_tree(f, p)) { - insert(goal_features, p, idx, sr_righttree); - } - else if (is_reflexive(f, p)) { - insert(goal_features, p, idx, sr_reflexive); - } - else if (is_total(f, p)) { - insert(goal_features, p, idx, sr_total); + if (!is_quantifier(f)) return; + unsigned index = 0; + app_ref_vector patterns(m); + if (m_pm.match_quantifier_index(to_quantifier(f), patterns, index)) { + p = to_app(patterns.get(0)->get_arg(0))->get_decl(); + insert(goal_features, p, idx, m_properties[index]); } } @@ -53,32 +42,68 @@ void special_relations_tactic::insert(obj_map& goal_featur } -bool special_relations_tactic::is_transitivity(expr* fml, func_decl_ref& p) { - // match Forall x, y, z . p(x,y) & p(y,z) -> p(x,z) - return false; +void special_relations_tactic::initialize() { + if (!m_properties.empty()) return; + sort_ref A(m); + func_decl_ref R(m.mk_func_decl(symbol("R"), A, A, m.mk_bool_sort()), m); + var_ref x(m.mk_var(0, A), m); + var_ref y(m.mk_var(1, A), m); + var_ref z(m.mk_var(2, A), m); + expr* _x = x, *_y = y, *_z = z; + + expr_ref Rxy(m.mk_app(R, _x, y), m); + expr_ref Ryz(m.mk_app(R, _y, z), m); + expr_ref Rxz(m.mk_app(R, _x, z), m); + expr_ref Rxx(m.mk_app(R, _x, x), m); + expr_ref Ryx(m.mk_app(R, _y, x), m); + expr_ref Rzy(m.mk_app(R, _z, y), m); + expr_ref Rzx(m.mk_app(R, _z, x), m); + expr_ref nRxy(m.mk_not(Rxy), m); + expr_ref nRyx(m.mk_not(Ryx), m); + expr_ref nRzx(m.mk_not(Rzx), m); + expr_ref nRxz(m.mk_not(Rxz), m); + + sort* As[3] = { A, A, A}; + symbol xyz[3] = { symbol("x"), symbol("y"), symbol("z") }; + expr_ref fml(m); + quantifier_ref q(m); + expr_ref pat(m.mk_pattern(to_app(Rxy)), m); + expr* pats[1] = { pat }; + fml = m.mk_or(m.mk_not(Rxy), m.mk_not(Ryz), Rxz); + q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); + register_pattern(m_pm.initialize(q), sr_transitive); + + fml = Rxx; + q = m.mk_forall(1, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); + register_pattern(m_pm.initialize(q), sr_reflexive); + + fml = m.mk_or(nRxy, nRyx, m.mk_eq(x, y)); + q = m.mk_forall(2, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); + register_pattern(m_pm.initialize(q), sr_antisymmetric); + + fml = m.mk_or(nRyx, nRzx, Ryz, Rzy); + q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); + register_pattern(m_pm.initialize(q), sr_lefttree); + + fml = m.mk_or(nRxy, nRxz, Ryx, Rzy); + q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); + register_pattern(m_pm.initialize(q), sr_righttree); + + fml = m.mk_or(Rxy, Ryx); + q = m.mk_forall(2, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); + register_pattern(m_pm.initialize(q), sr_total); } -bool special_relations_tactic::is_anti_symmetry(expr* fml, func_decl_ref& p) { - return false; -} -bool special_relations_tactic::is_left_tree(expr* fml, func_decl_ref& p) { - return false; -} -bool special_relations_tactic::is_right_tree(expr* fml, func_decl_ref& p) { - return false; -} -bool special_relations_tactic::is_reflexive(expr* fml, func_decl_ref& p) { - return false; -} -bool special_relations_tactic::is_total(expr* fml, func_decl_ref& p) { - return false; -} -bool special_relations_tactic::is_symmetric(expr* fml, func_decl_ref& p) { - return false; + +void special_relations_tactic::register_pattern(unsigned index, sr_property p) { + SASSERT(index == m_properties.size() + 1); + m_properties.push_back(p); } + void special_relations_tactic::operator()(goal_ref const & g, goal_ref_buffer & result) { tactic_report report("special_relations", *g); + initialize(); obj_map goal_features; unsigned size = g->size(); for (unsigned idx = 0; idx < size; idx++) { diff --git a/src/tactic/core/special_relations_tactic.h b/src/tactic/core/special_relations_tactic.h index 9d7be3717..58da2efbc 100644 --- a/src/tactic/core/special_relations_tactic.h +++ b/src/tactic/core/special_relations_tactic.h @@ -23,10 +23,13 @@ Notes: #include "tactic/tactic.h" #include "tactic/tactical.h" #include "ast/special_relations_decl_plugin.h" +#include "ast/pattern/expr_pattern_match.h" class special_relations_tactic : public tactic { ast_manager& m; params_ref m_params; + expr_pattern_match m_pm; + svector m_properties; struct sp_axioms { unsigned_vector m_goal_indices; @@ -37,6 +40,9 @@ class special_relations_tactic : public tactic { void collect_feature(goal const& g, unsigned idx, obj_map& goal_features); void insert(obj_map& goal_features, func_decl* f, unsigned idx, sr_property p); + void initialize(); + void register_pattern(unsigned index, sr_property); + bool is_transitivity(expr* fml, func_decl_ref& p); bool is_anti_symmetry(expr* fml, func_decl_ref& p); bool is_left_tree(expr* fml, func_decl_ref& p); @@ -47,7 +53,7 @@ class special_relations_tactic : public tactic { public: - special_relations_tactic(ast_manager & m, params_ref const & ref = params_ref()): m(m), m_params(ref) {} + special_relations_tactic(ast_manager & m, params_ref const & ref = params_ref()): m(m), m_params(ref), m_pm(m) {} ~special_relations_tactic() override {} From ebc4b93d52c74b017c4601d63264264c95d02196 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Mar 2019 08:41:31 -0700 Subject: [PATCH 122/156] update documentation Signed-off-by: Nikolaj Bjorner --- src/parsers/smt2/smt2parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index e09ea0f3c..4f382b30d 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -1591,7 +1591,7 @@ namespace smt2 { // parse: // 'as' ')' // '_' + ')' - // 'as' (|)+ ')' ')' + // 'as' '(' '_' (|)+ ')' ')' symbol parse_qualified_identifier_core(bool & has_as) { SASSERT(curr_is_identifier()); SASSERT(curr_id_is_underscore() || curr_id_is_as()); From 3afe081f62b4e89a3022a0a29e5865c19c8fb765 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Mar 2019 11:42:40 -0700 Subject: [PATCH 123/156] fixup compiled patterns Signed-off-by: Nikolaj Bjorner --- src/ast/ast_util.h | 15 ++++++++ src/ast/pattern/expr_pattern_match.cpp | 12 ++----- src/ast/pattern/expr_pattern_match.h | 21 +++--------- src/tactic/core/special_relations_tactic.cpp | 36 ++++++++++++++++---- src/tactic/core/special_relations_tactic.h | 14 +++----- 5 files changed, 54 insertions(+), 44 deletions(-) diff --git a/src/ast/ast_util.h b/src/ast/ast_util.h index a45c65d82..a8c9131c7 100644 --- a/src/ast/ast_util.h +++ b/src/ast/ast_util.h @@ -111,6 +111,17 @@ app * mk_and(ast_manager & m, unsigned num_args, app * const * args); inline app_ref mk_and(app_ref_vector const& args) { return app_ref(mk_and(args.get_manager(), args.size(), args.c_ptr()), args.get_manager()); } inline expr_ref mk_and(expr_ref_vector const& args) { return expr_ref(mk_and(args.get_manager(), args.size(), args.c_ptr()), args.get_manager()); } +inline app_ref operator&(expr_ref& a, expr* b) { return app_ref(a.m().mk_and(a, b), a.m()); } +inline app_ref operator&(app_ref& a, expr* b) { return app_ref(a.m().mk_and(a, b), a.m()); } +inline app_ref operator&(var_ref& a, expr* b) { return app_ref(a.m().mk_and(a, b), a.m()); } +inline app_ref operator&(quantifier_ref& a, expr* b) { return app_ref(a.m().mk_and(a, b), a.m()); } + +inline app_ref operator|(expr_ref& a, expr* b) { return app_ref(a.m().mk_or(a, b), a.m()); } +inline app_ref operator|(app_ref& a, expr* b) { return app_ref(a.m().mk_or(a, b), a.m()); } +inline app_ref operator|(var_ref& a, expr* b) { return app_ref(a.m().mk_or(a, b), a.m()); } +inline app_ref operator|(quantifier_ref& a, expr* b) { return app_ref(a.m().mk_or(a, b), a.m()); } + + /** Return (or args[0] ... args[num_args-1]) if num_args >= 2 Return args[0] if num_args == 1 @@ -129,6 +140,10 @@ expr * mk_not(ast_manager & m, expr * arg); expr_ref mk_not(const expr_ref& e); +inline expr_ref not(const expr_ref& e) { return mk_not(e); } +inline app_ref not(const app_ref& e) { return app_ref(e.m().mk_not(e), e.m()); } + + /** Negate and push over conjunction or disjunction. */ diff --git a/src/ast/pattern/expr_pattern_match.cpp b/src/ast/pattern/expr_pattern_match.cpp index 5a1f20c3b..8ae0dcbf2 100644 --- a/src/ast/pattern/expr_pattern_match.cpp +++ b/src/ast/pattern/expr_pattern_match.cpp @@ -102,7 +102,7 @@ expr_pattern_match::instantiate(expr* a, unsigned num_bound, subst& s, expr_ref& for (unsigned i = 0; i < num_bound; ++i) { b.insert(m_bound_dom[i], m_bound_rng[i]); } - + TRACE("expr_pattern_match", tout << mk_pp(a, m_manager) << " " << num_bound << "\n";); inst_proc proc(m_manager, s, b, m_regs); for_each_ast(proc, a); expr* v = nullptr; @@ -273,11 +273,7 @@ expr_pattern_match::match(expr* a, unsigned init, subst& s) break; } case CHECK_BOUND: - TRACE("expr_pattern_match", - tout - << "check bound " - << pc.m_num_bound << " " << pc.m_reg; - ); + TRACE("expr_pattern_match", tout << "check bound " << pc.m_num_bound << " " << pc.m_reg << "\n";); ok = m_bound_rng[pc.m_num_bound] == m_regs[pc.m_reg]; break; case BIND: @@ -418,7 +414,6 @@ expr_pattern_match::initialize(char const * spec_string) { for (expr * e : ctx.assertions()) { compile(e); } - TRACE("expr_pattern_match", display(tout); ); } unsigned expr_pattern_match::initialize(quantifier* q) { @@ -444,7 +439,6 @@ expr_pattern_match::display(std::ostream& out, instr const& pc) const { break; case BIND: out << "bind "; - out << mk_pp(to_app(pc.m_pat)->get_decl(), m_manager) << " "; out << mk_pp(pc.m_pat, m_manager) << "\n"; out << "next: " << pc.m_next << "\n"; out << "offset: " << pc.m_offset << "\n"; @@ -452,7 +446,6 @@ expr_pattern_match::display(std::ostream& out, instr const& pc) const { break; case BIND_AC: out << "bind_ac "; - out << mk_pp(to_app(pc.m_pat)->get_decl(), m_manager) << " "; out << mk_pp(pc.m_pat, m_manager) << "\n"; out << "next: " << pc.m_next << "\n"; out << "offset: " << pc.m_offset << "\n"; @@ -460,7 +453,6 @@ expr_pattern_match::display(std::ostream& out, instr const& pc) const { break; case BIND_C: out << "bind_c "; - out << mk_pp(to_app(pc.m_pat)->get_decl(), m_manager) << " "; out << mk_pp(pc.m_pat, m_manager) << "\n"; out << "next: " << pc.m_next << "\n"; out << "offset: " << pc.m_offset << "\n"; diff --git a/src/ast/pattern/expr_pattern_match.h b/src/ast/pattern/expr_pattern_match.h index 679d69fbb..6c472d708 100644 --- a/src/ast/pattern/expr_pattern_match.h +++ b/src/ast/pattern/expr_pattern_match.h @@ -80,13 +80,7 @@ class expr_pattern_match { } void operator()(var* v) { - var* b = nullptr; - if (m_bound.find(v, b)) { - m_memoize.insert(v, b); - } - else { - UNREACHABLE(); - } + m_memoize.insert(v, m_bound[v]); } void operator()(app * n) { @@ -98,15 +92,9 @@ class expr_pattern_match { if (m_subst.find(decl, r)) { decl = to_app(m_regs[r])->get_decl(); } - for (unsigned i = 0; i < num_args; ++i) { - expr* arg = nullptr; - if (m_memoize.find(n->get_arg(i), arg)) { - SASSERT(arg); - args.push_back(arg); - } - else { - UNREACHABLE(); - } + for (expr* arg : *n) { + arg = m_memoize[arg]; + args.push_back(arg); } if (m_manager.is_pattern(n)) { result = m_manager.mk_pattern(num_args, reinterpret_cast(args.c_ptr())); @@ -116,7 +104,6 @@ class expr_pattern_match { } m_pinned.push_back(result); m_memoize.insert(n, result); - return; } }; diff --git a/src/tactic/core/special_relations_tactic.cpp b/src/tactic/core/special_relations_tactic.cpp index be0706c5c..75f8e270c 100644 --- a/src/tactic/core/special_relations_tactic.cpp +++ b/src/tactic/core/special_relations_tactic.cpp @@ -19,6 +19,8 @@ Notes: --*/ #include "tactic/core/special_relations_tactic.h" #include "ast/rewriter/func_decl_replace.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" void special_relations_tactic::collect_feature(goal const& g, unsigned idx, obj_map& goal_features) { @@ -27,7 +29,10 @@ void special_relations_tactic::collect_feature(goal const& g, unsigned idx, if (!is_quantifier(f)) return; unsigned index = 0; app_ref_vector patterns(m); - if (m_pm.match_quantifier_index(to_quantifier(f), patterns, index)) { + bool is_match = m_pm.match_quantifier_index(to_quantifier(f), patterns, index); + TRACE("special_relations", tout << "check " << is_match << " " << mk_pp(f, m) << "\n"; + if (is_match) tout << patterns << " " << index << "\n";); + if (is_match) { p = to_app(patterns.get(0)->get_arg(0))->get_decl(); insert(goal_features, p, idx, m_properties[index]); } @@ -44,8 +49,8 @@ void special_relations_tactic::insert(obj_map& goal_featur void special_relations_tactic::initialize() { if (!m_properties.empty()) return; - sort_ref A(m); - func_decl_ref R(m.mk_func_decl(symbol("R"), A, A, m.mk_bool_sort()), m); + sort_ref A(m.mk_uninterpreted_sort(symbol("A")), m); + func_decl_ref R(m.mk_func_decl(symbol("?R"), A, A, m.mk_bool_sort()), m); var_ref x(m.mk_var(0, A), m); var_ref y(m.mk_var(1, A), m); var_ref z(m.mk_var(2, A), m); @@ -68,34 +73,51 @@ void special_relations_tactic::initialize() { expr_ref fml(m); quantifier_ref q(m); expr_ref pat(m.mk_pattern(to_app(Rxy)), m); + expr_ref pat0(m.mk_pattern(to_app(Rxx)), m); expr* pats[1] = { pat }; + expr* pats0[1] = { pat0 }; + fml = m.mk_or(m.mk_not(Rxy), m.mk_not(Ryz), Rxz); q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_transitive); - + fml = m.mk_or(not(Rxy & Ryz), Rxz); + q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); + register_pattern(m_pm.initialize(q), sr_transitive); + fml = Rxx; - q = m.mk_forall(1, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); + q = m.mk_forall(1, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats0); register_pattern(m_pm.initialize(q), sr_reflexive); fml = m.mk_or(nRxy, nRyx, m.mk_eq(x, y)); q = m.mk_forall(2, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_antisymmetric); + fml = m.mk_or(not(Rxy & Ryx), m.mk_eq(x, y)); + q = m.mk_forall(2, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); + register_pattern(m_pm.initialize(q), sr_antisymmetric); fml = m.mk_or(nRyx, nRzx, Ryz, Rzy); q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_lefttree); + fml = m.mk_or(not (Ryx & Rzx), Ryz, Rzy); + q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); + register_pattern(m_pm.initialize(q), sr_lefttree); - fml = m.mk_or(nRxy, nRxz, Ryx, Rzy); + fml = m.mk_or(nRxy, nRxz, Ryz, Rzy); + q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); + register_pattern(m_pm.initialize(q), sr_righttree); + fml = m.mk_or(not(Rxy & Rxz), Ryz, Rzy); q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_righttree); fml = m.mk_or(Rxy, Ryx); q = m.mk_forall(2, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_total); + + TRACE("special_relations", m_pm.display(tout);); } void special_relations_tactic::register_pattern(unsigned index, sr_property p) { - SASSERT(index == m_properties.size() + 1); + SASSERT(index == m_properties.size()); m_properties.push_back(p); } diff --git a/src/tactic/core/special_relations_tactic.h b/src/tactic/core/special_relations_tactic.h index 58da2efbc..c706c78e8 100644 --- a/src/tactic/core/special_relations_tactic.h +++ b/src/tactic/core/special_relations_tactic.h @@ -43,17 +43,10 @@ class special_relations_tactic : public tactic { void initialize(); void register_pattern(unsigned index, sr_property); - bool is_transitivity(expr* fml, func_decl_ref& p); - bool is_anti_symmetry(expr* fml, func_decl_ref& p); - bool is_left_tree(expr* fml, func_decl_ref& p); - bool is_right_tree(expr* fml, func_decl_ref& p); - bool is_reflexive(expr* fml, func_decl_ref& p); - bool is_total(expr* fml, func_decl_ref& p); - bool is_symmetric(expr* fml, func_decl_ref& p); - public: - special_relations_tactic(ast_manager & m, params_ref const & ref = params_ref()): m(m), m_params(ref), m_pm(m) {} + special_relations_tactic(ast_manager & m, params_ref const & ref = params_ref()): + m(m), m_params(ref), m_pm(m) {} ~special_relations_tactic() override {} @@ -71,8 +64,9 @@ public: tactic * mk_special_relations_tactic(ast_manager & m, params_ref const & p = params_ref()); + /* - ADD_TACTIC("special_relations", "detect and replace by special relations.", "mk_special_relations_tactic(m, p)") + ADD_TACTIC("special-relations", "detect and replace by special relations.", "mk_special_relations_tactic(m, p)") */ #endif From 4fb867a49c55de90c04721f7c5e53d114fb5c6d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Apr 2019 11:57:07 -0700 Subject: [PATCH 124/156] na Signed-off-by: Nikolaj Bjorner --- src/ast/recfun_decl_plugin.cpp | 13 ++++++++++++- src/ast/recfun_decl_plugin.h | 3 ++- src/ast/static_features.cpp | 7 +++++-- src/ast/static_features.h | 3 +++ src/smt/smt_setup.cpp | 3 ++- src/smt/theory_recfun.cpp | 2 +- src/smt/theory_special_relations.cpp | 7 +++---- 7 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index ebdf86ca5..bdaf3fcf0 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -316,6 +316,7 @@ namespace recfun { return alloc(def, m(), m_fid, name, n, domain, range); } + 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); } @@ -384,7 +385,17 @@ namespace recfun { promise_def plugin::mk_def(symbol const& name, unsigned n, sort *const * params, sort * range) { def* d = u().decl_fun(name, n, params, range); - SASSERT(! m_defs.contains(d->get_decl())); + SASSERT(!m_defs.contains(d->get_decl())); + m_defs.insert(d->get_decl(), d); + return promise_def(&u(), d); + } + + promise_def plugin::ensure_def(symbol const& name, unsigned n, sort *const * params, sort * range) { + def* d = u().decl_fun(name, n, params, range); + def* d2 = nullptr; + if (m_defs.find(d->get_decl(), d2)) { + dealloc(d2); + } m_defs.insert(d->get_decl(), d); return promise_def(&u(), d); } diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index b294cdfce..33b5294f5 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -172,6 +172,8 @@ namespace recfun { unsigned arity, sort * const * domain, sort * range) override; promise_def mk_def(symbol const& name, unsigned n, sort *const * params, sort * range); + + promise_def ensure_def(symbol const& name, unsigned n, sort *const * params, sort * range); void set_definition(replace& r, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs); @@ -223,7 +225,6 @@ namespace recfun { //has_def(f)); return m_plugin->get_def(f); diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp index e3530b4b5..e86475252 100644 --- a/src/ast/static_features.cpp +++ b/src/ast/static_features.cpp @@ -30,6 +30,7 @@ static_features::static_features(ast_manager & m): m_afid(m.mk_family_id("arith")), m_lfid(m.mk_family_id("label")), m_arrfid(m.mk_family_id("array")), + m_srfid(m.mk_family_id("special_relations")), m_label_sym("label"), m_pattern_sym("pattern"), m_expr_list_sym("expr-list") { @@ -78,6 +79,7 @@ void static_features::reset() { m_has_real = false; m_has_bv = false; m_has_fpa = false; + m_has_sr = false; m_has_str = false; m_has_seq_non_str = false; m_has_arrays = false; @@ -274,6 +276,8 @@ void static_features::update_core(expr * e) { m_has_bv = true; if (!m_has_fpa && (m_fpautil.is_float(e) || m_fpautil.is_rm(e))) m_has_fpa = true; + if (is_app(e) && to_app(e)->get_family_id() == m_srfid) + m_has_sr = true; if (!m_has_arrays && m_arrayutil.is_array(e)) m_has_arrays = true; if (!m_has_ext_arrays && m_arrayutil.is_array(e) && @@ -281,9 +285,8 @@ void static_features::update_core(expr * e) { m_has_ext_arrays = true; if (!m_has_str && m_sequtil.str.is_string_term(e)) m_has_str = true; - if (!m_has_seq_non_str && m_sequtil.str.is_non_string_sequence(e)) { + if (!m_has_seq_non_str && m_sequtil.str.is_non_string_sequence(e)) m_has_seq_non_str = true; - } if (is_app(e)) { family_id fid = to_app(e)->get_family_id(); mark_theory(fid); diff --git a/src/ast/static_features.h b/src/ast/static_features.h index 197947026..047c429b7 100644 --- a/src/ast/static_features.h +++ b/src/ast/static_features.h @@ -25,6 +25,7 @@ Revision History: #include "ast/array_decl_plugin.h" #include "ast/fpa_decl_plugin.h" #include "ast/seq_decl_plugin.h" +#include "ast/special_relations_decl_plugin.h" #include "util/map.h" struct static_features { @@ -38,6 +39,7 @@ struct static_features { family_id m_afid; family_id m_lfid; family_id m_arrfid; + family_id m_srfid; ast_mark m_already_visited; bool m_cnf; unsigned m_num_exprs; // @@ -79,6 +81,7 @@ struct static_features { bool m_has_real; // bool m_has_bv; // bool m_has_fpa; // + bool m_has_sr; // has special relations bool m_has_str; // has String-typed terms bool m_has_seq_non_str; // has non-String-typed Sequence terms bool m_has_arrays; // diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 89213c86d..5f916899b 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -955,7 +955,7 @@ namespace smt { setup_seq_str(st); setup_card(); setup_fpa(); - setup_special_relations(); + if (st.m_has_sr) setup_special_relations(); } void setup::setup_unknown(static_features & st) { @@ -972,6 +972,7 @@ namespace smt { setup_card(); setup_fpa(); setup_recfuns(); + if (st.m_has_sr) setup_special_relations(); return; } diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index af2d56cf1..cc7ec0e36 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -460,7 +460,7 @@ namespace smt { } void theory_recfun::display(std::ostream & out) const { - out << "recfun{}"; + out << "recfun{}\n"; } void theory_recfun::collect_statistics(::statistics & st) const { diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 6e8c04a97..e8c276206 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -655,11 +655,11 @@ namespace smt { func_decl_ref fst(m), snd(m), pair(m); sort_ref tup(dt.mk_pair_datatype(listS, m.mk_bool_sort(), fst, snd, pair), m); sort* dom1[5] = { s, s, listS, s, s }; - recfun::promise_def c1 = p.mk_def(symbol("connected1"), 5, dom1, tup); + recfun::promise_def c1 = p.ensure_def(symbol("connected1"), 5, dom1, tup); sort* dom2[3] = { s, s, listS }; - recfun::promise_def c2 = p.mk_def(symbol("connected2"), 3, dom2, tup); + recfun::promise_def c2 = p.ensure_def(symbol("connected2"), 3, dom2, tup); sort* dom3[2] = { s, listS }; - recfun::promise_def mem = p.mk_def(symbol("member"), 2, dom3, m.mk_bool_sort()); + recfun::promise_def mem = p.ensure_def(symbol("member"), 2, dom3, m.mk_bool_sort()); var_ref xV(m.mk_var(1, s), m); var_ref SV(m.mk_var(0, listS), m); var_ref yV(m), vV(m), wV(m); @@ -718,7 +718,6 @@ namespace smt { SASSERT(ctx.get_assignment(a.var()) == l_true); expr* n1 = get_enode(a.v1())->get_root()->get_owner(); expr* n2 = get_enode(a.v2())->get_root()->get_owner(); - expr* Sr = connected_rec_body; expr* args[5] = { x, y, m.mk_app(fst, Sr), n1, n2}; expr* Sc = m.mk_app(conn1, 5, args); From 7e7cdf3635db9d37fb4079d3b755be3323032fe1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Apr 2019 12:13:50 -0700 Subject: [PATCH 125/156] update dependencies in legacy build system Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 8 ++++---- src/smt/theory_bv.cpp | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 2748e30a1..535dbbb10 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -34,19 +34,19 @@ def init_project_def(): add_lib('parser_util', ['ast'], 'parsers/util') add_lib('grobner', ['ast'], 'math/grobner') add_lib('euclid', ['util'], 'math/euclid') - add_lib('core_tactics', ['tactic', 'macros', 'normal_forms', 'rewriter'], 'tactic/core') add_lib('proofs', ['rewriter', 'util'], 'ast/proofs') add_lib('solver', ['model', 'tactic', 'proofs']) + add_lib('cmd_context', ['solver', 'rewriter']) add_lib('sat_tactic', ['tactic', 'sat', 'solver'], 'sat/tactic') + add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2') + add_lib('pattern', ['normal_forms', 'smt2parser', 'rewriter'], 'ast/pattern') + add_lib('core_tactics', ['tactic', 'macros', 'normal_forms', 'rewriter', 'pattern'], 'tactic/core') add_lib('arith_tactics', ['core_tactics', 'sat'], 'tactic/arith') add_lib('nlsat_tactic', ['nlsat', 'sat_tactic', 'arith_tactics'], 'nlsat/tactic') add_lib('subpaving_tactic', ['core_tactics', 'subpaving'], 'math/subpaving/tactic') add_lib('aig_tactic', ['tactic'], 'tactic/aig') add_lib('ackermannization', ['model', 'rewriter', 'ast', 'solver', 'tactic'], 'ackermannization') - add_lib('cmd_context', ['solver', 'rewriter']) - add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2') add_lib('fpa', ['ast', 'util', 'rewriter', 'model'], 'ast/fpa') - add_lib('pattern', ['normal_forms', 'smt2parser', 'rewriter'], 'ast/pattern') add_lib('bit_blaster', ['rewriter', 'rewriter'], 'ast/rewriter/bit_blaster') add_lib('smt_params', ['ast', 'rewriter', 'pattern', 'bit_blaster'], 'smt/params') add_lib('proto_model', ['model', 'rewriter', 'smt_params'], 'smt/proto_model') diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 89b211af6..5fad04f00 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -120,9 +120,10 @@ namespace smt { unsigned idx = n->get_decl()->get_parameter(0).get_int(); SASSERT(a->m_occs == 0); a->m_occs = new (get_region()) var_pos_occ(v_arg, idx); -#if 1 +#if 0 // possible fix for #2182, but effect of fix needs to be checked. if (idx < m_bits[v_arg].size()) { + //std::cout << mk_pp(n, get_manager()) << "\n"; ctx.mk_th_axiom(get_id(), m_bits[v_arg][idx], literal(bv, true)); ctx.mk_th_axiom(get_id(), ~m_bits[v_arg][idx], literal(bv, false)); } From 5fdf5b67a45bf7cc9259ad30273eef148c16f6d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Apr 2019 12:17:49 -0700 Subject: [PATCH 126/156] remove not Signed-off-by: Nikolaj Bjorner --- src/ast/ast_util.h | 3 +-- src/tactic/core/special_relations_tactic.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ast/ast_util.h b/src/ast/ast_util.h index a8c9131c7..e317d14ec 100644 --- a/src/ast/ast_util.h +++ b/src/ast/ast_util.h @@ -140,8 +140,7 @@ expr * mk_not(ast_manager & m, expr * arg); expr_ref mk_not(const expr_ref& e); -inline expr_ref not(const expr_ref& e) { return mk_not(e); } -inline app_ref not(const app_ref& e) { return app_ref(e.m().mk_not(e), e.m()); } +inline app_ref mk_not(const app_ref& e) { return app_ref(e.m().mk_not(e), e.m()); } /** diff --git a/src/tactic/core/special_relations_tactic.cpp b/src/tactic/core/special_relations_tactic.cpp index 75f8e270c..a8b74db31 100644 --- a/src/tactic/core/special_relations_tactic.cpp +++ b/src/tactic/core/special_relations_tactic.cpp @@ -80,7 +80,7 @@ void special_relations_tactic::initialize() { fml = m.mk_or(m.mk_not(Rxy), m.mk_not(Ryz), Rxz); q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_transitive); - fml = m.mk_or(not(Rxy & Ryz), Rxz); + fml = m.mk_or(mk_not(Rxy & Ryz), Rxz); q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_transitive); @@ -91,21 +91,21 @@ void special_relations_tactic::initialize() { fml = m.mk_or(nRxy, nRyx, m.mk_eq(x, y)); q = m.mk_forall(2, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_antisymmetric); - fml = m.mk_or(not(Rxy & Ryx), m.mk_eq(x, y)); + fml = m.mk_or(mk_not(Rxy & Ryx), m.mk_eq(x, y)); q = m.mk_forall(2, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_antisymmetric); fml = m.mk_or(nRyx, nRzx, Ryz, Rzy); q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_lefttree); - fml = m.mk_or(not (Ryx & Rzx), Ryz, Rzy); + fml = m.mk_or(mk_not (Ryx & Rzx), Ryz, Rzy); q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_lefttree); fml = m.mk_or(nRxy, nRxz, Ryz, Rzy); q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_righttree); - fml = m.mk_or(not(Rxy & Rxz), Ryz, Rzy); + fml = m.mk_or(mk_not(Rxy & Rxz), Ryz, Rzy); q = m.mk_forall(3, As, xyz, fml, 0, symbol::null, symbol::null, 1, pats); register_pattern(m_pm.initialize(q), sr_righttree); From ff6d703c052e8e13b889e5645ea586ca126a9cd6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Apr 2019 12:20:55 -0700 Subject: [PATCH 127/156] add tracing, fix #2214, remove unused variables Signed-off-by: Nikolaj Bjorner --- src/opt/opt_parse.cpp | 6 +++--- src/smt/diff_logic.h | 1 - src/smt/theory_special_relations.cpp | 19 +++++++++++-------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp index 09845ff07..47ce31e1b 100644 --- a/src/opt/opt_parse.cpp +++ b/src/opt/opt_parse.cpp @@ -417,7 +417,7 @@ private: if (is_num(c)) { rational n(0); - unsigned div = 1; + rational div(1); while (is_num(c) && !in.eof()) { n = n*rational(10) + rational(c - '0'); in.next(); @@ -429,11 +429,11 @@ private: while (is_num(c) && !in.eof()) { n = n*rational(10) + rational(c - '0'); in.next(); - div *= 10; + div *= rational(10); c = in.ch(); } } - if (div > 1) n = n / rational(div); + if (div > rational(1)) n = n / div; if (neg) n.neg(); m_tokens.push_back(asymbol(n, in.line())); IF_VERBOSE(10, verbose_stream() << "num: " << m_tokens.back() << "\n"); diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 605390cf1..85330de87 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -1752,7 +1752,6 @@ public: find_subsumed1(id, subsumed); - typename edge_id_vector::const_iterator it, end, it3, end3; for (edge_id e_id : m_in_edges[src]) { edge const& e2 = m_edges[e_id]; if (!e2.is_enabled() || e2.get_source() == dst) { diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index e8c276206..9dcc7afad 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -133,7 +133,6 @@ namespace smt { } void theory_special_relations::new_eq_eh(theory_var v1, theory_var v2) { - context& ctx = get_context(); app* t1 = get_enode(v1)->get_owner(); app* t2 = get_enode(v2)->get_owner(); literal eq = mk_eq(t1, t2, false); @@ -282,6 +281,7 @@ namespace smt { void theory_special_relations::set_conflict(relation& r) { literal_vector const& lits = r.m_explanation; context & ctx = get_context(); + TRACE("special_relations", ctx.display_literals_verbose(tout, lits) << "\n";); vector params; ctx.set_conflict( ctx.mk_justification( @@ -319,22 +319,26 @@ namespace smt { int_vector scc_id; u_map roots; context& ctx = get_context(); + ast_manager& m = get_manager(); + (void)m; r.m_graph.compute_zero_edge_scc(scc_id); for (unsigned i = 0, j = 0; !ctx.inconsistent() && i < scc_id.size(); ++i) { if (scc_id[i] == -1) { continue; } - enode* n = get_enode(i); + enode* x = get_enode(i); if (roots.find(scc_id[i], j)) { - enode* m = get_enode(j); - if (n->get_root() != m->get_root()) { + enode* y = get_enode(j); + if (x->get_root() != y->get_root()) { new_eq = true; unsigned timestamp = r.m_graph.get_timestamp(); r.m_explanation.reset(); r.m_graph.find_shortest_zero_edge_path(i, j, timestamp, r); r.m_graph.find_shortest_zero_edge_path(j, i, timestamp, r); - eq_justification js(ctx.mk_justification(theory_axiom_justification(get_id(), ctx.get_region(), r.m_explanation.size(), r.m_explanation.c_ptr()))); - ctx.assign_eq(n, m, js); + literal_vector const& lits = r.m_explanation; + TRACE("special_relations", ctx.display_literals_verbose(tout << mk_pp(x->get_owner(), m) << " = " << mk_pp(y->get_owner(), m) << " ", lits) << "\n";); + eq_justification js(ctx.mk_justification(theory_axiom_justification(get_id(), ctx.get_region(), lits.size(), lits.c_ptr()))); + ctx.assign_eq(x, y, js); } } else { @@ -646,7 +650,6 @@ namespace smt { void theory_special_relations::init_model_po(relation& r, model_generator& mg) { ast_manager& m = get_manager(); sort* s = r.m_decl->get_domain(0); - context& ctx = get_context(); datatype_util dt(m); recfun::util rf(m); recfun::decl::plugin& p = rf.get_plugin(); @@ -715,7 +718,7 @@ namespace smt { for (atom* ap : r.m_asserted_atoms) { atom& a = *ap; if (!a.phase()) continue; - SASSERT(ctx.get_assignment(a.var()) == l_true); + SASSERT(get_context().get_assignment(a.var()) == l_true); expr* n1 = get_enode(a.v1())->get_root()->get_owner(); expr* n2 = get_enode(a.v2())->get_root()->get_owner(); expr* Sr = connected_rec_body; From 6360798a536767121570939a56a71c76f1069bd8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Apr 2019 17:40:34 -0700 Subject: [PATCH 128/156] local Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 17 ++++++++++------- src/util/rlimit.h | 5 +++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index a40efe228..796a170fc 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -86,8 +86,7 @@ namespace smt { m_generation(0), m_last_search_result(l_undef), m_last_search_failure(UNKNOWN), - m_searching(false), - m_propagating(false) { + m_searching(false) { SASSERT(m_scope_lvl == 0); SASSERT(m_base_lvl == 0); @@ -134,11 +133,10 @@ namespace smt { /** \brief retrieve flag for when cancelation is possible. - Cancelation is not safe during propagation at base level because - congruences cannot be retracted to a consistent state. - */ + */ + bool context::get_cancel_flag() { - return !m_manager.limit().inc() && !(at_base_level() && m_propagating); + return !m_manager.limit().inc(); } void context::updt_params(params_ref const& p) { @@ -1701,8 +1699,13 @@ namespace smt { !m_th_diseq_propagation_queue.empty(); } + /** + \brief unit propagation. + Cancelation is not safe during propagation at base level because + congruences cannot be retracted to a consistent state. + */ bool context::propagate() { - flet _prop(m_propagating, true); + scoped_suspend_rlimit _suspend_cancel(m_manager.limit(), at_base_level()); TRACE("propagate", tout << "propagating... " << m_qhead << ":" << m_assigned_literals.size() << "\n";); while (true) { if (inconsistent()) diff --git a/src/util/rlimit.h b/src/util/rlimit.h index cc022a963..77fab7b6b 100644 --- a/src/util/rlimit.h +++ b/src/util/rlimit.h @@ -71,6 +71,11 @@ public: m_suspend = r.m_suspend; r.m_suspend = true; } + + scoped_suspend_rlimit(reslimit& r, bool do_suspend): m_limit(r) { + m_suspend = r.m_suspend; + r.m_suspend |= do_suspend; + } ~scoped_suspend_rlimit() { m_limit.m_suspend = m_suspend; } From dfd327f287389b2cae03e400f3e9ccdb9cafa1d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Apr 2019 18:36:35 -0700 Subject: [PATCH 129/156] add tuple and disjoint sum shorthands Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 267a24a20..76e87775a 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -4937,6 +4937,29 @@ class DatatypeRef(ExprRef): """Return the datatype sort of the datatype expression `self`.""" return DatatypeSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx) +def TupleSort(name, sorts, ctx = None): + """Create a named tuple sort base on a set of underlying sorts + Example: + >>> pair, mk_pair, (first, second) = TupleSort("pair", [IntSort(), StringSort()]) + """ + tuple = Datatype(name, ctx) + projects = [ ('project%d' % i, sorts[i]) for i in range(len(sorts)) ] + tuple.declare(name, *projects) + tuple = tuple.create() + return tuple, tuple.constructor(0), [tuple.accessor(0, i) for i in range(len(sorts))] + +def DisjointSum(name, sorts, ctx=None): + """Create a named tagged union sort base on a set of underlying sorts + Example: + >>> sum, ((inject0, extract0), (inject1, extract1)) = DisjointSum("+", [IntSort(), StringSort()]) + """ + sum = Datatype(name, ctx) + for i in range(len(sorts)): + sum.declare("inject%d" % i, ("project%d" % i, sorts[i])) + sum = sum.create() + return sum, [(sum.constructor(i), sum.accessor(i, 0)) for i in range(len(sorts))] + + def EnumSort(name, values, ctx=None): """Return a new enumeration sort named `name` containing the given values. From 56ac3f86a5ad4d1e2ff147d74edf246dbd0c4b72 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Apr 2019 17:08:10 -0700 Subject: [PATCH 130/156] fix justification for implied equalities in special relations Signed-off-by: Nikolaj Bjorner --- examples/python/union_sort.py | 20 ++++++++++++++++++++ src/smt/smt_context.cpp | 5 +++-- src/smt/theory_special_relations.cpp | 14 +++++++++++--- 3 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 examples/python/union_sort.py diff --git a/examples/python/union_sort.py b/examples/python/union_sort.py new file mode 100644 index 000000000..5a609d6cd --- /dev/null +++ b/examples/python/union_sort.py @@ -0,0 +1,20 @@ +# Copyright Microsoft Corporation 2019 +# This example illustrates the use of union types +# from the Python API. It is given as an example +# as response to #2215. + +from z3 import * + +u = Datatype('IntOrString') +u.declare('IntV', ('int', IntSort())) +u.declare('StringV', ('string', StringSort())) +IntOrString = u.create() +StringV = IntOrString.StringV +IntV = IntOrString.IntV + +print(IntV(1)) +print(StringV(StringVal("abc"))) +print(IntV(1).sort()) +print(IntV(1) == StringV(StringVal("abc"))) +s = String('s') +print(simplify(IntV(1) == StringV(s))) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index a40efe228..a5c722d4b 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1330,10 +1330,11 @@ namespace smt { for (; i < m_eq_propagation_queue.size() && !get_cancel_flag(); i++) { new_eq & entry = m_eq_propagation_queue[i]; add_eq(entry.m_lhs, entry.m_rhs, entry.m_justification); - if (inconsistent()) + if (inconsistent()) { + m_eq_propagation_queue.reset(); return false; + } } - TRACE("add_eq", tout << m_eq_propagation_queue.size() << " " << i << "\n";); m_eq_propagation_queue.reset(); return true; } diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 9dcc7afad..d7ba74a87 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -162,6 +162,10 @@ namespace smt { for (auto const& kv : m_relations) { if (extract_equalities(*kv.m_value)) { new_equality = true; + //return FC_CONTINUE; + } + if (get_context().inconsistent()) { + return FC_CONTINUE; } } if (new_equality) { @@ -322,7 +326,9 @@ namespace smt { ast_manager& m = get_manager(); (void)m; r.m_graph.compute_zero_edge_scc(scc_id); - for (unsigned i = 0, j = 0; !ctx.inconsistent() && i < scc_id.size(); ++i) { + int start = ctx.get_random_value(); + for (unsigned idx = 0, j = 0; !ctx.inconsistent() && idx < scc_id.size(); ++idx) { + unsigned i = (start + idx) % scc_id.size(); if (scc_id[i] == -1) { continue; } @@ -336,8 +342,10 @@ namespace smt { r.m_graph.find_shortest_zero_edge_path(i, j, timestamp, r); r.m_graph.find_shortest_zero_edge_path(j, i, timestamp, r); literal_vector const& lits = r.m_explanation; - TRACE("special_relations", ctx.display_literals_verbose(tout << mk_pp(x->get_owner(), m) << " = " << mk_pp(y->get_owner(), m) << " ", lits) << "\n";); - eq_justification js(ctx.mk_justification(theory_axiom_justification(get_id(), ctx.get_region(), lits.size(), lits.c_ptr()))); + TRACE("special_relations", ctx.display_literals_verbose(tout << mk_pp(x->get_owner(), m) << " = " << mk_pp(y->get_owner(), m) << "\n", lits) << "\n";); + IF_VERBOSE(20, ctx.display_literals_verbose(verbose_stream() << mk_pp(x->get_owner(), m) << " = " << mk_pp(y->get_owner(), m) << "\n", lits) << "\n";); + eq_justification js(ctx.mk_justification(ext_theory_eq_propagation_justification(get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), 0, nullptr, + x, y))); ctx.assign_eq(x, y, js); } } From f1a2e875b594391a2491aacc56d70f283a3fed80 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 5 Apr 2019 03:06:41 -0700 Subject: [PATCH 131/156] fixing #2217 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 7 +++++++ src/ast/datatype_decl_plugin.cpp | 6 +++++- src/smt/smt_context.h | 1 - src/smt/theory_datatype.cpp | 8 +++++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 76e87775a..9276c3502 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10379,3 +10379,10 @@ def Range(lo, hi, ctx = None): # Special Relations +def PartialOrder(n, s): + ctx = s.ctx + return FuncDeclRef(Z3_mk_partial_order(ctx, n, s.ast), ctx) + +def TreeOrder(n, s): + ctx = s.ctx + return FuncDeclRef(Z3_mk_tree_order(ctx, n, s.ast), ctx) diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index e8f276aa8..c98cc06f8 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -290,6 +290,7 @@ namespace datatype { obj_map S; for (unsigned i = 0; i + 1 < num_parameters; ++i) { sort* r = to_sort(parameters[i + 1].get_ast()); + TRACE("datatype", tout << "inserting " << mk_ismt2_pp(r, *m_manager) << " " << r->get_num_elements() << "\n";); S.insert(d->params()[i], r->get_num_elements()); } sort_size ts = d->sort_size()->eval(S); @@ -693,7 +694,7 @@ namespace datatype { } param_size::size* util::get_sort_size(sort_ref_vector const& params, sort* s) { - if (params.empty()) { + if (params.empty() && !is_datatype(s)) { return param_size::size::mk_offset(s->get_num_elements()); } if (is_datatype(s)) { @@ -742,6 +743,7 @@ namespace datatype { map already_found; map szs; + TRACE("datatype", for (auto const& s : names) tout << s << " "; tout << "\n";); svector todo(names); status st; while (!todo.empty()) { @@ -780,6 +782,7 @@ namespace datatype { todo.pop_back(); already_found.insert(s, BLACK); if (is_infinite) { + TRACE("datatype", tout << "infinite " << s << "\n";); d.set_sort_size(param_size::size::mk_offset(sort_size::mk_infinite())); continue; } @@ -792,6 +795,7 @@ namespace datatype { } s_add.push_back(param_size::size::mk_times(s_mul)); } + TRACE("datatype", tout << "set sort size " << s << "\n";); d.set_sort_size(param_size::size::mk_plus(s_add)); } } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 42111c591..d4d4ec6fb 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -923,7 +923,6 @@ namespace smt { failure m_last_search_failure; ptr_vector m_incomplete_theories; //!< theories that failed to produce a model bool m_searching; - bool m_propagating; unsigned m_num_conflicts; unsigned m_num_conflicts_since_restart; unsigned m_num_conflicts_since_lemma_gc; diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index dd1b302e1..d084191be 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -372,7 +372,13 @@ namespace smt { // // If the theory variable is not created for 'a', then a wrong model will be generated. TRACE("datatype", tout << "apply_sort_cnstr: #" << n->get_owner_id() << "\n";); - TRACE("datatype_bug", tout << "apply_sort_cnstr:\n" << mk_pp(n->get_owner(), get_manager()) << "\n";); + TRACE("datatype_bug", + tout << "apply_sort_cnstr:\n" << mk_pp(n->get_owner(), get_manager()) << " "; + tout << m_util.is_datatype(s) << " "; + if (m_util.is_datatype(s)) tout << "is-infinite: " << s->is_infinite() << " "; + if (m_util.is_datatype(s)) tout << "attached: " << is_attached_to_var(n) << " "; + tout << "\n"; + ); if ((get_context().has_quantifiers() || (m_util.is_datatype(s) && !s->is_infinite())) && !is_attached_to_var(n)) { mk_var(n); } From 6cc82f0401835add8fac7a56390fb56faca3a7ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 7 Apr 2019 07:23:32 -0700 Subject: [PATCH 132/156] enable theory_lra on non-linear reals if configured to use Signed-off-by: Nikolaj Bjorner --- src/smt/smt_setup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 5f916899b..74b9328e8 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -838,7 +838,7 @@ namespace smt { m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); break; case AS_NEW_ARITH: - if (st.m_num_non_linear != 0) + if (st.m_num_non_linear != 0 && st.m_has_int) m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); else setup_lra_arith(); From 45595af6655c3ba2d44e211025a22762aab72a48 Mon Sep 17 00:00:00 2001 From: Max Zinkus Date: Tue, 9 Apr 2019 12:35:04 -0400 Subject: [PATCH 133/156] Require verbosity=1 to log parallel tactic progress --- src/solver/parallel_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp index d820dbd9b..0e20ab7a9 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -351,7 +351,7 @@ private: } void log_branches(lbool status) { - IF_VERBOSE(0, verbose_stream() << "(tactic.parallel :progress " << m_progress << "% "; + IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :progress " << m_progress << "% "; if (status == l_true) verbose_stream() << ":status sat"; if (status == l_undef) verbose_stream() << ":status unknown"; if (m_num_unsat > 0) verbose_stream() << " :closed " << m_num_unsat << "@" << m_last_depth; From ae982c5225f82d0b9848bd1764523353f5422d10 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 9 Apr 2019 22:47:01 +0200 Subject: [PATCH 134/156] add tc and trc functionals for binary relations Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 2 + src/api/api_special_relations.cpp | 58 ++---- src/api/z3_api.h | 43 +++- src/ast/special_relations_decl_plugin.cpp | 21 +- src/ast/special_relations_decl_plugin.h | 30 ++- src/model/model_pp.cpp | 3 +- src/smt/diff_logic.h | 9 +- src/smt/smt_context.h | 4 + src/smt/smt_theory.cpp | 4 + src/smt/smt_theory.h | 11 + src/smt/theory_array.cpp | 6 + src/smt/theory_special_relations.cpp | 234 ++++++++++++++++++++-- src/smt/theory_special_relations.h | 13 +- 13 files changed, 361 insertions(+), 77 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 999ebab6b..5c945d168 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1058,6 +1058,8 @@ extern "C" { case OP_SPECIAL_RELATION_PO : return Z3_OP_SPECIAL_RELATION_PO; case OP_SPECIAL_RELATION_PLO: return Z3_OP_SPECIAL_RELATION_PLO; case OP_SPECIAL_RELATION_TO : return Z3_OP_SPECIAL_RELATION_TO; + case OP_SPECIAL_RELATION_TC : return Z3_OP_SPECIAL_RELATION_TC; + case OP_SPECIAL_RELATION_TRC : return Z3_OP_SPECIAL_RELATION_TRC; default: UNREACHABLE(); } } diff --git a/src/api/api_special_relations.cpp b/src/api/api_special_relations.cpp index e852c2b34..497ac15e0 100644 --- a/src/api/api_special_relations.cpp +++ b/src/api/api_special_relations.cpp @@ -27,47 +27,7 @@ Revision History: extern "C" { -#if 0 - bool Z3_API Z3_is_sr_lo(Z3_context c, Z3_ast s) { - Z3_TRY; - LOG_Z3_is_sr_lo(c, s); - RESET_ERROR_CODE(); - RETURN_Z3(mk_c(c)->sr_util().is_lo( to_expr(s) )); - Z3_CATCH_RETURN(false); - } - bool Z3_API Z3_is_sr_po(Z3_context c, Z3_ast s) { - Z3_TRY; - LOG_Z3_is_sr_po(c, s); - RESET_ERROR_CODE(); - RETURN_Z3(mk_c(c)->sr_util().is_po( to_expr(s) )); - Z3_CATCH_RETURN(false); - } - - bool Z3_API Z3_is_sr_po_ao(Z3_context c, Z3_ast s) { - Z3_TRY; - LOG_Z3_is_sr_po_ao(c, s); - RESET_ERROR_CODE(); - RETURN_Z3(mk_c(c)->sr_util().is_po_ao( to_expr(s) )); - Z3_CATCH_RETURN(false); - } - - bool Z3_API Z3_is_sr_plo(Z3_context c, Z3_ast s) { - Z3_TRY; - LOG_Z3_is_sr_plo(c, s); - RESET_ERROR_CODE(); - RETURN_Z3(mk_c(c)->sr_util().is_plo( to_expr(s) )); - Z3_CATCH_RETURN(false); - } - - bool Z3_API Z3_is_sr_to(Z3_context c, Z3_ast s) { - Z3_TRY; - LOG_Z3_is_sr_to(c, s); - RESET_ERROR_CODE(); - RETURN_Z3(mk_c(c)->sr_util().is_to( to_expr(s) )); - Z3_CATCH_RETURN(false); - } -#endif #define MK_TERN(NAME, FID) \ Z3_ast Z3_API NAME(Z3_context c, unsigned index, Z3_ast a, Z3_ast b) { \ LOG_ ##NAME(c, index, a, b); \ @@ -85,4 +45,22 @@ extern "C" { MK_TERN(Z3_mk_piecewise_linear_order, OP_SPECIAL_RELATION_PLO); MK_TERN(Z3_mk_tree_order, OP_SPECIAL_RELATION_TO); + +#define MK_DECL(NAME, FID) \ + Z3_func_decl Z3_API NAME(Z3_context c,Z3_func_decl f) { \ + Z3_TRY; \ + LOG_ ##NAME(c, f); \ + RESET_ERROR_CODE(); \ + ast_manager & m = mk_c(c)->m(); \ + func_decl* _f = to_func_decl(f); \ + parameter param(_f); \ + sort* domain[2] = { _f->get_domain(0), _f->get_domain(1) }; \ + func_decl * d = m.mk_func_decl(mk_c(c)->get_special_relations_fid(), FID, 1, ¶m, 2, domain); \ + mk_c(c)->save_ast_trail(d); \ + RETURN_Z3(of_func_decl(d)); \ + Z3_CATCH_RETURN(nullptr); \ +} + + MK_DECL(Z3_mk_transitive_closure, OP_SPECIAL_RELATION_TC); + MK_DECL(Z3_mk_transitive_reflexive_closure, OP_SPECIAL_RELATION_TRC); }; diff --git a/src/api/z3_api.h b/src/api/z3_api.h index e1fe76175..78a6247ed 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -875,6 +875,18 @@ typedef enum - Z3_OP_PB_EQ: Generalized Pseudo-Boolean equality constraint. Example 2*x + 1*y + 2*z + 1*u = 4 + - Z3_OP_SPECIAL_RELATION_LO: A relation that is a total linear order + + - Z3_OP_SPECIAL_RELATION_PO: A relation that is a partial order + + - Z3_OP_SPECIAL_RELATION_PLO: A relation that is a piecewise linear order + + - Z3_OP_SPECIAL_RELATION_TO: A relation that is a tree order + + - Z3_OP_SPECIAL_RELATION_TC: Transitive closure of a relation + + - Z3_OP_SPECIAL_RELATION_TRC: Transitive reflexive closure of a relation + - Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN: Floating-point rounding mode RNE - Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY: Floating-point rounding mode RNA @@ -1101,12 +1113,6 @@ typedef enum { Z3_OP_BUREM_I, Z3_OP_BSMOD_I, - // Special relations - Z3_OP_SPECIAL_RELATION_LO, - Z3_OP_SPECIAL_RELATION_PO, - Z3_OP_SPECIAL_RELATION_PLO, - Z3_OP_SPECIAL_RELATION_TO, - // Proofs Z3_OP_PR_UNDEF = 0x500, Z3_OP_PR_TRUE, @@ -1216,8 +1222,17 @@ typedef enum { Z3_OP_PB_GE, Z3_OP_PB_EQ, + // Special relations + Z3_OP_SPECIAL_RELATION_LO = 0xa000, + Z3_OP_SPECIAL_RELATION_PO, + Z3_OP_SPECIAL_RELATION_PLO, + Z3_OP_SPECIAL_RELATION_TO, + Z3_OP_SPECIAL_RELATION_TC, + Z3_OP_SPECIAL_RELATION_TRC, + + // Floating-Point Arithmetic - Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN, + Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN = 0xb000, Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY, Z3_OP_FPA_RM_TOWARD_POSITIVE, Z3_OP_FPA_RM_TOWARD_NEGATIVE, @@ -3643,6 +3658,20 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_tree_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); + /** + \brief create transitive closure of binary relation. + + def_API('Z3_mk_transitive_closure', FUNC_DECL ,(_in(CONTEXT), _in(FUNC_DECL))) + */ + Z3_func_decl Z3_API Z3_mk_transitive_closure(Z3_context c,Z3_func_decl f); + + /** + \brief create transitive reflexive closure of binary relation. + + def_API('Z3_mk_transitive_reflexive_closure', FUNC_DECL ,(_in(CONTEXT), _in(FUNC_DECL))) + */ + Z3_func_decl Z3_API Z3_mk_transitive_reflexive_closure(Z3_context c,Z3_func_decl f); + /*@}*/ /** @name Quantifiers */ diff --git a/src/ast/special_relations_decl_plugin.cpp b/src/ast/special_relations_decl_plugin.cpp index 6dd0af1b4..b1254552c 100644 --- a/src/ast/special_relations_decl_plugin.cpp +++ b/src/ast/special_relations_decl_plugin.cpp @@ -21,13 +21,13 @@ Revision History: #include "ast/ast.h" #include "ast/special_relations_decl_plugin.h" - - special_relations_decl_plugin::special_relations_decl_plugin(): m_lo("linear-order"), m_po("partial-order"), m_plo("piecewise-linear-order"), - m_to("tree-order") + m_to("tree-order"), + m_tc("transitive-closure"), + m_trc("transitive-reflexive-closure") {} func_decl * special_relations_decl_plugin::mk_func_decl( @@ -39,9 +39,12 @@ func_decl * special_relations_decl_plugin::mk_func_decl( return nullptr; } if (domain[0] != domain[1]) { - m_manager->raise_exception("argument sort missmatch"); + m_manager->raise_exception("argument sort missmatch. The two arguments should have the same sort"); return nullptr; } + if (!range) { + range = m_manager->mk_bool_sort(); + } func_decl_info info(m_family_id, k, num_parameters, parameters); symbol name; switch(k) { @@ -49,8 +52,11 @@ func_decl * special_relations_decl_plugin::mk_func_decl( case OP_SPECIAL_RELATION_LO: name = m_lo; break; case OP_SPECIAL_RELATION_PLO: name = m_plo; break; case OP_SPECIAL_RELATION_TO: name = m_to; break; + case OP_SPECIAL_RELATION_TC: name = m_tc; break; + case OP_SPECIAL_RELATION_TRC: name = m_trc; break; + case OP_SPECIAL_RELATION_NEXT: name = symbol("next"); break; } - return m_manager->mk_func_decl(name, arity, domain, m_manager->mk_bool_sort(), info); + return m_manager->mk_func_decl(name, arity, domain, range, info); } void special_relations_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { @@ -59,6 +65,8 @@ void special_relations_decl_plugin::get_op_names(svector & op_name op_names.push_back(builtin_name(m_lo.bare_str(), OP_SPECIAL_RELATION_LO)); op_names.push_back(builtin_name(m_plo.bare_str(), OP_SPECIAL_RELATION_PLO)); op_names.push_back(builtin_name(m_to.bare_str(), OP_SPECIAL_RELATION_TO)); + op_names.push_back(builtin_name(m_tc.bare_str(), OP_SPECIAL_RELATION_TC)); + op_names.push_back(builtin_name(m_trc.bare_str(), OP_SPECIAL_RELATION_TRC)); } } @@ -68,6 +76,9 @@ sr_property special_relations_util::get_property(func_decl* f) const { case OP_SPECIAL_RELATION_LO: return sr_lo; case OP_SPECIAL_RELATION_PLO: return sr_plo; case OP_SPECIAL_RELATION_TO: return sr_to; + case OP_SPECIAL_RELATION_TC: return sr_tc; + case OP_SPECIAL_RELATION_TRC: return sr_trc; + case OP_SPECIAL_RELATION_NEXT: return sr_none; default: UNREACHABLE(); return sr_po; diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index 5926057f5..8e32e9817 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -28,6 +28,9 @@ enum special_relations_op_kind { OP_SPECIAL_RELATION_PO, OP_SPECIAL_RELATION_PLO, OP_SPECIAL_RELATION_TO, + OP_SPECIAL_RELATION_TC, + OP_SPECIAL_RELATION_TRC, + OP_SPECIAL_RELATION_NEXT, LAST_SPECIAL_RELATIONS_OP }; @@ -36,6 +39,8 @@ class special_relations_decl_plugin : public decl_plugin { symbol m_po; symbol m_plo; symbol m_to; + symbol m_tc; + symbol m_trc; public: special_relations_decl_plugin(); @@ -65,11 +70,17 @@ enum sr_property { sr_to = 0x01 | 0x02 | 0x04 | 0x10, // right-tree sr_plo = 0x01 | 0x02 | 0x04 | 0x08 | 0x10, // piecewise linear order sr_lo = 0x01 | 0x02 | 0x04 | 0x20, // linear order + sr_tc = 0x40, // transitive closure of relation + sr_trc = 0x42 // transitive reflexive closure of relation }; class special_relations_util { ast_manager& m; family_id m_fid; + func_decl* mk_rel_decl(func_decl* f, decl_kind k) { + parameter p(f); SASSERT(f->get_arity() == 2); + return m.mk_func_decl(m_fid, k, 1, &p, 2, f->get_domain(), f->get_range()); + } public: special_relations_util(ast_manager& m) : m(m), m_fid(m.get_family_id("special_relations")) {} @@ -78,15 +89,26 @@ public: sr_property get_property(func_decl* f) const; sr_property get_property(app* e) const { return get_property(e->get_decl()); } - func_decl* mk_to_decl(func_decl* f) { parameter p(f); SASSERT(f->get_arity() == 2); return m.mk_func_decl(m_fid, OP_SPECIAL_RELATION_TO, 1, &p, 2, f->get_domain(), f->get_range()); } - func_decl* mk_po_decl(func_decl* f) { parameter p(f); SASSERT(f->get_arity() == 2); return m.mk_func_decl(m_fid, OP_SPECIAL_RELATION_PO, 1, &p, 2, f->get_domain(), f->get_range()); } - func_decl* mk_plo_decl(func_decl* f) { parameter p(f); SASSERT(f->get_arity() == 2); return m.mk_func_decl(m_fid, OP_SPECIAL_RELATION_PLO, 1, &p, 2, f->get_domain(), f->get_range()); } - func_decl* mk_lo_decl(func_decl* f) { parameter p(f); SASSERT(f->get_arity() == 2); return m.mk_func_decl(m_fid, OP_SPECIAL_RELATION_LO, 1, &p, 2, f->get_domain(), f->get_range()); } + func_decl* mk_to_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_TO); } + func_decl* mk_po_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_PO); } + func_decl* mk_plo_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_PLO); } + func_decl* mk_lo_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_LO); } + func_decl* mk_tc_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_TC); } + func_decl* mk_trc_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_TRC); } + func_decl* mk_next(func_decl* f) { + sort* s = f->get_domain(0); + sort* domain[2] = { s, s }; + parameter p(f); SASSERT(f->get_arity() == 2); + return m.mk_func_decl(m_fid, OP_SPECIAL_RELATION_NEXT, 1, &p, 2, domain, s); + } bool is_lo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_LO); } bool is_po(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO); } bool is_plo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PLO); } bool is_to(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TO); } + bool is_tc(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TC); } + bool is_trc(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TRC); } + bool is_next(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_NEXT); } app * mk_lo (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_LO, arg1, arg2); } app * mk_po (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO, arg1, arg2); } diff --git a/src/model/model_pp.cpp b/src/model/model_pp.cpp index 08d63803b..727d2e1da 100644 --- a/src/model/model_pp.cpp +++ b/src/model/model_pp.cpp @@ -30,8 +30,7 @@ static void display_uninterp_sorts(std::ostream & out, model_core const & md) { for (unsigned i = 0; i < sz; i++) { sort * s = md.get_uninterpreted_sort(i); out << "(define-sort " << mk_pp(s, m); - ptr_vector const & univ = md.get_universe(s); - for (expr* e : univ) { + for (expr* e : md.get_universe(s)) { out << " " << mk_ismt2_pp(e, m); } out << ")\n"; diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 85330de87..0e8bd47e1 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -468,8 +468,9 @@ public: // That is init_var receives the id as an argument. void init_var(dl_var v) { TRACE("diff_logic_bug", tout << "init_var " << v << "\n";); - SASSERT(static_cast(v) >= m_out_edges.size() || - m_out_edges[v].empty()); + if (static_cast(v) < m_out_edges.size() && (!m_out_edges[v].empty() || !m_in_edges[v].empty())) { + return; + } SASSERT(check_invariant()); while (static_cast(v) >= m_out_edges.size()) { m_assignment .push_back(numeral()); @@ -649,6 +650,10 @@ public: } bool can_reach(dl_var src, dl_var dst) { + if (static_cast(src) >= m_out_edges.size() || + static_cast(dst) >= m_out_edges.size()) { + return false; + } uint_set target, visited; target.insert(dst); return reachable(src, target, visited, dst); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index d4d4ec6fb..cd909cf03 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -301,6 +301,10 @@ namespace smt { return m_expr2bool_var[n->get_id()]; } + bool_var get_bool_var(enode const * n) const { + return get_bool_var(n->get_owner()); + } + bool_var get_bool_var_of_id(unsigned id) const { return m_expr2bool_var[id]; } diff --git a/src/smt/smt_theory.cpp b/src/smt/smt_theory.cpp index b791991f2..9fec0e1d3 100644 --- a/src/smt/smt_theory.cpp +++ b/src/smt/smt_theory.cpp @@ -188,5 +188,9 @@ namespace smt { out.flush(); } + theory_var theory::get_th_var(expr* e) const { + return get_th_var(get_context().get_enode(e)); + } + }; diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index 92aa87163..e5798f6c3 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -66,6 +66,13 @@ namespace smt { m_var2enode.push_back(n); return v; } + + theory_var get_th_var(expr* e) const; + + theory_var get_th_var(enode* n) const { + return n->get_th_var(get_id()); + } + public: /** @@ -317,6 +324,10 @@ namespace smt { return m_var2enode[v]; } + app * get_expr(theory_var v) const { + return get_enode(v)->get_owner(); + } + /** \brief Return the equivalence class representative of the given theory variable. diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index ffeb1b274..3398d0894 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -297,6 +297,12 @@ namespace smt { void theory_array::new_eq_eh(theory_var v1, theory_var v2) { m_find.merge(v1, v2); +#if 0 + if (is_lambda(get_enode(v1)->get_owner()) || + is_lambda(get_enode(v2)->get_owner())) { + instantiate_extensionality(get_enode(v1), get_enode(v2)); + } +#endif } void theory_array::new_diseq_eh(theory_var v1, theory_var v2) { diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index d7ba74a87..0995458d5 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -85,7 +85,8 @@ namespace smt { theory_special_relations::theory_special_relations(ast_manager& m): theory(m.mk_family_id("special_relations")), - m_util(m) { + m_util(m), + m_can_propagate(false) { } theory_special_relations::~theory_special_relations() { @@ -99,6 +100,7 @@ namespace smt { bool theory_special_relations::internalize_atom(app * atm, bool gate_ctx) { SASSERT(m_util.is_special_relation(atm)); relation* r = 0; + ast_manager& m = get_manager(); if (!m_relations.find(atm->get_decl(), r)) { r = alloc(relation, m_util.get_property(atm), atm->get_decl()); m_relations.insert(atm->get_decl(), r); @@ -113,7 +115,7 @@ namespace smt { ctx.set_var_theory(v, get_id()); atom* a = alloc(atom, v, *r, v0, v1); m_atoms.push_back(a); - TRACE("special_relations", tout << mk_pp(atm, get_manager()) << " : bv" << v << " v" << a->v1() << " v" << a->v2() << ' ' << gate_ctx << "\n";); + TRACE("special_relations", tout << mk_pp(atm, m) << " : bv" << v << " v" << a->v1() << " v" << a->v2() << ' ' << gate_ctx << "\n";); m_bool_var2atom.insert(v, a); return true; } @@ -127,14 +129,15 @@ namespace smt { theory_var v = n->get_th_var(get_id()); if (null_theory_var == v) { v = theory::mk_var(n); + TRACE("special_relations", tout << "v" << v << " := " << mk_pp(e, get_manager()) << "\n";); ctx.attach_th_var(n, this, v); } return v; } void theory_special_relations::new_eq_eh(theory_var v1, theory_var v2) { - app* t1 = get_enode(v1)->get_owner(); - app* t2 = get_enode(v2)->get_owner(); + app* t1 = get_expr(v1); + app* t2 = get_expr(v2); literal eq = mk_eq(t1, t2, false); for (auto const& kv : m_relations) { relation& r = *kv.m_value; @@ -162,7 +165,6 @@ namespace smt { for (auto const& kv : m_relations) { if (extract_equalities(*kv.m_value)) { new_equality = true; - //return FC_CONTINUE; } if (get_context().inconsistent()) { return FC_CONTINUE; @@ -224,6 +226,137 @@ namespace smt { return res; } + + lbool theory_special_relations::final_check_tc(relation& r) { + // + // Ensure that Rxy -> TC(R)xy + // + func_decl* tcf = r.decl(); + func_decl* f = to_func_decl(tcf->get_parameter(0).get_ast()); + context& ctx = get_context(); + ast_manager& m = get_manager(); + bool new_assertion = false; + graph r_graph; + for (enode* n : ctx.enodes_of(f)) { + literal lit = ctx.enode2literal(n); + if (l_true == ctx.get_assignment(lit)) { + expr* e = ctx.bool_var2expr(lit.var()); + expr* arg1 = to_app(e)->get_arg(0); + expr* arg2 = to_app(e)->get_arg(1); + expr_ref tc_app(m.mk_app(tcf, arg1, arg2), m); + enode* tcn = ensure_enode(tc_app); + if (ctx.get_assignment(tcn) != l_true) { + literal consequent = ctx.get_literal(tc_app); + justification* j = ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), 1, &lit, consequent)); + TRACE("special_relations", tout << "propagate: " << tc_app << "\n";); + ctx.assign(consequent, j); + new_assertion = true; + } + else { + theory_var v1 = get_representative(get_th_var(arg1)); + theory_var v2 = get_representative(get_th_var(arg2)); + r_graph.init_var(v1); + r_graph.init_var(v2); + literal_vector ls; + r_graph.enable_edge(r_graph.add_edge(v1, v2, s_integer(0), ls)); + } + } + } + + // + // Ensure that TC(R)xy -> Rxz1 Rz1z2 .. Rzky + // + // if not Rxy and no path in graph: + // Find z reachable from x and u that an creach y, such that not Ruz is not forced + // introduce Ruy + // If no such element for infinite domains, then introduce z + // Rxz & Rzy + // For finite domains extract conflict. + // TBD: + // - infinite/large domain version is naive. + // It could be made fair by finding cut-points between x and y + // quantified axioms could prevent + // + unsigned sz = r.m_asserted_atoms.size(); + for (unsigned i = 0; i < sz; ++i) { + atom& a = *r.m_asserted_atoms[i]; + if (a.phase()) { + bool_var bv = a.var(); + TRACE("special_relations", tout << bv << " is positive\n";); + expr* arg1 = get_expr(a.v1()); + expr* arg2 = get_expr(a.v2()); + + // we need reachability in the R graph not R* graph + theory_var r1 = get_representative(a.v1()); + theory_var r2 = get_representative(a.v2()); + if (r_graph.can_reach(r1, r2)) { + TRACE("special_relations", + tout << a.v1() << ": " << mk_pp(arg1, m) << " -> " + << a.v2() << ": " << mk_pp(arg2, m) << " is positive reachable\n"; + r.m_graph.display(tout); + ); + continue; + } + expr_ref f_app(m.mk_app(f, arg1, arg2), m); + enode* fn = ensure_enode(f_app); + literal f_lit = ctx.get_literal(f_app); + switch (ctx.get_assignment(f_lit)) { + case l_true: + UNREACHABLE(); + // it should already be the case that v1 and reach v2 in the graph. + // whenever f(n1, n2) is asserted. + break; + case l_false: { + // TBD: perhaps replace by recursion unfolding similar to theory_rec_fun + expr_ref next(m.mk_app(m_util.mk_next(f), arg1, arg2), m); + expr_ref a2next(m.mk_app(f, arg1, next), m); + expr_ref next2b(m.mk_app(tcf, next, arg2), m); + expr_ref next_b(m.mk_app(f, next, arg2), m); + ensure_enode(a2next); + ensure_enode(next2b); + ensure_enode(next_b); + literal next2b_l = ctx.get_literal(next2b); + literal a2next_l = ctx.get_literal(a2next); + if (ctx.get_assignment(next2b_l) == l_true && ctx.get_assignment(a2next_l) == l_true) { + break; + } + ctx.mk_th_axiom(get_id(), ~literal(bv), f_lit, a2next_l); + ctx.mk_th_axiom(get_id(), ~literal(bv), f_lit, next2b_l); + expr* nxt = next; + while (m_util.is_next(nxt)) { + expr* left = to_app(nxt)->get_arg(0); + expr* right = to_app(nxt)->get_arg(1); + ctx.assign(~mk_eq(next, left, false), nullptr); + ctx.assign(~mk_eq(next, right, false), nullptr); + nxt = left; + } + ctx.set_true_first_flag(ctx.get_literal(next_b).var()); + new_assertion = true; + break; + } + case l_undef: + ctx.set_true_first_flag(bv); + TRACE("special_relations", tout << f_app << " is undefined\n";); + new_assertion = true; + break; + } + } + } + if (new_assertion) { + TRACE("special_relations", tout << "new assertion\n";); + return l_false; + } + return final_check_po(r); + } + + lbool theory_special_relations::final_check_trc(relation& r) { + // + // reflexivity is enforced from propagation. + // enforce transitivity. + // + return final_check_tc(r); + } + lbool theory_special_relations::final_check_to(relation& r) { uint_set visited, target; for (atom* ap : r.m_asserted_atoms) { @@ -310,15 +443,29 @@ namespace smt { case sr_to: res = final_check_to(r); break; + case sr_tc: + res = final_check_tc(r); + break; + case sr_trc: + res = final_check_trc(r); + break; default: UNREACHABLE(); res = l_undef; + break; } - TRACE("special_relations", r.display(*this, tout);); + TRACE("special_relations", r.display(*this, tout << res << "\n");); return res; } bool theory_special_relations::extract_equalities(relation& r) { + switch (r.m_property) { + case sr_tc: + case sr_trc: + return false; + default: + break; + } bool new_eq = false; int_vector scc_id; u_map roots; @@ -374,14 +521,47 @@ namespace smt { lbool theory_special_relations::propagate_po(atom& a) { lbool res = l_true; - relation& r = a.get_relation(); if (a.phase()) { + relation& r = a.get_relation(); r.m_uf.merge(a.v1(), a.v2()); res = enable(a); } return res; } + /** + \brief ensure that reflexivity is enforce for Transitive Reflexive closures + !TRC(R)xy => x != y + */ + lbool theory_special_relations::propagate_trc(atom& a) { + lbool res = l_true; + if (a.phase()) { + VERIFY(a.enable()); + relation& r = a.get_relation(); + r.m_uf.merge(a.v1(), a.v2()); + } + else { + literal lit(a.var(), true); + context& ctx = get_context(); + expr* arg1 = get_expr(a.v1()); + expr* arg2 = get_expr(a.v2()); + literal consequent = ~mk_eq(arg1, arg2, false); + justification* j = ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), 1, &lit, consequent)); + ctx.assign(consequent, j); + res = l_false; + } + return res; + } + + lbool theory_special_relations::propagate_tc(atom& a) { + if (a.phase()) { + VERIFY(a.enable()); + relation& r = a.get_relation(); + r.m_uf.merge(a.v1(), a.v2()); + } + return l_true; + } + lbool theory_special_relations::final_check_po(relation& r) { for (atom* ap : r.m_asserted_atoms) { atom& a = *ap; @@ -392,6 +572,7 @@ namespace smt { unsigned timestamp = r.m_graph.get_timestamp(); bool found_path = r.m_graph.find_shortest_reachable_path(a.v1(), a.v2(), timestamp, r); if (found_path) { + TRACE("special_relations", tout << "check po conflict\n";); r.m_explanation.push_back(a.explanation()); set_conflict(r); return l_false; @@ -401,6 +582,15 @@ namespace smt { return l_true; } + void theory_special_relations::propagate() { + if (m_can_propagate) { + for (auto const& kv : m_relations) { + propagate(*kv.m_value); + } + m_can_propagate = false; + } + } + lbool theory_special_relations::propagate(relation& r) { lbool res = l_true; while (res == l_true && r.m_asserted_qhead < r.m_asserted_atoms.size()) { @@ -415,6 +605,12 @@ namespace smt { case sr_po: res = propagate_po(a); break; + case sr_tc: + res = propagate_trc(a); + break; + case sr_trc: + res = propagate_tc(a); + break; default: if (a.phase()) { res = enable(a); @@ -439,9 +635,11 @@ namespace smt { atom* a = m_bool_var2atom[v]; a->set_phase(is_true); a->get_relation().m_asserted_atoms.push_back(a); + m_can_propagate = true; } void theory_special_relations::push_scope_eh() { + theory::push_scope_eh(); for (auto const& kv : m_relations) { kv.m_value->push(); } @@ -455,6 +653,7 @@ namespace smt { unsigned new_lvl = m_atoms_lim.size() - num_scopes; del_atoms(m_atoms_lim[new_lvl]); m_atoms_lim.shrink(new_lvl); + theory::pop_scope_eh(num_scopes); } void theory_special_relations::del_atoms(unsigned old_size) { @@ -562,7 +761,7 @@ namespace smt { func_interp* fi = alloc(func_interp, m, 1); for (unsigned i = 0; i < sz; ++i) { s_integer val = r.m_graph.get_assignment(i); - expr* arg = get_enode(i)->get_owner(); + expr* arg = get_expr(i); fi->insert_new_entry(&arg, arith.mk_numeral(val.to_rational(), true)); } TRACE("special_relations", r.m_graph.display(tout);); @@ -584,7 +783,7 @@ namespace smt { unsigned sz = r.m_graph.get_num_nodes(); for (unsigned i = 0; i < sz; ++i) { unsigned val = r.m_uf.find(i); - expr* arg = get_enode(i)->get_owner(); + expr* arg = get_expr(i); fi->insert_new_entry(&arg, arith.mk_numeral(rational(val), true)); } fi->set_else(arith.mk_numeral(rational(0), true)); @@ -606,7 +805,7 @@ namespace smt { hifn = m.mk_fresh_func_decl("hi", 1, ty, arith.mk_int()); unsigned sz = g.get_num_nodes(); for (unsigned i = 0; i < sz; ++i) { - expr* arg = get_enode(i)->get_owner(); + expr* arg = get_expr(i); lofi->insert_new_entry(&arg, arith.mk_numeral(rational(lo[i]), true)); hifi->insert_new_entry(&arg, arith.mk_numeral(rational(hi[i]), true)); } @@ -655,7 +854,7 @@ namespace smt { */ - void theory_special_relations::init_model_po(relation& r, model_generator& mg) { + void theory_special_relations::init_model_po(relation& r, model_generator& mg, bool is_reflexive) { ast_manager& m = get_manager(); sort* s = r.m_decl->get_domain(0); datatype_util dt(m); @@ -735,6 +934,7 @@ namespace smt { connected_rec_body = m.mk_ite(m.mk_app(snd, Sr), ST, Sc); } var* vars3[3] = { xV, yV, SV }; + IF_VERBOSE(0, verbose_stream() << connected_rec_body << "\n"); p.set_definition(rep, c2, 3, vars3, connected_rec_body); // r.m_decl(x,y) -> snd(connected2(x,y,nil)) @@ -743,7 +943,11 @@ namespace smt { x = xV, y = yV; func_interp* fi = alloc(func_interp, m, 2); - fi->set_else(m.mk_app(snd, m.mk_app(conn2, x, y, m.mk_app(cons, x, m.mk_const(nil))))); + expr_ref pred(m.mk_app(snd, m.mk_app(conn2, x, y, m.mk_app(cons, y, m.mk_const(nil)))), m); + if (is_reflexive) { + pred = m.mk_or(pred, m.mk_eq(x, y)); + } + fi->set_else(pred); mg.get_model().register_decl(r.decl(), fi); } @@ -881,7 +1085,11 @@ namespace smt { init_model_to(*kv.m_value, m); break; case sr_po: - init_model_po(*kv.m_value, m); + init_model_po(*kv.m_value, m, true); + break; + case sr_tc: + break; + case sr_trc: break; default: // other 28 combinations of 0x1F diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 81a968e54..dfcc3adb9 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -130,6 +130,7 @@ namespace smt { unsigned_vector m_atoms_lim; obj_map m_relations; bool_var2atom m_bool_var2atom; + bool m_can_propagate; void del_atoms(unsigned old_size); @@ -138,6 +139,8 @@ namespace smt { lbool final_check_lo(relation& r); lbool final_check_plo(relation& r); lbool final_check_to(relation& r); + lbool final_check_tc(relation& r); + lbool final_check_trc(relation& r); lbool propagate(relation& r); lbool enable(atom& a); bool extract_equalities(relation& r); @@ -145,6 +148,8 @@ namespace smt { void set_conflict(relation& r); lbool propagate_plo(atom& a); lbool propagate_po(atom& a); + lbool propagate_tc(atom& a); + lbool propagate_trc(atom& a); theory_var mk_var(expr* e); void count_children(graph const& g, unsigned_vector& num_children); void ensure_strict(graph& g); @@ -155,7 +160,7 @@ namespace smt { expr_ref mk_interval(relation& r, model_generator& mg, unsigned_vector & lo, unsigned_vector& hi); void init_model_lo(relation& r, model_generator& m); void init_model_to(relation& r, model_generator& m); - void init_model_po(relation& r, model_generator& m); + void init_model_po(relation& r, model_generator& m, bool is_reflexive); void init_model_plo(relation& r, model_generator& m); bool is_neighbour_edge(graph const& g, edge_id id) const; bool is_strict_neighbour_edge(graph const& g, edge_id id) const; @@ -174,7 +179,7 @@ namespace smt { theory * mk_fresh(context * new_ctx) override; bool internalize_atom(app * atom, bool gate_ctx) override; - bool internalize_term(app * term) override { UNREACHABLE(); return false; } + bool internalize_term(app * term) override { return false; } void new_eq_eh(theory_var v1, theory_var v2) override; void new_diseq_eh(theory_var v1, theory_var v2) override {} bool use_diseqs() const override { return false; } @@ -189,8 +194,8 @@ namespace smt { void collect_statistics(::statistics & st) const override; model_value_proc * mk_value(enode * n, model_generator & mg) override; void init_model(model_generator & m) override; - bool can_propagate() override { return false; } - void propagate() override {} + bool can_propagate() override { return m_can_propagate; } + void propagate() override; void display(std::ostream & out) const override; }; From 182039eb44c392078000002f31e8da2ca924b97a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 9 Apr 2019 22:58:43 +0200 Subject: [PATCH 135/156] add tc and trc functionals for binary relations Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 8 ++++++++ src/api/python/z3/z3.py | 18 ++++++++++++------ src/api/z3_api.h | 12 ++++++++++-- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 8df43d477..fd7cb3a90 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -633,6 +633,14 @@ namespace z3 { symbol name() const { Z3_symbol s = Z3_get_decl_name(ctx(), *this); check_error(); return symbol(ctx(), s); } Z3_decl_kind decl_kind() const { return Z3_get_decl_kind(ctx(), *this); } + func_decl transitive_closure(func_decl const& f) { + Z3_func_decl tc = Z3_mk_transitive_closure(ctx(), *this); check_error(); return func_decl(ctx(), tc); + } + + func_decl transitive_reflexive_closure(func_decl const& f) { + Z3_func_decl tc = Z3_mk_transitive_reflexive_closure(ctx(), *this); check_error(); return func_decl(ctx(), tc); + } + bool is_const() const { return arity() == 0; } expr operator()() const; diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 9276c3502..242c73e67 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10379,10 +10379,16 @@ def Range(lo, hi, ctx = None): # Special Relations -def PartialOrder(n, s): - ctx = s.ctx - return FuncDeclRef(Z3_mk_partial_order(ctx, n, s.ast), ctx) +def TransitiveClosure(f): + """Given a binary relation R, such that the two arguments have the same sort + create the transitive closure relation R+. + The transitive closure R+ is a new relation. + """ + return FuncDeclRef(Z3_mk_transitive_closure(f.ctx_ref(), f.ast), f.ctx) -def TreeOrder(n, s): - ctx = s.ctx - return FuncDeclRef(Z3_mk_tree_order(ctx, n, s.ast), ctx) +def TransitiveReflexiveClosure(f): + """Given a binary relation R, such that the two arguments have the same sort + create the transitive reflexive closure relation R*. + The transitive reflexive closure R* is a new relation. + """ + return FuncDeclRef(Z3_mk_transitive_reflexive_closure(f.ctx_ref(), f.ast), f.ctx) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 78a6247ed..e154eaf50 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3661,16 +3661,24 @@ extern "C" { /** \brief create transitive closure of binary relation. + \pre f is a binary relation, such that the two arguments have the same sorts. + + The resulting relation f+ represents the transitive closure of f. + def_API('Z3_mk_transitive_closure', FUNC_DECL ,(_in(CONTEXT), _in(FUNC_DECL))) */ - Z3_func_decl Z3_API Z3_mk_transitive_closure(Z3_context c,Z3_func_decl f); + Z3_func_decl Z3_API Z3_mk_transitive_closure(Z3_context c, Z3_func_decl f); /** \brief create transitive reflexive closure of binary relation. + \pre f is a binary relation, such that the two arguments have the same sorts. + + The resulting relation f* represents the transitive-reflexive closure of f. + def_API('Z3_mk_transitive_reflexive_closure', FUNC_DECL ,(_in(CONTEXT), _in(FUNC_DECL))) */ - Z3_func_decl Z3_API Z3_mk_transitive_reflexive_closure(Z3_context c,Z3_func_decl f); + Z3_func_decl Z3_API Z3_mk_transitive_reflexive_closure(Z3_context c, Z3_func_decl f); /*@}*/ From 9c9cd5ebf7916037dd8fd1a27e1dacb04d49bfa8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 10 Apr 2019 00:57:50 +0200 Subject: [PATCH 136/156] add tc and trc functionals for binary relations Signed-off-by: Nikolaj Bjorner --- src/ast/special_relations_decl_plugin.cpp | 5 ++ src/smt/theory_special_relations.cpp | 74 ++++++++++++++++++++--- src/smt/theory_special_relations.h | 3 +- 3 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/ast/special_relations_decl_plugin.cpp b/src/ast/special_relations_decl_plugin.cpp index b1254552c..149f37aef 100644 --- a/src/ast/special_relations_decl_plugin.cpp +++ b/src/ast/special_relations_decl_plugin.cpp @@ -45,6 +45,9 @@ func_decl * special_relations_decl_plugin::mk_func_decl( if (!range) { range = m_manager->mk_bool_sort(); } + if (!m_manager->is_bool(range) && k != OP_SPECIAL_RELATION_NEXT) { + m_manager->raise_exception("range type is expected to be Boolean for special relations"); + } func_decl_info info(m_family_id, k, num_parameters, parameters); symbol name; switch(k) { @@ -67,6 +70,8 @@ void special_relations_decl_plugin::get_op_names(svector & op_name op_names.push_back(builtin_name(m_to.bare_str(), OP_SPECIAL_RELATION_TO)); op_names.push_back(builtin_name(m_tc.bare_str(), OP_SPECIAL_RELATION_TC)); op_names.push_back(builtin_name(m_trc.bare_str(), OP_SPECIAL_RELATION_TRC)); + // next is an internal skolem function used for unfolding a relation R to satisfy a relation that + // is asserted for the transitive closure of R. } } diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 0995458d5..72d48148f 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -97,9 +97,41 @@ namespace smt { return alloc(theory_special_relations, new_ctx->get_manager()); } + /** + \brief for term := next(next(a,b),c) for relation f + assert f(term,c) or term != c + assert f(term,c) or term != next(a,b) + assert f(term,c) or term != b + assert f(term,c) or term != a + */ + bool theory_special_relations::internalize_term(app * term) { + if (m_util.is_next(term)) { + return false; + } + mk_var(term); + context& ctx = get_context(); + ast_manager& m = get_manager(); + func_decl* f = to_func_decl(term->get_decl()->get_parameter(0).get_ast()); + expr* src = term->get_arg(0); + expr* dst = term->get_arg(1); + expr_ref f_rel(m.mk_app(f, src, dst), m); + literal f_lit = ctx.get_literal(f_rel); + src = term; + while (m_util.is_next(src)) { + dst = to_app(src)->get_arg(1); + src = to_app(src)->get_arg(0); + ctx.mk_th_axiom(get_id(), f_lit, ~mk_eq(term, src, false)); + ctx.mk_th_axiom(get_id(), f_lit, ~mk_eq(term, dst, false)); + } + return true; + } + bool theory_special_relations::internalize_atom(app * atm, bool gate_ctx) { SASSERT(m_util.is_special_relation(atm)); relation* r = 0; + if (m_util.is_next(atm)) { + return internalize_term(atm); + } ast_manager& m = get_manager(); if (!m_relations.find(atm->get_decl(), r)) { r = alloc(relation, m_util.get_property(atm), atm->get_decl()); @@ -267,28 +299,27 @@ namespace smt { // Ensure that TC(R)xy -> Rxz1 Rz1z2 .. Rzky // // if not Rxy and no path in graph: - // Find z reachable from x and u that an creach y, such that not Ruz is not forced - // introduce Ruy - // If no such element for infinite domains, then introduce z - // Rxz & Rzy - // For finite domains extract conflict. - // TBD: - // - infinite/large domain version is naive. - // It could be made fair by finding cut-points between x and y - // quantified axioms could prevent + // Introduce next(x,y), such that + // TC(R)(x,y) => R(x,y) or TR(R)(next(x,y),y) & R(x,next(x,y)) + // + // next(x,y) is fresh unless R(x,y) is true: + // R(x,y) or x != next(x,y) + // R(x,y) or y != next(x,y) // unsigned sz = r.m_asserted_atoms.size(); for (unsigned i = 0; i < sz; ++i) { atom& a = *r.m_asserted_atoms[i]; if (a.phase()) { bool_var bv = a.var(); - TRACE("special_relations", tout << bv << " is positive\n";); expr* arg1 = get_expr(a.v1()); expr* arg2 = get_expr(a.v2()); // we need reachability in the R graph not R* graph theory_var r1 = get_representative(a.v1()); theory_var r2 = get_representative(a.v2()); + if (r.m_property == sr_trc && r1 == r2) { + continue; + } if (r_graph.can_reach(r1, r2)) { TRACE("special_relations", tout << a.v1() << ": " << mk_pp(arg1, m) << " -> " @@ -307,7 +338,18 @@ namespace smt { // whenever f(n1, n2) is asserted. break; case l_false: { + // + // Add the axioms: + // TC(R)(x,y) => R(x,y) or TC(R)(next(x,y),y) + // TC(R)(x,y) => R(x,y) or R(x,next(x,y)) + // R(x,y) or next(x,y) != x + // R(x,y) or next(x,y) != y, + // and recursively on all next subterms of x. + // Add the literal R(next(x,y),y) - set case split preference to true. + // // TBD: perhaps replace by recursion unfolding similar to theory_rec_fun + // + expr_ref next(m.mk_app(m_util.mk_next(f), arg1, arg2), m); expr_ref a2next(m.mk_app(f, arg1, next), m); expr_ref next2b(m.mk_app(tcf, next, arg2), m); @@ -1072,6 +1114,10 @@ namespace smt { } } + bool theory_special_relations::has_quantifiers() { + return get_context().has_quantifiers(); + } + void theory_special_relations::init_model(model_generator & m) { for (auto const& kv : m_relations) { switch (kv.m_value->m_property) { @@ -1088,8 +1134,16 @@ namespace smt { init_model_po(*kv.m_value, m, true); break; case sr_tc: + if (has_quantifiers()) { + // model construction for transitive relation is reserved for quantified formulas where + // TC(R) may be needed to perform MBQI + init_model_po(*kv.m_value, m, true); + } break; case sr_trc: + if (has_quantifiers()) { + init_model_po(*kv.m_value, m, true); + } break; default: // other 28 combinations of 0x1F diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index dfcc3adb9..0f69bc1d9 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -172,6 +172,7 @@ namespace smt { void collect_asserted_po_atoms(vector< std::pair >& atoms) const; void display_atom(std::ostream & out, atom& a) const; + bool has_quantifiers(); public: theory_special_relations(ast_manager& m); @@ -179,7 +180,7 @@ namespace smt { theory * mk_fresh(context * new_ctx) override; bool internalize_atom(app * atom, bool gate_ctx) override; - bool internalize_term(app * term) override { return false; } + bool internalize_term(app * term) override; void new_eq_eh(theory_var v1, theory_var v2) override; void new_diseq_eh(theory_var v1, theory_var v2) override {} bool use_diseqs() const override { return false; } From 7d43a4bca5c11668d4a96872c96eb6af1d9fb253 Mon Sep 17 00:00:00 2001 From: Kate Date: Wed, 10 Apr 2019 13:49:26 +0100 Subject: [PATCH 137/156] Fix Makefile generation for the OCaml api --- 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 b8fbf9a45..3b71af793 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2255,7 +2255,7 @@ class MLComponent(Component): for m in self.modules: ff = os.path.join(src_dir, m + '.ml') ft = os.path.join(self.sub_dir, m + '.cmx') - out.write('%s: %s %s\n' % (ft, ff, cmos)) + out.write('%s: %s %s %s\n' % (ft, ff, cmos, cmxs)) out.write('\t%s -I %s -o %s -c %s\n' % (OCAMLOPTF, self.sub_dir, ft, ff)) cmxs = cmxs + ' ' + ft From 82658d1bce334b315b416ebd115d26552403812f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 10 Apr 2019 10:50:42 -0700 Subject: [PATCH 138/156] na Signed-off-by: Nikolaj Bjorner --- src/smt/theory_dense_diff_logic_def.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index 369209e49..88e95e517 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -55,10 +55,8 @@ namespace smt { bool is_int = m_autil.is_int(n->get_owner()); m_is_int.push_back(is_int); m_f_targets.push_back(f_target()); - typename matrix::iterator it = m_matrix.begin(); - typename matrix::iterator end = m_matrix.end(); - for (; it != end; ++it) { - it->push_back(cell()); + for (auto& rows : m_matrix) { + rows.push_back(cell()); } m_matrix.push_back(row()); row & r = m_matrix.back(); @@ -367,10 +365,8 @@ namespace smt { m_is_int.shrink(old_num_vars); m_f_targets.shrink(old_num_vars); m_matrix.shrink(old_num_vars); - typename matrix::iterator it = m_matrix.begin(); - typename matrix::iterator end = m_matrix.end(); - for (; it != end; ++it) { - it->shrink(old_num_vars); + for (auto& cells : m_matrix) { + cells.shrink(old_num_vars); } } } From 0d06bc5990f8a751a683beee38871c5ec260d520 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 10 Apr 2019 17:12:24 -0700 Subject: [PATCH 139/156] change to more digestible recursive function definition Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 154 +++++++++++++++++++++------ 1 file changed, 124 insertions(+), 30 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 72d48148f..4e3205c4f 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -893,6 +893,16 @@ namespace smt { let (S, c) = connected1(x, y, u, w, S) if c then (S, true) else connected2(x, y, S, edges) + +Take 2: + connected(A, dst, S) = + if A = nil then false else + if member(dst, A) then true else + let (A',S') = next1(a1, b1, A, next1(a2, b2, A, ... S, (nil, nil))) + connected(A', dst, S') + + next1(a, b, A, S, (A',S')) = + if member(a, A) and not member(b, S) then (cons(b, A'), cons(b, S')) else (A',S') */ @@ -905,40 +915,117 @@ namespace smt { func_decl_ref nil(m), is_nil(m), cons(m), is_cons(m), hd(m), tl(m); sort_ref listS(dt.mk_list_datatype(s, symbol("List"), cons, is_cons, hd, tl, nil, is_nil), m); func_decl_ref fst(m), snd(m), pair(m); + + expr* T = m.mk_true(); + expr* F = m.mk_false(); + + func_decl* memf, *nextf, *connectedf; + + { + sort* dom[2] = { s, listS }; + recfun::promise_def mem = p.ensure_def(symbol("member"), 2, dom, m.mk_bool_sort()); + memf = mem.get_def()->get_decl(); + + var_ref xV(m.mk_var(1, s), m); + var_ref SV(m.mk_var(0, listS), m); + var_ref yV(m), vV(m), wV(m); + + expr* x = xV, *S = SV; + expr_ref mem_body(m); + mem_body = m.mk_ite(m.mk_app(is_nil, S), + F, + m.mk_ite(m.mk_eq(m.mk_app(hd, S), x), + T, + m.mk_app(memf, x, m.mk_app(tl, S)))); + recfun_replace rep(m); + var* vars[2] = { xV, SV }; + p.set_definition(rep, mem, 2, vars, mem_body); + } + + +#if 1 + sort_ref tup(dt.mk_pair_datatype(listS, listS, fst, snd, pair), m); + + { + sort* dom[5] = { s, s, listS, listS, tup }; + recfun::promise_def nxt = p.ensure_def(symbol("next"), 5, dom, tup); + nextf = nxt.get_def()->get_decl(); + + expr_ref next_body(m); + var_ref aV(m.mk_var(4, s), m); + var_ref bV(m.mk_var(3, s), m); + var_ref AV(m.mk_var(2, listS), m); + var_ref SV(m.mk_var(1, listS), m); + var_ref tupV(m.mk_var(0, tup), m); + expr* a = aV, *b = bV, *A = AV, *S = SV, *t = tupV; + next_body = m.mk_ite(m.mk_and(m.mk_app(memf, a, A), m.mk_not(m.mk_app(memf, b, S))), + m.mk_app(pair, m.mk_app(cons, b, m.mk_app(fst, t)), m.mk_app(cons, b, m.mk_app(snd, t))), + t); + + recfun_replace rep(m); + var* vars[5] = { aV, bV, AV, SV, tupV }; + p.set_definition(rep, nxt, 5, vars, next_body); + } + + { + sort* dom[3] = { listS, s, listS }; + recfun::promise_def connected = p.ensure_def(symbol("connected"), 3, dom, m.mk_bool_sort()); + connectedf = connected.get_def()->get_decl(); + var_ref AV(m.mk_var(2, listS), m); + var_ref dstV(m.mk_var(1, s), m); + var_ref SV(m.mk_var(0, listS), m); + expr* A = AV, *dst = dstV, *S = SV; + expr_ref connected_body(m); + + connected_body = m.mk_app(pair, m.mk_const(nil), m.mk_const(nil)); + + for (atom* ap : r.m_asserted_atoms) { + atom& a = *ap; + if (!a.phase()) continue; + SASSERT(get_context().get_assignment(a.var()) == l_true); + expr* x = get_enode(a.v1())->get_root()->get_owner(); + expr* y = get_enode(a.v2())->get_root()->get_owner(); + expr* cb = connected_body; + expr* args[5] = { x, y, A, S, cb }; + connected_body = m.mk_app(nextf, 5, args); + } + + recfun_replace rep(m); + var* vars[3] = { AV, dstV, SV }; + p.set_definition(rep, connected, 3, vars, connected_body); + } + + { + var_ref xV(m.mk_var(0, s), m); + var_ref yV(m.mk_var(1, s), m); + expr* x = xV, *y = yV; + + func_interp* fi = alloc(func_interp, m, 2); + expr_ref pred(m.mk_app(connectedf, m.mk_app(cons, x, m.mk_const(nil)), y, m.mk_const(nil)), m); + if (is_reflexive) { + pred = m.mk_or(pred, m.mk_eq(x, y)); + } + fi->set_else(pred); + mg.get_model().register_decl(r.decl(), fi); + } + +#else sort_ref tup(dt.mk_pair_datatype(listS, m.mk_bool_sort(), fst, snd, pair), m); sort* dom1[5] = { s, s, listS, s, s }; recfun::promise_def c1 = p.ensure_def(symbol("connected1"), 5, dom1, tup); sort* dom2[3] = { s, s, listS }; recfun::promise_def c2 = p.ensure_def(symbol("connected2"), 3, dom2, tup); - sort* dom3[2] = { s, listS }; - recfun::promise_def mem = p.ensure_def(symbol("member"), 2, dom3, m.mk_bool_sort()); - var_ref xV(m.mk_var(1, s), m); - var_ref SV(m.mk_var(0, listS), m); - var_ref yV(m), vV(m), wV(m); - expr* x = xV, *S = SV; - expr* T = m.mk_true(); - expr* F = m.mk_false(); - func_decl* memf = mem.get_def()->get_decl(); func_decl* conn1 = c1.get_def()->get_decl(); func_decl* conn2 = c2.get_def()->get_decl(); - expr_ref mem_body(m); - mem_body = m.mk_ite(m.mk_app(is_nil, S), - F, - m.mk_ite(m.mk_eq(m.mk_app(hd, S), x), - T, - m.mk_app(memf, x, m.mk_app(tl, S)))); - recfun_replace rep(m); - var* vars[2] = { xV, SV }; - p.set_definition(rep, mem, 2, vars, mem_body); - - xV = m.mk_var(4, s); - yV = m.mk_var(3, s); - SV = m.mk_var(2, listS); - vV = m.mk_var(1, s); - wV = m.mk_var(0, s); + + var_ref xV(m.mk_var(4, s), m); + var_ref yV(m.mk_var(3, s), m); + var_ref SV(m.mk_var(2, listS), m); + var_ref vV(m.mk_var(1, s), m); + var_ref wV(m.mk_var(0, s), m); expr* y = yV, *v = vV, *w = wV; - x = xV, S = SV; + expr* x = xV, *S = SV; expr_ref ST(m.mk_app(pair, S, T), m); expr_ref SF(m.mk_app(pair, S, F), m); @@ -952,8 +1039,11 @@ namespace smt { m.mk_ite(m.mk_app(memf, w, S), SF, m.mk_app(conn2, w, y, m.mk_app(cons, w, S))))); - var* vars2[5] = { xV, yV, SV, vV, wV }; - p.set_definition(rep, c1, 5, vars2, connected_body); + { + var* vars2[5] = { xV, yV, SV, vV, wV }; + recfun_replace rep(m); + p.set_definition(rep, c1, 5, vars2, connected_body); + } xV = m.mk_var(2, s); yV = m.mk_var(1, s); @@ -975,9 +1065,11 @@ namespace smt { expr* Sc = m.mk_app(conn1, 5, args); connected_rec_body = m.mk_ite(m.mk_app(snd, Sr), ST, Sc); } - var* vars3[3] = { xV, yV, SV }; - IF_VERBOSE(0, verbose_stream() << connected_rec_body << "\n"); - p.set_definition(rep, c2, 3, vars3, connected_rec_body); + { + var* vars3[3] = { xV, yV, SV }; + recfun_replace rep(m); + p.set_definition(rep, c2, 3, vars3, connected_rec_body); + } // r.m_decl(x,y) -> snd(connected2(x,y,nil)) xV = m.mk_var(0, s); @@ -991,6 +1083,8 @@ namespace smt { } fi->set_else(pred); mg.get_model().register_decl(r.decl(), fi); + +#endif } From 551d72b294069ee3966622fc184874ca808c6c65 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Apr 2019 04:09:59 +0200 Subject: [PATCH 140/156] na Signed-off-by: Nikolaj Bjorner --- src/ast/recfun_decl_plugin.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index bdaf3fcf0..0feb21d86 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -238,6 +238,7 @@ namespace recfun { while (! stack.empty()) { expr * e = stack.back(); stack.pop_back(); + TRACEFN("unfold: " << mk_pp(e, m)); if (m.is_ite(e)) { // need to do a case split on `e`, forking the search space @@ -257,6 +258,7 @@ namespace recfun { if (b.to_split != nullptr) { // split one `ite`, which will lead to distinct (sets of) cases app * ite = b.to_split->ite; + TRACEFN("split: " << mk_pp(ite, m)); expr* c = nullptr, *th = nullptr, *el = nullptr; VERIFY(m.is_ite(ite, c, th, el)); @@ -287,6 +289,7 @@ namespace recfun { // substitute, to get rid of `ite` terms expr_ref case_rhs = subst(rhs); + TRACEFN("case_rhs: " << case_rhs); for (unsigned i = 0; i < conditions.size(); ++i) { conditions[i] = subst(conditions.get(i)); } From 6fee9b90cb6fb4a82b9d3acd26ab31dd1c7c7273 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Apr 2019 11:39:27 -0700 Subject: [PATCH 141/156] fix model generation for tc/po Signed-off-by: Nikolaj Bjorner --- src/ast/recfun_decl_plugin.cpp | 17 +-- src/ast/recfun_decl_plugin.h | 10 +- src/ast/rewriter/bool_rewriter.cpp | 33 +++-- src/ast/rewriter/bool_rewriter.h | 1 + src/ast/rewriter/bool_rewriter_params.pyg | 1 + src/ast/special_relations_decl_plugin.cpp | 6 +- src/ast/special_relations_decl_plugin.h | 8 -- src/model/model.cpp | 15 ++- src/model/model_evaluator.cpp | 27 ++-- src/model/model_smt2_pp.cpp | 2 +- src/smt/theory_special_relations.cpp | 157 ++++++---------------- src/smt/theory_special_relations.h | 11 +- src/util/obj_hashtable.h | 6 +- 13 files changed, 117 insertions(+), 177 deletions(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 0feb21d86..ba1b4f171 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -50,7 +50,7 @@ namespace recfun { } def::def(ast_manager &m, family_id fid, symbol const & s, - unsigned arity, sort* const * domain, sort* range) + unsigned arity, sort* const * domain, sort* range, bool is_generated) : m(m), m_name(s), m_domain(m, arity, domain), m_range(range, m), m_vars(m), m_cases(), @@ -59,7 +59,8 @@ namespace recfun { m_fid(fid) { SASSERT(arity == get_arity()); - func_decl_info info(fid, OP_FUN_DEFINED); + parameter p(is_generated); + func_decl_info info(fid, OP_FUN_DEFINED, 1, &p); m_decl = m.mk_func_decl(s, arity, domain, range, info); } @@ -315,8 +316,8 @@ namespace recfun { util::~util() { } - def * util::decl_fun(symbol const& name, unsigned n, sort *const * domain, sort * range) { - return alloc(def, m(), m_fid, name, n, domain, range); + def * util::decl_fun(symbol const& name, unsigned n, sort *const * domain, sort * range, bool is_generated) { + return alloc(def, m(), m_fid, name, n, domain, range, is_generated); } @@ -386,15 +387,15 @@ namespace recfun { return *(m_util.get()); } - promise_def plugin::mk_def(symbol const& name, unsigned n, sort *const * params, sort * range) { - def* d = u().decl_fun(name, n, params, range); + promise_def plugin::mk_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated) { + def* d = u().decl_fun(name, n, params, range, is_generated); SASSERT(!m_defs.contains(d->get_decl())); m_defs.insert(d->get_decl(), d); return promise_def(&u(), d); } - promise_def plugin::ensure_def(symbol const& name, unsigned n, sort *const * params, sort * range) { - def* d = u().decl_fun(name, n, params, range); + promise_def plugin::ensure_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated) { + def* d = u().decl_fun(name, n, params, range, is_generated); def* d2 = nullptr; if (m_defs.find(d->get_decl(), d2)) { dealloc(d2); diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index 33b5294f5..786ea9dd2 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -108,7 +108,7 @@ namespace recfun { expr_ref m_rhs; //!< definition family_id m_fid; - def(ast_manager &m, family_id fid, symbol const & s, unsigned arity, sort *const * domain, sort* range); + def(ast_manager &m, family_id fid, symbol const & s, unsigned arity, sort *const * domain, sort* range, bool is_generated); // compute cases for a function, given its RHS (possibly containing `ite`). void compute_cases(replace& subst, is_immediate_pred &, @@ -147,6 +147,7 @@ namespace recfun { class plugin : public decl_plugin { typedef obj_map def_map; typedef obj_map case_def_map; + mutable scoped_ptr m_util; def_map m_defs; // function->def @@ -171,9 +172,9 @@ namespace recfun { 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); + promise_def mk_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated = false); - promise_def ensure_def(symbol const& name, unsigned n, sort *const * params, sort * range); + promise_def ensure_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated = false); void set_definition(replace& r, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs); @@ -216,6 +217,7 @@ namespace recfun { 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_generated(func_decl* f) const { return is_defined(f) && f->get_parameter(0).get_int() == 1; } 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; } @@ -223,7 +225,7 @@ namespace recfun { bool has_defs() const { return m_plugin->has_defs(); } //has_def(f)); diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index d26c55fda..ce29eb9cf 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -24,6 +24,7 @@ void bool_rewriter::updt_params(params_ref const & _p) { bool_rewriter_params p(_p); m_flat = p.flat(); m_elim_and = p.elim_and(); + m_elim_ite = p.elim_ite(); m_local_ctx = p.local_ctx(); m_local_ctx_limit = p.local_ctx_limit(); m_blast_distinct = p.blast_distinct(); @@ -797,48 +798,52 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re result = c; return BR_DONE; } - mk_or(c, e, result); - return BR_DONE; + if (m_elim_ite) { + mk_or(c, e, result); + return BR_DONE; + } } if (m().is_false(t)) { if (m().is_true(e)) { mk_not(c, result); return BR_DONE; } - expr_ref tmp(m()); - mk_not(c, tmp); - mk_and(tmp, e, result); - return BR_DONE; + if (m_elim_ite) { + expr_ref tmp(m()); + mk_not(c, tmp); + mk_and(tmp, e, result); + return BR_DONE; + } } - if (m().is_true(e)) { + if (m().is_true(e) && m_elim_ite) { expr_ref tmp(m()); mk_not(c, tmp); mk_or(tmp, t, result); return BR_DONE; } - if (m().is_false(e)) { + if (m().is_false(e) && m_elim_ite) { mk_and(c, t, result); return BR_DONE; } - if (c == e) { + if (c == e && m_elim_ite) { mk_and(c, t, result); return BR_DONE; } - if (c == t) { + if (c == t && m_elim_ite) { mk_or(c, e, result); return BR_DONE; } - if (m().is_complement_core(t, e)) { // t = not(e) + if (m().is_complement_core(t, e) && m_elim_ite) { // t = not(e) mk_eq(c, t, result); return BR_DONE; } - if (m().is_complement_core(e, t)) { // e = not(t) + if (m().is_complement_core(e, t) && m_elim_ite) { // e = not(t) mk_eq(c, t, result); return BR_DONE; } } - if (m().is_ite(t) && m_ite_extra_rules) { + if (m().is_ite(t) && m_ite_extra_rules && m_elim_ite) { // (ite c1 (ite c2 t1 t2) t1) ==> (ite (and c1 (not c2)) t2 t1) if (e == to_app(t)->get_arg(1)) { expr_ref not_c2(m()); @@ -891,7 +896,7 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re } } - if (m().is_ite(e) && m_ite_extra_rules) { + if (m().is_ite(e) && m_ite_extra_rules && m_elim_ite) { // (ite c1 t1 (ite c2 t1 t2)) ==> (ite (or c1 c2) t1 t2) if (t == to_app(e)->get_arg(1)) { expr_ref new_c(m()); diff --git a/src/ast/rewriter/bool_rewriter.h b/src/ast/rewriter/bool_rewriter.h index 83ece2aae..cd122791b 100644 --- a/src/ast/rewriter/bool_rewriter.h +++ b/src/ast/rewriter/bool_rewriter.h @@ -59,6 +59,7 @@ class bool_rewriter { bool m_ite_extra_rules; unsigned m_local_ctx_limit; unsigned m_local_ctx_cost; + bool m_elim_ite; br_status mk_flat_and_core(unsigned num_args, expr * const * args, expr_ref & result); br_status mk_flat_or_core(unsigned num_args, expr * const * args, expr_ref & result); diff --git a/src/ast/rewriter/bool_rewriter_params.pyg b/src/ast/rewriter/bool_rewriter_params.pyg index 531bf4db9..85583cbca 100644 --- a/src/ast/rewriter/bool_rewriter_params.pyg +++ b/src/ast/rewriter/bool_rewriter_params.pyg @@ -4,6 +4,7 @@ def_module_params(module_name='rewriter', params=(("ite_extra_rules", BOOL, False, "extra ite simplifications, these additional simplifications may reduce size locally but increase globally"), ("flat", BOOL, True, "create nary applications for and,or,+,*,bvadd,bvmul,bvand,bvor,bvxor"), ("elim_and", BOOL, False, "conjunctions are rewritten using negation and disjunctions"), + ('elim_ite', BOOL, True, "eliminate ite in favor of and/or"), ("local_ctx", BOOL, False, "perform local (i.e., cheap) context simplifications"), ("local_ctx_limit", UINT, UINT_MAX, "limit for applying local context simplifier"), ("blast_distinct", BOOL, False, "expand a distinct predicate into a quadratic number of disequalities"), diff --git a/src/ast/special_relations_decl_plugin.cpp b/src/ast/special_relations_decl_plugin.cpp index 149f37aef..2b280b28a 100644 --- a/src/ast/special_relations_decl_plugin.cpp +++ b/src/ast/special_relations_decl_plugin.cpp @@ -45,7 +45,7 @@ func_decl * special_relations_decl_plugin::mk_func_decl( if (!range) { range = m_manager->mk_bool_sort(); } - if (!m_manager->is_bool(range) && k != OP_SPECIAL_RELATION_NEXT) { + if (!m_manager->is_bool(range)) { m_manager->raise_exception("range type is expected to be Boolean for special relations"); } func_decl_info info(m_family_id, k, num_parameters, parameters); @@ -57,7 +57,6 @@ func_decl * special_relations_decl_plugin::mk_func_decl( case OP_SPECIAL_RELATION_TO: name = m_to; break; case OP_SPECIAL_RELATION_TC: name = m_tc; break; case OP_SPECIAL_RELATION_TRC: name = m_trc; break; - case OP_SPECIAL_RELATION_NEXT: name = symbol("next"); break; } return m_manager->mk_func_decl(name, arity, domain, range, info); } @@ -70,8 +69,6 @@ void special_relations_decl_plugin::get_op_names(svector & op_name op_names.push_back(builtin_name(m_to.bare_str(), OP_SPECIAL_RELATION_TO)); op_names.push_back(builtin_name(m_tc.bare_str(), OP_SPECIAL_RELATION_TC)); op_names.push_back(builtin_name(m_trc.bare_str(), OP_SPECIAL_RELATION_TRC)); - // next is an internal skolem function used for unfolding a relation R to satisfy a relation that - // is asserted for the transitive closure of R. } } @@ -83,7 +80,6 @@ sr_property special_relations_util::get_property(func_decl* f) const { case OP_SPECIAL_RELATION_TO: return sr_to; case OP_SPECIAL_RELATION_TC: return sr_tc; case OP_SPECIAL_RELATION_TRC: return sr_trc; - case OP_SPECIAL_RELATION_NEXT: return sr_none; default: UNREACHABLE(); return sr_po; diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index 8e32e9817..f7a3b963d 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -30,7 +30,6 @@ enum special_relations_op_kind { OP_SPECIAL_RELATION_TO, OP_SPECIAL_RELATION_TC, OP_SPECIAL_RELATION_TRC, - OP_SPECIAL_RELATION_NEXT, LAST_SPECIAL_RELATIONS_OP }; @@ -95,12 +94,6 @@ public: func_decl* mk_lo_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_LO); } func_decl* mk_tc_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_TC); } func_decl* mk_trc_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_TRC); } - func_decl* mk_next(func_decl* f) { - sort* s = f->get_domain(0); - sort* domain[2] = { s, s }; - parameter p(f); SASSERT(f->get_arity() == 2); - return m.mk_func_decl(m_fid, OP_SPECIAL_RELATION_NEXT, 1, &p, 2, domain, s); - } bool is_lo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_LO); } bool is_po(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO); } @@ -108,7 +101,6 @@ public: bool is_to(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TO); } bool is_tc(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TC); } bool is_trc(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TRC); } - bool is_next(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_NEXT); } app * mk_lo (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_LO, arg1, arg2); } app * mk_po (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO, arg1, arg2); } diff --git a/src/model/model.cpp b/src/model/model.cpp index aa3976cb9..15344b35d 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -170,7 +170,11 @@ struct model::top_sort : public ::top_sort { top_sort(ast_manager& m): m_rewrite(m) - {} + { + params_ref p; + p.set_bool("elim_ite", false); + m_rewrite.updt_params(p); + } void add_occurs(func_decl* f) { m_occur_count.insert(f, occur_count(f) + 1); @@ -428,7 +432,12 @@ expr_ref model::cleanup_expr(top_sort& ts, expr* e, unsigned current_partition) } #endif else { - new_t = ts.m_rewrite.mk_app(f, args.size(), args.c_ptr()); + if (m.is_ite(f)) { + new_t = m.mk_app(f, args.size(), args.c_ptr()); + } + else { + new_t = ts.m_rewrite.mk_app(f, args.size(), args.c_ptr()); + } } if (t != new_t.get()) trail.push_back(new_t); @@ -443,7 +452,7 @@ expr_ref model::cleanup_expr(top_sort& ts, expr* e, unsigned current_partition) break; } } - + ts.m_rewrite(cache[e], new_t); return new_t; } diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 229ed875e..a060be8cf 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -99,7 +99,11 @@ struct evaluator_cfg : public default_rewriter_cfg { bool evaluate(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { func_interp * fi = m_model.get_func_interp(f); - return (fi != nullptr) && eval_fi(fi, num, args, result); + bool r = (fi != nullptr) && eval_fi(fi, num, args, result); + CTRACE("model_evaluator", r, tout << "reduce_app " << f->get_name() << "\n"; + for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m) << "\n"; + tout << "---->\n" << mk_ismt2_pp(result, m) << "\n";); + return r; } // Try to use the entries to quickly evaluate the fi @@ -138,6 +142,7 @@ struct evaluator_cfg : public default_rewriter_cfg { br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + TRACE("model_evaluator", tout << f->get_name() << "\n";); result_pr = nullptr; family_id fid = f->get_family_id(); bool is_uninterp = fid != null_family_id && m.get_plugin(fid)->is_considered_uninterpreted(f); @@ -188,7 +193,7 @@ struct evaluator_cfg : public default_rewriter_cfg { } return m_b_rw.mk_app_core(f, num, args, result); } - + CTRACE("model_evaluator", st != BR_FAILED, tout << result << "\n";); if (fid == m_a_rw.get_fid()) st = m_a_rw.mk_app_core(f, num, args, result); else if (fid == m_bv_rw.get_fid()) @@ -208,21 +213,19 @@ struct evaluator_cfg : public default_rewriter_cfg { st = BR_DONE; } else if (evaluate(f, num, args, result)) { - TRACE("model_evaluator", tout << "reduce_app " << f->get_name() << "\n"; - for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m) << "\n"; - tout << "---->\n" << mk_ismt2_pp(result, m) << "\n";); st = BR_REWRITE1; } - if (st == BR_FAILED && !m.is_builtin_family_id(fid)) + CTRACE("model_evaluator", st != BR_FAILED, tout << result << "\n";); + if (st == BR_FAILED && !m.is_builtin_family_id(fid)) { st = evaluate_partial_theory_func(f, num, args, result, result_pr); + CTRACE("model_evaluator", st != BR_FAILED, tout << result << "\n";); + } if (st == BR_DONE && is_app(result)) { app* a = to_app(result); if (evaluate(a->get_decl(), a->get_num_args(), a->get_args(), result)) { st = BR_REWRITE1; } } -#if 1 - TRACE("model_evaluator", tout << st << " " << num << " " << m_ar.is_as_array(f) << " " << m_model_completion << "\n";); if (st == BR_FAILED && num == 0 && m_ar.is_as_array(f) && m_model_completion) { func_decl* g = nullptr; VERIFY(m_ar.is_as_array(f, g)); @@ -253,7 +256,6 @@ struct evaluator_cfg : public default_rewriter_cfg { return BR_DONE; } } -#endif CTRACE("model_evaluator", st != BR_FAILED, tout << result << "\n";); return st; @@ -296,7 +298,7 @@ struct evaluator_cfg : public default_rewriter_cfg { return false; } def = fi->get_interp(); - SASSERT(def != 0); + SASSERT(def != nullptr); return true; } @@ -320,7 +322,7 @@ struct evaluator_cfg : public default_rewriter_cfg { br_status evaluate_partial_theory_func(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - SASSERT(f != 0); + SASSERT(f != nullptr); SASSERT(!m.is_builtin_family_id(f->get_family_id())); result = nullptr; result_pr = nullptr; @@ -433,8 +435,7 @@ struct evaluator_cfg : public default_rewriter_cfg { args_table table2(DEFAULT_HASHTABLE_INITIAL_CAPACITY, ah, ae); // stores with smaller index take precedence - for (unsigned i = stores1.size(); i > 0; ) { - --i; + for (unsigned i = stores1.size(); i-- > 0; ) { table1.insert(stores1[i].c_ptr()); } diff --git a/src/model/model_smt2_pp.cpp b/src/model/model_smt2_pp.cpp index b2a4f02aa..196843de4 100644 --- a/src/model/model_smt2_pp.cpp +++ b/src/model/model_smt2_pp.cpp @@ -196,7 +196,7 @@ 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)) { + if (recfun_util.is_defined(f) && !recfun_util.is_generated(f)) { continue; } func_interp * f_i = md.get_func_interp(f); diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 4e3205c4f..03f11dd26 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -34,6 +34,15 @@ Notes: namespace smt { + func_decl* theory_special_relations::relation::next() { + if (!m_next) { + sort* s = decl()->get_domain(0); + sort* domain[2] = {s, s}; + m_next = m.mk_fresh_func_decl("next", "", 2, domain, s); + } + return m_next; + } + void theory_special_relations::relation::push() { m_scopes.push_back(scope()); scope& s = m_scopes.back(); @@ -104,37 +113,35 @@ namespace smt { assert f(term,c) or term != b assert f(term,c) or term != a */ - bool theory_special_relations::internalize_term(app * term) { - if (m_util.is_next(term)) { - return false; - } - mk_var(term); + void theory_special_relations::internalize_next(func_decl* f, app* term) { context& ctx = get_context(); ast_manager& m = get_manager(); - func_decl* f = to_func_decl(term->get_decl()->get_parameter(0).get_ast()); + func_decl* nxt = term->get_decl(); expr* src = term->get_arg(0); expr* dst = term->get_arg(1); expr_ref f_rel(m.mk_app(f, src, dst), m); + ensure_enode(term); + ensure_enode(f_rel); literal f_lit = ctx.get_literal(f_rel); src = term; - while (m_util.is_next(src)) { + while (to_app(src)->get_decl() == nxt) { dst = to_app(src)->get_arg(1); src = to_app(src)->get_arg(0); ctx.mk_th_axiom(get_id(), f_lit, ~mk_eq(term, src, false)); ctx.mk_th_axiom(get_id(), f_lit, ~mk_eq(term, dst, false)); } - return true; + } + + bool theory_special_relations::internalize_term(app * term) { + return false; } bool theory_special_relations::internalize_atom(app * atm, bool gate_ctx) { SASSERT(m_util.is_special_relation(atm)); relation* r = 0; - if (m_util.is_next(atm)) { - return internalize_term(atm); - } ast_manager& m = get_manager(); if (!m_relations.find(atm->get_decl(), r)) { - r = alloc(relation, m_util.get_property(atm), atm->get_decl()); + r = alloc(relation, m_util.get_property(atm), atm->get_decl(), m); m_relations.insert(atm->get_decl(), r); for (unsigned i = 0; i < m_atoms_lim.size(); ++i) r->push(); } @@ -350,7 +357,8 @@ namespace smt { // TBD: perhaps replace by recursion unfolding similar to theory_rec_fun // - expr_ref next(m.mk_app(m_util.mk_next(f), arg1, arg2), m); + app_ref next(r.next(arg1, arg2), m); + internalize_next(f, next); expr_ref a2next(m.mk_app(f, arg1, next), m); expr_ref next2b(m.mk_app(tcf, next, arg2), m); expr_ref next_b(m.mk_app(f, next, arg2), m); @@ -365,7 +373,7 @@ namespace smt { ctx.mk_th_axiom(get_id(), ~literal(bv), f_lit, a2next_l); ctx.mk_th_axiom(get_id(), ~literal(bv), f_lit, next2b_l); expr* nxt = next; - while (m_util.is_next(nxt)) { + while (r.is_next(nxt)) { expr* left = to_app(nxt)->get_arg(0); expr* right = to_app(nxt)->get_arg(1); ctx.assign(~mk_eq(next, left, false), nullptr); @@ -896,9 +904,9 @@ namespace smt { Take 2: connected(A, dst, S) = - if A = nil then false else - if member(dst, A) then true else - let (A',S') = next1(a1, b1, A, next1(a2, b2, A, ... S, (nil, nil))) + let (A',S') = next1(a1, b1, A, next1(a2, b2, A, ... S, (nil, S))) + if A' = nil then false else + if member(dst, A') then true else connected(A', dst, S') next1(a, b, A, S, (A',S')) = @@ -915,6 +923,7 @@ Take 2: func_decl_ref nil(m), is_nil(m), cons(m), is_cons(m), hd(m), tl(m); sort_ref listS(dt.mk_list_datatype(s, symbol("List"), cons, is_cons, hd, tl, nil, is_nil), m); func_decl_ref fst(m), snd(m), pair(m); + expr_ref nilc(m.mk_const(nil), m); expr* T = m.mk_true(); expr* F = m.mk_false(); @@ -923,7 +932,7 @@ Take 2: { sort* dom[2] = { s, listS }; - recfun::promise_def mem = p.ensure_def(symbol("member"), 2, dom, m.mk_bool_sort()); + recfun::promise_def mem = p.ensure_def(symbol("member"), 2, dom, m.mk_bool_sort(), true); memf = mem.get_def()->get_decl(); var_ref xV(m.mk_var(1, s), m); @@ -941,14 +950,12 @@ Take 2: var* vars[2] = { xV, SV }; p.set_definition(rep, mem, 2, vars, mem_body); } - -#if 1 sort_ref tup(dt.mk_pair_datatype(listS, listS, fst, snd, pair), m); { sort* dom[5] = { s, s, listS, listS, tup }; - recfun::promise_def nxt = p.ensure_def(symbol("next"), 5, dom, tup); + recfun::promise_def nxt = p.ensure_def(symbol("next"), 5, dom, tup, true); nextf = nxt.get_def()->get_decl(); expr_ref next_body(m); @@ -969,7 +976,7 @@ Take 2: { sort* dom[3] = { listS, s, listS }; - recfun::promise_def connected = p.ensure_def(symbol("connected"), 3, dom, m.mk_bool_sort()); + recfun::promise_def connected = p.ensure_def(symbol("connected"), 3, dom, m.mk_bool_sort(), true); connectedf = connected.get_def()->get_decl(); var_ref AV(m.mk_var(2, listS), m); var_ref dstV(m.mk_var(1, s), m); @@ -977,7 +984,7 @@ Take 2: expr* A = AV, *dst = dstV, *S = SV; expr_ref connected_body(m); - connected_body = m.mk_app(pair, m.mk_const(nil), m.mk_const(nil)); + connected_body = m.mk_app(pair, nilc, S); for (atom* ap : r.m_asserted_atoms) { atom& a = *ap; @@ -989,7 +996,14 @@ Take 2: expr* args[5] = { x, y, A, S, cb }; connected_body = m.mk_app(nextf, 5, args); } + expr_ref Ap(m.mk_app(fst, connected_body), m); + expr_ref Sp(m.mk_app(snd, connected_body), m); + + connected_body = m.mk_ite(m.mk_eq(Ap, nilc), F, + m.mk_ite(m.mk_app(memf, dst, Ap), T, + m.mk_app(connectedf, Ap, dst, Sp))); + TRACE("special_relations", tout << connected_body << "\n";); recfun_replace rep(m); var* vars[3] = { AV, dstV, SV }; p.set_definition(rep, connected, 3, vars, connected_body); @@ -1001,91 +1015,14 @@ Take 2: expr* x = xV, *y = yV; func_interp* fi = alloc(func_interp, m, 2); - expr_ref pred(m.mk_app(connectedf, m.mk_app(cons, x, m.mk_const(nil)), y, m.mk_const(nil)), m); + expr_ref consx(m.mk_app(cons, x, nilc), m); + expr_ref pred(m.mk_app(connectedf, consx, y, consx), m); if (is_reflexive) { pred = m.mk_or(pred, m.mk_eq(x, y)); } fi->set_else(pred); mg.get_model().register_decl(r.decl(), fi); - } - -#else - sort_ref tup(dt.mk_pair_datatype(listS, m.mk_bool_sort(), fst, snd, pair), m); - sort* dom1[5] = { s, s, listS, s, s }; - recfun::promise_def c1 = p.ensure_def(symbol("connected1"), 5, dom1, tup); - sort* dom2[3] = { s, s, listS }; - recfun::promise_def c2 = p.ensure_def(symbol("connected2"), 3, dom2, tup); - - func_decl* conn1 = c1.get_def()->get_decl(); - func_decl* conn2 = c2.get_def()->get_decl(); - - var_ref xV(m.mk_var(4, s), m); - var_ref yV(m.mk_var(3, s), m); - var_ref SV(m.mk_var(2, listS), m); - var_ref vV(m.mk_var(1, s), m); - var_ref wV(m.mk_var(0, s), m); - expr* y = yV, *v = vV, *w = wV; - expr* x = xV, *S = SV; - - expr_ref ST(m.mk_app(pair, S, T), m); - expr_ref SF(m.mk_app(pair, S, F), m); - - expr_ref connected_body(m); - connected_body = - m.mk_ite(m.mk_not(m.mk_eq(x, v)), - SF, - m.mk_ite(m.mk_eq(y, w), - ST, - m.mk_ite(m.mk_app(memf, w, S), - SF, - m.mk_app(conn2, w, y, m.mk_app(cons, w, S))))); - { - var* vars2[5] = { xV, yV, SV, vV, wV }; - recfun_replace rep(m); - p.set_definition(rep, c1, 5, vars2, connected_body); - } - - xV = m.mk_var(2, s); - yV = m.mk_var(1, s); - SV = m.mk_var(0, listS); - x = xV, y = yV, S = SV; - ST = m.mk_app(pair, S, T); - SF = m.mk_app(pair, S, F); - expr_ref connected_rec_body(m); - connected_rec_body = SF; - - for (atom* ap : r.m_asserted_atoms) { - atom& a = *ap; - if (!a.phase()) continue; - SASSERT(get_context().get_assignment(a.var()) == l_true); - expr* n1 = get_enode(a.v1())->get_root()->get_owner(); - expr* n2 = get_enode(a.v2())->get_root()->get_owner(); - expr* Sr = connected_rec_body; - expr* args[5] = { x, y, m.mk_app(fst, Sr), n1, n2}; - expr* Sc = m.mk_app(conn1, 5, args); - connected_rec_body = m.mk_ite(m.mk_app(snd, Sr), ST, Sc); - } - { - var* vars3[3] = { xV, yV, SV }; - recfun_replace rep(m); - p.set_definition(rep, c2, 3, vars3, connected_rec_body); - } - - // r.m_decl(x,y) -> snd(connected2(x,y,nil)) - xV = m.mk_var(0, s); - yV = m.mk_var(1, s); - x = xV, y = yV; - - func_interp* fi = alloc(func_interp, m, 2); - expr_ref pred(m.mk_app(snd, m.mk_app(conn2, x, y, m.mk_app(cons, y, m.mk_const(nil)))), m); - if (is_reflexive) { - pred = m.mk_or(pred, m.mk_eq(x, y)); - } - fi->set_else(pred); - mg.get_model().register_decl(r.decl(), fi); - -#endif - + } } /** @@ -1208,10 +1145,6 @@ Take 2: } } - bool theory_special_relations::has_quantifiers() { - return get_context().has_quantifiers(); - } - void theory_special_relations::init_model(model_generator & m) { for (auto const& kv : m_relations) { switch (kv.m_value->m_property) { @@ -1228,16 +1161,10 @@ Take 2: init_model_po(*kv.m_value, m, true); break; case sr_tc: - if (has_quantifiers()) { - // model construction for transitive relation is reserved for quantified formulas where - // TC(R) may be needed to perform MBQI - init_model_po(*kv.m_value, m, true); - } + init_model_po(*kv.m_value, m, true); break; case sr_trc: - if (has_quantifiers()) { - init_model_po(*kv.m_value, m, true); - } + init_model_po(*kv.m_value, m, true); break; default: // other 28 combinations of 0x1F diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 0f69bc1d9..fd88cc456 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -92,6 +92,8 @@ namespace smt { typedef union_find union_find_t; struct relation { + ast_manager& m; + func_decl_ref m_next; sr_property m_property; func_decl* m_decl; atoms m_asserted_atoms; // set of asserted atoms @@ -102,9 +104,14 @@ namespace smt { union_find_t m_uf; literal_vector m_explanation; - relation(sr_property p, func_decl* d): m_property(p), m_decl(d), m_asserted_qhead(0), m_uf(m_ufctx) {} + relation(sr_property p, func_decl* d, ast_manager& m): m(m), m_next(m), m_property(p), m_decl(d), m_asserted_qhead(0), m_uf(m_ufctx) {} func_decl* decl() { return m_decl; } + + app_ref next(expr* a, expr* b) { return app_ref(m.mk_app(next(), a, b), m); } + bool is_next(expr* n) { return is_app(n) && next() == to_app(n)->get_decl(); } + func_decl* next(); + void push(); void pop(unsigned num_scopes); void ensure_var(theory_var v); @@ -172,7 +179,7 @@ namespace smt { void collect_asserted_po_atoms(vector< std::pair >& atoms) const; void display_atom(std::ostream & out, atom& a) const; - bool has_quantifiers(); + void internalize_next(func_decl* f, app * term); public: theory_special_relations(ast_manager& m); diff --git a/src/util/obj_hashtable.h b/src/util/obj_hashtable.h index c5cb0c319..f407120cf 100644 --- a/src/util/obj_hashtable.h +++ b/src/util/obj_hashtable.h @@ -222,10 +222,8 @@ public: */ template void reset_dealloc_values(obj_map & m) { - typename obj_map::iterator it = m.begin(); - typename obj_map::iterator end = m.end(); - for (; it != end; ++it) { - dealloc(it->m_value); + for (auto & kv : m) { + dealloc(kv.m_value); } m.reset(); } From 3c0e8cb182204504b371d4125a32756bf1c55610 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Apr 2019 11:42:55 -0700 Subject: [PATCH 142/156] fix model generation for tc/po Signed-off-by: Nikolaj Bjorner --- src/model/model.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/model/model.cpp b/src/model/model.cpp index 15344b35d..756fe2251 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -432,12 +432,7 @@ expr_ref model::cleanup_expr(top_sort& ts, expr* e, unsigned current_partition) } #endif else { - if (m.is_ite(f)) { - new_t = m.mk_app(f, args.size(), args.c_ptr()); - } - else { - new_t = ts.m_rewrite.mk_app(f, args.size(), args.c_ptr()); - } + new_t = ts.m_rewrite.mk_app(f, args.size(), args.c_ptr()); } if (t != new_t.get()) trail.push_back(new_t); From 4dbccbf23a0afe81af19358a70faf88926b02936 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Apr 2019 14:11:40 -0700 Subject: [PATCH 143/156] fix build Signed-off-by: Nikolaj Bjorner --- src/smt/theory_special_relations.cpp | 8 ++++---- src/smt/theory_special_relations.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 03f11dd26..07fd42ad6 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -336,7 +336,7 @@ namespace smt { continue; } expr_ref f_app(m.mk_app(f, arg1, arg2), m); - enode* fn = ensure_enode(f_app); + ensure_enode(f_app); literal f_lit = ctx.get_literal(f_app); switch (ctx.get_assignment(f_lit)) { case l_true: @@ -984,7 +984,7 @@ Take 2: expr* A = AV, *dst = dstV, *S = SV; expr_ref connected_body(m); - connected_body = m.mk_app(pair, nilc, S); + connected_body = m.mk_app(pair, nilc.get(), S); for (atom* ap : r.m_asserted_atoms) { atom& a = *ap; @@ -996,8 +996,8 @@ Take 2: expr* args[5] = { x, y, A, S, cb }; connected_body = m.mk_app(nextf, 5, args); } - expr_ref Ap(m.mk_app(fst, connected_body), m); - expr_ref Sp(m.mk_app(snd, connected_body), m); + expr_ref Ap(m.mk_app(fst, connected_body.get()), m); + expr_ref Sp(m.mk_app(snd, connected_body.get()), m); connected_body = m.mk_ite(m.mk_eq(Ap, nilc), F, m.mk_ite(m.mk_app(memf, dst, Ap), T, diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index fd88cc456..83beb35bb 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -175,7 +175,7 @@ namespace smt { literal mk_literal(expr* _e); enode* ensure_enode(expr* e); - theory_var mk_var(enode* n); + theory_var mk_var(enode* n) override; void collect_asserted_po_atoms(vector< std::pair >& atoms) const; void display_atom(std::ostream & out, atom& a) const; From 5708379ebc3886c516b4b946116de9e88b8ed354 Mon Sep 17 00:00:00 2001 From: Philipp Paulweber Date: Fri, 12 Apr 2019 14:52:00 +0200 Subject: [PATCH 144/156] MSYS2 and cmake based compilation support for clang and gcc --- src/shell/main.cpp | 4 ++++ src/util/hwf.cpp | 14 ++++++++++++-- src/util/warning.cpp | 4 ++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/shell/main.cpp b/src/shell/main.cpp index 1d22ce9b6..68b807f87 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -39,6 +39,10 @@ Revision History: #include "util/file_path.h" #include "shell/lp_frontend.h" +#if defined( _WINDOWS ) && defined( __MINGW32__ ) && ( defined( __GNUG__ ) || defined( __clang__ ) ) +#include +#endif + typedef enum { IN_UNSPECIFIED, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_LP, IN_Z3_LOG, IN_MPS } input_kind; static std::string g_aux_input_file; diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index 4a7a0b7e4..2c64ad7e3 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -21,10 +21,12 @@ Revision History: #include #ifdef _WINDOWS +#if defined(_MSC_VER) #pragma float_control( except, on ) // exception semantics; this does _not_ mean that exceptions are enabled (we want them off!) #pragma float_control( precise, on ) // precise semantics (no guessing!) #pragma fp_contract(off) // contractions off (`contraction' means x*y+z is turned into a fused-mul-add). #pragma fenv_access(on) // fpu environment sensitivity (needed to be allowed to make FPU mode changes). +#endif #else #include #endif @@ -267,6 +269,9 @@ void hwf_manager::fma(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf co // IA64 (Itanium) will do it, if contractions are on. o.value = x.value * y.value + z.value; #else +#if defined( __MINGW32__ ) && ( defined( __GNUG__ ) || defined( __clang__ ) ) + o.value = ::fma(x.value, y.value, z.value); +#else #if defined(_WINDOWS) #if _MSC_VER >= 1800 o.value = ::fma(x.value, y.value, z.value); @@ -283,6 +288,7 @@ void hwf_manager::fma(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf co o.value = ::fma(x.value, y.value, z.value); #endif #endif +#endif } #ifdef _M_IA64 @@ -306,7 +312,10 @@ void hwf_manager::round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o // According to the Intel Architecture manual, the x87-instruction FRNDINT is the // same in 32-bit and 64-bit mode. The _mm_round_* intrinsics are SSE4 extensions. #ifdef _WINDOWS -#if defined(USE_INTRINSICS) && \ +#if defined( __MINGW32__ ) && ( defined( __GNUG__ ) || defined( __clang__ ) ) + o.value = nearbyint(x.value); +#else + #if defined(USE_INTRINSICS) && \ (defined(_WINDOWS) && (defined(__AVX__) || defined(_M_X64))) || \ (!defined(_WINDOWS) && defined(__SSE4_1__)) switch (rm) { @@ -320,7 +329,7 @@ void hwf_manager::round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o default: UNREACHABLE(); // Unknown rounding mode. } -#else + #else double xv = x.value; double & ov = o.value; @@ -329,6 +338,7 @@ void hwf_manager::round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o frndint fstp ov // Store result away. } + #endif #endif #else // Linux, macOS. diff --git a/src/util/warning.cpp b/src/util/warning.cpp index 5ffc38527..7916115d9 100644 --- a/src/util/warning.cpp +++ b/src/util/warning.cpp @@ -25,6 +25,10 @@ Revision History: #include "util/vector.h" #ifdef _WINDOWS +#if defined( __MINGW32__ ) && ( defined( __GNUG__ ) || defined( __clang__ ) ) +#include +#endif + #define VPRF vsprintf_s void STD_CALL myInvalidParameterHandler( From ebe58f78cf98da0f43cd63aca8dc4f26a9baa2cc Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sat, 13 Apr 2019 15:59:30 +0200 Subject: [PATCH 145/156] lp_tokenizer: Add missing verbose print Three out of two places that call m_tokens.push_back() in lp_tokenizer::parse_all() were followed by a verbose print. This commit adds a verbose print to the third such place. Signed-off-by: Uli Schlachter --- src/opt/opt_parse.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp index 47ce31e1b..215650300 100644 --- a/src/opt/opt_parse.cpp +++ b/src/opt/opt_parse.cpp @@ -411,6 +411,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"); continue; } } From 1123b47fb7559df213105fb246284550078df71d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 13 Apr 2019 16:15:32 -0700 Subject: [PATCH 146/156] bapa Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.cpp | 26 +- src/ast/array_decl_plugin.h | 10 + src/ast/ast_util.cpp | 16 + src/ast/ast_util.h | 5 +- src/ast/rewriter/array_rewriter.h | 14 + src/smt/CMakeLists.txt | 1 + src/smt/theory_array.cpp | 2 +- src/smt/theory_array_bapa.cpp | 476 ++++++++++++++++++++++++++++++ src/smt/theory_array_bapa.h | 43 +++ src/smt/theory_array_base.cpp | 1 + src/smt/theory_array_base.h | 5 + src/smt/theory_array_full.cpp | 12 +- src/util/trail.h | 6 + 13 files changed, 613 insertions(+), 4 deletions(-) create mode 100644 src/smt/theory_array_bapa.cpp create mode 100644 src/smt/theory_array_bapa.h diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index d361815b2..a470bd353 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -21,6 +21,7 @@ Revision History: #include "util/warning.h" #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" +#include "ast/arith_decl_plugin.h" array_decl_plugin::array_decl_plugin(): m_store_sym("store"), @@ -34,7 +35,8 @@ array_decl_plugin::array_decl_plugin(): m_set_complement_sym("complement"), m_set_subset_sym("subset"), m_array_ext_sym("array-ext"), - m_as_array_sym("as-array") { + m_as_array_sym("as-array"), + m_set_has_size_sym("set-has-size") { } #define ARRAY_SORT_STR "Array" @@ -438,6 +440,25 @@ func_decl * array_decl_plugin::mk_set_subset(unsigned arity, sort * const * doma func_decl_info(m_family_id, OP_SET_SUBSET)); } +func_decl * array_decl_plugin::mk_set_has_size(unsigned arity, sort * const* domain) { + if (arity != 2) { + m_manager->raise_exception("set-has-size takes two arguments"); + return nullptr; + } + // domain[0] is a Boolean array, + // domain[1] is Int + arith_util arith(*m_manager); + if (!arith.is_int(domain[1])) { + m_manager->raise_exception("set-has-size expects second argument to be an integer"); + } + if (!is_array_sort(domain[0]) || !m_manager->is_bool(get_array_range(domain[0]))) { + m_manager->raise_exception("set-has-size expects first argument to be an array of Booleans"); + } + sort * bool_sort = m_manager->mk_bool_sort(); + return m_manager->mk_func_decl(m_set_has_size_sym, arity, domain, bool_sort, + func_decl_info(m_family_id, OP_SET_HAS_SIZE)); +} + func_decl * array_decl_plugin::mk_as_array(func_decl * f) { vector parameters; for (unsigned i = 0; i < f->get_arity(); i++) { @@ -502,6 +523,8 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters return mk_set_complement(arity, domain); case OP_SET_SUBSET: return mk_set_subset(arity, domain); + case OP_SET_HAS_SIZE: + return mk_set_has_size(arity, domain); case OP_AS_ARRAY: { if (num_parameters != 1 || !parameters[0].is_ast() || @@ -544,6 +567,7 @@ void array_decl_plugin::get_op_names(svector& op_names, symbol con op_names.push_back(builtin_name("subset",OP_SET_SUBSET)); op_names.push_back(builtin_name("as-array", OP_AS_ARRAY)); op_names.push_back(builtin_name("array-ext", OP_ARRAY_EXT)); + op_names.push_back(builtin_name("set-has-size", OP_SET_HAS_SIZE)); } } diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 5b44d31c9..6ba129444 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -51,6 +51,7 @@ enum array_op_kind { OP_SET_DIFFERENCE, OP_SET_COMPLEMENT, OP_SET_SUBSET, + OP_SET_HAS_SIZE, OP_AS_ARRAY, // used for model construction LAST_ARRAY_OP }; @@ -68,6 +69,7 @@ class array_decl_plugin : public decl_plugin { symbol m_set_subset_sym; symbol m_array_ext_sym; symbol m_as_array_sym; + symbol m_set_has_size_sym; bool check_set_arguments(unsigned arity, sort * const * domain); @@ -95,6 +97,8 @@ class array_decl_plugin : public decl_plugin { func_decl * mk_as_array(func_decl * f); + func_decl* mk_set_has_size(unsigned arity, sort * const* domain); + bool is_array_sort(sort* s) const; public: array_decl_plugin(); @@ -144,11 +148,13 @@ public: bool is_map(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_MAP); } bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); } bool is_as_array(expr * n, func_decl*& f) const { return is_as_array(n) && (f = get_as_array_func_decl(n), true); } + bool is_set_has_size(expr* e) const { return is_app_of(e, m_fid, OP_SET_HAS_SIZE); } bool is_select(func_decl* f) const { return is_decl_of(f, m_fid, OP_SELECT); } bool is_store(func_decl* f) const { return is_decl_of(f, m_fid, OP_STORE); } bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); } bool is_map(func_decl* f) const { return is_decl_of(f, m_fid, OP_ARRAY_MAP); } bool is_as_array(func_decl* f) const { return is_decl_of(f, m_fid, OP_AS_ARRAY); } + bool is_set_has_size(func_decl* f) const { return is_decl_of(f, m_fid, OP_SET_HAS_SIZE); } bool is_as_array(func_decl* f, func_decl*& g) const { return is_decl_of(f, m_fid, OP_AS_ARRAY) && (g = get_as_array_func_decl(f), true); } func_decl * get_as_array_func_decl(expr * n) const; func_decl * get_as_array_func_decl(func_decl* f) const; @@ -189,6 +195,10 @@ public: return mk_const_array(s, m_manager.mk_true()); } + app* mk_has_size(expr* set, expr* n) { + return m_manager.mk_app(m_fid, OP_SET_HAS_SIZE, set, n); + } + func_decl * mk_array_ext(sort* domain, unsigned i); sort * mk_array_sort(sort* dom, sort* range) { return mk_array_sort(1, &dom, range); } diff --git a/src/ast/ast_util.cpp b/src/ast/ast_util.cpp index 601eee58e..15eab50b9 100644 --- a/src/ast/ast_util.cpp +++ b/src/ast/ast_util.cpp @@ -17,6 +17,7 @@ Revision History: --*/ #include "ast/ast_util.h" +#include "ast/arith_decl_plugin.h" app * mk_list_assoc_app(ast_manager & m, func_decl * f, unsigned num_args, expr * const * args) { SASSERT(f->is_associative()); @@ -361,3 +362,18 @@ void flatten_or(expr* fml, expr_ref_vector& result) { result.push_back(fml); flatten_or(result); } + +static app_ref plus(ast_manager& m, expr* a, expr* b) { + arith_util arith(m); + return app_ref(arith.mk_add(a, b), m); +} + +static app_ref plus(ast_manager& m, expr* a, int i) { + arith_util arith(m); + return app_ref(arith.mk_add(a, arith.mk_int(i)), m); +} + +app_ref operator+(expr_ref& a, expr* b) { return plus(a.m(), a, b); } +app_ref operator+(app_ref& a, expr* b) { return plus(a.m(), a, b); } +app_ref operator+(expr_ref& a, int i) { return plus(a.m(), a, i); } +app_ref operator+(app_ref& a, int i) { return plus(a.m(), a, i); } diff --git a/src/ast/ast_util.h b/src/ast/ast_util.h index e317d14ec..fe4bde465 100644 --- a/src/ast/ast_util.h +++ b/src/ast/ast_util.h @@ -120,7 +120,10 @@ inline app_ref operator|(expr_ref& a, expr* b) { return app_ref(a.m().mk_or(a, b inline app_ref operator|(app_ref& a, expr* b) { return app_ref(a.m().mk_or(a, b), a.m()); } inline app_ref operator|(var_ref& a, expr* b) { return app_ref(a.m().mk_or(a, b), a.m()); } inline app_ref operator|(quantifier_ref& a, expr* b) { return app_ref(a.m().mk_or(a, b), a.m()); } - +app_ref operator+(expr_ref& a, expr* b); +app_ref operator+(app_ref& a, expr* b); +app_ref operator+(expr_ref& a, int i); +app_ref operator+(app_ref& a, int i); /** Return (or args[0] ... args[num_args-1]) if num_args >= 2 diff --git a/src/ast/rewriter/array_rewriter.h b/src/ast/rewriter/array_rewriter.h index a8108711a..056ef66c4 100644 --- a/src/ast/rewriter/array_rewriter.h +++ b/src/ast/rewriter/array_rewriter.h @@ -69,6 +69,20 @@ public: br_status mk_set_difference(expr * arg1, expr * arg2, expr_ref & result); br_status mk_set_subset(expr * arg1, expr * arg2, expr_ref & result); br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result); + + expr_ref mk_set_difference(expr* a, expr* b) { + expr_ref result(m()); + mk_set_difference(a, b, result); + return result; + } + + expr_ref mk_set_intersect(expr* a, expr* b) { + expr_ref result(m()); + expr* args[2] = { a, b }; + mk_set_intersect(2, args, result); + return result; + } + }; #endif diff --git a/src/smt/CMakeLists.txt b/src/smt/CMakeLists.txt index adc348633..0eda8f86b 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -46,6 +46,7 @@ z3_add_component(smt smt_value_sort.cpp smt2_extra_cmds.cpp theory_arith.cpp + theory_array_bapa.cpp theory_array_base.cpp theory_array.cpp theory_array_full.cpp diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index 3398d0894..d9e0b1995 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -388,9 +388,9 @@ namespace smt { r = assert_delayed_axioms(); } } - TRACE("array", tout << "m_found_unsupported_op: " << m_found_unsupported_op << " " << r << "\n";); if (r == FC_DONE && m_found_unsupported_op && !get_context().get_fparams().m_array_fake_support) r = FC_GIVEUP; + CTRACE("array", r != FC_DONE || m_found_unsupported_op, tout << r << "\n";); return r; } diff --git a/src/smt/theory_array_bapa.cpp b/src/smt/theory_array_bapa.cpp new file mode 100644 index 000000000..51b0186e2 --- /dev/null +++ b/src/smt/theory_array_bapa.cpp @@ -0,0 +1,476 @@ +/** + + Size(S, n), Size(T, m) + S, T are intersecting. n != m or S != T +D --------------------------------------------------------- + Size(S, n) => Size(S\T, k1), Size(S n T, k2), n = k1 + k2 + Size(T, m) => Size(T\S, k3), SIze(S n T, k2), m = k2 + k3 + + Size(S, n) +P -------------------- + Size(S, n) => n >= 0 + + Size(S, n), is infinite domain +B ------------------------------ + Size(S, n) => default(S) = false + + Size(S, n), Size(S, m) +F -------------------------------- + Size(S, n), Size(S, m) => n = m + + Fixing values during final check: + Size(S, n) +V ------------------- + assume value(n) = n + + Size(S, n), S[i1], ..., S[ik] +O ------------------------------- + ~distinct(i1, ... ik) or n >= k + + Size(S,n) +Ak -------------------------------------------------- + S[i1] & .. & S[ik] & distinct(i1, .., ik) or n < k + +Q: Is this sufficient? Axiom A1 could be adjusted to add new elements i' until there are k witnesses for Size(S, k). +This is quite bad when k is very large. Instead rely on stably infiniteness or other domain properties of the theories. + +When A is finite domain, or there are quantifiers there could be constraints that force domain sizes so domain sizes may have +to be enforced. A succinct way would be through domain comprehension assertions. Thus, if we have +S[i1],.., S[ik], !S[j1],...,!S[jl] asserted on integer domain i, then + +Finite domains: + + Size(S, n), is finite domain + ---------------------------- + S <= |A| + + Size(S, n), !S[i1], .... !S[ik], S is finite domain + ---------------------------------------------------------- + default(S) = false or ~distinct(i1,..,ik) or |A| - k <= n + + + ~Size(S, m) is negative on all occurrences, S is finite domain + --------------------------------------------------------------- + Size(S, n) n fresh. + + */ + +#include "ast/ast_util.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/array_rewriter.h" +#include "smt/smt_context.h" +#include "smt/smt_arith_value.h" +#include "smt/theory_array_full.h" +#include "smt/theory_array_bapa.h" + +namespace smt { + + class theory_array_bapa::imp { + struct sz_info { + bool m_is_leaf; // has it been split into disjoint subsets already? + rational m_value; // set to >= integer if fixed in final check, otherwise -1 + literal m_literal; // literal that enforces value is set. + obj_map m_selects; + sz_info(): m_is_leaf(true), m_value(rational::minus_one()), m_literal(null_literal) {} + }; + + typedef std::pair func_decls; + + ast_manager& m; + theory_array_full& th; + arith_util m_arith; + array_util m_autil; + array_rewriter m_rw; + arith_value m_arith_value; + ast_ref_vector m_pinned; + obj_map m_sizeof; + obj_map m_index_skolems; + unsigned m_max_set_enumeration; + + context& ctx() { return th.get_context(); } + + void reset() { + for (auto& kv : m_sizeof) { + dealloc(kv.m_value); + } + } + + bool is_true(expr* e) { return is_true(ctx().get_literal(e)); } + bool is_true(enode* e) { return is_true(e->get_owner()); } + bool is_true(literal l) { return ctx().is_relevant(l) && ctx().get_assignment(l) == l_true; } + bool is_leaf(sz_info& i) const { return i.m_is_leaf; } + bool is_leaf(sz_info* i) const { return is_leaf(*i); } + enode* get_root(expr* e) { return ctx().get_enode(e)->get_root(); } + bool is_select(enode* n) { return th.is_select(n); } + app_ref mk_select(expr* a, expr* i) { expr* args[2] = { a, i }; return app_ref(m_autil.mk_select(2, args), m); } + literal get_literal(expr* e) { return ctx().get_literal(e); } + literal mk_literal(expr* e) { if (!ctx().e_internalized(e)) ctx().internalize(e, false); ctx().mark_as_relevant(e); return get_literal(e); } + literal mk_eq(expr* a, expr* b) { return th.mk_eq(a, b, false); } + void mk_th_axiom(literal l1, literal l2) { + literal lits[2] = { l1, l2 }; + mk_th_axiom(2, lits); + } + void mk_th_axiom(literal l1, literal l2, literal l3) { + literal lits[3] = { l1, l2, l3 }; + mk_th_axiom(3, lits); + } + void mk_th_axiom(unsigned n, literal* lits) { + TRACE("array", ctx().display_literals_verbose(tout, n, lits) << "\n";); + ctx().mk_th_axiom(th.get_id(), n, lits); + } + + void update_indices() { + for (auto const& kv : m_sizeof) { + app* k = kv.m_key; + sz_info& v = *kv.m_value; + v.m_selects.reset(); + if (is_true(k) && is_leaf(v)) { + expr* set = k->get_arg(0); + for (enode* parent : enode::parents(get_root(set))) { + if (is_select(parent) && is_true(parent)) { + v.m_selects.insert(parent->get_arg(1)->get_root(), parent->get_owner()); + } + } + } + } + } + + /** + F: Size(S, k1) & Size(S, k2) => k1 = k2 + */ + lbool ensure_functional() { + lbool result = l_true; + obj_map parents; + for (auto const& kv : m_sizeof) { + app* sz1 = kv.m_key; + if (!is_true(sz1)) { + continue; + } + enode* r = get_root(sz1->get_arg(0)); + app* sz2 = nullptr; + if (parents.find(r, sz2)) { + expr* k1 = sz1->get_arg(1); + expr* k2 = sz2->get_arg(1); + if (get_root(k1) != get_root(k2)) { + mk_th_axiom(~get_literal(sz1), ~get_literal(sz2), mk_eq(k1, k2)); + result = l_false; + } + } + else { + parents.insert(r, sz1); + } + } + return result; + } + + /** + Enforce D + */ + lbool ensure_disjoint() { + auto i = m_sizeof.begin(), end = m_sizeof.end(); + for (; i != end; ++i) { + auto& kv = *i; + if (!kv.m_value->m_is_leaf) { + continue; + } + for (auto j = i; ++j != end; ) { + if (j->m_value->m_is_leaf && !ensure_disjoint(i->m_key, j->m_key)) { + return l_false; + } + } + } + return l_true; + } + + lbool ensure_disjoint(app* sz1, app* sz2) { + sz_info& i1 = *m_sizeof[sz1]; + sz_info& i2 = *m_sizeof[sz2]; + SASSERT(i1.m_is_leaf); + SASSERT(i2.m_is_leaf); + expr* s = sz1->get_arg(0); + expr* t = sz2->get_arg(0); + enode* r1 = get_root(s); + enode* r2 = get_root(t); + if (r1 == r2) { + return l_true; + } + if (!ctx().is_diseq(r1, r2) && ctx().assume_eq(r1, r2)) { + return l_false; + } + if (do_intersect(i1.m_selects, i2.m_selects)) { + add_disjoint(sz1, sz2); + return l_false; + } + return l_true; + } + + bool do_intersect(obj_map const& s, obj_map const& t) const { + if (s.size() > t.size()) { + return do_intersect(t, s); + } + for (auto const& idx : s) + if (t.contains(idx.m_key)) + return true; + return false; + } + + void add_disjoint(app* sz1, app* sz2) { + sz_info& i1 = *m_sizeof[sz1]; + sz_info& i2 = *m_sizeof[sz2]; + SASSERT(i1.m_is_leaf); + SASSERT(i2.m_is_leaf); + expr* t = sz1->get_arg(0); + expr* s = sz2->get_arg(0); + expr_ref tms = mk_subtract(t, s); + expr_ref smt = mk_subtract(s, t); + expr_ref tns = mk_intersect(t, s); + ctx().push_trail(value_trail(i1.m_is_leaf, false)); + ctx().push_trail(value_trail(i2.m_is_leaf, false)); + expr_ref k1(m), k2(m), k3(m); + expr_ref sz_tms(m), sz_tns(m), sz_smt(m); + k1 = m.mk_fresh_const("K", m_arith.mk_int()); + k2 = m.mk_fresh_const("K", m_arith.mk_int()); + k3 = m.mk_fresh_const("K", m_arith.mk_int()); + sz_tms = m_autil.mk_has_size(tms, k1); + sz_tns = m_autil.mk_has_size(tns, k2); + sz_smt = m_autil.mk_has_size(smt, k3); + propagate(sz1, sz_tms); + propagate(sz1, sz_tns); + propagate(sz2, sz_smt); + propagate(sz2, sz_tns); + propagate(sz1, mk_eq(k1 + k2, sz1->get_arg(1))); + propagate(sz2, mk_eq(k3 + k2, sz2->get_arg(1))); + } + + expr_ref mk_subtract(expr* t, expr* s) { + return m_rw.mk_set_difference(t, s); + } + + expr_ref mk_intersect(expr* t, expr* s) { + return m_rw.mk_set_intersect(t, s); + } + + void propagate(expr* assumption, expr* conseq) { + propagate(assumption, mk_literal(conseq)); + } + + void propagate(expr* assumption, literal conseq) { + mk_th_axiom(~mk_literal(assumption), conseq); + } + + /** + Enforce V + */ + lbool ensure_values_assigned() { + lbool result = l_true; + for (auto const& kv : m_sizeof) { + app* k = kv.m_key; + sz_info& i = *kv.m_value; + if (is_leaf(kv.m_value) && (i.m_literal == null_literal || !is_true(i.m_literal))) { + rational value; + if (!m_arith_value.get_value(k->get_arg(1), value)) { + return l_undef; + } + literal lit = mk_eq(k->get_arg(1), m_arith.mk_int(value)); + ctx().mark_as_relevant(lit); + ctx().set_true_first_flag(lit.var()); + ctx().push_trail(value_trail(i.m_literal, lit)); + i.m_value = value; + result = l_false; + } + } + return result; + } + + /** + Enforce Ak, k <= m_max_set_enumeration + */ + lbool ensure_non_empty() { + for (auto const& kv : m_sizeof) { + sz_info& i = *kv.m_value; + app* sz = kv.m_key; + if (is_true(sz) && is_leaf(i) && i.m_selects.size() < i.m_value && i.m_selects.size() < m_max_set_enumeration) { + expr* a = sz->get_arg(0); + expr_ref le(m_arith.mk_le(sz->get_arg(1), m_arith.mk_int(0)), m); + literal le_lit = mk_literal(le); + literal sz_lit = mk_literal(sz); + for (unsigned k = 0; k < m_max_set_enumeration && rational(k) < i.m_value; ++k) { + expr_ref idx = mk_index_skolem(sz, a, k); + app_ref sel(mk_select(a, idx)); + mk_th_axiom(~sz_lit, le_lit, mk_literal(sel)); + } + return l_false; + } + } + return l_true; + } + + // create skolem function that is injective on integers (ensures uniqueness). + expr_ref mk_index_skolem(app* sz, expr* a, unsigned n) { + func_decls fg; + sort* s = m.get_sort(a); + if (!m_index_skolems.find(s, fg)) { + sort* idx_sort = get_array_domain(s, 0); + sort* dom1[2] = { s, m_arith.mk_int() }; + sort* dom2[1] = { idx_sort }; + func_decl* f = m.mk_fresh_func_decl("to-index", "", 2, dom1, idx_sort); + func_decl* g = m.mk_fresh_func_decl("from-index", "", 1, dom2, m_arith.mk_int()); + fg = std::make_pair(f, g); + m_index_skolems.insert(s, fg); + m_pinned.push_back(f); + m_pinned.push_back(g); + m_pinned.push_back(s); + } + expr_ref nV(m_arith.mk_int(n), m); + expr_ref result(m.mk_app(fg.first, a, nV), m); + expr_ref le(m_arith.mk_le(sz->get_arg(1), nV), m); + // set-has-size(a, k) => k <= n or g(f(a,n)) = n + mk_th_axiom(~mk_literal(sz), mk_literal(le), mk_eq(nV, m.mk_app(fg.second, result))); + return result; + } + + + /** + Enforce O + */ + lbool ensure_no_overflow() { + for (auto const& kv : m_sizeof) { + if (is_true(kv.m_key) && is_leaf(kv.m_value)) { + lbool r = ensure_no_overflow(kv.m_key, *kv.m_value); + if (r != l_true) return r; + } + } + return l_true; + } + + lbool ensure_no_overflow(app* sz, sz_info& info) { + SASSERT(!info.m_value.is_neg()); + if (info.m_value < info.m_selects.size()) { + for (auto i = info.m_selects.begin(), e = info.m_selects.end(); i != e; ++i) { + for (auto j = i; ++j != e; ) { + if (ctx().assume_eq(i->m_key, j->m_key)) { + return l_false; + } + } + } + // if all is exhausted, then add axiom: set-has-size(s, n) & s[indices] & all-diff(indices) => n >= |indices| + literal_vector lits; + lits.push_back(~mk_literal(sz)); + for (auto const& kv : info.m_selects) { + lits.push_back(~mk_literal(kv.m_value)); + } + if (info.m_selects.size() > 1) { + ptr_vector args; + for (auto const& kv : info.m_selects) { + args.push_back(kv.m_key->get_owner()); + } + expr_ref diff(m.mk_distinct(args.size(), args.c_ptr()), m); + lits.push_back(~mk_literal(diff)); + } + expr_ref ge(m_arith.mk_ge(sz->get_arg(1), m_arith.mk_int(info.m_selects.size())), m); + lits.push_back(mk_literal(ge)); + mk_th_axiom(lits.size(), lits.c_ptr()); + return l_false; + } + return l_true; + } + + class remove_sz : public trail { + obj_map & m_table; + app* m_obj; + public: + remove_sz(obj_map& tab, app* t): m_table(tab), m_obj(t) {} + ~remove_sz() override {} + void undo(context& ctx) override { dealloc(m_table[m_obj]); m_table.remove(m_obj); } + }; + + std::ostream& display(std::ostream& out) { + for (auto const& kv : m_sizeof) { + display(out << mk_pp(kv.m_key, m) << ": ", *kv.m_value); + } + return out; + } + + std::ostream& display(std::ostream& out, sz_info& sz) { + return out << (sz.m_is_leaf ? "leaf": "") << " value: " << sz.m_value << " selects: " << sz.m_selects.size() << "\n"; + } + + public: + imp(theory_array_full& th): + m(th.get_manager()), + th(th), + m_rw(m), + m_arith(m), + m_autil(m), + m_arith_value(m), + m_pinned(m) + { + context& ctx = th.get_context(); + m_arith_value.init(&ctx); + m_max_set_enumeration = 100; + } + + ~imp() { + reset(); + } + + /** + * Size(S, n) => n >= 0, default(S) = false + */ + void internalize_size(app* term) { + SASSERT(ctx().e_internalized(term)); + literal lit = mk_literal(term); + expr* s = term->get_arg(0); + expr* n = term->get_arg(1); + mk_th_axiom(~lit, mk_literal(m_arith.mk_ge(n, m_arith.mk_int(0)))); + sort_size const& sz = m.get_sort(s)->get_num_elements(); + if (sz.is_infinite()) { + mk_th_axiom(~lit, mk_eq(th.mk_default(s), m.mk_false())); + } + else { + warning_msg("correct handling of finite domains is TBD"); + // add upper bound on size of set. + // add case where default(S) = true, and add negative elements. + } + m_sizeof.insert(term, alloc(sz_info)); + ctx().push_trail(remove_sz(m_sizeof, term)); + } + + final_check_status final_check() { + lbool r = ensure_functional(); + if (r == l_true) update_indices(); + if (r == l_true) r = ensure_disjoint(); + if (r == l_true) r = ensure_values_assigned(); + if (r == l_true) r = ensure_non_empty(); + if (r == l_true) r = ensure_no_overflow(); + CTRACE("array", r != l_true, display(tout);); + switch (r) { + case l_true: + return FC_DONE; + case l_false: + return FC_CONTINUE; + case l_undef: + return FC_GIVEUP; + } + return FC_GIVEUP; + } + + void init_model() { + for (auto const& kv : m_sizeof) { + sz_info& i = *kv.m_value; + app* sz = kv.m_key; + if (is_true(sz) && is_leaf(i) && rational(i.m_selects.size()) != i.m_value) { + warning_msg("models for BAPA is TBD"); + break; + } + } + } + + }; + + theory_array_bapa::theory_array_bapa(theory_array_full& th) { m_imp = alloc(imp, th); } + theory_array_bapa::~theory_array_bapa() { dealloc(m_imp); } + void theory_array_bapa::internalize_size(app* term) { m_imp->internalize_size(term); } + final_check_status theory_array_bapa::final_check() { return m_imp->final_check(); } + void theory_array_bapa::init_model() { m_imp->init_model(); } +} diff --git a/src/smt/theory_array_bapa.h b/src/smt/theory_array_bapa.h new file mode 100644 index 000000000..b3e91ca2c --- /dev/null +++ b/src/smt/theory_array_bapa.h @@ -0,0 +1,43 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + theory_array_bapa.h + +Abstract: + + + +Author: + + Nikolaj Bjorner 2019-04-13 + +Revision History: + +--*/ +#ifndef THEORY_ARRAY_BAPA_H_ +#define THEORY_ARRAY_BAPA_H_ + +#include "ast/ast.h" +#include "smt/smt_theory.h" + +namespace smt { + + class theory_array_full; + + class theory_array_bapa { + class imp; + imp* m_imp; + public: + theory_array_bapa(theory_array_full& th); + ~theory_array_bapa(); + void internalize_size(app* term); + final_check_status final_check(); + void init_model(); + }; + +}; + +#endif /* THEORY_ARRAY_BAPA_H_ */ + diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 9706f7160..af9d87cf5 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -602,6 +602,7 @@ namespace smt { collect_defaults(); collect_selects(); propagate_selects(); + if (m_bapa) m_bapa->init_model(); } /** diff --git a/src/smt/theory_array_base.h b/src/smt/theory_array_base.h index 730c02f94..5a6321379 100644 --- a/src/smt/theory_array_base.h +++ b/src/smt/theory_array_base.h @@ -20,12 +20,14 @@ Revision History: #define THEORY_ARRAY_BASE_H_ #include "smt/smt_theory.h" +#include "smt/theory_array_bapa.h" #include "ast/array_decl_plugin.h" #include "smt/proto_model/array_factory.h" namespace smt { class theory_array_base : public theory { + friend class theory_array_bapa; protected: bool m_found_unsupported_op; @@ -40,6 +42,7 @@ namespace smt { bool is_as_array(app const * n) const { return n->is_app_of(get_id(), OP_AS_ARRAY); } bool is_array_sort(sort const* s) const { return s->is_sort_of(get_id(), ARRAY_SORT); } bool is_array_sort(app const* n) const { return is_array_sort(get_manager().get_sort(n)); } + bool is_set_has_size(app const* n) const { return n->is_app_of(get_id(), OP_SET_HAS_SIZE); } bool is_store(enode const * n) const { return is_store(n->get_owner()); } bool is_map(enode const* n) const { return is_map(n->get_owner()); } @@ -48,6 +51,7 @@ namespace smt { bool is_as_array(enode const * n) const { return is_as_array(n->get_owner()); } bool is_default(enode const* n) const { return is_default(n->get_owner()); } bool is_array_sort(enode const* n) const { return is_array_sort(n->get_owner()); } + bool is_set_has_size(enode const* n) const { return is_set_has_size(n->get_owner()); } app * mk_select(unsigned num_args, expr * const * args); @@ -60,6 +64,7 @@ namespace smt { ptr_vector m_axiom1_todo; enode_pair_vector m_axiom2_todo; enode_pair_vector m_extensionality_todo; + scoped_ptr m_bapa; void assert_axiom(unsigned num_lits, literal * lits); void assert_axiom(literal l1, literal l2); diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 3931f06fb..4457d99ff 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -250,7 +250,7 @@ namespace smt { return theory_array::internalize_term(n); } - if (!is_const(n) && !is_default(n) && !is_map(n) && !is_as_array(n)) { + if (!is_const(n) && !is_default(n) && !is_map(n) && !is_as_array(n) && !is_set_has_size(n)) { if (!is_array_ext(n)) found_unsupported_op(n); return false; @@ -274,6 +274,12 @@ namespace smt { mk_var(arg0); } } + else if (is_set_has_size(n)) { + if (!m_bapa) { + m_bapa = alloc(theory_array_bapa, *this); + } + m_bapa->internalize_size(n); + } enode* node = ctx.get_enode(n); if (!is_attached_to_var(node)) { @@ -748,6 +754,10 @@ namespace smt { assert_axiom(eq); r = FC_CONTINUE; } + if (r == FC_DONE && m_bapa) { + r = m_bapa->final_check(); + } + if (r == FC_DONE && m_found_unsupported_op) r = FC_GIVEUP; return r; diff --git a/src/util/trail.h b/src/util/trail.h index fadafe724..984281e5a 100644 --- a/src/util/trail.h +++ b/src/util/trail.h @@ -43,6 +43,12 @@ public: m_old_value(value) { } + value_trail(T & value, T const& new_value): + m_value(value), + m_old_value(value) { + m_value = new_value; + } + ~value_trail() override { } From f0c013843f7fc149a1f3b492a9d66853cd52a480 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 13 Apr 2019 16:30:47 -0700 Subject: [PATCH 147/156] operator+ Signed-off-by: Nikolaj Bjorner --- src/ast/ast_util.cpp | 5 +---- src/ast/ast_util.h | 5 +---- src/smt/theory_array_bapa.cpp | 5 +++-- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/ast/ast_util.cpp b/src/ast/ast_util.cpp index 15eab50b9..89c662822 100644 --- a/src/ast/ast_util.cpp +++ b/src/ast/ast_util.cpp @@ -373,7 +373,4 @@ static app_ref plus(ast_manager& m, expr* a, int i) { return app_ref(arith.mk_add(a, arith.mk_int(i)), m); } -app_ref operator+(expr_ref& a, expr* b) { return plus(a.m(), a, b); } -app_ref operator+(app_ref& a, expr* b) { return plus(a.m(), a, b); } -app_ref operator+(expr_ref& a, int i) { return plus(a.m(), a, i); } -app_ref operator+(app_ref& a, int i) { return plus(a.m(), a, i); } +app_ref operator+(expr_ref& a, expr_ref& b) { return plus(a.m(), a, b); } diff --git a/src/ast/ast_util.h b/src/ast/ast_util.h index fe4bde465..58cfa48b9 100644 --- a/src/ast/ast_util.h +++ b/src/ast/ast_util.h @@ -120,10 +120,7 @@ inline app_ref operator|(expr_ref& a, expr* b) { return app_ref(a.m().mk_or(a, b inline app_ref operator|(app_ref& a, expr* b) { return app_ref(a.m().mk_or(a, b), a.m()); } inline app_ref operator|(var_ref& a, expr* b) { return app_ref(a.m().mk_or(a, b), a.m()); } inline app_ref operator|(quantifier_ref& a, expr* b) { return app_ref(a.m().mk_or(a, b), a.m()); } -app_ref operator+(expr_ref& a, expr* b); -app_ref operator+(app_ref& a, expr* b); -app_ref operator+(expr_ref& a, int i); -app_ref operator+(app_ref& a, int i); +app_ref operator+(expr_ref& a, expr_ref& b); /** Return (or args[0] ... args[num_args-1]) if num_args >= 2 diff --git a/src/smt/theory_array_bapa.cpp b/src/smt/theory_array_bapa.cpp index 51b0186e2..3ed16592d 100644 --- a/src/smt/theory_array_bapa.cpp +++ b/src/smt/theory_array_bapa.cpp @@ -35,8 +35,7 @@ Q: Is this sufficient? Axiom A1 could be adjusted to add new elements i' until t This is quite bad when k is very large. Instead rely on stably infiniteness or other domain properties of the theories. When A is finite domain, or there are quantifiers there could be constraints that force domain sizes so domain sizes may have -to be enforced. A succinct way would be through domain comprehension assertions. Thus, if we have -S[i1],.., S[ik], !S[j1],...,!S[jl] asserted on integer domain i, then +to be enforced. A succinct way would be through domain comprehension assertions. Finite domains: @@ -53,6 +52,8 @@ Finite domains: --------------------------------------------------------------- Size(S, n) n fresh. + Model construction for infinite domains when all Size(S, m) are negative for S. + */ #include "ast/ast_util.h" From b4ba44ce9d39b784a07d9b6a878193af03946219 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 13 Apr 2019 16:35:10 -0700 Subject: [PATCH 148/156] remove unused candidate function Signed-off-by: Nikolaj Bjorner --- src/ast/ast_util.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/ast/ast_util.cpp b/src/ast/ast_util.cpp index 89c662822..6ca9d3797 100644 --- a/src/ast/ast_util.cpp +++ b/src/ast/ast_util.cpp @@ -368,9 +368,7 @@ static app_ref plus(ast_manager& m, expr* a, expr* b) { return app_ref(arith.mk_add(a, b), m); } -static app_ref plus(ast_manager& m, expr* a, int i) { - arith_util arith(m); - return app_ref(arith.mk_add(a, arith.mk_int(i)), m); -} -app_ref operator+(expr_ref& a, expr_ref& b) { return plus(a.m(), a, b); } +app_ref operator+(expr_ref& a, expr_ref& b) { + return plus(a.m(), a.get(), b.get()); +} From 6158ea61c8133360c31d4d0f3ba50fc1512e09ce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Apr 2019 00:04:48 -0700 Subject: [PATCH 149/156] fix tree-order, change API for special relations to produce function declarations Signed-off-by: Nikolaj Bjorner --- src/api/api_special_relations.cpp | 22 ++++----- src/api/c++/z3++.h | 24 +++------ src/api/python/z3/z3.py | 12 +++++ src/api/z3_api.h | 28 +++++------ src/ast/reg_decl_plugins.cpp | 4 ++ src/smt/diff_logic.h | 16 +++--- src/smt/theory_special_relations.cpp | 74 ++++++++++++++-------------- src/smt/theory_special_relations.h | 3 -- 8 files changed, 92 insertions(+), 91 deletions(-) diff --git a/src/api/api_special_relations.cpp b/src/api/api_special_relations.cpp index 497ac15e0..2bb40a5e1 100644 --- a/src/api/api_special_relations.cpp +++ b/src/api/api_special_relations.cpp @@ -28,22 +28,22 @@ Revision History: extern "C" { -#define MK_TERN(NAME, FID) \ - Z3_ast Z3_API NAME(Z3_context c, unsigned index, Z3_ast a, Z3_ast b) { \ - LOG_ ##NAME(c, index, a, b); \ +#define MK_SPECIAL_R(NAME, FID) \ + Z3_func_decl Z3_API NAME(Z3_context c, Z3_sort s, unsigned index) { \ + LOG_ ##NAME(c, s, index); \ Z3_TRY; \ - expr* args[2] = { to_expr(a), to_expr(b) }; \ parameter p(index); \ - ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_special_relations_fid(), FID, 1, &p, 2, args); \ - mk_c(c)->save_ast_trail(a); \ - RETURN_Z3(of_ast(a)); \ + sort* domain[2] = { to_sort(s), to_sort(s) }; \ + func_decl* f = mk_c(c)->m().mk_func_decl(mk_c(c)->get_special_relations_fid(), FID, 1, &p, 2, domain, mk_c(c)->m().mk_bool_sort()); \ + mk_c(c)->save_ast_trail(f); \ + RETURN_Z3(of_func_decl(f)); \ Z3_CATCH_RETURN(nullptr); \ } - MK_TERN(Z3_mk_linear_order, OP_SPECIAL_RELATION_LO); - MK_TERN(Z3_mk_partial_order, OP_SPECIAL_RELATION_PO); - MK_TERN(Z3_mk_piecewise_linear_order, OP_SPECIAL_RELATION_PLO); - MK_TERN(Z3_mk_tree_order, OP_SPECIAL_RELATION_TO); + MK_SPECIAL_R(Z3_mk_linear_order, OP_SPECIAL_RELATION_LO); + MK_SPECIAL_R(Z3_mk_partial_order, OP_SPECIAL_RELATION_PO); + MK_SPECIAL_R(Z3_mk_piecewise_linear_order, OP_SPECIAL_RELATION_PLO); + MK_SPECIAL_R(Z3_mk_tree_order, OP_SPECIAL_RELATION_TO); #define MK_DECL(NAME, FID) \ diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index fd7cb3a90..a7f1259a0 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1715,25 +1715,17 @@ namespace z3 { */ inline expr sext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_sign_ext(a.ctx(), i, a)); } - typedef Z3_ast Z3_apply_order(Z3_context, unsigned, Z3_ast, Z3_ast); - - inline expr apply_order(Z3_apply_order app, unsigned index, expr const& a, expr const& b) { - check_context(a, b); - Z3_ast r = app(a.ctx(), index, a, b); - a.check_error(); - return expr(a.ctx(), r); + inline func_decl linear_order(sort const& a, unsigned index) { + return to_func_decl(a.ctx(), Z3_mk_linear_order(a.ctx(), a, index)); } - inline expr linear_order(unsigned index, expr const& a, expr const& b) { - return apply_order(Z3_mk_linear_order, index, a, b); + inline func_decl partial_order(sort const& a, unsigned index) { + return to_func_decl(a.ctx(), Z3_mk_partial_order(a.ctx(), a, index)); } - inline expr partial_order(unsigned index, expr const& a, expr const& b) { - return apply_order(Z3_mk_partial_order, index, a, b); + inline func_decl piecewise_linear_order(sort const& a, unsigned index) { + return to_func_decl(a.ctx(), Z3_mk_piecewise_linear_order(a.ctx(), a, index)); } - inline expr piecewise_linear_order(unsigned index, expr const& a, expr const& b) { - return apply_order(Z3_mk_piecewise_linear_order, index, a, b); - } - inline expr tree_order(unsigned index, expr const& a, expr const& b) { - return apply_order(Z3_mk_tree_order, index, a, b); + inline func_decl tree_order(sort const& a, unsigned index) { + return to_func_decl(a.ctx(), Z3_mk_tree_order(a.ctx(), a, index)); } template class cast_ast; diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 242c73e67..dfa5a0b41 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10379,6 +10379,18 @@ def Range(lo, hi, ctx = None): # Special Relations +def PartialOrder(a, index): + return FuncDeclRef(Z3_mk_partial_order(a.ctx_ref(), a.ast, index), a.ctx); + +def LinearOrder(a, index): + return FuncDeclRef(Z3_mk_linear_order(a.ctx_ref(), a.ast, index), a.ctx); + +def TreeOrder(a, index): + return FuncDeclRef(Z3_mk_tree_order(a.ctx_ref(), a.ast, index), a.ctx); + +def PiecewiseLinearOrder(a, index): + return FuncDeclRef(Z3_mk_piecewise_linear_order(a.ctx_ref(), a.ast, index), a.ctx); + def TransitiveClosure(f): """Given a binary relation R, such that the two arguments have the same sort create the transitive closure relation R+. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index e154eaf50..2c07ae73a 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3627,36 +3627,30 @@ extern "C" { \pre a and b are of same type. - def_API('Z3_mk_linear_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) + def_API('Z3_mk_linear_order', FUNC_DECL ,(_in(CONTEXT), _in(SORT), _in(UINT))) */ - Z3_ast Z3_API Z3_mk_linear_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); + Z3_func_decl Z3_API Z3_mk_linear_order(Z3_context c, Z3_sort a, unsigned id); /** - \brief declare \c a and \c b are in partial order over a relation indexed by \c id. + \brief create a partial ordering relation over signature \c a and index \c id. - \pre a and b are of same type. - - def_API('Z3_mk_partial_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) + def_API('Z3_mk_partial_order', FUNC_DECL ,(_in(CONTEXT), _in(SORT), _in(UINT))) */ - Z3_ast Z3_API Z3_mk_partial_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); + Z3_func_decl Z3_API Z3_mk_partial_order(Z3_context c, Z3_sort a, unsigned id); /** - \brief declare \c a and \c b are in piecewise linear order indexed by relation \c id. + \brief create a piecewise linear ordering relation over signature \c a and index \c id. - \pre a and b are of same type. - - def_API('Z3_mk_piecewise_linear_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) + def_API('Z3_mk_piecewise_linear_order', FUNC_DECL ,(_in(CONTEXT), _in(SORT), _in(UINT))) */ - Z3_ast Z3_API Z3_mk_piecewise_linear_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); + Z3_func_decl Z3_API Z3_mk_piecewise_linear_order(Z3_context c, Z3_sort a, unsigned id); /** - \brief declare \c a and \c b are in tree order indexed by \c id. + \brief create a tree ordering lreation over signature \c a identified using index \c id. - \pre a and b are of same type. - - def_API('Z3_mk_tree_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) + def_API('Z3_mk_tree_order', FUNC_DECL, (_in(CONTEXT), _in(SORT), _in(UINT))) */ - Z3_ast Z3_API Z3_mk_tree_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); + Z3_func_decl Z3_API Z3_mk_tree_order(Z3_context c, Z3_sort a, unsigned id); /** \brief create transitive closure of binary relation. diff --git a/src/ast/reg_decl_plugins.cpp b/src/ast/reg_decl_plugins.cpp index 7e121eb7f..6c88f2503 100644 --- a/src/ast/reg_decl_plugins.cpp +++ b/src/ast/reg_decl_plugins.cpp @@ -27,6 +27,7 @@ Revision History: #include "ast/seq_decl_plugin.h" #include "ast/pb_decl_plugin.h" #include "ast/fpa_decl_plugin.h" +#include "ast/special_relations_decl_plugin.h" void reg_decl_plugins(ast_manager & m) { if (!m.get_plugin(m.mk_family_id(symbol("arith")))) { @@ -56,4 +57,7 @@ void reg_decl_plugins(ast_manager & m) { if (!m.get_plugin(m.mk_family_id(symbol("pb")))) { m.register_plugin(symbol("pb"), alloc(pb_decl_plugin)); } + if (!m.get_plugin(m.mk_family_id(symbol("special_relations")))) { + m.register_plugin(symbol("special_relations"), alloc(special_relations_decl_plugin)); + } } diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 0e8bd47e1..7899ef8da 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -663,19 +663,19 @@ public: visited.reset(); svector nodes; nodes.push_back(start); - for (dl_var n : nodes) { + for (unsigned i = 0; i < nodes.size(); ++i) { + dl_var n = nodes[i]; if (visited.contains(n)) continue; visited.insert(n); edge_id_vector & edges = m_out_edges[n]; for (edge_id e_id : edges) { - edge & e = m_edges[e_id]; - if (e.is_enabled()) { - dst = e.get_target(); - if (target.contains(dst)) { - return true; - } - nodes.push_back(dst); + edge & e = m_edges[e_id]; + if (!e.is_enabled()) continue; + dst = e.get_target(); + if (target.contains(dst)) { + return true; } + nodes.push_back(dst); } } return false; diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 07fd42ad6..e385034b8 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -20,16 +20,14 @@ Notes: #include -#include "smt/smt_context.h" -#include "smt/theory_arith.h" -#include "smt/theory_special_relations.h" -#include "smt/smt_solver.h" -#include "solver/solver.h" #include "ast/reg_decl_plugins.h" #include "ast/datatype_decl_plugin.h" #include "ast/recfun_decl_plugin.h" #include "ast/ast_pp.h" #include "ast/rewriter/recfun_replace.h" +#include "smt/smt_context.h" +#include "smt/theory_arith.h" +#include "smt/theory_special_relations.h" namespace smt { @@ -411,19 +409,22 @@ namespace smt { uint_set visited, target; for (atom* ap : r.m_asserted_atoms) { atom& a = *ap; - if (a.phase() || r.m_uf.find(a.v1()) != r.m_uf.find(a.v2())) { + if (a.phase()) { continue; } + TRACE("special_relations", tout << a.v1() << " !<= " << a.v2() << "\n";); target.reset(); theory_var w; - // v2 !<= v1 is asserted - target.insert(a.v2()); - if (r.m_graph.reachable(a.v1(), target, visited, w)) { - // we already have v1 <= v2 + // v1 !<= v2 is asserted + target.insert(a.v1()); + if (r.m_graph.reachable(a.v2(), target, visited, w)) { + // we already have v2 <= v1 + TRACE("special_relations", tout << "already: " << a.v2() << " <= " << a.v1() << "\n";); continue; } // the nodes visited from v1 become target for v2 if (r.m_graph.reachable(a.v2(), visited, target, w)) { + // // we have the following: // v1 <= w // v2 <= w @@ -437,6 +438,7 @@ namespace smt { r.m_explanation.reset(); r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r); r.m_graph.find_shortest_reachable_path(a.v2(), w, timestamp, r); + TRACE("special_relations", tout << "added edge\n";); r.m_explanation.push_back(a.explanation()); literal_vector const& lits = r.m_explanation; if (!r.m_graph.add_non_strict_edge(a.v2(), a.v1(), lits)) { @@ -444,6 +446,18 @@ namespace smt { return l_false; } } + target.reset(); + visited.reset(); + target.insert(a.v2()); + if (r.m_graph.reachable(a.v1(), target, visited, w)) { + // we have v1 <= v2 + unsigned timestamp = r.m_graph.get_timestamp(); + r.m_explanation.reset(); + r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r); + r.m_explanation.push_back(a.explanation()); + set_conflict(r); + } + } return l_true; } @@ -743,24 +757,26 @@ namespace smt { TRACE("special_relations", g.display(tout);); } + /** + src1 <= i, src2 <= i, src1 != src2 => src1 !<= src2 + */ + void theory_special_relations::ensure_tree(graph& g) { unsigned sz = g.get_num_nodes(); for (unsigned i = 0; i < sz; ++i) { int_vector const& edges = g.get_in_edges(i); for (unsigned j = 0; j < edges.size(); ++j) { edge_id e1 = edges[j]; - if (g.is_enabled(e1)) { - SASSERT (i == g.get_target(e1)); - dl_var src1 = g.get_source(e1); - for (unsigned k = j + 1; k < edges.size(); ++k) { - edge_id e2 = edges[k]; - if (g.is_enabled(e2)) { - dl_var src2 = g.get_source(e2); - if (get_enode(src1)->get_root() != get_enode(src2)->get_root() && - disconnected(g, src1, src2)) { - VERIFY(g.add_strict_edge(src1, src2, literal_vector())); - } - } + if (!g.is_enabled(e1)) continue; + SASSERT (i == g.get_target(e1)); + dl_var src1 = g.get_source(e1); + for (unsigned k = j + 1; k < edges.size(); ++k) { + edge_id e2 = edges[k]; + if (!g.is_enabled(e2)) continue; + dl_var src2 = g.get_source(e2); + if (get_enode(src1)->get_root() != get_enode(src2)->get_root() && + disconnected(g, src1, src2)) { + VERIFY(g.add_strict_edge(src1, src2, literal_vector())); } } } @@ -889,20 +905,6 @@ namespace smt { a fixed set of edges. It runs in O(e*n^2) where n is the number of vertices and e number of edges. - connected1(x, y, v, w, S) = - if x = v then - if y = w then (S, true) else - if w in S then (S, false) else - connected2(w, y, S u { w }, edges) - else (S, false) - - connected2(x, y, S, []) = (S, false) - connected2(x, y, S, (u,w)::edges) = - let (S, c) = connected1(x, y, u, w, S) - if c then (S, true) else connected2(x, y, S, edges) - - -Take 2: connected(A, dst, S) = let (A',S') = next1(a1, b1, A, next1(a2, b2, A, ... S, (nil, S))) if A' = nil then false else diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 83beb35bb..ae134a366 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -127,9 +127,6 @@ namespace smt { std::ostream& display(theory_special_relations const& sr, std::ostream& out) const; }; - - - typedef u_map bool_var2atom; special_relations_util m_util; From c611fbeaee1ac8587e0fd6e6aeda1736506628c2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 16 Apr 2019 12:50:04 +0100 Subject: [PATCH 150/156] Fix RoundingMode value generation in FPA theory. Fixes #2239. --- src/smt/theory_fpa.h | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 75bcec13c..e46ddd92b 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -47,19 +47,31 @@ namespace smt { expr * get_some_value(sort * s) override { mpf_manager & mpfm = m_util.fm(); - scoped_mpf q(mpfm); - mpfm.set(q, m_util.get_ebits(s), m_util.get_sbits(s), 0); - return m_util.mk_value(q); + + if (m_util.is_rm(s)) + return m_util.mk_round_toward_zero(); + else + { + scoped_mpf q(mpfm); + mpfm.set(q, m_util.get_ebits(s), m_util.get_sbits(s), 0); + return m_util.mk_value(q); + } } bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) override { mpf_manager & mpfm = m_util.fm(); - scoped_mpf q(mpfm); - mpfm.set(q, m_util.get_ebits(s), m_util.get_sbits(s), 0); - v1 = m_util.mk_value(q); - mpfm.set(q, m_util.get_ebits(s), m_util.get_sbits(s), 1); - v2 = m_util.mk_value(q); - return true; + + if (m_util.is_rm(s)) + v1 = v2 = m_util.mk_round_toward_zero(); + else + { + scoped_mpf q(mpfm); + mpfm.set(q, m_util.get_ebits(s), m_util.get_sbits(s), 0); + v1 = m_util.mk_value(q); + mpfm.set(q, m_util.get_ebits(s), m_util.get_sbits(s), 1); + v2 = m_util.mk_value(q); + } + return true; } expr * get_fresh_value(sort * s) override { return get_some_value(s); } From 596acf26ce68b053b7277e3159adc0110154d1a0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Apr 2019 10:39:34 -0700 Subject: [PATCH 151/156] take second suggestion from #2234 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_parse.cpp | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp index 215650300..2a8528ca3 100644 --- a/src/opt/opt_parse.cpp +++ b/src/opt/opt_parse.cpp @@ -687,14 +687,22 @@ private: return peek(pos) == "<=" || peek(pos) == "=<"; } - bool peek_minus_infty(unsigned pos) { + bool peek_minus_infty_long(unsigned pos) { return peek(pos) == "-" && (peek(pos+1) == "inf" || peek(pos+1) == "infinity"); } - bool peek_plus_infty(unsigned pos) { + bool peek_minus_infty_short(unsigned pos) { + return peek(pos) == "-inf" || peek(pos) == "-infinity"; + } + + bool peek_plus_infty_long(unsigned pos) { return peek(pos) == "+" && (peek(pos+1) == "inf" || peek(pos+1) == "infinity"); } + bool peek_plus_infty_short(unsigned pos) { + return peek(pos) == "+inf" || peek(pos) == "+infinity"; + } + void parse_indicator(symbol& var, rational& val) { if (peek(1) == "=" && tok.peek_num(2) && peek(3) == "->") { var = peek(0); @@ -731,14 +739,22 @@ private: tok.next(3); parse_upper(v); } - else if (peek_minus_infty(0) && peek_le(2)) { + else if (peek_minus_infty_long(0) && peek_le(2)) { v = peek(3); tok.next(4); parse_upper(v); } - else if (peek_plus_infty(2) && peek_le(1)) { + else if (peek_minus_infty_short(0) && peek_le(1)) { + v = peek(2); + tok.next(3); + parse_upper(v); + } + else if (peek_plus_infty_long(2) && peek_le(1)) { tok.next(4); } + else if (peek_plus_infty_short(2) && peek_le(1)) { + tok.next(3); + } else if (peek_le(1) && tok.peek_num(2)) { v = peek(0); tok.next(2); @@ -757,9 +773,11 @@ private: update_upper(v, rhs); tok.next(2); } - else if (peek_le(0) && peek_plus_infty(1)) { + else if (peek_le(0) && peek_plus_infty_long(1)) { tok.next(3); } + else if (peek_le(0) && peek_plus_infty_short(1)) { + tok.next(2); } } From 153106a6a781a16bb10ed3896f7d631d12205f30 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Apr 2019 12:43:41 -0700 Subject: [PATCH 152/156] fix initialization ordering to follow declaration order Signed-off-by: Nikolaj Bjorner --- src/smt/theory_array_bapa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_array_bapa.cpp b/src/smt/theory_array_bapa.cpp index 3ed16592d..e6234e76a 100644 --- a/src/smt/theory_array_bapa.cpp +++ b/src/smt/theory_array_bapa.cpp @@ -400,9 +400,9 @@ namespace smt { imp(theory_array_full& th): m(th.get_manager()), th(th), - m_rw(m), m_arith(m), m_autil(m), + m_rw(m), m_arith_value(m), m_pinned(m) { From d4410d0872df166c3b8c72e075ae73a1d0d2e65d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Apr 2019 14:32:48 -0700 Subject: [PATCH 153/156] address compilation warnings of unused parameters, add shorthands to set parameters on Optimize Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Optimize.cs | 41 ++++++++++++++++++++ src/ast/array_decl_plugin.cpp | 1 - src/sat/sat_solver.cpp | 5 +-- src/tactic/core/special_relations_tactic.cpp | 1 - 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index 9a7bd3bd1..66b0df82c 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -53,6 +53,47 @@ namespace Microsoft.Z3 } } + /// + /// Sets parameter on the optimize solver + /// + public void Set(string name, bool value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the optimize solver + /// + public void Set(string name, uint value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the optimize solver + /// + public void Set(string name, double value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the optimize solver + /// + public void Set(string name, string value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the optimize solver + /// + public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the optimize solver + /// + public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the optimize solver + /// + public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the optimize solver + /// + public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the optimize solver + /// + public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the optimize solver + /// + public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + /// /// Retrieves parameter descriptions for Optimize solver. /// diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index a470bd353..f7a299131 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -605,7 +605,6 @@ bool array_recognizers::is_const(expr* e, expr*& v) const { } bool array_recognizers::is_store_ext(expr* _e, expr_ref& a, expr_ref_vector& args, expr_ref& value) { - ast_manager& m = a.m(); if (is_store(_e)) { app* e = to_app(_e); a = e->get_arg(0); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a0bd94303..9241c4eaa 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2508,13 +2508,12 @@ namespace sat { TRACE("sat_lemma", tout << "new lemma size: " << m_lemma.size() << "\n" << m_lemma << "\n";); unsigned new_scope_lvl = 0; - bool sub_min = false, res_min = false; if (!m_lemma.empty()) { if (m_config.m_minimize_lemmas) { - res_min = minimize_lemma(); + minimize_lemma(); reset_lemma_var_marks(); if (m_config.m_dyn_sub_res) - sub_min = dyn_sub_res(); + dyn_sub_res(); TRACE("sat_lemma", tout << "new lemma (after minimization) size: " << m_lemma.size() << "\n" << m_lemma << "\n";); } else diff --git a/src/tactic/core/special_relations_tactic.cpp b/src/tactic/core/special_relations_tactic.cpp index a8b74db31..0016e2fe0 100644 --- a/src/tactic/core/special_relations_tactic.cpp +++ b/src/tactic/core/special_relations_tactic.cpp @@ -135,7 +135,6 @@ void special_relations_tactic::operator()(goal_ref const & g, goal_ref_buffer & func_decl_replace replace(m); unsigned_vector to_delete; for(auto const& kv : goal_features) { - func_decl* sp = nullptr; sr_property feature = kv.m_value.m_sp_features; switch (feature) { case sr_po: From 502b29c4249e3363e9e0aa96d890c1a0c831bb45 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Apr 2019 15:38:14 -0700 Subject: [PATCH 154/156] add set-has-size to API and python bindings Signed-off-by: Nikolaj Bjorner --- src/api/api_array.cpp | 1 + src/api/python/z3/z3.py | 5 +++++ src/api/z3_api.h | 8 ++++++++ src/smt/theory_array_base.cpp | 2 +- 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index a9f5d7d70..bec0e7560 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -263,6 +263,7 @@ extern "C" { MK_UNARY(Z3_mk_set_complement, mk_c(c)->get_array_fid(), OP_SET_COMPLEMENT, SKIP); MK_BINARY(Z3_mk_set_subset, mk_c(c)->get_array_fid(), OP_SET_SUBSET, SKIP); MK_BINARY(Z3_mk_array_ext, mk_c(c)->get_array_fid(), OP_ARRAY_EXT, SKIP); + MK_BINARY(Z3_mk_set_has_size, mk_c(c)->get_array_fid(), OP_SET_HAS_SIZE, SKIP); Z3_ast Z3_API Z3_mk_as_array(Z3_context c, Z3_func_decl f) { Z3_TRY; diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index dfa5a0b41..485107e44 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -4504,6 +4504,11 @@ def Ext(a, b): _z3_assert(is_array(a) and is_array(b), "arguments must be arrays") return _to_expr_ref(Z3_mk_array_ext(ctx.ref(), a.as_ast(), b.as_ast()), ctx) +def SetHasSize(a, k): + ctx = a.ctx + k = _py2expr(k, ctx) + return _to_expr_ref(Z3_mk_set_has_size(ctx.ref(), a.as_ast(), k.as_ast()), ctx) + def is_select(a): """Return `True` if `a` is a Z3 array select application. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 2c07ae73a..f4db07cfc 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3106,6 +3106,14 @@ extern "C" { def_API('Z3_mk_as_array', AST, (_in(CONTEXT), _in(FUNC_DECL))) */ Z3_ast Z3_API Z3_mk_as_array(Z3_context c, Z3_func_decl f); + + /** + \brief Create predicate that holds if Boolean array \c set has \c k elements set to true. + + def_API('Z3_mk_set_has_size', AST, (_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_set_has_size(Z3_context c, Z3_ast set, Z3_ast k); + /*@}*/ /** @name Sets */ diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index af9d87cf5..a9418f3b6 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -621,7 +621,7 @@ namespace smt { if (!ctx.is_relevant(n)) continue; - if (is_store(n) || is_const(n) || is_default(n)) + if (is_store(n) || is_const(n) || is_default(n) || is_set_has_size(n)) return false; } return true; From 86b98e3477e8f57ccbbcf7a1444ac8ffbf0fae73 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Apr 2019 10:47:46 -0700 Subject: [PATCH 155/156] remove trc Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 1 - src/api/api_special_relations.cpp | 1 - src/api/z3_api.h | 11 ------ src/ast/special_relations_decl_plugin.cpp | 6 +--- src/ast/special_relations_decl_plugin.h | 5 --- src/smt/theory_array_bapa.cpp | 27 +++++++++++++- src/smt/theory_array_bapa.h | 2 +- src/smt/theory_special_relations.cpp | 44 ----------------------- src/smt/theory_special_relations.h | 2 -- 9 files changed, 28 insertions(+), 71 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 5c945d168..6c1f068b5 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1059,7 +1059,6 @@ extern "C" { case OP_SPECIAL_RELATION_PLO: return Z3_OP_SPECIAL_RELATION_PLO; case OP_SPECIAL_RELATION_TO : return Z3_OP_SPECIAL_RELATION_TO; case OP_SPECIAL_RELATION_TC : return Z3_OP_SPECIAL_RELATION_TC; - case OP_SPECIAL_RELATION_TRC : return Z3_OP_SPECIAL_RELATION_TRC; default: UNREACHABLE(); } } diff --git a/src/api/api_special_relations.cpp b/src/api/api_special_relations.cpp index 2bb40a5e1..3b4872435 100644 --- a/src/api/api_special_relations.cpp +++ b/src/api/api_special_relations.cpp @@ -62,5 +62,4 @@ extern "C" { } MK_DECL(Z3_mk_transitive_closure, OP_SPECIAL_RELATION_TC); - MK_DECL(Z3_mk_transitive_reflexive_closure, OP_SPECIAL_RELATION_TRC); }; diff --git a/src/api/z3_api.h b/src/api/z3_api.h index f4db07cfc..0d9f548ef 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3671,17 +3671,6 @@ extern "C" { */ Z3_func_decl Z3_API Z3_mk_transitive_closure(Z3_context c, Z3_func_decl f); - /** - \brief create transitive reflexive closure of binary relation. - - \pre f is a binary relation, such that the two arguments have the same sorts. - - The resulting relation f* represents the transitive-reflexive closure of f. - - def_API('Z3_mk_transitive_reflexive_closure', FUNC_DECL ,(_in(CONTEXT), _in(FUNC_DECL))) - */ - Z3_func_decl Z3_API Z3_mk_transitive_reflexive_closure(Z3_context c, Z3_func_decl f); - /*@}*/ /** @name Quantifiers */ diff --git a/src/ast/special_relations_decl_plugin.cpp b/src/ast/special_relations_decl_plugin.cpp index 2b280b28a..5dc5f32fe 100644 --- a/src/ast/special_relations_decl_plugin.cpp +++ b/src/ast/special_relations_decl_plugin.cpp @@ -26,8 +26,7 @@ special_relations_decl_plugin::special_relations_decl_plugin(): m_po("partial-order"), m_plo("piecewise-linear-order"), m_to("tree-order"), - m_tc("transitive-closure"), - m_trc("transitive-reflexive-closure") + m_tc("transitive-closure") {} func_decl * special_relations_decl_plugin::mk_func_decl( @@ -56,7 +55,6 @@ func_decl * special_relations_decl_plugin::mk_func_decl( case OP_SPECIAL_RELATION_PLO: name = m_plo; break; case OP_SPECIAL_RELATION_TO: name = m_to; break; case OP_SPECIAL_RELATION_TC: name = m_tc; break; - case OP_SPECIAL_RELATION_TRC: name = m_trc; break; } return m_manager->mk_func_decl(name, arity, domain, range, info); } @@ -68,7 +66,6 @@ void special_relations_decl_plugin::get_op_names(svector & op_name op_names.push_back(builtin_name(m_plo.bare_str(), OP_SPECIAL_RELATION_PLO)); op_names.push_back(builtin_name(m_to.bare_str(), OP_SPECIAL_RELATION_TO)); op_names.push_back(builtin_name(m_tc.bare_str(), OP_SPECIAL_RELATION_TC)); - op_names.push_back(builtin_name(m_trc.bare_str(), OP_SPECIAL_RELATION_TRC)); } } @@ -79,7 +76,6 @@ sr_property special_relations_util::get_property(func_decl* f) const { case OP_SPECIAL_RELATION_PLO: return sr_plo; case OP_SPECIAL_RELATION_TO: return sr_to; case OP_SPECIAL_RELATION_TC: return sr_tc; - case OP_SPECIAL_RELATION_TRC: return sr_trc; default: UNREACHABLE(); return sr_po; diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index f7a3b963d..339fdc82e 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -29,7 +29,6 @@ enum special_relations_op_kind { OP_SPECIAL_RELATION_PLO, OP_SPECIAL_RELATION_TO, OP_SPECIAL_RELATION_TC, - OP_SPECIAL_RELATION_TRC, LAST_SPECIAL_RELATIONS_OP }; @@ -39,7 +38,6 @@ class special_relations_decl_plugin : public decl_plugin { symbol m_plo; symbol m_to; symbol m_tc; - symbol m_trc; public: special_relations_decl_plugin(); @@ -70,7 +68,6 @@ enum sr_property { sr_plo = 0x01 | 0x02 | 0x04 | 0x08 | 0x10, // piecewise linear order sr_lo = 0x01 | 0x02 | 0x04 | 0x20, // linear order sr_tc = 0x40, // transitive closure of relation - sr_trc = 0x42 // transitive reflexive closure of relation }; class special_relations_util { @@ -93,14 +90,12 @@ public: func_decl* mk_plo_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_PLO); } func_decl* mk_lo_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_LO); } func_decl* mk_tc_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_TC); } - func_decl* mk_trc_decl(func_decl* f) { return mk_rel_decl(f, OP_SPECIAL_RELATION_TRC); } bool is_lo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_LO); } bool is_po(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PO); } bool is_plo(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_PLO); } bool is_to(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TO); } bool is_tc(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TC); } - bool is_trc(expr const * e) const { return is_app_of(e, m_fid, OP_SPECIAL_RELATION_TRC); } app * mk_lo (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_LO, arg1, arg2); } app * mk_po (expr * arg1, expr * arg2) { return m.mk_app( m_fid, OP_SPECIAL_RELATION_PO, arg1, arg2); } diff --git a/src/smt/theory_array_bapa.cpp b/src/smt/theory_array_bapa.cpp index e6234e76a..1dce9832d 100644 --- a/src/smt/theory_array_bapa.cpp +++ b/src/smt/theory_array_bapa.cpp @@ -1,4 +1,19 @@ -/** +/*++ +Copyright (c) 2019 Microsoft Corporation + +Module Name: + + theory_array_bapa.cpp + +Abstract: + + Saturation procedure for BAPA predicates. + Assume there is a predicate + + Size(S, n) for S : Array(T, Bool) and n : Int + + The predicate is true if S is a set of size n. + Size(S, n), Size(T, m) S, T are intersecting. n != m or S != T @@ -54,6 +69,12 @@ Finite domains: Model construction for infinite domains when all Size(S, m) are negative for S. +Author: + + Nikolaj Bjorner 2019-04-13 + +Revision History: + */ #include "ast/ast_util.h" @@ -470,8 +491,12 @@ namespace smt { }; theory_array_bapa::theory_array_bapa(theory_array_full& th) { m_imp = alloc(imp, th); } + theory_array_bapa::~theory_array_bapa() { dealloc(m_imp); } + void theory_array_bapa::internalize_size(app* term) { m_imp->internalize_size(term); } + final_check_status theory_array_bapa::final_check() { return m_imp->final_check(); } + void theory_array_bapa::init_model() { m_imp->init_model(); } } diff --git a/src/smt/theory_array_bapa.h b/src/smt/theory_array_bapa.h index b3e91ca2c..e99843cdd 100644 --- a/src/smt/theory_array_bapa.h +++ b/src/smt/theory_array_bapa.h @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2006 Microsoft Corporation +Copyright (c) 2019 Microsoft Corporation Module Name: diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index e385034b8..52708699a 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -322,9 +322,6 @@ namespace smt { // we need reachability in the R graph not R* graph theory_var r1 = get_representative(a.v1()); theory_var r2 = get_representative(a.v2()); - if (r.m_property == sr_trc && r1 == r2) { - continue; - } if (r_graph.can_reach(r1, r2)) { TRACE("special_relations", tout << a.v1() << ": " << mk_pp(arg1, m) << " -> " @@ -397,13 +394,6 @@ namespace smt { return final_check_po(r); } - lbool theory_special_relations::final_check_trc(relation& r) { - // - // reflexivity is enforced from propagation. - // enforce transitivity. - // - return final_check_tc(r); - } lbool theory_special_relations::final_check_to(relation& r) { uint_set visited, target; @@ -510,9 +500,6 @@ namespace smt { case sr_tc: res = final_check_tc(r); break; - case sr_trc: - res = final_check_trc(r); - break; default: UNREACHABLE(); res = l_undef; @@ -525,7 +512,6 @@ namespace smt { bool theory_special_relations::extract_equalities(relation& r) { switch (r.m_property) { case sr_tc: - case sr_trc: return false; default: break; @@ -593,30 +579,6 @@ namespace smt { return res; } - /** - \brief ensure that reflexivity is enforce for Transitive Reflexive closures - !TRC(R)xy => x != y - */ - lbool theory_special_relations::propagate_trc(atom& a) { - lbool res = l_true; - if (a.phase()) { - VERIFY(a.enable()); - relation& r = a.get_relation(); - r.m_uf.merge(a.v1(), a.v2()); - } - else { - literal lit(a.var(), true); - context& ctx = get_context(); - expr* arg1 = get_expr(a.v1()); - expr* arg2 = get_expr(a.v2()); - literal consequent = ~mk_eq(arg1, arg2, false); - justification* j = ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), 1, &lit, consequent)); - ctx.assign(consequent, j); - res = l_false; - } - return res; - } - lbool theory_special_relations::propagate_tc(atom& a) { if (a.phase()) { VERIFY(a.enable()); @@ -670,9 +632,6 @@ namespace smt { res = propagate_po(a); break; case sr_tc: - res = propagate_trc(a); - break; - case sr_trc: res = propagate_tc(a); break; default: @@ -1165,9 +1124,6 @@ namespace smt { case sr_tc: init_model_po(*kv.m_value, m, true); break; - case sr_trc: - init_model_po(*kv.m_value, m, true); - break; default: // other 28 combinations of 0x1F NOT_IMPLEMENTED_YET(); diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index ae134a366..8bf966009 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -144,7 +144,6 @@ namespace smt { lbool final_check_plo(relation& r); lbool final_check_to(relation& r); lbool final_check_tc(relation& r); - lbool final_check_trc(relation& r); lbool propagate(relation& r); lbool enable(atom& a); bool extract_equalities(relation& r); @@ -153,7 +152,6 @@ namespace smt { lbool propagate_plo(atom& a); lbool propagate_po(atom& a); lbool propagate_tc(atom& a); - lbool propagate_trc(atom& a); theory_var mk_var(expr* e); void count_children(graph const& g, unsigned_vector& num_children); void ensure_strict(graph& g); From aafb16e8ede6df8015e0c644c3e47cd4426de162 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Apr 2019 11:10:57 -0700 Subject: [PATCH 156/156] remove trc from C++ and python Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 4 ---- src/api/python/z3/z3.py | 6 ------ 2 files changed, 10 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index a7f1259a0..6af38cb82 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -637,10 +637,6 @@ namespace z3 { Z3_func_decl tc = Z3_mk_transitive_closure(ctx(), *this); check_error(); return func_decl(ctx(), tc); } - func_decl transitive_reflexive_closure(func_decl const& f) { - Z3_func_decl tc = Z3_mk_transitive_reflexive_closure(ctx(), *this); check_error(); return func_decl(ctx(), tc); - } - bool is_const() const { return arity() == 0; } expr operator()() const; diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 485107e44..6d6220fb5 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10403,9 +10403,3 @@ def TransitiveClosure(f): """ return FuncDeclRef(Z3_mk_transitive_closure(f.ctx_ref(), f.ast), f.ctx) -def TransitiveReflexiveClosure(f): - """Given a binary relation R, such that the two arguments have the same sort - create the transitive reflexive closure relation R*. - The transitive reflexive closure R* is a new relation. - """ - return FuncDeclRef(Z3_mk_transitive_reflexive_closure(f.ctx_ref(), f.ast), f.ctx)