From a863a91b130bd0e2a7af2f4ce9f7943df71555a8 Mon Sep 17 00:00:00 2001 From: fleisherdev <55119509+fleisherdev@users.noreply.github.com> Date: Thu, 7 Apr 2022 02:19:21 -0400 Subject: [PATCH 001/253] Allow nightly builds to complete even if package signing fails - NOT published to nuget.org (#5951) Co-authored-by: jofleish --- scripts/nightly.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 374249432..e81135ab5 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -194,6 +194,7 @@ stages: patchVersion: $(Patch) arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.sym.nuspec -Version $(NightlyVersion) -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out' - task: EsrpCodeSigning@1 + continueOnError: true displayName: 'Sign Package' inputs: ConnectedServiceName: 'z3-esrp-signing-2' @@ -221,6 +222,7 @@ stages: MaxConcurrency: '50' MaxRetryAttempts: '5' - task: EsrpCodeSigning@1 + continueOnError: true displayName: 'Sign Symbol Package' inputs: ConnectedServiceName: 'z3-esrp-signing-2' @@ -297,6 +299,7 @@ stages: patchVersion: $(Patch) arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.x86.sym.nuspec -Version $(NightlyVersion) -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out' - task: EsrpCodeSigning@1 + continueOnError: true displayName: 'Sign Package' inputs: ConnectedServiceName: 'z3-esrp-signing-2' @@ -324,6 +327,7 @@ stages: MaxConcurrency: '50' MaxRetryAttempts: '5' - task: EsrpCodeSigning@1 + continueOnError: true displayName: 'Sign Symbol Package' inputs: ConnectedServiceName: 'z3-esrp-signing-2' From 19531654227522416cd37d48e7407d1ae055ec4b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Apr 2022 08:35:45 +0200 Subject: [PATCH 002/253] set ARM64 if detected under OSX --- CMakeLists.txt | 4 +++- cmake/target_arch_detect.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a9e121d02..5fef02be9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -198,7 +198,9 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "GNU") message(STATUS "Platform: GNU/Hurd") list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_HURD_") elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin") - # Does macOS really not need any special flags? + if (TARGET_ARCHITECTURE STREQUAL "arm64") + set(CMAKE_OSX_ARCHITECTURES "arm64") + endif() message(STATUS "Platform: Darwin") elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") message(STATUS "Platform: FreeBSD") diff --git a/cmake/target_arch_detect.cpp b/cmake/target_arch_detect.cpp index 0a2d0f3e6..379b5817e 100644 --- a/cmake/target_arch_detect.cpp +++ b/cmake/target_arch_detect.cpp @@ -5,6 +5,8 @@ #error CMAKE_TARGET_ARCH_i686 #elif defined(__x86_64__) || defined(_M_X64) #error CMAKE_TARGET_ARCH_x86_64 +#elif defined(__ARM_ARCH_ISA_A64) +#error CMAKE_TARGET_ARCH_arm64 #elif defined(__ARM_ARCH) #error CMAKE_TARGET_ARCH_arm #else From 8c2909f52bda61ce2422f6fb6484fa69a651e59d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Apr 2022 13:36:23 +0200 Subject: [PATCH 003/253] working on python make for arm Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 4 ++++ src/ast/pb_decl_plugin.cpp | 10 +++++----- src/ast/special_relations_decl_plugin.cpp | 10 +++++----- src/util/params.cpp | 17 +++++++++-------- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 1fca64f29..78c983ec4 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -69,6 +69,7 @@ IS_WINDOWS=False IS_LINUX=False IS_HURD=False IS_OSX=False +IS_OS_ARM64=False IS_FREEBSD=False IS_NETBSD=False IS_OPENBSD=False @@ -598,6 +599,9 @@ if os.name == 'nt': elif os.name == 'posix': if os.uname()[0] == 'Darwin': IS_OSX=True + print("setting Darwin", os.uname()[4]) + if os.uname()[4] == 'arm64': + IS_OS_ARM64 = True elif os.uname()[0] == 'Linux': IS_LINUX=True elif os.uname()[0] == 'GNU': diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index d4797b507..10e6c694c 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -90,11 +90,11 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p void pb_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { if (logic == symbol::null || logic == "QF_FD" || logic == "ALL" || logic == "HORN") { - op_names.push_back(builtin_name(m_at_most_sym.bare_str(), OP_AT_MOST_K)); - op_names.push_back(builtin_name(m_at_least_sym.bare_str(), OP_AT_LEAST_K)); - op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE)); - op_names.push_back(builtin_name(m_pbge_sym.bare_str(), OP_PB_GE)); - op_names.push_back(builtin_name(m_pbeq_sym.bare_str(), OP_PB_EQ)); + op_names.push_back(builtin_name(m_at_most_sym.str(), OP_AT_MOST_K)); + op_names.push_back(builtin_name(m_at_least_sym.str(), OP_AT_LEAST_K)); + op_names.push_back(builtin_name(m_pble_sym.str(), OP_PB_LE)); + op_names.push_back(builtin_name(m_pbge_sym.str(), OP_PB_GE)); + op_names.push_back(builtin_name(m_pbeq_sym.str(), OP_PB_EQ)); } } diff --git a/src/ast/special_relations_decl_plugin.cpp b/src/ast/special_relations_decl_plugin.cpp index 5dc5f32fe..7ed5e8346 100644 --- a/src/ast/special_relations_decl_plugin.cpp +++ b/src/ast/special_relations_decl_plugin.cpp @@ -61,11 +61,11 @@ 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_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_po.str(), OP_SPECIAL_RELATION_PO)); + op_names.push_back(builtin_name(m_lo.str(), OP_SPECIAL_RELATION_LO)); + op_names.push_back(builtin_name(m_plo.str(), OP_SPECIAL_RELATION_PLO)); + op_names.push_back(builtin_name(m_to.str(), OP_SPECIAL_RELATION_TO)); + op_names.push_back(builtin_name(m_tc.str(), OP_SPECIAL_RELATION_TC)); } } diff --git a/src/util/params.cpp b/src/util/params.cpp index aefe4e074..1745e56fd 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -24,15 +24,14 @@ Notes: params_ref params_ref::g_empty_params_ref; -std::string norm_param_name(char const * n) { - if (n == nullptr) - return "_"; +std::string norm_param_name(char const* n) { if (*n == ':') n++; std::string r = n; unsigned sz = static_cast(r.size()); if (sz == 0) return "_"; + for (unsigned i = 0; i < sz; i++) { char curr = r[i]; if ('A' <= curr && curr <= 'Z') @@ -44,6 +43,8 @@ std::string norm_param_name(char const * n) { } std::string norm_param_name(symbol const & n) { + if (n.is_null()) + return "_"; return norm_param_name(n.bare_str()); } @@ -156,8 +157,8 @@ struct param_descrs::imp { return m_names[idx]; } - struct lt { - bool operator()(symbol const & s1, symbol const & s2) const { return strcmp(s1.bare_str(), s2.bare_str()) < 0; } + struct symlt { + bool operator()(symbol const & s1, symbol const & s2) const { return ::lt(s1, s2); } }; void display(std::ostream & out, unsigned indent, bool smt2_style, bool include_descr) const { @@ -165,13 +166,13 @@ struct param_descrs::imp { for (auto const& kv : m_info) { names.push_back(kv.m_key); } - std::sort(names.begin(), names.end(), lt()); + std::sort(names.begin(), names.end(), symlt()); for (symbol const& name : names) { for (unsigned i = 0; i < indent; i++) out << " "; if (smt2_style) out << ':'; - char const * s = name.bare_str(); - unsigned n = static_cast(strlen(s)); + std::string s = name.str(); + unsigned n = static_cast(s.length()); for (unsigned i = 0; i < n; i++) { if (smt2_style && s[i] == '_') out << '-'; From c47bd1d01f8abdd4937f761e0d32e46c61d46d7f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Apr 2022 13:43:35 +0200 Subject: [PATCH 004/253] add arm64 auto-detect Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 78c983ec4..e25d90433 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -599,7 +599,6 @@ if os.name == 'nt': elif os.name == 'posix': if os.uname()[0] == 'Darwin': IS_OSX=True - print("setting Darwin", os.uname()[4]) if os.uname()[4] == 'arm64': IS_OS_ARM64 = True elif os.uname()[0] == 'Linux': @@ -2640,6 +2639,10 @@ def mk_config(): LDFLAGS = '%s -static-libgcc -static-libstdc++' % LDFLAGS if sysname == 'Linux' and machine.startswith('armv7') or machine.startswith('armv8'): CXXFLAGS = '%s -fpic' % CXXFLAGS + if IS_OSX and IS_OS_ARM64: + CXXFLAGS = '%s -arch arm64' % CXXFLAGS + LDFLAGS = '%s -arch arm64' % LDFLAGS + SLIBEXTRAFLAGS = '%s -arch arm64' % SLIBEXTRAFLAGS config.write('PREFIX=%s\n' % PREFIX) config.write('CC=%s\n' % CC) From 2e91d6688883552f635c53f0d30469ec65b8f00c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 06:28:36 +0200 Subject: [PATCH 005/253] Update mk_util.py use more meaningful name --- scripts/mk_util.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index e25d90433..6575f0dbf 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -69,7 +69,7 @@ IS_WINDOWS=False IS_LINUX=False IS_HURD=False IS_OSX=False -IS_OS_ARM64=False +IS_ARCH_ARM64=False IS_FREEBSD=False IS_NETBSD=False IS_OPENBSD=False @@ -599,8 +599,6 @@ if os.name == 'nt': elif os.name == 'posix': if os.uname()[0] == 'Darwin': IS_OSX=True - if os.uname()[4] == 'arm64': - IS_OS_ARM64 = True elif os.uname()[0] == 'Linux': IS_LINUX=True elif os.uname()[0] == 'GNU': @@ -624,7 +622,10 @@ elif os.name == 'posix': else: LINUX_X64=False +if os.uname()[4] == 'arm64': + IS_ARCH_ARM64 = True + def display_help(exit_code): print("mk_make.py: Z3 Makefile generator\n") print("This script generates the Makefile for the Z3 theorem prover.") @@ -2639,7 +2640,7 @@ def mk_config(): LDFLAGS = '%s -static-libgcc -static-libstdc++' % LDFLAGS if sysname == 'Linux' and machine.startswith('armv7') or machine.startswith('armv8'): CXXFLAGS = '%s -fpic' % CXXFLAGS - if IS_OSX and IS_OS_ARM64: + if IS_OSX and IS_ARCH_ARM64: CXXFLAGS = '%s -arch arm64' % CXXFLAGS LDFLAGS = '%s -arch arm64' % LDFLAGS SLIBEXTRAFLAGS = '%s -arch arm64' % SLIBEXTRAFLAGS From 83d2aa85ec7276a53b8978756bc94e7214b5097d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 06:35:25 +0200 Subject: [PATCH 006/253] add arm64 build path --- scripts/mk_unix_dist.py | 6 ++++++ scripts/nightly.yaml | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 28d68a01b..f5cbf6504 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -72,6 +72,7 @@ def parse_options(): 'nojava', 'nodotnet', 'dotnet-key=', + 'arch=', 'githash', 'nopython' ]) @@ -96,6 +97,11 @@ def parse_options(): JAVA_ENABLED = False elif opt == '--githash': GIT_HASH = True + elif opt == '--arch': + if arg == "arm64": + mk_util.IS_ARCH_ARM64 = True + else: + raise MKException(f"Invalid architecture directive '{arg}'. Legal directives: arm64") else: raise MKException("Invalid command line option '%s'" % opt) set_build_dir(path) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index e81135ab5..4296cab08 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -4,7 +4,6 @@ variables: Minor: '8' Patch: '16' NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName) - MacFlags: 'CXXFLAGS="-arch x86_64" LINK_EXTRA_FLAGS="-arch x86_64" SLINK_EXTRA_FLAGS="-arch x86_64"' stages: - stage: Build @@ -15,7 +14,7 @@ stages: pool: vmImage: "macOS-latest" steps: - - script: $(MacFlags) python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk + - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk - script: git clone https://github.com/z3prover/z3test z3test - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. @@ -25,6 +24,21 @@ stages: targetPath: $(Build.ArtifactStagingDirectory) + - job: MacArm64 + displayName: "Mac ARM64 Build" + pool: + vmImage: "macOS-latest" + steps: + - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 + - script: git clone https://github.com/z3prover/z3test z3test + - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 + - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. + - task: PublishPipelineArtifact@1 + inputs: + artifactName: 'MacArm64' + targetPath: $(Build.ArtifactStagingDirectory) + + - job: Ubuntu displayName: "Ubuntu build" pool: From babac78c999437ce7fe5c5c9e9e3eab45ded95b2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 06:59:07 +0200 Subject: [PATCH 007/253] syntax error? --- scripts/mk_unix_dist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index f5cbf6504..39f48f448 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -101,7 +101,7 @@ def parse_options(): if arg == "arm64": mk_util.IS_ARCH_ARM64 = True else: - raise MKException(f"Invalid architecture directive '{arg}'. Legal directives: arm64") + raise MKException("Invalid architecture directive '%s'. Legal directives: arm64" % arg) else: raise MKException("Invalid command line option '%s'" % opt) set_build_dir(path) From 1346a168a1346405a313c2a9eceb2560576f8e02 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 07:00:53 +0200 Subject: [PATCH 008/253] #5952 --- src/cmd_context/cmd_context.cpp | 1 + src/cmd_context/cmd_context.h | 1 + src/cmd_context/pdecl.cpp | 59 +++++++++++++++++++++++---------- src/cmd_context/pdecl.h | 17 ++++++---- 4 files changed, 54 insertions(+), 24 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 89efc439f..580cc2de4 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1636,6 +1636,7 @@ void cmd_context::pop(unsigned n) { restore_aux_pdecls(s.m_aux_pdecls_lim); restore_assertions(s.m_assertions_lim); restore_psort_inst(s.m_psort_inst_stack_lim); + m_dt_eh.get()->reset(); m_mcs.shrink(m_mcs.size() - n); m_scopes.shrink(new_lvl); if (!m_global_decls) diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 4f9d80a8d..60a6e930b 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -267,6 +267,7 @@ protected: cmd_context & m_owner; datatype_util m_dt_util; public: + void reset() { m_dt_util.reset(); } dt_eh(cmd_context & owner); ~dt_eh() override; void operator()(sort * dt, pdecl* pd) override; diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 7a93382e9..2bf21de3a 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -156,8 +156,8 @@ public: return false; return m_sort == static_cast(other)->m_sort; } - void display(std::ostream & out) const override { - out << m_sort->get_name(); + std::ostream& display(std::ostream & out) const override { + return out << m_sort->get_name(); } }; @@ -180,8 +180,8 @@ public: get_num_params() == other->get_num_params() && m_idx == static_cast(other)->m_idx; } - void display(std::ostream & out) const override { - out << "s_" << m_idx; + std::ostream& display(std::ostream & out) const override { + return out << "s_" << m_idx; } unsigned idx() const { return m_idx; } }; @@ -254,7 +254,7 @@ public: } return true; } - void display(std::ostream & out) const override { + std::ostream& display(std::ostream & out) const override { if (m_args.empty()) { out << m_decl->get_name(); } @@ -267,6 +267,7 @@ public: } out << ")"; } + return out; } }; @@ -342,12 +343,12 @@ void display_sort_args(std::ostream & out, unsigned num_params) { out << ") "; } -void psort_user_decl::display(std::ostream & out) const { +std::ostream& psort_user_decl::display(std::ostream & out) const { out << "(declare-sort " << m_name; display_sort_args(out, m_num_params); if (m_def) m_def->display(out); - out << ")"; + return out << ")"; } // ------------------- @@ -364,8 +365,8 @@ sort * psort_dt_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * return m.instantiate_datatype(this, m_name, n, s); } -void psort_dt_decl::display(std::ostream & out) const { - out << "(datatype-sort " << m_name << ")"; +std::ostream& psort_dt_decl::display(std::ostream & out) const { + return out << "(datatype-sort " << m_name << ")"; } // ------------------- @@ -410,8 +411,8 @@ sort * psort_builtin_decl::instantiate(pdecl_manager & m, unsigned n, unsigned c } } -void psort_builtin_decl::display(std::ostream & out) const { - out << "(declare-builtin-sort " << m_name << ")"; +std::ostream& psort_builtin_decl::display(std::ostream & out) const { + return out << "(declare-builtin-sort " << m_name << ")"; } void ptype::display(std::ostream & out, pdatatype_decl const * const * dts) const { @@ -615,7 +616,7 @@ sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * } -void pdatatype_decl::display(std::ostream & out) const { +std::ostream& pdatatype_decl::display(std::ostream & out) const { out << "(declare-datatype " << m_name; display_sort_args(out, m_num_params); bool first = true; @@ -631,7 +632,7 @@ void pdatatype_decl::display(std::ostream & out) const { } first = false; } - out << ")"; + return out << ")"; } bool pdatatype_decl::commit(pdecl_manager& m) { @@ -645,9 +646,11 @@ bool pdatatype_decl::commit(pdecl_manager& m) { datatype_decl * d_ptr = dts.m_buffer[0]; sort_ref_vector sorts(m.m()); bool is_ok = m.get_dt_plugin()->mk_datatypes(1, &d_ptr, m_num_params, ps.data(), sorts); + m.notify_mk_datatype(m_name); if (is_ok && m_num_params == 0) { m.notify_new_dt(sorts.get(0), this); } + return is_ok; } @@ -722,6 +725,7 @@ void pdecl_manager::notify_datatype(sort *r, psort_decl* p, unsigned n, sort* co void pdecl_manager::push() { m_notified_lim.push_back(m_notified_trail.size()); + m_datatypes_lim.push_back(m_datatypes_trail.size()); } void pdecl_manager::pop(unsigned n) { @@ -732,6 +736,16 @@ void pdecl_manager::pop(unsigned n) { } m_notified_trail.shrink(new_sz); m_notified_lim.shrink(m_notified_lim.size() - n); + + new_sz = m_datatypes_lim[m_datatypes_lim.size() - n]; + if (new_sz != m_datatypes_trail.size()) { + datatype_util util(m()); + for (unsigned i = m_datatypes_trail.size(); i-- > new_sz; ) + util.plugin().remove(m_datatypes_trail[i]); + } + m_datatypes_trail.shrink(new_sz); + m_datatypes_lim.shrink(m_datatypes_lim.size() - n); + } bool pdatatypes_decl::instantiate(pdecl_manager & m, sort * const * s) { @@ -751,16 +765,24 @@ bool pdatatypes_decl::commit(pdecl_manager& m) { sort_ref_vector sorts(m.m()); bool is_ok = m.get_dt_plugin()->mk_datatypes(m_datatypes.size(), dts.m_buffer.data(), 0, nullptr, sorts); if (is_ok) { + for (pdatatype_decl* d : m_datatypes) { + m.notify_mk_datatype(d->get_name()); + } for (unsigned i = 0; i < m_datatypes.size(); ++i) { pdatatype_decl* d = m_datatypes[i]; - if (d->get_num_params() == 0) { + if (d->get_num_params() == 0) m.notify_new_dt(sorts.get(i), this); - } } } + return is_ok; } +void pdecl_manager::notify_mk_datatype(symbol const& name) { + m_datatypes_trail.push_back(name); +} + + struct pdecl_manager::sort_info { psort_decl * m_decl; @@ -985,16 +1007,19 @@ void pdecl_manager::del_decl_core(pdecl * p) { } void pdecl_manager::del_decl(pdecl * p) { - TRACE("pdecl_manager", tout << "del psort "; p->display(tout); tout << "\n";); + TRACE("pdecl_manager", tout << "del psort "; p->display(tout); tout << "\n";); if (p->is_psort()) { psort * _p = static_cast(p); if (_p->is_sort_wrapper()) { - m_sort2psort.erase(static_cast(_p)->get_sort()); + sort* s = static_cast(_p)->get_sort(); + m_sort2psort.erase(s); } else { m_table.erase(_p); } + } + del_decl_core(p); } diff --git a/src/cmd_context/pdecl.h b/src/cmd_context/pdecl.h index 3a1db06c1..4f9c56825 100644 --- a/src/cmd_context/pdecl.h +++ b/src/cmd_context/pdecl.h @@ -45,7 +45,7 @@ public: unsigned get_id() const { return m_id; } unsigned get_ref_count() const { return m_ref_count; } unsigned hash() const { return m_id; } - virtual void display(std::ostream & out) const {} + virtual std::ostream& display(std::ostream & out) const { return out;} virtual void reset_cache(pdecl_manager& m) {} }; @@ -123,7 +123,7 @@ protected: ~psort_user_decl() override {} public: sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; - void display(std::ostream & out) const override; + std::ostream& display(std::ostream & out) const override; }; class psort_builtin_decl : public psort_decl { @@ -137,7 +137,7 @@ protected: public: sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; sort * instantiate(pdecl_manager & m, unsigned n, unsigned const * s) override; - void display(std::ostream & out) const override; + std::ostream& display(std::ostream & out) const override; }; class psort_dt_decl : public psort_decl { @@ -148,7 +148,7 @@ protected: ~psort_dt_decl() override {} public: sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; - void display(std::ostream & out) const override; + std::ostream& display(std::ostream & out) const override; }; @@ -198,7 +198,7 @@ class paccessor_decl : public pdecl { ptype const & get_type() const { return m_type; } ~paccessor_decl() override {} public: - void display(std::ostream & out) const override { pdecl::display(out); } + std::ostream& display(std::ostream & out) const override { pdecl::display(out); return out; } void display(std::ostream & out, pdatatype_decl const * const * dts) const; }; @@ -219,7 +219,7 @@ class pconstructor_decl : public pdecl { constructor_decl * instantiate_decl(pdecl_manager & m, unsigned n, sort * const * s); ~pconstructor_decl() override {} public: - void display(std::ostream & out) const override { pdecl::display(out); } + std::ostream& display(std::ostream & out) const override { pdecl::display(out); return out; } void display(std::ostream & out, pdatatype_decl const * const * dts) const; }; @@ -237,7 +237,7 @@ class pdatatype_decl : public psort_decl { ~pdatatype_decl() override {} public: sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; - void display(std::ostream & out) const override; + std::ostream& display(std::ostream & out) const override; bool has_missing_refs(symbol & missing) const; bool has_duplicate_accessors(symbol & repeated) const; bool commit(pdecl_manager& m); @@ -289,6 +289,8 @@ class pdecl_manager { obj_hashtable m_notified; ptr_vector m_notified_trail; unsigned_vector m_notified_lim; + svector m_datatypes_trail; + unsigned_vector m_datatypes_lim; void init_list(); void del_decl_core(pdecl * p); @@ -319,6 +321,7 @@ public: sort * instantiate_datatype(psort_decl* p, symbol const& name, unsigned n, sort * const* s); sort * instantiate(psort * s, unsigned num, sort * const * args); void notify_datatype(sort *r, psort_decl* p, unsigned n, sort* const* s); + void notify_mk_datatype(symbol const& name); void push(); void pop(unsigned n); From 79553261d189b0583f68bbbc48fb9fc81f45128f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 07:02:32 +0200 Subject: [PATCH 009/253] no uname on nt --- scripts/mk_util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 6575f0dbf..534910a69 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -621,8 +621,9 @@ elif os.name == 'posix': LINUX_X64=True else: LINUX_X64=False + -if os.uname()[4] == 'arm64': +if os.name == 'posix' and os.uname()[4] == 'arm64': IS_ARCH_ARM64 = True From cb6aba2315e71c0be80451456a75962512fbda92 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:07:56 +0200 Subject: [PATCH 010/253] more arm --- scripts/mk_unix_dist.py | 1 + scripts/mk_util.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 39f48f448..e89ca410f 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -56,6 +56,7 @@ def display_help(): print(" -f, --force force script to regenerate Makefiles.") print(" --nodotnet do not include .NET bindings in the binary distribution files.") print(" --dotnet-key= sign the .NET assembly with the private key in .") + print(" --arch= set architecture (to arm64) to force arm64 build") print(" --nojava do not include Java bindings in the binary distribution files.") print(" --nopython do not include Python bindings in the binary distribution files.") print(" --githash include git hash in the Zip file.") diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 534910a69..4d7cedba8 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2436,7 +2436,7 @@ def mk_config(): if ONLY_MAKEFILES: return config = open(os.path.join(BUILD_DIR, 'config.mk'), 'w') - global CXX, CC, GMP, GUARD_CF, STATIC_BIN, GIT_HASH, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS, LOG_SYNC, SINGLE_THREADED + global CXX, CC, GMP, GUARD_CF, STATIC_BIN, GIT_HASH, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS, LOG_SYNC, SINGLE_THREADED, IS_ARCH_ARM64 if IS_WINDOWS: CXXFLAGS = '/nologo /Zi /D WIN32 /D _WINDOWS /EHsc /GS /Gd /std:c++17' config.write( @@ -2642,6 +2642,7 @@ def mk_config(): if sysname == 'Linux' and machine.startswith('armv7') or machine.startswith('armv8'): CXXFLAGS = '%s -fpic' % CXXFLAGS if IS_OSX and IS_ARCH_ARM64: + print("Setting arm64") CXXFLAGS = '%s -arch arm64' % CXXFLAGS LDFLAGS = '%s -arch arm64' % LDFLAGS SLIBEXTRAFLAGS = '%s -arch arm64' % SLIBEXTRAFLAGS From 746a4161af454a89bc6d4308d73e47c1021815cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:24:21 +0200 Subject: [PATCH 011/253] more passing of parameters --- scripts/mk_unix_dist.py | 2 ++ scripts/mk_util.py | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index e89ca410f..9c2a15c67 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -126,6 +126,8 @@ def mk_build_dir(path): opts.append('--git-describe') if PYTHON_ENABLED: opts.append('--python') + if mk_util.IS_ARCH_ARM64: + opts.append('--arm64=true') if subprocess.call(opts) != 0: raise MKException("Failed to generate build directory at '%s'" % path) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 4d7cedba8..74e761877 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -649,6 +649,7 @@ def display_help(exit_code): print(" -x, --x64 create 64 binary when using Visual Studio.") else: print(" --x86 force 32-bit x86 build on x64 systems.") + print(" --arm64= forcearm64 bit build on/off (supported for Darwin).") print(" -m, --makefiles generate only makefiles.") if IS_WINDOWS: print(" -v, --vsproj generate Visual Studio Project Files.") @@ -691,11 +692,11 @@ def parse_options(): global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM global DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED global LINUX_X64, SLOW_OPTIMIZE, LOG_SYNC, SINGLE_THREADED - global GUARD_CF, ALWAYS_DYNAMIC_BASE + global GUARD_CF, ALWAYS_DYNAMIC_BASE, IS_ARCH_ARM64 try: options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:df:sxhmcvtnp:gj', - ['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', + ['build=', 'debug', 'silent', 'x64', 'arm64', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js', 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'pypkgdir=', 'python', 'staticbin', 'log-sync', 'single-threaded']) except: @@ -718,6 +719,8 @@ def parse_options(): VS_X64 = True elif opt in ('--x86'): LINUX_X64=False + elif opt in ('--arm64'): + IS_ARCH_ARM64 = arg in ('true','on','True','TRUE') elif opt in ('-h', '--help'): display_help(0) elif opt in ('-m', '--makefiles'): From 9533dbaf5c956aee76211b9da5db6b2f49d2259c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:34:52 +0200 Subject: [PATCH 012/253] missing arg specifier --- 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 74e761877..338dd822f 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -696,7 +696,7 @@ def parse_options(): try: options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:df:sxhmcvtnp:gj', - ['build=', 'debug', 'silent', 'x64', 'arm64', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', + ['build=', 'debug', 'silent', 'x64', 'arm64=', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js', 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'pypkgdir=', 'python', 'staticbin', 'log-sync', 'single-threaded']) except: From 67434a309670297b435d230fb054e49f3c8e446d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:40:55 +0200 Subject: [PATCH 013/253] again --- 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 338dd822f..34ca9a38a 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -695,7 +695,7 @@ def parse_options(): global GUARD_CF, ALWAYS_DYNAMIC_BASE, IS_ARCH_ARM64 try: options, remainder = getopt.gnu_getopt(sys.argv[1:], - 'b:df:sxhmcvtnp:gj', + 'b:df:sxa:hmcvtnp:gj', ['build=', 'debug', 'silent', 'x64', 'arm64=', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js', 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'pypkgdir=', 'python', 'staticbin', 'log-sync', 'single-threaded']) From f3789e21a349626ae351abd4c1d38a24e57387a5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:42:18 +0200 Subject: [PATCH 014/253] id doesn't use mk_util --- src/api/python/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/api/python/CMakeLists.txt b/src/api/python/CMakeLists.txt index e791a2f11..067a25e8c 100644 --- a/src/api/python/CMakeLists.txt +++ b/src/api/python/CMakeLists.txt @@ -42,8 +42,6 @@ add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/z3core.py" ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} "${PROJECT_SOURCE_DIR}/scripts/update_api.py" ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} - # FIXME: When update_api.py no longer uses ``mk_util`` drop this dependency - "${PROJECT_SOURCE_DIR}/scripts/mk_util.py" COMMENT "Generating z3core.py" ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} ) From 3821eb4134c977a4a35f57d5384de843d4c2991e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:47:38 +0200 Subject: [PATCH 015/253] fpflags --- scripts/mk_util.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 34ca9a38a..761de8b26 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -279,10 +279,13 @@ def test_gmp(cc): def test_fpmath(cc): - global FPMATH_FLAGS + global FPMATH_FLAGS, IS_ARCH_ARM64, IS_OSX if FPMATH_ENABLED == "False": FPMATH_FLAGS="" return "Disabled" + if IS_ARCH_ARM64 and IS_OSX: + FPMATH_FLAGS = "" + return "Disabled-ARM64" if is_verbose(): print("Testing floating point support...") t = TempFile('tstsse.cpp') From 91ca02864cb8552c837a848e8e681373720f6e48 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:59:22 +0200 Subject: [PATCH 016/253] arm64 Signed-off-by: Nikolaj Bjorner --- scripts/mk_unix_dist.py | 4 +++- scripts/nightly.yaml | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 9c2a15c67..97de725e9 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -181,7 +181,9 @@ def get_os_name(): def get_z3_name(): major, minor, build, revision = get_version() - if sys.maxsize >= 2**32: + if mk_util.IS_ARCH_ARM64: + platform = "arm64" + elif sys.maxsize >= 2**32: platform = "x64" else: platform = "x86" diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 4296cab08..1ba0ea5af 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -180,6 +180,11 @@ stages: inputs: artifact: 'Mac' path: $(Agent.TempDirectory)\package + - task: DownloadPipelineArtifact@2 + displayName: 'Download macOS Arm64 Build' + inputs: + artifact: 'MacArm64' + path: $(Agent.TempDirectory)\package - task: NuGetToolInstaller@0 inputs: versionSpec: 5.x @@ -435,6 +440,11 @@ stages: inputs: artifactName: 'Mac' targetPath: tmp + - task: DownloadPipelineArtifact@2 + displayName: "Download MacArm64" + inputs: + artifactName: 'MacArm64' + targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download Ubuntu" inputs: From fbd35fb58d333b28208eb9da696aa10824e99370 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 16:55:39 +0200 Subject: [PATCH 017/253] skip unit tests for arm --- scripts/nightly.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 1ba0ea5af..488e5aedf 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -31,7 +31,6 @@ stages: steps: - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 - script: git clone https://github.com/z3prover/z3test z3test - - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@1 inputs: From d6d9b25c6854989afcb2b7a72f92759ec2cecde9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 17:12:20 +0200 Subject: [PATCH 018/253] Allow adding constraints in the model_eh callback --- src/opt/opt_context.cpp | 23 +++++++++++++++++------ src/opt/opt_context.h | 1 + 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 3551686f7..02cd90113 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -185,17 +185,27 @@ namespace opt { } void context::set_hard_constraints(expr_ref_vector const& fmls) { - if (m_scoped_state.set(fmls)) { + if (m_calling_on_model) { + for (expr* f : fmls) + add_hard_constraint(f); + return; + } + if (m_scoped_state.set(fmls)) + clear_state(); + } + + void context::add_hard_constraint(expr* f) { + if (m_calling_on_model) + get_solver().assert_expr(f); + else { + m_scoped_state.add(f); clear_state(); } } - void context::add_hard_constraint(expr* f) { - m_scoped_state.add(f); - clear_state(); - } - void context::add_hard_constraint(expr* f, expr* t) { + if (m_calling_on_model) + throw default_exception("adding soft constraints is not supported during callbacks"); m_scoped_state.m_asms.push_back(t); m_scoped_state.add(m.mk_implies(t, f)); clear_state(); @@ -389,6 +399,7 @@ namespace opt { model_ref md = m->copy(); if (!m_model_fixed.contains(md.get())) fix_model(md); + flet _calling(m_calling_on_model, true); m_on_model_eh(m_on_model_ctx, md); m_model_fixed.pop_back(); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index dd717c392..1e950174a 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -165,6 +165,7 @@ namespace opt { ast_manager& m; on_model_t m_on_model_ctx; std::function m_on_model_eh; + bool m_calling_on_model = false; arith_util m_arith; bv_util m_bv; expr_ref_vector m_hard_constraints; From c98eda03f7c834f771f7e5f1ddfc5517c1029dbd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Apr 2022 06:55:31 +0200 Subject: [PATCH 019/253] nightly osx arm64 wheel --- scripts/nightly.yaml | 10 ++++++++-- src/api/python/setup.py | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 488e5aedf..ad64d05b7 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -399,7 +399,12 @@ stages: inputs: artifactName: 'Mac' targetPath: $(Agent.TempDirectory) - - script: cd $(Agent.TempDirectory); mkdir osx-bin; cd osx-bin; unzip ../*osx*.zip + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: 'MacArm64' + targetPath: $(Agent.TempDirectory) + - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*osx*x64.zip + - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*osx*arm64.zip - script: cd $(Agent.TempDirectory); mkdir linux-bin; cd linux-bin; unzip ../*glibc*.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip @@ -409,7 +414,8 @@ stages: - script: cd src/api/python; echo $(Agent.TempDirectory)/linux-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-x64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-arm64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - task: PublishPipelineArtifact@0 inputs: artifactName: 'Python packages' diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 8c73c29e6..796f30e6b 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -279,8 +279,10 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: osver = RELEASE_METADATA[3] if osver.count('.') > 1: osver = '.'.join(osver.split('.')[:2]) - if arch == 'x64': + if arch == 'x64': plat_name ='macosx_%s_x86_64' % osver.replace('.', '_') + elif arc == 'arm64': + plat_name ='macosx_%s_arm64' % osver.replace('.', '_') else: raise Exception(f"idk how os {distos} {osver} works. what goes here?") else: From fe834b9e4e5519891da0d053ea9caea4640aaaa5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Apr 2022 07:40:48 +0200 Subject: [PATCH 020/253] update regex --- scripts/nightly.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index ad64d05b7..0add769b9 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -403,8 +403,8 @@ stages: inputs: artifactName: 'MacArm64' targetPath: $(Agent.TempDirectory) - - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*osx*x64.zip - - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*osx*arm64.zip + - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*x64-osx*.zip + - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*arm64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir linux-bin; cd linux-bin; unzip ../*glibc*.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip From 005b8e3cf85d00dd7360d901580aba9925725c56 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Apr 2022 08:28:22 +0200 Subject: [PATCH 021/253] arc -> arch --- src/api/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 796f30e6b..1b455bb56 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -281,7 +281,7 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: osver = '.'.join(osver.split('.')[:2]) if arch == 'x64': plat_name ='macosx_%s_x86_64' % osver.replace('.', '_') - elif arc == 'arm64': + elif arch == 'arm64': plat_name ='macosx_%s_arm64' % osver.replace('.', '_') else: raise Exception(f"idk how os {distos} {osver} works. what goes here?") From 405a26c5856ba726c31582eaf51103d01f1b51a7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Apr 2022 09:55:02 +0200 Subject: [PATCH 022/253] allow adding constraints during on_model --- src/opt/maxres.cpp | 17 ++++++++--------- src/opt/maxsmt.cpp | 14 +++++++++++++- src/opt/maxsmt.h | 3 +++ src/opt/opt_context.cpp | 11 ++++++++++- src/sat/sat_solver.cpp | 2 ++ 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 27b3b7260..1b4348105 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -791,11 +791,10 @@ public: improve_model(mdl); mdl->set_model_completion(true); unsigned correction_set_size = 0; - for (expr* a : m_asms) { - if (mdl->is_false(a)) { + for (expr* a : m_asms) + if (mdl->is_false(a)) ++correction_set_size; - } - } + if (!m_csmodel.get() || correction_set_size < m_correction_set_size) { m_csmodel = mdl; m_correction_set_size = correction_set_size; @@ -810,22 +809,22 @@ public: return; } - if (!m_c.verify_model(m_index, mdl.get(), upper)) { + if (!m_c.verify_model(m_index, mdl.get(), upper)) return; - } + unsigned num_assertions = s().get_num_assertions(); m_model = mdl; m_c.model_updated(mdl.get()); TRACE("opt", tout << "updated upper: " << upper << "\n";); - for (soft& s : m_soft) { + for (soft& s : m_soft) s.set_value(m_model->is_true(s.s)); - } verify_assignment(); - m_upper = upper; + if (num_assertions == s().get_num_assertions()) + m_upper = upper; trace(); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 6a8a2ee35..bf25f3f95 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -50,7 +50,13 @@ namespace opt { void maxsmt_solver_base::updt_params(params_ref& p) { m_params.copy(p); - } + } + + void maxsmt_solver_base::reset_upper() { + m_upper = m_lower; + for (soft& s : m_soft) + m_upper += s.weight; + } solver& maxsmt_solver_base::s() { return m_c.get_solver(); @@ -289,6 +295,12 @@ namespace opt { } } + void maxsmt::reset_upper() { + if (m_msolver) { + m_msolver->reset_upper(); + m_upper = m_msolver->get_upper(); + } + } void maxsmt::verify_assignment() { // TBD: have to use a different solver diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index ad355cc9e..5bf637dde 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -103,6 +103,8 @@ namespace opt { }; lbool find_mutexes(obj_map& new_soft); + + void reset_upper(); protected: @@ -153,6 +155,7 @@ namespace opt { void display_answer(std::ostream& out) const; void collect_statistics(statistics& st) const; void model_updated(model* mdl); + void reset_upper(); private: bool is_maxsat_problem(weights_t& ws) const; void verify_assignment(); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 02cd90113..8848b61c9 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -195,13 +195,22 @@ namespace opt { } void context::add_hard_constraint(expr* f) { - if (m_calling_on_model) + if (m_calling_on_model) { get_solver().assert_expr(f); + for (auto const& [k, v] : m_maxsmts) + v->reset_upper(); + for (unsigned i = 0; i < num_objectives(); ++i) { + auto const& o = m_scoped_state.m_objectives[i]; + if (o.m_type != O_MAXSMT) + m_optsmt.update_upper(o.m_index, inf_eps::infinity()); + } + } else { m_scoped_state.add(f); clear_state(); } } + void context::add_hard_constraint(expr* f, expr* t) { if (m_calling_on_model) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5505cfa70..4a254ac06 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3818,6 +3818,8 @@ namespace sat { void solver::move_to_front(bool_var b) { if (b >= num_vars()) return; + if (m_case_split_queue.empty()) + return; bool_var next = m_case_split_queue.min_var(); auto next_act = m_activity[next]; set_activity(b, next_act + 1); From 011c1b2dd2bd394ac043668e289bfdabbe2b1f27 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Apr 2022 12:06:27 +0200 Subject: [PATCH 023/253] remove refs to bare_str --- src/api/api_ast.cpp | 2 +- src/api/api_log.cpp | 2 +- src/api/api_tactic.cpp | 6 +-- src/ast/ast_smt2_pp.cpp | 12 ++---- src/cmd_context/basic_cmds.cpp | 2 +- src/muz/fp/datalog_parser.cpp | 40 ++++++++++--------- src/muz/rel/dl_finite_product_relation.cpp | 2 +- src/muz/rel/dl_instruction.cpp | 20 +++++----- src/muz/rel/dl_table_relation.cpp | 2 +- src/muz/rel/rel_context.cpp | 2 +- src/tactic/portfolio/smt_strategic_solver.cpp | 5 +-- 11 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index d5de6b5fb..8144c2baf 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -355,7 +355,7 @@ extern "C" { return mk_c(c)->mk_external_string(buffer.str()); } else { - return mk_c(c)->mk_external_string(_s.bare_str()); + return mk_c(c)->mk_external_string(_s.str()); } Z3_CATCH_RETURN(""); } diff --git a/src/api/api_log.cpp b/src/api/api_log.cpp index c1864ae8c..ed5f68e8a 100644 --- a/src/api/api_log.cpp +++ b/src/api/api_log.cpp @@ -88,7 +88,7 @@ void Sy(Z3_symbol sym) { *g_z3_log << "# " << s.get_num(); } else { - *g_z3_log << "$ |" << ll_escaped{s.bare_str()} << '|'; + *g_z3_log << "$ |" << ll_escaped{s.str().c_str()} << '|'; } *g_z3_log << std::endl; } diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index 45073cdb1..f67a373dd 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -331,8 +331,8 @@ extern "C" { if (idx >= mk_c(c)->num_tactics()) { SET_ERROR_CODE(Z3_IOB, nullptr); return ""; - } - return mk_c(c)->get_tactic(idx)->get_name().bare_str(); + } + return mk_c(c)->mk_external_string(mk_c(c)->get_tactic(idx)->get_name().str().c_str()); Z3_CATCH_RETURN(""); } @@ -352,7 +352,7 @@ extern "C" { SET_ERROR_CODE(Z3_IOB, nullptr); return ""; } - return mk_c(c)->get_probe(idx)->get_name().bare_str(); + return mk_c(c)->mk_external_string(mk_c(c)->get_probe(idx)->get_name().str().c_str()); Z3_CATCH_RETURN(""); } diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 9854195a4..59f9ecda6 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -47,18 +47,14 @@ format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len, bo len = static_cast(str.length()); return mk_string(m, str); } - else if (s.is_numerical()) { - std::string str = s.str(); - len = static_cast(str.length()); - return mk_string(m, str); - } - else if (!s.bare_str()) { + else if (s.is_null()) { len = 4; return mk_string(m, "null"); } else { - len = static_cast(strlen(s.bare_str())); - return mk_string(m, s.bare_str()); + std::string str = s.str(); + len = static_cast(str.length()); + return mk_string(m, str); } } diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index afe800af6..f3bd0ed57 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -58,7 +58,7 @@ public: cmd * c = ctx.find_cmd(s); if (c == nullptr) { std::string err_msg("unknown command '"); - err_msg = err_msg + s.bare_str() + "'"; + err_msg = err_msg + s.str() + "'"; throw cmd_exception(std::move(err_msg)); } m_cmds.push_back(s); diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index 899ec497c..030d88d71 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -777,6 +777,7 @@ protected: // Sym ::= String | NUM | Var // dtoken parse_infix(dtoken tok1, char const* td, app_ref& pred) { + std::string td1_(td); symbol td1(td); expr_ref v1(m), v2(m); sort* s = nullptr; @@ -793,12 +794,12 @@ protected: if (tok1 == TK_ID) { expr* _v1 = nullptr; - m_vars.find(td1.bare_str(), _v1); + m_vars.find(td1_, _v1); v1 = _v1; } if (tok3 == TK_ID) { expr* _v2 = nullptr; - m_vars.find(td2.bare_str(), _v2); + m_vars.find(td, _v2); v2 = _v2; } if (!v1 && !v2) { @@ -950,18 +951,19 @@ protected: break; } case TK_ID: { - symbol data (m_lexer->get_token_data()); - if (is_var(data.bare_str())) { + char const* d = m_lexer->get_token_data(); + symbol data (d); + if (is_var(d)) { unsigned idx = 0; expr* v = nullptr; - if (!m_vars.find(data.bare_str(), v)) { + if (!m_vars.find(d, v)) { idx = m_num_vars++; v = m.mk_var(idx, s); - m_vars.insert(data.bare_str(), v); + m_vars.insert(d, v); } else if (s != v->get_sort()) { throw default_exception(default_exception::fmt(), "sort: %s expected, but got: %s\n", - s->get_name().bare_str(), v->get_sort()->get_name().bare_str()); + s->get_name().str().c_str(), v->get_sort()->get_name().str().c_str()); } args.push_back(v); } @@ -1075,21 +1077,21 @@ protected: } sort * register_finite_sort(symbol name, uint64_t domain_size, context::sort_kind k) { - if(m_sort_dict.contains(name.bare_str())) { - throw default_exception(default_exception::fmt(), "sort %s already declared", name.bare_str()); + if(m_sort_dict.contains(name.str().c_str())) { + throw default_exception(default_exception::fmt(), "sort %s already declared", name.str().c_str()); } sort * s = m_decl_util.mk_sort(name, domain_size); m_context.register_finite_sort(s, k); - m_sort_dict.insert(name.bare_str(), s); + m_sort_dict.insert(name.str(), s); return s; } sort * register_int_sort(symbol name) { - if(m_sort_dict.contains(name.bare_str())) { - throw default_exception(default_exception::fmt(), "sort %s already declared", name.bare_str()); + if(m_sort_dict.contains(name.str().c_str())) { + throw default_exception(default_exception::fmt(), "sort %s already declared", name.str().c_str()); } sort * s = m_arith.mk_int(); - m_sort_dict.insert(name.bare_str(), s); + m_sort_dict.insert(name.str(), s); return s; } @@ -1105,8 +1107,8 @@ protected: app * res; if(m_arith.is_int(s)) { uint64_t val; - if (!string_to_uint64(name.bare_str(), val)) { - throw default_exception(default_exception::fmt(), "Invalid integer: \"%s\"", name.bare_str()); + if (!string_to_uint64(name.str().c_str(), val)) { + throw default_exception(default_exception::fmt(), "Invalid integer: \"%s\"", name.str().c_str()); } res = m_arith.mk_numeral(rational(val, rational::ui64()), s); } @@ -1288,7 +1290,7 @@ private: uint64_set & sort_content = *e->get_data().m_value; if(!sort_content.contains(num)) { warning_msg("symbol number %I64u on line %d in file %s does not belong to sort %s", - num, m_current_line, m_current_file.c_str(), s->get_name().bare_str()); + num, m_current_line, m_current_file.c_str(), s->get_name().str().c_str()); return false; } if(!m_use_map_names) { @@ -1366,7 +1368,7 @@ private: func_decl * pred = m_context.try_get_predicate_decl(predicate_name); if(!pred) { throw default_exception(default_exception::fmt(), "tuple file %s for undeclared predicate %s", - m_current_file.c_str(), predicate_name.bare_str()); + m_current_file.c_str(), predicate_name.str().c_str()); } unsigned pred_arity = pred->get_arity(); sort * const * arg_sorts = pred->get_domain(); @@ -1531,9 +1533,9 @@ private: if(m_use_map_names) { auto const & value = m_number_names.insert_if_not_there(num, el_name); - if (value!=el_name) { + if (value != el_name) { warning_msg("mismatch of number names on line %d in file %s. old: \"%s\" new: \"%s\"", - m_current_line, fname.c_str(), value.bare_str(), el_name.bare_str()); + m_current_line, fname.c_str(), value.str().c_str(), el_name.str().c_str()); } } } diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index 8a4b86e6d..07921a3be 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -64,7 +64,7 @@ namespace datalog { } symbol finite_product_relation_plugin::get_name(relation_plugin & inner_plugin) { - std::string str = std::string("fpr_")+inner_plugin.get_name().bare_str(); + std::string str = std::string("fpr_")+inner_plugin.get_name().str(); return symbol(str.c_str()); } diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index 0df03172f..63846e7d5 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -213,10 +213,10 @@ namespace datalog { return true; } void make_annotations(execution_context & ctx) override { - ctx.set_register_annotation(m_reg, m_pred->get_name().bare_str()); + ctx.set_register_annotation(m_reg, m_pred->get_name().str().c_str()); } std::ostream& display_head_impl(execution_context const& ctx, std::ostream & out) const override { - const char * rel_name = m_pred->get_name().bare_str(); + auto rel_name = m_pred->get_name(); if (m_store) { return out << "store " << m_reg << " into " << rel_name; } @@ -378,7 +378,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported join operation on relations of kinds %s and %s", - r1.get_plugin().get_name().bare_str(), r2.get_plugin().get_name().bare_str()); + r1.get_plugin().get_name().str().c_str(), r2.get_plugin().get_name().str().c_str()); } store_fn(r1, r2, fn); } @@ -441,7 +441,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported filter_equal operation on a relation of kind %s", - r.get_plugin().get_name().bare_str()); + r.get_plugin().get_name().str().c_str()); } store_fn(r, fn); } @@ -490,7 +490,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported filter_identical operation on a relation of kind %s", - r.get_plugin().get_name().bare_str()); + r.get_plugin().get_name().str().c_str()); } store_fn(r, fn); } @@ -537,7 +537,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported filter_interpreted operation on a relation of kind %s", - r.get_plugin().get_name().bare_str()); + r.get_plugin().get_name().str().c_str()); } store_fn(r, fn); } @@ -594,7 +594,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported filter_interpreted_and_project operation on a relation of kind %s", - reg.get_plugin().get_name().bare_str()); + reg.get_plugin().get_name().str().c_str()); } store_fn(reg, fn); } @@ -837,7 +837,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported join-project operation on relations of kinds %s and %s", - r1.get_plugin().get_name().bare_str(), r2.get_plugin().get_name().bare_str()); + r1.get_plugin().get_name().str().c_str(), r2.get_plugin().get_name().str().c_str()); } store_fn(r1, r2, fn); } @@ -910,7 +910,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported select_equal_and_project operation on a relation of kind %s", - r.get_plugin().get_name().bare_str()); + r.get_plugin().get_name().str().c_str()); } store_fn(r, fn); } @@ -1076,7 +1076,7 @@ namespace datalog { return true; } std::ostream& display_head_impl(execution_context const& ctx, std::ostream & out) const override { - return out << "mark_saturated " << m_pred->get_name().bare_str(); + return out << "mark_saturated " << m_pred->get_name(); } void make_annotations(execution_context & ctx) override { } diff --git a/src/muz/rel/dl_table_relation.cpp b/src/muz/rel/dl_table_relation.cpp index de55998f8..8a69f8f85 100644 --- a/src/muz/rel/dl_table_relation.cpp +++ b/src/muz/rel/dl_table_relation.cpp @@ -33,7 +33,7 @@ namespace datalog { // ----------------------------------- symbol table_relation_plugin::create_plugin_name(const table_plugin &p) { - std::string name = std::string("tr_") + p.get_name().bare_str(); + std::string name = std::string("tr_") + p.get_name().str(); return symbol(name.c_str()); } diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 957c85adb..76411a290 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -157,7 +157,7 @@ namespace datalog { //IF_VERBOSE(3, m_context.display_smt2(0,0,verbose_stream());); if (m_context.print_aig().is_non_empty_string()) { - const char *filename = m_context.print_aig().bare_str(); + std::string filename = m_context.print_aig().str(); aig_exporter aig(m_context.get_rules(), get_context(), &m_table_facts); std::ofstream strm(filename, std::ios_base::binary); aig(strm); diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 52df38247..0c304aa3f 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -143,10 +143,9 @@ public: tactic_ref t; if (tp.default_tactic() != symbol::null && !tp.default_tactic().is_numerical() && - tp.default_tactic().bare_str() && - tp.default_tactic().bare_str()[0]) { + tp.default_tactic().str()[0]) { cmd_context ctx(false, &m, l); - std::istringstream is(tp.default_tactic().bare_str()); + std::istringstream is(tp.default_tactic().str()); char const* file_name = ""; sexpr_ref se = parse_sexpr(ctx, is, p, file_name); if (se) { From f55b23322860a8e186ae919daa4796ac4850a82e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Apr 2022 12:06:39 +0200 Subject: [PATCH 024/253] #5778 --- src/sat/smt/arith_solver.cpp | 9 +++++---- src/sat/smt/q_model_fixer.cpp | 6 ++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 5a102fa14..e02a42979 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -549,13 +549,14 @@ namespace arith { found_compatible = false; for (; it != end; ++it) { api_bound* a2 = *it; - if (a1 == a2) continue; - if (a2->get_bound_kind() != kind) continue; + if (a1 == a2) + continue; + if (a2->get_bound_kind() != kind) + continue; rational const& k2(a2->get_value()); found_compatible = true; - if (k1 < k2) { + if (k1 < k2) return it; - } } return end; } diff --git a/src/sat/smt/q_model_fixer.cpp b/src/sat/smt/q_model_fixer.cpp index 456525c42..cdea60d23 100644 --- a/src/sat/smt/q_model_fixer.cpp +++ b/src/sat/smt/q_model_fixer.cpp @@ -184,6 +184,8 @@ namespace q { for (euf::enode* n : ctx.get_egraph().enodes_of(f)) { expr* t = n->get_arg(idx)->get_expr(); values.push_back(mdl(t)); + if (!m.is_value(values.back())) + return expr_ref(m.mk_var(idx, srt), m); md->v2t.insert(values.back(), t); md->t2v.insert(t, values.back()); } @@ -299,6 +301,10 @@ namespace q { auto term = [&](unsigned j) { return md->v2t[md->values[j]]; }; + + for (unsigned j = 0; j < sz; ++j) + std::cout << mk_pp(md->values[j], m) << "\n"; + expr* arg = t->get_arg(i); From 0b20a4ebf4b8e3e0188ccbb5dad9b51a88966f04 Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Sat, 9 Apr 2022 21:46:21 +0200 Subject: [PATCH 025/253] Added rewriting distinct with bitvectors to false if bit-size is too low (#5956) * Fixed problem with registering bitvector functions * Added rewriting distinct with bitvectors to false if bit-size is too low * Removed debug output * Incorporated Nikolaj's comments * Simplifications --- src/ast/rewriter/bv_rewriter.cpp | 15 +++++++++++++++ src/ast/rewriter/bv_rewriter.h | 3 ++- src/ast/rewriter/th_rewriter.cpp | 20 +++++++++++--------- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 073885c21..1fdd7bd14 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2803,6 +2803,21 @@ br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resu return BR_FAILED; } +br_status bv_rewriter::mk_distinct(unsigned num_args, expr * const * args, expr_ref & result) { + if (num_args <= 1) { + result = m().mk_true(); + return BR_DONE; + } + unsigned sz = get_bv_size(args[0]); + // check if num_args > 2^sz + if (sz >= 32) + return BR_FAILED; + if (num_args <= 1u << sz) + return BR_FAILED; + result = m().mk_false(); + return BR_DONE; +} + br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool is_overflow, expr_ref & result) { SASSERT(num == 2); unsigned bv_sz; diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index 7f0c67540..88d952c06 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -180,7 +180,8 @@ public: bool is_urem_any(expr * e, expr * & dividend, expr * & divisor); br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result); - br_status mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resul); + br_status mk_ite_core(expr * c, expr * t, expr * e, expr_ref & result); + br_status mk_distinct(unsigned num_args, expr * const * args, expr_ref & result); bool hi_div0() const { return m_hi_div0; } diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 22d6a83b7..9cf9fc810 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -60,7 +60,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { expr_substitution * m_subst = nullptr; unsigned long long m_max_memory; // in bytes bool m_new_subst = false; - unsigned m_max_steps = UINT_MAX; + unsigned m_max_steps = UINT_MAX; bool m_pull_cheap_ite = true; bool m_flat = true; bool m_cache_all = false; @@ -180,7 +180,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { // theory dispatch for = SASSERT(num == 2); family_id s_fid = args[0]->get_sort()->get_family_id(); - if (s_fid == m_a_rw.get_fid()) + 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()) st = m_bv_rw.mk_eq_core(args[0], args[1], result); @@ -193,10 +193,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { 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; - } - if (k == OP_EQ) { - SASSERT(num == 2); + return st; st = apply_tamagotchi(args[0], args[1], result); if (st != BR_FAILED) return st; @@ -210,16 +207,21 @@ struct th_rewriter_cfg : public default_rewriter_cfg { return st; } if ((k == OP_AND || k == OP_OR) && m_seq_rw.u().has_re()) { - st = m_seq_rw.mk_bool_app(f, num, args, result); + st = m_seq_rw.mk_bool_app(f, num, args, result); if (st != BR_FAILED) return st; } - if (k == OP_EQ && m_seq_rw.u().has_seq() && is_app(args[0]) && + if (k == OP_EQ && m_seq_rw.u().has_seq() && is_app(args[0]) && to_app(args[0])->get_family_id() == m_seq_rw.get_fid()) { st = m_seq_rw.mk_eq_core(args[0], args[1], result); if (st != BR_FAILED) return st; } + if (k == OP_DISTINCT && num > 0 && m_bv_rw.is_bv(args[0])) { + st = m_bv_rw.mk_distinct(num, args, result); + if (st != BR_FAILED) + return st; + } return m_b_rw.mk_app_core(f, num, args, result); } @@ -250,7 +252,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { if (fid == m_seq_rw.get_fid()) return m_seq_rw.mk_app_core(f, num, args, result); if (fid == m_char_rw.get_fid()) - return m_char_rw.mk_app_core(f, num, args, result); + return m_char_rw.mk_app_core(f, num, args, result); if (fid == m_rec_rw.get_fid()) return m_rec_rw.mk_app_core(f, num, args, result); return BR_FAILED; From 4f4e9a9963309518c7cdd92a01ae5429533d6369 Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 11 Apr 2022 02:40:03 -0400 Subject: [PATCH 026/253] fix a tiny typo (#5960) A dot. --- doc/website.dox.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/website.dox.in b/doc/website.dox.in index 69395492e..f4caa1277 100644 --- a/doc/website.dox.in +++ b/doc/website.dox.in @@ -4,7 +4,7 @@ Z3 is a high-performance theorem prover being developed at Microsoft Research. - The Z3 website is at http://github.com/z3prover.. + The Z3 website is at http://github.com/z3prover. This website hosts the automatically generated documentation for the Z3 APIs. From f43d9d00d4ba7ee040d7e3736a848926a842c082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Bour?= Date: Mon, 11 Apr 2022 13:38:20 +0200 Subject: [PATCH 027/253] Z3_add_rec_def body is not a macro (#5963) --- src/api/api_ast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 8144c2baf..7ee95afc8 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -164,7 +164,7 @@ extern "C" { return; } recfun_replace replace(m); - p.set_definition(replace, pd, true, n, _vars.data(), abs_body); + p.set_definition(replace, pd, false, n, _vars.data(), abs_body); Z3_CATCH; } From b0d8b27f37cf184fe632ec84f19785dc20a9ff80 Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Mon, 11 Apr 2022 16:50:13 +0200 Subject: [PATCH 028/253] Fixed registering expressions in push/pop (#5964) * Fixed registering expressions in push/pop * Reused existing function --- src/api/api_solver.cpp | 4 ++-- src/api/c++/z3++.h | 17 +++++++++++------ src/api/z3_api.h | 4 ++-- src/sat/smt/user_solver.cpp | 4 ++-- src/smt/theory_user_propagator.cpp | 13 ++++++++----- src/tactic/user_propagator_base.h | 12 ++++++------ 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 99d332724..948064af6 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -883,8 +883,8 @@ extern "C" { Z3_TRY; RESET_ERROR_CODE(); init_solver(c, s); - user_propagator::push_eh_t _push = push_eh; - user_propagator::pop_eh_t _pop = pop_eh; + user_propagator::push_eh_t _push = (void(*)(void*,user_propagator::callback*)) push_eh; + user_propagator::pop_eh_t _pop = (void(*)(void*,user_propagator::callback*,unsigned)) pop_eh; user_propagator::fresh_eh_t _fresh = [=](void * user_ctx, ast_manager& m, user_propagator::context_obj*& _ctx) { ast_context_params params; params.set_foreign_manager(&m); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 4d60de433..101fa04a3 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -3964,18 +3964,23 @@ namespace z3 { } }; - static void push_eh(void* p) { + static void push_eh(void* _p, Z3_solver_callback cb) { + user_propagator_base* p = static_cast(_p); + scoped_cb _cb(p, cb); static_cast(p)->push(); } - static void pop_eh(void* p, unsigned num_scopes) { - static_cast(p)->pop(num_scopes); + static void pop_eh(void* _p, Z3_solver_callback cb, unsigned num_scopes) { + user_propagator_base* p = static_cast(_p); + scoped_cb _cb(p, cb); + static_cast(_p)->pop(num_scopes); } - static void* fresh_eh(void* p, Z3_context ctx) { + static void* fresh_eh(void* _p, Z3_context ctx) { + user_propagator_base* p = static_cast(_p); context* c = new context(ctx); - static_cast(p)->subcontexts.push_back(c); - return static_cast(p)->fresh(*c); + p->subcontexts.push_back(c); + return p->fresh(*c); } static void fixed_eh(void* _p, Z3_solver_callback cb, Z3_ast _var, Z3_ast _value) { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index d7dd0a332..8a610bc6d 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1434,8 +1434,8 @@ Z3_DECLARE_CLOSURE(Z3_error_handler, void, (Z3_context c, Z3_error_code e)); /** \brief callback functions for user propagator. */ -Z3_DECLARE_CLOSURE(Z3_push_eh, void, (void* ctx)); -Z3_DECLARE_CLOSURE(Z3_pop_eh, void, (void* ctx, unsigned num_scopes)); +Z3_DECLARE_CLOSURE(Z3_push_eh, void, (void* ctx, Z3_solver_callback cb)); +Z3_DECLARE_CLOSURE(Z3_pop_eh, void, (void* ctx, Z3_solver_callback cb, unsigned num_scopes)); Z3_DECLARE_CLOSURE(Z3_fresh_eh, void*, (void* ctx, Z3_context new_context)); Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t, Z3_ast value)); Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t)); diff --git a/src/sat/smt/user_solver.cpp b/src/sat/smt/user_solver.cpp index 6b3eb6718..d24af253e 100644 --- a/src/sat/smt/user_solver.cpp +++ b/src/sat/smt/user_solver.cpp @@ -88,7 +88,7 @@ namespace user_solver { void solver::push_core() { th_euf_solver::push_core(); m_prop_lim.push_back(m_prop.size()); - m_push_eh(m_user_context); + m_push_eh(m_user_context, this); } void solver::pop_core(unsigned num_scopes) { @@ -96,7 +96,7 @@ namespace user_solver { unsigned old_sz = m_prop_lim.size() - num_scopes; m_prop.shrink(m_prop_lim[old_sz]); m_prop_lim.shrink(old_sz); - m_pop_eh(m_user_context, num_scopes); + m_pop_eh(m_user_context, this, num_scopes); } void solver::propagate_consequence(prop_info const& prop) { diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 7c53aa8eb..daded32c7 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -25,6 +25,7 @@ using namespace smt; theory_user_propagator::theory_user_propagator(context& ctx): theory(ctx, ctx.get_manager().mk_family_id(user_propagator::plugin::name())), m_var2expr(ctx.get_manager()), + m_push_popping(false), m_to_add(ctx.get_manager()) {} @@ -38,7 +39,7 @@ void theory_user_propagator::force_push() { theory::push_scope_eh(); m_prop_lim.push_back(m_prop.size()); m_to_add_lim.push_back(m_to_add.size()); - m_push_eh(m_user_context); + m_push_eh(m_user_context, this); } } @@ -122,7 +123,8 @@ final_check_status theory_user_propagator::final_check_eh() { if (!(bool)m_final_eh) return FC_DONE; force_push(); - unsigned sz = m_prop.size(); + unsigned sz1 = m_prop.size(); + unsigned sz2 = m_expr2var.size(); try { m_final_eh(m_user_context, this); } @@ -130,7 +132,8 @@ final_check_status theory_user_propagator::final_check_eh() { throw default_exception("Exception thrown in \"final\"-callback"); } propagate(); - bool done = (sz == m_prop.size()) && !ctx.inconsistent(); + // check if it became inconsistent or something new was propagated/registered + bool done = !can_propagate() && !ctx.inconsistent(); return done ? FC_DONE : FC_CONTINUE; } @@ -169,11 +172,11 @@ void theory_user_propagator::pop_scope_eh(unsigned num_scopes) { old_sz = m_to_add_lim.size() - num_scopes; m_to_add.shrink(m_to_add_lim[old_sz]); m_to_add_lim.shrink(old_sz); - m_pop_eh(m_user_context, num_scopes); + m_pop_eh(m_user_context, this, num_scopes); } bool theory_user_propagator::can_propagate() { - return m_qhead < m_prop.size() || !m_to_add.empty(); + return m_qhead < m_prop.size() || m_to_add_qhead < m_to_add.size(); } void theory_user_propagator::propagate_consequence(prop_info const& prop) { diff --git a/src/tactic/user_propagator_base.h b/src/tactic/user_propagator_base.h index 07270ffe6..02a027762 100644 --- a/src/tactic/user_propagator_base.h +++ b/src/tactic/user_propagator_base.h @@ -17,13 +17,13 @@ namespace user_propagator { virtual ~context_obj() = default; }; - typedef std::function final_eh_t; - typedef std::function fixed_eh_t; - typedef std::function eq_eh_t; + typedef std::function final_eh_t; + typedef std::function fixed_eh_t; + typedef std::function eq_eh_t; typedef std::function fresh_eh_t; - typedef std::function push_eh_t; - typedef std::function pop_eh_t; - typedef std::function created_eh_t; + typedef std::function push_eh_t; + typedef std::function pop_eh_t; + typedef std::function created_eh_t; class plugin : public decl_plugin { From c996a66da04c882bc47dccacbf3507f1ab56f8e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Apr 2022 17:05:49 +0200 Subject: [PATCH 029/253] separate pre-processing, add callback parameter to push/pop in python API --- scripts/update_api.py | 4 +- src/api/python/z3/z3.py | 12 ++- src/opt/CMakeLists.txt | 1 + src/opt/maxlex.cpp | 18 ++--- src/opt/maxlex.h | 4 +- src/opt/maxres.cpp | 25 +++--- src/opt/maxres.h | 4 +- src/opt/maxsmt.cpp | 131 ++++++++------------------------ src/opt/maxsmt.h | 42 +++++----- src/opt/opt_mux.h | 32 ++++++++ src/opt/opt_preprocess.cpp | 102 +++++++++++++++++++++++++ src/opt/opt_preprocess.h | 38 +++++++++ src/opt/sortmax.cpp | 41 ++++------ src/opt/wmax.cpp | 28 +++---- src/opt/wmax.h | 4 +- src/sat/smt/euf_internalize.cpp | 1 + 16 files changed, 287 insertions(+), 200 deletions(-) create mode 100644 src/opt/opt_mux.h create mode 100644 src/opt/opt_preprocess.cpp create mode 100644 src/opt/opt_preprocess.h diff --git a/scripts/update_api.py b/scripts/update_api.py index ab1b4d6fd..d4d1ab0e0 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1820,8 +1820,8 @@ _error_handler_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_uint) _lib.Z3_set_error_handler.restype = None _lib.Z3_set_error_handler.argtypes = [ContextObj, _error_handler_type] -push_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p) -pop_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_uint) +push_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p) +pop_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint) fresh_eh_type = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) fixed_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 6f4dcf430..d3d6067c3 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -11237,12 +11237,16 @@ def ensure_prop_closures(): _prop_closures = PropClosures() -def user_prop_push(ctx): - _prop_closures.get(ctx).push() +def user_prop_push(ctx, cb): + prop = _prop_closures.get(ctx) + prop.cb = cb + prop.push() -def user_prop_pop(ctx, num_scopes): - _prop_closures.get(ctx).pop(num_scopes) +def user_prop_pop(ctx, cb, num_scopes): + prop = _prop_closures.get(ctx) + prop.cb = cb + pop(num_scopes) def user_prop_fresh(id, ctx): diff --git a/src/opt/CMakeLists.txt b/src/opt/CMakeLists.txt index d88d11c0f..c652bcaea 100644 --- a/src/opt/CMakeLists.txt +++ b/src/opt/CMakeLists.txt @@ -8,6 +8,7 @@ z3_add_component(opt opt_lns.cpp opt_pareto.cpp opt_parse.cpp + opt_preprocess.cpp optsmt.cpp opt_solver.cpp pb_sls.cpp diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp index 46c7104d5..82eee6f5e 100644 --- a/src/opt/maxlex.cpp +++ b/src/opt/maxlex.cpp @@ -26,15 +26,15 @@ Author: namespace opt { - bool is_maxlex(weights_t & _ws) { - vector ws(_ws); - std::sort(ws.begin(), ws.end()); + bool is_maxlex(vector const & _ws) { + vector ws(_ws); + std::sort(ws.begin(), ws.end(), [&](soft const& s1, soft const& s2) { return s1.weight < s2.weight; }); ws.reverse(); rational sum(0); - for (rational const& w : ws) { + for (auto const& [e, w, t] : ws) { sum += w; } - for (rational const& w : ws) { + for (auto const& [e, w, t] : ws) { if (sum > w + w) return false; sum -= w; } @@ -185,8 +185,8 @@ namespace opt { public: - maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& s): - maxsmt_solver_base(c, ws, s), + maxlex(maxsat_context& c, unsigned id, vector& s): + maxsmt_solver_base(c, s), m(c.get_manager()), m_c(c) { // ensure that soft constraints are sorted with largest soft constraints first. @@ -210,8 +210,8 @@ namespace opt { } }; - maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft) { - return alloc(maxlex, c, id, ws, soft); + maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, vector& soft) { + return alloc(maxlex, c, id, soft); } } diff --git a/src/opt/maxlex.h b/src/opt/maxlex.h index b5c1a6e20..fc30b1fd8 100644 --- a/src/opt/maxlex.h +++ b/src/opt/maxlex.h @@ -21,9 +21,9 @@ Notes: namespace opt { - bool is_maxlex(weights_t & ws); + bool is_maxlex(vector const & ws); - maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, vector& soft); }; diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 1b4348105..0d1bf2394 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -129,10 +129,10 @@ private: typedef ptr_vector exprs; public: - maxres(maxsat_context& c, unsigned index, - weights_t& ws, expr_ref_vector const& soft, + maxres(maxsat_context& c, unsigned index, + vector& soft, strategy_t st): - maxsmt_solver_base(c, ws, soft), + maxsmt_solver_base(c, soft), m_index(index), m_B(m), m_asms(m), m_defs(m), m_new_core(m), @@ -875,17 +875,10 @@ public: } lbool init_local() { - m_lower.reset(); m_trail.reset(); lbool is_sat = l_true; - obj_map new_soft; - is_sat = find_mutexes(new_soft); - if (is_sat != l_true) { - return is_sat; - } - for (auto const& kv : new_soft) { - add_soft(kv.m_key, kv.m_value); - } + for (auto const& [e, w, t] : m_soft) + add_soft(e, w); m_max_upper = m_upper; m_found_feasible_optimum = false; m_last_index = 0; @@ -953,12 +946,12 @@ public: }; opt::maxsmt_solver_base* opt::mk_maxres( - maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft) { - return alloc(maxres, c, id, ws, soft, maxres::s_primal); + maxsat_context& c, unsigned id, vector& soft) { + return alloc(maxres, c, id, soft, maxres::s_primal); } opt::maxsmt_solver_base* opt::mk_primal_dual_maxres( - maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft) { - return alloc(maxres, c, id, ws, soft, maxres::s_primal_dual); + maxsat_context& c, unsigned id, vector& soft) { + return alloc(maxres, c, id, soft, maxres::s_primal_dual); } diff --git a/src/opt/maxres.h b/src/opt/maxres.h index 85c83efba..25ef9bf05 100644 --- a/src/opt/maxres.h +++ b/src/opt/maxres.h @@ -21,9 +21,9 @@ Notes: namespace opt { - maxsmt_solver_base* mk_maxres(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_maxres(maxsat_context& c, unsigned id, vector& soft); - maxsmt_solver_base* mk_primal_dual_maxres(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_primal_dual_maxres(maxsat_context& c, unsigned id, vector& soft); }; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index bf25f3f95..538ecf59b 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -28,6 +28,7 @@ Notes: #include "opt/wmax.h" #include "opt/opt_params.hpp" #include "opt/opt_context.h" +#include "opt/opt_preprocess.h" #include "smt/theory_wmaxsat.h" #include "smt/theory_pb.h" @@ -35,17 +36,15 @@ Notes: namespace opt { maxsmt_solver_base::maxsmt_solver_base( - maxsat_context& c, vector const& ws, expr_ref_vector const& softs): + maxsat_context& c, vector& s): m(c.get_manager()), m_c(c), + m_soft(s), m_assertions(m), m_trail(m) { c.get_base_model(m_model); SASSERT(m_model); updt_params(c.params()); - for (unsigned i = 0; i < ws.size(); ++i) { - m_soft.push_back(soft(expr_ref(softs.get(i), m), ws[i], false)); - } } void maxsmt_solver_base::updt_params(params_ref& p) { @@ -88,14 +87,22 @@ namespace opt { m_upper.reset(); for (soft& s : m_soft) { s.set_value(m.is_true(s.s)); - if (!s.is_true()) m_upper += s.weight; + if (!s.is_true()) + m_upper += s.weight; } + + preprocess pp(s()); + rational lower(0); + bool r = pp(m_soft, lower); + + if (lower != 0) + m_adjust_value.set_offset(lower + m_adjust_value.get_offset()); TRACE("opt", tout << "upper: " << m_upper << " assignments: "; for (soft& s : m_soft) tout << (s.is_true()?"T":"F"); tout << "\n";); - return true; + return r; } void maxsmt_solver_base::set_mus(bool f) { @@ -165,74 +172,9 @@ namespace opt { verbose_stream() << "(opt." << solver << " [" << l << ":" << u << "])\n";); } - lbool maxsmt_solver_base::find_mutexes(obj_map& new_soft) { - m_lower.reset(); - expr_ref_vector fmls(m); - for (soft& s : m_soft) { - new_soft.insert(s.s, s.weight); - fmls.push_back(s.s); - } - vector mutexes; - lbool is_sat = s().find_mutexes(fmls, mutexes); - if (is_sat != l_true) { - return is_sat; - } - for (auto& mux : mutexes) { - process_mutex(mux, new_soft); - } - return l_true; - } - - struct maxsmt_compare_soft { - obj_map const& m_soft; - maxsmt_compare_soft(obj_map const& soft): m_soft(soft) {} - bool operator()(expr* a, expr* b) const { - return m_soft.find(a) > m_soft.find(b); - } - }; - - void maxsmt_solver_base::process_mutex(expr_ref_vector& mutex, obj_map& new_soft) { - TRACE("opt", - for (expr* e : mutex) { - tout << mk_pp(e, m) << " |-> " << new_soft.find(e) << "\n"; - }); - if (mutex.size() <= 1) { - return; - } - maxsmt_compare_soft cmp(new_soft); - ptr_vector _mutex(mutex.size(), mutex.data()); - std::sort(_mutex.begin(), _mutex.end(), cmp); - mutex.reset(); - mutex.append(_mutex.size(), _mutex.data()); - - rational weight(0), sum1(0), sum2(0); - vector weights; - for (expr* e : mutex) { - rational w = new_soft.find(e); - weights.push_back(w); - sum1 += w; - new_soft.remove(e); - } - for (unsigned i = mutex.size(); i-- > 0; ) { - expr_ref soft(m.mk_or(i+1, mutex.data()), m); - m_trail.push_back(soft); - rational w = weights[i]; - weight = w - weight; - m_lower += weight*rational(i); - IF_VERBOSE(1, verbose_stream() << "(opt.maxsat mutex size: " << i + 1 << " weight: " << weight << ")\n";); - sum2 += weight*rational(i+1); - new_soft.insert(soft, weight); - for (; i > 0 && weights[i-1] == w; --i) {} - weight = w; - } - SASSERT(sum1 == sum2); - } - - maxsmt::maxsmt(maxsat_context& c, unsigned index): - m(c.get_manager()), m_c(c), m_index(index), - m_soft_constraints(m), m_answer(m) {} + m(c.get_manager()), m_c(c), m_index(index), m_answer(m) {} lbool maxsmt::operator()() { lbool is_sat = l_undef; @@ -241,25 +183,25 @@ namespace opt { symbol const& maxsat_engine = m_c.maxsat_engine(); IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";); TRACE("opt_verbose", s().display(tout << "maxsmt\n") << "\n";); - if (optp.maxlex_enable() && is_maxlex(m_weights)) { - m_msolver = mk_maxlex(m_c, m_index, m_weights, m_soft_constraints); + if (optp.maxlex_enable() && is_maxlex(m_soft)) { + m_msolver = mk_maxlex(m_c, m_index, m_soft); } - else if (m_soft_constraints.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) { - m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints); + else if (m_soft.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) { + m_msolver = mk_maxres(m_c, m_index, m_soft); } else if (maxsat_engine == symbol("pd-maxres")) { - m_msolver = mk_primal_dual_maxres(m_c, m_index, m_weights, m_soft_constraints); + m_msolver = mk_primal_dual_maxres(m_c, m_index, m_soft); } else if (maxsat_engine == symbol("wmax")) { - m_msolver = mk_wmax(m_c, m_weights, m_soft_constraints); + m_msolver = mk_wmax(m_c, m_soft); } else if (maxsat_engine == symbol("sortmax")) { - m_msolver = mk_sortmax(m_c, m_weights, m_soft_constraints); + m_msolver = mk_sortmax(m_c, m_soft); } else { auto str = maxsat_engine.str(); warning_msg("solver %s is not recognized, using default 'maxres'", str.c_str()); - m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints); + m_msolver = mk_maxres(m_c, m_index, m_soft); } if (m_msolver) { @@ -360,39 +302,32 @@ namespace opt { SASSERT(w.is_pos()); unsigned index = 0; if (m_soft_constraint_index.find(f, index)) { - m_weights[index] += w; + m_soft[index].weight += w; } else { - m_soft_constraint_index.insert(f, m_weights.size()); - m_soft_constraints.push_back(f); - m_weights.push_back(w); + m_soft_constraint_index.insert(f, m_soft.size()); + m_soft.push_back(soft(expr_ref(f, m), w, false)); } m_upper += w; } struct cmp_first { bool operator()(std::pair const& x, std::pair const& y) const { - return x.first < y.first; + return x.second < y.second; } }; void maxsmt::display_answer(std::ostream& out) const { - vector> sorted_weights; - unsigned n = m_weights.size(); - for (unsigned i = 0; i < n; ++i) { - sorted_weights.push_back(std::make_pair(i, m_weights[i])); - } - std::sort(sorted_weights.begin(), sorted_weights.end(), cmp_first()); - sorted_weights.reverse(); - for (unsigned i = 0; i < n; ++i) { - unsigned idx = sorted_weights[i].first; - expr* e = m_soft_constraints[idx]; + + unsigned idx = 0; + for (auto const & [_e, w, t] : m_soft) { + expr* e = _e.get(); bool is_not = m.is_not(e, e); - out << m_weights[idx] << ": " << mk_pp(e, m) + out << w << ": " << mk_pp(e, m) << ((is_not != get_assignment(idx))?" |-> true ":" |-> false ") << "\n"; - - } + ++idx; + } } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 5bf637dde..4029bb911 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -52,21 +52,23 @@ namespace opt { // --------------------------------------------- // base class with common utilities used // by maxsmt solvers - // + // + + struct soft { + expr_ref s; + rational weight; + lbool value; + void set_value(bool t) { value = t?l_true:l_undef; } + void set_value(lbool t) { value = t; } + bool is_true() const { return value == l_true; } + soft(expr_ref const& s, rational const& w, bool t): s(s), weight(w), value(t?l_true:l_undef) {} + }; + class maxsmt_solver_base : public maxsmt_solver { protected: - struct soft { - expr_ref s; - rational weight; - lbool value; - void set_value(bool t) { value = t?l_true:l_undef; } - void set_value(lbool t) { value = t; } - bool is_true() const { return value == l_true; } - soft(expr_ref const& s, rational const& w, bool t): s(s), weight(w), value(t?l_true:l_undef) {} - }; ast_manager& m; maxsat_context& m_c; - vector m_soft; + vector& m_soft; expr_ref_vector m_assertions; expr_ref_vector m_trail; rational m_lower; @@ -76,8 +78,8 @@ namespace opt { params_ref m_params; // config public: - maxsmt_solver_base(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft); - + maxsmt_solver_base(maxsat_context& c, vector& soft); + ~maxsmt_solver_base() override {} rational get_lower() const override { return m_lower; } rational get_upper() const override { return m_upper; } @@ -102,8 +104,6 @@ namespace opt { smt::theory_wmaxsat& operator()(); }; - lbool find_mutexes(obj_map& new_soft); - void reset_upper(); @@ -111,9 +111,6 @@ namespace opt { void enable_sls(bool force); void trace_bounds(char const* solver); - void process_mutex(expr_ref_vector& mutex, obj_map& new_soft); - - }; /** @@ -126,10 +123,9 @@ namespace opt { maxsat_context& m_c; unsigned m_index; scoped_ptr m_msolver; - expr_ref_vector m_soft_constraints; + vector m_soft; obj_map m_soft_constraint_index; expr_ref_vector m_answer; - vector m_weights; rational m_lower; rational m_upper; adjust_value m_adjust_value; @@ -142,9 +138,9 @@ namespace opt { void updt_params(params_ref& p); void add(expr* f, rational const& w); void set_adjust_value(adjust_value& adj); - unsigned size() const { return m_soft_constraints.size(); } - expr* operator[](unsigned idx) const { return m_soft_constraints[idx]; } - rational weight(unsigned idx) const { return m_weights[idx]; } + unsigned size() const { return m_soft.size(); } + expr* operator[](unsigned idx) const { return m_soft[idx].s; } + rational weight(unsigned idx) const { return m_soft[idx].weight; } void commit_assignment(); rational get_lower() const; rational get_upper() const; diff --git a/src/opt/opt_mux.h b/src/opt/opt_mux.h new file mode 100644 index 000000000..b093026f0 --- /dev/null +++ b/src/opt/opt_mux.h @@ -0,0 +1,32 @@ +/*++ +Copyright (c) 2021 Microsoft Corporation + +Module Name: + + opt_mux.h + +Abstract: + + Find mutexes - at most 1 constraints and modify soft constraints and bounds. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-04-11 + +--*/ + +#pragma once + +#include "opt/maxsmt.h" + +namespace opt { + + class mux { + ast_manager& m; + solver& s; + + public: + mux(solver& s); + lbool operator()(vector& soft, rational& bound); + }; +}; diff --git a/src/opt/opt_preprocess.cpp b/src/opt/opt_preprocess.cpp new file mode 100644 index 000000000..f65d5d09b --- /dev/null +++ b/src/opt/opt_preprocess.cpp @@ -0,0 +1,102 @@ +/*++ +Copyright (c) 2021 Microsoft Corporation + +Module Name: + + opt_preprocess.cpp + +Abstract: + + Pre-processing for MaxSMT + + Find mutexes - at most 1 constraints and modify soft constraints and bounds. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-04-11 + +--*/ + +#pragma once + +#include "opt/opt_preprocess.h" + +namespace opt { + + bool preprocess::find_mutexes(vector& softs, rational& lower) { + expr_ref_vector fmls(m); + obj_map new_soft; + for (soft& sf : softs) { + m_trail.push_back(sf.s); + if (new_soft.contains(sf.s)) + new_soft[sf.s] += sf.weight; + else + new_soft.insert(sf.s, sf.weight); + fmls.push_back(sf.s); + } + vector mutexes; + lbool is_sat = s.find_mutexes(fmls, mutexes); + if (is_sat == l_false) + return true; + if (is_sat == l_undef) + return false; + for (auto& mux : mutexes) + process_mutex(mux, new_soft, lower); + softs.reset(); + for (auto const& [k, v] : new_soft) + softs.push_back(soft(expr_ref(k, m), v, false)); + m_trail.reset(); + return true; + } + + struct maxsmt_compare_soft { + obj_map const& m_soft; + maxsmt_compare_soft(obj_map const& soft): m_soft(soft) {} + bool operator()(expr* a, expr* b) const { + return m_soft.find(a) > m_soft.find(b); + } + }; + + void preprocess::process_mutex(expr_ref_vector& mutex, obj_map& new_soft, rational& lower) { + TRACE("opt", + for (expr* e : mutex) { + tout << mk_pp(e, m) << " |-> " << new_soft.find(e) << "\n"; + }); + if (mutex.size() <= 1) + return; + + maxsmt_compare_soft cmp(new_soft); + ptr_vector _mutex(mutex.size(), mutex.data()); + std::sort(_mutex.begin(), _mutex.end(), cmp); + mutex.reset(); + mutex.append(_mutex.size(), _mutex.data()); + + rational weight(0), sum1(0), sum2(0); + vector weights; + for (expr* e : mutex) { + rational w = new_soft.find(e); + weights.push_back(w); + sum1 += w; + new_soft.remove(e); + } + for (unsigned i = mutex.size(); i-- > 0; ) { + expr_ref soft(m.mk_or(i+1, mutex.data()), m); + m_trail.push_back(soft); + rational w = weights[i]; + weight = w - weight; + lower += weight*rational(i); + IF_VERBOSE(1, verbose_stream() << "(opt.maxsat mutex size: " << i + 1 << " weight: " << weight << ")\n";); + sum2 += weight*rational(i+1); + new_soft.insert(soft, weight); + for (; i > 0 && weights[i-1] == w; --i) {} + weight = w; + } + SASSERT(sum1 == sum2); + } + + preprocess::preprocess(solver& s): m(s.get_manager()), s(s), m_trail(m) {} + + bool preprocess::operator()(vector& soft, rational& lower) { + return find_mutexes(soft, lower); + } +}; diff --git a/src/opt/opt_preprocess.h b/src/opt/opt_preprocess.h new file mode 100644 index 000000000..8918e5e89 --- /dev/null +++ b/src/opt/opt_preprocess.h @@ -0,0 +1,38 @@ +/*++ +Copyright (c) 2021 Microsoft Corporation + +Module Name: + + opt_preprocess.h + +Abstract: + + Pre-processing for MaxSMT + + Find mutexes - at most 1 constraints and modify soft constraints and bounds. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-04-11 + +--*/ + +#pragma once + +#include "opt/maxsmt.h" + +namespace opt { + + class preprocess { + ast_manager& m; + solver& s; + expr_ref_vector m_trail; + + bool find_mutexes(vector& softs, rational& lower); + void process_mutex(expr_ref_vector& mutex, obj_map& new_soft, rational& lower); + + public: + preprocess(solver& s); + bool operator()(vector& soft, rational& lower); + }; +}; diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index c6a2f04a9..a6539e129 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -36,34 +36,27 @@ namespace opt { expr_ref_vector m_trail; func_decl_ref_vector m_fresh; ref m_filter; - sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft), m_sort(*this), m_trail(m), m_fresh(m) {} + sortmax(maxsat_context& c, vector& s): + maxsmt_solver_base(c, s), m_sort(*this), m_trail(m), m_fresh(m) {} ~sortmax() override {} lbool operator()() override { - obj_map soft; - if (!init()) { - return l_false; - } - lbool is_sat = find_mutexes(soft); - if (is_sat != l_true) { - return is_sat; - } + if (!init()) + return l_undef; + + lbool is_sat = l_true; m_filter = alloc(generic_model_converter, m, "sortmax"); - rational offset = m_lower; - m_upper = offset; expr_ref_vector in(m); expr_ref tmp(m); ptr_vector out; - obj_map::iterator it = soft.begin(), end = soft.end(); - for (; it != end; ++it) { - if (!it->m_value.is_unsigned()) { + for (auto const & [e, w, t] : m_soft) { + if (!w.is_unsigned()) { throw default_exception("sortmax can only handle unsigned weights. Use a different heuristic."); } - unsigned n = it->m_value.get_unsigned(); + unsigned n = w.get_unsigned(); while (n > 0) { - in.push_back(it->m_key); + in.push_back(e); --n; } } @@ -71,19 +64,15 @@ namespace opt { // initialize sorting network outputs using the initial assignment. unsigned first = 0; - it = soft.begin(); - for (; it != end; ++it) { - if (m_model->is_true(it->m_key)) { - unsigned n = it->m_value.get_unsigned(); + for (auto const & [e, w, t] : m_soft) { + if (t == l_true) { + unsigned n = w.get_unsigned(); while (n > 0) { s().assert_expr(out[first]); ++first; --n; } } - else { - m_upper += it->m_value; - } } while (l_true == is_sat && first < out.size() && m_lower < m_upper) { trace_bounds("sortmax"); @@ -149,8 +138,8 @@ namespace opt { }; - maxsmt_solver_base* mk_sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(sortmax, c, ws, soft); + maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector& s) { + return alloc(sortmax, c, s); } } diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 22a660799..812c8f954 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -44,8 +44,8 @@ namespace opt { } public: - wmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft), + wmax(maxsat_context& c, vector& s): + maxsmt_solver_base(c, s), m_trail(m), m_defs(m) {} @@ -54,22 +54,18 @@ namespace opt { lbool operator()() override { TRACE("opt", tout << "weighted maxsat\n";); scoped_ensure_theory wth(*this); - obj_map soft; reset(); - lbool is_sat = find_mutexes(soft); - if (is_sat != l_true) { - return is_sat; - } - m_upper = m_lower; + if (init()) + return l_undef; + + lbool is_sat = l_true; + expr_ref_vector asms(m); vector cores; - for (auto const& kv : soft) { - assert_weighted(wth(), kv.m_key, kv.m_value); - if (!is_true(kv.m_key)) { - m_upper += kv.m_value; - } - } + for (auto const& [k, w, t] : m_soft) + assert_weighted(wth(), k, w); + wth().init_min_cost(m_upper - m_lower); trace_bounds("wmax"); @@ -308,8 +304,8 @@ namespace opt { }; - maxsmt_solver_base* mk_wmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(wmax, c, ws, soft); + maxsmt_solver_base* mk_wmax(maxsat_context& c, vector & s) { + return alloc(wmax, c, s); } } diff --git a/src/opt/wmax.h b/src/opt/wmax.h index 6cc3ed46b..0a5167269 100644 --- a/src/opt/wmax.h +++ b/src/opt/wmax.h @@ -22,8 +22,8 @@ Notes: #include "opt/maxsmt.h" namespace opt { - maxsmt_solver_base* mk_wmax(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_wmax(maxsat_context& c, vector& s); - maxsmt_solver_base* mk_sortmax(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector& s); } diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 116621dcc..045b92c99 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -312,6 +312,7 @@ namespace euf { } } else if (m.is_distinct(e)) { + // TODO - add lazy case for large values of sz. expr_ref_vector eqs(m); unsigned sz = n->num_args(); for (unsigned i = 0; i < sz; ++i) { From ac55e29a56d78bc0bbba26c7346ba0f45431f99b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Apr 2022 22:23:42 +0200 Subject: [PATCH 030/253] disable propagation Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 19 +++++++++++-------- src/opt/maxsmt.h | 6 +++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 538ecf59b..dab9ae445 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -91,12 +91,15 @@ namespace opt { m_upper += s.weight; } + return true; + preprocess pp(s()); rational lower(0); bool r = pp(m_soft, lower); + if (lower != 0) - m_adjust_value.set_offset(lower + m_adjust_value.get_offset()); + m_adjust_value->set_offset(lower + m_adjust_value->get_offset()); TRACE("opt", tout << "upper: " << m_upper << " assignments: "; @@ -166,8 +169,8 @@ namespace opt { void maxsmt_solver_base::trace_bounds(char const * solver) { IF_VERBOSE(1, - rational l = m_adjust_value(m_lower); - rational u = m_adjust_value(m_upper); + rational l = (*m_adjust_value)(m_lower); + rational u = (*m_adjust_value)(m_upper); if (l > u) std::swap(l, u); verbose_stream() << "(opt." << solver << " [" << l << ":" << u << "])\n";); } @@ -206,7 +209,7 @@ namespace opt { if (m_msolver) { m_msolver->updt_params(m_params); - m_msolver->set_adjust_value(m_adjust_value); + m_msolver->set_adjust_value(*m_adjust_value); is_sat = l_undef; try { is_sat = (*m_msolver)(); @@ -231,9 +234,9 @@ namespace opt { } void maxsmt::set_adjust_value(adjust_value& adj) { - m_adjust_value = adj; + m_adjust_value = &adj; if (m_msolver) { - m_msolver->set_adjust_value(m_adjust_value); + m_msolver->set_adjust_value(adj); } } @@ -265,7 +268,7 @@ namespace opt { rational q = m_msolver->get_lower(); if (q > r) r = q; } - return m_adjust_value(r); + return (*m_adjust_value)(r); } rational maxsmt::get_upper() const { @@ -274,7 +277,7 @@ namespace opt { rational q = m_msolver->get_upper(); if (q < r) r = q; } - return m_adjust_value(r); + return (*m_adjust_value)(r); } void maxsmt::update_lower(rational const& r) { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 4029bb911..5a3dc4ca8 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -35,7 +35,7 @@ namespace opt { class maxsmt_solver { protected: - adjust_value m_adjust_value; + adjust_value* m_adjust_value = nullptr; public: virtual ~maxsmt_solver() {} virtual lbool operator()() = 0; @@ -45,7 +45,7 @@ namespace opt { virtual void collect_statistics(statistics& st) const = 0; virtual void get_model(model_ref& mdl, svector& labels) = 0; virtual void updt_params(params_ref& p) = 0; - void set_adjust_value(adjust_value& adj) { m_adjust_value = adj; } + void set_adjust_value(adjust_value& adj) { m_adjust_value = &adj; } }; @@ -128,7 +128,7 @@ namespace opt { expr_ref_vector m_answer; rational m_lower; rational m_upper; - adjust_value m_adjust_value; + adjust_value* m_adjust_value = nullptr; model_ref m_model; svector m_labels; params_ref m_params; From b264e6c2904456beae27ce19ec4997251034e42c Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Tue, 12 Apr 2022 12:29:53 +0200 Subject: [PATCH 031/253] Reverted reusing can_propagate (#5966) * Fixed registering expressions in push/pop * Reused existing function * Reverted reusing can_propagate --- src/smt/theory_user_propagator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index daded32c7..f783f22fb 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -133,7 +133,7 @@ final_check_status theory_user_propagator::final_check_eh() { } propagate(); // check if it became inconsistent or something new was propagated/registered - bool done = !can_propagate() && !ctx.inconsistent(); + bool done = (sz1 == m_prop.size()) && (sz2 == m_expr2var.size()) && !ctx.inconsistent(); return done ? FC_DONE : FC_CONTINUE; } From 032768b0fc2a6350950ac3065f50ca29eb5495f0 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Tue, 12 Apr 2022 23:29:36 -0700 Subject: [PATCH 032/253] setup.py: copy generated python files correctly (#5975) --- src/api/python/setup.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 1b455bb56..5309142f2 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -154,16 +154,10 @@ def _copy_bins(): _clean_bins() - python_dir = None - if RELEASE_DIR is not None: - python_dir = os.path.join(RELEASE_DIR, 'bin', 'python') - elif SRC_DIR == SRC_DIR_LOCAL: - python_dir = os.path.join(SRC_DIR, 'src', 'api', 'python') - if python_dir is not None: - py_z3_build_dir = os.path.join(BUILD_DIR, 'python', 'z3') - root_z3_dir = os.path.join(ROOT_DIR, 'z3') - shutil.copy(os.path.join(py_z3_build_dir, 'z3core.py'), root_z3_dir) - shutil.copy(os.path.join(py_z3_build_dir, 'z3consts.py'), root_z3_dir) + py_z3_build_dir = os.path.join(BUILD_DIR, 'python', 'z3') + root_z3_dir = os.path.join(ROOT_DIR, 'z3') + shutil.copy(os.path.join(py_z3_build_dir, 'z3core.py'), root_z3_dir) + shutil.copy(os.path.join(py_z3_build_dir, 'z3consts.py'), root_z3_dir) # STEP 2: Copy the shared library, the executable and the headers From 9834d7aae0faf2b1cc9b96c7c20b087f96374c51 Mon Sep 17 00:00:00 2001 From: Zachary Wimer Date: Tue, 12 Apr 2022 23:31:24 -0700 Subject: [PATCH 033/253] Setup.py fix dependencies (#5971) * Add wheel as build dependency * pyproject toml update --- src/api/python/pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/api/python/pyproject.toml diff --git a/src/api/python/pyproject.toml b/src/api/python/pyproject.toml new file mode 100644 index 000000000..ead8162b7 --- /dev/null +++ b/src/api/python/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools>=46.4.0", "wheel"] +build-backend = "setuptools.build_meta" From c0b455e01089fdafd2dadd5124d2080dff777823 Mon Sep 17 00:00:00 2001 From: Zachary Wimer Date: Tue, 12 Apr 2022 23:48:08 -0700 Subject: [PATCH 034/253] Add cmake setup.py build dep (#5972) * Add wheel as build dependency * Add cmake as a python build dependency * pyproject toml update Co-authored-by: Nikolaj Bjorner --- src/api/python/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/pyproject.toml b/src/api/python/pyproject.toml index ead8162b7..a9f2676a7 100644 --- a/src/api/python/pyproject.toml +++ b/src/api/python/pyproject.toml @@ -1,3 +1,3 @@ [build-system] -requires = ["setuptools>=46.4.0", "wheel"] +requires = ["setuptools>=46.4.0", "wheel", "cmake"] build-backend = "setuptools.build_meta" From c9fa00aec1442464c9cc2ab6f3d2e5c749232b6e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Apr 2022 11:22:43 +0200 Subject: [PATCH 035/253] expose recursive functions with own op-code over API --- src/api/api_ast.cpp | 3 +++ src/api/z3_api.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 7ee95afc8..9f9039378 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1329,6 +1329,9 @@ extern "C" { } } + if (mk_c(c)->recfun().get_family_id() == _d->get_family_id()) + return Z3_OP_RECURSIVE; + return Z3_OP_UNINTERPRETED; Z3_CATCH_RETURN(Z3_OP_UNINTERPRETED); } diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 8a610bc6d..1388d0ab1 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -996,6 +996,8 @@ typedef enum information is exposed. Tools may use the string representation of the function declaration to obtain more information. + - Z3_OP_RECURSIVE: function declared as recursive + - Z3_OP_UNINTERPRETED: kind used for uninterpreted symbols. */ typedef enum { @@ -1320,6 +1322,7 @@ typedef enum { Z3_OP_FPA_BV2RM, Z3_OP_INTERNAL, + Z3_OP_RECURSIVE, Z3_OP_UNINTERPRETED } Z3_decl_kind; From 3f5eb7fcf29dad76498e560826f9474016358027 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Apr 2022 11:24:16 +0200 Subject: [PATCH 036/253] re-enable pre-process --- src/opt/maxlex.cpp | 2 +- src/opt/maxres.cpp | 4 +--- src/opt/maxsmt.cpp | 42 ++++++++++++++++++++--------------------- src/opt/maxsmt.h | 10 +++------- src/opt/opt_context.cpp | 40 +++++++++++++++++++++------------------ src/opt/opt_context.h | 9 +++++++-- src/opt/opt_solver.h | 1 + src/opt/sortmax.cpp | 8 ++++---- src/opt/wmax.cpp | 8 ++++---- src/opt/wmax.h | 4 ++-- 10 files changed, 66 insertions(+), 62 deletions(-) diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp index 82eee6f5e..fa97359d0 100644 --- a/src/opt/maxlex.cpp +++ b/src/opt/maxlex.cpp @@ -186,7 +186,7 @@ namespace opt { public: maxlex(maxsat_context& c, unsigned id, vector& s): - maxsmt_solver_base(c, s), + maxsmt_solver_base(c, s, id), m(c.get_manager()), m_c(c) { // ensure that soft constraints are sorted with largest soft constraints first. diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 0d1bf2394..135e0f80e 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -95,7 +95,6 @@ private: expr_ref_vector const& soft() override { return i.m_asms; } }; - unsigned m_index; stats m_stats; expr_ref_vector m_B; expr_ref_vector m_asms; @@ -132,8 +131,7 @@ public: maxres(maxsat_context& c, unsigned index, vector& soft, strategy_t st): - maxsmt_solver_base(c, soft), - m_index(index), + maxsmt_solver_base(c, soft, index), m_B(m), m_asms(m), m_defs(m), m_new_core(m), m_mus(c.get_solver()), diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index dab9ae445..a3d5f2f45 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -35,10 +35,10 @@ Notes: namespace opt { - maxsmt_solver_base::maxsmt_solver_base( - maxsat_context& c, vector& s): + maxsmt_solver_base::maxsmt_solver_base(maxsat_context& c, vector& s, unsigned index): m(c.get_manager()), m_c(c), + m_index(index), m_soft(s), m_assertions(m), m_trail(m) { @@ -91,18 +91,17 @@ namespace opt { m_upper += s.weight; } - return true; + // return true; preprocess pp(s()); rational lower(0); bool r = pp(m_soft, lower); - - if (lower != 0) - m_adjust_value->set_offset(lower + m_adjust_value->get_offset()); + m_c.add_offset(m_index, lower); + m_upper -= lower; TRACE("opt", - tout << "upper: " << m_upper << " assignments: "; + tout << "lower " << lower << " upper: " << m_upper << " assignments: "; for (soft& s : m_soft) tout << (s.is_true()?"T":"F"); tout << "\n";); return r; @@ -169,8 +168,8 @@ namespace opt { void maxsmt_solver_base::trace_bounds(char const * solver) { IF_VERBOSE(1, - rational l = (*m_adjust_value)(m_lower); - rational u = (*m_adjust_value)(m_upper); + rational l = m_c.adjust(m_index, m_lower); + rational u = m_c.adjust(m_index, m_upper); if (l > u) std::swap(l, u); verbose_stream() << "(opt." << solver << " [" << l << ":" << u << "])\n";); } @@ -196,10 +195,10 @@ namespace opt { m_msolver = mk_primal_dual_maxres(m_c, m_index, m_soft); } else if (maxsat_engine == symbol("wmax")) { - m_msolver = mk_wmax(m_c, m_soft); + m_msolver = mk_wmax(m_c, m_soft, m_index); } else if (maxsat_engine == symbol("sortmax")) { - m_msolver = mk_sortmax(m_c, m_soft); + m_msolver = mk_sortmax(m_c, m_soft, m_index); } else { auto str = maxsat_engine.str(); @@ -209,7 +208,6 @@ namespace opt { if (m_msolver) { m_msolver->updt_params(m_params); - m_msolver->set_adjust_value(*m_adjust_value); is_sat = l_undef; try { is_sat = (*m_msolver)(); @@ -233,13 +231,6 @@ namespace opt { return is_sat; } - void maxsmt::set_adjust_value(adjust_value& adj) { - m_adjust_value = &adj; - if (m_msolver) { - m_msolver->set_adjust_value(adj); - } - } - void maxsmt::reset_upper() { if (m_msolver) { m_msolver->reset_upper(); @@ -268,7 +259,7 @@ namespace opt { rational q = m_msolver->get_lower(); if (q > r) r = q; } - return (*m_adjust_value)(r); + return m_c.adjust(m_index, r); } rational maxsmt::get_upper() const { @@ -277,7 +268,7 @@ namespace opt { rational q = m_msolver->get_upper(); if (q < r) r = q; } - return (*m_adjust_value)(r); + return m_c.adjust(m_index, r); } void maxsmt::update_lower(rational const& r) { @@ -370,6 +361,7 @@ namespace opt { model_ref m_model; ref m_fm; symbol m_maxsat_engine; + vector m_offsets; public: solver_maxsat_context(params_ref& p, solver* s, model * m): m_params(p), @@ -394,6 +386,14 @@ namespace opt { bool verify_model(unsigned id, model* mdl, rational const& v) override { return true; }; void set_model(model_ref& _m) override { m_model = _m; } void model_updated(model* mdl) override { } // no-op + rational adjust(unsigned id, rational const& r) override { + m_offsets.reserve(id+1); + return r + m_offsets[id]; + } + void add_offset(unsigned id, rational const& r) override { + m_offsets.reserve(id+1); + m_offsets[id] += r; + } }; lbool maxsmt_wrapper::operator()(vector>& soft) { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 5a3dc4ca8..b0ae5eeb1 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -34,8 +34,6 @@ namespace opt { class maxsat_context; class maxsmt_solver { - protected: - adjust_value* m_adjust_value = nullptr; public: virtual ~maxsmt_solver() {} virtual lbool operator()() = 0; @@ -45,7 +43,6 @@ namespace opt { virtual void collect_statistics(statistics& st) const = 0; virtual void get_model(model_ref& mdl, svector& labels) = 0; virtual void updt_params(params_ref& p) = 0; - void set_adjust_value(adjust_value& adj) { m_adjust_value = &adj; } }; @@ -67,7 +64,8 @@ namespace opt { class maxsmt_solver_base : public maxsmt_solver { protected: ast_manager& m; - maxsat_context& m_c; + maxsat_context& m_c; + unsigned m_index; vector& m_soft; expr_ref_vector m_assertions; expr_ref_vector m_trail; @@ -78,7 +76,7 @@ namespace opt { params_ref m_params; // config public: - maxsmt_solver_base(maxsat_context& c, vector& soft); + maxsmt_solver_base(maxsat_context& c, vector& soft, unsigned index); ~maxsmt_solver_base() override {} rational get_lower() const override { return m_lower; } @@ -128,7 +126,6 @@ namespace opt { expr_ref_vector m_answer; rational m_lower; rational m_upper; - adjust_value* m_adjust_value = nullptr; model_ref m_model; svector m_labels; params_ref m_params; @@ -137,7 +134,6 @@ namespace opt { lbool operator()(); void updt_params(params_ref& p); void add(expr* f, rational const& w); - void set_adjust_value(adjust_value& adj); unsigned size() const { return m_soft.size(); } expr* operator[](unsigned idx) const { return m_soft[idx].s; } rational weight(unsigned idx) const { return m_soft[idx].weight; } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 8848b61c9..25982e89e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -398,7 +398,7 @@ namespace opt { } void context::set_model(model_ref& m) { - m_model = m; + m_model = m; opt_params optp(m_params); if (optp.dump_models() && m) { model_ref md = m->copy(); @@ -930,7 +930,8 @@ namespace opt { bool context::is_maxsat(expr* fml, expr_ref_vector& terms, vector& weights, rational& offset, bool& neg, symbol& id, expr_ref& orig_term, unsigned& index) { - if (!is_app(fml)) return false; + if (!is_app(fml)) + return false; neg = false; orig_term = nullptr; index = 0; @@ -1105,8 +1106,7 @@ namespace opt { obj.m_weights.append(weights); obj.m_adjust_value.set_offset(offset); obj.m_adjust_value.set_negate(neg); - m_maxsmts.find(id)->set_adjust_value(obj.m_adjust_value); - TRACE("opt", tout << "maxsat: " << id << " offset:" << offset << "\n"; + TRACE("opt", tout << "maxsat: " << neg << " " << id << " offset: " << offset << "\n"; tout << terms << "\n";); } else if (is_maximize(fml, tr, orig_term, index)) { @@ -1158,7 +1158,14 @@ namespace opt { #endif } + rational context::adjust(unsigned id, rational const& v) { + return m_objectives[id].m_adjust_value(v); + } + void context::add_offset(unsigned id, rational const& o) { + m_objectives[id].m_adjust_value.add_offset(o); + } + bool context::verify_model(unsigned index, model* md, rational const& _v) { rational r; app_ref term = m_objectives[index].m_term; @@ -1341,24 +1348,21 @@ namespace opt { break; } case O_MAXSMT: { - bool ok = true; - for (unsigned j = 0; ok && j < obj.m_terms.size(); ++j) { + for (unsigned j = 0; j < obj.m_terms.size(); ++j) { val = (*m_model)(obj.m_terms[j]); TRACE("opt", tout << mk_pp(obj.m_terms[j], m) << " " << val << "\n";); - if (!m.is_true(val)) { + if (!m.is_true(val)) r += obj.m_weights[j]; - } } - if (ok) { - maxsmt& ms = *m_maxsmts.find(obj.m_id); - if (is_lower) { - ms.update_upper(r); - TRACE("opt", tout << "update upper from " << r << " to " << ms.get_upper() << "\n";); - } - else { - ms.update_lower(r); - TRACE("opt", tout << "update lower from " << r << " to " << ms.get_lower() << "\n";); - } + + maxsmt& ms = *m_maxsmts.find(obj.m_id); + if (is_lower) { + ms.update_upper(r); + TRACE("opt", tout << "update upper from " << r << " to " << ms.get_upper() << "\n";); + } + else { + ms.update_lower(r); + TRACE("opt", tout << "update lower from " << r << " to " << ms.get_lower() << "\n";); } break; } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 1e950174a..c02689a38 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -57,6 +57,8 @@ namespace opt { virtual smt::context& smt_context() = 0; // access SMT context for SMT based MaxSMT solver (wmax requires SMT core) virtual unsigned num_objectives() = 0; virtual bool verify_model(unsigned id, model* mdl, rational const& v) = 0; + virtual rational adjust(unsigned id, rational const& v) = 0; + virtual void add_offset(unsigned id, rational const& o) = 0; virtual void set_model(model_ref& _m) = 0; virtual void model_updated(model* mdl) = 0; }; @@ -93,7 +95,7 @@ namespace opt { app_ref m_term; // for maximize, minimize term expr_ref_vector m_terms; // for maxsmt vector m_weights; // for maxsmt - adjust_value m_adjust_value; + adjust_value m_adjust_value; symbol m_id; // for maxsmt unsigned m_index; // for maximize/minimize index @@ -269,11 +271,14 @@ namespace opt { void model_updated(model* mdl) override; + rational adjust(unsigned id, rational const& v) override; + + void add_offset(unsigned id, rational const& o) override; + void register_on_model(on_model_t& ctx, std::function& on_model) { m_on_model_ctx = ctx; m_on_model_eh = on_model; } - void collect_timer_stats(statistics& st) const { if (m_time != 0) diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index caac008fd..47fe86f94 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -48,6 +48,7 @@ namespace opt { void set_offset(rational const& o) { m_offset = o; } void set_negate(bool neg) { m_negate = neg; } rational const& get_offset() const { return m_offset; } + void add_offset(rational const& o) { if (m_negate) m_offset -= o; else m_offset += o; } bool get_negate() { return m_negate; } inf_eps operator()(inf_eps const& r) const { inf_eps result = r; diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index a6539e129..962369bf2 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -36,8 +36,8 @@ namespace opt { expr_ref_vector m_trail; func_decl_ref_vector m_fresh; ref m_filter; - sortmax(maxsat_context& c, vector& s): - maxsmt_solver_base(c, s), m_sort(*this), m_trail(m), m_fresh(m) {} + sortmax(maxsat_context& c, vector& s, unsigned index): + maxsmt_solver_base(c, s, index), m_sort(*this), m_trail(m), m_fresh(m) {} ~sortmax() override {} @@ -138,8 +138,8 @@ namespace opt { }; - maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector& s) { - return alloc(sortmax, c, s); + maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector& s, unsigned index) { + return alloc(sortmax, c, s, index); } } diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 812c8f954..1fbd26cb8 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -44,8 +44,8 @@ namespace opt { } public: - wmax(maxsat_context& c, vector& s): - maxsmt_solver_base(c, s), + wmax(maxsat_context& c, vector& s, unsigned index): + maxsmt_solver_base(c, s, index), m_trail(m), m_defs(m) {} @@ -304,8 +304,8 @@ namespace opt { }; - maxsmt_solver_base* mk_wmax(maxsat_context& c, vector & s) { - return alloc(wmax, c, s); + maxsmt_solver_base* mk_wmax(maxsat_context& c, vector & s, unsigned index) { + return alloc(wmax, c, s, index); } } diff --git a/src/opt/wmax.h b/src/opt/wmax.h index 0a5167269..7f5b26ac6 100644 --- a/src/opt/wmax.h +++ b/src/opt/wmax.h @@ -22,8 +22,8 @@ Notes: #include "opt/maxsmt.h" namespace opt { - maxsmt_solver_base* mk_wmax(maxsat_context& c, vector& s); + maxsmt_solver_base* mk_wmax(maxsat_context& c, vector& s, unsigned index); - maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector& s); + maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector& s, unsigned index); } From ddbe17d581d9835f9bc57079383eefce2b841162 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Apr 2022 16:08:54 +0200 Subject: [PATCH 037/253] #5965 define the is_bool on ArithSortRef --- src/api/python/z3/z3.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index d3d6067c3..223b3e038 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -2279,6 +2279,9 @@ class ArithSortRef(SortRef): """ return self.kind() == Z3_INT_SORT + def is_bool(self): + return False + def subsort(self, other): """Return `True` if `self` is a subsort of `other`.""" return self.is_int() and is_arith_sort(other) and other.is_real() From 7d47e45c6b734ce89b511817c3589a382f241878 Mon Sep 17 00:00:00 2001 From: Zachary Wimer Date: Fri, 15 Apr 2022 00:57:51 -0700 Subject: [PATCH 038/253] Add a hacky patch so that Z3 on M1 hardware can link to libs properly (#5974) * Add a hacky patch so that Z3 on M1 hardware can link to libs properly * Update setup.py Co-authored-by: Nikolaj Bjorner --- src/api/python/setup.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 5309142f2..6179422df 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -178,6 +178,20 @@ def _copy_bins(): continue shutil.copy(os.path.join(header_dir, fname), os.path.join(HEADERS_DIR, fname)) + # This hack lets z3 installed libs link on M1 macs; it is a hack, not a proper fix + # @TODO: Linked issue: https://github.com/Z3Prover/z3/issues/5926 + major_minor = '.'.join(_z3_version().split('.')[:2]) + link_name = None + if BUILD_PLATFORM in ('win32', 'cygwin', 'win'): + pass # TODO: When windows VMs work on M1, fill this in + elif BUILD_PLATFORM in ('darwin', 'osx'): + split = LIBRARY_FILE.split('.') + link_name = split[0] + '.' + major_minor + '.' + split[1] + else: + link_name = LIBRARY_FILE + '.' + major_minor + if link_name: + os.symlink(LIBRARY_FILE, os.path.join(LIBS_DIR, link_name), True) + def _copy_sources(): """ Prepare for a source distribution by assembling a minimal set of source files needed @@ -273,10 +287,10 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: osver = RELEASE_METADATA[3] if osver.count('.') > 1: osver = '.'.join(osver.split('.')[:2]) - if arch == 'x64': + if arch == 'x64': plat_name ='macosx_%s_x86_64' % osver.replace('.', '_') elif arch == 'arm64': - plat_name ='macosx_%s_arm64' % osver.replace('.', '_') + plat_name ='macosx_%s_arm64' % osver.replace('.', '_') else: raise Exception(f"idk how os {distos} {osver} works. what goes here?") else: @@ -287,7 +301,6 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: sys.argv.insert(idx + 1, plat_name) sys.argv.insert(idx + 2, '--universal') # supports py2+py3. if --plat-name is not specified this will also mean that the package can be installed on any machine regardless of architecture, so watch out! - setup( name='z3-solver', version=_z3_version(), From a634876180430cf110e9d11691f816cd1f7b96dd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Apr 2022 18:00:02 +0200 Subject: [PATCH 039/253] sort muxes --- src/cmd_context/eval_cmd.cpp | 2 ++ src/sat/sat_solver.cpp | 12 +++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/cmd_context/eval_cmd.cpp b/src/cmd_context/eval_cmd.cpp index 8819eb584..70a48da5f 100644 --- a/src/cmd_context/eval_cmd.cpp +++ b/src/cmd_context/eval_cmd.cpp @@ -57,6 +57,8 @@ public: void execute(cmd_context & ctx) override { model_ref md; + if (ctx.ignore_check()) + return; if (!ctx.is_model_available(md)) throw cmd_exception("model is not available"); if (!m_target) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 4a254ac06..12dfb72b5 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -4192,17 +4192,19 @@ namespace sat { m_ext->find_mutexes(_lits, mutexes); } unsigned_vector ps; - for (literal lit : _lits) { + for (literal lit : _lits) ps.push_back(lit.index()); - } mc.cliques(ps, _mutexes); + vector> sorted; for (auto const& mux : _mutexes) { literal_vector clique; - for (auto const& idx : mux) { + sorted.reserve(mux.size() + 1); + for (auto const& idx : mux) clique.push_back(to_literal(idx)); - } - mutexes.push_back(clique); + sorted[mux.size()].push_back(clique); } + for (unsigned i = sorted.size(); i-- > 0; ) + mutexes.append(sorted[i]); return l_true; } From 3cc9d7f4438ffb56bb909c8bed8a84c133acede2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Apr 2022 12:55:17 +0200 Subject: [PATCH 040/253] improve pre-processing --- src/api/api_solver.cpp | 2 +- src/muz/spacer/spacer_iuc_solver.h | 2 +- src/opt/opt_preprocess.cpp | 15 ++- src/opt/opt_preprocess.h | 1 + src/opt/opt_solver.h | 2 +- src/sat/sat_solver.cpp | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 8 +- src/sat/smt/atom2bool_var.cpp | 8 +- src/smt/smt_context.cpp | 23 ++-- src/smt/smt_context.h | 2 +- src/smt/smt_kernel.cpp | 4 +- src/smt/smt_kernel.h | 2 +- src/smt/smt_solver.cpp | 4 +- src/solver/combined_solver.cpp | 6 +- src/solver/solver.h | 2 +- src/solver/solver_pool.cpp | 4 +- src/solver/tactic2solver.cpp | 2 +- .../fd_solver/bounded_int2bv_solver.cpp | 4 +- src/tactic/fd_solver/enum2bv_solver.cpp | 4 +- src/tactic/fd_solver/pb2bv_solver.cpp | 4 +- src/tactic/fd_solver/smtfd_solver.cpp | 4 +- src/util/max_cliques.h | 122 +++++++++++++----- 22 files changed, 147 insertions(+), 80 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 948064af6..c9eda8712 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -564,7 +564,7 @@ extern "C" { init_solver(c, s); Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); - expr_ref_vector trail = to_solver_ref(s)->get_trail(); + expr_ref_vector trail = to_solver_ref(s)->get_trail(UINT_MAX); for (expr* f : trail) { v->m_ast_vector.push_back(f); } diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index fa9f76311..739588c6b 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -126,7 +126,7 @@ public: void move_to_front(expr* e) override { m_solver.move_to_front(e); } expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { m_solver.get_levels(vars, depth); } - expr_ref_vector get_trail() override { return m_solver.get_trail(); } + expr_ref_vector get_trail(unsigned max_level) override { return m_solver.get_trail(max_level); } void push() override; void pop(unsigned n) override; diff --git a/src/opt/opt_preprocess.cpp b/src/opt/opt_preprocess.cpp index f65d5d09b..6cbc8b1b9 100644 --- a/src/opt/opt_preprocess.cpp +++ b/src/opt/opt_preprocess.cpp @@ -23,10 +23,9 @@ Author: namespace opt { - bool preprocess::find_mutexes(vector& softs, rational& lower) { - expr_ref_vector fmls(m); + obj_map preprocess::soft2map(vector const& softs, expr_ref_vector& fmls) { obj_map new_soft; - for (soft& sf : softs) { + for (soft const& sf : softs) { m_trail.push_back(sf.s); if (new_soft.contains(sf.s)) new_soft[sf.s] += sf.weight; @@ -34,6 +33,12 @@ namespace opt { new_soft.insert(sf.s, sf.weight); fmls.push_back(sf.s); } + return new_soft; + } + + bool preprocess::find_mutexes(vector& softs, rational& lower) { + expr_ref_vector fmls(m); + obj_map new_soft = soft2map(softs, fmls); vector mutexes; lbool is_sat = s.find_mutexes(fmls, mutexes); if (is_sat == l_false) @@ -97,6 +102,8 @@ namespace opt { preprocess::preprocess(solver& s): m(s.get_manager()), s(s), m_trail(m) {} bool preprocess::operator()(vector& soft, rational& lower) { - return find_mutexes(soft, lower); + if (!find_mutexes(soft, lower)) + return false; + return true; } }; diff --git a/src/opt/opt_preprocess.h b/src/opt/opt_preprocess.h index 8918e5e89..f5f1c9db6 100644 --- a/src/opt/opt_preprocess.h +++ b/src/opt/opt_preprocess.h @@ -28,6 +28,7 @@ namespace opt { solver& s; expr_ref_vector m_trail; + obj_map soft2map(vector const& softs, expr_ref_vector& fmls); bool find_mutexes(vector& softs, rational& lower); void process_mutex(expr_ref_vector& mutex, obj_map& new_soft, rational& lower); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 47fe86f94..e71287400 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -108,7 +108,7 @@ namespace opt { lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override; lbool preferred_sat(expr_ref_vector const& asms, vector& cores) override; void get_levels(ptr_vector const& vars, unsigned_vector& depth) override; - expr_ref_vector get_trail() override { return m_context.get_trail(); } + expr_ref_vector get_trail(unsigned max_level) override { return m_context.get_trail(max_level); } expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } void set_phase(expr* e) override { m_context.set_phase(e); } phase* get_phase() override { return m_context.get_phase(); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 12dfb72b5..4f5c9ca8d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -4194,7 +4194,7 @@ namespace sat { unsigned_vector ps; for (literal lit : _lits) ps.push_back(lit.index()); - mc.cliques(ps, _mutexes); + mc.cliques2(ps, _mutexes); vector> sorted; for (auto const& mux : _mutexes) { literal_vector clique; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 61dc53cd8..af0d9dd1b 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -390,7 +390,7 @@ public: } } - expr_ref_vector get_trail() override { + expr_ref_vector get_trail(unsigned max_level) override { expr_ref_vector result(m); unsigned sz = m_solver.trail_size(); expr_ref_vector lit2expr(m); @@ -398,7 +398,11 @@ public: m_map.mk_inv(lit2expr); for (unsigned i = 0; i < sz; ++i) { sat::literal lit = m_solver.trail_literal(i); - result.push_back(lit2expr[lit.index()].get()); + if (m_solver.lvl(lit) > max_level) + continue; + expr_ref e(lit2expr.get(lit.index()), m); + if (e) + result.push_back(e); } return result; } diff --git a/src/sat/smt/atom2bool_var.cpp b/src/sat/smt/atom2bool_var.cpp index 996e8e5e9..b12f51fb0 100644 --- a/src/sat/smt/atom2bool_var.cpp +++ b/src/sat/smt/atom2bool_var.cpp @@ -41,12 +41,12 @@ void atom2bool_var::mk_var_inv(expr_ref_vector & var2expr) const { sat::bool_var atom2bool_var::to_bool_var(expr * n) const { unsigned idx = m_id2map.get(n->get_id(), UINT_MAX); - if (idx == UINT_MAX) { + if (idx == UINT_MAX) return sat::null_bool_var; - } - else { + else if (idx >= m_mapping.size()) + return sat::null_bool_var; + else return m_mapping[idx].m_value; - } } struct collect_boolean_interface_proc { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 377ad1f2b..a9b44ab3c 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4612,9 +4612,15 @@ namespace smt { } } - expr_ref_vector context::get_trail() { + expr_ref_vector context::get_trail(unsigned max_level) { expr_ref_vector result(get_manager()); - get_assignments(result); + for (literal lit : m_assigned_literals) { + if (get_assign_level(lit) > max_level + m_base_lvl) + continue; + expr_ref e(m); + literal2expr(lit, e); + result.push_back(std::move(e)); + } return result; } @@ -4622,15 +4628,10 @@ namespace smt { expr_mark visited; for (expr* fml : result) visited.mark(fml); - for (literal lit : m_assigned_literals) { - if (get_assign_level(lit) > m_base_lvl) - break; - expr_ref e(m); - literal2expr(lit, e); - if (visited.is_marked(e)) - continue; - result.push_back(std::move(e)); - } + expr_ref_vector trail = get_trail(0); + for (expr* t : trail) + if (!visited.is_marked(t)) + result.push_back(t); } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index ac2b0cfc8..637c2171b 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1667,7 +1667,7 @@ namespace smt { void get_levels(ptr_vector const& vars, unsigned_vector& depth); - expr_ref_vector get_trail(); + expr_ref_vector get_trail(unsigned max_level); void get_model(model_ref & m); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 87e5fd36d..2d082170c 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -248,8 +248,8 @@ namespace smt { m_imp->m_kernel.get_levels(vars, depth); } - expr_ref_vector kernel::get_trail() { - return m_imp->m_kernel.get_trail(); + expr_ref_vector kernel::get_trail(unsigned max_level) { + return m_imp->m_kernel.get_trail(max_level); } void kernel::user_propagate_init( diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 77ad2559c..068bd1b52 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -248,7 +248,7 @@ namespace smt { /** \brief retrieve trail of assignment stack. */ - expr_ref_vector get_trail(); + expr_ref_vector get_trail(unsigned max_level); /** \brief (For debubbing purposes) Prints the state of the kernel diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index ad67c19d1..344cf9e6f 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -208,8 +208,8 @@ namespace { m_context.get_levels(vars, depth); } - expr_ref_vector get_trail() override { - return m_context.get_trail(); + expr_ref_vector get_trail(unsigned max_level) override { + return m_context.get_trail(max_level); } void user_propagate_init( diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index b95d2d7f8..bfe495b6e 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -311,11 +311,11 @@ public: m_solver2->get_levels(vars, depth); } - expr_ref_vector get_trail() override { + expr_ref_vector get_trail(unsigned max_level) override { if (m_use_solver1_results) - return m_solver1->get_trail(); + return m_solver1->get_trail(max_level); else - return m_solver2->get_trail(); + return m_solver2->get_trail(max_level); } proof * get_proof() override { diff --git a/src/solver/solver.h b/src/solver/solver.h index 13692c857..dde4ccbe0 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -265,7 +265,7 @@ public: expr_ref_vector get_non_units(); - virtual expr_ref_vector get_trail() = 0; // { return expr_ref_vector(get_manager()); } + virtual expr_ref_vector get_trail(unsigned max_level) = 0; // { return expr_ref_vector(get_manager()); } virtual void get_levels(ptr_vector const& vars, unsigned_vector& depth) = 0; diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 9e897208f..bbc46c9c8 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -127,8 +127,8 @@ public: m_base->get_levels(vars, depth); } - expr_ref_vector get_trail() override { - return m_base->get_trail(); + expr_ref_vector get_trail(unsigned max_level) override { + return m_base->get_trail(max_level); } lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index a2909fd7b..e8a30a009 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -134,7 +134,7 @@ public: throw default_exception("cannot retrieve depth from solvers created using tactics"); } - expr_ref_vector get_trail() override { + expr_ref_vector get_trail(unsigned max_level) override { throw default_exception("cannot retrieve trail from solvers created using tactics"); } }; diff --git a/src/tactic/fd_solver/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp index e907abc72..bc05a3328 100644 --- a/src/tactic/fd_solver/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -165,8 +165,8 @@ public: void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { m_solver->get_levels(vars, depth); } - expr_ref_vector get_trail() override { - return m_solver->get_trail(); + expr_ref_vector get_trail(unsigned max_level) override { + return m_solver->get_trail(max_level); } model_converter* external_model_converter() const { diff --git a/src/tactic/fd_solver/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp index 80e265676..cb136ad9f 100644 --- a/src/tactic/fd_solver/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -189,8 +189,8 @@ public: m_solver->get_levels(vars, depth); } - expr_ref_vector get_trail() override { - return m_solver->get_trail(); + expr_ref_vector get_trail(unsigned max_level) override { + return m_solver->get_trail(max_level); } unsigned get_num_assertions() const override { diff --git a/src/tactic/fd_solver/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp index f5d493af6..cd19b0dca 100644 --- a/src/tactic/fd_solver/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -105,8 +105,8 @@ public: m_solver->get_levels(vars, depth); } - expr_ref_vector get_trail() override { - return m_solver->get_trail(); + expr_ref_vector get_trail(unsigned max_level) override { + return m_solver->get_trail(max_level); } model_converter* external_model_converter() const{ diff --git a/src/tactic/fd_solver/smtfd_solver.cpp b/src/tactic/fd_solver/smtfd_solver.cpp index c5d67506e..32f9df9af 100644 --- a/src/tactic/fd_solver/smtfd_solver.cpp +++ b/src/tactic/fd_solver/smtfd_solver.cpp @@ -2098,9 +2098,9 @@ namespace smtfd { m_fd_sat_solver->get_levels(vars, depth); } - expr_ref_vector get_trail() override { + expr_ref_vector get_trail(unsigned max_level) override { init(); - return m_fd_sat_solver->get_trail(); + return m_fd_sat_solver->get_trail(max_level); } unsigned get_num_assertions() const override { diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index 64a718bd1..ad6bc0219 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -20,6 +20,7 @@ Notes: #include "util/vector.h" #include "util/uint_set.h" +#include "util/heap.h" template @@ -43,12 +44,9 @@ class max_cliques : public T { m_seen1.insert(p); if (m_seen2.contains(p)) { unsigned_vector const& tc = m_tc[p]; - for (unsigned j = 0; j < tc.size(); ++j) { - unsigned np = tc[j]; - if (goal.contains(np)) { + for (unsigned np : tc) + if (goal.contains(np)) reachable.insert(np); - } - } } else { unsigned np = negate(p); @@ -61,29 +59,30 @@ class max_cliques : public T { for (unsigned i = m_todo.size(); i > 0; ) { --i; p = m_todo[i]; - if (m_seen2.contains(p)) { + if (m_seen2.contains(p)) continue; - } m_seen2.insert(p); unsigned np = negate(p); unsigned_vector& tc = m_tc[p]; - if (goal.contains(np)) { + if (goal.contains(np)) tc.push_back(np); - } - else { - unsigned_vector const& succ = next(np); - for (unsigned j = 0; j < succ.size(); ++j) { - tc.append(m_tc[succ[j]]); - } - } + else + for (unsigned s : next(np)) + tc.append(m_tc[s]); } } - - - - unsigned_vector const& next(unsigned vertex) const { return m_next[vertex]; } + + void init(unsigned_vector const& ps) { + unsigned max = 0; + for (unsigned p : ps) { + unsigned np = negate(p); + max = std::max(max, std::max(np, p) + 1); + } + m_next.reserve(max); + m_tc.reserve(m_next.size()); + } public: void add_edge(unsigned src, unsigned dst) { @@ -94,20 +93,11 @@ public: } void cliques(unsigned_vector const& ps, vector& cliques) { - unsigned max = 0; - unsigned num_ps = ps.size(); - for (unsigned i = 0; i < num_ps; ++i) { - unsigned p = ps[i]; - unsigned np = negate(p); - max = std::max(max, std::max(np, p) + 1); - } - m_next.reserve(max); - m_tc.reserve(m_next.size()); + init(ps); unsigned_vector clique; uint_set vars; - for (unsigned i = 0; i < num_ps; ++i) { - vars.insert(ps[i]); - } + for (unsigned v : ps) + vars.insert(v); while (!vars.empty()) { clique.reset(); @@ -118,9 +108,8 @@ public: m_reachable[turn].remove(p); vars.remove(p); clique.push_back(p); - if (m_reachable[turn].empty()) { + if (m_reachable[turn].empty()) break; - } m_reachable[!turn].reset(); get_reachable(p, m_reachable[turn], m_reachable[!turn]); turn = !turn; @@ -129,10 +118,75 @@ public: if (clique.size() == 2 && clique[0] == negate(clique[1])) { // no op } - else { + else cliques.push_back(clique); + } + } + } + + + // better quality cliques + void cliques2(unsigned_vector const& ps, vector& cliques) { + + uint_set all_vars, todo; + u_map conns; + + init(ps); + + struct compare_degree { + u_map& conns; + compare_degree(u_map& conns): conns(conns) {} + bool operator()(unsigned x, unsigned y) const { + return conns[x].num_elems() < conns[y].num_elems(); + } + }; + compare_degree lt(conns); + heap heap(m_next.size(), lt); + + for (unsigned p : ps) { + all_vars.insert(p); + todo.insert(p); + } + + for (unsigned v : ps) { + uint_set reach; + get_reachable(v, all_vars, reach); + conns.insert(v, reach); + heap.insert(v); + } + + while (!todo.empty()) { + unsigned v = heap.min_value(); + uint_set am1; + unsigned_vector next; + for (unsigned n : conns[v]) + if (todo.contains(n)) + next.push_back(n); + std::sort(next.begin(), next.end(), [&](unsigned a, unsigned b) { return conns[a].num_elems() < conns[b].num_elems(); }); + for (unsigned x : next) { + if (std::all_of(am1.begin(), am1.end(), [&](unsigned y) { return conns[x].contains(y); })) + am1.insert(x); + } + am1.insert(v); + for (unsigned x : am1) { + todo.remove(x); + for (unsigned y : conns[x]) { + conns[y].remove(x); + heap.decreased(y); } } + for (unsigned x : am1) + heap.erase(x); + + if (am1.num_elems() > 1) { + unsigned_vector mux; + for (unsigned x : am1) + mux.push_back(x); + if (mux.size() == 2 && mux[0] == negate(mux[1])) { + continue; + } + cliques.push_back(mux); + } } } From cc36dd1e0d4d998d62b6f8e8c1807c56699e0729 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Apr 2022 19:18:17 +0200 Subject: [PATCH 041/253] include map for non vs builds Signed-off-by: Nikolaj Bjorner --- src/util/max_cliques.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index ad6bc0219..1e1611b45 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -21,7 +21,7 @@ Notes: #include "util/vector.h" #include "util/uint_set.h" #include "util/heap.h" - +#include "util/map.h" template class max_cliques : public T { From c33611e9e07fb3a49acfd63ab9659169d41078c5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Apr 2022 19:23:48 +0200 Subject: [PATCH 042/253] include map for non vs builds Signed-off-by: Nikolaj Bjorner --- src/util/max_cliques.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index 1e1611b45..4dd91b366 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -164,7 +164,14 @@ public: next.push_back(n); std::sort(next.begin(), next.end(), [&](unsigned a, unsigned b) { return conns[a].num_elems() < conns[b].num_elems(); }); for (unsigned x : next) { - if (std::all_of(am1.begin(), am1.end(), [&](unsigned y) { return conns[x].contains(y); })) + bool all = true; + for (unsigned y : am1) { + if (!conns[x].contains(y)) { + all = false; + break; + } + } + if (all) am1.insert(x); } am1.insert(v); From 9ecd4f840683e6928cc693b7235de7128321c1f1 Mon Sep 17 00:00:00 2001 From: Zachary Wimer Date: Fri, 15 Apr 2022 10:53:16 -0700 Subject: [PATCH 043/253] MANIFEST.in will now include pyproject.toml (#5979) --- src/api/python/MANIFEST.in | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/python/MANIFEST.in b/src/api/python/MANIFEST.in index 35a0627e5..7317d7b21 100644 --- a/src/api/python/MANIFEST.in +++ b/src/api/python/MANIFEST.in @@ -5,3 +5,4 @@ recursive-include core *.cmake recursive-include core/src * recursive-include core/cmake * recursive-include core/scripts * +include pyproject.toml From e11496bc65beb4b15aa7805413254d3c73407cc7 Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Fri, 15 Apr 2022 20:07:17 +0200 Subject: [PATCH 044/253] Added decide-callback to user-propagator (#5978) * Fixed registering expressions in push/pop * Reused existing function * Reverted reusing can_propagate * Added decide-callback to user-propagator * Refactoring * Fixed index --- src/api/api_solver.cpp | 8 ++ src/api/c++/z3++.h | 31 +++++- src/api/z3_api.h | 9 ++ src/smt/smt_context.cpp | 157 +++++++++++++++-------------- src/smt/smt_context.h | 10 ++ src/smt/smt_kernel.cpp | 4 + src/smt/smt_kernel.h | 2 + src/smt/smt_solver.cpp | 4 + src/smt/tactic/smt_tactic_core.cpp | 2 + src/smt/theory_bv.cpp | 34 ++++++- src/smt/theory_bv.h | 6 ++ src/smt/theory_user_propagator.cpp | 69 +++++++++++++ src/smt/theory_user_propagator.h | 6 +- src/solver/tactic2solver.cpp | 4 + src/tactic/tactical.cpp | 4 + src/tactic/user_propagator_base.h | 21 ++-- 16 files changed, 284 insertions(+), 87 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index c9eda8712..a0803516f 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -975,6 +975,14 @@ extern "C" { Z3_CATCH; } + void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh) { + Z3_TRY; + RESET_ERROR_CODE(); + user_propagator::decide_eh_t c = (void(*)(void*, user_propagator::callback*, expr*&, unsigned&, lbool&))decide_eh; + to_solver_ref(s)->user_propagate_register_decide(c); + Z3_CATCH; + } + Z3_func_decl Z3_API Z3_solver_propagate_declare(Z3_context c, Z3_symbol name, unsigned n, Z3_sort* domain, Z3_sort range) { Z3_TRY; LOG_Z3_solver_propagate_declare(c, name, n, domain, range); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 101fa04a3..57a87415d 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -3943,11 +3943,13 @@ namespace z3 { typedef std::function final_eh_t; typedef std::function eq_eh_t; typedef std::function created_eh_t; + typedef std::function decide_eh_t; final_eh_t m_final_eh; eq_eh_t m_eq_eh; fixed_eh_t m_fixed_eh; created_eh_t m_created_eh; + decide_eh_t m_decide_eh; solver* s; context* c; std::vector subcontexts; @@ -4009,8 +4011,15 @@ namespace z3 { expr e(p->ctx(), _e); p->m_created_eh(e); } - - + + static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast& _val, unsigned& bit, Z3_lbool& is_pos) { + user_propagator_base* p = static_cast(_p); + scoped_cb _cb(p, cb); + expr val(p->ctx(), _val); + p->m_decide_eh(val, bit, is_pos); + _val = val; + } + public: user_propagator_base(context& c) : s(nullptr), c(&c) {} @@ -4119,6 +4128,22 @@ namespace z3 { Z3_solver_propagate_created(ctx(), *s, created_eh); } } + + void register_decide(decide_eh_t& c) { + m_decide_eh = c; + if (s) { + Z3_solver_propagate_decide(ctx(), *s, decide_eh); + } + } + + void register_decide() { + m_decide_eh = [this](expr& val, unsigned& bit, Z3_lbool& is_pos) { + decide(val, bit, is_pos); + }; + if (s) { + Z3_solver_propagate_decide(ctx(), *s, decide_eh); + } + } virtual void fixed(expr const& /*id*/, expr const& /*e*/) { } @@ -4127,6 +4152,8 @@ namespace z3 { virtual void final() { } virtual void created(expr const& /*e*/) {} + + virtual void decide(expr& /*val*/, unsigned& /*bit*/, Z3_lbool& /*is_pos*/) {} /** \brief tracks \c e by a unique identifier that is returned by the call. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 1388d0ab1..1eb2164d5 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1444,6 +1444,7 @@ Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, Z3_as Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t)); Z3_DECLARE_CLOSURE(Z3_final_eh, void, (void* ctx, Z3_solver_callback cb)); Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t)); +Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast&, unsigned&, Z3_lbool&)); /** @@ -6758,6 +6759,14 @@ extern "C" { * The registered function appears at the top level and is created using \ref Z3_propagate_solver_declare. */ void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh); + + /** + * \brief register a callback when a the solver decides to split on a registered expression + * The callback may set passed expression to another registered expression which will be selected instead. + * In case the expression is a bitvector the bit to split on is determined by the bit argument and the + * truth-value to try first is given by is_pos + */ + void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh); /** Create uninterpreted function declaration for the user propagator. diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index a9b44ab3c..3e444bec7 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1766,6 +1766,70 @@ namespace smt { m_bvar_inc *= INV_ACTIVITY_LIMIT; } + /** + \brief Returns a truth value for the given variable + */ + bool context::guess(bool_var var, lbool phase) { + if (is_quantifier(m_bool_var2expr[var])) { + // Overriding any decision on how to assign the quantifier. + // assigning a quantifier to false is equivalent to make it irrelevant. + phase = l_false; + } + literal l(var, false); + + if (phase != l_undef) + return phase == l_true; + + bool_var_data & d = m_bdata[var]; + if (d.try_true_first()) + return true; + switch (m_fparams.m_phase_selection) { + case PS_THEORY: + if (m_phase_cache_on && d.m_phase_available) { + return m_bdata[var].m_phase; + } + if (!m_phase_cache_on && d.is_theory_atom()) { + theory * th = m_theories.get_plugin(d.get_theory()); + lbool th_phase = th->get_phase(var); + if (th_phase != l_undef) { + return th_phase == l_true; + } + } + if (track_occs()) { + if (m_lit_occs[l.index()] == 0) { + return false; + } + if (m_lit_occs[(~l).index()] == 0) { + return true; + } + } + return m_phase_default; + case PS_CACHING: + case PS_CACHING_CONSERVATIVE: + case PS_CACHING_CONSERVATIVE2: + if (m_phase_cache_on && d.m_phase_available) { + TRACE("phase_selection", tout << "using cached value, is_pos: " << m_bdata[var].m_phase << ", var: p" << var << "\n";); + return m_bdata[var].m_phase; + } + else { + TRACE("phase_selection", tout << "setting to false\n";); + return m_phase_default; + } + case PS_ALWAYS_FALSE: + return false; + case PS_ALWAYS_TRUE: + return true; + case PS_RANDOM: + return m_random() % 2 == 0; + case PS_OCCURRENCE: { + return m_lit_occs[l.index()] > m_lit_occs[(~l).index()]; + } + default: + UNREACHABLE(); + return false; + } + } + /** \brief Execute next case split, return false if there are no more case splits to be performed. @@ -1807,81 +1871,15 @@ namespace smt { TRACE("decide", tout << "splitting, lvl: " << m_scope_lvl << "\n";); TRACE("decide_detail", tout << mk_pp(bool_var2expr(var), m) << "\n";); - - bool is_pos; - - if (is_quantifier(m_bool_var2expr[var])) { - // Overriding any decision on how to assign the quantifier. - // assigning a quantifier to false is equivalent to make it irrelevant. - phase = l_false; - } + + bool is_pos = guess(var, phase); literal l(var, false); - if (phase != l_undef) { - is_pos = phase == l_true; - } - else { - bool_var_data & d = m_bdata[var]; - if (d.try_true_first()) { - is_pos = true; - } - else { - switch (m_fparams.m_phase_selection) { - case PS_THEORY: - if (m_phase_cache_on && d.m_phase_available) { - is_pos = m_bdata[var].m_phase; - break; - } - if (!m_phase_cache_on && d.is_theory_atom()) { - theory * th = m_theories.get_plugin(d.get_theory()); - lbool th_phase = th->get_phase(var); - if (th_phase != l_undef) { - is_pos = th_phase == l_true; - break; - } - } - if (track_occs()) { - if (m_lit_occs[l.index()] == 0) { - is_pos = false; - break; - } - if (m_lit_occs[(~l).index()] == 0) { - is_pos = true; - break; - } - } - is_pos = m_phase_default; - break; - case PS_CACHING: - case PS_CACHING_CONSERVATIVE: - case PS_CACHING_CONSERVATIVE2: - if (m_phase_cache_on && d.m_phase_available) { - TRACE("phase_selection", tout << "using cached value, is_pos: " << m_bdata[var].m_phase << ", var: p" << var << "\n";); - is_pos = m_bdata[var].m_phase; - } - else { - TRACE("phase_selection", tout << "setting to false\n";); - is_pos = m_phase_default; - } - break; - case PS_ALWAYS_FALSE: - is_pos = false; - break; - case PS_ALWAYS_TRUE: - is_pos = true; - break; - case PS_RANDOM: - is_pos = (m_random() % 2 == 0); - break; - case PS_OCCURRENCE: { - is_pos = m_lit_occs[l.index()] > m_lit_occs[(~l).index()]; - break; - } - default: - is_pos = false; - UNREACHABLE(); - } - } + bool_var original_choice = var; + + if (decide_user_interference(var, is_pos)) { + m_case_split_queue->unassign_var_eh(original_choice); + l = literal(var, false); } if (!is_pos) l.neg(); @@ -1889,7 +1887,7 @@ namespace smt { assign(l, b_justification::mk_axiom(), true); return true; } - + /** \brief Update counter that is used to enable/disable phase caching. */ @@ -2906,6 +2904,14 @@ namespace smt { return m_user_propagator && m_user_propagator->has_fixed() && n->get_th_var(m_user_propagator->get_family_id()) != null_theory_var; } + bool context::decide_user_interference(bool_var& var, bool& is_pos) { + if (!m_user_propagator || !m_user_propagator->has_decide()) + return false; + bool_var old = var; + m_user_propagator->decide(var, is_pos); + return old != var; + } + void context::assign_fixed(enode* n, expr* val, unsigned sz, literal const* explain) { theory_var v = n->get_th_var(m_user_propagator->get_family_id()); m_user_propagator->new_fixed_eh(v, val, sz, explain); @@ -3042,7 +3048,8 @@ namespace smt { } } } - } else { + } + else { literal_vector new_case_split; for (unsigned i = 0; i < num_lits; ++i) { literal l = lits[i]; diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 637c2171b..696a5cc39 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1134,6 +1134,8 @@ namespace smt { enode * get_enode_eq_to(func_decl * f, unsigned num_args, enode * const * args); + bool guess(bool_var var, lbool phase); + protected: bool decide(); @@ -1738,8 +1740,16 @@ namespace smt { m_user_propagator->register_created(r); } + void user_propagate_register_decide(user_propagator::decide_eh_t& r) { + if (!m_user_propagator) + throw default_exception("user propagator must be initialized"); + m_user_propagator->register_decide(r); + } + bool watches_fixed(enode* n) const; + bool decide_user_interference(bool_var& var, bool& is_pos); + void assign_fixed(enode* n, expr* val, unsigned sz, literal const* explain); void assign_fixed(enode* n, expr* val, literal_vector const& explain) { diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 2d082170c..8f442596c 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -284,4 +284,8 @@ namespace smt { m_imp->m_kernel.user_propagate_register_created(r); } + void kernel::user_propagate_register_decide(user_propagator::decide_eh_t& r) { + m_imp->m_kernel.user_propagate_register_decide(r); + } + }; diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 068bd1b52..4fa840f5e 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -311,6 +311,8 @@ namespace smt { void user_propagate_register_created(user_propagator::created_eh_t& r); + void user_propagate_register_decide(user_propagator::decide_eh_t& r); + /** \brief Return a reference to smt::context. This breaks abstractions. diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 344cf9e6f..5064ed7ef 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -244,6 +244,10 @@ namespace { m_context.user_propagate_register_created(c); } + void user_propagate_register_decide(user_propagator::decide_eh_t& c) override { + m_context.user_propagate_register_decide(c); + } + struct scoped_minimize_core { smt_solver& s; expr_ref_vector m_assumptions; diff --git a/src/smt/tactic/smt_tactic_core.cpp b/src/smt/tactic/smt_tactic_core.cpp index 072e1ed24..9c5fc1c8e 100644 --- a/src/smt/tactic/smt_tactic_core.cpp +++ b/src/smt/tactic/smt_tactic_core.cpp @@ -322,6 +322,7 @@ public: user_propagator::eq_eh_t m_eq_eh; user_propagator::eq_eh_t m_diseq_eh; user_propagator::created_eh_t m_created_eh; + user_propagator::decide_eh_t m_decide_eh; void user_propagate_delay_init() { @@ -333,6 +334,7 @@ public: if (m_eq_eh) m_ctx->user_propagate_register_eq(m_eq_eh); if (m_diseq_eh) m_ctx->user_propagate_register_diseq(m_diseq_eh); if (m_created_eh) m_ctx->user_propagate_register_created(m_created_eh); + if (m_decide_eh) m_ctx->user_propagate_register_decide(m_decide_eh); for (expr* v : m_vars) m_ctx->user_propagate_register_expr(v); diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 341daedec..682f4d6f9 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -531,7 +531,6 @@ namespace smt { return true; } - bool theory_bv::get_fixed_value(theory_var v, numeral & result) const { result.reset(); unsigned i = 0; @@ -1821,6 +1820,39 @@ namespace smt { st.update("bv dynamic eqs", m_stats.m_num_eq_dynamic); } + theory_bv::var_enode_pos theory_bv::get_bv_with_theory(bool_var v, theory_id id) const { + atom* a = get_bv2a(v); + svector vec; + if (!a->is_bit()) + return var_enode_pos(nullptr, UINT32_MAX); + bit_atom * b = static_cast(a); + var_pos_occ * curr = b->m_occs; + while (curr) { + enode* n = get_enode(curr->m_var); + if (n->get_th_var(id) != null_theory_var) + return var_enode_pos(n, curr->m_idx); + curr = curr->m_next; + } + return var_enode_pos(nullptr, UINT32_MAX); + } + + bool_var theory_bv::get_first_unassigned(unsigned start_bit, enode* n) const { + theory_var v = n->get_th_var(get_family_id()); + auto& bits = m_bits[v]; + unsigned sz = bits.size(); + + for (unsigned i = start_bit; i < sz; ++i) { + if (ctx.get_assignment(bits[i].var()) != l_undef) + return bits[i].var(); + } + for (unsigned i = 0; i < start_bit; ++i) { + if (ctx.get_assignment(bits[i].var()) != l_undef) + return bits[i].var(); + } + + return null_bool_var; + } + bool theory_bv::check_assignment(theory_var v) { if (!is_root(v)) return true; diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index ebca3fa83..d73b7a008 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -260,6 +260,9 @@ namespace smt { smt_params const& params() const; public: + + typedef std::pair var_enode_pos; + theory_bv(context& ctx); ~theory_bv() override; @@ -284,6 +287,9 @@ namespace smt { bool get_fixed_value(app* x, numeral & result) const; bool is_fixed_propagated(theory_var v, expr_ref& val, literal_vector& explain) override; + var_enode_pos get_bv_with_theory(bool_var v, theory_id id) const; + bool_var get_first_unassigned(unsigned start_bit, enode* n) const; + bool check_assignment(theory_var v); bool check_invariant(); bool check_zero_one_bits(theory_var v); diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index f783f22fb..bf8722701 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -17,6 +17,7 @@ Author: #include "ast/ast_pp.h" +#include "smt/theory_bv.h" #include "smt/theory_user_propagator.h" #include "smt/smt_context.h" @@ -116,6 +117,7 @@ theory * theory_user_propagator::mk_fresh(context * new_ctx) { if ((bool)m_eq_eh) th->register_eq(m_eq_eh); if ((bool)m_diseq_eh) th->register_diseq(m_diseq_eh); if ((bool)m_created_eh) th->register_created(m_created_eh); + if ((bool)m_decide_eh) th->register_decide(m_decide_eh); return th; } @@ -154,6 +156,73 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu } } +void theory_user_propagator::decide(bool_var& var, bool& is_pos) { + + const bool_var_data& d = ctx.get_bdata(var); + + if (!d.is_theory_atom()) + return; + + theory* th = ctx.get_theory(d.get_theory()); + + bv_util bv(m); + enode* original_enode = nullptr; + unsigned original_bit = 0; + + if (d.is_enode() && th->get_family_id() == get_family_id()) { + // variable is just a registered expression + original_enode = ctx.bool_var2enode(var); + } + else if (th->get_family_id() == bv.get_fid()) { + // it might be a registered bit-vector + auto registered_bv = ((theory_bv*)th)->get_bv_with_theory(var, get_family_id()); + if (!registered_bv.first) + // there is no registered bv associated with the bit + return; + original_enode = registered_bv.first; + original_bit = registered_bv.second; + } + else + return; + + // call the registered callback + unsigned new_bit = original_bit; + lbool phase = is_pos ? l_true : l_false; + + expr* e = var2expr(original_enode->get_th_var(get_family_id())); + m_decide_eh(m_user_context, this, e, new_bit, phase); + enode* new_enode = ctx.get_enode(e); + + // check if the callback changed something + if (original_enode == new_enode && (new_enode->is_bool() || original_bit == new_bit)) { + if (phase != l_undef) + // it only affected the truth value + is_pos = phase == l_true; + return; + } + + bool_var old_var = var; + if (new_enode->is_bool()) { + // expression was set to a boolean + bool_var new_var = ctx.enode2bool_var(new_enode); + if (ctx.get_assignment(new_var) == l_undef) { + var = new_var; + } + } + else { + // expression was set to a bit-vector + auto th_bv = (theory_bv*)ctx.get_theory(bv.get_fid()); + bool_var new_var = th_bv->get_first_unassigned(new_bit, new_enode); + + if (new_var != null_bool_var) { + var = new_var; + } + } + + // in case the callback did not decide on a truth value -> let Z3 decide + is_pos = ctx.guess(var, phase); +} + void theory_user_propagator::push_scope_eh() { ++m_num_scopes; } diff --git a/src/smt/theory_user_propagator.h b/src/smt/theory_user_propagator.h index 9b271e9c3..bf82883e4 100644 --- a/src/smt/theory_user_propagator.h +++ b/src/smt/theory_user_propagator.h @@ -56,7 +56,7 @@ namespace smt { void reset() { memset(this, 0, sizeof(*this)); } }; - void* m_user_context = nullptr; + void* m_user_context = nullptr; user_propagator::push_eh_t m_push_eh; user_propagator::pop_eh_t m_pop_eh; user_propagator::fresh_eh_t m_fresh_eh; @@ -65,6 +65,7 @@ namespace smt { user_propagator::eq_eh_t m_eq_eh; user_propagator::eq_eh_t m_diseq_eh; user_propagator::created_eh_t m_created_eh; + user_propagator::decide_eh_t m_decide_eh; user_propagator::context_obj* m_api_context = nullptr; unsigned m_qhead = 0; @@ -121,13 +122,16 @@ namespace smt { void register_eq(user_propagator::eq_eh_t& eq_eh) { m_eq_eh = eq_eh; } void register_diseq(user_propagator::eq_eh_t& diseq_eh) { m_diseq_eh = diseq_eh; } void register_created(user_propagator::created_eh_t& created_eh) { m_created_eh = created_eh; } + void register_decide(user_propagator::decide_eh_t& decide_eh) { m_decide_eh = decide_eh; } bool has_fixed() const { return (bool)m_fixed_eh; } + bool has_decide() const { return (bool)m_decide_eh; } void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* lhs, expr* const* rhs, expr* conseq) override; void register_cb(expr* e) override; void new_fixed_eh(theory_var v, expr* value, unsigned num_lits, literal const* jlits); + void decide(bool_var& var, bool& is_pos); theory * mk_fresh(context * new_ctx) override; bool internalize_atom(app* atom, bool gate_ctx) override; diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index e8a30a009..fe89d6533 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -116,6 +116,10 @@ public: m_tactic->user_propagate_register_created(created_eh); } + void user_propagate_register_decide(user_propagator::decide_eh_t& created_eh) override { + m_tactic->user_propagate_register_decide(created_eh); + } + void user_propagate_clear() override { if (m_tactic) m_tactic->user_propagate_clear(); diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 9167650ad..67a0e3062 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -204,6 +204,10 @@ public: m_t2->user_propagate_register_created(created_eh); } + void user_propagate_register_decide(user_propagator::decide_eh_t& decide_eh) override { + m_t2->user_propagate_register_decide(decide_eh); + } + }; tactic * and_then(tactic * t1, tactic * t2) { diff --git a/src/tactic/user_propagator_base.h b/src/tactic/user_propagator_base.h index 02a027762..c67a073cd 100644 --- a/src/tactic/user_propagator_base.h +++ b/src/tactic/user_propagator_base.h @@ -2,6 +2,7 @@ #pragma once #include "ast/ast.h" +#include "util/lbool.h" namespace user_propagator { @@ -17,14 +18,14 @@ namespace user_propagator { virtual ~context_obj() = default; }; - typedef std::function final_eh_t; - typedef std::function fixed_eh_t; - typedef std::function eq_eh_t; - typedef std::function fresh_eh_t; - typedef std::function push_eh_t; - typedef std::function pop_eh_t; - typedef std::function created_eh_t; - + typedef std::function final_eh_t; + typedef std::function fixed_eh_t; + typedef std::function eq_eh_t; + typedef std::function fresh_eh_t; + typedef std::function push_eh_t; + typedef std::function pop_eh_t; + typedef std::function created_eh_t; + typedef std::function decide_eh_t; class plugin : public decl_plugin { public: @@ -85,6 +86,10 @@ namespace user_propagator { throw default_exception("user-propagators are only supported on the SMT solver"); } + virtual void user_propagate_register_decide(decide_eh_t& r) { + throw default_exception("user-propagators are only supported on the SMT solver"); + } + virtual void user_propagate_clear() { } From 11d992a3352e2b1d172af5c3b3e066ce28cd65cc Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 15 Apr 2022 14:08:39 -0400 Subject: [PATCH 045/253] wip: tweak GC further (#5982) --- src/api/ml/z3native_stubs.c.pre | 42 +++++++++++++++++---------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/api/ml/z3native_stubs.c.pre b/src/api/ml/z3native_stubs.c.pre index 895e20235..0efaa110f 100644 --- a/src/api/ml/z3native_stubs.c.pre +++ b/src/api/ml/z3native_stubs.c.pre @@ -294,7 +294,8 @@ static struct custom_operations Z3_ast_plus_custom_ops = { Z3_ast_compare_ext }; -MK_CTX_OF(ast, 16) // let's say 16 bytes per ast +// FUDGE +MK_CTX_OF(ast, 8) // let's say 16 bytes per ast #define MK_PLUS_OBJ_NO_REF(X, USED) \ typedef struct { \ @@ -410,25 +411,26 @@ MK_CTX_OF(ast, 16) // let's say 16 bytes per ast \ MK_CTX_OF(X, USED) -MK_PLUS_OBJ_NO_REF(symbol, 32) -MK_PLUS_OBJ_NO_REF(constructor, 32) -MK_PLUS_OBJ_NO_REF(constructor_list, 32) -MK_PLUS_OBJ_NO_REF(rcf_num, 32) -MK_PLUS_OBJ(params, 128) -MK_PLUS_OBJ(param_descrs, 128) -MK_PLUS_OBJ(model, 512) -MK_PLUS_OBJ(func_interp, 128) -MK_PLUS_OBJ(func_entry, 128) -MK_PLUS_OBJ(goal, 128) -MK_PLUS_OBJ(tactic, 128) -MK_PLUS_OBJ(probe, 128) -MK_PLUS_OBJ(apply_result, 128) -MK_PLUS_OBJ(solver, 20 * 1000 * 1000) // pretend a solver is 20MB -MK_PLUS_OBJ(stats, 128) -MK_PLUS_OBJ(ast_map, 1024 * 2) -MK_PLUS_OBJ(ast_vector, 128) -MK_PLUS_OBJ(fixedpoint, 20 * 1000 * 1000) -MK_PLUS_OBJ(optimize, 20 * 1000 * 1000) +// FUDGE +MK_PLUS_OBJ_NO_REF(symbol, 16) +MK_PLUS_OBJ_NO_REF(constructor, 16) +MK_PLUS_OBJ_NO_REF(constructor_list, 16) +MK_PLUS_OBJ_NO_REF(rcf_num, 16) +MK_PLUS_OBJ(params, 64) +MK_PLUS_OBJ(param_descrs, 64) +MK_PLUS_OBJ(model, 64) +MK_PLUS_OBJ(func_interp, 32) +MK_PLUS_OBJ(func_entry, 32) +MK_PLUS_OBJ(goal, 64) +MK_PLUS_OBJ(tactic, 64) +MK_PLUS_OBJ(probe, 64) +MK_PLUS_OBJ(apply_result, 32) +MK_PLUS_OBJ(solver, 20 * 1000) +MK_PLUS_OBJ(stats, 32) +MK_PLUS_OBJ(ast_map, 32) +MK_PLUS_OBJ(ast_vector, 32) +MK_PLUS_OBJ(fixedpoint, 20 * 1000) +MK_PLUS_OBJ(optimize, 20 * 1000) #ifdef __cplusplus extern "C" { From 8e701128322ed9ea6e9f42573e9346c811099fab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Apr 2022 23:31:15 +0200 Subject: [PATCH 046/253] Update z3.py allow ading funcinterp to models --- src/api/python/z3/z3.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 223b3e038..ed9c7f0a8 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6594,6 +6594,19 @@ class ModelRef(Z3PPObject): """Update the interpretation of a constant""" if is_expr(x): x = x.decl() + if is_func_decl(x) and x.arity() != 0 and isinstance(value, FuncInterp): + fi1 = value.f + fi2 = Z3_add_func_interp(x.ctx_ref(), self.model, x.ast, value.else_value().ast); + fi2 = FuncInterp(fi2, x.ctx) + for i in range(value.num_entries()): + e = value.entry(i) + n = Z3_func_entry_get_num_args(x.ctx_ref(), e.entry) + v = AstVector() + for j in range(n): + v.push(entry.arg_value(j)) + val = Z3_func_entry_get_value(x.ctx_ref(), e.entry) + Z3_func_interp_add_entry(x.ctx_ref(), fi2.f, v.vector, val) + return if not is_func_decl(x) or x.arity() != 0: raise Z3Exception("Expecting 0-ary function or constant expression") value = _py2expr(value) From 807121aa03161fbd777a4ae57e865a958bb89684 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Apr 2022 14:55:43 +0200 Subject: [PATCH 047/253] wip --- src/opt/maxres.cpp | 83 ++++++++++++++++++++++++++++++++++ src/opt/opt_preprocess.cpp | 86 ++++++++++++++++++++++++++++++++++++ src/opt/opt_preprocess.h | 2 + src/smt/smt_consequences.cpp | 2 +- src/util/max_cliques.h | 63 ++++++++++++++++---------- 5 files changed, 212 insertions(+), 24 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 135e0f80e..d316f9360 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -649,6 +649,7 @@ public: } } + void max_resolve(exprs const& core, rational const& w) { SASSERT(!core.empty()); expr_ref fml(m), asum(m); @@ -699,6 +700,88 @@ public: } } +#if 0 + + void bin_max_resolve(exprs const& _core, rational const& w) { + expr_ref_vector core(m, _core.size(), _core.data()); + expr_ref fml(m), cls(m); + for (unsigned i = 0; i + 1 < core.size(); ++i) { + expr* a = core.get(i); + expr* b = core.get(i + 1); + expr_ref u = mk_fresh_bool("u"); + expr_ref v = mk_fresh_bool("v"); + // u = a or b + // v = a and b + cls = m.mk_or(a, b); + fml = m.mk_implies(u, cls); + add(fml); + update_model(u, cls); + m_defs.push_back(fml); + cls = m.mk_and(a, b); + fml = m.mk_implies(v, cls); + add(fml); + update_model(v, cls); + m_defs.push_back(fml); + new_assumption(u, w); + core.push_back(v); + } + } + + struct unfold_record { + ptr_vector ws; + rational weight; + }; + + void bin_delay_max_resolve(exprs const& _core, rational const& w) { + expr_ref_vector core(m, _core.size(), _core.data()), us(m), partial(m); + expr_ref fml(m), cls(m); + for (expr* c : core) { + unfold_record ws; + if (!m_unfold.find(c, ws)) + continue; + for (expr* f : ws.ws) + new_assumption(f, ws.weight); + } + if (core.size() <= 1) + return; + + for (expr* core) + partial.push_back(nullptr); + + for (unsigned i = 0; i + 1 < core.size(); ++i) { + expr* a = core.get(i); + expr* b = core.get(i + 1); + expr_ref u = mk_fresh_bool("u"); + expr_ref v = mk_fresh_bool("v"); + // u = a or b + // v = a and b + cls = m.mk_or(a, b); + fml = m.mk_implies(u, cls); + add(fml); + update_model(u, cls); + m_defs.push_back(fml); + cls = m.mk_and(a, b); + fml = m.mk_implies(v, cls); + add(fml); + update_model(v, cls); + m_defs.push_back(fml); + us.push_back(u); + core.push_back(v); + + unfold_record r; + r.ws.push_back(u); + if (partial.get(i)) + r.ws.push_back(partia.get(i)); + if (partial.get(i + 1)) + r.ws.push_back(partia.get(i + 1)); + partial.push_back(m.mk_and(r.ws)); + m_unfold.insert(partial.back(), r); + } + expr_ref u = mk_and(us); + new_assumption(u, w); + } +#endif + // cs is a correction set (a complement of a (maximal) satisfying assignment). void cs_max_resolve(exprs const& cs, rational const& w) { if (cs.empty()) return; diff --git a/src/opt/opt_preprocess.cpp b/src/opt/opt_preprocess.cpp index 6cbc8b1b9..bbf119266 100644 --- a/src/opt/opt_preprocess.cpp +++ b/src/opt/opt_preprocess.cpp @@ -20,9 +20,93 @@ Author: #pragma once #include "opt/opt_preprocess.h" +#include "util/max_cliques.h" namespace opt { + expr_ref_vector preprocess::propagate(expr* f, lbool& is_sat) { + expr_ref_vector asms(m); + asms.push_back(f); + is_sat = s.check_sat(asms); + return s.get_trail(1); + } + + bool preprocess::prop_mutexes(vector& softs, rational& lower) { + expr_ref_vector fmls(m); + obj_map new_soft = soft2map(softs, fmls); + + params_ref p; + p.set_uint("max_conflicts", 1); + s.updt_params(p); + + obj_hashtable pfmls, nfmls; + for (expr* f : fmls) + if (m.is_not(f, f)) + nfmls.insert(f); + else + pfmls.insert(f); + + u_map ids; + unsigned_vector ps; + for (expr* f : fmls) { + ids.insert(f->get_id(), f); + ps.push_back(f->get_id()); + } + + u_map conns; + + for (expr* f : fmls) { + lbool is_sat; + expr_ref_vector trail = propagate(f, is_sat); + if (is_sat == l_false) { + rational w = new_soft[f]; + lower += w; + s.assert_expr(m.mk_not(f)); + new_soft.remove(f); + continue; + } + + expr_ref_vector mux(m); + for (expr* g : trail) { + if (m.is_not(g, g)) { + if (pfmls.contains(g)) + mux.push_back(g); + } + else if (nfmls.contains(g)) + mux.push_back(m.mk_not(g)); + } + uint_set reach; + for (expr* g : mux) + reach.insert(g->get_id()); + conns.insert(f->get_id(), reach); + } + + p.set_uint("max_conflicts", UINT_MAX); + s.updt_params(p); + + struct neg_literal { + unsigned negate(unsigned id) { + throw default_exception("unexpected call"); + } + }; + max_cliques mc; + vector mutexes; + mc.cliques(ps, conns, mutexes); + + for (auto& mux : mutexes) { + expr_ref_vector _mux(m); + for (auto p : mux) + _mux.push_back(ids[p]); + process_mutex(_mux, new_soft, lower); + } + + softs.reset(); + for (auto const& [k, v] : new_soft) + softs.push_back(soft(expr_ref(k, m), v, false)); + m_trail.reset(); + return true; + } + obj_map preprocess::soft2map(vector const& softs, expr_ref_vector& fmls) { obj_map new_soft; for (soft const& sf : softs) { @@ -104,6 +188,8 @@ namespace opt { bool preprocess::operator()(vector& soft, rational& lower) { if (!find_mutexes(soft, lower)) return false; + if (false && !prop_mutexes(soft, lower)) + return false; return true; } }; diff --git a/src/opt/opt_preprocess.h b/src/opt/opt_preprocess.h index f5f1c9db6..567a750ed 100644 --- a/src/opt/opt_preprocess.h +++ b/src/opt/opt_preprocess.h @@ -28,8 +28,10 @@ namespace opt { solver& s; expr_ref_vector m_trail; + expr_ref_vector propagate(expr* f, lbool& is_sat); obj_map soft2map(vector const& softs, expr_ref_vector& fmls); bool find_mutexes(vector& softs, rational& lower); + bool prop_mutexes(vector& softs, rational& lower); void process_mutex(expr_ref_vector& mutex, obj_map& new_soft, rational& lower); public: diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index b54e92a70..657e222da 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -612,7 +612,7 @@ namespace smt { } } vector _mutexes; - mc.cliques(ps, _mutexes); + mc.cliques2(ps, _mutexes); for (auto const& mux : _mutexes) { expr_ref_vector lits(m); for (unsigned idx : mux) { diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index 4dd91b366..979a5b795 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -83,6 +83,29 @@ class max_cliques : public T { m_next.reserve(max); m_tc.reserve(m_next.size()); } + + struct compare_degree { + u_map& conns; + compare_degree(u_map& conns): conns(conns) {} + bool operator()(unsigned x, unsigned y) const { + return conns[x].num_elems() < conns[y].num_elems(); + } + }; + + + void init(unsigned_vector const& ps, u_map& conns) { + + uint_set vars; + + for (unsigned p : ps) + vars.insert(p); + + for (unsigned v : ps) { + uint_set reach; + get_reachable(v, vars, reach); + conns.insert(v, reach); + } + } public: void add_edge(unsigned src, unsigned dst) { @@ -92,7 +115,7 @@ public: m_next[dst].push_back(src); } - void cliques(unsigned_vector const& ps, vector& cliques) { + void cliques1(unsigned_vector const& ps, vector& cliques) { init(ps); unsigned_vector clique; uint_set vars; @@ -124,35 +147,29 @@ public: } } - // better quality cliques - void cliques2(unsigned_vector const& ps, vector& cliques) { - - uint_set all_vars, todo; + void cliques2(unsigned_vector const& ps, vector& cs) { u_map conns; - init(ps); + // compute connections using TC of implication graph + init(ps, conns); + cliques(ps, conns, cs); + } - struct compare_degree { - u_map& conns; - compare_degree(u_map& conns): conns(conns) {} - bool operator()(unsigned x, unsigned y) const { - return conns[x].num_elems() < conns[y].num_elems(); - } - }; + // cliques after connections are computed. + void cliques(unsigned_vector const& ps, u_map& conns, vector& cliques) { + + unsigned maxp = 1; + for (unsigned p : ps) + maxp = std::max(p, maxp); + + uint_set todo; compare_degree lt(conns); - heap heap(m_next.size(), lt); + heap heap(maxp + 1, lt); - for (unsigned p : ps) { - all_vars.insert(p); + for (unsigned p : ps) { todo.insert(p); - } - - for (unsigned v : ps) { - uint_set reach; - get_reachable(v, all_vars, reach); - conns.insert(v, reach); - heap.insert(v); + heap.insert(p); } while (!todo.empty()) { From f4c500c5197f559870e1fd78bd52496024493c4e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Apr 2022 15:16:53 +0200 Subject: [PATCH 048/253] fix build reference types are not part of C --- src/api/api_solver.cpp | 2 +- src/api/z3_api.h | 2 +- src/opt/maxres.cpp | 11 ++++++++--- src/smt/theory_user_propagator.cpp | 2 +- src/tactic/user_propagator_base.h | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index a0803516f..05b125546 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -978,7 +978,7 @@ extern "C" { void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh) { Z3_TRY; RESET_ERROR_CODE(); - user_propagator::decide_eh_t c = (void(*)(void*, user_propagator::callback*, expr*&, unsigned&, lbool&))decide_eh; + user_propagator::decide_eh_t c = (void(*)(void*, user_propagator::callback*, expr**, unsigned*, lbool*))decide_eh; to_solver_ref(s)->user_propagate_register_decide(c); Z3_CATCH; } diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 1eb2164d5..2680b6f82 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1444,7 +1444,7 @@ Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, Z3_as Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t)); Z3_DECLARE_CLOSURE(Z3_final_eh, void, (void* ctx, Z3_solver_callback cb)); Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t)); -Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast&, unsigned&, Z3_lbool&)); +Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast*, unsigned*, Z3_lbool*)); /** diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index d316f9360..4c9964cf4 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -700,7 +700,7 @@ public: } } -#if 0 +#if 1 void bin_max_resolve(exprs const& _core, rational const& w) { expr_ref_vector core(m, _core.size(), _core.data()); @@ -708,8 +708,8 @@ public: for (unsigned i = 0; i + 1 < core.size(); ++i) { expr* a = core.get(i); expr* b = core.get(i + 1); - expr_ref u = mk_fresh_bool("u"); - expr_ref v = mk_fresh_bool("v"); + expr* u = mk_fresh_bool("u"); + expr* v = mk_fresh_bool("v"); // u = a or b // v = a and b cls = m.mk_or(a, b); @@ -725,8 +725,13 @@ public: new_assumption(u, w); core.push_back(v); } + s().assert_expr(m.mk_not(core.back())); } +#endif + +#if 0 + struct unfold_record { ptr_vector ws; rational weight; diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index bf8722701..1b0cc429d 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -190,7 +190,7 @@ void theory_user_propagator::decide(bool_var& var, bool& is_pos) { lbool phase = is_pos ? l_true : l_false; expr* e = var2expr(original_enode->get_th_var(get_family_id())); - m_decide_eh(m_user_context, this, e, new_bit, phase); + m_decide_eh(m_user_context, this, &e, &new_bit, &phase); enode* new_enode = ctx.get_enode(e); // check if the callback changed something diff --git a/src/tactic/user_propagator_base.h b/src/tactic/user_propagator_base.h index c67a073cd..3f4af0329 100644 --- a/src/tactic/user_propagator_base.h +++ b/src/tactic/user_propagator_base.h @@ -25,7 +25,7 @@ namespace user_propagator { typedef std::function push_eh_t; typedef std::function pop_eh_t; typedef std::function created_eh_t; - typedef std::function decide_eh_t; + typedef std::function decide_eh_t; class plugin : public decl_plugin { public: From c131eb4db1c03484605c729ec6f6876e4aa5ff2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Apr 2022 16:42:45 +0200 Subject: [PATCH 049/253] build fix --- src/api/c++/z3++.h | 9 +++-- src/opt/maxres.cpp | 96 ++++++++++++++++++++++++++++++++-------------- src/opt/maxsmt.cpp | 6 +++ 3 files changed, 79 insertions(+), 32 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 57a87415d..04e0b78e2 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -4012,12 +4012,13 @@ namespace z3 { p->m_created_eh(e); } - static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast& _val, unsigned& bit, Z3_lbool& is_pos) { + static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast* _val, unsigned* bit, Z3_lbool* is_pos) { user_propagator_base* p = static_cast(_p); scoped_cb _cb(p, cb); - expr val(p->ctx(), _val); - p->m_decide_eh(val, bit, is_pos); - _val = val; + expr val(p->ctx(), *_val); + p->m_decide_eh(val, *bit, *is_pos); + // TBD: life time of val is within the scope of this callback. + *_val = val; } public: diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 4c9964cf4..9fcce1fce 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -72,7 +72,9 @@ class maxres : public maxsmt_solver_base { public: enum strategy_t { s_primal, - s_primal_dual + s_primal_dual, + s_primal_binary, + s_primal_binary_delay }; private: struct stats { @@ -157,6 +159,12 @@ public: case s_primal_dual: m_trace_id = "pd-maxres"; break; + case s_primal_binary: + m_trace_id = "maxres-bin"; + break; + case s_primal_binary_delay: + m_trace_id = "maxres-bin-delay"; + break; } } @@ -357,6 +365,8 @@ public: m_defs.reset(); switch(m_st) { case s_primal: + case s_primal_binary: + case s_primal_binary_delay: return mus_solver(); case s_primal_dual: return primal_dual_solver(); @@ -532,8 +542,18 @@ public: expr_ref fml(m); SASSERT(!core.empty()); TRACE("opt", display_vec(tout << "minimized core: ", core);); - IF_VERBOSE(10, display_vec(verbose_stream() << "core: ", core);); - max_resolve(core, w); + IF_VERBOSE(10, display_vec(verbose_stream() << "core: ", core);); + switch (m_st) { + case strategy_t::s_primal_binary: + bin_max_resolve(core, w); + break; + case strategy_t::s_primal_binary_delay: + bin_delay_max_resolve(core, w); + break; + default: + max_resolve(core, w); + break; + } fml = mk_not(m, mk_and(m, core.size(), core.data())); add(fml); // save small cores such that lex-combinations of maxres can reuse these cores. @@ -700,12 +720,11 @@ public: } } -#if 1 void bin_max_resolve(exprs const& _core, rational const& w) { expr_ref_vector core(m, _core.size(), _core.data()); expr_ref fml(m), cls(m); - for (unsigned i = 0; i + 1 < core.size(); ++i) { + for (unsigned i = 0; i + 1 < core.size(); i += 2) { expr* a = core.get(i); expr* b = core.get(i + 1); expr* u = mk_fresh_bool("u"); @@ -728,36 +747,39 @@ public: s().assert_expr(m.mk_not(core.back())); } -#endif - -#if 0 struct unfold_record { ptr_vector ws; rational weight; }; - void bin_delay_max_resolve(exprs const& _core, rational const& w) { - expr_ref_vector core(m, _core.size(), _core.data()), us(m), partial(m); + obj_map m_unfold; + rational m_unfold_upper; + + void bin_delay_max_resolve(exprs const& _core, rational const& weight) { + expr_ref_vector core(m, _core.size(), _core.data()), partial(m); expr_ref fml(m), cls(m); for (expr* c : core) { - unfold_record ws; - if (!m_unfold.find(c, ws)) + unfold_record r; + if (!m_unfold.find(c, r)) continue; - for (expr* f : ws.ws) - new_assumption(f, ws.weight); + IF_VERBOSE(2, verbose_stream() << "to unfold " << mk_pp(c, m) << "\n"); + for (expr* f : r.ws) { + IF_VERBOSE(2, verbose_stream() << "unfold " << mk_pp(f, m) << "\n"); + new_assumption(f, r.weight); + } + m_unfold_upper -= r.weight * rational(r.ws.size() - 1); + m_unfold.remove(c); } - if (core.size() <= 1) - return; - for (expr* core) + for (expr* _ : core) partial.push_back(nullptr); for (unsigned i = 0; i + 1 < core.size(); ++i) { expr* a = core.get(i); expr* b = core.get(i + 1); - expr_ref u = mk_fresh_bool("u"); - expr_ref v = mk_fresh_bool("v"); + expr* u = mk_fresh_bool("u"); + expr* v = mk_fresh_bool("v"); // u = a or b // v = a and b cls = m.mk_or(a, b); @@ -770,22 +792,28 @@ public: add(fml); update_model(v, cls); m_defs.push_back(fml); - us.push_back(u); core.push_back(v); + // w = u and w1 and w2 unfold_record r; r.ws.push_back(u); if (partial.get(i)) - r.ws.push_back(partia.get(i)); + r.ws.push_back(partial.get(i)); if (partial.get(i + 1)) - r.ws.push_back(partia.get(i + 1)); - partial.push_back(m.mk_and(r.ws)); - m_unfold.insert(partial.back(), r); + r.ws.push_back(partial.get(i + 1)); + m_trail.append(r.ws.size(), r.ws.data()); + w = mk_fresh_bool("w"); + cls = m.mk_and(r.ws); + fml = m.mk_implies(w, cls); + partial.push_back(w); + add(fml); + update_model(w, cls); + m_defs.push_back(fml); + m_unfold.insert(w, r); } - expr_ref u = mk_and(us); - new_assumption(u, w); + new_assumption(w, weight); + s().assert_expr(m.mk_not(core.back())); } -#endif // cs is a correction set (a complement of a (maximal) satisfying assignment). void cs_max_resolve(exprs const& cs, rational const& w) { @@ -866,7 +894,7 @@ public: } rational cost(model& mdl) { - rational upper(0); + rational upper = m_unfold_upper; for (soft& s : m_soft) if (!mdl.is_true(s.s)) upper += s.weight; @@ -971,6 +999,8 @@ public: add_upper_bound_block(); m_csmodel = nullptr; m_correction_set_size = 0; + m_unfold.reset(); + m_unfold_upper = 0; return l_true; } @@ -1036,6 +1066,16 @@ opt::maxsmt_solver_base* opt::mk_maxres( return alloc(maxres, c, id, soft, maxres::s_primal); } +opt::maxsmt_solver_base* opt::mk_maxres_binary( + maxsat_context& c, unsigned id, vector& soft) { + return alloc(maxres, c, id, soft, maxres::s_primal_binary); +} + +opt::maxsmt_solver_base* opt::mk_maxres_binary_delay( + maxsat_context& c, unsigned id, vector& soft) { + return alloc(maxres, c, id, soft, maxres::s_primal_binary_delay); +} + opt::maxsmt_solver_base* opt::mk_primal_dual_maxres( maxsat_context& c, unsigned id, vector& soft) { return alloc(maxres, c, id, soft, maxres::s_primal_dual); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index a3d5f2f45..f346a8980 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -191,6 +191,12 @@ namespace opt { else if (m_soft.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) { m_msolver = mk_maxres(m_c, m_index, m_soft); } + else if (maxsat_engine == symbol("maxres-bin")) { + m_msolver = mk_maxres_binary(m_c, m_index, m_soft); + } + else if (maxsat_engine == symbol("maxres-bin-delay")) { + m_msolver = mk_maxres_binary_delay(m_c, m_index, m_soft); + } else if (maxsat_engine == symbol("pd-maxres")) { m_msolver = mk_primal_dual_maxres(m_c, m_index, m_soft); } From b5309d5fd073c1e056b3ce436c393b28e13afe10 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Apr 2022 16:42:57 +0200 Subject: [PATCH 050/253] na --- src/opt/maxres.cpp | 10 ++++++++-- src/opt/maxres.h | 4 ++++ src/opt/opt_params.pyg | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 9fcce1fce..10ab3c77b 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -774,8 +774,14 @@ public: for (expr* _ : core) partial.push_back(nullptr); - - for (unsigned i = 0; i + 1 < core.size(); ++i) { + + std::cout << "Core size " << core.size() << "\n"; + + if (core.size() > 2) + m_unfold_upper += rational(core.size()-2)*weight; + + expr* w = nullptr; + for (unsigned i = 0; i + 1 < core.size(); i += 2) { expr* a = core.get(i); expr* b = core.get(i + 1); expr* u = mk_fresh_bool("u"); diff --git a/src/opt/maxres.h b/src/opt/maxres.h index 25ef9bf05..947b60492 100644 --- a/src/opt/maxres.h +++ b/src/opt/maxres.h @@ -23,6 +23,10 @@ namespace opt { maxsmt_solver_base* mk_maxres(maxsat_context& c, unsigned id, vector& soft); + maxsmt_solver_base* mk_maxres_binary(maxsat_context& c, unsigned id, vector& soft); + + maxsmt_solver_base* mk_maxres_binary_delay(maxsat_context& c, unsigned id, vector& soft); + maxsmt_solver_base* mk_primal_dual_maxres(maxsat_context& c, unsigned id, vector& soft); }; diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 5106c5492..cb8f1d129 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -2,7 +2,7 @@ def_module_params('opt', description='optimization parameters', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'symba'"), - ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), + ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'maxres-bin', 'maxres-bin-delay'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('dump_models', BOOL, False, 'display intermediary models to stdout'), From 7496f1154249cc3d139f96188183367fa4ecef7b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Apr 2022 18:30:35 +0200 Subject: [PATCH 051/253] na --- src/opt/maxres.cpp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 10ab3c77b..9b9cc18f5 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -763,19 +763,16 @@ public: unfold_record r; if (!m_unfold.find(c, r)) continue; - IF_VERBOSE(2, verbose_stream() << "to unfold " << mk_pp(c, m) << "\n"); + IF_VERBOSE(1, verbose_stream() << "to unfold " << mk_pp(c, m) << " unfold size " << m_unfold.size() << " core " << core.size() << "\n"); for (expr* f : r.ws) { - IF_VERBOSE(2, verbose_stream() << "unfold " << mk_pp(f, m) << "\n"); + IF_VERBOSE(1, verbose_stream() << "unfold " << mk_pp(f, m) << "\n"); new_assumption(f, r.weight); } m_unfold_upper -= r.weight * rational(r.ws.size() - 1); m_unfold.remove(c); } - - for (expr* _ : core) - partial.push_back(nullptr); - std::cout << "Core size " << core.size() << "\n"; + partial.resize(core.size(), nullptr); if (core.size() > 2) m_unfold_upper += rational(core.size()-2)*weight; @@ -808,16 +805,21 @@ public: if (partial.get(i + 1)) r.ws.push_back(partial.get(i + 1)); m_trail.append(r.ws.size(), r.ws.data()); - w = mk_fresh_bool("w"); - cls = m.mk_and(r.ws); - fml = m.mk_implies(w, cls); - partial.push_back(w); - add(fml); - update_model(w, cls); - m_defs.push_back(fml); - m_unfold.insert(w, r); + if (r.ws.size() == 1) + w = u; + else { + w = mk_fresh_bool("w"); + cls = m.mk_and(r.ws); + fml = m.mk_implies(w, cls); + add(fml); + update_model(w, cls); + m_defs.push_back(fml); + m_unfold.insert(w, r); + } + partial.push_back(w); } - new_assumption(w, weight); + if (w) + new_assumption(w, weight); s().assert_expr(m.mk_not(core.back())); } From 4a59ae41b30b9b0b817f312a0ac2da7162392314 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Apr 2022 19:19:05 +0200 Subject: [PATCH 052/253] fixes Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 9b9cc18f5..c4639c726 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -629,9 +629,8 @@ public: if (core.empty()) return rational(0); // find the minimal weight: rational w = get_weight(core[0]); - for (unsigned i = 1; i < core.size(); ++i) { + for (unsigned i = 1; i < core.size(); ++i) w = std::min(w, get_weight(core[i])); - } return w; } @@ -721,7 +720,7 @@ public: } - void bin_max_resolve(exprs const& _core, rational const& w) { + void bin_max_resolve(exprs const& _core, rational w) { expr_ref_vector core(m, _core.size(), _core.data()); expr_ref fml(m), cls(m); for (unsigned i = 0; i + 1 < core.size(); i += 2) { @@ -756,7 +755,7 @@ public: obj_map m_unfold; rational m_unfold_upper; - void bin_delay_max_resolve(exprs const& _core, rational const& weight) { + void bin_delay_max_resolve(exprs const& _core, rational weight) { expr_ref_vector core(m, _core.size(), _core.data()), partial(m); expr_ref fml(m), cls(m); for (expr* c : core) { @@ -805,6 +804,7 @@ public: if (partial.get(i + 1)) r.ws.push_back(partial.get(i + 1)); m_trail.append(r.ws.size(), r.ws.data()); + r.weight = weight; if (r.ws.size() == 1) w = u; else { From c727e2d048ef010983528c8c7e90197f93054ea4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Apr 2022 10:31:56 +0200 Subject: [PATCH 053/253] add rc2 option Signed-off-by: Nikolaj Bjorner --- src/opt/CMakeLists.txt | 2 +- src/opt/{maxres.cpp => maxcore.cpp} | 120 ++++++++++++++++++++++------ src/opt/{maxres.h => maxcore.h} | 4 +- src/opt/maxsmt.cpp | 5 +- src/opt/opt_params.pyg | 2 +- 5 files changed, 105 insertions(+), 28 deletions(-) rename src/opt/{maxres.cpp => maxcore.cpp} (91%) rename src/opt/{maxres.h => maxcore.h} (78%) diff --git a/src/opt/CMakeLists.txt b/src/opt/CMakeLists.txt index c652bcaea..c815ae08e 100644 --- a/src/opt/CMakeLists.txt +++ b/src/opt/CMakeLists.txt @@ -1,7 +1,7 @@ z3_add_component(opt SOURCES + maxcore.cpp maxlex.cpp - maxres.cpp maxsmt.cpp opt_cmds.cpp opt_context.cpp diff --git a/src/opt/maxres.cpp b/src/opt/maxcore.cpp similarity index 91% rename from src/opt/maxres.cpp rename to src/opt/maxcore.cpp index c4639c726..4369b10fa 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxcore.cpp @@ -3,14 +3,17 @@ Copyright (c) 2014 Microsoft Corporation Module Name: - maxsres.cpp + maxcore.cpp Abstract: - MaxRes (weighted) max-sat algorithms: + Core based (weighted) max-sat algorithms: + + - mu: max-sat algorithm by Nina and Bacchus, AAAI 2014. + - mus-mss: based on dual refinement of bounds. + - binary + - binary-delay - - mus: max-sat algorithm by Nina and Bacchus, AAAI 2014. - - mus-mss: based on dual refinement of bounds. MaxRes is a core-guided approach to maxsat. MusMssMaxRes extends the core-guided approach by @@ -64,17 +67,18 @@ Notes: #include "opt/opt_params.hpp" #include "opt/opt_lns.h" #include "opt/maxsmt.h" -#include "opt/maxres.h" +#include "opt/maxcore.h" using namespace opt; -class maxres : public maxsmt_solver_base { +class maxcore : public maxsmt_solver_base { public: enum strategy_t { s_primal, s_primal_dual, s_primal_binary, - s_primal_binary_delay + s_primal_binary_delay, + s_rc2 }; private: struct stats { @@ -86,10 +90,10 @@ private: } }; - struct lns_maxres : public lns_context { - maxres& i; - lns_maxres(maxres& i) :i(i) {} - ~lns_maxres() override {} + struct lns_maxcore : public lns_context { + maxcore& i; + lns_maxcore(maxcore& i) :i(i) {} + ~lns_maxcore() override {} void update_model(model_ref& mdl) override { i.update_assignment(mdl); } void relax_cores(vector const& cores) override { i.relax_cores(cores); } rational cost(model& mdl) override { return i.cost(mdl); } @@ -108,7 +112,7 @@ private: strategy_t m_st; rational m_max_upper; model_ref m_csmodel; - lns_maxres m_lnsctx; + lns_maxcore m_lnsctx; lns m_lns; unsigned m_correction_set_size; bool m_found_feasible_optimum; @@ -130,7 +134,7 @@ private: typedef ptr_vector exprs; public: - maxres(maxsat_context& c, unsigned index, + maxcore(maxsat_context& c, unsigned index, vector& soft, strategy_t st): maxsmt_solver_base(c, soft, index), @@ -168,7 +172,7 @@ public: } } - ~maxres() override {} + ~maxcore() override {} bool is_literal(expr* l) { return @@ -375,8 +379,8 @@ public: } void collect_statistics(statistics& st) const override { - st.update("maxres-cores", m_stats.m_num_cores); - st.update("maxres-correction-sets", m_stats.m_num_cs); + st.update("maxsat-cores", m_stats.m_num_cores); + st.update("maxsat-correction-sets", m_stats.m_num_cs); } struct weighted_core { @@ -456,8 +460,8 @@ public: } struct compare_asm { - maxres& mr; - compare_asm(maxres& mr):mr(mr) {} + maxcore& mr; + compare_asm(maxcore& mr):mr(mr) {} bool operator()(expr* a, expr* b) const { rational w1 = mr.get_weight(a); rational w2 = mr.get_weight(b); @@ -550,6 +554,9 @@ public: case strategy_t::s_primal_binary_delay: bin_delay_max_resolve(core, w); break; + case strategy_t::s_rc2: + max_resolve_rc2(core, w); + break; default: max_resolve(core, w); break; @@ -747,6 +754,7 @@ public: } + // binary - with delayed unfolding of new soft clauses. struct unfold_record { ptr_vector ws; rational weight; @@ -823,6 +831,63 @@ public: s().assert_expr(m.mk_not(core.back())); } + // rc2, using cardinality constraints + + // create and cache at-most k constraints + struct bound_info { + ptr_vector es; + unsigned k = 0; + rational weight; + bound_info() {} + bound_info(ptr_vector const& es, unsigned k, rational const& weight): + es(es), k(k), weight(weight) {} + bound_info(expr_ref_vector const& es, unsigned k, rational const& weight): + es(es.size(), es.data()), k(k), weight(weight) {} + }; + + obj_map m_at_mostk; + obj_map m_bounds; + + expr* mk_atmost(expr_ref_vector const& es, unsigned bound, rational const& weight) { + pb_util pb(m); + expr_ref am(pb.mk_at_most_k(es, bound), m); + expr* r = nullptr; + if (m_at_mostk.find(am, r)) + return r; + r = mk_fresh_bool("r"); + m_trail.push_back(am); + bound_info b(es, bound, weight); + m_at_mostk.insert(am, r); + m_bounds.insert(r, b); + expr_ref fml(m); + fml = m.mk_implies(r, am); + add(fml); + m_defs.push_back(fml); + update_model(r, am); + return r; + } + + void max_resolve_rc2(exprs const& core, rational weight) { + expr_ref_vector ncore(m); + for (expr* f : core) { + bound_info b; + if (!m_bounds.find(f, b)) + continue; + m_bounds.remove(f); + if (b.k + 1 >= b.es.size()) + continue; + expr_ref_vector es(m, b.es.size(), b.es.data()); + expr* amk = mk_atmost(es, b.k + 1, b.weight); + new_assumption(amk, b.weight); + ncore.push_back(mk_not(m, f)); + m_unfold_upper -= b.weight; + } + m_unfold_upper += rational(core.size() - 1) * weight; + expr* am = mk_atmost(ncore, 1, weight); + new_assumption(am, weight); + } + + // cs is a correction set (a complement of a (maximal) satisfying assignment). void cs_max_resolve(exprs const& cs, rational const& w) { if (cs.empty()) return; @@ -1009,6 +1074,8 @@ public: m_correction_set_size = 0; m_unfold.reset(); m_unfold_upper = 0; + m_at_mostk.reset(); + m_bounds.reset(); return l_true; } @@ -1016,8 +1083,7 @@ public: if (m_found_feasible_optimum) { add(m_defs); add(m_asms); - TRACE("opt", tout << "Committing feasible solution\ndefs:" << m_defs << "\nasms:" << m_asms << "\n";); - + TRACE("opt", tout << "Committing feasible solution\ndefs:" << m_defs << "\nasms:" << m_asms << "\n"); } // else: there is only a single assignment to these soft constraints. } @@ -1071,21 +1137,27 @@ public: opt::maxsmt_solver_base* opt::mk_maxres( maxsat_context& c, unsigned id, vector& soft) { - return alloc(maxres, c, id, soft, maxres::s_primal); + return alloc(maxcore, c, id, soft, maxcore::s_primal); +} + +opt::maxsmt_solver_base* opt::mk_rc2( + maxsat_context& c, unsigned id, vector& soft) { + return alloc(maxcore, c, id, soft, maxcore::s_rc2); } opt::maxsmt_solver_base* opt::mk_maxres_binary( maxsat_context& c, unsigned id, vector& soft) { - return alloc(maxres, c, id, soft, maxres::s_primal_binary); + return alloc(maxcore, c, id, soft, maxcore::s_primal_binary); } opt::maxsmt_solver_base* opt::mk_maxres_binary_delay( maxsat_context& c, unsigned id, vector& soft) { - return alloc(maxres, c, id, soft, maxres::s_primal_binary_delay); + return alloc(maxcore, c, id, soft, maxcore::s_primal_binary_delay); } opt::maxsmt_solver_base* opt::mk_primal_dual_maxres( maxsat_context& c, unsigned id, vector& soft) { - return alloc(maxres, c, id, soft, maxres::s_primal_dual); + return alloc(maxcore, c, id, soft, maxcore::s_primal_dual); } + diff --git a/src/opt/maxres.h b/src/opt/maxcore.h similarity index 78% rename from src/opt/maxres.h rename to src/opt/maxcore.h index 947b60492..42efeb0bf 100644 --- a/src/opt/maxres.h +++ b/src/opt/maxcore.h @@ -7,7 +7,7 @@ Module Name: Abstract: - MaxRes (weighted) max-sat algorithm by Nina and Bacchus, AAAI 2014. + Maxcore (weighted) max-sat algorithm by Nina and Bacchus, AAAI 2014. Author: @@ -21,6 +21,8 @@ Notes: namespace opt { + maxsmt_solver_base* mk_rc2(maxsat_context& c, unsigned id, vector& soft); + maxsmt_solver_base* mk_maxres(maxsat_context& c, unsigned id, vector& soft); maxsmt_solver_base* mk_maxres_binary(maxsat_context& c, unsigned id, vector& soft); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index f346a8980..b2cdedf64 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -23,7 +23,7 @@ Notes: #include "ast/ast_util.h" #include "ast/pb_decl_plugin.h" #include "opt/maxsmt.h" -#include "opt/maxres.h" +#include "opt/maxcore.h" #include "opt/maxlex.h" #include "opt/wmax.h" #include "opt/opt_params.hpp" @@ -194,6 +194,9 @@ namespace opt { else if (maxsat_engine == symbol("maxres-bin")) { m_msolver = mk_maxres_binary(m_c, m_index, m_soft); } + else if (maxsat_engine == symbol("rc2")) { + m_msolver = mk_rc2(m_c, m_index, m_soft); + } else if (maxsat_engine == symbol("maxres-bin-delay")) { m_msolver = mk_maxres_binary_delay(m_c, m_index, m_soft); } diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index cb8f1d129..914b3a72b 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -2,7 +2,7 @@ def_module_params('opt', description='optimization parameters', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'symba'"), - ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'maxres-bin', 'maxres-bin-delay'"), + ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'maxres-bin', 'maxres-bin-delay', 'rc2'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('dump_models', BOOL, False, 'display intermediary models to stdout'), From 98c7069f75b19df1aed92087cc4fef34a76c38b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Apr 2022 14:29:16 +0200 Subject: [PATCH 054/253] add rewrite for hoisting multipliers over modular inverses Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.cpp | 23 +++++++++++++++++++++++ src/ast/rewriter/arith_rewriter.h | 4 +++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 857ae0755..1b52e335d 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -700,9 +700,32 @@ br_status arith_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result else if (m_arith_lhs || is_arith_term(arg1) || is_arith_term(arg2)) { st = mk_le_ge_eq_core(arg1, arg2, EQ, result); } + + if (st == BR_FAILED && mk_eq_mod(arg1, arg2, result)) + st = BR_REWRITE2; return st; } +bool arith_rewriter::mk_eq_mod(expr* arg1, expr* arg2, expr_ref& result) { + expr* x = nullptr, *y = nullptr, *z = nullptr, *u = nullptr; + rational p, k, l; + // match k*u mod p = l, where k, p, l are integers + if (m_util.is_mod(arg1, x, y) && m_util.is_numeral(y, p) && + m_util.is_mul(x, z, u) && m_util.is_numeral(z, k) && + m_util.is_numeral(arg2, l) && 0 <= l && l < p) { + // a*p + k*b = g + rational a, b; + rational g = gcd(p, k, a, b); + if (g == 1) { + expr_ref nb(m_util.mk_numeral(b, true), m()); + result = m().mk_eq(m_util.mk_mod(u, y), + m_util.mk_mod(m_util.mk_mul(nb, arg2), y)); + return true; + } + } + return false; +} + expr_ref arith_rewriter::neg_monomial(expr* e) const { expr_ref_vector args(m()); rational a1; diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index d64896d3d..19a8363a0 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -104,7 +104,9 @@ class arith_rewriter : public poly_rewriter { bool divides(expr* d, expr* n, expr_ref& result); expr_ref remove_divisor(expr* arg, expr* num, expr* den); void flat_mul(expr* e, ptr_buffer& args); - void remove_divisor(expr* d, ptr_buffer& args); + void remove_divisor(expr* d, ptr_buffer& args); + + bool mk_eq_mod(expr* arg1, expr* arg2, expr_ref& result); public: arith_rewriter(ast_manager & m, params_ref const & p = params_ref()): poly_rewriter(m, p) { From df981666fd4c99e744be145ba4df35c9908ed896 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Apr 2022 16:27:46 +0200 Subject: [PATCH 055/253] na Signed-off-by: Nikolaj Bjorner --- src/opt/maxcore.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/opt/maxcore.cpp b/src/opt/maxcore.cpp index 4369b10fa..c71a7944e 100644 --- a/src/opt/maxcore.cpp +++ b/src/opt/maxcore.cpp @@ -882,9 +882,11 @@ public: ncore.push_back(mk_not(m, f)); m_unfold_upper -= b.weight; } - m_unfold_upper += rational(core.size() - 1) * weight; - expr* am = mk_atmost(ncore, 1, weight); - new_assumption(am, weight); + if (core.size() > 1) { + m_unfold_upper += rational(core.size() - 2) * weight; + expr* am = mk_atmost(ncore, 1, weight); + new_assumption(am, weight); + } } From 09b0c4bc9db7548674b65357f3bbb5939c1ec289 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Apr 2022 07:17:24 +0200 Subject: [PATCH 056/253] fix #5988 --- src/util/max_cliques.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index 979a5b795..576408f51 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -181,7 +181,7 @@ public: next.push_back(n); std::sort(next.begin(), next.end(), [&](unsigned a, unsigned b) { return conns[a].num_elems() < conns[b].num_elems(); }); for (unsigned x : next) { - bool all = true; + bool all = heap.contains(x); for (unsigned y : am1) { if (!conns[x].contains(y)) { all = false; @@ -190,15 +190,18 @@ public: } if (all) am1.insert(x); - } + } am1.insert(v); + for (unsigned x : am1) { todo.remove(x); for (unsigned y : conns[x]) { conns[y].remove(x); - heap.decreased(y); + if (heap.contains(y)) + heap.decreased(y); } } + for (unsigned x : am1) heap.erase(x); From 9b66d8600bdb527098792efdb00f154f39e1a067 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Apr 2022 07:21:22 +0200 Subject: [PATCH 057/253] add shortcut to serialize/deserialize based on question at FV hangout use case ``` from z3 import * x, y = Ints('x y') s = (x + y).serialize() y = deserialize(s) print(y) ``` --- src/api/python/z3/z3.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index ed9c7f0a8..af1d32972 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1101,6 +1101,28 @@ class ExprRef(AstRef): else: return [] + def from_string(self, s): + pass + + def serialize(self): + s = Solver() + f = Function('F', self.sort(), BoolSort(self.ctx)) + s.add(f(self)) + return s.sexpr() + +def deserialize(st): + """inverse function to the serialize method on ExprRef. + It is made available to make it easier for users to serialize expressions back and forth between + strings. Solvers can be serialized using the 'sexpr()' method. + """ + s = Solver() + s.from_string(st) + if len(s.assertions()) != 1: + raise Z3Exception("single assertion expected") + fml = s.assertions()[0] + if fml.num_args() != 1: + raise Z3Exception("dummy function 'F' expected") + return fml.arg(0) def _to_expr_ref(a, ctx): if isinstance(a, Pattern): From a1ead5f47d4f596f7f59202cf6f8752c8e165b2a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Apr 2022 07:31:40 +0200 Subject: [PATCH 058/253] #5986 add memory limit check to internalize --- src/smt/smt_internalizer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index fd55d5fd0..eee811e62 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -350,6 +350,8 @@ namespace smt { - gate_ctx is true if the expression is in the context of a logical gate. */ void context::internalize(expr * n, bool gate_ctx) { + if (memory::above_high_watermark()) + throw default_exception("resource limit exceeded during internalization"); internalize_deep(n); internalize_rec(n, gate_ctx); } From b7169e2a41121a979072d3f17075b2f0604e30ba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Apr 2022 07:54:55 +0200 Subject: [PATCH 059/253] fix #5985 --- src/ast/dl_decl_plugin.cpp | 45 +++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index 1291e72e2..608940da4 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -700,16 +700,8 @@ namespace datalog { } bool dl_decl_util::is_numeral_ext(expr* e, uint64_t& v) const { - if (is_numeral(e, v)) { + if (is_numeral(e, v)) return true; - } - rational val; - unsigned bv_size = 0; - if (bv().is_numeral(e, val, bv_size) && bv_size < 64) { - SASSERT(val.is_uint64()); - v = val.get_uint64(); - return true; - } if (m.is_true(e)) { v = 1; return true; @@ -718,16 +710,43 @@ namespace datalog { v = 0; return true; } + + rational val; + unsigned bv_size = 0; + if (bv().is_numeral(e, val, bv_size) && bv_size < 64) { + SASSERT(val.is_uint64()); + v = val.get_uint64(); + return true; + } + + datatype::util dt(m); + if (dt.is_enum_sort(e->get_sort()) && dt.is_constructor(e)) { + auto& cs = *dt.get_datatype_constructors(e->get_sort()); + v = 0; + for (func_decl* f : cs) { + if (f == to_app(e)->get_decl()) + return true; + ++v; + } + } return false; } bool dl_decl_util::is_numeral_ext(expr* c) const { - if (is_numeral(c)) return true; + if (is_numeral(c)) + return true; rational val; unsigned bv_size = 0; - if (arith().is_numeral(c, val) && val.is_uint64()) return true; - if (bv().is_numeral(c, val, bv_size) && bv_size < 64) return true; - return m.is_true(c) || m.is_false(c); + if (arith().is_numeral(c, val) && val.is_uint64()) + return true; + if (bv().is_numeral(c, val, bv_size) && bv_size < 64) + return true; + if (m.is_true(c) || m.is_false(c)) + return true; + datatype::util dt(m); + if (dt.is_enum_sort(c->get_sort()) && dt.is_constructor(c)) + return true; + return false; } sort* dl_decl_util::mk_sort(const symbol& name, uint64_t domain_size) { From a180254c1a7b220d77175557c5d832a5063c4e65 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Apr 2022 11:10:20 +0100 Subject: [PATCH 060/253] fix #5980 --- src/ast/recfun_decl_plugin.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 0e9c27655..9dd82bc1a 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -79,13 +79,15 @@ namespace recfun { } // does `e` contain any `ite` construct? + // subject to the then/else branch using a recursive call, + // but the guard does not. bool def::contains_ite(util& u, expr * e) { struct ite_find_p : public i_expr_pred { ast_manager & m; def& d; util& u; ite_find_p(ast_manager & m, def& d, util& u) : m(m), d(d), u(u) {} - bool operator()(expr * e) override { return m.is_ite(e) && d.contains_def(u, e); } + bool operator()(expr * e) override { return m.is_ite(e) && !d.contains_def(u, to_app(e)->get_arg(0)) && d.contains_def(u, e); } }; // ignore ites under quantifiers. // this is redundant as the code @@ -273,9 +275,9 @@ namespace recfun { // explore arguments for (expr * arg : *to_app(e)) { if (contains_ite(u, arg)) { + for (expr * arg : *to_app(e)) + if (contains_ite(u, arg)) stack.push_back(arg); - } - } } } } From 5393f1d98fb3aef28ffed2694c43821d64c1ad66 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Apr 2022 11:10:37 +0100 Subject: [PATCH 061/253] #5980 --- src/ast/recfun_decl_plugin.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 9dd82bc1a..ca2e1584d 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -273,8 +273,6 @@ namespace recfun { } else if (is_app(e)) { // explore arguments - for (expr * arg : *to_app(e)) { - if (contains_ite(u, arg)) { for (expr * arg : *to_app(e)) if (contains_ite(u, arg)) stack.push_back(arg); From ec57d3b15c0e0f3a7192bd3c0213a9ab3b8a7084 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Apr 2022 16:20:02 +0100 Subject: [PATCH 062/253] missing switch cases --- src/opt/maxcore.cpp | 7 +++++++ src/sat/smt/q_ematch.cpp | 5 ++++- src/solver/assertions/asserted_formulas.cpp | 6 ++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/opt/maxcore.cpp b/src/opt/maxcore.cpp index c71a7944e..fc3ad1b91 100644 --- a/src/opt/maxcore.cpp +++ b/src/opt/maxcore.cpp @@ -169,6 +169,12 @@ public: case s_primal_binary_delay: m_trace_id = "maxres-bin-delay"; break; + case s_rc2: + m_trace_id = "rc2"; + break; + default: + UNREACHABLE(); + break; } } @@ -371,6 +377,7 @@ public: case s_primal: case s_primal_binary: case s_primal_binary_delay: + case s_rc2: return mus_solver(); case s_primal_dual: return primal_dual_solver(); diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 5f2d4a50e..5675c204c 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -669,8 +669,11 @@ namespace q { if (m_inst_queue.lazy_propagate()) return true; for (unsigned i = 0; i < m_clauses.size(); ++i) - if (m_clauses[i]->m_bindings) + if (m_clauses[i]->m_bindings) { IF_VERBOSE(0, verbose_stream() << "missed propagation " << i << "\n"); + TRACE("q", display(tout)); + break; + } TRACE("q", tout << "no more propagation\n";); return false; diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index d852d9383..d246dc06f 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -190,10 +190,11 @@ void asserted_formulas::push_scope() { } void asserted_formulas::push_scope_core() { + std::cout << "push\n"; reduce(); commit(); SASSERT(inconsistent() || m_qhead == m_formulas.size() || m.limit().is_canceled()); - TRACE("asserted_formulas_scopes", tout << "before push: " << m_scopes.size() << "\n";); + TRACE("asserted_formulas_scopes", tout << "before push: " << m_scopes.size() << "\n"); m_scoped_substitution.push(); m_scopes.push_back(scope()); scope & s = m_scopes.back(); @@ -205,7 +206,7 @@ void asserted_formulas::push_scope_core() { m_bv_sharing.push_scope(); m_macro_manager.push_scope(); commit(); - TRACE("asserted_formulas_scopes", tout << "after push: " << m_scopes.size() << "\n";); + TRACE("asserted_formulas_scopes", tout << "after push: " << m_scopes.size() << "\n"); } void asserted_formulas::force_push() { @@ -260,6 +261,7 @@ bool asserted_formulas::check_well_sorted() const { } void asserted_formulas::reduce() { + std::cout << "reduce\n"; if (inconsistent()) return; if (canceled()) From e3c35840bb67ef1bc4c42699d305ab4ac69b4778 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Apr 2022 11:26:16 +0100 Subject: [PATCH 063/253] remove out Signed-off-by: Nikolaj Bjorner --- src/solver/assertions/asserted_formulas.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index d246dc06f..d283a4b13 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -190,7 +190,6 @@ void asserted_formulas::push_scope() { } void asserted_formulas::push_scope_core() { - std::cout << "push\n"; reduce(); commit(); SASSERT(inconsistent() || m_qhead == m_formulas.size() || m.limit().is_canceled()); @@ -261,7 +260,6 @@ bool asserted_formulas::check_well_sorted() const { } void asserted_formulas::reduce() { - std::cout << "reduce\n"; if (inconsistent()) return; if (canceled()) From d9f3625f93cb7989962e42faa0e968c006bb9034 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Apr 2022 17:11:46 +0100 Subject: [PATCH 064/253] change default output to print objective value Signed-off-by: Nikolaj Bjorner --- src/opt/maxcore.cpp | 4 ++-- src/opt/opt_context.cpp | 34 +++++++++++++++++----------------- src/shell/opt_frontend.cpp | 22 ++++++++++++---------- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/opt/maxcore.cpp b/src/opt/maxcore.cpp index fc3ad1b91..2c4c87306 100644 --- a/src/opt/maxcore.cpp +++ b/src/opt/maxcore.cpp @@ -859,7 +859,7 @@ public: pb_util pb(m); expr_ref am(pb.mk_at_most_k(es, bound), m); expr* r = nullptr; - if (m_at_mostk.find(am, r)) + if (m_at_mostk.find(am, r)) return r; r = mk_fresh_bool("r"); m_trail.push_back(am); @@ -877,6 +877,7 @@ public: void max_resolve_rc2(exprs const& core, rational weight) { expr_ref_vector ncore(m); for (expr* f : core) { + ncore.push_back(mk_not(m, f)); bound_info b; if (!m_bounds.find(f, b)) continue; @@ -886,7 +887,6 @@ public: expr_ref_vector es(m, b.es.size(), b.es.data()); expr* amk = mk_atmost(es, b.k + 1, b.weight); new_assumption(amk, b.weight); - ncore.push_back(mk_not(m, f)); m_unfold_upper -= b.weight; } if (core.size() > 1) { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 25982e89e..85835f08d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -703,25 +703,25 @@ namespace opt { void context::update_solver() { sat_params p(m_params); - if (p.euf()) + if (!p.euf() && (!m_enable_sat || !probe_fd())) + return; + + if (m_maxsat_engine != symbol("maxres") && + m_maxsat_engine != symbol("rc2") && + m_maxsat_engine != symbol("maxres-bin") && + m_maxsat_engine != symbol("maxres-bin-delay") && + m_maxsat_engine != symbol("pd-maxres") && + m_maxsat_engine != symbol("bcd2") && + m_maxsat_engine != symbol("sls")) { return; - if (!p.euf()) { - if (!m_enable_sat || !probe_fd()) { - return; - } - if (m_maxsat_engine != symbol("maxres") && - m_maxsat_engine != symbol("pd-maxres") && - m_maxsat_engine != symbol("bcd2") && - m_maxsat_engine != symbol("sls")) { - return; - } - if (opt_params(m_params).priority() == symbol("pareto")) { - return; - } - if (m.proofs_enabled()) { - return; - } } + + if (opt_params(m_params).priority() == symbol("pareto")) + return; + + if (m.proofs_enabled()) + return; + m_params.set_bool("minimize_core_partial", true); m_params.set_bool("minimize_core", true); m_sat_solver = mk_inc_sat_solver(m, m_params); diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 0e5806ec0..78102eb6e 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -33,9 +33,14 @@ static void display_model(std::ostream& out) { return; model_ref mdl; g_opt->get_model(mdl); - if (mdl) { - model_smt2_pp(out, g_opt->get_manager(), *mdl, 0); - } + if (mdl) + model_smt2_pp(out, g_opt->get_manager(), *mdl, 0); +} + +static void display_objective() { + if (!g_opt) + return; + std::ostream& out = std::cout; for (unsigned h : g_handles) { expr_ref lo = g_opt->get_lower(h); expr_ref hi = g_opt->get_upper(h); @@ -48,14 +53,12 @@ static void display_model(std::ostream& out) { } } -static void display_model() { - if (g_display_model) + +static void display_model() { + if (g_display_model) display_model(std::cout); } -static void display_results() { - IF_VERBOSE(1, display_model(verbose_stream())); -} static void display_statistics() { lock_guard lock(*display_stats_mux); @@ -66,8 +69,6 @@ static void display_statistics() { double end_time = static_cast(clock()); std::cout << "time: " << (end_time - g_start_time)/CLOCKS_PER_SEC << " secs\n"; } - - display_results(); } static void STD_CALL on_ctrl_c(int) { @@ -136,6 +137,7 @@ static unsigned parse_opt(std::istream& in, opt_format f) { } display_statistics(); display_model(); + display_objective(); g_opt = nullptr; return 0; } From e6e00d894fe2ebcfdb0be06558dba4b14d3e853d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Apr 2022 10:18:40 +0100 Subject: [PATCH 065/253] update nightly/release scripts to produce arm64 for what is tested Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- scripts/release.yml | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 0add769b9..fc70b0e85 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -29,7 +29,7 @@ stages: pool: vmImage: "macOS-latest" steps: - - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 + - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 --nojava - script: git clone https://github.com/z3prover/z3test z3test - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@1 diff --git a/scripts/release.yml b/scripts/release.yml index cd860d177..7d355c3ea 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -43,6 +43,36 @@ stages: artifactName: 'macOSBuild' targetPath: $(Build.ArtifactStagingDirectory) + - job: MacBuildArm64 + displayName: "macOS Build" + pool: + vmImage: "macOS-latest" + steps: + - task: PythonScript@0 + displayName: Build + inputs: + scriptSource: 'filepath' + scriptPath: scripts/mk_unix_dist.py + arguments: --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --nojava --arch=arm64 + - script: git clone https://github.com/z3prover/z3test z3test + displayName: 'Clone z3test' + - task: PythonScript@0 + displayName: Test + inputs: + scriptSource: 'filepath' + scriptPath: z3test/scripts/test_benchmarks.py + arguments: build-dist/z3 z3test/regressions/smt2 + - task: CopyFiles@2 + inputs: + sourceFolder: dist + contents: '*.zip' + targetFolder: $(Build.ArtifactStagingDirectory) + - task: PublishPipelineArtifact@0 + inputs: + artifactName: 'macOSBuildArm64' + targetPath: $(Build.ArtifactStagingDirectory) + + - job: UbuntuBuild displayName: "Ubuntu build" pool: @@ -429,6 +459,11 @@ stages: inputs: artifact: 'macOSBuild' path: $(Agent.TempDirectory) + - task: DownloadPipelineArtifact@2 + displayName: 'Download macOSArm64 Build' + inputs: + artifact: 'macOSBuildArm64' + path: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 displayName: 'Download Win32 Build' inputs: From 0dd0fd26d49740bba504e7580d68006158369107 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Apr 2022 10:44:49 +0100 Subject: [PATCH 066/253] remove buggy prototype Signed-off-by: Nikolaj Bjorner --- src/opt/maxcore.cpp | 84 +----------------------------------------- src/opt/maxcore.h | 2 - src/opt/maxsmt.cpp | 3 -- src/opt/opt_params.pyg | 2 +- 4 files changed, 2 insertions(+), 89 deletions(-) diff --git a/src/opt/maxcore.cpp b/src/opt/maxcore.cpp index 2c4c87306..792e5e17a 100644 --- a/src/opt/maxcore.cpp +++ b/src/opt/maxcore.cpp @@ -558,9 +558,6 @@ public: case strategy_t::s_primal_binary: bin_max_resolve(core, w); break; - case strategy_t::s_primal_binary_delay: - bin_delay_max_resolve(core, w); - break; case strategy_t::s_rc2: max_resolve_rc2(core, w); break; @@ -761,82 +758,7 @@ public: } - // binary - with delayed unfolding of new soft clauses. - struct unfold_record { - ptr_vector ws; - rational weight; - }; - obj_map m_unfold; - rational m_unfold_upper; - - void bin_delay_max_resolve(exprs const& _core, rational weight) { - expr_ref_vector core(m, _core.size(), _core.data()), partial(m); - expr_ref fml(m), cls(m); - for (expr* c : core) { - unfold_record r; - if (!m_unfold.find(c, r)) - continue; - IF_VERBOSE(1, verbose_stream() << "to unfold " << mk_pp(c, m) << " unfold size " << m_unfold.size() << " core " << core.size() << "\n"); - for (expr* f : r.ws) { - IF_VERBOSE(1, verbose_stream() << "unfold " << mk_pp(f, m) << "\n"); - new_assumption(f, r.weight); - } - m_unfold_upper -= r.weight * rational(r.ws.size() - 1); - m_unfold.remove(c); - } - - partial.resize(core.size(), nullptr); - - if (core.size() > 2) - m_unfold_upper += rational(core.size()-2)*weight; - - expr* w = nullptr; - for (unsigned i = 0; i + 1 < core.size(); i += 2) { - expr* a = core.get(i); - expr* b = core.get(i + 1); - expr* u = mk_fresh_bool("u"); - expr* v = mk_fresh_bool("v"); - // u = a or b - // v = a and b - cls = m.mk_or(a, b); - fml = m.mk_implies(u, cls); - add(fml); - update_model(u, cls); - m_defs.push_back(fml); - cls = m.mk_and(a, b); - fml = m.mk_implies(v, cls); - add(fml); - update_model(v, cls); - m_defs.push_back(fml); - core.push_back(v); - - // w = u and w1 and w2 - unfold_record r; - r.ws.push_back(u); - if (partial.get(i)) - r.ws.push_back(partial.get(i)); - if (partial.get(i + 1)) - r.ws.push_back(partial.get(i + 1)); - m_trail.append(r.ws.size(), r.ws.data()); - r.weight = weight; - if (r.ws.size() == 1) - w = u; - else { - w = mk_fresh_bool("w"); - cls = m.mk_and(r.ws); - fml = m.mk_implies(w, cls); - add(fml); - update_model(w, cls); - m_defs.push_back(fml); - m_unfold.insert(w, r); - } - partial.push_back(w); - } - if (w) - new_assumption(w, weight); - s().assert_expr(m.mk_not(core.back())); - } // rc2, using cardinality constraints @@ -854,6 +776,7 @@ public: obj_map m_at_mostk; obj_map m_bounds; + rational m_unfold_upper; expr* mk_atmost(expr_ref_vector const& es, unsigned bound, rational const& weight) { pb_util pb(m); @@ -1081,7 +1004,6 @@ public: add_upper_bound_block(); m_csmodel = nullptr; m_correction_set_size = 0; - m_unfold.reset(); m_unfold_upper = 0; m_at_mostk.reset(); m_bounds.reset(); @@ -1159,10 +1081,6 @@ opt::maxsmt_solver_base* opt::mk_maxres_binary( return alloc(maxcore, c, id, soft, maxcore::s_primal_binary); } -opt::maxsmt_solver_base* opt::mk_maxres_binary_delay( - maxsat_context& c, unsigned id, vector& soft) { - return alloc(maxcore, c, id, soft, maxcore::s_primal_binary_delay); -} opt::maxsmt_solver_base* opt::mk_primal_dual_maxres( maxsat_context& c, unsigned id, vector& soft) { diff --git a/src/opt/maxcore.h b/src/opt/maxcore.h index 42efeb0bf..2dba613a7 100644 --- a/src/opt/maxcore.h +++ b/src/opt/maxcore.h @@ -27,8 +27,6 @@ namespace opt { maxsmt_solver_base* mk_maxres_binary(maxsat_context& c, unsigned id, vector& soft); - maxsmt_solver_base* mk_maxres_binary_delay(maxsat_context& c, unsigned id, vector& soft); - maxsmt_solver_base* mk_primal_dual_maxres(maxsat_context& c, unsigned id, vector& soft); }; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index b2cdedf64..02de67bb5 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -197,9 +197,6 @@ namespace opt { else if (maxsat_engine == symbol("rc2")) { m_msolver = mk_rc2(m_c, m_index, m_soft); } - else if (maxsat_engine == symbol("maxres-bin-delay")) { - m_msolver = mk_maxres_binary_delay(m_c, m_index, m_soft); - } else if (maxsat_engine == symbol("pd-maxres")) { m_msolver = mk_primal_dual_maxres(m_c, m_index, m_soft); } diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 914b3a72b..9c00020d5 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -2,7 +2,7 @@ def_module_params('opt', description='optimization parameters', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'symba'"), - ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'maxres-bin', 'maxres-bin-delay', 'rc2'"), + ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'maxres-bin', 'rc2'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('dump_models', BOOL, False, 'display intermediary models to stdout'), From 81189d6fddd48f43527b0ce388eb33bb0d68b03f Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Fri, 22 Apr 2022 10:54:21 +0200 Subject: [PATCH 067/253] Added bit2bool to the API (#5992) * Fixed registering expressions in push/pop * Reused existing function * Reverted reusing can_propagate * Added decide-callback to user-propagator * Refactoring * Fixed index * Added bit2bool to the API Fixed bug in user-propagator's decide callback * Fixed typo --- src/api/api_bv.cpp | 1 + src/api/c++/z3++.h | 1 + src/api/z3_api.h | 22 ++++++++--- src/smt/theory_bv.cpp | 4 +- src/smt/theory_user_propagator.cpp | 61 +++++++++++++++++++----------- 5 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/api/api_bv.cpp b/src/api/api_bv.cpp index 685463e19..bb4263730 100644 --- a/src/api/api_bv.cpp +++ b/src/api/api_bv.cpp @@ -102,6 +102,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ MK_BV_PUNARY(Z3_mk_sign_ext, OP_SIGN_EXT); MK_BV_PUNARY(Z3_mk_zero_ext, OP_ZERO_EXT); MK_BV_PUNARY(Z3_mk_repeat, OP_REPEAT); + MK_BV_PUNARY(Z3_mk_bit2bool, OP_BIT2BOOL); MK_BV_PUNARY(Z3_mk_rotate_left, OP_ROTATE_LEFT); MK_BV_PUNARY(Z3_mk_rotate_right, OP_ROTATE_RIGHT); MK_BV_PUNARY(Z3_mk_int2bv, OP_INT2BV); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 04e0b78e2..e817a5859 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1359,6 +1359,7 @@ namespace z3 { friend expr operator~(expr const & a); expr extract(unsigned hi, unsigned lo) const { Z3_ast r = Z3_mk_extract(ctx(), hi, lo, *this); ctx().check_error(); return expr(ctx(), r); } + expr bit2bool(unsigned i) const { Z3_ast r = Z3_mk_bit2bool(ctx(), i, *this); ctx().check_error(); return expr(ctx(), r); } unsigned lo() const { assert (is_app() && Z3_get_decl_num_parameters(ctx(), decl()) == 2); return static_cast(Z3_get_decl_int_parameter(ctx(), decl(), 1)); } unsigned hi() const { assert (is_app() && Z3_get_decl_num_parameters(ctx(), decl()) == 2); return static_cast(Z3_get_decl_int_parameter(ctx(), decl(), 0)); } diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 2680b6f82..a9e0c6b7c 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -2914,6 +2914,16 @@ extern "C" { def_API('Z3_mk_repeat', AST, (_in(CONTEXT), _in(UINT), _in(AST))) */ Z3_ast Z3_API Z3_mk_repeat(Z3_context c, unsigned i, Z3_ast t1); + + /** + \brief Extracts the bit at position \ccode{i} of a bit-vector and + yields a boolean. + + The node \c t1 must have a bit-vector sort. + + def_API('Z3_mk_bit2bool', AST, (_in(CONTEXT), _in(UINT), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_bit2bool(Z3_context c, unsigned i, Z3_ast t1); /** \brief Shift left. @@ -6755,16 +6765,16 @@ extern "C" { void Z3_API Z3_solver_propagate_diseq(Z3_context c, Z3_solver s, Z3_eq_eh eq_eh); /** - * \brief register a callback when a new expression with a registered function is used by the solver - * The registered function appears at the top level and is created using \ref Z3_propagate_solver_declare. + \brief register a callback when a new expression with a registered function is used by the solver + The registered function appears at the top level and is created using \ref Z3_propagate_solver_declare. */ void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh); /** - * \brief register a callback when a the solver decides to split on a registered expression - * The callback may set passed expression to another registered expression which will be selected instead. - * In case the expression is a bitvector the bit to split on is determined by the bit argument and the - * truth-value to try first is given by is_pos + \brief register a callback when the solver decides to split on a registered expression. + The callback may set the passed expression to another registered expression which will be selected instead. + In case the expression is a bitvector the bit to split on is determined by the bit argument and the + truth-value to try first is given by is_pos. In case the truth value is undefined the solver will decide. */ void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh); diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 682f4d6f9..90c8cd89e 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -1842,11 +1842,11 @@ namespace smt { unsigned sz = bits.size(); for (unsigned i = start_bit; i < sz; ++i) { - if (ctx.get_assignment(bits[i].var()) != l_undef) + if (ctx.get_assignment(bits[i].var()) == l_undef) return bits[i].var(); } for (unsigned i = 0; i < start_bit; ++i) { - if (ctx.get_assignment(bits[i].var()) != l_undef) + if (ctx.get_assignment(bits[i].var()) == l_undef) return bits[i].var(); } diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 1b0cc429d..e5b1a9c0d 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -159,37 +159,53 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu void theory_user_propagator::decide(bool_var& var, bool& is_pos) { const bool_var_data& d = ctx.get_bdata(var); - - if (!d.is_theory_atom()) + + if (!d.is_enode() && !d.is_theory_atom()) return; - - theory* th = ctx.get_theory(d.get_theory()); - - bv_util bv(m); - enode* original_enode = nullptr; + + enode* original_enode = nullptr; unsigned original_bit = 0; - - if (d.is_enode() && th->get_family_id() == get_family_id()) { - // variable is just a registered expression + bv_util bv(m); + theory* th = nullptr; + theory_var v = null_theory_var; + + // get the associated theory + if (!d.is_enode()) { + // it might be a value that does not have an enode + th = ctx.get_theory(d.get_theory()); + } + else { original_enode = ctx.bool_var2enode(var); + v = original_enode->get_th_var(get_family_id()); + if (v == null_theory_var) { + // it is not a registered boolean expression + th = ctx.get_theory(d.get_theory()); + } } - else if (th->get_family_id() == bv.get_fid()) { - // it might be a registered bit-vector - auto registered_bv = ((theory_bv*)th)->get_bv_with_theory(var, get_family_id()); - if (!registered_bv.first) - // there is no registered bv associated with the bit - return; - original_enode = registered_bv.first; - original_bit = registered_bv.second; - } - else + + if (!th && v == null_theory_var) return; + if (v == null_theory_var) { + if (th->get_family_id() == bv.get_fid()) { + // it is not a registered boolean value but it is a bitvector + auto registered_bv = ((theory_bv*)th)->get_bv_with_theory(var, get_family_id()); + if (!registered_bv.first) + // there is no registered bv associated with the bit + return; + original_enode = registered_bv.first; + original_bit = registered_bv.second; + v = original_enode->get_th_var(get_family_id()); + } + else + return; + } + // call the registered callback unsigned new_bit = original_bit; lbool phase = is_pos ? l_true : l_false; - - expr* e = var2expr(original_enode->get_th_var(get_family_id())); + + expr* e = var2expr(v); m_decide_eh(m_user_context, this, &e, &new_bit, &phase); enode* new_enode = ctx.get_enode(e); @@ -201,7 +217,6 @@ void theory_user_propagator::decide(bool_var& var, bool& is_pos) { return; } - bool_var old_var = var; if (new_enode->is_bool()) { // expression was set to a boolean bool_var new_var = ctx.enode2bool_var(new_enode); From 5a2c92f4af8980920507b5e6991fadf774f55d0e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Apr 2022 17:25:24 +0100 Subject: [PATCH 068/253] format --- src/util/max_cliques.h | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index 576408f51..2841db609 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -38,9 +38,8 @@ class max_cliques : public T { m_todo.push_back(p); for (unsigned i = 0; i < m_todo.size(); ++i) { p = m_todo[i]; - if (m_seen1.contains(p)) { - continue; - } + if (m_seen1.contains(p)) + continue; m_seen1.insert(p); if (m_seen2.contains(p)) { unsigned_vector const& tc = m_tc[p]; @@ -50,14 +49,12 @@ class max_cliques : public T { } else { unsigned np = negate(p); - if (goal.contains(np)) { - reachable.insert(np); - } + if (goal.contains(np)) + reachable.insert(np); m_todo.append(next(np)); } } - for (unsigned i = m_todo.size(); i > 0; ) { - --i; + for (unsigned i = m_todo.size(); i-- > 0; ) { p = m_todo[i]; if (m_seen2.contains(p)) continue; @@ -209,9 +206,8 @@ public: unsigned_vector mux; for (unsigned x : am1) mux.push_back(x); - if (mux.size() == 2 && mux[0] == negate(mux[1])) { - continue; - } + if (mux.size() == 2 && mux[0] == negate(mux[1])) + continue; cliques.push_back(mux); } } From 8778f4d43f688c155e29d7eab02b9f800f45ec38 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Apr 2022 17:59:23 +0100 Subject: [PATCH 069/253] updated release script Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index 7d355c3ea..2451d8233 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -527,7 +527,7 @@ stages: # Enable on release: - job: PyPIPublish - condition: eq(1,1) + condition: eq(0,1) displayName: "Publish to PyPI" pool: vmImage: "ubuntu-latest" From 8e509d34b596a625b73dbb3df8baaa55e29c6d91 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Apr 2022 19:05:42 +0100 Subject: [PATCH 070/253] remove test Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/scripts/release.yml b/scripts/release.yml index 2451d8233..71557021a 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -54,14 +54,6 @@ stages: scriptSource: 'filepath' scriptPath: scripts/mk_unix_dist.py arguments: --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --nojava --arch=arm64 - - script: git clone https://github.com/z3prover/z3test z3test - displayName: 'Clone z3test' - - task: PythonScript@0 - displayName: Test - inputs: - scriptSource: 'filepath' - scriptPath: z3test/scripts/test_benchmarks.py - arguments: build-dist/z3 z3test/regressions/smt2 - task: CopyFiles@2 inputs: sourceFolder: dist From 459cfc8eb4b5a76e99ffda95d95bceeb6b67deac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Apr 2022 19:33:55 +0100 Subject: [PATCH 071/253] fix #5993 Signed-off-by: Nikolaj Bjorner --- src/ast/fpa/fpa2bv_converter.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 7876d2d79..e1439a316 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -95,7 +95,16 @@ void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { } void fpa2bv_converter::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) { - if (m_util.is_fp(t) && m_util.is_fp(f)) { + expr* c2 = nullptr, *t2 = nullptr, *f2 = nullptr; + if (m.is_ite(t, c2, t2, f2)) { + mk_ite(c2, t2, f2, result); + mk_ite(c, result, f, result); + } + else if (m.is_ite(f, c2, t2, f2)) { + mk_ite(c2, t2, f2, result); + mk_ite(c, t, result, result); + } + else if (m_util.is_fp(t) && m_util.is_fp(f)) { expr_ref t_sgn(m), t_sig(m), t_exp(m); expr_ref f_sgn(m), f_sig(m), f_exp(m); split_fp(t, t_sgn, t_exp, t_sig); @@ -115,8 +124,11 @@ void fpa2bv_converter::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) { m_simp.mk_ite(c, to_app(t)->get_arg(0), to_app(f)->get_arg(0), result); result = m_util.mk_bv2rm(result); } - else + else { + std::cout << mk_pp(t, m) << " " << mk_pp(f, m) << "\n"; UNREACHABLE(); + + } } void fpa2bv_converter::mk_distinct(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { From 0529e88589f73119e258a1697cbbc8272cc69d54 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Apr 2022 19:51:25 +0100 Subject: [PATCH 072/253] enable pypi Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index 71557021a..49624f270 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -519,7 +519,7 @@ stages: # Enable on release: - job: PyPIPublish - condition: eq(0,1) + condition: eq(1,1) displayName: "Publish to PyPI" pool: vmImage: "ubuntu-latest" From bd6b3027cdda2d2a3547f6a8da73863942bf748a Mon Sep 17 00:00:00 2001 From: Victor Date: Sat, 23 Apr 2022 19:52:35 +0100 Subject: [PATCH 073/253] Document gotcha with z3-js (#5994) --- src/api/js/PUBLISHED_README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/js/PUBLISHED_README.md b/src/api/js/PUBLISHED_README.md index 897edabf5..4be8a7d51 100644 --- a/src/api/js/PUBLISHED_README.md +++ b/src/api/js/PUBLISHED_README.md @@ -9,6 +9,8 @@ Z3 itself is distributed as a wasm artifact as part of this package. You can fin This requires threads, which means you'll need to be running in an environment which supports `SharedArrayBuffer`. In browsers, in addition to ensuring the browser has implemented `SharedArrayBuffer`, you'll need to serve your page with [special headers](https://web.dev/coop-coep/). There's a [neat trick](https://github.com/gzuidhof/coi-serviceworker) for doing that client-side on e.g. Github Pages, though you shouldn't use that trick in more complex applications. +The Emscripten worker model will spawn multiple instances of `z3-built.js` for long-running operations. If you are using a bundler like Webpack, Emscripten can no longer reference `z3-built.js` - that file will be merged with the rest of your codebase. To fix this, you need to host the unmodified file separately, and set `Module['mainScriptUrlOrBlob']` to the URL of this file. If you don't do this, your bundle `main.js` will be used in all workers, which will undoubtedly fail and cause weird issues. + Other than the differences below, the bindings can be used exactly as you'd use the C library. Because this is a wrapper around a C library, most of the values you'll use are just numbers representing pointers. For this reason you are strongly encouraged to make use of the TypeScript types to differentiate among the different kinds of value. The module exports an `init` function, is an async function which initializes the library and returns `{ em, Z3 }` - `em` contains the underlying emscripten module, which you can use to e.g. kill stray threads, and `Z3` contains the actual bindings. The other module exports are the enums defined in the Z3 API. From 39f57fb7ca6ce4f6bbc1a030f89853c91fff82c4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Apr 2022 20:02:07 +0100 Subject: [PATCH 074/253] update release notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 8e61f55bd..449d6fc69 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -10,6 +10,20 @@ Version 4.8.next - native word level bit-vector solving. - introduction of simple induction lemmas to handle a limited repertoire of induction proofs. +Version 4.8.16 +============== + - initial support for Darwin Arm64 (for M1, M2, .. users) thanks to zwimer and Anja Petkovi'c + Komel for updates. + Java is not yet supported, pypi native arm64 distributions are not yet supported. + cmake dependency added to enable users to build for not-yet-supported platforms directly; + specifically M1 seems to come up. + - added functionality to user propagator decisions. Thanks to Clemens Eisenhofer. + - added options for rc2 and maxres-bin to maxsat (note that there was no real difference measured + from maxres on MaxSAT unweighted so default option is unchanged) + - improved search for mutex constraints (at-most-1 constraints) among soft + constraints for maxsat derived from approach used in rc2 sample. + - multiple merges + Version 4.8.15 ============== - elaborate user propagator API. Change id based scheme to expressions From 312e037458e18fbd203287e187752dcc751101dd Mon Sep 17 00:00:00 2001 From: Kevin Gibbons Date: Sun, 24 Apr 2022 03:04:08 -0700 Subject: [PATCH 075/253] wasm build: disable error handler (#5996) * wasm: set error handler to no-op * wasm: better wrapper for use in html --- src/api/js/PUBLISHED_README.md | 2 +- src/api/js/example-raw.ts | 12 ++++++++- src/api/js/package.json | 6 ++--- src/api/js/scripts/list-exports.js | 2 +- src/api/js/scripts/make-cc-wrapper.js | 39 ++++++++++++++++++++++++--- src/api/js/scripts/make-ts-wrapper.js | 26 +++++++++++++----- src/api/js/src/node-wrapper.ts | 10 +++++++ src/api/js/test-ts-api.ts | 4 +-- 8 files changed, 83 insertions(+), 18 deletions(-) create mode 100644 src/api/js/src/node-wrapper.ts diff --git a/src/api/js/PUBLISHED_README.md b/src/api/js/PUBLISHED_README.md index 4be8a7d51..4ccd4bea7 100644 --- a/src/api/js/PUBLISHED_README.md +++ b/src/api/js/PUBLISHED_README.md @@ -9,7 +9,7 @@ Z3 itself is distributed as a wasm artifact as part of this package. You can fin This requires threads, which means you'll need to be running in an environment which supports `SharedArrayBuffer`. In browsers, in addition to ensuring the browser has implemented `SharedArrayBuffer`, you'll need to serve your page with [special headers](https://web.dev/coop-coep/). There's a [neat trick](https://github.com/gzuidhof/coi-serviceworker) for doing that client-side on e.g. Github Pages, though you shouldn't use that trick in more complex applications. -The Emscripten worker model will spawn multiple instances of `z3-built.js` for long-running operations. If you are using a bundler like Webpack, Emscripten can no longer reference `z3-built.js` - that file will be merged with the rest of your codebase. To fix this, you need to host the unmodified file separately, and set `Module['mainScriptUrlOrBlob']` to the URL of this file. If you don't do this, your bundle `main.js` will be used in all workers, which will undoubtedly fail and cause weird issues. +The Emscripten worker model will spawn multiple instances of `z3-built.js` for long-running operations. When building for the web, you should include that file as its own script on the page - using a bundler like webpack will prevent it from loading correctly. That script defines a global variable named `initZ3`. Your main script, which can be bundled, should do `let { init } = require('z3-solver/build/wrapper.js'); let { Z3 } = await init(initZ3);`. Other than the differences below, the bindings can be used exactly as you'd use the C library. Because this is a wrapper around a C library, most of the values you'll use are just numbers representing pointers. For this reason you are strongly encouraged to make use of the TypeScript types to differentiate among the different kinds of value. diff --git a/src/api/js/example-raw.ts b/src/api/js/example-raw.ts index 9b19e782c..0ade4273a 100644 --- a/src/api/js/example-raw.ts +++ b/src/api/js/example-raw.ts @@ -1,4 +1,4 @@ -import { init } from './build/wrapper'; +import { init, Z3_error_code } from './build/node-wrapper'; // demonstrates use of the raw API @@ -47,6 +47,16 @@ import { init } from './build/wrapper'; console.log(Z3.query_constructor(ctx, nil_con, 0)); console.log(Z3.query_constructor(ctx, cons_con, 2)); + if (Z3.get_error_code(ctx) !== Z3_error_code.Z3_OK) { + throw new Error('something failed: ' + Z3.get_error_msg(ctx, Z3.get_error_code(ctx))); + } + await Z3.eval_smtlib2_string(ctx, '(simplify)'); + if (Z3.get_error_code(ctx) === Z3_error_code.Z3_OK) { + throw new Error('expected call to eval_smtlib2_string with invalid argument to fail'); + } + console.log('confirming error messages work:', Z3.get_error_msg(ctx, Z3.get_error_code(ctx))); + + Z3.dec_ref(ctx, strAst); Z3.del_context(ctx); diff --git a/src/api/js/package.json b/src/api/js/package.json index 85fd2d24c..63a7e7568 100644 --- a/src/api/js/package.json +++ b/src/api/js/package.json @@ -6,13 +6,13 @@ "engines": { "node": ">=16" }, - "main": "build/wrapper.js", - "types": "build/wrapper.d.ts", + "main": "build/node-wrapper.js", + "types": "build/node-wrapper.d.ts", "files": [ "build/*.{js,d.ts,wasm}" ], "scripts": { - "build-ts": "mkdir -p build && node scripts/make-ts-wrapper.js > build/wrapper.ts && tsc", + "build-ts": "mkdir -p build && rm -rf build/*.ts && cp src/node-wrapper.ts build && node scripts/make-ts-wrapper.js > build/wrapper.ts && tsc", "build-wasm": "mkdir -p build && node scripts/make-cc-wrapper.js > build/async-fns.cc && ./build-wasm.sh", "format": "prettier --write --single-quote --arrow-parens avoid --print-width 120 --trailing-comma all '{,src/,scripts/}*.{js,ts}'", "test": "node test-ts-api.js" diff --git a/src/api/js/scripts/list-exports.js b/src/api/js/scripts/list-exports.js index 4513b7e58..e86850e91 100644 --- a/src/api/js/scripts/list-exports.js +++ b/src/api/js/scripts/list-exports.js @@ -5,7 +5,7 @@ let { functions } = require('./parse-api.js'); let asyncFns = require('./async-fns.js'); -let extras = asyncFns.map(f => '_async_' + f); +let extras = ['_set_throwy_error_handler', '_set_noop_error_handler', ...asyncFns.map(f => '_async_' + f)]; let fns = functions.filter(f => !asyncFns.includes(f.name)); console.log(JSON.stringify([...extras, ...functions.map(f => '_' + f.name)])); diff --git a/src/api/js/scripts/make-cc-wrapper.js b/src/api/js/scripts/make-cc-wrapper.js index b0860e349..b522e4ebc 100644 --- a/src/api/js/scripts/make-cc-wrapper.js +++ b/src/api/js/scripts/make-cc-wrapper.js @@ -51,11 +51,14 @@ void wrapper(Args&&... args) { MAIN_THREAD_ASYNC_EM_ASM({ resolve_async($0); }, result); + } catch (std::exception& e) { + MAIN_THREAD_ASYNC_EM_ASM({ + reject_async(new Error(UTF8ToString($0))); + }, e.what()); } catch (...) { MAIN_THREAD_ASYNC_EM_ASM({ reject_async('failed with unknown exception'); }); - throw; } }); t.detach(); @@ -69,14 +72,44 @@ void wrapper_str(Args&&... args) { MAIN_THREAD_ASYNC_EM_ASM({ resolve_async(UTF8ToString($0)); }, result); + } catch (std::exception& e) { + MAIN_THREAD_ASYNC_EM_ASM({ + reject_async(new Error(UTF8ToString($0))); + }, e.what()); } catch (...) { MAIN_THREAD_ASYNC_EM_ASM({ - reject_async('failed with unknown exception'); + reject_async(new Error('failed with unknown exception')); }); - throw; } }); t.detach(); } + + +class Z3Exception : public std::exception { +public: + const std::string m_msg; + Z3Exception(const std::string& msg) : m_msg(msg) {} + virtual const char* what() const throw () { + return m_msg.c_str(); + } +}; + +void throwy_error_handler(Z3_context ctx, Z3_error_code c) { + throw Z3Exception(Z3_get_error_msg(ctx, c)); +} + +void noop_error_handler(Z3_context ctx, Z3_error_code c) { + // pass +} + +extern "C" void set_throwy_error_handler(Z3_context ctx) { + Z3_set_error_handler(ctx, throwy_error_handler); +} + +extern "C" void set_noop_error_handler(Z3_context ctx) { + Z3_set_error_handler(ctx, noop_error_handler); +} + ${wrappers.join('\n\n')}`); diff --git a/src/api/js/scripts/make-ts-wrapper.js b/src/api/js/scripts/make-ts-wrapper.js index 4a51c5ec9..e80de68a8 100644 --- a/src/api/js/scripts/make-ts-wrapper.js +++ b/src/api/js/scripts/make-ts-wrapper.js @@ -19,6 +19,8 @@ let makePointerType = t => // or up to 3 out int64s const BYTES_TO_ALLOCATE_FOR_OUT_PARAMS = 24; +const CUSTOM_IMPLEMENTATIONS = ['Z3_mk_context', 'Z3_mk_context_rc']; + function toEmType(type) { if (type in primitiveTypes) { type = primitiveTypes[type]; @@ -70,6 +72,10 @@ function toEm(p) { let isInParam = p => ['in', 'in_array'].includes(p.kind); function wrapFunction(fn) { + if (CUSTOM_IMPLEMENTATIONS.includes(fn.name)) { + return null; + } + let inParams = fn.params.filter(isInParam); let outParams = fn.params.map((p, idx) => ({ ...p, idx })).filter(p => !isInParam(p)); @@ -318,9 +324,6 @@ function wrapFunction(fn) { `.trim(); } - if (isAsync) { - } - // prettier-ignore let invocation = `Mod.ccall('${isAsync ? 'async_' : ''}${fn.name}', '${cReturnType}', ${JSON.stringify(ctypes)}, [${args.map(toEm).join(', ')}])`; @@ -358,8 +361,6 @@ let out = ` // THIS FILE IS AUTOMATICALLY GENERATED BY ${path.basename(__filename)} // DO NOT EDIT IT BY HAND -// @ts-ignore no-implicit-any -import initModule = require('./z3-built.js'); interface Pointer extends Number { readonly __typeName: T; } @@ -381,7 +382,7 @@ ${Object.entries(enums) .map(e => wrapEnum(e[0], e[1])) .join('\n\n')} -export async function init() { +export async function init(initModule: any) { let Mod = await initModule(); // this works for both signed and unsigned, because JS will wrap for you when constructing the Uint32Array @@ -410,10 +411,21 @@ export async function init() { return { em: Mod, Z3: { - ${functions + mk_context: function(c: Z3_config): Z3_context { + let ctx = Mod._Z3_mk_context(c); + Mod._set_noop_error_handler(ctx); + return ctx; + }, + mk_context_rc: function(c: Z3_config): Z3_context { + let ctx = Mod._Z3_mk_context_rc(c); + Mod._set_noop_error_handler(ctx); + return ctx; + }, + ${functions .map(wrapFunction) .filter(f => f != null) .join(',\n')} + } }; } diff --git a/src/api/js/src/node-wrapper.ts b/src/api/js/src/node-wrapper.ts new file mode 100644 index 000000000..cd315a026 --- /dev/null +++ b/src/api/js/src/node-wrapper.ts @@ -0,0 +1,10 @@ +// @ts-ignore no-implicit-any +import initModule = require('./z3-built.js'); + +// @ts-ignore no-implicit-any +import { init as initWrapper } from './wrapper'; + +export * from './wrapper'; +export function init() { + return initWrapper(initModule); +} diff --git a/src/api/js/test-ts-api.ts b/src/api/js/test-ts-api.ts index 0e371fc6e..ace3c2b5c 100644 --- a/src/api/js/test-ts-api.ts +++ b/src/api/js/test-ts-api.ts @@ -16,8 +16,8 @@ import type { Z3_func_decl, Z3_func_interp, Z3_func_entry, -} from './build/wrapper'; -import { init, Z3_lbool, Z3_ast_kind, Z3_sort_kind, Z3_symbol_kind } from './build/wrapper'; +} from './build/node-wrapper'; +import { init, Z3_lbool, Z3_ast_kind, Z3_sort_kind, Z3_symbol_kind } from './build/node-wrapper'; // @ts-ignore we're not going to bother with types for this import { sprintf } from 'sprintf-js'; From 33ffd464cfe47447cddd2560213c09220263fc61 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Apr 2022 12:17:07 +0100 Subject: [PATCH 076/253] inc version number Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fef02be9..640dda928 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake") -project(Z3 VERSION 4.8.16.0 LANGUAGES CXX) +project(Z3 VERSION 4.8.17.0 LANGUAGES CXX) ################################################################################ # Project version diff --git a/scripts/mk_project.py b/scripts/mk_project.py index a19ce613f..c855bc27c 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -8,7 +8,7 @@ from mk_util import * def init_version(): - set_version(4, 8, 16, 0) + set_version(4, 8, 17, 0) # Z3 Project definition def init_project_def(): From 24baf56e278da8c400b682b9d95bd1d15d759b46 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Apr 2022 16:29:25 +0100 Subject: [PATCH 077/253] fix missing propagation on final --- src/sat/smt/euf_model.cpp | 2 +- src/sat/smt/q_ematch.cpp | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index 9f7f3b938..55c916aa8 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -335,8 +335,8 @@ namespace euf { continue; if (!tt && !mdl.is_true(e)) continue; - IF_VERBOSE(0, display_validation_failure(verbose_stream(), mdl, n);); CTRACE("euf", first, display_validation_failure(tout, mdl, n);); + IF_VERBOSE(0, display_validation_failure(verbose_stream(), mdl, n);); (void)first; first = false; exit(1); diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 5675c204c..6f646555b 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -341,7 +341,6 @@ namespace q { return false; if (ctx.s().inconsistent()) return true; - TRACE("q", c.display(ctx, tout) << "\n";); unsigned idx = UINT_MAX; m_evidence.reset(); lbool ev = m_eval(binding, c, idx, m_evidence); @@ -614,12 +613,13 @@ namespace q { bool ematch::propagate(bool flush) { m_mam->propagate(); bool propagated = flush_prop_queue(); - if (m_qhead >= m_clause_queue.size()) + if (!flush && m_qhead >= m_clause_queue.size()) return m_inst_queue.propagate() || propagated; ctx.push(value_trail(m_qhead)); ptr_buffer to_remove; - for (; m_qhead < m_clause_queue.size() && m.inc(); ++m_qhead) { - unsigned idx = m_clause_queue[m_qhead]; + unsigned qhead = flush ? 0 : m_qhead; + for (; qhead < m_clause_queue.size() && m.inc(); ++qhead) { + unsigned idx = m_clause_queue[qhead]; clause& c = *m_clauses[idx]; binding* b = c.m_bindings; if (!b) @@ -645,6 +645,7 @@ namespace q { } to_remove.reset(); } + m_qhead = std::max(m_qhead, qhead); m_clause_in_queue.reset(); m_node_in_queue.reset(); m_in_queue_set = true; @@ -662,7 +663,7 @@ namespace q { if (propagate(false)) return true; for (unsigned i = 0; i < m_clauses.size(); ++i) - if (m_clauses[i]->m_bindings) + if (m_clauses[i]->m_bindings) insert_clause_in_queue(i); if (propagate(true)) return true; @@ -671,7 +672,7 @@ namespace q { for (unsigned i = 0; i < m_clauses.size(); ++i) if (m_clauses[i]->m_bindings) { IF_VERBOSE(0, verbose_stream() << "missed propagation " << i << "\n"); - TRACE("q", display(tout)); + TRACE("q", display(tout << "missed propagation\n")); break; } From dc18b479673f08ae90bbf62b2797c221746c1606 Mon Sep 17 00:00:00 2001 From: Kevin Gibbons Date: Sun, 24 Apr 2022 10:06:36 -0700 Subject: [PATCH 078/253] automatically release wasm build (#5997) --- .github/workflows/wasm-release.yml | 2 ++ src/api/js/example-raw.ts | 1 - src/api/js/scripts/make-ts-wrapper.js | 6 +++--- src/api/js/scripts/parse-api.js | 11 +++++------ 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/wasm-release.yml b/.github/workflows/wasm-release.yml index b91e06a80..907246e8d 100644 --- a/.github/workflows/wasm-release.yml +++ b/.github/workflows/wasm-release.yml @@ -2,6 +2,8 @@ name: WebAssembly Publish on: workflow_dispatch: + release: + types: [published] defaults: run: diff --git a/src/api/js/example-raw.ts b/src/api/js/example-raw.ts index 0ade4273a..684b8e7ea 100644 --- a/src/api/js/example-raw.ts +++ b/src/api/js/example-raw.ts @@ -56,7 +56,6 @@ import { init, Z3_error_code } from './build/node-wrapper'; } console.log('confirming error messages work:', Z3.get_error_msg(ctx, Z3.get_error_code(ctx))); - Z3.dec_ref(ctx, strAst); Z3.del_context(ctx); diff --git a/src/api/js/scripts/make-ts-wrapper.js b/src/api/js/scripts/make-ts-wrapper.js index e80de68a8..91e7eb653 100644 --- a/src/api/js/scripts/make-ts-wrapper.js +++ b/src/api/js/scripts/make-ts-wrapper.js @@ -422,9 +422,9 @@ export async function init(initModule: any) { return ctx; }, ${functions - .map(wrapFunction) - .filter(f => f != null) - .join(',\n')} + .map(wrapFunction) + .filter(f => f != null) + .join(',\n')} } }; diff --git a/src/api/js/scripts/parse-api.js b/src/api/js/scripts/parse-api.js index 53655424f..db12945bd 100644 --- a/src/api/js/scripts/parse-api.js +++ b/src/api/js/scripts/parse-api.js @@ -121,7 +121,6 @@ for (let file of files) { throw new Error(`extra text in parameter list ${JSON.stringify(text)}`); } - if (name in defApis) { throw new Error(`multiple defApi calls for ${name}`); } @@ -132,11 +131,11 @@ for (let file of files) { types[match.groups.type] = match.groups.type; } - // we don't have to pre-populate the types map with closure types - // use the Z3_DECLARE_CLOSURE to identify closure types - // for (let match of contents.matchAll(/Z3_DECLARE_CLOSURE\((?[A-Za-z0-9_]+),/g)) { - // types[match.groups.type] = match.groups.type - // } + // we don't have to pre-populate the types map with closure types + // use the Z3_DECLARE_CLOSURE to identify closure types + // for (let match of contents.matchAll(/Z3_DECLARE_CLOSURE\((?[A-Za-z0-9_]+),/g)) { + // types[match.groups.type] = match.groups.type + // } // parse enum declarations for (let idx = 0; idx < contents.length; ) { From 0b453a4af51434ee31b2114c5c2ec08464f3bfd1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Apr 2022 08:57:32 +0100 Subject: [PATCH 079/253] set release version --- scripts/nightly.yaml | 2 +- scripts/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index fc70b0e85..73a3aaec7 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -2,7 +2,7 @@ variables: Major: '4' Minor: '8' - Patch: '16' + Patch: '17' NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName) stages: diff --git a/scripts/release.yml b/scripts/release.yml index 49624f270..f878265d6 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -6,7 +6,7 @@ trigger: none variables: - ReleaseVersion: '4.8.16' + ReleaseVersion: '4.8.17' stages: From 489459a1f77f47ce8c1e05945ccd7fed9c7a8d98 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Apr 2022 11:22:00 +0100 Subject: [PATCH 080/253] #5778 reprogram flush, mark clauses during reinit as non-redundant. --- src/sat/smt/euf_solver.cpp | 2 +- src/sat/smt/q_ematch.cpp | 67 +++++++++++++++++++++----------------- src/sat/smt/q_ematch.h | 1 + 3 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 2ef77ac6a..12e066437 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -614,7 +614,7 @@ namespace euf { if (si.is_bool_op(e)) lit = literal(replay.m[e], false); else - lit = si.internalize(e, true); + lit = si.internalize(e, false); VERIFY(lit.var() == v); if (!m_egraph.find(e) && (!m.is_iff(e) && !m.is_or(e) && !m.is_and(e) && !m.is_not(e))) { ptr_buffer args; diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 6f646555b..57841fcbc 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -610,42 +610,51 @@ namespace q { return ctx.get_config().m_ematching && propagate(false); } + void ematch::propagate(clause& c, bool flush, bool& propagated) { + ptr_buffer to_remove; + binding* b = c.m_bindings; + if (!b) + return; + + do { + if (propagate(true, b->m_nodes, b->m_max_generation, c, propagated)) + to_remove.push_back(b); + else if (flush) { + instantiate(*b); + to_remove.push_back(b); + propagated = true; + } + b = b->next(); + } + while (b != c.m_bindings); + + for (auto* b : to_remove) { + SASSERT(binding::contains(c.m_bindings, b)); + binding::remove_from(c.m_bindings, b); + binding::detach(b); + ctx.push(insert_binding(ctx, c, b)); + } + } + + bool ematch::propagate(bool flush) { m_mam->propagate(); bool propagated = flush_prop_queue(); if (!flush && m_qhead >= m_clause_queue.size()) return m_inst_queue.propagate() || propagated; - ctx.push(value_trail(m_qhead)); - ptr_buffer to_remove; - unsigned qhead = flush ? 0 : m_qhead; - for (; qhead < m_clause_queue.size() && m.inc(); ++qhead) { - unsigned idx = m_clause_queue[qhead]; - clause& c = *m_clauses[idx]; - binding* b = c.m_bindings; - if (!b) - continue; - do { - if (propagate(true, b->m_nodes, b->m_max_generation, c, propagated)) - to_remove.push_back(b); - else if (flush) { - instantiate(*b); - to_remove.push_back(b); - propagated = true; - } - b = b->next(); - } - while (b != c.m_bindings); - - for (auto* b : to_remove) { - SASSERT(binding::contains(c.m_bindings, b)); - binding::remove_from(c.m_bindings, b); - binding::detach(b); - ctx.push(insert_binding(ctx, c, b)); - } - to_remove.reset(); + if (flush) { + for (auto* c : m_clauses) + propagate(*c, flush, propagated); + } + else { + ctx.push(value_trail(m_qhead)); + for (; m_qhead < m_clause_queue.size() && m.inc(); ++m_qhead) { + unsigned idx = m_clause_queue[m_qhead]; + clause& c = *m_clauses[idx]; + propagate(c, flush, propagated); + } } - m_qhead = std::max(m_qhead, qhead); m_clause_in_queue.reset(); m_node_in_queue.reset(); m_in_queue_set = true; diff --git a/src/sat/smt/q_ematch.h b/src/sat/smt/q_ematch.h index 98ee26fc4..ef933a3a8 100644 --- a/src/sat/smt/q_ematch.h +++ b/src/sat/smt/q_ematch.h @@ -121,6 +121,7 @@ namespace q { void propagate(bool is_conflict, unsigned idx, sat::ext_justification_idx j_idx); bool propagate(bool flush); + void propagate(clause& c, bool flush, bool& propagated); expr_ref_vector m_new_defs; proof_ref_vector m_new_proofs; From 0a665b0fa0b6d6f99607992e7f7bc769dd54fab2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Apr 2022 14:27:38 +0100 Subject: [PATCH 081/253] #5778 --- src/sat/smt/q_ematch.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 57841fcbc..29db324f9 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -640,14 +640,13 @@ namespace q { bool ematch::propagate(bool flush) { m_mam->propagate(); bool propagated = flush_prop_queue(); - if (!flush && m_qhead >= m_clause_queue.size()) - return m_inst_queue.propagate() || propagated; - if (flush) { for (auto* c : m_clauses) propagate(*c, flush, propagated); } else { + if (m_qhead >= m_clause_queue.size()) + return m_inst_queue.propagate() || propagated; ctx.push(value_trail(m_qhead)); for (; m_qhead < m_clause_queue.size() && m.inc(); ++m_qhead) { unsigned idx = m_clause_queue[m_qhead]; From 8e2f09b517ae84b2f70d0e4af74df95c8ecf38b2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Apr 2022 17:17:59 +0100 Subject: [PATCH 082/253] #5778 - ensure arrays used inside of extensionality function are treated as shared Signed-off-by: Nikolaj Bjorner --- src/sat/smt/array_axioms.cpp | 6 +++++- src/smt/theory_array_base.cpp | 36 ++++------------------------------- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index c0f0e9a72..84b12cf7d 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -629,12 +629,14 @@ namespace array { euf::enode * n = var2enode(i); if (!is_array(n)) continue; + CTRACE("array", !ctx.is_relevant(n), tout << "not relevant: " << ctx.bpp(n) << "\n"); if (!ctx.is_relevant(n)) continue; euf::enode * r = n->get_root(); if (r->is_marked1()) continue; - // arrays used as indices in other arrays have to be treated as shared issue #3532, #3529 + // arrays used as indices in other arrays have to be treated as shared issue #3532, #3529 + CTRACE("array", !ctx.is_shared(r) && !is_shared_arg(r), tout << "not shared: " << ctx.bpp(r) << "\n"); if (ctx.is_shared(r) || is_shared_arg(r)) roots.push_back(r->get_th_var(get_id())); r->mark1(); @@ -655,6 +657,8 @@ namespace array { return true; if (a.is_const(e)) return true; + if (a.is_ext(e)) + return true; } return false; diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 9bc0b733f..33944c96c 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -473,39 +473,12 @@ namespace smt { return false; } -#if 0 - void theory_array_base::collect_shared_vars(sbuffer & result) { - TRACE("array_shared", tout << "collecting shared vars...\n";); - ptr_buffer to_unmark; - unsigned num_vars = get_num_vars(); - for (unsigned i = 0; i < num_vars; i++) { - enode * n = get_enode(i); - if (ctx.is_relevant(n) && ctx.is_shared(n)) { - enode * r = n->get_root(); - if (!r->is_marked() && is_array_sort(r)) { - TRACE("array_shared", tout << "new shared var: #" << r->get_expr_id() << "\n";); - r->set_mark(); - to_unmark.push_back(r); - theory_var r_th_var = r->get_var(get_id()); - SASSERT(r_th_var != null_theory_var); - result.push_back(r_th_var); - } - } - } - unmark_enodes(to_unmark.size(), to_unmark.c_ptr()); - } -#else - bool theory_array_base::is_select_arg(enode* r) { - for (enode* n : r->get_parents()) { - if (is_select(n)) { - for (unsigned i = 1; i < n->get_num_args(); ++i) { - if (r == n->get_arg(i)->get_root()) { + for (enode* n : r->get_parents()) + if (is_select(n)) + for (unsigned i = 1; i < n->get_num_args(); ++i) + if (r == n->get_arg(i)->get_root()) return true; - } - } - } - } return false; } @@ -536,7 +509,6 @@ namespace smt { TRACE("array", tout << "collecting shared vars...\n" << unsigned_vector(result.size(), (unsigned*)result.data()) << "\n";); unmark_enodes(to_unmark.size(), to_unmark.data()); } -#endif /** \brief Create interface variables for shared array variables. From 81d97a81af7aeaf1773d5c9569567e8b6dd8549f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Apr 2022 09:58:38 +0100 Subject: [PATCH 083/253] enable nested ADT and sequences add API to define forward reference to recursively defined datatype. The forward reference should be used only when passed to constructor declarations that are used in a datatype definition (Z3_mk_datatypes). The call to Z3_mk_datatypes ensures that the forward reference can be resolved with respect to constructors. --- src/api/api_datatype.cpp | 14 ++++ src/api/z3_api.h | 13 ++++ src/ast/datatype_decl_plugin.cpp | 65 +++++++++++------- src/ast/datatype_decl_plugin.h | 10 +-- src/cmd_context/pdecl.cpp | 16 ++--- src/model/datatype_factory.cpp | 2 +- src/sat/smt/dt_solver.cpp | 80 +++++++++++++++++----- src/sat/smt/dt_solver.h | 5 +- src/smt/theory_datatype.cpp | 114 ++++++++++++++++++++++--------- src/smt/theory_datatype.h | 5 +- 10 files changed, 232 insertions(+), 92 deletions(-) diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 673ceb3c1..23ff21575 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -365,6 +365,20 @@ extern "C" { Z3_CATCH; } + Z3_sort Z3_API Z3_mk_datatype_sort(Z3_context c, Z3_symbol name) { + Z3_TRY; + LOG_Z3_mk_datatype_sort(c, name); + RESET_ERROR_CODE(); + ast_manager& m = mk_c(c)->m(); + datatype_util data_util(m); + parameter param(name); + sort * s = m.mk_sort(util.get_family_id(), DATATYPE_SORT, 1, ¶m); + mk_c(c)->save_ast_trail(s); + RETURN_Z3(of_sort(s)); + Z3_CATCH_RETURN(nullptr); + } + + void Z3_API Z3_mk_datatypes(Z3_context c, unsigned num_sorts, Z3_symbol const sort_names[], diff --git a/src/api/z3_api.h b/src/api/z3_api.h index a9e0c6b7c..7ca693984 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -2094,6 +2094,19 @@ extern "C" { unsigned num_constructors, Z3_constructor constructors[]); + /** + \brief create a forward reference to a recursive datatype being declared. + The forward reference can be used in a nested occurrence: the range of an array + or as element sort of a sequence. The forward reference should only be used when + used in an accessor for a recursive datatype that gets declared. + + Forward references can replace the use sort references, that are unsigned integers + in the \c Z3_mk_constructor call + + def_API('Z3_mk_datatype_sort', SORT, (_in(CONTEXT), _in(SYMBOL))) + */ + Z3_sort Z3_API Z3_mk_datatype_sort(Z3_context c, Z3_symbol name); + /** \brief Create list of constructors. diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index bc574fc1c..11c33d695 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -19,6 +19,7 @@ Revision History: #include "util/warning.h" #include "ast/array_decl_plugin.h" +#include "ast/seq_decl_plugin.h" #include "ast/datatype_decl_plugin.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_pp.h" @@ -462,28 +463,27 @@ namespace datatype { } for (symbol const& s : m_def_block) { def& d = *m_defs[s]; - for (constructor* c : d) { - for (accessor* a : *c) { + for (constructor* c : d) + for (accessor* a : *c) a->fix_range(sorts); - } - } } - if (!u().is_well_founded(sorts.size(), sorts.data())) { + if (!u().is_well_founded(sorts.size(), sorts.data())) m_manager->raise_exception("datatype is not well-founded"); - } - if (!u().is_covariant(sorts.size(), sorts.data())) { + if (!u().is_covariant(sorts.size(), sorts.data())) m_manager->raise_exception("datatype is not co-variant"); - } - + array_util autil(m); + seq_util sutil(m); + sort* sr; for (sort* s : sorts) { for (constructor const* c : get_def(s)) { for (accessor const* a : *c) { - if (autil.is_array(a->range())) { - if (sorts.contains(get_array_range(a->range()))) { - m_has_nested_arrays = true; - } - } + if (autil.is_array(a->range()) && sorts.contains(get_array_range(a->range()))) + m_has_nested_rec = true; + else if (sutil.is_seq(a->range(), sr) && sorts.contains(sr)) + m_has_nested_rec = true; + else if (sutil.is_re(a->range(), sr) && sorts.contains(sr)) + m_has_nested_rec = true; } } } @@ -1103,12 +1103,19 @@ namespace datatype { return r; } - bool util::is_recursive_array(sort* a) { + bool util::is_recursive_nested(sort* a) { array_util autil(m); - if (!autil.is_array(a)) - return false; - a = autil.get_array_range_rec(a); - return is_datatype(a) && is_recursive(a); + seq_util sutil(m); + sort* sr; + if (autil.is_array(a)) { + a = autil.get_array_range_rec(a); + return is_datatype(a) && is_recursive(a); + } + if (sutil.is_seq(a, sr)) + return is_datatype(sr) && is_recursive(sr); + if (sutil.is_re(a, sr)) + return is_datatype(sr) && is_recursive(sr); + return false; } bool util::is_enum_sort(sort* s) { @@ -1273,14 +1280,22 @@ namespace datatype { */ bool util::are_siblings(sort * s1, sort * s2) { array_util autil(m); - s1 = autil.get_array_range_rec(s1); - s2 = autil.get_array_range_rec(s2); - if (!is_datatype(s1) || !is_datatype(s2)) { + seq_util sutil(m); + auto get_nested = [&](sort* s) { + while (true) { + if (autil.is_array(s)) + s = get_array_range(s); + else if (!sutil.is_seq(s, s)) + break; + } + return s; + }; + s1 = get_nested(s1); + s2 = get_nested(s2); + if (!is_datatype(s1) || !is_datatype(s2)) return s1 == s2; - } - else { + else return get_def(s1).id() == get_def(s2).id(); - } } unsigned util::get_datatype_num_constructors(sort * ty) { diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 0172d0b1d..0698bf821 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -207,14 +207,14 @@ namespace datatype { unsigned m_id_counter; svector m_def_block; unsigned m_class_id; - mutable bool m_has_nested_arrays; + mutable bool m_has_nested_rec; void inherit(decl_plugin* other_p, ast_translation& tr) override; void log_axiom_definitions(symbol const& s, sort * new_sort); public: - plugin(): m_id_counter(0), m_class_id(0), m_has_nested_arrays(false) {} + plugin(): m_id_counter(0), m_class_id(0), m_has_nested_rec(false) {} ~plugin() override; void finalize() override; @@ -254,7 +254,7 @@ namespace datatype { unsigned get_axiom_base_id(symbol const& s) { return m_axiom_bases[s]; } util & u() const; - bool has_nested_arrays() const { return m_has_nested_arrays; } + bool has_nested_rec() const { return m_has_nested_rec; } private: bool is_value_visit(bool unique, expr * arg, ptr_buffer & todo) const; @@ -334,7 +334,7 @@ namespace datatype { bool is_datatype(sort const* s) const { return is_sort_of(s, fid(), DATATYPE_SORT); } bool is_enum_sort(sort* s); bool is_recursive(sort * ty); - bool is_recursive_array(sort * ty); + bool is_recursive_nested(sort * ty); bool is_constructor(func_decl * f) const { return is_decl_of(f, fid(), OP_DT_CONSTRUCTOR); } bool is_recognizer(func_decl * f) const { return is_recognizer0(f) || is_is(f); } bool is_recognizer0(func_decl * f) const { return is_decl_of(f, fid(), OP_DT_RECOGNISER); } @@ -365,7 +365,7 @@ namespace datatype { func_decl * get_accessor_constructor(func_decl * accessor); func_decl * get_recognizer_constructor(func_decl * recognizer) const; func_decl * get_update_accessor(func_decl * update) const; - bool has_nested_arrays() const { return plugin().has_nested_arrays(); } + bool has_nested_rec() const { return plugin().has_nested_rec(); } family_id get_family_id() const { return fid(); } decl::plugin& plugin() const; bool are_siblings(sort * s1, sort * s2); diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 2bf21de3a..1545487c7 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -493,18 +493,16 @@ void pconstructor_decl::finalize(pdecl_manager & m) { } bool pconstructor_decl::has_missing_refs(symbol & missing) const { - for (paccessor_decl* a : m_accessors) { + for (paccessor_decl* a : m_accessors) if (a->has_missing_refs(missing)) return true; - } return false; } bool pconstructor_decl::fix_missing_refs(dictionary const & symbol2idx, symbol & missing) { - for (paccessor_decl* a : m_accessors) { + for (paccessor_decl* a : m_accessors) if (!a->fix_missing_refs(symbol2idx, missing)) return false; - } return true; } @@ -561,18 +559,16 @@ bool pdatatype_decl::has_duplicate_accessors(symbol & duplicated) const { bool pdatatype_decl::fix_missing_refs(dictionary const & symbol2idx, symbol & missing) { - for (auto c : m_constructors) { + for (auto c : m_constructors) if (!c->fix_missing_refs(symbol2idx, missing)) return false; - } return true; } datatype_decl * pdatatype_decl::instantiate_decl(pdecl_manager & m, unsigned n, sort * const * s) { ptr_buffer cs; - for (auto c : m_constructors) { + for (auto c : m_constructors) cs.push_back(c->instantiate_decl(m, n, s)); - } datatype_util util(m.m()); return mk_datatype_decl(util, m_name, m_num_params, s, cs.size(), cs.data()); } @@ -647,10 +643,8 @@ bool pdatatype_decl::commit(pdecl_manager& m) { sort_ref_vector sorts(m.m()); bool is_ok = m.get_dt_plugin()->mk_datatypes(1, &d_ptr, m_num_params, ps.data(), sorts); m.notify_mk_datatype(m_name); - if (is_ok && m_num_params == 0) { + if (is_ok && m_num_params == 0) m.notify_new_dt(sorts.get(0), this); - } - return is_ok; } diff --git a/src/model/datatype_factory.cpp b/src/model/datatype_factory.cpp index e58812a1f..56312839a 100644 --- a/src/model/datatype_factory.cpp +++ b/src/model/datatype_factory.cpp @@ -166,7 +166,7 @@ expr * datatype_factory::get_fresh_value(sort * s) { for (unsigned i = 0; i < num; i++) { sort * s_arg = constructor->get_domain(i); if (!found_fresh_arg && - !m_util.is_recursive_array(s_arg) && + !m_util.is_recursive_nested(s_arg) && (!m_util.is_recursive(s) || !m_util.is_datatype(s_arg) || !m_util.are_siblings(s, s_arg))) { expr * new_arg = m_model.get_fresh_value(s_arg); if (new_arg != nullptr) { diff --git a/src/sat/smt/dt_solver.cpp b/src/sat/smt/dt_solver.cpp index 76c154a4a..13d9768e2 100644 --- a/src/sat/smt/dt_solver.cpp +++ b/src/sat/smt/dt_solver.cpp @@ -29,6 +29,7 @@ namespace dt { th_euf_solver(ctx, ctx.get_manager().get_family_name(id), id), dt(m), m_autil(m), + m_sutil(m), m_find(*this), m_args(m) {} @@ -496,13 +497,41 @@ namespace dt { } ptr_vector const& solver::get_array_args(enode* n) { - m_array_args.reset(); + m_nodes.reset(); array::solver* th = dynamic_cast(ctx.fid2solver(m_autil.get_family_id())); for (enode* p : th->parent_selects(n)) - m_array_args.push_back(p); + m_nodes.push_back(p); app_ref def(m_autil.mk_default(n->get_expr()), m); - m_array_args.push_back(ctx.get_enode(def)); - return m_array_args; + m_nodes.push_back(ctx.get_enode(def)); + return m_nodes; + } + + ptr_vector const& solver::get_seq_args(enode* n) { + m_nodes.reset(); + m_todo.reset(); + auto add_todo = [&](enode* n) { + if (!n->is_marked1()) { + n->mark1(); + m_todo.push_back(n); + } + }; + + for (enode* sib : euf::enode_class(n)) + add_todo(sib); + + for (unsigned i = 0; i < m_todo.size(); ++i) { + enode* n = m_todo[i]; + expr* e = n->get_expr(); + if (m_sutil.str.is_unit(e)) + m_nodes.push_back(n->get_arg(0)); + else if (m_sutil.str.is_concat(e)) + for (expr* arg : *to_app(e)) + add_todo(ctx.get_enode(arg)); + } + for (enode* n : m_todo) + n->unmark1(); + + return m_nodes; } // Assuming `app` is equal to a constructor term, return the constructor enode @@ -536,6 +565,12 @@ namespace dt { for (enode* aarg : get_array_args(arg)) add(aarg); } + sort* se; + if (m_sutil.is_seq(child->get_sort(), se) && dt.is_datatype(se)) { + for (enode* aarg : get_seq_args(child)) + add(aarg); + } + VERIFY(found); } @@ -575,6 +610,21 @@ namespace dt { return false; enode* parent = d->m_constructor; oc_mark_on_stack(parent); + + auto process_arg = [&](enode* aarg) { + if (oc_cycle_free(aarg)) + return false; + if (oc_on_stack(aarg)) { + occurs_check_explain(parent, aarg); + return true; + } + if (dt.is_datatype(aarg->get_sort())) { + m_parent.insert(aarg->get_root(), parent); + oc_push_stack(aarg); + } + return false; + }; + for (enode* arg : euf::enode_args(parent)) { if (oc_cycle_free(arg)) continue; @@ -585,24 +635,20 @@ namespace dt { } // explore `arg` (with parent) expr* earg = arg->get_expr(); - sort* s = earg->get_sort(); + sort* s = earg->get_sort(), *se; if (dt.is_datatype(s)) { m_parent.insert(arg->get_root(), parent); oc_push_stack(arg); } - else if (m_autil.is_array(s) && dt.is_datatype(get_array_range(s))) { - for (enode* aarg : get_array_args(arg)) { - if (oc_cycle_free(aarg)) - continue; - if (oc_on_stack(aarg)) { - occurs_check_explain(parent, aarg); + else if (m_sutil.is_seq(s, se) && dt.is_datatype(se)) { + for (enode* sarg : get_seq_args(arg)) + if (process_arg(sarg)) + return true; + } + else if (m_autil.is_array(s) && dt.is_datatype(get_array_range(s))) { + for (enode* sarg : get_array_args(arg)) + if (process_arg(sarg)) return true; - } - if (is_datatype(aarg)) { - m_parent.insert(aarg->get_root(), parent); - oc_push_stack(aarg); - } - } } } return false; diff --git a/src/sat/smt/dt_solver.h b/src/sat/smt/dt_solver.h index cd5529075..e0a076a2d 100644 --- a/src/sat/smt/dt_solver.h +++ b/src/sat/smt/dt_solver.h @@ -19,6 +19,7 @@ Author: #include "sat/smt/sat_th.h" #include "ast/datatype_decl_plugin.h" #include "ast/array_decl_plugin.h" +#include "ast/seq_decl_plugin.h" namespace euf { class solver; @@ -62,6 +63,7 @@ namespace dt { mutable datatype_util dt; array_util m_autil; + seq_util m_sutil; stats m_stats; ptr_vector m_var_data; dt_union_find m_find; @@ -108,8 +110,9 @@ namespace dt { bool oc_cycle_free(enode * n) const { return n->get_root()->is_marked2(); } void oc_push_stack(enode * n); - ptr_vector m_array_args; + ptr_vector m_nodes, m_todo; ptr_vector const& get_array_args(enode* n); + ptr_vector const& get_seq_args(enode* n); void pop_core(unsigned n) override; diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 035b647dc..27b922dba 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -275,7 +275,7 @@ namespace smt { else if (is_update_field(n)) { assert_update_field_axioms(n); } - else { + else if (m_util.is_datatype(n->get_sort())) { sort * s = n->get_sort(); if (m_util.get_datatype_num_constructors(s) == 1) { func_decl * c = m_util.get_datatype_constructors(s)->get(0); @@ -343,7 +343,7 @@ namespace smt { } arg = ctx.get_enode(def); } - if (!m_util.is_datatype(s)) + if (!m_util.is_datatype(s) && !m_sutil.is_seq(s)) continue; if (is_attached_to_var(arg)) continue; @@ -393,7 +393,7 @@ namespace smt { if (!is_attached_to_var(n) && (ctx.has_quantifiers() || - (m_util.is_datatype(s) && m_util.has_nested_arrays()) || + (m_util.is_datatype(s) && m_util.has_nested_rec()) || (m_util.is_datatype(s) && !s->is_infinite()))) { mk_var(n); } @@ -485,7 +485,10 @@ namespace smt { for (int v = 0; v < num_vars; v++) { if (v == static_cast(m_find.find(v))) { enode * node = get_enode(v); - if (m_util.is_recursive(node->get_sort()) && !oc_cycle_free(node) && occurs_check(node)) { + sort* s = node->get_sort(); + if (!m_util.is_datatype(s)) + continue; + if (m_util.is_recursive(s) && !oc_cycle_free(node) && occurs_check(node)) { // conflict was detected... // return... return FC_CONTINUE; @@ -541,6 +544,17 @@ namespace smt { } } } + sort* se = nullptr; + if (m_sutil.is_seq(s, se) && m_util.is_datatype(se)) { + for (enode* aarg : get_seq_args(arg)) { + if (aarg->get_root() == child->get_root()) { + if (aarg != child) { + m_used_eqs.push_back(enode_pair(aarg, child)); + } + found = true; + } + } + } } VERIFY(found); } @@ -587,6 +601,20 @@ namespace smt { } enode * parent = d->m_constructor; oc_mark_on_stack(parent); + auto process_arg = [&](enode* aarg) { + if (oc_cycle_free(aarg)) + return false; + if (oc_on_stack(aarg)) { + occurs_check_explain(parent, aarg); + return true; + } + if (m_util.is_datatype(aarg->get_sort())) { + m_parent.insert(aarg->get_root(), parent); + oc_push_stack(aarg); + } + return false; + }; + for (enode * arg : enode::args(parent)) { if (oc_cycle_free(arg)) { continue; @@ -598,39 +626,61 @@ namespace smt { } // explore `arg` (with parent) expr* earg = arg->get_expr(); - sort* s = earg->get_sort(); + sort* s = earg->get_sort(), *se = nullptr; if (m_util.is_datatype(s)) { m_parent.insert(arg->get_root(), parent); oc_push_stack(arg); } - else if (m_autil.is_array(s) && m_util.is_datatype(get_array_range(s))) { - for (enode* aarg : get_array_args(arg)) { - if (oc_cycle_free(aarg)) { - continue; - } - if (oc_on_stack(aarg)) { - occurs_check_explain(parent, aarg); + else if (m_sutil.is_seq(s, se) && m_util.is_datatype(se)) { + for (enode* sarg : get_seq_args(arg)) + if (process_arg(sarg)) return true; - } - if (m_util.is_datatype(aarg->get_sort())) { - m_parent.insert(aarg->get_root(), parent); - oc_push_stack(aarg); - } - } - } + } + else if (m_autil.is_array(s) && m_util.is_datatype(get_array_range(s))) { + for (enode* aarg : get_array_args(arg)) + if (process_arg(aarg)) + return true; + } } return false; } - ptr_vector const& theory_datatype::get_array_args(enode* n) { - m_array_args.reset(); - theory_array* th = dynamic_cast(ctx.get_theory(m_autil.get_family_id())); - for (enode* p : th->parent_selects(n)) { - m_array_args.push_back(p); + ptr_vector const& theory_datatype::get_seq_args(enode* n) { + m_args.reset(); + m_todo.reset(); + auto add_todo = [&](enode* n) { + if (!n->is_marked()) { + n->set_mark(); + m_todo.push_back(n); + } + }; + + for (enode* sib : *n) + add_todo(sib); + + for (unsigned i = 0; i < m_todo.size(); ++i) { + enode* n = m_todo[i]; + expr* e = n->get_expr(); + if (m_sutil.str.is_unit(e)) + m_args.push_back(n->get_arg(0)); + else if (m_sutil.str.is_concat(e)) + for (expr* arg : *to_app(e)) + add_todo(ctx.get_enode(arg)); } + for (enode* n : m_todo) + n->unset_mark(); + + return m_args; + } + + ptr_vector const& theory_datatype::get_array_args(enode* n) { + m_args.reset(); + theory_array* th = dynamic_cast(ctx.get_theory(m_autil.get_family_id())); + for (enode* p : th->parent_selects(n)) + m_args.push_back(p); app_ref def(m_autil.mk_default(n->get_expr()), m); - m_array_args.push_back(ctx.get_enode(def)); - return m_array_args; + m_args.push_back(ctx.get_enode(def)); + return m_args; } /** @@ -653,18 +703,19 @@ namespace smt { enode * app = m_stack.back().second; m_stack.pop_back(); - if (oc_cycle_free(app)) continue; + if (oc_cycle_free(app)) + continue; TRACE("datatype", tout << "occurs check loop: " << enode_pp(app, ctx) << (op==ENTER?" enter":" exit")<< "\n";); switch (op) { case ENTER: - res = occurs_check_enter(app); - break; + res = occurs_check_enter(app); + break; case EXIT: - oc_mark_cycle_free(app); - break; + oc_mark_cycle_free(app); + break; } } @@ -702,6 +753,7 @@ namespace smt { theory(ctx, ctx.get_manager().mk_family_id("datatype")), m_util(m), m_autil(m), + m_sutil(m), m_find(*this), m_trail_stack() { } diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index d219b1f9d..c0e06b58d 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -20,6 +20,7 @@ Revision History: #include "util/union_find.h" #include "ast/array_decl_plugin.h" +#include "ast/seq_decl_plugin.h" #include "ast/datatype_decl_plugin.h" #include "model/datatype_factory.h" #include "smt/smt_theory.h" @@ -46,6 +47,7 @@ namespace smt { datatype_util m_util; array_util m_autil; + seq_util m_sutil; ptr_vector m_var_data; th_union_find m_find; trail_stack m_trail_stack; @@ -90,8 +92,9 @@ namespace smt { bool oc_cycle_free(enode * n) const { return n->get_root()->is_marked2(); } void oc_push_stack(enode * n); - ptr_vector m_array_args; + ptr_vector m_args, m_todo; ptr_vector const& get_array_args(enode* n); + ptr_vector const& get_seq_args(enode* n); // class for managing state of final_check class final_check_st { From 02d6f6a613bbd5dd7b53d77672ca1c756c21b96e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Apr 2022 10:01:51 +0100 Subject: [PATCH 084/253] fix build for Z3_mk_datatype_sort Signed-off-by: Nikolaj Bjorner --- src/api/api_datatype.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 23ff21575..f1c65b626 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -370,9 +370,9 @@ extern "C" { LOG_Z3_mk_datatype_sort(c, name); RESET_ERROR_CODE(); ast_manager& m = mk_c(c)->m(); - datatype_util data_util(m); - parameter param(name); - sort * s = m.mk_sort(util.get_family_id(), DATATYPE_SORT, 1, ¶m); + datatype_util adt_util(m); + parameter p(to_symbol(name)); + sort * s = m.mk_sort(adt_util.get_family_id(), DATATYPE_SORT, 1, &p); mk_c(c)->save_ast_trail(s); RETURN_Z3(of_sort(s)); Z3_CATCH_RETURN(nullptr); From 99e299b90c474613f083dd6d393ac7129f8a2f95 Mon Sep 17 00:00:00 2001 From: Ryan Goulden Date: Wed, 27 Apr 2022 03:36:09 -0700 Subject: [PATCH 085/253] ocaml: fix is_arithmetic_numeral and is_bv_numeral (#6003) --- src/api/ml/z3.ml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index b904937a9..b551688c5 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -119,6 +119,7 @@ sig val get_ast_kind : ast -> Z3enums.ast_kind val is_expr : ast -> bool val is_app : ast -> bool + val is_numeral : ast -> bool val is_var : ast -> bool val is_quantifier : ast -> bool val is_sort : ast -> bool @@ -191,6 +192,7 @@ end = struct | _ -> false let is_app (x:ast) = get_ast_kind x = APP_AST + let is_numeral (x:ast) = get_ast_kind x = NUMERAL_AST let is_var (x:ast) = get_ast_kind x = VAR_AST let is_quantifier (x:ast) = get_ast_kind x = QUANTIFIER_AST let is_sort (x:ast) = get_ast_kind x = SORT_AST @@ -1018,7 +1020,7 @@ struct let is_int (x:expr) = ((sort_kind_of_int (Z3native.get_sort_kind (Expr.gc x) (Z3native.get_sort (Expr.gc x) x))) = INT_SORT) - let is_arithmetic_numeral (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_ANUM) + let is_arithmetic_numeral (x:expr) = (AST.is_numeral x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_ANUM) let is_le (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_LE) let is_ge (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_GE) let is_lt (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_LT) @@ -1129,7 +1131,7 @@ struct let mk_sort (ctx:context) size = Z3native.mk_bv_sort ctx size let is_bv (x:expr) = ((sort_kind_of_int (Z3native.get_sort_kind (Expr.gc x) (Z3native.get_sort (Expr.gc x) x))) = BV_SORT) - let is_bv_numeral (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BNUM) + let is_bv_numeral (x:expr) = (AST.is_numeral x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BNUM) let is_bv_bit1 (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BIT1) let is_bv_bit0 (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BIT0) let is_bv_uminus (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_BNEG) From 5a9b0dd747a2fc26513fcb15181678781e6667a7 Mon Sep 17 00:00:00 2001 From: JohnLyu2 <65240623+JohnLyu2@users.noreply.github.com> Date: Wed, 27 Apr 2022 06:37:07 -0400 Subject: [PATCH 086/253] Z3str3 Debug (#6000) * z3str3 debug * add comments of reference to bugs in the report Co-authored-by: John Lu --- src/smt/theory_str.cpp | 147 +++++++++++++++++++++++++++-------------- src/smt/theory_str.h | 5 +- 2 files changed, 101 insertions(+), 51 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 0b772f17d..8bd6c49aa 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -201,7 +201,7 @@ namespace smt { } void theory_str::assert_axiom(expr * _e) { - if (_e == nullptr) + if (_e == nullptr) return; if (opt_VerifyFinalCheckProgress) { finalCheckProgressIndicator = true; @@ -1100,9 +1100,10 @@ namespace smt { TRACE("str", tout << "instantiate CharAt axiom for " << mk_pp(expr, m) << std::endl;); - expr_ref ts0(mk_str_var("ts0"), m); - expr_ref ts1(mk_str_var("ts1"), m); - expr_ref ts2(mk_str_var("ts2"), m); + // change subvaribale names to solve some invalide model problems + expr_ref ts0(mk_str_var("ch_ts0"), m); + expr_ref ts1(mk_str_var("ch_ts1"), m); + expr_ref ts2(mk_str_var("ch_ts2"), m); expr_ref cond(m.mk_and( m_autil.mk_ge(arg1, mk_int(0)), @@ -1134,8 +1135,9 @@ namespace smt { TRACE("str", tout << "instantiate prefixof axiom for " << mk_pp(expr, m) << std::endl;); - expr_ref ts0(mk_str_var("ts0"), m); - expr_ref ts1(mk_str_var("ts1"), m); + // change subvaribale names to solve some invalide model problems + expr_ref ts0(mk_str_var("p_ts0"), m); + expr_ref ts1(mk_str_var("p_ts1"), m); expr_ref_vector innerItems(m); innerItems.push_back(ctx.mk_eq_atom(expr->get_arg(1), mk_concat(ts0, ts1))); @@ -1170,8 +1172,9 @@ namespace smt { TRACE("str", tout << "instantiate suffixof axiom for " << mk_pp(expr, m) << std::endl;); - expr_ref ts0(mk_str_var("ts0"), m); - expr_ref ts1(mk_str_var("ts1"), m); + // change subvaribale names to solve some invalide model problems + expr_ref ts0(mk_str_var("s_ts0"), m); + expr_ref ts1(mk_str_var("s_ts1"), m); expr_ref_vector innerItems(m); innerItems.push_back(ctx.mk_eq_atom(expr->get_arg(1), mk_concat(ts0, ts1))); @@ -1235,8 +1238,9 @@ namespace smt { TRACE("str", tout << "instantiate Contains axiom for " << mk_pp(ex, m) << std::endl;); - expr_ref ts0(mk_str_var("ts0"), m); - expr_ref ts1(mk_str_var("ts1"), m); + // change subvaribale names to solve some invalide model problems + expr_ref ts0(mk_str_var("c_ts0"), m); + expr_ref ts1(mk_str_var("c_ts1"), m); expr_ref breakdownAssert(ctx.mk_eq_atom(ex, ctx.mk_eq_atom(ex->get_arg(0), mk_concat(ts0, mk_concat(ex->get_arg(1), ts1)))), m); SASSERT(breakdownAssert); @@ -1287,8 +1291,9 @@ namespace smt { TRACE("str", tout << "instantiate str.indexof axiom for " << mk_pp(ex, m) << std::endl;); - expr_ref x1(mk_str_var("x1"), m); - expr_ref x2(mk_str_var("x2"), m); + // change subvaribale names to solve some invalide model problems + expr_ref x1(mk_str_var("i_x1"), m); + expr_ref x2(mk_str_var("i_x2"), m); expr_ref condAst1(mk_contains(exHaystack, exNeedle), m); expr_ref condAst2(m.mk_not(ctx.mk_eq_atom(exNeedle, mk_string(""))), m); @@ -1305,8 +1310,9 @@ namespace smt { // args[0] = x3 . x4 // /\ |x3| = |x1| + |args[1]| - 1 // /\ ! contains(x3, args[1]) - expr_ref x3(mk_str_var("x3"), m); - expr_ref x4(mk_str_var("x4"), m); + // change subvaribale names to solve some invalide model problems + expr_ref x3(mk_str_var("i_x3"), m); + expr_ref x4(mk_str_var("i_x4"), m); expr_ref tmpLen(m_autil.mk_add(ex, mk_strlen(ex->get_arg(1)), mk_int(-1)), m); SASSERT(tmpLen); thenItems.push_back(ctx.mk_eq_atom(exHaystack, mk_concat(x3, x4))); @@ -1501,8 +1507,9 @@ namespace smt { TRACE("str", tout << "instantiate LastIndexof axiom for " << mk_pp(expr, m) << std::endl;); - expr_ref x1(mk_str_var("x1"), m); - expr_ref x2(mk_str_var("x2"), m); + // change subvaribale names to solve some invalide model problems + expr_ref x1(mk_str_var("li_x1"), m); + expr_ref x2(mk_str_var("li_x2"), m); expr_ref indexAst(mk_int_var("index"), m); expr_ref_vector items(m); @@ -1532,8 +1539,9 @@ namespace smt { if (!canSkip) { // args[0] = x3 . x4 /\ |x3| = |x1| + 1 /\ ! contains(x4, args[1]) - expr_ref x3(mk_str_var("x3"), m); - expr_ref x4(mk_str_var("x4"), m); + // change subvaribale names to solve some invalide model problems + expr_ref x3(mk_str_var("li_x3"), m); + expr_ref x4(mk_str_var("li_x4"), m); expr_ref tmpLen(m_autil.mk_add(indexAst, mk_int(1)), m); thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); @@ -1690,10 +1698,11 @@ namespace smt { TRACE("str", tout << "instantiate Replace axiom for " << mk_pp(ex, m) << std::endl;); - expr_ref x1(mk_str_var("x1"), m); - expr_ref x2(mk_str_var("x2"), m); + // change subvaribale names to solve some invalide model problems + expr_ref x1(mk_str_var("rp_x1"), m); + expr_ref x2(mk_str_var("rp_x2"), m); expr_ref i1(mk_int_var("i1"), m); - expr_ref result(mk_str_var("result"), m); + expr_ref result(mk_str_var("rp_result"), m); expr * replaceS = nullptr; expr * replaceT = nullptr; @@ -1714,8 +1723,9 @@ namespace smt { // i1 = |x1| thenItems.push_back(ctx.mk_eq_atom(i1, mk_strlen(x1))); // args[0] = x3 . x4 /\ |x3| = |x1| + |args[1]| - 1 /\ ! contains(x3, args[1]) - expr_ref x3(mk_str_var("x3"), m); - expr_ref x4(mk_str_var("x4"), m); + // change subvaribale names to solve some invalide model problems + expr_ref x3(mk_str_var("rp_x3"), m); + expr_ref x4(mk_str_var("rp_x4"), m); expr_ref tmpLen(m_autil.mk_add(i1, mk_strlen(ex->get_arg(1)), mk_int(-1)), m); thenItems.push_back(ctx.mk_eq_atom(ex->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); @@ -1812,7 +1822,7 @@ namespace smt { expr_ref zero(mk_string("0"), m); // let (the result starts with a "0") be p expr_ref starts_with_zero(u.str.mk_prefix(zero, ex), m); - // let (the result is "0") be q + // let (the result is "0") be q expr_ref is_zero(ctx.mk_eq_atom(ex, zero), m); // encoding: the result does NOT start with a "0" (~p) xor the result is "0" (q) // ~p xor q == (~p or q) and (p or ~q) @@ -1847,7 +1857,7 @@ namespace smt { expr_ref axiom(ctx.mk_eq_atom(ex, rhs), m); assert_axiom_rw(axiom); } - + void theory_str::instantiate_axiom_str_from_code(enode * e) { ast_manager & m = get_manager(); @@ -3245,7 +3255,11 @@ namespace smt { if (!overlapAssumptionUsed) { overlapAssumptionUsed = true; - assert_implication(ax_l, m_theoryStrOverlapAssumption_term); + // add context dependent formula overlap predicate and relate it to the global overlap predicate + sort * s = get_manager().mk_bool_sort(); + expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager()); + assert_implication(ax_l, new_OverlapAssumption_term); + assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term); } } } else if (splitType == 1) { @@ -3303,7 +3317,11 @@ namespace smt { if (!overlapAssumptionUsed) { overlapAssumptionUsed = true; - assert_implication(ax_l, m_theoryStrOverlapAssumption_term); + // add context dependent formula overlap predicate and relate it to the global overlap predicate + sort * s = get_manager().mk_bool_sort(); + expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager()); + assert_implication(ax_l, new_OverlapAssumption_term); + assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term); } } @@ -3355,7 +3373,11 @@ namespace smt { if (!overlapAssumptionUsed) { overlapAssumptionUsed = true; - arrangement_disjunction.push_back(m_theoryStrOverlapAssumption_term); + // add context dependent formula overlap predicate and relate it to the global overlap predicate + sort * s = get_manager().mk_bool_sort(); + expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager()); + arrangement_disjunction.push_back(new_OverlapAssumption_term); + assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term); } } @@ -3400,7 +3422,11 @@ namespace smt { if (!overlapAssumptionUsed) { overlapAssumptionUsed = true; - arrangement_disjunction.push_back(m_theoryStrOverlapAssumption_term); + // add context dependent formula overlap predicate and relate it to the global overlap predicate + sort * s = get_manager().mk_bool_sort(); + expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager()); + arrangement_disjunction.push_back(new_OverlapAssumption_term); + assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term); } } @@ -3641,7 +3667,11 @@ namespace smt { if (!overlapAssumptionUsed) { overlapAssumptionUsed = true; - assert_implication(ax_l, m_theoryStrOverlapAssumption_term); + // add context dependent formula overlap predicate and relate it to the global overlap predicate + sort * s = get_manager().mk_bool_sort(); + expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager()); + assert_implication(ax_l, new_OverlapAssumption_term); + assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term); } } @@ -3742,7 +3772,11 @@ namespace smt { if (!overlapAssumptionUsed) { overlapAssumptionUsed = true; - arrangement_disjunction.push_back(m_theoryStrOverlapAssumption_term); + // add context dependent formula overlap predicate and relate it to the global overlap predicate + sort * s = get_manager().mk_bool_sort(); + expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager()); + arrangement_disjunction.push_back(new_OverlapAssumption_term); + assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term); } } } @@ -4037,7 +4071,11 @@ namespace smt { if (!overlapAssumptionUsed) { overlapAssumptionUsed = true; - assert_implication(ax_l, m_theoryStrOverlapAssumption_term); + // add context dependent formula overlap predicate and relate it to the global overlap predicate + sort * s = get_manager().mk_bool_sort(); + expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager()); + assert_implication(ax_l, new_OverlapAssumption_term); + assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term); } } } @@ -4116,7 +4154,11 @@ namespace smt { if (!overlapAssumptionUsed) { overlapAssumptionUsed = true; - arrangement_disjunction.push_back(m_theoryStrOverlapAssumption_term); + // add context dependent formula overlap predicate and relate it to the global overlap predicate + sort * s = get_manager().mk_bool_sort(); + expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager()); + arrangement_disjunction.push_back(new_OverlapAssumption_term); + assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term); } } } @@ -4513,7 +4555,11 @@ namespace smt { // only add the overlap assumption one time if (!overlapAssumptionUsed) { - arrangement_disjunction.push_back(m_theoryStrOverlapAssumption_term); + // add context dependent formula overlap predicate and relate it to the global overlap predicate + sort * s = get_manager().mk_bool_sort(); + expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager()); + arrangement_disjunction.push_back(new_OverlapAssumption_term); + assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term); overlapAssumptionUsed = true; } @@ -4577,7 +4623,7 @@ namespace smt { u.str.is_string(strExpr, stringVal); return true; } - + /* * Look through the equivalence class of n to find a string constant. * Return that constant if it is found, and set hasEqcValue to true. @@ -4604,7 +4650,7 @@ namespace smt { return a; } curr = m_find.next(curr); - } + } while (curr != first && curr != null_theory_var); } hasEqcValue = false; @@ -4781,10 +4827,13 @@ namespace smt { //} else if (getNodeType(t, node) == my_Z3_Func) { } else if (is_app(node)) { app * func_app = to_app(node); - unsigned int argCount = func_app->get_num_args(); - for (unsigned int i = 0; i < argCount; i++) { - expr * argAst = func_app->get_arg(i); - get_const_str_asts_in_node(argAst, astList); + // the following check is only valid when the operator is string concatenate + if (u.str.is_concat(func_app)) { + unsigned int argCount = func_app->get_num_args(); + for (unsigned int i = 0; i < argCount; i++) { + expr * argAst = func_app->get_arg(i); + get_const_str_asts_in_node(argAst, astList); + } } } } @@ -6885,7 +6934,7 @@ namespace smt { } // heuristics - + if (u.str.is_prefix(e)) { check_consistency_prefix(e, is_true); } else if (u.str.is_suffix(e)) { @@ -6905,7 +6954,7 @@ namespace smt { VERIFY(u.str.is_prefix(e, needle, haystack)); TRACE("str", tout << "check consistency of prefix predicate: " << mk_pp(needle, m) << " prefixof " << mk_pp(haystack, m) << std::endl;); - + zstring needleStringConstant; if (get_string_constant_eqc(needle, needleStringConstant)) { if (u.str.is_itos(haystack) && is_true) { @@ -6932,7 +6981,7 @@ namespace smt { VERIFY(u.str.is_suffix(e, needle, haystack)); TRACE("str", tout << "check consistency of suffix predicate: " << mk_pp(needle, m) << " suffixof " << mk_pp(haystack, m) << std::endl;); - + zstring needleStringConstant; if (get_string_constant_eqc(needle, needleStringConstant)) { if (u.str.is_itos(haystack) && is_true) { @@ -6959,7 +7008,7 @@ namespace smt { VERIFY(u.str.is_contains(e, haystack, needle)); // first string contains second one TRACE("str", tout << "check consistency of contains predicate: " << mk_pp(haystack, m) << " contains " << mk_pp(needle, m) << std::endl;); - + zstring needleStringConstant; if (get_string_constant_eqc(needle, needleStringConstant)) { if (u.str.is_itos(haystack) && is_true) { @@ -7052,7 +7101,7 @@ namespace smt { m_concat_eval_todo.reset(); m_delayed_axiom_setup_terms.reset(); m_delayed_assertions_todo.reset(); - + TRACE_CODE(if (is_trace_enabled("t_str_dump_assign_on_scope_change")) { dump_assignments(); }); // list of expr* to remove from cut_var_map @@ -8386,7 +8435,7 @@ namespace smt { } } } - + if (!needToAssignFreeVars) { // check string-int terms @@ -8685,7 +8734,7 @@ namespace smt { } else if (u.str.is_itos(ex)) { expr* fromInt = nullptr; u.str.is_itos(ex, fromInt); - + arith_value v(m); v.init(&ctx); rational val; @@ -8808,7 +8857,7 @@ namespace smt { if (!u.str.is_string(to_app(Gamma.get(left_count)))) { rational offsetLen = offset - left_length + 1; extra_left_cond = m_autil.mk_ge(u.str.mk_length(Gamma.get(left_count)), mk_int(offsetLen)); - } + } // find len(Delta[:j]) unsigned right_count = 0; @@ -8887,7 +8936,7 @@ namespace smt { expr* theory_str::refine_dis(expr* lhs, expr* rhs) { ast_manager & m = get_manager(); - + expr_ref lesson(m); lesson = m.mk_not(m.mk_eq(lhs, rhs)); TRACE("str", tout << "learning not " << mk_pp(lesson, m) << std::endl;); diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index d96a4e4af..090a5fe36 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -393,6 +393,8 @@ protected: // does not introduce equalities when they weren't enforced. unsigned m_unused_id; + const char* newOverlapStr = "!!NewOverlapAssumption!!"; + // terms we couldn't go through set_up_axioms() with because they weren't internalized expr_ref_vector m_delayed_axiom_setup_terms; @@ -492,7 +494,7 @@ protected: obj_map> fixed_length_lesson; //keep track of information for the lesson unsigned preprocessing_iteration_count; // number of attempts we've made to solve by preprocessing length information obj_map candidate_model; - + stats m_stats; protected: @@ -777,4 +779,3 @@ protected: }; }; - From b5c7f000dedad76e3b26e363173ad80e93cbfcc4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 May 2022 20:58:11 +0200 Subject: [PATCH 087/253] add option to "rotate" cores during core finding enable to find multiple cores in a round and at the same time facilitate rotation around satisfiable subsets to explore neighborhoods for improved assignments. --- src/opt/CMakeLists.txt | 1 + src/opt/maxcore.cpp | 53 +++--- src/opt/maxsmt.h | 7 + src/opt/opt_cores.cpp | 398 +++++++++++++++++++++++++++++++++++++++++ src/opt/opt_cores.h | 71 ++++++++ src/opt/opt_params.pyg | 5 +- 6 files changed, 510 insertions(+), 25 deletions(-) create mode 100644 src/opt/opt_cores.cpp create mode 100644 src/opt/opt_cores.h diff --git a/src/opt/CMakeLists.txt b/src/opt/CMakeLists.txt index c815ae08e..9c20b7d2d 100644 --- a/src/opt/CMakeLists.txt +++ b/src/opt/CMakeLists.txt @@ -5,6 +5,7 @@ z3_add_component(opt maxsmt.cpp opt_cmds.cpp opt_context.cpp + opt_cores.cpp opt_lns.cpp opt_pareto.cpp opt_parse.cpp diff --git a/src/opt/maxcore.cpp b/src/opt/maxcore.cpp index 792e5e17a..a25da928f 100644 --- a/src/opt/maxcore.cpp +++ b/src/opt/maxcore.cpp @@ -11,8 +11,8 @@ Abstract: - mu: max-sat algorithm by Nina and Bacchus, AAAI 2014. - mus-mss: based on dual refinement of bounds. - - binary - - binary-delay + - binary: binary versino of maxres + - rc2: implementaion of rc2 heuristic using cardinality constraints MaxRes is a core-guided approach to maxsat. @@ -66,6 +66,7 @@ Notes: #include "opt/opt_context.h" #include "opt/opt_params.hpp" #include "opt/opt_lns.h" +#include "opt/opt_cores.h" #include "opt/maxsmt.h" #include "opt/maxcore.h" @@ -119,7 +120,6 @@ private: bool m_hill_climb; // prefer large weight soft clauses for cores unsigned m_last_index; // last index used during hill-climbing bool m_add_upper_bound_block; // restrict upper bound with constraint - unsigned m_max_num_cores; // max number of cores per round. unsigned m_max_core_size; // max core size per round. bool m_maximize_assignment; // maximize assignment to find MCS unsigned m_max_correction_set_size;// maximal set of correction set that is tolerated. @@ -127,9 +127,9 @@ private: // this option is disabled if SAT core is used. bool m_pivot_on_cs; // prefer smaller correction set to core. bool m_dump_benchmarks; // display benchmarks (into wcnf format) - bool m_enable_lns { false }; // enable LNS improvements - unsigned m_lns_conflicts { 1000 }; // number of conflicts used for LNS improvement - + bool m_enable_lns = false; // enable LNS improvements + unsigned m_lns_conflicts = 1000; // number of conflicts used for LNS improvement + bool m_enable_core_rotate = false; std::string m_trace_id; typedef ptr_vector exprs; @@ -148,7 +148,6 @@ public: m_correction_set_size(0), m_found_feasible_optimum(false), m_hill_climb(true), - m_last_index(0), m_add_upper_bound_block(false), m_max_num_cores(UINT_MAX), m_max_core_size(3), @@ -323,17 +322,15 @@ public: Give preference to cores that have large minimal values. */ sort_assumptions(asms); - m_last_index = 0; + unsigned last_index = 0; unsigned index = 0; - bool first = index > 0; SASSERT(index < asms.size() || asms.empty()); IF_VERBOSE(10, verbose_stream() << "start hill climb " << index << " asms: " << asms.size() << "\n";); while (index < asms.size() && is_sat == l_true) { - while (!first && asms.size() > 20*(index - m_last_index) && index < asms.size()) { + while (asms.size() > 20*(index - last_index) && index < asms.size()) { index = next_index(asms, index); } - first = false; - m_last_index = index; + last_index = index; is_sat = check_sat(index, asms.data()); } } @@ -390,13 +387,6 @@ public: st.update("maxsat-correction-sets", m_stats.m_num_cs); } - struct weighted_core { - exprs m_core; - rational m_weight; - weighted_core(exprs const& c, rational const& w): - m_core(c), m_weight(w) {} - }; - lbool get_cores(vector& cores) { // assume m_s is unsat. lbool is_sat = l_false; @@ -434,8 +424,8 @@ public: remove_soft(core, m_asms); split_core(core); - if (core.size() >= m_max_core_size) break; - if (cores.size() >= m_max_num_cores) break; + if (core.size() >= m_max_core_size) + break; is_sat = check_sat_hill_climb(m_asms); } @@ -511,6 +501,9 @@ public: } lbool process_unsat() { + if (m_enable_core_rotate) + return core_rotate(); + vector cores; lbool is_sat = get_cores(cores); if (is_sat != l_true) { @@ -525,6 +518,21 @@ public: } } + lbool core_rotate() { + cores find_cores(s(), m_lnsctx); + find_cores.updt_params(m_params); + vector const& cores = find_cores(); + for (auto const & [core, w] : cores) { + if (core.empty()) + return l_false; + remove_soft(core, m_asms); + split_core(core); + process_unsat(core, w); + } + return l_true; + } + + unsigned max_core_size(vector const& cores) { unsigned result = 0; for (auto const& c : cores) { @@ -980,7 +988,6 @@ public: opt_params p(_p); m_hill_climb = p.maxres_hill_climb(); m_add_upper_bound_block = p.maxres_add_upper_bound_block(); - m_max_num_cores = p.maxres_max_num_cores(); m_max_core_size = p.maxres_max_core_size(); m_maximize_assignment = p.maxres_maximize_assignment(); m_max_correction_set_size = p.maxres_max_correction_set_size(); @@ -988,6 +995,7 @@ public: m_wmax = p.maxres_wmax(); m_dump_benchmarks = p.dump_benchmarks(); m_enable_lns = p.enable_lns(); + m_enable_core_rotate = p.enable_core_rotate(); m_lns_conflicts = p.lns_conflicts(); if (m_c.num_objectives() > 1) m_add_upper_bound_block = false; @@ -1000,7 +1008,6 @@ public: add_soft(e, w); m_max_upper = m_upper; m_found_feasible_optimum = false; - m_last_index = 0; add_upper_bound_block(); m_csmodel = nullptr; m_correction_set_size = 0; diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index b0ae5eeb1..2f8992e01 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -31,6 +31,13 @@ namespace opt { typedef vector const weights_t; + struct weighted_core { + ptr_vector m_core; + rational m_weight; + weighted_core(ptr_vector const& c, rational const& w): + m_core(c), m_weight(w) {} + }; + class maxsat_context; class maxsmt_solver { diff --git a/src/opt/opt_cores.cpp b/src/opt/opt_cores.cpp new file mode 100644 index 000000000..d9afe8757 --- /dev/null +++ b/src/opt/opt_cores.cpp @@ -0,0 +1,398 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + opt_cores.cpp + +Abstract: + + "walk" subsets of soft constraints to extract multiple cores and satisfying assignments. + + core rotation starts with an initial unsat core, which is a subset of soft constraints. + Then it removes one element from the core from the soft constraints and finds remaining cores. + At every stage it operates over a set of detected cores, and a subset of soft constraints have + a hitting set from the cores removed. + When enough constraints are removed, the remaining soft constraints become satisfiable. + It then attempts extend the satisfying assignment by adding soft constraints removed in + the hitting set. In this process it detects new cores and may find assignments that improve + the current feasible bound. As a final effort, it takes a maximal satisfying assignment and + rotates out elements that belong to cores to explore a neighborhood for satisfying assignments + that may potentially satisfy other soft constraints and potentially more of them. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-04-27 + +--*/ + +#include "solver/solver.h" +#include "opt/maxsmt.h" +#include "opt/opt_cores.h" +#include "opt/opt_params.hpp" + +namespace opt { + + cores::cores(solver& s, lns_context& ctx): + m(s.get_manager()), s(s), ctx(ctx) {} + + void cores::hitting_set(obj_hashtable& set) { + for (auto const& [core, w] : m_cores) { + bool seen = false; + for (auto * c : core) + seen |= set.contains(c); + if (seen) + continue; + set.insert(core[m_rand(core.size())]); + } + } + + bool cores::improve() { + model_ref mdl; + s.get_model(mdl); + rational cost = ctx.cost(*mdl); + IF_VERBOSE(3, verbose_stream() << "(opt.maxcore new model cost " << cost << ")\n"); + if (m_best_cost < 0 || cost < m_best_cost) { + m_best_cost = cost; + ctx.update_model(mdl); + return true; + } + return false; + } + + /** + * retrieve cores that are disjoint modulo weights. + * weighted soft constraints are treated as multi-sets. + */ + vector const& cores::disjoint_cores() { + std::sort(m_cores.begin(), m_cores.end(), [&](weighted_core const& c1, weighted_core const& c2) { return c1.m_core.size() < c2.m_core.size(); }); + vector result; + for (auto const& [core, w] : m_cores) { + rational weight = core_weight(core); + if (weight == 0 && !core.empty()) + continue; + for (auto *c : core) + m_weight[c] -= weight; + result.push_back(weighted_core(core, weight)); + } + IF_VERBOSE(3, verbose_stream() << "(opt.cores :cores-found " << m_cores.size() << " :disjoint-cores " << result.size() << ")\n"); + m_cores.reset(); + m_cores.append(result); + return m_cores; + } + + void cores::rotate_rec(obj_hashtable const& _mss, obj_map>& backbone2core, unsigned depth) { + obj_map counts; + obj_hashtable mss(_mss); + for (auto* f : mss) + counts.insert(f, 0); + for (auto const& [k, core] : backbone2core) + for (auto* c : core) + counts[c] += 1; + + unsigned plateaus = 0; + for (auto const& [c, count] : counts) + if (count <= 1) + ++plateaus; + IF_VERBOSE(3, verbose_stream() << "(opt.maxcore :num-plateaus " << plateaus << "\n"); + + for (auto const& [c, count] : counts) { + if (count <= 1) + continue; + mss.remove(c); + bool rotated = rotate(mss, c, depth + 1); + mss.insert(c); + if (rotated) + break; + } + } + + /** + * collect soft constraints that are not in the satisfying assignment mss into the set ps. + * Try to add elements from ps in some order. + * If an element can be added, (mss + p is sat), then mss is extended. + * If mss + p is unsat, then extract core that includes p and a subset of mss + * Then Not(p) is a backbone, and we maintain a map from Not(p) to the subset of mss used + * in the core. Backbone literals are used in the satisfiability check. + * For backbone literals that are used in other cores, resolve away Not(p) by the subset + * of mss that comprised the core for p + mss. + * The set qs accumulates don't knows. If a satisfiable assignment is found that satisfies + * elements from qs, they are added to mss. + */ + bool cores::rotate(obj_hashtable const& _mss, expr* excl, unsigned depth) { + obj_hashtable ps, qs, mss(_mss); + expr_ref_vector backbones(m); + obj_map> backbone2core; + bool improved = false; + for (expr* f : ctx.soft()) + if (!mss.contains(f) && f != excl) + ps.insert(f); + while (!ps.empty() && m.inc() && m_cores.size() < m_max_num_cores) { + expr* p = *ps.begin(); + ps.remove(p); + expr_ref_vector asms(backbones); + asms.push_back(p); + for (expr* f : mss) + asms.push_back(f); + lbool is_sat = s.check_sat(asms); + switch (is_sat) { + case l_true: { + model_ref mdl; + s.get_model(mdl); + ptr_vector moved; + moved.push_back(p); + for (auto* q : qs) + if (mdl->is_true(q)) + moved.push_back(q); + + for (auto* q : ps) + if (mdl->is_true(q)) + moved.push_back(q); + + for (auto* q : moved) { + mss.insert(q); + qs.remove(q); + ps.remove(q); + } + + if (improve()) + improved = true; + break; + } + case l_false: { + obj_hashtable core; + for (auto* f : unsat_core()) { + ptr_vector core1; + if (backbone2core.find(f, core1)) + for (expr* c : core1) + core.insert(c); + else + core.insert(f); + } + expr_ref_vector core1(m); + for (expr* c : core) + core1.push_back(c); + saturate_core(core1); + add_core(core1); + expr_ref not_p(m.mk_not(p), m); + backbones.push_back(not_p); + ptr_vector core2(core1.size(), core1.data()); + core2.erase(p); + backbone2core.insert(not_p, core2); + break; + } + default: + qs.insert(p); + break; + } + } + if (improved) + rotate_rec(mss, backbone2core, depth); + return improved; + } + + struct cores::scoped_update { + cores& c; + char const* par; + bool is_uint = true; + unsigned old_uval; + bool old_bval; + public: + scoped_update(cores& c, char const* par, unsigned old_val, unsigned new_val): + c(c), par(par), old_uval(old_val) { + params_ref p; + p.set_uint(par, new_val); + c.s.updt_params(p); + } + + scoped_update(cores& c, char const* par, bool old_val, bool new_val): + c(c), par(par), old_bval(old_val) { + is_uint = false; + params_ref p; + p.set_bool(par, new_val); + c.s.updt_params(p); + } + + ~scoped_update() { + params_ref p; + if (is_uint) + p.set_uint(par, old_uval); + else + p.set_bool(par, old_bval); + c.s.updt_params(p); + } + }; + + void cores::saturate_core(expr_ref_vector& core) { + scoped_update _upd(*this, "max_conflicts", m_max_conflicts, m_max_saturate_conflicts); + shuffle(core.size(), core.data(), m_rand); + while (l_false == s.check_sat(core) && unsat_core().size() < core.size()) { + core.reset(); + core.append(unsat_core()); + shuffle(core.size(), core.data(), m_rand); + } + } + + void cores::local_mss() { + obj_hashtable mss; + model_ref mdl; + s.get_model(mdl); + for (expr* f : ctx.soft()) + if (mdl->is_true(f)) + mss.insert(f); + rotate(mss, nullptr, 0); + } + + expr_ref_vector cores::unsat_core() { + expr_ref_vector core(m); + s.get_unsat_core(core); + return core; + } + + /** + * The solver state is unsatisfiable when this function is called. + * Erase one element from each code that is found + */ + void cores::rotate_cores() { + expr_ref_vector soft(m); + soft.append(ctx.soft()); + unsigned num_sat = 0, num_unsat = 0, num_undef = 0; + lbool is_sat = l_false; + while (m.inc() && m_cores.size() < m_max_num_cores) { + switch (is_sat) { + case l_false: { + ++num_unsat; + auto core = unsat_core(); + add_core(core); + if (core.empty()) + return; + soft.erase(core.get(m_rand(core.size()))); + num_sat = 0; + break; + } + case l_true: { + ++num_sat; + improve(); + local_mss(); + if (num_sat > 1) + return; + soft.reset(); + obj_hashtable hs; + hitting_set(hs); + for (auto s : ctx.soft()) + if (!hs.contains(s)) + soft.push_back(s); + break; + } + case l_undef: + ++num_undef; + if (num_undef > 2) + return; + } + is_sat = s.check_sat(soft); + } + } + + rational cores::core_weight(unsigned sz, expr* const* core) { + if (sz == 0) + return rational(0); + rational min_weight = m_weight[core[0]]; + for (unsigned i = 1; i < sz; ++i) { + auto* c = core[i]; + if (m_weight[c] < min_weight) + min_weight = m_weight[c]; + } + return min_weight; + } + + + vector const& cores::weighted_disjoint_cores() { + lbool is_sat = l_false; + expr_ref_vector soft = ctx.soft(); + + while (is_sat == l_false && m.inc()) { + auto core = unsat_core(); + saturate_core(core); + rational weight = core_weight(core); + add_core(core); + if (core.empty()) { + IF_VERBOSE(100, verbose_stream() << "(opt.maxres :empty-core)\n";); + TRACE("opt", tout << "empty core\n";); + break; + } + + for (auto *c : core) { + m_weight[c] -= weight; + if (m_weight[c] == 0) + soft.erase(c); + } + + if (core.size() >= m_max_core_size) + break; + + if (m_cores.size() >= m_max_num_cores) + break; + + if (m_hill_climb) + is_sat = check_sat_hill_climb(soft); + else + is_sat = s.check_sat(soft); + } + return m_cores; + } + + /** + * Give preference to cores that have large minimal values. + * Explore largest values, and grow the set of explored values by at least 5% + * of all soft constraints in iterations (capping maximal iterations at 20). + */ + lbool cores::check_sat_hill_climb(expr_ref_vector const& _soft) { + expr_ref_vector soft(_soft); + lbool is_sat = l_true; + std::sort(soft.data(), soft.data() + soft.size(), [&](expr* a, expr* b) { return m_weight[a] > m_weight[b]; }); + unsigned index = 0, last_index = 0; + SASSERT(index < soft.size() || soft.empty()); + IF_VERBOSE(10, verbose_stream() << "start hill climb " << index << " soft: " << soft.size() << "\n";); + while (index < soft.size() && is_sat == l_true) { + while (soft.size() > 20*(index - last_index) && index < soft.size()) { + rational w = m_weight[_soft[index]]; + for (++index; index < soft.size() && w == m_weight[_soft[index]]; ++index); + } + last_index = index; + is_sat = s.check_sat(index, soft.data()); + } + return is_sat; + } + + void cores::add_core(expr_ref_vector const& core) { + IF_VERBOSE(3, verbose_stream() << "(opt.maxcore :core-size " << core.size() << ")\n"); + m_cores.push_back(weighted_core(ptr_vector(core.size(), core.data()), core_weight(core))); + } + + void cores::updt_params(params_ref& _p) { + std::cout << _p << "\n"; + opt_params p(_p); + m_hill_climb = p.maxres_hill_climb(); + m_max_num_cores = p.maxres_max_num_cores(); + m_max_core_size = p.maxres_max_core_size(); + m_enable_core_rotate = p.enable_core_rotate(); + } + + vector const& cores::operator()() { + scoped_update _upd1(*this, "max_conflicts", UINT_MAX, m_max_conflicts); + m_cores.reset(); + m_weight.reset(); + for (expr* s : ctx.soft()) + m_weight.insert(s, ctx.weight(s)); + + if (m_enable_core_rotate) { + scoped_update _upd2(*this, "minimize_core", false, false); + rotate_cores(); + return disjoint_cores(); + } + else { + return weighted_disjoint_cores(); + } + } + +}; diff --git a/src/opt/opt_cores.h b/src/opt/opt_cores.h new file mode 100644 index 000000000..6dda34fd7 --- /dev/null +++ b/src/opt/opt_cores.h @@ -0,0 +1,71 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + opt_cores.h + +Abstract: + + "walk" subsets of soft constraints to extract multiple cores and satisfying assignments. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-04-27 + +--*/ + +#pragma once +#include "opt/opt_lns.h" + +namespace opt { + + + class cores { + ast_manager& m; + solver& s; + lns_context& ctx; + + random_gen m_rand; + rational m_best_cost = rational::minus_one(); + vector m_cores; + obj_map m_weight; + + unsigned m_max_saturate_conflicts = 500; + unsigned m_max_conflicts = 1000; + bool m_hill_climb = true; + unsigned m_max_num_cores = UINT_MAX; + unsigned m_max_core_size = 4; + bool m_enable_core_rotate = false; + + struct scoped_update; + + bool improve(); + void rotate_rec(obj_hashtable const& mss, obj_map>& backbone2core, unsigned depth); + bool rotate(obj_hashtable const& mss, expr* excl, unsigned depth); + void saturate_core(expr_ref_vector& core); + void local_mss(); + void hitting_set(obj_hashtable& hs); + rational core_weight(expr_ref_vector const& core) { return core_weight(core.size(), core.data()); } + rational core_weight(ptr_vector const& core) { return core_weight(core.size(), core.data()); } + rational core_weight(unsigned sz, expr* const* core); + lbool check_sat_hill_climb(expr_ref_vector const& _soft); + + void add_core(expr_ref_vector const& core); + + vector const& disjoint_cores(); + + void rotate_cores(); + + vector const& weighted_disjoint_cores(); + + expr_ref_vector unsat_core(); + + public: + cores(solver& s, lns_context& ctx); + + vector const& operator()(); + + void updt_params(params_ref& p); + }; +}; diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 9c00020d5..93ecddbe4 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -10,8 +10,9 @@ def_module_params('opt', ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsat'), - ('enable_lns', BOOL, False, 'enable LNS during weighted maxsat'), + ('enable_lns', BOOL, False, 'enable LNS during weighted maxsat'), ('lns_conflicts', UINT, 1000, 'initial conflict count for LNS search'), + ('enable_core_rotate', BOOL, False, 'enable core rotation to both sample cores and correction sets'), ('enable_sat', BOOL, True, 'enable the new SAT core for propositional constraints'), ('elim_01', BOOL, True, 'eliminate 01 variables'), ('pp.neat', BOOL, True, 'use neat (as opposed to less readable, but faster) pretty printer when displaying context'), @@ -20,7 +21,7 @@ def_module_params('opt', ('maxlex.enable', BOOL, True, 'enable maxlex heuristic for lexicographic MaxSAT problems'), ('maxres.hill_climb', BOOL, True, 'give preference for large weight cores'), ('maxres.add_upper_bound_block', BOOL, False, 'restict upper bound with constraint'), - ('maxres.max_num_cores', UINT, UINT_MAX, 'maximal number of cores per round'), + ('maxres.max_num_cores', UINT, 200, 'maximal number of cores per round'), ('maxres.max_core_size', UINT, 3, 'break batch of generated cores if size reaches this number'), ('maxres.maximize_assignment', BOOL, False, 'find an MSS/MCS to improve current assignment'), ('maxres.max_correction_set_size', UINT, 3, 'allow generating correction set constraints up to maximal size'), From 9cc5f6901a4ccee00bc8b2d9962ae5cbc83e72a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 May 2022 21:04:35 +0200 Subject: [PATCH 088/253] na --- src/opt/maxcore.cpp | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/src/opt/maxcore.cpp b/src/opt/maxcore.cpp index a25da928f..93a9985d4 100644 --- a/src/opt/maxcore.cpp +++ b/src/opt/maxcore.cpp @@ -78,7 +78,6 @@ public: s_primal, s_primal_dual, s_primal_binary, - s_primal_binary_delay, s_rc2 }; private: @@ -115,21 +114,20 @@ private: model_ref m_csmodel; lns_maxcore m_lnsctx; lns m_lns; - unsigned m_correction_set_size; - bool m_found_feasible_optimum; - bool m_hill_climb; // prefer large weight soft clauses for cores - unsigned m_last_index; // last index used during hill-climbing - bool m_add_upper_bound_block; // restrict upper bound with constraint - unsigned m_max_core_size; // max core size per round. - bool m_maximize_assignment; // maximize assignment to find MCS - unsigned m_max_correction_set_size;// maximal set of correction set that is tolerated. - bool m_wmax; // Block upper bound using wmax - // this option is disabled if SAT core is used. - bool m_pivot_on_cs; // prefer smaller correction set to core. - bool m_dump_benchmarks; // display benchmarks (into wcnf format) - bool m_enable_lns = false; // enable LNS improvements - unsigned m_lns_conflicts = 1000; // number of conflicts used for LNS improvement - bool m_enable_core_rotate = false; + unsigned m_correction_set_size = 0; + bool m_found_feasible_optimum = false; + bool m_hill_climb = true; // prefer large weight soft clauses for cores + bool m_add_upper_bound_block = false; // restrict upper bound with constraint + unsigned m_max_core_size = 3; // max core size per round. + bool m_maximize_assignment = false; // maximize assignment to find MCS + unsigned m_max_correction_set_size = 3; // maximal set of correction set that is tolerated. + bool m_wmax = false; // Block upper bound using wmax + // this option is disabled if SAT core is used. + bool m_pivot_on_cs = true; // prefer smaller correction set to core. + bool m_dump_benchmarks; // display benchmarks (into wcnf format) + bool m_enable_lns = false; // enable LNS improvements + unsigned m_lns_conflicts = 1000; // number of conflicts used for LNS improvement + bool m_enable_core_rotate = false; // enable core rotation std::string m_trace_id; typedef ptr_vector exprs; @@ -144,16 +142,7 @@ public: m_trail(m), m_st(st), m_lnsctx(*this), - m_lns(s(), m_lnsctx), - m_correction_set_size(0), - m_found_feasible_optimum(false), - m_hill_climb(true), - m_add_upper_bound_block(false), - m_max_num_cores(UINT_MAX), - m_max_core_size(3), - m_maximize_assignment(false), - m_max_correction_set_size(3), - m_pivot_on_cs(true) + m_lns(s(), m_lnsctx) { switch(st) { case s_primal: @@ -165,9 +154,6 @@ public: case s_primal_binary: m_trace_id = "maxres-bin"; break; - case s_primal_binary_delay: - m_trace_id = "maxres-bin-delay"; - break; case s_rc2: m_trace_id = "rc2"; break; @@ -373,7 +359,6 @@ public: switch(m_st) { case s_primal: case s_primal_binary: - case s_primal_binary_delay: case s_rc2: return mus_solver(); case s_primal_dual: From 98e1c86128019874d313d22742fd0a928a4c151c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 May 2022 21:06:54 +0200 Subject: [PATCH 089/253] na --- src/opt/opt_cores.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/opt/opt_cores.cpp b/src/opt/opt_cores.cpp index d9afe8757..83cca8d5a 100644 --- a/src/opt/opt_cores.cpp +++ b/src/opt/opt_cores.cpp @@ -370,7 +370,6 @@ namespace opt { } void cores::updt_params(params_ref& _p) { - std::cout << _p << "\n"; opt_params p(_p); m_hill_climb = p.maxres_hill_climb(); m_max_num_cores = p.maxres_max_num_cores(); From d1f1e4ce3464e87b30c4aa7e05b53a0e8d057ad9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 May 2022 22:07:09 +0200 Subject: [PATCH 090/253] selectively enable dual strengthening --- src/opt/maxcore.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/opt/maxcore.cpp b/src/opt/maxcore.cpp index 93a9985d4..216ca1877 100644 --- a/src/opt/maxcore.cpp +++ b/src/opt/maxcore.cpp @@ -520,16 +520,14 @@ public: unsigned max_core_size(vector const& cores) { unsigned result = 0; - for (auto const& c : cores) { + for (auto const& c : cores) result = std::max(c.size(), result); - } return result; } void process_unsat(vector const& cores) { - for (auto const & c : cores) { + for (auto const & c : cores) process_unsat(c.m_core, c.m_weight); - } improve_model(m_model); } @@ -573,7 +571,8 @@ public: --m_correction_set_size; } trace(); - if (m_c.num_objectives() == 1 && m_pivot_on_cs && m_csmodel.get() && m_correction_set_size < core.size()) { + bool no_hidden_soft = (m_st == s_primal_dual || m_st == s_primal || m_st == s_primal_binary); + if (no_hidden_soft && m_c.num_objectives() == 1 && m_pivot_on_cs && m_csmodel.get() && m_correction_set_size < core.size()) { exprs cs; get_current_correction_set(m_csmodel.get(), cs); m_correction_set_size = cs.size(); @@ -601,25 +600,21 @@ public: else { w = m_mus.get_best_model(mdl); } - if (mdl.get() && w < m_upper) { + if (mdl.get() && w < m_upper) update_assignment(mdl); - } return nullptr != mdl.get(); } lbool minimize_core(expr_ref_vector& core) { - if (core.empty()) { + if (core.empty()) return l_true; - } - if (m_c.sat_enabled()) { + if (m_c.sat_enabled()) return l_true; - } m_mus.reset(); m_mus.add_soft(core.size(), core.data()); lbool is_sat = m_mus.get_mus(m_new_core); - if (is_sat != l_true) { + if (is_sat != l_true) return is_sat; - } core.reset(); core.append(m_new_core); return l_true; @@ -667,9 +662,8 @@ public: } void display(std::ostream& out) { - for (expr * a : m_asms) { + for (expr * a : m_asms) out << mk_pp(a, m) << " : " << get_weight(a) << "\n"; - } } From be653dab0efc13b20dd3a1f1be6ae1b88f4b71f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 May 2022 15:21:45 -0700 Subject: [PATCH 091/253] init value --- src/opt/opt_cores.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/opt/opt_cores.cpp b/src/opt/opt_cores.cpp index 83cca8d5a..124df63d7 100644 --- a/src/opt/opt_cores.cpp +++ b/src/opt/opt_cores.cpp @@ -381,6 +381,7 @@ namespace opt { scoped_update _upd1(*this, "max_conflicts", UINT_MAX, m_max_conflicts); m_cores.reset(); m_weight.reset(); + m_best_cost = -1; for (expr* s : ctx.soft()) m_weight.insert(s, ctx.weight(s)); From b3e0213cab15bafa573938059ce9d64fa57e27b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 May 2022 12:35:28 -0700 Subject: [PATCH 092/253] missing object ref 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 af1d32972..69959d181 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -11284,7 +11284,7 @@ def user_prop_push(ctx, cb): def user_prop_pop(ctx, cb, num_scopes): prop = _prop_closures.get(ctx) prop.cb = cb - pop(num_scopes) + prop.pop(num_scopes) def user_prop_fresh(id, ctx): From 87d2a3b4e55081955720e4081b320a1f61ce0650 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 May 2022 01:10:18 -0700 Subject: [PATCH 093/253] map/mapi/foldl/foldli Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.h | 2 + src/ast/rewriter/seq_rewriter.cpp | 121 ++++++++++++++++++++++++++++++ src/ast/rewriter/seq_rewriter.h | 4 + src/ast/seq_decl_plugin.cpp | 25 +++++- src/ast/seq_decl_plugin.h | 17 ++++- 5 files changed, 167 insertions(+), 2 deletions(-) diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 7298a0e47..5a606a509 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -272,6 +272,8 @@ public: func_decl * mk_array_ext(sort* domain, unsigned i); sort * mk_array_sort(sort* dom, sort* range) { return mk_array_sort(1, &dom, range); } + sort * mk_array_sort(sort* a, sort* b, sort* range) { sort* dom[2] = { a, b }; return mk_array_sort(2, dom, range); } + sort * mk_array_sort(sort* a, sort* b, sort* c, sort* range) { sort* dom[3] = { a, b, c}; return mk_array_sort(3, dom, range); } sort * mk_array_sort(unsigned arity, sort* const* domain, sort* range); diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 9fcc35b2d..877263e79 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -673,6 +673,22 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con SASSERT(num_args == 3); st = mk_seq_replace_all(args[0], args[1], args[2], result); break; + case OP_SEQ_MAP: + SASSERT(num_args == 2); + st = mk_seq_map(args[0], args[1], result); + break; + case OP_SEQ_MAPI: + SASSERT(num_args == 3); + st = mk_seq_mapi(args[0], args[1], args[2], result); + break; + case OP_SEQ_FOLDL: + SASSERT(num_args == 3); + st = mk_seq_foldl(args[0], args[1], args[2], result); + break; + case OP_SEQ_FOLDLI: + SASSERT(num_args == 4); + st = mk_seq_foldli(args[0], args[1], args[2], args[3], result); + break; case OP_SEQ_REPLACE_RE: SASSERT(num_args == 3); st = mk_seq_replace_re(args[0], args[1], args[2], result); @@ -850,6 +866,14 @@ br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) { result = str().mk_length(x); return BR_REWRITE1; } + if (str().is_map(a, x, y)) { + result = str().mk_length(y); + return BR_REWRITE1; + } + if (str().is_mapi(a, x, y, z)) { + result = str().mk_length(z); + return BR_REWRITE1; + } #if 0 expr* s = nullptr, *offset = nullptr, *length = nullptr; if (str().is_extract(a, s, offset, length)) { @@ -1640,6 +1664,13 @@ br_status seq_rewriter::mk_seq_nth_i(expr* a, expr* b, expr_ref& result) { return BR_REWRITE1; } + expr* f, *s; + if (str().is_map(a, f, s)) { + expr* args[2] = { f, str().mk_nth_i(s, b) }; + result = array_util(m()).mk_select(2, args); + return BR_REWRITE1; + } + expr_ref_vector as(m()); str().get_concat_units(a, as); @@ -2008,6 +2039,96 @@ br_status seq_rewriter::mk_seq_replace_all(expr* a, expr* b, expr* c, expr_ref& return BR_FAILED; } +/** + rewrites for map(f, s): + + map(f, []) = [] + map(f, [x]) = [f(x)] + map(f, s + t) = map(f, s) + map(f, t) + len(map(f, s)) = len(s) + nth_i(map(f,s), i) = f(nth_i(s, i)) + + */ +br_status seq_rewriter::mk_seq_map(expr* f, expr* seqA, expr_ref& result) { + if (str().is_empty(seqA)) { + result = str().mk_empty(get_array_range(f->get_sort())); + return BR_DONE; + } + expr* a, *s1, *s2; + if (str().is_unit(seqA, a)) { + array_util array(m()); + expr* args[2] = { f, a }; + result = str().mk_unit(array.mk_select(2, args)); + return BR_REWRITE2; + } + if (str().is_concat(seqA, s1, s2)) { + result = str().mk_concat(str().mk_map(f, s1), str().mk_map(f, s2)); + return BR_REWRITE2; + } + return BR_FAILED; +} + +br_status seq_rewriter::mk_seq_mapi(expr* f, expr* i, expr* seqA, expr_ref& result) { + if (str().is_empty(seqA)) { + result = str().mk_empty(get_array_range(f->get_sort())); + return BR_DONE; + } + expr* a, *s1, *s2; + if (str().is_unit(seqA, a)) { + array_util array(m()); + expr* args[3] = { f, i, a }; + result = str().mk_unit(array.mk_select(3, args)); + return BR_REWRITE2; + } + if (str().is_concat(seqA, s1, s2)) { + expr_ref j(m_autil.mk_add(i, str().mk_length(s1)), m()); + result = str().mk_concat(str().mk_mapi(f, i, s1), str().mk_mapi(f, j, s2)); + return BR_REWRITE2; + } + return BR_FAILED; +} + +br_status seq_rewriter::mk_seq_foldl(expr* f, expr* b, expr* seqA, expr_ref& result) { + if (str().is_empty(seqA)) { + result = b; + return BR_DONE; + } + expr* a, *s1, *s2; + if (str().is_unit(seqA, a)) { + array_util array(m()); + expr* args[3] = { f, b, a }; + result = array.mk_select(3, args); + return BR_REWRITE1; + } + if (str().is_concat(seqA, s1, s2)) { + result = str().mk_foldl(f, b, s1); + result = str().mk_foldl(f, result, s2); + return BR_REWRITE3; + } + return BR_FAILED; +} + +br_status seq_rewriter::mk_seq_foldli(expr* f, expr* i, expr* b, expr* seqA, expr_ref& result) { + if (str().is_empty(seqA)) { + result = b; + return BR_DONE; + } + expr* a, *s1, *s2; + if (str().is_unit(seqA, a)) { + array_util array(m()); + expr* args[4] = { f, i, b, a }; + result = array.mk_select(4, args); + return BR_REWRITE1; + } + if (str().is_concat(seqA, s1, s2)) { + expr_ref j(m_autil.mk_add(i, str().mk_length(s1)), m()); + result = str().mk_foldli(f, i, b, s1); + result = str().mk_foldli(f, j, result, s2); + return BR_REWRITE3; + } + return BR_FAILED; +} + /* * Returns false if s is not a single unit value or concatenation of unit values. * Else extracts the units from s into vals and returns true. diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index f10532572..500972b1f 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -256,6 +256,10 @@ class seq_rewriter { br_status mk_seq_replace_re(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); + br_status mk_seq_map(expr* f, expr* s, expr_ref& result); + br_status mk_seq_mapi(expr* f, expr* i, expr* s, expr_ref& result); + br_status mk_seq_foldl(expr* f, expr* b, expr* s, expr_ref& result); + br_status mk_seq_foldli(expr* f, expr* i, expr* b, expr* s, expr_ref& result); br_status mk_str_units(func_decl* f, expr_ref& result); br_status mk_str_itos(expr* a, expr_ref& result); br_status mk_str_stoi(expr* a, expr_ref& result); diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index f4cf2ecaa..77179a263 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -182,18 +182,26 @@ sort* seq_decl_plugin::apply_binding(ptr_vector const& binding, sort* s) { void seq_decl_plugin::init() { if (m_init) return; ast_manager& m = *m_manager; + array_util autil(m); m_init = true; sort* A = m.mk_uninterpreted_sort(symbol(0u)); + sort* B = m.mk_uninterpreted_sort(symbol(1u)); sort* strT = m_string; parameter paramA(A); + parameter paramB(B); parameter paramS(strT); sort* seqA = m.mk_sort(m_family_id, SEQ_SORT, 1, ¶mA); + sort* seqB = m.mk_sort(m_family_id, SEQ_SORT, 1, ¶mB); parameter paramSA(seqA); sort* reA = m.mk_sort(m_family_id, RE_SORT, 1, ¶mSA); sort* reT = m.mk_sort(m_family_id, RE_SORT, 1, ¶mS); sort* boolT = m.mk_bool_sort(); sort* intT = arith_util(m).mk_int(); - sort* predA = array_util(m).mk_array_sort(A, boolT); + sort* predA = autil.mk_array_sort(A, boolT); + sort* arrAB = autil.mk_array_sort(A, B); + sort* arrIAB = autil.mk_array_sort(intT, A, B); + sort* arrBAB = autil.mk_array_sort(B, A, B); + sort* arrIBAB = autil.mk_array_sort(intT, B, A, B); sort* seqAseqAseqA[3] = { seqA, seqA, seqA }; sort* seqAreAseqA[3] = { seqA, reA, seqA }; sort* seqAseqA[2] = { seqA, seqA }; @@ -209,6 +217,11 @@ void seq_decl_plugin::init() { sort* str2TintT[3] = { strT, strT, intT }; sort* seqAintT[2] = { seqA, intT }; sort* seq3A[3] = { seqA, seqA, seqA }; + sort* arrABseqA[2] = { arrAB, seqA }; + sort* arrIABintTseqA[3] = { arrIAB, intT, seqA }; + sort* arrBAB_BseqA[3] = { arrBAB, B,seqA }; + sort* arrIBABintTBseqA[4] = { arrIBAB, intT, B, seqA }; + m_sigs.resize(LAST_SEQ_OP); // TBD: have (par ..) construct and load parameterized signature from premable. m_sigs[OP_SEQ_UNIT] = alloc(psig, m, "seq.unit", 1, 1, &A, seqA); @@ -226,6 +239,10 @@ void seq_decl_plugin::init() { m_sigs[OP_SEQ_NTH_I] = alloc(psig, m, "seq.nth_i", 1, 2, seqAintT, A); m_sigs[OP_SEQ_NTH_U] = alloc(psig, m, "seq.nth_u", 1, 2, seqAintT, A); m_sigs[OP_SEQ_LENGTH] = alloc(psig, m, "seq.len", 1, 1, &seqA, intT); + m_sigs[OP_SEQ_MAP] = alloc(psig, m, "seq.map", 2, 2, arrABseqA, seqB); + m_sigs[OP_SEQ_MAPI] = alloc(psig, m, "seq.mapi", 2, 3, arrIABintTseqA, seqB); + m_sigs[OP_SEQ_FOLDL] = alloc(psig, m, "seq.fold_left", 2, 3, arrBAB_BseqA, B); + m_sigs[OP_SEQ_FOLDLI] = alloc(psig, m, "seq.fold_leftli", 2, 4, arrIBABintTBseqA, B); m_sigs[OP_RE_PLUS] = alloc(psig, m, "re.+", 1, 1, &reA, reA); m_sigs[OP_RE_STAR] = alloc(psig, m, "re.*", 1, 1, &reA, reA); m_sigs[OP_RE_OPTION] = alloc(psig, m, "re.opt", 1, 1, &reA, reA); @@ -582,6 +599,12 @@ func_decl* seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p case _OP_STRING_STRCTN: return mk_str_fun(k, arity, domain, range, OP_SEQ_CONTAINS); + case OP_SEQ_MAP: + case OP_SEQ_MAPI: + case OP_SEQ_FOLDL: + case OP_SEQ_FOLDLI: + return mk_str_fun(k, arity, domain, range, k); + case OP_SEQ_TO_RE: m_has_re = true; return mk_seq_fun(k, arity, domain, range, _OP_STRING_TO_REGEXP); diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index ddde7fa6a..03cfef033 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -55,7 +55,11 @@ enum seq_op_kind { OP_SEQ_REPLACE_RE_ALL, // Seq -> RegEx -> Seq -> Seq OP_SEQ_REPLACE_RE, // Seq -> RegEx -> Seq -> Seq OP_SEQ_REPLACE_ALL, // Seq -> Seq -> Seq -> Seq - + OP_SEQ_MAP, // Array[A,B] -> Seq[A] -> Seq[B] + OP_SEQ_MAPI, // Array[Int,A,B] -> Int -> Seq[A] -> Seq[B] + OP_SEQ_FOLDL, // Array[B,A,B] -> B -> Seq[A] -> B + OP_SEQ_FOLDLI, // Array[Int,B,A,B] -> Int -> B -> Seq[A] -> B + OP_RE_PLUS, OP_RE_STAR, OP_RE_OPTION, @@ -296,6 +300,10 @@ public: app* mk_nth_i(expr* s, expr* i) const { expr* es[2] = { s, i }; return m.mk_app(m_fid, OP_SEQ_NTH_I, 2, es); } app* mk_nth_u(expr* s, expr* i) const { expr* es[2] = { s, i }; return m.mk_app(m_fid, OP_SEQ_NTH_U, 2, es); } app* mk_nth_c(expr* s, unsigned i) const; + app* mk_map(expr* f, expr* s) const { expr* es[2] = { f, s }; return m.mk_app(m_fid, OP_SEQ_MAP, 2, es); } + app* mk_mapi(expr* f, expr* i, expr* s) const { expr* es[3] = { f, i, s }; return m.mk_app(m_fid, OP_SEQ_MAPI, 3, es); } + app* mk_foldl(expr* f, expr* b, expr* s) const { expr* es[3] = { f, b, s }; return m.mk_app(m_fid, OP_SEQ_FOLDL, 3, es); } + app* mk_foldli(expr* f, expr* i, expr* b, expr* s) const { expr* es[4] = { f, i, b, s }; return m.mk_app(m_fid, OP_SEQ_FOLDLI, 4, es); } app* mk_substr(expr* a, expr* b, expr* c) const { expr* es[3] = { a, b, c }; return m.mk_app(m_fid, OP_SEQ_EXTRACT, 3, es); } app* mk_contains(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONTAINS, 2, es); } @@ -333,6 +341,10 @@ public: } bool is_concat(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_CONCAT); } bool is_length(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_LENGTH); } + bool is_map(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_MAP); } + bool is_mapi(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_MAPI); } + bool is_foldl(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_FOLDL); } + bool is_foldli(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_FOLDLI); } bool is_extract(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_EXTRACT); } bool is_contains(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_CONTAINS); } bool is_at(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_AT); } @@ -384,6 +396,9 @@ public: MATCH_BINARY(is_nth_u); MATCH_BINARY(is_index); MATCH_TERNARY(is_index); + MATCH_BINARY(is_map); + MATCH_TERNARY(is_mapi); + MATCH_TERNARY(is_foldl); MATCH_BINARY(is_last_index); MATCH_TERNARY(is_replace); MATCH_TERNARY(is_replace_re); From c29cfa81aee0c68f5e6b3b4a393ddd35745a8229 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 May 2022 02:08:11 -0700 Subject: [PATCH 094/253] prep for max/min diff --- src/ast/array_decl_plugin.cpp | 20 ++++++++++++ src/ast/array_decl_plugin.h | 6 ++++ src/sat/smt/array_axioms.cpp | 52 ++++++++++++++++++++++++++++++- src/sat/smt/array_internalize.cpp | 11 ++++++- src/sat/smt/array_solver.h | 6 ++++ 5 files changed, 93 insertions(+), 2 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 0757902f5..8b8047dd7 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -527,6 +527,19 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters return nullptr; } return mk_array_ext(arity, domain, parameters[0].get_int()); + case OP_ARRAY_MAXDIFF: + case OP_ARRAY_MINDIFF: { + if (num_parameters != 0) + m_manager->raise_exception("min/maxdiff don't take any parameters"); + if (arity != 2 || domain[0] != domain[1] || !is_array_sort(domain[0]) || 1 != get_array_arity(domain[0])) + m_manager->raise_exception("min/maxdiff don't take two arrays of same sort and with integer index"); + sort* idx = get_array_domain(domain[0], 0); + arith_util arith(*m_manager); + if (!arith.is_int(domain[0])) + m_manager->raise_exception("min/maxdiff take integer index domain"); + return m_manager->mk_func_decl(k == OP_ARRAY_MAXDIFF ? symbol("maxdiff") : symbol("mindiff"), + arity, domain, arith.mk_int(), func_decl_info(m_family_id, k)); + } case OP_ARRAY_DEFAULT: return mk_default(arity, domain); case OP_SET_UNION: @@ -587,6 +600,13 @@ 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)); + +#if 0 +// not exposed + op_names.push_back(builtin_name("mindiff", OP_ARRAY_MINDIFF)); + op_names.push_back(builtin_name("maxdiff", OP_ARRAY_MAXDIFF)); +#endif + #if 0 op_names.push_back(builtin_name("set-has-size", OP_SET_HAS_SIZE)); op_names.push_back(builtin_name("card", OP_SET_CARD)); diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 5a606a509..dd8443025 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -45,6 +45,8 @@ enum array_op_kind { OP_ARRAY_EXT, OP_ARRAY_DEFAULT, OP_ARRAY_MAP, + OP_ARRAY_MAXDIFF, + OP_ARRAY_MINDIFF, OP_SET_UNION, OP_SET_INTERSECT, OP_SET_DIFFERENCE, @@ -157,6 +159,8 @@ public: bool is_complement(expr* n) const { return is_app_of(n, m_fid, OP_SET_COMPLEMENT); } 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_maxdiff(expr const* n) const { return is_app_of(n, m_fid, OP_ARRAY_MAXDIFF); } + bool is_mindiff(expr const* n) const { return is_app_of(n, m_fid, OP_ARRAY_MINDIFF); } bool is_set_has_size(expr* e) const { return is_app_of(e, m_fid, OP_SET_HAS_SIZE); } bool is_set_card(expr* e) const { return is_app_of(e, m_fid, OP_SET_CARD); } bool is_select(func_decl* f) const { return is_decl_of(f, m_fid, OP_SELECT); } @@ -182,6 +186,8 @@ public: bool is_store_ext(expr* e, expr_ref& a, expr_ref_vector& args, expr_ref& value); MATCH_BINARY(is_subset); + MATCH_BINARY(is_maxdiff); + MATCH_BINARY(is_mindiff); }; class array_util : public array_recognizers { diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index 84b12cf7d..40be702b1 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -59,13 +59,15 @@ namespace array { axiom_record& r = m_axiom_trail[idx]; switch (r.m_kind) { case axiom_record::kind_t::is_store: - return assert_store_axiom(to_app(r.n->get_expr())); + return assert_store_axiom(r.n->get_app()); case axiom_record::kind_t::is_select: return assert_select(idx, r); case axiom_record::kind_t::is_default: return assert_default(r); case axiom_record::kind_t::is_extensionality: return assert_extensionality(r.n->get_expr(), r.select->get_expr()); + case axiom_record::kind_t::is_diff: + return assert_diff(r.n->get_app()); case axiom_record::kind_t::is_congruence: return assert_congruent_axiom(r.n->get_expr(), r.select->get_expr()); default: @@ -273,6 +275,54 @@ namespace array { return add_clause(lit1, ~lit2); } + /** + * a = b or default(a) != default(b) or a[md(a,b)] != b[md(a,b)] + */ + bool solver::assert_diff(expr* md) { + expr* x, *y; + SASSERT(a.is_maxdiff(md, x, y) || a.is_mindiff(md, x, y)); + expr* args1[2] = { x, md }; + expr* args2[2] = { y, md }; + literal eq = eq_internalize(x, y); + literal eq_default = eq_internalize(a.mk_default(x), a.mk_default(y)); + literal eq_md = eq_internalize(a.mk_select(2, args1), a.mk_select(2, args2)); + return add_clause(eq, ~eq_default, ~eq_md); + } + + /** + * a = b and a[i] != c[i] => i <= md(b, c) or default(b) != default(c) + * a = c and a[i] != b[i] => i <= md(b, c) or default(b) != default(c) + * where ai = a[i], md = md(b, c) + */ + bool solver::assert_diff_select(app* ai, app* md) { + SASSERT(a.is_select(ai)); + SASSERT(ai->get_num_args() == 2); + expr* A = ai->get_arg(0); + expr* i = ai->get_arg(1); + expr* B = md->get_arg(0); + expr* C = md->get_arg(1); + literal eq_default = eq_internalize(a.mk_default(B), a.mk_default(C)); + arith_util autil(m); + literal ineq = mk_literal(autil.mk_le(i, md)); + bool is_new = false; + if (ctx.get_enode(A)->get_root() == ctx.get_enode(B)->get_root()) { + literal eq_ab = eq_internalize(A, B); + expr* args[2] = { C, i }; + literal eq_select = eq_internalize(ai, a.mk_select(2, args)); + if (add_clause(~eq_ab, eq_select, ineq, ~eq_default)) + is_new = true; + } + + if (ctx.get_enode(A)->get_root() == ctx.get_enode(C)->get_root()) { + literal eq_ac = eq_internalize(A, C); + expr* args[2] = { B, i }; + literal eq_select = eq_internalize(ai, a.mk_select(2, args)); + if (add_clause(~eq_ac, eq_select, ineq, ~eq_default)) + is_new = true; + } + return is_new; + } + bool solver::is_map_combinator(expr* map) const { return a.is_map(map) || a.is_union(map) || a.is_intersect(map) || a.is_difference(map) || a.is_complement(map); } diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index e1d0d4b33..a83bce1e9 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -99,7 +99,8 @@ namespace array { } void solver::internalize_eh(euf::enode* n) { - switch (n->get_decl()->get_decl_kind()) { + auto k = n->get_decl()->get_decl_kind(); + switch (k) { case OP_STORE: ctx.push_vec(get_var_data(find(n)).m_lambdas, n); push_axiom(store_axiom(n)); @@ -114,6 +115,10 @@ namespace array { SASSERT(is_array(n->get_arg(0))); push_axiom(extensionality_axiom(n->get_arg(0), n->get_arg(1))); break; + case OP_ARRAY_MINDIFF: + case OP_ARRAY_MAXDIFF: + push_axiom(diff_axiom(n)); + break; case OP_ARRAY_DEFAULT: add_parent_default(find(n->get_arg(0)), n); break; @@ -169,6 +174,10 @@ namespace array { break; case OP_ARRAY_EXT: break; + case OP_ARRAY_MINDIFF: + case OP_ARRAY_MAXDIFF: + // todo + break; case OP_ARRAY_DEFAULT: set_prop_upward(find(n->get_arg(0))); break; diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index 511f971a3..4ad27842b 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -83,6 +83,8 @@ namespace array { is_store, is_select, is_extensionality, + is_diff, + is_diffselect, is_default, is_congruence }; @@ -163,6 +165,8 @@ namespace array { axiom_record store_axiom(euf::enode* n) { return axiom_record(axiom_record::kind_t::is_store, n); } axiom_record extensionality_axiom(euf::enode* x, euf::enode* y) { return axiom_record(axiom_record::kind_t::is_extensionality, x, y); } axiom_record congruence_axiom(euf::enode* a, euf::enode* b) { return axiom_record(axiom_record::kind_t::is_congruence, a, b); } + axiom_record diff_axiom(euf::enode* md) { return axiom_record(axiom_record::kind_t::is_diff, md); } + axiom_record diff_select_axiom(euf::enode* ai, euf::enode* md) { return axiom_record(axiom_record::kind_t::is_diffselect, ai, md); } scoped_ptr m_constraint; @@ -175,6 +179,8 @@ namespace array { bool assert_select_map_axiom(app* select, app* map); bool assert_select_lambda_axiom(app* select, expr* lambda); bool assert_extensionality(expr* e1, expr* e2); + bool assert_diff(expr* md); + bool assert_diff_select(app* ai, app* md); bool assert_default_map_axiom(app* map); bool assert_default_const_axiom(app* cnst); bool assert_default_store_axiom(app* store); From 367bfedab0f984ec7aefcb98cb1d6c088abf0dac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 May 2022 07:39:38 -0700 Subject: [PATCH 095/253] add min/max diff in final check Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 51 +++++++++++++++++++++---------- src/ast/seq_decl_plugin.h | 3 ++ src/sat/smt/array_axioms.cpp | 27 ++++++++++++++-- src/sat/smt/array_internalize.cpp | 2 ++ src/sat/smt/array_solver.cpp | 7 ++++- src/sat/smt/array_solver.h | 10 +++--- 6 files changed, 77 insertions(+), 23 deletions(-) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 77179a263..8b859d587 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -198,10 +198,6 @@ void seq_decl_plugin::init() { sort* boolT = m.mk_bool_sort(); sort* intT = arith_util(m).mk_int(); sort* predA = autil.mk_array_sort(A, boolT); - sort* arrAB = autil.mk_array_sort(A, B); - sort* arrIAB = autil.mk_array_sort(intT, A, B); - sort* arrBAB = autil.mk_array_sort(B, A, B); - sort* arrIBAB = autil.mk_array_sort(intT, B, A, B); sort* seqAseqAseqA[3] = { seqA, seqA, seqA }; sort* seqAreAseqA[3] = { seqA, reA, seqA }; sort* seqAseqA[2] = { seqA, seqA }; @@ -217,10 +213,6 @@ void seq_decl_plugin::init() { sort* str2TintT[3] = { strT, strT, intT }; sort* seqAintT[2] = { seqA, intT }; sort* seq3A[3] = { seqA, seqA, seqA }; - sort* arrABseqA[2] = { arrAB, seqA }; - sort* arrIABintTseqA[3] = { arrIAB, intT, seqA }; - sort* arrBAB_BseqA[3] = { arrBAB, B,seqA }; - sort* arrIBABintTBseqA[4] = { arrIBAB, intT, B, seqA }; m_sigs.resize(LAST_SEQ_OP); // TBD: have (par ..) construct and load parameterized signature from premable. @@ -239,10 +231,6 @@ void seq_decl_plugin::init() { m_sigs[OP_SEQ_NTH_I] = alloc(psig, m, "seq.nth_i", 1, 2, seqAintT, A); m_sigs[OP_SEQ_NTH_U] = alloc(psig, m, "seq.nth_u", 1, 2, seqAintT, A); m_sigs[OP_SEQ_LENGTH] = alloc(psig, m, "seq.len", 1, 1, &seqA, intT); - m_sigs[OP_SEQ_MAP] = alloc(psig, m, "seq.map", 2, 2, arrABseqA, seqB); - m_sigs[OP_SEQ_MAPI] = alloc(psig, m, "seq.mapi", 2, 3, arrIABintTseqA, seqB); - m_sigs[OP_SEQ_FOLDL] = alloc(psig, m, "seq.fold_left", 2, 3, arrBAB_BseqA, B); - m_sigs[OP_SEQ_FOLDLI] = alloc(psig, m, "seq.fold_leftli", 2, 4, arrIBABintTBseqA, B); m_sigs[OP_RE_PLUS] = alloc(psig, m, "re.+", 1, 1, &reA, reA); m_sigs[OP_RE_STAR] = alloc(psig, m, "re.*", 1, 1, &reA, reA); m_sigs[OP_RE_OPTION] = alloc(psig, m, "re.opt", 1, 1, &reA, reA); @@ -290,6 +278,7 @@ void seq_decl_plugin::init() { m_sigs[_OP_STRING_SUBSTR] = alloc(psig, m, "str.substr", 0, 3, strTint2T, strT); } + sort* seq_decl_plugin::mk_reglan() { if (!m_reglan) { ast_manager& m = *m_manager; @@ -603,7 +592,8 @@ func_decl* seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p case OP_SEQ_MAPI: case OP_SEQ_FOLDL: case OP_SEQ_FOLDLI: - return mk_str_fun(k, arity, domain, range, k); + add_map_sig(); + return mk_str_fun(k, arity, domain, range, k); case OP_SEQ_TO_RE: m_has_re = true; @@ -648,13 +638,42 @@ func_decl* seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p } } +void seq_decl_plugin::add_map_sig() { + if (m_sigs[OP_SEQ_MAP]) + return; + ast_manager& m = *m_manager; + array_util autil(m); + sort* A = m.mk_uninterpreted_sort(symbol(0u)); + sort* B = m.mk_uninterpreted_sort(symbol(1u)); + parameter paramA(A); + parameter paramB(B); + sort* seqA = m.mk_sort(m_family_id, SEQ_SORT, 1, ¶mA); + sort* seqB = m.mk_sort(m_family_id, SEQ_SORT, 1, ¶mB); + sort* intT = arith_util(m).mk_int(); + sort* arrAB = autil.mk_array_sort(A, B); + sort* arrIAB = autil.mk_array_sort(intT, A, B); + sort* arrBAB = autil.mk_array_sort(B, A, B); + sort* arrIBAB = autil.mk_array_sort(intT, B, A, B); + sort* arrABseqA[2] = { arrAB, seqA }; + sort* arrIABintTseqA[3] = { arrIAB, intT, seqA }; + sort* arrBAB_BseqA[3] = { arrBAB, B,seqA }; + sort* arrIBABintTBseqA[4] = { arrIBAB, intT, B, seqA }; + m_sigs[OP_SEQ_MAP] = alloc(psig, m, "seq.map", 2, 2, arrABseqA, seqB); + m_sigs[OP_SEQ_MAPI] = alloc(psig, m, "seq.mapi", 2, 3, arrIABintTseqA, seqB); + m_sigs[OP_SEQ_FOLDL] = alloc(psig, m, "seq.fold_left", 2, 3, arrBAB_BseqA, B); + m_sigs[OP_SEQ_FOLDLI] = alloc(psig, m, "seq.fold_leftli", 2, 4, arrIBABintTBseqA, B); +} + void seq_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { init(); for (unsigned i = 0; i < m_sigs.size(); ++i) { - if (m_sigs[i]) { - op_names.push_back(builtin_name(m_sigs[i]->m_name.str(), i)); - } + if (m_sigs[i]) + op_names.push_back(builtin_name(m_sigs[i]->m_name.str(), i)); } + op_names.push_back(builtin_name("seq.map", OP_SEQ_MAP)); + op_names.push_back(builtin_name("seq.mapi", OP_SEQ_MAPI)); + op_names.push_back(builtin_name("seq.foldl", OP_SEQ_FOLDL)); + op_names.push_back(builtin_name("seq.foldli", OP_SEQ_FOLDLI)); op_names.push_back(builtin_name("str.in.re", _OP_STRING_IN_REGEXP)); op_names.push_back(builtin_name("str.in-re", _OP_STRING_IN_REGEXP)); op_names.push_back(builtin_name("str.to.re", _OP_STRING_TO_REGEXP)); diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 03cfef033..29d7b08ef 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -140,6 +140,9 @@ class seq_decl_plugin : public decl_plugin { bool m_has_seq; char_decl_plugin* m_char_plugin { nullptr }; + + void add_map_sig(); + void match(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng); void match_assoc(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng); diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index 40be702b1..613d7a17c 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -68,6 +68,8 @@ namespace array { return assert_extensionality(r.n->get_expr(), r.select->get_expr()); case axiom_record::kind_t::is_diff: return assert_diff(r.n->get_app()); + case axiom_record::kind_t::is_diffselect: + return assert_diff_select(r.n->get_app(), r.select->get_app()); case axiom_record::kind_t::is_congruence: return assert_congruent_axiom(r.n->get_expr(), r.select->get_expr()); default: @@ -294,7 +296,7 @@ namespace array { * a = c and a[i] != b[i] => i <= md(b, c) or default(b) != default(c) * where ai = a[i], md = md(b, c) */ - bool solver::assert_diff_select(app* ai, app* md) { + bool solver::assert_diff_select(app* md, app* ai) { SASSERT(a.is_select(ai)); SASSERT(ai->get_num_args() == 2); expr* A = ai->get_arg(0); @@ -303,7 +305,7 @@ namespace array { expr* C = md->get_arg(1); literal eq_default = eq_internalize(a.mk_default(B), a.mk_default(C)); arith_util autil(m); - literal ineq = mk_literal(autil.mk_le(i, md)); + literal ineq = mk_literal(a.is_maxdiff(md) ? autil.mk_le(i, md) : autil.mk_le(md, i)); bool is_new = false; if (ctx.get_enode(A)->get_root() == ctx.get_enode(B)->get_root()) { literal eq_ab = eq_internalize(A, B); @@ -714,5 +716,26 @@ namespace array { return false; } + bool solver::add_diff_select_axioms() { + bool added = false; + + auto add_diff_select = [&](euf::enode* md, euf::enode* a) { + var_data const& d = get_var_data(find(get_th_var(a))); + for (euf::enode* select : d.m_parent_selects) { + if (assert_diff_select(md->get_app(), select->get_app())) + added = true; + } + }; + for (euf::enode* md : m_minmaxdiffs) { + euf::enode* a = md->get_arg(0); + euf::enode* b = md->get_arg(1); + add_diff_select(md, a); + add_diff_select(md, b); + } + return added; + } + + + } diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index a83bce1e9..030018088 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -118,6 +118,8 @@ namespace array { case OP_ARRAY_MINDIFF: case OP_ARRAY_MAXDIFF: push_axiom(diff_axiom(n)); + m_minmaxdiffs.push_back(n); + ctx.push(push_back_vector(m_minmaxdiffs)); break; case OP_ARRAY_DEFAULT: add_parent_default(find(n->get_arg(0)), n); diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp index f2836d9aa..eb8986098 100644 --- a/src/sat/smt/array_solver.cpp +++ b/src/sat/smt/array_solver.cpp @@ -101,9 +101,14 @@ namespace array { else if (!turn[idx] && add_interface_equalities()) return sat::check_result::CR_CONTINUE; } - if (m_delay_qhead < m_axiom_trail.size()) + + if (add_diff_select_axioms()) return sat::check_result::CR_CONTINUE; + if (m_delay_qhead < m_axiom_trail.size()) + return sat::check_result::CR_CONTINUE; + + // validate_check(); return sat::check_result::CR_DONE; } diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index 4ad27842b..239de0904 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -147,9 +147,9 @@ namespace array { axiom_record::eq m_eq; axiom_table_t m_axioms; svector m_axiom_trail; - unsigned m_qhead { 0 }; - unsigned m_delay_qhead { 0 }; - bool m_enable_delay { true }; + unsigned m_qhead = 0; + unsigned m_delay_qhead = 0; + bool m_enable_delay = true; struct reset_new; void push_axiom(axiom_record const& r); bool propagate_axiom(unsigned idx); @@ -166,7 +166,8 @@ namespace array { axiom_record extensionality_axiom(euf::enode* x, euf::enode* y) { return axiom_record(axiom_record::kind_t::is_extensionality, x, y); } axiom_record congruence_axiom(euf::enode* a, euf::enode* b) { return axiom_record(axiom_record::kind_t::is_congruence, a, b); } axiom_record diff_axiom(euf::enode* md) { return axiom_record(axiom_record::kind_t::is_diff, md); } - axiom_record diff_select_axiom(euf::enode* ai, euf::enode* md) { return axiom_record(axiom_record::kind_t::is_diffselect, ai, md); } + euf::enode_vector m_minmaxdiffs; + axiom_record diff_select_axiom(euf::enode* md, euf::enode* ai) { return axiom_record(axiom_record::kind_t::is_diffselect, md, ai); } scoped_ptr m_constraint; @@ -187,6 +188,7 @@ namespace array { bool assert_congruent_axiom(expr* e1, expr* e2); bool add_delayed_axioms(); bool add_as_array_eqs(euf::enode* n); + bool add_diff_select_axioms(); expr_ref apply_map(app* map, unsigned n, expr* const* args); bool is_map_combinator(expr* e) const; From 5a685ba9b5e1cab470acbe0a378466bf44d15ae9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 May 2022 08:52:42 -0700 Subject: [PATCH 096/253] expose maxdiff Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.cpp | 5 +---- src/ast/seq_decl_plugin.cpp | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 8b8047dd7..31bbaac1e 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -535,7 +535,7 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters m_manager->raise_exception("min/maxdiff don't take two arrays of same sort and with integer index"); sort* idx = get_array_domain(domain[0], 0); arith_util arith(*m_manager); - if (!arith.is_int(domain[0])) + if (!arith.is_int(idx)) m_manager->raise_exception("min/maxdiff take integer index domain"); return m_manager->mk_func_decl(k == OP_ARRAY_MAXDIFF ? symbol("maxdiff") : symbol("mindiff"), arity, domain, arith.mk_int(), func_decl_info(m_family_id, k)); @@ -601,11 +601,8 @@ void array_decl_plugin::get_op_names(svector& op_names, symbol con op_names.push_back(builtin_name("as-array", OP_AS_ARRAY)); op_names.push_back(builtin_name("array-ext", OP_ARRAY_EXT)); -#if 0 -// not exposed op_names.push_back(builtin_name("mindiff", OP_ARRAY_MINDIFF)); op_names.push_back(builtin_name("maxdiff", OP_ARRAY_MAXDIFF)); -#endif #if 0 op_names.push_back(builtin_name("set-has-size", OP_SET_HAS_SIZE)); diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 8b859d587..95b9b8579 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -185,13 +185,10 @@ void seq_decl_plugin::init() { array_util autil(m); m_init = true; sort* A = m.mk_uninterpreted_sort(symbol(0u)); - sort* B = m.mk_uninterpreted_sort(symbol(1u)); sort* strT = m_string; parameter paramA(A); - parameter paramB(B); parameter paramS(strT); sort* seqA = m.mk_sort(m_family_id, SEQ_SORT, 1, ¶mA); - sort* seqB = m.mk_sort(m_family_id, SEQ_SORT, 1, ¶mB); parameter paramSA(seqA); sort* reA = m.mk_sort(m_family_id, RE_SORT, 1, ¶mSA); sort* reT = m.mk_sort(m_family_id, RE_SORT, 1, ¶mS); From ffbabf251d81e63aebebc1e00af4c2f2818b8acc Mon Sep 17 00:00:00 2001 From: Sacha Ayoun Date: Wed, 4 May 2022 20:03:22 +0100 Subject: [PATCH 097/253] enhance ocaml seq api (#6010) Signed-off-by: Sacha Ayoun --- src/api/ml/z3.ml | 8 ++++++++ src/api/ml/z3.mli | 18 +++++++++++++++++- src/api/z3_api.h | 4 ++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index b551688c5..36753a4f9 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -916,6 +916,12 @@ struct let mk_sort_s (ctx:context) (name:string) (constructors:Constructor.constructor list) = mk_sort ctx (Symbol.mk_string ctx name) constructors + + let mk_sort_ref (ctx: context) (name:Symbol.symbol) = + Z3native.mk_datatype_sort ctx name + + let mk_sort_ref_s (ctx: context) (name: string) = + mk_sort_ref ctx (Symbol.mk_string ctx name) let mk_sorts (ctx:context) (names:Symbol.symbol list) (c:Constructor.constructor list list) = let n = List.length names in @@ -1260,7 +1266,9 @@ struct let mk_seq_replace = Z3native.mk_seq_replace let mk_seq_at = Z3native.mk_seq_at let mk_seq_length = Z3native.mk_seq_length + let mk_seq_nth = Z3native.mk_seq_nth let mk_seq_index = Z3native.mk_seq_index + let mk_seq_last_index = Z3native.mk_seq_last_index let mk_str_to_int = Z3native.mk_str_to_int let mk_str_le = Z3native.mk_str_le let mk_str_lt = Z3native.mk_str_lt diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 08e0a6747..74320dd72 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -1061,6 +1061,15 @@ sig if the corresponding sort reference is 0, then the value in sort_refs should be an index referring to one of the recursive datatypes that is declared. *) val mk_constructor_s : context -> string -> Symbol.symbol -> Symbol.symbol list -> Sort.sort option list -> int list -> Constructor.constructor + + (* Create a forward reference to a recursive datatype being declared. + The forward reference can be used in a nested occurrence: the range of an array + or as element sort of a sequence. The forward reference should only be used when + used in an accessor for a recursive datatype that gets declared. *) + val mk_sort_ref : context -> Symbol.symbol -> Sort.sort + + (* [mk_sort_ref_s ctx s] is [mk_sort_ref ctx (Symbol.mk_string ctx s)] *) + val mk_sort_ref_s : context -> string -> Sort.sort (** Create a new datatype sort. *) val mk_sort : context -> Symbol.symbol -> Constructor.constructor list -> Sort.sort @@ -1858,7 +1867,7 @@ sig (** create regular expression sorts over sequences of the argument sort *) val mk_re_sort : context -> Sort.sort -> Sort.sort - + (** test if sort is a regular expression sort *) val is_re_sort : context -> Sort.sort -> bool @@ -1906,10 +1915,17 @@ sig (** length of a sequence *) val mk_seq_length : context -> Expr.expr -> Expr.expr + + (** [mk_seq_nth ctx s index] retrieves from [s] the element at position [index]. + The function is under-specified if the index is out of bounds. *) + val mk_seq_nth : context -> Expr.expr -> Expr.expr -> Expr.expr (** index of the first occurrence of the second argument in the first *) val mk_seq_index : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr + (** [mk_seq_last_index ctx s substr] occurence of [substr] in the sequence [s] *) + val mk_seq_last_index : context -> Expr.expr -> Expr.expr -> Expr.expr + (** retrieve integer expression encoded in string *) val mk_str_to_int : context -> Expr.expr -> Expr.expr diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 7ca693984..13c4131bb 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3710,7 +3710,7 @@ extern "C" { /** - \brief Return index of first occurrence of \c substr in \c s starting from offset \c offset. + \brief Return index of the 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 value is -1 if \c offset is negative or larger than the length of \c s. @@ -3719,7 +3719,7 @@ extern "C" { 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. + \brief Return index of 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))) */ From 47459ca795fa2b050c744bc0b047acbcff28a3d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 May 2022 12:04:51 -0700 Subject: [PATCH 098/253] pre-release Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index f878265d6..e16aa0281 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -519,7 +519,7 @@ stages: # Enable on release: - job: PyPIPublish - condition: eq(1,1) + condition: eq(0,1) displayName: "Publish to PyPI" pool: vmImage: "ubuntu-latest" From cf1802dac7e1e47c557475008c481aee86e7808b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 May 2022 12:07:54 -0700 Subject: [PATCH 099/253] release notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 449d6fc69..e9c5c1fd7 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -10,6 +10,14 @@ Version 4.8.next - native word level bit-vector solving. - introduction of simple induction lemmas to handle a limited repertoire of induction proofs. +Version 4.8.17 +============== + - fix breaking bug in python interface for user propagator pop + - integrate fixes to z3str3 + - initial support for nested algebraic datatypes with sequences + - initiate map/fold operators on sequences - full integration for next releases + - initiate maxdiff/mindiff on arrays - full integration for next releases + Version 4.8.16 ============== - initial support for Darwin Arm64 (for M1, M2, .. users) thanks to zwimer and Anja Petkovi'c From d420706eaed675f7a83fc9f5c76efee3ab5b3e7b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 May 2022 17:16:30 -0700 Subject: [PATCH 100/253] enable pypi release Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index e16aa0281..f878265d6 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -519,7 +519,7 @@ stages: # Enable on release: - job: PyPIPublish - condition: eq(0,1) + condition: eq(1,1) displayName: "Publish to PyPI" pool: vmImage: "ubuntu-latest" From 3ae781039b43d6e8452d1ec6f6b4cb3dd84bdffc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 5 May 2022 07:09:54 -0700 Subject: [PATCH 101/253] inc version number Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- scripts/nightly.yaml | 2 +- scripts/release.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 640dda928..9b0d111e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake") -project(Z3 VERSION 4.8.17.0 LANGUAGES CXX) +project(Z3 VERSION 4.8.18.0 LANGUAGES CXX) ################################################################################ # Project version diff --git a/scripts/mk_project.py b/scripts/mk_project.py index c855bc27c..ccc855734 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -8,7 +8,7 @@ from mk_util import * def init_version(): - set_version(4, 8, 17, 0) + set_version(4, 8, 18, 0) # Z3 Project definition def init_project_def(): diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 73a3aaec7..416cb1889 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -2,7 +2,7 @@ variables: Major: '4' Minor: '8' - Patch: '17' + Patch: '18' NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName) stages: diff --git a/scripts/release.yml b/scripts/release.yml index f878265d6..265230198 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -6,7 +6,7 @@ trigger: none variables: - ReleaseVersion: '4.8.17' + ReleaseVersion: '4.8.18' stages: From 14214c5a074c058524f65955a7a7cda7cbc31cb3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 May 2022 11:08:40 -0700 Subject: [PATCH 102/253] exposing user propagators over .Net Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 50 +++++- src/api/dotnet/CMakeLists.txt | 1 + src/api/dotnet/UserPropagator.cs | 222 +++++++++++++++++++++++++ src/api/z3_api.h | 15 +- src/muz/spacer/spacer_generalizers.cpp | 20 +-- src/sat/sat_solver.h | 2 +- src/sat/smt/arith_solver.cpp | 4 + 7 files changed, 296 insertions(+), 18 deletions(-) create mode 100644 src/api/dotnet/UserPropagator.cs diff --git a/scripts/update_api.py b/scripts/update_api.py index d4d1ab0e0..b9da427df 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -42,6 +42,7 @@ IN_ARRAY = 3 OUT_ARRAY = 4 INOUT_ARRAY = 5 OUT_MANAGED_ARRAY = 6 +FN_PTR = 7 # Primitive Types VOID = 0 @@ -61,11 +62,16 @@ FLOAT = 13 CHAR = 14 CHAR_PTR = 15 +FIRST_FN_ID = 50 + FIRST_OBJ_ID = 100 def is_obj(ty): return ty >= FIRST_OBJ_ID +def is_fn(ty): + return FIRST_FN_ID <= ty and ty < FIRST_OBJ_ID + Type2Str = { VOID : 'void', VOID_PTR : 'void*', INT : 'int', UINT : 'unsigned', INT64 : 'int64_t', UINT64 : 'uint64_t', DOUBLE : 'double', FLOAT : 'float', STRING : 'Z3_string', STRING_PTR : 'Z3_string_ptr', BOOL : 'bool', SYMBOL : 'Z3_symbol', PRINT_MODE : 'Z3_ast_print_mode', ERROR_CODE : 'Z3_error_code', CHAR: 'char', CHAR_PTR: 'Z3_char_ptr' @@ -88,9 +94,12 @@ Type2ML = { VOID : 'unit', VOID_PTR : 'VOIDP', INT : 'int', UINT : 'int', INT64 FLOAT : 'float', STRING : 'string', STRING_PTR : 'char**', BOOL : 'bool', SYMBOL : 'z3_symbol', PRINT_MODE : 'int', ERROR_CODE : 'int', CHAR : 'char', CHAR_PTR : 'string' } +Closures = [] + class APITypes: def __init__(self): self.next_type_id = FIRST_OBJ_ID + self.next_fntype_id = FIRST_FN_ID def def_Type(self, var, c_type, py_type): """Process type definitions of the form def_Type(var, c_type, py_type) @@ -103,24 +112,42 @@ class APITypes: Type2Str[id] = c_type Type2PyStr[id] = py_type self.next_type_id += 1 + def def_Types(self, api_files): + global Closures pat1 = re.compile(" *def_Type\(\'(.*)\',[^\']*\'(.*)\',[^\']*\'(.*)\'\)[ \t]*") + pat2 = re.compile("Z3_DECLARE_CLOSURE\((.*),(.*), \((.*)\)\)") for api_file in api_files: with open(api_file, 'r') as api: for line in api: m = pat1.match(line) if m: self.def_Type(m.group(1), m.group(2), m.group(3)) + continue + m = pat2.match(line) + if m: + self.fun_Type(m.group(1)) + Closures += [(m.group(1), m.group(2), m.group(3))] + continue # # Populate object type entries in dotnet and ML bindings. # for k in Type2Str: v = Type2Str[k] - if is_obj(k): + if is_obj(k) or is_fn(k): Type2Dotnet[k] = v Type2ML[k] = v.lower() + def fun_Type(self, var): + """Process function type definitions""" + id = self.next_fntype_id + exec('%s = %s' % (var, id), globals()) + Type2Str[id] = var + Type2PyStr[id] = var + self.next_fntype_id += 1 + + def type2str(ty): global Type2Str return Type2Str[ty] @@ -147,6 +174,9 @@ def _in(ty): def _in_array(sz, ty): return (IN_ARRAY, ty, sz) +def _fnptr(ty): + return (FN_PTR, ty) + def _out(ty): return (OUT, ty) @@ -180,7 +210,7 @@ def param_array_size_pos(p): def param2str(p): if param_kind(p) == IN_ARRAY: return "%s const *" % type2str(param_type(p)) - elif param_kind(p) == OUT_ARRAY or param_kind(p) == IN_ARRAY or param_kind(p) == INOUT_ARRAY: + elif param_kind(p) == OUT_ARRAY or param_kind(p) == IN_ARRAY or param_kind(p) == INOUT_ARRAY or param_kind(p) == FN_PTR: return "%s*" % type2str(param_type(p)) elif param_kind(p) == OUT: return "%s*" % type2str(param_type(p)) @@ -374,11 +404,20 @@ def mk_dotnet(dotnet): v = Type2Str[k] if is_obj(k): dotnet.write(' using %s = System.IntPtr;\n' % v) + + dotnet.write(' using voidp = System.IntPtr;\n') dotnet.write('\n') dotnet.write(' public class Native\n') dotnet.write(' {\n\n') - dotnet.write(' [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n') - dotnet.write(' public delegate void Z3_error_handler(Z3_context c, Z3_error_code e);\n\n') + + for name, ret, sig in Closures: + sig = sig.replace("void*","voidp").replace("unsigned","uint") + ret = ret.replace("void*","voidp").replace("unsigned","uint") + if "*" in sig or "*" in ret: + continue + dotnet.write(' [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n') + dotnet.write(f" public delegate {ret} {name}({sig});\n") + dotnet.write(' public class LIB\n') dotnet.write(' {\n') dotnet.write(' const string Z3_DLL_NAME = \"libz3\";\n' @@ -1070,6 +1109,9 @@ def def_API(name, result, params): log_c.write(" }\n") log_c.write(" Ap(%s);\n" % sz_e) exe_c.write("reinterpret_cast<%s**>(in.get_obj_array(%s))" % (tstr, i)) + elif kind == FN_PTR: + log_c.write(" P(a%s);\n" % i) + exe_c.write("reinterpret_cast<%s>(in.get_obj(%s))" % (param2str(p), i)) else: error ("unsupported parameter for %s, %s" % (name, p)) i = i + 1 diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index e2055cd7a..1e9f598e7 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -113,6 +113,7 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE Tactic.cs TupleSort.cs UninterpretedSort.cs + UserPropagator.cs Version.cs Z3Exception.cs Z3Object.cs diff --git a/src/api/dotnet/UserPropagator.cs b/src/api/dotnet/UserPropagator.cs new file mode 100644 index 000000000..8e7831390 --- /dev/null +++ b/src/api/dotnet/UserPropagator.cs @@ -0,0 +1,222 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + UserPropagator.cs + +Abstract: + + User Propagator plugin + +Author: + + Nikolaj Bjorner (nbjorner) 2022-05-07 + +Notes: + +// Todo: fresh, created, declare user function, register_cb, decide, + +--*/ + +using System; +using System.Diagnostics; +using System.Linq; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Microsoft.Z3 +{ + + using Z3_solver_callback = System.IntPtr; + using Z3_context = System.IntPtr; + using Z3_solver = System.IntPtr; + using voidp = System.IntPtr; + using Z3_ast = System.IntPtr; + + + /// + /// Propagator context for .Net + /// + public class UserPropagator + { + /// + /// Delegate type for fixed callback + /// + public delegate void FixedEh(Expr term, Expr value); + + /// + /// Delegate type for equality or disequality callback + /// + public delegate void EqEh(Expr term, Expr value); + + + Solver solver; + GCHandle gch; + Z3_solver_callback callback; + FixedEh fixed_eh; + Action final_eh; + EqEh eq_eh; + EqEh diseq_eh; + + + unsafe static void _push(voidp ctx, Z3_solver_callback cb) { + var gch = GCHandle.FromIntPtr(ctx); + var prop = (UserPropagator)gch.Target; + prop.callback = cb; + prop.Push(); + } + + unsafe static void _pop(voidp ctx, Z3_solver_callback cb, uint num_scopes) { + var gch = GCHandle.FromIntPtr(ctx); + var prop = (UserPropagator)gch.Target; + prop.callback = cb; + prop.Pop(num_scopes); + } + + unsafe static voidp _fresh(voidp ctx, Z3_context new_context) { + var gch = GCHandle.FromIntPtr(ctx); + var prop = (UserPropagator)gch.Target; + throw new Z3Exception("fresh is NYI"); + } + + unsafe static void _fixed(voidp ctx, Z3_solver_callback cb, Z3_ast _term, Z3_ast _value) { + var gch = GCHandle.FromIntPtr(ctx); + var prop = (UserPropagator)gch.Target; + var term = Expr.Create(prop.solver.Context, _term); + var value = Expr.Create(prop.solver.Context, _value); + prop.callback = cb; + prop.fixed_eh(term, value); + } + + unsafe static void _final(voidp ctx, Z3_solver_callback cb) { + var gch = GCHandle.FromIntPtr(ctx); + var prop = (UserPropagator)gch.Target; + prop.callback = cb; + prop.final_eh(); + } + + unsafe static void _eq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) { + var gch = GCHandle.FromIntPtr(ctx); + var prop = (UserPropagator)gch.Target; + var s = Expr.Create(prop.solver.Context, a); + var t = Expr.Create(prop.solver.Context, b); + prop.callback = cb; + prop.eq_eh(s, t); + } + + unsafe static void _diseq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) { + var gch = GCHandle.FromIntPtr(ctx); + var prop = (UserPropagator)gch.Target; + var s = Expr.Create(prop.solver.Context, a); + var t = Expr.Create(prop.solver.Context, b); + prop.callback = cb; + prop.diseq_eh(s, t); + } + + /// + /// Propagator constructor from a solver class. + /// + public UserPropagator(Solver s) + { + gch = GCHandle.Alloc(this); + solver = s; + var cb = GCHandle.ToIntPtr(gch); + Native.Z3_solver_propagate_init(solver.Context.nCtx, solver.NativeObject, cb, _push, _pop, _fresh); + } + + /// + /// Release provate memory. + /// + ~UserPropagator() + { + gch.Free(); + } + + /// + /// Virtual method for push. It must be overwritten by inherited class. + /// + public virtual void Push() { throw new Z3Exception("Push method should be overwritten"); } + + /// + /// Virtual method for pop. It must be overwritten by inherited class. + /// + public virtual void Pop(uint n) { throw new Z3Exception("Pop method should be overwritten"); } + + /// + /// Virtual method for fresh. It must be overwritten by inherited class. + /// + public virtual UserPropagator Fresh(Context ctx) { throw new Z3Exception("Fresh method should be overwritten"); } + + /// + /// Declare combination of assigned expressions a conflict + /// + void Conflict(params Expr[] terms) { + Propagate(terms, solver.Context.MkFalse()); + } + + /// + /// Propagate consequence + /// + void Propagate(Expr[] terms, Expr conseq) { + var nTerms = Z3Object.ArrayToNative(terms); + Native.Z3_solver_propagate_consequence(solver.Context.nCtx, this.callback, (uint)nTerms.Length, nTerms, 0u, null, null, conseq.NativeObject); + } + + + /// + /// Set fixed callback + /// + public FixedEh Fixed + { + set + { + this.fixed_eh = value; + Native.Z3_solver_propagate_fixed(solver.Context.nCtx, solver.NativeObject, _fixed); + } + } + + /// + /// Set final callback + /// + public Action Final + { + set + { + this.final_eh = value; + Native.Z3_solver_propagate_final(solver.Context.nCtx, solver.NativeObject, _final); + } + } + + /// + /// Set equality event callback + /// + public EqEh Eq + { + set + { + this.eq_eh = value; + Native.Z3_solver_propagate_eq(solver.Context.nCtx, solver.NativeObject, _eq); + } + } + + /// + /// Set disequality event callback + /// + public EqEh Diseq + { + set + { + this.diseq_eh = value; + Native.Z3_solver_propagate_diseq(solver.Context.nCtx, solver.NativeObject, _diseq); + } + } + + /// + /// Track assignments to a term + /// + public void Register(Expr term) { + Native.Z3_solver_propagate_register(solver.Context.nCtx, solver.NativeObject, term.NativeObject); + } + } +} diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 13c4131bb..e7528da55 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1444,7 +1444,7 @@ Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, Z3_as Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t)); Z3_DECLARE_CLOSURE(Z3_final_eh, void, (void* ctx, Z3_solver_callback cb)); Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t)); -Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast*, unsigned*, Z3_lbool*)); +Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast* t, unsigned* idx, Z3_lbool* phase)); /** @@ -6733,6 +6733,8 @@ extern "C" { \param push_eh - a callback invoked when scopes are pushed \param pop_eh - a callback invoked when scopes are poped \param fresh_eh - a solver may spawn new solvers internally. This callback is used to produce a fresh user_context to be associated with fresh solvers. + + def_API('Z3_solver_propagate_init', VOID, (_in(CONTEXT), _in(SOLVER), _in(VOID_PTR), _fnptr(Z3_push_eh), _fnptr(Z3_pop_eh), _fnptr(Z3_fresh_eh))) */ void Z3_API Z3_solver_propagate_init( @@ -6748,6 +6750,8 @@ extern "C" { The supported expression types are - Booleans - Bit-vectors + + def_API('Z3_solver_propagate_fixed', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_fixed_eh))) */ void Z3_API Z3_solver_propagate_fixed(Z3_context c, Z3_solver s, Z3_fixed_eh fixed_eh); @@ -6764,22 +6768,30 @@ extern "C" { The callback context can only be accessed (for propagation and for dynamically registering expressions) within a callback. If the callback context gets used for propagation or conflicts, those propagations take effect and may trigger new decision variables to be set. + + def_API('Z3_solver_propagate_final', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_final_eh))) */ void Z3_API Z3_solver_propagate_final(Z3_context c, Z3_solver s, Z3_final_eh final_eh); /** \brief register a callback on expression equalities. + + def_API('Z3_solver_propagate_eq', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_eq_eh))) */ void Z3_API Z3_solver_propagate_eq(Z3_context c, Z3_solver s, Z3_eq_eh eq_eh); /** \brief register a callback on expression dis-equalities. + + def_API('Z3_solver_propagate_diseq', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_eq_eh))) */ void Z3_API Z3_solver_propagate_diseq(Z3_context c, Z3_solver s, Z3_eq_eh eq_eh); /** \brief register a callback when a new expression with a registered function is used by the solver The registered function appears at the top level and is created using \ref Z3_propagate_solver_declare. + + def_API('Z3_solver_propagate_created', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_created_eh))) */ void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh); @@ -6788,6 +6800,7 @@ extern "C" { The callback may set the passed expression to another registered expression which will be selected instead. In case the expression is a bitvector the bit to split on is determined by the bit argument and the truth-value to try first is given by is_pos. In case the truth value is undefined the solver will decide. + */ void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh); diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 9a63a4a7c..d3f083904 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -195,8 +195,10 @@ public: void operator()(app* a) { if (a->get_family_id() == null_family_id && m_au.is_array(a)) { - if (m_sort && m_sort != a->get_sort()) { return; } - if (!m_sort) { m_sort = a->get_sort(); } + if (m_sort && m_sort != a->get_sort()) + return; + if (!m_sort) + m_sort = a->get_sort(); m_symbs.insert(a->get_decl()); } } @@ -208,16 +210,10 @@ public: bool lemma_array_eq_generalizer::is_array_eq (ast_manager &m, expr* e) { expr *e1 = nullptr, *e2 = nullptr; - if (m.is_eq(e, e1, e2) && is_app(e1) && is_app(e2)) { - app *a1 = to_app(e1); - app *a2 = to_app(e2); - array_util au(m); - if (a1->get_family_id() == null_family_id && - a2->get_family_id() == null_family_id && - au.is_array(a1) && au.is_array(a2)) - return true; - } - return false; + array_util au(m); + return m.is_eq(e, e1, e2) && + is_uninterp(e1) && is_uninterp(e2) && + au.is_array(e1) && au.is_array(e2); } void lemma_array_eq_generalizer::operator() (lemma_ref &lemma) diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 0f242bd4d..f7113609f 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -288,7 +288,7 @@ namespace sat { inline clause_allocator& cls_allocator() { return m_cls_allocator[m_cls_allocator_idx]; } inline clause_allocator const& cls_allocator() const { return m_cls_allocator[m_cls_allocator_idx]; } inline clause * alloc_clause(unsigned num_lits, literal const * lits, bool learned) { return cls_allocator().mk_clause(num_lits, lits, learned); } - inline void dealloc_clause(clause* c) { cls_allocator().del_clause(c); } + inline void dealloc_clause(clause* c) { cls_allocator().del_clause(c); } struct cmp_activity; void defrag_clauses(); bool should_defrag(); diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index e02a42979..a6eaeffbf 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -1190,6 +1190,10 @@ namespace arith { } void solver::assign(literal lit, literal_vector const& core, svector const& eqs, vector const& params) { + std::cout << "assign: "; + for (auto const& p : params) + std::cout << p << " "; + std::cout << "\n"; if (core.size() < small_lemma_size() && eqs.empty()) { m_core2.reset(); for (auto const& c : core) From 1e586888c901a0a918a6612f9677aa791056dcf3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 May 2022 11:18:19 -0700 Subject: [PATCH 103/253] patch js for fnptr Signed-off-by: Nikolaj Bjorner --- src/api/js/scripts/parse-api.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/js/scripts/parse-api.js b/src/api/js/scripts/parse-api.js index db12945bd..b24c362de 100644 --- a/src/api/js/scripts/parse-api.js +++ b/src/api/js/scripts/parse-api.js @@ -86,7 +86,7 @@ for (let file of files) { let apiLines = contents.split('\n').filter(l => /def_API|extra_API/.test(l)); for (let line of apiLines) { let match = line.match( - /^\s*(?def_API|extra_API) *\(\s*'(?[A-Za-z0-9_]+)'\s*,\s*(?[A-Za-z0-9_]+)\s*,\s*\((?((_in|_out|_in_array|_out_array|_inout_array)\([^)]+\)\s*,?\s*)*)\)\s*\)\s*$/, + /^\s*(?def_API|extra_API) *\(\s*'(?[A-Za-z0-9_]+)'\s*,\s*(?[A-Za-z0-9_]+)\s*,\s*\((?((_in|_out|_in_array|_out_array|_fnptr|_inout_array)\([^)]+\)\s*,?\s*)*)\)\s*\)\s*$/, ); if (match == null) { throw new Error(`failed to match def_API call ${JSON.stringify(line)}`); @@ -97,11 +97,12 @@ for (let file of files) { let parsedParams = []; while (true) { text = eatWs(text); - ({ text, match } = eat(text, /^_(?in|out|in_array|out_array|inout_array)\(/)); + ({ text, match } = eat(text, /^_(?in|out|in_array|out_array|inout_array|fnptr)\(/)); if (match == null) { break; } let kind = match.groups.kind; + if (kind == 'fnptr') kind = 'in_array' if (kind === 'inout_array') kind = 'in_array'; // https://github.com/Z3Prover/z3/discussions/5761 if (kind === 'in' || kind === 'out') { ({ text, match } = expect(text, /^[A-Za-z0-9_]+/)); From 6d40e6f401e4fcc7be4a5307e351211194783f78 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 May 2022 11:24:46 -0700 Subject: [PATCH 104/253] java Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index b9da427df..ee99d95ff 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -520,14 +520,14 @@ Type2JavaW = { VOID : 'void', VOID_PTR : 'jlong', INT : 'jint', UINT : 'jint', I def type2java(ty): global Type2Java - if (ty >= FIRST_OBJ_ID): + if (ty >= FIRST_FN_ID): return 'long' else: return Type2Java[ty] def type2javaw(ty): global Type2JavaW - if (ty >= FIRST_OBJ_ID): + if (ty >= FIRST_FN_ID): return 'jlong' else: return Type2JavaW[ty] @@ -552,6 +552,8 @@ def param2java(p): return "UIntArrayPtr" else: return "ObjArrayPtr" + elif k == FN_PTR: + return "LongPtr" else: return type2java(param_type(p)) From b6339477626769a0a79258f1365a40fec50efc23 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 May 2022 12:41:51 -0700 Subject: [PATCH 105/253] don't log function pointers Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index ee99d95ff..fcd4ac9ef 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -209,11 +209,13 @@ def param_array_size_pos(p): def param2str(p): if param_kind(p) == IN_ARRAY: - return "%s const *" % type2str(param_type(p)) - elif param_kind(p) == OUT_ARRAY or param_kind(p) == IN_ARRAY or param_kind(p) == INOUT_ARRAY or param_kind(p) == FN_PTR: - return "%s*" % type2str(param_type(p)) + return f"{type2str(param_type(p))} const *" + elif param_kind(p) == OUT_ARRAY or param_kind(p) == IN_ARRAY or param_kind(p) == INOUT_ARRAY: + return f"{type2str(param_type(p))}*" elif param_kind(p) == OUT: - return "%s*" % type2str(param_type(p)) + return f"{type2str(param_type(p))}*" + elif param_kind(p) == FN_PTR: + return f"{type2str(param_type(p))}*" else: return type2str(param_type(p)) @@ -1112,7 +1114,7 @@ def def_API(name, result, params): log_c.write(" Ap(%s);\n" % sz_e) exe_c.write("reinterpret_cast<%s**>(in.get_obj_array(%s))" % (tstr, i)) elif kind == FN_PTR: - log_c.write(" P(a%s);\n" % i) + log_c.write("// P(a%s);\n" % i) exe_c.write("reinterpret_cast<%s>(in.get_obj(%s))" % (param2str(p), i)) else: error ("unsupported parameter for %s, %s" % (name, p)) From 04b0b3690d4df20af1a6e7e71efe1f2a82a6f153 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 May 2022 12:46:52 -0700 Subject: [PATCH 106/253] js Signed-off-by: Nikolaj Bjorner --- src/api/js/scripts/parse-api.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/api/js/scripts/parse-api.js b/src/api/js/scripts/parse-api.js index b24c362de..73eaeb35e 100644 --- a/src/api/js/scripts/parse-api.js +++ b/src/api/js/scripts/parse-api.js @@ -102,9 +102,8 @@ for (let file of files) { break; } let kind = match.groups.kind; - if (kind == 'fnptr') kind = 'in_array' if (kind === 'inout_array') kind = 'in_array'; // https://github.com/Z3Prover/z3/discussions/5761 - if (kind === 'in' || kind === 'out') { + if (kind === 'in' || kind === 'out' || kind == 'fnptr') { ({ text, match } = expect(text, /^[A-Za-z0-9_]+/)); parsedParams.push({ kind, type: match[0] }); } else { From a3b066f0b4bf58fa1cfda30fd295d26c3f98c898 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 May 2022 12:49:05 -0700 Subject: [PATCH 107/253] ml: VOIDP -> ptr Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index fcd4ac9ef..a3198e172 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -90,7 +90,7 @@ Type2Dotnet = { VOID : 'void', VOID_PTR : 'IntPtr', INT : 'int', UINT : 'uint', # Mapping to ML types -Type2ML = { VOID : 'unit', VOID_PTR : 'VOIDP', INT : 'int', UINT : 'int', INT64 : 'int', UINT64 : 'int', DOUBLE : 'float', +Type2ML = { VOID : 'unit', VOID_PTR : 'ptr', INT : 'int', UINT : 'int', INT64 : 'int', UINT64 : 'int', DOUBLE : 'float', FLOAT : 'float', STRING : 'string', STRING_PTR : 'char**', BOOL : 'bool', SYMBOL : 'z3_symbol', PRINT_MODE : 'int', ERROR_CODE : 'int', CHAR : 'char', CHAR_PTR : 'string' } From 3bf09b114af8e2d0fa3693c83e26fb7cab038811 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 May 2022 13:53:07 -0700 Subject: [PATCH 108/253] safe Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/UserPropagator.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/dotnet/UserPropagator.cs b/src/api/dotnet/UserPropagator.cs index 8e7831390..bab29d41b 100644 --- a/src/api/dotnet/UserPropagator.cs +++ b/src/api/dotnet/UserPropagator.cs @@ -60,7 +60,7 @@ namespace Microsoft.Z3 EqEh diseq_eh; - unsafe static void _push(voidp ctx, Z3_solver_callback cb) { + static void _push(voidp ctx, Z3_solver_callback cb) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; prop.callback = cb; @@ -74,13 +74,13 @@ namespace Microsoft.Z3 prop.Pop(num_scopes); } - unsafe static voidp _fresh(voidp ctx, Z3_context new_context) { + static voidp _fresh(voidp ctx, Z3_context new_context) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; throw new Z3Exception("fresh is NYI"); } - unsafe static void _fixed(voidp ctx, Z3_solver_callback cb, Z3_ast _term, Z3_ast _value) { + static void _fixed(voidp ctx, Z3_solver_callback cb, Z3_ast _term, Z3_ast _value) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; var term = Expr.Create(prop.solver.Context, _term); @@ -89,14 +89,14 @@ namespace Microsoft.Z3 prop.fixed_eh(term, value); } - unsafe static void _final(voidp ctx, Z3_solver_callback cb) { + static void _final(voidp ctx, Z3_solver_callback cb) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; prop.callback = cb; prop.final_eh(); } - unsafe static void _eq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) { + static void _eq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; var s = Expr.Create(prop.solver.Context, a); @@ -105,7 +105,7 @@ namespace Microsoft.Z3 prop.eq_eh(s, t); } - unsafe static void _diseq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) { + static void _diseq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; var s = Expr.Create(prop.solver.Context, a); From e2625cb760874f5df1c9de7d89942d058fc0ac7a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 May 2022 13:53:37 -0700 Subject: [PATCH 109/253] safe Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/UserPropagator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/dotnet/UserPropagator.cs b/src/api/dotnet/UserPropagator.cs index bab29d41b..a31bd0b75 100644 --- a/src/api/dotnet/UserPropagator.cs +++ b/src/api/dotnet/UserPropagator.cs @@ -67,7 +67,7 @@ namespace Microsoft.Z3 prop.Push(); } - unsafe static void _pop(voidp ctx, Z3_solver_callback cb, uint num_scopes) { + static void _pop(voidp ctx, Z3_solver_callback cb, uint num_scopes) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; prop.callback = cb; From 1ab7be67d0978c5ede56a9d128a4850ccff2191b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 09:58:43 -0700 Subject: [PATCH 110/253] java build Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index a3198e172..b7a402fd0 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -209,13 +209,13 @@ def param_array_size_pos(p): def param2str(p): if param_kind(p) == IN_ARRAY: - return f"{type2str(param_type(p))} const *" + return "%s const *" % (type2str(param_type(p))) elif param_kind(p) == OUT_ARRAY or param_kind(p) == IN_ARRAY or param_kind(p) == INOUT_ARRAY: - return f"{type2str(param_type(p))}*" + return "%s*" % (type2str(param_type(p))) elif param_kind(p) == OUT: - return f"{type2str(param_type(p))}*" + return "%s*" % (type2str(param_type(p))) elif param_kind(p) == FN_PTR: - return f"{type2str(param_type(p))}*" + return "%s*" % (type2str(param_type(p))) else: return type2str(param_type(p)) From cf4149d53ed28c864f2b8c39b41149f2ac7c1a5f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 10:02:41 -0700 Subject: [PATCH 111/253] freeze functions with callbacks for ocaml Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index b7a402fd0..fafe2dc6d 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1397,7 +1397,12 @@ z3_long_funs = frozenset([ ]) z3_ml_overrides = frozenset([ - 'Z3_mk_config' + 'Z3_mk_config', + 'Z3_solver_propagate_init', + 'Z3_solver_propagate_fixed', + 'Z3_solver_propagate_eq', + 'Z3_solver_propagate_diseq', + 'Z3_solver_propagate_created' ]) def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface From a71ce54c34db52996a2325303b1f8a29132985e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 10:04:50 -0700 Subject: [PATCH 112/253] freeze functions with callbacks for ocaml Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index fafe2dc6d..cf34d3675 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1332,6 +1332,25 @@ def ml_alloc_and_store(t, lhs, rhs): alloc_str = '%s = caml_alloc_custom(&%s, sizeof(%s), 0, 1); ' % (lhs, pops, pts) return alloc_str + ml_set_wrap(t, lhs, rhs) + +z3_long_funs = frozenset([ + 'Z3_solver_check', + 'Z3_solver_check_assumptions', + 'Z3_simplify', + 'Z3_simplify_ex', + ]) + +z3_ml_overrides = frozenset([ + 'Z3_mk_config']) + +z3_ml_callbacks = frozenset([ + 'Z3_solver_propagate_init', + 'Z3_solver_propagate_fixed', + 'Z3_solver_propagate_eq', + 'Z3_solver_propagate_diseq', + 'Z3_solver_propagate_created' + ]) + def mk_ml(ml_src_dir, ml_output_dir): global Type2Str ml_nativef = os.path.join(ml_output_dir, 'z3native.ml') @@ -1345,6 +1364,8 @@ def mk_ml(ml_src_dir, ml_output_dir): ml_native.write('\n') for name, result, params in _dotnet_decls: + if name in z3_ml_callbacks: + continue ml_native.write('external %s : ' % ml_method_name(name)) ip = inparams(params) op = outparams(params) @@ -1389,22 +1410,6 @@ def mk_ml(ml_src_dir, ml_output_dir): mk_z3native_stubs_c(ml_src_dir, ml_output_dir) -z3_long_funs = frozenset([ - 'Z3_solver_check', - 'Z3_solver_check_assumptions', - 'Z3_simplify', - 'Z3_simplify_ex', - ]) - -z3_ml_overrides = frozenset([ - 'Z3_mk_config', - 'Z3_solver_propagate_init', - 'Z3_solver_propagate_fixed', - 'Z3_solver_propagate_eq', - 'Z3_solver_propagate_diseq', - 'Z3_solver_propagate_created' - ]) - def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface ml_wrapperf = os.path.join(ml_output_dir, 'z3native_stubs.c') ml_wrapper = open(ml_wrapperf, 'w') @@ -1419,6 +1424,8 @@ def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface if name in z3_ml_overrides: continue + if name in z3_ml_callbacks: + continue ip = inparams(params) op = outparams(params) From d58de2f8e42e8ebaa5822fc542e0ce0a4c23d89a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 10:20:32 -0700 Subject: [PATCH 113/253] java build Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 2 +- src/cmd_context/cmd_context.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index cf34d3675..06dc96011 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -418,7 +418,7 @@ def mk_dotnet(dotnet): if "*" in sig or "*" in ret: continue dotnet.write(' [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n') - dotnet.write(f" public delegate {ret} {name}({sig});\n") + dotnet.write(' public delegate %s %s(%s);\n' % (ret,name,sig)) dotnet.write(' public class LIB\n') dotnet.write(' {\n') diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 580cc2de4..303fcd00b 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -597,9 +597,8 @@ opt_wrapper* cmd_context::get_opt() { void cmd_context::set_opt(opt_wrapper* opt) { m_opt = opt; - for (unsigned i = 0; i < m_scopes.size(); ++i) { + for (unsigned i = 0; i < m_scopes.size(); ++i) m_opt->push(); - } m_opt->set_logic(m_logic); } From 7def610a6983345085d32f3f111d013389ec8b4f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 10:31:11 -0700 Subject: [PATCH 114/253] build warnings Signed-off-by: Nikolaj Bjorner --- src/sat/smt/array_axioms.cpp | 4 ++-- src/sat/smt/pb_solver.cpp | 2 +- src/smt/theory_array.cpp | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index 613d7a17c..df1fecc49 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -281,8 +281,8 @@ namespace array { * a = b or default(a) != default(b) or a[md(a,b)] != b[md(a,b)] */ bool solver::assert_diff(expr* md) { - expr* x, *y; - SASSERT(a.is_maxdiff(md, x, y) || a.is_mindiff(md, x, y)); + expr* x = nullptr, *y = nullptr; + VERIFY(a.is_maxdiff(md, x, y) || a.is_mindiff(md, x, y)); expr* args1[2] = { x, md }; expr* args2[2] = { y, md }; literal eq = eq_internalize(x, y); diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 8340543ec..ff08ab284 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -2699,7 +2699,7 @@ namespace pb { } } ++m_stats.m_num_big_strengthenings; - constraint* c = add_pb_ge(sat::null_literal, wlits, b, p.learned()); + add_pb_ge(sat::null_literal, wlits, b, p.learned()); p.set_removed(); return; } diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index 2d166c5f6..9d3e93839 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -239,7 +239,6 @@ namespace smt { // bool theory_array::internalize_term_core(app * n) { TRACE("array_bug", tout << mk_bounded_pp(n, m) << "\n";); - unsigned num_args = n->get_num_args(); for (expr* arg : *n) ctx.internalize(arg, false); // force merge-tf by re-internalizing expression. From 3b441137c0ddf3ef53f6842bdd0b193e8f71a150 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 11:01:23 -0700 Subject: [PATCH 115/253] ocaml build Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/update_api.py b/scripts/update_api.py index 06dc96011..b0b795b23 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1346,6 +1346,7 @@ z3_ml_overrides = frozenset([ z3_ml_callbacks = frozenset([ 'Z3_solver_propagate_init', 'Z3_solver_propagate_fixed', + 'Z3_solver_propagate_final', 'Z3_solver_propagate_eq', 'Z3_solver_propagate_diseq', 'Z3_solver_propagate_created' From cca49154ff3c39f23b9490cab68b2dabec365165 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 11:24:56 -0700 Subject: [PATCH 116/253] fix #6021 Signed-off-by: Nikolaj Bjorner --- src/tactic/smtlogics/qflia_tactic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/smtlogics/qflia_tactic.h b/src/tactic/smtlogics/qflia_tactic.h index 8b4206d12..ea9db48eb 100644 --- a/src/tactic/smtlogics/qflia_tactic.h +++ b/src/tactic/smtlogics/qflia_tactic.h @@ -7,7 +7,7 @@ Module Name: Abstract: - Tactic for QF_LRA + Tactic for QF_LRI Author: From 97af3a61201ea5c864c51ad72137ce1c88e8e410 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 11:25:24 -0700 Subject: [PATCH 117/253] fix #6021 Signed-off-by: Nikolaj Bjorner --- src/tactic/smtlogics/qflia_tactic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/smtlogics/qflia_tactic.h b/src/tactic/smtlogics/qflia_tactic.h index ea9db48eb..4a68c881e 100644 --- a/src/tactic/smtlogics/qflia_tactic.h +++ b/src/tactic/smtlogics/qflia_tactic.h @@ -7,7 +7,7 @@ Module Name: Abstract: - Tactic for QF_LRI + Tactic for QF_LIA Author: From 1e7a9e3e61c3cc2dbb8fea6744ee369ea0dbdc4b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 12:03:13 -0700 Subject: [PATCH 118/253] fix #6023 --- src/cmd_context/parametric_cmd.h | 1 + src/opt/opt_cmds.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/cmd_context/parametric_cmd.h b/src/cmd_context/parametric_cmd.h index fa90e7d33..c5f715eb6 100644 --- a/src/cmd_context/parametric_cmd.h +++ b/src/cmd_context/parametric_cmd.h @@ -34,6 +34,7 @@ public: virtual void init_pdescrs(cmd_context & ctx, param_descrs & d) = 0; param_descrs const & pdescrs(cmd_context & ctx) const; params_ref const & ps() const { return m_params; } + void reset_params() { m_params.reset(); } virtual char const * get_main_descr() const = 0; char const * get_descr(cmd_context & ctx) const override; unsigned get_arity() const override { return VAR_ARITY; } diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index f01df0bdd..41f7bedb3 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -105,6 +105,7 @@ public: get_opt(ctx, m_opt).add_soft_constraint(m_formula, weight, id); ctx.print_success(); reset(ctx); + reset_params(); } void finalize(cmd_context & ctx) override { From 506f8f88aabbd57dc01a666cc8d48eadc5beee16 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 12:43:46 -0700 Subject: [PATCH 119/253] add user propagator functionality --- src/api/dotnet/Context.cs | 34 +++++++++++- src/api/dotnet/UserPropagator.cs | 95 +++++++++++++++++++++++++------- 2 files changed, 108 insertions(+), 21 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index a0676b4e2..c71289d4d 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -25,6 +25,8 @@ using System.Runtime.InteropServices; namespace Microsoft.Z3 { + + using Z3_context = System.IntPtr; /// /// The main interaction with Z3 happens via the Context. /// @@ -77,6 +79,23 @@ namespace Microsoft.Z3 InitContext(); } } + + /// + /// Internal Constructor. It is used from UserPropagator + /// + internal Context(Z3_context ctx) + : base() + { + lock (creation_lock) + { + is_external = true; + m_ctx = ctx; + InitContext(); + } + } + + bool is_external = false; + #endregion #region Symbols @@ -669,6 +688,16 @@ namespace Microsoft.Z3 CheckContextMatch(range); return new FuncDecl(this, prefix, null, range); } + + /// + /// Declare a function to be processed by the user propagator plugin. + /// + public FuncDecl MkUserPropagatorFuncDecl(string name, Sort[] domain, Sort range) + { + using var _name = MkSymbol(name); + var fn = Native.Z3_solver_propagate_declare(nCtx, _name.NativeObject, AST.ArrayLength(domain), AST.ArrayToNative(domain), range.NativeObject); + return new FuncDecl(this, fn); + } #endregion #region Bound Variables @@ -4978,11 +5007,14 @@ namespace Microsoft.Z3 m_n_err_handler = null; IntPtr ctx = m_ctx; m_ctx = IntPtr.Zero; - Native.Z3_del_context(ctx); + if (!is_external) + Native.Z3_del_context(ctx); } else GC.ReRegisterForFinalize(this); } + + #endregion } } diff --git a/src/api/dotnet/UserPropagator.cs b/src/api/dotnet/UserPropagator.cs index a31bd0b75..4c9c6208b 100644 --- a/src/api/dotnet/UserPropagator.cs +++ b/src/api/dotnet/UserPropagator.cs @@ -15,7 +15,7 @@ Author: Notes: -// Todo: fresh, created, declare user function, register_cb, decide, +// Todo: decide, --*/ @@ -50,14 +50,20 @@ namespace Microsoft.Z3 /// public delegate void EqEh(Expr term, Expr value); + /// + /// Delegate type for when a new term using a registered function symbol is created internally + /// + public delegate void CreatedEh(Expr term); Solver solver; + Context ctx; GCHandle gch; - Z3_solver_callback callback; + Z3_solver_callback callback = IntPtr.Zero; FixedEh fixed_eh; Action final_eh; EqEh eq_eh; EqEh diseq_eh; + CreatedEh created_eh; static void _push(voidp ctx, Z3_solver_callback cb) { @@ -65,6 +71,7 @@ namespace Microsoft.Z3 var prop = (UserPropagator)gch.Target; prop.callback = cb; prop.Push(); + prop.callback = IntPtr.Zero; } static void _pop(voidp ctx, Z3_solver_callback cb, uint num_scopes) { @@ -72,21 +79,25 @@ namespace Microsoft.Z3 var prop = (UserPropagator)gch.Target; prop.callback = cb; prop.Pop(num_scopes); + prop.callback = IntPtr.Zero; } - static voidp _fresh(voidp ctx, Z3_context new_context) { - var gch = GCHandle.FromIntPtr(ctx); + static voidp _fresh(voidp _ctx, Z3_context new_context) { + var gch = GCHandle.FromIntPtr(_ctx); var prop = (UserPropagator)gch.Target; - throw new Z3Exception("fresh is NYI"); + var ctx = new Context(new_context); + var prop1 = prop.Fresh(ctx); + return GCHandle.ToIntPtr(GCHandle.Alloc(prop1)); } static void _fixed(voidp ctx, Z3_solver_callback cb, Z3_ast _term, Z3_ast _value) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; - var term = Expr.Create(prop.solver.Context, _term); - var value = Expr.Create(prop.solver.Context, _value); + using var term = Expr.Create(prop.solver.Context, _term); + using var value = Expr.Create(prop.solver.Context, _value); prop.callback = cb; prop.fixed_eh(term, value); + prop.callback = IntPtr.Zero; } static void _final(voidp ctx, Z3_solver_callback cb) { @@ -94,24 +105,36 @@ namespace Microsoft.Z3 var prop = (UserPropagator)gch.Target; prop.callback = cb; prop.final_eh(); + prop.callback = IntPtr.Zero; } static void _eq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; - var s = Expr.Create(prop.solver.Context, a); - var t = Expr.Create(prop.solver.Context, b); + using var s = Expr.Create(prop.solver.Context, a); + using var t = Expr.Create(prop.solver.Context, b); prop.callback = cb; prop.eq_eh(s, t); + prop.callback = IntPtr.Zero; } static void _diseq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; - var s = Expr.Create(prop.solver.Context, a); - var t = Expr.Create(prop.solver.Context, b); + using var s = Expr.Create(prop.solver.Context, a); + using var t = Expr.Create(prop.solver.Context, b); prop.callback = cb; prop.diseq_eh(s, t); + prop.callback = IntPtr.Zero; + } + + static void _created(voidp ctx, Z3_solver_callback cb, Z3_ast a) { + var gch = GCHandle.FromIntPtr(ctx); + var prop = (UserPropagator)gch.Target; + using var t = Expr.Create(prop.solver.Context, a); + prop.callback = cb; + prop.created_eh(t); + prop.callback = IntPtr.Zero; } /// @@ -121,8 +144,17 @@ namespace Microsoft.Z3 { gch = GCHandle.Alloc(this); solver = s; + ctx = solver.Context; var cb = GCHandle.ToIntPtr(gch); - Native.Z3_solver_propagate_init(solver.Context.nCtx, solver.NativeObject, cb, _push, _pop, _fresh); + Native.Z3_solver_propagate_init(ctx.nCtx, solver.NativeObject, cb, _push, _pop, _fresh); + } + + /// + /// Propagator constructor from a context. It is used from inside of Fresh. + /// + public UserPropagator(Context ctx) + { + this.ctx = ctx; } /// @@ -130,7 +162,8 @@ namespace Microsoft.Z3 /// ~UserPropagator() { - gch.Free(); + if (gch != null) + gch.Free(); } /// @@ -152,7 +185,7 @@ namespace Microsoft.Z3 /// Declare combination of assigned expressions a conflict /// void Conflict(params Expr[] terms) { - Propagate(terms, solver.Context.MkFalse()); + Propagate(terms, ctx.MkFalse()); } /// @@ -160,7 +193,7 @@ namespace Microsoft.Z3 /// void Propagate(Expr[] terms, Expr conseq) { var nTerms = Z3Object.ArrayToNative(terms); - Native.Z3_solver_propagate_consequence(solver.Context.nCtx, this.callback, (uint)nTerms.Length, nTerms, 0u, null, null, conseq.NativeObject); + Native.Z3_solver_propagate_consequence(ctx.nCtx, this.callback, (uint)nTerms.Length, nTerms, 0u, null, null, conseq.NativeObject); } @@ -172,7 +205,8 @@ namespace Microsoft.Z3 set { this.fixed_eh = value; - Native.Z3_solver_propagate_fixed(solver.Context.nCtx, solver.NativeObject, _fixed); + if (solver != null) + Native.Z3_solver_propagate_fixed(ctx.nCtx, solver.NativeObject, _fixed); } } @@ -184,7 +218,8 @@ namespace Microsoft.Z3 set { this.final_eh = value; - Native.Z3_solver_propagate_final(solver.Context.nCtx, solver.NativeObject, _final); + if (solver != null) + Native.Z3_solver_propagate_final(ctx.nCtx, solver.NativeObject, _final); } } @@ -196,7 +231,8 @@ namespace Microsoft.Z3 set { this.eq_eh = value; - Native.Z3_solver_propagate_eq(solver.Context.nCtx, solver.NativeObject, _eq); + if (solver != null) + Native.Z3_solver_propagate_eq(ctx.nCtx, solver.NativeObject, _eq); } } @@ -208,7 +244,21 @@ namespace Microsoft.Z3 set { this.diseq_eh = value; - Native.Z3_solver_propagate_diseq(solver.Context.nCtx, solver.NativeObject, _diseq); + if (solver != null) + Native.Z3_solver_propagate_diseq(ctx.nCtx, solver.NativeObject, _diseq); + } + } + + /// + /// Set created callback + /// + public CreatedEh Created + { + set + { + this.created_eh = value; + if (solver != null) + Native.Z3_solver_propagate_created(ctx.nCtx, solver.NativeObject, _created); } } @@ -216,7 +266,12 @@ namespace Microsoft.Z3 /// Track assignments to a term /// public void Register(Expr term) { - Native.Z3_solver_propagate_register(solver.Context.nCtx, solver.NativeObject, term.NativeObject); + if (this.callback != IntPtr.Zero) { + Native.Z3_solver_propagate_register_cb(ctx.nCtx, callback, term.NativeObject); + } + else { + Native.Z3_solver_propagate_register(ctx.nCtx, solver.NativeObject, term.NativeObject); + } } } } From c8d12975c961fe0e032377a8667dfbceea27bbce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 12:49:04 -0700 Subject: [PATCH 120/253] fixes for fresh --- src/api/dotnet/UserPropagator.cs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/api/dotnet/UserPropagator.cs b/src/api/dotnet/UserPropagator.cs index 4c9c6208b..13532fdf4 100644 --- a/src/api/dotnet/UserPropagator.cs +++ b/src/api/dotnet/UserPropagator.cs @@ -87,14 +87,14 @@ namespace Microsoft.Z3 var prop = (UserPropagator)gch.Target; var ctx = new Context(new_context); var prop1 = prop.Fresh(ctx); - return GCHandle.ToIntPtr(GCHandle.Alloc(prop1)); + return GCHandle.ToIntPtr(prop1.gch); } static void _fixed(voidp ctx, Z3_solver_callback cb, Z3_ast _term, Z3_ast _value) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; - using var term = Expr.Create(prop.solver.Context, _term); - using var value = Expr.Create(prop.solver.Context, _value); + using var term = Expr.Create(prop.ctx, _term); + using var value = Expr.Create(prop.ctx, _value); prop.callback = cb; prop.fixed_eh(term, value); prop.callback = IntPtr.Zero; @@ -111,8 +111,8 @@ namespace Microsoft.Z3 static void _eq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; - using var s = Expr.Create(prop.solver.Context, a); - using var t = Expr.Create(prop.solver.Context, b); + using var s = Expr.Create(prop.ctx, a); + using var t = Expr.Create(prop.ctx, b); prop.callback = cb; prop.eq_eh(s, t); prop.callback = IntPtr.Zero; @@ -121,8 +121,8 @@ namespace Microsoft.Z3 static void _diseq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; - using var s = Expr.Create(prop.solver.Context, a); - using var t = Expr.Create(prop.solver.Context, b); + using var s = Expr.Create(prop.ctx, a); + using var t = Expr.Create(prop.ctx, b); prop.callback = cb; prop.diseq_eh(s, t); prop.callback = IntPtr.Zero; @@ -131,7 +131,7 @@ namespace Microsoft.Z3 static void _created(voidp ctx, Z3_solver_callback cb, Z3_ast a) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; - using var t = Expr.Create(prop.solver.Context, a); + using var t = Expr.Create(prop.ctx, a); prop.callback = cb; prop.created_eh(t); prop.callback = IntPtr.Zero; @@ -152,9 +152,11 @@ namespace Microsoft.Z3 /// /// Propagator constructor from a context. It is used from inside of Fresh. /// - public UserPropagator(Context ctx) + public UserPropagator(Context _ctx) { - this.ctx = ctx; + gch = GCHandle.Alloc(this); + solver = null; + ctx = _ctx; } /// @@ -164,6 +166,8 @@ namespace Microsoft.Z3 { if (gch != null) gch.Free(); + if (solver == null) + ctx.Dispose(); } /// From 8218f25222d343952eca306d1a906a5d6b617c2c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 15:30:03 -0700 Subject: [PATCH 121/253] add decide callback Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 4 +++- src/api/dotnet/UserPropagator.cs | 36 ++++++++++++++++++++++++++++++++ src/api/z3_api.h | 1 + 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index b0b795b23..0553843cb 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -414,6 +414,7 @@ def mk_dotnet(dotnet): for name, ret, sig in Closures: sig = sig.replace("void*","voidp").replace("unsigned","uint") + sig = sig.replace("Z3_ast*","ref IntPtr").replace("uint*","ref uint").replace("Z3_lbool*","ref int") ret = ret.replace("void*","voidp").replace("unsigned","uint") if "*" in sig or "*" in ret: continue @@ -1349,7 +1350,8 @@ z3_ml_callbacks = frozenset([ 'Z3_solver_propagate_final', 'Z3_solver_propagate_eq', 'Z3_solver_propagate_diseq', - 'Z3_solver_propagate_created' + 'Z3_solver_propagate_created', + 'Z3_solver_propagate_decide' ]) def mk_ml(ml_src_dir, ml_output_dir): diff --git a/src/api/dotnet/UserPropagator.cs b/src/api/dotnet/UserPropagator.cs index 13532fdf4..4f604b4cb 100644 --- a/src/api/dotnet/UserPropagator.cs +++ b/src/api/dotnet/UserPropagator.cs @@ -55,6 +55,14 @@ namespace Microsoft.Z3 /// public delegate void CreatedEh(Expr term); + /// + /// Delegate type for callback into solver's branching + /// A bit-vector or Boolean used for branching + /// If the term is a bit-vector, then an index into the bit-vector being branched on + /// Set phase to -1 (false) or 1 (true) to override solver's phase + /// + public delegate void DecideEh(ref Expr term, ref uint idx, ref int phase); + Solver solver; Context ctx; GCHandle gch; @@ -64,6 +72,7 @@ namespace Microsoft.Z3 EqEh eq_eh; EqEh diseq_eh; CreatedEh created_eh; + DecideEh decide_eh; static void _push(voidp ctx, Z3_solver_callback cb) { @@ -137,6 +146,20 @@ namespace Microsoft.Z3 prop.callback = IntPtr.Zero; } + static void _decide(voidp ctx, Z3_solver_callback cb, ref Z3_ast a, ref uint idx, ref int phase) { + var gch = GCHandle.FromIntPtr(ctx); + var prop = (UserPropagator)gch.Target; + var t = Expr.Create(prop.ctx, a); + var u = t; + prop.callback = cb; + prop.decide_eh(ref t, ref idx, ref phase); + prop.callback = IntPtr.Zero; + if (u != t) { + a = t.NativeObject; + } + t.Dispose(); + } + /// /// Propagator constructor from a solver class. /// @@ -266,6 +289,19 @@ namespace Microsoft.Z3 } } + /// + /// Set decision callback + /// + public DecideEh Decide + { + set + { + this.decide_eh = value; + if (solver != null) + Native.Z3_solver_propagate_decide(ctx.nCtx, solver.NativeObject, _decide); + } + } + /// /// Track assignments to a term /// diff --git a/src/api/z3_api.h b/src/api/z3_api.h index e7528da55..4e5f5f5b5 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6801,6 +6801,7 @@ extern "C" { In case the expression is a bitvector the bit to split on is determined by the bit argument and the truth-value to try first is given by is_pos. In case the truth value is undefined the solver will decide. + def_API('Z3_solver_propagate_decide', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_decide_eh))) */ void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh); From da9ed82889795e55b046670c3d2403951f179a00 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 May 2022 15:31:05 -0700 Subject: [PATCH 122/253] add decide callback Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/UserPropagator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/dotnet/UserPropagator.cs b/src/api/dotnet/UserPropagator.cs index 4f604b4cb..d0f46c189 100644 --- a/src/api/dotnet/UserPropagator.cs +++ b/src/api/dotnet/UserPropagator.cs @@ -15,7 +15,6 @@ Author: Notes: -// Todo: decide, --*/ From 4549ec73313f69a983339e8aba237f67a8704af8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 May 2022 08:38:35 -0700 Subject: [PATCH 123/253] misc --- src/api/dotnet/UserPropagator.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/api/dotnet/UserPropagator.cs b/src/api/dotnet/UserPropagator.cs index d0f46c189..590b84e9c 100644 --- a/src/api/dotnet/UserPropagator.cs +++ b/src/api/dotnet/UserPropagator.cs @@ -153,10 +153,8 @@ namespace Microsoft.Z3 prop.callback = cb; prop.decide_eh(ref t, ref idx, ref phase); prop.callback = IntPtr.Zero; - if (u != t) { + if (u != t) a = t.NativeObject; - } - t.Dispose(); } /// @@ -203,9 +201,9 @@ namespace Microsoft.Z3 public virtual void Pop(uint n) { throw new Z3Exception("Pop method should be overwritten"); } /// - /// Virtual method for fresh. It must be overwritten by inherited class. + /// Virtual method for fresh. It can be overwritten by inherited class. /// - public virtual UserPropagator Fresh(Context ctx) { throw new Z3Exception("Fresh method should be overwritten"); } + public virtual UserPropagator Fresh(Context ctx) { return new UserPropagator(ctx); } /// /// Declare combination of assigned expressions a conflict From fbf5e322dca7bfadd823cc4f8087a8612a07afbb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 May 2022 08:49:02 -0700 Subject: [PATCH 124/253] js Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/UserPropagator.cs | 43 ++++++++++++++++---------------- src/api/js/scripts/parse-api.js | 3 ++- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/api/dotnet/UserPropagator.cs b/src/api/dotnet/UserPropagator.cs index 590b84e9c..bfd7887dd 100644 --- a/src/api/dotnet/UserPropagator.cs +++ b/src/api/dotnet/UserPropagator.cs @@ -73,21 +73,30 @@ namespace Microsoft.Z3 CreatedEh created_eh; DecideEh decide_eh; + void Callback(Action fn, Z3_solver_callback cb) { + this.callback = cb; + try { + fn(); + } + catch { + // TBD: add debug log or exception handler + } + finally { + this.callback = IntPtr.Zero; + } + } + static void _push(voidp ctx, Z3_solver_callback cb) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; - prop.callback = cb; - prop.Push(); - prop.callback = IntPtr.Zero; + prop.Callback(() => prop.Push(), cb); } static void _pop(voidp ctx, Z3_solver_callback cb, uint num_scopes) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; - prop.callback = cb; - prop.Pop(num_scopes); - prop.callback = IntPtr.Zero; + prop.Callback(() => prop.Pop(num_scopes), cb); } static voidp _fresh(voidp _ctx, Z3_context new_context) { @@ -103,17 +112,13 @@ namespace Microsoft.Z3 var prop = (UserPropagator)gch.Target; using var term = Expr.Create(prop.ctx, _term); using var value = Expr.Create(prop.ctx, _value); - prop.callback = cb; - prop.fixed_eh(term, value); - prop.callback = IntPtr.Zero; + prop.Callback(() => prop.fixed_eh(term, value), cb); } static void _final(voidp ctx, Z3_solver_callback cb) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; - prop.callback = cb; - prop.final_eh(); - prop.callback = IntPtr.Zero; + prop.Callback(() => prop.final_eh(), cb); } static void _eq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) { @@ -121,9 +126,7 @@ namespace Microsoft.Z3 var prop = (UserPropagator)gch.Target; using var s = Expr.Create(prop.ctx, a); using var t = Expr.Create(prop.ctx, b); - prop.callback = cb; - prop.eq_eh(s, t); - prop.callback = IntPtr.Zero; + prop.Callback(() => prop.eq_eh(s, t), cb); } static void _diseq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b) { @@ -131,18 +134,14 @@ namespace Microsoft.Z3 var prop = (UserPropagator)gch.Target; using var s = Expr.Create(prop.ctx, a); using var t = Expr.Create(prop.ctx, b); - prop.callback = cb; - prop.diseq_eh(s, t); - prop.callback = IntPtr.Zero; + prop.Callback(() => prop.diseq_eh(s, t), cb); } static void _created(voidp ctx, Z3_solver_callback cb, Z3_ast a) { var gch = GCHandle.FromIntPtr(ctx); var prop = (UserPropagator)gch.Target; using var t = Expr.Create(prop.ctx, a); - prop.callback = cb; - prop.created_eh(t); - prop.callback = IntPtr.Zero; + prop.Callback(() => prop.created_eh(t), cb); } static void _decide(voidp ctx, Z3_solver_callback cb, ref Z3_ast a, ref uint idx, ref int phase) { @@ -152,7 +151,7 @@ namespace Microsoft.Z3 var u = t; prop.callback = cb; prop.decide_eh(ref t, ref idx, ref phase); - prop.callback = IntPtr.Zero; + prop.callback = IntPtr.Zero; if (u != t) a = t.NativeObject; } diff --git a/src/api/js/scripts/parse-api.js b/src/api/js/scripts/parse-api.js index 73eaeb35e..48ea68cc0 100644 --- a/src/api/js/scripts/parse-api.js +++ b/src/api/js/scripts/parse-api.js @@ -54,7 +54,8 @@ let types = { Z3_fixed_eh: 'Z3_fixed_eh', Z3_eq_eh: 'Z3_eq_eh', Z3_final_eh: 'Z3_final_eh', - Z3_created_eh: 'Z3_created_eh', + Z3_created_eh: 'Z3_created_eh', + Z3_decide_eh: 'Z3_decide_eh' }; let defApis = Object.create(null); From 6670cf0b65330f119aac68652e5c54c48c44fccb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 May 2022 09:16:05 -0700 Subject: [PATCH 125/253] na --- src/api/js/scripts/parse-api.js | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/api/js/scripts/parse-api.js b/src/api/js/scripts/parse-api.js index 48ea68cc0..4176f8b26 100644 --- a/src/api/js/scripts/parse-api.js +++ b/src/api/js/scripts/parse-api.js @@ -44,16 +44,16 @@ let optTypes = { // parse type declarations let types = { - __proto__: null, + __proto__: null, - // these are function types I can't be bothered to parse - Z3_error_handler: 'Z3_error_handler', - Z3_push_eh: 'Z3_push_eh', - Z3_pop_eh: 'Z3_pop_eh', - Z3_fresh_eh: 'Z3_fresh_eh', - Z3_fixed_eh: 'Z3_fixed_eh', - Z3_eq_eh: 'Z3_eq_eh', - Z3_final_eh: 'Z3_final_eh', + // these are function types I can't be bothered to parse + Z3_error_handler: 'Z3_error_handler', + Z3_push_eh: 'Z3_push_eh', + Z3_pop_eh: 'Z3_pop_eh', + Z3_fresh_eh: 'Z3_fresh_eh', + Z3_fixed_eh: 'Z3_fixed_eh', + Z3_eq_eh: 'Z3_eq_eh', + Z3_final_eh: 'Z3_final_eh', Z3_created_eh: 'Z3_created_eh', Z3_decide_eh: 'Z3_decide_eh' }; @@ -83,6 +83,12 @@ for (let file of files) { pytypes[groups.name] = groups.cname; } + // we don't have to pre-populate the types map with closure types + // use the Z3_DECLARE_CLOSURE to identify closure types + // for (let match of contents.matchAll(/Z3_DECLARE_CLOSURE\((?[A-Za-z0-9_]+),/g)) { + // types[match.groups.type] = match.groups.type + // } + // we filter first to ensure our regex isn't too strict let apiLines = contents.split('\n').filter(l => /def_API|extra_API/.test(l)); for (let line of apiLines) { @@ -132,11 +138,6 @@ for (let file of files) { types[match.groups.type] = match.groups.type; } - // we don't have to pre-populate the types map with closure types - // use the Z3_DECLARE_CLOSURE to identify closure types - // for (let match of contents.matchAll(/Z3_DECLARE_CLOSURE\((?[A-Za-z0-9_]+),/g)) { - // types[match.groups.type] = match.groups.type - // } // parse enum declarations for (let idx = 0; idx < contents.length; ) { From dcc01b874a31a4fa2db76c9d6b3206237355ef8a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 May 2022 11:18:15 -0700 Subject: [PATCH 126/253] prep for pragmas --- src/sat/dimacs.cpp | 27 ++++++++++++++++++- src/sat/dimacs.h | 5 ++-- src/sat/sat_drat.cpp | 8 ++++++ src/sat/sat_types.h | 10 ++++--- src/sat/smt/arith_axioms.cpp | 23 ++++++++-------- src/sat/smt/arith_solver.cpp | 47 +++++++++++++------------------- src/sat/smt/arith_solver.h | 4 +-- src/sat/smt/euf_proof.cpp | 2 +- src/sat/smt/sat_th.cpp | 52 +++++++++++++++++++++++------------- src/sat/smt/sat_th.h | 24 ++++++++++------- 10 files changed, 124 insertions(+), 78 deletions(-) diff --git a/src/sat/dimacs.cpp b/src/sat/dimacs.cpp index 9c9a40a24..4a818af6c 100644 --- a/src/sat/dimacs.cpp +++ b/src/sat/dimacs.cpp @@ -112,6 +112,27 @@ static void read_clause(Buffer & in, std::ostream& err, sat::literal_vector & li } } +template +static void read_pragma(Buffer & in, std::ostream& err, std::string& p) { + skip_whitespace(in); + if (*in != 'p') + return; + ++in; + while (*in == ' ') + ++in; + while (true) { + if (*in == EOF) + return; + if (*in == '\n') { + ++in; + return; + } + p.push_back(*in); + ++in; + } +} + + template static bool parse_dimacs_core(Buffer & in, std::ostream& err, sat::solver & solver) { sat::literal_vector lits; @@ -156,7 +177,9 @@ namespace dimacs { sat::status_pp pp(r.m_status, p.th); switch (r.m_tag) { case drat_record::tag_t::is_clause: - return out << pp << " " << r.m_lits << " 0\n"; + if (!r.m_pragma.empty()) + return out << pp << " " << r.m_lits << " 0 p " << r.m_pragma << "\n"; + return out << pp << " " << r.m_lits << " 0\n"; case drat_record::tag_t::is_node: return out << "e " << r.m_node_id << " " << r.m_name << " " << r.m_args << "0\n"; case drat_record::tag_t::is_sort: @@ -280,6 +303,7 @@ namespace dimacs { try { loop: skip_whitespace(in); + m_record.m_pragma.clear(); switch (*in) { case EOF: return false; @@ -304,6 +328,7 @@ namespace dimacs { theory_id = read_theory_id(); skip_whitespace(in); read_clause(in, err, m_record.m_lits); + read_pragma(in, err, m_record.m_pragma); m_record.m_tag = drat_record::tag_t::is_clause; m_record.m_status = sat::status::th(false, theory_id); break; diff --git a/src/sat/dimacs.h b/src/sat/dimacs.h index cc4b27182..7b4e8557c 100644 --- a/src/sat/dimacs.h +++ b/src/sat/dimacs.h @@ -59,10 +59,11 @@ namespace dimacs { // a node populates m_node_id, m_name, m_args // a bool def populates m_node_id and one element in m_args sat::literal_vector m_lits; - sat::status m_status{ sat::status::redundant() }; - unsigned m_node_id{ 0 }; + sat::status m_status = sat::status::redundant(); + unsigned m_node_id = 0; std::string m_name; unsigned_vector m_args; + std::string m_pragma; }; struct drat_pp { diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 6d8c4d477..72872e370 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -137,6 +137,14 @@ namespace sat { } } buffer[len++] = '0'; + if (st.get_pragma()) { + buffer[len++] = ' '; + buffer[len++] = 'p'; + buffer[len++] = ' '; + char const* ps = st.get_pragma(); + while (*ps) + buffer[len++] = *ps++; + } buffer[len++] = '\n'; m_out->write(buffer, len); diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 57300a705..12c013734 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -98,22 +98,24 @@ namespace sat { enum class st { input, asserted, redundant, deleted }; st m_st; int m_orig; + char const* m_pragma; public: - status(st s, int o) : m_st(s), m_orig(o) {}; - status(status const& s) : m_st(s.m_st), m_orig(s.m_orig) {} - status(status&& s) noexcept { m_st = st::asserted; m_orig = -1; std::swap(m_st, s.m_st); std::swap(m_orig, s.m_orig); } + status(st s, int o, char const* ps = nullptr) : m_st(s), m_orig(o), m_pragma(ps) {}; + status(status const& s) : m_st(s.m_st), m_orig(s.m_orig), m_pragma(s.m_pragma) {} + status(status&& s) noexcept { m_st = st::asserted; m_orig = -1; std::swap(m_st, s.m_st); std::swap(m_orig, s.m_orig); std::swap(m_pragma, s.m_pragma); } status& operator=(status const& other) { m_st = other.m_st; m_orig = other.m_orig; return *this; } static status redundant() { return status(status::st::redundant, -1); } static status asserted() { return status(status::st::asserted, -1); } static status deleted() { return status(status::st::deleted, -1); } static status input() { return status(status::st::input, -1); } - static status th(bool redundant, int id) { return status(redundant ? st::redundant : st::asserted, id); } + static status th(bool redundant, int id, char const* ps = nullptr) { return status(redundant ? st::redundant : st::asserted, id, ps); } bool is_input() const { return st::input == m_st; } bool is_redundant() const { return st::redundant == m_st; } bool is_asserted() const { return st::asserted == m_st; } bool is_deleted() const { return st::deleted == m_st; } + char const* get_pragma() const { return m_pragma; } bool is_sat() const { return -1 == m_orig; } int get_th() const { return m_orig; } diff --git a/src/sat/smt/arith_axioms.cpp b/src/sat/smt/arith_axioms.cpp index 1a60f597f..7efd83ead 100644 --- a/src/sat/smt/arith_axioms.cpp +++ b/src/sat/smt/arith_axioms.cpp @@ -233,45 +233,46 @@ namespace arith { SASSERT(b1.get_var() == b2.get_var()); if (k1 == k2 && kind1 == kind2) return; SASSERT(k1 != k2 || kind1 != kind2); + char const* bound_params = "farkas 1 1"; if (kind1 == lp_api::lower_t) { if (kind2 == lp_api::lower_t) { if (k2 <= k1) - add_clause(~l1, l2); + add_clause(~l1, l2, bound_params); else - add_clause(l1, ~l2); + add_clause(l1, ~l2, bound_params); } else if (k1 <= k2) // k1 <= k2, k1 <= x or x <= k2 add_clause(l1, l2); else { // k1 > hi_inf, k1 <= x => ~(x <= hi_inf) - add_clause(~l1, ~l2); + add_clause(~l1, ~l2, bound_params); if (v_is_int && k1 == k2 + rational(1)) // k1 <= x or x <= k1-1 - add_clause(l1, l2); + add_clause(l1, l2, bound_params); } } else if (kind2 == lp_api::lower_t) { if (k1 >= k2) // k1 >= lo_inf, k1 >= x or lo_inf <= x - add_clause(l1, l2); + add_clause(l1, l2, bound_params); else { // k1 < k2, k2 <= x => ~(x <= k1) - add_clause(~l1, ~l2); + add_clause(~l1, ~l2, bound_params); if (v_is_int && k1 == k2 - rational(1)) // x <= k1 or k1+l <= x - add_clause(l1, l2); + add_clause(l1, l2, bound_params); } } else { // kind1 == A_UPPER, kind2 == A_UPPER if (k1 >= k2) // k1 >= k2, x <= k2 => x <= k1 - add_clause(l1, ~l2); + add_clause(l1, ~l2, bound_params); else // k1 <= hi_sup , x <= k1 => x <= hi_sup - add_clause(~l1, l2); + add_clause(~l1, l2, bound_params); } } @@ -498,8 +499,8 @@ namespace arith { if (x->get_root() == y->get_root()) return; reset_evidence(); - set_evidence(ci1, m_core, m_eqs); - set_evidence(ci2, m_core, m_eqs); + set_evidence(ci1); + set_evidence(ci2); ++m_stats.m_fixed_eqs; auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, x, y); ctx.propagate(x, y, jst->to_index()); diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index a6eaeffbf..151bc81d1 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -194,11 +194,8 @@ namespace arith { ++m_stats.m_bound_propagations2; reset_evidence(); m_core.push_back(lit1); - m_params.push_back(parameter(m_farkas)); - m_params.push_back(parameter(rational(1))); - m_params.push_back(parameter(rational(1))); TRACE("arith", tout << lit2 << " <- " << m_core << "\n";); - assign(lit2, m_core, m_eqs, m_params); + assign(lit2, m_core, m_eqs, "farkas 1 1"); ++m_stats.m_bounds_propagations; } @@ -239,13 +236,11 @@ namespace arith { bool first = true; for (unsigned i = 0; i < bounds.size(); ++i) { api_bound* b = bounds[i]; - if (s().value(b->get_lit()) != l_undef) { + if (s().value(b->get_lit()) != l_undef) continue; - } literal lit = is_bound_implied(be.kind(), be.m_bound, *b); - if (lit == sat::null_literal) { + if (lit == sat::null_literal) continue; - } TRACE("arith", tout << lit << " bound: " << *b << " first: " << first << "\n";); lp().settings().stats().m_num_of_implied_bounds++; @@ -260,7 +255,7 @@ namespace arith { TRACE("arith", for (auto lit : m_core) tout << lit << ": " << s().value(lit) << "\n";); DEBUG_CODE(for (auto lit : m_core) { VERIFY(s().value(lit) == l_true); }); ++m_stats.m_bound_propagations1; - assign(lit, m_core, m_eqs, m_params); + assign(lit, m_core, m_eqs, "bounds"); } if (should_refine_bounds() && first) @@ -297,7 +292,7 @@ namespace arith { void solver::consume(rational const& v, lp::constraint_index j) { - set_evidence(j, m_core, m_eqs); + set_evidence(j); m_explanation.add_pair(j, v); } @@ -318,7 +313,7 @@ namespace arith { return false; reset_evidence(); for (auto ev : e) - set_evidence(ev.ci(), m_core, m_eqs); + set_evidence(ev.ci()); auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, n1, n2); ctx.propagate(n1, n2, jst->to_index()); return true; @@ -375,7 +370,7 @@ namespace arith { reset_evidence(); m_explanation.clear(); lp().explain_implied_bound(be, m_bp); - assign(bound, m_core, m_eqs, m_params); + assign(bound, m_core, m_eqs, nullptr); } @@ -748,10 +743,10 @@ namespace arith { ++m_stats.m_fixed_eqs; reset_evidence(); - set_evidence(ci1, m_core, m_eqs); - set_evidence(ci2, m_core, m_eqs); - set_evidence(ci3, m_core, m_eqs); - set_evidence(ci4, m_core, m_eqs); + set_evidence(ci1); + set_evidence(ci2); + set_evidence(ci3); + set_evidence(ci4); enode* x = var2enode(v1); enode* y = var2enode(v2); auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, x, y); @@ -1161,13 +1156,13 @@ namespace arith { // m_explanation implies term <= k reset_evidence(); for (auto ev : m_explanation) - set_evidence(ev.ci(), m_core, m_eqs); + set_evidence(ev.ci()); // The call mk_bound() can set the m_infeasible_column in lar_solver // so the explanation is safer to take before this call. app_ref b = mk_bound(m_lia->get_term(), m_lia->get_offset(), !m_lia->is_upper()); IF_VERBOSE(4, verbose_stream() << "cut " << b << "\n"); literal lit = expr2literal(b); - assign(lit, m_core, m_eqs, m_params); + assign(lit, m_core, m_eqs, nullptr); lia_check = l_false; break; } @@ -1189,20 +1184,16 @@ namespace arith { return lia_check; } - void solver::assign(literal lit, literal_vector const& core, svector const& eqs, vector const& params) { - std::cout << "assign: "; - for (auto const& p : params) - std::cout << p << " "; - std::cout << "\n"; + void solver::assign(literal lit, literal_vector const& core, svector const& eqs, char const* pma) { if (core.size() < small_lemma_size() && eqs.empty()) { m_core2.reset(); for (auto const& c : core) m_core2.push_back(~c); m_core2.push_back(lit); - add_clause(m_core2); + add_clause(m_core2, pma); } else { - auto* jst = euf::th_explain::propagate(*this, core, eqs, lit); + auto* jst = euf::th_explain::propagate(*this, core, eqs, lit, pma); ctx.propagate(lit, jst->to_index()); } } @@ -1225,7 +1216,7 @@ namespace arith { ++m_num_conflicts; ++m_stats.m_conflicts; for (auto ev : m_explanation) - set_evidence(ev.ci(), m_core, m_eqs); + set_evidence(ev.ci()); TRACE("arith", tout << "Lemma - " << (is_conflict ? "conflict" : "propagation") << "\n"; for (literal c : m_core) tout << literal2expr(c) << "\n"; @@ -1247,7 +1238,7 @@ namespace arith { return lp().get_status() == lp::lp_status::INFEASIBLE; } - void solver::set_evidence(lp::constraint_index idx, literal_vector& core, svector& eqs) { + void solver::set_evidence(lp::constraint_index idx) { if (idx == UINT_MAX) { return; } @@ -1255,7 +1246,7 @@ namespace arith { case inequality_source: { literal lit = m_inequalities[idx]; SASSERT(lit != sat::null_literal); - core.push_back(lit); + m_core.push_back(lit); break; } case equality_source: diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index a1d9c8629..3496e42d3 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -413,8 +413,8 @@ namespace arith { void get_infeasibility_explanation_and_set_conflict(); void set_conflict(); void set_conflict_or_lemma(literal_vector const& core, bool is_conflict); - void set_evidence(lp::constraint_index idx, literal_vector& core, svector& eqs); - void assign(literal lit, literal_vector const& core, svector const& eqs, vector const& params); + void set_evidence(lp::constraint_index idx); + void assign(literal lit, literal_vector const& core, svector const& eqs, char const* pma); void false_case_of_check_nla(const nla::lemma& l); void dbg_finalize_model(model& mdl); diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 9335e283f..8e5eb9dd7 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -166,7 +166,7 @@ namespace euf { lits.push_back(jst.lit_consequent()); if (jst.eq_consequent().first != nullptr) lits.push_back(add_lit(jst.eq_consequent())); - get_drat().add(lits, sat::status::th(m_is_redundant, jst.ext().get_id())); + get_drat().add(lits, sat::status::th(m_is_redundant, jst.ext().get_id(), jst.get_pragma())); } void solver::drat_eq_def(literal lit, expr* eq) { diff --git a/src/sat/smt/sat_th.cpp b/src/sat/smt/sat_th.cpp index f72ff601a..1f4c5b572 100644 --- a/src/sat/smt/sat_th.cpp +++ b/src/sat/smt/sat_th.cpp @@ -125,8 +125,8 @@ namespace euf { pop_core(n); } - sat::status th_euf_solver::mk_status() { - return sat::status::th(m_is_redundant, get_id()); + sat::status th_euf_solver::mk_status(char const* ps) { + return sat::status::th(m_is_redundant, get_id(), ps); } bool th_euf_solver::add_unit(sat::literal lit) { @@ -149,6 +149,11 @@ namespace euf { return add_clause(2, lits); } + bool th_euf_solver::add_clause(sat::literal a, sat::literal b, char const* ps) { + sat::literal lits[2] = { a, b }; + return add_clause(2, lits, ps); + } + bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c) { sat::literal lits[3] = { a, b, c }; return add_clause(3, lits); @@ -159,12 +164,12 @@ namespace euf { return add_clause(4, lits); } - bool th_euf_solver::add_clause(unsigned n, sat::literal* lits) { + bool th_euf_solver::add_clause(unsigned n, sat::literal* lits, char const* ps) { bool was_true = false; for (unsigned i = 0; i < n; ++i) was_true |= is_true(lits[i]); ctx.add_root(n, lits); - s().add_clause(n, lits, mk_status()); + s().add_clause(n, lits, mk_status(ps)); return !was_true; } @@ -221,37 +226,44 @@ namespace euf { return ctx.s().rand()(); } - size_t th_explain::get_obj_size(unsigned num_lits, unsigned num_eqs) { - return sat::constraint_base::obj_size(sizeof(th_explain) + sizeof(sat::literal) * num_lits + sizeof(enode_pair) * num_eqs); + size_t th_explain::get_obj_size(unsigned num_lits, unsigned num_eqs, char const* pma) { + return sat::constraint_base::obj_size(sizeof(th_explain) + sizeof(sat::literal) * num_lits + sizeof(enode_pair) * num_eqs + (pma?strlen(pma)+1:1)); } - th_explain::th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& p) { + th_explain::th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& p, char const* pma) { m_consequent = c; m_eq = p; m_num_literals = n_lits; m_num_eqs = n_eqs; - m_literals = reinterpret_cast(reinterpret_cast(this) + sizeof(th_explain)); - for (unsigned i = 0; i < n_lits; ++i) + char * base_ptr = reinterpret_cast(this) + sizeof(th_explain); + m_literals = reinterpret_cast(base_ptr); + unsigned i; + for (i = 0; i < n_lits; ++i) m_literals[i] = lits[i]; - m_eqs = reinterpret_cast(reinterpret_cast(this) + sizeof(th_explain) + sizeof(literal) * n_lits); - for (unsigned i = 0; i < n_eqs; ++i) - m_eqs[i] = eqs[i]; - + base_ptr += sizeof(literal) * n_lits; + m_eqs = reinterpret_cast(base_ptr); + for (i = 0; i < n_eqs; ++i) + m_eqs[i] = eqs[i]; + base_ptr += sizeof(enode_pair) * n_eqs; + m_pragma = reinterpret_cast(base_ptr); + for (i = 0; pma && pma[i]; ++i) + m_pragma[i] = pma[i]; + m_pragma[i] = 0; } - th_explain* th_explain::mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y) { + th_explain* th_explain::mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, char const* pma) { region& r = th.ctx.get_region(); - void* mem = r.allocate(get_obj_size(n_lits, n_eqs)); + void* mem = r.allocate(get_obj_size(n_lits, n_eqs, pma)); sat::constraint_base::initialize(mem, &th); return new (sat::constraint_base::ptr2mem(mem)) th_explain(n_lits, lits, n_eqs, eqs, c, enode_pair(x, y)); } - th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent) { - return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), consequent, nullptr, nullptr); + th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, char const* pma) { + return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), consequent, nullptr, nullptr, pma); } - th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y) { - return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), sat::null_literal, x, y); + th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, char const* pma) { + return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), sat::null_literal, x, y, pma); } th_explain* th_explain::propagate(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y) { @@ -293,6 +305,8 @@ namespace euf { out << "--> " << m_consequent; if (m_eq.first != nullptr) out << "--> " << m_eq.first->get_expr_id() << " == " << m_eq.second->get_expr_id(); + if (m_pragma != nullptr) + out << " p " << m_pragma; return out; } diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index dbd042e98..ffc9d4247 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -143,15 +143,16 @@ namespace euf { region& get_region(); - sat::status mk_status(); + sat::status mk_status(char const* ps = nullptr); bool add_unit(sat::literal lit); bool add_units(sat::literal_vector const& lits); bool add_clause(sat::literal lit) { return add_unit(lit); } bool add_clause(sat::literal a, sat::literal b); + bool add_clause(sat::literal a, sat::literal b, char const* ps); bool add_clause(sat::literal a, sat::literal b, sat::literal c); bool add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d); - bool add_clause(sat::literal_vector const& lits) { return add_clause(lits.size(), lits.data()); } - bool add_clause(unsigned n, sat::literal* lits); + bool add_clause(sat::literal_vector const& lits, char const* ps = nullptr) { return add_clause(lits.size(), lits.data(), ps); } + bool add_clause(unsigned n, sat::literal* lits, char const* ps = nullptr); void add_equiv(sat::literal a, sat::literal b); void add_equiv_and(sat::literal a, sat::literal_vector const& bs); @@ -213,15 +214,16 @@ namespace euf { * that retrieve literals on demand. */ class th_explain { - sat::literal m_consequent { sat::null_literal }; // literal consequent for propagations - enode_pair m_eq { enode_pair() }; // equality consequent for propagations + sat::literal m_consequent = sat::null_literal; // literal consequent for propagations + enode_pair m_eq = enode_pair(); // equality consequent for propagations unsigned m_num_literals; unsigned m_num_eqs; sat::literal* m_literals; enode_pair* m_eqs; - static size_t get_obj_size(unsigned num_lits, unsigned num_eqs); - th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& eq); - static th_explain* mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y); + char* m_pragma; + static size_t get_obj_size(unsigned num_lits, unsigned num_eqs, char const* pma); + th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& eq, char const* pma = nullptr); + static th_explain* mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, char const* pma = nullptr); public: static th_explain* conflict(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs); @@ -232,8 +234,8 @@ namespace euf { static th_explain* conflict(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y); static th_explain* conflict(th_euf_solver& th, euf::enode* x, euf::enode* y); static th_explain* propagate(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y); - static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent); - static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y); + static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, char const* pma = nullptr); + static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, char const* pma = nullptr); sat::ext_constraint_idx to_index() const { return sat::constraint_base::mem2base(this); @@ -268,6 +270,8 @@ namespace euf { enode_pair eq_consequent() const { return m_eq; } + char const* get_pragma() const { return *m_pragma ? m_pragma : nullptr; } + }; From 361888f299ba0499c23b6856d06090c052fc3cdb Mon Sep 17 00:00:00 2001 From: John Jones Date: Mon, 9 May 2022 14:13:08 -0700 Subject: [PATCH 127/253] Generate bdist wheels for musllinux_1_1 (#6025) --- scripts/nightly.yaml | 31 ++++++++++++++++++++++++------- scripts/release.yml | 33 +++++++++++++++++++++++++-------- src/api/python/setup.py | 21 +++++++++++++++++++-- 3 files changed, 68 insertions(+), 17 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 416cb1889..c91c01d62 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -86,13 +86,23 @@ stages: artifactName: 'UbuntuDoc' targetPath: $(Build.ArtifactStagingDirectory) - - job: Manylinux - displayName: "Manylinux build" + - job: LinuxBuilds + strategy: + matrix: + manyLinux: + name: ManyLinux + image: "quay.io/pypa/manylinux2010_x86_64:latest" + python: "/opt/python/cp37-cp37m/bin/python" + muslLinux: + name: MuslLinux + image: "quay.io/pypa/musllinux_1_1_x86_64:latest" + python: "/opt/python/cp310-cp310/bin/python" + displayName: "$(name) build" pool: vmImage: "Ubuntu-18.04" - container: "quay.io/pypa/manylinux2010_x86_64:latest" + container: $(image) variables: - python: "/opt/python/cp37-cp37m/bin/python" + python: $(python) steps: - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava - script: git clone https://github.com/z3prover/z3test z3test @@ -100,7 +110,7 @@ stages: - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/ - task: PublishPipelineArtifact@0 inputs: - artifactName: 'Manylinux' + artifactName: '$(name)Build' targetPath: $(Build.ArtifactStagingDirectory) - job: Windows32 @@ -395,6 +405,11 @@ stages: inputs: artifactName: 'Manylinux' targetPath: $(Agent.TempDirectory) + - task: DownloadPipelineArtifact@2 + displayName: 'Download MuslLinux Build' + inputs: + artifact: 'MuslLinuxBuild' + path: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: artifactName: 'Mac' @@ -405,13 +420,15 @@ stages: targetPath: $(Agent.TempDirectory) - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*x64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*arm64-osx*.zip - - script: cd $(Agent.TempDirectory); mkdir linux-bin; cd linux-bin; unzip ../*glibc*.zip + - script: cd $(Agent.TempDirectory); mkdir libc-bin; cd libc-bin; unzip ../*glibc*.zip + - script: cd $(Agent.TempDirectory); mkdir musl-bin; cd musl-bin; unzip ../*-linux.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip - script: python3 -m pip install --user -U setuptools wheel - script: cd src/api/python; python3 setup.py sdist # take a look at this PREMIUM HACK I came up with to get around the fact that the azure variable syntax overloads the bash syntax for subshells - - script: cd src/api/python; echo $(Agent.TempDirectory)/linux-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/musl-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-x64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel diff --git a/scripts/release.yml b/scripts/release.yml index 265230198..ab61bf8e7 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -129,13 +129,23 @@ stages: artifactName: 'UbuntuDoc' targetPath: $(Build.ArtifactStagingDirectory) - - job: ManyLinuxBuild - displayName: "ManyLinux build" + - job: LinuxBuilds + strategy: + matrix: + manyLinux: + name: ManyLinux + image: "quay.io/pypa/manylinux2010_x86_64:latest" + python: "/opt/python/cp37-cp37m/bin/python" + muslLinux: + name: MuslLinux + image: "quay.io/pypa/musllinux_1_1_x86_64:latest" + python: "/opt/python/cp310-cp310/bin/python" + displayName: "$(name) build" pool: vmImage: "ubuntu-latest" - container: "quay.io/pypa/manylinux2010_x86_64:latest" + container: $(image) variables: - python: "/opt/python/cp37-cp37m/bin/python" + python: $(python) steps: - task: PythonScript@0 displayName: Build @@ -160,7 +170,7 @@ stages: targetFolder: $(Build.ArtifactStagingDirectory) - task: PublishPipelineArtifact@0 inputs: - artifactName: 'ManyLinuxBuild' + artifactName: '$(name)Build' targetPath: $(Build.ArtifactStagingDirectory) - template: build-win-signed.yml @@ -400,6 +410,11 @@ stages: inputs: artifact: 'ManyLinuxBuild' path: $(Agent.TempDirectory) + - task: DownloadPipelineArtifact@2 + displayName: 'Download MuslLinux Build' + inputs: + artifact: 'MuslLinuxBuild' + path: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 displayName: 'Download Win32 Build' inputs: @@ -411,14 +426,16 @@ stages: artifact: 'WindowsBuild-x64' path: $(Agent.TempDirectory) - script: cd $(Agent.TempDirectory); mkdir osx-bin; cd osx-bin; unzip ../*osx*.zip - - script: cd $(Agent.TempDirectory); mkdir linux-bin; cd linux-bin; unzip ../*glibc*.zip + - script: cd $(Agent.TempDirectory); mkdir libc-bin; cd libc-bin; unzip ../*glibc*.zip + - script: cd $(Agent.TempDirectory); mkdir musl-bin; cd musl-bin; unzip ../*-linux.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip - script: python3 -m pip install --user -U setuptools wheel - script: cd src/api/python; python3 setup.py sdist # take a look at this PREMIUM HACK I came up with to get around the fact that the azure variable syntax overloads the bash syntax for subshells - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - - script: cd src/api/python; echo $(Agent.TempDirectory)/linux-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/musl-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - task: PublishPipelineArtifact@0 @@ -534,4 +551,4 @@ stages: secureFile: 'pypircs' - script: python3 -m pip install --upgrade pip - script: python3 -m pip install --user -U setuptools importlib_metadata wheel twine - - script: python3 -m twine upload --config-file $(pypircs.secureFilePath) -r $(pypiReleaseServer) dist/* \ No newline at end of file + - script: python3 -m twine upload --config-file $(pypircs.secureFilePath) -r $(pypiReleaseServer) dist/* diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 6179422df..572b0a7a7 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -250,6 +250,16 @@ class clean(_clean): #try: os.makedirs(os.path.join(ROOT_DIR, 'build')) #except OSError: pass +# platform.freedesktop_os_release was added in 3.10 +os_id = '' +if hasattr(platform, 'freedesktop_os_release'): + try: + osr = platform.freedesktop_os_release() + print(osr) + os_id = osr['ID'] + except OSError: + pass + if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: if RELEASE_DIR is None: name = get_platform() @@ -271,13 +281,20 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: # extract the architecture of the release from the directory name arch = RELEASE_METADATA[1] distos = RELEASE_METADATA[2] - if distos in ('debian', 'ubuntu') or 'linux' in distos: - raise Exception("Linux binary distributions must be built on centos to conform to PEP 513") + if distos in ('debian', 'ubuntu'): + raise Exception( + "Linux binary distributions must be built on centos to conform to PEP 513 or alpine if targetting musl" + ) elif distos == 'glibc': if arch == 'x64': plat_name = 'manylinux1_x86_64' else: plat_name = 'manylinux1_i686' + elif distos == 'linux' and os_id == 'alpine': + if arch == 'x64': + plat_name = 'musllinux_1_1_x86_64' + else: + plat_name = 'musllinux_1_1_i686' elif distos == 'win': if arch == 'x64': plat_name = 'win_amd64' From ad2445e42337c7ab347a3e3b207603cd12055473 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 May 2022 16:33:05 -0700 Subject: [PATCH 128/253] gauss jordan Signed-off-by: Nikolaj Bjorner --- src/math/simplex/simplex.cpp | 4 ++ src/math/simplex/simplex.h | 2 + src/math/simplex/sparse_matrix.h | 69 ++++++++++++++++++++++++++-- src/math/simplex/sparse_matrix_ops.h | 68 +++++++++++++++++++++++++++ src/sat/smt/arith_diagnostics.cpp | 13 ++++++ src/sat/smt/arith_solver.cpp | 2 +- src/sat/smt/arith_solver.h | 3 ++ src/test/simplex.cpp | 31 +++++++++++-- 8 files changed, 183 insertions(+), 9 deletions(-) create mode 100644 src/math/simplex/sparse_matrix_ops.h diff --git a/src/math/simplex/simplex.cpp b/src/math/simplex/simplex.cpp index 6d1c4d348..7649586df 100644 --- a/src/math/simplex/simplex.cpp +++ b/src/math/simplex/simplex.cpp @@ -18,6 +18,7 @@ Notes: --*/ #include "math/simplex/simplex.h" +#include "math/simplex/sparse_matrix_ops.h" #include "math/simplex/sparse_matrix_def.h" #include "math/simplex/simplex_def.h" #include "util/rational.h" @@ -36,6 +37,9 @@ namespace simplex { } } + void gauss_jordan(sparse_matrix& M) { + sparse_matrix_ops::gauss_jordan(M); + } void ensure_rational_solution(simplex& S) { rational delta(1); diff --git a/src/math/simplex/simplex.h b/src/math/simplex/simplex.h index b8781d4ab..44ff3191e 100644 --- a/src/math/simplex/simplex.h +++ b/src/math/simplex/simplex.h @@ -200,5 +200,7 @@ namespace simplex { }; void ensure_rational_solution(simplex& s); + + void gauss_jordan(sparse_matrix& s); }; diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index f18bb6f87..ffbe009e0 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -201,8 +201,22 @@ namespace simplex { row_iterator row_begin(row const& r) { return row_iterator(m_rows[r.id()], true); } row_iterator row_end(row const& r) { return row_iterator(m_rows[r.id()], false); } + class row_vars { + friend class sparse_matrix; + sparse_matrix& s; + row r; + row_vars(sparse_matrix& s, row r): s(s), r(r) {} + public: + row_iterator begin() { return s.row_begin(r); } + row_iterator end() { return s.row_end(r); } + }; + + row_vars get_row(row r) { return row_vars(*this, r); } + unsigned column_size(var_t v) const { return m_columns[v].size(); } + unsigned num_vars() const { return m_columns.size(); } + class col_iterator { friend class sparse_matrix; unsigned m_curr; @@ -228,15 +242,16 @@ namespace simplex { --m_col.m_refs; } - row get_row() { + row get_row() const { return row(m_col.m_entries[m_curr].m_row_id); } - row_entry const& get_row_entry() { + row_entry const& get_row_entry() const { col_entry const& c = m_col.m_entries[m_curr]; int row_id = c.m_row_id; return m_rows[row_id].m_entries[c.m_row_idx]; } - + + std::pair operator*() { return std::make_pair(get_row(), &get_row_entry()); } col_iterator & operator++() { ++m_curr; move_to_used(); return *this; } col_iterator operator++(int) { col_iterator tmp = *this; ++*this; return tmp; } bool operator==(col_iterator const & it) const { return m_curr == it.m_curr; } @@ -246,10 +261,58 @@ namespace simplex { col_iterator col_begin(int v) const { return col_iterator(m_columns[v], m_rows, true); } col_iterator col_end(int v) const { return col_iterator(m_columns[v], m_rows, false); } + class var_rows { + friend class sparse_matrix; + sparse_matrix& s; + int v; + var_rows(sparse_matrix& s, int v):s(s), v(v) {} + public: + col_iterator begin() { return s.col_begin(v); } + col_iterator end() { return s.col_end(v); } + }; + + var_rows get_rows(int v) { return var_rows(*this, v); } + + class all_row_iterator { + friend class sparse_matrix; + unsigned m_curr; + vector<_row> const& m_rows; + void move_to_next() { + while (m_curr < m_rows.size() && m_rows[m_curr].size() == 0) { + std::cout << "size is 0 for " << m_curr << "\n"; + ++m_curr; + } + } + public: + all_row_iterator(unsigned curr, vector<_row> const& rows): m_curr(curr), m_rows(rows) { + move_to_next(); + } + row operator*() { return row(m_curr); } + all_row_iterator & operator++() { m_curr++; move_to_next(); return *this; } + all_row_iterator operator++(int) { all_row_iterator tmp = *this; ++*this; return tmp; } + bool operator==(all_row_iterator const& it) const { return m_curr == it.m_curr; } + bool operator!=(all_row_iterator const& it) const { return m_curr != it.m_curr; } + }; + + class all_rows { + friend class sparse_matrix; + sparse_matrix& s; + all_rows(sparse_matrix& s): s(s) {} + public: + all_row_iterator begin() { return all_row_iterator(0, s.m_rows); } + all_row_iterator end() { return all_row_iterator(s.m_rows.size(), s.m_rows); } + }; + + + all_rows get_rows() { return all_rows(*this); } + + void display(std::ostream& out); void display_row(std::ostream& out, row const& r); bool well_formed() const; + manager& get_manager() { return m; } + void collect_statistics(::statistics & st) const; }; diff --git a/src/math/simplex/sparse_matrix_ops.h b/src/math/simplex/sparse_matrix_ops.h new file mode 100644 index 000000000..249c9bc1e --- /dev/null +++ b/src/math/simplex/sparse_matrix_ops.h @@ -0,0 +1,68 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + sparse_matrix_ops.h + +Abstract: + + +Author: + + Nikolaj Bjorner (nbjorner) 2014-01-15 + +Notes: + +--*/ + +#pragma once + +#include "math/simplex/sparse_matrix.h" +#include "util/rational.h" + +namespace simplex { + + class sparse_matrix_ops { + public: + static void gauss_jordan(sparse_matrix& M) { + mpq_ext::numeral coeff; + vector c, d; + unsigned m = M.num_vars(); + for (unsigned v = 0; v < m; ++v) + c.push_back(0); + + for (auto const& row : M.get_rows()) { + // scan for non-zero variable in row + bool found = false; + for (auto const& [coeff1, v] : M.get_row(row)) { + if (mpq_manager::is_zero(coeff1)) + continue; + found = true; + d.push_back(v); + c[v] = row.id() + 1; + // eliminate v from other rows. + for (auto const& [row2, row_entry2] : M.get_rows(v)) { + if (row.id() == row2.id()) + continue; + if (row_entry2->m_coeff == 0) + continue; + M.get_manager().set(coeff, (- row_entry2->m_coeff / coeff1).to_mpq()); + M.add(row2, coeff, row); + } + break; + } + if (!found) + d.push_back(0); + + } + + M.get_manager().del(coeff); + + // TODO: do something with c and d + } + }; + + +} + diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index 2dfd508d1..28105472d 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -79,4 +79,17 @@ namespace arith { lp().settings().stats().collect_statistics(st); if (m_nla) m_nla->collect_statistics(st); } + + char const* solver::bounds_pragma() { + if (!ctx.use_drat()) + return nullptr; + m_bounds_pragma.clear(); + m_bounds_pragma += "bounds "; + for (sat::literal c : m_core) { + if (c.sign()) m_bounds_pragma += "-"; + m_bounds_pragma += std::to_string(c.var()); + m_bounds_pragma += " "; + } + return m_bounds_pragma.c_str(); + } } diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 151bc81d1..14ed76738 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -255,7 +255,7 @@ namespace arith { TRACE("arith", for (auto lit : m_core) tout << lit << ": " << s().value(lit) << "\n";); DEBUG_CODE(for (auto lit : m_core) { VERIFY(s().value(lit) == l_true); }); ++m_stats.m_bound_propagations1; - assign(lit, m_core, m_eqs, "bounds"); + assign(lit, m_core, m_eqs, bounds_pragma()); } if (should_refine_bounds() && first) diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 3496e42d3..5906ed736 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -419,6 +419,9 @@ namespace arith { void false_case_of_check_nla(const nla::lemma& l); void dbg_finalize_model(model& mdl); + std::string m_bounds_pragma; + char const* bounds_pragma(); + public: solver(euf::solver& ctx, theory_id id); diff --git a/src/test/simplex.cpp b/src/test/simplex.cpp index 713cdd31c..e66a880d6 100644 --- a/src/test/simplex.cpp +++ b/src/test/simplex.cpp @@ -15,6 +15,7 @@ Copyright (c) 2015 Microsoft Corporation #define R rational typedef simplex::simplex Simplex; typedef simplex::sparse_matrix sparse_matrix; +typedef simplex::sparse_matrix qmatrix; static vector vec(int i, int j) { vector nv; @@ -24,11 +25,11 @@ static vector vec(int i, int j) { return nv; } -// static vector vec(int i, int j, int k) { -// vector nv = vec(i, j); -// nv.push_back(R(k)); -// return nv; -// } +static vector vec(int i, int j, int k) { + vector nv = vec(i, j); + nv.push_back(R(k)); + return nv; +} // static vector vec(int i, int j, int k, int l) { // vector nv = vec(i, j, k); @@ -131,6 +132,25 @@ static void test4() { feas(S); } +static void add(qmatrix& m, vector const& v) { + m.ensure_var(v.size()); + auto r = m.mk_row(); + for (unsigned u = 0; u < v.size(); ++u) + m.add_var(r, v[u].to_mpq(), u); +} + +static void test5() { + unsynch_mpq_manager m; + qmatrix M(m); + add(M, vec(1, 2, 3)); + add(M, vec(2, 2, 4)); + M.display(std::cout); + gauss_jordan(M); + std::cout << "after\n"; + M.display(std::cout); + +} + void tst_simplex() { reslimit rl; Simplex S(rl); @@ -166,4 +186,5 @@ void tst_simplex() { test2(); test3(); test4(); + test5(); } From 6a8ac5f9b195cd5d0ad92608c598848d2c6e7ff0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 May 2022 16:47:26 -0700 Subject: [PATCH 129/253] adding K Signed-off-by: Nikolaj Bjorner --- src/math/simplex/simplex.cpp | 4 ++-- src/math/simplex/simplex.h | 2 +- src/math/simplex/sparse_matrix_ops.h | 31 ++++++++++++++++++---------- src/test/simplex.cpp | 3 ++- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/math/simplex/simplex.cpp b/src/math/simplex/simplex.cpp index 7649586df..372bbc221 100644 --- a/src/math/simplex/simplex.cpp +++ b/src/math/simplex/simplex.cpp @@ -37,8 +37,8 @@ namespace simplex { } } - void gauss_jordan(sparse_matrix& M) { - sparse_matrix_ops::gauss_jordan(M); + void kernel(sparse_matrix& M, vector>& K) { + sparse_matrix_ops::kernel(M, K); } void ensure_rational_solution(simplex& S) { diff --git a/src/math/simplex/simplex.h b/src/math/simplex/simplex.h index 44ff3191e..58efef553 100644 --- a/src/math/simplex/simplex.h +++ b/src/math/simplex/simplex.h @@ -201,6 +201,6 @@ namespace simplex { void ensure_rational_solution(simplex& s); - void gauss_jordan(sparse_matrix& s); + void kernel(sparse_matrix& s, vector>& K); }; diff --git a/src/math/simplex/sparse_matrix_ops.h b/src/math/simplex/sparse_matrix_ops.h index 249c9bc1e..5545f5774 100644 --- a/src/math/simplex/sparse_matrix_ops.h +++ b/src/math/simplex/sparse_matrix_ops.h @@ -25,22 +25,25 @@ namespace simplex { class sparse_matrix_ops { public: - static void gauss_jordan(sparse_matrix& M) { + static void kernel(sparse_matrix& M, vector>& K) { mpq_ext::numeral coeff; - vector c, d; + vector d; + bool_vector c; unsigned m = M.num_vars(); for (unsigned v = 0; v < m; ++v) - c.push_back(0); + c.push_back(false); for (auto const& row : M.get_rows()) { // scan for non-zero variable in row bool found = false; + d.push_back(0); for (auto const& [coeff1, v] : M.get_row(row)) { if (mpq_manager::is_zero(coeff1)) continue; - found = true; - d.push_back(v); - c[v] = row.id() + 1; + if (c[v]) + continue; + d.back() = v + 1; + c[v] = true; // eliminate v from other rows. for (auto const& [row2, row_entry2] : M.get_rows(v)) { if (row.id() == row2.id()) @@ -51,15 +54,21 @@ namespace simplex { M.add(row2, coeff, row); } break; - } - if (!found) - d.push_back(0); - + } } M.get_manager().del(coeff); - // TODO: do something with c and d + // TODO: extract kernel using d + for (unsigned k = 0; k < d.size(); ++k) { + if (d[k] != 0) + continue; + K.push_back(vector()); + for (unsigned i = 0; i < d.size(); ++i) { + // K.back().push_back(d[i] > 0 ? M[d[i]-1][k] : (i == k) ? 1 : 0); + } + } + } }; diff --git a/src/test/simplex.cpp b/src/test/simplex.cpp index e66a880d6..f351bc15e 100644 --- a/src/test/simplex.cpp +++ b/src/test/simplex.cpp @@ -145,7 +145,8 @@ static void test5() { add(M, vec(1, 2, 3)); add(M, vec(2, 2, 4)); M.display(std::cout); - gauss_jordan(M); + vector> K; + kernel(M, K); std::cout << "after\n"; M.display(std::cout); From 0557d72d1c5e7d3ea42eae41dddcdce58cca3627 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 May 2022 07:42:32 -0700 Subject: [PATCH 130/253] na Signed-off-by: Nikolaj Bjorner --- src/math/simplex/simplex.cpp | 2 +- src/math/simplex/simplex.h | 3 +- src/math/simplex/sparse_matrix_ops.h | 41 +++++++++++++++++++--------- src/test/simplex.cpp | 2 +- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/math/simplex/simplex.cpp b/src/math/simplex/simplex.cpp index 372bbc221..643db9c5b 100644 --- a/src/math/simplex/simplex.cpp +++ b/src/math/simplex/simplex.cpp @@ -37,7 +37,7 @@ namespace simplex { } } - void kernel(sparse_matrix& M, vector>& K) { + void kernel(sparse_matrix& M, vector>& K) { sparse_matrix_ops::kernel(M, K); } diff --git a/src/math/simplex/simplex.h b/src/math/simplex/simplex.h index 58efef553..8c470a242 100644 --- a/src/math/simplex/simplex.h +++ b/src/math/simplex/simplex.h @@ -33,6 +33,7 @@ Notes: #include "math/simplex/sparse_matrix.h" #include "util/mpq_inf.h" +#include "util/rational.h" #include "util/heap.h" #include "util/lbool.h" #include "util/uint_set.h" @@ -201,6 +202,6 @@ namespace simplex { void ensure_rational_solution(simplex& s); - void kernel(sparse_matrix& s, vector>& K); + void kernel(sparse_matrix& s, vector>& K); }; diff --git a/src/math/simplex/sparse_matrix_ops.h b/src/math/simplex/sparse_matrix_ops.h index 5545f5774..e12f421a1 100644 --- a/src/math/simplex/sparse_matrix_ops.h +++ b/src/math/simplex/sparse_matrix_ops.h @@ -25,45 +25,60 @@ namespace simplex { class sparse_matrix_ops { public: - static void kernel(sparse_matrix& M, vector>& K) { + static void kernel(sparse_matrix& M, vector>& K) { mpq_ext::numeral coeff; - vector d; - bool_vector c; + rational D1, D2; + vector d, c; unsigned m = M.num_vars(); + auto& mgr = M.get_manager(); for (unsigned v = 0; v < m; ++v) - c.push_back(false); + c.push_back(0); for (auto const& row : M.get_rows()) { // scan for non-zero variable in row bool found = false; d.push_back(0); - for (auto const& [coeff1, v] : M.get_row(row)) { + for (auto& [coeff1, v] : M.get_row(row)) { if (mpq_manager::is_zero(coeff1)) continue; - if (c[v]) + if (c[v] != 0) continue; d.back() = v + 1; - c[v] = true; + c[v] = row.id() + 1; + D1 = rational(-1) / coeff1; + mgr.set(coeff1, mpq(-1)); // eliminate v from other rows. for (auto const& [row2, row_entry2] : M.get_rows(v)) { - if (row.id() == row2.id()) + if (row.id() >= row2.id() || row_entry2->m_coeff == 0) continue; - if (row_entry2->m_coeff == 0) + for (auto& [coeff2, w] : M.get_row(row2)) { + if (v == w) + mgr.set(coeff2, (D1*coeff2).to_mpq()); + } + } + + for (auto& [coeff2, w] : M.get_row(row)) { + if (v == w) continue; - M.get_manager().set(coeff, (- row_entry2->m_coeff / coeff1).to_mpq()); - M.add(row2, coeff, row); + D2 = coeff2; + mgr.set(coeff2, mpq(0)); + for (auto const& [row2, row_entry2] : M.get_rows(w)) { + if (row.id() >= row2.id() || row_entry2->m_coeff == 0 || row_entry2->m_var == v) + continue; + // mgr.set(row_entry2->m_coeff, row_entry2->m_coeff + D2*row2[v]); + } } break; } } - M.get_manager().del(coeff); + mgr.del(coeff); // TODO: extract kernel using d for (unsigned k = 0; k < d.size(); ++k) { if (d[k] != 0) continue; - K.push_back(vector()); + K.push_back(vector()); for (unsigned i = 0; i < d.size(); ++i) { // K.back().push_back(d[i] > 0 ? M[d[i]-1][k] : (i == k) ? 1 : 0); } diff --git a/src/test/simplex.cpp b/src/test/simplex.cpp index f351bc15e..a3be5d3bb 100644 --- a/src/test/simplex.cpp +++ b/src/test/simplex.cpp @@ -145,7 +145,7 @@ static void test5() { add(M, vec(1, 2, 3)); add(M, vec(2, 2, 4)); M.display(std::cout); - vector> K; + vector> K; kernel(M, K); std::cout << "after\n"; M.display(std::cout); From 805443c8abc009c237262d90aafbefd56f3768ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 May 2022 11:17:34 -0700 Subject: [PATCH 131/253] wip Signed-off-by: Nikolaj Bjorner --- src/math/simplex/sparse_matrix.h | 19 ++++++++----- src/math/simplex/sparse_matrix_ops.h | 40 ++++++++++++++++------------ 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index ffbe009e0..669b8c2b9 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -221,13 +221,13 @@ namespace simplex { friend class sparse_matrix; unsigned m_curr; column const& m_col; - vector<_row> const& m_rows; + vector<_row>& m_rows; void move_to_used() { while (m_curr < m_col.num_entries() && m_col.m_entries[m_curr].is_dead()) { ++m_curr; } } - col_iterator(column const& c, vector<_row> const& r, bool begin): + col_iterator(column const& c, vector<_row>& r, bool begin): m_curr(0), m_col(c), m_rows(r) { ++m_col.m_refs; if (begin) { @@ -245,21 +245,21 @@ namespace simplex { row get_row() const { return row(m_col.m_entries[m_curr].m_row_id); } - row_entry const& get_row_entry() const { + row_entry& get_row_entry() { col_entry const& c = m_col.m_entries[m_curr]; int row_id = c.m_row_id; return m_rows[row_id].m_entries[c.m_row_idx]; } - std::pair operator*() { return std::make_pair(get_row(), &get_row_entry()); } + std::pair operator*() { return std::make_pair(get_row(), &get_row_entry()); } col_iterator & operator++() { ++m_curr; move_to_used(); return *this; } col_iterator operator++(int) { col_iterator tmp = *this; ++*this; return tmp; } bool operator==(col_iterator const & it) const { return m_curr == it.m_curr; } bool operator!=(col_iterator const & it) const { return m_curr != it.m_curr; } }; - col_iterator col_begin(int v) const { return col_iterator(m_columns[v], m_rows, true); } - col_iterator col_end(int v) const { return col_iterator(m_columns[v], m_rows, false); } + col_iterator col_begin(int v) { return col_iterator(m_columns[v], m_rows, true); } + col_iterator col_end(int v) { return col_iterator(m_columns[v], m_rows, false); } class var_rows { friend class sparse_matrix; @@ -305,6 +305,13 @@ namespace simplex { all_rows get_rows() { return all_rows(*this); } + + numeral& get_coeff(row r, unsigned v) { + for (auto & [coeff, u] : get_row(r)) + if (u == v) + return coeff; + throw default_exception("variable not in row"); + } void display(std::ostream& out); diff --git a/src/math/simplex/sparse_matrix_ops.h b/src/math/simplex/sparse_matrix_ops.h index e12f421a1..1827f9b12 100644 --- a/src/math/simplex/sparse_matrix_ops.h +++ b/src/math/simplex/sparse_matrix_ops.h @@ -27,7 +27,7 @@ namespace simplex { public: static void kernel(sparse_matrix& M, vector>& K) { mpq_ext::numeral coeff; - rational D1, D2; + rational D; vector d, c; unsigned m = M.num_vars(); auto& mgr = M.get_manager(); @@ -45,27 +45,26 @@ namespace simplex { continue; d.back() = v + 1; c[v] = row.id() + 1; - D1 = rational(-1) / coeff1; + D = rational(-1) / coeff1; mgr.set(coeff1, mpq(-1)); // eliminate v from other rows. - for (auto const& [row2, row_entry2] : M.get_rows(v)) { - if (row.id() >= row2.id() || row_entry2->m_coeff == 0) + for (auto& [row2, row_entry2] : M.get_rows(v)) { + if (row.id() >= row2.id()) continue; - for (auto& [coeff2, w] : M.get_row(row2)) { - if (v == w) - mgr.set(coeff2, (D1*coeff2).to_mpq()); - } + mpq & m_js = row_entry2->m_coeff; + mgr.set(m_js, (D * m_js).to_mpq()); } - - for (auto& [coeff2, w] : M.get_row(row)) { + for (auto& [m_ik, w] : M.get_row(row)) { if (v == w) continue; - D2 = coeff2; - mgr.set(coeff2, mpq(0)); - for (auto const& [row2, row_entry2] : M.get_rows(w)) { - if (row.id() >= row2.id() || row_entry2->m_coeff == 0 || row_entry2->m_var == v) + D = m_ik; + mgr.set(m_ik, mpq(0)); + for (auto& [row2, row_entry2] : M.get_rows(w)) { + if (row.id() >= row2.id()) continue; - // mgr.set(row_entry2->m_coeff, row_entry2->m_coeff + D2*row2[v]); + auto& m_js = M.get_coeff(row2, v); + auto & m_is = row_entry2->m_coeff; + mgr.set(m_is, (m_is + D * m_js).to_mpq()); } } break; @@ -79,8 +78,15 @@ namespace simplex { if (d[k] != 0) continue; K.push_back(vector()); - for (unsigned i = 0; i < d.size(); ++i) { - // K.back().push_back(d[i] > 0 ? M[d[i]-1][k] : (i == k) ? 1 : 0); + for (unsigned i = 0; i < d.size(); ++i) { + if (d[i] > 0) { + // row r = row(i); + // K.back().push_back(M[d[i]-1][k]); + } + else if (i == k) + K.back().push_back(rational(1)); + else + K.back().push_back(rational(0)); } } From 2928cc261ca2aae4127f977f461df7269dc10ed9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 May 2022 13:17:25 -0700 Subject: [PATCH 132/253] fix Signed-off-by: Nikolaj Bjorner --- src/math/simplex/sparse_matrix_ops.h | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/math/simplex/sparse_matrix_ops.h b/src/math/simplex/sparse_matrix_ops.h index 1827f9b12..5b508afcf 100644 --- a/src/math/simplex/sparse_matrix_ops.h +++ b/src/math/simplex/sparse_matrix_ops.h @@ -33,22 +33,26 @@ namespace simplex { auto& mgr = M.get_manager(); for (unsigned v = 0; v < m; ++v) c.push_back(0); - + + unsigned nullity = 0, rank = 0; for (auto const& row : M.get_rows()) { // scan for non-zero variable in row bool found = false; d.push_back(0); + ++nullity; for (auto& [coeff1, v] : M.get_row(row)) { if (mpq_manager::is_zero(coeff1)) continue; if (c[v] != 0) continue; + --nullity; + ++rank; d.back() = v + 1; c[v] = row.id() + 1; D = rational(-1) / coeff1; mgr.set(coeff1, mpq(-1)); // eliminate v from other rows. - for (auto& [row2, row_entry2] : M.get_rows(v)) { + for (auto [row2, row_entry2] : M.get_rows(v)) { if (row.id() >= row2.id()) continue; mpq & m_js = row_entry2->m_coeff; @@ -59,7 +63,7 @@ namespace simplex { continue; D = m_ik; mgr.set(m_ik, mpq(0)); - for (auto& [row2, row_entry2] : M.get_rows(w)) { + for (auto [row2, row_entry2] : M.get_rows(w)) { if (row.id() >= row2.id()) continue; auto& m_js = M.get_coeff(row2, v); @@ -73,6 +77,13 @@ namespace simplex { mgr.del(coeff); + std::cout << "nullity " << nullity << "\n"; + std::cout << "rank " << rank << "\n"; + unsigned_vector pivots(rank, 0u); + unsigned_vector nonpivots(nullity, 0u); + + + // TODO: extract kernel using d for (unsigned k = 0; k < d.size(); ++k) { if (d[k] != 0) From 54648f6b508f9e5bf4100693a6ee4223297b1410 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 May 2022 14:58:15 -0700 Subject: [PATCH 133/253] add stats for binary clause creation Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context_pp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 181d9d529..77b42c6c2 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -415,6 +415,7 @@ namespace smt { st.update("final checks", m_stats.m_num_final_checks); st.update("added eqs", m_stats.m_num_add_eq); st.update("mk clause", m_stats.m_num_mk_clause); + st.update("mk clause binary", m_stats.m_num_mk_bin_clause); st.update("del clause", m_stats.m_num_del_clause); st.update("dyn ack", m_stats.m_num_dyn_ack); st.update("interface eqs", m_stats.m_num_interface_eqs); From 5ca3bc32122129cee5c20504185559a69fbdec9c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 May 2022 15:48:06 -0700 Subject: [PATCH 134/253] kernel Signed-off-by: Nikolaj Bjorner --- src/math/simplex/sparse_matrix.h | 8 ++- src/math/simplex/sparse_matrix_ops.h | 82 +++++++++------------------- src/test/simplex.cpp | 40 ++++++++------ 3 files changed, 54 insertions(+), 76 deletions(-) diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index 669b8c2b9..b51b57181 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -136,6 +136,7 @@ namespace simplex { svector m_var_pos; // temporary map from variables to positions in row unsigned_vector m_var_pos_idx; // indices in m_var_pos stats m_stats; + scoped_numeral m_zero; bool well_formed_row(unsigned row_id) const; bool well_formed_column(unsigned column_id) const; @@ -144,7 +145,7 @@ namespace simplex { public: - sparse_matrix(manager& _m): m(_m) {} + sparse_matrix(manager& _m): m(_m), m_zero(m) {} ~sparse_matrix(); void reset(); @@ -216,6 +217,7 @@ namespace simplex { unsigned column_size(var_t v) const { return m_columns[v].size(); } unsigned num_vars() const { return m_columns.size(); } + unsigned num_rows() const { return m_rows.size(); } class col_iterator { friend class sparse_matrix; @@ -306,11 +308,11 @@ namespace simplex { all_rows get_rows() { return all_rows(*this); } - numeral& get_coeff(row r, unsigned v) { + numeral const& get_coeff(row r, unsigned v) { for (auto & [coeff, u] : get_row(r)) if (u == v) return coeff; - throw default_exception("variable not in row"); + return m_zero; } diff --git a/src/math/simplex/sparse_matrix_ops.h b/src/math/simplex/sparse_matrix_ops.h index 5b508afcf..8ed36f8bb 100644 --- a/src/math/simplex/sparse_matrix_ops.h +++ b/src/math/simplex/sparse_matrix_ops.h @@ -26,73 +26,44 @@ namespace simplex { class sparse_matrix_ops { public: static void kernel(sparse_matrix& M, vector>& K) { - mpq_ext::numeral coeff; rational D; vector d, c; - unsigned m = M.num_vars(); + unsigned n = M.num_vars(), m = M.num_rows(); auto& mgr = M.get_manager(); - for (unsigned v = 0; v < m; ++v) - c.push_back(0); + c.resize(m, 0u); + d.resize(n, 0u); - unsigned nullity = 0, rank = 0; - for (auto const& row : M.get_rows()) { - // scan for non-zero variable in row - bool found = false; - d.push_back(0); - ++nullity; - for (auto& [coeff1, v] : M.get_row(row)) { - if (mpq_manager::is_zero(coeff1)) + for (unsigned k = 0; k < n; ++k) { + d[k] = 0; + for (auto [row, row_entry] : M.get_rows(k)) { + if (c[row.id()] != 0) + continue; + auto& m_jk = row_entry->m_coeff; + if (mpq_manager::is_zero(m_jk)) continue; - if (c[v] != 0) - continue; - --nullity; - ++rank; - d.back() = v + 1; - c[v] = row.id() + 1; - D = rational(-1) / coeff1; - mgr.set(coeff1, mpq(-1)); - // eliminate v from other rows. - for (auto [row2, row_entry2] : M.get_rows(v)) { - if (row.id() >= row2.id()) - continue; - mpq & m_js = row_entry2->m_coeff; - mgr.set(m_js, (D * m_js).to_mpq()); - } - for (auto& [m_ik, w] : M.get_row(row)) { - if (v == w) - continue; - D = m_ik; - mgr.set(m_ik, mpq(0)); - for (auto [row2, row_entry2] : M.get_rows(w)) { - if (row.id() >= row2.id()) - continue; - auto& m_js = M.get_coeff(row2, v); - auto & m_is = row_entry2->m_coeff; - mgr.set(m_is, (m_is + D * m_js).to_mpq()); - } - } + D = rational(-1) / m_jk; + M.mul(row, D.to_mpq()); + for (auto [row_i, row_i_entry] : M.get_rows(k)) { + if (row_i.id() == row.id()) + continue; + auto& m_ik = row_i_entry->m_coeff; + // row_i += m_ik * row + M.add(row_i, m_ik, row); + } + c[row.id()] = k + 1; + d[k] = row.id() + 1; break; - } + } } - mgr.del(coeff); - - std::cout << "nullity " << nullity << "\n"; - std::cout << "rank " << rank << "\n"; - unsigned_vector pivots(rank, 0u); - unsigned_vector nonpivots(nullity, 0u); - - - - // TODO: extract kernel using d - for (unsigned k = 0; k < d.size(); ++k) { + for (unsigned k = 0; k < n; ++k) { if (d[k] != 0) continue; K.push_back(vector()); - for (unsigned i = 0; i < d.size(); ++i) { + for (unsigned i = 0; i < n; ++i) { if (d[i] > 0) { - // row r = row(i); - // K.back().push_back(M[d[i]-1][k]); + auto r = sparse_matrix::row(d[i]-1); + K.back().push_back(rational(M.get_coeff(r, k))); } else if (i == k) K.back().push_back(rational(1)); @@ -102,6 +73,7 @@ namespace simplex { } } + }; diff --git a/src/test/simplex.cpp b/src/test/simplex.cpp index a3be5d3bb..5c52642bd 100644 --- a/src/test/simplex.cpp +++ b/src/test/simplex.cpp @@ -31,23 +31,23 @@ static vector vec(int i, int j, int k) { return nv; } -// static vector vec(int i, int j, int k, int l) { -// vector nv = vec(i, j, k); -// nv.push_back(R(l)); -// return nv; -// } +static vector vec(int i, int j, int k, int l) { + vector nv = vec(i, j, k); + nv.push_back(R(l)); + return nv; +} -/// static vector vec(int i, int j, int k, int l, int x) { -/// vector nv = vec(i, j, k, l); -/// nv.push_back(R(x)); -/// return nv; -/// } +static vector vec(int i, int j, int k, int l, int x) { + vector nv = vec(i, j, k, l); + nv.push_back(R(x)); + return nv; +} -// static vector vec(int i, int j, int k, int l, int x, int y) { -// vector nv = vec(i, j, k, l, x); -// nv.push_back(R(y)); -// return nv; -// } +static vector vec(int i, int j, int k, int l, int x, int y) { + vector nv = vec(i, j, k, l, x); + nv.push_back(R(y)); + return nv; +} // static vector vec(int i, int j, int k, int l, int x, int y, int z) { // vector nv = vec(i, j, k, l, x, y); @@ -133,7 +133,7 @@ static void test4() { } static void add(qmatrix& m, vector const& v) { - m.ensure_var(v.size()); + m.ensure_var(v.size()-1); auto r = m.mk_row(); for (unsigned u = 0; u < v.size(); ++u) m.add_var(r, v[u].to_mpq(), u); @@ -142,12 +142,16 @@ static void add(qmatrix& m, vector const& v) { static void test5() { unsynch_mpq_manager m; qmatrix M(m); - add(M, vec(1, 2, 3)); - add(M, vec(2, 2, 4)); + add(M, vec(1, 0, -3, 0, 2, -8)); + add(M, vec(0, 1, 5, 0, -1, 4)); + add(M, vec(0, 0, 0, 1, 7, -9)); + add(M, vec(0, 0, 0, 0, 0, 0)); M.display(std::cout); vector> K; kernel(M, K); std::cout << "after\n"; + for (auto const& v : K) + std::cout << v << "\n"; M.display(std::cout); } From cbaa16df57ce3861d84cbb5f3d614385c5b38748 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 May 2022 09:03:57 -0700 Subject: [PATCH 135/253] lcm normalization Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 19 +++++++++++++++++-- src/math/simplex/model_based_opt.h | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index e63e71be6..62d1f4c55 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -485,6 +485,21 @@ namespace opt { } } + model_based_opt::row& model_based_opt::row::normalize() { + if (m_type == t_mod) + return *this; + rational D(abs(m_coeff)); + for (auto const& [id, coeff] : m_vars) + D = lcm(D, coeff); + if (D == 1) + return *this; + SASSERT(D > 0); + for (auto & [id, coeff] : m_vars) + coeff *= D; + m_coeff *= D; + return *this; + } + // // Let // row1: t1 + a1*x <= 0 @@ -923,9 +938,9 @@ namespace opt { } void model_based_opt::get_live_rows(vector& rows) { - for (row const& r : m_rows) { + for (row & r : m_rows) { if (r.m_alive) { - rows.push_back(r); + rows.push_back(r.normalize()); } } } diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index bb6f8f91c..cb8c18542 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -59,6 +59,7 @@ namespace opt { bool m_alive; // rows can be marked dead if they have been processed. void reset() { m_vars.reset(); m_coeff.reset(); m_value.reset(); } + row& normalize(); void neg() { for (var & v : m_vars) v.m_coeff.neg(); m_coeff.neg(); m_value.neg(); } rational get_coefficient(unsigned x) const; }; From 361155685ce228c4fcd5d4ded7fc86bb9765ece2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 May 2022 09:09:00 -0700 Subject: [PATCH 136/253] ensure abs Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 62d1f4c55..2420ab7f7 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -490,7 +490,7 @@ namespace opt { return *this; rational D(abs(m_coeff)); for (auto const& [id, coeff] : m_vars) - D = lcm(D, coeff); + D = lcm(D, abs(coeff)); if (D == 1) return *this; SASSERT(D > 0); From 860d90469934da236624b4e163703f21d44b4e25 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 May 2022 10:11:17 -0700 Subject: [PATCH 137/253] check zero Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 2420ab7f7..fbbe05801 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -490,7 +490,8 @@ namespace opt { return *this; rational D(abs(m_coeff)); for (auto const& [id, coeff] : m_vars) - D = lcm(D, abs(coeff)); + if (coeff != 0) + D = lcm(D, abs(coeff)); if (D == 1) return *this; SASSERT(D > 0); From 5aec9b32bde8446f5f79c04a8dde676b99e00373 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 May 2022 10:13:07 -0700 Subject: [PATCH 138/253] check zero Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index fbbe05801..5321d2d0c 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -489,6 +489,8 @@ namespace opt { if (m_type == t_mod) return *this; rational D(abs(m_coeff)); + if (D == 0) + D = 1; for (auto const& [id, coeff] : m_vars) if (coeff != 0) D = lcm(D, abs(coeff)); From 6deb4dee37519da51f6d0eb392e565ae781158a1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 May 2022 13:30:50 -0700 Subject: [PATCH 139/253] disable normalize Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 2 ++ src/math/simplex/model_based_opt.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 66a1384f5..2c245534d 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -101,6 +101,7 @@ namespace api { m_dt_plugin = static_cast(m().get_plugin(m_dt_fid)); install_tactics(*this); + std::cout << "alloc\n"; } @@ -113,6 +114,7 @@ namespace api { } if (m_params.owns_manager()) m_manager.detach(); + std::cout << "dealloc " << memory::get_allocation_size() << "\n"; } context::set_interruptable::set_interruptable(context & ctx, event_handler & i): diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 5321d2d0c..8b8f82a31 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -486,20 +486,22 @@ namespace opt { } model_based_opt::row& model_based_opt::row::normalize() { +#if 0 if (m_type == t_mod) return *this; - rational D(abs(m_coeff)); + rational D(denominator(abs(m_coeff))); if (D == 0) D = 1; for (auto const& [id, coeff] : m_vars) if (coeff != 0) - D = lcm(D, abs(coeff)); + D = lcm(D, denominator(abs(coeff))); if (D == 1) return *this; SASSERT(D > 0); for (auto & [id, coeff] : m_vars) coeff *= D; m_coeff *= D; +#endif return *this; } From b1aa6b260bb622ffa84c1b75ccfc2eb4c8f82b14 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 May 2022 13:31:35 -0700 Subject: [PATCH 140/253] disable normalize Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 2c245534d..3eb375f12 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -101,7 +101,7 @@ namespace api { m_dt_plugin = static_cast(m().get_plugin(m_dt_fid)); install_tactics(*this); - std::cout << "alloc\n"; + // std::cout << "alloc\n"; } @@ -114,7 +114,8 @@ namespace api { } if (m_params.owns_manager()) m_manager.detach(); - std::cout << "dealloc " << memory::get_allocation_size() << "\n"; + // std::cout << "dealloc " << memory::get_allocation_size() << "\n"; + } context::set_interruptable::set_interruptable(context & ctx, event_handler & i): From 7497856dedd21c185e94caaf11f68be0bd847ae9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 May 2022 15:14:22 -0700 Subject: [PATCH 141/253] add ignore int to new arithmetic solvers Signed-off-by: Nikolaj Bjorner --- src/sat/smt/arith_solver.cpp | 9 ++++++++- src/smt/theory_lra.cpp | 10 +++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 14ed76738..68c25c110 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -1014,6 +1014,9 @@ namespace arith { return sat::check_result::CR_CONTINUE; case l_undef: TRACE("arith", tout << "check-lia giveup\n";); + if (ctx.get_config().m_arith_ignore_int) + return sat::check_result::CR_GIVEUP; + st = sat::check_result::CR_CONTINUE; break; } @@ -1127,7 +1130,11 @@ namespace arith { if (!check_idiv_bounds()) return l_false; - switch (m_lia->check(&m_explanation)) { + auto cr = m_lia->check(&m_explanation); + if (cr != lp::lia_move::sat && ctx.get_config().m_arith_ignore_int) + return l_undef; + + switch (cr) { case lp::lia_move::sat: lia_check = l_true; break; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index cf1d73892..94702a32b 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1539,6 +1539,8 @@ public: return FC_CONTINUE; case l_undef: TRACE("arith", tout << "check-lia giveup\n";); + if (ctx().get_fparams().m_arith_ignore_int) + return FC_GIVEUP; st = FC_CONTINUE; break; } @@ -1866,7 +1868,11 @@ public: return l_undef; } lbool lia_check = l_undef; - switch (m_lia->check(&m_explanation)) { + auto cr = m_lia->check(&m_explanation); + if (cr != lp::lia_move::sat && ctx().get_fparams().m_arith_ignore_int) + return l_undef; + + switch (cr) { case lp::lia_move::sat: lia_check = l_true; break; @@ -1896,6 +1902,8 @@ public: break; } case lp::lia_move::cut: { + if (ctx().get_fparams().m_arith_ignore_int) + return l_undef; TRACE("arith", tout << "cut\n";); ++m_stats.m_gomory_cuts; // m_explanation implies term <= k From 6f7be77e2bdf00ed38ca7755f3ca38e7facbb384 Mon Sep 17 00:00:00 2001 From: Gleb Popov <6yearold@gmail.com> Date: Thu, 12 May 2022 20:54:57 +0300 Subject: [PATCH 142/253] Buildsystem fixes for FreeBSD. (#6029) * Enable thread-local storage on FreeBSD. * Pass -soname linker flag on FreeBSD. --- scripts/mk_util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 761de8b26..8a56e843a 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2599,6 +2599,7 @@ def mk_config(): OS_DEFINES = '-D_FREEBSD_' SO_EXT = '.so' SLIBFLAGS = '-shared' + SLIBEXTRAFLAGS = '%s -Wl,-soname,libz3.so' % SLIBEXTRAFLAGS elif sysname == 'NetBSD': CXXFLAGS = '%s -D_NETBSD_' % CXXFLAGS OS_DEFINES = '-D_NETBSD_' @@ -2632,7 +2633,7 @@ def mk_config(): if is64(): if not sysname.startswith('CYGWIN') and not sysname.startswith('MSYS') and not sysname.startswith('MINGW'): CXXFLAGS = '%s -fPIC' % CXXFLAGS - if sysname == 'Linux': + if sysname == 'Linux' or sysname == 'FreeBSD': CPPFLAGS = '%s -D_USE_THREAD_LOCAL' % CPPFLAGS elif not LINUX_X64: CXXFLAGS = '%s -m32' % CXXFLAGS From 7f62fa2b669864e4107972ab2b619da8b87e175b Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 13 May 2022 17:30:35 -0700 Subject: [PATCH 143/253] Sparse matrix kernel (#6035) * Subtle bug in kernel computation Coefficient was being passed by reference and, therefore, was being changed indirectly. In the process, updated the code to be more generic to avoid rational computation in the middle of matrix manipulation. * sparse_matrix: fixed handling of 0 in add_var() and add() particularly in add_var(), without the fix the user is responsible for checking coefficients for 0. --- src/math/simplex/sparse_matrix_def.h | 2 + src/math/simplex/sparse_matrix_ops.h | 106 ++++++++++++++------------- 2 files changed, 57 insertions(+), 51 deletions(-) diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index a3170461b..b20aa76ba 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -299,6 +299,7 @@ namespace simplex { template void sparse_matrix::add_var(row dst, numeral const& n, var_t v) { + if (m.is_zero(n)) return; _row& r = m_rows[dst.id()]; column& c = m_columns[v]; unsigned r_idx; @@ -317,6 +318,7 @@ namespace simplex { */ template void sparse_matrix::add(row row1, numeral const& n, row row2) { + if (m.is_zero(n)) return; m_stats.m_add_rows++; _row & r1 = m_rows[row1.id()]; diff --git a/src/math/simplex/sparse_matrix_ops.h b/src/math/simplex/sparse_matrix_ops.h index 8ed36f8bb..039d2fede 100644 --- a/src/math/simplex/sparse_matrix_ops.h +++ b/src/math/simplex/sparse_matrix_ops.h @@ -7,7 +7,7 @@ Module Name: Abstract: - + Author: Nikolaj Bjorner (nbjorner) 2014-01-15 @@ -23,59 +23,63 @@ Notes: namespace simplex { - class sparse_matrix_ops { - public: - static void kernel(sparse_matrix& M, vector>& K) { - rational D; - vector d, c; - unsigned n = M.num_vars(), m = M.num_rows(); - auto& mgr = M.get_manager(); - c.resize(m, 0u); - d.resize(n, 0u); +class sparse_matrix_ops { + public: + template + static void kernel(sparse_matrix &M, vector> &K) { + using scoped_numeral = typename Ext::scoped_numeral; - for (unsigned k = 0; k < n; ++k) { - d[k] = 0; - for (auto [row, row_entry] : M.get_rows(k)) { - if (c[row.id()] != 0) - continue; - auto& m_jk = row_entry->m_coeff; - if (mpq_manager::is_zero(m_jk)) - continue; - D = rational(-1) / m_jk; - M.mul(row, D.to_mpq()); - for (auto [row_i, row_i_entry] : M.get_rows(k)) { - if (row_i.id() == row.id()) - continue; - auto& m_ik = row_i_entry->m_coeff; - // row_i += m_ik * row - M.add(row_i, m_ik, row); - } - c[row.id()] = k + 1; - d[k] = row.id() + 1; - break; + vector d, c; + unsigned n_vars = M.num_vars(), n_rows = M.num_rows(); + c.resize(n_rows, 0u); + d.resize(n_vars, 0u); + + auto &m = M.get_manager(); + scoped_numeral m_ik(m); + scoped_numeral D(m); + + for (unsigned k = 0; k < n_vars; ++k) { + d[k] = 0; + for (auto [row, row_entry] : M.get_rows(k)) { + if (c[row.id()] != 0) continue; + auto &m_jk = row_entry->m_coeff; + if (mpq_manager::is_zero(m_jk)) continue; + + // D = rational(-1) / m_jk; + m.set(D, m_jk); + m.inv(D); + m.neg(D); + + M.mul(row, D); + for (auto [row_i, row_i_entry] : M.get_rows(k)) { + if (row_i.id() == row.id()) continue; + m.set(m_ik, row_i_entry->m_coeff); + // row_i += m_ik * row + M.add(row_i, m_ik, row); } + c[row.id()] = k + 1; + d[k] = row.id() + 1; + break; } - - for (unsigned k = 0; k < n; ++k) { - if (d[k] != 0) - continue; - K.push_back(vector()); - for (unsigned i = 0; i < n; ++i) { - if (d[i] > 0) { - auto r = sparse_matrix::row(d[i]-1); - K.back().push_back(rational(M.get_coeff(r, k))); - } - else if (i == k) - K.back().push_back(rational(1)); - else - K.back().push_back(rational(0)); - } - } - } - }; - - -} + for (unsigned k = 0; k < n_vars; ++k) { + if (d[k] != 0) continue; + K.push_back(vector()); + for (unsigned i = 0; i < n_vars; ++i) { + if (d[i] > 0) { + auto r = sparse_matrix::row(d[i] - 1); + K.back().push_back(rational(M.get_coeff(r, k))); + } else if (i == k) + K.back().push_back(rational(1)); + else + K.back().push_back(rational(0)); + } + } + } + static void kernel(sparse_matrix &M, vector> &K) { + kernel(M, K); + } +}; +} // namespace simplex From 1028c8085169221329a9b960cb908408fcd87532 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 May 2022 12:14:07 -0700 Subject: [PATCH 144/253] update pretty printer for recursive function filtering Signed-off-by: Nikolaj Bjorner --- src/ast/ast_pp_util.cpp | 49 +++++++++++++++++++------------------- src/ast/ast_pp_util.h | 12 ++++++---- src/ast/decl_collector.cpp | 30 +++++++++++++---------- src/ast/decl_collector.h | 14 ++++++----- src/util/stacked_value.h | 17 ++++++------- 5 files changed, 65 insertions(+), 57 deletions(-) diff --git a/src/ast/ast_pp_util.cpp b/src/ast/ast_pp_util.cpp index 2f2dad0d1..008a7cc9a 100644 --- a/src/ast/ast_pp_util.cpp +++ b/src/ast/ast_pp_util.cpp @@ -27,9 +27,8 @@ void ast_pp_util::collect(expr* e) { } void ast_pp_util::collect(unsigned n, expr* const* es) { - for (unsigned i = 0; i < n; ++i) { + for (unsigned i = 0; i < n; ++i) coll.visit(es[i]); - } } void ast_pp_util::collect(expr_ref_vector const& es) { @@ -38,31 +37,31 @@ void ast_pp_util::collect(expr_ref_vector const& es) { void ast_pp_util::display_decls(std::ostream& out) { ast_smt_pp pp(m); - bool first = m_num_decls == 0; - coll.order_deps(m_num_sorts); + coll.order_deps(m_sorts); unsigned n = coll.get_num_sorts(); ast_mark seen; - for (unsigned i = m_num_sorts; i < n; ++i) + for (unsigned i = m_sorts; i < n; ++i) pp.display_sort_decl(out, coll.get_sorts()[i], seen); - m_num_sorts = n; + m_sorts = n; + n = coll.get_num_decls(); - for (unsigned i = m_num_decls; i < n; ++i) { + for (unsigned i = m_decls; i < n; ++i) { func_decl* f = coll.get_func_decls()[i]; - if (f->get_family_id() == null_family_id && !m_removed.contains(f)) { + if (f->get_family_id() == null_family_id && !m_removed.contains(f)) ast_smt2_pp(out, f, m_env) << "\n"; - } } - m_num_decls = n; - if (first) { - vector> recfuns; - recfun::util u(m); - func_decl_ref_vector funs = u.get_rec_funs(); - if (funs.empty()) return; - for (func_decl * f : funs) { - recfuns.push_back(std::make_pair(f, u.get_def(f).get_rhs())); - } + m_decls = n; + + n = coll.get_rec_decls().size(); + vector> recfuns; + recfun::util u(m); + for (unsigned i = m_rec_decls; i < n; ++i) { + func_decl* f = coll.get_rec_decls()[i]; + recfuns.push_back(std::make_pair(f, u.get_def(f).get_rhs())); + } + if (!recfuns.empty()) ast_smt2_pp_recdefs(out, recfuns, m_env); - } + m_rec_decls = n; } void ast_pp_util::remove_decl(func_decl* f) { @@ -116,14 +115,14 @@ void ast_pp_util::display_asserts(std::ostream& out, expr_ref_vector const& fmls void ast_pp_util::push() { coll.push(); - m_num_sorts_trail.push_back(m_num_sorts); - m_num_decls_trail.push_back(m_num_decls); + m_rec_decls.push(); + m_decls.push(); + m_sorts.push(); } void ast_pp_util::pop(unsigned n) { coll.pop(n); - m_num_sorts = m_num_sorts_trail[m_num_sorts_trail.size() - n]; - m_num_decls = m_num_decls_trail[m_num_decls_trail.size() - n]; - m_num_sorts_trail.shrink(m_num_sorts_trail.size() - n); - m_num_decls_trail.shrink(m_num_decls_trail.size() - n); + m_rec_decls.pop(n); + m_decls.pop(n); + m_sorts.pop(n); } diff --git a/src/ast/ast_pp_util.h b/src/ast/ast_pp_util.h index d03419020..1a04f8af0 100644 --- a/src/ast/ast_pp_util.h +++ b/src/ast/ast_pp_util.h @@ -21,22 +21,24 @@ Revision History: #include "ast/decl_collector.h" #include "ast/ast_smt2_pp.h" #include "util/obj_hashtable.h" +#include "util/stacked_value.h" class ast_pp_util { ast_manager& m; obj_hashtable m_removed; smt2_pp_environment_dbg m_env; - unsigned m_num_sorts, m_num_decls; - unsigned_vector m_num_sorts_trail, m_num_decls_trail; + stacked_value m_rec_decls; + stacked_value m_decls; + stacked_value m_sorts; public: decl_collector coll; - ast_pp_util(ast_manager& m): m(m), m_env(m), m_num_sorts(0), m_num_decls(0), coll(m) {} - - void reset() { coll.reset(); m_removed.reset(); m_num_sorts = 0; m_num_decls = 0; } + ast_pp_util(ast_manager& m): m(m), m_env(m), coll(m), m_rec_decls(0), m_decls(0), m_sorts(0) {} + void reset() { coll.reset(); m_removed.reset(); m_sorts.clear(0u); m_decls.clear(0u); m_rec_decls.clear(0u); } + void collect(expr* e); diff --git a/src/ast/decl_collector.cpp b/src/ast/decl_collector.cpp index 2333188c5..ecad96521 100644 --- a/src/ast/decl_collector.cpp +++ b/src/ast/decl_collector.cpp @@ -19,6 +19,7 @@ Revision History: --*/ #include "ast/decl_collector.h" #include "ast/ast_pp.h" +#include "ast/recfun_decl_plugin.h" void decl_collector::visit_sort(sort * n) { SASSERT(!m_visited.is_marked(n)); @@ -49,8 +50,12 @@ bool decl_collector::is_bool(sort * s) { void decl_collector::visit_func(func_decl * n) { if (!m_visited.is_marked(n)) { family_id fid = n->get_family_id(); - if (fid == null_family_id) { + if (fid == null_family_id) m_decls.push_back(n); + else if (fid == m_rec_fid) { + m_rec_decls.push_back(n); + recfun::util u(m()); + m_todo.push_back(u.get_def(n).get_rhs()); } m_visited.mark(n, true); m_trail.push_back(n); @@ -63,6 +68,8 @@ decl_collector::decl_collector(ast_manager & m): m_dt_util(m) { m_basic_fid = m_manager.get_basic_family_id(); m_dt_fid = m_dt_util.get_family_id(); + recfun::util rec_util(m); + m_rec_fid = rec_util.get_family_id(); } void decl_collector::visit(ast* n) { @@ -143,9 +150,8 @@ void decl_collector::collect_deps(sort* s, sort_set& set) { set.insert(s); if (s->is_sort_of(m_dt_util.get_family_id(), DATATYPE_SORT)) { unsigned num_sorts = m_dt_util.get_datatype_num_parameter_sorts(s); - for (unsigned i = 0; i < num_sorts; ++i) { + for (unsigned i = 0; i < num_sorts; ++i) set.insert(m_dt_util.get_datatype_parameter_sort(s, i)); - } unsigned num_cnstr = m_dt_util.get_datatype_num_constructors(s); for (unsigned i = 0; i < num_cnstr; i++) { func_decl * cnstr = m_dt_util.get_datatype_constructors(s)->get(i); @@ -157,29 +163,27 @@ void decl_collector::collect_deps(sort* s, sort_set& set) { for (unsigned i = s->get_num_parameters(); i-- > 0; ) { parameter const& p = s->get_parameter(i); - if (p.is_ast() && is_sort(p.get_ast())) { + if (p.is_ast() && is_sort(p.get_ast())) set.insert(to_sort(p.get_ast())); - } } } void decl_collector::push() { m_trail_lim.push_back(m_trail.size()); - m_sorts_lim.push_back(m_sorts.size()); - m_decls_lim.push_back(m_decls.size()); + m_sorts.push_scope(); + m_decls.push_scope(); + m_rec_decls.push_scope(); } void decl_collector::pop(unsigned n) { SASSERT(n > 0); unsigned sz = m_trail_lim[m_trail_lim.size() - n]; - for (unsigned i = m_trail.size(); i-- > sz; ) { + for (unsigned i = m_trail.size(); i-- > sz; ) m_visited.mark(m_trail.get(i), false); - } m_trail.shrink(sz); - m_sorts.shrink(m_sorts_lim[m_sorts_lim.size() - n]); - m_decls.shrink(m_decls_lim[m_decls_lim.size() - n]); m_trail_lim.shrink(m_trail_lim.size() - n); - m_sorts_lim.shrink(m_sorts_lim.size() - n); - m_decls_lim.shrink(m_decls_lim.size() - n); + m_sorts.pop_scope(n); + m_decls.pop_scope(n); + m_rec_decls.pop_scope(n); } diff --git a/src/ast/decl_collector.h b/src/ast/decl_collector.h index 1fead3587..876b97188 100644 --- a/src/ast/decl_collector.h +++ b/src/ast/decl_collector.h @@ -20,21 +20,22 @@ Revision History: #pragma once #include "util/top_sort.h" +#include "util/lim_vector.h" #include "ast/ast.h" #include "ast/datatype_decl_plugin.h" class decl_collector { ast_manager & m_manager; - ptr_vector m_sorts; - ptr_vector m_decls; + lim_svector m_sorts; + lim_svector m_decls; + lim_svector m_rec_decls; ast_mark m_visited; ast_ref_vector m_trail; unsigned_vector m_trail_lim; - unsigned_vector m_sorts_lim; - unsigned_vector m_decls_lim; family_id m_basic_fid; family_id m_dt_fid; datatype_util m_dt_util; + family_id m_rec_fid; ptr_vector m_todo; void visit_sort(sort* n); @@ -64,7 +65,8 @@ public: unsigned get_num_sorts() const { return m_sorts.size(); } unsigned get_num_decls() const { return m_decls.size(); } - ptr_vector const& get_sorts() const { return m_sorts; } - ptr_vector const& get_func_decls() const { return m_decls; } + lim_svector const& get_sorts() const { return m_sorts; } + lim_svector const& get_func_decls() const { return m_decls; } + lim_svector const& get_rec_decls() const { return m_rec_decls; } }; diff --git a/src/util/stacked_value.h b/src/util/stacked_value.h index 3f01f3766..89be6fa53 100644 --- a/src/util/stacked_value.h +++ b/src/util/stacked_value.h @@ -20,23 +20,24 @@ Revision History: #pragma once // add to value the stack semantics -#include +#include "util/vector.h" template class stacked_value { T m_value; - std::stack m_stack; + vector m_stack; public: void push() { - m_stack.push(m_value); + m_stack.push_back(m_value); } - void clear() { - m_stack.clear(); + void clear(T const& m) { + pop(m_stack.size()); + m_value = m; } unsigned stack_size() const { - return static_cast(m_stack.size()); + return m_stack.size(); } void pop() { @@ -46,8 +47,8 @@ public: while (k-- > 0) { if (m_stack.empty()) return; - m_value = m_stack.top(); - m_stack.pop(); + m_value = m_stack.back(); + m_stack.pop_back(); } } From 186a3c58e5e4fb5b30b4c8ca91489b5c7bf4d09b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 May 2022 12:00:25 -0700 Subject: [PATCH 145/253] merge Signed-off-by: Nikolaj Bjorner --- src/math/simplex/sparse_matrix_def.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index b20aa76ba..dc3700f2e 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -299,7 +299,8 @@ namespace simplex { template void sparse_matrix::add_var(row dst, numeral const& n, var_t v) { - if (m.is_zero(n)) return; + if (m.is_zero(n)) + return; _row& r = m_rows[dst.id()]; column& c = m_columns[v]; unsigned r_idx; @@ -318,7 +319,9 @@ namespace simplex { */ template void sparse_matrix::add(row row1, numeral const& n, row row2) { - if (m.is_zero(n)) return; + + if (m.is_zero(n)) + return; m_stats.m_add_rows++; _row & r1 = m_rows[row1.id()]; From ca2497eecb837205861179599ebaa0bf3ba98cf4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 May 2022 11:59:37 -0700 Subject: [PATCH 146/253] na Signed-off-by: Nikolaj Bjorner --- src/ast/ast.h | 5 ++--- src/smt/smt_context.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index 3cb90193f..79a3cebc7 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1914,9 +1914,8 @@ public: return mk_fresh_const(prefix.c_str(), s, skolem); } - app * mk_fresh_const(symbol const& prefix, sort * s, bool skolem = true) { - auto str = prefix.str(); - return mk_fresh_const(str.c_str(), s, skolem); + app * mk_fresh_const(symbol const& prefix, sort * s, bool skolem = true) { + return mk_const(mk_fresh_func_decl(prefix, symbol::null, 0, nullptr, s, skolem)); } symbol mk_fresh_var_name(char const * prefix = nullptr); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 3e444bec7..49c76ca53 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3168,7 +3168,7 @@ namespace smt { } else { expr_ref proxy(m), fml(m); - proxy = m.mk_fresh_const("proxy", m.mk_bool_sort()); + proxy = m.mk_fresh_const(symbol(), m.mk_bool_sort()); fml = m.mk_implies(proxy, e); m_asserted_formulas.assert_expr(fml); asm2proxy.push_back(std::make_pair(e, proxy)); From f6b2874d7ce951a0771c504f6ea7c4894342dfb2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 May 2022 10:30:54 -0700 Subject: [PATCH 147/253] update to take effect of def_API for callback functions Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 24 +++++++++--------------- src/api/python/z3/z3.py | 14 +++++++------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 0553843cb..6fb4fee53 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1881,28 +1881,22 @@ _error_handler_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_uint) _lib.Z3_set_error_handler.restype = None _lib.Z3_set_error_handler.argtypes = [ContextObj, _error_handler_type] -push_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p) -pop_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint) -fresh_eh_type = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) +Z3_push_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p) +Z3_pop_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint) +Z3_fresh_eh = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) -fixed_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) -final_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p) -eq_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) +Z3_fixed_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) +Z3_final_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p) +Z3_eq_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) + +Z3_created_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) +Z3_decide_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) _lib.Z3_solver_propagate_init.restype = None -_lib.Z3_solver_propagate_init.argtypes = [ContextObj, SolverObj, ctypes.c_void_p, push_eh_type, pop_eh_type, fresh_eh_type] - _lib.Z3_solver_propagate_final.restype = None -_lib.Z3_solver_propagate_final.argtypes = [ContextObj, SolverObj, final_eh_type] - _lib.Z3_solver_propagate_fixed.restype = None -_lib.Z3_solver_propagate_fixed.argtypes = [ContextObj, SolverObj, fixed_eh_type] - _lib.Z3_solver_propagate_eq.restype = None -_lib.Z3_solver_propagate_eq.argtypes = [ContextObj, SolverObj, eq_eh_type] - _lib.Z3_solver_propagate_diseq.restype = None -_lib.Z3_solver_propagate_diseq.argtypes = [ContextObj, SolverObj, eq_eh_type] on_model_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p) _lib.Z3_optimize_register_model_eh.restype = None diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 69959d181..c45a3d86e 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -11330,13 +11330,13 @@ def user_prop_diseq(ctx, cb, x, y): prop.cb = None -_user_prop_push = push_eh_type(user_prop_push) -_user_prop_pop = pop_eh_type(user_prop_pop) -_user_prop_fresh = fresh_eh_type(user_prop_fresh) -_user_prop_fixed = fixed_eh_type(user_prop_fixed) -_user_prop_final = final_eh_type(user_prop_final) -_user_prop_eq = eq_eh_type(user_prop_eq) -_user_prop_diseq = eq_eh_type(user_prop_diseq) +_user_prop_push = Z3_push_eh(user_prop_push) +_user_prop_pop = Z3_pop_eh(user_prop_pop) +_user_prop_fresh = Z3_fresh_eh(user_prop_fresh) +_user_prop_fixed = Z3_fixed_eh(user_prop_fixed) +_user_prop_final = Z3_final_eh(user_prop_final) +_user_prop_eq = Z3_eq_eh(user_prop_eq) +_user_prop_diseq = Z3_eq_eh(user_prop_diseq) class UserPropagateBase: From 363b69f58856b95814f45065eee82f2e27e120e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 May 2022 16:44:13 -0700 Subject: [PATCH 148/253] fix #6034 --- scripts/update_api.py | 17 ++++++++++++----- src/api/api_ast_map.cpp | 1 - src/api/api_ast_vector.cpp | 1 - src/api/api_context.cpp | 3 ++- src/api/api_goal.cpp | 1 - src/api/api_model.cpp | 1 - src/api/api_opt.cpp | 1 - src/api/api_params.cpp | 5 ++--- src/api/api_solver.cpp | 7 +++---- src/api/api_tactic.cpp | 3 --- 10 files changed, 19 insertions(+), 21 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 6fb4fee53..24cf3745b 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -308,6 +308,13 @@ def display_args_to_z3(params): NULLWrapped = [ 'Z3_mk_context', 'Z3_mk_context_rc' ] Unwrapped = [ 'Z3_del_context', 'Z3_get_error_code' ] +Unchecked = frozenset([ 'Z3_dec_ref', 'Z3_params_dec_ref', 'Z3_model_dec_ref', + 'Z3_func_interp_dec_ref', 'Z3_func_entry_dec_ref', + 'Z3_goal_dec_ref', 'Z3_tactic_dec_ref', 'Z3_probe_dec_ref', + 'Z3_fixedpoint_dec_ref', 'Z3_param_descrs_dec_ref', + 'Z3_ast_vector_dec_ref', 'Z3_ast_map_dec_ref', + 'Z3_apply_result_dec_ref', 'Z3_solver_dec_ref', + 'Z3_stats_dec_ref', 'Z3_optimize_dec_ref']) def mk_py_wrappers(): core_py.write(""" @@ -377,7 +384,7 @@ def mk_py_wrapper_single(sig, decode_string=True): core_py.write(" %s_elems.f(" % lval) display_args_to_z3(params) core_py.write(")\n") - if len(params) > 0 and param_type(params[0]) == CONTEXT and not name in Unwrapped: + if len(params) > 0 and param_type(params[0]) == CONTEXT and not name in Unwrapped and not name in Unchecked: core_py.write(" _elems.Check(a0)\n") if result == STRING and decode_string: core_py.write(" return _to_pystr(r)\n") @@ -498,7 +505,7 @@ def mk_dotnet_wrappers(dotnet): dotnet.write(" if (r == IntPtr.Zero)\n") dotnet.write(" throw new Z3Exception(\"Object allocation failed.\");\n") else: - if len(params) > 0 and param_type(params[0]) == CONTEXT: + if len(params) > 0 and param_type(params[0]) == CONTEXT and name not in Unchecked: dotnet.write(" Z3_error_code err = (Z3_error_code)LIB.Z3_get_error_code(a0);\n") dotnet.write(" if (err != Z3_error_code.Z3_OK)\n") dotnet.write(" throw new Z3Exception(Marshal.PtrToStringAnsi(LIB.Z3_get_error_msg(a0, (uint)err)));\n") @@ -671,7 +678,7 @@ def mk_java(java_dir, package_name): java_native.write(" if (res == 0)\n") java_native.write(" throw new Z3Exception(\"Object allocation failed.\");\n") else: - if len(params) > 0 and param_type(params[0]) == CONTEXT: + if len(params) > 0 and param_type(params[0]) == CONTEXT and name not in Unchecked: java_native.write(' Z3_error_code err = Z3_error_code.fromInt(INTERNALgetErrorCode(a0));\n') java_native.write(' if (err != Z3_error_code.Z3_OK)\n') java_native.write(' throw new Z3Exception(INTERNALgetErrorMsg(a0, err.toInt()));\n') @@ -1494,7 +1501,7 @@ def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface # determine if the function has a context as parameter. have_context = (len(params) > 0) and (param_type(params[0]) == CONTEXT) - if have_context and name not in Unwrapped: + if have_context and name not in Unwrapped and name not in Unchecked: ml_wrapper.write(' Z3_error_code ec;\n') if result != VOID: @@ -1620,7 +1627,7 @@ def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface if release_caml_gc: ml_wrapper.write('\n caml_acquire_runtime_system();\n') - if have_context and name not in Unwrapped: + if have_context and name not in Unwrapped and name not in Unchecked: ml_wrapper.write(' ec = Z3_get_error_code(ctx_p->ctx);\n') ml_wrapper.write(' if (ec != Z3_OK) {\n') ml_wrapper.write(' const char * msg = Z3_get_error_msg(ctx_p->ctx, ec);\n') diff --git a/src/api/api_ast_map.cpp b/src/api/api_ast_map.cpp index 714712faf..e252b9aca 100644 --- a/src/api/api_ast_map.cpp +++ b/src/api/api_ast_map.cpp @@ -52,7 +52,6 @@ extern "C" { void Z3_API Z3_ast_map_dec_ref(Z3_context c, Z3_ast_map m) { Z3_TRY; LOG_Z3_ast_map_dec_ref(c, m); - RESET_ERROR_CODE(); if (m) to_ast_map(m)->dec_ref(); Z3_CATCH; diff --git a/src/api/api_ast_vector.cpp b/src/api/api_ast_vector.cpp index 335fb6170..a8a64ce2c 100644 --- a/src/api/api_ast_vector.cpp +++ b/src/api/api_ast_vector.cpp @@ -47,7 +47,6 @@ extern "C" { void Z3_API Z3_ast_vector_dec_ref(Z3_context c, Z3_ast_vector v) { Z3_TRY; LOG_Z3_ast_vector_dec_ref(c, v); - RESET_ERROR_CODE(); if (v) to_ast_vector(v)->dec_ref(); Z3_CATCH; diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 3eb375f12..9f7376c68 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -374,8 +374,9 @@ extern "C" { void Z3_API Z3_dec_ref(Z3_context c, Z3_ast a) { Z3_TRY; LOG_Z3_dec_ref(c, a); - RESET_ERROR_CODE(); if (a && to_ast(a)->get_ref_count() == 0) { + // the error is unchecked (but should not happen) in GC'ed wrappers + RESET_ERROR_CODE(); SET_ERROR_CODE(Z3_DEC_REF_ERROR, nullptr); return; } diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index 7e2b5cd55..dd9f8959f 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -52,7 +52,6 @@ extern "C" { void Z3_API Z3_goal_dec_ref(Z3_context c, Z3_goal g) { Z3_TRY; LOG_Z3_goal_dec_ref(c, g); - RESET_ERROR_CODE(); if (g) to_goal(g)->dec_ref(); Z3_CATCH; diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index f22873f7b..3512b4b05 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -53,7 +53,6 @@ extern "C" { void Z3_API Z3_model_dec_ref(Z3_context c, Z3_model m) { Z3_TRY; LOG_Z3_model_dec_ref(c, m); - RESET_ERROR_CODE(); if (m) { to_model(m)->dec_ref(); } diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index a682a83da..140c655cd 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -67,7 +67,6 @@ extern "C" { void Z3_API Z3_optimize_dec_ref(Z3_context c, Z3_optimize o) { Z3_TRY; LOG_Z3_optimize_dec_ref(c, o); - RESET_ERROR_CODE(); if (o) to_optimize(o)->dec_ref(); Z3_CATCH; diff --git a/src/api/api_params.cpp b/src/api/api_params.cpp index d17018638..6e06fbf78 100644 --- a/src/api/api_params.cpp +++ b/src/api/api_params.cpp @@ -54,7 +54,6 @@ extern "C" { void Z3_API Z3_params_dec_ref(Z3_context c, Z3_params p) { Z3_TRY; LOG_Z3_params_dec_ref(c, p); - RESET_ERROR_CODE(); if (p) to_params(p)->dec_ref(); Z3_CATCH; @@ -141,8 +140,8 @@ extern "C" { void Z3_API Z3_param_descrs_dec_ref(Z3_context c, Z3_param_descrs p) { Z3_TRY; LOG_Z3_param_descrs_dec_ref(c, p); - RESET_ERROR_CODE(); - to_param_descrs(p)->dec_ref(); + if (p) + to_param_descrs(p)->dec_ref(); Z3_CATCH; } diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 05b125546..b8765a69b 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -207,7 +207,7 @@ extern "C" { if (!smt_logics::supported_logic(to_symbol(logic))) { std::ostringstream strm; strm << "logic '" << to_symbol(logic) << "' is not recognized"; - throw default_exception(strm.str()); + SET_ERROR_CODE(Z3_INVALID_ARG, strm.str()); RETURN_Z3(nullptr); } else { @@ -412,9 +412,8 @@ extern "C" { void Z3_API Z3_solver_dec_ref(Z3_context c, Z3_solver s) { Z3_TRY; LOG_Z3_solver_dec_ref(c, s); - RESET_ERROR_CODE(); - if (s) - to_solver(s)->dec_ref(); + if (s) + to_solver(s)->dec_ref(); Z3_CATCH; } diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index f67a373dd..edf9ab262 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -73,7 +73,6 @@ extern "C" { void Z3_API Z3_tactic_dec_ref(Z3_context c, Z3_tactic t) { Z3_TRY; LOG_Z3_tactic_dec_ref(c, t); - RESET_ERROR_CODE(); if (t) to_tactic(t)->dec_ref(); Z3_CATCH; @@ -104,7 +103,6 @@ extern "C" { void Z3_API Z3_probe_dec_ref(Z3_context c, Z3_probe p) { Z3_TRY; LOG_Z3_probe_dec_ref(c, p); - RESET_ERROR_CODE(); if (p) to_probe(p)->dec_ref(); Z3_CATCH; @@ -477,7 +475,6 @@ extern "C" { void Z3_API Z3_apply_result_dec_ref(Z3_context c, Z3_apply_result r) { Z3_TRY; LOG_Z3_apply_result_dec_ref(c, r); - RESET_ERROR_CODE(); if (r) to_apply_result(r)->dec_ref(); Z3_CATCH; From 40fe472e9555ee5a67b64f70c71577c9a2941bd7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 May 2022 13:23:33 -0700 Subject: [PATCH 149/253] nit --- src/ast/ast.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 65e2a5d1a..332116d71 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1672,9 +1672,8 @@ void ast_manager::add_lambda_def(func_decl* f, quantifier* q) { } quantifier* ast_manager::is_lambda_def(func_decl* f) { - if (f->get_info() && f->get_info()->is_lambda()) { + if (f->get_info() && f->get_info()->is_lambda()) return m_lambda_defs[f]; - } return nullptr; } From 127af83c53251095d4c3f2fa40afe7d58b5a105a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 May 2022 13:04:47 -0700 Subject: [PATCH 150/253] remove ad-hoc diagnostics --- src/api/api_context.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 9f7376c68..3ba279dca 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -101,7 +101,6 @@ namespace api { m_dt_plugin = static_cast(m().get_plugin(m_dt_fid)); install_tactics(*this); - // std::cout << "alloc\n"; } @@ -114,7 +113,6 @@ namespace api { } if (m_params.owns_manager()) m_manager.detach(); - // std::cout << "dealloc " << memory::get_allocation_size() << "\n"; } From 386c511f54b48cde503cb33ad698fa61ef6a83bd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 21 May 2022 10:27:32 -0400 Subject: [PATCH 151/253] core opt --- src/opt/maxcore.cpp | 1 + src/opt/maxsmt.cpp | 6 +- src/opt/opt_context.cpp | 14 ++-- src/opt/opt_preprocess.cpp | 53 ++++++++++++++- src/opt/opt_preprocess.h | 2 + src/sat/sat_solver/inc_sat_solver.cpp | 92 +++++++++++++++++++-------- src/sat/tactic/goal2sat.cpp | 58 +++++++++++++---- src/sat/tactic/goal2sat.h | 12 +++- 8 files changed, 182 insertions(+), 56 deletions(-) diff --git a/src/opt/maxcore.cpp b/src/opt/maxcore.cpp index 216ca1877..1a89129c5 100644 --- a/src/opt/maxcore.cpp +++ b/src/opt/maxcore.cpp @@ -510,6 +510,7 @@ public: for (auto const & [core, w] : cores) { if (core.empty()) return l_false; + ++m_stats.m_num_cores; remove_soft(core, m_asms); split_core(core); process_unsat(core, w); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 02de67bb5..6064ef899 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -342,15 +342,13 @@ namespace opt { void maxsmt::updt_params(params_ref& p) { m_params.append(p); - if (m_msolver) { + if (m_msolver) m_msolver->updt_params(p); - } } void maxsmt::collect_statistics(statistics& st) const { - if (m_msolver) { + if (m_msolver) m_msolver->collect_statistics(st); - } } solver& maxsmt::s() { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 85835f08d..fcc8cdd46 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1533,20 +1533,16 @@ namespace opt { } void context::collect_statistics(statistics& stats) const { - if (m_solver) { + if (m_solver) m_solver->collect_statistics(stats); - } - if (m_simplify) { - m_simplify->collect_statistics(stats); - } - for (auto const& kv : m_maxsmts) { + if (m_simplify) + m_simplify->collect_statistics(stats); + for (auto const& kv : m_maxsmts) kv.m_value->collect_statistics(stats); - } get_memory_statistics(stats); get_rlimit_statistics(m.limit(), stats); - if (m_qmax) { + if (m_qmax) m_qmax->collect_statistics(stats); - } } void context::collect_param_descrs(param_descrs & r) { diff --git a/src/opt/opt_preprocess.cpp b/src/opt/opt_preprocess.cpp index bbf119266..268aa8986 100644 --- a/src/opt/opt_preprocess.cpp +++ b/src/opt/opt_preprocess.cpp @@ -15,6 +15,19 @@ Author: Nikolaj Bjorner (nbjorner) 2022-04-11 + +Notes: + + maxsat x, y, z, u . x + y + z <= 1 and F +=> + maxsst x or y or z, u . x + y + z <= 1 and F + lower bound increased by 2 + + maxsat x, y, z, u . x + y + z >= 2 and F +=> + maxsst x and y and z, u . x + y + z >= 2 and F + lower bound decreased by 2 + --*/ #pragma once @@ -113,13 +126,28 @@ namespace opt { m_trail.push_back(sf.s); if (new_soft.contains(sf.s)) new_soft[sf.s] += sf.weight; - else + else { new_soft.insert(sf.s, sf.weight); - fmls.push_back(sf.s); + fmls.push_back(sf.s); + } } return new_soft; } + obj_map preprocess::dualize(obj_map const& soft, expr_ref_vector& fmls) { + obj_map new_soft; + for (auto const& [k, v] : soft) { + expr* nk = mk_not(m, k); + m_trail.push_back(nk); + new_soft.insert(nk, v); + } + unsigned i = 0; + for (expr* f : fmls) + fmls[i++] = mk_not(m, f); + + return new_soft; + } + bool preprocess::find_mutexes(vector& softs, rational& lower) { expr_ref_vector fmls(m); obj_map new_soft = soft2map(softs, fmls); @@ -131,6 +159,24 @@ namespace opt { return false; for (auto& mux : mutexes) process_mutex(mux, new_soft, lower); + + + if (mutexes.empty()) + { + obj_map dual_soft = dualize(new_soft, fmls); + mutexes.reset(); + lbool is_sat = s.find_mutexes(fmls, mutexes); + if (is_sat == l_false) + return true; + if (is_sat == l_undef) + return false; + rational llower(0); + for (auto& mux : mutexes) + process_mutex(mux, dual_soft, llower); + if (dual_soft.size() != new_soft.size()) + new_soft = dualize(dual_soft, fmls); + } + softs.reset(); for (auto const& [k, v] : new_soft) softs.push_back(soft(expr_ref(k, m), v, false)); @@ -175,7 +221,7 @@ namespace opt { weight = w - weight; lower += weight*rational(i); IF_VERBOSE(1, verbose_stream() << "(opt.maxsat mutex size: " << i + 1 << " weight: " << weight << ")\n";); - sum2 += weight*rational(i+1); + sum2 += weight * rational(i + 1); new_soft.insert(soft, weight); for (; i > 0 && weights[i-1] == w; --i) {} weight = w; @@ -183,6 +229,7 @@ namespace opt { SASSERT(sum1 == sum2); } + preprocess::preprocess(solver& s): m(s.get_manager()), s(s), m_trail(m) {} bool preprocess::operator()(vector& soft, rational& lower) { diff --git a/src/opt/opt_preprocess.h b/src/opt/opt_preprocess.h index 567a750ed..71e06eb2c 100644 --- a/src/opt/opt_preprocess.h +++ b/src/opt/opt_preprocess.h @@ -34,6 +34,8 @@ namespace opt { bool prop_mutexes(vector& softs, rational& lower); void process_mutex(expr_ref_vector& mutex, obj_map& new_soft, rational& lower); + obj_map dualize(obj_map const& soft, expr_ref_vector& fmls); + public: preprocess(solver& s); bool operator()(vector& soft, rational& lower); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index af0d9dd1b..cf46b1f27 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -698,6 +698,33 @@ public: private: + lbool check_uninterpreted() { + func_decl_ref_vector funs(m); + m_goal2sat.get_interpreted_funs(funs); + + if (!funs.empty()) { + m_has_uninterpreted = true; + std::stringstream strm; + strm << "(sat.giveup interpreted functions sent to SAT solver " << funs <<")"; + TRACE("sat", tout << strm.str() << "\n";); + IF_VERBOSE(1, verbose_stream() << strm.str() << "\n";); + set_reason_unknown(strm.str()); + return l_undef; + } + return l_true; + } + + lbool internalize_goal(unsigned sz, expr* const* fmls) { + m_solver.pop_to_base_level(); + if (m_solver.inconsistent()) + return l_false; + m_pc.reset(); + m_goal2sat(m, sz, fmls, m_params, m_solver, m_map, m_dep2asm, is_incremental()); + if (!m_sat_mc) m_sat_mc = alloc(sat2goal::mc, m); + m_sat_mc->flush_smc(m_solver, m_map); + return check_uninterpreted(); + } + lbool internalize_goal(goal_ref& g) { m_solver.pop_to_base_level(); if (m_solver.inconsistent()) @@ -712,12 +739,14 @@ private: } SASSERT(!g->proofs_enabled()); TRACE("sat", m_solver.display(tout); g->display(tout);); + try { if (m_is_cnf) { m_subgoals.push_back(g.get()); } else { (*m_preprocess)(g, m_subgoals); + m_is_cnf = true; } } catch (tactic_exception & ex) { @@ -737,8 +766,8 @@ private: IF_VERBOSE(0, verbose_stream() << "size of subgoals is not 1, it is: " << m_subgoals.size() << "\n"); return l_undef; } + g = m_subgoals[0]; - func_decl_ref_vector funs(m); m_pc = g->pc(); m_mcs.set(m_mcs.size()-1, concat(m_mcs.back(), g->mc())); TRACE("sat", g->display_with_dependencies(tout);); @@ -746,19 +775,10 @@ private: // ensure that if goal is already internalized, then import mc from m_solver. m_goal2sat(*g, m_params, m_solver, m_map, m_dep2asm, is_incremental()); - m_goal2sat.get_interpreted_funs(funs); + if (!m_sat_mc) m_sat_mc = alloc(sat2goal::mc, m); m_sat_mc->flush_smc(m_solver, m_map); - if (!funs.empty()) { - m_has_uninterpreted = true; - std::stringstream strm; - strm << "(sat.giveup interpreted functions sent to SAT solver " << funs <<")"; - TRACE("sat", tout << strm.str() << "\n";); - IF_VERBOSE(1, verbose_stream() << strm.str() << "\n";); - set_reason_unknown(strm.str()); - return l_undef; - } - return l_true; + return check_uninterpreted(); } lbool internalize_assumptions(unsigned sz, expr* const* asms) { @@ -766,17 +786,30 @@ private: m_asms.shrink(0); return l_true; } + for (unsigned i = 0; i < sz; ++i) + m_is_cnf &= is_literal(asms[i]); + for (unsigned i = 0; i < get_num_assumptions(); ++i) + m_is_cnf &= is_literal(get_assumption(i)); + + if (m_is_cnf) { + // std::cout << "assumptions " << sz << " " << get_num_assumptions() << " " << m_fmls_head << " " << m_fmls.size() << "\n"; + expr_ref_vector fmls(m); + fmls.append(sz, asms); + for (unsigned i = 0; i < get_num_assumptions(); ++i) + fmls.push_back(get_assumption(i)); + m_goal2sat.assumptions(m, fmls.size(), fmls.data(), m_params, m_solver, m_map, m_dep2asm, is_incremental()); + extract_assumptions(fmls.size(), fmls.data()); + return l_true; + } + goal_ref g = alloc(goal, m, true, true); // models and cores are enabled. - for (unsigned i = 0; i < sz; ++i) { + for (unsigned i = 0; i < sz; ++i) g->assert_expr(asms[i], m.mk_leaf(asms[i])); - } - for (unsigned i = 0; i < get_num_assumptions(); ++i) { + for (unsigned i = 0; i < get_num_assumptions(); ++i) g->assert_expr(get_assumption(i), m.mk_leaf(get_assumption(i))); - } lbool res = internalize_goal(g); - if (res == l_true) { + if (res == l_true) extract_assumptions(sz, asms); - } return res; } @@ -905,18 +938,25 @@ private: } lbool internalize_formulas() { - if (m_fmls_head == m_fmls.size()) { + if (m_fmls_head == m_fmls.size()) return l_true; + + lbool res; + + if (m_is_cnf) { + std::cout << "cnf\n"; + res = internalize_goal(m_fmls.size() - m_fmls_head, m_fmls.data() + m_fmls_head); } - goal_ref g = alloc(goal, m, true, false); // models, maybe cores are enabled - for (unsigned i = m_fmls_head ; i < m_fmls.size(); ++i) { - expr* fml = m_fmls.get(i); - g->assert_expr(fml); + else { + goal_ref g = alloc(goal, m, true, false); // models, maybe cores are enabled + for (unsigned i = m_fmls_head ; i < m_fmls.size(); ++i) { + expr* fml = m_fmls.get(i); + g->assert_expr(fml); + } + res = internalize_goal(g); } - lbool res = internalize_goal(g); - if (res != l_undef) { + if (res != l_undef) m_fmls_head = m_fmls.size(); - } m_internalized_converted = false; return res; } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index af07001e3..73d8561df 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -894,16 +894,36 @@ struct goal2sat::imp : public sat::sat_internalizer { m_result_stack.pop_back(); } + struct scoped_reset { + imp& i; + scoped_reset(imp& i) :i(i) {} + ~scoped_reset() { + i.m_interface_vars.reset(); + i.m_app2lit.reset(); + i.m_lit2app.reset(); + } + }; + + void operator()(unsigned n, expr* const* fmls) { + scoped_reset _reset(*this); + // collect_boolean_interface(g, m_interface_vars); + for (unsigned i = 0; i < n; ++i) + process(fmls[i]); + } + + void assumptions(unsigned n, expr* const* fmls) { + scoped_reset _reset(*this); + // collect_boolean_interface(g, m_interface_vars); + for (unsigned i = 0; i < n; ++i) { + expr* f = fmls[i]; + expr* f1 = f; + bool sign = m.is_not(f, f1); + insert_dep(f, f1, sign); + } + } + + void operator()(goal const & g) { - struct scoped_reset { - imp& i; - scoped_reset(imp& i) :i(i) {} - ~scoped_reset() { - i.m_interface_vars.reset(); - i.m_app2lit.reset(); - i.m_lit2app.reset(); - } - }; scoped_reset _reset(*this); collect_boolean_interface(g, m_interface_vars); unsigned size = g.size(); @@ -1002,16 +1022,30 @@ void goal2sat::collect_param_descrs(param_descrs & r) { r.insert("ite_extra", CPK_BOOL, "(default: true) add redundant clauses (that improve unit propagation) when encoding if-then-else formulas"); } - -void goal2sat::operator()(goal const & g, params_ref const & p, sat::solver_core & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external) { +void goal2sat::init(ast_manager& m, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external) { if (!m_imp) { - m_imp = alloc(imp, g.m(), p, t, m, dep2asm, default_external); + m_imp = alloc(imp, m, p, t, map, dep2asm, default_external); for (unsigned i = 0; i < m_scopes; ++i) m_imp->user_push(); } +} + +void goal2sat::operator()(goal const & g, params_ref const & p, sat::solver_core & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external) { + init(g.m(), p, t, m, dep2asm, default_external); (*m_imp)(g); } +void goal2sat::operator()(ast_manager& m, unsigned n, expr* const* fmls, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external) { + init(m, p, t, map, dep2asm, default_external); + (*m_imp)(n, fmls); +} + +void goal2sat::assumptions(ast_manager& m, unsigned n, expr* const* fmls, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external) { + init(m, p, t, map, dep2asm, default_external); + m_imp->assumptions(n, fmls); +} + + void goal2sat::get_interpreted_funs(func_decl_ref_vector& funs) { if (m_imp) funs.append(m_imp->interpreted_funs()); diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index 8b344c9c3..08fd5f088 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -34,15 +34,19 @@ Notes: #include "sat/smt/sat_internalizer.h" class goal2sat { +public: + typedef obj_map dep2asm_map; +private: struct imp; imp * m_imp; - unsigned m_scopes { 0 }; + unsigned m_scopes = 0; + + void init(ast_manager& m, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external); public: goal2sat(); ~goal2sat(); - typedef obj_map dep2asm_map; static void collect_param_descrs(param_descrs & r); @@ -60,6 +64,10 @@ public: */ void operator()(goal const & g, params_ref const & p, sat::solver_core & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external = false); + void operator()(ast_manager& m, unsigned n, expr* const* fmls, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external = false); + + void assumptions(ast_manager& m, unsigned n, expr* const* fmls, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external = false); + void get_interpreted_funs(func_decl_ref_vector& funs); bool has_interpreted_funs() const; From c850259f891a2b592f994cc6c958c3e93cdb3c71 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 22 May 2022 07:54:27 -0400 Subject: [PATCH 152/253] rw --- src/ast/rewriter/seq_rewriter.cpp | 199 +++++++++++++++++++++--------- src/ast/rewriter/seq_rewriter.h | 9 +- src/opt/opt_preprocess.cpp | 6 +- 3 files changed, 149 insertions(+), 65 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 877263e79..ee3d3aa71 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -833,18 +833,11 @@ br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) { unsigned len = 0; unsigned j = 0; for (expr* e : m_es) { - if (str().is_string(e, b)) { - len += b.length(); - } - else if (str().is_unit(e)) { - len += 1; - } - else if (str().is_empty(e)) { - // skip - } - else { - m_es[j++] = e; - } + auto [bounded, len_e] = min_length(e); + if (bounded) + len += len_e; + else + m_es[j++] = e; } if (j == 0) { result = m_autil.mk_int(len); @@ -1091,15 +1084,14 @@ expr_ref seq_rewriter::mk_len(rational const& p, expr_ref_vector const& xs) { } bool seq_rewriter::extract_pop_suffix(expr_ref_vector const& as, expr* b, expr* c, expr_ref& result) { - unsigned len_a1 = 0, len_a2 = 0; - min_length(as, len_a1); + auto len_a1 = min_length(as).second; rational pos, len; if (!as.empty() && m_autil.is_numeral(b, pos) && m_autil.is_numeral(c, len) && len_a1 >= pos + len && pos >= 0 && len >= 0) { unsigned i = 0; len_a1 = 0; for ( ; i < as.size() && len_a1 < pos + len; ++i) { - min_length(as.get(i), len_a2); + auto len_a2 = min_length(as.get(i)).second; len_a1 += len_a2; } if (i < as.size()) { @@ -1449,10 +1441,9 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { return BR_DONE; } - unsigned lenA = 0, lenB = 0; - bool lA = min_length(as, lenA); + auto [lA, lenA] = min_length(as); if (lA) { - min_length(bs, lenB); + auto lenB = min_length(bs).second; if (lenB > lenA) { result = m().mk_false(); return BR_DONE; @@ -1642,6 +1633,16 @@ br_status seq_rewriter::mk_seq_nth(expr* a, expr* b, expr_ref& result) { } } + auto [bounded_a, len_a] = min_length(a); + + if (bounded_a && m_autil.is_numeral(b, pos1)) { + if (0 <= pos1 && pos1 < len_a) + result = str().mk_nth_i(a, b); + else + result = str().mk_nth_u(a, b); + return BR_REWRITE_FULL; + } + expr* la = str().mk_length(a); result = m().mk_ite(m().mk_and(m_autil.mk_ge(b, zero()), m().mk_not(m_autil.mk_le(la, b))), str().mk_nth_i(a, b), @@ -1656,10 +1657,10 @@ br_status seq_rewriter::mk_seq_nth_i(expr* a, expr* b, expr_ref& result) { if (!m_autil.is_numeral(b, r) || !r.is_unsigned()) { return BR_FAILED; } - unsigned len = r.get_unsigned(); + unsigned offset = r.get_unsigned(); expr* a2, *i2; - if (len == 0 && str().is_at(a, a2, i2) && m_autil.is_numeral(i2, r) && r.is_zero()) { + if (offset == 0 && str().is_at(a, a2, i2) && m_autil.is_numeral(i2, r) && r.is_zero()) { result = str().mk_nth_i(a2, i2); return BR_REWRITE1; } @@ -1674,18 +1675,35 @@ br_status seq_rewriter::mk_seq_nth_i(expr* a, expr* b, expr_ref& result) { expr_ref_vector as(m()); str().get_concat_units(a, as); + expr* cond = nullptr, *el = nullptr, *th = nullptr; for (unsigned i = 0; i < as.size(); ++i) { expr* a = as.get(i), *u = nullptr; if (str().is_unit(a, u)) { - if (len == i) { + if (offset == i) { result = u; return BR_DONE; - } + } + continue; } - else { - return BR_FAILED; + else if (m().is_ite(a, cond, th, el)) { + auto [bounded, len1] = min_length(a); + if (!bounded) + break; + if (i + len1 < offset) { + offset -= len1; + continue; + } + expr_ref idx(m()); + idx = m_autil.mk_int(offset - i); + th = str().mk_nth_i(th, idx); + el = str().mk_nth_i(el, idx); + result = m().mk_ite(cond, th, el); + return BR_REWRITE2; } + else + break; } + return BR_FAILED; } @@ -1915,9 +1933,8 @@ br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& resu // a = "", |b| > 0 -> replace("",b,c) = "" if (m_lhs.empty()) { - unsigned len = 0; str().get_concat(b, m_lhs); - min_length(m_lhs, len); + unsigned len = min_length(m_lhs).second; if (len > 0) { result = a; return BR_DONE; @@ -2301,10 +2318,9 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { } - unsigned len_a; - rational len_b; - if (max_length(b, len_b)) { - min_length(a, len_a); + auto [bounded_b, len_b] = max_length(b); + if (bounded_b) { + auto [bounded_a, len_a] = min_length(a); if (len_b <= len_a) { result = m().mk_eq(a, b); return BR_REWRITE1; @@ -2379,10 +2395,9 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { result = str().mk_suffix(a1, b); return BR_DONE; } - unsigned len_a; - rational len_b; - if (max_length(b, len_b)) { - min_length(a, len_a); + auto [bounded_b, len_b] = max_length(b); + if (bounded_b) { + auto [bounded_a, len_a] = min_length(a); if (len_b <= len_a) { result = m().mk_eq(a, b); return BR_REWRITE1; @@ -5011,21 +5026,20 @@ br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) { br_status seq_rewriter::mk_re_range(expr* lo, expr* hi, expr_ref& result) { zstring s; unsigned len = 0; - rational rlen; bool is_empty = false; if (str().is_string(lo, s) && s.length() != 1) is_empty = true; if (str().is_string(hi, s) && s.length() != 1) is_empty = true; - min_length(lo, len); + len = min_length(lo).second; if (len > 1) is_empty = true; - min_length(hi, len); + len = min_length(hi).second; if (len > 1) is_empty = true; - if (max_length(lo, rlen) && rlen == 0) + if (max_length(lo) == std::make_pair(true, rational(0))) is_empty = true; - if (max_length(hi, rlen) && rlen == 0) + if (max_length(hi) == std::make_pair(true, rational(0))) is_empty = true; if (is_empty) { sort* srt = re().mk_re(lo->get_sort()); @@ -5631,10 +5645,13 @@ bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pa } lbool seq_rewriter::eq_length(expr* x, expr* y) { - unsigned xl = 0, yl = 0; - if (min_length(x, xl) && min_length(y, yl)) - return xl == yl ? l_true : l_false; - return l_undef; + auto [bounded_x, xl] = min_length(x); + if (!bounded_x) + return l_undef; + auto [bounded_y, yl] = min_length(y); + if (!bounded_y) + return l_undef; + return xl == yl ? l_true : l_false; } /*** @@ -5643,13 +5660,66 @@ lbool seq_rewriter::eq_length(expr* x, expr* y) { maximal length (the sequence is bounded). */ -bool seq_rewriter::min_length(unsigned sz, expr* const* ss, unsigned& len) { - ptr_buffer es; +std::pair seq_rewriter::min_length(unsigned sz, expr* const* ss) { + ptr_buffer es, sub; for (unsigned i = 0; i < sz; ++i) es.push_back(ss[i]); + obj_map> cache; + zstring s; - len = 0; + unsigned len = 0; bool bounded = true; + expr* c, *th, *el; + auto visit = [&](expr* e) { + if (cache.contains(e)) + return true; + if (str().is_unit(e)) { + cache.insert(e, { true, 1u }); + return true; + } + else if (str().is_empty(e)) { + cache.insert(e, { true, 0u }); + return true; + } + else if (str().is_string(e, s)) { + cache.insert(e, { true, s.length() }); + return true; + } + else if (str().is_concat(e)) { + bool visited = true; + std::pair result(true, 0u), r; + for (expr* arg : *to_app(e)) { + if (cache.find(arg, r)) { + result.first &= r.first; + result.second += r.second; + } + else { + sub.push_back(arg); + visited = false; + } + } + if (visited) + cache.insert(e, result); + return visited; + } + else if (m().is_ite(e, c, th, el)) { + unsigned sz = sub.size(); + std::pair r1, r2; + if (!cache.find(th, r1)) + sub.push_back(th); + if (!cache.find(el, r2)) + sub.push_back(el); + if (sz != sub.size()) + return false; + + cache.insert(e, { r1.first && r2.first && r1.second == r2.second, std::min(r1.second, r2.second)}); + return true; + } + else { + cache.insert(e, { false, 0u }); + return true; + } + }; while (!es.empty()) { expr* e = es.back(); es.pop_back(); @@ -5662,24 +5732,38 @@ bool seq_rewriter::min_length(unsigned sz, expr* const* ss, unsigned& len) { else if (str().is_concat(e)) for (expr* arg : *to_app(e)) es.push_back(arg); + else if (m().is_ite(e, c, th, el)) { + sub.push_back(th); + sub.push_back(el); + while (!sub.empty()) { + e = sub.back(); + if (visit(e)) + sub.pop_back(); + } + auto [bounded1, len1] = cache[th]; + auto [bounded2, len2] = cache[el]; + if (!bounded1 || !bounded2 || len1 != len2) + bounded = false; + len += std::min(len1, len2); + } else bounded = false; } - return bounded; + return { bounded, len }; } -bool seq_rewriter::min_length(expr* e, unsigned& len) { - return min_length(1, &e, len); +std::pair seq_rewriter::min_length(expr* e) { + return min_length(1, &e); } -bool seq_rewriter::min_length(expr_ref_vector const& es, unsigned& len) { - return min_length(es.size(), es.data(), len); +std::pair seq_rewriter::min_length(expr_ref_vector const& es) { + return min_length(es.size(), es.data()); } -bool seq_rewriter::max_length(expr* e, rational& len) { +std::pair seq_rewriter::max_length(expr* e) { ptr_buffer es; es.push_back(e); - len = 0; + rational len(0); zstring s; expr* s1 = nullptr, *i = nullptr, *l = nullptr; rational n; @@ -5702,9 +5786,9 @@ bool seq_rewriter::max_length(expr* e, rational& len) { es.push_back(arg); } else - return false; + return std::make_pair(false, len); } - return true; + return std::make_pair(true, len); } @@ -5806,9 +5890,8 @@ bool seq_rewriter::reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, if (ls.empty() && rs.empty()) return true; - unsigned len1 = 0, len2 = 0; - bool bounded1 = min_length(ls, len1); - bool bounded2 = min_length(rs, len2); + auto [bounded1, len1] = min_length(ls); + auto [bounded2, len2] = min_length(rs); if (bounded1 && len1 < len2) return false; if (bounded2 && len2 < len1) diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 500972b1f..eecf032b6 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -324,10 +324,11 @@ class seq_rewriter { bool reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs); bool reduce_itos(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs); bool reduce_eq_empty(expr* l, expr* r, expr_ref& result); - bool min_length(expr_ref_vector const& es, unsigned& len); - bool min_length(expr* e, unsigned& len); - bool min_length(unsigned sz, expr* const* es, unsigned& len); - bool max_length(expr* e, rational& len); + std::pair min_length(expr_ref_vector const& es); + std::pair min_length(expr* e); + std::pair min_length(unsigned sz, expr* const* es); + std::pair max_length(expr* e); + bool max_length(expr* e, rational& len) { auto ml = max_length(e); len = ml.second; return ml.first; } lbool eq_length(expr* x, expr* y); expr* concat_non_empty(expr_ref_vector& es); bool reduce_by_char(expr_ref& r, expr* ch, unsigned depth); diff --git a/src/opt/opt_preprocess.cpp b/src/opt/opt_preprocess.cpp index 268aa8986..d3475fcb0 100644 --- a/src/opt/opt_preprocess.cpp +++ b/src/opt/opt_preprocess.cpp @@ -78,6 +78,8 @@ namespace opt { new_soft.remove(f); continue; } + if (!m.inc()) + return false; expr_ref_vector mux(m); for (expr* g : trail) { @@ -160,9 +162,7 @@ namespace opt { for (auto& mux : mutexes) process_mutex(mux, new_soft, lower); - - if (mutexes.empty()) - { + if (mutexes.empty()) { obj_map dual_soft = dualize(new_soft, fmls); mutexes.reset(); lbool is_sat = s.find_mutexes(fmls, mutexes); From 8c95dff33b10aed6b8931d7c0d00fb730027d608 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 22 May 2022 09:10:26 -0400 Subject: [PATCH 153/253] cnf --- src/sat/sat_solver/inc_sat_solver.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index cf46b1f27..3d46ec643 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -792,7 +792,6 @@ private: m_is_cnf &= is_literal(get_assumption(i)); if (m_is_cnf) { - // std::cout << "assumptions " << sz << " " << get_num_assumptions() << " " << m_fmls_head << " " << m_fmls.size() << "\n"; expr_ref_vector fmls(m); fmls.append(sz, asms); for (unsigned i = 0; i < get_num_assumptions(); ++i) @@ -923,18 +922,19 @@ private: } bool is_clause(expr* fml) { - if (is_literal(fml)) { + if (get_depth(fml) > 4) + return false; + + if (is_literal(fml)) + return true; + + if (m.is_or(fml) || m.is_and(fml) || m.is_implies(fml) || m.is_not(fml) || m.is_iff(fml)) { + for (expr* n : *to_app(fml)) + if (!is_clause(n)) + return false; return true; } - if (!m.is_or(fml)) { - return false; - } - for (expr* n : *to_app(fml)) { - if (!is_literal(n)) { - return false; - } - } - return true; + return false; } lbool internalize_formulas() { @@ -944,7 +944,6 @@ private: lbool res; if (m_is_cnf) { - std::cout << "cnf\n"; res = internalize_goal(m_fmls.size() - m_fmls_head, m_fmls.data() + m_fmls_head); } else { From 4d8e4b5bd315dc4e559ed6ffb39236594f928eae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 May 2022 17:21:01 -0400 Subject: [PATCH 154/253] fix #6052 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 46 +++++++++++++++++-------------- src/ast/rewriter/seq_rewriter.h | 1 + 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index ee3d3aa71..9b4091724 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -5607,7 +5607,7 @@ expr* seq_rewriter::concat_non_empty(expr_ref_vector& es) { sort* s = es[0]->get_sort(); unsigned j = 0; for (expr* e : es) { - if (str().is_unit(e) || str().is_string(e)) + if (str().is_unit(e) || str().is_string(e) || m().is_ite(e)) es[j++] = e; } es.shrink(j); @@ -5623,23 +5623,16 @@ bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pa zstring s; expr* emp = nullptr; for (unsigned i = 0; i < sz; ++i) { - if (str().is_unit(es[i])) { - if (all) return false; - } - else if (str().is_empty(es[i])) { + auto [bounded, len] = min_length(es[i]); + if (len > 0) { + if (all) + return false; continue; } - else if (str().is_string(es[i], s)) { - if (s.length() == 0) - continue; - if (all) { - return false; - } - } - else { - emp = emp?emp:str().mk_empty(es[i]->get_sort()); - eqs.push_back(emp, es[i]); - } + if (bounded && len == 0) + continue; + emp = emp?emp:str().mk_empty(es[i]->get_sort()); + eqs.push_back(emp, es[i]); } return true; } @@ -5669,6 +5662,9 @@ std::pair seq_rewriter::min_length(unsigned sz, expr* const* ss) zstring s; unsigned len = 0; bool bounded = true; + + if (sz == 0) + return { bounded, len }; expr* c, *th, *el; auto visit = [&](expr* e) { if (cache.contains(e)) @@ -5703,13 +5699,13 @@ std::pair seq_rewriter::min_length(unsigned sz, expr* const* ss) return visited; } else if (m().is_ite(e, c, th, el)) { - unsigned sz = sub.size(); + unsigned subsz = sub.size(); std::pair r1, r2; if (!cache.find(th, r1)) sub.push_back(th); if (!cache.find(el, r2)) sub.push_back(el); - if (sz != sub.size()) + if (subsz != sub.size()) return false; cache.insert(e, { r1.first && r2.first && r1.second == r2.second, std::min(r1.second, r2.second)}); @@ -5884,6 +5880,16 @@ bool seq_rewriter::reduce_eq_empty(expr* l, expr* r, expr_ref& result) { return false; } +bool seq_rewriter::has_var(expr_ref_vector const& es) { + for (expr* e : es) { + auto [bounded, len] = min_length(e); + if (len == 0) + return true; + } + return false; +} + + bool seq_rewriter::reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs) { @@ -5896,14 +5902,14 @@ bool seq_rewriter::reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, return false; if (bounded2 && len2 < len1) return false; - if (bounded1 && len1 == len2 && len1 > 0) { + if (bounded1 && len1 == len2 && len1 > 0 && has_var(rs)) { if (!set_empty(rs.size(), rs.data(), false, eqs)) return false; eqs.push_back(concat_non_empty(ls), concat_non_empty(rs)); ls.reset(); rs.reset(); } - else if (bounded2 && len1 == len2 && len1 > 0) { + else if (bounded2 && len1 == len2 && len1 > 0 && has_var(ls)) { if (!set_empty(ls.size(), ls.data(), false, eqs)) return false; eqs.push_back(concat_non_empty(ls), concat_non_empty(rs)); diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index eecf032b6..4c7c3883a 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -322,6 +322,7 @@ class seq_rewriter { bool reduce_non_overlap(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs); bool reduce_subsequence(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs); bool reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs); + bool has_var(expr_ref_vector const& es); bool reduce_itos(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs); bool reduce_eq_empty(expr* l, expr* r, expr_ref& result); std::pair min_length(expr_ref_vector const& es); From f77037e9a56adadf1b6c988f10c6e9aceb00a7fe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 May 2022 20:23:43 -0400 Subject: [PATCH 155/253] expand select/store when I/J are values #6053 Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.cpp | 19 +++++++++++++++++++ src/ast/array_decl_plugin.h | 3 +++ src/ast/rewriter/array_rewriter.cpp | 18 ++++++++++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 31bbaac1e..b336dd2e5 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -630,6 +630,24 @@ bool array_decl_plugin::is_fully_interp(sort * s) const { return m_manager->is_fully_interp(get_array_range(s)); } +bool array_decl_plugin::is_value(app * _e) const { + expr* e = _e; + array_util u(*m_manager); + while (true) { + if (u.is_const(e, e)) + return m_manager->is_value(e); + if (u.is_store(e)) { + for (unsigned i = 1; i < to_app(e)->get_num_args(); ++i) + if (!m_manager->is_value(to_app(e)->get_arg(i))) + return false; + e = to_app(e)->get_arg(0); + continue; + } + return false; + } +} + + func_decl * array_recognizers::get_as_array_func_decl(expr * n) const { SASSERT(is_as_array(n)); return to_func_decl(to_app(n)->get_decl()->get_parameter(0).get_ast()); @@ -704,3 +722,4 @@ func_decl* array_util::mk_array_ext(sort *domain, unsigned i) { parameter p(i); return m_manager.mk_func_decl(m_fid, OP_ARRAY_EXT, 1, &p, 2, domains); } + diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index dd8443025..51f380243 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -137,6 +137,9 @@ class array_decl_plugin : public decl_plugin { expr * get_some_value(sort * s) override; bool is_fully_interp(sort * s) const override; + + bool is_value(app * e) const override; + }; class array_recognizers { diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 88a0ee28e..b8b30a206 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -179,8 +179,21 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, result = m().mk_app(get_fid(), OP_SELECT, num_args, new_args.data()); return BR_REWRITE1; } - default: - if (m_blast_select_store || (m_expand_select_store && to_app(args[0])->get_arg(0)->get_ref_count() == 1)) { + default: { + auto are_values = [&]() { + for (unsigned i = 1; i < num_args; ++i) { + if (!m().is_value(args[i])) + return false; + if (!m().is_value(to_app(args[0])->get_arg(i))) + return false; + } + return true; + }; + bool should_expand = + m_blast_select_store || + are_values() || + (m_expand_select_store && to_app(args[0])->get_arg(0)->get_ref_count() == 1); + if (should_expand) { // select(store(a, I, v), J) --> ite(I=J, v, select(a, J)) ptr_buffer new_args; new_args.push_back(to_app(args[0])->get_arg(0)); @@ -203,6 +216,7 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, } return BR_FAILED; } + } } if (m_util.is_const(args[0])) { From de892ed9f2fd4e9f4e629242fbba92b6833b8a15 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 26 May 2022 15:51:57 -0400 Subject: [PATCH 156/253] fix #6054 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 9b4091724..4f70b7933 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -5665,8 +5665,8 @@ std::pair seq_rewriter::min_length(unsigned sz, expr* const* ss) if (sz == 0) return { bounded, len }; - expr* c, *th, *el; auto visit = [&](expr* e) { + expr* c, *th, *el; if (cache.contains(e)) return true; if (str().is_unit(e)) { @@ -5706,8 +5706,7 @@ std::pair seq_rewriter::min_length(unsigned sz, expr* const* ss) if (!cache.find(el, r2)) sub.push_back(el); if (subsz != sub.size()) - return false; - + return false; cache.insert(e, { r1.first && r2.first && r1.second == r2.second, std::min(r1.second, r2.second)}); return true; } @@ -5717,6 +5716,7 @@ std::pair seq_rewriter::min_length(unsigned sz, expr* const* ss) } }; while (!es.empty()) { + expr* c, *th, *el; expr* e = es.back(); es.pop_back(); if (str().is_unit(e)) @@ -5898,6 +5898,7 @@ bool seq_rewriter::reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, auto [bounded1, len1] = min_length(ls); auto [bounded2, len2] = min_length(rs); + if (bounded1 && len1 < len2) return false; if (bounded2 && len2 < len1) @@ -5915,7 +5916,7 @@ bool seq_rewriter::reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, eqs.push_back(concat_non_empty(ls), concat_non_empty(rs)); ls.reset(); rs.reset(); - } + } return true; } From 7da9f12521f259a689dd53e4e504cab046921d4d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 27 May 2022 08:50:40 -0400 Subject: [PATCH 157/253] expose description of global parameters #6048 Signed-off-by: Nikolaj Bjorner --- src/api/api_config_params.cpp | 11 +++++++++++ src/api/c++/z3++.h | 1 + src/api/python/z3/z3.py | 4 ++++ src/api/z3_api.h | 8 ++++++++ src/util/gparams.cpp | 9 +++++++++ src/util/gparams.h | 1 + 6 files changed, 34 insertions(+) diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp index 1b551bd73..cbe89e9fb 100644 --- a/src/api/api_config_params.cpp +++ b/src/api/api_config_params.cpp @@ -64,6 +64,17 @@ extern "C" { } } + Z3_param_descrs Z3_API Z3_get_global_param_descrs(Z3_context c) { + Z3_TRY; + LOG_Z3_get_global_param_descrs(c); + Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref, *mk_c(c)); + mk_c(c)->save_object(d); + d->m_descrs = gparams::get_global_param_descrs(); + auto r = of_param_descrs(d); + RETURN_Z3(r); + Z3_CATCH_RETURN(nullptr); + } + Z3_config Z3_API Z3_mk_config(void) { try { memory::initialize(UINT_MAX); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index e817a5859..de55bb765 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -459,6 +459,7 @@ namespace z3 { } ~param_descrs() { Z3_param_descrs_dec_ref(ctx(), m_descrs); } static param_descrs simplify_param_descrs(context& c) { return param_descrs(c, Z3_simplify_get_param_descrs(c)); } + static param_descrs global_param_descrs(context& c) { return param_descrs(c, Z3_get_global_param_descrs(c)); } unsigned size() { return Z3_param_descrs_size(ctx(), m_descrs); } symbol name(unsigned i) { return symbol(ctx(), Z3_param_descrs_get_name(ctx(), m_descrs, i)); } diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index c45a3d86e..5ad8ede50 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -225,6 +225,10 @@ class Context: """ Z3_interrupt(self.ref()) + def param_descrs(self): + """Return the global parameter description set.""" + return ParamDescrsRef(Z3_get_global_param_descrs(self.ref()), self) + # Global Z3 context _main_ctx = None diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 4e5f5f5b5..b8bca8fab 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1685,6 +1685,14 @@ extern "C" { */ void Z3_API Z3_update_param_value(Z3_context c, Z3_string param_id, Z3_string param_value); + + /** + \brief Retrieve description of global parameters. + + def_API('Z3_get_global_param_descrs', PARAM_DESCRS, (_in(CONTEXT),)) + */ + Z3_param_descrs Z3_API Z3_get_global_param_descrs(Z3_context c); + /** \brief Interrupt the execution of a Z3 procedure. This procedure can be used to interrupt: solvers, simplifiers and tactics. diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 28ce5a867..e7c8a4d53 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -534,6 +534,11 @@ public: d->display(out, 4, false); } + param_descrs const& get_global_param_descrs() { + lock_guard lock(*gparams_mux); + return get_param_descrs(); + } + void display_parameter(std::ostream & out, char const * name) { std::string m, p; normalize(name, m, p); @@ -624,6 +629,10 @@ void gparams::display(std::ostream & out, unsigned indent, bool smt2_style, bool g_imp->display(out, indent, smt2_style, include_descr); } +param_descrs const& gparams::get_global_param_descrs() { + return g_imp->get_global_param_descrs(); +} + void gparams::display_modules(std::ostream & out) { SASSERT(g_imp); g_imp->display_modules(out); diff --git a/src/util/gparams.h b/src/util/gparams.h index 0959c20fc..0bd5e4d60 100644 --- a/src/util/gparams.h +++ b/src/util/gparams.h @@ -120,6 +120,7 @@ public: static void display_modules(std::ostream & out); static void display_module(std::ostream & out, char const * module_name); static void display_parameter(std::ostream & out, char const * name); + static param_descrs const& get_global_param_descrs(); /** \brief Initialize the global parameter management module. From dd46224a1dd91c5bb7a3e12a52a23cf87441e6c1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 09:37:41 -0700 Subject: [PATCH 158/253] use structured proof hints Signed-off-by: Nikolaj Bjorner --- examples/python/tutorial/jupyter/guide.ipynb | 2 +- src/sat/sat_drat.cpp | 116 +++++++++++++++++-- src/sat/sat_types.h | 28 ++++- src/sat/smt/arith_axioms.cpp | 31 +++-- src/sat/smt/arith_diagnostics.cpp | 38 ++++-- src/sat/smt/arith_solver.cpp | 20 +++- src/sat/smt/arith_solver.h | 7 +- src/sat/smt/sat_th.cpp | 25 ++-- src/sat/smt/sat_th.h | 20 ++-- src/util/sat_literal.h | 9 ++ 10 files changed, 233 insertions(+), 63 deletions(-) diff --git a/examples/python/tutorial/jupyter/guide.ipynb b/examples/python/tutorial/jupyter/guide.ipynb index 27c1b60df..5562c30d5 100644 --- a/examples/python/tutorial/jupyter/guide.ipynb +++ b/examples/python/tutorial/jupyter/guide.ipynb @@ -1395,7 +1395,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.1" + "version": "3.8.8" } }, "nbformat": 4, diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 72872e370..4ecb8ed1f 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -19,8 +19,10 @@ Author: Notes: --*/ -#include "sat_solver.h" -#include "sat_drat.h" + +#include "util/rational.h" +#include "sat/sat_solver.h" +#include "sat/sat_drat.h" namespace sat { @@ -137,13 +139,13 @@ namespace sat { } } buffer[len++] = '0'; - if (st.get_pragma()) { + if (st.get_hint()) { buffer[len++] = ' '; buffer[len++] = 'p'; buffer[len++] = ' '; - char const* ps = st.get_pragma(); - while (*ps) - buffer[len++] = *ps++; + auto* ps = st.get_hint(); + for (auto ch : ps->to_string()) + buffer[len++] = ch; } buffer[len++] = '\n'; m_out->write(buffer, len); @@ -905,6 +907,106 @@ namespace sat { if (!st.is_sat()) out << " " << p.th(st.get_th()); return out; - } + } + + + std::string proof_hint::to_string() const { + std::ostringstream ous; + switch (m_ty) { + case hint_type::null_h: + return std::string(); + case hint_type::farkas_h: + ous << "farkas "; + break; + case hint_type::bound_h: + ous << "bound "; + break; + case hint_type::cut_h: + ous << "cut "; + break; + } + for (auto const& [q, l] : m_literals) + ous << rational(q) << " * " << l << " "; + for (auto const& [q, a, b] : m_eqs) + ous << rational(q) << " = " << a << " " << b << " "; + return ous.str(); + } + + proof_hint proof_hint::from_string(char const* s) { + proof_hint h; + h.m_ty = hint_type::null_h; + if (!s) + return h; + auto ws = [&]() { + while (*s == ' ' || *s == '\n' || *s == '\t') + ++s; + }; + + auto parse_type = [&]() { + if (0 == strncmp(s, "farkas", 6)) { + h.m_ty = hint_type::farkas_h; + s += 6; + return true; + } + if (0 == strncmp(s, "bound", 5)) { + h.m_ty = hint_type::bound_h; + s += 5; + return true; + } + return false; + }; + + sbuffer buff; + auto parse_coeff = [&]() { + buff.reset(); + while (*s && *s != ' ') { + buff.push_back(*s); + ++s; + } + buff.push_back(0); + return rational(buff.data()); + }; + + auto parse_literal = [&]() { + rational r = parse_coeff(); + if (!r.is_int()) + return sat::null_literal; + if (r < 0) + return sat::literal((-r).get_unsigned(), true); + return sat::literal(r.get_unsigned(), false); + }; + auto parse_coeff_literal = [&]() { + rational coeff = parse_coeff(); + ws(); + if (*s == '*') { + ++s; + ws(); + sat::literal lit = parse_literal(); + h.m_literals.push_back(std::make_pair(coeff, lit)); + return true; + } + if (*s == '=') { + ++s; + ws(); + unsigned a = parse_coeff().get_unsigned(); + ws(); + unsigned b = parse_coeff().get_unsigned(); + h.m_eqs.push_back(std::make_tuple(coeff, a, b)); + return true; + } + return false; + }; + + ws(); + if (!parse_type()) + return h; + ws(); + while (*s) { + if (!parse_coeff_literal()) + return h; + ws(); + } + return h; + } } diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 12c013734..1adcbc6b6 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -28,6 +28,7 @@ Revision History: #include "util/stopwatch.h" #include "util/symbol.h" #include "util/sat_literal.h" +#include "util/rational.h" class params_ref; class reslimit; @@ -93,29 +94,44 @@ namespace sat { }; + enum class hint_type { + null_h, + farkas_h, + bound_h, + cut_h + }; + + struct proof_hint { + hint_type m_ty; + vector> m_literals; + vector> m_eqs; + std::string to_string() const; + static proof_hint from_string(char const* s); + }; + class status { public: enum class st { input, asserted, redundant, deleted }; st m_st; int m_orig; - char const* m_pragma; + const proof_hint* m_hint; public: - status(st s, int o, char const* ps = nullptr) : m_st(s), m_orig(o), m_pragma(ps) {}; - status(status const& s) : m_st(s.m_st), m_orig(s.m_orig), m_pragma(s.m_pragma) {} - status(status&& s) noexcept { m_st = st::asserted; m_orig = -1; std::swap(m_st, s.m_st); std::swap(m_orig, s.m_orig); std::swap(m_pragma, s.m_pragma); } + status(st s, int o, proof_hint const* ps = nullptr) : m_st(s), m_orig(o), m_hint(ps) {}; + status(status const& s) : m_st(s.m_st), m_orig(s.m_orig), m_hint(s.m_hint) {} + status(status&& s) noexcept { m_st = st::asserted; m_orig = -1; std::swap(m_st, s.m_st); std::swap(m_orig, s.m_orig); std::swap(m_hint, s.m_hint); } status& operator=(status const& other) { m_st = other.m_st; m_orig = other.m_orig; return *this; } static status redundant() { return status(status::st::redundant, -1); } static status asserted() { return status(status::st::asserted, -1); } static status deleted() { return status(status::st::deleted, -1); } static status input() { return status(status::st::input, -1); } - static status th(bool redundant, int id, char const* ps = nullptr) { return status(redundant ? st::redundant : st::asserted, id, ps); } + static status th(bool redundant, int id, proof_hint const* ps = nullptr) { return status(redundant ? st::redundant : st::asserted, id, ps); } bool is_input() const { return st::input == m_st; } bool is_redundant() const { return st::redundant == m_st; } bool is_asserted() const { return st::asserted == m_st; } bool is_deleted() const { return st::deleted == m_st; } - char const* get_pragma() const { return m_pragma; } + proof_hint const* get_hint() const { return m_hint; } bool is_sat() const { return -1 == m_orig; } int get_th() const { return m_orig; } diff --git a/src/sat/smt/arith_axioms.cpp b/src/sat/smt/arith_axioms.cpp index 7efd83ead..f63714fdd 100644 --- a/src/sat/smt/arith_axioms.cpp +++ b/src/sat/smt/arith_axioms.cpp @@ -233,46 +233,55 @@ namespace arith { SASSERT(b1.get_var() == b2.get_var()); if (k1 == k2 && kind1 == kind2) return; SASSERT(k1 != k2 || kind1 != kind2); - char const* bound_params = "farkas 1 1"; + auto bin_clause = [&](sat::literal l1, sat::literal l2) { + sat::proof_hint* bound_params = nullptr; + if (ctx.use_drat()) { + bound_params = &m_farkas2; + m_farkas2.m_literals[0] = std::make_pair(rational(1), l1); + m_farkas2.m_literals[1] = std::make_pair(rational(1), l2); + } + add_clause(l1, l2, bound_params); + }; + if (kind1 == lp_api::lower_t) { if (kind2 == lp_api::lower_t) { if (k2 <= k1) - add_clause(~l1, l2, bound_params); + bin_clause(~l1, l2); else - add_clause(l1, ~l2, bound_params); + bin_clause(l1, ~l2); } else if (k1 <= k2) // k1 <= k2, k1 <= x or x <= k2 - add_clause(l1, l2); + bin_clause(l1, l2); else { // k1 > hi_inf, k1 <= x => ~(x <= hi_inf) - add_clause(~l1, ~l2, bound_params); + bin_clause(~l1, ~l2); if (v_is_int && k1 == k2 + rational(1)) // k1 <= x or x <= k1-1 - add_clause(l1, l2, bound_params); + bin_clause(l1, l2); } } else if (kind2 == lp_api::lower_t) { if (k1 >= k2) // k1 >= lo_inf, k1 >= x or lo_inf <= x - add_clause(l1, l2, bound_params); + bin_clause(l1, l2); else { // k1 < k2, k2 <= x => ~(x <= k1) - add_clause(~l1, ~l2, bound_params); + bin_clause(~l1, ~l2); if (v_is_int && k1 == k2 - rational(1)) // x <= k1 or k1+l <= x - add_clause(l1, l2, bound_params); + bin_clause(l1, l2); } } else { // kind1 == A_UPPER, kind2 == A_UPPER if (k1 >= k2) // k1 >= k2, x <= k2 => x <= k1 - add_clause(l1, ~l2, bound_params); + bin_clause(l1, ~l2); else // k1 <= hi_sup , x <= k1 => x <= hi_sup - add_clause(~l1, l2, bound_params); + bin_clause(~l1, l2); } } diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index 28105472d..f3e90e266 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -80,16 +80,38 @@ namespace arith { if (m_nla) m_nla->collect_statistics(st); } - char const* solver::bounds_pragma() { + /** + * Assumption: + * A bound literal ax <= b is explained by a set of weighted literals + * r1*(a1*x <= b1) + .... + r_k*(a_k*x <= b_k), where r_i > 0 + * such that there is a r >= 1 + * (r1*a1+..+r_k*a_k) = r*a, (r1*b1+..+r_k*b_k) <= r*b + */ + sat::proof_hint const* solver::explain(sat::hint_type ty) { if (!ctx.use_drat()) return nullptr; - m_bounds_pragma.clear(); - m_bounds_pragma += "bounds "; - for (sat::literal c : m_core) { - if (c.sign()) m_bounds_pragma += "-"; - m_bounds_pragma += std::to_string(c.var()); - m_bounds_pragma += " "; + m_bounds_pragma.m_ty = ty; + m_bounds_pragma.m_literals.reset(); + m_bounds_pragma.m_eqs.reset(); + for (auto ev : m_explanation) { + auto idx = ev.ci(); + if (UINT_MAX == idx) + continue; + switch (m_constraint_sources[idx]) { + case inequality_source: { + literal lit = m_inequalities[idx]; + m_bounds_pragma.m_literals.push_back({ev.coeff(), lit}); + break; + } + case equality_source: { + auto [u, v] = m_equalities[idx]; + m_bounds_pragma.m_eqs.push_back({ev.coeff(), u->get_expr_id(), v->get_expr_id()}); + break; + } + default: + break; + } } - return m_bounds_pragma.c_str(); + return &m_bounds_pragma; } } diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 68c25c110..4209dd5e3 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -39,6 +39,8 @@ namespace arith { lp().settings().set_random_seed(get_config().m_random_seed); m_lia = alloc(lp::int_solver, *m_solver.get()); + m_farkas2.m_ty = sat::hint_type::farkas_h; + m_farkas2.m_literals.resize(2); } solver::~solver() { @@ -195,7 +197,13 @@ namespace arith { reset_evidence(); m_core.push_back(lit1); TRACE("arith", tout << lit2 << " <- " << m_core << "\n";); - assign(lit2, m_core, m_eqs, "farkas 1 1"); + sat::proof_hint* ph = nullptr; + if (ctx.use_drat()) { + ph = &m_farkas2; + m_farkas2.m_literals[0] = std::make_pair(rational(1), lit1); + m_farkas2.m_literals[1] = std::make_pair(rational(1), lit2); + } + assign(lit2, m_core, m_eqs, ph); ++m_stats.m_bounds_propagations; } @@ -255,7 +263,7 @@ namespace arith { TRACE("arith", for (auto lit : m_core) tout << lit << ": " << s().value(lit) << "\n";); DEBUG_CODE(for (auto lit : m_core) { VERIFY(s().value(lit) == l_true); }); ++m_stats.m_bound_propagations1; - assign(lit, m_core, m_eqs, bounds_pragma()); + assign(lit, m_core, m_eqs, explain(sat::hint_type::bound_h)); } if (should_refine_bounds() && first) @@ -370,7 +378,7 @@ namespace arith { reset_evidence(); m_explanation.clear(); lp().explain_implied_bound(be, m_bp); - assign(bound, m_core, m_eqs, nullptr); + assign(bound, m_core, m_eqs, explain(sat::hint_type::bound_h)); } @@ -1169,7 +1177,7 @@ namespace arith { app_ref b = mk_bound(m_lia->get_term(), m_lia->get_offset(), !m_lia->is_upper()); IF_VERBOSE(4, verbose_stream() << "cut " << b << "\n"); literal lit = expr2literal(b); - assign(lit, m_core, m_eqs, nullptr); + assign(lit, m_core, m_eqs, explain(sat::hint_type::cut_h)); lia_check = l_false; break; } @@ -1191,7 +1199,7 @@ namespace arith { return lia_check; } - void solver::assign(literal lit, literal_vector const& core, svector const& eqs, char const* pma) { + void solver::assign(literal lit, literal_vector const& core, svector const& eqs, sat::proof_hint const* pma) { if (core.size() < small_lemma_size() && eqs.empty()) { m_core2.reset(); for (auto const& c : core) @@ -1238,7 +1246,7 @@ namespace arith { for (literal& c : m_core) c.neg(); - add_clause(m_core); + add_clause(m_core, explain(sat::hint_type::farkas_h)); } bool solver::is_infeasible() const { diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 5906ed736..bac985848 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -414,13 +414,14 @@ namespace arith { void set_conflict(); void set_conflict_or_lemma(literal_vector const& core, bool is_conflict); void set_evidence(lp::constraint_index idx); - void assign(literal lit, literal_vector const& core, svector const& eqs, char const* pma); + void assign(literal lit, literal_vector const& core, svector const& eqs, sat::proof_hint const* pma); void false_case_of_check_nla(const nla::lemma& l); void dbg_finalize_model(model& mdl); - std::string m_bounds_pragma; - char const* bounds_pragma(); + sat::proof_hint m_bounds_pragma; + sat::proof_hint m_farkas2; + sat::proof_hint const* explain(sat::hint_type ty); public: diff --git a/src/sat/smt/sat_th.cpp b/src/sat/smt/sat_th.cpp index 1f4c5b572..2cbba7589 100644 --- a/src/sat/smt/sat_th.cpp +++ b/src/sat/smt/sat_th.cpp @@ -125,7 +125,7 @@ namespace euf { pop_core(n); } - sat::status th_euf_solver::mk_status(char const* ps) { + sat::status th_euf_solver::mk_status(sat::proof_hint const* ps) { return sat::status::th(m_is_redundant, get_id(), ps); } @@ -149,7 +149,7 @@ namespace euf { return add_clause(2, lits); } - bool th_euf_solver::add_clause(sat::literal a, sat::literal b, char const* ps) { + bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::proof_hint const* ps) { sat::literal lits[2] = { a, b }; return add_clause(2, lits, ps); } @@ -164,7 +164,7 @@ namespace euf { return add_clause(4, lits); } - bool th_euf_solver::add_clause(unsigned n, sat::literal* lits, char const* ps) { + bool th_euf_solver::add_clause(unsigned n, sat::literal* lits, sat::proof_hint const* ps) { bool was_true = false; for (unsigned i = 0; i < n; ++i) was_true |= is_true(lits[i]); @@ -226,11 +226,11 @@ namespace euf { return ctx.s().rand()(); } - size_t th_explain::get_obj_size(unsigned num_lits, unsigned num_eqs, char const* pma) { - return sat::constraint_base::obj_size(sizeof(th_explain) + sizeof(sat::literal) * num_lits + sizeof(enode_pair) * num_eqs + (pma?strlen(pma)+1:1)); + size_t th_explain::get_obj_size(unsigned num_lits, unsigned num_eqs, sat::proof_hint const* pma) { + return sat::constraint_base::obj_size(sizeof(th_explain) + sizeof(sat::literal) * num_lits + sizeof(enode_pair) * num_eqs + (pma?pma->to_string().length()+1:1)); } - th_explain::th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& p, char const* pma) { + th_explain::th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& p, sat::proof_hint const* pma) { m_consequent = c; m_eq = p; m_num_literals = n_lits; @@ -246,23 +246,26 @@ namespace euf { m_eqs[i] = eqs[i]; base_ptr += sizeof(enode_pair) * n_eqs; m_pragma = reinterpret_cast(base_ptr); - for (i = 0; pma && pma[i]; ++i) - m_pragma[i] = pma[i]; + if (pma) { + std::string s = pma->to_string(); + for (i = 0; s[i]; ++i) + m_pragma[i] = s[i]; + } m_pragma[i] = 0; } - th_explain* th_explain::mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, char const* pma) { + th_explain* th_explain::mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, sat::proof_hint const* pma) { region& r = th.ctx.get_region(); void* mem = r.allocate(get_obj_size(n_lits, n_eqs, pma)); sat::constraint_base::initialize(mem, &th); return new (sat::constraint_base::ptr2mem(mem)) th_explain(n_lits, lits, n_eqs, eqs, c, enode_pair(x, y)); } - th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, char const* pma) { + th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, sat::proof_hint const* pma) { return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), consequent, nullptr, nullptr, pma); } - th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, char const* pma) { + th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, sat::proof_hint const* pma) { return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), sat::null_literal, x, y, pma); } diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index ffc9d4247..879049497 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -143,16 +143,16 @@ namespace euf { region& get_region(); - sat::status mk_status(char const* ps = nullptr); + sat::status mk_status(sat::proof_hint const* ps = nullptr); bool add_unit(sat::literal lit); bool add_units(sat::literal_vector const& lits); bool add_clause(sat::literal lit) { return add_unit(lit); } bool add_clause(sat::literal a, sat::literal b); - bool add_clause(sat::literal a, sat::literal b, char const* ps); + bool add_clause(sat::literal a, sat::literal b, sat::proof_hint const* ps); bool add_clause(sat::literal a, sat::literal b, sat::literal c); bool add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d); - bool add_clause(sat::literal_vector const& lits, char const* ps = nullptr) { return add_clause(lits.size(), lits.data(), ps); } - bool add_clause(unsigned n, sat::literal* lits, char const* ps = nullptr); + bool add_clause(sat::literal_vector const& lits, sat::proof_hint const* ps = nullptr) { return add_clause(lits.size(), lits.data(), ps); } + bool add_clause(unsigned n, sat::literal* lits, sat::proof_hint const* ps = nullptr); void add_equiv(sat::literal a, sat::literal b); void add_equiv_and(sat::literal a, sat::literal_vector const& bs); @@ -221,9 +221,9 @@ namespace euf { sat::literal* m_literals; enode_pair* m_eqs; char* m_pragma; - static size_t get_obj_size(unsigned num_lits, unsigned num_eqs, char const* pma); - th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& eq, char const* pma = nullptr); - static th_explain* mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, char const* pma = nullptr); + static size_t get_obj_size(unsigned num_lits, unsigned num_eqs, sat::proof_hint const* pma); + th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& eq, sat::proof_hint const* pma = nullptr); + static th_explain* mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, sat::proof_hint const* pma = nullptr); public: static th_explain* conflict(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs); @@ -234,8 +234,8 @@ namespace euf { static th_explain* conflict(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y); static th_explain* conflict(th_euf_solver& th, euf::enode* x, euf::enode* y); static th_explain* propagate(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y); - static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, char const* pma = nullptr); - static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, char const* pma = nullptr); + static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, sat::proof_hint const* pma = nullptr); + static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, sat::proof_hint const* pma = nullptr); sat::ext_constraint_idx to_index() const { return sat::constraint_base::mem2base(this); @@ -270,7 +270,7 @@ namespace euf { enode_pair eq_consequent() const { return m_eq; } - char const* get_pragma() const { return *m_pragma ? m_pragma : nullptr; } + sat::proof_hint const* get_pragma() const { return nullptr; } //*m_pragma ? m_pragma : nullptr; } }; diff --git a/src/util/sat_literal.h b/src/util/sat_literal.h index ccfecffba..920b0528b 100644 --- a/src/util/sat_literal.h +++ b/src/util/sat_literal.h @@ -95,6 +95,7 @@ namespace sat { inline bool operator!=(literal const & l1, literal const & l2) { return l1.m_val != l2.m_val; } inline std::ostream & operator<<(std::ostream & out, sat::literal l) { if (l == sat::null_literal) out << "null"; else out << (l.sign() ? "-" : "") << l.var(); return out; } + typedef svector literal_vector; @@ -192,3 +193,11 @@ namespace sat { } }; + +namespace std { + + inline std::string to_string(sat::literal l) { + if (l.sign()) return "-" + to_string(l.var()); + return to_string(l.var()); + } +}; From 8d980ea704065123ca7c243a490502cbcfb16c38 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 12:13:18 -0700 Subject: [PATCH 159/253] remove internal configuration Signed-off-by: Nikolaj Bjorner --- doc/mk_api_doc.py | 1 - src/ast/rewriter/bv_rewriter.cpp | 21 --------------------- src/ast/rewriter/bv_rewriter.h | 4 ++-- 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index 2ef219506..fd994166a 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -11,7 +11,6 @@ import getopt import pydoc import sys import subprocess -import shutil ML_ENABLED=False MLD_ENABLED=False diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 1fdd7bd14..fe44f8fda 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -33,7 +33,6 @@ void bv_rewriter::updt_local_params(params_ref const & _p) { m_split_concat_eq = p.split_concat_eq(); m_bvnot_simpl = p.bv_not_simpl(); m_bv_sort_ac = p.bv_sort_ac(); - m_mkbv2num = _p.get_bool("mkbv2num", false); m_extract_prop = p.bv_extract_prop(); m_ite2id = p.bv_ite2id(); m_le_extra = p.bv_le_extra(); @@ -49,9 +48,6 @@ void bv_rewriter::updt_params(params_ref const & p) { void bv_rewriter::get_param_descrs(param_descrs & r) { poly_rewriter::get_param_descrs(r); bv_rewriter_params::collect_param_descrs(r); -#ifndef _EXTERNAL_RELEASE - r.insert("mkbv2num", CPK_BOOL, "(default: false) convert (mkbv [true/false]*) into a numeral"); -#endif } br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { @@ -2723,23 +2719,6 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { br_status bv_rewriter::mk_mkbv(unsigned num, expr * const * args, expr_ref & result) { - if (m_mkbv2num) { - unsigned i; - for (i = 0; i < num; i++) - if (!m().is_true(args[i]) && !m().is_false(args[i])) - return BR_FAILED; - numeral val; - numeral two(2); - i = num; - while (i > 0) { - --i; - val *= two; - if (m().is_true(args[i])) - val++; - } - result = mk_numeral(val, num); - return BR_DONE; - } return BR_FAILED; } diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index 88d952c06..23ae67277 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -55,7 +55,6 @@ class bv_rewriter : public poly_rewriter { bool m_mul2concat; bool m_bit2bool; bool m_blast_eq_value; - bool m_mkbv2num; bool m_ite2id; bool m_split_concat_eq; bool m_bv_sort_ac; @@ -63,7 +62,8 @@ class bv_rewriter : public poly_rewriter { bool m_bvnot_simpl; bool m_le_extra; bool m_le2extract; - + bool m_mkbv2num = false; + bool is_zero_bit(expr * x, unsigned idx); br_status mk_ule(expr * a, expr * b, expr_ref & result); From 4953b95baad354a342dbd915fe2832e005e843c6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 12:19:39 -0700 Subject: [PATCH 160/253] cleanup pre-processor for z3_api.h Signed-off-by: Nikolaj Bjorner --- doc/mk_api_doc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index fd994166a..01fe482b9 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -132,10 +132,12 @@ def cleanup_API(inf, outf): pat1 = re.compile(".*def_API.*") pat2 = re.compile(".*extra_API.*") pat3 = re.compile(r".*def_Type\(.*") + pat4 = re.compile("Z3_DECLARE_CLOSURE.*") + pat5 = re.compile("DEFINE_TYPE.*") _inf = open(inf, 'r') _outf = open(outf, 'w') for line in _inf: - if not pat1.match(line) and not pat2.match(line) and not pat3.match(line): + if not pat1.match(line) and not pat2.match(line) and not pat3.match(line) and not pat4.match(line) and not pat5.match(line): _outf.write(line) def configure_file(template_file_path, output_file_path, substitutions): From 48701826f17a273aaad86d9c9b0ced8a91eb27e3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 13:57:03 -0700 Subject: [PATCH 161/253] indent Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- src/sat/dimacs.cpp | 13 ++++++++----- src/sat/dimacs.h | 1 + src/sat/sat_drat.cpp | 13 +++++++------ src/sat/sat_types.h | 6 ++++-- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index c91c01d62..dc17d42c5 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -100,7 +100,7 @@ stages: displayName: "$(name) build" pool: vmImage: "Ubuntu-18.04" - container: $(image) + container: $(image) variables: python: $(python) steps: diff --git a/src/sat/dimacs.cpp b/src/sat/dimacs.cpp index 4a818af6c..710cefe8a 100644 --- a/src/sat/dimacs.cpp +++ b/src/sat/dimacs.cpp @@ -113,8 +113,9 @@ static void read_clause(Buffer & in, std::ostream& err, sat::literal_vector & li } template -static void read_pragma(Buffer & in, std::ostream& err, std::string& p) { +static void read_pragma(Buffer & in, std::ostream& err, std::string& p, sat::proof_hint& h) { skip_whitespace(in); + h.reset(); if (*in != 'p') return; ++in; @@ -122,14 +123,16 @@ static void read_pragma(Buffer & in, std::ostream& err, std::string& p) { ++in; while (true) { if (*in == EOF) - return; + break; if (*in == '\n') { ++in; - return; + break; } p.push_back(*in); ++in; } + if (!p.empty()) + h.from_string(p); } @@ -177,7 +180,7 @@ namespace dimacs { sat::status_pp pp(r.m_status, p.th); switch (r.m_tag) { case drat_record::tag_t::is_clause: - if (!r.m_pragma.empty()) + if (!r.m_pragma.empty()) return out << pp << " " << r.m_lits << " 0 p " << r.m_pragma << "\n"; return out << pp << " " << r.m_lits << " 0\n"; case drat_record::tag_t::is_node: @@ -328,7 +331,7 @@ namespace dimacs { theory_id = read_theory_id(); skip_whitespace(in); read_clause(in, err, m_record.m_lits); - read_pragma(in, err, m_record.m_pragma); + read_pragma(in, err, m_record.m_pragma, m_record.m_hint); m_record.m_tag = drat_record::tag_t::is_clause; m_record.m_status = sat::status::th(false, theory_id); break; diff --git a/src/sat/dimacs.h b/src/sat/dimacs.h index 7b4e8557c..7a5a66283 100644 --- a/src/sat/dimacs.h +++ b/src/sat/dimacs.h @@ -64,6 +64,7 @@ namespace dimacs { std::string m_name; unsigned_vector m_args; std::string m_pragma; + sat::proof_hint m_hint; }; struct drat_pp { diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 4ecb8ed1f..ac5cb272c 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -932,11 +932,12 @@ namespace sat { return ous.str(); } - proof_hint proof_hint::from_string(char const* s) { - proof_hint h; + void proof_hint::from_string(char const* s) { + proof_hint& h = *this; + h.reset(); h.m_ty = hint_type::null_h; if (!s) - return h; + return; auto ws = [&]() { while (*s == ' ' || *s == '\n' || *s == '\t') ++s; @@ -999,14 +1000,14 @@ namespace sat { ws(); if (!parse_type()) - return h; + return; ws(); while (*s) { if (!parse_coeff_literal()) - return h; + return; ws(); } - return h; + return; } } diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 1adcbc6b6..bc7ea6ef9 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -102,11 +102,13 @@ namespace sat { }; struct proof_hint { - hint_type m_ty; + hint_type m_ty = hint_type::null_h; vector> m_literals; vector> m_eqs; + void reset() { m_ty = hint_type::null_h; m_literals.reset(); m_eqs.reset(); } std::string to_string() const; - static proof_hint from_string(char const* s); + void from_string(char const* s); + void from_string(std::string const& s) { from_string(s.c_str()); } }; class status { From 003881765677d84681ba691ddafe95283308fddc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 14:13:50 -0700 Subject: [PATCH 162/253] Update nightly.yaml for Azure Pipelines --- scripts/nightly.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index dc17d42c5..358804c82 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -97,10 +97,11 @@ stages: name: MuslLinux image: "quay.io/pypa/musllinux_1_1_x86_64:latest" python: "/opt/python/cp310-cp310/bin/python" + maxParallel: 2 displayName: "$(name) build" pool: vmImage: "Ubuntu-18.04" - container: $(image) + container: $(image) variables: python: $(python) steps: From 6ce03cd6f03e5a788645b833e4b862ff79cce1f7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 14:18:50 -0700 Subject: [PATCH 163/253] Update nightly.yaml for Azure Pipelines --- scripts/nightly.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 358804c82..95cb694b7 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -98,12 +98,14 @@ stages: image: "quay.io/pypa/musllinux_1_1_x86_64:latest" python: "/opt/python/cp310-cp310/bin/python" maxParallel: 2 + variables: + python: $(python) + name: $(name) + image: $(image) displayName: "$(name) build" pool: vmImage: "Ubuntu-18.04" - container: $(image) - variables: - python: $(python) + container: "quay.io/pypa/manylinux2010_x86_64:latest" steps: - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava - script: git clone https://github.com/z3prover/z3test z3test From e9660016bc7d810f8763834f9f55758b4fb3a741 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 14:21:23 -0700 Subject: [PATCH 164/253] remove hardwired image name Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 95cb694b7..1af5fc387 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -105,7 +105,7 @@ stages: displayName: "$(name) build" pool: vmImage: "Ubuntu-18.04" - container: "quay.io/pypa/manylinux2010_x86_64:latest" + container: $(image) steps: - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava - script: git clone https://github.com/z3prover/z3test z3test From 6b4bc5bd3898273752d327b6b0885de5940be41c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 14:26:00 -0700 Subject: [PATCH 165/253] remove broken matrix Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 1af5fc387..9f1851bca 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -86,23 +86,11 @@ stages: artifactName: 'UbuntuDoc' targetPath: $(Build.ArtifactStagingDirectory) - - job: LinuxBuilds - strategy: - matrix: - manyLinux: - name: ManyLinux - image: "quay.io/pypa/manylinux2010_x86_64:latest" - python: "/opt/python/cp37-cp37m/bin/python" - muslLinux: - name: MuslLinux - image: "quay.io/pypa/musllinux_1_1_x86_64:latest" - python: "/opt/python/cp310-cp310/bin/python" - maxParallel: 2 + - job: LinuxBuild variables: - python: $(python) - name: $(name) - image: $(image) - displayName: "$(name) build" + python: "/opt/python/cp37-cp37m/bin/python" + image: "quay.io/pypa/manylinux2010_x86_64:latest" + displayName: "ManyLinux build" pool: vmImage: "Ubuntu-18.04" container: $(image) @@ -408,11 +396,11 @@ stages: inputs: artifactName: 'Manylinux' targetPath: $(Agent.TempDirectory) - - task: DownloadPipelineArtifact@2 - displayName: 'Download MuslLinux Build' - inputs: - artifact: 'MuslLinuxBuild' - path: $(Agent.TempDirectory) +# - task: DownloadPipelineArtifact@2 +# displayName: 'Download MuslLinux Build' +# inputs: +# artifact: 'MuslLinuxBuild' +# path: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: artifactName: 'Mac' From d09d37cb104074e91c50298ae0a0d10ba6855ea0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 14:27:22 -0700 Subject: [PATCH 166/253] wt$ Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 9f1851bca..2211e32d2 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -93,7 +93,7 @@ stages: displayName: "ManyLinux build" pool: vmImage: "Ubuntu-18.04" - container: $(image) + container: "quay.io/pypa/manylinux2010_x86_64:latest" steps: - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava - script: git clone https://github.com/z3prover/z3test z3test From 35db0ae58bb6a87d5efcb8d2505f8ae9598e77f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 14:34:58 -0700 Subject: [PATCH 167/253] workaround manylinux build failure (it is advertized as a compiler bug) Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 9 +++++---- src/math/simplex/sparse_matrix.h | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 2211e32d2..4bf873e96 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -89,7 +89,8 @@ stages: - job: LinuxBuild variables: python: "/opt/python/cp37-cp37m/bin/python" - image: "quay.io/pypa/manylinux2010_x86_64:latest" + image: "quay.io/pypa/manylinux2010_x86_64:latest" + name: Linux displayName: "ManyLinux build" pool: vmImage: "Ubuntu-18.04" @@ -400,7 +401,7 @@ stages: # displayName: 'Download MuslLinux Build' # inputs: # artifact: 'MuslLinuxBuild' -# path: $(Agent.TempDirectory) +# path: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: artifactName: 'Mac' @@ -412,14 +413,14 @@ stages: - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*x64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*arm64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir libc-bin; cd libc-bin; unzip ../*glibc*.zip - - script: cd $(Agent.TempDirectory); mkdir musl-bin; cd musl-bin; unzip ../*-linux.zip +# - script: cd $(Agent.TempDirectory); mkdir musl-bin; cd musl-bin; unzip ../*-linux.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip - script: python3 -m pip install --user -U setuptools wheel - script: cd src/api/python; python3 setup.py sdist # take a look at this PREMIUM HACK I came up with to get around the fact that the azure variable syntax overloads the bash syntax for subshells - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - - script: cd src/api/python; echo $(Agent.TempDirectory)/musl-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel +# - script: cd src/api/python; echo $(Agent.TempDirectory)/musl-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-x64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index b51b57181..e26531c82 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -309,9 +309,9 @@ namespace simplex { all_rows get_rows() { return all_rows(*this); } numeral const& get_coeff(row r, unsigned v) { - for (auto & [coeff, u] : get_row(r)) - if (u == v) - return coeff; + for (auto & row : get_row(r)) + if (row.m_var == v) + return row.m_coeff; return m_zero; } From ddc344570747727d4916539d9aa13fc168112377 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 14:47:39 -0700 Subject: [PATCH 168/253] try to add back musllinux Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 4bf873e96..2438d0f03 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -89,7 +89,6 @@ stages: - job: LinuxBuild variables: python: "/opt/python/cp37-cp37m/bin/python" - image: "quay.io/pypa/manylinux2010_x86_64:latest" name: Linux displayName: "ManyLinux build" pool: @@ -105,6 +104,24 @@ stages: artifactName: '$(name)Build' targetPath: $(Build.ArtifactStagingDirectory) + - job: MuslLinuxBuild + variables: + python: "/opt/python/cp310-cp310/bin/python" + name: MuslLinux + displayName: "MuslLinux build" + pool: + vmImage: "Ubuntu-18.04" + container: "quay.io/pypa/musllinux_1_1_x86_64:latest" + steps: + - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava + - script: git clone https://github.com/z3prover/z3test z3test + - script: $(python) z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 + - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/ + - task: PublishPipelineArtifact@0 + inputs: + artifactName: '$(name)Build' + targetPath: $(Build.ArtifactStagingDirectory) + - job: Windows32 displayName: "Windows 32-bit build" pool: @@ -397,11 +414,11 @@ stages: inputs: artifactName: 'Manylinux' targetPath: $(Agent.TempDirectory) -# - task: DownloadPipelineArtifact@2 -# displayName: 'Download MuslLinux Build' -# inputs: -# artifact: 'MuslLinuxBuild' -# path: $(Agent.TempDirectory) + - task: DownloadPipelineArtifact@2 + displayName: 'Download MuslLinux Build' + inputs: + artifact: 'MuslLinuxBuild' + path: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: artifactName: 'Mac' @@ -413,14 +430,14 @@ stages: - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*x64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*arm64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir libc-bin; cd libc-bin; unzip ../*glibc*.zip -# - script: cd $(Agent.TempDirectory); mkdir musl-bin; cd musl-bin; unzip ../*-linux.zip + - script: cd $(Agent.TempDirectory); mkdir musl-bin; cd musl-bin; unzip ../*-linux.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip - script: python3 -m pip install --user -U setuptools wheel - script: cd src/api/python; python3 setup.py sdist # take a look at this PREMIUM HACK I came up with to get around the fact that the azure variable syntax overloads the bash syntax for subshells - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel -# - script: cd src/api/python; echo $(Agent.TempDirectory)/musl-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/musl-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-x64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel From b8532bec7eb60188dcee188f8c7cefb5e0dcd7b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 14:48:38 -0700 Subject: [PATCH 169/253] remove pragma from cpp file Signed-off-by: Nikolaj Bjorner --- src/opt/opt_preprocess.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/opt/opt_preprocess.cpp b/src/opt/opt_preprocess.cpp index d3475fcb0..886d7fbb0 100644 --- a/src/opt/opt_preprocess.cpp +++ b/src/opt/opt_preprocess.cpp @@ -30,7 +30,6 @@ Notes: --*/ -#pragma once #include "opt/opt_preprocess.h" #include "util/max_cliques.h" From 6abea2de2c28d4c3605397eb261400c4ebb2871c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 18:03:15 -0700 Subject: [PATCH 170/253] fix nightly, fix regression identified by Nuno Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 16 ++++++++-------- src/ast/rewriter/bv_rewriter.cpp | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 2438d0f03..6ee80a7e7 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -412,13 +412,13 @@ stages: targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: - artifactName: 'Manylinux' + artifactName: 'ManyLinuxBuild' targetPath: $(Agent.TempDirectory) - - task: DownloadPipelineArtifact@2 - displayName: 'Download MuslLinux Build' - inputs: - artifact: 'MuslLinuxBuild' - path: $(Agent.TempDirectory) +# - task: DownloadPipelineArtifact@2 +# displayName: 'Download MuslLinux Build' +# inputs: +# artifact: 'MuslLinuxBuild' +# path: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: artifactName: 'Mac' @@ -430,14 +430,14 @@ stages: - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*x64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*arm64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir libc-bin; cd libc-bin; unzip ../*glibc*.zip - - script: cd $(Agent.TempDirectory); mkdir musl-bin; cd musl-bin; unzip ../*-linux.zip +# - script: cd $(Agent.TempDirectory); mkdir musl-bin; cd musl-bin; unzip ../*-linux.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip - script: python3 -m pip install --user -U setuptools wheel - script: cd src/api/python; python3 setup.py sdist # take a look at this PREMIUM HACK I came up with to get around the fact that the azure variable syntax overloads the bash syntax for subshells - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - - script: cd src/api/python; echo $(Agent.TempDirectory)/musl-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel +# - script: cd src/api/python; echo $(Agent.TempDirectory)/musl-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-x64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index fe44f8fda..5e2d3816e 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2719,6 +2719,23 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { br_status bv_rewriter::mk_mkbv(unsigned num, expr * const * args, expr_ref & result) { + if (m_mkbv2num) { + unsigned i; + for (i = 0; i < num; i++) + if (!m().is_true(args[i]) && !m().is_false(args[i])) + return BR_FAILED; + numeral val; + numeral two(2); + i = num; + while (i > 0) { + --i; + val *= two; + if (m().is_true(args[i])) + val++; + } + result = mk_numeral(val, num); + return BR_DONE; + } return BR_FAILED; } From 9ec34d96cecdbf1ddb3cdacc6e3b306c1a17da67 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 18:14:42 -0700 Subject: [PATCH 171/253] comment out muslinux build Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 6ee80a7e7..2a163c41b 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -104,23 +104,23 @@ stages: artifactName: '$(name)Build' targetPath: $(Build.ArtifactStagingDirectory) - - job: MuslLinuxBuild - variables: - python: "/opt/python/cp310-cp310/bin/python" - name: MuslLinux - displayName: "MuslLinux build" - pool: - vmImage: "Ubuntu-18.04" - container: "quay.io/pypa/musllinux_1_1_x86_64:latest" - steps: - - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava - - script: git clone https://github.com/z3prover/z3test z3test - - script: $(python) z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/ - - task: PublishPipelineArtifact@0 - inputs: - artifactName: '$(name)Build' - targetPath: $(Build.ArtifactStagingDirectory) +# - job: MuslLinuxBuild +# variables: +# python: "/opt/python/cp310-cp310/bin/python" +# name: MuslLinux +# displayName: "MuslLinux build" +# pool: +# vmImage: "Ubuntu-18.04" +# container: "quay.io/pypa/musllinux_1_1_x86_64:latest" +# steps: +# - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava +# - script: git clone https://github.com/z3prover/z3test z3test +# - script: $(python) z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 +# - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/ +# - task: PublishPipelineArtifact@0 +# inputs: +# artifactName: '$(name)Build' +# targetPath: $(Build.ArtifactStagingDirectory) - job: Windows32 displayName: "Windows 32-bit build" From 63b9c4bdf02c551384192f4426a9d3f6026e18fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 May 2022 18:49:27 -0700 Subject: [PATCH 172/253] for AG Signed-off-by: Nikolaj Bjorner --- src/ast/proofs/proof_checker.h | 2 +- src/shell/drat_frontend.cpp | 63 +++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/ast/proofs/proof_checker.h b/src/ast/proofs/proof_checker.h index b69a6b54d..27f872d25 100644 --- a/src/ast/proofs/proof_checker.h +++ b/src/ast/proofs/proof_checker.h @@ -70,12 +70,12 @@ public: proof_checker(ast_manager& m); void set_dump_lemmas(char const * logic = "AUFLIA") { m_dump_lemmas = true; m_logic = logic; } bool check(proof* p, expr_ref_vector& side_conditions); + bool check_arith_literal(bool is_pos, app* lit, rational const& coeff, expr_ref& sum, bool& is_strict); private: bool check1(proof* p, expr_ref_vector& side_conditions); bool check1_basic(proof* p, expr_ref_vector& side_conditions); bool check1_spc(proof* p, expr_ref_vector& side_conditions); bool check_arith_proof(proof* p); - bool check_arith_literal(bool is_pos, app* lit, rational const& coeff, expr_ref& sum, bool& is_strict); bool match_fact(proof const* p, expr*& fact) const; void add_premise(proof* p); bool match_proof(proof const* p) const; diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index 1dba2e768..81ebdddd4 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -15,6 +15,8 @@ Copyright (c) 2020 Microsoft Corporation #include "shell/drat_frontend.h" #include "parsers/smt2/smt2parser.h" #include "cmd_context/cmd_context.h" +#include "ast/proofs/proof_checker.h" +#include "ast/rewriter/th_rewriter.h" class smt_checker { ast_manager& m; @@ -156,7 +158,65 @@ public: else if (!st.is_sat() && !st.is_deleted()) check_clause(lits); // m_drat.add(lits, st); - } + } + + void validate_hint(sat::literal_vector const& lits, sat::proof_hint const& hint) { + return; // remove when testing this + proof_checker pc(m); + arith_util autil(m); + switch (hint.m_ty) { + case sat::hint_type::null_h: + break; + case sat::hint_type::bound_h: { + // TODO: combine bound_h and farkas_h into a single rule + // TODO: use proof_checker.cpp check_arith_proof to check farkas claim + expr_ref sum(m); + bool is_strict = false; + vector coeffs; + rational lc(1); + for (auto const& [coeff, lit] : hint.m_literals) { + coeffs.push_back(coeff); + lc = lcm(lc, denominator(coeff)); + } + if (!lc.is_one()) + for (auto& coeff : coeffs) + coeff *= lc; + + unsigned i = 0; + for (auto const& [coeff, lit] : hint.m_literals) { + app_ref e(to_app(m_b2e[lit.var()]), m); + if (!pc.check_arith_literal(!lit.sign(), e, coeffs[i], sum, is_strict)) { + std::cout << "Failed checking hint " << e << "\n"; + return; + } + ++i; + } + if (!sum.get()) { + std::cout << "no summation\n"; + return; + } + + if (is_strict) + sum = autil.mk_lt(sum, autil.mk_numeral(rational(0), sum->get_sort())); + else + sum = autil.mk_le(sum, autil.mk_numeral(rational(0), sum->get_sort())); + + th_rewriter rw(m); + rw(sum); + if (!m.is_false(sum)) { + std::cout << "Lemma not simplified " << sum << "\n"; + return; + } + break; + } + case sat::hint_type::farkas_h: + std::cout << "FARKAS\n"; + break; + case sat::hint_type::cut_h: + std::cout << "CUT\n"; + break; + } + } /** * Add an assertion from the source file @@ -345,6 +405,7 @@ static void verify_smt(char const* drat_file, char const* smt_file) { switch (r.m_tag) { case dimacs::drat_record::tag_t::is_clause: checker.add(r.m_lits, r.m_status); + checker.validate_hint(r.m_lits, r.m_hint); if (drat_checker.inconsistent()) { std::cout << "inconsistent\n"; return; From 36ad377a7dc9d7876a9e3afc630b71e16b8093af Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 29 May 2022 09:21:43 -0700 Subject: [PATCH 173/253] na Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 2a163c41b..0c58c47b2 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -86,10 +86,10 @@ stages: artifactName: 'UbuntuDoc' targetPath: $(Build.ArtifactStagingDirectory) - - job: LinuxBuild + - job: ManyLinuxBuild variables: python: "/opt/python/cp37-cp37m/bin/python" - name: Linux + name: ManyLinux displayName: "ManyLinux build" pool: vmImage: "Ubuntu-18.04" From bffa7ff2f6fc57d858a8cd4495142d5f139e8e42 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 29 May 2022 10:12:05 -0700 Subject: [PATCH 174/253] add hint verification, combine bounds/farkas into one rule Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 37 ++++++++++++++-------------- src/sat/dimacs.cpp | 2 +- src/sat/sat_drat.cpp | 8 ------ src/sat/sat_types.h | 1 - src/sat/smt/arith_diagnostics.cpp | 9 +++++-- src/sat/smt/arith_solver.cpp | 6 ++--- src/sat/smt/arith_solver.h | 2 +- src/sat/smt/euf_solver.h | 2 +- src/shell/drat_frontend.cpp | 41 ++++++++++++++++++++----------- 9 files changed, 59 insertions(+), 49 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 0c58c47b2..f8bb7e447 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -104,25 +104,26 @@ stages: artifactName: '$(name)Build' targetPath: $(Build.ArtifactStagingDirectory) -# - job: MuslLinuxBuild -# variables: -# python: "/opt/python/cp310-cp310/bin/python" -# name: MuslLinux -# displayName: "MuslLinux build" -# pool: -# vmImage: "Ubuntu-18.04" -# container: "quay.io/pypa/musllinux_1_1_x86_64:latest" -# steps: -# - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava -# - script: git clone https://github.com/z3prover/z3test z3test -# - script: $(python) z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 -# - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/ -# - task: PublishPipelineArtifact@0 -# inputs: -# artifactName: '$(name)Build' -# targetPath: $(Build.ArtifactStagingDirectory) + - job: MuslLinuxBuild + condition: eq(0,1) + variables: + python: "/opt/python/cp310-cp310/bin/python" + name: MuslLinux + displayName: "MuslLinux build" + pool: + vmImage: "Ubuntu-18.04" + container: "quay.io/pypa/musllinux_1_1_x86_64:latest" + steps: + - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava + - script: git clone https://github.com/z3prover/z3test z3test + - script: $(python) z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 + - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/ + - task: PublishPipelineArtifact@0 + inputs: + artifactName: '$(name)Build' + targetPath: $(Build.ArtifactStagingDirectory) - - job: Windows32 +- job: Windows32 displayName: "Windows 32-bit build" pool: vmImage: "windows-latest" diff --git a/src/sat/dimacs.cpp b/src/sat/dimacs.cpp index 710cefe8a..629fefb7b 100644 --- a/src/sat/dimacs.cpp +++ b/src/sat/dimacs.cpp @@ -115,7 +115,6 @@ static void read_clause(Buffer & in, std::ostream& err, sat::literal_vector & li template static void read_pragma(Buffer & in, std::ostream& err, std::string& p, sat::proof_hint& h) { skip_whitespace(in); - h.reset(); if (*in != 'p') return; ++in; @@ -307,6 +306,7 @@ namespace dimacs { loop: skip_whitespace(in); m_record.m_pragma.clear(); + m_record.m_hint.reset(); switch (*in) { case EOF: return false; diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index ac5cb272c..ba4c543a8 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -918,9 +918,6 @@ namespace sat { case hint_type::farkas_h: ous << "farkas "; break; - case hint_type::bound_h: - ous << "bound "; - break; case hint_type::cut_h: ous << "cut "; break; @@ -949,11 +946,6 @@ namespace sat { s += 6; return true; } - if (0 == strncmp(s, "bound", 5)) { - h.m_ty = hint_type::bound_h; - s += 5; - return true; - } return false; }; diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index bc7ea6ef9..e03cdfbff 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -97,7 +97,6 @@ namespace sat { enum class hint_type { null_h, farkas_h, - bound_h, cut_h }; diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index f3e90e266..1ff464164 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -81,13 +81,14 @@ namespace arith { } /** - * Assumption: + * It may be necessary to use the following assumption when checking Farkas claims + * generated from bounds propagation: * A bound literal ax <= b is explained by a set of weighted literals * r1*(a1*x <= b1) + .... + r_k*(a_k*x <= b_k), where r_i > 0 * such that there is a r >= 1 * (r1*a1+..+r_k*a_k) = r*a, (r1*b1+..+r_k*b_k) <= r*b */ - sat::proof_hint const* solver::explain(sat::hint_type ty) { + sat::proof_hint const* solver::explain(sat::hint_type ty, sat::literal lit) { if (!ctx.use_drat()) return nullptr; m_bounds_pragma.m_ty = ty; @@ -105,6 +106,8 @@ namespace arith { } case equality_source: { auto [u, v] = m_equalities[idx]; + ctx.drat_log_expr(u->get_expr()); + ctx.drat_log_expr(v->get_expr()); m_bounds_pragma.m_eqs.push_back({ev.coeff(), u->get_expr_id(), v->get_expr_id()}); break; } @@ -112,6 +115,8 @@ namespace arith { break; } } + if (lit != sat::null_literal) + m_bounds_pragma.m_literals.push_back({rational(1), ~lit}); return &m_bounds_pragma; } } diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 4209dd5e3..7796585de 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -263,7 +263,7 @@ namespace arith { TRACE("arith", for (auto lit : m_core) tout << lit << ": " << s().value(lit) << "\n";); DEBUG_CODE(for (auto lit : m_core) { VERIFY(s().value(lit) == l_true); }); ++m_stats.m_bound_propagations1; - assign(lit, m_core, m_eqs, explain(sat::hint_type::bound_h)); + assign(lit, m_core, m_eqs, explain(sat::hint_type::farkas_h, lit)); } if (should_refine_bounds() && first) @@ -378,7 +378,7 @@ namespace arith { reset_evidence(); m_explanation.clear(); lp().explain_implied_bound(be, m_bp); - assign(bound, m_core, m_eqs, explain(sat::hint_type::bound_h)); + assign(bound, m_core, m_eqs, explain(sat::hint_type::farkas_h, bound)); } @@ -1177,7 +1177,7 @@ namespace arith { app_ref b = mk_bound(m_lia->get_term(), m_lia->get_offset(), !m_lia->is_upper()); IF_VERBOSE(4, verbose_stream() << "cut " << b << "\n"); literal lit = expr2literal(b); - assign(lit, m_core, m_eqs, explain(sat::hint_type::cut_h)); + assign(lit, m_core, m_eqs, explain(sat::hint_type::cut_h, lit)); lia_check = l_false; break; } diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index bac985848..8df8b7ec2 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -421,7 +421,7 @@ namespace arith { sat::proof_hint m_bounds_pragma; sat::proof_hint m_farkas2; - sat::proof_hint const* explain(sat::hint_type ty); + sat::proof_hint const* explain(sat::hint_type ty, sat::literal lit = sat::null_literal); public: diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 63439625b..21a9c4d1d 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -176,7 +176,6 @@ namespace euf { void log_antecedents(literal l, literal_vector const& r); void log_justification(literal l, th_explain const& jst); void drat_log_decl(func_decl* f); - void drat_log_expr(expr* n); void drat_log_expr1(expr* n); ptr_vector m_drat_todo; obj_hashtable m_drat_asts; @@ -345,6 +344,7 @@ namespace euf { sat::drat& get_drat() { return s().get_drat(); } void drat_bool_def(sat::bool_var v, expr* n); void drat_eq_def(sat::literal lit, expr* eq); + void drat_log_expr(expr* n); // decompile bool extract_pb(std::function& card, diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index 81ebdddd4..8ac24ac12 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -160,16 +160,15 @@ public: // m_drat.add(lits, st); } - void validate_hint(sat::literal_vector const& lits, sat::proof_hint const& hint) { - return; // remove when testing this + void validate_hint(expr_ref_vector const& exprs, sat::literal_vector const& lits, sat::proof_hint const& hint) { + // return; // remove when testing this proof_checker pc(m); arith_util autil(m); switch (hint.m_ty) { case sat::hint_type::null_h: break; - case sat::hint_type::bound_h: { - // TODO: combine bound_h and farkas_h into a single rule - // TODO: use proof_checker.cpp check_arith_proof to check farkas claim + case sat::hint_type::cut_h: + case sat::hint_type::farkas_h: { expr_ref sum(m); bool is_strict = false; vector coeffs; @@ -178,6 +177,10 @@ public: coeffs.push_back(coeff); lc = lcm(lc, denominator(coeff)); } + for (auto const& [coeff, a, b]: hint.m_eqs) { + coeffs.push_back(coeff); + lc = lcm(lc, denominator(coeff)); + } if (!lc.is_one()) for (auto& coeff : coeffs) coeff *= lc; @@ -186,13 +189,25 @@ public: for (auto const& [coeff, lit] : hint.m_literals) { app_ref e(to_app(m_b2e[lit.var()]), m); if (!pc.check_arith_literal(!lit.sign(), e, coeffs[i], sum, is_strict)) { - std::cout << "Failed checking hint " << e << "\n"; + std::cout << "p failed checking hint " << e << "\n"; return; } ++i; } + for (auto const& [coeff, a, b]: hint.m_eqs) { + expr* x = exprs[a]; + expr* y = exprs[b]; + coeffs.push_back(coeff); + app_ref e(m.mk_eq(x, y), m); + if (!pc.check_arith_literal(true, e, coeffs[i], sum, is_strict)) { + std::cout << "p failed checking hint " << e << "\n"; + return; + } + ++i; + } + if (!sum.get()) { - std::cout << "no summation\n"; + std::cout << "p no summation\n"; return; } @@ -204,16 +219,14 @@ public: th_rewriter rw(m); rw(sum); if (!m.is_false(sum)) { - std::cout << "Lemma not simplified " << sum << "\n"; + std::cout << "p hint not verified " << sum << "\n"; return; } + std::cout << "p hint verified\n"; break; } - case sat::hint_type::farkas_h: - std::cout << "FARKAS\n"; - break; - case sat::hint_type::cut_h: - std::cout << "CUT\n"; + default: + UNREACHABLE(); break; } } @@ -405,7 +418,7 @@ static void verify_smt(char const* drat_file, char const* smt_file) { switch (r.m_tag) { case dimacs::drat_record::tag_t::is_clause: checker.add(r.m_lits, r.m_status); - checker.validate_hint(r.m_lits, r.m_hint); + checker.validate_hint(exprs, r.m_lits, r.m_hint); if (drat_checker.inconsistent()) { std::cout << "inconsistent\n"; return; From cb279fba2b16b4c9c23114533ba2ef58357f1d70 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 29 May 2022 10:32:05 -0700 Subject: [PATCH 175/253] fix sign for binary propagation hints Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 6 +++++- src/sat/smt/arith_axioms.cpp | 4 ++-- src/sat/smt/arith_solver.cpp | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index ba4c543a8..12ce52b19 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -946,6 +946,11 @@ namespace sat { s += 6; return true; } + if (0 == strncmp(s, "cut", 3)) { + h.m_ty = hint_type::cut_h; + s += 3; + return true; + } return false; }; @@ -999,7 +1004,6 @@ namespace sat { return; ws(); } - return; } } diff --git a/src/sat/smt/arith_axioms.cpp b/src/sat/smt/arith_axioms.cpp index f63714fdd..7cb6a05b6 100644 --- a/src/sat/smt/arith_axioms.cpp +++ b/src/sat/smt/arith_axioms.cpp @@ -238,8 +238,8 @@ namespace arith { sat::proof_hint* bound_params = nullptr; if (ctx.use_drat()) { bound_params = &m_farkas2; - m_farkas2.m_literals[0] = std::make_pair(rational(1), l1); - m_farkas2.m_literals[1] = std::make_pair(rational(1), l2); + m_farkas2.m_literals[0] = std::make_pair(rational(1), ~l1); + m_farkas2.m_literals[1] = std::make_pair(rational(1), ~l2); } add_clause(l1, l2, bound_params); }; diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 7796585de..acc810120 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -201,7 +201,7 @@ namespace arith { if (ctx.use_drat()) { ph = &m_farkas2; m_farkas2.m_literals[0] = std::make_pair(rational(1), lit1); - m_farkas2.m_literals[1] = std::make_pair(rational(1), lit2); + m_farkas2.m_literals[1] = std::make_pair(rational(1), ~lit2); } assign(lit2, m_core, m_eqs, ph); ++m_stats.m_bounds_propagations; From da3f31697b52e7f711488072a9bad02572f5167f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 May 2022 10:18:16 -0700 Subject: [PATCH 176/253] fix proof checking for bounds propagation --- src/math/lp/explanation.h | 3 +- src/math/lp/gomory.cpp | 63 ++++++++++++-------------- src/sat/sat_drat.cpp | 8 ++++ src/sat/sat_types.h | 1 + src/sat/smt/arith_diagnostics.cpp | 4 +- src/sat/smt/arith_solver.cpp | 13 +++--- src/shell/drat_frontend.cpp | 74 ++++++++++++++++++++++++------- 7 files changed, 105 insertions(+), 61 deletions(-) diff --git a/src/math/lp/explanation.h b/src/math/lp/explanation.h index 1b4bd9ddb..700a30acc 100644 --- a/src/math/lp/explanation.h +++ b/src/math/lp/explanation.h @@ -73,13 +73,14 @@ public: }; class iterator { bool m_run_on_vector; + mpq m_one = one_of_type(); pair_vec::const_iterator m_vi; ci_set::iterator m_ci; public: cimpq operator*() const { return m_run_on_vector? cimpq( m_vi->first, m_vi->second) : - cimpq( *m_ci, one_of_type()); + cimpq( *m_ci, m_one); } iterator operator++() { if (m_run_on_vector) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 70b09aba3..2d187c9f4 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -82,7 +82,8 @@ class create_cut { TRACE("gomory_cut_detail", tout << "new_a = " << new_a << ", k = " << m_k << ", lcm_den = " << m_lcm_den << "\n";); #if SMALL_CUTS // if (numerator(new_a).is_big()) throw found_big(); - if (numerator(new_a) > m_big_number) throw found_big(); + if (numerator(new_a) > m_big_number) + throw found_big(); #endif } @@ -90,28 +91,24 @@ class create_cut { TRACE("gomory_cut_detail_real", tout << "j = " << j << ", a = " << a << ", m_k = " << m_k << "\n";); mpq new_a; if (at_lower(j)) { - if (a.is_pos()) { + if (a.is_pos()) // the delta is a (x - f) is positive it has to grow and fight m_one_minus_f new_a = a / m_one_minus_f; - } - else { + else // the delta is negative and it works again m_f new_a = - a / m_f; - } m_k.addmul(new_a, lower_bound(j).x); // is it a faster operation than // k += lower_bound(j).x * new_a; m_ex->push_back(column_lower_bound_constraint(j)); } else { lp_assert(at_upper(j)); - if (a.is_pos()) { + if (a.is_pos()) // the delta is works again m_f new_a = - a / m_f; - } - else { + else // the delta is positive works again m_one_minus_f new_a = a / m_one_minus_f; - } m_k.addmul(new_a, upper_bound(j).x); // k += upper_bound(j).x * new_a; m_ex->push_back(column_upper_bound_constraint(j)); } @@ -121,7 +118,8 @@ class create_cut { #if SMALL_CUTS // if (numerator(new_a).is_big()) throw found_big(); - if (numerator(new_a) > m_big_number) throw found_big(); + if (numerator(new_a) > m_big_number) + throw found_big(); #endif } @@ -146,13 +144,15 @@ class create_cut { if (!m_k.is_int()) m_k = ceil(m_k); m_t.add_monomial(mpq(1), v); - } else { + } + else { m_k /= -a; if (!m_k.is_int()) m_k = ceil(m_k); m_t.add_monomial(-mpq(1), v); } - } else { + } + else { m_lcm_den = lcm(m_lcm_den, denominator(m_k)); lp_assert(m_lcm_den.is_pos()); TRACE("gomory_cut_detail", tout << "pol.size() > 1 den: " << m_lcm_den << std::endl;); @@ -176,14 +176,12 @@ class create_cut { } std::ostream& dump_coeff_val(std::ostream & out, const mpq & a) const { - if (a.is_int()) { + if (a.is_int()) out << a; - } else if ( a >= zero_of_type()) out << "(/ " << numerator(a) << " " << denominator(a) << ")"; - else { - out << "(- ( / " << numerator(-a) << " " << denominator(-a) << "))"; - } + else + out << "(- (/ " << numerator(-a) << " " << denominator(-a) << "))"; return out; } @@ -197,12 +195,10 @@ class create_cut { std::ostream& dump_row_coefficients(std::ostream & out) const { mpq lc(1); - for (const auto& p : m_row) { + for (const auto& p : m_row) lc = lcm(lc, denominator(p.coeff())); - } - for (const auto& p : m_row) { + for (const auto& p : m_row) dump_coeff_val(out << " (* ", p.coeff()*lc) << " " << var_name(p.var()) << ")"; - } return out; } @@ -218,9 +214,8 @@ class create_cut { void dump_declarations(std::ostream& out) const { // for a column j the var name is vj - for (const auto & p : m_row) { + for (const auto & p : m_row) dump_declaration(out, p.var()); - } for (lar_term::ival p : m_t) { auto t = lia.lra.column2tv(p.column()); if (t.is_term()) { @@ -239,12 +234,11 @@ class create_cut { void dump_explanations(std::ostream& out) const { for (const auto & p : m_row) { unsigned j = p.var(); - if (j == m_inf_col || (!is_real(j) && p.coeff().is_int())) { + if (j == m_inf_col || (!is_real(j) && p.coeff().is_int())) continue; - } - else if (at_lower(j)) { + else if (at_lower(j)) dump_lower_bound_expl(out, j); - } else { + else { lp_assert(at_upper(j)); dump_upper_bound_expl(out, j); } @@ -252,9 +246,8 @@ class create_cut { } std::ostream& dump_term_coefficients(std::ostream & out) const { - for (lar_term::ival p : m_t) { + for (lar_term::ival p : m_t) dump_coeff(out, p); - } return out; } @@ -281,9 +274,8 @@ class create_cut { public: void dump(std::ostream& out) { out << "applying cut at:\n"; print_linear_combination_indices_only, mpq>(m_row, out); out << std::endl; - for (auto & p : m_row) { + for (auto & p : m_row) lia.lra.print_column_info(p.var(), out); - } out << "inf_col = " << m_inf_col << std::endl; } @@ -304,7 +296,8 @@ public: m_abs_max = 0; for (const auto & p : m_row) { mpq t = abs(ceil(p.coeff())); - if (t > m_abs_max) m_abs_max = t; + if (t > m_abs_max) + m_abs_max = t; } m_big_number = m_abs_max.expt(2); #endif @@ -324,9 +317,8 @@ public: m_ex->push_back(column_upper_bound_constraint(j)); continue; } - if (is_real(j)) { + if (is_real(j)) real_case_in_gomory_cut(- p.coeff(), j); - } else if (!p.coeff().is_int()) { some_int_columns = true; m_fj = fractional_part(-p.coeff()); @@ -411,7 +403,8 @@ int gomory::find_basic_var() { lia_move gomory::operator()() { lra.move_non_basic_columns_to_bounds(true); int j = find_basic_var(); - if (j == -1) return lia_move::undef; + if (j == -1) + return lia_move::undef; unsigned r = lia.row_of_basic_column(j); const row_strip& row = lra.get_row(r); SASSERT(lra.row_is_correct(r)); diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 12ce52b19..e8594b048 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -918,6 +918,9 @@ namespace sat { case hint_type::farkas_h: ous << "farkas "; break; + case hint_type::bound_h: + ous << "bound "; + break; case hint_type::cut_h: ous << "cut "; break; @@ -946,6 +949,11 @@ namespace sat { s += 6; return true; } + if (0 == strncmp(s, "bound", 5)) { + h.m_ty = hint_type::bound_h; + s += 5; + return true; + } if (0 == strncmp(s, "cut", 3)) { h.m_ty = hint_type::cut_h; s += 3; diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index e03cdfbff..bc7ea6ef9 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -97,6 +97,7 @@ namespace sat { enum class hint_type { null_h, farkas_h, + bound_h, cut_h }; diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index 1ff464164..3dd4f58de 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -94,7 +94,9 @@ namespace arith { m_bounds_pragma.m_ty = ty; m_bounds_pragma.m_literals.reset(); m_bounds_pragma.m_eqs.reset(); - for (auto ev : m_explanation) { + unsigned i = 0; + for (auto const & ev : m_explanation) { + ++i; auto idx = ev.ci(); if (UINT_MAX == idx) continue; diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index acc810120..6d93b3378 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -232,14 +232,13 @@ namespace arith { if (v == euf::null_theory_var) return; - TRACE("arith", tout << "v" << v << " " << be.kind() << " " << be.m_bound << "\n";); - reserve_bounds(v); - if (m_unassigned_bounds[v] == 0 && !should_refine_bounds()) { - TRACE("arith", tout << "return\n";); + if (m_unassigned_bounds[v] == 0 && !should_refine_bounds()) return; - } + + TRACE("arith", tout << "lp bound v" << v << " " << be.kind() << " " << be.m_bound << "\n";); + lp_bounds const& bounds = m_bounds[v]; bool first = true; for (unsigned i = 0; i < bounds.size(); ++i) { @@ -249,7 +248,7 @@ namespace arith { literal lit = is_bound_implied(be.kind(), be.m_bound, *b); if (lit == sat::null_literal) continue; - TRACE("arith", tout << lit << " bound: " << *b << " first: " << first << "\n";); + TRACE("arith", tout << "lp bound " << lit << " bound: " << *b << " first: " << first << "\n";); lp().settings().stats().m_num_of_implied_bounds++; if (first) { @@ -263,7 +262,7 @@ namespace arith { TRACE("arith", for (auto lit : m_core) tout << lit << ": " << s().value(lit) << "\n";); DEBUG_CODE(for (auto lit : m_core) { VERIFY(s().value(lit) == l_true); }); ++m_stats.m_bound_propagations1; - assign(lit, m_core, m_eqs, explain(sat::hint_type::farkas_h, lit)); + assign(lit, m_core, m_eqs, explain(sat::hint_type::bound_h, lit)); } if (should_refine_bounds() && first) diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index 8ac24ac12..8bd629845 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -160,7 +160,7 @@ public: // m_drat.add(lits, st); } - void validate_hint(expr_ref_vector const& exprs, sat::literal_vector const& lits, sat::proof_hint const& hint) { + bool validate_hint(expr_ref_vector const& exprs, sat::literal_vector const& lits, sat::proof_hint const& hint) { // return; // remove when testing this proof_checker pc(m); arith_util autil(m); @@ -168,16 +168,18 @@ public: case sat::hint_type::null_h: break; case sat::hint_type::cut_h: + case sat::hint_type::bound_h: case sat::hint_type::farkas_h: { - expr_ref sum(m); + expr_ref sum(m), last_sum(m); bool is_strict = false; vector coeffs; rational lc(1); - for (auto const& [coeff, lit] : hint.m_literals) { + for (auto const& [coeff, a, b]: hint.m_eqs) { coeffs.push_back(coeff); lc = lcm(lc, denominator(coeff)); } - for (auto const& [coeff, a, b]: hint.m_eqs) { + + for (auto const& [coeff, lit] : hint.m_literals) { coeffs.push_back(coeff); lc = lcm(lc, denominator(coeff)); } @@ -185,15 +187,7 @@ public: for (auto& coeff : coeffs) coeff *= lc; - unsigned i = 0; - for (auto const& [coeff, lit] : hint.m_literals) { - app_ref e(to_app(m_b2e[lit.var()]), m); - if (!pc.check_arith_literal(!lit.sign(), e, coeffs[i], sum, is_strict)) { - std::cout << "p failed checking hint " << e << "\n"; - return; - } - ++i; - } + unsigned i = 0; for (auto const& [coeff, a, b]: hint.m_eqs) { expr* x = exprs[a]; expr* y = exprs[b]; @@ -201,14 +195,41 @@ public: app_ref e(m.mk_eq(x, y), m); if (!pc.check_arith_literal(true, e, coeffs[i], sum, is_strict)) { std::cout << "p failed checking hint " << e << "\n"; - return; + return false; } ++i; } + for (auto const& [coeff, lit] : hint.m_literals) { + last_sum = sum; + app_ref e(to_app(m_b2e[lit.var()]), m); + if (!pc.check_arith_literal(!lit.sign(), e, coeffs[i], sum, is_strict)) { + std::cout << "p failed checking hint " << e << "\n"; + return false; + } + ++i; + } + if (!sum.get()) { std::cout << "p no summation\n"; - return; + return false; + } + + th_rewriter rw(m); + if (sat::hint_type::bound_h == hint.m_ty) { + rw(last_sum); + sum = last_sum; + auto const& [coeff, lit] = hint.m_literals.back(); + rational last_coeff = coeff, r; + expr* x, *y, *z; + if (autil.is_add(sum)) { + x = to_app(sum)->get_arg(1); + if (autil.is_mul(x, y, z) && autil.is_numeral(y, r)) { + last_coeff = r; + } + } + app_ref e(to_app(m_b2e[lit.var()]), m); + VERIFY(pc.check_arith_literal(!lit.sign(), e, last_coeff, sum, is_strict)); } if (is_strict) @@ -216,11 +237,29 @@ public: else sum = autil.mk_le(sum, autil.mk_numeral(rational(0), sum->get_sort())); - th_rewriter rw(m); rw(sum); if (!m.is_false(sum)) { + // check hint: std::cout << "p hint not verified " << sum << "\n"; - return; + auto const& [coeff, lit] = hint.m_literals.back(); + expr_ref sum1(m); + bool is_strict1 = false; + app_ref e(to_app(m_b2e[lit.var()]), m); + rational coeffb = coeffs.back(); + VERIFY(pc.check_arith_literal(!lit.sign(), e, coeffb, sum1, is_strict1)); + std::cout << last_sum << " => ~" << sum1 << "\n"; + for (auto const& [coeff, a, b]: hint.m_eqs) { + expr* x = exprs[a]; + expr* y = exprs[b]; + app_ref e(m.mk_eq(x, y), m); + std::cout << e << "\n"; + } + for (auto const& [coeff, lit] : hint.m_literals) { + app_ref e(to_app(m_b2e[lit.var()]), m); + if (lit.sign()) e = m.mk_not(e); + std::cout << e << "\n"; + } + return false; } std::cout << "p hint verified\n"; break; @@ -229,6 +268,7 @@ public: UNREACHABLE(); break; } + return true; } /** From 15c47808d6fe6e36dc35b0e3a6af1b886bb6e78f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 May 2022 11:03:50 -0700 Subject: [PATCH 177/253] #6059 Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 85 +++++++++++++++++++++++++++++++++++++++++ src/api/python/z3/z3.py | 21 ++++++++++ src/api/z3_api.h | 14 +++++++ 3 files changed, 120 insertions(+) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 9f9039378..7cd3b2dd9 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -874,6 +874,91 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } + Z3_ast Z3_API Z3_substitute_funs(Z3_context c, + Z3_ast _a, + unsigned num_funs, + Z3_func_decl const _from[], + Z3_ast const _to[]) { + Z3_TRY; + LOG_Z3_substitute_funs(c, _a, num_funs, _from, _to); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + expr * a = to_expr(_a); + func_decl * const * from = to_func_decls(_from); + expr * const * to = to_exprs(num_funs, _to); + + expr * r = nullptr, *v, *w; + expr_ref_vector trail(m), args(m); + ptr_vector todo; + obj_map rep; + obj_map cache; + + for (unsigned i = 0; i < num_funs; i++) { + if (from[i]->get_range() != to[i]->get_sort()) { + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); + RETURN_Z3(of_expr(nullptr)); + } + rep.insert(from[i], to[i]); + } + + var_subst subst(m, false); + todo.push_back(a); + while (!todo.empty()) { + r = todo.back(); + if (cache.contains(r)) + todo.pop_back(); + else if (is_app(r)) { + args.reset(); + unsigned sz = todo.size(); + bool change = false; + for (expr* arg : *to_app(r)) { + if (cache.find(arg, v)) { + args.push_back(v); + change |= v != arg; + } + else { + todo.push_back(arg); + } + } + if (todo.size() == sz) { + if (rep.find(to_app(r)->get_decl(), w)) { + expr_ref new_v = subst(w, args); + v = new_v; + trail.push_back(v); + } + else if (change) { + v = m.mk_app(to_app(r)->get_decl(), args); + trail.push_back(v); + } + else + v = r; + cache.insert(r, v); + todo.pop_back(); + } + } + else if (is_var(r)) { + cache.insert(r, r); + todo.pop_back(); + } + else if (is_quantifier(r)) { + if (cache.find(to_quantifier(r)->get_expr(), v)) { + v = m.update_quantifier(to_quantifier(r), v); + trail.push_back(v); + cache.insert(r, v); + todo.pop_back(); + } + else + todo.push_back(to_quantifier(r)->get_expr()); + } + else + UNREACHABLE(); + } + r = cache[a]; + mk_c(c)->save_ast_trail(r); + RETURN_Z3(of_expr(r)); + Z3_CATCH_RETURN(nullptr); + } + Z3_ast Z3_API Z3_substitute_vars(Z3_context c, Z3_ast _a, unsigned num_exprs, diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 5ad8ede50..99be0055e 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8803,6 +8803,27 @@ def substitute_vars(t, *m): _to[i] = m[i].as_ast() return _to_expr_ref(Z3_substitute_vars(t.ctx.ref(), t.as_ast(), num, _to), t.ctx) +def substitute_funs(t, *m): + """Apply subistitution m on t, m is a list of pairs of a function and expression (from, to) + Every occurrence in to of the function from is replaced with the expression to. + The expression to can have free variables, that refer to the arguments of from. + For examples, see + """ + if isinstance(m, tuple): + m1 = _get_args(m) + if isinstance(m1, list) and all(isinstance(p, tuple) for p in m1): + m = m1 + if z3_debug(): + _z3_assert(is_expr(t), "Z3 expression expected") + _z3_assert(all([isinstance(p, tuple) and is_func_decl(p[0]) and is_expr(p[1]) for p in m]), "Z3 invalid substitution, funcion pairs expected.") + num = len(m) + _from = (FuncDecl * num)() + _to = (Ast * num)() + for i in range(num): + _from[i] = m[i][0].as_func_decl() + _to[i] = m[i][1].as_ast() + return _to_expr_ref(Z3_substitute_funs(t.ctx.ref(), t.as_ast(), num, _from, _to), t.ctx) + def Sum(*args): """Create the sum of the Z3 expressions. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index b8bca8fab..740e304ad 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5292,6 +5292,20 @@ extern "C" { unsigned num_exprs, Z3_ast const to[]); + /** + \brief Substitute funcions in \c from with new expressions in \c to. + + The expressions in \c to can have free variables. The free variable in \c to at index 0 + refers to the first argument of \c from, the free variable at index 1 corresponds to the second argument. + + def_API('Z3_substitute_funs', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, FUNC_DECL), _in_array(2, AST))) + */ + Z3_ast Z3_API Z3_substitute_funs(Z3_context c, + Z3_ast a, + unsigned num_funs, + Z3_func_decl const from[], + Z3_ast const to[]); + /** \brief Translate/Copy the AST \c a from context \c source to context \c target. AST \c a must have been created using context \c source. From e9cff33feb45db366cce824b96ad3ec1df0ea3f0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 May 2022 11:24:58 -0700 Subject: [PATCH 178/253] fix #5068 Signed-off-by: Nikolaj Bjorner --- src/sat/smt/sat_th.cpp | 3 ++- src/sat/smt/sat_th.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/sat_th.cpp b/src/sat/smt/sat_th.cpp index 2cbba7589..6167d3b9b 100644 --- a/src/sat/smt/sat_th.cpp +++ b/src/sat/smt/sat_th.cpp @@ -244,8 +244,9 @@ namespace euf { m_eqs = reinterpret_cast(base_ptr); for (i = 0; i < n_eqs; ++i) m_eqs[i] = eqs[i]; - base_ptr += sizeof(enode_pair) * n_eqs; + base_ptr += sizeof(enode_pair) * n_eqs; m_pragma = reinterpret_cast(base_ptr); + i = 0; if (pma) { std::string s = pma->to_string(); for (i = 0; s[i]; ++i) diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index 879049497..8e1ab571d 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -220,7 +220,7 @@ namespace euf { unsigned m_num_eqs; sat::literal* m_literals; enode_pair* m_eqs; - char* m_pragma; + char* m_pragma = nullptr; static size_t get_obj_size(unsigned num_lits, unsigned num_eqs, sat::proof_hint const* pma); th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& eq, sat::proof_hint const* pma = nullptr); static th_explain* mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, sat::proof_hint const* pma = nullptr); From a9d70fca1a0cdb073178521acea7200a9561f3ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 May 2022 19:09:10 -0700 Subject: [PATCH 179/253] fix #6061 Signed-off-by: Nikolaj Bjorner --- src/sat/smt/arith_solver.cpp | 4 ++-- src/smt/mam.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 6d93b3378..66a4c2a65 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -321,7 +321,7 @@ namespace arith { reset_evidence(); for (auto ev : e) set_evidence(ev.ci()); - auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, n1, n2); + auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, n1, n2); // TODO add equality explanation ctx.propagate(n1, n2, jst->to_index()); return true; } @@ -756,7 +756,7 @@ namespace arith { set_evidence(ci4); enode* x = var2enode(v1); enode* y = var2enode(v2); - auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, x, y); + auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, x, y); // TODO add equality explanation ctx.propagate(x, y, jst->to_index()); } diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index a90403626..3d880aa80 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -1952,7 +1952,7 @@ namespace { m_args[i] = m_registers[pc->m_iregs[i]]->get_root(); SASSERT(n != 0); do { - if (n->get_decl() == f) { + if (n->get_decl() == f && n->get_num_args() == num_args) { unsigned i = 0; for (; i < num_args; i++) { if (n->get_arg(i)->get_root() != m_args[i]) From aa8e89c5f3e4f2b24a2562d7553ff36110b6daf0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Jun 2022 19:11:17 -0700 Subject: [PATCH 180/253] try macos12 for arm64 Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index f8bb7e447..20ba54a99 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -27,7 +27,7 @@ stages: - job: MacArm64 displayName: "Mac ARM64 Build" pool: - vmImage: "macOS-latest" + vmImage: "macOS-12" steps: - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 --nojava - script: git clone https://github.com/z3prover/z3test z3test From 9ed7fd9454efde0735ec09378ebeb19286c2b64d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Jun 2022 19:17:27 -0700 Subject: [PATCH 181/253] Update nightly.yaml for Azure Pipelines --- scripts/nightly.yaml | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 20ba54a99..c60c92698 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -104,26 +104,27 @@ stages: artifactName: '$(name)Build' targetPath: $(Build.ArtifactStagingDirectory) - - job: MuslLinuxBuild - condition: eq(0,1) - variables: - python: "/opt/python/cp310-cp310/bin/python" - name: MuslLinux - displayName: "MuslLinux build" - pool: - vmImage: "Ubuntu-18.04" - container: "quay.io/pypa/musllinux_1_1_x86_64:latest" - steps: - - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava - - script: git clone https://github.com/z3prover/z3test z3test - - script: $(python) z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/ - - task: PublishPipelineArtifact@0 - inputs: - artifactName: '$(name)Build' - targetPath: $(Build.ArtifactStagingDirectory) +# - job: MuslLinuxBuild +# condition: eq(0,1) +# variables: +# python: "/opt/python/cp310-cp310/bin/python" +# name: MuslLinux +# displayName: "MuslLinux build" +# pool: +# vmImage: "Ubuntu-18.04" +# container: "quay.io/pypa/musllinux_1_1_x86_64:latest" +# steps: +# - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava +# - script: git clone https://github.com/z3prover/z3test z3test +# - script: $(python) z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 +# - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/ +# - task: PublishPipelineArtifact@0 +# inputs: +# artifactName: '$(name)Build' +# targetPath: $(Build.ArtifactStagingDirectory) -- job: Windows32 + + - job: Windows32 displayName: "Windows 32-bit build" pool: vmImage: "windows-latest" From b81b7710556af3ad2f46899801acf1817755419f Mon Sep 17 00:00:00 2001 From: Naveen <172697+naveensrinivasan@users.noreply.github.com> Date: Wed, 1 Jun 2022 22:02:30 -0500 Subject: [PATCH 182/253] chore: Included githubactions in the dependabot config (#6064) This should help with keeping the GitHub actions updated on new releases. This will also help with keeping it secure. Dependabot helps in keeping the supply chain secure https://docs.github.com/en/code-security/dependabot GitHub actions up to date https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot https://github.com/ossf/scorecard/blob/main/docs/checks.md#dependency-update-tool Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..5ace4600a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" From 8384c321fc2f62ae52146d0a53ca749de6e94a36 Mon Sep 17 00:00:00 2001 From: Naveen <172697+naveensrinivasan@users.noreply.github.com> Date: Wed, 1 Jun 2022 22:02:45 -0500 Subject: [PATCH 183/253] chore: Set permissions for GitHub actions (#6063) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restrict the GitHub token permissions only to the required ones; this way, even if the attackers will succeed in compromising your workflow, they won’t be able to do much. - Included permissions for the action. https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> --- .github/workflows/android-build.yml | 3 +++ .github/workflows/coverage.yml | 3 +++ .github/workflows/cross-build.yml | 3 +++ .github/workflows/docker-image.yml | 3 +++ .github/workflows/wip.yml | 3 +++ 5 files changed, 15 insertions(+) diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml index b3a17f301..57a1860f9 100644 --- a/.github/workflows/android-build.yml +++ b/.github/workflows/android-build.yml @@ -7,6 +7,9 @@ on: env: BUILD_TYPE: Release +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 75a866233..00ca4d3ae 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -6,6 +6,9 @@ on: schedule: - cron: "0 11 * * *" +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest diff --git a/.github/workflows/cross-build.yml b/.github/workflows/cross-build.yml index 5efd00329..5586f936a 100644 --- a/.github/workflows/cross-build.yml +++ b/.github/workflows/cross-build.yml @@ -4,6 +4,9 @@ on: push: pull_request: +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 843b1c75e..e2a1d2f1f 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -5,6 +5,9 @@ on: - cron: "0 1 * * 0" # every Sunday at 1 am workflow_dispatch: # on button click +permissions: + contents: read + jobs: push_to_registry: name: Push Docker image to GitHub Docker registry diff --git a/.github/workflows/wip.yml b/.github/workflows/wip.yml index e0129757b..81986ebc2 100644 --- a/.github/workflows/wip.yml +++ b/.github/workflows/wip.yml @@ -7,6 +7,9 @@ on: env: BUILD_TYPE: Debug +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest From 6396cfd6e7139f11a3f97fea2ad9aba113a5662e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Jun 2022 21:20:19 -0700 Subject: [PATCH 184/253] os Signed-off-by: Nikolaj Bjorner --- scripts/mk_unix_dist.py | 8 +++++++- scripts/nightly.yaml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 97de725e9..ca1d76975 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -28,6 +28,7 @@ JAVA_ENABLED=True GIT_HASH=False PYTHON_ENABLED=True MAKEJOBS=getenv("MAKEJOBS", '8') +OS_VERSION=None def set_verbose(flag): global VERBOSE @@ -58,13 +59,14 @@ def display_help(): print(" --dotnet-key= sign the .NET assembly with the private key in .") print(" --arch= set architecture (to arm64) to force arm64 build") print(" --nojava do not include Java bindings in the binary distribution files.") + print(" -os= set OS version.") print(" --nopython do not include Python bindings in the binary distribution files.") print(" --githash include git hash in the Zip file.") exit(0) # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, OS_VERSION path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', @@ -103,6 +105,8 @@ def parse_options(): mk_util.IS_ARCH_ARM64 = True else: raise MKException("Invalid architecture directive '%s'. Legal directives: arm64" % arg) + else if opt == '--os': + OS_VERSION = arg else: raise MKException("Invalid command line option '%s'" % opt) set_build_dir(path) @@ -154,6 +158,8 @@ def mk_z3(): return 1 def get_os_name(): + if OS_VERSION is not None: + return OS_VERSION import platform basic = os.uname()[0].lower() if basic == 'linux': diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index c60c92698..be071feb3 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -29,7 +29,7 @@ stages: pool: vmImage: "macOS-12" steps: - - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 --nojava + - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 --nojava --os=12.0 - script: git clone https://github.com/z3prover/z3test z3test - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@1 From 9190f22eb40407b86aa4eaf94adbce956939ed09 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Jun 2022 21:23:44 -0700 Subject: [PATCH 185/253] os Signed-off-by: Nikolaj Bjorner --- scripts/mk_unix_dist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index ca1d76975..301782ec8 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -105,7 +105,7 @@ def parse_options(): mk_util.IS_ARCH_ARM64 = True else: raise MKException("Invalid architecture directive '%s'. Legal directives: arm64" % arg) - else if opt == '--os': + elif opt == '--os': OS_VERSION = arg else: raise MKException("Invalid command line option '%s'" % opt) From b8367247f5fbf3e04e6aa47d95cfcf484d7b35f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jun 2022 09:14:08 +0100 Subject: [PATCH 186/253] Bump actions/checkout from 2 to 3 (#6066) --- .github/workflows/android-build.yml | 2 +- .github/workflows/coverage.yml | 2 +- .github/workflows/cross-build.yml | 2 +- .github/workflows/docker-image.yml | 2 +- .github/workflows/wasm-release.yml | 2 +- .github/workflows/wasm.yml | 2 +- .github/workflows/wip.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml index 57a1860f9..43b11d2fd 100644 --- a/.github/workflows/android-build.yml +++ b/.github/workflows/android-build.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Configure CMake and build run: | diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 00ca4d3ae..4325b8ada 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -21,7 +21,7 @@ jobs: COV_DETAILS_PATH: ${{github.workspace}}/cov-details steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup run: | diff --git a/.github/workflows/cross-build.yml b/.github/workflows/cross-build.yml index 5586f936a..83fae7a5d 100644 --- a/.github/workflows/cross-build.yml +++ b/.github/workflows/cross-build.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install cross build tools run: apt update && apt install -y ninja-build cmake python3 g++-11-${{ matrix.arch }}-linux-gnu diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index e2a1d2f1f..64ea7cfd5 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Check out the repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Log in to GitHub Docker registry uses: docker/login-action@v1 diff --git a/.github/workflows/wasm-release.yml b/.github/workflows/wasm-release.yml index 907246e8d..706ed32fb 100644 --- a/.github/workflows/wasm-release.yml +++ b/.github/workflows/wasm-release.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup node uses: actions/setup-node@v2 diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 6ad00cc47..756a8b64f 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup node uses: actions/setup-node@v2 diff --git a/.github/workflows/wip.yml b/.github/workflows/wip.yml index 81986ebc2..ffea6225c 100644 --- a/.github/workflows/wip.yml +++ b/.github/workflows/wip.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Configure CMake run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} From 05c1d6d5d1a08f5e39f6f347847fcab7aba73aea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jun 2022 09:16:02 +0100 Subject: [PATCH 187/253] Bump actions/upload-artifact from 2 to 3 (#6065) --- .github/workflows/android-build.yml | 2 +- .github/workflows/coverage.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml index 43b11d2fd..8bbfd5ab0 100644 --- a/.github/workflows/android-build.yml +++ b/.github/workflows/android-build.yml @@ -32,7 +32,7 @@ jobs: tar -cvf z3-build-${{ matrix.android-abi }}.tar *.jar *.so - name: Archive production artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: android-build-${{ matrix.android-abi }} path: build/z3-build-${{ matrix.android-abi }}.tar diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 4325b8ada..e46b96734 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -90,13 +90,13 @@ jobs: id: date run: echo "::set-output name=date::$(date +'%Y-%m-%d')" - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: coverage-${{steps.date.outputs.date}} path: ${{github.workspace}}/coverage.html retention-days: 4 - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: coverage-details-${{steps.date.outputs.date}} path: ${{env.COV_DETAILS_PATH}} From 96e317620c350e7ef3c6a47ecf3083729b1cf817 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jun 2022 09:56:41 +0100 Subject: [PATCH 188/253] Bump actions/setup-node from 2 to 3 (#6067) --- .github/workflows/wasm-release.yml | 2 +- .github/workflows/wasm.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wasm-release.yml b/.github/workflows/wasm-release.yml index 706ed32fb..1a77f9fe5 100644 --- a/.github/workflows/wasm-release.yml +++ b/.github/workflows/wasm-release.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v3 - name: Setup node - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: 'lts/*' registry-url: 'https://registry.npmjs.org' diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 756a8b64f..93ebb99fa 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v3 - name: Setup node - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: 'lts/*' From f54e8e55de0b2ee1cb398d64a41f1553ac0adf5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jun 2022 09:57:00 +0100 Subject: [PATCH 189/253] Bump docker/build-push-action from 2.7.0 to 3.0.0 (#6069) --- .github/workflows/docker-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 64ea7cfd5..ed30e1a9d 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -41,7 +41,7 @@ jobs: type=edge type=sha,prefix=ubuntu-20.04-bare-z3-sha- - name: Build and push Bare Z3 Docker Image - uses: docker/build-push-action@v2.7.0 + uses: docker/build-push-action@v3.0.0 with: context: . push: true From c05c75c1091c22b50a5099b522b41fd312608021 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jun 2022 09:57:17 +0100 Subject: [PATCH 190/253] Bump docker/login-action from 1 to 2 (#6068) --- .github/workflows/docker-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index ed30e1a9d..ec6559162 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v3 - name: Log in to GitHub Docker registry - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ secrets.DOCKER_USERNAME }} From 0b17a568ee4cc700b08a4a1123151a051db15a33 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Jun 2022 06:59:59 -0700 Subject: [PATCH 191/253] fixes to script Signed-off-by: Nikolaj Bjorner --- scripts/mk_unix_dist.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 301782ec8..72a7ba15f 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -59,7 +59,7 @@ def display_help(): print(" --dotnet-key= sign the .NET assembly with the private key in .") print(" --arch= set architecture (to arm64) to force arm64 build") print(" --nojava do not include Java bindings in the binary distribution files.") - print(" -os= set OS version.") + print(" --os= set OS version.") print(" --nopython do not include Python bindings in the binary distribution files.") print(" --githash include git hash in the Zip file.") exit(0) @@ -76,6 +76,7 @@ def parse_options(): 'nodotnet', 'dotnet-key=', 'arch=', + 'os=', 'githash', 'nopython' ]) From 4191d84e582108c32201fbf86fadc46e20b1100b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Jun 2022 07:12:45 -0700 Subject: [PATCH 192/253] change to 11.0 Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index be071feb3..b20db08b6 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -29,7 +29,7 @@ stages: pool: vmImage: "macOS-12" steps: - - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 --nojava --os=12.0 + - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 --nojava --os=11.0 - script: git clone https://github.com/z3prover/z3test z3test - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@1 From c7560e13941e4928bfa1a29040e3d46bfb26a1f7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Jun 2022 07:20:28 -0700 Subject: [PATCH 193/253] change to osx-11.0 Signed-off-by: Nikolaj Bjorner --- scripts/mk_unix_dist.py | 10 +++++----- scripts/nightly.yaml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 72a7ba15f..d152b3625 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -28,7 +28,7 @@ JAVA_ENABLED=True GIT_HASH=False PYTHON_ENABLED=True MAKEJOBS=getenv("MAKEJOBS", '8') -OS_VERSION=None +OS_NAME=None def set_verbose(flag): global VERBOSE @@ -66,7 +66,7 @@ def display_help(): # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, OS_VERSION + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, OS_NAME path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', @@ -107,7 +107,7 @@ def parse_options(): else: raise MKException("Invalid architecture directive '%s'. Legal directives: arm64" % arg) elif opt == '--os': - OS_VERSION = arg + OS_NAME = arg else: raise MKException("Invalid command line option '%s'" % opt) set_build_dir(path) @@ -159,8 +159,8 @@ def mk_z3(): return 1 def get_os_name(): - if OS_VERSION is not None: - return OS_VERSION + if OS_NAME is not None: + return OS_NAME import platform basic = os.uname()[0].lower() if basic == 'linux': diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index b20db08b6..6a91310ff 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -29,7 +29,7 @@ stages: pool: vmImage: "macOS-12" steps: - - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 --nojava --os=11.0 + - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 --nojava --os=osx-11.0 - script: git clone https://github.com/z3prover/z3test z3test - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@1 From 366860be4611e6ae09c23cfeed6f989b6c372b0d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Jun 2022 07:21:48 -0700 Subject: [PATCH 194/253] change to osx-11.0 Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 6a91310ff..0e49061aa 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -27,7 +27,7 @@ stages: - job: MacArm64 displayName: "Mac ARM64 Build" pool: - vmImage: "macOS-12" + vmImage: "macOS-latest" steps: - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 --nojava --os=osx-11.0 - script: git clone https://github.com/z3prover/z3test z3test From 93a0322cac64c7b26d1efd74037e50886c90628c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Jun 2022 11:48:12 -0700 Subject: [PATCH 195/253] update distribution scripts --- scripts/nightly.yaml | 2 +- scripts/release.yml | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 0e49061aa..e7ccb4731 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -29,7 +29,7 @@ stages: pool: vmImage: "macOS-latest" steps: - - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 --nojava --os=osx-11.0 + - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 --os=osx-11.0 - script: git clone https://github.com/z3prover/z3test z3test - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@1 diff --git a/scripts/release.yml b/scripts/release.yml index ab61bf8e7..20361e9ca 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -53,7 +53,7 @@ stages: inputs: scriptSource: 'filepath' scriptPath: scripts/mk_unix_dist.py - arguments: --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --nojava --arch=arm64 + arguments: --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --nojava --arch=arm64 --os=osx-11.0 - task: CopyFiles@2 inputs: sourceFolder: dist @@ -426,7 +426,8 @@ stages: artifact: 'WindowsBuild-x64' path: $(Agent.TempDirectory) - script: cd $(Agent.TempDirectory); mkdir osx-bin; cd osx-bin; unzip ../*osx*.zip - - script: cd $(Agent.TempDirectory); mkdir libc-bin; cd libc-bin; unzip ../*glibc*.zip + - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*arm64-osx*.zip + - script: cd $(Agent.TempDirectory); mkdir libc-bin; cd libc-bin; unzip ../*glibc*.zip - script: cd $(Agent.TempDirectory); mkdir musl-bin; cd musl-bin; unzip ../*-linux.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip @@ -434,6 +435,7 @@ stages: - script: cd src/api/python; python3 setup.py sdist # take a look at this PREMIUM HACK I came up with to get around the fact that the azure variable syntax overloads the bash syntax for subshells - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-arm64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/musl-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel From 3d1e03e00a46b5816342788f9871c86b11d4d384 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Jun 2022 09:11:02 -0700 Subject: [PATCH 196/253] add start of self-contained proof checker for arithmetic Signed-off-by: Nikolaj Bjorner --- src/sat/smt/arith_proof_checker.h | 289 ++++++++++++++++++++++++++++++ src/shell/drat_frontend.cpp | 92 +++------- 2 files changed, 311 insertions(+), 70 deletions(-) create mode 100644 src/sat/smt/arith_proof_checker.h diff --git a/src/sat/smt/arith_proof_checker.h b/src/sat/smt/arith_proof_checker.h new file mode 100644 index 000000000..b6721300a --- /dev/null +++ b/src/sat/smt/arith_proof_checker.h @@ -0,0 +1,289 @@ +/*++ +Copyright (c) 2020 Microsoft Corporation + +Module Name: + + arith_proof_checker.h + +Abstract: + + Plugin for checking arithmetic lemmas + +Author: + + Nikolaj Bjorner (nbjorner) 2020-09-08 + +--*/ +#pragma once + +#include "util/obj_pair_set.h" +#include "ast/ast_trail.h" +#include "ast/arith_decl_plugin.h" + + +namespace arith { + + class proof_checker { + struct row { + obj_map m_coeffs; + rational m_coeff; + void reset() { + m_coeffs.reset(); + m_coeff.reset(); + } + }; + + ast_manager& m; + arith_util a; + vector> m_todo; + bool m_strict = false; + row m_ineq; + row m_conseq; + vector m_eqs; + + void add(row& r, expr* v, rational const& coeff) { + rational coeff1; + if (coeff.is_zero()) + return; + if (r.m_coeffs.find(v, coeff1)) { + coeff1 += coeff; + if (coeff1.is_zero()) + r.m_coeffs.erase(v); + else + r.m_coeffs[v] = coeff1; + } + else + r.m_coeffs.insert(v, coeff); + } + + void mul(row& r, rational const& coeff) { + if (coeff == 1) + return; + for (auto & [v, c] : r.m_coeffs) + c *= coeff; + r.m_coeff *= coeff; + } + + // dst <- dst + mul*src + void add(row& dst, row const& src, rational const& mul) { + for (auto const& [v, c] : src.m_coeffs) + add(dst, v, c*mul); + dst.m_coeff += mul*src.m_coeff; + } + + // dst <- X*dst + Y*src + // where + // X = lcm(a,b)/b, Y = -lcm(a,b)/a if v is integer + // X = 1/b, Y = -1/a if v is real + // + void resolve(expr* v, row& dst, rational const& A, row const& src) { + rational B, x, y; + if (!dst.m_coeffs.find(v, B)) + return; + if (a.is_int(v)) { + rational lc = lcm(abs(A), abs(B)); + x = lc / abs(B); + y = lc / abs(A); + } + else { + x = rational(1) / abs(B); + y = rational(1) / abs(A); + } + if (A < 0 && B < 0) + y.neg(); + if (A > 0 && B > 0) + y.neg(); + mul(dst, x); + add(dst, src, y); + } + + /** + * \brief populate m_coeffs, m_coeff based on mul*e + */ + void linearize(row& r, rational const& mul, expr* e) { + SASSERT(m_todo.empty()); + m_todo.push_back({ mul, e }); + rational mul1; + expr* e1, *e2; + for (unsigned i = 0; i < m_todo.size(); ++i) { + auto [coeff, e] = m_todo[i]; + if (a.is_mul(e, e1, e2) && a.is_numeral(e1, mul1)) + m_todo.push_back({mul*mul1, e2}); + else if (a.is_mul(e, e1, e2) && a.is_numeral(e2, mul1)) + m_todo.push_back({mul*mul1, e1}); + else if (a.is_add(e)) + for (expr* arg : *to_app(e)) + m_todo.push_back({mul, arg}); + else if (a.is_uminus(e, e1)) + m_todo.push_back({-mul, e1}); + else if (a.is_sub(e, e1, e2)) { + m_todo.push_back({mul, e1}); + m_todo.push_back({-mul, e2}); + } + else if (a.is_numeral(e, mul1)) + r.m_coeff += mul*mul1; + else + add(r, e, mul); + } + } + + bool check_ineq(row& r) { + if (r.m_coeffs.empty() && r.m_coeff > 0) + return true; + if (r.m_coeffs.empty() && m_strict && r.m_coeff == 0) + return true; + return false; + } + + // triangulate equalities, substitute results into m_ineq, m_conseq. + void reduce_eq() { + for (unsigned i = 0; i < m_eqs.size(); ++i) { + auto& r = m_eqs[i]; + if (r.m_coeffs.empty()) + continue; + auto [v, coeff] = *r.m_coeffs.begin(); + for (unsigned j = i + 1; j < m_eqs.size(); ++j) + resolve(v, m_eqs[j], coeff, r); + resolve(v, m_ineq, coeff, r); + resolve(v, m_conseq, coeff, r); + } + } + + + bool add_literal(row& r, rational const& coeff, expr* e, bool sign) { + expr* e1, *e2 = nullptr; + if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && !sign) { + linearize(r, coeff, e1); + linearize(r, -coeff, e2); + } + else if ((a.is_lt(e, e1, e2) || a.is_lt(e, e2, e1)) && sign) { + linearize(r, coeff, e2); + linearize(r, -coeff, e1); + } + else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && sign) { + linearize(r, coeff, e2); + linearize(r, -coeff, e1); + if (a.is_int(e1)) + r.m_coeff += coeff; + else + m_strict = true; + } + else if ((a.is_lt(e, e1, e2) || a.is_lt(e, e2, e1)) && !sign) { + linearize(r, coeff, e1); + linearize(r, -coeff, e2); + if (a.is_int(e1)) + r.m_coeff += coeff; + else + m_strict = true; + } + else + return false; + return true; + } + + bool check_farkas() { + if (check_ineq(m_ineq)) + return true; + reduce_eq(); + if (check_ineq(m_ineq)) + return true; + + // convert to expression, maybe follows from a cut. + return false; + } + + // + // farkas coefficient is computed for m_conseq + // after all inequalities in ineq have been added up + // + bool check_bound() { + reduce_eq(); + if (check_ineq(m_conseq)) + return true; + if (m_ineq.m_coeffs.empty() || + m_conseq.m_coeffs.empty()) + return false; + auto const& [v, coeff1] = *m_ineq.m_coeffs.begin(); + rational coeff2; + if (!m_conseq.m_coeffs.find(v, coeff2)) + return false; + add(m_conseq, m_ineq, abs(coeff2/coeff1)); + if (check_ineq(m_conseq)) + return true; + return false; + } + + void display_row(std::ostream& out, row const& r) { + bool first = true; + for (auto const& [v, coeff] : r.m_coeffs) { + if (!first && coeff > 0) + out << " + "; + if (coeff != 1) + out << coeff << " * "; + out << mk_pp(v, m) << " "; + first = false; + } + if (r.m_coeff != 0) { + if (r.m_coeff > 0) + out << "+ "; + out << r.m_coeff; + } + } + + + void display_eq(std::ostream& out, row const& r) { + display_row(out, r); + out << " = 0\n"; + } + + void display_ineq(std::ostream& out, row const& r) { + display_row(out, r); + out << " <= 0\n"; + } + + + public: + proof_checker(ast_manager& m): m(m), a(m) {} + + void reset() { + m_ineq.reset(); + m_conseq.reset(); + m_eqs.reset(); + m_strict = false; + } + + bool add_ineq(rational const& coeff, expr* e, bool sign) { + return add_literal(m_ineq, coeff, e, sign); + } + + bool add_conseq(rational const& coeff, expr* e, bool sign) { + return add_literal(m_conseq, coeff, e, sign); + } + + void add_eq(expr* a, expr* b) { + m_eqs.push_back(row()); + row& r = m_eqs.back(); + linearize(r, rational(1), a); + linearize(r, rational(-1), b); + } + + bool check() { + if (!m_conseq.m_coeffs.empty()) + return check_bound(); + else + return check_farkas(); + } + + std::ostream& display(std::ostream& out) { + for (auto & r : m_eqs) + display_eq(out, r); + display_ineq(out, m_ineq); + if (!m_conseq.m_coeffs.empty()) + display_ineq(out, m_conseq); + return out; + } + + + }; + +} diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index 8bd629845..53260be54 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -17,6 +17,8 @@ Copyright (c) 2020 Microsoft Corporation #include "cmd_context/cmd_context.h" #include "ast/proofs/proof_checker.h" #include "ast/rewriter/th_rewriter.h" +#include "sat/smt/arith_proof_checker.h" + class smt_checker { ast_manager& m; @@ -162,92 +164,40 @@ public: bool validate_hint(expr_ref_vector const& exprs, sat::literal_vector const& lits, sat::proof_hint const& hint) { // return; // remove when testing this - proof_checker pc(m); arith_util autil(m); + arith::proof_checker achecker(m); switch (hint.m_ty) { case sat::hint_type::null_h: break; case sat::hint_type::cut_h: case sat::hint_type::bound_h: case sat::hint_type::farkas_h: { - expr_ref sum(m), last_sum(m); - bool is_strict = false; - vector coeffs; - rational lc(1); - for (auto const& [coeff, a, b]: hint.m_eqs) { - coeffs.push_back(coeff); - lc = lcm(lc, denominator(coeff)); - } - - for (auto const& [coeff, lit] : hint.m_literals) { - coeffs.push_back(coeff); - lc = lcm(lc, denominator(coeff)); - } - if (!lc.is_one()) - for (auto& coeff : coeffs) - coeff *= lc; - - unsigned i = 0; + achecker.reset(); for (auto const& [coeff, a, b]: hint.m_eqs) { expr* x = exprs[a]; expr* y = exprs[b]; - coeffs.push_back(coeff); - app_ref e(m.mk_eq(x, y), m); - if (!pc.check_arith_literal(true, e, coeffs[i], sum, is_strict)) { - std::cout << "p failed checking hint " << e << "\n"; - return false; - } - ++i; + achecker.add_eq(x, y); } - - for (auto const& [coeff, lit] : hint.m_literals) { - last_sum = sum; + unsigned sz = hint.m_literals.size(); + for (unsigned i = 0; i < sz; ++i) { + auto const& [coeff, lit] = hint.m_literals[i]; app_ref e(to_app(m_b2e[lit.var()]), m); - if (!pc.check_arith_literal(!lit.sign(), e, coeffs[i], sum, is_strict)) { - std::cout << "p failed checking hint " << e << "\n"; - return false; - } - ++i; - } - - if (!sum.get()) { - std::cout << "p no summation\n"; - return false; - } - - th_rewriter rw(m); - if (sat::hint_type::bound_h == hint.m_ty) { - rw(last_sum); - sum = last_sum; - auto const& [coeff, lit] = hint.m_literals.back(); - rational last_coeff = coeff, r; - expr* x, *y, *z; - if (autil.is_add(sum)) { - x = to_app(sum)->get_arg(1); - if (autil.is_mul(x, y, z) && autil.is_numeral(y, r)) { - last_coeff = r; + if (i + 1 == sz && sat::hint_type::bound_h == hint.m_ty) { + if (!achecker.add_conseq(coeff, e, lit.sign())) { + std::cout << "p failed checking hint " << e << "\n"; + return false; } + + } + else if (!achecker.add_ineq(coeff, e, lit.sign())) { + std::cout << "p failed checking hint " << e << "\n"; + return false; } - app_ref e(to_app(m_b2e[lit.var()]), m); - VERIFY(pc.check_arith_literal(!lit.sign(), e, last_coeff, sum, is_strict)); } - if (is_strict) - sum = autil.mk_lt(sum, autil.mk_numeral(rational(0), sum->get_sort())); - else - sum = autil.mk_le(sum, autil.mk_numeral(rational(0), sum->get_sort())); - - rw(sum); - if (!m.is_false(sum)) { - // check hint: - std::cout << "p hint not verified " << sum << "\n"; - auto const& [coeff, lit] = hint.m_literals.back(); - expr_ref sum1(m); - bool is_strict1 = false; - app_ref e(to_app(m_b2e[lit.var()]), m); - rational coeffb = coeffs.back(); - VERIFY(pc.check_arith_literal(!lit.sign(), e, coeffb, sum1, is_strict1)); - std::cout << last_sum << " => ~" << sum1 << "\n"; + bool ok = achecker.check(); + + if (!ok) { for (auto const& [coeff, a, b]: hint.m_eqs) { expr* x = exprs[a]; expr* y = exprs[b]; @@ -261,6 +211,8 @@ public: } return false; } + + std::cout << "p hint verified\n"; break; } From f652c57bfe3f0fb25d47b031027c84d055d1bc08 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Jun 2022 20:17:59 -0700 Subject: [PATCH 197/253] fix proof checker Signed-off-by: Nikolaj Bjorner --- src/sat/smt/arith_proof_checker.h | 61 ++++++++++++++++--------------- src/shell/drat_frontend.cpp | 24 ++++++++++++ 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/src/sat/smt/arith_proof_checker.h b/src/sat/smt/arith_proof_checker.h index b6721300a..e55f2635a 100644 --- a/src/sat/smt/arith_proof_checker.h +++ b/src/sat/smt/arith_proof_checker.h @@ -29,7 +29,7 @@ namespace arith { rational m_coeff; void reset() { m_coeffs.reset(); - m_coeff.reset(); + m_coeff = 0; } }; @@ -103,28 +103,29 @@ namespace arith { void linearize(row& r, rational const& mul, expr* e) { SASSERT(m_todo.empty()); m_todo.push_back({ mul, e }); - rational mul1; + rational coeff1; expr* e1, *e2; for (unsigned i = 0; i < m_todo.size(); ++i) { auto [coeff, e] = m_todo[i]; - if (a.is_mul(e, e1, e2) && a.is_numeral(e1, mul1)) - m_todo.push_back({mul*mul1, e2}); - else if (a.is_mul(e, e1, e2) && a.is_numeral(e2, mul1)) - m_todo.push_back({mul*mul1, e1}); + if (a.is_mul(e, e1, e2) && a.is_numeral(e1, coeff1)) + m_todo.push_back({coeff*coeff1, e2}); + else if (a.is_mul(e, e1, e2) && a.is_numeral(e2, coeff1)) + m_todo.push_back({coeff*coeff1, e1}); else if (a.is_add(e)) for (expr* arg : *to_app(e)) - m_todo.push_back({mul, arg}); + m_todo.push_back({coeff, arg}); else if (a.is_uminus(e, e1)) - m_todo.push_back({-mul, e1}); + m_todo.push_back({-coeff, e1}); else if (a.is_sub(e, e1, e2)) { - m_todo.push_back({mul, e1}); - m_todo.push_back({-mul, e2}); + m_todo.push_back({coeff, e1}); + m_todo.push_back({-coeff, e2}); } - else if (a.is_numeral(e, mul1)) - r.m_coeff += mul*mul1; + else if (a.is_numeral(e, coeff1)) + r.m_coeff += coeff*coeff1; else - add(r, e, mul); - } + add(r, e, coeff); + } + m_todo.reset(); } bool check_ineq(row& r) { @@ -154,11 +155,11 @@ namespace arith { expr* e1, *e2 = nullptr; if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && !sign) { linearize(r, coeff, e1); - linearize(r, -coeff, e2); + linearize(r, -coeff, e2); } - else if ((a.is_lt(e, e1, e2) || a.is_lt(e, e2, e1)) && sign) { + else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && sign) { linearize(r, coeff, e2); - linearize(r, -coeff, e1); + linearize(r, -coeff, e1); } else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && sign) { linearize(r, coeff, e2); @@ -168,7 +169,7 @@ namespace arith { else m_strict = true; } - else if ((a.is_lt(e, e1, e2) || a.is_lt(e, e2, e1)) && !sign) { + else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && !sign) { linearize(r, coeff, e1); linearize(r, -coeff, e2); if (a.is_int(e1)) @@ -178,6 +179,7 @@ namespace arith { } else return false; + // display_row(std::cout << coeff << " * " << (sign?"~":"") << mk_pp(e, m) << "\n", r) << "\n"; return true; } @@ -213,21 +215,19 @@ namespace arith { return false; } - void display_row(std::ostream& out, row const& r) { + std::ostream& display_row(std::ostream& out, row const& r) { bool first = true; for (auto const& [v, coeff] : r.m_coeffs) { - if (!first && coeff > 0) + if (!first) out << " + "; if (coeff != 1) out << coeff << " * "; - out << mk_pp(v, m) << " "; + out << mk_pp(v, m); first = false; } - if (r.m_coeff != 0) { - if (r.m_coeff > 0) - out << "+ "; - out << r.m_coeff; - } + if (r.m_coeff != 0) + out << " + " << r.m_coeff; + return out; } @@ -238,7 +238,10 @@ namespace arith { void display_ineq(std::ostream& out, row const& r) { display_row(out, r); - out << " <= 0\n"; + if (m_strict) + out << " < 0\n"; + else + out << " <= 0\n"; } @@ -253,11 +256,11 @@ namespace arith { } bool add_ineq(rational const& coeff, expr* e, bool sign) { - return add_literal(m_ineq, coeff, e, sign); + return add_literal(m_ineq, abs(coeff), e, sign); } bool add_conseq(rational const& coeff, expr* e, bool sign) { - return add_literal(m_conseq, coeff, e, sign); + return add_literal(m_conseq, abs(coeff), e, sign); } void add_eq(expr* a, expr* b) { diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index 53260be54..aad4ad2ba 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -166,6 +166,7 @@ public: // return; // remove when testing this arith_util autil(m); arith::proof_checker achecker(m); + proof_checker pc(m); switch (hint.m_ty) { case sat::hint_type::null_h: break; @@ -178,6 +179,7 @@ public: expr* y = exprs[b]; achecker.add_eq(x, y); } + unsigned sz = hint.m_literals.size(); for (unsigned i = 0; i < sz; ++i) { auto const& [coeff, lit] = hint.m_literals[i]; @@ -195,9 +197,29 @@ public: } } + // achecker.display(std::cout << "checking\n"); bool ok = achecker.check(); if (!ok) { + rational lc(1); + for (auto const& [coeff, lit] : hint.m_literals) + lc = lcm(lc, denominator(coeff)); + bool is_strict = false; + expr_ref sum(m); + for (auto const& [coeff, lit] : hint.m_literals) { + app_ref e(to_app(m_b2e[lit.var()]), m); + VERIFY(pc.check_arith_literal(!lit.sign(), e, coeff*lc, sum, is_strict)); + std::cout << "sum: " << sum << "\n"; + } + sort* s = sum->get_sort(); + if (is_strict) + sum = autil.mk_lt(sum, autil.mk_numeral(rational(0), s)); + else + sum = autil.mk_le(sum, autil.mk_numeral(rational(0), s)); + th_rewriter rw(m); + rw(sum); + std::cout << "sum: " << sum << "\n"; + for (auto const& [coeff, a, b]: hint.m_eqs) { expr* x = exprs[a]; expr* y = exprs[b]; @@ -209,6 +231,8 @@ public: if (lit.sign()) e = m.mk_not(e); std::cout << e << "\n"; } + achecker.display(std::cout); + std::cout << "p hint not verified\n"; return false; } From ed7db892f9835ffb405e877e2e8b6ca62098bde2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 4 Jun 2022 08:00:56 +0100 Subject: [PATCH 198/253] Fix a couple compiler warnings --- src/ast/ast_pp_util.h | 10 +-- src/opt/maxcore.cpp | 163 +++++++++++++++++++++--------------------- 2 files changed, 86 insertions(+), 87 deletions(-) diff --git a/src/ast/ast_pp_util.h b/src/ast/ast_pp_util.h index 1a04f8af0..06ade7eed 100644 --- a/src/ast/ast_pp_util.h +++ b/src/ast/ast_pp_util.h @@ -30,15 +30,15 @@ class ast_pp_util { stacked_value m_rec_decls; stacked_value m_decls; stacked_value m_sorts; - - public: + + public: decl_collector coll; - ast_pp_util(ast_manager& m): m(m), m_env(m), coll(m), m_rec_decls(0), m_decls(0), m_sorts(0) {} + ast_pp_util(ast_manager& m): m(m), m_env(m), m_rec_decls(0), m_decls(0), m_sorts(0), coll(m) {} void reset() { coll.reset(); m_removed.reset(); m_sorts.clear(0u); m_decls.clear(0u); m_rec_decls.clear(0u); } - + void collect(expr* e); @@ -59,7 +59,7 @@ class ast_pp_util { std::ostream& display_expr(std::ostream& out, expr* f, bool neat = true); void push(); - + void pop(unsigned n); smt2_pp_environment& env() { return m_env; } diff --git a/src/opt/maxcore.cpp b/src/opt/maxcore.cpp index 1a89129c5..46e4c5a7d 100644 --- a/src/opt/maxcore.cpp +++ b/src/opt/maxcore.cpp @@ -6,7 +6,7 @@ Module Name: maxcore.cpp Abstract: - + Core based (weighted) max-sat algorithms: - mu: max-sat algorithm by Nina and Bacchus, AAAI 2014. @@ -26,20 +26,20 @@ Abstract: the approach updates the upper bound if the current assignment improves the current best assignmet. Furthermore, take the soft constraints that are complements - to the current satisfying subset. - E.g, if F are the hard constraints and - s1,...,sn, t1,..., tm are the soft clauses and - F & s1 & ... & sn is satisfiable, then the complement + to the current satisfying subset. + E.g, if F are the hard constraints and + s1,...,sn, t1,..., tm are the soft clauses and + F & s1 & ... & sn is satisfiable, then the complement of of the current satisfying subset is t1, .., tm. Update the hard constraint: F := F & (t1 or ... or tm) Replace t1, .., tm by m-1 new soft clauses: t1 & t2, t3 & (t1 or t2), t4 & (t1 or t2 or t3), ..., tn & (t1 or ... t_{n-1}) - Claim: - If k of these soft clauses are satisfied, then k+1 of + Claim: + If k of these soft clauses are satisfied, then k+1 of the previous soft clauses are satisfied. - If k of these soft clauses are false in the satisfying assignment - for the updated F, then k of the original soft clauses are also false + If k of these soft clauses are false in the satisfying assignment + for the updated F, then k of the original soft clauses are also false under the assignment. In summary: any assignment to the new clauses that satsfies F has the same cost. @@ -78,7 +78,7 @@ public: s_primal, s_primal_dual, s_primal_binary, - s_rc2 + s_rc2 }; private: struct stats { @@ -103,14 +103,14 @@ private: stats m_stats; expr_ref_vector m_B; - expr_ref_vector m_asms; + expr_ref_vector m_asms; expr_ref_vector m_defs; obj_map m_asm2weight; expr_ref_vector m_new_core; mus m_mus; expr_ref_vector m_trail; strategy_t m_st; - rational m_max_upper; + rational m_max_upper; model_ref m_csmodel; lns_maxcore m_lnsctx; lns m_lns; @@ -160,16 +160,16 @@ public: default: UNREACHABLE(); break; - } + } } ~maxcore() override {} bool is_literal(expr* l) { - return + return is_uninterp_const(l) || (m.is_not(l, l) && is_uninterp_const(l)); - } + } void add(expr_ref_vector const& es) { for (expr* e : es) add(e); @@ -205,7 +205,7 @@ public: IF_VERBOSE(13, verbose_stream() << "new assumption " << mk_pp(e, m) << " " << w << "\n";); m_asm2weight.insert(e, w); m_asms.push_back(e); - m_trail.push_back(e); + m_trail.push_back(e); TRACE("opt", tout << "insert: " << mk_pp(e, m) << " : " << w << "\n"; tout << m_asms << " " << "\n"; ); } @@ -222,7 +222,7 @@ public: improve_model(); if (is_sat != l_true) return is_sat; while (m_lower < m_upper) { - TRACE("opt_verbose", + TRACE("opt_verbose", s().display(tout << m_asms << "\n") << "\n"; display(tout);); is_sat = check_sat_hill_climb(m_asms); @@ -230,8 +230,8 @@ public: return l_undef; } switch (is_sat) { - case l_true: - CTRACE("opt", m_model->is_false(m_asms), + case l_true: + CTRACE("opt", m_model->is_false(m_asms), tout << *m_model << "assumptions: "; for (expr* a : m_asms) tout << mk_pp(a, m) << " -> " << (*m_model)(a) << " "; tout << "\n";); @@ -244,7 +244,7 @@ public: m_lower = m_upper; } if (is_sat == l_undef) { - return is_sat; + return is_sat; } break; case l_undef: @@ -270,7 +270,7 @@ public: return l_undef; } switch (is_sat) { - case l_true: + case l_true: get_current_correction_set(cs); if (cs.empty()) { m_found_feasible_optimum = m_model.get() != nullptr; @@ -286,7 +286,7 @@ public: m_lower = m_upper; } if (is_sat == l_undef) { - return is_sat; + return is_sat; } break; case l_undef: @@ -307,7 +307,7 @@ public: /** Give preference to cores that have large minimal values. */ - sort_assumptions(asms); + sort_assumptions(asms); unsigned last_index = 0; unsigned index = 0; SASSERT(index < asms.size() || asms.empty()); @@ -318,16 +318,16 @@ public: } last_index = index; is_sat = check_sat(index, asms.data()); - } + } } else { - is_sat = check_sat(asms.size(), asms.data()); - } + is_sat = check_sat(asms.size(), asms.data()); + } return is_sat; } lbool check_sat(unsigned sz, expr* const* asms) { - lbool r = s().check_sat(sz, asms); + lbool r = s().check_sat(sz, asms); if (r == l_true) { model_ref mdl; s().get_model(mdl); @@ -399,7 +399,7 @@ public: return l_true; } - + // 1. remove all core literals from m_asms // 2. re-add literals of higher weight than min-weight. // 3. 'core' stores the core literals that are @@ -407,19 +407,19 @@ public: cores.push_back(weighted_core(core, core_weight(core))); remove_soft(core, m_asms); - split_core(core); + split_core(core); if (core.size() >= m_max_core_size) break; - is_sat = check_sat_hill_climb(m_asms); + is_sat = check_sat_hill_climb(m_asms); } - TRACE("opt", + TRACE("opt", tout << "sat: " << is_sat << " num cores: " << cores.size() << "\n"; for (auto const& c : cores) display_vec(tout, c.m_core); tout << "num assumptions: " << m_asms.size() << "\n";); - + return is_sat; } @@ -479,14 +479,14 @@ public: TRACE("opt", display_vec(tout << "corr_set: ", corr_set);); remove_soft(corr_set, m_asms); rational w = split_core(corr_set); - cs_max_resolve(corr_set, w); + cs_max_resolve(corr_set, w); IF_VERBOSE(2, verbose_stream() << "(opt.maxres.correction-set " << corr_set.size() << ")\n";); m_csmodel = nullptr; m_correction_set_size = 0; } lbool process_unsat() { - if (m_enable_core_rotate) + if (m_enable_core_rotate) return core_rotate(); vector cores; @@ -518,28 +518,28 @@ public: return l_true; } - + unsigned max_core_size(vector const& cores) { unsigned result = 0; - for (auto const& c : cores) + for (auto const& c : cores) result = std::max(c.size(), result); return result; } void process_unsat(vector const& cores) { - for (auto const & c : cores) + for (auto const & c : cores) process_unsat(c.m_core, c.m_weight); improve_model(m_model); } void update_model(expr* def, expr* value) { - SASSERT(is_uninterp_const(def)); - if (m_csmodel) + SASSERT(is_uninterp_const(def)); + if (m_csmodel) m_csmodel->register_decl(to_app(def)->get_decl(), (*m_csmodel)(value)); if (m_model) m_model->register_decl(to_app(def)->get_decl(), (*m_model)(value)); } - + void process_unsat(exprs const& core, rational w) { IF_VERBOSE(3, verbose_stream() << "(maxres cs model valid: " << (m_csmodel.get() != nullptr) << " cs size:" << m_correction_set_size << " core: " << core.size() << ")\n";); expr_ref fml(m); @@ -568,7 +568,7 @@ public: m_lower = std::min(m_lower, m_upper); } if (m_csmodel.get() && m_correction_set_size > 0) { - // this estimate can overshoot for weighted soft constraints. + // this estimate can overshoot for weighted soft constraints. --m_correction_set_size; } trace(); @@ -578,7 +578,7 @@ public: get_current_correction_set(m_csmodel.get(), cs); m_correction_set_size = cs.size(); TRACE("opt", tout << "cs " << m_correction_set_size << " " << core.size() << "\n";); - if (m_correction_set_size >= core.size()) + if (m_correction_set_size >= core.size()) return; rational w(0); for (expr* a : m_asms) { @@ -593,7 +593,7 @@ public: bool get_mus_model(model_ref& mdl) { rational w(0); if (m_c.sat_enabled()) { - // SAT solver core extracts some model + // SAT solver core extracts some model // during unsat core computation. mdl = nullptr; s().get_model(mdl); @@ -601,20 +601,20 @@ public: else { w = m_mus.get_best_model(mdl); } - if (mdl.get() && w < m_upper) + if (mdl.get() && w < m_upper) update_assignment(mdl); return nullptr != mdl.get(); } lbool minimize_core(expr_ref_vector& core) { - if (core.empty()) + if (core.empty()) return l_true; - if (m_c.sat_enabled()) + if (m_c.sat_enabled()) return l_true; m_mus.reset(); m_mus.add_soft(core.size(), core.data()); lbool is_sat = m_mus.get_mus(m_new_core); - if (is_sat != l_true) + if (is_sat != l_true) return is_sat; core.reset(); core.append(m_new_core); @@ -629,7 +629,7 @@ public: if (core.empty()) return rational(0); // find the minimal weight: rational w = get_weight(core[0]); - for (unsigned i = 1; i < core.size(); ++i) + for (unsigned i = 1; i < core.size(); ++i) w = std::min(w, get_weight(core[i])); return w; } @@ -643,7 +643,7 @@ public: rational w3 = w2 - w; new_assumption(e, w3); } - } + } return w; } @@ -663,7 +663,7 @@ public: } void display(std::ostream& out) { - for (expr * a : m_asms) + for (expr * a : m_asms) out << mk_pp(a, m) << " : " << get_weight(a) << "\n"; } @@ -677,15 +677,15 @@ public: // // d_0 := true // d_i := b_{i-1} and d_{i-1} for i = 1...sz-1 - // soft (b_i or !d_i) + // soft (b_i or !d_i) // == (b_i or !(!b_{i-1} or d_{i-1})) // == (b_i or b_0 & b_1 & ... & b_{i-1}) - // + // // Soft constraint is satisfied if previous soft constraint // holds or if it is the first soft constraint to fail. - // + // // Soundness of this rule can be established using MaxRes - // + // for (unsigned i = 1; i < core.size(); ++i) { expr* b_i = core[i-1]; expr* b_i1 = core[i]; @@ -761,7 +761,7 @@ public: bound_info(expr_ref_vector const& es, unsigned k, rational const& weight): es(es.size(), es.data()), k(k), weight(weight) {} }; - + obj_map m_at_mostk; obj_map m_bounds; rational m_unfold_upper; @@ -770,7 +770,7 @@ public: pb_util pb(m); expr_ref am(pb.mk_at_most_k(es, bound), m); expr* r = nullptr; - if (m_at_mostk.find(am, r)) + if (m_at_mostk.find(am, r)) return r; r = mk_fresh_bool("r"); m_trail.push_back(am); @@ -806,7 +806,7 @@ public: new_assumption(am, weight); } } - + // cs is a correction set (a complement of a (maximal) satisfying assignment). void cs_max_resolve(exprs const& cs, rational const& w) { @@ -820,7 +820,7 @@ public: // // d_0 := false // d_i := b_{i-1} or d_{i-1} for i = 1...sz-1 - // soft (b_i and d_i) + // soft (b_i and d_i) // == (b_i and (b_0 or b_1 or ... or b_{i-1})) // // asm => b_i @@ -836,7 +836,7 @@ public: fml = m.mk_implies(d, cls); update_model(d, cls); add(fml); - m_defs.push_back(fml); + m_defs.push_back(fml); } else { d = cls; @@ -869,7 +869,7 @@ public: void improve_model(model_ref& mdl) { - if (!m_enable_lns) + if (!m_enable_lns) return; flet _disable_lns(m_enable_lns, false); m_lns.climb(mdl); @@ -881,16 +881,16 @@ public: exprs _core(core.size(), core.data()); wcores.push_back(weighted_core(_core, core_weight(_core))); remove_soft(_core, m_asms); - split_core(_core); + split_core(_core); } process_unsat(wcores); } rational cost(model& mdl) { rational upper = m_unfold_upper; - for (soft& s : m_soft) - if (!mdl.is_true(s.s)) - upper += s.weight; + for (soft& s : m_soft) + if (!mdl.is_true(s.s)) + upper += s.weight; return upper; } @@ -898,8 +898,8 @@ public: improve_model(mdl); mdl->set_model_completion(true); unsigned correction_set_size = 0; - for (expr* a : m_asms) - if (mdl->is_false(a)) + for (expr* a : m_asms) + if (mdl->is_false(a)) ++correction_set_size; if (!m_csmodel.get() || correction_set_size < m_correction_set_size) { @@ -916,7 +916,7 @@ public: return; } - if (!m_c.verify_model(m_index, mdl.get(), upper)) + if (!m_c.verify_model(m_index, mdl.get(), upper)) return; unsigned num_assertions = s().get_num_assertions(); @@ -925,14 +925,14 @@ public: TRACE("opt", tout << "updated upper: " << upper << "\n";); - for (soft& s : m_soft) + for (soft& s : m_soft) s.set_value(m_model->is_true(s.s)); - + verify_assignment(); if (num_assertions == s().get_num_assertions()) m_upper = upper; - + trace(); add_upper_bound_block(); @@ -947,17 +947,17 @@ public: for (soft& s : m_soft) { nsoft.push_back(mk_not(m, s.s)); weights.push_back(s.weight); - } + } fml = u.mk_lt(nsoft.size(), weights.data(), nsoft.data(), m_upper); TRACE("opt", tout << "block upper bound " << fml << "\n";);; - add(fml); + add(fml); } void remove_soft(exprs const& core, expr_ref_vector& asms) { TRACE("opt", tout << "before remove: " << asms << "\n";); unsigned j = 0; - for (expr* a : asms) - if (!core.contains(a)) + for (expr* a : asms) + if (!core.contains(a)) asms[j++] = a; asms.shrink(j); TRACE("opt", tout << "after remove: " << asms << "\n";); @@ -974,8 +974,8 @@ public: m_pivot_on_cs = p.maxres_pivot_on_correction_set(); m_wmax = p.maxres_wmax(); m_dump_benchmarks = p.dump_benchmarks(); - m_enable_lns = p.enable_lns(); - m_enable_core_rotate = p.enable_core_rotate(); + m_enable_lns = p.enable_lns(); + m_enable_core_rotate = p.enable_core_rotate(); m_lns_conflicts = p.lns_conflicts(); if (m_c.num_objectives() > 1) m_add_upper_bound_block = false; @@ -983,7 +983,6 @@ public: lbool init_local() { m_trail.reset(); - lbool is_sat = l_true; for (auto const& [e, w, t] : m_soft) add_soft(e, w); m_max_upper = m_upper; @@ -1008,13 +1007,13 @@ public: void verify_core(exprs const& core) { return; - IF_VERBOSE(1, verbose_stream() << "verify core " << s().check_sat(core.size(), core.data()) << "\n";); + IF_VERBOSE(1, verbose_stream() << "verify core " << s().check_sat(core.size(), core.data()) << "\n";); ref _solver = mk_smt_solver(m, m_params, symbol()); _solver->assert_expr(s().get_assertions()); _solver->assert_expr(core); lbool is_sat = _solver->check_sat(0, nullptr); IF_VERBOSE(0, verbose_stream() << "core status (l_false:) " << is_sat << " core size " << core.size() << "\n"); - CTRACE("opt", is_sat != l_false, + CTRACE("opt", is_sat != l_false, for (expr* c : core) tout << "core: " << mk_pp(c, m) << "\n"; _solver->display(tout); tout << "other solver\n"; @@ -1025,18 +1024,18 @@ public: void verify_assumptions() { return; - IF_VERBOSE(1, verbose_stream() << "verify assumptions\n";); + IF_VERBOSE(1, verbose_stream() << "verify assumptions\n";); ref _solver = mk_smt_solver(m, m_params, symbol()); _solver->assert_expr(s().get_assertions()); _solver->assert_expr(m_asms); lbool is_sat = _solver->check_sat(0, nullptr); - IF_VERBOSE(1, verbose_stream() << "assignment status (l_true) " << is_sat << "\n";); + IF_VERBOSE(1, verbose_stream() << "assignment status (l_true) " << is_sat << "\n";); VERIFY(is_sat == l_true); } void verify_assignment() { return; - IF_VERBOSE(1, verbose_stream() << "verify assignment\n";); + IF_VERBOSE(1, verbose_stream() << "verify assignment\n";); ref _solver = mk_smt_solver(m, m_params, symbol()); _solver->assert_expr(s().get_assertions()); expr_ref n(m); From 33454193d40e1652499e9dfe5769c40e96bf2349 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 4 Jun 2022 08:45:52 +0100 Subject: [PATCH 199/253] Change FP default rounding mode in the Python API --- 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 99be0055e..899f9640a 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -9210,7 +9210,7 @@ def parse_smt2_file(f, sorts={}, decls={}, ctx=None): # Global default rounding mode -_dflt_rounding_mode = Z3_OP_FPA_RM_TOWARD_ZERO +_dflt_rounding_mode = Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN _dflt_fpsort_ebits = 11 _dflt_fpsort_sbits = 53 From 6422a6b5a774c48f3fe2ae9a732874af9e61ee68 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 4 Jun 2022 14:32:08 +0100 Subject: [PATCH 200/253] Fix rounding bug in to_fp (#6074) --- src/ast/fpa/fpa2bv_converter.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index e1439a316..0eb784e8c 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2667,7 +2667,8 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * unsigned sbits = m_util.get_sbits(s); if (m_bv_util.is_numeral(bv_rm) && m_util.au().is_numeral(x)) { - rational tmp_rat; unsigned sz; + rational tmp_rat; + unsigned sz; m_bv_util.is_numeral(to_expr(bv_rm), tmp_rat, sz); SASSERT(tmp_rat.is_int32()); SASSERT(sz == 3); @@ -2751,9 +2752,9 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * mk_bias(unbiased_exp, exp); v4 = m_util.mk_fp(sgn, exp, sig); - sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tp)) ? 1 : 0, 1); - sig = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); - unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tp), ebits); + sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tz)) ? 1 : 0, 1); + sig = m_bv_util.mk_numeral(m_util.fm().sig(v_tz), sbits - 1); + unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tz), ebits); mk_bias(unbiased_exp, exp); result = m_util.mk_fp(sgn, exp, sig); From d722c73d4c46aec029b12713959b3eb2a13fd169 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 4 Jun 2022 15:55:26 +0100 Subject: [PATCH 201/253] Fix corner case in MPF FMA (#6075) --- src/util/mpf.cpp | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index f1cf1d598..ebbf235fb 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -904,8 +904,6 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co SASSERT(m_mpz_manager.lt(res.significand(), m_powers2(2 * x.sbits + 1 + 3))); if (m_mpz_manager.ge(res.significand(), m_powers2(2 * x.sbits + 3))) { - SASSERT(exp(res) < mk_max_exp(x.ebits)); // NYI. - res.get().exponent++; renorm_sticky = !m_mpz_manager.is_even(res.significand()); m_mpz_manager.machine_div2k(res.significand(), 1); @@ -923,26 +921,32 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co TRACE("mpf_dbg", tout << "R*= " << to_string_binary(res, 2, 0) << " (renormalized, delta=" << renorm_delta << ")" << std::endl;); - set(o, x.ebits, x.sbits, res.sign(), res.exponent(), mpz(0)); + if (exp(res) <= mk_max_exp(x.ebits)) + { + set(o, x.ebits, x.sbits, res.sign(), res.exponent(), mpz(0)); - if (x.sbits >= 4) { - m_mpz_manager.machine_div_rem(res.significand(), m_powers2(x.sbits - 4 + 3), o.significand, sticky_rem); - renorm_sticky |= !m_mpz_manager.is_zero(sticky_rem); + if (x.sbits >= 4) { + m_mpz_manager.machine_div_rem(res.significand(), m_powers2(x.sbits - 4 + 3), o.significand, sticky_rem); + renorm_sticky |= !m_mpz_manager.is_zero(sticky_rem); + } + else { + m_mpz_manager.mul2k(res.significand(), 4 - x.sbits + 3, o.significand); + } + + if (renorm_sticky && m_mpz_manager.is_even(o.significand)) + m_mpz_manager.inc(o.significand); + + TRACE("mpf_dbg", tout << "sum[-1:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl; + tout << "R = " << to_string_binary(o, 1, 3) << std::endl;); + + if (m_mpz_manager.is_zero(o.significand)) + mk_zero(x.ebits, x.sbits, rm == MPF_ROUND_TOWARD_NEGATIVE, o); + else + round(rm, o); } else { - m_mpz_manager.mul2k(res.significand(), 4 - x.sbits + 3, o.significand); + mk_inf(x.ebits, x.sbits, res.sign(), o); } - - if (renorm_sticky && m_mpz_manager.is_even(o.significand)) - m_mpz_manager.inc(o.significand); - - TRACE("mpf_dbg", tout << "sum[-1:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl; - tout << "R = " << to_string_binary(o, 1, 3) << std::endl;); - - if (m_mpz_manager.is_zero(o.significand)) - mk_zero(x.ebits, x.sbits, rm == MPF_ROUND_TOWARD_NEGATIVE, o); - else - round(rm, o); } } From f77608ed884b8233dbba4e434e25845f3a042a9e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 4 Jun 2022 17:53:23 +0100 Subject: [PATCH 202/253] Add interpreted versions of unspecified cases of fp.to_ieee_bv and fp.to_real (#6077) --- src/ast/fpa/bv2fpa_converter.cpp | 20 ++++++++++++++++---- src/ast/fpa/fpa2bv_converter.cpp | 19 ++++++++++++++----- src/ast/fpa/fpa2bv_converter.h | 4 +++- src/ast/fpa/fpa2bv_rewriter.cpp | 18 ++++++++++-------- src/ast/fpa_decl_plugin.cpp | 10 ++++++++-- src/ast/fpa_decl_plugin.h | 4 ++++ src/ast/rewriter/fpa_rewriter.cpp | 2 ++ 7 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index 3da45781f..3611f848a 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -312,17 +312,29 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * } } + auto fid = m_fpa_util.get_family_id(); + expr_ref_vector dom(m); + for (unsigned i = 0; i < f->get_arity(); ++i) + dom.push_back(m.mk_var(i, f->get_domain(i))); + if (m_fpa_util.is_to_sbv(f) || m_fpa_util.is_to_ubv(f)) { - auto fid = m_fpa_util.get_family_id(); auto k = m_fpa_util.is_to_sbv(f) ? OP_FPA_TO_SBV_I : OP_FPA_TO_UBV_I; - expr_ref_vector dom(m); - for (unsigned i = 0; i < f->get_arity(); ++i) - dom.push_back(m.mk_var(i, f->get_domain(i))); parameter param = f->get_parameter(0); func_decl_ref to_bv_i(m.mk_func_decl(fid, k, 1, ¶m, dom.size(), dom.data()), m); expr_ref else_value(m.mk_app(to_bv_i, dom.size(), dom.data()), m); result->set_else(else_value); } + else if (m_fpa_util.is_to_real(f)) { + expr_ref_vector dom(m); + func_decl_ref to_real_i(m.mk_func_decl(fid, OP_FPA_TO_REAL_I, 0, NULL, dom.size(), dom.data()), m); + expr_ref else_value(m.mk_app(to_real_i, dom.size(), dom.data()), m); + result->set_else(else_value); + } + else if (m_fpa_util.is_to_ieee_bv(f)) { + func_decl_ref to_ieee_bv_i(m.mk_func_decl(fid, OP_FPA_TO_IEEE_BV_I, 0, NULL, dom.size(), dom.data()), m); + expr_ref else_value(m.mk_app(to_ieee_bv_i, dom.size(), dom.data()), m); + result->set_else(else_value); + } else if (bv_fi->get_else()) { expr_ref ft_els = rebuild_floats(mc, rng, bv_fi->get_else()); m_th_rw(ft_els); diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 0eb784e8c..64155d48b 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -52,7 +52,6 @@ fpa2bv_converter::~fpa2bv_converter() { void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { if (is_float(a) && is_float(b)) { - TRACE("fpa2bv", tout << "mk_eq a=" << mk_ismt2_pp(a, m) << std::endl; tout << "mk_eq b=" << mk_ismt2_pp(b, m) << std::endl;); @@ -98,12 +97,12 @@ void fpa2bv_converter::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) { expr* c2 = nullptr, *t2 = nullptr, *f2 = nullptr; if (m.is_ite(t, c2, t2, f2)) { mk_ite(c2, t2, f2, result); - mk_ite(c, result, f, result); + mk_ite(c, result, f, result); } else if (m.is_ite(f, c2, t2, f2)) { mk_ite(c2, t2, f2, result); - mk_ite(c, t, result, result); - } + mk_ite(c, t, result, result); + } else if (m_util.is_fp(t) && m_util.is_fp(f)) { expr_ref t_sgn(m), t_sig(m), t_exp(m); expr_ref f_sgn(m), f_sig(m), f_exp(m); @@ -3261,6 +3260,12 @@ void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, ex SASSERT(is_well_sorted(m, result)); } +void fpa2bv_converter::mk_to_ieee_bv_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) +{ + func_decl_ref fu(m.mk_func_decl(f->get_family_id(), OP_FPA_TO_IEEE_BV, 0, nullptr, num, args), m); + mk_to_bv(f, num, args, true, result); +} + void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result) { TRACE("fpa2bv_to_bv", for (unsigned i = 0; i < num; i++) tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); @@ -3491,6 +3496,11 @@ void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr } } +void fpa2bv_converter::mk_to_real_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + func_decl_ref fu(m.mk_func_decl(f->get_family_id(), OP_FPA_TO_REAL, 0, nullptr, num, args), m); + mk_to_real(f, num, args, result); +} + void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); SASSERT(m_bv_util.get_bv_size(args[0]) == 1); @@ -3500,7 +3510,6 @@ void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, e TRACE("fpa2bv_mk_fp", tout << "mk_fp result = " << mk_ismt2_pp(result, m) << std::endl;); } - void fpa2bv_converter::split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_ref & sig) const { expr* e_sgn = nullptr, *e_exp = nullptr, *e_sig = nullptr; VERIFY(m_util.is_fp(e, e_sgn, e_exp, e_sig)); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 471a7c6fc..d663fda95 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -136,6 +136,7 @@ public: void mk_to_fp_unsigned(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_to_ieee_bv_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result); void mk_to_fp_real_int(func_decl * f, unsigned num, expr * const * args, expr_ref & result); @@ -145,6 +146,7 @@ public: void mk_to_sbv_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_to_real_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void set_unspecified_fp_hi(bool v) { m_hi_fp_unspecified = v; } @@ -245,6 +247,6 @@ class fpa2bv_converter_wrapped : public fpa2bv_converter { expr* bv2rm_value(expr* b); expr* bv2fpa_value(sort* s, expr* a, expr* b = nullptr, expr* c = nullptr); - + }; diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 68a5cd784..88fde8b67 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -149,7 +149,9 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_TO_UBV_I: m_conv.mk_to_ubv_i(f, num, args, result); return BR_DONE; case OP_FPA_TO_SBV_I: m_conv.mk_to_sbv_i(f, num, args, result); return BR_DONE; case OP_FPA_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE; + case OP_FPA_TO_REAL_I: m_conv.mk_to_real_i(f, num, args, result); return BR_DONE; case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE; + case OP_FPA_TO_IEEE_BV_I: m_conv.mk_to_ieee_bv_i(f, num, args, result); return BR_DONE; case OP_FPA_BVWRAP: case OP_FPA_BV2RM: @@ -290,15 +292,15 @@ expr_ref fpa2bv_rewriter::convert_atom(th_rewriter& rw, expr * e) { expr_ref fpa2bv_rewriter::convert_term(th_rewriter& rw, expr * e) { SASSERT(fu().is_rm(e) || fu().is_float(e)); ast_manager& m = m_cfg.m(); - + expr_ref e_conv(m), res(m); proof_ref pr(m); - + (*this)(e, e_conv); - + TRACE("t_fpa_detail", tout << "term: " << mk_ismt2_pp(e, m) << std::endl; tout << "converted term: " << mk_ismt2_pp(e_conv, m) << std::endl;); - + if (fu().is_rm(e)) { SASSERT(fu().is_bv2rm(e_conv)); expr_ref bv_rm(m); @@ -316,7 +318,7 @@ expr_ref fpa2bv_rewriter::convert_term(th_rewriter& rw, expr * e) { } else UNREACHABLE(); - + return res; } @@ -333,7 +335,7 @@ expr_ref fpa2bv_rewriter::convert(th_rewriter& rw, expr * e) { ast_manager& m = m_cfg.m(); expr_ref res(m); TRACE("t_fpa", tout << "converting " << mk_ismt2_pp(e, m) << std::endl;); - + if (fu().is_fp(e)) res = e; else if (m.is_bool(e)) @@ -342,10 +344,10 @@ expr_ref fpa2bv_rewriter::convert(th_rewriter& rw, expr * e) { res = convert_term(rw, e); else res = convert_conversion_term(rw, e); - + TRACE("t_fpa_detail", tout << "converted; caching:" << std::endl; tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << mk_ismt2_pp(res, m) << std::endl;); - + return res; } diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 5062615f2..78d300ca7 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -784,12 +784,14 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_FPA_TO_SBV_I: return mk_to_sbv(k, num_parameters, parameters, arity, domain, range); case OP_FPA_TO_REAL: + case OP_FPA_TO_REAL_I: return mk_to_real(k, num_parameters, parameters, arity, domain, range); case OP_FPA_TO_FP: return mk_to_fp(k, num_parameters, parameters, arity, domain, range); case OP_FPA_TO_FP_UNSIGNED: return mk_to_fp_unsigned(k, num_parameters, parameters, arity, domain, range); case OP_FPA_TO_IEEE_BV: + case OP_FPA_TO_IEEE_BV_I: return mk_to_ieee_bv(k, num_parameters, parameters, arity, domain, range); case OP_FPA_BVWRAP: @@ -857,6 +859,7 @@ void fpa_decl_plugin::get_op_names(svector & op_names, symbol cons op_names.push_back(builtin_name("fp.to_ubv_I", OP_FPA_TO_UBV_I)); op_names.push_back(builtin_name("fp.to_sbv_I", OP_FPA_TO_SBV_I)); op_names.push_back(builtin_name("fp.to_real", OP_FPA_TO_REAL)); + op_names.push_back(builtin_name("fp.to_real_I", OP_FPA_TO_REAL_I)); op_names.push_back(builtin_name("to_fp", OP_FPA_TO_FP)); op_names.push_back(builtin_name("to_fp_unsigned", OP_FPA_TO_FP_UNSIGNED)); @@ -864,6 +867,7 @@ void fpa_decl_plugin::get_op_names(svector & op_names, symbol cons /* Extensions */ op_names.push_back(builtin_name("to_ieee_bv", OP_FPA_TO_IEEE_BV)); op_names.push_back(builtin_name("fp.to_ieee_bv", OP_FPA_TO_IEEE_BV)); + op_names.push_back(builtin_name("fp.to_ieee_bv_I", OP_FPA_TO_IEEE_BV_I)); } void fpa_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { @@ -1074,7 +1078,8 @@ bool fpa_util::is_considered_uninterpreted(func_decl * f, unsigned n, expr* cons if (f->get_family_id() != ffid) return false; - if (is_decl_of(f, ffid, OP_FPA_TO_IEEE_BV)) { + if (is_decl_of(f, ffid, OP_FPA_TO_IEEE_BV) || + is_decl_of(f, ffid, OP_FPA_TO_IEEE_BV_I)) { SASSERT(n == 1); expr* x = args[0]; return is_nan(x); @@ -1101,7 +1106,8 @@ bool fpa_util::is_considered_uninterpreted(func_decl * f, unsigned n, expr* cons else return mpqm.is_neg(r) || mpqm.bitsize(r) > bv_sz; } - else if (is_decl_of(f, ffid, OP_FPA_TO_REAL)) { + else if (is_decl_of(f, ffid, OP_FPA_TO_REAL) || + is_decl_of(f, ffid, OP_FPA_TO_REAL_I)) { SASSERT(n == 1); expr* x = args[0]; return is_nan(x) || is_inf(x); diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index ef0a1882c..0357efa47 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -83,12 +83,14 @@ enum fpa_op_kind { OP_FPA_TO_UBV, OP_FPA_TO_SBV, OP_FPA_TO_REAL, + OP_FPA_TO_REAL_I, OP_FPA_TO_SBV_I, OP_FPA_TO_UBV_I, /* Extensions */ OP_FPA_TO_IEEE_BV, + OP_FPA_TO_IEEE_BV_I, OP_FPA_BVWRAP, OP_FPA_BV2RM, @@ -353,11 +355,13 @@ public: bool is_bv2rm(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_BV2RM); } bool is_to_ubv(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_TO_UBV); } bool is_to_sbv(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_TO_SBV); } + bool is_to_real(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_TO_REAL); } bool is_bvwrap(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BVWRAP; } bool is_bv2rm(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BV2RM; } bool is_to_ubv(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_TO_UBV; } bool is_to_sbv(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_TO_SBV; } + bool is_to_real(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_TO_REAL; } bool is_to_ieee_bv(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_TO_IEEE_BV; } bool contains_floats(ast * a); diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index e135268d6..b7ba20ab7 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -93,7 +93,9 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con case OP_FPA_TO_UBV_I: SASSERT(num_args == 2); st = mk_to_ubv(f, args[0], args[1], result); break; case OP_FPA_TO_SBV_I: SASSERT(num_args == 2); st = mk_to_sbv(f, args[0], args[1], result); break; case OP_FPA_TO_IEEE_BV: SASSERT(num_args == 1); st = mk_to_ieee_bv(f, args[0], result); break; + case OP_FPA_TO_IEEE_BV_I: SASSERT(num_args == 1); st = mk_to_ieee_bv(f, args[0], result); break; case OP_FPA_TO_REAL: SASSERT(num_args == 1); st = mk_to_real(args[0], result); break; + case OP_FPA_TO_REAL_I: SASSERT(num_args == 1); st = mk_to_real(args[0], result); break; case OP_FPA_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break; case OP_FPA_BV2RM: SASSERT(num_args == 1); st = mk_bv2rm(args[0], result); break; From da9382956c0bd30703b63bf64879197feb9386e2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 May 2022 15:36:26 -0700 Subject: [PATCH 203/253] use common functionality --- src/cmd_context/cmd_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 303fcd00b..9bd6e6556 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -792,7 +792,7 @@ void cmd_context::init_manager_core(bool new_manager) { TRACE("cmd_context", tout << "init manager " << m_logic << "\n";); // add list type only if the logic is not specified. // it prevents clashes with builtin types. - insert(pm().mk_plist_decl()); + register_plist(); } if (m_solver_factory) { mk_solver(); From ea365de82085bc52a5bcfda5cd1dd20d59ada2bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 4 Jun 2022 11:59:00 -0700 Subject: [PATCH 204/253] add cut Signed-off-by: Nikolaj Bjorner --- src/sat/smt/arith_proof_checker.h | 26 ++++++++++++++++++++++++++ src/shell/drat_frontend.cpp | 13 +++++++------ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/sat/smt/arith_proof_checker.h b/src/sat/smt/arith_proof_checker.h index e55f2635a..755f9a3bd 100644 --- a/src/sat/smt/arith_proof_checker.h +++ b/src/sat/smt/arith_proof_checker.h @@ -96,6 +96,31 @@ namespace arith { mul(dst, x); add(dst, src, y); } + + void cut(row& r) { + if (r.m_coeffs.empty()) + return; + auto const& [v, coeff] = *r.m_coeffs.begin(); + if (!a.is_int(v)) + return; + rational lc = denominator(r.m_coeff); + for (auto const& [v, coeff] : r.m_coeffs) + lc = lcm(lc, denominator(coeff)); + if (lc != 1) { + r.m_coeff *= lc; + for (auto & [v, coeff] : r.m_coeffs) + coeff *= lc; + } + rational g(0); + for (auto const& [v, coeff] : r.m_coeffs) + g = gcd(coeff, g); + if (g == 1) + return; + rational m = mod(r.m_coeff, g); + if (m == 0) + return; + r.m_coeff += g - m; + } /** * \brief populate m_coeffs, m_coeff based on mul*e @@ -205,6 +230,7 @@ namespace arith { if (m_ineq.m_coeffs.empty() || m_conseq.m_coeffs.empty()) return false; + cut(m_ineq); auto const& [v, coeff1] = *m_ineq.m_coeffs.begin(); rational coeff2; if (!m_conseq.m_coeffs.find(v, coeff2)) diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index aad4ad2ba..1886c6dfc 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -151,13 +151,13 @@ public: m_input_solver = mk_smt_solver(m, m_params, symbol()); } - void add(sat::literal_vector const& lits, sat::status const& st) { + void add(sat::literal_vector const& lits, sat::status const& st, bool validated) { for (sat::literal lit : lits) while (lit.var() >= m_drat.get_solver().num_vars()) m_drat.get_solver().mk_var(true); if (st.is_input() && m_check_inputs) check_assertion_redundant(lits); - else if (!st.is_sat() && !st.is_deleted()) + else if (!st.is_sat() && !st.is_deleted() && !validated) check_clause(lits); // m_drat.add(lits, st); } @@ -184,7 +184,7 @@ public: for (unsigned i = 0; i < sz; ++i) { auto const& [coeff, lit] = hint.m_literals[i]; app_ref e(to_app(m_b2e[lit.var()]), m); - if (i + 1 == sz && sat::hint_type::bound_h == hint.m_ty) { + if (i + 1 == sz && (sat::hint_type::bound_h == hint.m_ty || sat::hint_type::cut_h == hint.m_ty)) { if (!achecker.add_conseq(coeff, e, lit.sign())) { std::cout << "p failed checking hint " << e << "\n"; return false; @@ -432,14 +432,15 @@ static void verify_smt(char const* drat_file, char const* smt_file) { std::cout << dimacs::drat_pp(r, write_theory); std::cout.flush(); switch (r.m_tag) { - case dimacs::drat_record::tag_t::is_clause: - checker.add(r.m_lits, r.m_status); - checker.validate_hint(exprs, r.m_lits, r.m_hint); + case dimacs::drat_record::tag_t::is_clause: { + bool validated = checker.validate_hint(exprs, r.m_lits, r.m_hint); + checker.add(r.m_lits, r.m_status, validated); if (drat_checker.inconsistent()) { std::cout << "inconsistent\n"; return; } break; + } case dimacs::drat_record::tag_t::is_node: { expr_ref e(m); args.reset(); From b629960afb41cd40dd59ab33207445015a89267d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Jun 2022 07:18:33 -0700 Subject: [PATCH 205/253] proof format Signed-off-by: Nikolaj Bjorner --- src/math/lp/explanation.h | 4 +- src/sat/sat_drat.cpp | 46 +++++++++++++-------- src/sat/sat_types.h | 11 ++--- src/sat/smt/arith_diagnostics.cpp | 68 ++++++++++++++++++------------- src/sat/smt/arith_proof_checker.h | 44 ++++++++++++++++++-- src/sat/smt/arith_solver.cpp | 8 ++-- src/sat/smt/arith_solver.h | 4 +- src/shell/drat_frontend.cpp | 21 +++++++--- 8 files changed, 144 insertions(+), 62 deletions(-) diff --git a/src/math/lp/explanation.h b/src/math/lp/explanation.h index 700a30acc..d2e7edc33 100644 --- a/src/math/lp/explanation.h +++ b/src/math/lp/explanation.h @@ -53,7 +53,8 @@ public: if (e.m_vector.empty()) { for (constraint_index j : e.m_set) push_back(j); - } else { + } + else { for (const auto & p : e.m_vector) { add_pair(p.first, p.second); } @@ -71,6 +72,7 @@ public: constraint_index ci() const { return m_var; } const mpq &coeff() const { return m_coeff; } }; + class iterator { bool m_run_on_vector; mpq m_one = one_of_type(); diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index e8594b048..12a0b2600 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -921,14 +921,19 @@ namespace sat { case hint_type::bound_h: ous << "bound "; break; - case hint_type::cut_h: - ous << "cut "; + case hint_type::implied_eq_h: + ous << "implied_eq "; + break; + default: + UNREACHABLE(); break; } for (auto const& [q, l] : m_literals) ous << rational(q) << " * " << l << " "; - for (auto const& [q, a, b] : m_eqs) - ous << rational(q) << " = " << a << " " << b << " "; + for (auto const& [a, b] : m_eqs) + ous << " = " << a << " " << b << " "; + for (auto const& [a, b] : m_diseqs) + ous << " != " << a << " " << b << " "; return ous.str(); } @@ -954,9 +959,9 @@ namespace sat { s += 5; return true; } - if (0 == strncmp(s, "cut", 3)) { - h.m_ty = hint_type::cut_h; - s += 3; + if (0 == strncmp(s, "implied_eq", 10)) { + h.m_ty = hint_type::implied_eq_h; + s += 10; return true; } return false; @@ -982,6 +987,24 @@ namespace sat { return sat::literal(r.get_unsigned(), false); }; auto parse_coeff_literal = [&]() { + if (*s == '=') { + ++s; + ws(); + unsigned a = parse_coeff().get_unsigned(); + ws(); + unsigned b = parse_coeff().get_unsigned(); + h.m_eqs.push_back(std::make_pair(a, b)); + return true; + } + if (*s == '!' && *(s + 1) == '=') { + s += 2; + ws(); + unsigned a = parse_coeff().get_unsigned(); + ws(); + unsigned b = parse_coeff().get_unsigned(); + h.m_diseqs.push_back(std::make_pair(a, b)); + return true; + } rational coeff = parse_coeff(); ws(); if (*s == '*') { @@ -991,15 +1014,6 @@ namespace sat { h.m_literals.push_back(std::make_pair(coeff, lit)); return true; } - if (*s == '=') { - ++s; - ws(); - unsigned a = parse_coeff().get_unsigned(); - ws(); - unsigned b = parse_coeff().get_unsigned(); - h.m_eqs.push_back(std::make_tuple(coeff, a, b)); - return true; - } return false; }; diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index bc7ea6ef9..fa42f0712 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -98,14 +98,15 @@ namespace sat { null_h, farkas_h, bound_h, - cut_h + implied_eq_h, }; struct proof_hint { - hint_type m_ty = hint_type::null_h; - vector> m_literals; - vector> m_eqs; - void reset() { m_ty = hint_type::null_h; m_literals.reset(); m_eqs.reset(); } + hint_type m_ty = hint_type::null_h; + vector> m_literals; + vector> m_eqs; + vector> m_diseqs; + void reset() { m_ty = hint_type::null_h; m_literals.reset(); m_eqs.reset(); m_diseqs.reset(); } std::string to_string() const; void from_string(char const* s); void from_string(std::string const& s) { from_string(s.c_str()); } diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index 3dd4f58de..1208dca11 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -80,6 +80,33 @@ namespace arith { if (m_nla) m_nla->collect_statistics(st); } + void solver::add_assumptions() { + m_arith_hint.reset(); + unsigned i = 0; + for (auto const & ev : m_explanation) { + ++i; + auto idx = ev.ci(); + if (UINT_MAX == idx) + continue; + switch (m_constraint_sources[idx]) { + case inequality_source: { + literal lit = m_inequalities[idx]; + m_arith_hint.m_literals.push_back({ev.coeff(), lit}); + break; + } + case equality_source: { + auto [u, v] = m_equalities[idx]; + ctx.drat_log_expr(u->get_expr()); + ctx.drat_log_expr(v->get_expr()); + m_arith_hint.m_eqs.push_back({u->get_expr_id(), v->get_expr_id()}); + break; + } + default: + break; + } + } + } + /** * It may be necessary to use the following assumption when checking Farkas claims * generated from bounds propagation: @@ -91,34 +118,19 @@ namespace arith { sat::proof_hint const* solver::explain(sat::hint_type ty, sat::literal lit) { if (!ctx.use_drat()) return nullptr; - m_bounds_pragma.m_ty = ty; - m_bounds_pragma.m_literals.reset(); - m_bounds_pragma.m_eqs.reset(); - unsigned i = 0; - for (auto const & ev : m_explanation) { - ++i; - auto idx = ev.ci(); - if (UINT_MAX == idx) - continue; - switch (m_constraint_sources[idx]) { - case inequality_source: { - literal lit = m_inequalities[idx]; - m_bounds_pragma.m_literals.push_back({ev.coeff(), lit}); - break; - } - case equality_source: { - auto [u, v] = m_equalities[idx]; - ctx.drat_log_expr(u->get_expr()); - ctx.drat_log_expr(v->get_expr()); - m_bounds_pragma.m_eqs.push_back({ev.coeff(), u->get_expr_id(), v->get_expr_id()}); - break; - } - default: - break; - } - } + m_arith_hint.m_ty = ty; + add_assumptions(); if (lit != sat::null_literal) - m_bounds_pragma.m_literals.push_back({rational(1), ~lit}); - return &m_bounds_pragma; + m_arith_hint.m_literals.push_back({rational(1), ~lit}); + return &m_arith_hint; + } + + sat::proof_hint const* solver::explain_implied_eq(euf::enode* a, euf::enode* b) { + if (!ctx.use_drat()) + return nullptr; + m_arith_hint.m_ty = sat::hint_type::implied_eq_h; + add_assumptions(); + m_arith_hint.m_diseqs.push_back({a->get_expr_id(), b->get_expr_id()}); + return &m_arith_hint; } } diff --git a/src/sat/smt/arith_proof_checker.h b/src/sat/smt/arith_proof_checker.h index 755f9a3bd..c37a4f7c2 100644 --- a/src/sat/smt/arith_proof_checker.h +++ b/src/sat/smt/arith_proof_checker.h @@ -40,6 +40,8 @@ namespace arith { row m_ineq; row m_conseq; vector m_eqs; + vector m_ineqs; + vector m_diseqs; void add(row& r, expr* v, rational const& coeff) { rational coeff1; @@ -241,6 +243,26 @@ namespace arith { return false; } + // + // checking disequalities is TBD. + // it has to select only a subset of bounds to justify each inequality. + // example + // c <= x <= c, c <= y <= c => x = y + // for the proof of x <= y use the inequalities x <= c <= y + // for the proof of y <= x use the inequalities y <= c <= x + // example + // x <= y, y <= z, z <= u, u <= x => x = z + // for the proof of x <= z use the inequalities x <= y, y <= z + // for the proof of z <= x use the inequalities z <= u, u <= x + // + // so when m_diseqs is non-empty we can't just add inequalities with Farkas coefficients + // into m_ineq, since coefficients of the usable subset vanish. + // + + bool check_diseq() { + return false; + } + std::ostream& display_row(std::ostream& out, row const& r) { bool first = true; for (auto const& [v, coeff] : r.m_coeffs) { @@ -270,6 +292,11 @@ namespace arith { out << " <= 0\n"; } + row& fresh(vector& rows) { + rows.push_back(row()); + return rows.back(); + } + public: proof_checker(ast_manager& m): m(m), a(m) {} @@ -278,10 +305,14 @@ namespace arith { m_ineq.reset(); m_conseq.reset(); m_eqs.reset(); + m_ineqs.reset(); + m_diseqs.reset(); m_strict = false; } bool add_ineq(rational const& coeff, expr* e, bool sign) { + if (!m_diseqs.empty()) + return add_literal(fresh(m_ineqs), abs(coeff), e, sign); return add_literal(m_ineq, abs(coeff), e, sign); } @@ -290,14 +321,21 @@ namespace arith { } void add_eq(expr* a, expr* b) { - m_eqs.push_back(row()); - row& r = m_eqs.back(); + row& r = fresh(m_eqs); linearize(r, rational(1), a); linearize(r, rational(-1), b); } + + void add_diseq(expr* a, expr* b) { + row& r = fresh(m_diseqs); + linearize(r, rational(1), a); + linearize(r, rational(-1), b); + } bool check() { - if (!m_conseq.m_coeffs.empty()) + if (!m_diseqs.empty()) + return check_diseq(); + else if (!m_conseq.m_coeffs.empty()) return check_bound(); else return check_farkas(); diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 66a4c2a65..fc3677cb9 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -321,7 +321,8 @@ namespace arith { reset_evidence(); for (auto ev : e) set_evidence(ev.ci()); - auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, n1, n2); // TODO add equality explanation + auto* ex = explain_implied_eq(n1, n2); + auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, n1, n2, ex); ctx.propagate(n1, n2, jst->to_index()); return true; } @@ -756,7 +757,8 @@ namespace arith { set_evidence(ci4); enode* x = var2enode(v1); enode* y = var2enode(v2); - auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, x, y); // TODO add equality explanation + auto* ex = explain_implied_eq(x, y); + auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, x, y, ex); ctx.propagate(x, y, jst->to_index()); } @@ -1176,7 +1178,7 @@ namespace arith { app_ref b = mk_bound(m_lia->get_term(), m_lia->get_offset(), !m_lia->is_upper()); IF_VERBOSE(4, verbose_stream() << "cut " << b << "\n"); literal lit = expr2literal(b); - assign(lit, m_core, m_eqs, explain(sat::hint_type::cut_h, lit)); + assign(lit, m_core, m_eqs, explain(sat::hint_type::bound_h, lit)); lia_check = l_false; break; } diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 8df8b7ec2..858d19ab8 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -419,9 +419,11 @@ namespace arith { void false_case_of_check_nla(const nla::lemma& l); void dbg_finalize_model(model& mdl); - sat::proof_hint m_bounds_pragma; + sat::proof_hint m_arith_hint; sat::proof_hint m_farkas2; sat::proof_hint const* explain(sat::hint_type ty, sat::literal lit = sat::null_literal); + sat::proof_hint const* explain_implied_eq(euf::enode* a, euf::enode* b); + void add_assumptions(); public: diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index 1886c6dfc..8c486cca8 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -170,21 +170,26 @@ public: switch (hint.m_ty) { case sat::hint_type::null_h: break; - case sat::hint_type::cut_h: case sat::hint_type::bound_h: - case sat::hint_type::farkas_h: { + case sat::hint_type::farkas_h: + case sat::hint_type::implied_eq_h: { achecker.reset(); - for (auto const& [coeff, a, b]: hint.m_eqs) { + for (auto const& [a, b]: hint.m_eqs) { expr* x = exprs[a]; expr* y = exprs[b]; achecker.add_eq(x, y); } + for (auto const& [a, b]: hint.m_diseqs) { + expr* x = exprs[a]; + expr* y = exprs[b]; + achecker.add_diseq(x, y); + } unsigned sz = hint.m_literals.size(); for (unsigned i = 0; i < sz; ++i) { auto const& [coeff, lit] = hint.m_literals[i]; app_ref e(to_app(m_b2e[lit.var()]), m); - if (i + 1 == sz && (sat::hint_type::bound_h == hint.m_ty || sat::hint_type::cut_h == hint.m_ty)) { + if (i + 1 == sz && sat::hint_type::bound_h == hint.m_ty) { if (!achecker.add_conseq(coeff, e, lit.sign())) { std::cout << "p failed checking hint " << e << "\n"; return false; @@ -220,12 +225,18 @@ public: rw(sum); std::cout << "sum: " << sum << "\n"; - for (auto const& [coeff, a, b]: hint.m_eqs) { + for (auto const& [a, b]: hint.m_eqs) { expr* x = exprs[a]; expr* y = exprs[b]; app_ref e(m.mk_eq(x, y), m); std::cout << e << "\n"; } + for (auto const& [a, b]: hint.m_diseqs) { + expr* x = exprs[a]; + expr* y = exprs[b]; + app_ref e(m.mk_not(m.mk_eq(x, y)), m); + std::cout << e << "\n"; + } for (auto const& [coeff, lit] : hint.m_literals) { app_ref e(to_app(m_b2e[lit.var()]), m); if (lit.sign()) e = m.mk_not(e); From dca1dcca6da50b721e789ce027cf30b78d4acddc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Jun 2022 08:42:47 -0700 Subject: [PATCH 206/253] ea Signed-off-by: Nikolaj Bjorner --- src/sat/smt/arith_diagnostics.cpp | 6 +++--- src/sat/smt/arith_solver.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index 1208dca11..4f016746c 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -80,7 +80,7 @@ namespace arith { if (m_nla) m_nla->collect_statistics(st); } - void solver::add_assumptions() { + void solver::explain_assumptions() { m_arith_hint.reset(); unsigned i = 0; for (auto const & ev : m_explanation) { @@ -119,7 +119,7 @@ namespace arith { if (!ctx.use_drat()) return nullptr; m_arith_hint.m_ty = ty; - add_assumptions(); + explain_assumptions(); if (lit != sat::null_literal) m_arith_hint.m_literals.push_back({rational(1), ~lit}); return &m_arith_hint; @@ -129,7 +129,7 @@ namespace arith { if (!ctx.use_drat()) return nullptr; m_arith_hint.m_ty = sat::hint_type::implied_eq_h; - add_assumptions(); + explain_assumptions(); m_arith_hint.m_diseqs.push_back({a->get_expr_id(), b->get_expr_id()}); return &m_arith_hint; } diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 858d19ab8..76bdeca9d 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -423,7 +423,7 @@ namespace arith { sat::proof_hint m_farkas2; sat::proof_hint const* explain(sat::hint_type ty, sat::literal lit = sat::null_literal); sat::proof_hint const* explain_implied_eq(euf::enode* a, euf::enode* b); - void add_assumptions(); + void explain_assumptions(); public: From bb6c274ad3c09b6c1a1a3ed1bc98ca49c85013d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Jun 2022 10:00:08 -0700 Subject: [PATCH 207/253] fix #6085 Signed-off-by: Nikolaj Bjorner --- src/util/mpz.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 159fc0ed8..c07235ab1 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -2248,7 +2248,7 @@ template unsigned mpz_manager::mlog2(mpz const & a) { if (is_nonneg(a)) return 0; - if (is_small(a)) + if (is_small(a) && a.m_val > INT_MIN) return ::log2((unsigned)-a.m_val); #ifndef _MP_GMP static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, ""); From cc045debac782019b8872a7dd3a82df17df468d6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Jun 2022 11:23:18 -0700 Subject: [PATCH 208/253] again --- src/util/mpz.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index c07235ab1..bdad1ddfe 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -2248,7 +2248,10 @@ template unsigned mpz_manager::mlog2(mpz const & a) { if (is_nonneg(a)) return 0; - if (is_small(a) && a.m_val > INT_MIN) + if (is_small(a) && a.m_val == INT_MIN) + return ::log2((unsigned)a.m_val); + + if (is_small(a)) return ::log2((unsigned)-a.m_val); #ifndef _MP_GMP static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, ""); From fe08c9976e9ed48d183bb54d0ef7e058ebc1d070 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Jun 2022 11:29:11 -0700 Subject: [PATCH 209/253] fix #6081 --- src/ast/ast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 332116d71..9112d6dae 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2412,7 +2412,7 @@ bool ast_manager::is_pattern(expr const * n, ptr_vector &args) { static void trace_quant(std::ostream& strm, quantifier* q) { strm << (is_lambda(q) ? "[mk-lambda]" : "[mk-quant]") - << " #" << q->get_id() << " " << q->get_qid() << " " << q->get_num_decls(); + << " #" << q->get_id() << " " << ensure_quote(q->get_qid()) << " " << q->get_num_decls(); for (unsigned i = 0; i < q->get_num_patterns(); ++i) { strm << " #" << q->get_pattern(i)->get_id(); } From 35986f3979405d2cbbcdee61598e01ad2a9644e8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Jun 2022 11:29:57 -0700 Subject: [PATCH 210/253] fix #6084 Signed-off-by: Nikolaj Bjorner --- src/math/polynomial/algebraic_numbers.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index 57ce00e2c..1a4769ac3 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -1466,7 +1466,10 @@ namespace algebraic_numbers { qm().add(il, nbv, il); qm().add(iu, nbv, iu); // (il, iu) is an isolating refinable (rational) interval for the new polynomial. - upm().convert_q2bq_interval(m_add_tmp.size(), m_add_tmp.data(), il, iu, bqm(), l, u); + if (!upm().convert_q2bq_interval(m_add_tmp.size(), m_add_tmp.data(), il, iu, bqm(), l, u)) { + TRACE("algebraic", tout << "conversion failed\n"); + } + } TRACE("algebraic", upm().display(tout, m_add_tmp.size(), m_add_tmp.data()); @@ -1576,7 +1579,9 @@ namespace algebraic_numbers { if (is_neg) qm().swap(il, iu); // (il, iu) is an isolating refinable (rational) interval for the new polynomial. - upm().convert_q2bq_interval(mulp.size(), mulp.data(), il, iu, bqm(), l, u); + if (!upm().convert_q2bq_interval(mulp.size(), mulp.data(), il, iu, bqm(), l, u)) { + TRACE("algebraic", tout << "conversion failed\n"); + } } TRACE("algebraic", upm().display(tout, mulp.size(), mulp.data()); @@ -1690,7 +1695,10 @@ namespace algebraic_numbers { qm().swap(inv_lower, inv_upper); TRACE("algebraic_bug", tout << "inv new_bounds: " << qm().to_string(inv_lower) << ", " << qm().to_string(inv_upper) << "\n";); // convert isolating interval back as a binary rational bound - upm().convert_q2bq_interval(cell_a->m_p_sz, cell_a->m_p, inv_lower, inv_upper, bqm(), lower(cell_a), upper(cell_a)); + if (!upm().convert_q2bq_interval(cell_a->m_p_sz, cell_a->m_p, inv_lower, inv_upper, bqm(), lower(cell_a), upper(cell_a))) { + TRACE("algebraic_bug", tout << "root isolation failed\n"); + throw algebraic_exception("inversion of algebraic number failed"); + } TRACE("algebraic_bug", tout << "after inv: "; display_root(tout, a); tout << "\n"; display_interval(tout, a); tout << "\n";); update_sign_lower(cell_a); SASSERT(acell_inv(*cell_a)); From a7b6f30b292d8583836ed13142663ec74ae6b4d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jun 2022 19:41:36 +0100 Subject: [PATCH 211/253] Bump docker/metadata-action from 3 to 4 (#6086) --- .github/workflows/docker-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index ec6559162..e7ca0f1b5 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -29,7 +29,7 @@ jobs: # ------- - name: Extract metadata (tags, labels) for Bare Z3 Docker Image id: meta - uses: docker/metadata-action@v3 + uses: docker/metadata-action@v4 with: images: ghcr.io/z3prover/z3 flavor: | From 0e6c64510ac3bd4392204a4da3921d4eb414820d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Jun 2022 13:14:36 -0700 Subject: [PATCH 212/253] display model in add/del format Signed-off-by: Nikolaj Bjorner --- src/tactic/model_converter.cpp | 41 ++++++++++++++++++++++------------ src/tactic/model_converter.h | 7 ++++-- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 6bb2f48c5..55b7b27b4 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -23,12 +23,16 @@ Notes: /* * Add or overwrite value in model. */ -void model_converter::display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const { +void model_converter::display_add(std::ostream& out, smt2_pp_environment& env, ast_manager& m, func_decl* f, expr* e) { VERIFY(e); - smt2_pp_environment_dbg env(m); - smt2_pp_environment* _env = m_env ? m_env : &env; VERIFY(f->get_range() == e->get_sort()); - ast_smt2_pp(out, f, e, *_env, params_ref(), 0, "model-add") << "\n"; + ast_smt2_pp(out, f, e, env, params_ref(), 0, "model-add") << "\n"; +} + +void model_converter::display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const { + smt2_pp_environment_dbg dbgenv(m); + smt2_pp_environment& env = m_env ? *m_env : dbgenv; + display_add(out, env, m, f, e); } /* @@ -57,14 +61,22 @@ void model_converter::display_add(std::ostream& out, ast_manager& m) { // default printer for converter that adds entries model_ref mdl = alloc(model, m); (*this)(mdl); - for (unsigned i = 0, sz = mdl->get_num_constants(); i < sz; ++i) { - func_decl* f = mdl->get_constant(i); - display_add(out, m, f, mdl->get_const_interp(f)); + smt2_pp_environment_dbg dbgenv(m); + smt2_pp_environment& env = m_env ? *m_env : dbgenv; + display_add(out, env, *mdl); +} + +void model_converter::display_add(std::ostream& out, smt2_pp_environment& env, model& mdl) { + + ast_manager& m = mdl.get_manager(); + for (unsigned i = 0, sz = mdl.get_num_constants(); i < sz; ++i) { + func_decl* f = mdl.get_constant(i); + display_add(out, env, m, f, mdl.get_const_interp(f)); } - for (unsigned i = 0, sz = mdl->get_num_functions(); i < sz; ++i) { - func_decl* f = mdl->get_function(i); - func_interp* fi = mdl->get_func_interp(f); - display_add(out, m, f, fi->get_interp()); + for (unsigned i = 0, sz = mdl.get_num_functions(); i < sz; ++i) { + func_decl* f = mdl.get_function(i); + func_interp* fi = mdl.get_func_interp(f); + display_add(out, env, m, f, fi->get_interp()); } } @@ -153,9 +165,10 @@ public: } void display(std::ostream & out) override { - out << "(rmodel->model-converter-wrapper\n"; - model_v2_pp(out, *m_model); - out << ")\n"; + ast_manager& m = m_model->get_manager(); + smt2_pp_environment_dbg dbgenv(m); + smt2_pp_environment& env = m_env ? *m_env : dbgenv; + model_converter::display_add(out, env, *m_model); } model_converter * translate(ast_translation & translator) override { diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index 3ed9f298b..377ecce67 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -64,11 +64,11 @@ class smt2_pp_environment; class model_converter : public converter { protected: - smt2_pp_environment* m_env; + smt2_pp_environment* m_env; + static void display_add(std::ostream& out, smt2_pp_environment& env, ast_manager& m, func_decl* f, expr* e); void display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const; void display_del(std::ostream& out, func_decl* f) const; void display_add(std::ostream& out, ast_manager& m); - public: model_converter(): m_env(nullptr) {} @@ -90,6 +90,9 @@ public: */ virtual void get_units(obj_map& fmls) { UNREACHABLE(); } + + static void display_add(std::ostream& out, smt2_pp_environment& env, model& mdl); + }; typedef ref model_converter_ref; From 51ed13f96ad17e9aba9f06f0029b37cb6a41bd83 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Jun 2022 06:28:24 -0700 Subject: [PATCH 213/253] update topological sort to use arrays instead of hash tables, expose Context over Z3Object for programmability Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Z3Object.cs | 2 +- src/ast/ast.cpp | 8 +-- src/ast/ast.h | 7 ++- src/ast/euf/euf_egraph.cpp | 6 +- src/ast/euf/euf_enode.h | 4 +- src/ast/static_features.h | 2 +- src/ast/substitution/substitution_tree.cpp | 35 ++++------- src/model/model.cpp | 2 +- src/qe/mbp/mbp_term_graph.cpp | 4 +- src/sat/smt/array_model.cpp | 2 +- src/sat/smt/euf_proof.cpp | 2 +- src/sat/smt/q_mam.cpp | 20 +++--- src/smt/mam.cpp | 20 +++--- src/smt/smt_context.h | 8 +-- src/smt/smt_enode.h | 2 +- src/smt/smt_internalizer.cpp | 4 +- src/util/top_sort.h | 71 +++++++++++++--------- 17 files changed, 103 insertions(+), 96 deletions(-) diff --git a/src/api/dotnet/Z3Object.cs b/src/api/dotnet/Z3Object.cs index d25dfc25a..d385d9d62 100644 --- a/src/api/dotnet/Z3Object.cs +++ b/src/api/dotnet/Z3Object.cs @@ -113,7 +113,7 @@ namespace Microsoft.Z3 return s.NativeObject; } - internal Context Context + public Context Context { get { diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 9112d6dae..56a98b051 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -498,9 +498,9 @@ bool compare_nodes(ast const * n1, ast const * n2) { template inline unsigned ast_array_hash(T * const * array, unsigned size, unsigned init_value) { - if (size == 0) - return init_value; switch (size) { + case 0: + return init_value; case 1: return combine_hash(array[0]->hash(), init_value); case 2: @@ -993,7 +993,7 @@ sort * basic_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, paramete } func_decl * basic_decl_plugin::mk_eq_decl_core(char const * name, decl_kind k, sort * s, ptr_vector & cache) { - unsigned id = s->get_decl_id(); + unsigned id = s->get_small_id(); force_ptr_array_size(cache, id + 1); if (cache[id] == 0) { sort * domain[2] = { s, s}; @@ -1009,7 +1009,7 @@ func_decl * basic_decl_plugin::mk_eq_decl_core(char const * name, decl_kind k, s } func_decl * basic_decl_plugin::mk_ite_decl(sort * s) { - unsigned id = s->get_decl_id(); + unsigned id = s->get_small_id(); force_ptr_array_size(m_ite_decls, id + 1); if (m_ite_decls[id] == 0) { sort * domain[3] = { m_bool_sort, s, s}; diff --git a/src/ast/ast.h b/src/ast/ast.h index 79a3cebc7..fe7586afa 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -572,7 +572,7 @@ protected: decl(ast_kind k, symbol const & name, decl_info * info):ast(k), m_name(name), m_info(info) {} public: - unsigned get_decl_id() const { SASSERT(get_id() >= c_first_decl_id); return get_id() - c_first_decl_id; } + unsigned get_small_id() const { SASSERT(get_id() >= c_first_decl_id); return get_id() - c_first_decl_id; } symbol const & get_name() const { return m_name; } decl_info * get_info() const { return m_info; } family_id get_family_id() const { return m_info == nullptr ? null_family_id : m_info->get_family_id(); } @@ -671,6 +671,9 @@ protected: public: sort* get_sort() const; + + unsigned get_small_id() const { return get_id(); } + }; // ----------------------------------- @@ -2573,7 +2576,7 @@ typedef ast_ref_fast_mark2 expr_ref_fast_mark2; when N is deleted. */ class ast_mark { - struct decl2uint { unsigned operator()(decl const & d) const { return d.get_decl_id(); } }; + struct decl2uint { unsigned operator()(decl const & d) const { return d.get_small_id(); } }; obj_mark m_expr_marks; obj_mark m_decl_marks; public: diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 5d0bd4b17..3820d2592 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -30,7 +30,7 @@ namespace euf { m_nodes.push_back(n); m_exprs.push_back(f); if (is_app(f) && num_args > 0) { - unsigned id = to_app(f)->get_decl()->get_decl_id(); + unsigned id = to_app(f)->get_decl()->get_small_id(); m_decl2enodes.reserve(id+1); m_decl2enodes[id].push_back(n); } @@ -60,7 +60,7 @@ namespace euf { enode_vector const& egraph::enodes_of(func_decl* f) { - unsigned id = f->get_decl_id(); + unsigned id = f->get_small_id(); if (id < m_decl2enodes.size()) return m_decl2enodes[id]; return m_empty_enodes; @@ -341,7 +341,7 @@ namespace euf { m_expr2enode[e->get_id()] = nullptr; n->~enode(); if (is_app(e) && n->num_args() > 0) - m_decl2enodes[to_app(e)->get_decl()->get_decl_id()].pop_back(); + m_decl2enodes[to_app(e)->get_decl()->get_small_id()].pop_back(); m_nodes.pop_back(); m_exprs.pop_back(); }; diff --git a/src/ast/euf/euf_enode.h b/src/ast/euf/euf_enode.h index 7014223be..18a1a86af 100644 --- a/src/ast/euf/euf_enode.h +++ b/src/ast/euf/euf_enode.h @@ -162,7 +162,7 @@ namespace euf { bool merge_tf() const { return merge_enabled() && (class_size() > 1 || num_parents() > 0 || num_args() > 0); } enode* get_arg(unsigned i) const { SASSERT(i < num_args()); return m_args[i]; } - unsigned hash() const { return m_expr->hash(); } + unsigned hash() const { return m_expr->get_id(); } unsigned get_table_id() const { return m_table_id; } void set_table_id(unsigned t) { m_table_id = t; } @@ -204,6 +204,8 @@ namespace euf { app* get_app() const { return to_app(m_expr); } func_decl* get_decl() const { return is_app(m_expr) ? to_app(m_expr)->get_decl() : nullptr; } unsigned get_expr_id() const { return m_expr->get_id(); } + unsigned get_id() const { return m_expr->get_id(); } + unsigned get_small_id() const { return m_expr->get_small_id(); } unsigned get_root_id() const { return m_root->m_expr->get_id(); } bool children_are_roots() const; enode* get_next() const { return m_next; } diff --git a/src/ast/static_features.h b/src/ast/static_features.h index 40532f939..88e7934d4 100644 --- a/src/ast/static_features.h +++ b/src/ast/static_features.h @@ -162,7 +162,7 @@ struct static_features { bool arith_k_sum_is_small() const { return m_arith_k_sum < rational(INT_MAX / 8); } - void inc_num_apps(func_decl const * d) { unsigned id = d->get_decl_id(); m_num_apps.reserve(id+1, 0); m_num_apps[id]++; } + void inc_num_apps(func_decl const * d) { unsigned id = d->get_small_id(); m_num_apps.reserve(id+1, 0); m_num_apps[id]++; } void inc_theory_terms(family_id fid) { m_num_theory_terms.reserve(fid+1, 0); m_num_theory_terms[fid]++; } void inc_theory_atoms(family_id fid) { m_num_theory_atoms.reserve(fid+1, 0); m_num_theory_atoms[fid]++; } void inc_theory_constants(family_id fid) { m_num_theory_constants.reserve(fid+1, 0); m_num_theory_constants[fid]++; } diff --git a/src/ast/substitution/substitution_tree.cpp b/src/ast/substitution/substitution_tree.cpp index c0c3e5205..af2ca1039 100644 --- a/src/ast/substitution/substitution_tree.cpp +++ b/src/ast/substitution/substitution_tree.cpp @@ -137,10 +137,7 @@ void substitution_tree::reset_registers(unsigned old_size) { unsigned substitution_tree::get_compatibility_measure(svector const & sv) { unsigned old_size = m_todo.size(); unsigned measure = 0; - svector::const_iterator it = sv.begin(); - svector::const_iterator end = sv.end(); - for (; it != end; ++it) { - subst const & s = *it; + for (subst const& s : sv) { unsigned ireg = s.first->get_idx(); expr * out = s.second; expr * in = get_reg_value(ireg); @@ -254,7 +251,7 @@ void substitution_tree::insert(expr * new_expr) { else { SASSERT(is_var(new_expr)); sort * s = to_var(new_expr)->get_sort(); - unsigned id = s->get_decl_id(); + unsigned id = s->get_small_id(); if (id >= m_vars.size()) m_vars.resize(id+1); if (m_vars[id] == 0) @@ -274,7 +271,7 @@ void substitution_tree::insert(app * new_expr) { m_todo.push_back(0); func_decl * d = new_expr->get_decl(); - unsigned id = d->get_decl_id(); + unsigned id = d->get_small_id(); if (id >= m_roots.size()) m_roots.resize(id+1); @@ -439,7 +436,7 @@ void substitution_tree::erase(expr * e) { else { SASSERT(is_var(e)); sort * s = to_var(e)->get_sort(); - unsigned id = s->get_decl_id(); + unsigned id = s->get_small_id(); if (id >= m_vars.size() || m_vars[id] == 0) return; var_ref_vector * v = m_vars[id]; @@ -453,7 +450,7 @@ void substitution_tree::erase(expr * e) { */ void substitution_tree::erase(app * e) { func_decl * d = e->get_decl(); - unsigned id = d->get_decl_id(); + unsigned id = d->get_small_id(); if (id >= m_roots.size() || !m_roots[id]) return; @@ -732,7 +729,7 @@ bool substitution_tree::visit_vars(expr * e, st_visitor & st) { if (m_vars.empty()) return true; // continue sort * s = e->get_sort(); - unsigned s_id = s->get_decl_id(); + unsigned s_id = s->get_small_id(); if (s_id < m_vars.size()) { var_ref_vector * v = m_vars[s_id]; if (v && !v->empty()) { @@ -832,17 +829,14 @@ void substitution_tree::visit(expr * e, st_visitor & st, unsigned in_offset, uns if (visit_vars(e, st)) { if (is_app(e)) { func_decl * d = to_app(e)->get_decl(); - unsigned id = d->get_decl_id(); + unsigned id = d->get_small_id(); node * r = m_roots.get(id, 0); if (r) visit(e, st, r); } else { SASSERT(is_var(e)); - ptr_vector::iterator it = m_roots.begin(); - ptr_vector::iterator end = m_roots.end(); - for (; it != end; ++it) { - node * r = *it; + for (node* r : m_roots) { if (r != nullptr) { var * v = r->m_subst[0].first; if (v->get_sort() == to_var(e)->get_sort()) @@ -868,16 +862,11 @@ void substitution_tree::gen(expr * e, st_visitor & v, unsigned in_offset, unsign void substitution_tree::display(std::ostream & out) const { out << "substitution tree:\n"; - ptr_vector::const_iterator it = m_roots.begin(); - ptr_vector::const_iterator end = m_roots.end(); - for (; it != end; ++it) - if (*it) - display(out, *it, 0); + for (node* n : m_roots) + if (n) + display(out, n, 0); bool found_var = false; - ptr_vector::const_iterator it2 = m_vars.begin(); - ptr_vector::const_iterator end2 = m_vars.end(); - for (; it2 != end2; ++it2) { - var_ref_vector * v = *it2; + for (var_ref_vector* v : m_vars) { if (v == nullptr) continue; // m_vars may contain null pointers. See substitution_tree::insert. unsigned num = v->size(); diff --git a/src/model/model.cpp b/src/model/model.cpp index 21938766b..dfa76db68 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -476,7 +476,7 @@ expr_ref model::cleanup_expr(top_sort& ts, expr* e, unsigned current_partition, // noop } else if (f->is_skolem() && can_inline_def(ts, f, force_inline) && (fi = get_func_interp(f)) && - fi->get_interp() && (!ts.partition_ids().find(f, pid) || pid != current_partition)) { + fi->get_interp() && (!ts.find(f, pid) || pid != current_partition)) { var_subst vs(m, false); new_t = vs(fi->get_interp(), args.size(), args.data()); } diff --git a/src/qe/mbp/mbp_term_graph.cpp b/src/qe/mbp/mbp_term_graph.cpp index 52d633417..76b6a2b31 100644 --- a/src/qe/mbp/mbp_term_graph.cpp +++ b/src/qe/mbp/mbp_term_graph.cpp @@ -755,7 +755,7 @@ namespace mbp { app* a = to_app(e); func_decl* d = a->get_decl(); if (d->get_arity() == 0) continue; - unsigned id = d->get_decl_id(); + unsigned id = d->get_small_id(); m_decl2terms.reserve(id+1); if (m_decl2terms[id].empty()) m_decls.push_back(d); m_decl2terms[id].push_back(t); @@ -770,7 +770,7 @@ namespace mbp { // are distinct. // for (func_decl* d : m_decls) { - unsigned id = d->get_decl_id(); + unsigned id = d->get_small_id(); ptr_vector const& terms = m_decl2terms[id]; if (terms.size() <= 1) continue; unsigned arity = d->get_arity(); diff --git a/src/sat/smt/array_model.cpp b/src/sat/smt/array_model.cpp index c437629f5..8b56ff3ae 100644 --- a/src/sat/smt/array_model.cpp +++ b/src/sat/smt/array_model.cpp @@ -54,7 +54,7 @@ namespace array { euf::enode* d = get_default(v); if (d) dep.add(n, d); - if (!dep.deps().contains(n)) + if (!dep.contains_dep(n)) dep.insert(n, nullptr); return true; } diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 8e5eb9dd7..c072022df 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -104,7 +104,7 @@ namespace euf { std::ostringstream strm; smt2_pp_environment_dbg env(m); ast_smt2_pp(strm, f, env); - get_drat().def_begin('f', f->get_decl_id(), strm.str()); + get_drat().def_begin('f', f->get_small_id(), strm.str()); get_drat().def_end(); } diff --git a/src/sat/smt/q_mam.cpp b/src/sat/smt/q_mam.cpp index d860b3c3c..4be554633 100644 --- a/src/sat/smt/q_mam.cpp +++ b/src/sat/smt/q_mam.cpp @@ -104,7 +104,7 @@ namespace q { public: unsigned char operator()(func_decl * lbl) { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); if (lbl_id >= m_lbl2hash.size()) m_lbl2hash.resize(lbl_id + 1, -1); if (m_lbl2hash[lbl_id] == -1) { @@ -2868,7 +2868,7 @@ namespace q { SASSERT(first_idx < mp->get_num_args()); app * p = to_app(mp->get_arg(first_idx)); func_decl * lbl = p->get_decl(); - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); m_trees.reserve(lbl_id+1, nullptr); if (m_trees[lbl_id] == nullptr) { m_trees[lbl_id] = m_compiler.mk_tree(qa, mp, first_idx, false); @@ -2898,7 +2898,7 @@ namespace q { } code_tree * get_code_tree_for(func_decl * lbl) const { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); if (lbl_id < m_trees.size()) return m_trees[lbl_id]; else @@ -3112,11 +3112,11 @@ namespace q { } bool is_plbl(func_decl * lbl) const { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); return lbl_id < m_is_plbl.size() && m_is_plbl[lbl_id]; } bool is_clbl(func_decl * lbl) const { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); return lbl_id < m_is_clbl.size() && m_is_clbl[lbl_id]; } @@ -3129,7 +3129,7 @@ namespace q { } void update_clbls(func_decl * lbl) { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); m_is_clbl.reserve(lbl_id+1, false); TRACE("trigger_bug", tout << "update_clbls: " << lbl->get_name() << " is already clbl: " << m_is_clbl[lbl_id] << "\n";); TRACE("mam_bug", tout << "update_clbls: " << lbl->get_name() << " is already clbl: " << m_is_clbl[lbl_id] << "\n";); @@ -3169,7 +3169,7 @@ namespace q { } void update_plbls(func_decl * lbl) { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); m_is_plbl.reserve(lbl_id+1, false); TRACE("trigger_bug", tout << "update_plbls: " << lbl->get_name() << " is already plbl: " << m_is_plbl[lbl_id] << ", lbl_id: " << lbl_id << "\n"; tout << "mam: " << this << "\n";); @@ -3698,7 +3698,7 @@ namespace q { app * p = to_app(mp->get_arg(0)); func_decl * lbl = p->get_decl(); if (!m_egraph.enodes_of(lbl).empty()) { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); m_tmp_trees.reserve(lbl_id+1, 0); if (m_tmp_trees[lbl_id] == 0) { m_tmp_trees[lbl_id] = m_compiler.mk_tree(qa, mp, 0, false); @@ -3711,7 +3711,7 @@ namespace q { } for (func_decl * lbl : m_tmp_trees_to_delete) { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); code_tree * tmp_tree = m_tmp_trees[lbl_id]; SASSERT(tmp_tree != 0); SASSERT(!m_egraph.enodes_of(lbl).empty()); @@ -3843,7 +3843,7 @@ namespace q { unsigned h = m_lbl_hasher(lbl); TRACE("trigger_bug", tout << "lbl: " << lbl->get_name() << " is_clbl(lbl): " << is_clbl(lbl) << ", is_plbl(lbl): " << is_plbl(lbl) << ", h: " << h << "\n"; - tout << "lbl_id: " << lbl->get_decl_id() << "\n";); + tout << "lbl_id: " << lbl->get_small_id() << "\n";); if (is_clbl(lbl)) update_lbls(n, h); if (is_plbl(lbl)) diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 3d880aa80..ea335b1dc 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -78,7 +78,7 @@ namespace { public: unsigned char operator()(func_decl * lbl) { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); if (lbl_id >= m_lbl2hash.size()) m_lbl2hash.resize(lbl_id + 1, -1); if (m_lbl2hash[lbl_id] == -1) { @@ -2906,7 +2906,7 @@ namespace { SASSERT(first_idx < mp->get_num_args()); app * p = to_app(mp->get_arg(first_idx)); func_decl * lbl = p->get_decl(); - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); m_trees.reserve(lbl_id+1, nullptr); if (m_trees[lbl_id] == nullptr) { m_trees[lbl_id] = m_compiler.mk_tree(qa, mp, first_idx, false); @@ -2935,7 +2935,7 @@ namespace { } code_tree * get_code_tree_for(func_decl * lbl) const { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); if (lbl_id < m_trees.size()) return m_trees[lbl_id]; else @@ -3165,11 +3165,11 @@ namespace { } bool is_plbl(func_decl * lbl) const { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); return lbl_id < m_is_plbl.size() && m_is_plbl[lbl_id]; } bool is_clbl(func_decl * lbl) const { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); return lbl_id < m_is_clbl.size() && m_is_clbl[lbl_id]; } @@ -3182,7 +3182,7 @@ namespace { } void update_clbls(func_decl * lbl) { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); m_is_clbl.reserve(lbl_id+1, false); TRACE("trigger_bug", tout << "update_clbls: " << lbl->get_name() << " is already clbl: " << m_is_clbl[lbl_id] << "\n";); TRACE("mam_bug", tout << "update_clbls: " << lbl->get_name() << " is already clbl: " << m_is_clbl[lbl_id] << "\n";); @@ -3222,7 +3222,7 @@ namespace { } void update_plbls(func_decl * lbl) { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); m_is_plbl.reserve(lbl_id+1, false); TRACE("trigger_bug", tout << "update_plbls: " << lbl->get_name() << " is already plbl: " << m_is_plbl[lbl_id] << ", lbl_id: " << lbl_id << "\n"; tout << "mam: " << this << "\n";); @@ -3744,7 +3744,7 @@ namespace { app * p = to_app(mp->get_arg(0)); func_decl * lbl = p->get_decl(); if (m_context.get_num_enodes_of(lbl) > 0) { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); m_tmp_trees.reserve(lbl_id+1, 0); if (m_tmp_trees[lbl_id] == 0) { m_tmp_trees[lbl_id] = m_compiler.mk_tree(qa, mp, 0, false); @@ -3757,7 +3757,7 @@ namespace { } for (func_decl * lbl : m_tmp_trees_to_delete) { - unsigned lbl_id = lbl->get_decl_id(); + unsigned lbl_id = lbl->get_small_id(); code_tree * tmp_tree = m_tmp_trees[lbl_id]; SASSERT(tmp_tree != 0); SASSERT(m_context.get_num_enodes_of(lbl) > 0); @@ -3963,7 +3963,7 @@ namespace { unsigned h = m_lbl_hasher(lbl); TRACE("trigger_bug", tout << "lbl: " << lbl->get_name() << " is_clbl(lbl): " << is_clbl(lbl) << ", is_plbl(lbl): " << is_plbl(lbl) << ", h: " << h << "\n"; - tout << "lbl_id: " << lbl->get_decl_id() << "\n";); + tout << "lbl_id: " << lbl->get_small_id() << "\n";); if (is_clbl(lbl)) update_lbls(n, h); if (is_plbl(lbl)) diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 696a5cc39..7c4989aca 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -531,22 +531,22 @@ namespace smt { } unsigned get_num_enodes_of(func_decl const * decl) const { - unsigned id = decl->get_decl_id(); + unsigned id = decl->get_small_id(); return id < m_decl2enodes.size() ? m_decl2enodes[id].size() : 0; } enode_vector const& enodes_of(func_decl const * d) const { - unsigned id = d->get_decl_id(); + unsigned id = d->get_small_id(); return id < m_decl2enodes.size() ? m_decl2enodes[id] : m_empty_vector; } enode_vector::const_iterator begin_enodes_of(func_decl const * decl) const { - unsigned id = decl->get_decl_id(); + unsigned id = decl->get_small_id(); return id < m_decl2enodes.size() ? m_decl2enodes[id].begin() : nullptr; } enode_vector::const_iterator end_enodes_of(func_decl const * decl) const { - unsigned id = decl->get_decl_id(); + unsigned id = decl->get_small_id(); return id < m_decl2enodes.size() ? m_decl2enodes[id].end() : nullptr; } diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index 8995f7fba..196d28396 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -171,7 +171,7 @@ namespace smt { unsigned get_expr_id() const { return m_owner->get_id(); } func_decl * get_decl() const { return m_owner->get_decl(); } - unsigned get_decl_id() const { return m_owner->get_decl()->get_decl_id(); } + unsigned get_decl_id() const { return m_owner->get_decl()->get_small_id(); } sort* get_sort() const { return m_owner->get_sort(); } diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index eee811e62..2c1abec8a 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1010,7 +1010,7 @@ namespace smt { } } if (!e->is_eq()) { - unsigned decl_id = n->get_decl()->get_decl_id(); + unsigned decl_id = n->get_decl()->get_small_id(); if (decl_id >= m_decl2enodes.size()) m_decl2enodes.resize(decl_id+1); m_decl2enodes[decl_id].push_back(e); @@ -1054,7 +1054,7 @@ namespace smt { m_cg_table.erase(e); } if (e->get_num_args() > 0 && !e->is_eq()) { - unsigned decl_id = to_app(n)->get_decl()->get_decl_id(); + unsigned decl_id = to_app(n)->get_decl()->get_small_id(); SASSERT(decl_id < m_decl2enodes.size()); SASSERT(m_decl2enodes[decl_id].back() == e); m_decl2enodes[decl_id].pop_back(); diff --git a/src/util/top_sort.h b/src/util/top_sort.h index 8f9df7d52..46fe45446 100644 --- a/src/util/top_sort.h +++ b/src/util/top_sort.h @@ -24,39 +24,51 @@ Revision History: #include "util/obj_hashtable.h" #include "util/vector.h" #include "util/memory_manager.h" +#include "util/tptr.h" template class top_sort { typedef obj_hashtable T_set; - obj_map m_partition_id; - obj_map m_dfs_num; + unsigned_vector m_partition_id; + unsigned_vector m_dfs_num; ptr_vector m_top_sorted; ptr_vector m_stack_S; ptr_vector m_stack_P; unsigned m_next_preorder; - obj_map m_deps; + ptr_vector m_deps; + ptr_vector m_dep_keys; + + static T_set* add_tag(T_set* t) { return TAG(T_set*, t, 1); } + static T_set* del_tag(T_set* t) { return UNTAG(T_set*, t); } + T_set* get_dep(T* t) const { return del_tag(m_deps.get(t->get_small_id())); } + + + bool contains_partition(T* f) const { + return m_partition_id.get(f->get_small_id()) != UINT_MAX; + } + void traverse(T* f) { - unsigned p_id = 0; - if (m_dfs_num.find(f, p_id)) { - if (!m_partition_id.contains(f)) { - while (!m_stack_P.empty() && m_partition_id.contains(m_stack_P.back()) && m_partition_id[m_stack_P.back()] > p_id) { + unsigned p_id = m_dfs_num.get(f->get_small_id(), UINT_MAX); + if (p_id != UINT_MAX) { + if (!contains_partition(f)) { + while (!m_stack_P.empty() && contains_partition(m_stack_P.back()) && partition_id(m_stack_P.back()) > p_id) { m_stack_P.pop_back(); } } } - else if (!m_deps.contains(f)) { + else if (!contains_dep(f)) return; - } else { - m_dfs_num.insert(f, m_next_preorder++); + m_dfs_num.setx(f->get_small_id(), m_next_preorder, UINT_MAX); + ++m_next_preorder; m_stack_S.push_back(f); m_stack_P.push_back(f); - if (m_deps[f]) { - for (T* g : *m_deps[f]) { + T_set* ts = get_dep(f); + if (ts) { + for (T* g : *ts) traverse(g); - } } if (f == m_stack_P.back()) { p_id = m_top_sorted.size(); @@ -65,7 +77,7 @@ class top_sort { s_f = m_stack_S.back(); m_stack_S.pop_back(); m_top_sorted.push_back(s_f); - m_partition_id.insert(s_f, p_id); + m_partition_id.setx(s_f->get_small_id(), p_id, UINT_MAX); } while (s_f != f); m_stack_P.pop_back(); @@ -76,28 +88,29 @@ class top_sort { public: virtual ~top_sort() { - for (auto & kv : m_deps) dealloc(kv.m_value); + for (auto * t : m_dep_keys) + dealloc(get_dep(t)); } void topological_sort() { m_next_preorder = 0; m_partition_id.reset(); m_top_sorted.reset(); - for (auto & kv : m_deps) { - traverse(kv.m_key); - } + for (auto * t : m_dep_keys) + traverse(t); SASSERT(m_stack_S.empty()); SASSERT(m_stack_P.empty()); m_dfs_num.reset(); } - void insert(T* t, T_set* s) { - m_deps.insert(t, s); + void insert(T* t, T_set* s) { + m_deps.setx(t->get_small_id(), add_tag(s), nullptr); + m_dep_keys.push_back(t); } void add(T* t, T* s) { - T_set* tb = nullptr; - if (!m_deps.find(t, tb) || !tb) { + T_set* tb = get_dep(t); + if (!tb) { tb = alloc(T_set); insert(t, tb); } @@ -106,18 +119,18 @@ public: ptr_vector const& top_sorted() const { return m_top_sorted; } - obj_map const& partition_ids() const { return m_partition_id; } + unsigned partition_id(T* t) const { return m_partition_id[t->get_small_id()]; } - unsigned partition_id(T* t) const { return m_partition_id[t]; } + bool find(T* t, unsigned& p) const { p = m_partition_id.get(t->get_small_id(), UINT_MAX); return p != UINT_MAX; } + + bool contains_dep(T* t) const { return m_deps.get(t->get_small_id(), nullptr) != nullptr; } bool is_singleton_partition(T* f) const { - unsigned pid = m_partition_id[f]; + unsigned pid = m_partition_id(f); return f == m_top_sorted[pid] && - (pid == 0 || m_partition_id[m_top_sorted[pid-1]] != pid) && - (pid + 1 == m_top_sorted.size() || m_partition_id[m_top_sorted[pid+1]] != pid); + (pid == 0 || partition_id(m_top_sorted[pid-1]) != pid) && + (pid + 1 == m_top_sorted.size() || partition_id(m_top_sorted[pid+1]) != pid); } - obj_map const& deps() const { return m_deps; } - }; From 80604c7bc56c1b382119ccf0cb2cc691be1e7748 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Jun 2022 07:00:59 -0700 Subject: [PATCH 214/253] na Signed-off-by: Nikolaj Bjorner --- src/sat/smt/euf_model.cpp | 9 +++++---- src/util/top_sort.h | 6 +++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index 55c916aa8..84f435fc2 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -128,10 +128,11 @@ namespace euf { n->unmark1(); TRACE("model", - for (auto const& d : deps.deps()) - if (d.m_value) { - tout << bpp(d.m_key) << ":\n"; - for (auto* n : *d.m_value) + for (auto * t : deps.deps()) { + auto* v = deps.get_dep(t); + if (v) { + tout << bpp(t) << ":\n"; + for (auto* n : *v) tout << " " << bpp(n) << "\n"; } ); diff --git a/src/util/top_sort.h b/src/util/top_sort.h index 46fe45446..2943b68b6 100644 --- a/src/util/top_sort.h +++ b/src/util/top_sort.h @@ -41,7 +41,6 @@ class top_sort { static T_set* add_tag(T_set* t) { return TAG(T_set*, t, 1); } static T_set* del_tag(T_set* t) { return UNTAG(T_set*, t); } - T_set* get_dep(T* t) const { return del_tag(m_deps.get(t->get_small_id())); } bool contains_partition(T* f) const { @@ -108,6 +107,8 @@ public: m_dep_keys.push_back(t); } + ptr_vector const& deps() { return m_dep_keys; } + void add(T* t, T* s) { T_set* tb = get_dep(t); if (!tb) { @@ -125,6 +126,9 @@ public: bool contains_dep(T* t) const { return m_deps.get(t->get_small_id(), nullptr) != nullptr; } + T_set* get_dep(T* t) const { return del_tag(m_deps.get(t->get_small_id(), nullptr)); } + + bool is_singleton_partition(T* f) const { unsigned pid = m_partition_id(f); return f == m_top_sorted[pid] && From dee6c30f1be89013459543c15ef286eef5b76e0b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Jun 2022 08:05:19 -0700 Subject: [PATCH 215/253] na Signed-off-by: Nikolaj Bjorner --- src/sat/smt/euf_model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index 84f435fc2..4b7745dd7 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -135,6 +135,7 @@ namespace euf { for (auto* n : *v) tout << " " << bpp(n) << "\n"; } + } ); } From e4683863592f5118c6ccdc4164bcdccd3b1369de Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Jun 2022 09:59:29 -0700 Subject: [PATCH 216/253] #5656 guard __del__ operator by checking if library was unloaded. --- src/api/python/z3/z3.py | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 899f9640a..dbd623a2f 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -209,7 +209,8 @@ class Context: Z3_del_config(conf) def __del__(self): - Z3_del_context(self.ctx) + if Z3_del_context is not None: + Z3_del_context(self.ctx) self.ctx = None self.eh = None @@ -346,7 +347,7 @@ class AstRef(Z3PPObject): Z3_inc_ref(self.ctx.ref(), self.as_ast()) def __del__(self): - if self.ctx.ref() is not None and self.ast is not None: + if self.ctx.ref() is not None and self.ast is not None and Z3_dec_ref is not None: Z3_dec_ref(self.ctx.ref(), self.as_ast()) self.ast = None @@ -5128,7 +5129,7 @@ class ScopedConstructor: self.ctx = ctx def __del__(self): - if self.ctx.ref() is not None: + if self.ctx.ref() is not None and Z3_del_constructor is not None: Z3_del_constructor(self.ctx.ref(), self.c) @@ -5140,7 +5141,7 @@ class ScopedConstructorList: self.ctx = ctx def __del__(self): - if self.ctx.ref() is not None: + if self.ctx.ref() is not None and Z3_del_constructor_list is not None: Z3_del_constructor_list(self.ctx.ref(), self.c) @@ -5420,7 +5421,7 @@ class ParamsRef: return ParamsRef(self.ctx, self.params) def __del__(self): - if self.ctx.ref() is not None: + if self.ctx.ref() is not None and Z3_params_dec_ref is not None: Z3_params_dec_ref(self.ctx.ref(), self.params) def set(self, name, val): @@ -5485,7 +5486,7 @@ class ParamDescrsRef: return ParamsDescrsRef(self.descr, self.ctx) def __del__(self): - if self.ctx.ref() is not None: + if self.ctx.ref() is not None and Z3_param_descrs_dec_ref is not None: Z3_param_descrs_dec_ref(self.ctx.ref(), self.descr) def size(self): @@ -5548,7 +5549,7 @@ class Goal(Z3PPObject): Z3_goal_inc_ref(self.ctx.ref(), self.goal) def __del__(self): - if self.goal is not None and self.ctx.ref() is not None: + if self.goal is not None and self.ctx.ref() is not None and Z3_goal_dec_ref is not None: Z3_goal_dec_ref(self.ctx.ref(), self.goal) def depth(self): @@ -5852,7 +5853,7 @@ class AstVector(Z3PPObject): Z3_ast_vector_inc_ref(self.ctx.ref(), self.vector) def __del__(self): - if self.vector is not None and self.ctx.ref() is not None: + if self.vector is not None and self.ctx.ref() is not None and Z3_ast_vector_dec_ref is not None: Z3_ast_vector_dec_ref(self.ctx.ref(), self.vector) def __len__(self): @@ -6015,7 +6016,7 @@ class AstMap: return AstMap(self.map, self.ctx) def __del__(self): - if self.map is not None and self.ctx.ref() is not None: + if self.map is not None and self.ctx.ref() is not None and Z3_ast_map_dec_ref is not None: Z3_ast_map_dec_ref(self.ctx.ref(), self.map) def __len__(self): @@ -6134,7 +6135,7 @@ class FuncEntry: return FuncEntry(self.entry, self.ctx) def __del__(self): - if self.ctx.ref() is not None: + if self.ctx.ref() is not None and Z3_func_entry_dec_ref is not None: Z3_func_entry_dec_ref(self.ctx.ref(), self.entry) def num_args(self): @@ -6241,7 +6242,7 @@ class FuncInterp(Z3PPObject): Z3_func_interp_inc_ref(self.ctx.ref(), self.f) def __del__(self): - if self.f is not None and self.ctx.ref() is not None: + if self.f is not None and self.ctx.ref() is not None and Z3_func_interp_dec_ref is not None: Z3_func_interp_dec_ref(self.ctx.ref(), self.f) def else_value(self): @@ -6359,7 +6360,7 @@ class ModelRef(Z3PPObject): Z3_model_inc_ref(self.ctx.ref(), self.model) def __del__(self): - if self.ctx.ref() is not None: + if self.ctx.ref() is not None and Z3_model_dec_ref is not None: Z3_model_dec_ref(self.ctx.ref(), self.model) def __repr__(self): @@ -6688,7 +6689,7 @@ class Statistics: return Statistics(self.stats, self.ctx) def __del__(self): - if self.ctx.ref() is not None: + if self.ctx.ref() is not None and Z3_stats_dec_ref is not None: Z3_stats_dec_ref(self.ctx.ref(), self.stats) def __repr__(self): @@ -6881,7 +6882,7 @@ class Solver(Z3PPObject): self.set("smtlib2_log", logFile) def __del__(self): - if self.solver is not None and self.ctx.ref() is not None: + if self.solver is not None and self.ctx.ref() is not None and Z3_solver_dec_ref is not None: Z3_solver_dec_ref(self.ctx.ref(), self.solver) def set(self, *args, **keys): @@ -7404,7 +7405,7 @@ class Fixedpoint(Z3PPObject): return FixedPoint(self.fixedpoint, self.ctx) def __del__(self): - if self.fixedpoint is not None and self.ctx.ref() is not None: + if self.fixedpoint is not None and self.ctx.ref() is not None and Z3_fixedpoint_dec_ref is not None: Z3_fixedpoint_dec_ref(self.ctx.ref(), self.fixedpoint) def set(self, *args, **keys): @@ -7827,7 +7828,7 @@ class Optimize(Z3PPObject): return Optimize(self.optimize, self.ctx) def __del__(self): - if self.optimize is not None and self.ctx.ref() is not None: + if self.optimize is not None and self.ctx.ref() is not None and Z3_optimize_dec_ref is not None: Z3_optimize_dec_ref(self.ctx.ref(), self.optimize) if self._on_models_id is not None: del _on_models[self._on_models_id] @@ -8052,7 +8053,7 @@ class ApplyResult(Z3PPObject): return ApplyResult(self.result, self.ctx) def __del__(self): - if self.ctx.ref() is not None: + if self.ctx.ref() is not None and Z3_apply_result_dec_ref is not None: Z3_apply_result_dec_ref(self.ctx.ref(), self.result) def __len__(self): @@ -8157,7 +8158,7 @@ class Tactic: return Tactic(self.tactic, self.ctx) def __del__(self): - if self.tactic is not None and self.ctx.ref() is not None: + if self.tactic is not None and self.ctx.ref() is not None and Z3_tactic_dec_ref is not None: Z3_tactic_dec_ref(self.ctx.ref(), self.tactic) def solver(self, logFile=None): @@ -8468,7 +8469,7 @@ class Probe: return Probe(self.probe, self.ctx) def __del__(self): - if self.probe is not None and self.ctx.ref() is not None: + if self.probe is not None and self.ctx.ref() is not None and Z3_probe_dec_ref is not None: Z3_probe_dec_ref(self.ctx.ref(), self.probe) def __lt__(self, other): From 72a6384353e64a959ca83cd574d8883e3681a830 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Jun 2022 10:00:16 -0700 Subject: [PATCH 217/253] time overflow before stack overflow --- src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index 4c7870cbd..ae125a0ad 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -1123,6 +1123,8 @@ bool bit_blaster_tpl::mk_const_case_multiplier(unsigned sz, expr * const * } if (case_size >= circuit_size) return false; + if (sz >= 100) + return false; SASSERT(out_bits.empty()); ptr_buffer na_bits; From 6a1193eebd50680fae4e9a18a8499c623f3f6ac8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Jun 2022 10:00:45 -0700 Subject: [PATCH 218/253] reorg if-then-else structure --- src/smt/theory_user_propagator.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index e5b1a9c0d..04bb4b248 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -183,22 +183,21 @@ void theory_user_propagator::decide(bool_var& var, bool& is_pos) { } } - if (!th && v == null_theory_var) + if (v == null_theory_var && !th) + return; + + if (v == null_theory_var && th->get_family_id() != bv.get_fid()) return; if (v == null_theory_var) { - if (th->get_family_id() == bv.get_fid()) { - // it is not a registered boolean value but it is a bitvector - auto registered_bv = ((theory_bv*)th)->get_bv_with_theory(var, get_family_id()); - if (!registered_bv.first) - // there is no registered bv associated with the bit - return; - original_enode = registered_bv.first; - original_bit = registered_bv.second; - v = original_enode->get_th_var(get_family_id()); - } - else + // it is not a registered boolean value but it is a bitvector + auto registered_bv = ((theory_bv*)th)->get_bv_with_theory(var, get_family_id()); + if (!registered_bv.first) + // there is no registered bv associated with the bit return; + original_enode = registered_bv.first; + original_bit = registered_bv.second; + v = original_enode->get_th_var(get_family_id()); } // call the registered callback @@ -228,10 +227,8 @@ void theory_user_propagator::decide(bool_var& var, bool& is_pos) { // expression was set to a bit-vector auto th_bv = (theory_bv*)ctx.get_theory(bv.get_fid()); bool_var new_var = th_bv->get_first_unassigned(new_bit, new_enode); - - if (new_var != null_bool_var) { + if (new_var != null_bool_var) var = new_var; - } } // in case the callback did not decide on a truth value -> let Z3 decide From c5847504ff563e457234adc0f16dccffe4be684f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Jun 2022 12:20:45 -0700 Subject: [PATCH 219/253] contains-partition --- src/util/top_sort.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/top_sort.h b/src/util/top_sort.h index 2943b68b6..0f2c32cb7 100644 --- a/src/util/top_sort.h +++ b/src/util/top_sort.h @@ -44,7 +44,7 @@ class top_sort { bool contains_partition(T* f) const { - return m_partition_id.get(f->get_small_id()) != UINT_MAX; + return m_partition_id.get(f->get_small_id(), UINT_MAX) != UINT_MAX; } From 828850f298e7ce5d9961f7c00029649923978471 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 9 Jun 2022 10:08:57 -0700 Subject: [PATCH 220/253] prepare for trim --- src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_drat.cpp | 237 +++++++++++++++++++---------------------- src/sat/sat_drat.h | 27 +++-- src/sat/sat_params.pyg | 1 + 5 files changed, 128 insertions(+), 139 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 877653bf6..a53a4b856 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -197,6 +197,7 @@ namespace sat { m_drat = (m_drat_check_unsat || m_drat_file.is_non_empty_string() || m_drat_check_sat) && p.threads() == 1; m_drat_binary = p.drat_binary(); m_drat_activity = p.drat_activity(); + m_drup_trim = p.drup_trim(); m_dyn_sub_res = p.dyn_sub_res(); // Parameters used in Liang, Ganesh, Poupart, Czarnecki AAAI 2016. diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 65ceaeb54..34ffeed5c 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -179,6 +179,7 @@ namespace sat { symbol m_drat_file; bool m_drat_check_unsat; bool m_drat_check_sat; + bool m_drup_trim; bool m_drat_activity; bool m_card_solver; diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 12a0b2600..c6efc83f4 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - Produce DRAT proofs. + Produce DRUP/DRAT proofs. Check them using a very simple forward checker that interacts with external plugins. @@ -24,17 +24,10 @@ Notes: #include "sat/sat_solver.h" #include "sat/sat_drat.h" - namespace sat { + drat::drat(solver& s) : - s(s), - m_out(nullptr), - m_bout(nullptr), - m_inconsistent(false), - m_check_unsat(false), - m_check_sat(false), - m_check(false), - m_activity(false) + s(s) { if (s.get_config().m_drat && s.get_config().m_drat_file.is_non_empty_string()) { auto mode = s.get_config().m_drat_binary ? (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc) : std::ios_base::out; @@ -49,11 +42,8 @@ namespace sat { if (m_bout) m_bout->flush(); dealloc(m_out); dealloc(m_bout); - for (unsigned i = 0; i < m_proof.size(); ++i) { - clause* c = m_proof[i]; - if (c) - m_alloc.del_clause(c); - } + for (auto & [c, st] : m_proof) + m_alloc.del_clause(&c); m_proof.reset(); m_out = nullptr; m_bout = nullptr; @@ -61,9 +51,10 @@ namespace sat { void drat::updt_config() { m_check_unsat = s.get_config().m_drat_check_unsat; - m_check_sat = s.get_config().m_drat_check_sat; - m_check = m_check_unsat || m_check_sat; - m_activity = s.get_config().m_drat_activity; + m_check_sat = s.get_config().m_drat_check_sat; + m_trim = s.get_config().m_drup_trim; + m_check = m_check_unsat || m_check_sat || m_trim; + m_activity = s.get_config().m_drat_activity; } std::ostream& drat::pp(std::ostream& out, status st) const { @@ -149,14 +140,12 @@ namespace sat { } buffer[len++] = '\n'; m_out->write(buffer, len); - } void drat::dump_activity() { (*m_out) << "c activity "; - for (unsigned v = 0; v < s.num_vars(); ++v) { + for (unsigned v = 0; v < s.num_vars(); ++v) (*m_out) << s.m_activity[v] << " "; - } (*m_out) << "\n"; } @@ -183,7 +172,8 @@ namespace sat { m_bout->write(buffer, len); len = 0; } - } while (v); + } + while (v); } buffer[len++] = 0; m_bout->write(buffer, len); @@ -193,7 +183,8 @@ namespace sat { literal last = null_literal; unsigned n = c.size(); for (unsigned i = 0; i < n; ++i) { - if (c[i] == last) return true; + if (c[i] == last) + return true; last = c[i]; } return false; @@ -243,12 +234,12 @@ namespace sat { if (st.is_redundant() && st.is_sat()) verify(2, lits); - clause* c = m_alloc.mk_clause(2, lits, st.is_redundant()); - m_proof.push_back(c); - m_status.push_back(st); - if (!m_check_unsat) return; + clause& c = mk_clause(2, lits, st.is_redundant()); + m_proof.push_back({c, st}); + if (!m_check_unsat) + return; unsigned idx = m_watched_clauses.size(); - m_watched_clauses.push_back(watched_clause(c, l1, l2)); + m_watched_clauses.push_back(watched_clause(&c, l1, l2)); m_watches[(~l1).index()].push_back(idx); m_watches[(~l2).index()].push_back(idx); @@ -286,40 +277,16 @@ namespace sat { fn(*m_out); } - -#if 0 - // debugging code - bool drat::is_clause(clause& c, literal l1, literal l2, literal l3, drat::status st1, drat::status st2) { - //if (st1 != st2) return false; - if (c.size() != 3) return false; - if (l1 == c[0]) { - if (l2 == c[1] && l3 == c[2]) return true; - if (l2 == c[2] && l3 == c[1]) return true; - } - if (l2 == c[0]) { - if (l1 == c[1] && l3 == c[2]) return true; - if (l1 == c[2] && l3 == c[1]) return true; - } - if (l3 == c[0]) { - if (l1 == c[1] && l2 == c[2]) return true; - if (l1 == c[2] && l2 == c[1]) return true; - } - return false; - } -#endif - void drat::append(clause& c, status st) { TRACE("sat_drat", pp(tout, st) << " " << c << "\n";); for (literal lit : c) declare(lit); unsigned n = c.size(); IF_VERBOSE(20, trace(verbose_stream(), n, c.begin(), st);); - if (st.is_redundant() && st.is_sat()) { + if (st.is_redundant() && st.is_sat()) verify(c); - } - m_status.push_back(st); - m_proof.push_back(&c); + m_proof.push_back({c, st}); if (st.is_deleted()) { if (n > 0) del_watch(c, c[0]); if (n > 1) del_watch(c, c[1]); @@ -370,7 +337,8 @@ namespace sat { } void drat::declare(literal l) { - if (!m_check) return; + if (!m_check) + return; unsigned n = static_cast(l.var()); while (m_assignment.size() <= n) { m_assignment.push_back(l_undef); @@ -391,9 +359,9 @@ namespace sat { assign_propagate(~c[i]); } - for (unsigned i = num_units; i < m_units.size(); ++i) { + for (unsigned i = num_units; i < m_units.size(); ++i) m_assignment[m_units[i].var()] = l_undef; - } + units.append(m_units.size() - num_units, m_units.data() + num_units); m_units.shrink(num_units); bool ok = m_inconsistent; @@ -487,10 +455,8 @@ namespace sat { } void drat::validate_propagation() const { - for (unsigned i = 0; i < m_proof.size(); ++i) { - status st = m_status[i]; - if (m_proof[i] && m_proof[i]->size() > 1 && !st.is_deleted()) { - clause& c = *m_proof[i]; + for (auto const& [c, st] : m_proof) { + if (c.size() > 1 && !st.is_deleted()) { unsigned num_undef = 0, num_true = 0; for (unsigned j = 0; j < c.size(); ++j) { switch (value(c[j])) { @@ -510,10 +476,8 @@ namespace sat { literal l = c[pos]; literal_vector lits(n, c); SASSERT(lits.size() == n); - for (unsigned i = 0; i < m_proof.size(); ++i) { - status st = m_status[i]; - if (m_proof[i] && m_proof[i]->size() > 1 && st.is_asserted()) { - clause& c = *m_proof[i]; + for (auto const& [c, st] : m_proof) { + if (c.size() > 1 && st.is_asserted()) { unsigned j = 0; for (; j < c.size() && c[j] != ~l; ++j) {} if (j != c.size()) { @@ -530,12 +494,10 @@ namespace sat { } void drat::verify(unsigned n, literal const* c) { - if (!m_check_unsat) { + if (!m_check_unsat) return; - } - for (unsigned i = 0; i < n; ++i) { + for (unsigned i = 0; i < n; ++i) declare(c[i]); - } if (is_drup(n, c)) { ++m_stats.m_num_drup; return; @@ -584,12 +546,12 @@ namespace sat { } bool drat::contains(unsigned n, literal const* lits) { - if (!m_check) return true; + if (!m_check) + return true; unsigned num_add = 0; unsigned num_del = 0; for (unsigned i = m_proof.size(); i-- > 0; ) { - clause& c = *m_proof[i]; - status st = m_status[i]; + auto const & [c, st] = m_proof[i]; if (match(n, lits, c)) { if (st.is_deleted()) { num_del++; @@ -603,52 +565,53 @@ namespace sat { } bool drat::match(unsigned n, literal const* lits, clause const& c) const { - if (n == c.size()) { - for (unsigned i = 0; i < n; ++i) { - literal lit1 = lits[i]; - bool found = false; - for (literal lit2 : c) { - if (lit1 == lit2) { - found = true; - break; - } - } - if (!found) { - return false; + if (n != c.size()) + return false; + for (unsigned i = 0; i < n; ++i) { + literal lit1 = lits[i]; + bool found = false; + for (literal lit2 : c) { + if (lit1 == lit2) { + found = true; + break; } } - return true; + if (!found) + return false; } - return false; + return true; } void drat::display(std::ostream& out) const { out << "units: " << m_units << "\n"; for (unsigned i = 0; i < m_assignment.size(); ++i) { lbool v = value(literal(i, false)); - if (v != l_undef) out << i << ": " << v << "\n"; + if (v != l_undef) + out << i << ": " << v << "\n"; } - for (unsigned i = 0; i < m_proof.size(); ++i) { - clause* c = m_proof[i]; - if (!m_status[i].is_deleted() && c) { - unsigned num_true = 0; - unsigned num_undef = 0; - for (unsigned j = 0; j < c->size(); ++j) { - switch (value((*c)[j])) { - case l_true: num_true++; break; - case l_undef: num_undef++; break; - default: break; - } + unsigned i = 0; + for (auto const& [c, st] : m_proof) { + ++i; + if (st.is_deleted()) + continue; + unsigned num_true = 0; + unsigned num_undef = 0; + for (unsigned j = 0; j < c.size(); ++j) { + switch (value(c[j])) { + case l_true: num_true++; break; + case l_undef: num_undef++; break; + default: break; } - if (num_true == 0 && num_undef == 0) { - out << "False "; - } - if (num_true == 0 && num_undef == 1) { - out << "Unit "; - } - pp(out, m_status[i]) << " " << i << ": " << *c << "\n"; } + if (num_true == 0 && num_undef == 0) + out << "False "; + + if (num_true == 0 && num_undef == 1) + out << "Unit "; + + pp(out, st) << " " << i << ": " << c << "\n"; } + for (unsigned i = 0; i < m_assignment.size(); ++i) { watch const& w1 = m_watches[2 * i]; watch const& w2 = m_watches[2 * i + 1]; @@ -690,9 +653,8 @@ namespace sat { void drat::assign_propagate(literal l) { unsigned num_units = m_units.size(); assign(l); - for (unsigned i = num_units; !m_inconsistent && i < m_units.size(); ++i) { - propagate(m_units[i]); - } + for (unsigned i = num_units; !m_inconsistent && i < m_units.size(); ++i) + propagate(m_units[i]); } void drat::propagate(literal l) { @@ -784,11 +746,9 @@ namespace sat { ++m_stats.m_num_add; if (m_out) dump(c.size(), c.begin(), st); if (m_bout) bdump(c.size(), c.begin(), st); - if (m_check) { - clause* cl = m_alloc.mk_clause(c.size(), c.begin(), st.is_redundant()); - append(*cl, st); - } + if (m_check) append(mk_clause(c), st); } + void drat::add(literal_vector const& lits, status st) { add(lits.size(), lits.data(), st); } @@ -802,11 +762,7 @@ namespace sat { switch (sz) { case 0: add(); break; case 1: append(lits[0], st); break; - default: { - clause* c = m_alloc.mk_clause(sz, lits, st.is_redundant()); - append(*c, st); - break; - } + default: append(mk_clause(sz, lits, st.is_redundant()), st); break; } } if (m_out) @@ -818,14 +774,14 @@ namespace sat { if (m_out) dump(c.size(), c.begin(), status::redundant()); if (m_bout) bdump(c.size(), c.begin(), status::redundant()); if (m_check) { - for (literal lit : c) declare(lit); + for (literal lit : c) + declare(lit); switch (c.size()) { case 0: add(); break; case 1: append(c[0], status::redundant()); break; default: { verify(c.size(), c.begin()); - clause* cl = m_alloc.mk_clause(c.size(), c.data(), true); - append(*cl, status::redundant()); + append(mk_clause(c.size(), c.data(), true), status::redundant()); break; } } @@ -836,7 +792,7 @@ namespace sat { ++m_stats.m_num_del; if (m_out) dump(1, &l, status::deleted()); if (m_bout) bdump(1, &l, status::deleted()); - if (m_check_unsat) append(l, status::deleted()); + if (m_check) append(l, status::deleted()); } void drat::del(literal l1, literal l2) { @@ -862,20 +818,22 @@ namespace sat { ++m_stats.m_num_del; if (m_out) dump(c.size(), c.begin(), status::deleted()); if (m_bout) bdump(c.size(), c.begin(), status::deleted()); - if (m_check) { - clause* c1 = m_alloc.mk_clause(c.size(), c.begin(), c.is_learned()); - append(*c1, status::deleted()); - } + if (m_check) append(mk_clause(c), status::deleted()); + } + + clause& drat::mk_clause(clause& c) { + return mk_clause(c.size(), c.begin(), c.is_learned()); + } + + clause& drat::mk_clause(unsigned n, literal const* lits, bool is_learned) { + return *m_alloc.mk_clause(n, lits, is_learned); } void drat::del(literal_vector const& c) { ++m_stats.m_num_del; if (m_out) dump(c.size(), c.begin(), status::deleted()); if (m_bout) bdump(c.size(), c.begin(), status::deleted()); - if (m_check) { - clause* c1 = m_alloc.mk_clause(c.size(), c.begin(), true); - append(*c1, status::deleted()); - } + if (m_check) append(mk_clause(c.size(), c.begin(), true), status::deleted()); } void drat::check_model(model const& m) { @@ -1028,4 +986,25 @@ namespace sat { } } +#if 0 + // debugging code + bool drat::is_clause(clause& c, literal l1, literal l2, literal l3, drat::status st1, drat::status st2) { + //if (st1 != st2) return false; + if (c.size() != 3) return false; + if (l1 == c[0]) { + if (l2 == c[1] && l3 == c[2]) return true; + if (l2 == c[2] && l3 == c[1]) return true; + } + if (l2 == c[0]) { + if (l1 == c[1] && l3 == c[2]) return true; + if (l1 == c[2] && l3 == c[1]) return true; + } + if (l3 == c[0]) { + if (l1 == c[1] && l2 == c[2]) return true; + if (l1 == c[2] && l2 == c[1]) return true; + } + return false; + } +#endif + } diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index a9690f635..671a3d8e8 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -62,10 +62,10 @@ namespace sat { class drat { struct stats { - unsigned m_num_drup { 0 }; - unsigned m_num_drat { 0 }; - unsigned m_num_add { 0 }; - unsigned m_num_del { 0 }; + unsigned m_num_drup = 0; + unsigned m_num_drat = 0; + unsigned m_num_add = 0; + unsigned m_num_del = 0; }; struct watched_clause { clause* m_clause; @@ -77,16 +77,19 @@ namespace sat { typedef svector watch; solver& s; clause_allocator m_alloc; - std::ostream* m_out; - std::ostream* m_bout; - ptr_vector m_proof; - svector m_status; + std::ostream* m_out = nullptr; + std::ostream* m_bout = nullptr; + svector> m_proof; literal_vector m_units; vector m_watches; svector m_assignment; vector m_theory; - bool m_inconsistent; - bool m_check_unsat, m_check_sat, m_check, m_activity; + bool m_inconsistent = false; + bool m_check_unsat = false; + bool m_check_sat = false; + bool m_check = false; + bool m_activity = false; + bool m_trim = false; stats m_stats; void dump_activity(); @@ -115,6 +118,10 @@ namespace sat { void validate_propagation() const; bool match(unsigned n, literal const* lits, clause const& c) const; + clause& mk_clause(clause& c); + clause& mk_clause(unsigned n, literal const* lits, bool is_learned); + + public: drat(solver& s); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 23e0d3a0c..c122e6601 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -50,6 +50,7 @@ def_module_params('sat', ('drat.binary', BOOL, False, 'use Binary DRAT output format'), ('drat.check_unsat', BOOL, False, 'build up internal proof and check'), ('drat.check_sat', BOOL, False, 'build up internal trace, check satisfying model'), + ('drup.trim', BOOL, False, 'build and trim drup proof'), ('drat.activity', BOOL, False, 'dump variable activities'), ('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), binary_merge, segmented, solver (use native solver)'), From 97437bce4c5cf8afa61dc2bc0ebfc78ff7ca30a1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 9 Jun 2022 10:09:30 -0700 Subject: [PATCH 221/253] Update sat_params.pyg --- src/sat/sat_params.pyg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index c122e6601..71ac81715 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -50,7 +50,7 @@ def_module_params('sat', ('drat.binary', BOOL, False, 'use Binary DRAT output format'), ('drat.check_unsat', BOOL, False, 'build up internal proof and check'), ('drat.check_sat', BOOL, False, 'build up internal trace, check satisfying model'), - ('drup.trim', BOOL, False, 'build and trim drup proof'), + ('drup.trim', BOOL, False, 'build and trim drup proof'), ('drat.activity', BOOL, False, 'dump variable activities'), ('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), binary_merge, segmented, solver (use native solver)'), From 5db133f87579d08d576c549f5f1a0099ee7e5133 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Jun 2022 14:35:20 -0700 Subject: [PATCH 222/253] add a way to supress lambdas Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 23 +++++++++++++++-------- src/sat/sat_solver.cpp | 3 +-- src/smt/qi_queue.cpp | 1 + src/smt/smt_context.cpp | 6 +++--- src/smt/smt_context.h | 5 ++++- src/smt/smt_internalizer.cpp | 17 +++++++++++++++-- src/smt/theory_seq.cpp | 21 ++++++++++++++++++++- src/smt/theory_seq.h | 1 + 8 files changed, 60 insertions(+), 17 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index c6efc83f4..7f6ad1a26 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -214,7 +214,10 @@ namespace sat { return; if (m_check_unsat) - assign_propagate(l); + assign_propagate(l); + + if (m_trim) + append(mk_clause(1, &l, st.is_redundant()), st); m_units.push_back(l); } @@ -307,11 +310,15 @@ namespace sat { } } } + + if (!m_check_unsat) + return; + switch (num_watch) { case 0: m_inconsistent = true; break; - case 1: + case 1: assign_propagate(l1); break; default: { @@ -553,12 +560,10 @@ namespace sat { for (unsigned i = m_proof.size(); i-- > 0; ) { auto const & [c, st] = m_proof[i]; if (match(n, lits, c)) { - if (st.is_deleted()) { + if (st.is_deleted()) num_del++; - } - else { + else num_add++; - } } } return num_add > num_del; @@ -596,8 +601,8 @@ namespace sat { continue; unsigned num_true = 0; unsigned num_undef = 0; - for (unsigned j = 0; j < c.size(); ++j) { - switch (value(c[j])) { + for (literal lit : c) { + switch (value(lit)) { case l_true: num_true++; break; case l_undef: num_undef++; break; default: break; @@ -651,6 +656,8 @@ namespace sat { } void drat::assign_propagate(literal l) { + if (!m_check_unsat) + return; unsigned num_units = m_units.size(); assign(l); for (unsigned i = num_units; !m_inconsistent && i < m_units.size(); ++i) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 4f5c9ca8d..9d84d8439 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -600,9 +600,8 @@ namespace sat { else { m_clauses.push_back(r); } - if (m_config.m_drat) { + if (m_config.m_drat) m_drat.add(*r, st); - } for (literal l : *r) { m_touched[l.var()] = m_touch_index; } diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 1cef2a0f1..de52cdb01 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -232,6 +232,7 @@ namespace smt { expr_ref s_instance(m); proof_ref pr(m); m_context.get_rewriter()(instance, s_instance, pr); + TRACE("qi_queue_bug", tout << "new instance after simplification:\n" << s_instance << "\n";); if (m.is_true(s_instance)) { TRACE("checker", tout << "reduced to true, before:\n" << mk_ll_pp(instance, m);); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 49c76ca53..6f5fd6607 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3743,7 +3743,7 @@ namespace smt { if (status == l_false) { return false; } - if (status == l_true && !m_qmanager->has_quantifiers() && !m_has_lambda) { + if (status == l_true && !m_qmanager->has_quantifiers() && m_lambdas.empty()) { return false; } if (status == l_true && m_qmanager->has_quantifiers()) { @@ -3766,7 +3766,7 @@ namespace smt { break; } } - if (status == l_true && m_has_lambda) { + if (status == l_true && !m_lambdas.empty()) { m_last_search_failure = LAMBDAS; status = l_undef; return false; @@ -4010,7 +4010,7 @@ namespace smt { TRACE("final_check_step", tout << "RESULT final_check: " << result << "\n";); if (result == FC_GIVEUP && f != OK) m_last_search_failure = f; - if (result == FC_DONE && m_has_lambda) { + if (result == FC_DONE && !m_lambdas.empty()) { m_last_search_failure = LAMBDAS; result = FC_GIVEUP; } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 7c4989aca..0334a9daf 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -773,7 +773,7 @@ namespace smt { void internalize_quantifier(quantifier * q, bool gate_ctx); - bool m_has_lambda = false; + obj_hashtable m_lambdas, m_non_lambdas; void internalize_lambda(quantifier * q); void internalize_formula_core(app * n, bool gate_ctx); @@ -783,6 +783,9 @@ namespace smt { friend class set_enode_flag_trail; public: + + void add_non_lambda(quantifier* q); + void set_enode_flag(bool_var v, bool is_new_var); protected: diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 2c1abec8a..88623bb2c 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -606,8 +606,21 @@ namespace smt { bool_var bv = get_bool_var(fa); assign(literal(bv, false), nullptr); mark_as_relevant(bv); - push_trail(value_trail(m_has_lambda)); - m_has_lambda = true; + if (m_non_lambdas.contains(q)) + return; + push_trail(insert_obj_trail(m_lambdas, q)); + m_lambdas.insert(q); + } + + void context::add_non_lambda(quantifier* q) { + if (m_non_lambdas.contains(q)) + return; + m_non_lambdas.insert(q); + push_trail(insert_obj_trail(m_lambdas, q)); + if (m_lambdas.contains(q)) { + m_lambdas.remove(q); + push_trail(remove_obj_trail(m_lambdas, q)); + } } /** diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index d09069ce4..7ca0dfe41 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1455,7 +1455,9 @@ bool theory_seq::internalize_term(app* term) { if (ctx.e_internalized(term)) { mk_var(ctx.get_enode(term)); return true; - } + } + + suppress_lambda(term); if (m.is_bool(term) && (m_util.str.is_in_re(term) || m_sk.is_skolem(term))) { @@ -1490,6 +1492,23 @@ bool theory_seq::internalize_term(app* term) { return true; } +void theory_seq::suppress_lambda(app* term) { + if (!m_util.str.is_map(term) && !m_util.str.is_mapi(term) && + !m_util.str.is_foldl(term) && !m_util.str.is_foldli(term)) + return; + + expr* fn = to_app(term)->get_arg(0); + quantifier* q = nullptr; + if (is_lambda(fn)) + q = to_quantifier(fn); + else if (is_app(fn)) + q = m.is_lambda_def(to_app(fn)->get_decl()); + + if (q) + ctx.add_non_lambda(q); +} + + void theory_seq::add_length(expr* l) { expr* e = nullptr; VERIFY(m_util.str.is_length(l, e)); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 4b4c1d80b..b57c9122c 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -388,6 +388,7 @@ namespace smt { bool internalize_atom(app* atom, bool) override; bool internalize_term(app*) override; void internalize_eq_eh(app * atom, bool_var v) override; + void suppress_lambda(app* term); void new_eq_eh(theory_var, theory_var) override; void new_diseq_eh(theory_var, theory_var) override; void assign_eh(bool_var v, bool is_true) override; From b9b5377c6943cb88bbd0efcc3cded932574f0767 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Jun 2022 14:37:25 -0700 Subject: [PATCH 223/253] add a way to supress lambdas Signed-off-by: Nikolaj Bjorner --- src/smt/smt_internalizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 88623bb2c..63e5b0e7b 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -616,7 +616,7 @@ namespace smt { if (m_non_lambdas.contains(q)) return; m_non_lambdas.insert(q); - push_trail(insert_obj_trail(m_lambdas, q)); + push_trail(insert_obj_trail(m_non_lambdas, q)); if (m_lambdas.contains(q)) { m_lambdas.remove(q); push_trail(remove_obj_trail(m_lambdas, q)); From 8efa3c8ade0c8736d1364c8561e1428cefa4d93b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Jun 2022 17:35:01 -0700 Subject: [PATCH 224/253] introduce notion of beta redex to deal with lambdas in non-extensional positions Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 1 + src/ast/ast.h | 2 +- src/smt/smt_context.cpp | 24 ++++++++++++++---------- src/smt/smt_context.h | 9 ++++++--- src/smt/smt_internalizer.cpp | 35 +++++++++++++++++------------------ src/smt/smt_theory.h | 7 +++++++ src/smt/theory_array_base.cpp | 9 +++++++++ src/smt/theory_array_base.h | 1 + src/smt/theory_seq.cpp | 26 ++++++++------------------ src/smt/theory_seq.h | 2 +- 10 files changed, 65 insertions(+), 51 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 56a98b051..190da1366 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1677,6 +1677,7 @@ quantifier* ast_manager::is_lambda_def(func_decl* f) { return nullptr; } + void ast_manager::register_plugin(family_id id, decl_plugin * plugin) { SASSERT(m_plugins.get(id, 0) == 0); m_plugins.setx(id, plugin, 0); diff --git a/src/ast/ast.h b/src/ast/ast.h index fe7586afa..fcf83a65c 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1618,7 +1618,7 @@ public: bool is_lambda_def(quantifier* q) const { return q->get_qid() == m_lambda_def; } void add_lambda_def(func_decl* f, quantifier* q); quantifier* is_lambda_def(func_decl* f); - + quantifier* is_lambda_def(app* e) { return is_lambda_def(e->get_decl()); } symbol const& lambda_def_qid() const { return m_lambda_def; } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 6f5fd6607..49fe8f22f 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3737,15 +3737,12 @@ namespace smt { reset_model(); - if (m_last_search_failure != OK) { + if (m_last_search_failure != OK) return false; - } - if (status == l_false) { + if (status == l_false) return false; - } - if (status == l_true && !m_qmanager->has_quantifiers() && m_lambdas.empty()) { + if (status == l_true && !m_qmanager->has_quantifiers() && !has_lambda()) return false; - } if (status == l_true && m_qmanager->has_quantifiers()) { // possible outcomes DONE l_true, DONE l_undef, CONTINUE mk_proto_model(); @@ -3766,7 +3763,7 @@ namespace smt { break; } } - if (status == l_true && !m_lambdas.empty()) { + if (status == l_true && has_lambda()) { m_last_search_failure = LAMBDAS; status = l_undef; return false; @@ -4010,7 +4007,7 @@ namespace smt { TRACE("final_check_step", tout << "RESULT final_check: " << result << "\n";); if (result == FC_GIVEUP && f != OK) m_last_search_failure = f; - if (result == FC_DONE && !m_lambdas.empty()) { + if (result == FC_DONE && has_lambda()) { m_last_search_failure = LAMBDAS; result = FC_GIVEUP; } @@ -4468,9 +4465,8 @@ namespace smt { return false; } case 1: { - if (m_qmanager->is_shared(n)) { + if (m_qmanager->is_shared(n) && !m.is_lambda_def(n->get_expr()) && !m_lambdas.contains(n)) return true; - } // the variable is shared if the equivalence class of n // contains a parent application. @@ -4482,6 +4478,8 @@ namespace smt { app* p = parent->get_expr(); family_id fid = p->get_family_id(); if (fid != th_id && fid != m.get_basic_family_id()) { + if (is_beta_redex(parent, n)) + continue; TRACE("is_shared", tout << enode_pp(n, *this) << "\nis shared because of:\n" << enode_pp(parent, *this) << "\n";); @@ -4522,6 +4520,12 @@ namespace smt { } } + bool context::is_beta_redex(enode* p, enode* n) const { + family_id th_id = p->get_expr()->get_family_id(); + theory * th = get_theory(th_id); + return th && th->is_beta_redex(p, n); + } + bool context::get_value(enode * n, expr_ref & value) { sort * s = n->get_sort(); family_id fid = s->get_family_id(); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 0334a9daf..e2fc3a35f 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -773,7 +773,12 @@ namespace smt { void internalize_quantifier(quantifier * q, bool gate_ctx); - obj_hashtable m_lambdas, m_non_lambdas; + obj_map m_lambdas; + + bool has_lambda(); + + bool is_beta_redex(enode* p, enode* n) const; + void internalize_lambda(quantifier * q); void internalize_formula_core(app * n, bool gate_ctx); @@ -783,8 +788,6 @@ namespace smt { friend class set_enode_flag_trail; public: - - void add_non_lambda(quantifier* q); void set_enode_flag(bool_var v, bool is_new_var); diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 63e5b0e7b..451136351 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -578,20 +578,19 @@ namespace smt { m_qmanager->add(q, generation); } + void context::internalize_lambda(quantifier * q) { TRACE("internalize_quantifier", tout << mk_pp(q, m) << "\n";); SASSERT(is_lambda(q)); - if (e_internalized(q)) { + if (e_internalized(q)) return; - } app_ref lam_name(m.mk_fresh_const("lambda", q->get_sort()), m); app_ref eq(m), lam_app(m); expr_ref_vector vars(m); vars.push_back(lam_name); unsigned sz = q->get_num_decls(); - for (unsigned i = 0; i < sz; ++i) { + for (unsigned i = 0; i < sz; ++i) vars.push_back(m.mk_var(sz - i - 1, q->get_decl_sort(i))); - } array_util autil(m); lam_app = autil.mk_select(vars.size(), vars.data()); eq = m.mk_eq(lam_app, q->get_expr()); @@ -599,28 +598,28 @@ namespace smt { expr * patterns[1] = { m.mk_pattern(lam_app) }; fa = m.mk_forall(sz, q->get_decl_sorts(), q->get_decl_names(), eq, 0, m.lambda_def_qid(), symbol::null, 1, patterns); internalize_quantifier(fa, true); - if (!e_internalized(lam_name)) internalize_uninterpreted(lam_name); - m_app2enode.setx(q->get_id(), get_enode(lam_name), nullptr); + if (!e_internalized(lam_name)) + internalize_uninterpreted(lam_name); + enode* lam_node = get_enode(lam_name); + push_trail(insert_obj_map(m_lambdas, lam_node)); + m_lambdas.insert(lam_node, q); + m_app2enode.setx(q->get_id(), lam_node, nullptr); m_l_internalized_stack.push_back(q); m_trail_stack.push_back(&m_mk_lambda_trail); bool_var bv = get_bool_var(fa); assign(literal(bv, false), nullptr); mark_as_relevant(bv); - if (m_non_lambdas.contains(q)) - return; - push_trail(insert_obj_trail(m_lambdas, q)); - m_lambdas.insert(q); } - void context::add_non_lambda(quantifier* q) { - if (m_non_lambdas.contains(q)) - return; - m_non_lambdas.insert(q); - push_trail(insert_obj_trail(m_non_lambdas, q)); - if (m_lambdas.contains(q)) { - m_lambdas.remove(q); - push_trail(remove_obj_trail(m_lambdas, q)); + bool context::has_lambda() { + for (auto const & [n, q] : m_lambdas) { + if (n->get_class_size() != 1) + return true; + for (enode* p : enode::parents(n)) + if (!is_beta_redex(p, n)) + return true; } + return false; } /** diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index d723bfee8..c715f215f 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -321,6 +321,13 @@ namespace smt { virtual bool is_shared(theory_var v) const { return false; } + + /** + \brief Determine if node \c n under parent \c p is in a beta redex position. + */ + virtual bool is_beta_redex(enode* p, enode* n) const { + return false; + } /** \brief Return true if the theory has something to propagate diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 33944c96c..f6d4306a5 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -473,6 +473,15 @@ namespace smt { return false; } + bool theory_array_base::is_beta_redex(enode* p, enode* n) const { + if (is_select(p)) + return p->get_arg(0)->get_root() == n->get_root(); + if (is_map(p)) + return true; + return false; + } + + bool theory_array_base::is_select_arg(enode* r) { for (enode* n : r->get_parents()) if (is_select(n)) diff --git a/src/smt/theory_array_base.h b/src/smt/theory_array_base.h index a0550683f..f0d698f26 100644 --- a/src/smt/theory_array_base.h +++ b/src/smt/theory_array_base.h @@ -142,6 +142,7 @@ namespace smt { // // -------------------------------------------------- bool is_shared(theory_var v) const override; + bool is_beta_redex(enode* p, enode* n) const override; void collect_shared_vars(sbuffer & result); unsigned mk_interface_eqs(); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 7ca0dfe41..e1285e749 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1457,8 +1457,6 @@ bool theory_seq::internalize_term(app* term) { return true; } - suppress_lambda(term); - if (m.is_bool(term) && (m_util.str.is_in_re(term) || m_sk.is_skolem(term))) { bool_var bv = ctx.mk_bool_var(term); @@ -1486,26 +1484,18 @@ bool theory_seq::internalize_term(app* term) { mk_var(e); if (!ctx.relevancy()) { relevant_eh(term); - } - - + } return true; } -void theory_seq::suppress_lambda(app* term) { +bool theory_seq::is_beta_redex(enode* p, enode* n) const { + expr* term = p->get_expr(); if (!m_util.str.is_map(term) && !m_util.str.is_mapi(term) && !m_util.str.is_foldl(term) && !m_util.str.is_foldli(term)) - return; - - expr* fn = to_app(term)->get_arg(0); - quantifier* q = nullptr; - if (is_lambda(fn)) - q = to_quantifier(fn); - else if (is_app(fn)) - q = m.is_lambda_def(to_app(fn)->get_decl()); - - if (q) - ctx.add_non_lambda(q); + return false; + if (p->get_arg(0)->get_root() == n->get_root()) + return true; + return false; } @@ -3292,7 +3282,7 @@ bool theory_seq::should_research(expr_ref_vector & unsat_core) { k_min *= 2; if (m_util.is_seq(s_min)) k_min = std::max(m_util.str.min_length(s_min), k_min); - IF_VERBOSE(1, verbose_stream() << "(smt.seq :increase-length " << mk_pp(s_min, m) << " " << k_min << ")\n"); + IF_VERBOSE(1, verbose_stream() << "(smt.seq :increase-length " << mk_bounded_pp(s_min, m, 3) << " " << k_min << ")\n"); add_length_limit(s_min, k_min, false); return true; } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index b57c9122c..cf7e9da23 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -388,7 +388,6 @@ namespace smt { bool internalize_atom(app* atom, bool) override; bool internalize_term(app*) override; void internalize_eq_eh(app * atom, bool_var v) override; - void suppress_lambda(app* term); void new_eq_eh(theory_var, theory_var) override; void new_diseq_eh(theory_var, theory_var) override; void assign_eh(bool_var v, bool is_true) override; @@ -413,6 +412,7 @@ namespace smt { void finalize_model(model_generator & mg) override; void init_search_eh() override; void validate_model(model& mdl) override; + bool is_beta_redex(enode* p, enode* n) const override; void init_model(expr_ref_vector const& es); app* get_ite_value(expr* a); From 994dab8eb68cd6d61d24c9e123903d4ffcd1b679 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Jun 2022 17:56:48 -0700 Subject: [PATCH 225/253] add pre-filter for F* use case Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/th_rewriter.cpp | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 9cf9fc810..5b0df8147 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -37,6 +37,7 @@ Notes: #include "ast/ast_pp.h" #include "ast/ast_util.h" #include "ast/well_sorted.h" +#include "ast/for_each_expr.h" namespace { struct th_rewriter_cfg : public default_rewriter_cfg { @@ -60,6 +61,9 @@ struct th_rewriter_cfg : public default_rewriter_cfg { expr_substitution * m_subst = nullptr; unsigned long long m_max_memory; // in bytes bool m_new_subst = false; + expr_fast_mark1 m_visited; + expr_mark m_marks; + bool m_new_mark = false; unsigned m_max_steps = UINT_MAX; bool m_pull_cheap_ite = true; bool m_flat = true; @@ -692,11 +696,43 @@ struct th_rewriter_cfg : public default_rewriter_cfg { return result; } + /** + * Apply substitution on pattern expressions. + * It happens only very rarely that this operation has an effect. + * To avoid expensive calls to expr_safe_replace we check with a pre-filter + * whether the substitution possibly could apply. + */ + void apply_subst(ptr_buffer& patterns) { if (!m_subst) return; if (patterns.empty()) return; + if (m_subst->sub().empty()) + return; + if (m_new_mark) { + m_marks.reset(); + for (auto const& [k, v] : m_subst->sub()) + m_marks.mark(k); + m_new_mark = false; + } + struct has_mark { + expr_mark& m_marks; + bool found = false; + has_mark(expr_mark& m) : m_marks(m) {} + void operator()(quantifier* q) { + found = true; + } + void operator()(expr* e) { + found |= m_marks.is_marked(e); + } + }; + has_mark has_mark(m_marks); + for (expr* p : patterns) + quick_for_each_expr(has_mark, m_visited, p); + m_visited.reset(); + if (!has_mark.found) + return; if (m_new_subst) { m_rep.reset(); for (auto const& kv : m_subst->sub()) @@ -822,6 +858,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { reset(); m_subst = s; m_new_subst = true; + m_new_mark = true; } void reset() { From 9cd339841a6698f2dc5a75915aedc5ddb9ac1487 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Jun 2022 18:07:54 -0700 Subject: [PATCH 226/253] for Arie Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 1b52e335d..35b45295f 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -729,7 +729,9 @@ bool arith_rewriter::mk_eq_mod(expr* arg1, expr* arg2, expr_ref& result) { expr_ref arith_rewriter::neg_monomial(expr* e) const { expr_ref_vector args(m()); rational a1; - if (is_app(e) && m_util.is_mul(e)) { + if (m_util.is_numeral(e, a1)) + args.push_back(m_util.mk_numeral(-a1, e->get_sort())); + else if (is_app(e) && m_util.is_mul(e)) { if (is_numeral(to_app(e)->get_arg(0), a1)) { if (!a1.is_minus_one()) { args.push_back(m_util.mk_numeral(-a1, m_util.is_int(e))); From 470bf27d1d58ff81e273b7bdf157e545d962bffe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Jun 2022 09:15:32 -0700 Subject: [PATCH 227/253] drat Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 162 +++++++++++++++++------------- src/sat/sat_drat.h | 7 +- src/sat/smt/array_internalize.cpp | 8 ++ src/sat/smt/array_solver.h | 1 + src/sat/smt/euf_internalize.cpp | 10 ++ src/sat/smt/euf_solver.h | 1 + src/sat/smt/sat_th.h | 7 ++ src/shell/drat_frontend.cpp | 5 +- 8 files changed, 128 insertions(+), 73 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 7f6ad1a26..7557a885e 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -209,17 +209,17 @@ namespace sat { IF_VERBOSE(20, trace(verbose_stream(), 1, &l, st);); if (st.is_redundant() && st.is_sat()) verify(1, &l); - + + if (m_trim) + m_proof.push_back({mk_clause(1, &l, st.is_redundant()), st}); + if (st.is_deleted()) return; - if (m_check_unsat) + if (m_check_unsat) { assign_propagate(l); - - if (m_trim) - append(mk_clause(1, &l, st.is_redundant()), st); - - m_units.push_back(l); + m_units.push_back({l, nullptr}); + } } void drat::append(literal l1, literal l2, status st) { @@ -230,8 +230,8 @@ namespace sat { IF_VERBOSE(20, trace(verbose_stream(), 2, lits, st);); if (st.is_deleted()) { - // noop - // don't record binary as deleted. + if (m_trim) + m_proof.push_back({mk_clause(2, lits, true), st}); } else { if (st.is_redundant() && st.is_sat()) @@ -367,9 +367,10 @@ namespace sat { } for (unsigned i = num_units; i < m_units.size(); ++i) - m_assignment[m_units[i].var()] = l_undef; - - units.append(m_units.size() - num_units, m_units.data() + num_units); + m_assignment[m_units[i].first.var()] = l_undef; + + for (unsigned i = num_units; i < m_units.size(); ++i) + units.push_back(m_units[i].first); m_units.shrink(num_units); bool ok = m_inconsistent; m_inconsistent = false; @@ -387,63 +388,12 @@ namespace sat { DEBUG_CODE(if (!m_inconsistent) validate_propagation();); DEBUG_CODE( - for (literal u : m_units) + for (auto const& [u,c] : m_units) SASSERT(m_assignment[u.var()] != l_undef); ); -#if 0 - if (!m_inconsistent) { - literal_vector lits(n, c); - IF_VERBOSE(0, verbose_stream() << "not drup " << lits << "\n"); - for (unsigned v = 0; v < m_assignment.size(); ++v) { - lbool val = m_assignment[v]; - if (val != l_undef) { - IF_VERBOSE(0, verbose_stream() << literal(v, false) << " |-> " << val << "\n"); - } - } - for (clause* cp : s.m_clauses) { - clause& cl = *cp; - bool found = false; - for (literal l : cl) { - if (m_assignment[l.var()] != (l.sign() ? l_true : l_false)) { - found = true; - break; - } - } - if (!found) { - IF_VERBOSE(0, verbose_stream() << "Clause is false under assignment: " << cl << "\n"); - } - } - for (clause* cp : s.m_learned) { - clause& cl = *cp; - bool found = false; - for (literal l : cl) { - if (m_assignment[l.var()] != (l.sign() ? l_true : l_false)) { - found = true; - break; - } - } - if (!found) { - IF_VERBOSE(0, verbose_stream() << "Clause is false under assignment: " << cl << "\n"); - } - } - svector bin; - s.collect_bin_clauses(bin, true); - for (auto& b : bin) { - bool found = false; - if (m_assignment[b.first.var()] != (b.first.sign() ? l_true : l_false)) found = true; - if (m_assignment[b.second.var()] != (b.second.sign() ? l_true : l_false)) found = true; - if (!found) { - IF_VERBOSE(0, verbose_stream() << "Bin clause is false under assignment: " << b.first << " " << b.second << "\n"); - } - } - IF_VERBOSE(0, s.display(verbose_stream())); - exit(0); - } -#endif - for (unsigned i = num_units; i < m_units.size(); ++i) - m_assignment[m_units[i].var()] = l_undef; + m_assignment[m_units[i].first.var()] = l_undef; m_units.shrink(num_units); bool ok = m_inconsistent; @@ -540,7 +490,10 @@ namespace sat { } switch (j.get_kind()) { case justification::NONE: - return m_units.contains(c); + for (auto const& [u, j] : m_units) + if (u == c) + return true; + return false; case justification::BINARY: return contains(c, j.get_literal()); case justification::TERNARY: @@ -588,7 +541,11 @@ namespace sat { } void drat::display(std::ostream& out) const { - out << "units: " << m_units << "\n"; + + out << "units: "; + for (auto const& [u, c] : m_units) + out << u << " "; + out << "\n"; for (unsigned i = 0; i < m_assignment.size(); ++i) { lbool v = value(literal(i, false)); if (v != l_undef) @@ -650,7 +607,7 @@ namespace sat { break; case l_undef: m_assignment.setx(l.var(), new_value, l_undef); - m_units.push_back(l); + m_units.push_back({l, nullptr}); break; } } @@ -661,7 +618,7 @@ namespace sat { unsigned num_units = m_units.size(); assign(l); for (unsigned i = num_units; !m_inconsistent && i < m_units.size(); ++i) - propagate(m_units[i]); + propagate(m_units[i].first); } void drat::propagate(literal l) { @@ -843,6 +800,21 @@ namespace sat { if (m_check) append(mk_clause(c.size(), c.begin(), true), status::deleted()); } + // + // placeholder for trim function. + // 1. forward pass replaying propositional proof, populate trail stack. + // 2. backward pass to prune. + // + svector> drat::trim() { + SASSERT(m_units.empty()); + svector> proof; + for (auto const& [c, st] : m_proof) + if (!st.is_deleted()) + proof.push_back({c,st}); + return proof; + } + + void drat::check_model(model const& m) { } @@ -1014,4 +986,56 @@ namespace sat { } #endif + +#if 0 + if (!m_inconsistent) { + literal_vector lits(n, c); + IF_VERBOSE(0, verbose_stream() << "not drup " << lits << "\n"); + for (unsigned v = 0; v < m_assignment.size(); ++v) { + lbool val = m_assignment[v]; + if (val != l_undef) { + IF_VERBOSE(0, verbose_stream() << literal(v, false) << " |-> " << val << "\n"); + } + } + for (clause* cp : s.m_clauses) { + clause& cl = *cp; + bool found = false; + for (literal l : cl) { + if (m_assignment[l.var()] != (l.sign() ? l_true : l_false)) { + found = true; + break; + } + } + if (!found) { + IF_VERBOSE(0, verbose_stream() << "Clause is false under assignment: " << cl << "\n"); + } + } + for (clause* cp : s.m_learned) { + clause& cl = *cp; + bool found = false; + for (literal l : cl) { + if (m_assignment[l.var()] != (l.sign() ? l_true : l_false)) { + found = true; + break; + } + } + if (!found) { + IF_VERBOSE(0, verbose_stream() << "Clause is false under assignment: " << cl << "\n"); + } + } + svector bin; + s.collect_bin_clauses(bin, true); + for (auto& b : bin) { + bool found = false; + if (m_assignment[b.first.var()] != (b.first.sign() ? l_true : l_false)) found = true; + if (m_assignment[b.second.var()] != (b.second.sign() ? l_true : l_false)) found = true; + if (!found) { + IF_VERBOSE(0, verbose_stream() << "Bin clause is false under assignment: " << b.first << " " << b.second << "\n"); + } + } + IF_VERBOSE(0, s.display(verbose_stream())); + exit(0); + } +#endif + } diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index 671a3d8e8..2408e5d8e 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -80,7 +80,7 @@ namespace sat { std::ostream* m_out = nullptr; std::ostream* m_bout = nullptr; svector> m_proof; - literal_vector m_units; + svector> m_units; vector m_watches; svector m_assignment; vector m_theory; @@ -172,9 +172,12 @@ namespace sat { void collect_statistics(statistics& st) const; bool inconsistent() const { return m_inconsistent; } - literal_vector const& units() { return m_units; } + svector> const& units() { return m_units; } bool is_drup(unsigned n, literal const* c, literal_vector& units); solver& get_solver() { return s; } + + svector> trim(); + }; } diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index 030018088..68dea4d63 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -247,6 +247,14 @@ namespace array { return false; } + bool solver::is_beta_redex(euf::enode* p, euf::enode* n) const { + if (a.is_select(p->get_expr())) + return p->get_arg(0)->get_root() == n->get_root(); + if (a.is_map(p->get_expr())) + return true; + return false; + } + func_decl_ref_vector const& solver::sort2diff(sort* s) { func_decl_ref_vector* result = nullptr; if (m_sort2diff.find(s, result)) diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index 239de0904..f2b4fb565 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -299,6 +299,7 @@ namespace array { euf::theory_var mk_var(euf::enode* n) override; void apply_sort_cnstr(euf::enode* n, sort* s) override; bool is_shared(theory_var v) const override; + bool is_beta_redex(euf::enode* p, euf::enode* n) const override; bool enable_self_propagate() const override { return true; } void relevant_eh(euf::enode* n) override; bool enable_ackerman_axioms(euf::enode* n) const override { return !a.is_array(n->get_sort()); } diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 045b92c99..8b8c7da74 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -358,6 +358,7 @@ namespace euf { for (auto const& p : euf::enode_th_vars(n)) { family_id id = p.get_id(); if (m.get_basic_family_id() != id) { + if (th_id != m.get_basic_family_id()) return true; th_id = id; @@ -369,6 +370,8 @@ namespace euf { for (enode* parent : euf::enode_parents(n)) { app* p = to_app(parent->get_expr()); family_id fid = p->get_family_id(); + if (is_beta_redex(parent, n)) + continue; if (fid != th_id && fid != m.get_basic_family_id()) return true; } @@ -407,6 +410,13 @@ namespace euf { return false; } + bool solver::is_beta_redex(enode* p, enode* n) const { + for (auto const& th : enode_th_vars(p)) + if (fid2solver(th.get_id())->is_beta_redex(p, n)) + return true; + return false; + } + expr_ref solver::mk_eq(expr* e1, expr* e2) { expr_ref _e1(e1, m); expr_ref _e2(e2, m); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 21a9c4d1d..c66109473 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -371,6 +371,7 @@ namespace euf { th_rewriter& get_rewriter() { return m_rewriter; } void rewrite(expr_ref& e) { m_rewriter(e); } bool is_shared(euf::enode* n) const; + bool is_beta_redex(euf::enode* p, euf::enode* n) const; bool enable_ackerman_axioms(expr* n) const; bool is_fixed(euf::enode* n, expr_ref& val, sat::literal_vector& explain); diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index 8e1ab571d..f699c864b 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -127,6 +127,13 @@ namespace euf { */ virtual bool is_shared(theory_var v) const { return false; } + + /** + \brief Determine if argument n of parent p is a beta redex position + */ + + virtual bool is_beta_redex(euf::enode* p, euf::enode* n) const { return false; } + sat::status status() const { return sat::status::th(m_is_redundant, get_id()); } }; diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index 8c486cca8..485b1af91 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -77,11 +77,12 @@ class smt_checker { auto const& units = m_drat.units(); #if 0 for (unsigned i = m_units.size(); i < units.size(); ++i) { - sat::literal lit = units[i]; + sat::literal lit = units[i].first; m_lemma_solver->assert_expr(lit2expr(lit)); } #endif - m_units.append(units.size() - m_units.size(), units.data() + m_units.size()); + for (unsigned i = m_units.size(); i < units.size(); ++i) + m_units.push_back(units[i].first); } void check_assertion_redundant(sat::literal_vector const& input) { From 46bc726391a6f154b39262e66c9e22821ea335a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominic=20Steinh=C3=B6fel?= Date: Mon, 13 Jun 2022 22:46:30 +0200 Subject: [PATCH 228/253] Better error message for mismatching sorts in substitutions in z3.substitute (#6093) --- src/api/python/z3/z3.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index dbd623a2f..b2e7e250c 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8773,8 +8773,12 @@ def substitute(t, *m): m = m1 if z3_debug(): _z3_assert(is_expr(t), "Z3 expression expected") - _z3_assert(all([isinstance(p, tuple) and is_expr(p[0]) and is_expr(p[1]) and p[0].sort().eq( - p[1].sort()) for p in m]), "Z3 invalid substitution, expression pairs expected.") + _z3_assert( + all([isinstance(p, tuple) and is_expr(p[0]) and is_expr(p[1]) for p in m]), + "Z3 invalid substitution, expression pairs expected.") + _z3_assert( + all([p[0].sort().eq(p[1].sort()) for p in m]), + 'Z3 invalid substitution, mismatching "from" and "to" sorts.') num = len(m) _from = (Ast * num)() _to = (Ast * num)() From 04f94d818fdd2e5a5718b48114417719b5703c32 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Jun 2022 11:56:32 -0700 Subject: [PATCH 229/253] fix #6091 --- src/sat/sat_drat.cpp | 22 +++++++++++----------- src/sat/sat_drat.h | 4 ++-- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_nl.h | 17 +++++++++++++---- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 7557a885e..073110077 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -217,7 +217,7 @@ namespace sat { return; if (m_check_unsat) { - assign_propagate(l); + assign_propagate(l, nullptr); m_units.push_back({l, nullptr}); } } @@ -249,9 +249,9 @@ namespace sat { if (value(l1) == l_false && value(l2) == l_false) m_inconsistent = true; else if (value(l1) == l_false) - assign_propagate(l2); + assign_propagate(l2, &c); else if (value(l2) == l_false) - assign_propagate(l1); + assign_propagate(l1, &c); } } @@ -319,7 +319,7 @@ namespace sat { m_inconsistent = true; break; case 1: - assign_propagate(l1); + assign_propagate(l1, &c); break; default: { SASSERT(num_watch == 2); @@ -363,7 +363,7 @@ namespace sat { unsigned num_units = m_units.size(); for (unsigned i = 0; !m_inconsistent && i < n; ++i) { declare(c[i]); - assign_propagate(~c[i]); + assign_propagate(~c[i], nullptr); } for (unsigned i = num_units; i < m_units.size(); ++i) @@ -384,7 +384,7 @@ namespace sat { return false; unsigned num_units = m_units.size(); for (unsigned i = 0; !m_inconsistent && i < n; ++i) - assign_propagate(~c[i]); + assign_propagate(~c[i], nullptr); DEBUG_CODE(if (!m_inconsistent) validate_propagation();); DEBUG_CODE( @@ -595,7 +595,7 @@ namespace sat { return val == l_undef || !l.sign() ? val : ~val; } - void drat::assign(literal l) { + void drat::assign(literal l, clause* c) { lbool new_value = l.sign() ? l_false : l_true; lbool old_value = value(l); // TRACE("sat_drat", tout << "assign " << l << " := " << new_value << " from " << old_value << "\n";); @@ -607,16 +607,16 @@ namespace sat { break; case l_undef: m_assignment.setx(l.var(), new_value, l_undef); - m_units.push_back({l, nullptr}); + m_units.push_back({l, c}); break; } } - void drat::assign_propagate(literal l) { + void drat::assign_propagate(literal l, clause* c) { if (!m_check_unsat) return; unsigned num_units = m_units.size(); - assign(l); + assign(l, c); for (unsigned i = num_units; !m_inconsistent && i < m_units.size(); ++i) propagate(m_units[i].first); } @@ -661,7 +661,7 @@ namespace sat { else { *it2 = *it; it2++; - assign(wc.m_l1); + assign(wc.m_l1, &c); } } } diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index 2408e5d8e..18ca7b7b8 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -105,9 +105,9 @@ namespace sat { status get_status(bool learned) const; void declare(literal l); - void assign(literal l); + void assign(literal l, clause* c); void propagate(literal l); - void assign_propagate(literal l); + void assign_propagate(literal l, clause* c); void del_watch(clause& c, literal l); bool is_drup(unsigned n, literal const* c); bool is_drat(unsigned n, literal const* c); diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 6e1d77dd4..a1054423a 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -974,7 +974,7 @@ namespace smt { /** \brief A monomial is 'pure' if does not have a numeric coefficient. */ - bool is_pure_monomial(expr * m) const { return m_util.is_mul(m) && (to_app(m)->get_num_args() > 2 || !m_util.is_numeral(to_app(m)->get_arg(0))); } + bool is_pure_monomial(expr * m) const; bool is_pure_monomial(theory_var v) const { return is_pure_monomial(get_enode(v)->get_expr()); } void mark_var(theory_var v, svector & vars, var_set & already_found); void mark_dependents(theory_var v, svector & vars, var_set & already_found, row_set & already_visited_rows); diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index d73f604c1..044a42e7e 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -624,11 +624,9 @@ template bool theory_arith::check_monomial_assignments() { bool computed_epsilon = false; for (theory_var v : m_nl_monomials) { - TRACE("non_linear", tout << "v" << v << " is relevant: " << ctx.is_relevant(get_enode(v)) << "\n"; - tout << "check_monomial_assignments result: " << check_monomial_assignment(v, computed_epsilon) << "\n"; - tout << "computed_epsilon: " << computed_epsilon << "\n";); + TRACE("non_linear", tout << "v" << v << " is relevant: " << ctx.is_relevant(get_enode(v)) << "\n"); if (ctx.is_relevant(get_enode(v)) && !check_monomial_assignment(v, computed_epsilon)) { - TRACE("non_linear_failed", tout << "check_monomial_assignment failed for:\n" << mk_ismt2_pp(var2expr(v), get_manager()) << "\n"; + TRACE("non_linear", tout << "check_monomial_assignment failed for:\n" << mk_ismt2_pp(var2expr(v), get_manager()) << "\n"; display_var(tout, v);); return false; } @@ -1254,6 +1252,17 @@ bool theory_arith::in_monovariate_monomials(buffer & p, expr * } +template +bool theory_arith::is_pure_monomial(expr* mon) const { + if (!m_util.is_mul(mon)) + return false; + app* p = to_app(mon); + for (expr* arg : *p) + if (m_util.is_numeral(arg) || m_util.is_mul(arg)) + return false; + return true; +} + /** \brief Display a nested form expression */ From 35d46054256df241cfe7a7224d52560443945be8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 12 Jun 2022 10:44:07 -0700 Subject: [PATCH 230/253] remove spurious output to stdout --- src/sat/sat_gc.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sat/sat_gc.cpp b/src/sat/sat_gc.cpp index 6b5618b2b..ba89ed76f 100644 --- a/src/sat/sat_gc.cpp +++ b/src/sat/sat_gc.cpp @@ -398,7 +398,6 @@ namespace sat { else m_learned[j++] = &c; } - std::cout << "gc: " << to_gc.size() << " " << m_learned.size() << " -> " << j << "\n"; SASSERT(m_learned.size() - j == to_gc.size()); m_learned.shrink(j); } From 25ad5cb073ca81fd3b06cad9940c8ab6080c3b9b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 12 Jun 2022 10:45:39 -0700 Subject: [PATCH 231/253] prepare ground for drup trim By not deleting justifications in base level unit literals it is possible for drup-trim to inspect the trail for dependencies - which clauses were used to derive a literal. --- src/sat/sat_drat.cpp | 2 +- src/sat/sat_solver.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 073110077..d5ea181c4 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -802,7 +802,7 @@ namespace sat { // // placeholder for trim function. - // 1. forward pass replaying propositional proof, populate trail stack. + // 1. trail contains justification for the empty clause. // 2. backward pass to prune. // svector> drat::trim() { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 9d84d8439..f8f187fc2 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -945,8 +945,8 @@ namespace sat { if (j.level() == 0) { if (m_config.m_drat) drat_log_unit(l, j); - - j = justification(0); // erase justification for level 0 + if (!m_config.m_drup_trim) + j = justification(0); // erase justification for level 0 } else { VERIFY(!at_base_lvl()); From 637120ced59cefacca31cc43df4f2d1c1d64488e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 12 Jun 2022 10:48:55 -0700 Subject: [PATCH 232/253] Treat arguments to recursive functions as beta redexes An argument to a recursive function would escape the scope of the function application when the recursive function definitions are unfolded. Therefore, such argument occurrences need not be considered for extensional equality / equality sharing. This filter is mostly relevant for recursive functions that take a lambda expression as argument. Lambda expressions / arrays that occur in shared occurrences are checked for extensionality. --- src/sat/smt/recfun_solver.cpp | 5 +++++ src/sat/smt/recfun_solver.h | 1 + src/smt/theory_recfun.cpp | 9 +++++++++ src/smt/theory_recfun.h | 1 + 4 files changed, 16 insertions(+) diff --git a/src/sat/smt/recfun_solver.cpp b/src/sat/smt/recfun_solver.cpp index b908297ad..c88138d3f 100644 --- a/src/sat/smt/recfun_solver.cpp +++ b/src/sat/smt/recfun_solver.cpp @@ -333,6 +333,11 @@ namespace recfun { return found; } + bool solver::is_beta_redex(euf::enode* p, euf::enode* n) const { + return is_defined(p) || is_case_pred(p); + } + + bool solver::add_dep(euf::enode* n, top_sort& dep) { if (n->num_args() == 0) dep.insert(n, nullptr); diff --git a/src/sat/smt/recfun_solver.h b/src/sat/smt/recfun_solver.h index 69b799b4c..d469b7437 100644 --- a/src/sat/smt/recfun_solver.h +++ b/src/sat/smt/recfun_solver.h @@ -108,6 +108,7 @@ namespace recfun { bool is_shared(euf::theory_var v) const override { return true; } void init_search() override {} bool should_research(sat::literal_vector const& core) override; + bool is_beta_redex(euf::enode* p, euf::enode* n) const; void add_assumptions(sat::literal_set& assumptions) override; bool tracking_assumptions() override { return true; } }; diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 782510681..c18e5577b 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -467,6 +467,15 @@ namespace smt { return found; } + /** + * n is an argument of p, if p is a function definition or case predicate, + * then there is no reason for the solver to enforce that equality on n is + * fully determined. It is a beta-redex with respect to expanding p. + */ + bool theory_recfun::is_beta_redex(enode* p, enode* n) const { + return is_defined(p) || is_case_pred(p); + } + void theory_recfun::display(std::ostream & out) const { out << "recfun\n"; out << "disabled guards:\n" << m_disabled_guards << "\n"; diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 097181d22..2e576a29a 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -99,6 +99,7 @@ namespace smt { bool can_propagate() override; void propagate() override; bool should_research(expr_ref_vector &) override; + bool is_beta_redex(enode* p, enode* n) const override; void new_eq_eh(theory_var v1, theory_var v2) override {} void new_diseq_eh(theory_var v1, theory_var v2) override {} From 55421afd6110138e0719f80e5f35597c8e1d14f6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Jun 2022 09:49:25 -0700 Subject: [PATCH 233/253] fix regression in top-sort fix #6060 --- src/util/top_sort.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/util/top_sort.h b/src/util/top_sort.h index 0f2c32cb7..51a0d9733 100644 --- a/src/util/top_sort.h +++ b/src/util/top_sort.h @@ -87,8 +87,10 @@ class top_sort { public: virtual ~top_sort() { - for (auto * t : m_dep_keys) + for (auto * t : m_dep_keys) { dealloc(get_dep(t)); + m_deps[t->get_small_id()] = nullptr; + } } void topological_sort() { @@ -102,9 +104,12 @@ public: m_dfs_num.reset(); } - void insert(T* t, T_set* s) { + void insert(T* t, T_set* s) { + if (contains_dep(t)) + dealloc(get_dep(t)); + else + m_dep_keys.push_back(t); m_deps.setx(t->get_small_id(), add_tag(s), nullptr); - m_dep_keys.push_back(t); } ptr_vector const& deps() { return m_dep_keys; } @@ -126,7 +131,7 @@ public: bool contains_dep(T* t) const { return m_deps.get(t->get_small_id(), nullptr) != nullptr; } - T_set* get_dep(T* t) const { return del_tag(m_deps.get(t->get_small_id(), nullptr)); } + T_set* get_dep(T* t) const { return del_tag(m_deps.get(t->get_small_id(), nullptr)); } bool is_singleton_partition(T* f) const { From 8e2027107d61c47e95e2b93bd6d33d5a4f4e7059 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Jun 2022 09:49:41 -0700 Subject: [PATCH 234/253] fix spacing --- src/model/func_interp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/model/func_interp.cpp b/src/model/func_interp.cpp index 1c59b6107..b180a8a1f 100644 --- a/src/model/func_interp.cpp +++ b/src/model/func_interp.cpp @@ -294,9 +294,9 @@ void func_interp::compress() { m().dec_ref(m_else); m_else = new_else; } - else + //else #endif - if (!m_entries.empty() && is_identity()) { + if (!m_entries.empty() && is_identity()) { for (func_entry * curr : m_entries) { curr->deallocate(m(), m_arity); } From 3d00d1d56b26fa4ad92f3ad5a893342ddcb1e04d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Jun 2022 09:50:53 -0700 Subject: [PATCH 235/253] prepare for equality propagation from Grobner basis Attempt to remedy performance regressions from the new solver core for NLA. It misses easy lemmas, presumably due to weaker bounds information. --- src/math/dd/dd_pdd.h | 3 +- src/math/grobner/pdd_solver.cpp | 3 + src/math/lp/nla_core.cpp | 3981 ++++++++++++++++--------------- 3 files changed, 2009 insertions(+), 1978 deletions(-) diff --git a/src/math/dd/dd_pdd.h b/src/math/dd/dd_pdd.h index 28d273966..d061bb0f7 100644 --- a/src/math/dd/dd_pdd.h +++ b/src/math/dd/dd_pdd.h @@ -340,7 +340,8 @@ namespace dd { bool is_one() const { return m.is_one(root); } bool is_zero() const { return m.is_zero(root); } bool is_linear() const { return m.is_linear(root); } - bool is_unary() const { return !is_val() && lo().is_zero() && hi().is_val(); } + bool is_unary() const { return !is_val() && lo().is_zero() && hi().is_val(); } + bool is_offset() const { return !is_val() && lo().is_val() && hi().is_one(); } bool is_binary() const { return m.is_binary(root); } bool is_monomial() const { return m.is_monomial(root); } bool is_non_zero() const { return m.is_non_zero(root); } diff --git a/src/math/grobner/pdd_solver.cpp b/src/math/grobner/pdd_solver.cpp index 000193563..11c34e180 100644 --- a/src/math/grobner/pdd_solver.cpp +++ b/src/math/grobner/pdd_solver.cpp @@ -160,6 +160,9 @@ namespace dd { } while (simplified && !eq.poly().is_val()); + if (eq.poly().is_unary() && eq.poly().hi().val() < 0) + eq = -eq.poly(); + TRACE("dd.solver", display(tout << "simplification result: ", eq);); } diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index eedf46967..d8d4930ce 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1,1977 +1,2004 @@ - /*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - nla_core.cpp - -Author: - Lev Nachmanson (levnach) - Nikolaj Bjorner (nbjorner) - ---*/ -#include "util/uint_set.h" -#include "math/lp/nla_core.h" -#include "math/lp/factorization_factory_imp.h" -#include "math/lp/nex.h" -#include "math/grobner/pdd_solver.h" -#include "math/dd/pdd_interval.h" -#include "math/dd/pdd_eval.h" -namespace nla { - -typedef lp::lar_term term; - -core::core(lp::lar_solver& s, reslimit & lim) : - m_evars(), - m_lar_solver(s), - m_tangents(this), - m_basics(this), - m_order(this), - m_monotone(this), - m_intervals(this, lim), - m_monomial_bounds(this), - m_horner(this), - m_pdd_manager(s.number_of_vars()), - m_pdd_grobner(lim, m_pdd_manager), - m_emons(m_evars), - m_reslim(lim), - m_use_nra_model(false), - m_nra(s, m_nra_lim, *this) -{ - m_nlsat_delay = lp_settings().nlsat_delay(); -} - -bool core::compare_holds(const rational& ls, llc cmp, const rational& rs) const { - switch(cmp) { - case llc::LE: return ls <= rs; - case llc::LT: return ls < rs; - case llc::GE: return ls >= rs; - case llc::GT: return ls > rs; - case llc::EQ: return ls == rs; - case llc::NE: return ls != rs; - default: SASSERT(false); - }; - - return false; -} - -rational core::value(const lp::lar_term& r) const { - rational ret(0); - for (lp::lar_term::ival t : r) { - ret += t.coeff() * val(t.column()); - } - return ret; -} - -lp::lar_term core::subs_terms_to_columns(const lp::lar_term& t) const { - lp::lar_term r; - for (lp::lar_term::ival p : t) { - lpvar j = p.column(); - if (lp::tv::is_term(j)) - j = m_lar_solver.map_term_index_to_column_index(j); - r.add_monomial(p.coeff(), j); - } - return r; -} - -bool core::ineq_holds(const ineq& n) const { - return compare_holds(value(n.term()), n.cmp(), n.rs()); -} - -bool core::lemma_holds(const lemma& l) const { - for(const ineq &i : l.ineqs()) { - if (ineq_holds(i)) - return true; - } - return false; -} - -lpvar core::map_to_root(lpvar j) const { - return m_evars.find(j).var(); -} - -svector core::sorted_rvars(const factor& f) const { - if (f.is_var()) { - svector r; r.push_back(map_to_root(f.var())); - return r; - } - return m_emons[f.var()].rvars(); -} - -// the value of the factor is equal to the value of the variable multiplied -// by the canonize_sign -bool core::canonize_sign(const factor& f) const { - return f.sign() ^ (f.is_var()? canonize_sign(f.var()) : canonize_sign(m_emons[f.var()])); -} - -bool core::canonize_sign(lpvar j) const { - return m_evars.find(j).sign(); -} - -bool core::canonize_sign_is_correct(const monic& m) const { - bool r = false; - for (lpvar j : m.vars()) { - r ^= canonize_sign(j); - } - return r == m.rsign(); -} - -bool core::canonize_sign(const monic& m) const { - SASSERT(canonize_sign_is_correct(m)); - return m.rsign(); -} - -bool core::canonize_sign(const factorization& f) const { - bool r = false; - for (const factor & a : f) { - r ^= canonize_sign(a); - } - return r; -} - -void core::add_monic(lpvar v, unsigned sz, lpvar const* vs) { - m_add_buffer.resize(sz); - for (unsigned i = 0; i < sz; i++) { - lpvar j = vs[i]; - if (lp::tv::is_term(j)) - j = m_lar_solver.map_term_index_to_column_index(j); - m_add_buffer[i] = j; - } - m_emons.add(v, m_add_buffer); -} - -void core::push() { - TRACE("nla_solver_verbose", tout << "\n";); - m_emons.push(); -} - - -void core::pop(unsigned n) { - TRACE("nla_solver_verbose", tout << "n = " << n << "\n";); - m_emons.pop(n); - SASSERT(elists_are_consistent(false)); -} - -rational core::product_value(const monic& m) const { - rational r(1); - for (auto j : m.vars()) { - r *= m_lar_solver.get_column_value(j).x; - } - return r; -} - -// return true iff the monic value is equal to the product of the values of the factors -bool core::check_monic(const monic& m) const { - SASSERT((!m_lar_solver.column_is_int(m.var())) || m_lar_solver.get_column_value(m.var()).is_int()); - bool ret = product_value(m) == m_lar_solver.get_column_value(m.var()).x; - CTRACE("nla_solver_check_monic", !ret, print_monic(m, tout) << '\n';); - return ret; -} - - -template -std::ostream& core::print_product(const T & m, std::ostream& out) const { - bool first = true; - for (lpvar v : m) { - if (!first) out << "*"; else first = false; - if (lp_settings().print_external_var_name()) - out << "(" << m_lar_solver.get_variable_name(v) << "=" << val(v) << ")"; - else - out << "(j" << v << " = " << val(v) << ")"; - - } - return out; -} -template -std::string core::product_indices_str(const T & m) const { - std::stringstream out; - bool first = true; - for (lpvar v : m) { - if (!first) - out << "*"; - else - first = false; - out << "j" << v;; - } - return out.str(); -} - -std::ostream & core::print_factor(const factor& f, std::ostream& out) const { - if (f.sign()) - out << "- "; - if (f.is_var()) { - out << "VAR, " << pp(f.var()); - } else { - out << "MON, v" << m_emons[f.var()] << " = "; - print_product(m_emons[f.var()].rvars(), out); - } - out << "\n"; - return out; -} - -std::ostream & core::print_factor_with_vars(const factor& f, std::ostream& out) const { - if (f.is_var()) { - out << pp(f.var()); - } - else { - out << " MON = " << pp_mon_with_vars(*this, m_emons[f.var()]); - } - return out; -} - -std::ostream& core::print_monic(const monic& m, std::ostream& out) const { - if (lp_settings().print_external_var_name()) - out << "([" << m.var() << "] = " << m_lar_solver.get_variable_name(m.var()) << " = " << val(m.var()) << " = "; - else - out << "(j" << m.var() << " = " << val(m.var()) << " = "; - print_product(m.vars(), out) << ")\n"; - return out; -} - - -std::ostream& core::print_bfc(const factorization& m, std::ostream& out) const { - SASSERT(m.size() == 2); - out << "( x = " << pp(m[0]) << "* y = " << pp(m[1]) << ")"; - return out; -} - -std::ostream& core::print_monic_with_vars(lpvar v, std::ostream& out) const { - return print_monic_with_vars(m_emons[v], out); -} -template -std::ostream& core::print_product_with_vars(const T& m, std::ostream& out) const { - print_product(m, out) << "\n"; - for (unsigned k = 0; k < m.size(); k++) { - print_var(m[k], out); - } - return out; -} - -std::ostream& core::print_monic_with_vars(const monic& m, std::ostream& out) const { - out << "[" << pp(m.var()) << "]\n"; - out << "vars:"; print_product_with_vars(m.vars(), out) << "\n"; - if (m.vars() == m.rvars()) - out << "same rvars, and m.rsign = " << m.rsign() << " of course\n"; - else { - out << "rvars:"; print_product_with_vars(m.rvars(), out) << "\n"; - out << "rsign:" << m.rsign() << "\n"; - } - return out; -} - -std::ostream& core::print_explanation(const lp::explanation& exp, std::ostream& out) const { - out << "expl: "; - unsigned i = 0; - for (auto p : exp) { - out << "(" << p.ci() << ")"; - m_lar_solver.constraints().display(out, [this](lpvar j) { return var_str(j);}, p.ci()); - if (++i < exp.size()) - out << " "; - } - return out; -} - -bool core::explain_upper_bound(const lp::lar_term& t, const rational& rs, lp::explanation& e) const { - rational b(0); // the bound - for (lp::lar_term::ival p : t) { - rational pb; - if (explain_coeff_upper_bound(p, pb, e)) { - b += pb; - } else { - e.clear(); - return false; - } - } - if (b > rs ) { - e.clear(); - return false; - } - return true; -} -bool core::explain_lower_bound(const lp::lar_term& t, const rational& rs, lp::explanation& e) const { - rational b(0); // the bound - for (lp::lar_term::ival p : t) { - rational pb; - if (explain_coeff_lower_bound(p, pb, e)) { - b += pb; - } else { - e.clear(); - return false; - } - } - if (b < rs ) { - e.clear(); - return false; - } - return true; -} - -bool core::explain_coeff_lower_bound(const lp::lar_term::ival& p, rational& bound, lp::explanation& e) const { - const rational& a = p.coeff(); - SASSERT(!a.is_zero()); - unsigned c; // the index for the lower or the upper bound - if (a.is_pos()) { - unsigned c = m_lar_solver.get_column_lower_bound_witness(p.column()); - if (c + 1 == 0) - return false; - bound = a * m_lar_solver.get_lower_bound(p.column()).x; - e.push_back(c); - return true; - } - // a.is_neg() - c = m_lar_solver.get_column_upper_bound_witness(p.column()); - if (c + 1 == 0) - return false; - bound = a * m_lar_solver.get_upper_bound(p.column()).x; - e.push_back(c); - return true; -} - -bool core::explain_coeff_upper_bound(const lp::lar_term::ival& p, rational& bound, lp::explanation& e) const { - const rational& a = p.coeff(); - lpvar j = p.column(); - SASSERT(!a.is_zero()); - unsigned c; // the index for the lower or the upper bound - if (a.is_neg()) { - unsigned c = m_lar_solver.get_column_lower_bound_witness(j); - if (c + 1 == 0) - return false; - bound = a * m_lar_solver.get_lower_bound(j).x; - e.push_back(c); - return true; - } - // a.is_pos() - c = m_lar_solver.get_column_upper_bound_witness(j); - if (c + 1 == 0) - return false; - bound = a * m_lar_solver.get_upper_bound(j).x; - e.push_back(c); - return true; -} - -// return true iff the negation of the ineq can be derived from the constraints -bool core::explain_ineq(new_lemma& lemma, const lp::lar_term& t, llc cmp, const rational& rs) { - // check that we have something like 0 < 0, which is always false and can be safely - // removed from the lemma - - if (t.is_empty() && rs.is_zero() && - (cmp == llc::LT || cmp == llc::GT || cmp == llc::NE)) return true; - lp::explanation exp; - bool r; - switch (negate(cmp)) { - case llc::LE: - r = explain_upper_bound(t, rs, exp); - break; - case llc::LT: - r = explain_upper_bound(t, rs - rational(1), exp); - break; - case llc::GE: - r = explain_lower_bound(t, rs, exp); - break; - case llc::GT: - r = explain_lower_bound(t, rs + rational(1), exp); - break; - - case llc::EQ: - r = (explain_lower_bound(t, rs, exp) && explain_upper_bound(t, rs, exp)) || - (rs.is_zero() && explain_by_equiv(t, exp)); - break; - case llc::NE: - // TBD - NB: does this work for Reals? - r = explain_lower_bound(t, rs + rational(1), exp) || explain_upper_bound(t, rs - rational(1), exp); - break; - default: - UNREACHABLE(); - return false; - } - if (r) { - lemma &= exp; - return true; - } - - return false; -} - -/** - * \brief - if t is an octagon term -+x -+ y try to explain why the term always is - equal zero -*/ -bool core::explain_by_equiv(const lp::lar_term& t, lp::explanation& e) const { - lpvar i,j; - bool sign; - if (!is_octagon_term(t, sign, i, j)) - return false; - if (m_evars.find(signed_var(i, false)) != m_evars.find(signed_var(j, sign))) - return false; - - m_evars.explain(signed_var(i, false), signed_var(j, sign), e); - TRACE("nla_solver", tout << "explained :"; m_lar_solver.print_term_as_indices(t, tout);); - return true; -} - -void core::mk_ineq_no_expl_check(new_lemma& lemma, lp::lar_term& t, llc cmp, const rational& rs) { - TRACE("nla_solver_details", m_lar_solver.print_term_as_indices(t, tout << "t = ");); - lemma |= ineq(cmp, t, rs); - CTRACE("nla_solver", ineq_holds(ineq(cmp, t, rs)), print_ineq(ineq(cmp, t, rs), tout) << "\n";); - SASSERT(!ineq_holds(ineq(cmp, t, rs))); -} - -llc apply_minus(llc cmp) { - switch(cmp) { - case llc::LE: return llc::GE; - case llc::LT: return llc::GT; - case llc::GE: return llc::LE; - case llc::GT: return llc::LT; - default: break; - } - return cmp; -} - -// the monics should be equal by modulo sign but this is not so in the model -void core::fill_explanation_and_lemma_sign(new_lemma& lemma, const monic& a, const monic & b, rational const& sign) { - SASSERT(sign == 1 || sign == -1); - lemma &= a; - lemma &= b; - TRACE("nla_solver", tout << "used constraints: " << lemma;); - SASSERT(lemma.num_ineqs() == 0); - lemma |= ineq(term(rational(1), a.var(), -sign, b.var()), llc::EQ, 0); -} - -// Replaces each variable index by the root in the tree and flips the sign if the var comes with a minus. -// Also sorts the result. -// -svector core::reduce_monic_to_rooted(const svector & vars, rational & sign) const { - svector ret; - bool s = false; - for (lpvar v : vars) { - auto root = m_evars.find(v); - s ^= root.sign(); - TRACE("nla_solver_eq", - tout << pp(v) << " mapped to " << pp(root.var()) << "\n";); - ret.push_back(root.var()); - } - sign = rational(s? -1: 1); - std::sort(ret.begin(), ret.end()); - return ret; -} - - -// Replaces definition m_v = v1* .. * vn by -// m_v = coeff * w1 * ... * wn, where w1, .., wn are canonical -// representatives, which are the roots of the equivalence tree, under current equations. -// -monic_coeff core::canonize_monic(monic const& m) const { - rational sign = rational(1); - svector vars = reduce_monic_to_rooted(m.vars(), sign); - return monic_coeff(vars, sign); -} - -int core::vars_sign(const svector& v) { - int sign = 1; - for (lpvar j : v) { - sign *= nla::rat_sign(val(j)); - if (sign == 0) - return 0; - } - return sign; -} - -bool core::has_upper_bound(lpvar j) const { - return m_lar_solver.column_has_upper_bound(j); -} - -bool core::has_lower_bound(lpvar j) const { - return m_lar_solver.column_has_lower_bound(j); -} -const rational& core::get_upper_bound(unsigned j) const { - return m_lar_solver.get_upper_bound(j).x; -} - -const rational& core::get_lower_bound(unsigned j) const { - return m_lar_solver.get_lower_bound(j).x; -} - -bool core::zero_is_an_inner_point_of_bounds(lpvar j) const { - if (has_upper_bound(j) && get_upper_bound(j) <= rational(0)) - return false; - if (has_lower_bound(j) && get_lower_bound(j) >= rational(0)) - return false; - return true; -} - -int core::rat_sign(const monic& m) const { - int sign = 1; - for (lpvar j : m.vars()) { - auto v = val(j); - if (v.is_neg()) { - sign = - sign; - continue; - } - if (v.is_pos()) { - continue; - } - sign = 0; - break; - } - return sign; -} - -// Returns true if the monic sign is incorrect -bool core::sign_contradiction(const monic& m) const { - return nla::rat_sign(var_val(m)) != rat_sign(m); -} - -/* - unsigned_vector eq_vars(lpvar j) const { - TRACE("nla_solver_eq", tout << "j = " << pp(j) << "eqs = "; - for(auto jj : m_evars.eq_vars(j)) tout << pp(jj) << " "; - }); - return m_evars.eq_vars(j); - } -*/ - -bool core::var_is_fixed_to_zero(lpvar j) const { - return - m_lar_solver.column_is_fixed(j) && - m_lar_solver.get_lower_bound(j) == lp::zero_of_type(); -} -bool core::var_is_fixed_to_val(lpvar j, const rational& v) const { - return - m_lar_solver.column_is_fixed(j) && - m_lar_solver.get_lower_bound(j) == lp::impq(v); -} - -bool core::var_is_fixed(lpvar j) const { - return m_lar_solver.column_is_fixed(j); -} - -bool core::var_is_free(lpvar j) const { - return m_lar_solver.column_is_free(j); -} - -std::ostream & core::print_ineq(const ineq & in, std::ostream & out) const { - m_lar_solver.print_term_as_indices(in.term(), out); - out << " " << lconstraint_kind_string(in.cmp()) << " " << in.rs(); - return out; -} - -std::ostream & core::print_var(lpvar j, std::ostream & out) const { - if (m_emons.is_monic_var(j)) { - print_monic(m_emons[j], out); - } - - m_lar_solver.print_column_info(j, out); - signed_var jr = m_evars.find(j); - out << "root="; - if (jr.sign()) { - out << "-"; - } - - out << m_lar_solver.get_variable_name(jr.var()) << "\n"; - return out; -} - -std::ostream & core::print_monics(std::ostream & out) const { - for (auto &m : m_emons) { - print_monic_with_vars(m, out); - } - return out; -} - -std::ostream & core::print_ineqs(const lemma& l, std::ostream & out) const { - std::unordered_set vars; - out << "ineqs: "; - if (l.ineqs().size() == 0) { - out << "conflict\n"; - } else { - for (unsigned i = 0; i < l.ineqs().size(); i++) { - auto & in = l.ineqs()[i]; - print_ineq(in, out); - if (i + 1 < l.ineqs().size()) out << " or "; - for (lp::lar_term::ival p: in.term()) - vars.insert(p.column()); - } - out << std::endl; - for (lpvar j : vars) { - print_var(j, out); - } - out << "\n"; - } - return out; -} - -std::ostream & core::print_factorization(const factorization& f, std::ostream& out) const { - if (f.is_mon()){ - out << "is_mon " << pp_mon(*this, f.mon()); - } - else { - for (unsigned k = 0; k < f.size(); k++ ) { - out << "(" << pp(f[k]) << ")"; - if (k < f.size() - 1) - out << "*"; - } - } - return out; -} - -bool core::find_canonical_monic_of_vars(const svector& vars, lpvar & i) const { - monic const* sv = m_emons.find_canonical(vars); - return sv && (i = sv->var(), true); -} - -bool core::is_canonical_monic(lpvar j) const { - return m_emons.is_canonical_monic(j); -} - - -void core::trace_print_monic_and_factorization(const monic& rm, const factorization& f, std::ostream& out) const { - out << "rooted vars: "; - print_product(rm.rvars(), out) << "\n"; - out << "mon: " << pp_mon(*this, rm.var()) << "\n"; - out << "value: " << var_val(rm) << "\n"; - print_factorization(f, out << "fact: ") << "\n"; -} - - -bool core::var_has_positive_lower_bound(lpvar j) const { - return m_lar_solver.column_has_lower_bound(j) && m_lar_solver.get_lower_bound(j) > lp::zero_of_type(); -} - -bool core::var_has_negative_upper_bound(lpvar j) const { - return m_lar_solver.column_has_upper_bound(j) && m_lar_solver.get_upper_bound(j) < lp::zero_of_type(); -} - -bool core::var_is_separated_from_zero(lpvar j) const { - return - var_has_negative_upper_bound(j) || - var_has_positive_lower_bound(j); -} - - -bool core::vars_are_equiv(lpvar a, lpvar b) const { - SASSERT(abs(val(a)) == abs(val(b))); - return m_evars.vars_are_equiv(a, b); -} - -bool core::has_zero_factor(const factorization& factorization) const { - for (factor f : factorization) { - if (val(f).is_zero()) - return true; - } - return false; -} - - -template -bool core::mon_has_zero(const T& product) const { - for (lpvar j: product) { - if (val(j).is_zero()) - return true; - } - return false; -} - -template bool core::mon_has_zero(const unsigned_vector& product) const; - - -lp::lp_settings& core::lp_settings() { - return m_lar_solver.settings(); -} -const lp::lp_settings& core::lp_settings() const { - return m_lar_solver.settings(); -} - -unsigned core::random() { return lp_settings().random_next(); } - - -// we look for octagon constraints here, with a left part +-x +- y -void core::collect_equivs() { - const lp::lar_solver& s = m_lar_solver; - - for (unsigned i = 0; i < s.terms().size(); i++) { - if (!s.term_is_used_as_row(i)) - continue; - lpvar j = s.external_to_local(lp::tv::mask_term(i)); - if (var_is_fixed_to_zero(j)) { - TRACE("nla_solver_mons", s.print_term_as_indices(*s.terms()[i], tout << "term = ") << "\n";); - add_equivalence_maybe(s.terms()[i], s.get_column_upper_bound_witness(j), s.get_column_lower_bound_witness(j)); - } - } - m_emons.ensure_canonized(); -} - - -// returns true iff the term is in a form +-x-+y. -// the sign is true iff the term is x+y, -x-y. -bool core::is_octagon_term(const lp::lar_term& t, bool & sign, lpvar& i, lpvar &j) const { - if (t.size() != 2) - return false; - bool seen_minus = false; - bool seen_plus = false; - i = null_lpvar; - for(lp::lar_term::ival p : t) { - const auto & c = p.coeff(); - if (c == 1) { - seen_plus = true; - } else if (c == - 1) { - seen_minus = true; - } else { - return false; - } - if (i == null_lpvar) - i = p.column(); - else - j = p.column(); - } - SASSERT(j != null_lpvar); - sign = (seen_minus && seen_plus)? false : true; - return true; -} - -void core::add_equivalence_maybe(const lp::lar_term *t, lpci c0, lpci c1) { - bool sign; - lpvar i, j; - if (!is_octagon_term(*t, sign, i, j)) - return; - if (sign) - m_evars.merge_minus(i, j, eq_justification({c0, c1})); - else - m_evars.merge_plus(i, j, eq_justification({c0, c1})); -} - -// x is equivalent to y if x = +- y -void core::init_vars_equivalence() { - collect_equivs(); - // SASSERT(tables_are_ok()); -} - -bool core::vars_table_is_ok() const { - // return m_var_eqs.is_ok(); - return true; -} - -bool core::rm_table_is_ok() const { - // return m_emons.is_ok(); - return true; -} - -bool core::tables_are_ok() const { - return vars_table_is_ok() && rm_table_is_ok(); -} - -bool core::var_is_a_root(lpvar j) const { return m_evars.is_root(j); } - -template -bool core::vars_are_roots(const T& v) const { - for (lpvar j: v) { - if (!var_is_a_root(j)) - return false; - } - return true; -} - - - -template -void core::trace_print_rms(const T& p, std::ostream& out) { - out << "p = {\n"; - for (auto j : p) { - out << "j = " << j << ", rm = " << m_emons[j] << "\n"; - } - out << "}"; -} - -void core::print_monic_stats(const monic& m, std::ostream& out) { - if (m.size() == 2) return; - monic_coeff mc = canonize_monic(m); - for(unsigned i = 0; i < mc.vars().size(); i++){ - if (abs(val(mc.vars()[i])) == rational(1)) { - auto vv = mc.vars(); - vv.erase(vv.begin()+i); - monic const* sv = m_emons.find_canonical(vv); - if (!sv) { - out << "nf length" << vv.size() << "\n"; ; - } - } - } -} - -void core::print_stats(std::ostream& out) { -} - - -void core::clear() { - m_lemma_vec->clear(); -} - -void core::init_search() { - TRACE("nla_solver_mons", tout << "init\n";); - SASSERT(m_emons.invariant()); - clear(); - init_vars_equivalence(); - SASSERT(m_emons.invariant()); - SASSERT(elists_are_consistent(false)); -} - -void core::insert_to_refine(lpvar j) { - TRACE("lar_solver", tout << "j=" << j << '\n';); - m_to_refine.insert(j); -} - -void core::erase_from_to_refine(lpvar j) { - TRACE("lar_solver", tout << "j=" << j << '\n';); - m_to_refine.erase(j); -} - - -void core::init_to_refine() { - TRACE("nla_solver_details", tout << "emons:" << pp_emons(*this, m_emons);); - m_to_refine.clear(); - m_to_refine.resize(m_lar_solver.number_of_vars()); - unsigned r = random(), sz = m_emons.number_of_monics(); - for (unsigned k = 0; k < sz; k++) { - auto const & m = *(m_emons.begin() + (k + r)% sz); - if (!check_monic(m)) - insert_to_refine(m.var()); - } - - TRACE("nla_solver", - tout << m_to_refine.size() << " mons to refine:\n"; - for (lpvar v : m_to_refine) tout << pp_mon(*this, m_emons[v]) << ":error = " << - (val(v) - mul_val(m_emons[v])).get_double() << "\n";); -} - -std::unordered_set core::collect_vars(const lemma& l) const { - std::unordered_set vars; - auto insert_j = [&](lpvar j) { - vars.insert(j); - if (m_emons.is_monic_var(j)) { - for (lpvar k : m_emons[j].vars()) - vars.insert(k); - } - }; - - for (const auto& i : l.ineqs()) { - for (lp::lar_term::ival p : i.term()) { - insert_j(p.column()); - } - } - for (auto p : l.expl()) { - const auto& c = m_lar_solver.constraints()[p.ci()]; - for (const auto& r : c.coeffs()) { - insert_j(r.second); - } - } - return vars; -} - -// divides bc by c, so bc = b*c -bool core::divide(const monic& bc, const factor& c, factor & b) const { - svector c_rvars = sorted_rvars(c); - TRACE("nla_solver_div", tout << "c_rvars = "; print_product(c_rvars, tout); tout << "\nbc_rvars = "; print_product(bc.rvars(), tout);); - if (!lp::is_proper_factor(c_rvars, bc.rvars())) - return false; - - auto b_rvars = lp::vector_div(bc.rvars(), c_rvars); - TRACE("nla_solver_div", tout << "b_rvars = "; print_product(b_rvars, tout);); - SASSERT(b_rvars.size() > 0); - if (b_rvars.size() == 1) { - b = factor(b_rvars[0], factor_type::VAR); - } else { - monic const* sv = m_emons.find_canonical(b_rvars); - if (sv == nullptr) { - TRACE("nla_solver_div", tout << "not in rooted";); - return false; - } - b = factor(sv->var(), factor_type::MON); - } - SASSERT(!b.sign()); - // We have bc = canonize_sign(bc)*bc.rvars() = canonize_sign(b)*b.rvars()*canonize_sign(c)*c.rvars(). - // Dividing by bc.rvars() we get canonize_sign(bc) = canonize_sign(b)*canonize_sign(c) - // Currently, canonize_sign(b) is 1, we might need to adjust it - b.sign() = canonize_sign(b) ^ canonize_sign(c) ^ canonize_sign(bc); - TRACE("nla_solver", tout << "success div:" << pp(b) << "\n";); - return true; -} - - -void core::negate_factor_equality(new_lemma& lemma, const factor& c, - const factor& d) { - if (c == d) - return; - lpvar i = var(c); - lpvar j = var(d); - auto iv = val(i), jv = val(j); - SASSERT(abs(iv) == abs(jv)); - lemma |= ineq(term(i, rational(iv == jv ? -1 : 1), j), llc::NE, 0); -} - -void core::negate_factor_relation(new_lemma& lemma, const rational& a_sign, const factor& a, const rational& b_sign, const factor& b) { - rational a_fs = sign_to_rat(canonize_sign(a)); - rational b_fs = sign_to_rat(canonize_sign(b)); - llc cmp = a_sign*val(a) < b_sign*val(b)? llc::GE : llc::LE; - lemma |= ineq(term(a_fs*a_sign, var(a), - b_fs*b_sign, var(b)), cmp, 0); -} - -std::ostream& core::print_lemma(const lemma& l, std::ostream& out) const { - static int n = 0; - out << "lemma:" << ++n << " "; - print_ineqs(l, out); - print_explanation(l.expl(), out); - for (lpvar j : collect_vars(l)) { - print_var(j, out); - } - return out; -} - - -void core::trace_print_ol(const monic& ac, - const factor& a, - const factor& c, - const monic& bc, - const factor& b, - std::ostream& out) { - out << "ac = " << pp_mon(*this, ac) << "\n"; - out << "bc = " << pp_mon(*this, bc) << "\n"; - out << "a = "; - print_factor_with_vars(a, out); - out << ", \nb = "; - print_factor_with_vars(b, out); - out << "\nc = "; - print_factor_with_vars(c, out); -} - -void core::maybe_add_a_factor(lpvar i, - const factor& c, - std::unordered_set& found_vars, - std::unordered_set& found_rm, - vector & r) const { - SASSERT(abs(val(i)) == abs(val(c))); - if (!m_emons.is_monic_var(i)) { - i = m_evars.find(i).var(); - if (try_insert(i, found_vars)) { - r.push_back(factor(i, factor_type::VAR)); - } - } else { - if (try_insert(i, found_rm)) { - r.push_back(factor(i, factor_type::MON)); - TRACE("nla_solver", tout << "inserting factor = "; print_factor_with_vars(factor(i, factor_type::MON), tout); ); - } - } -} - - -// Returns rooted monics by arity -std::unordered_map core::get_rm_by_arity() { - std::unordered_map m; - for (auto const& mon : m_emons) { - unsigned arity = mon.vars().size(); - auto it = m.find(arity); - if (it == m.end()) { - it = m.insert(it, std::make_pair(arity, unsigned_vector())); - } - it->second.push_back(mon.var()); - } - return m; -} - -bool core::rm_check(const monic& rm) const { - return check_monic(m_emons[rm.var()]); -} - - -bool core::find_bfc_to_refine_on_monic(const monic& m, factorization & bf) { - for (auto f : factorization_factory_imp(m, *this)) { - if (f.size() == 2) { - auto a = f[0]; - auto b = f[1]; - if (var_val(m) != val(a) * val(b)) { - bf = f; - TRACE("nla_solver", tout << "found bf"; - tout << ":m:" << pp_mon_with_vars(*this, m) << "\n"; - tout << "bf:"; print_bfc(bf, tout);); - - return true; - } - } - } - return false; -} - -// finds a monic to refine with its binary factorization -bool core::find_bfc_to_refine(const monic* & m, factorization & bf){ - m = nullptr; - unsigned r = random(), sz = m_to_refine.size(); - for (unsigned k = 0; k < sz; k++) { - lpvar i = m_to_refine[(k + r) % sz]; - m = &m_emons[i]; - SASSERT (!check_monic(*m)); - if (has_real(m)) - continue; - if (m->size() == 2) { - bf.set_mon(m); - bf.push_back(factor(m->vars()[0], factor_type::VAR)); - bf.push_back(factor(m->vars()[1], factor_type::VAR)); - return true; - } - - if (find_bfc_to_refine_on_monic(*m, bf)) { - TRACE("nla_solver", - tout << "bf = "; print_factorization(bf, tout); - tout << "\nval(*m) = " << var_val(*m) << ", should be = (val(bf[0])=" << val(bf[0]) << ")*(val(bf[1]) = " << val(bf[1]) << ") = " << val(bf[0])*val(bf[1]) << "\n";); - return true; - } - } - return false; -} - -rational core::val(const factorization& f) const { - rational r(1); - for (const factor &p : f) { - r *= val(p); - } - return r; -} - -new_lemma::new_lemma(core& c, char const* name):name(name), c(c) { - c.m_lemma_vec->push_back(lemma()); -} - -new_lemma& new_lemma::operator|=(ineq const& ineq) { - if (!c.explain_ineq(*this, ineq.term(), ineq.cmp(), ineq.rs())) { - CTRACE("nla_solver", c.ineq_holds(ineq), c.print_ineq(ineq, tout) << "\n";); - SASSERT(!c.ineq_holds(ineq)); - current().push_back(ineq); - } - return *this; -} - - -new_lemma::~new_lemma() { - static int i = 0; - (void)i; - (void)name; - // code for checking lemma can be added here - TRACE("nla_solver", tout << name << " " << (++i) << "\n" << *this; ); -} - -lemma& new_lemma::current() const { - return c.m_lemma_vec->back(); -} - -new_lemma& new_lemma::operator&=(lp::explanation const& e) { - expl().add_expl(e); - return *this; -} - -new_lemma& new_lemma::operator&=(const monic& m) { - for (lpvar j : m.vars()) - *this &= j; - return *this; -} - -new_lemma& new_lemma::operator&=(const factor& f) { - if (f.type() == factor_type::VAR) - *this &= f.var(); - else - *this &= c.m_emons[f.var()]; - return *this; -} - -new_lemma& new_lemma::operator&=(const factorization& f) { - if (f.is_mon()) - return *this; - for (const auto& fc : f) { - *this &= fc; - } - return *this; -} - -new_lemma& new_lemma::operator&=(lpvar j) { - c.m_evars.explain(j, expl()); - return *this; -} - -new_lemma& new_lemma::explain_fixed(lpvar j) { - SASSERT(c.var_is_fixed(j)); - explain_existing_lower_bound(j); - explain_existing_upper_bound(j); - return *this; -} - -new_lemma& new_lemma::explain_equiv(lpvar a, lpvar b) { - SASSERT(abs(c.val(a)) == abs(c.val(b))); - if (c.vars_are_equiv(a, b)) { - *this &= a; - *this &= b; - } else { - explain_fixed(a); - explain_fixed(b); - } - return *this; -} - -new_lemma& new_lemma::explain_var_separated_from_zero(lpvar j) { - SASSERT(c.var_is_separated_from_zero(j)); - if (c.m_lar_solver.column_has_upper_bound(j) && - (c.m_lar_solver.get_upper_bound(j)< lp::zero_of_type())) - explain_existing_upper_bound(j); - else - explain_existing_lower_bound(j); - return *this; -} - -new_lemma& new_lemma::explain_existing_lower_bound(lpvar j) { - SASSERT(c.has_lower_bound(j)); - lp::explanation ex; - ex.push_back(c.m_lar_solver.get_column_lower_bound_witness(j)); - *this &= ex; - TRACE("nla_solver", tout << j << ": " << *this << "\n";); - return *this; -} - -new_lemma& new_lemma::explain_existing_upper_bound(lpvar j) { - SASSERT(c.has_upper_bound(j)); - lp::explanation ex; - ex.push_back(c.m_lar_solver.get_column_upper_bound_witness(j)); - *this &= ex; - return *this; -} - -std::ostream& new_lemma::display(std::ostream & out) const { - auto const& lemma = current(); - - for (auto p : lemma.expl()) { - out << "(" << p.ci() << ") "; - c.m_lar_solver.constraints().display(out, [this](lpvar j) { return c.var_str(j);}, p.ci()); - } - out << " ==> "; - if (lemma.ineqs().empty()) { - out << "false"; - } - else { - bool first = true; - for (auto & in : lemma.ineqs()) { - if (first) first = false; else out << " or "; - c.print_ineq(in, out); - } - } - out << "\n"; - for (lpvar j : c.collect_vars(lemma)) { - c.print_var(j, out); - } - return out; -} - -void core::negate_relation(new_lemma& lemma, unsigned j, const rational& a) { - SASSERT(val(j) != a); - lemma |= ineq(j, val(j) < a ? llc::GE : llc::LE, a); -} - -bool core::conflict_found() const { - for (const auto & l : * m_lemma_vec) { - if (l.is_conflict()) - return true; - } - return false; -} - -bool core::done() const { - return m_lemma_vec->size() >= 10 || - conflict_found() || - lp_settings().get_cancel_flag(); -} - -bool core::elist_is_consistent(const std::unordered_set & list) const { - bool first = true; - bool p; - for (lpvar j : list) { - if (first) { - p = check_monic(m_emons[j]); - first = false; - } else - if (check_monic(m_emons[j]) != p) - return false; - } - return true; -} - -bool core::elists_are_consistent(bool check_in_model) const { - std::unordered_map, hash_svector> lists; - if (!m_emons.elists_are_consistent(lists)) - return false; - - if (!check_in_model) - return true; - for (const auto & p : lists) { - if (! elist_is_consistent(p.second)) - return false; - } - return true; -} - -bool core::var_breaks_correct_monic_as_factor(lpvar j, const monic& m) const { - if (!val(var(m)).is_zero()) - return true; - - if (!val(j).is_zero()) // j was not zero: the new value does not matter - m must have another zero factor - return false; - // do we have another zero in m? - for (lpvar k : m) { - if (k != j && val(k).is_zero()) { - return false; // not breaking - } - } - // j was the only zero in m - return true; -} - -bool core::var_breaks_correct_monic(lpvar j) const { - if (emons().is_monic_var(j) && !m_to_refine.contains(j)) { - TRACE("nla_solver", tout << "j = " << j << ", m = "; print_monic(emons()[j], tout) << "\n";); - return true; // changing the value of a correct monic - } - - for (const monic & m : emons().get_use_list(j)) { - if (m_to_refine.contains(m.var())) - continue; - if (var_breaks_correct_monic_as_factor(j, m)) - return true; - } - - return false; -} - -void core::update_to_refine_of_var(lpvar j) { - for (const monic & m : emons().get_use_list(j)) { - if (var_val(m) == mul_val(m)) - erase_from_to_refine(var(m)); - else - insert_to_refine(var(m)); - } - if (is_monic_var(j)) { - const monic& m = emons()[j]; - if (var_val(m) == mul_val(m)) - erase_from_to_refine(j); - else - insert_to_refine(j); - } -} - -bool core::var_is_big(lpvar j) const { - return !var_is_int(j) && val(j).is_big(); -} - -bool core::has_big_num(const monic& m) const { - if (var_is_big(var(m))) - return true; - for (lpvar j : m.vars()) - if (var_is_big(j)) - return true; - return false; -} - -bool core::has_real(const factorization& f) const { - for (const factor& fc: f) { - lpvar j = var(fc); - if (!var_is_int(j)) - return true; - } - return false; -} - -bool core::has_real(const monic& m) const { - for (lpvar j : m.vars()) - if (!var_is_int(j)) - return true; - return false; -} - -// returns true if the patching is blocking -bool core::is_patch_blocked(lpvar u, const lp::impq& ival) const { - TRACE("nla_solver", tout << "u = " << u << '\n';); - if (m_cautious_patching && - (!m_lar_solver.inside_bounds(u, ival) || (var_is_int(u) && ival.is_int() == false))) { - TRACE("nla_solver", tout << "u = " << u << " blocked, for feas or integr\n";); - return true; // block - } - - if (u == m_patched_var) { - TRACE("nla_solver", tout << "u == m_patched_var, no block\n";); - - return false; // do not block - } - // we can change only one variable in variables of m_patched_var - if (m_patched_monic->contains_var(u) || u == var(*m_patched_monic)) { - TRACE("nla_solver", tout << "u = " << u << " blocked as contained\n";); - return true; // block - } - - if (var_breaks_correct_monic(u)) { - TRACE("nla_solver", tout << "u = " << u << " blocked as used in a correct monomial\n";); - return true; - } - - TRACE("nla_solver", tout << "u = " << u << ", m_patched_m = "; print_monic(*m_patched_monic, tout) << - ", not blocked\n";); - - return false; -} - -// it tries to patch m_patched_var -bool core::try_to_patch(const rational& v) { - auto is_blocked = [this](lpvar u, const lp::impq& iv) { return is_patch_blocked(u, iv); }; - auto change_report = [this](lpvar u) { update_to_refine_of_var(u); }; - return m_lar_solver.try_to_patch(m_patched_var, v, is_blocked, change_report); -} - -bool in_power(const svector& vs, unsigned l) { - unsigned k = vs[l]; - return (l != 0 && vs[l - 1] == k) || (l + 1 < vs.size() && k == vs[l + 1]); -} - -bool core::to_refine_is_correct() const { - for (unsigned j = 0; j < m_lar_solver.number_of_vars(); j++) { - if (!emons().is_monic_var(j)) continue; - bool valid = check_monic(emons()[j]); - if (valid == m_to_refine.contains(j)) { - TRACE("nla_solver", tout << "inconstency in m_to_refine : "; - print_monic(emons()[j], tout) << "\n"; - if (valid) tout << "should NOT be in to_refine\n"; - else tout << "should be in to_refine\n";); - return false; - } - } - return true; -} - -void core::patch_monomial(lpvar j) { - m_patched_monic =& (emons()[j]); - m_patched_var = j; - TRACE("nla_solver", tout << "m = "; print_monic(*m_patched_monic, tout) << "\n";); - rational v = mul_val(*m_patched_monic); - if (val(j) == v) { - erase_from_to_refine(j); - return; - } - if (!var_breaks_correct_monic(j) && try_to_patch(v)) { - SASSERT(to_refine_is_correct()); - return; - } - - // We could not patch j, now we try patching the factor variables. - TRACE("nla_solver", tout << " trying squares\n";); - // handle perfect squares - if ((*m_patched_monic).vars().size() == 2 && (*m_patched_monic).vars()[0] == (*m_patched_monic).vars()[1]) { - rational root; - if (v.is_perfect_square(root)) { - m_patched_var = (*m_patched_monic).vars()[0]; - if (!var_breaks_correct_monic(m_patched_var) && (try_to_patch(root) || try_to_patch(-root))) { - TRACE("nla_solver", tout << "patched square\n";); - return; - } - } - TRACE("nla_solver", tout << " cannot patch\n";); - return; - } - - // We have v != abc, but we need to have v = abc. - // If we patch b then b should be equal to v/ac = v/(abc/b) = b(v/abc) - if (!v.is_zero()) { - rational r = val(j) / v; - SASSERT((*m_patched_monic).is_sorted()); - TRACE("nla_solver", tout << "r = " << r << ", v = " << v << "\n";); - for (unsigned l = 0; l < (*m_patched_monic).size(); l++) { - m_patched_var = (*m_patched_monic).vars()[l]; - if (!in_power((*m_patched_monic).vars(), l) && - !var_breaks_correct_monic(m_patched_var) && - try_to_patch(r * val(m_patched_var))) { // r * val(k) gives the right value of k - TRACE("nla_solver", tout << "patched " << m_patched_var << "\n";); - SASSERT(mul_val((*m_patched_monic)) == val(j)); - erase_from_to_refine(j); - break; - } - } - } -} - -void core::patch_monomials_on_to_refine() { - auto to_refine = m_to_refine.index(); - // the rest of the function might change m_to_refine, so have to copy - unsigned sz = to_refine.size(); - - unsigned start = random(); - for (unsigned i = 0; i < sz; i++) { - patch_monomial(to_refine[(start + i) % sz]); - if (m_to_refine.size() == 0) - break; - } - TRACE("nla_solver", tout << "sz = " << sz << ", m_to_refine = " << m_to_refine.size() << - (sz > m_to_refine.size()? " less" : "same" ) << "\n";); -} - -void core::patch_monomials() { - m_cautious_patching = true; - patch_monomials_on_to_refine(); - if (m_to_refine.size() == 0 || !m_nla_settings.expensive_patching()) { - return; - } - NOT_IMPLEMENTED_YET(); - m_cautious_patching = false; - patch_monomials_on_to_refine(); - m_lar_solver.push(); - save_tableau(); - constrain_nl_in_tableau(); - if (solve_tableau() && integrality_holds()) { - m_lar_solver.pop(1); - } else { - m_lar_solver.pop(); - restore_tableau(); - m_lar_solver.clear_inf_set(); - } - SASSERT(m_lar_solver.ax_is_correct()); -} - -void core::constrain_nl_in_tableau() { - NOT_IMPLEMENTED_YET(); -} - -bool core::solve_tableau() { - NOT_IMPLEMENTED_YET(); - return false; -} - -void core::restore_tableau() { - NOT_IMPLEMENTED_YET(); -} - -void core::save_tableau() { - NOT_IMPLEMENTED_YET(); -} - -bool core::integrality_holds() { - NOT_IMPLEMENTED_YET(); - return false; -} - -/** - * Cycle through different end-game solvers weighted by probability. - */ -void core::check_weighted(unsigned sz, std::pair>* checks) { - unsigned bound = 0; - for (unsigned i = 0; i < sz; ++i) - bound += checks[i].first; - uint_set seen; - while (bound > 0 && !done() && m_lemma_vec->empty()) { - unsigned n = random() % bound; - for (unsigned i = 0; i < sz; ++i) { - if (seen.contains(i)) - continue; - if (n < checks[i].first) { - seen.insert(i); - checks[i].second(); - bound -= checks[i].first; - break; - } - n -= checks[i].first; - } - } -} - - -lbool core::check(vector& l_vec) { - lp_settings().stats().m_nla_calls++; - TRACE("nla_solver", tout << "calls = " << lp_settings().stats().m_nla_calls << "\n";); - m_lar_solver.get_rid_of_inf_eps(); - m_lemma_vec = &l_vec; - if (!(m_lar_solver.get_status() == lp::lp_status::OPTIMAL || - m_lar_solver.get_status() == lp::lp_status::FEASIBLE)) { - TRACE("nla_solver", tout << "unknown because of the m_lar_solver.m_status = " << m_lar_solver.get_status() << "\n";); - return l_undef; - } - - init_to_refine(); - patch_monomials(); - set_use_nra_model(false); - if (m_to_refine.empty()) { return l_true; } - init_search(); - - lbool ret = l_undef; - - if (l_vec.empty() && !done()) - m_monomial_bounds(); - - if (l_vec.empty() && !done() && need_run_horner()) - m_horner.horner_lemmas(); - - if (l_vec.empty() && !done() && need_run_grobner()) - run_grobner(); - - if (l_vec.empty() && !done()) - m_basics.basic_lemma(true); - - if (l_vec.empty() && !done()) - m_basics.basic_lemma(false); - - if (!conflict_found() && !done() && should_run_bounded_nlsat()) - ret = bounded_nlsat(); - - - if (l_vec.empty() && !done() && ret == l_undef) { - std::function check1 = [&]() { m_order.order_lemma(); }; - std::function check2 = [&]() { m_monotone.monotonicity_lemma(); }; - std::function check3 = [&]() { m_tangents.tangent_lemma(); }; - - std::pair> checks[] = - { { 6, check1 }, - { 2, check2 }, - { 1, check3 }}; - check_weighted(3, checks); - - unsigned num_calls = lp_settings().stats().m_nla_calls; - if (!conflict_found() && m_nla_settings.run_nra() && num_calls % 50 == 0 && num_calls > 500) - ret = bounded_nlsat(); - } - - if (l_vec.empty() && !done() && m_nla_settings.run_nra() && ret == l_undef) { - ret = m_nra.check(); - m_stats.m_nra_calls++; - } - - if (ret == l_undef && !l_vec.empty() && m_reslim.inc()) - ret = l_false; - - m_stats.m_nla_lemmas += l_vec.size(); - for (const auto& l : l_vec) - m_stats.m_nla_explanations += static_cast(l.expl().size()); - - - TRACE("nla_solver", tout << "ret = " << ret << ", lemmas count = " << l_vec.size() << "\n";); - IF_VERBOSE(2, if(ret == l_undef) {verbose_stream() << "Monomials\n"; print_monics(verbose_stream());}); - CTRACE("nla_solver", ret == l_undef, tout << "Monomials\n"; print_monics(tout);); - return ret; -} - -bool core::should_run_bounded_nlsat() { - if (!m_nla_settings.run_nra()) - return false; - if (m_nlsat_delay > m_nlsat_fails) - ++m_nlsat_fails; - return m_nlsat_delay <= m_nlsat_fails; -} - -lbool core::bounded_nlsat() { - params_ref p; - lbool ret; - p.set_uint("max_conflicts", 100); - m_nra.updt_params(p); - { - scoped_limits sl(m_reslim); - sl.push_child(&m_nra_lim); - scoped_rlimit sr(m_nra_lim, 100000); - ret = m_nra.check(); - } - p.set_uint("max_conflicts", UINT_MAX); - m_nra.updt_params(p); - m_stats.m_nra_calls++; - if (ret == l_undef) - ++m_nlsat_delay; - else { - m_nlsat_fails = 0; - m_nlsat_delay /= 2; - } - if (ret == l_true) { - m_lemma_vec->reset(); - } - return ret; -} - -bool core::no_lemmas_hold() const { - for (auto & l : * m_lemma_vec) { - if (lemma_holds(l)) { - TRACE("nla_solver", print_lemma(l, tout);); - return false; - } - } - return true; -} - -lbool core::test_check(vector& l) { - m_lar_solver.set_status(lp::lp_status::OPTIMAL); - return check(l); -} - -std::ostream& core::print_terms(std::ostream& out) const { - for (unsigned i = 0; i< m_lar_solver.terms().size(); i++) { - unsigned ext = lp::tv::mask_term(i); - if (!m_lar_solver.var_is_registered(ext)) { - out << "term is not registered\n"; - continue; - } - - const lp::lar_term & t = *m_lar_solver.terms()[i]; - out << "term:"; print_term(t, out) << std::endl; - lpvar j = m_lar_solver.external_to_local(ext); - print_var(j, out); - } - return out; -} - -std::string core::var_str(lpvar j) const { - return is_monic_var(j)? - (product_indices_str(m_emons[j].vars()) + (check_monic(m_emons[j])? "": "_")) : (std::string("j") + lp::T_to_string(j)); -} - -std::ostream& core::print_term( const lp::lar_term& t, std::ostream& out) const { - return lp::print_linear_combination_customized( - t.coeffs_as_vector(), - [this](lpvar j) { return var_str(j); }, - out); -} - - -void core::run_grobner() { - unsigned& quota = m_nla_settings.grobner_quota(); - if (quota == 1) { - return; - } - clear_and_resize_active_var_set(); - find_nl_cluster(); - - lp_settings().stats().m_grobner_calls++; - configure_grobner(); - m_pdd_grobner.saturate(); - bool conflict = false; - unsigned n = m_pdd_grobner.number_of_conflicts_to_report(); - SASSERT(n > 0); - for (auto eq : m_pdd_grobner.equations()) { - if (check_pdd_eq(eq)) { - conflict = true; - if (--n == 0) - break; - } - } - if (conflict) { - IF_VERBOSE(2, verbose_stream() << "grobner conflict\n"); - } - else { - if (quota > 1) - quota--; - IF_VERBOSE(2, verbose_stream() << "grobner miss, quota " << quota << "\n"); - IF_VERBOSE(4, diagnose_pdd_miss(verbose_stream())); - } -} - -void core::configure_grobner() { - m_pdd_grobner.reset(); - try { - set_level2var_for_grobner(); - for (unsigned i : m_rows) { - add_row_to_grobner(m_lar_solver.A_r().m_rows[i]); - } - } - catch (...) { - IF_VERBOSE(2, verbose_stream() << "pdd throw\n"); - return; - } -#if 0 - IF_VERBOSE(2, m_pdd_grobner.display(verbose_stream())); - dd::pdd_eval eval(m_pdd_manager); - eval.var2val() = [&](unsigned j){ return val(j); }; - for (auto* e : m_pdd_grobner.equations()) { - dd::pdd p = e->poly(); - rational v = eval(p); - if (p.is_linear() && !eval(p).is_zero()) { - IF_VERBOSE(0, verbose_stream() << "violated linear constraint " << p << "\n"); - } - } -#endif - - struct dd::solver::config cfg; - cfg.m_max_steps = m_pdd_grobner.equations().size(); - cfg.m_max_simplified = m_nla_settings.grobner_max_simplified(); - cfg.m_eqs_growth = m_nla_settings.grobner_eqs_growth(); - cfg.m_expr_size_growth = m_nla_settings.grobner_expr_size_growth(); - cfg.m_expr_degree_growth = m_nla_settings.grobner_expr_degree_growth(); - cfg.m_number_of_conflicts_to_report = m_nla_settings.grobner_number_of_conflicts_to_report(); - m_pdd_grobner.set(cfg); - m_pdd_grobner.adjust_cfg(); - m_pdd_manager.set_max_num_nodes(10000); // or something proportional to the number of initial nodes. -} - -std::ostream& core::diagnose_pdd_miss(std::ostream& out) { - - // m_pdd_grobner.display(out); - - dd::pdd_eval eval; - eval.var2val() = [&](unsigned j){ return val(j); }; - for (auto* e : m_pdd_grobner.equations()) { - dd::pdd p = e->poly(); - rational v = eval(p); - if (!v.is_zero()) { - out << p << " := " << v << "\n"; - } - } - - for (unsigned j = 0; j < m_lar_solver.number_of_vars(); ++j) { - if (m_lar_solver.column_has_lower_bound(j) || m_lar_solver.column_has_upper_bound(j)) { - out << j << ": ["; - if (m_lar_solver.column_has_lower_bound(j)) out << m_lar_solver.get_lower_bound(j); - out << ".."; - if (m_lar_solver.column_has_upper_bound(j)) out << m_lar_solver.get_upper_bound(j); - out << "]\n"; - } - } - return out; -} - -bool core::check_pdd_eq(const dd::solver::equation* e) { - auto& di = m_intervals.get_dep_intervals(); - dd::pdd_interval eval(di); - eval.var2interval() = [this](lpvar j, bool deps, scoped_dep_interval& a) { - if (deps) m_intervals.set_var_interval(j, a); - else m_intervals.set_var_interval(j, a); - }; - scoped_dep_interval i(di), i_wd(di); - eval.get_interval(e->poly(), i); - if (!di.separated_from_zero(i)) - return false; - eval.get_interval(e->poly(), i_wd); - std::function f = [this](const lp::explanation& e) { - new_lemma lemma(*this, "pdd"); - lemma &= e; - }; - if (di.check_interval_for_conflict_on_zero(i_wd, e->dep(), f)) { - lp_settings().stats().m_grobner_conflicts++; - return true; - } - else { - return false; - } -} - -void core::add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector & q) { - if (active_var_set_contains(j) || var_is_fixed(j)) return; - TRACE("grobner", tout << "j = " << j << ", " << pp(j);); - const auto& matrix = m_lar_solver.A_r(); - insert_to_active_var_set(j); - for (auto & s : matrix.m_columns[j]) { - unsigned row = s.var(); - if (m_rows.contains(row)) continue; - if (matrix.m_rows[row].size() > m_nla_settings.grobner_row_length_limit()) { - TRACE("grobner", tout << "ignore the row " << row << " with the size " << matrix.m_rows[row].size() << "\n";); - continue; - } - m_rows.insert(row); - for (auto& rc : matrix.m_rows[row]) { - add_var_and_its_factors_to_q_and_collect_new_rows(rc.var(), q); - } - } - - if (!is_monic_var(j)) - return; - - const monic& m = emons()[j]; - for (auto fcn : factorization_factory_imp(m, *this)) { - for (const factor& fc: fcn) { - q.push_back(var(fc)); - } - } -} - -const rational& core::val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep) { - unsigned lc, uc; - m_lar_solver.get_bound_constraint_witnesses_for_column(j, lc, uc); - dep = m_intervals.mk_join(dep, m_intervals.mk_leaf(lc)); - dep = m_intervals.mk_join(dep, m_intervals.mk_leaf(uc)); - return m_lar_solver.column_lower_bound(j).x; -} - -dd::pdd core::pdd_expr(const rational& c, lpvar j, u_dependency*& dep) { - if (m_nla_settings.grobner_subs_fixed() == 1 && var_is_fixed(j)) { - return m_pdd_manager.mk_val(c * val_of_fixed_var_with_deps(j, dep)); - } - - if (m_nla_settings.grobner_subs_fixed() == 2 && var_is_fixed_to_zero(j)) { - return m_pdd_manager.mk_val(val_of_fixed_var_with_deps(j, dep)); - } - - if (!is_monic_var(j)) - return c * m_pdd_manager.mk_var(j); - - u_dependency* zero_dep = dep; - // j is a monic var - dd::pdd r = m_pdd_manager.mk_val(c); - const monic& m = emons()[j]; - for (lpvar k : m.vars()) { - if (m_nla_settings.grobner_subs_fixed() && var_is_fixed(k)) { - r *= m_pdd_manager.mk_val(val_of_fixed_var_with_deps(k, dep)); - } else if (m_nla_settings.grobner_subs_fixed() == 2 && var_is_fixed_to_zero(k)) { - r = m_pdd_manager.mk_val(val_of_fixed_var_with_deps(k, zero_dep)); - dep = zero_dep; - return r; - } else { - r *= m_pdd_manager.mk_var(k); - } - } - return r; -} - -void core::add_row_to_grobner(const vector> & row) { - u_dependency *dep = nullptr; - dd::pdd sum = m_pdd_manager.mk_val(rational(0)); - for (const auto &p : row) { - sum += pdd_expr(p.coeff(), p.var(), dep); - } - m_pdd_grobner.add(sum, dep); -} - - -void core::find_nl_cluster() { - prepare_rows_and_active_vars(); - svector q; - for (lpvar j : m_to_refine) { - TRACE("grobner", print_monic(emons()[j], tout) << "\n";); - q.push_back(j); - } - - while (!q.empty()) { - lpvar j = q.back(); - q.pop_back(); - add_var_and_its_factors_to_q_and_collect_new_rows(j, q); - } - TRACE("grobner", display_matrix_of_m_rows(tout);); -} - -void core::prepare_rows_and_active_vars() { - m_rows.clear(); - m_rows.resize(m_lar_solver.row_count()); - clear_and_resize_active_var_set(); -} - - -std::unordered_set core::get_vars_of_expr_with_opening_terms(const nex *e ) { - auto ret = get_vars_of_expr(e); - auto & ls = m_lar_solver; - svector added; - for (auto j : ret) { - added.push_back(j); - } - for (unsigned i = 0; i < added.size(); ++i) { - lpvar j = added[i]; - if (ls.column_corresponds_to_term(j)) { - const auto& t = m_lar_solver.get_term(lp::tv::raw(ls.local_to_external(j))); - for (auto p : t) { - if (ret.find(p.column()) == ret.end()) { - added.push_back(p.column()); - ret.insert(p.column()); - } - } - } - } - return ret; -} - -void core::display_matrix_of_m_rows(std::ostream & out) const { - const auto& matrix = m_lar_solver.A_r(); - out << m_rows.size() << " rows" <<"\n"; - out << "the matrix\n"; - for (const auto & r : matrix.m_rows) { - print_row(r, out) << std::endl; - } -} - -void core::set_active_vars_weights(nex_creator& nc) { - nc.set_number_of_vars(m_lar_solver.column_count()); - for (lpvar j : active_var_set()) { - nc.set_var_weight(j, get_var_weight(j)); - } -} - -void core::set_level2var_for_grobner() { - unsigned n = m_lar_solver.column_count(); - unsigned_vector sorted_vars(n), weighted_vars(n); - for (unsigned j = 0; j < n; j++) { - sorted_vars[j] = j; - weighted_vars[j] = get_var_weight(j); - } -#if 1 - // potential update to weights - for (unsigned j = 0; j < n; j++) { - if (is_monic_var(j) && m_to_refine.contains(j)) { - for (lpvar k : m_emons[j].vars()) { - weighted_vars[k] += 6; - } - } - } -#endif - - std::sort(sorted_vars.begin(), sorted_vars.end(), [&](unsigned a, unsigned b) { - unsigned wa = weighted_vars[a]; - unsigned wb = weighted_vars[b]; - return wa < wb || (wa == wb && a < b); }); - - unsigned_vector l2v(n); - for (unsigned j = 0; j < n; j++) - l2v[j] = sorted_vars[j]; - - m_pdd_manager.reset(l2v); -} - -unsigned core::get_var_weight(lpvar j) const { - unsigned k; - switch (m_lar_solver.get_column_type(j)) { - - case lp::column_type::fixed: - k = 0; - break; - case lp::column_type::boxed: - k = 2; - break; - case lp::column_type::lower_bound: - case lp::column_type::upper_bound: - k = 4; - break; - case lp::column_type::free_column: - k = 6; - break; - default: - UNREACHABLE(); - break; - } - if (is_monic_var(j)) { - k++; - if (m_to_refine.contains(j)) { - k++; - } - } - return k; -} - -bool core::is_nl_var(lpvar j) const { - return is_monic_var(j) || m_emons.is_used_in_monic(j); -} - -bool core::influences_nl_var(lpvar j) const { - if (lp::tv::is_term(j)) - j = lp::tv::unmask_term(j); - if (is_nl_var(j)) - return true; - for (const auto & c : m_lar_solver.A_r().m_columns[j]) { - lpvar basic_in_row = m_lar_solver.r_basis()[c.var()]; - if (is_nl_var(basic_in_row)) - return true; - } - return false; -} - -void core::collect_statistics(::statistics & st) { - st.update("arith-nla-explanations", m_stats.m_nla_explanations); - st.update("arith-nla-lemmas", m_stats.m_nla_lemmas); - st.update("arith-nra-calls", m_stats.m_nra_calls); -} - - -} // end of nla - + /*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + nla_core.cpp + +Author: + Lev Nachmanson (levnach) + Nikolaj Bjorner (nbjorner) + +--*/ +#include "util/uint_set.h" +#include "math/lp/nla_core.h" +#include "math/lp/factorization_factory_imp.h" +#include "math/lp/nex.h" +#include "math/grobner/pdd_solver.h" +#include "math/dd/pdd_interval.h" +#include "math/dd/pdd_eval.h" +namespace nla { + +typedef lp::lar_term term; + +core::core(lp::lar_solver& s, reslimit & lim) : + m_evars(), + m_lar_solver(s), + m_tangents(this), + m_basics(this), + m_order(this), + m_monotone(this), + m_intervals(this, lim), + m_monomial_bounds(this), + m_horner(this), + m_pdd_manager(s.number_of_vars()), + m_pdd_grobner(lim, m_pdd_manager), + m_emons(m_evars), + m_reslim(lim), + m_use_nra_model(false), + m_nra(s, m_nra_lim, *this) +{ + m_nlsat_delay = lp_settings().nlsat_delay(); +} + +bool core::compare_holds(const rational& ls, llc cmp, const rational& rs) const { + switch(cmp) { + case llc::LE: return ls <= rs; + case llc::LT: return ls < rs; + case llc::GE: return ls >= rs; + case llc::GT: return ls > rs; + case llc::EQ: return ls == rs; + case llc::NE: return ls != rs; + default: SASSERT(false); + }; + + return false; +} + +rational core::value(const lp::lar_term& r) const { + rational ret(0); + for (lp::lar_term::ival t : r) { + ret += t.coeff() * val(t.column()); + } + return ret; +} + +lp::lar_term core::subs_terms_to_columns(const lp::lar_term& t) const { + lp::lar_term r; + for (lp::lar_term::ival p : t) { + lpvar j = p.column(); + if (lp::tv::is_term(j)) + j = m_lar_solver.map_term_index_to_column_index(j); + r.add_monomial(p.coeff(), j); + } + return r; +} + +bool core::ineq_holds(const ineq& n) const { + return compare_holds(value(n.term()), n.cmp(), n.rs()); +} + +bool core::lemma_holds(const lemma& l) const { + for(const ineq &i : l.ineqs()) { + if (ineq_holds(i)) + return true; + } + return false; +} + +lpvar core::map_to_root(lpvar j) const { + return m_evars.find(j).var(); +} + +svector core::sorted_rvars(const factor& f) const { + if (f.is_var()) { + svector r; r.push_back(map_to_root(f.var())); + return r; + } + return m_emons[f.var()].rvars(); +} + +// the value of the factor is equal to the value of the variable multiplied +// by the canonize_sign +bool core::canonize_sign(const factor& f) const { + return f.sign() ^ (f.is_var()? canonize_sign(f.var()) : canonize_sign(m_emons[f.var()])); +} + +bool core::canonize_sign(lpvar j) const { + return m_evars.find(j).sign(); +} + +bool core::canonize_sign_is_correct(const monic& m) const { + bool r = false; + for (lpvar j : m.vars()) { + r ^= canonize_sign(j); + } + return r == m.rsign(); +} + +bool core::canonize_sign(const monic& m) const { + SASSERT(canonize_sign_is_correct(m)); + return m.rsign(); +} + +bool core::canonize_sign(const factorization& f) const { + bool r = false; + for (const factor & a : f) { + r ^= canonize_sign(a); + } + return r; +} + +void core::add_monic(lpvar v, unsigned sz, lpvar const* vs) { + m_add_buffer.resize(sz); + for (unsigned i = 0; i < sz; i++) { + lpvar j = vs[i]; + if (lp::tv::is_term(j)) + j = m_lar_solver.map_term_index_to_column_index(j); + m_add_buffer[i] = j; + } + m_emons.add(v, m_add_buffer); +} + +void core::push() { + TRACE("nla_solver_verbose", tout << "\n";); + m_emons.push(); +} + + +void core::pop(unsigned n) { + TRACE("nla_solver_verbose", tout << "n = " << n << "\n";); + m_emons.pop(n); + SASSERT(elists_are_consistent(false)); +} + +rational core::product_value(const monic& m) const { + rational r(1); + for (auto j : m.vars()) { + r *= m_lar_solver.get_column_value(j).x; + } + return r; +} + +// return true iff the monic value is equal to the product of the values of the factors +bool core::check_monic(const monic& m) const { + SASSERT((!m_lar_solver.column_is_int(m.var())) || m_lar_solver.get_column_value(m.var()).is_int()); + bool ret = product_value(m) == m_lar_solver.get_column_value(m.var()).x; + CTRACE("nla_solver_check_monic", !ret, print_monic(m, tout) << '\n';); + return ret; +} + + +template +std::ostream& core::print_product(const T & m, std::ostream& out) const { + bool first = true; + for (lpvar v : m) { + if (!first) out << "*"; else first = false; + if (lp_settings().print_external_var_name()) + out << "(" << m_lar_solver.get_variable_name(v) << "=" << val(v) << ")"; + else + out << "(j" << v << " = " << val(v) << ")"; + + } + return out; +} +template +std::string core::product_indices_str(const T & m) const { + std::stringstream out; + bool first = true; + for (lpvar v : m) { + if (!first) + out << "*"; + else + first = false; + out << "j" << v;; + } + return out.str(); +} + +std::ostream & core::print_factor(const factor& f, std::ostream& out) const { + if (f.sign()) + out << "- "; + if (f.is_var()) { + out << "VAR, " << pp(f.var()); + } else { + out << "MON, v" << m_emons[f.var()] << " = "; + print_product(m_emons[f.var()].rvars(), out); + } + out << "\n"; + return out; +} + +std::ostream & core::print_factor_with_vars(const factor& f, std::ostream& out) const { + if (f.is_var()) { + out << pp(f.var()); + } + else { + out << " MON = " << pp_mon_with_vars(*this, m_emons[f.var()]); + } + return out; +} + +std::ostream& core::print_monic(const monic& m, std::ostream& out) const { + if (lp_settings().print_external_var_name()) + out << "([" << m.var() << "] = " << m_lar_solver.get_variable_name(m.var()) << " = " << val(m.var()) << " = "; + else + out << "(j" << m.var() << " = " << val(m.var()) << " = "; + print_product(m.vars(), out) << ")\n"; + return out; +} + + +std::ostream& core::print_bfc(const factorization& m, std::ostream& out) const { + SASSERT(m.size() == 2); + out << "( x = " << pp(m[0]) << "* y = " << pp(m[1]) << ")"; + return out; +} + +std::ostream& core::print_monic_with_vars(lpvar v, std::ostream& out) const { + return print_monic_with_vars(m_emons[v], out); +} +template +std::ostream& core::print_product_with_vars(const T& m, std::ostream& out) const { + print_product(m, out) << "\n"; + for (unsigned k = 0; k < m.size(); k++) { + print_var(m[k], out); + } + return out; +} + +std::ostream& core::print_monic_with_vars(const monic& m, std::ostream& out) const { + out << "[" << pp(m.var()) << "]\n"; + out << "vars:"; print_product_with_vars(m.vars(), out) << "\n"; + if (m.vars() == m.rvars()) + out << "same rvars, and m.rsign = " << m.rsign() << " of course\n"; + else { + out << "rvars:"; print_product_with_vars(m.rvars(), out) << "\n"; + out << "rsign:" << m.rsign() << "\n"; + } + return out; +} + +std::ostream& core::print_explanation(const lp::explanation& exp, std::ostream& out) const { + out << "expl: "; + unsigned i = 0; + for (auto p : exp) { + out << "(" << p.ci() << ")"; + m_lar_solver.constraints().display(out, [this](lpvar j) { return var_str(j);}, p.ci()); + if (++i < exp.size()) + out << " "; + } + return out; +} + +bool core::explain_upper_bound(const lp::lar_term& t, const rational& rs, lp::explanation& e) const { + rational b(0); // the bound + for (lp::lar_term::ival p : t) { + rational pb; + if (explain_coeff_upper_bound(p, pb, e)) { + b += pb; + } else { + e.clear(); + return false; + } + } + if (b > rs ) { + e.clear(); + return false; + } + return true; +} +bool core::explain_lower_bound(const lp::lar_term& t, const rational& rs, lp::explanation& e) const { + rational b(0); // the bound + for (lp::lar_term::ival p : t) { + rational pb; + if (explain_coeff_lower_bound(p, pb, e)) { + b += pb; + } else { + e.clear(); + return false; + } + } + if (b < rs ) { + e.clear(); + return false; + } + return true; +} + +bool core::explain_coeff_lower_bound(const lp::lar_term::ival& p, rational& bound, lp::explanation& e) const { + const rational& a = p.coeff(); + SASSERT(!a.is_zero()); + unsigned c; // the index for the lower or the upper bound + if (a.is_pos()) { + unsigned c = m_lar_solver.get_column_lower_bound_witness(p.column()); + if (c + 1 == 0) + return false; + bound = a * m_lar_solver.get_lower_bound(p.column()).x; + e.push_back(c); + return true; + } + // a.is_neg() + c = m_lar_solver.get_column_upper_bound_witness(p.column()); + if (c + 1 == 0) + return false; + bound = a * m_lar_solver.get_upper_bound(p.column()).x; + e.push_back(c); + return true; +} + +bool core::explain_coeff_upper_bound(const lp::lar_term::ival& p, rational& bound, lp::explanation& e) const { + const rational& a = p.coeff(); + lpvar j = p.column(); + SASSERT(!a.is_zero()); + unsigned c; // the index for the lower or the upper bound + if (a.is_neg()) { + unsigned c = m_lar_solver.get_column_lower_bound_witness(j); + if (c + 1 == 0) + return false; + bound = a * m_lar_solver.get_lower_bound(j).x; + e.push_back(c); + return true; + } + // a.is_pos() + c = m_lar_solver.get_column_upper_bound_witness(j); + if (c + 1 == 0) + return false; + bound = a * m_lar_solver.get_upper_bound(j).x; + e.push_back(c); + return true; +} + +// return true iff the negation of the ineq can be derived from the constraints +bool core::explain_ineq(new_lemma& lemma, const lp::lar_term& t, llc cmp, const rational& rs) { + // check that we have something like 0 < 0, which is always false and can be safely + // removed from the lemma + + if (t.is_empty() && rs.is_zero() && + (cmp == llc::LT || cmp == llc::GT || cmp == llc::NE)) return true; + lp::explanation exp; + bool r; + switch (negate(cmp)) { + case llc::LE: + r = explain_upper_bound(t, rs, exp); + break; + case llc::LT: + r = explain_upper_bound(t, rs - rational(1), exp); + break; + case llc::GE: + r = explain_lower_bound(t, rs, exp); + break; + case llc::GT: + r = explain_lower_bound(t, rs + rational(1), exp); + break; + + case llc::EQ: + r = (explain_lower_bound(t, rs, exp) && explain_upper_bound(t, rs, exp)) || + (rs.is_zero() && explain_by_equiv(t, exp)); + break; + case llc::NE: + // TBD - NB: does this work for Reals? + r = explain_lower_bound(t, rs + rational(1), exp) || explain_upper_bound(t, rs - rational(1), exp); + break; + default: + UNREACHABLE(); + return false; + } + if (r) { + lemma &= exp; + return true; + } + + return false; +} + +/** + * \brief + if t is an octagon term -+x -+ y try to explain why the term always is + equal zero +*/ +bool core::explain_by_equiv(const lp::lar_term& t, lp::explanation& e) const { + lpvar i,j; + bool sign; + if (!is_octagon_term(t, sign, i, j)) + return false; + if (m_evars.find(signed_var(i, false)) != m_evars.find(signed_var(j, sign))) + return false; + + m_evars.explain(signed_var(i, false), signed_var(j, sign), e); + TRACE("nla_solver", tout << "explained :"; m_lar_solver.print_term_as_indices(t, tout);); + return true; +} + +void core::mk_ineq_no_expl_check(new_lemma& lemma, lp::lar_term& t, llc cmp, const rational& rs) { + TRACE("nla_solver_details", m_lar_solver.print_term_as_indices(t, tout << "t = ");); + lemma |= ineq(cmp, t, rs); + CTRACE("nla_solver", ineq_holds(ineq(cmp, t, rs)), print_ineq(ineq(cmp, t, rs), tout) << "\n";); + SASSERT(!ineq_holds(ineq(cmp, t, rs))); +} + +llc apply_minus(llc cmp) { + switch(cmp) { + case llc::LE: return llc::GE; + case llc::LT: return llc::GT; + case llc::GE: return llc::LE; + case llc::GT: return llc::LT; + default: break; + } + return cmp; +} + +// the monics should be equal by modulo sign but this is not so in the model +void core::fill_explanation_and_lemma_sign(new_lemma& lemma, const monic& a, const monic & b, rational const& sign) { + SASSERT(sign == 1 || sign == -1); + lemma &= a; + lemma &= b; + TRACE("nla_solver", tout << "used constraints: " << lemma;); + SASSERT(lemma.num_ineqs() == 0); + lemma |= ineq(term(rational(1), a.var(), -sign, b.var()), llc::EQ, 0); +} + +// Replaces each variable index by the root in the tree and flips the sign if the var comes with a minus. +// Also sorts the result. +// +svector core::reduce_monic_to_rooted(const svector & vars, rational & sign) const { + svector ret; + bool s = false; + for (lpvar v : vars) { + auto root = m_evars.find(v); + s ^= root.sign(); + TRACE("nla_solver_eq", + tout << pp(v) << " mapped to " << pp(root.var()) << "\n";); + ret.push_back(root.var()); + } + sign = rational(s? -1: 1); + std::sort(ret.begin(), ret.end()); + return ret; +} + + +// Replaces definition m_v = v1* .. * vn by +// m_v = coeff * w1 * ... * wn, where w1, .., wn are canonical +// representatives, which are the roots of the equivalence tree, under current equations. +// +monic_coeff core::canonize_monic(monic const& m) const { + rational sign = rational(1); + svector vars = reduce_monic_to_rooted(m.vars(), sign); + return monic_coeff(vars, sign); +} + +int core::vars_sign(const svector& v) { + int sign = 1; + for (lpvar j : v) { + sign *= nla::rat_sign(val(j)); + if (sign == 0) + return 0; + } + return sign; +} + +bool core::has_upper_bound(lpvar j) const { + return m_lar_solver.column_has_upper_bound(j); +} + +bool core::has_lower_bound(lpvar j) const { + return m_lar_solver.column_has_lower_bound(j); +} +const rational& core::get_upper_bound(unsigned j) const { + return m_lar_solver.get_upper_bound(j).x; +} + +const rational& core::get_lower_bound(unsigned j) const { + return m_lar_solver.get_lower_bound(j).x; +} + +bool core::zero_is_an_inner_point_of_bounds(lpvar j) const { + if (has_upper_bound(j) && get_upper_bound(j) <= rational(0)) + return false; + if (has_lower_bound(j) && get_lower_bound(j) >= rational(0)) + return false; + return true; +} + +int core::rat_sign(const monic& m) const { + int sign = 1; + for (lpvar j : m.vars()) { + auto v = val(j); + if (v.is_neg()) { + sign = - sign; + continue; + } + if (v.is_pos()) { + continue; + } + sign = 0; + break; + } + return sign; +} + +// Returns true if the monic sign is incorrect +bool core::sign_contradiction(const monic& m) const { + return nla::rat_sign(var_val(m)) != rat_sign(m); +} + +/* + unsigned_vector eq_vars(lpvar j) const { + TRACE("nla_solver_eq", tout << "j = " << pp(j) << "eqs = "; + for(auto jj : m_evars.eq_vars(j)) tout << pp(jj) << " "; + }); + return m_evars.eq_vars(j); + } +*/ + +bool core::var_is_fixed_to_zero(lpvar j) const { + return + m_lar_solver.column_is_fixed(j) && + m_lar_solver.get_lower_bound(j) == lp::zero_of_type(); +} +bool core::var_is_fixed_to_val(lpvar j, const rational& v) const { + return + m_lar_solver.column_is_fixed(j) && + m_lar_solver.get_lower_bound(j) == lp::impq(v); +} + +bool core::var_is_fixed(lpvar j) const { + return m_lar_solver.column_is_fixed(j); +} + +bool core::var_is_free(lpvar j) const { + return m_lar_solver.column_is_free(j); +} + +std::ostream & core::print_ineq(const ineq & in, std::ostream & out) const { + m_lar_solver.print_term_as_indices(in.term(), out); + out << " " << lconstraint_kind_string(in.cmp()) << " " << in.rs(); + return out; +} + +std::ostream & core::print_var(lpvar j, std::ostream & out) const { + if (m_emons.is_monic_var(j)) { + print_monic(m_emons[j], out); + } + + m_lar_solver.print_column_info(j, out); + signed_var jr = m_evars.find(j); + out << "root="; + if (jr.sign()) { + out << "-"; + } + + out << m_lar_solver.get_variable_name(jr.var()) << "\n"; + return out; +} + +std::ostream & core::print_monics(std::ostream & out) const { + for (auto &m : m_emons) { + print_monic_with_vars(m, out); + } + return out; +} + +std::ostream & core::print_ineqs(const lemma& l, std::ostream & out) const { + std::unordered_set vars; + out << "ineqs: "; + if (l.ineqs().size() == 0) { + out << "conflict\n"; + } else { + for (unsigned i = 0; i < l.ineqs().size(); i++) { + auto & in = l.ineqs()[i]; + print_ineq(in, out); + if (i + 1 < l.ineqs().size()) out << " or "; + for (lp::lar_term::ival p: in.term()) + vars.insert(p.column()); + } + out << std::endl; + for (lpvar j : vars) { + print_var(j, out); + } + out << "\n"; + } + return out; +} + +std::ostream & core::print_factorization(const factorization& f, std::ostream& out) const { + if (f.is_mon()){ + out << "is_mon " << pp_mon(*this, f.mon()); + } + else { + for (unsigned k = 0; k < f.size(); k++ ) { + out << "(" << pp(f[k]) << ")"; + if (k < f.size() - 1) + out << "*"; + } + } + return out; +} + +bool core::find_canonical_monic_of_vars(const svector& vars, lpvar & i) const { + monic const* sv = m_emons.find_canonical(vars); + return sv && (i = sv->var(), true); +} + +bool core::is_canonical_monic(lpvar j) const { + return m_emons.is_canonical_monic(j); +} + + +void core::trace_print_monic_and_factorization(const monic& rm, const factorization& f, std::ostream& out) const { + out << "rooted vars: "; + print_product(rm.rvars(), out) << "\n"; + out << "mon: " << pp_mon(*this, rm.var()) << "\n"; + out << "value: " << var_val(rm) << "\n"; + print_factorization(f, out << "fact: ") << "\n"; +} + + +bool core::var_has_positive_lower_bound(lpvar j) const { + return m_lar_solver.column_has_lower_bound(j) && m_lar_solver.get_lower_bound(j) > lp::zero_of_type(); +} + +bool core::var_has_negative_upper_bound(lpvar j) const { + return m_lar_solver.column_has_upper_bound(j) && m_lar_solver.get_upper_bound(j) < lp::zero_of_type(); +} + +bool core::var_is_separated_from_zero(lpvar j) const { + return + var_has_negative_upper_bound(j) || + var_has_positive_lower_bound(j); +} + + +bool core::vars_are_equiv(lpvar a, lpvar b) const { + SASSERT(abs(val(a)) == abs(val(b))); + return m_evars.vars_are_equiv(a, b); +} + +bool core::has_zero_factor(const factorization& factorization) const { + for (factor f : factorization) { + if (val(f).is_zero()) + return true; + } + return false; +} + + +template +bool core::mon_has_zero(const T& product) const { + for (lpvar j: product) { + if (val(j).is_zero()) + return true; + } + return false; +} + +template bool core::mon_has_zero(const unsigned_vector& product) const; + + +lp::lp_settings& core::lp_settings() { + return m_lar_solver.settings(); +} +const lp::lp_settings& core::lp_settings() const { + return m_lar_solver.settings(); +} + +unsigned core::random() { return lp_settings().random_next(); } + + +// we look for octagon constraints here, with a left part +-x +- y +void core::collect_equivs() { + const lp::lar_solver& s = m_lar_solver; + + for (unsigned i = 0; i < s.terms().size(); i++) { + if (!s.term_is_used_as_row(i)) + continue; + lpvar j = s.external_to_local(lp::tv::mask_term(i)); + if (var_is_fixed_to_zero(j)) { + TRACE("nla_solver_mons", s.print_term_as_indices(*s.terms()[i], tout << "term = ") << "\n";); + add_equivalence_maybe(s.terms()[i], s.get_column_upper_bound_witness(j), s.get_column_lower_bound_witness(j)); + } + } + m_emons.ensure_canonized(); +} + + +// returns true iff the term is in a form +-x-+y. +// the sign is true iff the term is x+y, -x-y. +bool core::is_octagon_term(const lp::lar_term& t, bool & sign, lpvar& i, lpvar &j) const { + if (t.size() != 2) + return false; + bool seen_minus = false; + bool seen_plus = false; + i = null_lpvar; + for(lp::lar_term::ival p : t) { + const auto & c = p.coeff(); + if (c == 1) { + seen_plus = true; + } else if (c == - 1) { + seen_minus = true; + } else { + return false; + } + if (i == null_lpvar) + i = p.column(); + else + j = p.column(); + } + SASSERT(j != null_lpvar); + sign = (seen_minus && seen_plus)? false : true; + return true; +} + +void core::add_equivalence_maybe(const lp::lar_term *t, lpci c0, lpci c1) { + bool sign; + lpvar i, j; + if (!is_octagon_term(*t, sign, i, j)) + return; + if (sign) + m_evars.merge_minus(i, j, eq_justification({c0, c1})); + else + m_evars.merge_plus(i, j, eq_justification({c0, c1})); +} + +// x is equivalent to y if x = +- y +void core::init_vars_equivalence() { + collect_equivs(); + // SASSERT(tables_are_ok()); +} + +bool core::vars_table_is_ok() const { + // return m_var_eqs.is_ok(); + return true; +} + +bool core::rm_table_is_ok() const { + // return m_emons.is_ok(); + return true; +} + +bool core::tables_are_ok() const { + return vars_table_is_ok() && rm_table_is_ok(); +} + +bool core::var_is_a_root(lpvar j) const { return m_evars.is_root(j); } + +template +bool core::vars_are_roots(const T& v) const { + for (lpvar j: v) { + if (!var_is_a_root(j)) + return false; + } + return true; +} + + + +template +void core::trace_print_rms(const T& p, std::ostream& out) { + out << "p = {\n"; + for (auto j : p) { + out << "j = " << j << ", rm = " << m_emons[j] << "\n"; + } + out << "}"; +} + +void core::print_monic_stats(const monic& m, std::ostream& out) { + if (m.size() == 2) return; + monic_coeff mc = canonize_monic(m); + for(unsigned i = 0; i < mc.vars().size(); i++){ + if (abs(val(mc.vars()[i])) == rational(1)) { + auto vv = mc.vars(); + vv.erase(vv.begin()+i); + monic const* sv = m_emons.find_canonical(vv); + if (!sv) { + out << "nf length" << vv.size() << "\n"; ; + } + } + } +} + +void core::print_stats(std::ostream& out) { +} + + +void core::clear() { + m_lemma_vec->clear(); +} + +void core::init_search() { + TRACE("nla_solver_mons", tout << "init\n";); + SASSERT(m_emons.invariant()); + clear(); + init_vars_equivalence(); + SASSERT(m_emons.invariant()); + SASSERT(elists_are_consistent(false)); +} + +void core::insert_to_refine(lpvar j) { + TRACE("lar_solver", tout << "j=" << j << '\n';); + m_to_refine.insert(j); +} + +void core::erase_from_to_refine(lpvar j) { + TRACE("lar_solver", tout << "j=" << j << '\n';); + m_to_refine.erase(j); +} + + +void core::init_to_refine() { + TRACE("nla_solver_details", tout << "emons:" << pp_emons(*this, m_emons);); + m_to_refine.clear(); + m_to_refine.resize(m_lar_solver.number_of_vars()); + unsigned r = random(), sz = m_emons.number_of_monics(); + for (unsigned k = 0; k < sz; k++) { + auto const & m = *(m_emons.begin() + (k + r)% sz); + if (!check_monic(m)) + insert_to_refine(m.var()); + } + + TRACE("nla_solver", + tout << m_to_refine.size() << " mons to refine:\n"; + for (lpvar v : m_to_refine) tout << pp_mon(*this, m_emons[v]) << ":error = " << + (val(v) - mul_val(m_emons[v])).get_double() << "\n";); +} + +std::unordered_set core::collect_vars(const lemma& l) const { + std::unordered_set vars; + auto insert_j = [&](lpvar j) { + vars.insert(j); + if (m_emons.is_monic_var(j)) { + for (lpvar k : m_emons[j].vars()) + vars.insert(k); + } + }; + + for (const auto& i : l.ineqs()) { + for (lp::lar_term::ival p : i.term()) { + insert_j(p.column()); + } + } + for (auto p : l.expl()) { + const auto& c = m_lar_solver.constraints()[p.ci()]; + for (const auto& r : c.coeffs()) { + insert_j(r.second); + } + } + return vars; +} + +// divides bc by c, so bc = b*c +bool core::divide(const monic& bc, const factor& c, factor & b) const { + svector c_rvars = sorted_rvars(c); + TRACE("nla_solver_div", tout << "c_rvars = "; print_product(c_rvars, tout); tout << "\nbc_rvars = "; print_product(bc.rvars(), tout);); + if (!lp::is_proper_factor(c_rvars, bc.rvars())) + return false; + + auto b_rvars = lp::vector_div(bc.rvars(), c_rvars); + TRACE("nla_solver_div", tout << "b_rvars = "; print_product(b_rvars, tout);); + SASSERT(b_rvars.size() > 0); + if (b_rvars.size() == 1) { + b = factor(b_rvars[0], factor_type::VAR); + } else { + monic const* sv = m_emons.find_canonical(b_rvars); + if (sv == nullptr) { + TRACE("nla_solver_div", tout << "not in rooted";); + return false; + } + b = factor(sv->var(), factor_type::MON); + } + SASSERT(!b.sign()); + // We have bc = canonize_sign(bc)*bc.rvars() = canonize_sign(b)*b.rvars()*canonize_sign(c)*c.rvars(). + // Dividing by bc.rvars() we get canonize_sign(bc) = canonize_sign(b)*canonize_sign(c) + // Currently, canonize_sign(b) is 1, we might need to adjust it + b.sign() = canonize_sign(b) ^ canonize_sign(c) ^ canonize_sign(bc); + TRACE("nla_solver", tout << "success div:" << pp(b) << "\n";); + return true; +} + + +void core::negate_factor_equality(new_lemma& lemma, const factor& c, + const factor& d) { + if (c == d) + return; + lpvar i = var(c); + lpvar j = var(d); + auto iv = val(i), jv = val(j); + SASSERT(abs(iv) == abs(jv)); + lemma |= ineq(term(i, rational(iv == jv ? -1 : 1), j), llc::NE, 0); +} + +void core::negate_factor_relation(new_lemma& lemma, const rational& a_sign, const factor& a, const rational& b_sign, const factor& b) { + rational a_fs = sign_to_rat(canonize_sign(a)); + rational b_fs = sign_to_rat(canonize_sign(b)); + llc cmp = a_sign*val(a) < b_sign*val(b)? llc::GE : llc::LE; + lemma |= ineq(term(a_fs*a_sign, var(a), - b_fs*b_sign, var(b)), cmp, 0); +} + +std::ostream& core::print_lemma(const lemma& l, std::ostream& out) const { + static int n = 0; + out << "lemma:" << ++n << " "; + print_ineqs(l, out); + print_explanation(l.expl(), out); + for (lpvar j : collect_vars(l)) { + print_var(j, out); + } + return out; +} + + +void core::trace_print_ol(const monic& ac, + const factor& a, + const factor& c, + const monic& bc, + const factor& b, + std::ostream& out) { + out << "ac = " << pp_mon(*this, ac) << "\n"; + out << "bc = " << pp_mon(*this, bc) << "\n"; + out << "a = "; + print_factor_with_vars(a, out); + out << ", \nb = "; + print_factor_with_vars(b, out); + out << "\nc = "; + print_factor_with_vars(c, out); +} + +void core::maybe_add_a_factor(lpvar i, + const factor& c, + std::unordered_set& found_vars, + std::unordered_set& found_rm, + vector & r) const { + SASSERT(abs(val(i)) == abs(val(c))); + if (!m_emons.is_monic_var(i)) { + i = m_evars.find(i).var(); + if (try_insert(i, found_vars)) { + r.push_back(factor(i, factor_type::VAR)); + } + } else { + if (try_insert(i, found_rm)) { + r.push_back(factor(i, factor_type::MON)); + TRACE("nla_solver", tout << "inserting factor = "; print_factor_with_vars(factor(i, factor_type::MON), tout); ); + } + } +} + + +// Returns rooted monics by arity +std::unordered_map core::get_rm_by_arity() { + std::unordered_map m; + for (auto const& mon : m_emons) { + unsigned arity = mon.vars().size(); + auto it = m.find(arity); + if (it == m.end()) { + it = m.insert(it, std::make_pair(arity, unsigned_vector())); + } + it->second.push_back(mon.var()); + } + return m; +} + +bool core::rm_check(const monic& rm) const { + return check_monic(m_emons[rm.var()]); +} + + +bool core::find_bfc_to_refine_on_monic(const monic& m, factorization & bf) { + for (auto f : factorization_factory_imp(m, *this)) { + if (f.size() == 2) { + auto a = f[0]; + auto b = f[1]; + if (var_val(m) != val(a) * val(b)) { + bf = f; + TRACE("nla_solver", tout << "found bf"; + tout << ":m:" << pp_mon_with_vars(*this, m) << "\n"; + tout << "bf:"; print_bfc(bf, tout);); + + return true; + } + } + } + return false; +} + +// finds a monic to refine with its binary factorization +bool core::find_bfc_to_refine(const monic* & m, factorization & bf){ + m = nullptr; + unsigned r = random(), sz = m_to_refine.size(); + for (unsigned k = 0; k < sz; k++) { + lpvar i = m_to_refine[(k + r) % sz]; + m = &m_emons[i]; + SASSERT (!check_monic(*m)); + if (has_real(m)) + continue; + if (m->size() == 2) { + bf.set_mon(m); + bf.push_back(factor(m->vars()[0], factor_type::VAR)); + bf.push_back(factor(m->vars()[1], factor_type::VAR)); + return true; + } + + if (find_bfc_to_refine_on_monic(*m, bf)) { + TRACE("nla_solver", + tout << "bf = "; print_factorization(bf, tout); + tout << "\nval(*m) = " << var_val(*m) << ", should be = (val(bf[0])=" << val(bf[0]) << ")*(val(bf[1]) = " << val(bf[1]) << ") = " << val(bf[0])*val(bf[1]) << "\n";); + return true; + } + } + return false; +} + +rational core::val(const factorization& f) const { + rational r(1); + for (const factor &p : f) { + r *= val(p); + } + return r; +} + +new_lemma::new_lemma(core& c, char const* name):name(name), c(c) { + c.m_lemma_vec->push_back(lemma()); +} + +new_lemma& new_lemma::operator|=(ineq const& ineq) { + if (!c.explain_ineq(*this, ineq.term(), ineq.cmp(), ineq.rs())) { + CTRACE("nla_solver", c.ineq_holds(ineq), c.print_ineq(ineq, tout) << "\n";); + SASSERT(!c.ineq_holds(ineq)); + current().push_back(ineq); + } + return *this; +} + + +new_lemma::~new_lemma() { + static int i = 0; + (void)i; + (void)name; + // code for checking lemma can be added here + TRACE("nla_solver", tout << name << " " << (++i) << "\n" << *this; ); +} + +lemma& new_lemma::current() const { + return c.m_lemma_vec->back(); +} + +new_lemma& new_lemma::operator&=(lp::explanation const& e) { + expl().add_expl(e); + return *this; +} + +new_lemma& new_lemma::operator&=(const monic& m) { + for (lpvar j : m.vars()) + *this &= j; + return *this; +} + +new_lemma& new_lemma::operator&=(const factor& f) { + if (f.type() == factor_type::VAR) + *this &= f.var(); + else + *this &= c.m_emons[f.var()]; + return *this; +} + +new_lemma& new_lemma::operator&=(const factorization& f) { + if (f.is_mon()) + return *this; + for (const auto& fc : f) { + *this &= fc; + } + return *this; +} + +new_lemma& new_lemma::operator&=(lpvar j) { + c.m_evars.explain(j, expl()); + return *this; +} + +new_lemma& new_lemma::explain_fixed(lpvar j) { + SASSERT(c.var_is_fixed(j)); + explain_existing_lower_bound(j); + explain_existing_upper_bound(j); + return *this; +} + +new_lemma& new_lemma::explain_equiv(lpvar a, lpvar b) { + SASSERT(abs(c.val(a)) == abs(c.val(b))); + if (c.vars_are_equiv(a, b)) { + *this &= a; + *this &= b; + } else { + explain_fixed(a); + explain_fixed(b); + } + return *this; +} + +new_lemma& new_lemma::explain_var_separated_from_zero(lpvar j) { + SASSERT(c.var_is_separated_from_zero(j)); + if (c.m_lar_solver.column_has_upper_bound(j) && + (c.m_lar_solver.get_upper_bound(j)< lp::zero_of_type())) + explain_existing_upper_bound(j); + else + explain_existing_lower_bound(j); + return *this; +} + +new_lemma& new_lemma::explain_existing_lower_bound(lpvar j) { + SASSERT(c.has_lower_bound(j)); + lp::explanation ex; + ex.push_back(c.m_lar_solver.get_column_lower_bound_witness(j)); + *this &= ex; + TRACE("nla_solver", tout << j << ": " << *this << "\n";); + return *this; +} + +new_lemma& new_lemma::explain_existing_upper_bound(lpvar j) { + SASSERT(c.has_upper_bound(j)); + lp::explanation ex; + ex.push_back(c.m_lar_solver.get_column_upper_bound_witness(j)); + *this &= ex; + return *this; +} + +std::ostream& new_lemma::display(std::ostream & out) const { + auto const& lemma = current(); + + for (auto p : lemma.expl()) { + out << "(" << p.ci() << ") "; + c.m_lar_solver.constraints().display(out, [this](lpvar j) { return c.var_str(j);}, p.ci()); + } + out << " ==> "; + if (lemma.ineqs().empty()) { + out << "false"; + } + else { + bool first = true; + for (auto & in : lemma.ineqs()) { + if (first) first = false; else out << " or "; + c.print_ineq(in, out); + } + } + out << "\n"; + for (lpvar j : c.collect_vars(lemma)) { + c.print_var(j, out); + } + return out; +} + +void core::negate_relation(new_lemma& lemma, unsigned j, const rational& a) { + SASSERT(val(j) != a); + lemma |= ineq(j, val(j) < a ? llc::GE : llc::LE, a); +} + +bool core::conflict_found() const { + for (const auto & l : * m_lemma_vec) { + if (l.is_conflict()) + return true; + } + return false; +} + +bool core::done() const { + return m_lemma_vec->size() >= 10 || + conflict_found() || + lp_settings().get_cancel_flag(); +} + +bool core::elist_is_consistent(const std::unordered_set & list) const { + bool first = true; + bool p; + for (lpvar j : list) { + if (first) { + p = check_monic(m_emons[j]); + first = false; + } else + if (check_monic(m_emons[j]) != p) + return false; + } + return true; +} + +bool core::elists_are_consistent(bool check_in_model) const { + std::unordered_map, hash_svector> lists; + if (!m_emons.elists_are_consistent(lists)) + return false; + + if (!check_in_model) + return true; + for (const auto & p : lists) { + if (! elist_is_consistent(p.second)) + return false; + } + return true; +} + +bool core::var_breaks_correct_monic_as_factor(lpvar j, const monic& m) const { + if (!val(var(m)).is_zero()) + return true; + + if (!val(j).is_zero()) // j was not zero: the new value does not matter - m must have another zero factor + return false; + // do we have another zero in m? + for (lpvar k : m) { + if (k != j && val(k).is_zero()) { + return false; // not breaking + } + } + // j was the only zero in m + return true; +} + +bool core::var_breaks_correct_monic(lpvar j) const { + if (emons().is_monic_var(j) && !m_to_refine.contains(j)) { + TRACE("nla_solver", tout << "j = " << j << ", m = "; print_monic(emons()[j], tout) << "\n";); + return true; // changing the value of a correct monic + } + + for (const monic & m : emons().get_use_list(j)) { + if (m_to_refine.contains(m.var())) + continue; + if (var_breaks_correct_monic_as_factor(j, m)) + return true; + } + + return false; +} + +void core::update_to_refine_of_var(lpvar j) { + for (const monic & m : emons().get_use_list(j)) { + if (var_val(m) == mul_val(m)) + erase_from_to_refine(var(m)); + else + insert_to_refine(var(m)); + } + if (is_monic_var(j)) { + const monic& m = emons()[j]; + if (var_val(m) == mul_val(m)) + erase_from_to_refine(j); + else + insert_to_refine(j); + } +} + +bool core::var_is_big(lpvar j) const { + return !var_is_int(j) && val(j).is_big(); +} + +bool core::has_big_num(const monic& m) const { + if (var_is_big(var(m))) + return true; + for (lpvar j : m.vars()) + if (var_is_big(j)) + return true; + return false; +} + +bool core::has_real(const factorization& f) const { + for (const factor& fc: f) { + lpvar j = var(fc); + if (!var_is_int(j)) + return true; + } + return false; +} + +bool core::has_real(const monic& m) const { + for (lpvar j : m.vars()) + if (!var_is_int(j)) + return true; + return false; +} + +// returns true if the patching is blocking +bool core::is_patch_blocked(lpvar u, const lp::impq& ival) const { + TRACE("nla_solver", tout << "u = " << u << '\n';); + if (m_cautious_patching && + (!m_lar_solver.inside_bounds(u, ival) || (var_is_int(u) && ival.is_int() == false))) { + TRACE("nla_solver", tout << "u = " << u << " blocked, for feas or integr\n";); + return true; // block + } + + if (u == m_patched_var) { + TRACE("nla_solver", tout << "u == m_patched_var, no block\n";); + + return false; // do not block + } + // we can change only one variable in variables of m_patched_var + if (m_patched_monic->contains_var(u) || u == var(*m_patched_monic)) { + TRACE("nla_solver", tout << "u = " << u << " blocked as contained\n";); + return true; // block + } + + if (var_breaks_correct_monic(u)) { + TRACE("nla_solver", tout << "u = " << u << " blocked as used in a correct monomial\n";); + return true; + } + + TRACE("nla_solver", tout << "u = " << u << ", m_patched_m = "; print_monic(*m_patched_monic, tout) << + ", not blocked\n";); + + return false; +} + +// it tries to patch m_patched_var +bool core::try_to_patch(const rational& v) { + auto is_blocked = [this](lpvar u, const lp::impq& iv) { return is_patch_blocked(u, iv); }; + auto change_report = [this](lpvar u) { update_to_refine_of_var(u); }; + return m_lar_solver.try_to_patch(m_patched_var, v, is_blocked, change_report); +} + +bool in_power(const svector& vs, unsigned l) { + unsigned k = vs[l]; + return (l != 0 && vs[l - 1] == k) || (l + 1 < vs.size() && k == vs[l + 1]); +} + +bool core::to_refine_is_correct() const { + for (unsigned j = 0; j < m_lar_solver.number_of_vars(); j++) { + if (!emons().is_monic_var(j)) continue; + bool valid = check_monic(emons()[j]); + if (valid == m_to_refine.contains(j)) { + TRACE("nla_solver", tout << "inconstency in m_to_refine : "; + print_monic(emons()[j], tout) << "\n"; + if (valid) tout << "should NOT be in to_refine\n"; + else tout << "should be in to_refine\n";); + return false; + } + } + return true; +} + +void core::patch_monomial(lpvar j) { + m_patched_monic =& (emons()[j]); + m_patched_var = j; + TRACE("nla_solver", tout << "m = "; print_monic(*m_patched_monic, tout) << "\n";); + rational v = mul_val(*m_patched_monic); + if (val(j) == v) { + erase_from_to_refine(j); + return; + } + if (!var_breaks_correct_monic(j) && try_to_patch(v)) { + SASSERT(to_refine_is_correct()); + return; + } + + // We could not patch j, now we try patching the factor variables. + TRACE("nla_solver", tout << " trying squares\n";); + // handle perfect squares + if ((*m_patched_monic).vars().size() == 2 && (*m_patched_monic).vars()[0] == (*m_patched_monic).vars()[1]) { + rational root; + if (v.is_perfect_square(root)) { + m_patched_var = (*m_patched_monic).vars()[0]; + if (!var_breaks_correct_monic(m_patched_var) && (try_to_patch(root) || try_to_patch(-root))) { + TRACE("nla_solver", tout << "patched square\n";); + return; + } + } + TRACE("nla_solver", tout << " cannot patch\n";); + return; + } + + // We have v != abc, but we need to have v = abc. + // If we patch b then b should be equal to v/ac = v/(abc/b) = b(v/abc) + if (!v.is_zero()) { + rational r = val(j) / v; + SASSERT((*m_patched_monic).is_sorted()); + TRACE("nla_solver", tout << "r = " << r << ", v = " << v << "\n";); + for (unsigned l = 0; l < (*m_patched_monic).size(); l++) { + m_patched_var = (*m_patched_monic).vars()[l]; + if (!in_power((*m_patched_monic).vars(), l) && + !var_breaks_correct_monic(m_patched_var) && + try_to_patch(r * val(m_patched_var))) { // r * val(k) gives the right value of k + TRACE("nla_solver", tout << "patched " << m_patched_var << "\n";); + SASSERT(mul_val((*m_patched_monic)) == val(j)); + erase_from_to_refine(j); + break; + } + } + } +} + +void core::patch_monomials_on_to_refine() { + auto to_refine = m_to_refine.index(); + // the rest of the function might change m_to_refine, so have to copy + unsigned sz = to_refine.size(); + + unsigned start = random(); + for (unsigned i = 0; i < sz; i++) { + patch_monomial(to_refine[(start + i) % sz]); + if (m_to_refine.size() == 0) + break; + } + TRACE("nla_solver", tout << "sz = " << sz << ", m_to_refine = " << m_to_refine.size() << + (sz > m_to_refine.size()? " less" : "same" ) << "\n";); +} + +void core::patch_monomials() { + m_cautious_patching = true; + patch_monomials_on_to_refine(); + if (m_to_refine.size() == 0 || !m_nla_settings.expensive_patching()) { + return; + } + NOT_IMPLEMENTED_YET(); + m_cautious_patching = false; + patch_monomials_on_to_refine(); + m_lar_solver.push(); + save_tableau(); + constrain_nl_in_tableau(); + if (solve_tableau() && integrality_holds()) { + m_lar_solver.pop(1); + } else { + m_lar_solver.pop(); + restore_tableau(); + m_lar_solver.clear_inf_set(); + } + SASSERT(m_lar_solver.ax_is_correct()); +} + +void core::constrain_nl_in_tableau() { + NOT_IMPLEMENTED_YET(); +} + +bool core::solve_tableau() { + NOT_IMPLEMENTED_YET(); + return false; +} + +void core::restore_tableau() { + NOT_IMPLEMENTED_YET(); +} + +void core::save_tableau() { + NOT_IMPLEMENTED_YET(); +} + +bool core::integrality_holds() { + NOT_IMPLEMENTED_YET(); + return false; +} + +/** + * Cycle through different end-game solvers weighted by probability. + */ +void core::check_weighted(unsigned sz, std::pair>* checks) { + unsigned bound = 0; + for (unsigned i = 0; i < sz; ++i) + bound += checks[i].first; + uint_set seen; + while (bound > 0 && !done() && m_lemma_vec->empty()) { + unsigned n = random() % bound; + for (unsigned i = 0; i < sz; ++i) { + if (seen.contains(i)) + continue; + if (n < checks[i].first) { + seen.insert(i); + checks[i].second(); + bound -= checks[i].first; + break; + } + n -= checks[i].first; + } + } +} + + +lbool core::check(vector& l_vec) { + lp_settings().stats().m_nla_calls++; + TRACE("nla_solver", tout << "calls = " << lp_settings().stats().m_nla_calls << "\n";); + m_lar_solver.get_rid_of_inf_eps(); + m_lemma_vec = &l_vec; + if (!(m_lar_solver.get_status() == lp::lp_status::OPTIMAL || + m_lar_solver.get_status() == lp::lp_status::FEASIBLE)) { + TRACE("nla_solver", tout << "unknown because of the m_lar_solver.m_status = " << m_lar_solver.get_status() << "\n";); + return l_undef; + } + + init_to_refine(); + patch_monomials(); + set_use_nra_model(false); + if (m_to_refine.empty()) { return l_true; } + init_search(); + + lbool ret = l_undef; + + if (l_vec.empty() && !done()) + m_monomial_bounds(); + + if (l_vec.empty() && !done() && need_run_horner()) + m_horner.horner_lemmas(); + + if (l_vec.empty() && !done() && need_run_grobner()) + run_grobner(); + + if (l_vec.empty() && !done()) + m_basics.basic_lemma(true); + + if (l_vec.empty() && !done()) + m_basics.basic_lemma(false); + + if (!conflict_found() && !done() && should_run_bounded_nlsat()) + ret = bounded_nlsat(); + + + if (l_vec.empty() && !done() && ret == l_undef) { + std::function check1 = [&]() { m_order.order_lemma(); }; + std::function check2 = [&]() { m_monotone.monotonicity_lemma(); }; + std::function check3 = [&]() { m_tangents.tangent_lemma(); }; + + std::pair> checks[] = + { { 6, check1 }, + { 2, check2 }, + { 1, check3 }}; + check_weighted(3, checks); + + unsigned num_calls = lp_settings().stats().m_nla_calls; + if (!conflict_found() && m_nla_settings.run_nra() && num_calls % 50 == 0 && num_calls > 500) + ret = bounded_nlsat(); + } + + if (l_vec.empty() && !done() && m_nla_settings.run_nra() && ret == l_undef) { + ret = m_nra.check(); + m_stats.m_nra_calls++; + } + + if (ret == l_undef && !l_vec.empty() && m_reslim.inc()) + ret = l_false; + + m_stats.m_nla_lemmas += l_vec.size(); + for (const auto& l : l_vec) + m_stats.m_nla_explanations += static_cast(l.expl().size()); + + + TRACE("nla_solver", tout << "ret = " << ret << ", lemmas count = " << l_vec.size() << "\n";); + IF_VERBOSE(2, if(ret == l_undef) {verbose_stream() << "Monomials\n"; print_monics(verbose_stream());}); + CTRACE("nla_solver", ret == l_undef, tout << "Monomials\n"; print_monics(tout);); + return ret; +} + +bool core::should_run_bounded_nlsat() { + if (!m_nla_settings.run_nra()) + return false; + if (m_nlsat_delay > m_nlsat_fails) + ++m_nlsat_fails; + return m_nlsat_delay <= m_nlsat_fails; +} + +lbool core::bounded_nlsat() { + params_ref p; + lbool ret; + p.set_uint("max_conflicts", 100); + m_nra.updt_params(p); + { + scoped_limits sl(m_reslim); + sl.push_child(&m_nra_lim); + scoped_rlimit sr(m_nra_lim, 100000); + ret = m_nra.check(); + } + p.set_uint("max_conflicts", UINT_MAX); + m_nra.updt_params(p); + m_stats.m_nra_calls++; + if (ret == l_undef) + ++m_nlsat_delay; + else { + m_nlsat_fails = 0; + m_nlsat_delay /= 2; + } + if (ret == l_true) { + m_lemma_vec->reset(); + } + return ret; +} + +bool core::no_lemmas_hold() const { + for (auto & l : * m_lemma_vec) { + if (lemma_holds(l)) { + TRACE("nla_solver", print_lemma(l, tout);); + return false; + } + } + return true; +} + +lbool core::test_check(vector& l) { + m_lar_solver.set_status(lp::lp_status::OPTIMAL); + return check(l); +} + +std::ostream& core::print_terms(std::ostream& out) const { + for (unsigned i = 0; i< m_lar_solver.terms().size(); i++) { + unsigned ext = lp::tv::mask_term(i); + if (!m_lar_solver.var_is_registered(ext)) { + out << "term is not registered\n"; + continue; + } + + const lp::lar_term & t = *m_lar_solver.terms()[i]; + out << "term:"; print_term(t, out) << std::endl; + lpvar j = m_lar_solver.external_to_local(ext); + print_var(j, out); + } + return out; +} + +std::string core::var_str(lpvar j) const { + return is_monic_var(j)? + (product_indices_str(m_emons[j].vars()) + (check_monic(m_emons[j])? "": "_")) : (std::string("j") + lp::T_to_string(j)); +} + +std::ostream& core::print_term( const lp::lar_term& t, std::ostream& out) const { + return lp::print_linear_combination_customized( + t.coeffs_as_vector(), + [this](lpvar j) { return var_str(j); }, + out); +} + + +void core::run_grobner() { + unsigned& quota = m_nla_settings.grobner_quota(); + if (quota == 1) { + return; + } + clear_and_resize_active_var_set(); + find_nl_cluster(); + + lp_settings().stats().m_grobner_calls++; + configure_grobner(); + m_pdd_grobner.saturate(); + bool conflict = false; + unsigned n = m_pdd_grobner.number_of_conflicts_to_report(); + SASSERT(n > 0); + for (auto eq : m_pdd_grobner.equations()) { + if (check_pdd_eq(eq)) { + conflict = true; + if (--n == 0) + break; + } + } + if (conflict) { + IF_VERBOSE(2, verbose_stream() << "grobner conflict\n"); + return; + } + +#if 0 + bool propagated = false; + for (auto eq : m_pdd_grobner.equations()) { + auto const& p = eq->poly(); + if (p.is_offset()) { + lpvar v = p.var(); + if (m_lar_solver.column_has_lower_bound(v) && + m_lar_solver.column_has_upper_bound(v)) + continue; + rational fixed_val = -p.lo().val(); + lp::explanation ex; + u_dependency_manager dm; + vector lv; + dm.linearize(eq->dep(), lv); + for (unsigned ci : lv) + ex.push_back(ci); + new_lemma lemma(*this, "pdd-eq"); + lemma &= ex; + lemma |= ineq(v, llc::EQ, fixed_val); + propagated = true; + } + } + if (propagated) + return; +#endif + + if (quota > 1) + quota--; + IF_VERBOSE(2, verbose_stream() << "grobner miss, quota " << quota << "\n"); + IF_VERBOSE(4, diagnose_pdd_miss(verbose_stream())); + +} + +void core::configure_grobner() { + m_pdd_grobner.reset(); + try { + set_level2var_for_grobner(); + for (unsigned i : m_rows) { + add_row_to_grobner(m_lar_solver.A_r().m_rows[i]); + } + } + catch (...) { + IF_VERBOSE(2, verbose_stream() << "pdd throw\n"); + return; + } +#if 0 + IF_VERBOSE(2, m_pdd_grobner.display(verbose_stream())); + dd::pdd_eval eval(m_pdd_manager); + eval.var2val() = [&](unsigned j){ return val(j); }; + for (auto* e : m_pdd_grobner.equations()) { + dd::pdd p = e->poly(); + rational v = eval(p); + if (p.is_linear() && !eval(p).is_zero()) { + IF_VERBOSE(0, verbose_stream() << "violated linear constraint " << p << "\n"); + } + } +#endif + + struct dd::solver::config cfg; + cfg.m_max_steps = m_pdd_grobner.equations().size(); + cfg.m_max_simplified = m_nla_settings.grobner_max_simplified(); + cfg.m_eqs_growth = m_nla_settings.grobner_eqs_growth(); + cfg.m_expr_size_growth = m_nla_settings.grobner_expr_size_growth(); + cfg.m_expr_degree_growth = m_nla_settings.grobner_expr_degree_growth(); + cfg.m_number_of_conflicts_to_report = m_nla_settings.grobner_number_of_conflicts_to_report(); + m_pdd_grobner.set(cfg); + m_pdd_grobner.adjust_cfg(); + m_pdd_manager.set_max_num_nodes(10000); // or something proportional to the number of initial nodes. +} + +std::ostream& core::diagnose_pdd_miss(std::ostream& out) { + + // m_pdd_grobner.display(out); + + dd::pdd_eval eval; + eval.var2val() = [&](unsigned j){ return val(j); }; + for (auto* e : m_pdd_grobner.equations()) { + dd::pdd p = e->poly(); + rational v = eval(p); + if (!v.is_zero()) { + out << p << " := " << v << "\n"; + } + } + + for (unsigned j = 0; j < m_lar_solver.number_of_vars(); ++j) { + if (m_lar_solver.column_has_lower_bound(j) || m_lar_solver.column_has_upper_bound(j)) { + out << j << ": ["; + if (m_lar_solver.column_has_lower_bound(j)) out << m_lar_solver.get_lower_bound(j); + out << ".."; + if (m_lar_solver.column_has_upper_bound(j)) out << m_lar_solver.get_upper_bound(j); + out << "]\n"; + } + } + return out; +} + +bool core::check_pdd_eq(const dd::solver::equation* e) { + auto& di = m_intervals.get_dep_intervals(); + dd::pdd_interval eval(di); + eval.var2interval() = [this](lpvar j, bool deps, scoped_dep_interval& a) { + if (deps) m_intervals.set_var_interval(j, a); + else m_intervals.set_var_interval(j, a); + }; + scoped_dep_interval i(di), i_wd(di); + eval.get_interval(e->poly(), i); + if (!di.separated_from_zero(i)) + return false; + eval.get_interval(e->poly(), i_wd); + std::function f = [this](const lp::explanation& e) { + new_lemma lemma(*this, "pdd"); + lemma &= e; + }; + if (di.check_interval_for_conflict_on_zero(i_wd, e->dep(), f)) { + lp_settings().stats().m_grobner_conflicts++; + return true; + } + else { + return false; + } +} + +void core::add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector & q) { + if (active_var_set_contains(j) || var_is_fixed(j)) return; + TRACE("grobner", tout << "j = " << j << ", " << pp(j);); + const auto& matrix = m_lar_solver.A_r(); + insert_to_active_var_set(j); + for (auto & s : matrix.m_columns[j]) { + unsigned row = s.var(); + if (m_rows.contains(row)) continue; + if (matrix.m_rows[row].size() > m_nla_settings.grobner_row_length_limit()) { + TRACE("grobner", tout << "ignore the row " << row << " with the size " << matrix.m_rows[row].size() << "\n";); + continue; + } + m_rows.insert(row); + for (auto& rc : matrix.m_rows[row]) { + add_var_and_its_factors_to_q_and_collect_new_rows(rc.var(), q); + } + } + + if (!is_monic_var(j)) + return; + + const monic& m = emons()[j]; + for (auto fcn : factorization_factory_imp(m, *this)) { + for (const factor& fc: fcn) { + q.push_back(var(fc)); + } + } +} + +const rational& core::val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep) { + unsigned lc, uc; + m_lar_solver.get_bound_constraint_witnesses_for_column(j, lc, uc); + dep = m_intervals.mk_join(dep, m_intervals.mk_leaf(lc)); + dep = m_intervals.mk_join(dep, m_intervals.mk_leaf(uc)); + return m_lar_solver.column_lower_bound(j).x; +} + +dd::pdd core::pdd_expr(const rational& c, lpvar j, u_dependency*& dep) { + if (m_nla_settings.grobner_subs_fixed() == 1 && var_is_fixed(j)) { + return m_pdd_manager.mk_val(c * val_of_fixed_var_with_deps(j, dep)); + } + + if (m_nla_settings.grobner_subs_fixed() == 2 && var_is_fixed_to_zero(j)) { + return m_pdd_manager.mk_val(val_of_fixed_var_with_deps(j, dep)); + } + + if (!is_monic_var(j)) + return c * m_pdd_manager.mk_var(j); + + u_dependency* zero_dep = dep; + // j is a monic var + dd::pdd r = m_pdd_manager.mk_val(c); + const monic& m = emons()[j]; + for (lpvar k : m.vars()) { + if (m_nla_settings.grobner_subs_fixed() && var_is_fixed(k)) { + r *= m_pdd_manager.mk_val(val_of_fixed_var_with_deps(k, dep)); + } else if (m_nla_settings.grobner_subs_fixed() == 2 && var_is_fixed_to_zero(k)) { + r = m_pdd_manager.mk_val(val_of_fixed_var_with_deps(k, zero_dep)); + dep = zero_dep; + return r; + } else { + r *= m_pdd_manager.mk_var(k); + } + } + return r; +} + +void core::add_row_to_grobner(const vector> & row) { + u_dependency *dep = nullptr; + dd::pdd sum = m_pdd_manager.mk_val(rational(0)); + for (const auto &p : row) { + sum += pdd_expr(p.coeff(), p.var(), dep); + } + m_pdd_grobner.add(sum, dep); +} + + +void core::find_nl_cluster() { + prepare_rows_and_active_vars(); + svector q; + for (lpvar j : m_to_refine) { + TRACE("grobner", print_monic(emons()[j], tout) << "\n";); + q.push_back(j); + } + + while (!q.empty()) { + lpvar j = q.back(); + q.pop_back(); + add_var_and_its_factors_to_q_and_collect_new_rows(j, q); + } + TRACE("grobner", display_matrix_of_m_rows(tout);); +} + +void core::prepare_rows_and_active_vars() { + m_rows.clear(); + m_rows.resize(m_lar_solver.row_count()); + clear_and_resize_active_var_set(); +} + + +std::unordered_set core::get_vars_of_expr_with_opening_terms(const nex *e ) { + auto ret = get_vars_of_expr(e); + auto & ls = m_lar_solver; + svector added; + for (auto j : ret) { + added.push_back(j); + } + for (unsigned i = 0; i < added.size(); ++i) { + lpvar j = added[i]; + if (ls.column_corresponds_to_term(j)) { + const auto& t = m_lar_solver.get_term(lp::tv::raw(ls.local_to_external(j))); + for (auto p : t) { + if (ret.find(p.column()) == ret.end()) { + added.push_back(p.column()); + ret.insert(p.column()); + } + } + } + } + return ret; +} + +void core::display_matrix_of_m_rows(std::ostream & out) const { + const auto& matrix = m_lar_solver.A_r(); + out << m_rows.size() << " rows" <<"\n"; + out << "the matrix\n"; + for (const auto & r : matrix.m_rows) { + print_row(r, out) << std::endl; + } +} + +void core::set_active_vars_weights(nex_creator& nc) { + nc.set_number_of_vars(m_lar_solver.column_count()); + for (lpvar j : active_var_set()) { + nc.set_var_weight(j, get_var_weight(j)); + } +} + +void core::set_level2var_for_grobner() { + unsigned n = m_lar_solver.column_count(); + unsigned_vector sorted_vars(n), weighted_vars(n); + for (unsigned j = 0; j < n; j++) { + sorted_vars[j] = j; + weighted_vars[j] = get_var_weight(j); + } +#if 1 + // potential update to weights + for (unsigned j = 0; j < n; j++) { + if (is_monic_var(j) && m_to_refine.contains(j)) { + for (lpvar k : m_emons[j].vars()) { + weighted_vars[k] += 6; + } + } + } +#endif + + std::sort(sorted_vars.begin(), sorted_vars.end(), [&](unsigned a, unsigned b) { + unsigned wa = weighted_vars[a]; + unsigned wb = weighted_vars[b]; + return wa < wb || (wa == wb && a < b); }); + + unsigned_vector l2v(n); + for (unsigned j = 0; j < n; j++) + l2v[j] = sorted_vars[j]; + + m_pdd_manager.reset(l2v); +} + +unsigned core::get_var_weight(lpvar j) const { + unsigned k; + switch (m_lar_solver.get_column_type(j)) { + + case lp::column_type::fixed: + k = 0; + break; + case lp::column_type::boxed: + k = 2; + break; + case lp::column_type::lower_bound: + case lp::column_type::upper_bound: + k = 4; + break; + case lp::column_type::free_column: + k = 6; + break; + default: + UNREACHABLE(); + break; + } + if (is_monic_var(j)) { + k++; + if (m_to_refine.contains(j)) { + k++; + } + } + return k; +} + +bool core::is_nl_var(lpvar j) const { + return is_monic_var(j) || m_emons.is_used_in_monic(j); +} + +bool core::influences_nl_var(lpvar j) const { + if (lp::tv::is_term(j)) + j = lp::tv::unmask_term(j); + if (is_nl_var(j)) + return true; + for (const auto & c : m_lar_solver.A_r().m_columns[j]) { + lpvar basic_in_row = m_lar_solver.r_basis()[c.var()]; + if (is_nl_var(basic_in_row)) + return true; + } + return false; +} + +void core::collect_statistics(::statistics & st) { + st.update("arith-nla-explanations", m_stats.m_nla_explanations); + st.update("arith-nla-lemmas", m_stats.m_nla_lemmas); + st.update("arith-nra-calls", m_stats.m_nra_calls); +} + + +} // end of nla + From 7fdcbbaee95a574ea3e51341c8773d8c5f19dc4c Mon Sep 17 00:00:00 2001 From: Olaf Tomalka Date: Tue, 14 Jun 2022 18:55:58 +0200 Subject: [PATCH 236/253] Add high level bindings for js (#6048) * [Draft] Added unfinished code for high level bindings for js * * Rewrote structure of js api files * Added more high level apis * Minor fixes * Fixed wasm github action * Fix JS test * Removed ContextOptions type * * Added Ints to JS Api * Added tests to JS Api * Added run-time checks for contexts * Removed default contexts * Merged Context and createContext so that the api behaves the sames as in other constructors * Added a test for Solver * Added Reals * Added classes for IntVals and RealVals * Added abillity to specify logic for solver * Try to make CI tests not fail * Changed APIs after a round of review * Fix test * Added BitVectors * Made sort into getter * Added initial JS docs * Added more coercible types * Removed done TODOs --- .github/workflows/wasm-release.yml | 10 +- .github/workflows/wasm.yml | 10 +- .gitignore | 7 +- doc/mk_api_doc.py | 37 +- doc/website.dox.in | 8 +- scripts/mk_util.py | 43 +- src/api/js/.nvmrc | 1 + src/api/js/.prettierrc.json | 6 + src/api/js/PUBLISHED_README.md | 91 +- src/api/js/build-wasm.sh | 23 - .../{ => examples/low-level}/example-raw.ts | 3 +- .../{ => examples/low-level}/test-ts-api.ts | 24 +- src/api/js/jest.config.js | 7 + src/api/js/package-lock.json | 11342 +++++++++++++++- src/api/js/package.json | 52 +- .../js/scripts/{async-fns.js => async-fns.ts} | 4 +- src/api/js/scripts/build-wasm.ts | 77 + src/api/js/scripts/list-exports.js | 11 - ...{make-cc-wrapper.js => make-cc-wrapper.ts} | 60 +- src/api/js/scripts/make-ts-wrapper.js | 434 - src/api/js/scripts/make-ts-wrapper.ts | 468 + .../js/scripts/{parse-api.js => parse-api.ts} | 98 +- src/api/js/src/browser.ts | 16 + src/api/js/src/high-level/high-level.test.ts | 450 + src/api/js/src/high-level/high-level.ts | 1888 +++ src/api/js/src/high-level/index.ts | 2 + src/api/js/src/high-level/types.ts | 1132 ++ src/api/js/src/high-level/utils.test.ts | 90 + src/api/js/src/high-level/utils.ts | 85 + src/api/js/src/jest.ts | 62 + .../js/src/{ => low-level}/async-wrapper.js | 1 + src/api/js/src/low-level/index.ts | 4 + src/api/js/src/node-wrapper.ts | 10 - src/api/js/src/node.ts | 38 + src/api/js/tsconfig.build.json | 4 + src/api/js/tsconfig.json | 10 +- src/api/js/typedoc.json | 8 + 37 files changed, 15973 insertions(+), 643 deletions(-) create mode 100644 src/api/js/.nvmrc create mode 100644 src/api/js/.prettierrc.json delete mode 100755 src/api/js/build-wasm.sh rename src/api/js/{ => examples/low-level}/example-raw.ts (96%) rename src/api/js/{ => examples/low-level}/test-ts-api.ts (98%) create mode 100644 src/api/js/jest.config.js rename src/api/js/scripts/{async-fns.js => async-fns.ts} (94%) create mode 100644 src/api/js/scripts/build-wasm.ts delete mode 100644 src/api/js/scripts/list-exports.js rename src/api/js/scripts/{make-cc-wrapper.js => make-cc-wrapper.ts} (67%) delete mode 100644 src/api/js/scripts/make-ts-wrapper.js create mode 100644 src/api/js/scripts/make-ts-wrapper.ts rename src/api/js/scripts/{parse-api.js => parse-api.ts} (82%) create mode 100644 src/api/js/src/browser.ts create mode 100644 src/api/js/src/high-level/high-level.test.ts create mode 100644 src/api/js/src/high-level/high-level.ts create mode 100644 src/api/js/src/high-level/index.ts create mode 100644 src/api/js/src/high-level/types.ts create mode 100644 src/api/js/src/high-level/utils.test.ts create mode 100644 src/api/js/src/high-level/utils.ts create mode 100644 src/api/js/src/jest.ts rename src/api/js/src/{ => low-level}/async-wrapper.js (92%) create mode 100644 src/api/js/src/low-level/index.ts delete mode 100644 src/api/js/src/node-wrapper.ts create mode 100644 src/api/js/src/node.ts create mode 100644 src/api/js/tsconfig.build.json create mode 100644 src/api/js/typedoc.json diff --git a/.github/workflows/wasm-release.yml b/.github/workflows/wasm-release.yml index 1a77f9fe5..376a26684 100644 --- a/.github/workflows/wasm-release.yml +++ b/.github/workflows/wasm-release.yml @@ -23,8 +23,8 @@ jobs: - name: Setup node uses: actions/setup-node@v3 with: - node-version: 'lts/*' - registry-url: 'https://registry.npmjs.org' + node-version: "lts/*" + registry-url: "https://registry.npmjs.org" - name: Prepare for publish run: | @@ -37,13 +37,13 @@ jobs: with: no-install: true version: ${{env.EM_VERSION}} - actions-cache-folder: 'emsdk-cache' + actions-cache-folder: "emsdk-cache" - name: Install dependencies run: npm ci - name: Build TypeScript - run: npm run build-ts + run: npm run build:ts - name: Build wasm run: | @@ -52,7 +52,7 @@ jobs: source $(dirname $(which emsdk))/emsdk_env.sh which node which clang++ - npm run build-wasm + npm run build:wasm - name: Test run: npm test diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 93ebb99fa..809fad42e 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -2,7 +2,7 @@ name: WebAssembly Build on: push: - branches: [ master ] + branches: [master] pull_request: defaults: @@ -23,20 +23,20 @@ jobs: - name: Setup node uses: actions/setup-node@v3 with: - node-version: 'lts/*' + node-version: "lts/*" - name: Setup emscripten uses: mymindstorm/setup-emsdk@v11 with: no-install: true version: ${{env.EM_VERSION}} - actions-cache-folder: 'emsdk-cache' + actions-cache-folder: "emsdk-cache" - name: Install dependencies run: npm ci - name: Build TypeScript - run: npm run build-ts + run: npm run build:ts - name: Build wasm run: | @@ -45,7 +45,7 @@ jobs: source $(dirname $(which emsdk))/emsdk_env.sh which node which clang++ - npm run build-wasm + npm run build:wasm - name: Test run: npm test diff --git a/.gitignore b/.gitignore index 051580bb3..29c49a130 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,7 @@ src/api/python/z3/z3consts.py src/api/python/z3/z3core.py src/ast/pattern/database.h src/util/version.h +src/util/z3_version.h src/api/java/Native.cpp src/api/java/Native.java src/api/java/enumerations/*.java @@ -76,11 +77,8 @@ src/api/ml/z3native.mli src/api/ml/z3enums.mli src/api/ml/z3.mllib src/api/js/node_modules/ -src/api/js/*.js src/api/js/build/ -src/api/js/**/*.d.ts -!src/api/js/scripts/*.js -!src/api/js/src/*.js +src/api/js/**/*.__GENERATED__.* debug/* out/** @@ -92,3 +90,4 @@ examples/**/obj CMakeSettings.json # Editor temp files *.swp +.DS_Store \ No newline at end of file diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index 01fe482b9..7ca47b89a 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -14,11 +14,13 @@ import subprocess ML_ENABLED=False MLD_ENABLED=False +JS_ENABLED=False BUILD_DIR='../build' DOXYGEN_EXE='doxygen' TEMP_DIR=os.path.join(os.getcwd(), 'tmp') OUTPUT_DIRECTORY=os.path.join(os.getcwd(), 'api') Z3PY_PACKAGE_PATH='../src/api/python/z3' +JS_API_PATH='../src/api/js' Z3PY_ENABLED=True DOTNET_ENABLED=True JAVA_ENABLED=True @@ -28,8 +30,8 @@ SCRIPT_DIR=os.path.abspath(os.path.dirname(__file__)) def parse_options(): global ML_ENABLED, MLD_ENABLED, BUILD_DIR, DOXYGEN_EXE, TEMP_DIR, OUTPUT_DIRECTORY - global Z3PY_PACKAGE_PATH, Z3PY_ENABLED, DOTNET_ENABLED, JAVA_ENABLED - global DOTNET_API_SEARCH_PATHS, JAVA_API_SEARCH_PATHS + global Z3PY_PACKAGE_PATH, Z3PY_ENABLED, DOTNET_ENABLED, JAVA_ENABLED, JS_ENABLED + global DOTNET_API_SEARCH_PATHS, JAVA_API_SEARCH_PATHS, JS_API_PATH parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('-b', '--build', @@ -46,6 +48,11 @@ def parse_options(): default=False, help='Include ML/OCaml API documentation' ) + parser.add_argument('--js', + action='store_true', + default=False, + help='Include JS/TS API documentation' + ) parser.add_argument('--doxygen-executable', dest='doxygen_executable', default=DOXYGEN_EXE, @@ -104,6 +111,7 @@ def parse_options(): pargs = parser.parse_args() ML_ENABLED = pargs.ml MLD_ENABLED = pargs.mld + JS_ENABLED = pargs.js BUILD_DIR = pargs.build DOXYGEN_EXE = pargs.doxygen_executable TEMP_DIR = pargs.temp_dir @@ -224,6 +232,10 @@ try: print("Java documentation disabled") doxygen_config_substitutions['JAVA_API_FILES'] = '' doxygen_config_substitutions['JAVA_API_SEARCH_PATHS'] = '' + if JS_ENABLED: + print('Javascript documentation enabled') + else: + print('Javascript documentation disabled') doxygen_config_file = temp_path('z3api.cfg') configure_file( @@ -241,7 +253,7 @@ try: '{prefix}C API ' ).format( prefix=bullet_point_prefix) - + if Z3PY_ENABLED: print("Python documentation enabled") website_dox_substitutions['PYTHON_API'] = ( @@ -274,6 +286,13 @@ try: prefix=bullet_point_prefix) else: website_dox_substitutions['OCAML_API'] = '' + if JS_ENABLED: + website_dox_substitutions['JS_API'] = ( + '{prefix}Javascript/Typescript API' + ).format( + prefix=bullet_point_prefix) + else: + website_dox_substitutions['JS_API'] = '' configure_file( doc_path('website.dox.in'), temp_path('website.dox'), @@ -339,6 +358,18 @@ try: exit(1) print("Generated ML/OCaml documentation.") + if JS_ENABLED: + try: + subprocess.check_output(['npm', 'run', '--prefix=%s' % JS_API_PATH, 'check-engine']) + except subprocess.CalledProcessError as e: + print("ERROR: node version check failed.") + print(e.output) + exit(1) + if subprocess.call(['npm', 'run', '--prefix=%s' % JS_API_PATH, 'docs']) != 0: + print("ERROR: npm run docs failed.") + exit(1) + print("Generated Javascript documentation.") + print("Documentation was successfully generated at subdirectory '{}'.".format(OUTPUT_DIRECTORY)) except Exception: exctype, value = sys.exc_info()[:2] diff --git a/doc/website.dox.in b/doc/website.dox.in index f4caa1277..5d084550c 100644 --- a/doc/website.dox.in +++ b/doc/website.dox.in @@ -1,13 +1,13 @@ /** \mainpage An Efficient Theorem Prover - + Z3 is a high-performance theorem prover being developed at Microsoft Research. - + href="http://research.microsoft.com">Microsoft Research. + The Z3 website is at http://github.com/z3prover. This website hosts the automatically generated documentation for the Z3 APIs. - \ref @C_API@ - - \ref @CPP_API@ @DOTNET_API@ @JAVA_API@ @PYTHON_API@ @OCAML_API@ + - \ref @CPP_API@ @DOTNET_API@ @JAVA_API@ @PYTHON_API@ @OCAML_API@ @JS_API@ */ diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 8a56e843a..68bb9da14 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -246,10 +246,13 @@ def rmf(fname): def exec_compiler_cmd(cmd): r = exec_cmd(cmd) - if is_windows() or is_cygwin_mingw() or is_cygwin() or is_msys2(): - rmf('a.exe') - else: - rmf('a.out') + # Windows + rmf('a.exe') + # Unix + rmf('a.out') + # Emscripten + rmf('a.wasm') + rmf('a.worker.js') return r def test_cxx_compiler(cc): @@ -293,6 +296,10 @@ def test_fpmath(cc): t.commit() # -Werror is needed because some versions of clang warn about unrecognized # -m flags. + # TODO(ritave): Safari doesn't allow SIMD WebAssembly extension, add a flag to build script + if exec_compiler_cmd([cc, CPPFLAGS, '-Werror', 'tstsse.cpp', LDFLAGS, '-msse -msse2 -msimd128']) == 0: + FPMATH_FLAGS='-msse -msse2 -msimd128' + return 'SSE2-EMSCRIPTEN' if exec_compiler_cmd([cc, CPPFLAGS, '-Werror', 'tstsse.cpp', LDFLAGS, '-mfpmath=sse -msse -msse2']) == 0: FPMATH_FLAGS="-mfpmath=sse -msse -msse2" return "SSE2-GCC" @@ -499,7 +506,7 @@ def find_ml_lib(): def is64(): global LINUX_X64 - if is_sunos() and sys.version_info.major < 3: + if is_sunos() and sys.version_info.major < 3: return LINUX_X64 else: return LINUX_X64 and sys.maxsize >= 2**32 @@ -625,11 +632,11 @@ elif os.name == 'posix': else: LINUX_X64=False - + if os.name == 'posix' and os.uname()[4] == 'arm64': IS_ARCH_ARM64 = True - + def display_help(exit_code): print("mk_make.py: Z3 Makefile generator\n") print("This script generates the Makefile for the Z3 theorem prover.") @@ -792,7 +799,7 @@ def extract_c_includes(fname): linenum = 1 for line in f: m1 = std_inc_pat.match(line) - if m1: + if m1: root_file_name = m1.group(1) slash_pos = root_file_name.rfind('/') if slash_pos >= 0 and root_file_name.find("..") < 0 : #it is a hack for lp include files that behave as continued from "src" @@ -1650,7 +1657,7 @@ def set_key_file(self): else: print("Keyfile '%s' could not be found; %s.dll will be unsigned." % (self.key_file, self.dll_name)) self.key_file = None - + # build for dotnet core class DotNetDLLComponent(Component): @@ -1664,7 +1671,7 @@ class DotNetDLLComponent(Component): self.assembly_info_dir = assembly_info_dir self.key_file = default_key_file - + def mk_makefile(self, out): if not is_dotnet_core_enabled(): return @@ -1680,7 +1687,7 @@ class DotNetDLLComponent(Component): out.write(' ') out.write(cs_file) out.write('\n') - + set_key_file(self) key = "" if not self.key_file is None: @@ -1724,7 +1731,7 @@ class DotNetDLLComponent(Component): ous.write(core_csproj_str) dotnetCmdLine = [DOTNET, "build", csproj] - + dotnetCmdLine.extend(['-c']) if DEBUG_MODE: dotnetCmdLine.extend(['Debug']) @@ -1733,19 +1740,19 @@ class DotNetDLLComponent(Component): path = os.path.join(os.path.abspath(BUILD_DIR), ".") dotnetCmdLine.extend(['-o', "\"%s\"" % path]) - + MakeRuleCmd.write_cmd(out, ' '.join(dotnetCmdLine)) - out.write('\n') + out.write('\n') out.write('%s: %s\n\n' % (self.name, dllfile)) def main_component(self): return is_dotnet_core_enabled() - + def has_assembly_info(self): # TBD: is this required for dotnet core given that version numbers are in z3.csproj file? return False - + def mk_win_dist(self, build_path, dist_path): if is_dotnet_core_enabled(): mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR)) @@ -2038,7 +2045,7 @@ class MLComponent(Component): out.write('ml: %s.cma %s.cmxa %s.cmxs\n' % (z3mls, z3mls, z3mls)) if IS_OSX: out.write('\tinstall_name_tool -id %s/libz3.dylib libz3.dylib\n' % (stubs_install_path)) - out.write('\tinstall_name_tool -change libz3.dylib %s/libz3.dylib api/ml/dllz3ml.so\n' % (stubs_install_path)) + out.write('\tinstall_name_tool -change libz3.dylib %s/libz3.dylib api/ml/dllz3ml.so\n' % (stubs_install_path)) out.write('\n') if IS_WINDOWS: @@ -3117,7 +3124,7 @@ def get_platform_toolset_str(): if len(tokens) < 2: return default else: - if tokens[0] == "15": + if tokens[0] == "15": # Visual Studio 2017 reports 15.* but the PlatformToolsetVersion is 141 return "v141" else: diff --git a/src/api/js/.nvmrc b/src/api/js/.nvmrc new file mode 100644 index 000000000..7fd023741 --- /dev/null +++ b/src/api/js/.nvmrc @@ -0,0 +1 @@ +v16.15.0 diff --git a/src/api/js/.prettierrc.json b/src/api/js/.prettierrc.json new file mode 100644 index 000000000..afe608c18 --- /dev/null +++ b/src/api/js/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "arrowParens": "avoid", + "printWidth": 120, + "trailingComma": "all" +} diff --git a/src/api/js/PUBLISHED_README.md b/src/api/js/PUBLISHED_README.md index 4ccd4bea7..e4c385680 100644 --- a/src/api/js/PUBLISHED_README.md +++ b/src/api/js/PUBLISHED_README.md @@ -1,32 +1,86 @@ # Z3 TypeScript Bindings -This project provides low-level TypeScript bindings for the [Z3 theorem prover](https://github.com/Z3Prover/z3). It is available on npm as [z3-solver](https://www.npmjs.com/package/z3-solver). - -Z3 itself is distributed as a wasm artifact as part of this package. You can find the documentation for the Z3 API [here](https://z3prover.github.io/api/html/z3__api_8h.html), though note the differences below. +This project provides high-level and low-level TypeScript bindings for the [Z3 theorem prover](https://github.com/Z3Prover/z3). It is available on npm as [z3-solver](https://www.npmjs.com/package/z3-solver). +Z3 itself is distributed as a wasm artifact as part of this package. ## Using -This requires threads, which means you'll need to be running in an environment which supports `SharedArrayBuffer`. In browsers, in addition to ensuring the browser has implemented `SharedArrayBuffer`, you'll need to serve your page with [special headers](https://web.dev/coop-coep/). There's a [neat trick](https://github.com/gzuidhof/coi-serviceworker) for doing that client-side on e.g. Github Pages, though you shouldn't use that trick in more complex applications. +```javascript +const { init } = require('z3-solver'); +const { + Z3, // Low-level C-like API + Context, // High-level Z3Py-like API +} = await init(); +``` -The Emscripten worker model will spawn multiple instances of `z3-built.js` for long-running operations. When building for the web, you should include that file as its own script on the page - using a bundler like webpack will prevent it from loading correctly. That script defines a global variable named `initZ3`. Your main script, which can be bundled, should do `let { init } = require('z3-solver/build/wrapper.js'); let { Z3 } = await init(initZ3);`. +This package has different initialization for browser and node. Your bundler and node should choose good version automatically, but you can import the one you need manually - `const { init } = require('z3-solver/node');` or `const { init } = require('z3-solver/browser');`. -Other than the differences below, the bindings can be used exactly as you'd use the C library. Because this is a wrapper around a C library, most of the values you'll use are just numbers representing pointers. For this reason you are strongly encouraged to make use of the TypeScript types to differentiate among the different kinds of value. +### Limitations -The module exports an `init` function, is an async function which initializes the library and returns `{ em, Z3 }` - `em` contains the underlying emscripten module, which you can use to e.g. kill stray threads, and `Z3` contains the actual bindings. The other module exports are the enums defined in the Z3 API. +The package requires threads, which means you'll need to be running in an environment which supports `SharedArrayBuffer`. In browsers, in addition to ensuring the browser has implemented `SharedArrayBuffer`, you'll need to serve your page with [special headers](https://web.dev/coop-coep/). There's a [neat trick](https://github.com/gzuidhof/coi-serviceworker) for doing that client-side on e.g. Github Pages, though you shouldn't use that trick in more complex applications. -[`test-ts-api.ts`](./test-ts-api.ts) contains a couple real cases translated very mechanically from [this file](https://github.com/Z3Prover/z3/blob/90fd3d82fce20d45ed2eececdf65545bab769503/examples/c/test_capi.c). +The Emscripten worker model will spawn multiple instances of `z3-built.js` for long-running operations. When building for the web, you should include that file as its own script on the page - using a bundler like webpack will prevent it from loading correctly. +## High-level -## Differences from the C API +You can find the documentation for the high-level Z3 API [here](https://z3prover.github.io/api/html/js/index.html). There are some usage examples in `src/high-level/high-level.test.ts` -### Integers +Most of the API requires a context to run, and so you need to initialize one to access most functionality. + +```javascript +const { init } = require('z3-solver'); +const { Context } = await init(); +const { Solver, Int, And } = new Context('main'); + +const x = Int.const('x'); + +const solver = new Solver(); +solver.add(And(x.ge(0), x.le(9))); +console.log(await solver.check()); +// sat +``` + +Typescript types try to catch errors concerning mixing of Contexts during compile time. Objects returned from `new Context('name')` have a type narrowed by the provided Context name and will fail to compile if you try to mix them. + +```typescript +const { Int: Int1 } = new Context('context1'); +const { Int: Int2 } = new Context('context2'); + +const x = Int1.const('x'); +const y = Int2.const('y'); + +// The below will fail to compile in Typescript +x.ge(y); +``` + +```typescript +// Use templated functions to propagate narrowed types +function add(a: Arith, b: Arith): Arith { + return a.add(b).add(5); +} +``` + +Some long-running functions are promises and will run in a separate thread. +Currently Z3-solver is not thread safe, and so, high-level APIs ensures that only one long-running function can run at a time, and all other long-running requests will queue up and be run one after another. + +## Low-level + +You can find the documentation for the low-level Z3 API [here](https://z3prover.github.io/api/html/z3__api_8h.html), though note the differences below. `examples/low-level/` contains a couple real cases translated very mechanically from [this file](https://github.com/Z3Prover/z3/blob/90fd3d82fce20d45ed2eececdf65545bab769503/examples/c/test_capi.c). + +The bindings can be used exactly as you'd use the C library. Because this is a wrapper around a C library, most of the values you'll use are just numbers representing pointers. For this reason you are strongly encouraged to make use of the TypeScript types to differentiate among the different kinds of value. + +The module exports an `init` function, which is an async function which initializes the library and returns `{ em, Z3 }` - `em` contains the underlying emscripten module, which you can use to e.g. kill stray threads, and `Z3` contains the actual bindings. The other module exports are the enums defined in the Z3 API. + +### Differences from the C API + +#### Integers JavaScript numbers are IEEE double-precisions floats. These can be used wherever the C API expects an `int`, `unsigned int`, `float`, or `double`. `int64_t` and `uint64_t` cannot be precisely represented by JS numbers, so in the TS bindings they are represented by [BigInts](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#bigint_type). -### Out parameters +#### Out parameters In C, to return multiple values a function will take an address to write to, conventionally referred to as an "out parameter". Sometimes the function returns a boolean to indicate success; other times it may return nothing or some other value. @@ -56,7 +110,7 @@ is represented in the TS bindings as ```ts function model_eval(c: Z3_context, m: Z3_model, t: Z3_ast, model_completion: boolean): Z3_ast | null { - // ... + // ... } ``` @@ -64,12 +118,12 @@ Note that the boolean return type of the C function is translated into a nullabl When the return value is of interest it is included in the returned record under the key `rv`. - -### Arrays +#### Arrays The when the C API takes an array as an argument it will also require a parameter which specifies the length of the array (since arrays do not carry their own lengths in C). In the TS bindings this is automatically inferred. For example, the C declaration + ```js unsigned Z3_rcf_mk_roots(Z3_context c, unsigned n, Z3_rcf_num const a[], Z3_rcf_num roots[]); ``` @@ -84,8 +138,7 @@ function rcf_mk_roots(c: Z3_context, a: Z3_rcf_num[]): { rv: number; roots: Z3_r When there are multiple arrays which the C API expects to be of the same length, the TS bindings will enforce that this is the case. - -### Null pointers +#### Null pointers Some of the C APIs accept or return null pointers (represented by types whose name end in `_opt`). These are represented in the TS bindings as `| null`. For example, the C declaration @@ -101,8 +154,7 @@ function model_get_const_interp(c: Z3_context, m: Z3_model, a: Z3_func_decl): Z3 } ``` - -### Async functions +#### Async functions Certain long-running APIs are not appropriate to call on the main thread. In the TS bindings those APIs are marked as `async` and are automatically called on a different thread. This includes the following APIs: @@ -122,5 +174,4 @@ Certain long-running APIs are not appropriate to call on the main thread. In the - `Z3_fixedpoint_query_from_lvl` - `Z3_polynomial_subresultants` -Note that these are not thread-safe, and so only one call can be running at a time. Trying to call a second async API before the first completes will throw. - +Note that these are not thread-safe, and so only one call can be running at a time. In contrast to high-level APIs, trying to call a second async API before the first completes will throw. diff --git a/src/api/js/build-wasm.sh b/src/api/js/build-wasm.sh deleted file mode 100755 index e89b70862..000000000 --- a/src/api/js/build-wasm.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -set -euxo pipefail - - -export ROOT=$PWD - -cd ../../.. -export CXXFLAGS="-pthread -s USE_PTHREADS=1 -s DISABLE_EXCEPTION_CATCHING=0" -export LDFLAGS="-s WASM_BIGINT -s -pthread -s USE_PTHREADS=1" -if [ ! -f "build/Makefile" ]; then - emconfigure python scripts/mk_make.py --staticlib --single-threaded -fi - -cd build -emmake make -j$(nproc) libz3.a - -cd $ROOT - -export EM_CACHE=$HOME/.emscripten/ -export FNS=$(node scripts/list-exports.js) -export METHODS='["ccall","FS","allocate","UTF8ToString","intArrayFromString","ALLOC_NORMAL"]' -emcc build/async-fns.cc ../../../build/libz3.a --std=c++20 --pre-js src/async-wrapper.js -g2 -pthread -fexceptions -s WASM_BIGINT -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=0 -s PTHREAD_POOL_SIZE_STRICT=0 -s MODULARIZE=1 -s 'EXPORT_NAME="initZ3"' -s EXPORTED_RUNTIME_METHODS=$METHODS -s EXPORTED_FUNCTIONS=$FNS -s DISABLE_EXCEPTION_CATCHING=0 -s SAFE_HEAP=0 -s DEMANGLE_SUPPORT=1 -s TOTAL_MEMORY=1GB -I z3/src/api/ -o build/z3-built.js diff --git a/src/api/js/example-raw.ts b/src/api/js/examples/low-level/example-raw.ts similarity index 96% rename from src/api/js/example-raw.ts rename to src/api/js/examples/low-level/example-raw.ts index 684b8e7ea..6e34b4aba 100644 --- a/src/api/js/example-raw.ts +++ b/src/api/js/examples/low-level/example-raw.ts @@ -1,4 +1,5 @@ -import { init, Z3_error_code } from './build/node-wrapper'; +import process from 'process'; +import { init, Z3_error_code } from '../../build/node'; // demonstrates use of the raw API diff --git a/src/api/js/test-ts-api.ts b/src/api/js/examples/low-level/test-ts-api.ts similarity index 98% rename from src/api/js/test-ts-api.ts rename to src/api/js/examples/low-level/test-ts-api.ts index ace3c2b5c..3eaef5bfe 100644 --- a/src/api/js/test-ts-api.ts +++ b/src/api/js/examples/low-level/test-ts-api.ts @@ -3,24 +3,24 @@ // TypeScript can infer all of them. // They're just here so readers can see what types things are. +// @ts-ignore we're not going to bother with types for this +import process from 'process'; +import { sprintf } from 'sprintf-js'; import type { + Z3_app, + Z3_ast, + Z3_ast_vector, Z3_config, Z3_context, + Z3_func_decl, + Z3_func_entry, + Z3_func_interp, + Z3_model, Z3_solver, Z3_sort, - Z3_ast, - Z3_app, - Z3_model, Z3_symbol, - Z3_ast_vector, - Z3_func_decl, - Z3_func_interp, - Z3_func_entry, -} from './build/node-wrapper'; -import { init, Z3_lbool, Z3_ast_kind, Z3_sort_kind, Z3_symbol_kind } from './build/node-wrapper'; - -// @ts-ignore we're not going to bother with types for this -import { sprintf } from 'sprintf-js'; +} from '../../build/node'; +import { init, Z3_ast_kind, Z3_lbool, Z3_sort_kind, Z3_symbol_kind } from '../../build/node'; let printf = (str: string, ...args: unknown[]) => console.log(sprintf(str.replace(/\n$/, ''), ...args)); diff --git a/src/api/js/jest.config.js b/src/api/js/jest.config.js new file mode 100644 index 000000000..201c27090 --- /dev/null +++ b/src/api/js/jest.config.js @@ -0,0 +1,7 @@ +/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + roots: ['/src'], + verbose: true, +}; diff --git a/src/api/js/package-lock.json b/src/api/js/package-lock.json index 56bb70753..c860eda9b 100644 --- a/src/api/js/package-lock.json +++ b/src/api/js/package-lock.json @@ -1,29 +1,11351 @@ { + "name": "z3-solver", + "lockfileVersion": 2, "requires": true, - "lockfileVersion": 1, + "packages": { + "": { + "name": "z3-solver", + "license": "MIT", + "dependencies": { + "async-mutex": "^0.3.2" + }, + "devDependencies": { + "@types/jest": "^27.5.1", + "@types/node": "^17.0.8", + "@types/prettier": "^2.6.1", + "@types/sprintf-js": "^1.1.2", + "check-engine": "^1.10.1", + "iter-tools": "^7.3.1", + "jest": "^28.1.0", + "npm-run-all": "^4.1.5", + "prettier": "^2.5.1", + "rimraf": "^3.0.2", + "sprintf-js": "^1.1.2", + "ts-jest": "^28.0.3", + "ts-node": "^10.8.0", + "typedoc": "^0.22.17", + "typescript": "^4.5.4" + }, + "engines": { + "node": ">=16 <18" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", + "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", + "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.18.2", + "@babel/helper-compilation-targets": "^7.18.2", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helpers": "^7.18.2", + "@babel/parser": "^7.18.0", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.2", + "@jridgewell/gen-mapping": "^0.3.0", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", + "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz", + "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", + "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", + "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", + "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz", + "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", + "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", + "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.3.tgz", + "integrity": "sha512-rL50YcEuHbbauAFAysNsJA4/f89fGTOBRNs9P81sniKnKAr4xULe5AecolcsKbi88xu0ByWYDj/S1AJ3FSFuSQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz", + "integrity": "sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.17.12" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.3.tgz", + "integrity": "sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.2.tgz", + "integrity": "sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.18.2", + "@babel/helper-environment-visitor": "^7.18.2", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.18.0", + "@babel/types": "^7.18.2", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.2.tgz", + "integrity": "sha512-0On6B8A4/+mFUto5WERt3EEuG1NznDirvwca1O8UwXQHVY8g3R7OzYgxXdOfMwLO08UrpUD/2+3Bclyq+/C94Q==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.0.tgz", + "integrity": "sha512-tscn3dlJFGay47kb4qVruQg/XWlmvU0xp3EJOjzzY+sBaI+YgwKcvAmTcyYU7xEiLLIY5HCdWRooAL8dqkFlDA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.0", + "jest-util": "^28.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.0.tgz", + "integrity": "sha512-/2PTt0ywhjZ4NwNO4bUqD9IVJfmFVhVKGlhvSpmEfUCuxYf/3NHcKmRFI+I71lYzbTT3wMuYpETDCTHo81gC/g==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.0", + "@jest/reporters": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^28.0.2", + "jest-config": "^28.1.0", + "jest-haste-map": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.0", + "jest-resolve-dependencies": "^28.1.0", + "jest-runner": "^28.1.0", + "jest-runtime": "^28.1.0", + "jest-snapshot": "^28.1.0", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", + "jest-watcher": "^28.1.0", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/environment": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", + "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.0.tgz", + "integrity": "sha512-be9ETznPLaHOmeJqzYNIXv1ADEzENuQonIoobzThOYPuK/6GhrWNIJDVTgBLCrz3Am73PyEU2urQClZp0hLTtA==", + "dev": true, + "dependencies": { + "expect": "^28.1.0", + "jest-snapshot": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.0.tgz", + "integrity": "sha512-5BrG48dpC0sB80wpeIX5FU6kolDJI4K0n5BM9a5V38MGx0pyRvUBSS0u2aNTdDzmOrCjhOg8pGs6a20ivYkdmw==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", + "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@sinonjs/fake-timers": "^9.1.1", + "@types/node": "*", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.0.tgz", + "integrity": "sha512-3m7sTg52OTQR6dPhsEQSxAvU+LOBbMivZBwOvKEZ+Rb+GyxVnXi9HKgOTYkx/S99T8yvh17U4tNNJPIEQmtwYw==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.0", + "@jest/expect": "^28.1.0", + "@jest/types": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.0.tgz", + "integrity": "sha512-qxbFfqap/5QlSpIizH9c/bFCDKsQlM4uAKSOvZrP+nIdrjqre3FmKzpTtYyhsaVcOSNK7TTt2kjm+4BJIjysFA==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "@jridgewell/trace-mapping": "^0.3.7", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-util": "^28.1.0", + "jest-worker": "^28.1.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.0.2.tgz", + "integrity": "sha512-YVDJZjd4izeTDkij00vHHAymNXQ6WWsdChFRK86qck6Jpr3DCL5W3Is3vslviRlP+bLuMYRLbdp98amMvqudhA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.23.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.0.2.tgz", + "integrity": "sha512-Y9dxC8ZpN3kImkk0LkK5XCEneYMAXlZ8m5bflmSL5vrwyeUpJfentacCUg6fOb8NOpOO7hz2+l37MV77T6BFPw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.7", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.0.tgz", + "integrity": "sha512-sBBFIyoPzrZho3N+80P35A5oAkSKlGfsEFfXFWuPGBsW40UAjCkGakZhn4UQK4iQlW2vgCDMRDOob9FGKV8YoQ==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.0.tgz", + "integrity": "sha512-tZCEiVWlWNTs/2iK9yi6o3AlMfbbYgV4uuZInSVdzZ7ftpHZhCMuhvk2HLYhCZzLgPFQ9MnM1YaxMnh3TILFiQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^28.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.0.tgz", + "integrity": "sha512-omy2xe5WxlAfqmsTjTPxw+iXRTRnf+NtX0ToG+4S0tABeb4KsKmPUHq5UBuwunHg3tJRwgEQhEp0M/8oiatLEA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.0", + "@jridgewell/trace-mapping": "^0.3.7", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.0", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.5.tgz", + "integrity": "sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-fUy7YRpT+rHXto1YlL+J9rs0uLGyiqVt3ZOTQR+4ROc47yNl8WLdVLgUloBRhOxP1PZvguHl44T3H0wAWxahYQ==", + "dev": true, + "dependencies": { + "jest-matcher-utils": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, + "node_modules/@types/node": { + "version": "17.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prettier": { + "version": "2.6.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sprintf-js": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.7.1", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/argparse/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async-mutex": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz", + "integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==", + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/babel-jest": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.0.tgz", + "integrity": "sha512-zNKk0yhDZ6QUwfxh9k07GII6siNGMJWVUU49gmFj5gfdqDKLqa2RArXOF2CODp4Dr7dLxN2cvAV+667dGJ4b4w==", + "dev": true, + "dependencies": { + "@jest/transform": "^28.1.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^28.0.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.0.2.tgz", + "integrity": "sha512-Kizhn/ZL+68ZQHxSnHyuvJv8IchXD62KQxV77TBDV/xoBFBOfgRAk97GNs6hXdTTCiVES9nB2I6+7MXXrk5llQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.0.2.tgz", + "integrity": "sha512-sYzXIdgIXXroJTFeB3S6sNDWtlJ2dllCdTEsnZ65ACrMojj3hVNFRmnJ1HZtomGi+Be7aqpY/HJ92fr8OhKVkQ==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^28.0.2", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/call-bind": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001344", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", + "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/check-engine": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/check-engine/-/check-engine-1.10.1.tgz", + "integrity": "sha512-KqZ6sV7onqcc81qoK+NsCNjNfik1rRHzmxYJ+tDdCc+6nbpaj0X8SKSzb8lYIcQ+ire5ypMr4YP832/7RH843Q==", + "dev": true, + "dependencies": { + "bluebird": "3.7.2", + "colors": "1.4.0", + "command-line-usage": "6.1.0", + "jsonfile": "6.0.1", + "semver": "7.3.2", + "yargs": "16.1.0" + }, + "bin": { + "check-engine": "bin/check-engine.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/check-engine/node_modules/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/check-engine/node_modules/yargs": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.0.tgz", + "integrity": "sha512-upWFJOmDdHN0syLuESuvXDmrRcWd1QafJolHskzaw79uZa7/x53gxQKiR07W59GWY1tFhhU/Th9DrtSfpS782g==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.2", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz", + "integrity": "sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==", + "dev": true + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "node_modules/color-convert": { + "version": "1.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.0.tgz", + "integrity": "sha512-Ew1clU4pkUeo6AFVDFxCbnN7GIZfXl48HIOQeFQnkO3oOqvpI7wdqtLRwv9iOCZ/7A+z4csVZeiDdEcj8g6Wiw==", + "dev": true, + "dependencies": { + "array-back": "^4.0.0", + "chalk": "^2.4.2", + "table-layout": "^1.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-properties": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.140", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.140.tgz", + "integrity": "sha512-NLz5va823QfJBYOO/hLV4AfU4Crmkl/6Hl2pH3qdJcmi0ySZ3YTWHxOlDm3uJOFBEPy3pIhu8gKQo6prQTWKKA==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.20.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/execa/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/execa/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/execa/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/execa/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.0.tgz", + "integrity": "sha512-qFXKl8Pmxk8TBGfaFKRtcQjfXEnKAs+dmlxdwvukJZorwrAabT7M3h8oLOG01I2utEhkmUTi17CHaPBovZsKdw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^28.1.0", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-util": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/expect/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/expect/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/expect/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/expect/node_modules/diff-sequences": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", + "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/expect/node_modules/jest-diff": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", + "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.0.2", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/jest-matcher-utils": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", + "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.0", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/expect/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/expect/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "dev": true, + "license": "ISC" + }, + "node_modules/has": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "dev": true, + "license": "ISC" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iter-tools": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/iter-tools/-/iter-tools-7.3.1.tgz", + "integrity": "sha512-XYS0CjthZqQ7MomjB4Ww9NqrVKRlP2qoa1oWFcIQrkMykhkgFTpSNG+sRcqzHBp6fSxk8oDIjudFTgQ6nnA4mA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.1" + } + }, + "node_modules/jest": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.0.tgz", + "integrity": "sha512-TZR+tHxopPhzw3c3560IJXZWLNHgpcz1Zh0w5A65vynLGNcg/5pZ+VildAd7+XGOu6jd58XMY/HNn0IkZIXVXg==", + "dev": true, + "dependencies": { + "@jest/core": "^28.1.0", + "import-local": "^3.0.2", + "jest-cli": "^28.1.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.0.2.tgz", + "integrity": "sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.0.tgz", + "integrity": "sha512-rNYfqfLC0L0zQKRKsg4n4J+W1A2fbyGH7Ss/kDIocp9KXD9iaL111glsLu7+Z7FHuZxwzInMDXq+N1ZIBkI/TQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.0", + "@jest/expect": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^28.1.0", + "jest-matcher-utils": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-runtime": "^28.1.0", + "jest-snapshot": "^28.1.0", + "jest-util": "^28.1.0", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-circus/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-circus/node_modules/diff-sequences": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", + "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", + "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.0.2", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", + "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.0", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.0.tgz", + "integrity": "sha512-fDJRt6WPRriHrBsvvgb93OxgajHHsJbk4jZxiPqmZbMDRcHskfJBBfTyjFko0jjfprP544hOktdSi9HVgl4VUQ==", + "dev": true, + "dependencies": { + "@jest/core": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/types": "^28.1.0", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^28.1.0", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.0.tgz", + "integrity": "sha512-aOV80E9LeWrmflp7hfZNn/zGA4QKv/xsn2w8QCBP0t0+YqObuCWTSgNbHJ0j9YsTuCO08ZR/wsvlxqqHX20iUA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.0", + "@jest/types": "^28.1.0", + "babel-jest": "^28.1.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^28.1.0", + "jest-environment-node": "^28.1.0", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.0", + "jest-runner": "^28.1.0", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-config/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-config/node_modules/pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-config/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-docblock": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.0.2.tgz", + "integrity": "sha512-FH10WWw5NxLoeSdQlJwu+MTiv60aXV/t8KEwIRGEv74WARE1cXIqh1vGdy2CraHuWOOrnzTWj/azQKqW4fO7xg==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.0.tgz", + "integrity": "sha512-a/XX02xF5NTspceMpHujmOexvJ4GftpYXqr6HhhmKmExtMXsyIN/fvanQlt/BcgFoRKN4OCXxLQKth9/n6OPFg==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.0", + "pretty-format": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-each/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-node": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.0.tgz", + "integrity": "sha512-gBLZNiyrPw9CSMlTXF1yJhaBgWDPVvH0Pq6bOEwGMXaYNzhzhw2kA/OijNF8egbCgDS0/veRv97249x2CX+udQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.0", + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.0.tgz", + "integrity": "sha512-xyZ9sXV8PtKi6NCrJlmq53PyNVHzxmcfXNVvIRHpHmh1j/HChC4pwKgyjj7Z9us19JMw8PpQTJsFWOsIfT93Dw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.0", + "jest-worker": "^28.1.0", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.0.tgz", + "integrity": "sha512-uIJDQbxwEL2AMMs2xjhZl2hw8s77c3wrPaQ9v6tXJLGaaQ+4QrNJH5vuw7hA7w/uGT/iJ42a83opAqxGHeyRIA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", + "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.0.tgz", + "integrity": "sha512-vvfN7+tPNnnhDvISuzD1P+CRVP8cK0FHXRwPAcdDaQv4zgvwvag2n55/h5VjYcM5UJG7L4TwE5tZlzcI0X2Lhw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.0.tgz", + "integrity": "sha512-Ue1VYoSZquPwEvng7Uefw8RmZR+me/1kr30H2jMINjGeHgeO/JgrR6wxj2ofkJ7KSAA11W3cOrhNCbj5Dqqd9g==", + "dev": true, + "dependencies": { + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-resolve/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.0.tgz", + "integrity": "sha512-FBpmuh1HB2dsLklAlRdOxNTTHKFR6G1Qmd80pVDvwbZXTriqjWqjei5DKFC1UlM732KjYcE6yuCdiF0WUCOS2w==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.0", + "@jest/environment": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^28.0.2", + "jest-environment-node": "^28.1.0", + "jest-haste-map": "^28.1.0", + "jest-leak-detector": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-resolve": "^28.1.0", + "jest-runtime": "^28.1.0", + "jest-util": "^28.1.0", + "jest-watcher": "^28.1.0", + "jest-worker": "^28.1.0", + "source-map-support": "0.5.13", + "throat": "^6.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.0.tgz", + "integrity": "sha512-wNYDiwhdH/TV3agaIyVF0lsJ33MhyujOe+lNTUiolqKt8pchy1Hq4+tDMGbtD5P/oNLA3zYrpx73T9dMTOCAcg==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.0", + "@jest/fake-timers": "^28.1.0", + "@jest/globals": "^28.1.0", + "@jest/source-map": "^28.0.2", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.0", + "jest-snapshot": "^28.1.0", + "jest-util": "^28.1.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.0.tgz", + "integrity": "sha512-ex49M2ZrZsUyQLpLGxQtDbahvgBjlLPgklkqGM0hq/F7W/f8DyqZxVHjdy19QKBm4O93eDp+H5S23EiTbbUmHw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^28.1.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.0", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.0", + "jest-matcher-utils": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-util": "^28.1.0", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/diff-sequences": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", + "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", + "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.0.2", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", + "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.0", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.0.tgz", + "integrity": "sha512-Lly7CJYih3vQBfjLeANGgBSBJ7pEa18cxpQfQEq2go2xyEzehnHfQTjoUia8xUv4x4J80XKFIDwJJThXtRFQXQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "leven": "^3.1.0", + "pretty-format": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-validate/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.0.tgz", + "integrity": "sha512-tNHMtfLE8Njcr2IRS+5rXYA4BhU90gAOwI9frTGOqd+jX0P/Au/JfRSNqsf5nUTcWdbVYuLxS1KjnzILSoR5hA==", + "dev": true, + "dependencies": { + "@jest/test-result": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.0.tgz", + "integrity": "sha512-ZHwM6mNwaWBR52Snff8ZvsCTqQsvhCxP/bT1I6T6DAnb6ygkshsyLQIMxFwHpYxht0HOoqt23JlC01viI7T03A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "dev": true, + "dependencies": { + "universalify": "^1.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/marked": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz", + "integrity": "sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/nice-try": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all": { + "version": "4.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.3.1", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prettier": { + "version": "2.5.1", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/read-pkg": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/semver": { + "version": "5.7.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shell-quote": { + "version": "1.7.3", + "dev": true, + "license": "MIT" + }, + "node_modules/shiki": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", + "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.0.0", + "vscode-oniguruma": "^1.6.1", + "vscode-textmate": "5.2.0" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.11", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/sprintf-js": { + "version": "1.1.2", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.padend": { + "version": "3.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dev": true, + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-jest": { + "version": "28.0.3", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.3.tgz", + "integrity": "sha512-HzgbEDQ2KgVtDmpXToqAcKTyGHdHsG23i/iUjfxji92G5eT09S1m9UHZd7csF0Bfgh9txM4JzwHnv7r1waFPlw==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^28.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^20.x" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@types/jest": "^27.0.0", + "babel-jest": "^28.0.0", + "jest": "^28.0.0", + "typescript": ">=4.3" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node": { + "version": "10.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedoc": { + "version": "0.22.17", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.17.tgz", + "integrity": "sha512-h6+uXHVVCPDaANzjwzdsj9aePBjZiBTpiMpBBeyh1zcN2odVsDCNajz8zyKnixF93HJeGpl34j/70yoEE5BfNg==", + "dev": true, + "dependencies": { + "glob": "^8.0.3", + "lunr": "^2.3.9", + "marked": "^4.0.16", + "minimatch": "^5.1.0", + "shiki": "^0.10.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 12.10.0" + }, + "peerDependencies": { + "typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x || 4.7.x" + } + }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typedoc/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typescript": { + "version": "4.7.2", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.0.tgz", + "integrity": "sha512-HcvgY/xaRm7isYmyx+lFKA4uQmfUbN0J4M0nNItvzTvH/iQ9kW5j/t4YSR+Ge323/lrgDAWJoF46tzGQHwBHFw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.7", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vscode-oniguruma": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", + "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", + "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", + "dev": true + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "1.3.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dev": true, + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + } + }, "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/compat-data": { + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", + "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", + "dev": true + }, + "@babel/core": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", + "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.18.2", + "@babel/helper-compilation-targets": "^7.18.2", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helpers": "^7.18.2", + "@babel/parser": "^7.18.0", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", + "dev": true, + "requires": { + "@babel/types": "^7.18.2", + "@jridgewell/gen-mapping": "^0.3.0", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", + "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz", + "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.10", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", + "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", + "dev": true, + "requires": { + "@babel/template": "^7.16.7", + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-transforms": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", + "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", + "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz", + "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==", + "dev": true, + "requires": { + "@babel/types": "^7.18.2" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true + }, + "@babel/helpers": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", + "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", + "dev": true, + "requires": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2" + } + }, + "@babel/highlight": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", + "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.3.tgz", + "integrity": "sha512-rL50YcEuHbbauAFAysNsJA4/f89fGTOBRNs9P81sniKnKAr4xULe5AecolcsKbi88xu0ByWYDj/S1AJ3FSFuSQ==", + "dev": true + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz", + "integrity": "sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.17.12" + } + }, + "@babel/runtime": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.3.tgz", + "integrity": "sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/traverse": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.2.tgz", + "integrity": "sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.18.2", + "@babel/helper-environment-visitor": "^7.18.2", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.18.0", + "@babel/types": "^7.18.2", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.2.tgz", + "integrity": "sha512-0On6B8A4/+mFUto5WERt3EEuG1NznDirvwca1O8UwXQHVY8g3R7OzYgxXdOfMwLO08UrpUD/2+3Bclyq+/C94Q==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.0.tgz", + "integrity": "sha512-tscn3dlJFGay47kb4qVruQg/XWlmvU0xp3EJOjzzY+sBaI+YgwKcvAmTcyYU7xEiLLIY5HCdWRooAL8dqkFlDA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.0", + "jest-util": "^28.1.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/core": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.0.tgz", + "integrity": "sha512-/2PTt0ywhjZ4NwNO4bUqD9IVJfmFVhVKGlhvSpmEfUCuxYf/3NHcKmRFI+I71lYzbTT3wMuYpETDCTHo81gC/g==", + "dev": true, + "requires": { + "@jest/console": "^28.1.0", + "@jest/reporters": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^28.0.2", + "jest-config": "^28.1.0", + "jest-haste-map": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.0", + "jest-resolve-dependencies": "^28.1.0", + "jest-runner": "^28.1.0", + "jest-runtime": "^28.1.0", + "jest-snapshot": "^28.1.0", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", + "jest-watcher": "^28.1.0", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/environment": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", + "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0" + } + }, + "@jest/expect": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.0.tgz", + "integrity": "sha512-be9ETznPLaHOmeJqzYNIXv1ADEzENuQonIoobzThOYPuK/6GhrWNIJDVTgBLCrz3Am73PyEU2urQClZp0hLTtA==", + "dev": true, + "requires": { + "expect": "^28.1.0", + "jest-snapshot": "^28.1.0" + } + }, + "@jest/expect-utils": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.0.tgz", + "integrity": "sha512-5BrG48dpC0sB80wpeIX5FU6kolDJI4K0n5BM9a5V38MGx0pyRvUBSS0u2aNTdDzmOrCjhOg8pGs6a20ivYkdmw==", + "dev": true, + "requires": { + "jest-get-type": "^28.0.2" + } + }, + "@jest/fake-timers": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", + "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@sinonjs/fake-timers": "^9.1.1", + "@types/node": "*", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + } + }, + "@jest/globals": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.0.tgz", + "integrity": "sha512-3m7sTg52OTQR6dPhsEQSxAvU+LOBbMivZBwOvKEZ+Rb+GyxVnXi9HKgOTYkx/S99T8yvh17U4tNNJPIEQmtwYw==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.0", + "@jest/expect": "^28.1.0", + "@jest/types": "^28.1.0" + } + }, + "@jest/reporters": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.0.tgz", + "integrity": "sha512-qxbFfqap/5QlSpIizH9c/bFCDKsQlM4uAKSOvZrP+nIdrjqre3FmKzpTtYyhsaVcOSNK7TTt2kjm+4BJIjysFA==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "@jridgewell/trace-mapping": "^0.3.7", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-util": "^28.1.0", + "jest-worker": "^28.1.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^9.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/schemas": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.0.2.tgz", + "integrity": "sha512-YVDJZjd4izeTDkij00vHHAymNXQ6WWsdChFRK86qck6Jpr3DCL5W3Is3vslviRlP+bLuMYRLbdp98amMvqudhA==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.23.3" + } + }, + "@jest/source-map": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.0.2.tgz", + "integrity": "sha512-Y9dxC8ZpN3kImkk0LkK5XCEneYMAXlZ8m5bflmSL5vrwyeUpJfentacCUg6fOb8NOpOO7hz2+l37MV77T6BFPw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.7", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + } + }, + "@jest/test-result": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.0.tgz", + "integrity": "sha512-sBBFIyoPzrZho3N+80P35A5oAkSKlGfsEFfXFWuPGBsW40UAjCkGakZhn4UQK4iQlW2vgCDMRDOob9FGKV8YoQ==", + "dev": true, + "requires": { + "@jest/console": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.0.tgz", + "integrity": "sha512-tZCEiVWlWNTs/2iK9yi6o3AlMfbbYgV4uuZInSVdzZ7ftpHZhCMuhvk2HLYhCZzLgPFQ9MnM1YaxMnh3TILFiQ==", + "dev": true, + "requires": { + "@jest/test-result": "^28.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.0", + "slash": "^3.0.0" + } + }, + "@jest/transform": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.0.tgz", + "integrity": "sha512-omy2xe5WxlAfqmsTjTPxw+iXRTRnf+NtX0ToG+4S0tABeb4KsKmPUHq5UBuwunHg3tJRwgEQhEp0M/8oiatLEA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.0", + "@jridgewell/trace-mapping": "^0.3.7", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.0", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.0.7", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@sinclair/typebox": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.5.tgz", + "integrity": "sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@tsconfig/node10": { + "version": "1.0.8", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.9", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.1", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.2", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-fUy7YRpT+rHXto1YlL+J9rs0uLGyiqVt3ZOTQR+4ROc47yNl8WLdVLgUloBRhOxP1PZvguHl44T3H0wAWxahYQ==", + "dev": true, + "requires": { + "jest-matcher-utils": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, "@types/node": { "version": "17.0.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.8.tgz", - "integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==", "dev": true }, + "@types/prettier": { + "version": "2.6.1", + "dev": true + }, + "@types/sprintf-js": { + "version": "1.1.2", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "acorn": { + "version": "8.7.1", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "4.1.3", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + } + } + }, + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true + }, + "async-mutex": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz", + "integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==", + "requires": { + "tslib": "^2.3.1" + } + }, + "babel-jest": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.0.tgz", + "integrity": "sha512-zNKk0yhDZ6QUwfxh9k07GII6siNGMJWVUU49gmFj5gfdqDKLqa2RArXOF2CODp4Dr7dLxN2cvAV+667dGJ4b4w==", + "dev": true, + "requires": { + "@jest/transform": "^28.1.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^28.0.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.0.2.tgz", + "integrity": "sha512-Kizhn/ZL+68ZQHxSnHyuvJv8IchXD62KQxV77TBDV/xoBFBOfgRAk97GNs6hXdTTCiVES9nB2I6+7MXXrk5llQ==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.0.2.tgz", + "integrity": "sha512-sYzXIdgIXXroJTFeB3S6sNDWtlJ2dllCdTEsnZ65ACrMojj3hVNFRmnJ1HZtomGi+Be7aqpY/HJ92fr8OhKVkQ==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^28.0.2", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "dev": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001344", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", + "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "check-engine": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/check-engine/-/check-engine-1.10.1.tgz", + "integrity": "sha512-KqZ6sV7onqcc81qoK+NsCNjNfik1rRHzmxYJ+tDdCc+6nbpaj0X8SKSzb8lYIcQ+ire5ypMr4YP832/7RH843Q==", + "dev": true, + "requires": { + "bluebird": "3.7.2", + "colors": "1.4.0", + "command-line-usage": "6.1.0", + "jsonfile": "6.0.1", + "semver": "7.3.2", + "yargs": "16.1.0" + }, + "dependencies": { + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "yargs": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.0.tgz", + "integrity": "sha512-upWFJOmDdHN0syLuESuvXDmrRcWd1QafJolHskzaw79uZa7/x53gxQKiR07W59GWY1tFhhU/Th9DrtSfpS782g==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.2", + "yargs-parser": "^20.2.2" + } + } + } + }, + "ci-info": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz", + "integrity": "sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "dev": true + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "command-line-usage": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.0.tgz", + "integrity": "sha512-Ew1clU4pkUeo6AFVDFxCbnN7GIZfXl48HIOQeFQnkO3oOqvpI7wdqtLRwv9iOCZ/7A+z4csVZeiDdEcj8g6Wiw==", + "dev": true, + "requires": { + "array-back": "^4.0.0", + "chalk": "^2.4.2", + "table-layout": "^1.0.0", + "typical": "^5.2.0" + } + }, + "concat-map": { + "version": "0.0.1", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "create-require": { + "version": "1.1.1", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "define-properties": { + "version": "1.1.4", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "dev": true + }, + "diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.4.140", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.140.tgz", + "integrity": "sha512-NLz5va823QfJBYOO/hLV4AfU4Crmkl/6Hl2pH3qdJcmi0ySZ3YTWHxOlDm3uJOFBEPy3pIhu8gKQo6prQTWKKA==", + "dev": true + }, + "emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.20.1", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expect": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.0.tgz", + "integrity": "sha512-qFXKl8Pmxk8TBGfaFKRtcQjfXEnKAs+dmlxdwvukJZorwrAabT7M3h8oLOG01I2utEhkmUTi17CHaPBovZsKdw==", + "dev": true, + "requires": { + "@jest/expect-utils": "^28.1.0", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-util": "^28.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "diff-sequences": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", + "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-diff": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", + "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^28.0.2", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + } + }, + "jest-matcher-utils": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", + "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.0", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + } + }, + "pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.5", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functions-have-names": { + "version": "1.2.3", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.2.3", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.10", + "dev": true + }, + "has": { + "version": "1.0.3", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "dev": true + }, + "internal-slot": { + "version": "1.0.3", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "is-arrayish": { + "version": "0.2.1", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.4", + "dev": true + }, + "is-core-module": { + "version": "2.9.0", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-regex": { + "version": "1.1.4", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-string": { + "version": "1.0.7", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-weakref": { + "version": "1.0.2", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isexe": { + "version": "2.0.0", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "iter-tools": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/iter-tools/-/iter-tools-7.3.1.tgz", + "integrity": "sha512-XYS0CjthZqQ7MomjB4Ww9NqrVKRlP2qoa1oWFcIQrkMykhkgFTpSNG+sRcqzHBp6fSxk8oDIjudFTgQ6nnA4mA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.1" + } + }, + "jest": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.0.tgz", + "integrity": "sha512-TZR+tHxopPhzw3c3560IJXZWLNHgpcz1Zh0w5A65vynLGNcg/5pZ+VildAd7+XGOu6jd58XMY/HNn0IkZIXVXg==", + "dev": true, + "requires": { + "@jest/core": "^28.1.0", + "import-local": "^3.0.2", + "jest-cli": "^28.1.0" + } + }, + "jest-changed-files": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.0.2.tgz", + "integrity": "sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA==", + "dev": true, + "requires": { + "execa": "^5.0.0", + "throat": "^6.0.1" + } + }, + "jest-circus": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.0.tgz", + "integrity": "sha512-rNYfqfLC0L0zQKRKsg4n4J+W1A2fbyGH7Ss/kDIocp9KXD9iaL111glsLu7+Z7FHuZxwzInMDXq+N1ZIBkI/TQ==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.0", + "@jest/expect": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^28.1.0", + "jest-matcher-utils": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-runtime": "^28.1.0", + "jest-snapshot": "^28.1.0", + "jest-util": "^28.1.0", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "diff-sequences": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", + "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-diff": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", + "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^28.0.2", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + } + }, + "jest-matcher-utils": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", + "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.0", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + } + }, + "pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-cli": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.0.tgz", + "integrity": "sha512-fDJRt6WPRriHrBsvvgb93OxgajHHsJbk4jZxiPqmZbMDRcHskfJBBfTyjFko0jjfprP544hOktdSi9HVgl4VUQ==", + "dev": true, + "requires": { + "@jest/core": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/types": "^28.1.0", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^28.1.0", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-config": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.0.tgz", + "integrity": "sha512-aOV80E9LeWrmflp7hfZNn/zGA4QKv/xsn2w8QCBP0t0+YqObuCWTSgNbHJ0j9YsTuCO08ZR/wsvlxqqHX20iUA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.0", + "@jest/types": "^28.1.0", + "babel-jest": "^28.1.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^28.1.0", + "jest-environment-node": "^28.1.0", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.0", + "jest-runner": "^28.1.0", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-docblock": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.0.2.tgz", + "integrity": "sha512-FH10WWw5NxLoeSdQlJwu+MTiv60aXV/t8KEwIRGEv74WARE1cXIqh1vGdy2CraHuWOOrnzTWj/azQKqW4fO7xg==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.0.tgz", + "integrity": "sha512-a/XX02xF5NTspceMpHujmOexvJ4GftpYXqr6HhhmKmExtMXsyIN/fvanQlt/BcgFoRKN4OCXxLQKth9/n6OPFg==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.0", + "pretty-format": "^28.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-environment-node": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.0.tgz", + "integrity": "sha512-gBLZNiyrPw9CSMlTXF1yJhaBgWDPVvH0Pq6bOEwGMXaYNzhzhw2kA/OijNF8egbCgDS0/veRv97249x2CX+udQ==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.0", + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + } + }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, + "jest-haste-map": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.0.tgz", + "integrity": "sha512-xyZ9sXV8PtKi6NCrJlmq53PyNVHzxmcfXNVvIRHpHmh1j/HChC4pwKgyjj7Z9us19JMw8PpQTJsFWOsIfT93Dw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.0", + "jest-worker": "^28.1.0", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-leak-detector": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.0.tgz", + "integrity": "sha512-uIJDQbxwEL2AMMs2xjhZl2hw8s77c3wrPaQ9v6tXJLGaaQ+4QrNJH5vuw7hA7w/uGT/iJ42a83opAqxGHeyRIA==", + "dev": true, + "requires": { + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + }, + "react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + } + } + }, + "jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-mock": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", + "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "requires": {} + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + }, + "jest-resolve": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.0.tgz", + "integrity": "sha512-vvfN7+tPNnnhDvISuzD1P+CRVP8cK0FHXRwPAcdDaQv4zgvwvag2n55/h5VjYcM5UJG7L4TwE5tZlzcI0X2Lhw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-resolve-dependencies": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.0.tgz", + "integrity": "sha512-Ue1VYoSZquPwEvng7Uefw8RmZR+me/1kr30H2jMINjGeHgeO/JgrR6wxj2ofkJ7KSAA11W3cOrhNCbj5Dqqd9g==", + "dev": true, + "requires": { + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.0" + } + }, + "jest-runner": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.0.tgz", + "integrity": "sha512-FBpmuh1HB2dsLklAlRdOxNTTHKFR6G1Qmd80pVDvwbZXTriqjWqjei5DKFC1UlM732KjYcE6yuCdiF0WUCOS2w==", + "dev": true, + "requires": { + "@jest/console": "^28.1.0", + "@jest/environment": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^28.0.2", + "jest-environment-node": "^28.1.0", + "jest-haste-map": "^28.1.0", + "jest-leak-detector": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-resolve": "^28.1.0", + "jest-runtime": "^28.1.0", + "jest-util": "^28.1.0", + "jest-watcher": "^28.1.0", + "jest-worker": "^28.1.0", + "source-map-support": "0.5.13", + "throat": "^6.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-runtime": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.0.tgz", + "integrity": "sha512-wNYDiwhdH/TV3agaIyVF0lsJ33MhyujOe+lNTUiolqKt8pchy1Hq4+tDMGbtD5P/oNLA3zYrpx73T9dMTOCAcg==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.0", + "@jest/fake-timers": "^28.1.0", + "@jest/globals": "^28.1.0", + "@jest/source-map": "^28.0.2", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.0", + "jest-snapshot": "^28.1.0", + "jest-util": "^28.1.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-snapshot": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.0.tgz", + "integrity": "sha512-ex49M2ZrZsUyQLpLGxQtDbahvgBjlLPgklkqGM0hq/F7W/f8DyqZxVHjdy19QKBm4O93eDp+H5S23EiTbbUmHw==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^28.1.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.0", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.0", + "jest-matcher-utils": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-util": "^28.1.0", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.0", + "semver": "^7.3.5" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "diff-sequences": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", + "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-diff": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", + "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^28.0.2", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + } + }, + "jest-matcher-utils": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", + "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.0", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + } + }, + "pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-validate": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.0.tgz", + "integrity": "sha512-Lly7CJYih3vQBfjLeANGgBSBJ7pEa18cxpQfQEq2go2xyEzehnHfQTjoUia8xUv4x4J80XKFIDwJJThXtRFQXQ==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "leven": "^3.1.0", + "pretty-format": "^28.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "pretty-format": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-watcher": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.0.tgz", + "integrity": "sha512-tNHMtfLE8Njcr2IRS+5rXYA4BhU90gAOwI9frTGOqd+jX0P/Au/JfRSNqsf5nUTcWdbVYuLxS1KjnzILSoR5hA==", + "dev": true, + "requires": { + "@jest/test-result": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.0", + "string-length": "^4.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-worker": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.0.tgz", + "integrity": "sha512-ZHwM6mNwaWBR52Snff8ZvsCTqQsvhCxP/bT1I6T6DAnb6ygkshsyLQIMxFwHpYxht0HOoqt23JlC01viI7T03A==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + }, + "jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, + "jsonfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^1.0.0" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.6", + "dev": true + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "marked": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz", + "integrity": "sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA==", + "dev": true + }, + "memorystream": { + "version": "0.3.1", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "dev": true + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-releases": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-all": { + "version": "4.1.5", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + }, + "dependencies": { + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + } + } + }, + "object-inspect": { + "version": "1.12.1", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "once": { + "version": "1.4.0", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pidtree": { + "version": "0.3.1", + "dev": true + }, + "pify": { + "version": "3.0.0", + "dev": true + }, + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, "prettier": { "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "dev": true + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "resolve": { + "version": "1.22.0", + "dev": true, + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "dev": true + }, + "shell-quote": { + "version": "1.7.3", + "dev": true + }, + "shiki": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", + "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", + "dev": true, + "requires": { + "jsonc-parser": "^3.0.0", + "vscode-oniguruma": "^1.6.1", + "vscode-textmate": "5.2.0" + } + }, + "side-channel": { + "version": "1.0.4", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "spdx-correct": { + "version": "3.1.1", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.11", "dev": true }, "sprintf-js": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", "dev": true }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.padend": { + "version": "3.1.3", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.5", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.5", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true + }, + "table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dev": true, + "requires": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + } + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-jest": { + "version": "28.0.3", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.3.tgz", + "integrity": "sha512-HzgbEDQ2KgVtDmpXToqAcKTyGHdHsG23i/iUjfxji92G5eT09S1m9UHZd7csF0Bfgh9txM4JzwHnv7r1waFPlw==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^28.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^20.x" + }, + "dependencies": { + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "ts-node": { + "version": "10.8.0", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + }, + "typedoc": { + "version": "0.22.17", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.17.tgz", + "integrity": "sha512-h6+uXHVVCPDaANzjwzdsj9aePBjZiBTpiMpBBeyh1zcN2odVsDCNajz8zyKnixF93HJeGpl34j/70yoEE5BfNg==", + "dev": true, + "requires": { + "glob": "^8.0.3", + "lunr": "^2.3.9", + "marked": "^4.0.16", + "minimatch": "^5.1.0", + "shiki": "^0.10.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "typescript": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", - "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", + "version": "4.7.2", + "dev": true + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.2", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "dev": true + }, + "v8-to-istanbul": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.0.tgz", + "integrity": "sha512-HcvgY/xaRm7isYmyx+lFKA4uQmfUbN0J4M0nNItvzTvH/iQ9kW5j/t4YSR+Ge323/lrgDAWJoF46tzGQHwBHFw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.7", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vscode-oniguruma": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", + "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", + "dev": true + }, + "vscode-textmate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", + "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", + "dev": true + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "which": { + "version": "1.3.1", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dev": true, + "requires": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "dev": true + }, + "write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "dependencies": { + "yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "dev": true + } + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + }, + "yn": { + "version": "3.1.1", "dev": true } } diff --git a/src/api/js/package.json b/src/api/js/package.json index 63a7e7568..53fd25b2a 100644 --- a/src/api/js/package.json +++ b/src/api/js/package.json @@ -1,27 +1,61 @@ { "name": "z3-solver", - "keywords": ["Z3", "theorem", "prover", "solver", "satisfiability", "smt", "satisfiability modulo theories"], + "keywords": [ + "Z3", + "theorem", + "prover", + "solver", + "satisfiability", + "smt", + "satisfiability modulo theories" + ], "homepage": "https://github.com/Z3Prover/z3/tree/master/src/api/js", "repository": "github:Z3Prover/z3", "engines": { - "node": ">=16" + "node": ">=16 <18" }, - "main": "build/node-wrapper.js", - "types": "build/node-wrapper.d.ts", + "browser": "build/browser.js", + "main": "build/node.js", + "types": "build/node.d.ts", "files": [ "build/*.{js,d.ts,wasm}" ], "scripts": { - "build-ts": "mkdir -p build && rm -rf build/*.ts && cp src/node-wrapper.ts build && node scripts/make-ts-wrapper.js > build/wrapper.ts && tsc", - "build-wasm": "mkdir -p build && node scripts/make-cc-wrapper.js > build/async-fns.cc && ./build-wasm.sh", - "format": "prettier --write --single-quote --arrow-parens avoid --print-width 120 --trailing-comma all '{,src/,scripts/}*.{js,ts}'", - "test": "node test-ts-api.js" + "build:ts": "run-s -l build:ts:generate build:ts:tsc", + "build:ts:tsc": "tsc --pretty --project tsconfig.build.json ", + "build:ts:generate": "ts-node --transpileOnly scripts/make-ts-wrapper.ts src/low-level/wrapper.__GENERATED__.ts src/low-level/types.__GENERATED__.ts", + "build:wasm": "ts-node --transpileOnly ./scripts/build-wasm.ts", + "clean": "rimraf build 'src/**/*.__GENERATED__.*'", + "lint": "prettier -c '{,src/,scripts/,examples}*.{js,ts}'", + "format": "prettier --write '{,src/,scripts/}*.{js,ts}'", + "test": "jest", + "docs": "typedoc", + "check-engine": "check-engine" }, + "contributors": [ + "Kevin Gibbons ", + "Nikolaj Bjorner", + "Olaf Tomalka " + ], "devDependencies": { + "@types/jest": "^27.5.1", "@types/node": "^17.0.8", + "@types/prettier": "^2.6.1", + "@types/sprintf-js": "^1.1.2", + "check-engine": "^1.10.1", + "iter-tools": "^7.3.1", + "jest": "^28.1.0", + "npm-run-all": "^4.1.5", "prettier": "^2.5.1", + "rimraf": "^3.0.2", "sprintf-js": "^1.1.2", + "ts-jest": "^28.0.3", + "ts-node": "^10.8.0", + "typedoc": "^0.22.17", "typescript": "^4.5.4" }, - "license": "MIT" + "license": "MIT", + "dependencies": { + "async-mutex": "^0.3.2" + } } diff --git a/src/api/js/scripts/async-fns.js b/src/api/js/scripts/async-fns.ts similarity index 94% rename from src/api/js/scripts/async-fns.js rename to src/api/js/scripts/async-fns.ts index 515126b94..a71778e29 100644 --- a/src/api/js/scripts/async-fns.js +++ b/src/api/js/scripts/async-fns.ts @@ -1,8 +1,6 @@ -'use strict'; - // things which you probably want to do off-thread // from https://github.com/Z3Prover/z3/issues/5746#issuecomment-1006289146 -module.exports = [ +export const asyncFuncs = [ 'Z3_eval_smtlib2_string', 'Z3_simplify', 'Z3_simplify_ex', diff --git a/src/api/js/scripts/build-wasm.ts b/src/api/js/scripts/build-wasm.ts new file mode 100644 index 000000000..3caf643df --- /dev/null +++ b/src/api/js/scripts/build-wasm.ts @@ -0,0 +1,77 @@ +import assert from 'assert'; +import { SpawnOptions, spawnSync as originalSpawnSync } from 'child_process'; +import fs, { existsSync } from 'fs'; +import os from 'os'; +import path from 'path'; +import process from 'process'; +import { asyncFuncs } from './async-fns'; +import { makeCCWrapper } from './make-cc-wrapper'; +import { functions } from './parse-api'; + +console.log('--- Building WASM'); + +const SWAP_OPTS: SpawnOptions = { + shell: true, + stdio: 'inherit', + env: { + ...process.env, + CXXFLAGS: '-pthread -s USE_PTHREADS=1 -s DISABLE_EXCEPTION_CATCHING=0', + LDFLAGS: '-s WASM_BIGINT -s -pthread -s USE_PTHREADS=1', + FPMATH_ENABLED: 'False', // Until Safari supports WASM SSE, we have to disable fast FP support + // TODO(ritave): Setting EM_CACHE breaks compiling on M1 MacBook + //EM_CACHE: path.join(os.homedir(), '.emscripten/'), + }, +}; + +function spawnSync(command: string, opts: SpawnOptions = {}) { + console.log(`- ${command}`); + // TODO(ritave): Create a splitter that keeps track of quoted strings + const [cmd, ...args] = command.split(' '); + const { error, ...rest } = originalSpawnSync(cmd, args, { ...SWAP_OPTS, ...opts }); + if (error !== undefined || rest.status !== 0) { + if (error !== undefined) { + console.error(error.message); + } else { + console.error(`Process exited with status ${rest.status}`); + } + process.exit(1); + } + return rest; +} + +function exportedFuncs(): string[] { + const extras = ['_set_throwy_error_handler', '_set_noop_error_handler', ...asyncFuncs.map(f => '_async_' + f)]; + + // TODO(ritave): This variable is unused in original script, find out if it's important + const fns: any[] = (functions as any[]).filter(f => !asyncFuncs.includes(f.name)); + + return [...extras, ...(functions as any[]).map(f => '_' + f.name)]; +} + +assert(fs.existsSync('./package.json'), 'Not in the root directory of js api'); +const z3RootDir = path.join(process.cwd(), '../../../'); + +// TODO(ritave): Detect if it's in the configuration we need +if (!existsSync(path.join(z3RootDir, 'build/Makefile'))) { + spawnSync('emconfigure python scripts/mk_make.py --staticlib --single-threaded --arm64=false', { + cwd: z3RootDir, + }); +} + +spawnSync(`emmake make -j${os.cpus().length} libz3.a`, { cwd: path.join(z3RootDir, 'build') }); + +const ccWrapperPath = 'build/async-fns.cc'; +console.log(`- Building ${ccWrapperPath}`); +fs.mkdirSync(path.dirname(ccWrapperPath), { recursive: true }); +fs.writeFileSync(ccWrapperPath, makeCCWrapper()); + +const fns = JSON.stringify(exportedFuncs()); +const methods = '["ccall","FS","allocate","UTF8ToString","intArrayFromString","ALLOC_NORMAL"]'; +const libz3a = path.normalize('../../../build/libz3.a'); +spawnSync( + `emcc build/async-fns.cc ${libz3a} --std=c++20 --pre-js src/low-level/async-wrapper.js -g2 -pthread -fexceptions -s WASM_BIGINT -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=0 -s PTHREAD_POOL_SIZE_STRICT=0 -s MODULARIZE=1 -s 'EXPORT_NAME="initZ3"' -s EXPORTED_RUNTIME_METHODS=${methods} -s EXPORTED_FUNCTIONS=${fns} -s DISABLE_EXCEPTION_CATCHING=0 -s SAFE_HEAP=0 -s DEMANGLE_SUPPORT=1 -s TOTAL_MEMORY=1GB -I z3/src/api/ -o build/z3-built.js`, +); + +fs.rmSync(ccWrapperPath); + +console.log('--- WASM build finished'); diff --git a/src/api/js/scripts/list-exports.js b/src/api/js/scripts/list-exports.js deleted file mode 100644 index e86850e91..000000000 --- a/src/api/js/scripts/list-exports.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -// this is called by build.sh to generate the names of the bindings to export - -let { functions } = require('./parse-api.js'); -let asyncFns = require('./async-fns.js'); - -let extras = ['_set_throwy_error_handler', '_set_noop_error_handler', ...asyncFns.map(f => '_async_' + f)]; -let fns = functions.filter(f => !asyncFns.includes(f.name)); - -console.log(JSON.stringify([...extras, ...functions.map(f => '_' + f.name)])); diff --git a/src/api/js/scripts/make-cc-wrapper.js b/src/api/js/scripts/make-cc-wrapper.ts similarity index 67% rename from src/api/js/scripts/make-cc-wrapper.js rename to src/api/js/scripts/make-cc-wrapper.ts index b522e4ebc..2b7ca2536 100644 --- a/src/api/js/scripts/make-cc-wrapper.js +++ b/src/api/js/scripts/make-cc-wrapper.ts @@ -1,40 +1,38 @@ -'use strict'; - // generates c wrappers with off-thread versions of specified functions -let path = require('path'); +import path from 'path'; +import { asyncFuncs } from './async-fns'; +import { functions } from './parse-api'; -let { functions } = require('./parse-api.js'); -let asyncFns = require('./async-fns.js'); +export function makeCCWrapper() { + let wrappers = []; -let wrappers = []; + for (let fnName of asyncFuncs) { + let fn = functions.find(f => f.name === fnName); + if (fn == null) { + throw new Error(`could not find definition for ${fnName}`); + } + let wrapper; + if (fn.cRet === 'Z3_string') { + wrapper = `wrapper_str`; + } else if (['int', 'unsigned', 'void'].includes(fn.cRet) || fn.cRet.startsWith('Z3_')) { + wrapper = `wrapper`; + } else { + throw new Error(`async function with unknown return type ${fn.cRet}`); + } -for (let fnName of asyncFns) { - let fn = functions.find(f => f.name === fnName); - if (fn == null) { - throw new Error(`could not find definition for ${fnName}`); - } - let wrapper; - if (fn.cRet === 'Z3_string') { - wrapper = `wrapper_str`; - } else if (['int', 'unsigned', 'void'].includes(fn.cRet) || fn.cRet.startsWith('Z3_')) { - wrapper = `wrapper`; - } else { - throw new Error(`async function with unknown return type ${fn.cRet}`); - } - - wrappers.push( - ` + wrappers.push( + ` extern "C" void async_${fn.name}(${fn.params - .map(p => `${p.isConst ? 'const ' : ''}${p.cType}${p.isPtr ? '*' : ''} ${p.name}${p.isArray ? '[]' : ''}`) - .join(', ')}) { + .map(p => `${p.isConst ? 'const ' : ''}${p.cType}${p.isPtr ? '*' : ''} ${p.name}${p.isArray ? '[]' : ''}`) + .join(', ')}) { ${wrapper}(${fn.params.map(p => `${p.name}`).join(', ')}); } `.trim(), - ); -} + ); + } -console.log(`// THIS FILE IS AUTOMATICALLY GENERATED BY ${path.basename(__filename)} + return `// THIS FILE IS AUTOMATICALLY GENERATED BY ${path.basename(__filename)} // DO NOT EDIT IT BY HAND #include @@ -112,4 +110,10 @@ extern "C" void set_noop_error_handler(Z3_context ctx) { Z3_set_error_handler(ctx, noop_error_handler); } -${wrappers.join('\n\n')}`); +${wrappers.join('\n\n')} +`; +} + +if (require.main === module) { + console.log(makeCCWrapper()); +} diff --git a/src/api/js/scripts/make-ts-wrapper.js b/src/api/js/scripts/make-ts-wrapper.js deleted file mode 100644 index 91e7eb653..000000000 --- a/src/api/js/scripts/make-ts-wrapper.js +++ /dev/null @@ -1,434 +0,0 @@ -'use strict'; - -let path = require('path'); -let prettier = require('prettier'); - -let { primitiveTypes, types, enums, functions } = require('./parse-api.js'); -let asyncFns = require('./async-fns.js'); - -let subtypes = { - __proto__: null, - Z3_sort: 'Z3_ast', - Z3_func_decl: 'Z3_ast', -}; - -let makePointerType = t => - `export type ${t} = ` + (t in subtypes ? `Subpointer<'${t}', '${subtypes[t]}'>;` : `Pointer<'${t}'>;`); - -// this supports a up to 6 out intergers/pointers -// or up to 3 out int64s -const BYTES_TO_ALLOCATE_FOR_OUT_PARAMS = 24; - -const CUSTOM_IMPLEMENTATIONS = ['Z3_mk_context', 'Z3_mk_context_rc']; - -function toEmType(type) { - if (type in primitiveTypes) { - type = primitiveTypes[type]; - } - if (['boolean', 'number', 'string', 'bigint', 'void'].includes(type)) { - return type; - } - if (type.startsWith('Z3_')) { - return 'number'; - } - throw new Error(`unknown parameter type ${type}`); -} - -function isZ3PointerType(type) { - return type.startsWith('Z3_'); -} - -function toEm(p) { - if (typeof p === 'string') { - // we've already set this, e.g. by replacing it with an expression - return p; - } - let { type } = p; - if (p.kind === 'out') { - throw new Error(`unknown out parameter type ${JSON.stringify(p)}`); - } - if (p.isArray) { - if (isZ3PointerType(type) || type === 'unsigned' || type === 'int') { - // this works for nullables also because null coerces to 0 - return `intArrayToByteArr(${p.name} as unknown as number[])`; - } else if (type === 'boolean') { - return `boolArrayToByteArr(${p.name})`; - } else { - throw new Error(`only know how to deal with arrays of int/bool (got ${type})`); - } - } - if (type in primitiveTypes) { - type = primitiveTypes[type]; - } - - if (['boolean', 'number', 'bigint', 'string'].includes(type)) { - return p.name; - } - if (type.startsWith('Z3_')) { - return p.name; - } - throw new Error(`unknown parameter type ${JSON.stringify(p)}`); -} - -let isInParam = p => ['in', 'in_array'].includes(p.kind); -function wrapFunction(fn) { - if (CUSTOM_IMPLEMENTATIONS.includes(fn.name)) { - return null; - } - - let inParams = fn.params.filter(isInParam); - let outParams = fn.params.map((p, idx) => ({ ...p, idx })).filter(p => !isInParam(p)); - - // we'll figure out how to deal with these cases later - let unknownInParam = inParams.find( - p => - p.isPtr || - p.type === 'Z3_char_ptr' || - (p.isArray && !(isZ3PointerType(p.type) || p.type === 'unsigned' || p.type === 'int' || p.type === 'boolean')), - ); - if (unknownInParam) { - console.error(`skipping ${fn.name} - unknown in parameter ${JSON.stringify(unknownInParam)}`); - return null; - } - - if (fn.ret === 'Z3_char_ptr') { - console.error(`skipping ${fn.name} - returns a string or char pointer`); - return null; - } - // console.error(fn.name); - - let isAsync = asyncFns.includes(fn.name); - let trivial = - !['string', 'boolean'].includes(fn.ret) && - !fn.nullableRet && - outParams.length === 0 && - !inParams.some(p => p.type === 'string' || p.isArray || p.nullable); - - let name = fn.name.startsWith('Z3_') ? fn.name.substring(3) : fn.name; - - let params = inParams.map(p => { - let type = p.type; - if (p.isArray && p.nullable) { - type = `(${type} | null)[]`; - } else if (p.isArray) { - type = `${type}[]`; - } else if (p.nullable) { - type = `${type} | null`; - } - return `${p.name}: ${type}`; - }); - - if (trivial && isAsync) { - // i.e. and async - return `${name}: function (${params.join(', ')}): Promise<${fn.ret}> { - return Mod.async_call(Mod._async_${fn.name}, ${fn.params.map(toEm).join(', ')}); - }`; - } - - if (trivial) { - return `${name}: Mod._${fn.name} as ((${params.join(', ')}) => ${fn.ret})`; - } - - // otherwise fall back to ccall - - let ctypes = fn.params.map(p => - p.kind === 'in_array' ? 'array' : p.kind === 'out_array' ? 'number' : p.isPtr ? 'number' : toEmType(p.type), - ); - - let prefix = ''; - let infix = ''; - let rv = 'ret'; - let suffix = ''; - - let args = fn.params; - - let arrayLengthParams = new Map(); - for (let p of inParams) { - if (p.nullable && !p.isArray) { - // this would be easy to implement - just map null to 0 - but nothing actually uses nullable non-array input parameters, so we can't ensure we've done it right - console.error(`skipping ${fn.name} - nullable input parameter`); - return null; - } - if (!p.isArray) { - continue; - } - let { sizeIndex } = p; - if (arrayLengthParams.has(sizeIndex)) { - let otherParam = arrayLengthParams.get(sizeIndex); - prefix += ` - if (${otherParam}.length !== ${p.name}.length) { - throw new TypeError(\`${otherParam} and ${p.name} must be the same length (got \${${otherParam}.length} and \{${p.name}.length})\`); - } - `.trim(); - continue; - } - arrayLengthParams.set(sizeIndex, p.name); - - let sizeParam = fn.params[sizeIndex]; - if (!(sizeParam.kind === 'in' && sizeParam.type === 'unsigned' && !sizeParam.isPtr && !sizeParam.isArray)) { - throw new Error( - `size index is not unsigned int (for fn ${fn.name} parameter ${sizeIndex} got ${sizeParam.type})`, - ); - } - args[sizeIndex] = `${p.name}.length`; - params[sizeIndex] = null; - } - - let returnType = fn.ret; - let cReturnType = toEmType(fn.ret); - if (outParams.length > 0) { - let mapped = []; - let memIdx = 0; // offset from `outAddress` where the data should get written, in units of 4 bytes - - for (let outParam of outParams) { - if (outParam.isArray) { - if (isZ3PointerType(outParam.type) || outParam.type === 'unsigned') { - let { sizeIndex } = outParam; - - let count; - if (arrayLengthParams.has(sizeIndex)) { - // i.e. this is also the length of an input array - count = args[sizeIndex]; - } else { - let sizeParam = fn.params[sizeIndex]; - if (!(sizeParam.kind === 'in' && sizeParam.type === 'unsigned' && !sizeParam.isPtr && !sizeParam.isArray)) { - throw new Error( - `size index is not unsigned int (for fn ${fn.name} parameter ${sizeIndex} got ${sizeParam.type})`, - ); - } - count = sizeParam.name; - } - let outArrayAddress = `outArray_${outParam.name}`; - prefix += ` - let ${outArrayAddress} = Mod._malloc(4 * ${count}); - try { - `.trim(); - suffix = - ` - } finally { - Mod._free(${outArrayAddress}); - } - `.trim() + suffix; - args[outParam.idx] = outArrayAddress; - mapped.push({ - name: outParam.name, - read: - `readUintArray(${outArrayAddress}, ${count})` + - (outParam.type === 'unsigned' ? '' : `as unknown as ${outParam.type}[]`), - type: `${outParam.type}[]`, - }); - } else { - console.error(`skipping ${fn.name} - out array of ${outParam.type}`); - return null; - } - } else if (outParam.isPtr) { - function setArg() { - args[outParam.idx] = memIdx === 0 ? 'outAddress' : `outAddress + ${memIdx * 4}`; - } - let read, type; - if (outParam.type === 'string') { - read = `Mod.UTF8ToString(getOutUint(${memIdx}))`; - setArg(); - ++memIdx; - } else if (isZ3PointerType(outParam.type)) { - read = `getOutUint(${memIdx}) as unknown as ${outParam.type}`; - setArg(); - ++memIdx; - } else if (outParam.type === 'unsigned') { - read = `getOutUint(${memIdx})`; - setArg(); - ++memIdx; - } else if (outParam.type === 'int') { - read = `getOutInt(${memIdx})`; - setArg(); - ++memIdx; - } else if (outParam.type === 'uint64_t') { - if (memIdx % 2 === 1) { - ++memIdx; - } - read = `getOutUint64(${memIdx / 2})`; - setArg(); - memIdx += 2; - } else if (outParam.type === 'int64_t') { - if (memIdx % 2 === 1) { - ++memIdx; - } - read = `getOutInt64(${memIdx / 2})`; - setArg(); - memIdx += 2; - } else { - console.error(`skipping ${fn.name} - unknown out parameter type ${outParam.type}`); - return null; - } - if (memIdx > Math.floor(BYTES_TO_ALLOCATE_FOR_OUT_PARAMS / 4)) { - // prettier-ignore - console.error(`skipping ${fn.name} - out parameter sizes sum to ${memIdx * 4}, which is > ${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS}`); - return null; - } - mapped.push({ - name: outParam.name, - read, - type: outParam.type, - }); - } else { - console.error(`skipping ${fn.name} - out param is neither pointer nor array`); - return null; - } - } - - let ignoreReturn = fn.ret === 'boolean' || fn.ret === 'void'; - if (outParams.length === 1) { - let outParam = mapped[0]; - if (ignoreReturn) { - returnType = outParam.type; - rv = outParam.read; - } else { - returnType = `{ rv: ${fn.ret}, ${outParam.name} : ${outParam.type} }`; - rv = `{ rv: ret, ${outParam.name} : ${outParam.read} }`; - } - } else { - if (ignoreReturn) { - returnType = `{ ${mapped.map(p => `${p.name} : ${p.type}`).join(', ')} }`; - rv = `{ ${mapped.map(p => `${p.name}: ${p.read}`).join(', ')} }`; - } else { - returnType = `{ rv: ${fn.ret}, ${mapped.map(p => `${p.name} : ${p.type}`).join(', ')} }`; - rv = `{ rv: ret, ${mapped.map(p => `${p.name}: ${p.read}`).join(', ')} }`; - } - } - - if (fn.ret === 'boolean') { - // assume the boolean indicates success - infix += ` - if (!ret) { - return null; - } - `.trim(); - cReturnType = 'boolean'; - returnType += ' | null'; - } else if (fn.ret === 'void') { - cReturnType = 'void'; - } else if (isZ3PointerType(fn.ret) || fn.ret === 'unsigned') { - cReturnType = 'number'; - } else { - console.error(`skipping ${fn.name} - out parameter for function which returns non-boolean`); - return null; - } - } - - if (fn.nullableRet) { - returnType += ' | null'; - infix += ` - if (ret === 0) { - return null; - } - `.trim(); - } - - // prettier-ignore - let invocation = `Mod.ccall('${isAsync ? 'async_' : ''}${fn.name}', '${cReturnType}', ${JSON.stringify(ctypes)}, [${args.map(toEm).join(', ')}])`; - - if (isAsync) { - invocation = `await Mod.async_call(() => ${invocation})`; - returnType = `Promise<${returnType}>`; - } - - let out = `${name}: ${isAsync ? 'async' : ''} function(${params.filter(p => p != null).join(', ')}): ${returnType} { - ${prefix}`; - if (infix === '' && suffix === '' && rv === 'ret') { - out += `return ${invocation};`; - } else { - out += ` - let ret = ${invocation}; - ${infix}return ${rv};${suffix} - `.trim(); - } - out += '}'; - return out; -} - -function wrapEnum(name, values) { - let enumEntries = Object.entries(values); - return `export enum ${name} { - ${enumEntries.map(([k, v], i) => k + (v === (enumEntries[i - 1]?.[1] ?? -1) + 1 ? '' : ` = ${v}`) + ',').join('\n')} - };`; -} - -function getValidOutArrayIndexes(size) { - return Array.from({ length: Math.floor(BYTES_TO_ALLOCATE_FOR_OUT_PARAMS / size) }, (_, i) => i).join(' | '); -} - -let out = ` -// THIS FILE IS AUTOMATICALLY GENERATED BY ${path.basename(__filename)} -// DO NOT EDIT IT BY HAND - -interface Pointer extends Number { - readonly __typeName: T; -} -interface Subpointer extends Pointer { - readonly __typeName2: T; -} - -${Object.entries(primitiveTypes) - .filter(e => e[0] !== 'void') - .map(e => `type ${e[0]} = ${e[1]};`) - .join('\n')} - -${Object.keys(types) - .filter(k => k.startsWith('Z3')) - .map(makePointerType) - .join('\n')} - -${Object.entries(enums) - .map(e => wrapEnum(e[0], e[1])) - .join('\n\n')} - -export async function init(initModule: any) { - let Mod = await initModule(); - - // this works for both signed and unsigned, because JS will wrap for you when constructing the Uint32Array - function intArrayToByteArr(ints: number[]) { - return new Uint8Array((new Uint32Array(ints)).buffer); - } - - function boolArrayToByteArr(bools: boolean[]) { - return bools.map(b => b ? 1 : 0); - } - - function readUintArray(address: number, count: number) { - return Array.from(new Uint32Array(Mod.HEAPU32.buffer, address, count)); - } - - let outAddress = Mod._malloc(${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS}); - let outUintArray = (new Uint32Array(Mod.HEAPU32.buffer, outAddress, 4)); - let getOutUint = (i: ${getValidOutArrayIndexes(4)}) => outUintArray[i]; - let outIntArray = (new Int32Array(Mod.HEAPU32.buffer, outAddress, 4)); - let getOutInt = (i: ${getValidOutArrayIndexes(4)}) => outIntArray[i]; - let outUint64Array = (new BigUint64Array(Mod.HEAPU32.buffer, outAddress, 2)); - let getOutUint64 = (i: ${getValidOutArrayIndexes(8)}) => outUint64Array[i]; - let outInt64Array = (new BigInt64Array(Mod.HEAPU32.buffer, outAddress, 2)); - let getOutInt64 = (i: ${getValidOutArrayIndexes(8)}) => outInt64Array[i]; - - return { - em: Mod, - Z3: { - mk_context: function(c: Z3_config): Z3_context { - let ctx = Mod._Z3_mk_context(c); - Mod._set_noop_error_handler(ctx); - return ctx; - }, - mk_context_rc: function(c: Z3_config): Z3_context { - let ctx = Mod._Z3_mk_context_rc(c); - Mod._set_noop_error_handler(ctx); - return ctx; - }, - ${functions - .map(wrapFunction) - .filter(f => f != null) - .join(',\n')} - - } - }; -} -`; - -console.log(prettier.format(out, { singleQuote: true, parser: 'typescript' })); diff --git a/src/api/js/scripts/make-ts-wrapper.ts b/src/api/js/scripts/make-ts-wrapper.ts new file mode 100644 index 000000000..58b2ce0ae --- /dev/null +++ b/src/api/js/scripts/make-ts-wrapper.ts @@ -0,0 +1,468 @@ +import assert from 'assert'; +import fs from 'fs'; +import path from 'path'; +import prettier from 'prettier'; +import { asyncFuncs } from './async-fns'; +import { enums, Func, FuncParam, functions, primitiveTypes, types } from './parse-api'; + +assert(process.argv.length === 4, `Usage: ${process.argv[0]} ${process.argv[1]} wrapperFilePath typesFilePath`); + +const wrapperFilePath = process.argv[2]; +const typesFilePath = process.argv[3]; + +function makeTsWrapper() { + const subtypes = { + __proto__: null, + Z3_sort: 'Z3_ast', + Z3_func_decl: 'Z3_ast', + } as unknown as Record; + + const makePointerType = (t: string) => + `export type ${t} = ` + (t in subtypes ? `Subpointer<'${t}', '${subtypes[t]}'>;` : `Pointer<'${t}'>;`); + + // this supports a up to 6 out integers/pointers + // or up to 3 out int64s + const BYTES_TO_ALLOCATE_FOR_OUT_PARAMS = 24; + + const CUSTOM_IMPLEMENTATIONS = ['Z3_mk_context', 'Z3_mk_context_rc']; + + function toEmType(type: string) { + if (type in primitiveTypes) { + type = primitiveTypes[type]; + } + if (['boolean', 'number', 'string', 'bigint', 'void'].includes(type)) { + return type; + } + if (type.startsWith('Z3_')) { + return 'number'; + } + throw new Error(`unknown parameter type ${type}`); + } + + function isZ3PointerType(type: string) { + return type.startsWith('Z3_'); + } + + function toEm(p: string | FuncParam) { + if (typeof p === 'string') { + // we've already set this, e.g. by replacing it with an expression + return p; + } + let { type } = p; + if (p.kind === 'out') { + throw new Error(`unknown out parameter type ${JSON.stringify(p)}`); + } + if (p.isArray) { + if (isZ3PointerType(type) || type === 'unsigned' || type === 'int') { + // this works for nullables also because null coerces to 0 + return `intArrayToByteArr(${p.name} as unknown as number[])`; + } else if (type === 'boolean') { + return `boolArrayToByteArr(${p.name})`; + } else { + throw new Error(`only know how to deal with arrays of int/bool (got ${type})`); + } + } + if (type in primitiveTypes) { + type = primitiveTypes[type]; + } + + if (['boolean', 'number', 'bigint', 'string'].includes(type)) { + return p.name; + } + if (type.startsWith('Z3_')) { + return p.name; + } + throw new Error(`unknown parameter type ${JSON.stringify(p)}`); + } + + const isInParam = (p: FuncParam) => p.kind !== undefined && ['in', 'in_array'].includes(p.kind); + function wrapFunction(fn: Func) { + if (CUSTOM_IMPLEMENTATIONS.includes(fn.name)) { + return null; + } + + let inParams = fn.params.filter(isInParam); + let outParams = fn.params.map((p, idx) => ({ ...p, idx })).filter(p => !isInParam(p)); + + // we'll figure out how to deal with these cases later + let unknownInParam = inParams.find( + p => + p.isPtr || + p.type === 'Z3_char_ptr' || + (p.isArray && !(isZ3PointerType(p.type) || p.type === 'unsigned' || p.type === 'int' || p.type === 'boolean')), + ); + if (unknownInParam) { + console.error(`skipping ${fn.name} - unknown in parameter ${JSON.stringify(unknownInParam)}`); + return null; + } + + if (fn.ret === 'Z3_char_ptr') { + console.error(`skipping ${fn.name} - returns a string or char pointer`); + return null; + } + // console.error(fn.name); + + let isAsync = asyncFuncs.includes(fn.name); + let trivial = + !['string', 'boolean'].includes(fn.ret) && + !fn.nullableRet && + outParams.length === 0 && + !inParams.some(p => p.type === 'string' || p.isArray || p.nullable); + + let name = fn.name.startsWith('Z3_') ? fn.name.substring(3) : fn.name; + + const params: (string | null)[] = inParams.map(p => { + let type = p.type; + if (p.isArray && p.nullable) { + type = `(${type} | null)[]`; + } else if (p.isArray) { + type = `${type}[]`; + } else if (p.nullable) { + type = `${type} | null`; + } + return `${p.name}: ${type}`; + }); + + if (trivial && isAsync) { + // i.e. and async + return `${name}: function (${params.join(', ')}): Promise<${fn.ret}> { + return Mod.async_call(Mod._async_${fn.name}, ${fn.params.map(toEm).join(', ')}); + }`; + } + + if (trivial) { + return `${name}: Mod._${fn.name} as ((${params.join(', ')}) => ${fn.ret})`; + } + + // otherwise fall back to ccall + + const ctypes = fn.params.map(p => + p.kind === 'in_array' ? 'array' : p.kind === 'out_array' ? 'number' : p.isPtr ? 'number' : toEmType(p.type), + ); + + let prefix = ''; + let infix = ''; + let rv = 'ret'; + let suffix = ''; + + const args: (string | FuncParam)[] = fn.params; + + let arrayLengthParams = new Map(); + for (let p of inParams) { + if (p.nullable && !p.isArray) { + // this would be easy to implement - just map null to 0 - but nothing actually uses nullable non-array input parameters, so we can't ensure we've done it right + console.error(`skipping ${fn.name} - nullable input parameter`); + return null; + } + if (!p.isArray) { + continue; + } + let { sizeIndex } = p; + assert(sizeIndex !== undefined); + if (arrayLengthParams.has(sizeIndex)) { + let otherParam = arrayLengthParams.get(sizeIndex); + prefix += ` + if (${otherParam}.length !== ${p.name}.length) { + throw new TypeError(\`${otherParam} and ${p.name} must be the same length (got \${${otherParam}.length} and \{${p.name}.length})\`); + } + `.trim(); + continue; + } + arrayLengthParams.set(sizeIndex, p.name); + + const sizeParam = fn.params[sizeIndex]; + if (!(sizeParam.kind === 'in' && sizeParam.type === 'unsigned' && !sizeParam.isPtr && !sizeParam.isArray)) { + throw new Error( + `size index is not unsigned int (for fn ${fn.name} parameter ${sizeIndex} got ${sizeParam.type})`, + ); + } + args[sizeIndex] = `${p.name}.length`; + params[sizeIndex] = null; + } + + let returnType = fn.ret; + let cReturnType = toEmType(fn.ret); + if (outParams.length > 0) { + let mapped = []; + let memIdx = 0; // offset from `outAddress` where the data should get written, in units of 4 bytes + + for (let outParam of outParams) { + if (outParam.isArray) { + if (isZ3PointerType(outParam.type) || outParam.type === 'unsigned') { + let { sizeIndex } = outParam; + assert(sizeIndex !== undefined); + + let count; + if (arrayLengthParams.has(sizeIndex)) { + // i.e. this is also the length of an input array + count = args[sizeIndex]; + } else { + let sizeParam = fn.params[sizeIndex]; + if ( + !(sizeParam.kind === 'in' && sizeParam.type === 'unsigned' && !sizeParam.isPtr && !sizeParam.isArray) + ) { + throw new Error( + `size index is not unsigned int (for fn ${fn.name} parameter ${sizeIndex} got ${sizeParam.type})`, + ); + } + count = sizeParam.name; + } + let outArrayAddress = `outArray_${outParam.name}`; + prefix += ` + let ${outArrayAddress} = Mod._malloc(4 * ${count}); + try { + `.trim(); + suffix = + ` + } finally { + Mod._free(${outArrayAddress}); + } + `.trim() + suffix; + args[outParam.idx] = outArrayAddress; + mapped.push({ + name: outParam.name, + read: + `readUintArray(${outArrayAddress}, ${count})` + + (outParam.type === 'unsigned' ? '' : `as unknown as ${outParam.type}[]`), + type: `${outParam.type}[]`, + }); + } else { + console.error(`skipping ${fn.name} - out array of ${outParam.type}`); + return null; + } + } else if (outParam.isPtr) { + function setArg() { + args[outParam.idx] = memIdx === 0 ? 'outAddress' : `outAddress + ${memIdx * 4}`; + } + let read, type; + if (outParam.type === 'string') { + read = `Mod.UTF8ToString(getOutUint(${memIdx}))`; + setArg(); + ++memIdx; + } else if (isZ3PointerType(outParam.type)) { + read = `getOutUint(${memIdx}) as unknown as ${outParam.type}`; + setArg(); + ++memIdx; + } else if (outParam.type === 'unsigned') { + read = `getOutUint(${memIdx})`; + setArg(); + ++memIdx; + } else if (outParam.type === 'int') { + read = `getOutInt(${memIdx})`; + setArg(); + ++memIdx; + } else if (outParam.type === 'uint64_t') { + if (memIdx % 2 === 1) { + ++memIdx; + } + read = `getOutUint64(${memIdx / 2})`; + setArg(); + memIdx += 2; + } else if (outParam.type === 'int64_t') { + if (memIdx % 2 === 1) { + ++memIdx; + } + read = `getOutInt64(${memIdx / 2})`; + setArg(); + memIdx += 2; + } else { + console.error(`skipping ${fn.name} - unknown out parameter type ${outParam.type}`); + return null; + } + if (memIdx > Math.floor(BYTES_TO_ALLOCATE_FOR_OUT_PARAMS / 4)) { + // prettier-ignore + console.error(`skipping ${fn.name} - out parameter sizes sum to ${memIdx * 4}, which is > ${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS}`); + return null; + } + mapped.push({ + name: outParam.name, + read, + type: outParam.type, + }); + } else { + console.error(`skipping ${fn.name} - out param is neither pointer nor array`); + return null; + } + } + + let ignoreReturn = fn.ret === 'boolean' || fn.ret === 'void'; + if (outParams.length === 1) { + let outParam = mapped[0]; + if (ignoreReturn) { + returnType = outParam.type; + rv = outParam.read; + } else { + returnType = `{ rv: ${fn.ret}, ${outParam.name} : ${outParam.type} }`; + rv = `{ rv: ret, ${outParam.name} : ${outParam.read} }`; + } + } else { + if (ignoreReturn) { + returnType = `{ ${mapped.map(p => `${p.name} : ${p.type}`).join(', ')} }`; + rv = `{ ${mapped.map(p => `${p.name}: ${p.read}`).join(', ')} }`; + } else { + returnType = `{ rv: ${fn.ret}, ${mapped.map(p => `${p.name} : ${p.type}`).join(', ')} }`; + rv = `{ rv: ret, ${mapped.map(p => `${p.name}: ${p.read}`).join(', ')} }`; + } + } + + if (fn.ret === 'boolean') { + // assume the boolean indicates success + infix += ` + if (!ret) { + return null; + } + `.trim(); + cReturnType = 'boolean'; + returnType += ' | null'; + } else if (fn.ret === 'void') { + cReturnType = 'void'; + } else if (isZ3PointerType(fn.ret) || fn.ret === 'unsigned') { + cReturnType = 'number'; + } else { + console.error(`skipping ${fn.name} - out parameter for function which returns non-boolean`); + return null; + } + } + + if (fn.nullableRet) { + returnType += ' | null'; + infix += ` + if (ret === 0) { + return null; + } + `.trim(); + } + + // prettier-ignore + let invocation = `Mod.ccall('${isAsync ? 'async_' : ''}${fn.name}', '${cReturnType}', ${JSON.stringify(ctypes)}, [${args.map(toEm).join(', ')}])`; + + if (isAsync) { + invocation = `await Mod.async_call(() => ${invocation})`; + returnType = `Promise<${returnType}>`; + } + + let out = `${name}: ${isAsync ? 'async' : ''} function(${params.filter(p => p != null).join(', ')}): ${returnType} { + ${prefix}`; + if (infix === '' && suffix === '' && rv === 'ret') { + out += `return ${invocation};`; + } else { + out += ` + let ret = ${invocation}; + ${infix}return ${rv};${suffix} + `.trim(); + } + out += '}'; + return out; + } + + function wrapEnum(name: string, values: Record) { + let enumEntries = Object.entries(values); + return `export enum ${name} { + ${enumEntries.map(([k, v], i) => k + (v === (enumEntries[i - 1]?.[1] ?? -1) + 1 ? '' : ` = ${v}`) + ',').join('\n')} + };`; + } + + function getValidOutArrayIndexes(size: number) { + return Array.from({ length: Math.floor(BYTES_TO_ALLOCATE_FOR_OUT_PARAMS / size) }, (_, i) => i).join(' | '); + } + + const typesDocument = `// THIS FILE IS AUTOMATICALLY GENERATED BY ${path.basename(__filename)} +// DO NOT EDIT IT BY HAND + +interface Pointer extends Number { + readonly __typeName: T; +} +interface Subpointer extends Pointer { + readonly __typeName2: T; +} + +${Object.keys(types) + .filter(k => k.startsWith('Z3')) + .map(makePointerType) + .join('\n')} + +${Object.entries(enums) + .map(e => wrapEnum(e[0], e[1])) + .join('\n\n')} +`; + + const relativePath: string = path.relative(path.dirname(wrapperFilePath), path.dirname(typesFilePath)) || './'; + const ext: string = path.extname(typesFilePath); + const basename: string = path.basename(typesFilePath); + const importPath = relativePath + basename.slice(0, -ext.length); + + const wrapperDocument = `// THIS FILE IS AUTOMATICALLY GENERATED BY ${path.basename(__filename)} +// DO NOT EDIT IT BY HAND + +import { + ${Object.keys(types) + .filter(k => k.startsWith('Z3')) + .join(',\n')}, + ${Object.keys(enums).join(',\n')}, +} from '${importPath}'; + +${Object.entries(primitiveTypes) + .filter(e => e[0] !== 'void') + .map(e => `type ${e[0]} = ${e[1]};`) + .join('\n')} + +export async function init(initModule: any) { + let Mod = await initModule(); + + // this works for both signed and unsigned, because JS will wrap for you when constructing the Uint32Array + function intArrayToByteArr(ints: number[]) { + return new Uint8Array((new Uint32Array(ints)).buffer); + } + + function boolArrayToByteArr(bools: boolean[]) { + return bools.map(b => b ? 1 : 0); + } + + function readUintArray(address: number, count: number) { + return Array.from(new Uint32Array(Mod.HEAPU32.buffer, address, count)); + } + + let outAddress = Mod._malloc(${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS}); + let outUintArray = (new Uint32Array(Mod.HEAPU32.buffer, outAddress, 4)); + let getOutUint = (i: ${getValidOutArrayIndexes(4)}) => outUintArray[i]; + let outIntArray = (new Int32Array(Mod.HEAPU32.buffer, outAddress, 4)); + let getOutInt = (i: ${getValidOutArrayIndexes(4)}) => outIntArray[i]; + let outUint64Array = (new BigUint64Array(Mod.HEAPU32.buffer, outAddress, 2)); + let getOutUint64 = (i: ${getValidOutArrayIndexes(8)}) => outUint64Array[i]; + let outInt64Array = (new BigInt64Array(Mod.HEAPU32.buffer, outAddress, 2)); + let getOutInt64 = (i: ${getValidOutArrayIndexes(8)}) => outInt64Array[i]; + + return { + em: Mod, + Z3: { + mk_context: function(c: Z3_config): Z3_context { + let ctx = Mod._Z3_mk_context(c); + Mod._set_noop_error_handler(ctx); + return ctx; + }, + mk_context_rc: function(c: Z3_config): Z3_context { + let ctx = Mod._Z3_mk_context_rc(c); + Mod._set_noop_error_handler(ctx); + return ctx; + }, + ${functions + .map(wrapFunction) + .filter(f => f != null) + .join(',\n')} + + } + }; +} +`; + + return { + wrapperDocument: prettier.format(wrapperDocument, { singleQuote: true, parser: 'typescript' }), + typesDocument: prettier.format(typesDocument, { singleQuote: true, parser: 'typescript' }), + }; +} + +const { wrapperDocument, typesDocument } = makeTsWrapper(); +fs.mkdirSync(path.dirname(wrapperFilePath), { recursive: true }); +fs.writeFileSync(wrapperFilePath, wrapperDocument); +fs.mkdirSync(path.dirname(typesFilePath), { recursive: true }); +fs.writeFileSync(typesFilePath, typesDocument); diff --git a/src/api/js/scripts/parse-api.js b/src/api/js/scripts/parse-api.ts similarity index 82% rename from src/api/js/scripts/parse-api.js rename to src/api/js/scripts/parse-api.ts index 4176f8b26..3c8b37be0 100644 --- a/src/api/js/scripts/parse-api.js +++ b/src/api/js/scripts/parse-api.ts @@ -1,9 +1,8 @@ -'use strict'; +import assert from 'assert'; +import fs from 'fs'; +import path from 'path'; -let fs = require('fs'); -let path = require('path'); - -let files = [ +const files = [ 'z3_api.h', 'z3_algebraic.h', 'z3_ast_containers.h', @@ -15,15 +14,15 @@ let files = [ 'z3_spacer.h', ]; -let aliases = { +const aliases = { __proto__: null, Z3_bool: 'boolean', Z3_string: 'string', bool: 'boolean', signed: 'int', -}; +} as unknown as Record; -let primitiveTypes = { +const primitiveTypes = { __proto__: null, Z3_char_ptr: 'string', unsigned: 'number', @@ -32,35 +31,49 @@ let primitiveTypes = { int64_t: 'bigint', double: 'number', float: 'number', -}; +} as unknown as Record; -let optTypes = { +const optTypes = { __proto__: null, Z3_sort_opt: 'Z3_sort', Z3_ast_opt: 'Z3_ast', Z3_func_interp_opt: 'Z3_func_interp', -}; +} as unknown as Record; // parse type declarations -let types = { - __proto__: null, +const types = { + __proto__: null, - // these are function types I can't be bothered to parse - Z3_error_handler: 'Z3_error_handler', - Z3_push_eh: 'Z3_push_eh', - Z3_pop_eh: 'Z3_pop_eh', - Z3_fresh_eh: 'Z3_fresh_eh', - Z3_fixed_eh: 'Z3_fixed_eh', - Z3_eq_eh: 'Z3_eq_eh', - Z3_final_eh: 'Z3_final_eh', - Z3_created_eh: 'Z3_created_eh', - Z3_decide_eh: 'Z3_decide_eh' + // these are function types I can't be bothered to parse + Z3_error_handler: 'Z3_error_handler', + Z3_push_eh: 'Z3_push_eh', + Z3_pop_eh: 'Z3_pop_eh', + Z3_fresh_eh: 'Z3_fresh_eh', + Z3_fixed_eh: 'Z3_fixed_eh', + Z3_eq_eh: 'Z3_eq_eh', + Z3_final_eh: 'Z3_final_eh', + Z3_created_eh: 'Z3_created_eh', + Z3_decide_eh: 'Z3_decide_eh', +} as unknown as Record; + +export type ApiParam = { kind: string; sizeIndex?: number; type: string }; +export type Api = { params: ApiParam[]; ret: string; extra: boolean }; +const defApis: Record = Object.create(null); +export type FuncParam = { + type: string; + cType: string; + name: string; + isConst: boolean; + isPtr: boolean; + isArray: boolean; + nullable: boolean; + kind?: string; + sizeIndex?: number; }; - -let defApis = Object.create(null); -let functions = []; -let enums = Object.create(null); +export type Func = { ret: string; cRet: string; name: string; params: FuncParam[]; nullableRet: boolean }; +const functions: Func[] = []; +let enums: Record> = Object.create(null); for (let file of files) { let contents = fs.readFileSync(path.join(__dirname, '..', '..', file), 'utf8'); @@ -80,6 +93,7 @@ for (let file of files) { /def_Type\(\s*'(?[A-Za-z0-9_]+)',\s*'(?[A-Za-z0-9_]+)',\s*'(?[A-Za-z0-9_]+)'\)/g, ); for (let { groups } of typeMatches) { + assert(groups !== undefined); pytypes[groups.name] = groups.cname; } @@ -93,11 +107,12 @@ for (let file of files) { let apiLines = contents.split('\n').filter(l => /def_API|extra_API/.test(l)); for (let line of apiLines) { let match = line.match( - /^\s*(?def_API|extra_API) *\(\s*'(?[A-Za-z0-9_]+)'\s*,\s*(?[A-Za-z0-9_]+)\s*,\s*\((?((_in|_out|_in_array|_out_array|_fnptr|_inout_array)\([^)]+\)\s*,?\s*)*)\)\s*\)\s*$/, + /^\s*(?def_API|extra_API) *\(\s*'(?[A-Za-z0-9_]+)'\s*,\s*(?[A-Za-z0-9_]+)\s*,\s*\((?((_in|_out|_in_array|_out_array|_fnptr|_inout_array)\([^)]+\)\s*,?\s*)*)\)\s*\)\s*$/, ); - if (match == null) { + if (match === null) { throw new Error(`failed to match def_API call ${JSON.stringify(line)}`); } + assert(match.groups !== undefined); let { name, ret, def } = match.groups; let params = match.groups.params.trim(); let text = params; @@ -108,6 +123,7 @@ for (let file of files) { if (match == null) { break; } + assert(match.groups !== undefined); let kind = match.groups.kind; if (kind === 'inout_array') kind = 'in_array'; // https://github.com/Z3Prover/z3/discussions/5761 if (kind === 'in' || kind === 'out' || kind == 'fnptr') { @@ -135,10 +151,10 @@ for (let file of files) { } for (let match of contents.matchAll(/DEFINE_TYPE\((?[A-Za-z0-9_]+)\)/g)) { + assert(match.groups !== undefined); types[match.groups.type] = match.groups.type; } - // parse enum declarations for (let idx = 0; idx < contents.length; ) { let nextIdx = contents.indexOf('typedef enum', idx); @@ -156,12 +172,13 @@ for (let file of files) { if (match === null) { throw new Error(`could not parse enum ${JSON.stringify(slice)}`); } - let vals = Object.create(null); + let vals: Record = Object.create(null); let next = 0; while (true) { let blank = true; while (blank) { ({ match, text } = eat(text, /^\s*(\/\/[^\n]*\n)?/)); + assert(match !== null); blank = match[0].length > 0; } ({ match, text } = eat(text, /^[A-Za-z0-9_]+/)); @@ -173,6 +190,7 @@ for (let file of files) { ({ match, text } = eat(text, /^= *(?[^\n,\s]+)/)); if (match !== null) { + assert(match.groups !== undefined); let parsedVal = Number(match.groups.val); if (Object.is(parsedVal, NaN)) { throw new Error('unknown value ' + match.groups.val); @@ -222,12 +240,14 @@ for (let file of files) { if (match == null) { throw new Error(`failed to match c definition: ${JSON.stringify(slice)}`); } + assert(match.groups !== undefined); + let { ret, name, params } = match.groups; let parsedParams = []; if (params.trim() !== 'void') { for (let param of params.split(',')) { - let paramType, paramName, isConst, isPtr, isArray; + let paramType: string, paramName: string, isConst: boolean, isPtr: boolean, isArray: boolean; let { match, text } = eat(param, /^\s*/); ({ match, text } = eat(text, /^[A-Za-z0-9_]+/)); @@ -303,7 +323,7 @@ for (let file of files) { } } -function isKnownType(t) { +function isKnownType(t: string) { return t in enums || t in types || t in primitiveTypes || ['string', 'boolean', 'void'].includes(t); } @@ -340,19 +360,19 @@ for (let fn of functions) { } } -function eat(str, regex) { - const match = str.match(regex); - if (match == null) { +function eat(str: string, regex: string | RegExp) { + const match: RegExpMatchArray | null = str.match(regex); + if (match === null) { return { match, text: str }; } return { match, text: str.substring(match[0].length) }; } -function eatWs(text) { +function eatWs(text: string) { return eat(text, /^\s*/).text; } -function expect(str, regex) { +function expect(str: string, regex: string | RegExp) { let { text, match } = eat(str, regex); if (match === null) { throw new Error(`expected ${regex}, got ${JSON.stringify(text)}`); @@ -360,4 +380,4 @@ function expect(str, regex) { return { text, match }; } -module.exports = { primitiveTypes, types, enums, functions }; +export { primitiveTypes, types, enums, functions }; diff --git a/src/api/js/src/browser.ts b/src/api/js/src/browser.ts new file mode 100644 index 000000000..2a3b8ff5b --- /dev/null +++ b/src/api/js/src/browser.ts @@ -0,0 +1,16 @@ +import { createApi, Z3HighLevel } from './high-level'; +import { init as initWrapper, Z3LowLevel } from './low-level'; +export * from './high-level/types'; +export { Z3Core, Z3LowLevel } from './low-level'; +export * from './low-level/types.__GENERATED__'; + +export async function init(): Promise { + const initZ3 = (global as any).initZ3; + if (initZ3 === undefined) { + throw new Error('initZ3 was not imported correctly. Please consult documentation on how to load Z3 in browser'); + } + + const lowLevel = await initWrapper(initZ3); + const highLevel = createApi(lowLevel.Z3); + return { ...lowLevel, ...highLevel }; +} diff --git a/src/api/js/src/high-level/high-level.test.ts b/src/api/js/src/high-level/high-level.test.ts new file mode 100644 index 000000000..9555eea31 --- /dev/null +++ b/src/api/js/src/high-level/high-level.test.ts @@ -0,0 +1,450 @@ +import assert from 'assert'; +import asyncToArray from 'iter-tools/methods/async-to-array'; +import { init, killThreads } from '../jest'; +import { Arith, Bool, Model, sat, unsat, Z3AssertionError, Z3HighLevel } from './types'; + +/** + * Generate all possible solutions from given assumptions. + * + * **NOTE**: The set of solutions might be infinite. + * Always ensure to limit amount generated, either by knowing that the + * solution space is constrainted, or by taking only a specified + * amount of solutions + * ```typescript + * import { sliceAsync } from 'iter-tools'; + * // ... + * for await (const model of sliceAsync(10, solver.solutions())) { + * console.log(model.sexpr()); + * } + * ``` + * @see http://theory.stanford.edu/~nikolaj/programmingz3.html#sec-blocking-evaluations + * @returns Models with solutions. Nothing if no constants provided + */ +// TODO(ritave): Use faster solution https://stackoverflow.com/a/70656700 +// TODO(ritave): Move to high-level.ts +async function* allSolutions(...assertions: Bool[]): AsyncIterable> { + if (assertions.length === 0) { + return; + } + + const { Or } = assertions[0].ctx; + const solver = new assertions[0].ctx.Solver(); + solver.add(...assertions); + + while ((await solver.check()) === sat) { + const model = solver.model(); + const decls = model.decls(); + if (decls.length === 0) { + return; + } + yield model; + + solver.add( + Or( + ...decls + // TODO(ritave): Assert on arity > 0 + .filter(decl => decl.arity() === 0) + .map(decl => { + const term = decl.call(); + // TODO(ritave): Assert not an array / uinterpeted sort + const value = model.eval(term, true); + return term.neq(value); + }), + ), + ); + } +} + +async function prove(conjecture: Bool): Promise { + const solver = new conjecture.ctx.Solver(); + const { Not } = solver.ctx; + solver.add(Not(conjecture)); + expect(await solver.check()).toStrictEqual(unsat); +} + +async function solve(conjecture: Bool): Promise { + const solver = new conjecture.ctx.Solver(); + solver.add(conjecture); + expect(await solver.check()).toStrictEqual(sat); + return solver.model(); +} + +describe('high-level', () => { + let api: { em: any } & Z3HighLevel; + + beforeAll(async () => { + api = await init(); + }); + + afterAll(async () => { + await killThreads(api.em); + }); + + it('can set params', () => { + const { setParam, getParam, resetParams } = api; + + expect(getParam('pp.decimal')).toStrictEqual('false'); + setParam('pp.decimal', 'true'); + expect(getParam('pp.decimal')).toStrictEqual('true'); + setParam({ 'pp.decimal': 'false', timeout: 4 }); + expect(getParam('pp.decimal')).toStrictEqual('false'); + expect(getParam('timeout')).toStrictEqual('4'); + + resetParams(); + expect(getParam('pp.decimal')).toStrictEqual('false'); + expect(getParam('timeout')).toStrictEqual('4294967295'); + }); + + it('proves x = y implies g(x) = g(y)', async () => { + const { Solver, Int, Function, Implies, Not } = new api.Context('main'); + const solver = new Solver(); + + const sort = Int.sort(); + const x = Int.const('x'); + const y = Int.const('y'); + const g = Function.declare('g', sort, sort); + + const conjecture = Implies(x.eq(y), g.call(x).eq(g.call(y))); + solver.add(Not(conjecture)); + expect(await solver.check()).toStrictEqual(unsat); + }); + + it('disproves x = y implies g(g(x)) = g(y)', async () => { + const { Solver, Int, Function, Implies, Not } = new api.Context('main'); + const solver = new Solver(); + + const sort = Int.sort(); + const x = Int.const('x'); + const y = Int.const('y'); + const g = Function.declare('g', sort, sort); + const conjecture = Implies(x.eq(y), g.call(g.call(x)).eq(g.call(y))); + solver.add(Not(conjecture)); + expect(await solver.check()).toStrictEqual(sat); + }); + + it('checks that Context matches', () => { + const c1 = new api.Context('context'); + const c2 = new api.Context('context'); + const c3 = new api.Context('foo'); + const c4 = new api.Context('bar'); + + // Contexts with the same name don't do type checking during compile time. + // We need to check for different context dynamically + expect(() => c1.Or(c2.Int.val(5).eq(2))).toThrowError(Z3AssertionError); + + // On the other hand, this won't compile due to automatic generics + // @ts-expect-error + expect(() => c3.Or(c4.Int.val(5).eq(2))).toThrowError(Z3AssertionError); + + const allUniqueContexes = new Set([c1, c2, c3, c4]).size === 4; + expect(allUniqueContexes).toStrictEqual(true); + + expect(() => c1.Or(c1.Int.val(5).eq(2))).not.toThrowError(); + }); + + describe('booleans', () => { + it("proves De Morgan's Law", async () => { + const { Bool, Not, And, Eq, Or } = new api.Context('main'); + const [x, y] = [Bool.const('x'), Bool.const('y')]; + + const conjecture = Eq(Not(And(x, y)), Or(Not(x), Not(y))); + + await prove(conjecture); + }); + }); + + describe('ints', () => { + it('finds a model', async () => { + const { Solver, Int, isIntVal } = new api.Context('main'); + const solver = new Solver(); + const x = Int.const('x'); + const y = Int.const('y'); + + solver.add(x.ge(1)); // x >= 1 + solver.add(y.lt(x.add(3))); // y < x + 3 + + expect(await solver.check()).toStrictEqual(sat); + + const model = solver.model(); + expect(model.length).toStrictEqual(2); + + for (const decl of model) { + expect(decl.arity()).toStrictEqual(0); + } + const xValueExpr = model.get(x); + const yValueExpr = model.get(y); + assert(isIntVal(xValueExpr)); + assert(isIntVal(yValueExpr)); + const xValue = xValueExpr.value; + const yValue = yValueExpr.value; + assert(typeof xValue === 'bigint'); + assert(typeof yValue === 'bigint'); + expect(xValue).toBeGreaterThanOrEqual(1n); + expect(yValue).toBeLessThanOrEqual(xValue + 3n); + }); + + // TODO(ritave): After changes made since last commit (a332187c746c23450860deb210d94e6e042dd424), + // this test takes twice as long (from 5s to 10s). Figure out why + it('solves sudoku', async () => { + function toSudoku(data: string): (number | null)[][] { + const cells: (number | null)[][] = Array.from({ length: 9 }, () => Array.from({ length: 9 }, () => null)); + + const lines = data.trim().split('\n'); + for (let row = 0; row < 9; row++) { + const line = lines[row].trim(); + for (let col = 0; col < 9; col++) { + const char = line[col]; + if (char !== '.') { + cells[row][col] = Number.parseInt(char); + } + } + } + return cells; + } + const INSTANCE = toSudoku(` + ....94.3. + ...51...7 + .89....4. + ......2.8 + .6.2.1.5. + 1.2...... + .7....52. + 9...65... + .4.97.... + `); + + const EXPECTED = toSudoku(` + 715894632 + 234516897 + 689723145 + 493657218 + 867231954 + 152489763 + 376148529 + 928365471 + 541972386 + `); + + const { Solver, Int, Distinct, isIntVal } = new api.Context('main'); + + const cells: Arith[][] = []; + // 9x9 matrix of integer variables + for (let i = 0; i < 9; i++) { + const row = []; + for (let j = 0; j < 9; j++) { + row.push(Int.const(`x_${i}_${j}`)); + } + cells.push(row); + } + + const solver = new Solver(); + + // each cell contains a value 1<=x<=9 + for (let i = 0; i < 9; i++) { + for (let j = 0; j < 9; j++) { + solver.add(cells[i][j].ge(1), cells[i][j].le(9)); + } + } + + // each row contains a digit only once + for (let i = 0; i < 9; i++) { + solver.add(Distinct(...cells[i])); + } + + // each column contains a digit only once + for (let j = 0; j < 9; j++) { + const column = []; + for (let i = 0; i < 9; i++) { + column.push(cells[i][j]); + } + solver.add(Distinct(...column)); + } + + // each 3x3 contains a digit at most once + for (let iSquare = 0; iSquare < 3; iSquare++) { + for (let jSquare = 0; jSquare < 3; jSquare++) { + const square = []; + + for (let i = iSquare * 3; i < iSquare * 3 + 3; i++) { + for (let j = jSquare * 3; j < jSquare * 3 + 3; j++) { + square.push(cells[i][j]); + } + } + + solver.add(Distinct(...square)); + } + } + + for (let i = 0; i < 9; i++) { + for (let j = 0; j < 9; j++) { + const digit = INSTANCE[i][j]; + if (digit !== null) { + solver.add(cells[i][j].eq(digit)); + } + } + } + + expect(await solver.check()).toStrictEqual(sat); + + const model = solver.model(); + const result = []; + for (let i = 0; i < 9; i++) { + let row = []; + for (let j = 0; j < 9; j++) { + const cell = model.eval(cells[i][j]); + assert(isIntVal(cell)); + const value = cell.value; + assert(typeof value === 'bigint'); + expect(value).toBeGreaterThanOrEqual(0n); + expect(value).toBeLessThanOrEqual(9n); + // JSON.stringify doesn't handle bigints + row.push(Number(value)); + } + result.push(row); + } + expect(JSON.stringify(result)).toStrictEqual(JSON.stringify(EXPECTED)); + }, 120_000); + }); + + describe('reals', () => { + it('can work with numerals', async () => { + const { Real, And } = new api.Context('main'); + const n1 = Real.val('1/2'); + const n2 = Real.val('0.5'); + const n3 = Real.val(0.5); + await prove(And(n1.eq(n2), n1.eq(n3))); + + const n4 = Real.val('-1/3'); + const n5 = Real.val('-0.3333333333333333333333333333333333'); + await prove(n4.neq(n5)); + }); + + it('can do non-linear arithmetic', async () => { + api.setParam('pp.decimal', true); + api.setParam('pp.decimal_precision', 20); + const { Real, Solver, isReal, isRealVal } = new api.Context('main'); + const x = Real.const('x'); + const y = Real.const('y'); + const z = Real.const('z'); + + const solver = new Solver(); + solver.add(x.mul(x).add(y.mul(y)).eq(1)); // x^2 + y^2 == 1 + solver.add(x.mul(x).mul(x).add(z.mul(z).mul(z)).lt('1/2')); // x^3 + z^3 < 1/2 + + expect(await solver.check()).toStrictEqual(sat); + const model = solver.model(); + + expect(isRealVal(model.get(x))).toStrictEqual(true); + // solution of y is a polynomial + // https://stackoverflow.com/a/69740906 + expect(isReal(model.get(y))).toStrictEqual(true); + expect(isRealVal(model.get(z))).toStrictEqual(true); + }); + }); + + describe('bitvectors', () => { + it('can do simple proofs', async () => { + const { BitVec, Concat, Implies, isBitVecVal } = new api.Context('main'); + + const x = BitVec.const('x', 32); + + const sSol = (await solve(x.sub(10).sle(0).eq(x.sle(10)))).get(x); // signed: (x - 10 <= 0) == (x <= 10) + const uSol = (await solve(x.sub(10).ule(0).eq(x.ule(10)))).get(x); // unsigned: (x - 10 <= 0) == (x <= 10) + + assert(isBitVecVal(sSol) && isBitVecVal(uSol)); + let v = sSol.asSignedValue(); + expect(v - 10n <= 0n === v <= 10n).toStrictEqual(true); + v = uSol.value; + expect(v - 10n <= 0n === v <= 10n).toStrictEqual(true); + + const y = BitVec.const('y', 32); + + await prove(Implies(Concat(x, y).eq(Concat(y, x)), x.eq(y))); + }); + + it('finds x and y such that: x ^ y - 103 == x * y', async () => { + const { BitVec, isBitVecVal } = new api.Context('main'); + + const x = BitVec.const('x', 32); + const y = BitVec.const('y', 32); + + const model = await solve(x.xor(y).sub(103).eq(x.mul(y))); + const xSol = model.get(x); + const ySol = model.get(y); + assert(isBitVecVal(xSol) && isBitVecVal(ySol)); + const xv = xSol.asSignedValue(); + const yv = ySol.asSignedValue(); + + // this solutions wraps around so we need to check using modulo + expect((xv ^ yv) - 103n === (xv * yv) % 2n ** 32n).toStrictEqual(true); + }); + }); + + describe('Solver', () => { + it('can use push and pop', async () => { + const { Solver, Int } = new api.Context('main'); + const solver = new Solver(); + const x = Int.const('x'); + + solver.add(x.gt(0)); + + expect(await solver.check()).toStrictEqual(sat); + + solver.push(); + solver.add(x.lt(0)); + + expect(solver.numScopes()).toStrictEqual(1); + expect(await solver.check()).toStrictEqual(unsat); + + solver.pop(); + + expect(solver.numScopes()).toStrictEqual(0); + expect(await solver.check()).toStrictEqual(sat); + }); + + it('can find multiple solutions', async () => { + const { Int, isIntVal } = new api.Context('main'); + + const x = Int.const('x'); + + const solutions = await asyncToArray(allSolutions(x.ge(1), x.le(5))); + expect(solutions.length).toStrictEqual(5); + const results = solutions + .map(solution => { + const expr = solution.eval(x); + assert(isIntVal(expr)); + return expr.value; + }) + .sort((a, b) => { + assert(a !== null && b !== null && typeof a === 'bigint' && typeof b === 'bigint'); + if (a < b) { + return -1; + } else if (a == b) { + return 0; + } else { + return 1; + } + }); + expect(results).toStrictEqual([1n, 2n, 3n, 4n, 5n]); + }); + }); + + describe('AstVector', () => { + it('can use basic methods', async () => { + const { Solver, AstVector, Int } = new api.Context('main'); + const solver = new Solver(); + + const vector = new AstVector(); + for (let i = 0; i < 5; i++) { + vector.push(Int.const(`int__${i}`)); + } + + const length = vector.length; + for (let i = 0; i < length; i++) { + solver.add(vector.get(i).gt(1)); + } + + expect(await solver.check()).toStrictEqual(sat); + }); + }); +}); diff --git a/src/api/js/src/high-level/high-level.ts b/src/api/js/src/high-level/high-level.ts new file mode 100644 index 000000000..731e47b07 --- /dev/null +++ b/src/api/js/src/high-level/high-level.ts @@ -0,0 +1,1888 @@ +// TODO(ritave): Add typing for Context Options +// https://github.com/Z3Prover/z3/pull/6048#discussion_r883391669 +// TODO(ritave): Add an error handler +// TODO(ritave): Add support for building faster floats without support for Safari +// TODO(ritave): Use Z3_DECLARE_CLOSURE macro to generate code https://github.com/Z3Prover/z3/pull/6048#discussion_r884155462 +// TODO(ritave): Add pretty printing +// TODO(ritave): Make Z3 multi-threaded +// TODO(ritave): If a test times out, jest kills it, and the global state of Z3 is left in an unexpected state. +// This occurs specifically during longer check(). Afterwards, all next tests will fail to run +// thinking the previous call was not finished. Find a way to stop execution and clean up the global state +import { Mutex } from 'async-mutex'; +import { + Z3Core, + Z3_ast, + Z3_ast_kind, + Z3_ast_map, + Z3_ast_print_mode, + Z3_ast_vector, + Z3_context, + Z3_decl_kind, + Z3_func_decl, + Z3_func_interp, + Z3_lbool, + Z3_model, + Z3_parameter_kind, + Z3_probe, + Z3_solver, + Z3_sort, + Z3_sort_kind, + Z3_symbol, + Z3_symbol_kind, + Z3_tactic, +} from '../low-level'; +import { + AnyAst, + AnyExpr, + AnySort, + Arith, + ArithSort, + Ast, + AstMap, + AstMapCtor, + AstVector, + AstVectorCtor, + BitVec, + BitVecNum, + BitVecSort, + Bool, + BoolSort, + CheckSatResult, + CoercibleRational, + CoercibleToBitVec, + CoercibleToExpr, + CoercibleToExprMap, + Context, + ContextCtor, + Expr, + FuncDecl, + FuncDeclSignature, + FuncInterp, + IntNum, + Model, + Probe, + RatNum, + sat, + Solver, + Sort, + SortToExprMap, + Tactic, + unknown, + unsat, + Z3Error, + Z3HighLevel, +} from './types'; +import { allSatisfy, assert, assertExhaustive, autoBind } from './utils'; + +const FALLBACK_PRECISION = 17; + +const asyncMutex = new Mutex(); + +function isCoercibleRational(obj: any): obj is CoercibleRational { + // prettier-ignore + const r = ( + (obj !== null && + (typeof obj === 'object' || typeof obj === 'function')) && + (obj.numerator !== null && + (typeof obj.numerator === 'number' || typeof obj.numerator === 'bigint')) && + (obj.denominator !== null && + (typeof obj.denominator === 'number' || typeof obj.denominator === 'bigint')) + ); + r && + assert( + (typeof obj.numerator !== 'number' || Number.isSafeInteger(obj.numerator)) && + (typeof obj.denominator !== 'number' || Number.isSafeInteger(obj.denominator)), + 'Fraction numerator and denominator must be integers', + ); + return r; +} + +export function createApi(Z3: Z3Core): Z3HighLevel { + // TODO(ritave): Create a custom linting rule that checks if the provided callbacks to cleanup + // Don't capture `this` + const cleanup = new FinalizationRegistry<() => void>(callback => callback()); + + function enableTrace(tag: string) { + Z3.enable_trace(tag); + } + + function disableTrace(tag: string) { + Z3.disable_trace(tag); + } + + function getVersion() { + return Z3.get_version(); + } + + function getVersionString() { + const { major, minor, build_number } = Z3.get_version(); + return `${major}.${minor}.${build_number}`; + } + + function getFullVersion() { + return Z3.get_full_version(); + } + + function openLog(filename: string) { + return Z3.open_log(filename); + } + + function appendLog(s: string) { + Z3.append_log(s); + } + + function setParam(key: string, value: any): void; + function setParam(params: Record): void; + function setParam(key: string | Record, value?: any) { + if (typeof key === 'string') { + Z3.global_param_set(key, value.toString()); + } else { + assert(value === undefined, "Can't provide a Record and second parameter to set_param at the same time"); + Object.entries(key).forEach(([key, value]) => setParam(key, value)); + } + } + + function resetParams() { + Z3.global_param_reset_all(); + } + + function getParam(name: string) { + return Z3.global_param_get(name); + } + + function isContext(obj: unknown): obj is Context { + return obj instanceof ContextImpl; + } + + class ContextImpl implements Context { + declare readonly __typename: Context['__typename']; + + readonly ptr: Z3_context; + readonly name: string; + + constructor(name: string, params: Record = {}) { + const cfg = Z3.mk_config(); + Object.entries(params).forEach(([key, value]) => Z3.set_param_value(cfg, key, value.toString())); + const context = Z3.mk_context_rc(cfg); + + this.ptr = context; + this.name = name; + + Z3.set_ast_print_mode(this.ptr, Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT); + Z3.del_config(cfg); + + // We want to bind functions and operations to `this` inside Context + // So that the user can write things like this and have it work: + // ``` + // const { And, Or } = new Context('main'); + // ``` + // + // Typescript doesn't handle overloading of method fields, only + // methods. We can't use closures to bind this, so we use auto-bind library + // ``` + // class { + // // This works + // test(a: boolean): boolean; + // test(a: number): number; + // test(a: boolean | number): boolean | number { + // return 0; + // } + // + // // This fails to compile + // test2: (a: boolean) => boolean; + // test2: (a: number) => number; + // test2 = (a: boolean | number): boolean | number => { + // return 0; + // } + // } + // ``` + autoBind(this); + + cleanup.register(this, () => Z3.del_context(context)); + } + + /////////////// + // Functions // + /////////////// + interrupt(): void { + Z3.interrupt(this.ptr); + } + + isModel(obj: unknown): obj is Model { + const r = obj instanceof ModelImpl; + r && this._assertContext(obj); + return r; + } + + isAst(obj: unknown): obj is Ast { + const r = obj instanceof AstImpl; + r && this._assertContext(obj); + return r; + } + + isSort(obj: unknown): obj is Sort { + const r = obj instanceof SortImpl; + r && this._assertContext(obj); + return r; + } + + isFuncDecl(obj: unknown): obj is FuncDecl { + const r = obj instanceof FuncDeclImpl; + r && this._assertContext(obj); + return r; + } + + isApp(obj: unknown): boolean { + if (!this.isExpr(obj)) { + return false; + } + const kind = Z3.get_ast_kind(this.ptr, obj.ast); + return kind === Z3_ast_kind.Z3_NUMERAL_AST || kind === Z3_ast_kind.Z3_APP_AST; + } + + isConst(obj: unknown): boolean { + return this.isExpr(obj) && this.isApp(obj) && obj.numArgs() === 0; + } + + isExpr(obj: unknown): obj is Expr { + const r = obj instanceof ExprImpl; + r && this._assertContext(obj); + return r; + } + + isVar(obj: unknown): boolean { + return this.isExpr(obj) && Z3.get_ast_kind(this.ptr, obj.ast) === Z3_ast_kind.Z3_VAR_AST; + } + + isAppOf(obj: unknown, kind: Z3_decl_kind): boolean { + return this.isExpr(obj) && this.isApp(obj) && obj.decl().kind() === kind; + } + + isBool(obj: unknown): obj is Bool { + const r = obj instanceof BoolImpl; + r && this._assertContext(obj); + return r; + } + + isTrue(obj: unknown): boolean { + return this.isAppOf(obj, Z3_decl_kind.Z3_OP_TRUE); + } + + isFalse(obj: unknown): boolean { + return this.isAppOf(obj, Z3_decl_kind.Z3_OP_FALSE); + } + + isAnd(obj: unknown): boolean { + return this.isAppOf(obj, Z3_decl_kind.Z3_OP_AND); + } + + isOr(obj: unknown): boolean { + return this.isAppOf(obj, Z3_decl_kind.Z3_OP_OR); + } + + isImplies(obj: unknown): boolean { + return this.isAppOf(obj, Z3_decl_kind.Z3_OP_IMPLIES); + } + + isNot(obj: unknown): boolean { + return this.isAppOf(obj, Z3_decl_kind.Z3_OP_NOT); + } + + isEq(obj: unknown): boolean { + return this.isAppOf(obj, Z3_decl_kind.Z3_OP_EQ); + } + + isDistinct(obj: unknown): boolean { + return this.isAppOf(obj, Z3_decl_kind.Z3_OP_DISTINCT); + } + + isArith(obj: unknown): obj is Arith { + const r = obj instanceof ArithImpl; + r && this._assertContext(obj); + return r; + } + + isArithSort(obj: unknown): obj is ArithSort { + const r = obj instanceof ArithSortImpl; + r && this._assertContext(obj); + return r; + } + + isInt(obj: unknown): boolean { + return this.isArith(obj) && this.isIntSort(obj.sort); + } + + isIntVal(obj: unknown): obj is IntNum { + const r = obj instanceof IntNumImpl; + r && this._assertContext(obj); + return r; + } + + isIntSort(obj: unknown): boolean { + return this.isSort(obj) && obj.kind() === Z3_sort_kind.Z3_INT_SORT; + } + + isReal(obj: unknown): boolean { + return this.isArith(obj) && this.isRealSort(obj.sort); + } + + isRealVal(obj: unknown): obj is RatNum { + const r = obj instanceof RatNumImpl; + r && this._assertContext(obj); + return r; + } + + isRealSort(obj: unknown): boolean { + return this.isSort(obj) && obj.kind() === Z3_sort_kind.Z3_REAL_SORT; + } + + isBitVecSort(obj: unknown): obj is BitVecSort { + const r = obj instanceof BitVecSortImpl; + r && this._assertContext(obj); + return r; + } + + isBitVec(obj: unknown): obj is BitVec { + const r = obj instanceof BitVecImpl; + r && this._assertContext(obj); + return r; + } + + isBitVecVal(obj: unknown): obj is BitVecNum { + const r = obj instanceof BitVecNumImpl; + r && this._assertContext(obj); + return r; + } + + isProbe(obj: unknown): obj is Probe { + const r = obj instanceof ProbeImpl; + r && this._assertContext(obj); + return r; + } + + isTactic(obj: unknown): obj is Tactic { + const r = obj instanceof TacticImpl; + r && this._assertContext(obj); + return r; + } + + isAstVector(obj: unknown): obj is AstVector { + const r = obj instanceof AstVectorImpl; + r && this._assertContext(obj); + return r; + } + + eqIdentity(a: Ast, b: Ast): boolean { + return a.eqIdentity(b); + } + + getVarIndex(obj: Expr): number { + assert(this.isVar(obj), 'Z3 bound variable expected'); + return Z3.get_index_value(this.ptr, obj.ast); + } + + from(primitive: boolean): Bool; + from(primitive: number | CoercibleRational): RatNum; + from(primitive: bigint): IntNum; + from(expr: T): T; + from(expr: CoercibleToExpr): AnyExpr; + from(value: CoercibleToExpr): AnyExpr { + if (typeof value === 'boolean') { + return this.Bool.val(value); + } else if (typeof value === 'number' || isCoercibleRational(value)) { + return this.Real.val(value); + } else if (typeof value === 'bigint') { + return this.Int.val(value); + } else if (this.isExpr(value)) { + return value; + } + assert(false); + } + + async solve(...assertions: Bool[]): Promise { + const solver = new this.Solver(); + solver.add(...assertions); + const result = await solver.check(); + if (result === sat) { + return solver.model(); + } + return result; + } + + ///////////// + // Classes // + ///////////// + readonly Solver = SolverImpl.bind(SolverImpl, this); + readonly Model = ModelImpl.bind(ModelImpl, this); + readonly Tactic = TacticImpl.bind(TacticImpl, this); + readonly AstVector = AstVectorImpl.bind(AstVectorImpl, this) as AstVectorCtor; + readonly AstMap = AstMapImpl.bind(AstMapImpl, this) as AstMapCtor; + + ///////////// + // Objects // + ///////////// + readonly Sort = { + declare: (name: string) => new SortImpl(this, Z3.mk_uninterpreted_sort(this.ptr, this._toSymbol(name))), + }; + readonly Function = { + declare: (name: string, ...signature: FuncDeclSignature) => { + const arity = signature.length - 1; + const rng = signature[arity]; + this._assertContext(rng); + const dom = []; + for (let i = 0; i < arity; i++) { + this._assertContext(signature[i]); + dom.push(signature[i].ptr); + } + return new FuncDeclImpl(this, Z3.mk_func_decl(this.ptr, this._toSymbol(name), dom, rng.ptr)); + }, + fresh: (...signature: FuncDeclSignature) => { + const arity = signature.length - 1; + const rng = signature[arity]; + this._assertContext(rng); + const dom = []; + for (let i = 0; i < arity; i++) { + this._assertContext(signature[i]); + dom.push(signature[i].ptr); + } + return new FuncDeclImpl(this, Z3.mk_fresh_func_decl(this.ptr, 'f', dom, rng.ptr)); + }, + }; + readonly RecFunc = { + declare: (name: string, ...signature: FuncDeclSignature) => { + const arity = signature.length - 1; + const rng = signature[arity]; + this._assertContext(rng); + const dom = []; + for (let i = 0; i < arity; i++) { + this._assertContext(signature[i]); + dom.push(signature[i].ptr); + } + return new FuncDeclImpl(this, Z3.mk_rec_func_decl(this.ptr, this._toSymbol(name), dom, rng.ptr)); + }, + + addDefinition: (f: FuncDecl, args: Expr[], body: Expr) => { + this._assertContext(f, ...args, body); + Z3.add_rec_def( + this.ptr, + f.ptr, + args.map(arg => arg.ast), + body.ast, + ); + }, + }; + readonly Bool = { + sort: () => new BoolSortImpl(this, Z3.mk_bool_sort(this.ptr)), + + const: (name: string) => new BoolImpl(this, Z3.mk_const(this.ptr, this._toSymbol(name), this.Bool.sort().ptr)), + consts: (names: string | string[]) => { + if (typeof names === 'string') { + names = names.split(' '); + } + return names.map(name => this.Bool.const(name)); + }, + vector: (prefix: string, count: number) => { + const result = []; + for (let i = 0; i < count; i++) { + result.push(this.Bool.const(`${prefix}__${i}`)); + } + return result; + }, + fresh: (prefix = 'b') => new BoolImpl(this, Z3.mk_fresh_const(this.ptr, prefix, this.Bool.sort().ptr)), + + val: (value: boolean) => { + if (value) { + return new BoolImpl(this, Z3.mk_true(this.ptr)); + } + return new BoolImpl(this, Z3.mk_false(this.ptr)); + }, + }; + readonly Int = { + sort: () => new ArithSortImpl(this, Z3.mk_int_sort(this.ptr)), + + const: (name: string) => new ArithImpl(this, Z3.mk_const(this.ptr, this._toSymbol(name), this.Int.sort().ptr)), + consts: (names: string | string[]) => { + if (typeof names === 'string') { + names = names.split(' '); + } + return names.map(name => this.Int.const(name)); + }, + vector: (prefix: string, count: number) => { + const result = []; + for (let i = 0; i < count; i++) { + result.push(this.Int.const(`${prefix}__${i}`)); + } + return result; + }, + fresh: (prefix = 'x') => new ArithImpl(this, Z3.mk_fresh_const(this.ptr, prefix, this.Int.sort().ptr)), + + val: (value: number | bigint | string) => { + assert(typeof value === 'bigint' || typeof value === 'string' || Number.isSafeInteger(value)); + return new IntNumImpl(this, Z3.mk_numeral(this.ptr, value.toString(), this.Int.sort().ptr)); + }, + }; + readonly Real = { + sort: () => new ArithSortImpl(this, Z3.mk_real_sort(this.ptr)), + + const: (name: string) => new ArithImpl(this, Z3.mk_const(this.ptr, this._toSymbol(name), this.Real.sort().ptr)), + consts: (names: string | string[]) => { + if (typeof names === 'string') { + names = names.split(' '); + } + return names.map(name => this.Real.const(name)); + }, + vector: (prefix: string, count: number) => { + const result = []; + for (let i = 0; i < count; i++) { + result.push(this.Real.const(`${prefix}__${i}`)); + } + return result; + }, + fresh: (prefix = 'b') => new ArithImpl(this, Z3.mk_fresh_const(this.ptr, prefix, this.Real.sort().ptr)), + + val: (value: number | bigint | string | CoercibleRational) => { + if (isCoercibleRational(value)) { + value = `${value.numerator}/${value.denominator}`; + } + return new RatNumImpl(this, Z3.mk_numeral(this.ptr, value.toString(), this.Real.sort().ptr)); + }, + }; + readonly BitVec = { + sort: (bits: number): BitVecSort => { + assert(Number.isSafeInteger(bits), 'number of bits must be an integer'); + return new BitVecSortImpl(this, Z3.mk_bv_sort(this.ptr, bits)); + }, + + const: (name: string, bits: number | BitVecSort): BitVec => + new BitVecImpl( + this, + Z3.mk_const(this.ptr, this._toSymbol(name), this.isBitVecSort(bits) ? bits.ptr : this.BitVec.sort(bits).ptr), + ), + + consts: (names: string | string[], bits: number | BitVecSort): BitVec[] => { + if (typeof names === 'string') { + names = names.split(' '); + } + return names.map(name => this.BitVec.const(name, bits)); + }, + + val: (value: bigint | number | boolean, bits: number | BitVecSort): BitVecNum => { + if (value === true) { + return this.BitVec.val(1, bits); + } else if (value === false) { + return this.BitVec.val(0, bits); + } + return new BitVecNumImpl( + this, + Z3.mk_numeral(this.ptr, value.toString(), this.isBitVecSort(bits) ? bits.ptr : this.BitVec.sort(bits).ptr), + ); + }, + }; + + //////////////// + // Operations // + //////////////// + If(condition: Probe, onTrue: Tactic, onFalse: Tactic): Tactic; + If( + condition: Bool | boolean, + onTrue: OnTrueRef, + onFalse: OnFalseRef, + ): CoercibleToExprMap; + If( + condition: Bool | Probe | boolean, + onTrue: CoercibleToExpr | Tactic, + onFalse: CoercibleToExpr | Tactic, + ): Expr | Tactic { + if (this.isProbe(condition) && this.isTactic(onTrue) && this.isTactic(onFalse)) { + return this.Cond(condition, onTrue, onFalse); + } + assert( + !this.isProbe(condition) && !this.isTactic(onTrue) && !this.isTactic(onFalse), + 'Mixed expressions and goals', + ); + if (typeof condition === 'boolean') { + condition = this.Bool.val(condition); + } + onTrue = this.from(onTrue); + onFalse = this.from(onFalse); + return this._toExpr(Z3.mk_ite(this.ptr, condition.ptr, onTrue.ast, onFalse.ast)); + } + + Distinct(...exprs: CoercibleToExpr[]): Bool { + assert(exprs.length > 0, "Can't make Distinct ouf of nothing"); + + return new BoolImpl( + this, + Z3.mk_distinct( + this.ptr, + exprs.map(expr => { + expr = this.from(expr); + this._assertContext(expr); + return expr.ast; + }), + ), + ); + } + + Const(name: string, sort: S): SortToExprMap { + this._assertContext(sort); + return this._toExpr(Z3.mk_const(this.ptr, this._toSymbol(name), sort.ptr)) as SortToExprMap; + } + + Consts(names: string | string[], sort: S): SortToExprMap[] { + this._assertContext(sort); + if (typeof names === 'string') { + names = names.split(' '); + } + return names.map(name => this.Const(name, sort)); + } + + FreshConst(sort: S, prefix: string = 'c'): SortToExprMap { + this._assertContext(sort); + return this._toExpr(Z3.mk_fresh_const(sort.ctx.ptr, prefix, sort.ptr)) as SortToExprMap; + } + + Var(idx: number, sort: S): SortToExprMap { + this._assertContext(sort); + return this._toExpr(Z3.mk_bound(sort.ctx.ptr, idx, sort.ptr)) as SortToExprMap; + } + + Implies(a: Bool | boolean, b: Bool | boolean): Bool { + a = this.from(a) as Bool; + b = this.from(b) as Bool; + this._assertContext(a, b); + return new BoolImpl(this, Z3.mk_implies(this.ptr, a.ptr, b.ptr)); + } + + Eq(a: CoercibleToExpr, b: CoercibleToExpr): Bool { + a = this.from(a); + b = this.from(b); + this._assertContext(a, b); + return a.eq(b); + } + + Xor(a: Bool | boolean, b: Bool | boolean): Bool { + a = this.from(a) as Bool; + b = this.from(b) as Bool; + this._assertContext(a, b); + return new BoolImpl(this, Z3.mk_xor(this.ptr, a.ptr, b.ptr)); + } + + Not(a: Probe): Probe; + Not(a: Bool | boolean): Bool; + Not(a: Bool | boolean | Probe): Bool | Probe { + if (typeof a === 'boolean') { + a = this.from(a); + } + this._assertContext(a); + if (this.isProbe(a)) { + return new ProbeImpl(this, Z3.probe_not(this.ptr, a.ptr)); + } + return new BoolImpl(this, Z3.mk_not(this.ptr, a.ptr)); + } + + And(): Bool; + And(vector: AstVector): Bool; + And(...args: (Bool | boolean)[]): Bool; + And(...args: Probe[]): Probe; + And(...args: (AstVector | Probe | Bool | boolean)[]): Bool | Probe { + if (args.length == 1 && args[0] instanceof this.AstVector) { + args = [...args[0].values()]; + assert(allSatisfy(args, this.isBool.bind(this)) ?? true, 'AstVector containing not bools'); + } + + const allProbes = allSatisfy(args, this.isProbe.bind(this)) ?? false; + if (allProbes) { + return this._probeNary(Z3.probe_and, args as [Probe, ...Probe[]]); + } else { + args = args.map(this.from.bind(this)) as Bool[]; + this._assertContext(...(args as Bool[])); + return new BoolImpl( + this, + Z3.mk_and( + this.ptr, + args.map(arg => (arg as Bool).ptr), + ), + ); + } + } + + Or(): Bool; + Or(vector: AstVector): Bool; + Or(...args: (Bool | boolean)[]): Bool; + Or(...args: Probe[]): Probe; + Or(...args: (AstVector | Probe | Bool | boolean)[]): Bool | Probe { + if (args.length == 1 && args[0] instanceof this.AstVector) { + args = [...args[0].values()]; + assert(allSatisfy(args, this.isBool.bind(this)) ?? true, 'AstVector containing not bools'); + } + + const allProbes = allSatisfy(args, this.isProbe.bind(this)) ?? false; + if (allProbes) { + return this._probeNary(Z3.probe_or, args as [Probe, ...Probe[]]); + } else { + args = args.map(this.from.bind(this)) as Bool[]; + this._assertContext(...(args as Bool[])); + return new BoolImpl( + this, + Z3.mk_or( + this.ptr, + args.map(arg => (arg as Bool).ptr), + ), + ); + } + } + + ToReal(expr: Arith | bigint): Arith { + expr = this.from(expr) as Arith; + this._assertContext(expr); + assert(this.isInt(expr), 'Int expression expected'); + return new ArithImpl(this, Z3.mk_int2real(this.ptr, expr.ast)); + } + + ToInt(expr: Arith | number | CoercibleRational | string): Arith { + if (!this.isExpr(expr)) { + expr = this.Real.val(expr); + } + this._assertContext(expr); + assert(this.isReal(expr), 'Real expression expected'); + return new ArithImpl(this, Z3.mk_real2int(this.ptr, expr.ast)); + } + + IsInt(expr: Arith | number | CoercibleRational | string): Bool { + if (!this.isExpr(expr)) { + expr = this.Real.val(expr); + } + this._assertContext(expr); + assert(this.isReal(expr), 'Real expression expected'); + return new BoolImpl(this, Z3.mk_is_int(this.ptr, expr.ast)); + } + + Sqrt(a: Arith | number | bigint | string | CoercibleRational): Arith { + if (!this.isExpr(a)) { + a = this.Real.val(a); + } + return a.pow('1/2'); + } + + Cbrt(a: Arith | number | bigint | string | CoercibleRational): Arith { + if (!this.isExpr(a)) { + a = this.Real.val(a); + } + return a.pow('1/3'); + } + + BV2Int(a: BitVec, isSigned: boolean): Arith { + this._assertContext(a); + return new ArithImpl(this, Z3.mk_bv2int(this.ptr, a.ast, isSigned)); + } + + Int2BV(a: Arith | bigint | number, bits: number): BitVec { + if (this.isArith(a)) { + assert(this.isInt(a), 'parameter must be an integer'); + } else { + assert(typeof a !== 'number' || Number.isSafeInteger(a), 'parameter must not have decimal places'); + a = this.Int.val(a); + } + return new BitVecImpl(this, Z3.mk_int2bv(this.ptr, bits, a.ast)); + } + + Concat(...bitvecs: BitVec[]): BitVec { + this._assertContext(...bitvecs); + return bitvecs.reduce((prev, curr) => new BitVecImpl(this, Z3.mk_concat(this.ptr, prev.ast, curr.ast))); + } + + Cond(probe: Probe, onTrue: Tactic, onFalse: Tactic): Tactic { + this._assertContext(probe, onTrue, onFalse); + return new this.Tactic(Z3.tactic_cond(this.ptr, probe.ptr, onTrue.ptr, onFalse.ptr)); + } + + ///////////// + // Private // + ///////////// + _assertContext(...ctxs: (Context | { ctx: Context })[]) { + ctxs.forEach(other => assert('ctx' in other ? this === other.ctx : this === other, 'Context mismatch')); + } + + _toSymbol(s: string | number) { + if (typeof s === 'number') { + return Z3.mk_int_symbol(this.ptr, s); + } else { + return Z3.mk_string_symbol(this.ptr, s); + } + } + + _fromSymbol(sym: Z3_symbol) { + const kind = Z3.get_symbol_kind(this.ptr, sym); + switch (kind) { + case Z3_symbol_kind.Z3_INT_SYMBOL: + return Z3.get_symbol_int(this.ptr, sym); + case Z3_symbol_kind.Z3_STRING_SYMBOL: + return Z3.get_symbol_string(this.ptr, sym); + default: + assertExhaustive(kind); + } + } + + _toAst(ast: Z3_ast): AnyAst { + switch (Z3.get_ast_kind(this.ptr, ast)) { + case Z3_ast_kind.Z3_SORT_AST: + return this._toSort(ast as Z3_sort); + case Z3_ast_kind.Z3_FUNC_DECL_AST: + return new FuncDeclImpl(this, ast as Z3_func_decl); + default: + return this._toExpr(ast); + } + } + + _toSort(ast: Z3_sort): AnySort { + switch (Z3.get_sort_kind(this.ptr, ast)) { + case Z3_sort_kind.Z3_BOOL_SORT: + return new BoolSortImpl(this, ast); + case Z3_sort_kind.Z3_INT_SORT: + case Z3_sort_kind.Z3_REAL_SORT: + return new ArithSortImpl(this, ast); + case Z3_sort_kind.Z3_BV_SORT: + return new BitVecSortImpl(this, ast); + default: + return new SortImpl(this, ast); + } + } + + _toExpr(ast: Z3_ast): Bool | IntNum | RatNum | Arith | Expr { + const kind = Z3.get_ast_kind(this.ptr, ast); + if (kind === Z3_ast_kind.Z3_QUANTIFIER_AST) { + assert(false); + } + const sortKind = Z3.get_sort_kind(this.ptr, Z3.get_sort(this.ptr, ast)); + switch (sortKind) { + case Z3_sort_kind.Z3_BOOL_SORT: + return new BoolImpl(this, ast); + case Z3_sort_kind.Z3_INT_SORT: + if (kind === Z3_ast_kind.Z3_NUMERAL_AST) { + return new IntNumImpl(this, ast); + } + return new ArithImpl(this, ast); + case Z3_sort_kind.Z3_REAL_SORT: + if (kind === Z3_ast_kind.Z3_NUMERAL_AST) { + return new RatNumImpl(this, ast); + } + return new ArithImpl(this, ast); + case Z3_sort_kind.Z3_BV_SORT: + if (kind === Z3_ast_kind.Z3_NUMERAL_AST) { + return new BitVecNumImpl(this, ast); + } + return new BitVecImpl(this, ast); + default: + return new ExprImpl(this, ast); + } + } + + _flattenArgs(args: (T | AstVector)[]): T[] { + const result: T[] = []; + for (const arg of args) { + if (this.isAstVector(arg)) { + result.push(...arg.values()); + } else { + result.push(arg); + } + } + return result; + } + + _toProbe(p: Probe | Z3_probe): Probe { + if (this.isProbe(p)) { + return p; + } + return new ProbeImpl(this, p); + } + + _probeNary( + f: (ctx: Z3_context, left: Z3_probe, right: Z3_probe) => Z3_probe, + args: [Probe | Z3_probe, ...(Probe | Z3_probe)[]], + ) { + assert(args.length > 0, 'At least one argument expected'); + let r = this._toProbe(args[0]); + for (let i = 1; i < args.length; i++) { + r = new ProbeImpl(this, f(this.ptr, r.ptr, this._toProbe(args[i]).ptr)); + } + return r; + } + } + + class AstImpl implements Ast { + declare readonly __typename: Ast['__typename']; + + constructor(readonly ctx: ContextImpl, readonly ptr: Ptr) { + const myAst = this.ast; + + Z3.inc_ref(ctx.ptr, myAst); + cleanup.register(this, () => Z3.dec_ref(ctx.ptr, myAst)); + } + + get ast(): Z3_ast { + return this.ptr as any as Z3_ast; + } + + get id() { + return Z3.get_ast_id(this.ctx.ptr, this.ast); + } + + eqIdentity(other: Ast) { + this.ctx._assertContext(other); + return Z3.is_eq_ast(this.ctx.ptr, this.ast, other.ast); + } + + neqIdentity(other: Ast) { + this.ctx._assertContext(other); + return !this.eqIdentity(other); + } + + sexpr() { + return Z3.ast_to_string(this.ctx.ptr, this.ast); + } + + hash() { + return Z3.get_ast_hash(this.ctx.ptr, this.ast); + } + } + + class SolverImpl implements Solver { + declare readonly __typename: Solver['__typename']; + + readonly ptr: Z3_solver; + + constructor(readonly ctx: ContextImpl, ptr: Z3_solver | string = Z3.mk_solver(ctx.ptr)) { + let myPtr: Z3_solver; + if (typeof ptr === 'string') { + myPtr = Z3.mk_solver_for_logic(ctx.ptr, ctx._toSymbol(ptr)); + } else { + myPtr = ptr; + } + this.ptr = myPtr; + Z3.solver_inc_ref(ctx.ptr, myPtr); + cleanup.register(this, () => Z3.solver_dec_ref(ctx.ptr, myPtr)); + } + + push() { + Z3.solver_push(this.ctx.ptr, this.ptr); + } + pop(num: number = 1) { + Z3.solver_pop(this.ctx.ptr, this.ptr, num); + } + numScopes() { + return Z3.solver_get_num_scopes(this.ctx.ptr, this.ptr); + } + reset() { + Z3.solver_reset(this.ctx.ptr, this.ptr); + } + add(...exprs: (Bool | AstVector)[]) { + this.ctx._flattenArgs(exprs).forEach(expr => { + this.ctx._assertContext(expr); + Z3.solver_assert(this.ctx.ptr, this.ptr, expr.ast); + }); + } + addAndTrack(expr: Bool, constant: Bool | string) { + if (typeof constant === 'string') { + constant = this.ctx.Bool.const(constant); + } + assert(this.ctx.isConst(constant), 'Provided expression that is not a constant to addAndTrack'); + Z3.solver_assert_and_track(this.ctx.ptr, this.ptr, expr.ast, constant.ast); + } + + assertions(): AstVector { + return new AstVectorImpl(this.ctx, Z3.solver_get_assertions(this.ctx.ptr, this.ptr)); + } + + async check(...exprs: (Bool | AstVector)[]): Promise { + const assumptions = this.ctx._flattenArgs(exprs).map(expr => { + this.ctx._assertContext(expr); + return expr.ast; + }); + const result = await asyncMutex.runExclusive(() => + Z3.solver_check_assumptions(this.ctx.ptr, this.ptr, assumptions), + ); + switch (result) { + case Z3_lbool.Z3_L_FALSE: + return unsat; + case Z3_lbool.Z3_L_TRUE: + return sat; + case Z3_lbool.Z3_L_UNDEF: + return unknown; + default: + assertExhaustive(result); + } + } + + model() { + return new this.ctx.Model(Z3.solver_get_model(this.ctx.ptr, this.ptr)); + } + } + + class ModelImpl implements Model { + declare readonly __typename: Model['__typename']; + + constructor(readonly ctx: ContextImpl, readonly ptr: Z3_model = Z3.mk_model(ctx.ptr)) { + Z3.model_inc_ref(ctx.ptr, ptr); + cleanup.register(this, () => Z3.model_dec_ref(ctx.ptr, ptr)); + } + + get length() { + return Z3.model_get_num_consts(this.ctx.ptr, this.ptr) + Z3.model_get_num_funcs(this.ctx.ptr, this.ptr); + } + + [Symbol.iterator](): Iterator { + return this.values(); + } + + *entries(): IterableIterator<[number, FuncDecl]> { + const length = this.length; + for (let i = 0; i < length; i++) { + yield [i, this.get(i)]; + } + } + + *keys(): IterableIterator { + for (const [key] of this.entries()) { + yield key; + } + } + + *values(): IterableIterator { + for (const [, value] of this.entries()) { + yield value; + } + } + + decls() { + return [...this.values()]; + } + + sexpr() { + return Z3.model_to_string(this.ctx.ptr, this.ptr); + } + + eval(expr: Bool, modelCompletion?: boolean): Bool; + eval(expr: Arith, modelCompletion?: boolean): Arith; + eval(expr: Expr, modelCompletion: boolean = false) { + this.ctx._assertContext(expr); + const r = Z3.model_eval(this.ctx.ptr, this.ptr, expr.ast, modelCompletion); + if (r === null) { + throw new Z3Error('Failed to evaluatio expression in the model'); + } + return this.ctx._toExpr(r); + } + + get(i: number): FuncDecl; + get(from: number, to: number): FuncDecl[]; + get(declaration: FuncDecl): FuncInterp | Expr; + get(constant: Expr): Expr; + get(sort: Sort): AstVector; + get( + i: number | FuncDecl | Expr | Sort, + to?: number, + ): FuncDecl | FuncInterp | Expr | AstVector | FuncDecl[] { + assert(to === undefined || typeof i === 'number'); + if (typeof i === 'number') { + const length = this.length; + + if (i >= length) { + throw new RangeError(); + } + + if (to === undefined) { + const numConsts = Z3.model_get_num_consts(this.ctx.ptr, this.ptr); + if (i < numConsts) { + return new FuncDeclImpl(this.ctx, Z3.model_get_const_decl(this.ctx.ptr, this.ptr, i)); + } else { + return new FuncDeclImpl(this.ctx, Z3.model_get_func_decl(this.ctx.ptr, this.ptr, i - numConsts)); + } + } + + if (to < 0) { + to += length; + } + if (to >= length) { + throw new RangeError(); + } + const result = []; + for (let j = i; j < to; j++) { + result.push(this.get(j)); + } + return result; + } else if (this.ctx.isFuncDecl(i) || (this.ctx.isExpr(i) && this.ctx.isConst(i))) { + const result = this.getInterp(i); + assert(result !== null); + return result; + } else if (this.ctx.isSort(i)) { + return this.getUniverse(i); + } + assert(false, 'Number, declaration or constant expected'); + } + + private getInterp(expr: FuncDecl | Expr): Expr | FuncInterp | null { + assert(this.ctx.isFuncDecl(expr) || this.ctx.isConst(expr), 'Declaration expected'); + if (this.ctx.isConst(expr)) { + assert(this.ctx.isExpr(expr)); + expr = expr.decl(); + } + assert(this.ctx.isFuncDecl(expr)); + if (expr.arity() === 0) { + const result = Z3.model_get_const_interp(this.ctx.ptr, this.ptr, expr.ptr); + if (result === null) { + return null; + } + return this.ctx._toExpr(result); + } else { + const interp = Z3.model_get_func_interp(this.ctx.ptr, this.ptr, expr.ptr); + if (interp === null) { + return null; + } + return new FuncInterpImpl(this.ctx, interp); + } + } + + private getUniverse(sort: Sort): AstVector { + this.ctx._assertContext(sort); + return new AstVectorImpl(this.ctx, Z3.model_get_sort_universe(this.ctx.ptr, this.ptr, sort.ptr)); + } + } + + class FuncInterpImpl implements FuncInterp { + declare readonly __typename: FuncInterp['__typename']; + + constructor(readonly ctx: Context, readonly ptr: Z3_func_interp) { + Z3.func_interp_inc_ref(ctx.ptr, ptr); + cleanup.register(this, () => Z3.func_interp_dec_ref(ctx.ptr, ptr)); + } + } + + class SortImpl extends AstImpl implements Sort { + declare readonly __typename: Sort['__typename']; + + get ast(): Z3_ast { + return Z3.sort_to_ast(this.ctx.ptr, this.ptr); + } + + kind() { + return Z3.get_sort_kind(this.ctx.ptr, this.ptr); + } + + subsort(other: Sort) { + this.ctx._assertContext(other); + return false; + } + + cast(expr: Expr): Expr { + this.ctx._assertContext(expr); + assert(expr.sort.eqIdentity(expr.sort), 'Sort mismatch'); + return expr; + } + + name() { + return this.ctx._fromSymbol(Z3.get_sort_name(this.ctx.ptr, this.ptr)); + } + + eqIdentity(other: Sort) { + this.ctx._assertContext(other); + return Z3.is_eq_sort(this.ctx.ptr, this.ptr, other.ptr); + } + + neqIdentity(other: Sort) { + return !this.eqIdentity(other); + } + } + + class FuncDeclImpl extends AstImpl implements FuncDecl { + declare readonly __typename: FuncDecl['__typename']; + + get ast() { + return Z3.func_decl_to_ast(this.ctx.ptr, this.ptr); + } + + name() { + return this.ctx._fromSymbol(Z3.get_decl_name(this.ctx.ptr, this.ptr)); + } + + arity() { + return Z3.get_arity(this.ctx.ptr, this.ptr); + } + + domain(i: number) { + assert(i < this.arity(), 'Index out of bounds'); + return this.ctx._toSort(Z3.get_domain(this.ctx.ptr, this.ptr, i)); + } + + range() { + return this.ctx._toSort(Z3.get_range(this.ctx.ptr, this.ptr)); + } + + kind() { + return Z3.get_decl_kind(this.ctx.ptr, this.ptr); + } + + params(): (number | string | Z3_symbol | Sort | Expr | FuncDecl)[] { + const n = Z3.get_decl_num_parameters(this.ctx.ptr, this.ptr); + const result = []; + for (let i = 0; i < n; i++) { + const kind = Z3.get_decl_parameter_kind(this.ctx.ptr, this.ptr, i); + switch (kind) { + case Z3_parameter_kind.Z3_PARAMETER_INT: + result.push(Z3.get_decl_int_parameter(this.ctx.ptr, this.ptr, i)); + break; + case Z3_parameter_kind.Z3_PARAMETER_DOUBLE: + result.push(Z3.get_decl_double_parameter(this.ctx.ptr, this.ptr, i)); + break; + case Z3_parameter_kind.Z3_PARAMETER_RATIONAL: + result.push(Z3.get_decl_rational_parameter(this.ctx.ptr, this.ptr, i)); + break; + case Z3_parameter_kind.Z3_PARAMETER_SYMBOL: + result.push(Z3.get_decl_symbol_parameter(this.ctx.ptr, this.ptr, i)); + break; + case Z3_parameter_kind.Z3_PARAMETER_SORT: + result.push(new SortImpl(this.ctx, Z3.get_decl_sort_parameter(this.ctx.ptr, this.ptr, i))); + break; + case Z3_parameter_kind.Z3_PARAMETER_AST: + result.push(new ExprImpl(this.ctx, Z3.get_decl_ast_parameter(this.ctx.ptr, this.ptr, i))); + break; + case Z3_parameter_kind.Z3_PARAMETER_FUNC_DECL: + result.push(new FuncDeclImpl(this.ctx, Z3.get_decl_func_decl_parameter(this.ctx.ptr, this.ptr, i))); + break; + default: + assertExhaustive(kind); + } + } + return result; + } + + call(...args: CoercibleToExpr[]) { + assert(args.length === this.arity(), `Incorrect number of arguments to ${this}`); + return this.ctx._toExpr( + Z3.mk_app( + this.ctx.ptr, + this.ptr, + args.map((arg, i) => { + return this.domain(i).cast(arg).ast; + }), + ), + ); + } + } + + class ExprImpl extends AstImpl implements Expr { + declare readonly __typename: Expr['__typename']; + + get sort(): S { + return this.ctx._toSort(Z3.get_sort(this.ctx.ptr, this.ast)) as S; + } + + eq(other: CoercibleToExpr): Bool { + return new BoolImpl(this.ctx, Z3.mk_eq(this.ctx.ptr, this.ast, this.ctx.from(other).ast)); + } + + neq(other: CoercibleToExpr): Bool { + return new BoolImpl( + this.ctx, + Z3.mk_distinct( + this.ctx.ptr, + [this, other].map(expr => this.ctx.from(expr).ast), + ), + ); + } + + params() { + return this.decl().params(); + } + + decl(): FuncDecl { + assert(this.ctx.isApp(this), 'Z3 application expected'); + return new FuncDeclImpl(this.ctx, Z3.get_app_decl(this.ctx.ptr, Z3.to_app(this.ctx.ptr, this.ast))); + } + + numArgs(): number { + assert(this.ctx.isApp(this), 'Z3 applicaiton expected'); + return Z3.get_app_num_args(this.ctx.ptr, Z3.to_app(this.ctx.ptr, this.ast)); + } + + arg(i: number): ReturnType { + assert(this.ctx.isApp(this), 'Z3 applicaiton expected'); + assert(i < this.numArgs(), 'Invalid argument index'); + return this.ctx._toExpr(Z3.get_app_arg(this.ctx.ptr, Z3.to_app(this.ctx.ptr, this.ast), i)); + } + + children(): ReturnType[] { + const num_args = this.numArgs(); + if (this.ctx.isApp(this)) { + const result = []; + for (let i = 0; i < num_args; i++) { + result.push(this.arg(i)); + } + return result; + } + return []; + } + } + + class BoolSortImpl extends SortImpl implements BoolSort { + declare readonly __typename: BoolSort['__typename']; + + cast(other: Bool | boolean): Bool; + cast(other: CoercibleToExpr): never; + cast(other: CoercibleToExpr | Bool) { + if (typeof other === 'boolean') { + other = this.ctx.Bool.val(other); + } + assert(this.ctx.isExpr(other), 'true, false or Z3 Boolean expression expected.'); + assert(this.eqIdentity(other.sort), 'Value cannot be converted into a Z3 Boolean value'); + return other; + } + + subsort(other: Sort) { + this.ctx._assertContext(other.ctx); + return other instanceof ArithSortImpl; + } + } + + class BoolImpl extends ExprImpl implements Bool { + declare readonly __typename: Bool['__typename']; + + not(): Bool { + return this.ctx.Not(this); + } + and(other: Bool | boolean): Bool { + return this.ctx.And(this, other); + } + or(other: Bool | boolean): Bool { + return this.ctx.Or(this, other); + } + xor(other: Bool | boolean): Bool { + return this.ctx.Xor(this, other); + } + } + + class ProbeImpl implements Probe { + declare readonly __typename: Probe['__typename']; + + constructor(readonly ctx: ContextImpl, readonly ptr: Z3_probe) {} + } + + class TacticImpl implements Tactic { + declare readonly __typename: Tactic['__typename']; + + readonly ptr: Z3_tactic; + + constructor(readonly ctx: ContextImpl, tactic: string | Z3_tactic) { + let myPtr: Z3_tactic; + if (typeof tactic === 'string') { + myPtr = Z3.mk_tactic(ctx.ptr, tactic); + } else { + myPtr = tactic; + } + + this.ptr = myPtr; + + Z3.tactic_inc_ref(ctx.ptr, myPtr); + cleanup.register(this, () => Z3.tactic_dec_ref(ctx.ptr, myPtr)); + } + } + + class ArithSortImpl extends SortImpl implements ArithSort { + declare readonly __typename: ArithSort['__typename']; + + cast(other: bigint | number): IntNum | RatNum; + cast(other: CoercibleRational | RatNum): RatNum; + cast(other: IntNum): IntNum; + cast(other: Bool | Arith): Arith; + cast(other: CoercibleToExpr): never; + cast(other: CoercibleToExpr): Arith | RatNum | IntNum { + const { If, isExpr, isArith, isBool, isIntSort, isRealSort, ToReal, Int, Real } = this.ctx; + const sortTypeStr = isIntSort(this) ? 'IntSort' : 'RealSort'; + if (isExpr(other)) { + const otherS = other.sort; + if (isArith(other)) { + if (this.eqIdentity(otherS)) { + return other; + } else if (isIntSort(otherS) && isRealSort(this)) { + return this.ctx.ToReal(other); + } + assert(false, "Can't cast Real to IntSort without loss"); + } else if (isBool(other)) { + if (isIntSort(this)) { + return If(other, 1, 0); + } else { + return ToReal(If(other, 1, 0)); + } + } + assert(false, `Can't cast expression to ${sortTypeStr}`); + } else { + if (typeof other !== 'boolean') { + if (isIntSort(this)) { + assert(!isCoercibleRational(other), "Can't cast fraction to IntSort"); + return Int.val(other); + } + return Real.val(other); + } + assert(false, `Can't cast primitive to ${sortTypeStr}`); + } + } + } + + class ArithImpl extends ExprImpl implements Arith { + declare readonly __typename: Arith['__typename']; + + add(other: Arith | number | bigint | string | CoercibleRational) { + return new ArithImpl(this.ctx, Z3.mk_add(this.ctx.ptr, [this.ast, this.sort.cast(other).ast])); + } + + mul(other: Arith | number | bigint | string | CoercibleRational) { + return new ArithImpl(this.ctx, Z3.mk_mul(this.ctx.ptr, [this.ast, this.sort.cast(other).ast])); + } + + sub(other: Arith | number | bigint | string | CoercibleRational) { + return new ArithImpl(this.ctx, Z3.mk_sub(this.ctx.ptr, [this.ast, this.sort.cast(other).ast])); + } + + pow(exponent: Arith | number | bigint | string | CoercibleRational) { + return new ArithImpl(this.ctx, Z3.mk_power(this.ctx.ptr, this.ast, this.sort.cast(exponent).ast)); + } + + div(other: Arith | number | bigint | string | CoercibleRational) { + return new ArithImpl(this.ctx, Z3.mk_div(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + + mod(other: Arith | number | bigint | string | CoercibleRational) { + return new ArithImpl(this.ctx, Z3.mk_mod(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + + neg() { + return new ArithImpl(this.ctx, Z3.mk_unary_minus(this.ctx.ptr, this.ast)); + } + + le(other: Arith | number | bigint | string | CoercibleRational) { + return new BoolImpl(this.ctx, Z3.mk_le(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + + lt(other: Arith | number | bigint | string | CoercibleRational) { + return new BoolImpl(this.ctx, Z3.mk_lt(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + + gt(other: Arith | number | bigint | string | CoercibleRational) { + return new BoolImpl(this.ctx, Z3.mk_gt(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + + ge(other: Arith | number | bigint | string | CoercibleRational) { + return new BoolImpl(this.ctx, Z3.mk_ge(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + } + + class IntNumImpl extends ArithImpl implements IntNum { + declare readonly __typename: IntNum['__typename']; + + get value() { + return BigInt(this.asString()); + } + + asString() { + return Z3.get_numeral_string(this.ctx.ptr, this.ast); + } + + asBinary() { + return Z3.get_numeral_binary_string(this.ctx.ptr, this.ast); + } + } + + class RatNumImpl extends ArithImpl implements RatNum { + declare readonly __typename: RatNum['__typename']; + + get value() { + return { numerator: this.numerator().value, denominator: this.denominator().value }; + } + + numerator() { + return new IntNumImpl(this.ctx, Z3.get_numerator(this.ctx.ptr, this.ast)); + } + + denominator() { + return new IntNumImpl(this.ctx, Z3.get_denominator(this.ctx.ptr, this.ast)); + } + + asNumber() { + const { numerator, denominator } = this.value; + const div = numerator / denominator; + return Number(div) + Number(numerator - div * denominator) / Number(denominator); + } + + asDecimal(prec: number = Number.parseInt(getParam('precision') ?? FALLBACK_PRECISION.toString())) { + return Z3.get_numeral_decimal_string(this.ctx.ptr, this.ast, prec); + } + + asString() { + return Z3.get_numeral_string(this.ctx.ptr, this.ast); + } + } + + class BitVecSortImpl extends SortImpl implements BitVecSort { + declare readonly __typename: BitVecSort['__typename']; + + get size() { + return Z3.get_bv_sort_size(this.ctx.ptr, this.ptr); + } + + subsort(other: Sort): boolean { + return this.ctx.isBitVecSort(other) && this.size < other.size; + } + + cast(other: CoercibleToBitVec): BitVec; + cast(other: CoercibleToExpr): Expr; + cast(other: CoercibleToExpr): Expr { + if (this.ctx.isExpr(other)) { + this.ctx._assertContext(other); + return other; + } + assert(!isCoercibleRational(other), "Can't convert rational to BitVec"); + return this.ctx.BitVec.val(other, this.size); + } + } + + class BitVecImpl extends ExprImpl implements BitVec { + declare readonly __typename: BitVec['__typename']; + + get size() { + return this.sort.size; + } + + add(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvadd(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + mul(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvmul(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + sub(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvsub(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + sdiv(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvsdiv(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + udiv(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvudiv(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + smod(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvsmod(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + urem(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvurem(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + srem(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvsrem(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + neg(): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvneg(this.ctx.ptr, this.ast)); + } + + or(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvor(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + and(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvand(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + nand(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvnand(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + xor(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvxor(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + xnor(other: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvxnor(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + shr(count: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvashr(this.ctx.ptr, this.ast, this.sort.cast(count).ast)); + } + lshr(count: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvlshr(this.ctx.ptr, this.ast, this.sort.cast(count).ast)); + } + shl(count: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvshl(this.ctx.ptr, this.ast, this.sort.cast(count).ast)); + } + rotateRight(count: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_ext_rotate_right(this.ctx.ptr, this.ast, this.sort.cast(count).ast)); + } + rotateLeft(count: CoercibleToBitVec): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_ext_rotate_left(this.ctx.ptr, this.ast, this.sort.cast(count).ast)); + } + not(): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvnot(this.ctx.ptr, this.ast)); + } + + extract(high: number, low: number): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_extract(this.ctx.ptr, high, low, this.ast)); + } + signExt(count: number): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_sign_ext(this.ctx.ptr, count, this.ast)); + } + zeroExt(count: number): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_zero_ext(this.ctx.ptr, count, this.ast)); + } + repeat(count: number): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_repeat(this.ctx.ptr, count, this.ast)); + } + + sle(other: CoercibleToBitVec): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvsle(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + ule(other: CoercibleToBitVec): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvule(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + slt(other: CoercibleToBitVec): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvslt(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + ult(other: CoercibleToBitVec): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvult(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + sge(other: CoercibleToBitVec): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvsge(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + uge(other: CoercibleToBitVec): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvuge(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + sgt(other: CoercibleToBitVec): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvsgt(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + ugt(other: CoercibleToBitVec): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvugt(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + + redAnd(): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvredand(this.ctx.ptr, this.ast)); + } + redOr(): BitVec { + return new BitVecImpl(this.ctx, Z3.mk_bvredor(this.ctx.ptr, this.ast)); + } + + addNoOverflow(other: CoercibleToBitVec, isSigned: boolean): Bool { + return new BoolImpl( + this.ctx, + Z3.mk_bvadd_no_overflow(this.ctx.ptr, this.ast, this.sort.cast(other).ast, isSigned), + ); + } + addNoUnderflow(other: CoercibleToBitVec): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvadd_no_underflow(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + subNoOverflow(other: CoercibleToBitVec): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvsub_no_overflow(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + subNoUndeflow(other: CoercibleToBitVec, isSigned: boolean): Bool { + return new BoolImpl( + this.ctx, + Z3.mk_bvsub_no_underflow(this.ctx.ptr, this.ast, this.sort.cast(other).ast, isSigned), + ); + } + sdivNoOverflow(other: CoercibleToBitVec): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvsdiv_no_overflow(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + mulNoOverflow(other: CoercibleToBitVec, isSigned: boolean): Bool { + return new BoolImpl( + this.ctx, + Z3.mk_bvmul_no_overflow(this.ctx.ptr, this.ast, this.sort.cast(other).ast, isSigned), + ); + } + mulNoUndeflow(other: CoercibleToBitVec): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvmul_no_underflow(this.ctx.ptr, this.ast, this.sort.cast(other).ast)); + } + negNoOverflow(): Bool { + return new BoolImpl(this.ctx, Z3.mk_bvneg_no_overflow(this.ctx.ptr, this.ast)); + } + } + + class BitVecNumImpl extends BitVecImpl implements BitVecNum { + declare readonly __typename: BitVecNum['__typename']; + get value() { + return BigInt(this.asString()); + } + + asSignedValue() { + let val = this.value; + const size = BigInt(this.size); + if (val >= 2n ** (size - 1n)) { + val = val - 2n ** size; + } + if (val < (-2n) ** (size - 1n)) { + val = val + 2n ** size; + } + return val; + } + asString() { + return Z3.get_numeral_string(this.ctx.ptr, this.ast); + } + asBinaryString() { + return Z3.get_numeral_binary_string(this.ctx.ptr, this.ast); + } + } + + class AstVectorImpl { + declare readonly __typename: AstVector['__typename']; + + constructor(readonly ctx: ContextImpl, readonly ptr: Z3_ast_vector = Z3.mk_ast_vector(ctx.ptr)) { + Z3.ast_vector_inc_ref(ctx.ptr, ptr); + cleanup.register(this, () => Z3.ast_vector_dec_ref(ctx.ptr, ptr)); + } + + get length(): number { + return Z3.ast_vector_size(this.ctx.ptr, this.ptr); + } + + [Symbol.iterator](): IterableIterator { + return this.values(); + } + + *entries(): IterableIterator<[number, Item]> { + const length = this.length; + for (let i = 0; i < length; i++) { + yield [i, this.get(i)]; + } + } + + *keys(): IterableIterator { + for (let [key] of this.entries()) { + yield key; + } + } + + *values(): IterableIterator { + for (let [, value] of this.entries()) { + yield value; + } + } + + get(i: number): Item; + get(from: number, to: number): Item[]; + get(from: number, to?: number): Item | Item[] { + const length = this.length; + if (from < 0) { + from += length; + } + if (from >= length) { + throw new RangeError(); + } + + if (to === undefined) { + return this.ctx._toAst(Z3.ast_vector_get(this.ctx.ptr, this.ptr, from)) as Item; + } + + if (to < 0) { + to += length; + } + if (to >= length) { + throw new RangeError(); + } + + const result: Item[] = []; + for (let i = from; i < to; i++) { + result.push(this.ctx._toAst(Z3.ast_vector_get(this.ctx.ptr, this.ptr, i)) as Item); + } + return result; + } + + set(i: number, v: Item): void { + this.ctx._assertContext(v); + if (i >= this.length) { + throw new RangeError(); + } + Z3.ast_vector_set(this.ctx.ptr, this.ptr, i, v.ast); + } + + push(v: Item): void { + this.ctx._assertContext(v); + Z3.ast_vector_push(this.ctx.ptr, this.ptr, v.ast); + } + + resize(size: number): void { + Z3.ast_vector_resize(this.ctx.ptr, this.ptr, size); + } + + has(v: Item): boolean { + this.ctx._assertContext(v); + for (const item of this.values()) { + if (item.eqIdentity(v)) { + return true; + } + } + return false; + } + + sexpr(): string { + return Z3.ast_vector_to_string(this.ctx.ptr, this.ptr); + } + } + + class AstMapImpl implements AstMap { + declare readonly __typename: AstMap['__typename']; + + constructor(readonly ctx: ContextImpl, readonly ptr: Z3_ast_map = Z3.mk_ast_map(ctx.ptr)) { + Z3.ast_map_inc_ref(ctx.ptr, ptr); + cleanup.register(this, () => Z3.ast_map_dec_ref(ctx.ptr, ptr)); + } + + [Symbol.iterator](): Iterator<[Key, Value]> { + return this.entries(); + } + + get size(): number { + return Z3.ast_map_size(this.ctx.ptr, this.ptr); + } + + *entries(): IterableIterator<[Key, Value]> { + for (const key of this.keys()) { + yield [key, this.get(key)]; + } + } + + keys(): AstVector { + return new AstVectorImpl(this.ctx, Z3.ast_map_keys(this.ctx.ptr, this.ptr)); + } + + *values(): IterableIterator { + for (const [_, value] of this.entries()) { + yield value; + } + } + get(key: Key): Value { + return this.ctx._toAst(Z3.ast_map_find(this.ctx.ptr, this.ptr, key.ast)) as Value; + } + + set(key: Key, value: Value): void { + Z3.ast_map_insert(this.ctx.ptr, this.ptr, key.ast, value.ast); + } + + delete(key: Key): void { + Z3.ast_map_erase(this.ctx.ptr, this.ptr, key.ast); + } + + clear(): void { + Z3.ast_map_reset(this.ctx.ptr, this.ptr); + } + + has(key: Key): boolean { + return Z3.ast_map_contains(this.ctx.ptr, this.ptr, key.ast); + } + + sexpr(): string { + return Z3.ast_map_to_string(this.ctx.ptr, this.ptr); + } + } + + return { + enableTrace, + disableTrace, + getVersion, + getVersionString, + getFullVersion, + openLog, + appendLog, + getParam, + setParam, + resetParams, + isContext, + + Context: ContextImpl as ContextCtor, + }; +} diff --git a/src/api/js/src/high-level/index.ts b/src/api/js/src/high-level/index.ts new file mode 100644 index 000000000..cda96efee --- /dev/null +++ b/src/api/js/src/high-level/index.ts @@ -0,0 +1,2 @@ +export * from './high-level'; +export * from './types'; diff --git a/src/api/js/src/high-level/types.ts b/src/api/js/src/high-level/types.ts new file mode 100644 index 000000000..a056ef686 --- /dev/null +++ b/src/api/js/src/high-level/types.ts @@ -0,0 +1,1132 @@ +import { + Z3_ast, + Z3_ast_map, + Z3_ast_vector, + Z3_context, + Z3_decl_kind, + Z3_func_decl, + Z3_func_interp, + Z3_model, + Z3_probe, + Z3_solver, + Z3_sort, + Z3_sort_kind, + Z3_symbol, + Z3_tactic, +} from '../low-level'; + +/** @hidden */ +export type AnySort = + | Sort + | BoolSort + | ArithSort + | BitVecSort; +/** @hidden */ +export type AnyExpr = + | Expr + | Bool + | Arith + | IntNum + | RatNum + | BitVec + | BitVecNum; +/** @hidden */ +export type AnyAst = AnyExpr | AnySort | FuncDecl; + +/** @hidden */ +export type SortToExprMap, Name extends string = any> = S extends BoolSort + ? Bool + : S extends ArithSort + ? Arith + : S extends BitVecSort + ? BitVec + : S extends Sort + ? Expr + : never; + +/** @hidden */ +export type CoercibleToExprMap, Name extends string = any> = S extends bigint + ? IntNum + : S extends number | CoercibleRational + ? RatNum + : S extends boolean + ? Bool + : S extends Expr + ? S + : never; + +/** + * Used to create a Real constant + * + * ```typescript + * const x = from({ numerator: 1, denominator: 3 }) + * + * x + * // 1/3 + * isReal(x) + * // true + * isRealVal(x) + * // true + * x.asNumber() + * // 0.3333333333333333 + * ``` + * @see {@link Context.from} + * @category Global + */ +export type CoercibleRational = { numerator: bigint | number; denominator: bigint | number }; + +/** @hidden */ +export type CoercibleToExpr = number | bigint | boolean | CoercibleRational | Expr; + +export class Z3Error extends Error {} +export class Z3AssertionError extends Z3Error {} + +/** + * Returned by {@link Solver.check} when Z3 could find a solution + * @category Global + */ +export const sat = Symbol('Solver found a solution'); +/** + * Returned by {@link Solver.check} when Z3 couldn't find a solution + * @category Global + */ +export const unsat = Symbol("Solver didn't find a solution"); +/** + * Returned by {@link Solver.check} when Z3 couldn't reason about the assumptions + * @category Global + */ +export const unknown = Symbol("Solver couldn't reason about the assumptions"); +/** @category Global */ +export type CheckSatResult = typeof sat | typeof unsat | typeof unknown; + +/** @hidden */ +export interface ContextCtor { + new (name: Name, options?: Record): Context; +} + +export interface Context { + /** @hidden */ + readonly __typename: 'Context'; + + /** @hidden */ + readonly ptr: Z3_context; + /** + * Name of the current Context + * + * ```typescript + * const c = new Context('main') + * + * c.name + * // 'main' + * ``` + */ + readonly name: Name; + + /////////////// + // Functions // + /////////////// + /** @category Functions */ + interrupt(): void; + /** @category Functions */ + isModel(obj: unknown): obj is Model; + /** @category Functions */ + isAst(obj: unknown): obj is Ast; + /** @category Functions */ + isSort(obj: unknown): obj is Sort; + /** @category Functions */ + isFuncDecl(obj: unknown): obj is FuncDecl; + /** @category Functions */ + isApp(obj: unknown): boolean; + /** @category Functions */ + isConst(obj: unknown): boolean; + /** @category Functions */ + isExpr(obj: unknown): obj is Expr; + /** @category Functions */ + isVar(obj: unknown): boolean; + /** @category Functions */ + isAppOf(obj: unknown, kind: Z3_decl_kind): boolean; + /** @category Functions */ + isBool(obj: unknown): obj is Bool; + /** @category Functions */ + isTrue(obj: unknown): boolean; + /** @category Functions */ + isFalse(obj: unknown): boolean; + /** @category Functions */ + isAnd(obj: unknown): boolean; + /** @category Functions */ + isOr(obj: unknown): boolean; + /** @category Functions */ + isImplies(obj: unknown): boolean; + /** @category Functions */ + isNot(obj: unknown): boolean; + /** @category Functions */ + isEq(obj: unknown): boolean; + /** @category Functions */ + isDistinct(obj: unknown): boolean; + /** @category Functions */ + isArith(obj: unknown): obj is Arith; + /** @category Functions */ + isArithSort(obj: unknown): obj is ArithSort; + /** @category Functions */ + isInt(obj: unknown): boolean; + /** @category Functions */ + isIntVal(obj: unknown): obj is IntNum; + /** @category Functions */ + isIntSort(obj: unknown): boolean; + /** @category Functions */ + isReal(obj: unknown): boolean; + /** @category Functions */ + isRealVal(obj: unknown): obj is RatNum; + /** @category Functions */ + isRealSort(obj: unknown): boolean; + /** @category Functions */ + isBitVecSort(obj: unknown): obj is BitVecSort; + /** @category Functions */ + isBitVec(obj: unknown): obj is BitVec; + /** @category Functions */ + isBitVecVal(obj: unknown): obj is BitVecNum; + /** @category Functions */ + isProbe(obj: unknown): obj is Probe; + /** @category Functions */ + isTactic(obj: unknown): obj is Tactic; + /** @category Functions */ + isAstVector(obj: unknown): obj is AstVector, Name>; + /** + * Returns whether two Asts are the same thing + * @category Functions */ + eqIdentity(a: Ast, b: Ast): boolean; + /** @category Functions */ + getVarIndex(obj: Expr): number; + /** + * Coerce a boolean into a Bool expression + * @category Functions */ + from(primitive: boolean): Bool; + /** + * Coerce a number or rational into a Real expression + * @category Functions */ + from(primitive: number | CoercibleRational): RatNum; + /** + * Coerce a big number into a Integer expression + * @category Functions */ + from(primitive: bigint): IntNum; + /** + * Returns whatever expression was given + * @category Functions */ + from>(expr: E): E; + /** @hidden */ + from(value: CoercibleToExpr): AnyExpr; + /** + * Sugar function for getting a model for given assertions + * + * ```typescript + * const x = Int.const('x'); + * const y = Int.const('y'); + * const result = await solve(x.le(y)); + * if (isModel(result)) { + * console.log('Z3 found a solution'); + * console.log(`x=${result.get(x)}, y=${result.get(y)}`); + * } else { + * console.error('No solution found'); + * } + * ``` + * + * @see {@link Solver} + * @category Functions */ + solve(...assertions: Bool[]): Promise; + + ///////////// + // Classes // + ///////////// + /** + * Creates a Solver + * @param logic - Optional logic which the solver will use. Creates a general Solver otherwise + * @category Classes + */ + readonly Solver: new (logic?: string) => Solver; + /** + * Creates an empty Model + * @see {@link Solver.model} for common usage of Model + * @category Classes + */ + readonly Model: new () => Model; + /** @category Classes */ + readonly AstVector: new = AnyAst>() => AstVector; + /** @category Classes */ + readonly AstMap: new () => AstMap; + /** @category Classes */ + readonly Tactic: new (name: string) => Tactic; + + ///////////// + // Objects // + ///////////// + /** @category Expressions */ + readonly Sort: SortCreation; + /** @category Expressions */ + readonly Function: FuncDeclCreation; + /** @category Expressions */ + readonly RecFunc: RecFuncCreation; + /** @category Expressions */ + readonly Bool: BoolCreation; + /** @category Expressions */ + readonly Int: IntCreation; + /** @category Expressions */ + readonly Real: RealCreation; + /** @category Expressions */ + readonly BitVec: BitVecCreation; + + //////////////// + // Operations // + //////////////// + /** @category Operations */ + Const>(name: string, sort: S): SortToExprMap; + /** @category Operations */ + Consts>(name: string | string[], sort: S): SortToExprMap[]; + /** @category Operations */ + FreshConst>(sort: S, prefix?: string): SortToExprMap; + /** @category Operations */ + Var>(idx: number, sort: S): SortToExprMap; + // Booleans + /** @category Operations */ + If(condition: Probe, onTrue: Tactic, onFalse: Tactic): Tactic; + /** @category Operations */ + If, OnFalseRef extends CoercibleToExpr>( + condition: Bool | boolean, + onTrue: OnTrueRef, + onFalse: OnFalseRef, + ): CoercibleToExprMap; + /** @category Operations */ + Distinct(...args: CoercibleToExpr[]): Bool; + /** @category Operations */ + Implies(a: Bool | boolean, b: Bool | boolean): Bool; + /** @category Operations */ + Eq(a: CoercibleToExpr, b: CoercibleToExpr): Bool; + /** @category Operations */ + Xor(a: Bool | boolean, b: Bool | boolean): Bool; + /** @category Operations */ + Not(a: Probe): Probe; + /** @category Operations */ + Not(a: Bool | boolean): Bool; + /** @category Operations */ + And(): Bool; + /** @category Operations */ + And(vector: AstVector, Name>): Bool; + /** @category Operations */ + And(...args: (Bool | boolean)[]): Bool; + /** @category Operations */ + And(...args: Probe[]): Probe; + /** @category Operations */ + Or(): Bool; + /** @category Operations */ + Or(vector: AstVector, Name>): Bool; + /** @category Operations */ + Or(...args: (Bool | boolean)[]): Bool; + /** @category Operations */ + Or(...args: Probe[]): Probe; + // Arithmetic + /** @category Operations */ + ToReal(expr: Arith | bigint): Arith; + /** @category Operations */ + ToInt(expr: Arith | number | CoercibleRational | string): Arith; + /** + * Create an IsInt Z3 predicate + * + * ```typescript + * const x = Real.const('x'); + * await solve(IsInt(x.add("1/2")), x.gt(0), x.lt(1)) + * // x = 1/2 + * await solve(IsInt(x.add("1/2")), x.gt(0), x.lt(1), x.neq("1/2")) + * // unsat + * ``` + * @category Operations */ + IsInt(expr: Arith | number | CoercibleRational | string): Bool; + /** + * Returns a Z3 expression representing square root of a + * + * ```typescript + * const a = Real.const('a'); + * + * Sqrt(a); + * // a**(1/2) + * ``` + * @category Operations */ + Sqrt(a: Arith | number | bigint | string | CoercibleRational): Arith; + /** + * Returns a Z3 expression representing cubic root of a + * + * ```typescript + * const a = Real.const('a'); + * + * Cbrt(a); + * // a**(1/3) + * ``` + * @category Operations */ + Cbrt(a: Arith | number | bigint | string | CoercibleRational): Arith; + // Bit Vectors + /** @category Operations */ + BV2Int(a: BitVec, isSigned: boolean): Arith; + /** @category Operations */ + Int2BV(a: Arith | bigint | number, bits: Bits): BitVec; + /** @category Operations */ + Concat(...bitvecs: BitVec[]): BitVec; +} + +export interface Ast { + /** @hidden */ + readonly __typename: 'Ast' | Sort['__typename'] | FuncDecl['__typename'] | Expr['__typename']; + + readonly ctx: Context; + /** @hidden */ + readonly ptr: Ptr; + /** @virtual */ + get ast(): Z3_ast; + /** @virtual */ + get id(): number; + + eqIdentity(other: Ast): boolean; + neqIdentity(other: Ast): boolean; + sexpr(): string; + hash(): number; +} + +/** @hidden */ +export interface SolverCtor { + new (): Solver; +} +export interface Solver { + /** @hidden */ + readonly __typename: 'Solver'; + + readonly ctx: Context; + readonly ptr: Z3_solver; + + /* TODO(ritave): Decide on how to discern between integer and float parameters + set(key: string, value: any): void; + set(params: Record): void; + */ + push(): void; + pop(num?: number): void; + numScopes(): number; + reset(): void; + add(...exprs: (Bool | AstVector, Name>)[]): void; + addAndTrack(expr: Bool, constant: Bool | string): void; + assertions(): AstVector, Name>; + check(...exprs: (Bool | AstVector, Name>)[]): Promise; + model(): Model; +} + +/** @hidden */ +export interface ModelCtor { + new (): Model; +} +export interface Model extends Iterable> { + /** @hidden */ + readonly __typename: 'Model'; + + readonly ctx: Context; + readonly ptr: Z3_model; + + get length(): number; + + entries(): IterableIterator<[number, FuncDecl]>; + keys(): IterableIterator; + values(): IterableIterator>; + decls(): FuncDecl[]; + sexpr(): string; + eval(expr: Bool, modelCompletion?: boolean): Bool; + eval(expr: Arith, modelCompletion?: boolean): Arith; + eval(expr: Expr, modelCompletion?: boolean): Expr; + get(i: number): FuncDecl; + get(from: number, to: number): FuncDecl[]; + get(declaration: FuncDecl): FuncInterp | Expr; + get(constant: Expr): Expr; + get(sort: Sort): AstVector, Name>; +} + +/** + * Part of {@link Context}. Used to declare uninterpreted sorts + * + * ```typescript + * const A = context.Sort.declare('A'); + * const a = context.Const('a', A); + * const b = context.const('b', A); + * + * a.sort.eqIdentity(A) + * // true + * b.sort.eqIdentity(A) + * // true + * a.eq(b) + * // a == b + * ``` + */ +export interface SortCreation { + declare(name: string): Sort; +} +export interface Sort extends Ast { + /** @hidden */ + readonly __typename: 'Sort' | BoolSort['__typename'] | ArithSort['__typename'] | BitVecSort['__typename']; + + kind(): Z3_sort_kind; + /** @virtual */ + subsort(other: Sort): boolean; + /** @virtual */ + cast(expr: CoercibleToExpr): Expr; + name(): string | number; +} + +/** + * @category Functions + */ +export interface FuncInterp { + /** @hidden */ + readonly __typename: 'FuncInterp'; + + readonly ctx: Context; + readonly ptr: Z3_func_interp; +} + +/** @hidden */ +export type FuncDeclSignature = [Sort, Sort, ...Sort[]]; +/** + * Part of {@link Context}. Used to declare functions + * @category Functions + */ +export interface FuncDeclCreation { + /** + * Declare a new function + * + * ```typescript + * const f = ctx.Function.declare('f', ctx.Bool.sort(), ctx.Real.sort(), ctx.Int.sort()) + * + * f.call(true, "1/3").eq(5) + * // f(true, 1/3) == 5 + * ``` + * @param name Name of the function + * @param signature The domains, and last parameter - the range of the function + */ + declare(name: string, ...signature: FuncDeclSignature): FuncDecl; + fresh(...signature: FuncDeclSignature): FuncDecl; +} +/** + * @category Functions + */ +export interface RecFuncCreation { + declare(name: string, ...signature: FuncDeclSignature): FuncDecl; + addDefinition(f: FuncDecl, args: Expr[], body: Expr): void; +} +/** + * @category Functions + */ +export interface FuncDecl extends Ast { + /** @hidden */ + readonly __typename: 'FuncDecl'; + + name(): string | number; + arity(): number; + domain(i: number): Sort; + range(): Sort; + kind(): Z3_decl_kind; + params(): (number | string | Z3_symbol | Sort | Expr | FuncDecl)[]; + call(...args: CoercibleToExpr[]): AnyExpr; +} + +export interface Expr = AnySort, Ptr = unknown> + extends Ast { + /** @hidden */ + readonly __typename: 'Expr' | Bool['__typename'] | Arith['__typename'] | BitVec['__typename']; + + get sort(): S; + + eq(other: CoercibleToExpr): Bool; + neq(other: CoercibleToExpr): Bool; + params(): ReturnType['params']>; + decl(): FuncDecl; + numArgs(): number; + arg(i: number): AnyExpr; + children(): AnyExpr[]; +} + +/** @category Booleans */ +export interface BoolSort extends Sort { + /** @hidden */ + readonly __typename: 'BoolSort'; + + cast(expr: Bool | boolean): Bool; + cast(expr: CoercibleToExpr): never; +} +/** @category Booleans */ +export interface BoolCreation { + sort(): BoolSort; + + const(name: string): Bool; + consts(names: string | string[]): Bool[]; + vector(prefix: string, count: number): Bool[]; + fresh(prefix?: string): Bool; + + val(value: boolean): Bool; +} +/** @category Booleans */ +export interface Bool extends Expr, Z3_ast> { + /** @hidden */ + readonly __typename: 'Bool'; + + not(): Bool; + and(other: Bool | boolean): Bool; + or(other: Bool | boolean): Bool; + xor(other: Bool | boolean): Bool; +} + +/** + * A Sort that represents Integers or Real numbers + * @category Arithmetic + */ +export interface ArithSort extends Sort { + /** @hidden */ + readonly __typename: 'ArithSort'; + + cast(other: bigint | number | string): IntNum | RatNum; + cast(other: CoercibleRational | RatNum): RatNum; + cast(other: IntNum): IntNum; + cast(other: bigint | number | string | Bool | Arith | CoercibleRational): Arith; + cast(other: CoercibleToExpr | string): never; +} +/** @category Arithmetic */ +export interface IntCreation { + sort(): ArithSort; + + const(name: string): Arith; + consts(names: string | string[]): Arith[]; + vector(prefix: string, count: number): Arith[]; + fresh(prefix?: string): Arith; + + val(value: bigint | number | string): IntNum; +} +/** @category Arithmetic */ +export interface RealCreation { + sort(): ArithSort; + + const(name: string): Arith; + consts(names: string | string[]): Arith[]; + vector(prefix: string, count: number): Arith[]; + fresh(prefix?: string): Arith; + + val(value: number | string | bigint | CoercibleRational): RatNum; +} +/** + * Represents Integer or Real number expression + * @category Arithmetic + */ +export interface Arith extends Expr, Z3_ast> { + /** @hidden */ + readonly __typename: 'Arith' | IntNum['__typename'] | RatNum['__typename']; + + /** + * Adds two numbers together + */ + add(other: Arith | number | bigint | string): Arith; + /** + * Multiplies two numbers together + */ + mul(other: Arith | number | bigint | string): Arith; + /** + * Substract second number from the first one + */ + sub(other: Arith | number | bigint | string): Arith; + /** + * Applies power to the number + * + * ```typescript + * const x = Int.const('x'); + * + * await solve(x.pow(2).eq(4), x.lt(0)); // x**2 == 4, x < 0 + * // x=-2 + * ``` + */ + pow(exponent: Arith | number | bigint | string): Arith; + /** + * Divides the number by the second one + */ + div(other: Arith | number | bigint | string): Arith; + /** + * Returns a number modulo second one + * + * ```typescript + * const x = Int.const('x'); + * + * await solve(x.mod(7).eq(1), x.gt(7)) // x % 7 == 1, x > 7 + * // x=8 + * ``` + */ + mod(other: Arith | number | bigint | string): Arith; + /** + * Returns a negation of the number + */ + neg(): Arith; + /** + * Return whether the number is less or equal than the second one (`<=`) + */ + le(other: Arith | number | bigint | string): Bool; + /** + * Returns whether the number is less than the second one (`<`) + */ + lt(other: Arith | number | bigint | string): Bool; + /** + * Returns whether the number is greater than the second one (`>`) + */ + gt(other: Arith | number | bigint | string): Bool; + /** + * Returns whether the number is greater or equal than the second one (`>=`) + */ + ge(other: Arith | number | bigint | string): Bool; +} + +/** + * A constant Integer value expression + * @category Arithmetic + */ +export interface IntNum extends Arith { + /** @hidden */ + readonly __typename: 'IntNum'; + + get value(): bigint; + asString(): string; + asBinary(): string; +} + +/** + * A constant Rational value expression + * + * ```typescript + * const num = Real.val('1/3'); + * + * num.asString() + * // '1/3' + * num.value + * // { numerator: 1n, denominator: 3n } + * num.asNumber() + * // 0.3333333333333333 + * ``` + * @category Arithmetic + */ +export interface RatNum extends Arith { + /** @hidden */ + readonly __typename: 'RatNum'; + + get value(): { numerator: bigint; denominator: bigint }; + numerator(): IntNum; + denominator(): IntNum; + asNumber(): number; + asDecimal(prec?: number): string; + asString(): string; +} + +/** + * A Sort represting Bit Vector numbers of specified {@link BitVecSort.size size} + * + * @typeParam Bits - A number representing amount of bits for this sort + * @category Bit Vectors + */ +export interface BitVecSort extends Sort { + /** @hidden */ + readonly __typename: 'BitVecSort'; + + /** + * The amount of bits inside the sort + * + * ```typescript + * const x = BitVec.const('x', 32); + * + * console.log(x.sort.size) + * // 32 + * ``` + */ + get size(): Bits; + + cast(other: CoercibleToBitVec): BitVec; + cast(other: CoercibleToExpr): Expr; +} + +/** @hidden */ +export type CoercibleToBitVec = + | bigint + | number + | BitVec; +/** @category Bit Vectors */ +export interface BitVecCreation { + sort(bits: Bits): BitVecSort; + + const(name: string, bits: Bits | BitVecSort): BitVec; + consts( + names: string | string[], + bits: Bits | BitVecSort, + ): BitVec[]; + + val( + value: bigint | number | boolean, + bits: Bits | BitVecSort, + ): BitVecNum; +} +/** + * Represents Bit Vector expression + * @category Bit Vectors + */ +export interface BitVec + extends Expr, Z3_ast> { + /** @hidden */ + readonly __typename: 'BitVec' | BitVecNum['__typename']; + + /** + * The amount of bits of this BitVectors sort + * + * ```typescript + * const x = BitVec.const('x', 32); + * + * x.size + * // 32 + * + * const Y = BitVec.sort(8); + * const y = BitVec.const('y', Y); + * + * y.size + * // 8 + * ``` + */ + get size(): Bits; + + /** @category Arithmetic */ + add(other: CoercibleToBitVec): BitVec; + /** @category Arithmetic */ + mul(other: CoercibleToBitVec): BitVec; + /** @category Arithmetic */ + sub(other: CoercibleToBitVec): BitVec; + /** @category Arithmetic */ + sdiv(other: CoercibleToBitVec): BitVec; + /** @category Arithmetic */ + udiv(other: CoercibleToBitVec): BitVec; + /** @category Arithmetic */ + smod(other: CoercibleToBitVec): BitVec; + /** @category Arithmetic */ + urem(other: CoercibleToBitVec): BitVec; + /** @category Arithmetic */ + srem(other: CoercibleToBitVec): BitVec; + /** @category Arithmetic */ + neg(): BitVec; + + /** + * Creates a bitwise-or between two bitvectors + * @category4 Bitwise + */ + or(other: CoercibleToBitVec): BitVec; + /** + * Creates a bitwise-and between two bitvectors + * @category Bitwise + */ + and(other: CoercibleToBitVec): BitVec; + /** + * Creates a bitwise-not-and between two bitvectors + * @category Bitwise + */ + nand(other: CoercibleToBitVec): BitVec; + /** + * Creates a bitwise-exclusive-or between two bitvectors + * @category Bitwise + */ + xor(other: CoercibleToBitVec): BitVec; + /** + * Creates a bitwise-exclusive-not-or between two bitvectors + * @category Bitwise + */ + xnor(other: CoercibleToBitVec): BitVec; + /** + * Creates an arithmetic shift right operation + * @category Bitwise + */ + shr(count: CoercibleToBitVec): BitVec; + /** + * Creates a logical shift right operation + * @category Bitwise + */ + lshr(count: CoercibleToBitVec): BitVec; + /** + * Creates a shift left operation + * @category Bitwise + */ + shl(count: CoercibleToBitVec): BitVec; + /** + * Creates a rotate right operation + * @category Bitwise + */ + rotateRight(count: CoercibleToBitVec): BitVec; + /** + * Creates a rotate left operation + * @category Bitwise + */ + rotateLeft(count: CoercibleToBitVec): BitVec; + /** + * Creates a bitwise not operation + * @category Bitwise + */ + not(): BitVec; + + /** + * Creates an extraction operation. + * Bits are indexed starting from 1 from the most right one (least significant) increasing to left (most significant) + * + * ```typescript + * const x = BitVec.const('x', 8); + * + * x.extract(6, 2) + * // Extract(6, 2, x) + * x.extract(6, 2).sort + * // BitVec(5) + * ``` + * @param high The most significant bit to be extracted + * @param low The least significant bit to be extracted + */ + extract(high: number, low: number): BitVec; + signExt(count: number): BitVec; + zeroExt(count: number): BitVec; + repeat(count: number): BitVec; + + /** + * Creates a signed less-or-equal operation (`<=`) + * @category Comparision + */ + sle(other: CoercibleToBitVec): Bool; + /** + * Creates an unsigned less-or-equal operation (`<=`) + * @category Comparision + */ + ule(other: CoercibleToBitVec): Bool; + /** + * Creates a signed less-than operation (`<`) + * @category Comparision + */ + slt(other: CoercibleToBitVec): Bool; + /** + * Creates an unsigned less-than operation (`<`) + * @category Comparision + */ + ult(other: CoercibleToBitVec): Bool; + /** + * Creates a signed greater-or-equal operation (`>=`) + * @category Comparision + */ + sge(other: CoercibleToBitVec): Bool; + /** + * Creates an unsigned greater-or-equal operation (`>=`) + * @category Comparision + */ + uge(other: CoercibleToBitVec): Bool; + /** + * Creates a signed greater-than operation (`>`) + * @category Comparision + */ + sgt(other: CoercibleToBitVec): Bool; + /** + * Creates an unsigned greater-than operation (`>`) + * @category Comparision + */ + ugt(other: CoercibleToBitVec): Bool; + + /** + * Creates a reduction-and operation + */ + redAnd(): BitVec; + /** + * Creates a reduction-or operation + */ + redOr(): BitVec; + + /** @category Boolean */ + addNoOverflow(other: CoercibleToBitVec, isSigned: boolean): Bool; + /** @category Boolean */ + addNoUnderflow(other: CoercibleToBitVec): Bool; + /** @category Boolean */ + subNoOverflow(other: CoercibleToBitVec): Bool; + /** @category Boolean */ + subNoUndeflow(other: CoercibleToBitVec, isSigned: boolean): Bool; + /** @category Boolean */ + sdivNoOverflow(other: CoercibleToBitVec): Bool; + /** @category Boolean */ + mulNoOverflow(other: CoercibleToBitVec, isSigned: boolean): Bool; + /** @category Boolean */ + mulNoUndeflow(other: CoercibleToBitVec): Bool; + /** @category Boolean */ + negNoOverflow(): Bool; +} + +/** + * Represents Bit Vector constant value + * @category Bit Vectors + */ +export interface BitVecNum extends BitVec { + /** @hidden */ + readonly __typename: 'BitVecNum'; + + get value(): bigint; + asSignedValue(): bigint; + asString(): string; + asBinaryString(): string; +} + +export interface Probe { + /** @hidden */ + readonly __typename: 'Probe'; + + readonly ctx: Context; + readonly ptr: Z3_probe; +} + +/** @hidden */ +export interface TacticCtor { + new (name: string): Tactic; +} +export interface Tactic { + /** @hidden */ + readonly __typename: 'Tactic'; + + readonly ctx: Context; + readonly ptr: Z3_tactic; +} + +/** @hidden */ +export interface AstVectorCtor { + new = AnyAst>(): AstVector; +} +/** + * Stores multiple {@link Ast} objects + * + * ```typescript + * const vector = new AstVector(); + * vector.push(Bool.val(5)); + * vector.push(Bool.const('x')) + * + * vector.length + * // 2 + * vector.get(1) + * // x + * [...vector.values()] + * // [2, x] + * ``` + */ +export interface AstVector = AnyAst, Name extends string = any> extends Iterable { + /** @hidden */ + readonly __typename: 'AstVector'; + + readonly ctx: Context; + readonly ptr: Z3_ast_vector; + get length(): number; + + entries(): IterableIterator<[number, Item]>; + keys(): IterableIterator; + values(): IterableIterator; + get(i: number): Item; + get(from: number, to: number): Item[]; + set(i: number, v: Item): void; + push(v: Item): void; + resize(size: number): void; + has(v: Item): boolean; + sexpr(): string; +} + +/** @hidden */ +export interface AstMapCtor { + new (): AstMap; +} +/** + * Stores a mapping between different {@link Ast} objects + * + * ```typescript + * const map = new Map(); + * const x = Int.const('x') + * const y = Int.const('y') + * map.set(x, Bool.val(true)) + * map.Set(y, Bool.val(false)) + * + * map.size + * // 2 + * map.has(x) + * // true + * [...map.entries()] + * // [[x, true], [y, false]] + * map.clear() + * map.size + * // 0 + * ``` + */ +export interface AstMap = AnyAst, Value extends Ast = AnyAst, Name extends string = any> + extends Iterable<[Key, Value]> { + /** @hidden */ + readonly __typename: 'AstMap'; + + readonly ctx: Context; + readonly ptr: Z3_ast_map; + get size(): number; + + entries(): IterableIterator<[Key, Value]>; + keys(): AstVector; + values(): IterableIterator; + get(key: Key): Value | undefined; + set(key: Key, value: Value): void; + delete(key: Key): void; + clear(): void; + has(key: Key): boolean; + sexpr(): string; +} + +/** + * @category Global + */ +export interface Z3HighLevel { + // Global functions + enableTrace(tag: string): void; + disableTrace(tag: string): void; + getVersion(): { + major: number; + minor: number; + build_number: number; + revision_number: number; + }; + getVersionString(): string; + getFullVersion(): string; + openLog(filename: string): boolean; + appendLog(s: string): void; + /** + * Set a Z3 parameter + * + * ```typescript + * setParam('pp.decimal', true); + * ``` + */ + setParam(key: string, value: any): void; + /** + * Set multiple Z3 parameters at once + * + * ```typescript + * setParam({ + * 'pp.decimal': true, + * 'pp.decimal_precision': 20 + * }); + * ``` + */ + setParam(key: Record): void; + /** + * Resets all Z3 parameters + */ + resetParams(): void; + /** + * Returns a global Z3 parameter + */ + getParam(name: string): string | null; + + /** + * Returns whether the given object is a {@link Context} + */ + isContext(obj: unknown): obj is Context; + + /** + * Use this to create new contexts + * @see {@link Context} + */ + readonly Context: ContextCtor; +} diff --git a/src/api/js/src/high-level/utils.test.ts b/src/api/js/src/high-level/utils.test.ts new file mode 100644 index 000000000..945f7e9d0 --- /dev/null +++ b/src/api/js/src/high-level/utils.test.ts @@ -0,0 +1,90 @@ +import { Z3AssertionError } from './types'; +import { allSatisfy, assert, assertExhaustive, autoBind } from './utils'; + +describe('allSatisfy', () => { + it('returns null on empty array', () => { + expect(allSatisfy([], () => true)).toBeNull(); + }); + + it('returns true if all satisfy', () => { + expect(allSatisfy([2, 4, 6, 8], arg => arg % 2 === 0)).toStrictEqual(true); + }); + + it('returns false if any element fails', () => { + expect(allSatisfy([2, 4, 1, 8], arg => arg % 2 === 0)).toStrictEqual(false); + }); +}); + +describe('assertExhaustive', () => { + enum MyEnum { + A, + B, + } + it('stops compilation', () => { + const result: MyEnum = MyEnum.A as any; + switch (result) { + case MyEnum.A: + break; + default: + // @ts-expect-error + assertExhaustive(result); + } + }); + + it('allows compilation', () => { + const result: MyEnum = MyEnum.A as any; + switch (result) { + case MyEnum.A: + break; + case MyEnum.B: + break; + default: + assertExhaustive(result); + } + }); + + it('throws', () => { + const result: MyEnum = undefined as any; + switch (result) { + case MyEnum.A: + throw new Error(); + case MyEnum.B: + throw new Error(); + default: + expect(() => assertExhaustive(result)).toThrowError(); + } + }); +}); + +describe('autoBind', () => { + class Binded { + readonly name = 'Richard'; + constructor(shouldBind: boolean) { + if (shouldBind === true) { + autoBind(this); + } + } + + test(): string { + return `Hello ${this.name}`; + } + } + + it('binds this', () => { + const { test: withoutBind } = new Binded(false); + const { test: withBind } = new Binded(true); + expect(() => withoutBind()).toThrowError(TypeError); + expect(withBind()).toStrictEqual('Hello Richard'); + }); +}); + +describe('assert', () => { + it('throws on failure', () => { + expect(() => assert(false)).toThrowError(Z3AssertionError); + expect(() => assert(false, 'foobar')).toThrowError(new Z3AssertionError('foobar')); + }); + + it('does nothing on sucess', () => { + expect(() => assert(true, 'hello')).not.toThrow(); + }); +}); diff --git a/src/api/js/src/high-level/utils.ts b/src/api/js/src/high-level/utils.ts new file mode 100644 index 000000000..bd5013710 --- /dev/null +++ b/src/api/js/src/high-level/utils.ts @@ -0,0 +1,85 @@ +import { Z3AssertionError } from './types'; + +function getAllProperties(obj: Record) { + const properties = new Set<[any, string | symbol]>(); + do { + for (const key of Reflect.ownKeys(obj)) { + properties.add([obj, key]); + } + } while ((obj = Reflect.getPrototypeOf(obj)!) && obj !== Object.prototype); + return properties; +} + +// https://github.com/sindresorhus/auto-bind +// We modify it to use CommonJS instead of ESM +/* +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +export function autoBind>(self: Self): Self { + for (const [obj, key] of getAllProperties(self.constructor.prototype)) { + if (key === 'constructor') { + continue; + } + const descriptor = Reflect.getOwnPropertyDescriptor(obj, key); + if (descriptor && typeof descriptor.value === 'function') { + (self[key] as any) = self[key].bind(self); + } + } + return self; +} + +/** + * Use to ensure that switches are checked to be exhaustive at compile time + * + * @example Basic usage + * ```typescript + * enum Something { + * left, + * right, + * }; + * const something = getSomething(); + * switch (something) { + * case Something.left: + * ... + * case Something.right: + * ... + * default: + * assertExhaustive(something); + * } + * ``` + * + * @param x - The param on which the switch operates + */ +export function assertExhaustive(x: never): never { + throw new Error('Unexpected code execution detected, should be caught at compile time'); +} + +export function assert(condition: boolean, reason?: string): asserts condition { + if (!condition) { + throw new Z3AssertionError(reason ?? 'Assertion failed'); + } +} + +/** + * Check the all elements of a `collection` satisfy the `premise`. + * If any of the items fail the `premise`, returns false; + * @returns null if the `collection` is empty, boolean otherwise + */ +export function allSatisfy(collection: Iterable, premise: (arg: T) => boolean): boolean | null { + let hasItems = false; + for (const arg of collection) { + hasItems = true; + if (!premise(arg)) { + return false; + } + } + return hasItems === true ? true : null; +} diff --git a/src/api/js/src/jest.ts b/src/api/js/src/jest.ts new file mode 100644 index 000000000..9cbab31f1 --- /dev/null +++ b/src/api/js/src/jest.ts @@ -0,0 +1,62 @@ +// This file is not included in the build + +// @ts-ignore no-implicit-any +import { createApi, Z3HighLevel } from './high-level'; +import { init as initWrapper, Z3LowLevel } from './low-level'; +import initModule = require('../build/z3-built'); + +export * from './high-level/types'; +export { Z3Core, Z3LowLevel } from './low-level'; +export * from './low-level/types.__GENERATED__'; + +export async function init(): Promise { + const lowLevel = await initWrapper(initModule); + const highLevel = createApi(lowLevel.Z3); + return { ...lowLevel, ...highLevel }; +} + +function delay(ms: number): Promise & { cancel(): void }; +function delay(ms: number, result: Error): Promise & { cancel(): void }; +function delay(ms: number, result: T): Promise & { cancel(): void }; +function delay(ms: number, result?: T | Error): Promise & { cancel(): void } { + let handle: any; + const promise = new Promise( + (resolve, reject) => + (handle = setTimeout(() => { + if (result instanceof Error) { + reject(result); + } else if (result !== undefined) { + resolve(result); + } + resolve(); + }, ms)), + ); + return { ...promise, cancel: () => clearTimeout(handle) }; +} + +function waitWhile(premise: () => boolean, pollMs: number = 100): Promise & { cancel(): void } { + let handle: any; + const promise = new Promise(resolve => { + handle = setInterval(() => { + if (premise()) { + clearTimeout(handle); + resolve(); + } + }, pollMs); + }); + return { ...promise, cancel: () => clearInterval(handle) }; +} + +export function killThreads(em: any): Promise { + em.PThread.terminateAllThreads(); + + // Create a polling lock to wait for threads to return + // TODO(ritave): Threads should be killed automatically, or there should be a better way to wait for them + const lockPromise = waitWhile(() => !em.PThread.unusedWorkers.length && !em.PThread.runningWorkers.length); + const delayPromise = delay(5000, new Error('Waiting for threads to be killed timed out')); + + return Promise.race([lockPromise, delayPromise]).finally(() => { + lockPromise.cancel(); + delayPromise.cancel(); + }); +} diff --git a/src/api/js/src/async-wrapper.js b/src/api/js/src/low-level/async-wrapper.js similarity index 92% rename from src/api/js/src/async-wrapper.js rename to src/api/js/src/low-level/async-wrapper.js index 7a1b95c4f..78b3fee53 100644 --- a/src/api/js/src/async-wrapper.js +++ b/src/api/js/src/low-level/async-wrapper.js @@ -1,4 +1,5 @@ // this wrapper works with async-fns to provide promise-based off-thread versions of some functions +// It's prepended directly by emscripten to the resulting z3-built.js let capability = null; function resolve_async(val) { diff --git a/src/api/js/src/low-level/index.ts b/src/api/js/src/low-level/index.ts new file mode 100644 index 000000000..4a842bab6 --- /dev/null +++ b/src/api/js/src/low-level/index.ts @@ -0,0 +1,4 @@ +export * from './types.__GENERATED__'; +export * from './wrapper.__GENERATED__'; +export type Z3Core = Awaited>['Z3']; +export type Z3LowLevel = Awaited>; diff --git a/src/api/js/src/node-wrapper.ts b/src/api/js/src/node-wrapper.ts deleted file mode 100644 index cd315a026..000000000 --- a/src/api/js/src/node-wrapper.ts +++ /dev/null @@ -1,10 +0,0 @@ -// @ts-ignore no-implicit-any -import initModule = require('./z3-built.js'); - -// @ts-ignore no-implicit-any -import { init as initWrapper } from './wrapper'; - -export * from './wrapper'; -export function init() { - return initWrapper(initModule); -} diff --git a/src/api/js/src/node.ts b/src/api/js/src/node.ts new file mode 100644 index 000000000..6456d8979 --- /dev/null +++ b/src/api/js/src/node.ts @@ -0,0 +1,38 @@ +// @ts-ignore no-implicit-any +import initModule = require('./z3-built'); + +import { createApi, Z3HighLevel } from './high-level'; +import { init as initWrapper, Z3LowLevel } from './low-level'; +export * from './high-level/types'; +export { Z3Core, Z3LowLevel } from './low-level'; +export * from './low-level/types.__GENERATED__'; + +/** + * The main entry point to the Z3 API + * + * ```typescript + * import { init, sat } from 'z3-solver'; + * + * const { Context } = await init(); + * const { Solver, Int } = new Context('main'); + * + * const x = Int.const('x'); + * const y = Int.const('y'); + * + * const solver = new Solver(); + * solver.add(x.add(2).le(y.sub(10))); // x + 2 <= y - 10 + * + * if (await solver.check() !== sat) { + * throw new Error("couldn't find a solution") + * } + * const model = solver.model(); + * + * console.log(`x=${model.get(x)}, y=${model.get(y)}`); + * // x=0, y=12 + * ``` + * @category Global */ +export async function init(): Promise { + const lowLevel = await initWrapper(initModule); + const highLevel = createApi(lowLevel.Z3); + return { ...lowLevel, ...highLevel }; +} diff --git a/src/api/js/tsconfig.build.json b/src/api/js/tsconfig.build.json new file mode 100644 index 000000000..694df0544 --- /dev/null +++ b/src/api/js/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["src/**/*.test.ts", "src/jest.ts"] +} diff --git a/src/api/js/tsconfig.json b/src/api/js/tsconfig.json index 73406c691..709cdff9b 100644 --- a/src/api/js/tsconfig.json +++ b/src/api/js/tsconfig.json @@ -6,9 +6,11 @@ "declaration": true, "forceConsistentCasingInFileNames": true, "strict": true, - "skipLibCheck": true + "skipLibCheck": true, + "outDir": "build/", + "allowJs": true, + "checkJs": false }, - "exclude": [ - "src" - ] + "include": ["src/**/*.ts"], + "exclude": ["node_modules"] } diff --git a/src/api/js/typedoc.json b/src/api/js/typedoc.json new file mode 100644 index 000000000..692072136 --- /dev/null +++ b/src/api/js/typedoc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "entryPoints": ["./src/node.ts"], + "out": "../../../doc/api/html/js", + "exclude": ["./src/low-level/**/*"], + "readme": "./PUBLISHED_README.md", + "categorizeByGroup": false +} From 99b606b8612834062d8d1edf2d68bda97917a6b4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 16 Jun 2022 14:48:19 -0700 Subject: [PATCH 237/253] add logging --- src/smt/theory_arith_core.h | 2 ++ src/smt/theory_lra.cpp | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 0168652cb..88db34012 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -3097,6 +3097,8 @@ namespace smt { m_stats.m_conflicts++; m_num_conflicts++; TRACE("arith_conflict", + if (proof_rule) + tout << proof_rule << "\n"; tout << "scope: " << ctx.get_scope_level() << "\n"; for (unsigned i = 0; i < num_literals; i++) { ctx.display_detailed_literal(tout, lits[i]); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 94702a32b..67d9988ed 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -3159,11 +3159,15 @@ public: // lp().shrink_explanation_to_minimum(m_explanation); // todo, enable when perf is fixed ++m_num_conflicts; ++m_stats.m_conflicts; - TRACE("arith", tout << "scope: " << ctx().get_scope_level() << "\n"; display_evidence(tout, m_explanation); ); - TRACE("arith", display(tout << "is-conflict: " << is_conflict << "\n");); - for (auto ev : m_explanation) { + TRACE("arith", + tout << "lemma scope: " << ctx().get_scope_level(); + for (auto const& p : m_params) tout << " " << p; + tout << "\n"; + display_evidence(tout, m_explanation); + display(tout << "is-conflict: " << is_conflict << "\n");); + for (auto ev : m_explanation) set_evidence(ev.ci(), m_core, m_eqs); - } + // SASSERT(validate_conflict(m_core, m_eqs)); dump_conflict(m_core, m_eqs); if (is_conflict) { From 477e9625ef81de434f1e02f6d6577c4d71318306 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 16 Jun 2022 15:12:47 -0700 Subject: [PATCH 238/253] Don't reset the cache between applications of replace tactic/lia2card shows a huge slowdown because the same replace function is called on thousands of assertions. Each time the cache gets reset with thousands of entries - they are all the same. So don't reset the cache just because... Instead reset the cache if m_refs grows large. --- src/ast/rewriter/expr_safe_replace.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index c4b940522..300e82707 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -27,6 +27,7 @@ void expr_safe_replace::insert(expr* src, expr* dst) { SASSERT(src->get_sort() == dst->get_sort()); m_src.push_back(src); m_dst.push_back(dst); + m_cache.clear(); } void expr_safe_replace::operator()(expr_ref_vector& es) { @@ -45,13 +46,15 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { return; } - for (unsigned i = 0, e = m_src.size(); i < e; ++i) { - m_cache.emplace(m_src.get(i), m_dst.get(i)); + if (m_cache.empty()) { + for (unsigned i = 0, e = m_src.size(); i < e; ++i) + m_cache.emplace(m_src.get(i), m_dst.get(i)); } - + m_todo.push_back(e); expr* a, *b; - + + m_refs.push_back(e); while (!m_todo.empty()) { a = m_todo.back(); auto &cached = m_cache[a]; @@ -166,10 +169,12 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { } } res = m_cache.at(e); - m_cache.clear(); + if (m_refs.size() > 1 << 20) { + m_cache.clear(); + m_refs.reset(); + } m_todo.reset(); m_args.reset(); - m_refs.reset(); } void expr_safe_replace::reset() { From 08c44bc6f6d83f7490a1cb62e464a75fb840088c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 16 Jun 2022 15:39:40 -0700 Subject: [PATCH 239/253] remove unused static features remove static features that tax solving time on large instances. --- src/ast/static_features.cpp | 53 +------------------------------------ src/ast/static_features.h | 13 ++------- 2 files changed, 3 insertions(+), 63 deletions(-) diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp index ec1a73e9b..9c843d729 100644 --- a/src/ast/static_features.cpp +++ b/src/ast/static_features.cpp @@ -56,12 +56,6 @@ void static_features::reset() { m_num_nested_formulas = 0; m_num_bool_exprs = 0; m_num_bool_constants = 0; - m_num_formula_trees = 0; - m_max_formula_depth = 0; - m_sum_formula_depth = 0; - m_num_or_and_trees = 0; - m_max_or_and_tree_depth = 0; - m_sum_or_and_tree_depth = 0; m_num_ite_trees = 0; m_max_ite_tree_depth = 0; m_sum_ite_tree_depth = 0; @@ -461,10 +455,6 @@ void static_features::post_process(expr * e, bool form_ctx, bool or_and_ctx, boo m.is_not(arg, arg); SASSERT(is_marked_post(arg)); depth = std::max(depth, get_depth(arg)); - if (form_ctx_new) - form_depth = std::max(form_depth, get_form_depth(arg)); - if (or_and_ctx_new) - or_and_depth = std::max(or_and_depth, get_or_and_depth(arg)); if (ite_ctx_new) ite_depth = std::max(ite_depth, get_ite_depth(arg)); } @@ -473,27 +463,7 @@ void static_features::post_process(expr * e, bool form_ctx, bool or_and_ctx, boo set_depth(e, depth); if (depth > m_max_depth) m_max_depth = depth; - - if (form_ctx_new) { - form_depth++; - if (!form_ctx) { - m_num_formula_trees++; - m_sum_formula_depth += form_depth; - if (form_depth > m_max_formula_depth) - m_max_formula_depth = form_depth; - } - set_form_depth(e, form_depth); - } - if (or_and_ctx_new) { - or_and_depth++; - if (!or_and_ctx) { - m_num_or_and_trees++; - m_sum_or_and_tree_depth += or_and_depth; - if (or_and_depth > m_max_or_and_tree_depth) - m_max_or_and_tree_depth = or_and_depth; - } - set_or_and_depth(e, or_and_depth); - } + if (ite_ctx_new) { ite_depth++; if (!ite_ctx) { @@ -572,25 +542,11 @@ void static_features::process_root(expr * e) { add_process(arg, true, true, false); process_all(); depth = std::max(depth, get_depth(arg)); - form_depth = std::max(form_depth, get_form_depth(arg)); - or_and_depth = std::max(or_and_depth, get_or_and_depth(arg)); } depth++; set_depth(e, depth); if (depth > m_max_depth) m_max_depth = depth; - form_depth++; - m_num_formula_trees++; - m_sum_formula_depth += form_depth; - if (form_depth > m_max_formula_depth) - m_max_formula_depth = form_depth; - set_form_depth(e, form_depth); - or_and_depth++; - m_num_or_and_trees++; - m_sum_or_and_tree_depth += or_and_depth; - if (or_and_depth > m_max_or_and_tree_depth) - m_max_or_and_tree_depth = or_and_depth; - set_or_and_depth(e, or_and_depth); return; } if (!is_gate(e)) { @@ -647,12 +603,6 @@ void static_features::display_primitive(std::ostream & out) const { out << "NUM_NESTED_FORMULAS " << m_num_nested_formulas << "\n"; out << "NUM_BOOL_EXPRS " << m_num_bool_exprs << "\n"; out << "NUM_BOOL_CONSTANTS " << m_num_bool_constants << "\n"; - out << "NUM_FORMULA_TREES " << m_num_formula_trees << "\n"; - out << "MAX_FORMULA_DEPTH " << m_max_formula_depth << "\n"; - out << "SUM_FORMULA_DEPTH " << m_sum_formula_depth << "\n"; - out << "NUM_OR_AND_TREES " << m_num_or_and_trees << "\n"; - out << "MAX_OR_AND_TREE_DEPTH " << m_max_or_and_tree_depth << "\n"; - out << "SUM_OR_AND_TREE_DEPTH " << m_sum_or_and_tree_depth << "\n"; out << "NUM_ITE_TREES " << m_num_ite_trees << "\n"; out << "MAX_ITE_TREE_DEPTH " << m_max_ite_tree_depth << "\n"; out << "SUM_ITE_TREE_DEPTH " << m_sum_ite_tree_depth << "\n"; @@ -695,7 +645,6 @@ void static_features::display(std::ostream & out) const { out << "BEGIN_STATIC_FEATURES" << "\n"; out << "CNF " << m_cnf << "\n"; out << "MAX_DEPTH " << m_max_depth << "\n"; - out << "MAX_OR_AND_TREE_DEPTH " << m_max_or_and_tree_depth << "\n"; out << "MAX_ITE_TREE_DEPTH " << m_max_ite_tree_depth << "\n"; out << "HAS_INT " << m_has_int << "\n"; out << "HAS_REAL " << m_has_real << "\n"; diff --git a/src/ast/static_features.h b/src/ast/static_features.h index 88e7934d4..92e0331fb 100644 --- a/src/ast/static_features.h +++ b/src/ast/static_features.h @@ -59,13 +59,7 @@ struct static_features { unsigned m_sum_clause_size; unsigned m_num_nested_formulas; // unsigned m_num_bool_exprs; // - unsigned m_num_bool_constants; // - unsigned m_num_formula_trees; - unsigned m_max_formula_depth; - unsigned m_sum_formula_depth; - unsigned m_num_or_and_trees; - unsigned m_max_or_and_tree_depth; - unsigned m_sum_or_and_tree_depth; + unsigned m_num_bool_constants; // unsigned m_num_ite_trees; unsigned m_max_ite_tree_depth; unsigned m_sum_ite_tree_depth; @@ -179,12 +173,9 @@ struct static_features { void process_root(expr * e); unsigned get_depth(expr const * e) const { return m_expr2depth.get(e->get_id(), 1); } void set_depth(expr const * e, unsigned d) { m_expr2depth.setx(e->get_id(), d, 1); } - unsigned get_or_and_depth(expr const * e) const { unsigned d = 0; m_expr2or_and_depth.find(e->get_id(), d); return d; } - void set_or_and_depth(expr const * e, unsigned d) { m_expr2or_and_depth.insert(e->get_id(), d); } + unsigned get_ite_depth(expr const * e) const { unsigned d = 0; m_expr2ite_depth.find(e->get_id(), d); return d; } void set_ite_depth(expr const * e, unsigned d) { m_expr2ite_depth.insert(e->get_id(), d); } - unsigned get_form_depth(expr const * e) const { unsigned d = 0; m_expr2formula_depth.find(e->get_id(), d); return d; } - void set_form_depth(expr const * e, unsigned d) { m_expr2formula_depth.insert(e->get_id(), d); } static_features(ast_manager & m); void reset(); void flush_cache(); From 70bcf0b51da6917bf9d3e4a418e5744c601767a8 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 17 Jun 2022 12:07:15 +0100 Subject: [PATCH 240/253] reduce sizeof(enode) from 120 to 112 bytes by swapping the order of fields Yes, those 8 bytes are yours now, use responsibly. --- src/smt/smt_enode.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index 196d28396..b3a3bbf69 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -78,6 +78,8 @@ namespace smt { unsigned m_merge_tf:1; //!< True if the enode should be merged with true/false when the associated boolean variable is assigned. unsigned m_cgc_enabled:1; //!< True if congruence closure is enabled for this enode. unsigned m_iscope_lvl; //!< When the enode was internalized + bool m_proof_is_logged; //!< Indicates that the proof for the enode being equal to its root is in the log. + signed char m_lbl_hash; //!< It is different from -1, if enode is used in a pattern /* The following property is valid for m_parents @@ -96,8 +98,6 @@ namespace smt { enode_vector m_parents; //!< Parent enodes of the equivalence class. id_var_list<> m_th_var_list; //!< List of theories that 'care' about this enode. trans_justification m_trans; //!< A justification for the enode being equal to its root. - bool m_proof_is_logged; //!< Indicates that the proof for the enode being equal to its root is in the log. - signed char m_lbl_hash; //!< It is different from -1, if enode is used in a pattern approx_set m_lbls; approx_set m_plbls; enode * m_args[0]; //!< Cached args From 73a24ca0a90359f29c7085f99d4e61f3012e5d53 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 17 Jun 2022 14:10:19 +0100 Subject: [PATCH 241/253] remove '#include ' from headers and from unneeded places It's harmful to have iostream everywhere as it injects functions in the compiled files --- scripts/update_api.py | 1 - src/api/api_ast.cpp | 1 - src/api/api_ast_map.cpp | 1 - src/api/api_ast_vector.cpp | 1 - src/api/api_fpa.cpp | 1 - src/api/api_goal.cpp | 1 - src/api/api_numeral.cpp | 1 - src/api/api_opt.cpp | 1 - src/api/api_params.cpp | 1 - src/api/api_parsers.cpp | 1 - src/api/api_qe.cpp | 1 - src/api/api_rcf.cpp | 1 - src/api/api_solver.cpp | 1 - src/api/api_special_relations.cpp | 1 - src/api/api_stats.cpp | 1 - src/api/api_tactic.cpp | 1 - src/api/c++/z3++.h | 2 +- src/api/z3_private.h | 1 - src/api/z3_replayer.cpp | 1 + src/api/z3_replayer.h | 1 - src/ast/ast.cpp | 1 + src/ast/ast_ll_pp.cpp | 2 +- src/ast/ast_ll_pp.h | 2 +- src/ast/ast_pp_dot.h | 2 +- src/ast/ast_printer.cpp | 4 ++++ src/ast/ast_printer.h | 5 +++-- src/ast/ast_smt_pp.cpp | 2 +- src/ast/fpa/bv2fpa_converter.cpp | 2 +- src/ast/fpa/fpa2bv_converter.cpp | 2 +- src/cmd_context/cmd_context.cpp | 1 + src/math/lp/lp_settings.h | 1 + src/math/lp/lu.h | 2 +- src/math/lp/mps_reader.h | 2 +- src/math/realclosure/realclosure.cpp | 1 + src/math/simplex/sparse_matrix.h | 2 +- src/math/subpaving/subpaving_t.h | 2 +- src/math/subpaving/tactic/subpaving_tactic.cpp | 1 + src/model/model_pp.h | 2 +- src/model/model_v2_pp.cpp | 1 + src/model/model_v2_pp.h | 2 +- src/muz/base/dl_boogie_proof.cpp | 6 +++--- src/muz/base/dl_context.cpp | 1 + src/muz/base/dl_util.h | 2 ++ src/muz/ddnf/ddnf.cpp | 7 ++++--- src/muz/rel/aig_exporter.cpp | 6 ++---- src/muz/rel/dl_compiler.h | 2 -- src/muz/rel/dl_instruction.h | 2 +- src/muz/rel/dl_sparse_table.h | 1 - src/muz/rel/dl_table.h | 1 - src/muz/spacer/spacer_json.h | 2 +- src/muz/transforms/dl_mk_array_instantiation.cpp | 4 ++++ src/opt/opt_parse.cpp | 2 +- src/parsers/smt2/marshal.h | 2 +- src/parsers/smt2/smt2scanner.h | 2 +- src/parsers/util/cost_parser.h | 1 - src/parsers/util/scanner.cpp | 1 + src/parsers/util/simple_parser.cpp | 1 + src/sat/sat_aig_cuts.cpp | 11 ++++++----- src/sat/sat_cut_simplifier.cpp | 3 +-- src/sat/sat_drat.cpp | 4 +--- src/sat/sat_simplifier.cpp | 4 ++-- src/sat/smt/array_diagnostics.cpp | 2 ++ src/sat/smt/bv_invariant.cpp | 2 ++ src/sat/smt/pb_solver.cpp | 4 ++-- src/sat/smt/q_model_fixer.cpp | 3 ++- src/shell/lp_frontend.cpp | 1 + src/shell/opt_frontend.cpp | 1 + src/smt/smt_context.cpp | 4 ++-- src/smt/smt_context_stat.cpp | 6 +++--- src/smt/smt_statistics.h | 2 -- src/smt/theory_array_bapa.cpp | 2 ++ src/smt/theory_pb.cpp | 2 ++ src/tactic/arith/bv2real_rewriter.cpp | 1 - src/tactic/core/collect_statistics_tactic.cpp | 1 + src/util/approx_nat.h | 2 +- src/util/approx_set.h | 2 +- src/util/cmd_context_types.cpp | 1 - src/util/cmd_context_types.h | 1 + src/util/ext_numeral.h | 2 +- src/util/permutation.h | 2 +- src/util/region.h | 2 +- src/util/scoped_ctrl_c.cpp | 1 - src/util/statistics.h | 2 +- src/util/stopwatch.h | 2 +- src/util/stream_buffer.h | 4 +--- src/util/timeit.cpp | 6 +++--- src/util/timeit.h | 5 ++++- src/util/util.cpp | 2 +- src/util/util.h | 2 +- src/util/warning.h | 2 +- 90 files changed, 99 insertions(+), 95 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 24cf3745b..6c932d8ca 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1771,7 +1771,6 @@ def write_log_h_preamble(log_h): def write_log_c_preamble(log_c): log_c.write('// Automatically generated file\n') - log_c.write('#include\n') log_c.write('#include\"api/z3.h\"\n') log_c.write('#include\"api/api_log_macros.h\"\n') log_c.write('#include\"api/z3_logger.h\"\n') diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 7cd3b2dd9..647cc8631 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include "api/api_log_macros.h" #include "api/api_context.h" #include "api/api_util.h" diff --git a/src/api/api_ast_map.cpp b/src/api/api_ast_map.cpp index e252b9aca..5976d0e41 100644 --- a/src/api/api_ast_map.cpp +++ b/src/api/api_ast_map.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/api/api_ast_vector.cpp b/src/api/api_ast_vector.cpp index a8a64ce2c..028b971d3 100644 --- a/src/api/api_ast_vector.cpp +++ b/src/api/api_ast_vector.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/api/api_fpa.cpp b/src/api/api_fpa.cpp index 37c86e317..2dda84af4 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -16,7 +16,6 @@ Author: Notes: --*/ -#include #include "api/z3.h" #include "api/api_log_macros.h" #include "api/api_context.h" diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index dd9f8959f..086e8f302 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.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/api/api_numeral.cpp b/src/api/api_numeral.cpp index 7e655c9d1..60d663638 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -16,7 +16,6 @@ Revision History: --*/ #include -#include #include "api/z3.h" #include "api/api_log_macros.h" #include "api/api_context.h" diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 140c655cd..ebbe1a3db 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include "util/cancel_eh.h" #include "util/scoped_timer.h" #include "util/scoped_ctrl_c.h" diff --git a/src/api/api_params.cpp b/src/api/api_params.cpp index 6e06fbf78..1454525d6 100644 --- a/src/api/api_params.cpp +++ b/src/api/api_params.cpp @@ -17,7 +17,6 @@ Author: Revision History: --*/ -#include #include "api/z3.h" #include "api/api_log_macros.h" #include "api/api_context.h" diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 94132a361..1c5afb34f 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.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/api/api_qe.cpp b/src/api/api_qe.cpp index d1e5d195b..328b1f249 100644 --- a/src/api/api_qe.cpp +++ b/src/api/api_qe.cpp @@ -17,7 +17,6 @@ Notes: --*/ -#include #include "ast/expr_map.h" #include "api/z3.h" #include "api/api_log_macros.h" diff --git a/src/api/api_rcf.cpp b/src/api/api_rcf.cpp index 7c168dc62..8a000be1a 100644 --- a/src/api/api_rcf.cpp +++ b/src/api/api_rcf.cpp @@ -19,7 +19,6 @@ Author: Notes: --*/ -#include #include "api/z3.h" #include "api/api_log_macros.h" #include "api/api_context.h" diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index b8765a69b..3a28da0fd 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -16,7 +16,6 @@ Author: Revision History: --*/ -#include #include #include "util/scoped_ctrl_c.h" #include "util/cancel_eh.h" diff --git a/src/api/api_special_relations.cpp b/src/api/api_special_relations.cpp index 3b4872435..f29254cba 100644 --- a/src/api/api_special_relations.cpp +++ b/src/api/api_special_relations.cpp @@ -17,7 +17,6 @@ Revision History: --*/ -#include #include "api/z3.h" #include "api/api_log_macros.h" #include "api/api_context.h" diff --git a/src/api/api_stats.cpp b/src/api/api_stats.cpp index 01b521ed6..c90850404 100644 --- a/src/api/api_stats.cpp +++ b/src/api/api_stats.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/api/api_tactic.cpp b/src/api/api_tactic.cpp index edf9ab262..b3e3ca922 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.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/api/c++/z3++.h b/src/api/c++/z3++.h index de55bb765..10116d751 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -21,7 +21,7 @@ Notes: #pragma once #include -#include +#include #include #include #include diff --git a/src/api/z3_private.h b/src/api/z3_private.h index 528033c72..9a32eb06f 100644 --- a/src/api/z3_private.h +++ b/src/api/z3_private.h @@ -18,7 +18,6 @@ Notes: --*/ -#include #include "util/rational.h" #include "api/z3_macros.h" diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 398290b9e..ad5bc9523 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -22,6 +22,7 @@ Notes: #include "util/stream_buffer.h" #include "util/symbol.h" #include "util/trace.h" +#include #include #include diff --git a/src/api/z3_replayer.h b/src/api/z3_replayer.h index b5388251f..8c77f0e0a 100644 --- a/src/api/z3_replayer.h +++ b/src/api/z3_replayer.h @@ -18,7 +18,6 @@ Notes: --*/ #pragma once -#include #include "api/z3.h" #include "util/z3_exception.h" diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 190da1366..5c48f31d0 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -30,6 +30,7 @@ Revision History: #include "ast/arith_decl_plugin.h" #include "ast/ast_translation.h" #include "util/z3_version.h" +#include // ----------------------------------- diff --git a/src/ast/ast_ll_pp.cpp b/src/ast/ast_ll_pp.cpp index 4c48bc7e7..5de98c644 100644 --- a/src/ast/ast_ll_pp.cpp +++ b/src/ast/ast_ll_pp.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include +#include "ast/ast_ll_pp.h" #include "ast/for_each_ast.h" #include "ast/arith_decl_plugin.h" #include "ast/datatype_decl_plugin.h" diff --git a/src/ast/ast_ll_pp.h b/src/ast/ast_ll_pp.h index 17de34687..da0c1529b 100644 --- a/src/ast/ast_ll_pp.h +++ b/src/ast/ast_ll_pp.h @@ -19,7 +19,7 @@ Revision History: #pragma once #include "ast/ast.h" -#include +#include void ast_ll_pp(std::ostream & out, ast_manager & m, ast * n, bool only_exprs=true, bool compact=true); void ast_ll_pp(std::ostream & out, ast_manager & m, ast * n, ast_mark & visited, bool only_exprs=true, bool compact=true); diff --git a/src/ast/ast_pp_dot.h b/src/ast/ast_pp_dot.h index 7b4420a33..6860eaef5 100644 --- a/src/ast/ast_pp_dot.h +++ b/src/ast/ast_pp_dot.h @@ -6,7 +6,7 @@ Abstract: Pretty-printer for proofs in Graphviz format #pragma once -#include +#include #include "ast/ast_pp.h" class ast_pp_dot { diff --git a/src/ast/ast_printer.cpp b/src/ast/ast_printer.cpp index 7f2460e06..7f717df96 100644 --- a/src/ast/ast_printer.cpp +++ b/src/ast/ast_printer.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include "ast/ast_printer.h" #include "ast/pp.h" +#include class simple_ast_printer_context : public ast_printer_context { ast_manager & m_manager; @@ -51,3 +52,6 @@ public: ast_printer_context * mk_simple_ast_printer_context(ast_manager & m) { return alloc(simple_ast_printer_context, m); } + +std::ostream & ast_printer_context::regular_stream() { return std::cout; } +std::ostream & ast_printer_context::diagnostic_stream() { return std::cerr; } diff --git a/src/ast/ast_printer.h b/src/ast/ast_printer.h index 1cfb9b800..d57a9b845 100644 --- a/src/ast/ast_printer.h +++ b/src/ast/ast_printer.h @@ -20,6 +20,7 @@ Revision History: #include "ast/ast.h" #include "ast/ast_smt2_pp.h" +#include class ast_printer { public: @@ -46,8 +47,8 @@ class ast_printer_context : public ast_printer { public: ~ast_printer_context() override {} virtual ast_manager & get_ast_manager() = 0; - virtual std::ostream & regular_stream() { return std::cout; } - virtual std::ostream & diagnostic_stream() { return std::cerr; } + virtual std::ostream & regular_stream(); + virtual std::ostream & diagnostic_stream(); }; diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index dabf11d69..f40b8a554 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -20,7 +20,7 @@ Revision History: --*/ #include -#include +#include #include "util/vector.h" #include "util/smt2_util.h" #include "ast/ast_smt_pp.h" diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index 3611f848a..c541f72d0 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -162,7 +162,7 @@ expr_ref bv2fpa_converter::convert_bv2rm(expr * bv_rm) { } } else { - std::cout << expr_ref(bv_rm, m) << " not converted\n"; + //std::cout << expr_ref(bv_rm, m) << " not converted\n"; } return res; diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 64155d48b..862fe6929 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -124,7 +124,7 @@ void fpa2bv_converter::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) { result = m_util.mk_bv2rm(result); } else { - std::cout << mk_pp(t, m) << " " << mk_pp(f, m) << "\n"; + //std::cout << mk_pp(t, m) << " " << mk_pp(f, m) << "\n"; UNREACHABLE(); } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 9bd6e6556..2174c9e0b 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -51,6 +51,7 @@ Notes: #include "solver/smt_logics.h" #include "cmd_context/basic_cmds.h" #include "cmd_context/cmd_context.h" +#include func_decls::func_decls(ast_manager & m, func_decl * f): m_decls(TAG(func_decl*, f, 0)) { diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index 2be55dcb1..aa06cb263 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -24,6 +24,7 @@ Revision History: #include #include #include +#include #include #include "util/stopwatch.h" #include "util/statistics.h" diff --git a/src/math/lp/lu.h b/src/math/lp/lu.h index f5289211f..aca59065d 100644 --- a/src/math/lp/lu.h +++ b/src/math/lp/lu.h @@ -33,7 +33,7 @@ Revision History: #include "math/lp/static_matrix.h" #include #include "math/lp/numeric_pair.h" -#include +#include #include #include "math/lp/row_eta_matrix.h" #include "math/lp/square_dense_submatrix.h" diff --git a/src/math/lp/mps_reader.h b/src/math/lp/mps_reader.h index f165b08b3..f0fa074cc 100644 --- a/src/math/lp/mps_reader.h +++ b/src/math/lp/mps_reader.h @@ -26,7 +26,7 @@ Revision History: #include #include "util/vector.h" #include -#include +#include #include #include #include "math/lp/lp_primal_simplex.h" diff --git a/src/math/realclosure/realclosure.cpp b/src/math/realclosure/realclosure.cpp index 471c419ac..1ff2785ae 100644 --- a/src/math/realclosure/realclosure.cpp +++ b/src/math/realclosure/realclosure.cpp @@ -29,6 +29,7 @@ Notes: #include "util/ref_vector.h" #include "util/ref_buffer.h" #include "util/common_msgs.h" +#include #ifndef REALCLOSURE_INI_BUFFER_SIZE #define REALCLOSURE_INI_BUFFER_SIZE 32 diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index e26531c82..a33ea55bd 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -281,7 +281,7 @@ namespace simplex { vector<_row> const& m_rows; void move_to_next() { while (m_curr < m_rows.size() && m_rows[m_curr].size() == 0) { - std::cout << "size is 0 for " << m_curr << "\n"; + //std::cout << "size is 0 for " << m_curr << "\n"; ++m_curr; } } diff --git a/src/math/subpaving/subpaving_t.h b/src/math/subpaving/subpaving_t.h index 79abf0cc7..cfe3aea70 100644 --- a/src/math/subpaving/subpaving_t.h +++ b/src/math/subpaving/subpaving_t.h @@ -18,7 +18,7 @@ Revision History: --*/ #pragma once -#include +#include #include "util/tptr.h" #include "util/small_object_allocator.h" #include "util/chashtable.h" diff --git a/src/math/subpaving/tactic/subpaving_tactic.cpp b/src/math/subpaving/tactic/subpaving_tactic.cpp index 6124e726e..cdd8bac0a 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.cpp +++ b/src/math/subpaving/tactic/subpaving_tactic.cpp @@ -26,6 +26,7 @@ Revision History: #include "util/mpff.h" #include "util/mpfx.h" #include "util/f2n.h" +#include class subpaving_tactic : public tactic { diff --git a/src/model/model_pp.h b/src/model/model_pp.h index e71cab05c..b6450e677 100644 --- a/src/model/model_pp.h +++ b/src/model/model_pp.h @@ -19,7 +19,7 @@ Revision History: --*/ #pragma once -#include +#include class model_core; void model_pp(std::ostream & out, model_core const & m); diff --git a/src/model/model_v2_pp.cpp b/src/model/model_v2_pp.cpp index e50d70079..5ade6ba63 100644 --- a/src/model/model_v2_pp.cpp +++ b/src/model/model_v2_pp.cpp @@ -18,6 +18,7 @@ Revision History: #include "model/model_v2_pp.h" #include "model/model_core.h" #include "ast/ast_pp.h" +#include static void display_function(std::ostream & out, model_core const & md, func_decl * f, bool partial) { ast_manager & m = md.get_manager(); diff --git a/src/model/model_v2_pp.h b/src/model/model_v2_pp.h index c61175544..16edbd732 100644 --- a/src/model/model_v2_pp.h +++ b/src/model/model_v2_pp.h @@ -17,7 +17,7 @@ Revision History: --*/ #pragma once -#include +#include class model_core; void model_v2_pp(std::ostream & out, model_core const & m, bool partial = false); diff --git a/src/muz/base/dl_boogie_proof.cpp b/src/muz/base/dl_boogie_proof.cpp index 97e4689dc..889ec8a32 100644 --- a/src/muz/base/dl_boogie_proof.cpp +++ b/src/muz/base/dl_boogie_proof.cpp @@ -121,11 +121,11 @@ namespace datalog { } void boogie_proof::set_proof(proof* p) { - std::cout << "set proof\n"; + //std::cout << "set proof\n"; m_proof = p; proof_utils::push_instantiations_up(m_proof); mk_input_resolution(m_proof); - std::cout << "proof set\n"; + //std::cout << "proof set\n"; } void boogie_proof::set_model(model* m) { @@ -201,7 +201,7 @@ namespace datalog { ptr_vector todo; todo.push_back(p); ast_mark visited; - std::cout << "get_subst\n" << mk_pp(p, m) << "\n"; + //std::cout << "get_subst\n" << mk_pp(p, m) << "\n"; while (!todo.empty()) { proof* p = todo.back(); todo.pop_back(); diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 6d95b705f..01523e8d2 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -17,6 +17,7 @@ Revision History: --*/ +#include #include #include #include "ast/arith_decl_plugin.h" diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index 565b58c84..46e0b42bf 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -257,12 +257,14 @@ namespace datalog { } container[i-ofs] = container[i]; } +#if 0 if (r_i != removed_col_cnt) { for (unsigned i = 0; i < removed_col_cnt; ++i) { std::cout << removed_cols[i] << " "; } std::cout << " container size: " << n << "\n"; } +#endif SASSERT(r_i==removed_col_cnt); container.resize(n-removed_col_cnt); } diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index ad1994865..c0c3d839c 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -26,6 +26,7 @@ Revision History: #include "ast/scoped_proof.h" #include "ast/bv_decl_plugin.h" #include "muz/rel/tbv.h" +#include namespace datalog { @@ -224,9 +225,9 @@ namespace datalog { } void display_statistics(std::ostream& out) const { - std::cout << "Number of insertions: " << m_stats.m_num_inserts << "\n"; - std::cout << "Number of comparisons: " << m_stats.m_num_comparisons << "\n"; - std::cout << "Number of nodes: " << size() << "\n"; + out << "Number of insertions: " << m_stats.m_num_inserts << "\n" + "Number of comparisons: " << m_stats.m_num_comparisons << "\n" + "Number of nodes: " << size() << "\n"; } void display(std::ostream& out) const { diff --git a/src/muz/rel/aig_exporter.cpp b/src/muz/rel/aig_exporter.cpp index d22f1761b..c8ef1321f 100644 --- a/src/muz/rel/aig_exporter.cpp +++ b/src/muz/rel/aig_exporter.cpp @@ -108,13 +108,11 @@ namespace datalog { rule *r = *II; unsigned numqs = r->get_positive_tail_size(); if (numqs > 1) { - std::cerr << "non-linear clauses not supported\n"; - exit(-1); + throw default_exception("non-linear clauses not supported"); } if (numqs != r->get_uninterpreted_tail_size()) { - std::cerr << "negation of queries not supported\n"; - exit(-1); + throw default_exception("negation of queries not supported"); } exprs.reset(); diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 601b01eaa..106d1b791 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -18,8 +18,6 @@ Revision History: --*/ #pragma once -#include -#include #include #include "ast/ast.h" diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h index 8e56da545..1edacc94f 100644 --- a/src/muz/rel/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -18,7 +18,7 @@ Revision History: --*/ #pragma once -#include +#include #include #include #include "ast/ast.h" diff --git a/src/muz/rel/dl_sparse_table.h b/src/muz/rel/dl_sparse_table.h index a14512730..73e877401 100644 --- a/src/muz/rel/dl_sparse_table.h +++ b/src/muz/rel/dl_sparse_table.h @@ -19,7 +19,6 @@ Revision History: #pragma once -#include #include #include diff --git a/src/muz/rel/dl_table.h b/src/muz/rel/dl_table.h index 967c6e25b..96f68f44c 100644 --- a/src/muz/rel/dl_table.h +++ b/src/muz/rel/dl_table.h @@ -18,7 +18,6 @@ Revision History: --*/ #pragma once -#include #include #include diff --git a/src/muz/spacer/spacer_json.h b/src/muz/spacer/spacer_json.h index 1aa1dfae3..bb330cc03 100644 --- a/src/muz/spacer/spacer_json.h +++ b/src/muz/spacer/spacer_json.h @@ -19,7 +19,7 @@ Notes: #pragma once -#include +#include #include #include "util/ref.h" #include "util/ref_vector.h" diff --git a/src/muz/transforms/dl_mk_array_instantiation.cpp b/src/muz/transforms/dl_mk_array_instantiation.cpp index 5e54afed1..32c622ca2 100644 --- a/src/muz/transforms/dl_mk_array_instantiation.cpp +++ b/src/muz/transforms/dl_mk_array_instantiation.cpp @@ -39,6 +39,7 @@ namespace datalog { } rule_set * mk_array_instantiation::operator()(rule_set const & source) { +#if 0 std::cout<<"Array Instantiation called with parameters :" <<" enforce="< result = alloc(rule_set, m_ctx); dst = result.get(); @@ -55,8 +57,10 @@ namespace datalog { rule & r = *source.get_rule(i); instantiate_rule(r, *result); } +#if 0 std::cout<<"\n\nOutput rules = \n"; result->display(std::cout); +#endif return result.detach(); } diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp index f1aa40886..29e8a604c 100644 --- a/src/opt/opt_parse.cpp +++ b/src/opt/opt_parse.cpp @@ -18,7 +18,7 @@ Revision History: --*/ #include "opt/opt_context.h" #include "opt/opt_parse.h" - +#include class opt_stream_buffer { std::istream & m_stream; diff --git a/src/parsers/smt2/marshal.h b/src/parsers/smt2/marshal.h index 0e996b41f..82eb02786 100644 --- a/src/parsers/smt2/marshal.h +++ b/src/parsers/smt2/marshal.h @@ -12,7 +12,7 @@ Abstract: #pragma once #include -#include +#include #include "ast/ast.h" diff --git a/src/parsers/smt2/smt2scanner.h b/src/parsers/smt2/smt2scanner.h index 07e4ed678..5fb59c7cd 100644 --- a/src/parsers/smt2/smt2scanner.h +++ b/src/parsers/smt2/smt2scanner.h @@ -18,7 +18,7 @@ Revision History: --*/ #pragma once -#include +#include #include "util/symbol.h" #include "util/vector.h" #include "util/rational.h" diff --git a/src/parsers/util/cost_parser.h b/src/parsers/util/cost_parser.h index e3e57e236..70db48171 100644 --- a/src/parsers/util/cost_parser.h +++ b/src/parsers/util/cost_parser.h @@ -26,7 +26,6 @@ class cost_parser : public simple_parser { var_ref_vector m_vars; public: cost_parser(ast_manager & m); - ~cost_parser() override {} expr * parse_int(rational const & r) override; expr * parse_float(rational const & r) override; unsigned add_var(symbol name); diff --git a/src/parsers/util/scanner.cpp b/src/parsers/util/scanner.cpp index 2a5923ee2..db8453ffe 100644 --- a/src/parsers/util/scanner.cpp +++ b/src/parsers/util/scanner.cpp @@ -17,6 +17,7 @@ Revision History: --*/ #include "parsers/util/scanner.h" +#include inline int scanner::read_char() { if (m_is_interactive) { diff --git a/src/parsers/util/simple_parser.cpp b/src/parsers/util/simple_parser.cpp index 0157f1c11..6c3303e5c 100644 --- a/src/parsers/util/simple_parser.cpp +++ b/src/parsers/util/simple_parser.cpp @@ -17,6 +17,7 @@ Revision History: --*/ #include +#include #include #include "parsers/util/simple_parser.h" #include "util/warning.h" diff --git a/src/sat/sat_aig_cuts.cpp b/src/sat/sat_aig_cuts.cpp index 3474029ea..20f62cbdd 100644 --- a/src/sat/sat_aig_cuts.cpp +++ b/src/sat/sat_aig_cuts.cpp @@ -818,11 +818,12 @@ namespace sat { lbool r = s.check(); IF_VERBOSE(10, verbose_stream() << "check: " << r << "\n"); if (r == l_true) { - std::sort(vars.begin(), vars.end()); - s.display(std::cout); - for (auto v : vars) std::cout << v << " := " << s.get_model()[v] << "\n"; - std::string line; - std::getline(std::cin, line); + IF_VERBOSE(0, + std::sort(vars.begin(), vars.end()); + s.display(verbose_stream()); + for (auto v : vars) verbose_stream() << v << " := " << s.get_model()[v] << "\n"; + ); + UNREACHABLE(); } } }; diff --git a/src/sat/sat_cut_simplifier.cpp b/src/sat/sat_cut_simplifier.cpp index c10a35d11..d43219f25 100644 --- a/src/sat/sat_cut_simplifier.cpp +++ b/src/sat/sat_cut_simplifier.cpp @@ -75,8 +75,7 @@ namespace sat { IF_VERBOSE(0, verbose_stream() << "not validated: " << clause << "\n"; s.display(verbose_stream());); - std::string line; - std::getline(std::cin, line); + UNREACHABLE(); } } }; diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index d5ea181c4..9cac2e5ef 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -467,9 +467,7 @@ namespace sat { literal_vector lits(n, c); IF_VERBOSE(0, verbose_stream() << "Verification of " << lits << " failed\n"); // s.display(std::cout); - std::string line; - std::getline(std::cin, line); - exit(0); + UNREACHABLE(); #if 0 SASSERT(false); INVOKE_DEBUGGER(); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b3521452b..ea936600c 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1831,8 +1831,8 @@ namespace sat { if (not_l == l2) continue; if ((~l2).index() >= m_visited.size()) { - s.display(std::cout << l2 << " " << s.num_vars() << " " << m_visited.size() << "\n"); - exit(0); + //s.display(std::cout << l2 << " " << s.num_vars() << " " << m_visited.size() << "\n"); + UNREACHABLE(); } if (m_visited[(~l2).index()]) { res = false; diff --git a/src/sat/smt/array_diagnostics.cpp b/src/sat/smt/array_diagnostics.cpp index c1230ea7f..11ed4384d 100644 --- a/src/sat/smt/array_diagnostics.cpp +++ b/src/sat/smt/array_diagnostics.cpp @@ -93,8 +93,10 @@ namespace array { validate_extensionality(n, k); } expr* x = nullptr, *y = nullptr; +#if 0 if (m.is_eq(n->get_expr(), x, y) && a.is_array(x)) std::cout << ctx.bpp(n) << " " << s().value(n->bool_var()) << "\n"; +#endif if (m.is_eq(n->get_expr(), x, y) && a.is_array(x) && s().value(n->bool_var()) == l_false) validate_extensionality(expr2enode(x), expr2enode(y)); } diff --git a/src/sat/smt/bv_invariant.cpp b/src/sat/smt/bv_invariant.cpp index c73c9806d..490fa53e3 100644 --- a/src/sat/smt/bv_invariant.cpp +++ b/src/sat/smt/bv_invariant.cpp @@ -93,6 +93,7 @@ namespace bv { } while (curr != v); zero_one_bits const& _bits = m_zero_one_bits[v]; +#if 0 if (_bits.size() != num_bits) { std::cout << "v" << v << " " << _bits.size() << " " << num_bits << "\n"; std::cout << "true: " << mk_true() << "\n"; @@ -102,6 +103,7 @@ namespace bv { } while (curr != v); } +#endif SASSERT(_bits.size() == num_bits); VERIFY(_bits.size() == num_bits); bool_vector already_found; diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index ff08ab284..f85872db6 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -1624,7 +1624,7 @@ namespace pb { CTRACE("ba", coeff == 0, display(tout << l << " coeff: " << coeff << "\n", p, true);); if (_debug_conflict) { - std::cout << "coeff " << coeff << "\n"; + IF_VERBOSE(0, verbose_stream() << "coeff " << coeff << "\n";); } SASSERT(coeff > 0); @@ -2256,7 +2256,7 @@ namespace pb { SASSERT(c.lit() == sat::null_literal || c.is_watched(*this, c.lit())); // pre-condition is that the literals, except c.lit(), in c are unwatched. - if (c.id() == _bad_id) std::cout << "recompile: " << c << "\n"; + //if (c.id() == _bad_id) std::cout << "recompile: " << c << "\n"; m_weights.resize(2*s().num_vars(), 0); for (literal l : c) { ++m_weights[l.index()]; diff --git a/src/sat/smt/q_model_fixer.cpp b/src/sat/smt/q_model_fixer.cpp index cdea60d23..52d1a064c 100644 --- a/src/sat/smt/q_model_fixer.cpp +++ b/src/sat/smt/q_model_fixer.cpp @@ -302,9 +302,10 @@ namespace q { return md->v2t[md->values[j]]; }; +#if 0 for (unsigned j = 0; j < sz; ++j) std::cout << mk_pp(md->values[j], m) << "\n"; - +#endif expr* arg = t->get_arg(i); diff --git a/src/shell/lp_frontend.cpp b/src/shell/lp_frontend.cpp index 0234e61b4..70d2cffb1 100644 --- a/src/shell/lp_frontend.cpp +++ b/src/shell/lp_frontend.cpp @@ -15,6 +15,7 @@ Author: #include "util/rlimit.h" #include "util/gparams.h" #include "util/mutex.h" +#include #include #include "smt/params/smt_params_helper.hpp" diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 78102eb6e..c02d4ef03 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -4,6 +4,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ #include +#include #include #include #include "util/gparams.h" diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 49fe8f22f..1b6088c1f 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -42,6 +42,7 @@ Revision History: #include "smt/smt_model_finder.h" #include "smt/smt_parallel.h" #include "smt/smt_arith_value.h" +#include namespace smt { @@ -3943,8 +3944,7 @@ namespace smt { if (m_fparams.m_model_on_final_check) { mk_proto_model(); model_pp(std::cout, *m_proto_model); - std::cout << "END_OF_MODEL\n"; - std::cout.flush(); + std::cout << "END_OF_MODEL" << std::endl; } m_stats.m_num_final_checks++; diff --git a/src/smt/smt_context_stat.cpp b/src/smt/smt_context_stat.cpp index 9899ba322..5b2a541a2 100644 --- a/src/smt/smt_context_stat.cpp +++ b/src/smt/smt_context_stat.cpp @@ -136,9 +136,9 @@ namespace smt { } void context::display_profile_res_sub(std::ostream & out) const { - display_var_occs_histogram(std::cerr); - display_num_min_occs(std::cerr); - std::cerr << "\n"; + display_var_occs_histogram(out); + display_num_min_occs(out); + out << "\n"; } void context::display_profile(std::ostream & out) const { diff --git a/src/smt/smt_statistics.h b/src/smt/smt_statistics.h index 45022b31c..ce773864a 100644 --- a/src/smt/smt_statistics.h +++ b/src/smt/smt_statistics.h @@ -18,8 +18,6 @@ Revision History: --*/ #pragma once -#include - namespace smt { struct statistics { diff --git a/src/smt/theory_array_bapa.cpp b/src/smt/theory_array_bapa.cpp index 7b7f93f02..9379c939f 100644 --- a/src/smt/theory_array_bapa.cpp +++ b/src/smt/theory_array_bapa.cpp @@ -272,12 +272,14 @@ namespace smt { std::cout << smt << "\n"; std::cout << tns << "\n"; #endif +#if 0 if (tns == sz1) { std::cout << "SEEN " << tms << "\n"; } if (tns == sz2) { std::cout << "SEEN " << smt << "\n"; } +#endif 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); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 0dc52c1b2..f24e4746d 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1598,10 +1598,12 @@ namespace smt { lbool is_sat = k.check(); validating = false; // std::cout << is_sat << "\n"; +#if 0 if (is_sat == l_true) { std::cout << A << "\n"; std::cout << B << "\n"; } +#endif SASSERT(is_sat != l_true); return true; } diff --git a/src/tactic/arith/bv2real_rewriter.cpp b/src/tactic/arith/bv2real_rewriter.cpp index 03acc8161..f94965fe9 100644 --- a/src/tactic/arith/bv2real_rewriter.cpp +++ b/src/tactic/arith/bv2real_rewriter.cpp @@ -368,7 +368,6 @@ br_status bv2real_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * tout << "\n";); if (u().memory_exceeded()) { - std::cout << "tactic exception\n"; throw tactic_exception("bv2real-memory exceeded"); } if(f->get_family_id() == m_arith.get_family_id()) { diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index dc906cb32..04750a7c3 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -29,6 +29,7 @@ Notes: #include "ast/fpa_decl_plugin.h" #include "tactic/tactical.h" #include "util/stats.h" +#include #include "tactic/core/collect_statistics_tactic.h" diff --git a/src/util/approx_nat.h b/src/util/approx_nat.h index 08b1274d2..67e672f84 100644 --- a/src/util/approx_nat.h +++ b/src/util/approx_nat.h @@ -19,7 +19,7 @@ Notes: --*/ #pragma once -#include +#include #include class approx_nat { diff --git a/src/util/approx_set.h b/src/util/approx_set.h index 7355437b9..aa6f8d383 100644 --- a/src/util/approx_set.h +++ b/src/util/approx_set.h @@ -17,7 +17,7 @@ Revision History: --*/ #pragma once -#include +#include #include "util/debug.h" template class approx_set_traits; diff --git a/src/util/cmd_context_types.cpp b/src/util/cmd_context_types.cpp index 61a7bd755..9506b93cc 100644 --- a/src/util/cmd_context_types.cpp +++ b/src/util/cmd_context_types.cpp @@ -14,7 +14,6 @@ Author: Notes: --*/ -#include #include "util/cmd_context_types.h" std::ostream & operator<<(std::ostream & out, cmd_arg_kind k) { diff --git a/src/util/cmd_context_types.h b/src/util/cmd_context_types.h index f2d0d2a0c..80e284d90 100644 --- a/src/util/cmd_context_types.h +++ b/src/util/cmd_context_types.h @@ -18,6 +18,7 @@ Notes: #include "util/symbol.h" #include "util/z3_exception.h" +#include #include class rational; class expr; diff --git a/src/util/ext_numeral.h b/src/util/ext_numeral.h index 93bda8d32..cc2682c27 100644 --- a/src/util/ext_numeral.h +++ b/src/util/ext_numeral.h @@ -19,7 +19,7 @@ Revision History: --*/ #pragma once -#include +#include #include "util/debug.h" enum ext_numeral_kind { EN_MINUS_INFINITY, EN_NUMERAL, EN_PLUS_INFINITY }; diff --git a/src/util/permutation.h b/src/util/permutation.h index 2b0623fe9..1fb7dc9e7 100644 --- a/src/util/permutation.h +++ b/src/util/permutation.h @@ -18,7 +18,7 @@ Revision History: --*/ #pragma once -#include +#include #include "util/vector.h" class permutation { diff --git a/src/util/region.h b/src/util/region.h index f3f0d35ab..9f28be908 100644 --- a/src/util/region.h +++ b/src/util/region.h @@ -18,7 +18,7 @@ Revision History: --*/ #pragma once #include -#include +#include #ifdef Z3DEBUG diff --git a/src/util/scoped_ctrl_c.cpp b/src/util/scoped_ctrl_c.cpp index e6214cfab..a3f5ee772 100644 --- a/src/util/scoped_ctrl_c.cpp +++ b/src/util/scoped_ctrl_c.cpp @@ -17,7 +17,6 @@ Revision History: --*/ #include -#include #include "util/scoped_ctrl_c.h" static scoped_ctrl_c * g_obj = nullptr; diff --git a/src/util/statistics.h b/src/util/statistics.h index cea9099d1..32d6bac9f 100644 --- a/src/util/statistics.h +++ b/src/util/statistics.h @@ -18,7 +18,7 @@ Notes: --*/ #pragma once -#include +#include #include "util/vector.h" #include "util/rlimit.h" diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index 78482c0f1..bb170abe7 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -21,7 +21,7 @@ Revision History: #include "util/debug.h" #include -#include +#include #include diff --git a/src/util/stream_buffer.h b/src/util/stream_buffer.h index 104b22eac..f4b916ae7 100644 --- a/src/util/stream_buffer.h +++ b/src/util/stream_buffer.h @@ -20,7 +20,7 @@ Revision History: --*/ #pragma once -#include +#include class stream_buffer { std::istream & m_stream; @@ -40,5 +40,3 @@ public: m_val = m_stream.get(); } }; - - diff --git a/src/util/timeit.cpp b/src/util/timeit.cpp index 2a78f08a3..5db58705f 100644 --- a/src/util/timeit.cpp +++ b/src/util/timeit.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include #include "util/timeit.h" #include "util/memory_manager.h" #include "util/stopwatch.h" #include +#include struct timeit::imp { stopwatch m_watch; @@ -45,9 +45,9 @@ struct timeit::imp { } }; -timeit::timeit(bool enable, char const * msg, std::ostream & out) { +timeit::timeit(bool enable, char const * msg, std::ostream * out) { if (enable) - m_imp = alloc(imp, msg, out); + m_imp = alloc(imp, msg, out ? *out : std::cerr); else m_imp = nullptr; } diff --git a/src/util/timeit.h b/src/util/timeit.h index e29284a04..7b161103f 100644 --- a/src/util/timeit.h +++ b/src/util/timeit.h @@ -21,11 +21,14 @@ Revision History: --*/ #pragma once +#include + class timeit { struct imp; imp * m_imp; public: - timeit(bool enable, char const * msg, std::ostream & out = std::cerr); + timeit(bool enable, char const * msg, std::ostream * out = nullptr); + timeit(bool enable, char const * msg, std::ostream & out) : timeit(enable, msg, &out) {} ~timeit(); }; diff --git a/src/util/util.cpp b/src/util/util.cpp index a59b26990..ee1e734af 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -18,7 +18,7 @@ Revision History: --*/ #include "util/util.h" - +#include static unsigned g_verbosity_level = 0; diff --git a/src/util/util.h b/src/util/util.h index 4cac2123a..f08558f37 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -20,7 +20,7 @@ Revision History: #include "util/debug.h" #include "util/memory_manager.h" -#include +#include #include #include #include diff --git a/src/util/warning.h b/src/util/warning.h index 203fa6fe4..5a74ebd2d 100644 --- a/src/util/warning.h +++ b/src/util/warning.h @@ -17,7 +17,7 @@ Revision History: --*/ #pragma once -#include +#include #include void send_warnings_to_stdout(bool flag); From d9fcfdab34f57bdf43fb1cbb6a2b61fd973cb347 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 17 Jun 2022 14:35:33 +0100 Subject: [PATCH 242/253] fix debug build --- src/ast/ast_smt2_pp.cpp | 1 + src/ast/static_features.cpp | 4 ---- src/nlsat/nlsat_explain.cpp | 1 + src/qe/nlqsat.cpp | 3 +-- src/solver/assertions/asserted_formulas.cpp | 1 + src/tactic/fd_solver/smtfd_solver.cpp | 8 ++++---- src/util/params.cpp | 1 + src/util/small_object_allocator.cpp | 3 +++ 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 59f9ecda6..6ed647a27 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -1401,6 +1401,7 @@ std::ostream& operator<<(std::ostream& out, sort_ref_vector const& e) { #ifdef Z3DEBUG +#include void pp(expr const * n, ast_manager & m) { std::cout << mk_ismt2_pp(const_cast(n), m) << std::endl; } diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp index 9c843d729..ad289cf5e 100644 --- a/src/ast/static_features.cpp +++ b/src/ast/static_features.cpp @@ -445,8 +445,6 @@ void static_features::post_process(expr * e, bool form_ctx, bool or_and_ctx, boo } unsigned depth = 0; - unsigned form_depth = 0; - unsigned or_and_depth = 0; unsigned ite_depth = 0; auto [form_ctx_new, or_and_ctx_new, ite_ctx_new] = new_ctx(e); @@ -533,8 +531,6 @@ void static_features::process_root(expr * e) { if (num_args == 2) m_num_bin_clauses++; unsigned depth = 0; - unsigned form_depth = 0; - unsigned or_and_depth = 0; for (unsigned i = 0; i < num_args; i++) { expr * arg = to_app(e)->get_arg(i); if (m.is_not(arg)) diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index 3f3a9cc89..68a646f92 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -1883,6 +1883,7 @@ namespace nlsat { }; #ifdef Z3DEBUG +#include void pp(nlsat::explain::imp & ex, unsigned num, nlsat::literal const * ls) { ex.display(std::cout, num, ls); } diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index 28cfa5c3e..37924496a 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -387,8 +387,7 @@ namespace qe { for (unsigned i = vars.size(); i-- > 0;) { new_result.reset(); ex.project(vars[i], result.size(), result.data(), new_result); - TRACE("qe", display_project(tout, vars[i], result, new_result);); - TRACE("qe", display_project(std::cout, vars[i], result, new_result);); + TRACE("qe", display_project(tout, vars[i], result, new_result);); result.swap(new_result); } negate_clause(result); diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index d283a4b13..c6a8093ff 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -726,6 +726,7 @@ unsigned asserted_formulas::get_total_size() const { #ifdef Z3DEBUG +#include void pp(asserted_formulas & f) { f.display(std::cout); } diff --git a/src/tactic/fd_solver/smtfd_solver.cpp b/src/tactic/fd_solver/smtfd_solver.cpp index 32f9df9af..18b97d116 100644 --- a/src/tactic/fd_solver/smtfd_solver.cpp +++ b/src/tactic/fd_solver/smtfd_solver.cpp @@ -1756,14 +1756,14 @@ namespace smtfd { expr_ref val0 = (*m_model)(a); expr_ref val1 = (*m_model)(abs(a)); if (is_ground(a) && val0 != val1 && val0->get_sort() == val1->get_sort()) { - std::cout << mk_bounded_pp(a, m, 2) << " := " << val0 << " " << val1 << "\n"; + //std::cout << mk_bounded_pp(a, m, 2) << " := " << val0 << " " << val1 << "\n"; found_bad = true; } } if (found_bad) { - std::cout << "core: " << core << "\n"; - std::cout << *m_model.get() << "\n"; - exit(0); + //std::cout << "core: " << core << "\n"; + //std::cout << *m_model.get() << "\n"; + UNREACHABLE(); }); if (!has_q) { diff --git a/src/util/params.cpp b/src/util/params.cpp index 1745e56fd..04c70b71e 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -1046,6 +1046,7 @@ void params::set_sym(char const * k, symbol const & v) { } #ifdef Z3DEBUG +#include void pp(params_ref const & p) { std::cout << p << std::endl; } diff --git a/src/util/small_object_allocator.cpp b/src/util/small_object_allocator.cpp index b74b094ef..bd980df34 100644 --- a/src/util/small_object_allocator.cpp +++ b/src/util/small_object_allocator.cpp @@ -24,6 +24,9 @@ Revision History: #include "util/util.h" #include "util/vector.h" #include +#ifdef Z3DEBUG +# include +#endif small_object_allocator::small_object_allocator(char const * id) { for (unsigned i = 0; i < NUM_SLOTS; i++) { From fcbbf7ba76ba02fd4e71ce23d8e08af8841ecd1c Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 17 Jun 2022 16:43:34 +0100 Subject: [PATCH 243/253] fix build warning+error in c++ example --- examples/c++/example.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 15a37be31..0217c5cca 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -4,6 +4,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ +#include #include #include"z3++.h" @@ -737,7 +738,7 @@ void tactic_example8() { try { t(g); } - catch (exception) { + catch (exception&) { std::cout << "tactic failed...\n"; } std::cout << "trying again...\n"; From c3407fc30444bc3c95ba5212231dad4423439391 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 17 Jun 2022 17:11:18 +0100 Subject: [PATCH 244/253] fix build of tests --- src/test/algebraic.cpp | 1 + src/test/arith_rewriter.cpp | 2 +- src/test/arith_simplifier_plugin.cpp | 1 + src/test/bdd.cpp | 1 + src/test/bits.cpp | 1 + src/test/chashtable.cpp | 1 + src/test/cube_clause.cpp | 2 +- src/test/datalog_parser.cpp | 1 + src/test/dl_query.cpp | 1 + src/test/dl_table.cpp | 1 + src/test/doc.cpp | 2 +- src/test/egraph.cpp | 1 + src/test/escaped.cpp | 1 + src/test/expr_substitution.cpp | 1 + src/test/f2n.cpp | 1 + src/test/factor_rewriter.cpp | 1 + src/test/get_consequences.cpp | 1 + src/test/heap_trie.cpp | 1 + src/test/hilbert_basis.cpp | 1 + src/test/horn_subsume_model_converter.cpp | 1 + src/test/hwf.cpp | 1 + src/test/interval.cpp | 1 + src/test/karr.cpp | 1 + src/test/model2expr.cpp | 1 + src/test/model_based_opt.cpp | 1 + src/test/model_evaluator.cpp | 2 +- src/test/model_retrieval.cpp | 1 + src/test/mpbq.cpp | 1 + src/test/mpff.cpp | 1 + src/test/mpfx.cpp | 1 + src/test/mpq.cpp | 1 + src/test/mpz.cpp | 1 + src/test/nlarith_util.cpp | 1 + src/test/nlsat.cpp | 1 + src/test/old_interval.cpp | 1 + src/test/parray.cpp | 1 + src/test/pb2bv.cpp | 1 + src/test/pdd.cpp | 1 + src/test/pdd_solver.cpp | 1 + src/test/polynomial.cpp | 1 + src/test/polynorm.cpp | 2 +- src/test/prime_generator.cpp | 1 + src/test/proof_checker.cpp | 1 + src/test/qe_arith.cpp | 1 + src/test/quant_solve.cpp | 1 + src/test/rcf.cpp | 1 + src/test/sat_local_search.cpp | 1 + src/test/sat_lookahead.cpp | 1 + src/test/sat_user_scope.cpp | 1 + src/test/scoped_timer.cpp | 1 + src/test/simplex.cpp | 1 + src/test/solver_pool.cpp | 1 + src/test/sorting_network.cpp | 1 + src/test/substitution.cpp | 1 + src/test/tbv.cpp | 1 + src/test/theory_dl.cpp | 1 + src/test/theory_pb.cpp | 1 + src/test/total_order.cpp | 1 + src/test/trigo.cpp | 1 + src/test/udoc_relation.cpp | 2 +- src/test/uint_set.cpp | 1 + src/test/upolynomial.cpp | 1 + src/test/value_generator.cpp | 1 + src/test/value_sweep.cpp | 1 + src/test/var_subst.cpp | 1 + src/test/vector.cpp | 1 + src/test/zstring.cpp | 1 + 67 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/test/algebraic.cpp b/src/test/algebraic.cpp index 5c91623d0..371997c02 100644 --- a/src/test/algebraic.cpp +++ b/src/test/algebraic.cpp @@ -20,6 +20,7 @@ Notes: #include "math/polynomial/polynomial_var2value.h" #include "util/mpbq.h" #include "util/rlimit.h" +#include static void display_anums(std::ostream & out, scoped_anum_vector const & rs) { out << "numbers in decimal:\n"; diff --git a/src/test/arith_rewriter.cpp b/src/test/arith_rewriter.cpp index da49e58dc..d79f09cc3 100644 --- a/src/test/arith_rewriter.cpp +++ b/src/test/arith_rewriter.cpp @@ -10,7 +10,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/rewriter/th_rewriter.h" #include "model/model.h" #include "parsers/smt2/smt2parser.h" - +#include static expr_ref parse_fml(ast_manager& m, char const* str) { expr_ref result(m); diff --git a/src/test/arith_simplifier_plugin.cpp b/src/test/arith_simplifier_plugin.cpp index 63a6838d4..639fda765 100644 --- a/src/test/arith_simplifier_plugin.cpp +++ b/src/test/arith_simplifier_plugin.cpp @@ -6,6 +6,7 @@ Copyright (c) 2015 Microsoft Corporation #include "smt/arith_eq_solver.h" #include "smt/params/smt_params.h" +#include typedef rational numeral; typedef vector row; diff --git a/src/test/bdd.cpp b/src/test/bdd.cpp index 7c7af2fb4..d08d10a11 100644 --- a/src/test/bdd.cpp +++ b/src/test/bdd.cpp @@ -1,4 +1,5 @@ #include "math/dd/dd_bdd.h" +#include namespace dd { static void test1() { diff --git a/src/test/bits.cpp b/src/test/bits.cpp index 2bef6a0ba..2fc1efe0c 100644 --- a/src/test/bits.cpp +++ b/src/test/bits.cpp @@ -10,6 +10,7 @@ Copyright (c) 2015 Microsoft Corporation #include "util/vector.h" #include "util/mpz.h" #include "util/bit_util.h" +#include static void tst_shl(unsigned src_sz, unsigned const * src, unsigned k, unsigned dst_sz, unsigned const * dst, bool trace = true) { diff --git a/src/test/chashtable.cpp b/src/test/chashtable.cpp index 8e4dadf99..773509aba 100644 --- a/src/test/chashtable.cpp +++ b/src/test/chashtable.cpp @@ -20,6 +20,7 @@ Revision History: #include "util/hashtable.h" #include "util/hash.h" #include "util/util.h" +#include typedef chashtable > int_table; typedef cmap > int_map; diff --git a/src/test/cube_clause.cpp b/src/test/cube_clause.cpp index 0c783277b..920c5c57c 100644 --- a/src/test/cube_clause.cpp +++ b/src/test/cube_clause.cpp @@ -1,7 +1,7 @@ #include "ast/reg_decl_plugins.h" #include "solver/solver_pool.h" #include "smt/smt_solver.h" - +#include void tst_cube_clause() { ast_manager m; diff --git a/src/test/datalog_parser.cpp b/src/test/datalog_parser.cpp index ca5e94f75..ee69bff8b 100644 --- a/src/test/datalog_parser.cpp +++ b/src/test/datalog_parser.cpp @@ -11,6 +11,7 @@ Copyright (c) 2015 Microsoft Corporation #include "muz/fp/dl_register_engine.h" #include "smt/params/smt_params.h" #include "ast/reg_decl_plugins.h" +#include using namespace datalog; diff --git a/src/test/dl_query.cpp b/src/test/dl_query.cpp index 2181f97ad..34dc7e020 100644 --- a/src/test/dl_query.cpp +++ b/src/test/dl_query.cpp @@ -13,6 +13,7 @@ Copyright (c) 2015 Microsoft Corporation #include "util/stopwatch.h" #include "ast/reg_decl_plugins.h" #include "muz/rel/dl_relation_manager.h" +#include using namespace datalog; diff --git a/src/test/dl_table.cpp b/src/test/dl_table.cpp index b3082cc6a..0f429d223 100644 --- a/src/test/dl_table.cpp +++ b/src/test/dl_table.cpp @@ -6,6 +6,7 @@ Copyright (c) 2015 Microsoft Corporation #include "muz/rel/dl_table.h" #include "muz/fp/dl_register_engine.h" #include "muz/rel/dl_relation_manager.h" +#include typedef datalog::table_base* (*mk_table_fn)(datalog::relation_manager& m, datalog::table_signature& sig); diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 4d84ff964..f1b5cf2ce 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -17,7 +17,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/ast_util.h" #include "ast/rewriter/expr_safe_replace.h" #include "ast/rewriter/th_rewriter.h" - +#include static void tst_doc1(unsigned n) { doc_manager m(n); diff --git a/src/test/egraph.cpp b/src/test/egraph.cpp index 508384f8f..a3c61abad 100644 --- a/src/test/egraph.cpp +++ b/src/test/egraph.cpp @@ -9,6 +9,7 @@ Copyright (c) 2020 Microsoft Corporation #include "ast/reg_decl_plugins.h" #include "ast/ast_pp.h" #include "ast/arith_decl_plugin.h" +#include static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { return expr_ref(m.mk_const(symbol(name), s), m); diff --git a/src/test/escaped.cpp b/src/test/escaped.cpp index 9bc2aecec..4fb85960d 100644 --- a/src/test/escaped.cpp +++ b/src/test/escaped.cpp @@ -17,6 +17,7 @@ Revision History: --*/ #include "util/util.h" +#include void tst_escaped() { std::cout << "[" << escaped("\"hello\"\"world\"\n\n") << "]\n"; diff --git a/src/test/expr_substitution.cpp b/src/test/expr_substitution.cpp index 3b74535e7..c66681c1b 100644 --- a/src/test/expr_substitution.cpp +++ b/src/test/expr_substitution.cpp @@ -13,6 +13,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/arith_decl_plugin.h" #include "ast/reg_decl_plugins.h" #include "ast/rewriter/th_rewriter.h" +#include expr* mk_bv_xor(bv_util& bv, expr* a, expr* b) { expr* args[2]; diff --git a/src/test/f2n.cpp b/src/test/f2n.cpp index 7831a31cf..211cf6013 100644 --- a/src/test/f2n.cpp +++ b/src/test/f2n.cpp @@ -18,6 +18,7 @@ Revision History: #include "util/f2n.h" #include "util/hwf.h" #include "util/mpf.h" +#include static void tst1() { hwf_manager hm; diff --git a/src/test/factor_rewriter.cpp b/src/test/factor_rewriter.cpp index 486221e5b..223527c11 100644 --- a/src/test/factor_rewriter.cpp +++ b/src/test/factor_rewriter.cpp @@ -8,6 +8,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/bv_decl_plugin.h" #include "ast/ast_pp.h" #include "ast/reg_decl_plugins.h" +#include void tst_factor_rewriter() { ast_manager m; diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 0e5124d58..d8c070b6d 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -12,6 +12,7 @@ Copyright (c) 2016 Microsoft Corporation #include "tactic/tactic.h" #include "model/model_smt2_pp.h" #include "tactic/fd_solver/fd_solver.h" +#include static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { return expr_ref(m.mk_const(symbol(name), s), m); diff --git a/src/test/heap_trie.cpp b/src/test/heap_trie.cpp index b6f651633..a86e0e741 100644 --- a/src/test/heap_trie.cpp +++ b/src/test/heap_trie.cpp @@ -5,6 +5,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ #include "math/hilbert/heap_trie.h" +#include struct unsigned_le { static bool le(unsigned i, unsigned j) { return i <= j; } diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index 06446e8e9..93c58374e 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -15,6 +15,7 @@ Copyright (c) 2015 Microsoft Corporation #include "util/rlimit.h" #include #include +#include #include static bool g_use_ordered_support = false; diff --git a/src/test/horn_subsume_model_converter.cpp b/src/test/horn_subsume_model_converter.cpp index 6d4dcc26f..aea819d7a 100644 --- a/src/test/horn_subsume_model_converter.cpp +++ b/src/test/horn_subsume_model_converter.cpp @@ -9,6 +9,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/arith_decl_plugin.h" #include "model/model_smt2_pp.h" #include "ast/reg_decl_plugins.h" +#include void tst_horn_subsume_model_converter() { ast_manager m; diff --git a/src/test/hwf.cpp b/src/test/hwf.cpp index 697673473..8a019ec02 100644 --- a/src/test/hwf.cpp +++ b/src/test/hwf.cpp @@ -19,6 +19,7 @@ Revision History: #include "util/hwf.h" #include "util/f2n.h" #include "util/rational.h" +#include static void bug_set_double() { hwf_manager m; diff --git a/src/test/interval.cpp b/src/test/interval.cpp index 5180912f5..f289871de 100644 --- a/src/test/interval.cpp +++ b/src/test/interval.cpp @@ -23,6 +23,7 @@ Revision History: #include "ast/ast.h" #include "util/debug.h" #include "util/rlimit.h" +#include template class interval_manager; typedef im_default_config::interval interval; diff --git a/src/test/karr.cpp b/src/test/karr.cpp index cf5867324..2ec13ecc2 100644 --- a/src/test/karr.cpp +++ b/src/test/karr.cpp @@ -5,6 +5,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ #include "util/rlimit.h" #include "math/hilbert/hilbert_basis.h" +#include /* Test generation of linear congruences a la Karr. diff --git a/src/test/model2expr.cpp b/src/test/model2expr.cpp index 41047825c..5163abade 100644 --- a/src/test/model2expr.cpp +++ b/src/test/model2expr.cpp @@ -9,6 +9,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/arith_decl_plugin.h" #include "model/model_smt2_pp.h" #include "ast/reg_decl_plugins.h" +#include void tst_model2expr() { ast_manager m; diff --git a/src/test/model_based_opt.cpp b/src/test/model_based_opt.cpp index 1bae7435f..b307f85e4 100644 --- a/src/test/model_based_opt.cpp +++ b/src/test/model_based_opt.cpp @@ -1,6 +1,7 @@ #include "math/simplex/model_based_opt.h" #include "util/util.h" #include "util/uint_set.h" +#include typedef opt::model_based_opt::var var; diff --git a/src/test/model_evaluator.cpp b/src/test/model_evaluator.cpp index 3e1c95617..f4a64d4dc 100644 --- a/src/test/model_evaluator.cpp +++ b/src/test/model_evaluator.cpp @@ -4,7 +4,7 @@ #include "ast/arith_decl_plugin.h" #include "ast/reg_decl_plugins.h" #include "ast/ast_pp.h" - +#include void tst_model_evaluator() { ast_manager m; diff --git a/src/test/model_retrieval.cpp b/src/test/model_retrieval.cpp index e0fd28088..415a5772c 100644 --- a/src/test/model_retrieval.cpp +++ b/src/test/model_retrieval.cpp @@ -13,6 +13,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/array_decl_plugin.h" #include "model/model_v2_pp.h" #include "ast/reg_decl_plugins.h" +#include void tst_model_retrieval() { diff --git a/src/test/mpbq.cpp b/src/test/mpbq.cpp index 4dc92d80d..16dead4cf 100644 --- a/src/test/mpbq.cpp +++ b/src/test/mpbq.cpp @@ -17,6 +17,7 @@ Revision History: --*/ #include "util/mpbq.h" +#include static void tst1() { unsynch_mpz_manager zm; diff --git a/src/test/mpff.cpp b/src/test/mpff.cpp index 83c500b49..b03cc5f2e 100644 --- a/src/test/mpff.cpp +++ b/src/test/mpff.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include #include +#include #include "util/mpff.h" #include "util/mpz.h" #include "util/mpq.h" diff --git a/src/test/mpfx.cpp b/src/test/mpfx.cpp index f5cf7e2fb..7752157fd 100644 --- a/src/test/mpfx.cpp +++ b/src/test/mpfx.cpp @@ -17,6 +17,7 @@ Revision History: --*/ #include "util/mpfx.h" +#include static void tst1() { mpfx_manager m; diff --git a/src/test/mpq.cpp b/src/test/mpq.cpp index 6294a97f7..6c15c8556 100644 --- a/src/test/mpq.cpp +++ b/src/test/mpq.cpp @@ -20,6 +20,7 @@ Revision History: #include "util/mpq.h" #include "util/rational.h" #include "util/timeit.h" +#include static void tst0() { synch_mpq_manager m; diff --git a/src/test/mpz.cpp b/src/test/mpz.cpp index fc2177ca2..694f13e96 100644 --- a/src/test/mpz.cpp +++ b/src/test/mpz.cpp @@ -21,6 +21,7 @@ Revision History: #include "util/rational.h" #include "util/timeit.h" #include "util/scoped_numeral.h" +#include static void tst1() { synch_mpz_manager m; diff --git a/src/test/nlarith_util.cpp b/src/test/nlarith_util.cpp index 4769c1591..d6105cf82 100644 --- a/src/test/nlarith_util.cpp +++ b/src/test/nlarith_util.cpp @@ -8,6 +8,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/arith_decl_plugin.h" #include "ast/ast_pp.h" #include "ast/reg_decl_plugins.h" +#include void tst_nlarith_util() { ast_manager M; diff --git a/src/test/nlsat.cpp b/src/test/nlsat.cpp index 44d4120fe..9274938ef 100644 --- a/src/test/nlsat.cpp +++ b/src/test/nlsat.cpp @@ -24,6 +24,7 @@ Notes: #include "nlsat/nlsat_explain.h" #include "math/polynomial/polynomial_cache.h" #include "util/rlimit.h" +#include nlsat::interval_set_ref tst_interval(nlsat::interval_set_ref const & s1, nlsat::interval_set_ref const & s2, diff --git a/src/test/old_interval.cpp b/src/test/old_interval.cpp index 751f6fdbe..bc2f9fb13 100644 --- a/src/test/old_interval.cpp +++ b/src/test/old_interval.cpp @@ -17,6 +17,7 @@ Revision History: --*/ #include "smt/old_interval.h" +#include static void tst1() { ext_numeral inf(true); diff --git a/src/test/parray.cpp b/src/test/parray.cpp index 6aef4f359..7e6b78cd8 100644 --- a/src/test/parray.cpp +++ b/src/test/parray.cpp @@ -19,6 +19,7 @@ Revision History: #include "util/parray.h" #include "util/small_object_allocator.h" #include "ast/ast.h" +#include template struct int_parray_config { diff --git a/src/test/pb2bv.cpp b/src/test/pb2bv.cpp index 169df85ad..8772fec92 100644 --- a/src/test/pb2bv.cpp +++ b/src/test/pb2bv.cpp @@ -19,6 +19,7 @@ Copyright (c) 2015 Microsoft Corporation #include "tactic/fd_solver/fd_solver.h" #include "solver/solver.h" #include "ast/arith_decl_plugin.h" +#include static void test1() { ast_manager m; diff --git a/src/test/pdd.cpp b/src/test/pdd.cpp index b10abb891..b0cbb657c 100644 --- a/src/test/pdd.cpp +++ b/src/test/pdd.cpp @@ -1,4 +1,5 @@ #include "math/dd/dd_pdd.h" +#include namespace dd { diff --git a/src/test/pdd_solver.cpp b/src/test/pdd_solver.cpp index 7a1c07131..a86504266 100644 --- a/src/test/pdd_solver.cpp +++ b/src/test/pdd_solver.cpp @@ -9,6 +9,7 @@ #include "tactic/goal.h" #include "tactic/tactic.h" #include "tactic/bv/bit_blaster_tactic.h" +#include namespace dd { void print_eqs(ptr_vector const& eqs) { diff --git a/src/test/polynomial.cpp b/src/test/polynomial.cpp index 091d03c61..f259c4234 100644 --- a/src/test/polynomial.cpp +++ b/src/test/polynomial.cpp @@ -22,6 +22,7 @@ Notes: #include "math/polynomial/polynomial_cache.h" #include "math/polynomial/linear_eq_solver.h" #include "util/rlimit.h" +#include static void tst1() { std::cout << "\n----- Basic testing -------\n"; diff --git a/src/test/polynorm.cpp b/src/test/polynorm.cpp index 58481938b..80ff74904 100644 --- a/src/test/polynorm.cpp +++ b/src/test/polynorm.cpp @@ -10,7 +10,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/reg_decl_plugins.h" #include "ast/rewriter/arith_rewriter.h" #include "ast/ast_pp.h" - +#include static expr_ref parse_fml(ast_manager& m, char const* str) { expr_ref result(m); diff --git a/src/test/prime_generator.cpp b/src/test/prime_generator.cpp index 3a63b805a..a60418777 100644 --- a/src/test/prime_generator.cpp +++ b/src/test/prime_generator.cpp @@ -18,6 +18,7 @@ Notes: --*/ #include "util/mpz.h" #include "util/prime_generator.h" +#include void tst_prime_generator() { unsynch_mpz_manager m; diff --git a/src/test/proof_checker.cpp b/src/test/proof_checker.cpp index 7a9b619cd..bc3dd39ad 100644 --- a/src/test/proof_checker.cpp +++ b/src/test/proof_checker.cpp @@ -6,6 +6,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/proofs/proof_checker.h" #include "ast/ast_ll_pp.h" +#include void tst_checker1() { ast_manager m(PGM_ENABLED); diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index ab268a651..859d7f2e5 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -15,6 +15,7 @@ Copyright (c) 2015 Microsoft Corporation #include "smt/smt_context.h" #include "ast/expr_abstract.h" #include "ast/rewriter/expr_safe_replace.h" +#include static expr_ref parse_fml(ast_manager& m, char const* str) { expr_ref result(m); diff --git a/src/test/quant_solve.cpp b/src/test/quant_solve.cpp index fb89d1c8a..08c857809 100644 --- a/src/test/quant_solve.cpp +++ b/src/test/quant_solve.cpp @@ -18,6 +18,7 @@ Copyright (c) 2015 Microsoft Corporation #include "model/model_smt2_pp.h" #include "parsers/smt2/smt2parser.h" #include "ast/rewriter/var_subst.h" +#include static void validate_quant_solution(ast_manager& m, expr* fml, expr* guard, qe::def_vector const& defs) { // verify: diff --git a/src/test/rcf.cpp b/src/test/rcf.cpp index c577cba40..9b98d9e83 100644 --- a/src/test/rcf.cpp +++ b/src/test/rcf.cpp @@ -19,6 +19,7 @@ Notes: #include "math/realclosure/realclosure.h" #include "math/realclosure/mpz_matrix.h" #include "util/rlimit.h" +#include static void tst1() { unsynch_mpq_manager qm; diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index 7ba9e61f7..525c12f25 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -3,6 +3,7 @@ #include "util/cancel_eh.h" #include "util/scoped_ctrl_c.h" #include "util/scoped_timer.h" +#include static bool build_instance(char const * filename, sat::solver& s, sat::local_search& local_search) { diff --git a/src/test/sat_lookahead.cpp b/src/test/sat_lookahead.cpp index 23c4a4738..24dd7e919 100644 --- a/src/test/sat_lookahead.cpp +++ b/src/test/sat_lookahead.cpp @@ -3,6 +3,7 @@ #include "util/statistics.h" #include "sat/sat_lookahead.h" #include "sat/dimacs.h" +#include static void display_model(sat::model const & m) { for (unsigned i = 1; i < m.size(); i++) { diff --git a/src/test/sat_user_scope.cpp b/src/test/sat_user_scope.cpp index aeba0bf04..c3013cf82 100644 --- a/src/test/sat_user_scope.cpp +++ b/src/test/sat_user_scope.cpp @@ -6,6 +6,7 @@ Copyright (c) 2015 Microsoft Corporation #include "sat/sat_solver.h" #include "util/util.h" +#include typedef sat::literal_vector clause_t; typedef vector clauses_t; diff --git a/src/test/scoped_timer.cpp b/src/test/scoped_timer.cpp index ff9d52b06..742ea2652 100644 --- a/src/test/scoped_timer.cpp +++ b/src/test/scoped_timer.cpp @@ -9,6 +9,7 @@ #include "util/trace.h" #include #include +#include class test_scoped_eh : public event_handler { std::atomic m_called = false; diff --git a/src/test/simplex.cpp b/src/test/simplex.cpp index 5c52642bd..2e59b4171 100644 --- a/src/test/simplex.cpp +++ b/src/test/simplex.cpp @@ -11,6 +11,7 @@ Copyright (c) 2015 Microsoft Corporation #include "util/vector.h" #include "util/rational.h" #include "util/rlimit.h" +#include #define R rational typedef simplex::simplex Simplex; diff --git a/src/test/solver_pool.cpp b/src/test/solver_pool.cpp index 4a2e533bf..025106ad1 100644 --- a/src/test/solver_pool.cpp +++ b/src/test/solver_pool.cpp @@ -1,6 +1,7 @@ #include "ast/reg_decl_plugins.h" #include "solver/solver_pool.h" #include "smt/smt_solver.h" +#include void tst_solver_pool() { ast_manager m; diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index b86f6ad87..cd22ac9ae 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -14,6 +14,7 @@ Copyright (c) 2015 Microsoft Corporation #include "model/model_smt2_pp.h" #include "smt/smt_kernel.h" #include "smt/params/smt_params.h" +#include struct ast_ext { ast_manager& m; diff --git a/src/test/substitution.cpp b/src/test/substitution.cpp index 9b28927fc..77087c84c 100644 --- a/src/test/substitution.cpp +++ b/src/test/substitution.cpp @@ -12,6 +12,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/ast_pp.h" #include "ast/arith_decl_plugin.h" #include "ast/reg_decl_plugins.h" +#include void tst_substitution() { diff --git a/src/test/tbv.cpp b/src/test/tbv.cpp index c921551bd..6107fad85 100644 --- a/src/test/tbv.cpp +++ b/src/test/tbv.cpp @@ -5,6 +5,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ #include "muz/rel/tbv.h" +#include static void tst1(unsigned num_bits) { tbv_manager m(num_bits); diff --git a/src/test/theory_dl.cpp b/src/test/theory_dl.cpp index 5b11069aa..ad77195d5 100644 --- a/src/test/theory_dl.cpp +++ b/src/test/theory_dl.cpp @@ -10,6 +10,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/reg_decl_plugins.h" #include "smt/smt_context.h" #include "model/model_v2_pp.h" +#include void tst_theory_dl() { ast_manager m; diff --git a/src/test/theory_pb.cpp b/src/test/theory_pb.cpp index a6ccf733d..72a48fa2a 100644 --- a/src/test/theory_pb.cpp +++ b/src/test/theory_pb.cpp @@ -10,6 +10,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/reg_decl_plugins.h" #include "smt/theory_pb.h" #include "ast/rewriter/th_rewriter.h" +#include static unsigned populate_literals(unsigned k, smt::literal_vector& lits) { ENSURE(k < (1u << lits.size())); diff --git a/src/test/total_order.cpp b/src/test/total_order.cpp index a2ee234db..5f4ffbcad 100644 --- a/src/test/total_order.cpp +++ b/src/test/total_order.cpp @@ -19,6 +19,7 @@ Revision History: #include "util/total_order.h" #include "util/timeit.h" +#include static void tst1() { uint_total_order to; diff --git a/src/test/trigo.cpp b/src/test/trigo.cpp index 686800162..f03d5b3da 100644 --- a/src/test/trigo.cpp +++ b/src/test/trigo.cpp @@ -24,6 +24,7 @@ Revision History: #include "util/debug.h" #include "test/im_float_config.h" #include "util/rlimit.h" +#include #define PREC 100000 diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 0b49567b0..91e607679 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -22,7 +22,7 @@ Copyright (c) 2015 Microsoft Corporation #include "muz/rel/rel_context.h" #include "ast/bv_decl_plugin.h" #include "muz/rel/check_relation.h" - +#include class udoc_tester { typedef datalog::relation_base relation_base; diff --git a/src/test/uint_set.cpp b/src/test/uint_set.cpp index 656eaf1b3..f0c170860 100644 --- a/src/test/uint_set.cpp +++ b/src/test/uint_set.cpp @@ -19,6 +19,7 @@ Revision History: #include "util/uint_set.h" #include "util/vector.h" +#include static void tst1(unsigned n) { uint_set s1; diff --git a/src/test/upolynomial.cpp b/src/test/upolynomial.cpp index a020e104f..aee3086ae 100644 --- a/src/test/upolynomial.cpp +++ b/src/test/upolynomial.cpp @@ -19,6 +19,7 @@ Notes: #include "math/polynomial/upolynomial.h" #include "util/timeit.h" #include "util/rlimit.h" +#include static void tst1() { reslimit rl; diff --git a/src/test/value_generator.cpp b/src/test/value_generator.cpp index ecde58855..082a2aeba 100644 --- a/src/test/value_generator.cpp +++ b/src/test/value_generator.cpp @@ -4,6 +4,7 @@ #include "ast/datatype_decl_plugin.h" #include "ast/seq_decl_plugin.h" #include "ast/array_decl_plugin.h" +#include static void list(unsigned bound, ast_manager& m, sort* s) { value_generator gen(m); diff --git a/src/test/value_sweep.cpp b/src/test/value_sweep.cpp index 015a8be7c..7283c8e93 100644 --- a/src/test/value_sweep.cpp +++ b/src/test/value_sweep.cpp @@ -3,6 +3,7 @@ #include "ast/ast_pp.h" #include "ast/seq_decl_plugin.h" #include "ast/array_decl_plugin.h" +#include void tst_value_sweep() { ast_manager m; diff --git a/src/test/var_subst.cpp b/src/test/var_subst.cpp index 12646798f..a39c0e7f1 100644 --- a/src/test/var_subst.cpp +++ b/src/test/var_subst.cpp @@ -23,6 +23,7 @@ Revision History: #include "ast/array_decl_plugin.h" #include "ast/for_each_expr.h" #include "ast/reg_decl_plugins.h" +#include namespace find_q { struct proc { diff --git a/src/test/vector.cpp b/src/test/vector.cpp index c9a93dee4..fe0b50ddb 100644 --- a/src/test/vector.cpp +++ b/src/test/vector.cpp @@ -17,6 +17,7 @@ Revision History: --*/ #include "util/vector.h" +#include static void tst1() { svector v1; diff --git a/src/test/zstring.cpp b/src/test/zstring.cpp index ffeda7fce..bd79d873f 100644 --- a/src/test/zstring.cpp +++ b/src/test/zstring.cpp @@ -1,6 +1,7 @@ #include "util/debug.h" #include "util/trace.h" #include "util/zstring.h" +#include // Encode and check for roundtrip all printable ASCII characters. static void tst_ascii_roundtrip() { From f3c00a0a034cc0eace3260e0914b7741eeae48bd Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 17 Jun 2022 18:05:19 +0100 Subject: [PATCH 245/253] attempt to fix windows build bot --- src/test/diff_logic.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/diff_logic.cpp b/src/test/diff_logic.cpp index 5147bdf31..9a3403ad2 100644 --- a/src/test/diff_logic.cpp +++ b/src/test/diff_logic.cpp @@ -22,6 +22,7 @@ Revision History: #include "smt/smt_literal.h" #include "util/util.h" #include "util/debug.h" +#include struct diff_logic_ext { typedef rational numeral; From f08e3d70a950d9b13a3951481ca30ddc03786f67 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 17 Jun 2022 21:15:54 +0100 Subject: [PATCH 246/253] attempt to fix windows build bot --- src/test/dl_product_relation.cpp | 1 + src/test/dl_relation.cpp | 1 + src/test/matcher.cpp | 2 +- src/test/quant_elim.cpp | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/dl_product_relation.cpp b/src/test/dl_product_relation.cpp index 352748087..e418d5ea0 100644 --- a/src/test/dl_product_relation.cpp +++ b/src/test/dl_product_relation.cpp @@ -11,6 +11,7 @@ Copyright (c) 2015 Microsoft Corporation #include "muz/rel/dl_finite_product_relation.h" #include "muz/rel/dl_sparse_table.h" #include "muz/rel/rel_context.h" +#include namespace datalog { diff --git a/src/test/dl_relation.cpp b/src/test/dl_relation.cpp index 1940de3e9..a69e44cd2 100644 --- a/src/test/dl_relation.cpp +++ b/src/test/dl_relation.cpp @@ -14,6 +14,7 @@ Copyright (c) 2015 Microsoft Corporation #include "muz/rel/dl_bound_relation.h" #include "muz/rel/dl_product_relation.h" #include "util/util.h" +#include namespace datalog { diff --git a/src/test/matcher.cpp b/src/test/matcher.cpp index 68f37ccb6..6d5576714 100644 --- a/src/test/matcher.cpp +++ b/src/test/matcher.cpp @@ -20,7 +20,7 @@ Revision History: #include "ast/substitution/matcher.h" #include "ast/ast_pp.h" #include "ast/reg_decl_plugins.h" - +#include void tst_match(ast_manager & m, app * t, app * i) { substitution s(m); diff --git a/src/test/quant_elim.cpp b/src/test/quant_elim.cpp index f376e2c1d..8fd5416a1 100644 --- a/src/test/quant_elim.cpp +++ b/src/test/quant_elim.cpp @@ -11,7 +11,7 @@ Copyright (c) 2015 Microsoft Corporation #include "util/lbool.h" #include #include "ast/reg_decl_plugins.h" - +#include #if 0 static void test_qe(ast_manager& m, lbool expected_outcome, expr* fml, char const* option) { From 2fa60aa43ce3cbf52696d185ecfca479be1fb292 Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Sun, 19 Jun 2022 19:49:25 +0200 Subject: [PATCH 247/253] Added function to select the next variable to split on (User-Propagator) (#6096) * Added function to select the next variable to split on * Fixed typo * Small fixes * uint -> int --- scripts/update_api.py | 22 +++++---- src/api/api_solver.cpp | 8 +++ src/api/c++/z3++.h | 5 ++ src/api/z3_api.h | 17 +++++-- src/api/z3_fixedpoint.h | 4 +- src/api/z3_optimization.h | 2 +- src/api/z3_spacer.h | 2 +- src/sat/sat_extension.h | 6 ++- src/sat/sat_solver.cpp | 79 ++++++++++++++++++------------ src/sat/sat_solver.h | 1 + src/sat/smt/user_solver.cpp | 47 ++++++++++++++++++ src/sat/smt/user_solver.h | 45 ++++++++++------- src/smt/smt_context.cpp | 48 +++++++++++------- src/smt/smt_context.h | 2 + src/smt/theory_user_propagator.cpp | 60 +++++++++++++++++------ src/smt/theory_user_propagator.h | 10 +++- src/tactic/user_propagator_base.h | 1 + 17 files changed, 255 insertions(+), 104 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 6c932d8ca..45899ddef 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -61,6 +61,7 @@ DOUBLE = 12 FLOAT = 13 CHAR = 14 CHAR_PTR = 15 +LBOOL = 16 FIRST_FN_ID = 50 @@ -74,25 +75,25 @@ def is_fn(ty): Type2Str = { VOID : 'void', VOID_PTR : 'void*', INT : 'int', UINT : 'unsigned', INT64 : 'int64_t', UINT64 : 'uint64_t', DOUBLE : 'double', FLOAT : 'float', STRING : 'Z3_string', STRING_PTR : 'Z3_string_ptr', BOOL : 'bool', SYMBOL : 'Z3_symbol', - PRINT_MODE : 'Z3_ast_print_mode', ERROR_CODE : 'Z3_error_code', CHAR: 'char', CHAR_PTR: 'Z3_char_ptr' + PRINT_MODE : 'Z3_ast_print_mode', ERROR_CODE : 'Z3_error_code', CHAR: 'char', CHAR_PTR: 'Z3_char_ptr', LBOOL : 'Z3_lbool' } Type2PyStr = { VOID_PTR : 'ctypes.c_void_p', INT : 'ctypes.c_int', UINT : 'ctypes.c_uint', INT64 : 'ctypes.c_longlong', UINT64 : 'ctypes.c_ulonglong', DOUBLE : 'ctypes.c_double', FLOAT : 'ctypes.c_float', STRING : 'ctypes.c_char_p', STRING_PTR : 'ctypes.POINTER(ctypes.c_char_p)', BOOL : 'ctypes.c_bool', SYMBOL : 'Symbol', - PRINT_MODE : 'ctypes.c_uint', ERROR_CODE : 'ctypes.c_uint', CHAR : 'ctypes.c_char', CHAR_PTR: 'ctypes.POINTER(ctypes.c_char)' + PRINT_MODE : 'ctypes.c_uint', ERROR_CODE : 'ctypes.c_uint', CHAR : 'ctypes.c_char', CHAR_PTR: 'ctypes.POINTER(ctypes.c_char)', LBOOL : 'ctypes.c_int' } # Mapping to .NET types Type2Dotnet = { VOID : 'void', VOID_PTR : 'IntPtr', INT : 'int', UINT : 'uint', INT64 : 'Int64', UINT64 : 'UInt64', DOUBLE : 'double', FLOAT : 'float', STRING : 'string', STRING_PTR : 'byte**', BOOL : 'byte', SYMBOL : 'IntPtr', - PRINT_MODE : 'uint', ERROR_CODE : 'uint', CHAR : 'char', CHAR_PTR : 'IntPtr' } + PRINT_MODE : 'uint', ERROR_CODE : 'uint', CHAR : 'char', CHAR_PTR : 'IntPtr', LBOOL : 'int' } # Mapping to ML types Type2ML = { VOID : 'unit', VOID_PTR : 'ptr', INT : 'int', UINT : 'int', INT64 : 'int', UINT64 : 'int', DOUBLE : 'float', FLOAT : 'float', STRING : 'string', STRING_PTR : 'char**', - BOOL : 'bool', SYMBOL : 'z3_symbol', PRINT_MODE : 'int', ERROR_CODE : 'int', CHAR : 'char', CHAR_PTR : 'string' } + BOOL : 'bool', SYMBOL : 'z3_symbol', PRINT_MODE : 'int', ERROR_CODE : 'int', CHAR : 'char', CHAR_PTR : 'string', LBOOL : 'int' } Closures = [] @@ -522,11 +523,11 @@ def mk_dotnet_wrappers(dotnet): Type2Java = { VOID : 'void', VOID_PTR : 'long', INT : 'int', UINT : 'int', INT64 : 'long', UINT64 : 'long', DOUBLE : 'double', FLOAT : 'float', STRING : 'String', STRING_PTR : 'StringPtr', - BOOL : 'boolean', SYMBOL : 'long', PRINT_MODE : 'int', ERROR_CODE : 'int', CHAR : 'char', CHAR_PTR : 'long' } + BOOL : 'boolean', SYMBOL : 'long', PRINT_MODE : 'int', ERROR_CODE : 'int', CHAR : 'char', CHAR_PTR : 'long', LBOOL : 'int' } Type2JavaW = { VOID : 'void', VOID_PTR : 'jlong', INT : 'jint', UINT : 'jint', INT64 : 'jlong', UINT64 : 'jlong', DOUBLE : 'jdouble', FLOAT : 'jfloat', STRING : 'jstring', STRING_PTR : 'jobject', - BOOL : 'jboolean', SYMBOL : 'jlong', PRINT_MODE : 'jint', ERROR_CODE : 'jint', CHAR : 'jchar', CHAR_PTR : 'jlong'} + BOOL : 'jboolean', SYMBOL : 'jlong', PRINT_MODE : 'jint', ERROR_CODE : 'jint', CHAR : 'jchar', CHAR_PTR : 'jlong', LBOOL : 'jint'} def type2java(ty): global Type2Java @@ -1024,6 +1025,9 @@ def def_API(name, result, params): elif ty == VOID_PTR: log_c.write(" P(0);\n") exe_c.write("in.get_obj_addr(%s)" % i) + elif ty == LBOOL: + log_c.write(" I(static_cast(a%s));\n" % i) + exe_c.write("static_cast<%s>(in.get_int(%s))" % (type2str(ty), i)) elif ty == PRINT_MODE or ty == ERROR_CODE: log_c.write(" U(static_cast(a%s));\n" % i) exe_c.write("static_cast<%s>(in.get_uint(%s))" % (type2str(ty), i)) @@ -1298,7 +1302,7 @@ def ml_unwrap(t, ts, s): return '(' + ts + ') String_val(' + s + ')' elif t == BOOL or (type2str(t) == 'bool'): return '(' + ts + ') Bool_val(' + s + ')' - elif t == INT or t == PRINT_MODE or t == ERROR_CODE: + elif t == INT or t == PRINT_MODE or t == ERROR_CODE or t == LBOOL: return '(' + ts + ') Int_val(' + s + ')' elif t == UINT: return '(' + ts + ') Unsigned_int_val(' + s + ')' @@ -1319,7 +1323,7 @@ def ml_set_wrap(t, d, n): return d + ' = Val_unit;' elif t == BOOL or (type2str(t) == 'bool'): return d + ' = Val_bool(' + n + ');' - elif t == INT or t == UINT or t == PRINT_MODE or t == ERROR_CODE: + elif t == INT or t == UINT or t == PRINT_MODE or t == ERROR_CODE or t == LBOOL: return d + ' = Val_int(' + n + ');' elif t == INT64 or t == UINT64: return d + ' = Val_long(' + n + ');' @@ -1332,7 +1336,7 @@ def ml_set_wrap(t, d, n): return '*(' + pts + '*)Data_custom_val(' + d + ') = ' + n + ';' def ml_alloc_and_store(t, lhs, rhs): - if t == VOID or t == BOOL or t == INT or t == UINT or t == PRINT_MODE or t == ERROR_CODE or t == INT64 or t == UINT64 or t == DOUBLE or t == STRING or (type2str(t) == 'bool'): + if t == VOID or t == BOOL or t == INT or t == UINT or t == PRINT_MODE or t == ERROR_CODE or t == INT64 or t == UINT64 or t == DOUBLE or t == STRING or t == LBOOL or (type2str(t) == 'bool'): return ml_set_wrap(t, lhs, rhs) else: pts = ml_plus_type(type2str(t)) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 3a28da0fd..8e5ebcf2a 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -981,6 +981,14 @@ extern "C" { Z3_CATCH; } + void Z3_API Z3_solver_next_split(Z3_context c, Z3_solver_callback cb, Z3_ast t, unsigned idx, Z3_lbool phase) { + Z3_TRY; + LOG_Z3_solver_next_split(c, cb, t, idx, phase); + RESET_ERROR_CODE(); + reinterpret_cast(cb)->next_split_cb(to_expr(t), idx, (lbool)phase); + Z3_CATCH; + } + Z3_func_decl Z3_API Z3_solver_propagate_declare(Z3_context c, Z3_symbol name, unsigned n, Z3_sort* domain, Z3_sort range) { Z3_TRY; LOG_Z3_solver_propagate_declare(c, name, n, domain, range); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 10116d751..fc0601fe5 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -4158,6 +4158,11 @@ namespace z3 { virtual void decide(expr& /*val*/, unsigned& /*bit*/, Z3_lbool& /*is_pos*/) {} + void next_split(expr const & e, unsigned idx, Z3_lbool phase) { + assert(cb); + Z3_solver_next_split(ctx(), cb, e, idx, phase); + } + /** \brief tracks \c e by a unique identifier that is returned by the call. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 740e304ad..8c60a09d1 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4871,7 +4871,7 @@ extern "C" { /** \brief Return \c Z3_L_TRUE if \c a is true, \c Z3_L_FALSE if it is false, and \c Z3_L_UNDEF otherwise. - def_API('Z3_get_bool_value', INT, (_in(CONTEXT), _in(AST))) + def_API('Z3_get_bool_value', LBOOL, (_in(CONTEXT), _in(AST))) */ Z3_lbool Z3_API Z3_get_bool_value(Z3_context c, Z3_ast a); @@ -6827,6 +6827,13 @@ extern "C" { */ void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh); + /** + Sets the next expression to split on + + def_API('Z3_solver_next_split', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(AST), _in(UINT), _in(LBOOL))) + */ + void Z3_API Z3_solver_next_split(Z3_context c, Z3_solver_callback cb, Z3_ast t, unsigned idx, Z3_lbool phase); + /** Create uninterpreted function declaration for the user propagator. When expressions using the function are created by the solver invoke a callback @@ -6885,7 +6892,7 @@ extern "C" { \sa Z3_solver_check_assumptions - def_API('Z3_solver_check', INT, (_in(CONTEXT), _in(SOLVER))) + def_API('Z3_solver_check', LBOOL, (_in(CONTEXT), _in(SOLVER))) */ Z3_lbool Z3_API Z3_solver_check(Z3_context c, Z3_solver s); @@ -6898,7 +6905,7 @@ extern "C" { \sa Z3_solver_check - def_API('Z3_solver_check_assumptions', INT, (_in(CONTEXT), _in(SOLVER), _in(UINT), _in_array(2, AST))) + def_API('Z3_solver_check_assumptions', LBOOL, (_in(CONTEXT), _in(SOLVER), _in(UINT), _in_array(2, AST))) */ Z3_lbool Z3_API Z3_solver_check_assumptions(Z3_context c, Z3_solver s, unsigned num_assumptions, Z3_ast const assumptions[]); @@ -6919,7 +6926,7 @@ extern "C" { A side-effect of the function is a satisfiability check on the assertions on the solver that is passed in. The function return \c Z3_L_FALSE if the current assertions are not satisfiable. - def_API('Z3_get_implied_equalities', INT, (_in(CONTEXT), _in(SOLVER), _in(UINT), _in_array(2, AST), _out_array(2, UINT))) + def_API('Z3_get_implied_equalities', LBOOL, (_in(CONTEXT), _in(SOLVER), _in(UINT), _in_array(2, AST), _out_array(2, UINT))) */ Z3_lbool Z3_API Z3_get_implied_equalities(Z3_context c, Z3_solver s, @@ -6930,7 +6937,7 @@ extern "C" { /** \brief retrieve consequences from solver that determine values of the supplied function symbols. - def_API('Z3_solver_get_consequences', INT, (_in(CONTEXT), _in(SOLVER), _in(AST_VECTOR), _in(AST_VECTOR), _in(AST_VECTOR))) + def_API('Z3_solver_get_consequences', LBOOL, (_in(CONTEXT), _in(SOLVER), _in(AST_VECTOR), _in(AST_VECTOR), _in(AST_VECTOR))) */ Z3_lbool Z3_API Z3_solver_get_consequences(Z3_context c, diff --git a/src/api/z3_fixedpoint.h b/src/api/z3_fixedpoint.h index 5eadaaf46..6d4737d1b 100644 --- a/src/api/z3_fixedpoint.h +++ b/src/api/z3_fixedpoint.h @@ -109,7 +109,7 @@ extern "C" { - \c Z3_L_TRUE if the query is satisfiable. Obtain the answer by calling #Z3_fixedpoint_get_answer. - \c Z3_L_UNDEF if the query was interrupted, timed out or otherwise failed. - def_API('Z3_fixedpoint_query', INT, (_in(CONTEXT), _in(FIXEDPOINT), _in(AST))) + def_API('Z3_fixedpoint_query', LBOOL, (_in(CONTEXT), _in(FIXEDPOINT), _in(AST))) */ Z3_lbool Z3_API Z3_fixedpoint_query(Z3_context c, Z3_fixedpoint d, Z3_ast query); @@ -123,7 +123,7 @@ extern "C" { - \c Z3_L_TRUE if the query is satisfiable. Obtain the answer by calling #Z3_fixedpoint_get_answer. - \c Z3_L_UNDEF if the query was interrupted, timed out or otherwise failed. - def_API('Z3_fixedpoint_query_relations', INT, (_in(CONTEXT), _in(FIXEDPOINT), _in(UINT), _in_array(2, FUNC_DECL))) + def_API('Z3_fixedpoint_query_relations', LBOOL, (_in(CONTEXT), _in(FIXEDPOINT), _in(UINT), _in_array(2, FUNC_DECL))) */ Z3_lbool Z3_API Z3_fixedpoint_query_relations( Z3_context c, Z3_fixedpoint d, diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h index 889db94ea..8bf0e9da5 100644 --- a/src/api/z3_optimization.h +++ b/src/api/z3_optimization.h @@ -151,7 +151,7 @@ extern "C" { \sa Z3_optimize_get_statistics \sa Z3_optimize_get_unsat_core - def_API('Z3_optimize_check', INT, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT), _in_array(2, AST))) + def_API('Z3_optimize_check', LBOOL, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT), _in_array(2, AST))) */ Z3_lbool Z3_API Z3_optimize_check(Z3_context c, Z3_optimize o, unsigned num_assumptions, Z3_ast const assumptions[]); diff --git a/src/api/z3_spacer.h b/src/api/z3_spacer.h index dd1028433..1f7a7ef34 100644 --- a/src/api/z3_spacer.h +++ b/src/api/z3_spacer.h @@ -40,7 +40,7 @@ extern "C" { - \c Z3_L_TRUE if the query is satisfiable. Obtain the answer by calling #Z3_fixedpoint_get_answer. - \c Z3_L_UNDEF if the query was interrupted, timed out or otherwise failed. - def_API('Z3_fixedpoint_query_from_lvl', INT, (_in(CONTEXT), _in(FIXEDPOINT), _in(AST), _in(UINT))) + def_API('Z3_fixedpoint_query_from_lvl', LBOOL, (_in(CONTEXT), _in(FIXEDPOINT), _in(AST), _in(UINT))) */ Z3_lbool Z3_API Z3_fixedpoint_query_from_lvl (Z3_context c,Z3_fixedpoint d, Z3_ast query, unsigned lvl); diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 147bc90cc..1bb37b7d7 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -91,8 +91,10 @@ namespace sat { virtual double get_reward(literal l, ext_constraint_idx idx, literal_occs_fun& occs) const { return 0; } virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r, bool probing) = 0; virtual bool is_extended_binary(ext_justification_idx idx, literal_vector & r) { return false; } - virtual void asserted(literal l) {}; - virtual void set_eliminated(bool_var v) {}; + virtual bool decide(bool_var& var, lbool& phase) { return false; } + virtual bool get_case_split(bool_var& var, lbool& phase) { return false; } + virtual void asserted(literal l) {} + virtual void set_eliminated(bool_var v) {} virtual check_result check() = 0; virtual lbool resolve_conflict() { return l_undef; } // stores result in sat::solver::m_lemma virtual void push() = 0; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f8f187fc2..729b3c1f4 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1661,49 +1661,66 @@ namespace sat { return null_bool_var; } - - bool solver::decide() { - bool_var next = next_var(); - if (next == null_bool_var) - return false; - push(); - m_stats.m_decision++; + + bool solver::guess(bool_var next) { lbool lphase = m_ext ? m_ext->get_phase(next) : l_undef; - bool phase = lphase == l_true; - if (lphase == l_undef) { - switch (m_config.m_phase) { + if (lphase != l_undef) + return lphase == l_true; + switch (m_config.m_phase) { case PS_ALWAYS_TRUE: - phase = true; - break; + return true; case PS_ALWAYS_FALSE: - phase = false; - break; + return false; case PS_BASIC_CACHING: - phase = m_phase[next]; - break; + return m_phase[next]; case PS_FROZEN: - phase = m_best_phase[next]; - break; + return m_best_phase[next]; case PS_SAT_CACHING: - if (m_search_state == s_unsat) { - phase = m_phase[next]; - } - else { - phase = m_best_phase[next]; - } - break; + if (m_search_state == s_unsat) + return m_phase[next]; + return m_best_phase[next]; case PS_RANDOM: - phase = (m_rand() % 2) == 0; - break; + return (m_rand() % 2) == 0; default: UNREACHABLE(); - phase = false; - break; - } + return false; } + } - literal next_lit(next, !phase); + bool solver::decide() { + bool_var next; + lbool phase = l_undef; + bool is_pos; + bool used_queue = false; + if (!m_ext || !m_ext->get_case_split(next, phase)) { + used_queue = true; + next = next_var(); + if (next == null_bool_var) + return false; + } + push(); + m_stats.m_decision++; + + if (phase == l_undef) + phase = guess(next) ? l_true: l_false; + + literal next_lit(next, false); + + if (m_ext && m_ext->decide(next, phase)) { + if (used_queue) + m_case_split_queue.unassign_var_eh(next); + next_lit = literal(next, false); + } + + if (phase == l_undef) + is_pos = guess(next); + else + is_pos = phase == l_true; + + if (!is_pos) + next_lit.neg(); + TRACE("sat_decide", tout << scope_lvl() << ": next-case-split: " << next_lit << "\n";); assign_scoped(next_lit); return true; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index f7113609f..e5b13af98 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -541,6 +541,7 @@ namespace sat { unsigned m_next_simplify { 0 }; bool m_simplify_enabled { true }; bool m_restart_enabled { true }; + bool guess(bool_var next); bool decide(); bool_var next_var(); lbool bounded_search(); diff --git a/src/sat/smt/user_solver.cpp b/src/sat/smt/user_solver.cpp index d24af253e..9e2ea3eab 100644 --- a/src/sat/smt/user_solver.cpp +++ b/src/sat/smt/user_solver.cpp @@ -56,6 +56,18 @@ namespace user_solver { void solver::register_cb(expr* e) { add_expr(e); } + + void solver::next_split_cb(expr* e, unsigned idx, lbool phase) { + if (e == nullptr) { + m_next_split_expr = nullptr; + return; + } + force_push(); + ctx.internalize(e, false); + m_next_split_expr = e; + m_next_split_idx = idx; + m_next_split_phase = phase; + } sat::check_result solver::check() { if (!(bool)m_final_eh) @@ -72,6 +84,41 @@ namespace user_solver { m_id2justification.setx(v, sat::literal_vector(num_lits, jlits), sat::literal_vector()); m_fixed_eh(m_user_context, this, var2expr(v), value); } + + bool solver::decide(sat::bool_var& var, lbool& phase) { + + if (!m_decide_eh) + return false; + + euf::enode* original_enode = bool_var2enode(var); + + if (!is_attached_to_var(original_enode)) + return false; + + unsigned new_bit = 0; // ignored; currently no bv-support + expr* e = bool_var2expr(var); + + m_decide_eh(m_user_context, this, &e, &new_bit, &phase); + + euf::enode* new_enode = ctx.get_enode(e); + + if (original_enode == new_enode) + return false; + + var = new_enode->bool_var(); + return true; + } + + bool solver::get_case_split(sat::bool_var& var, lbool &phase){ + if (!m_next_split_expr) + return false; + + euf::enode* n = ctx.get_enode(m_next_split_expr); + var = n->bool_var(); + phase = m_next_split_phase; + m_next_split_expr = nullptr; + return true; + } void solver::asserted(sat::literal lit) { if (!m_fixed_eh) diff --git a/src/sat/smt/user_solver.h b/src/sat/smt/user_solver.h index 13948db81..951b97fb6 100644 --- a/src/sat/smt/user_solver.h +++ b/src/sat/smt/user_solver.h @@ -56,24 +56,28 @@ namespace user_solver { void reset() { memset(this, 0, sizeof(*this)); } }; - void* m_user_context; - user_propagator::push_eh_t m_push_eh; - user_propagator::pop_eh_t m_pop_eh; - user_propagator::fresh_eh_t m_fresh_eh; - user_propagator::final_eh_t m_final_eh; - user_propagator::fixed_eh_t m_fixed_eh; - user_propagator::eq_eh_t m_eq_eh; - user_propagator::eq_eh_t m_diseq_eh; - user_propagator::created_eh_t m_created_eh; + void* m_user_context; + user_propagator::push_eh_t m_push_eh = nullptr; + user_propagator::pop_eh_t m_pop_eh = nullptr; + user_propagator::fresh_eh_t m_fresh_eh = nullptr; + user_propagator::final_eh_t m_final_eh = nullptr; + user_propagator::fixed_eh_t m_fixed_eh = nullptr; + user_propagator::eq_eh_t m_eq_eh = nullptr; + user_propagator::eq_eh_t m_diseq_eh = nullptr; + user_propagator::created_eh_t m_created_eh = nullptr; + user_propagator::decide_eh_t m_decide_eh = nullptr; user_propagator::context_obj* m_api_context = nullptr; - unsigned m_qhead = 0; - vector m_prop; - unsigned_vector m_prop_lim; - vector m_id2justification; - sat::literal_vector m_lits; - euf::enode_pair_vector m_eqs; - unsigned_vector m_fixed_ids; - stats m_stats; + unsigned m_qhead = 0; + vector m_prop; + unsigned_vector m_prop_lim; + vector m_id2justification; + sat::literal_vector m_lits; + euf::enode_pair_vector m_eqs; + unsigned_vector m_fixed_ids; + stats m_stats; + expr* m_next_split_expr = nullptr; + unsigned m_next_split_idx; + lbool m_next_split_phase; struct justification { unsigned m_propagation_index { 0 }; @@ -94,7 +98,7 @@ namespace user_solver { void propagate_consequence(prop_info const& prop); void propagate_new_fixed(prop_info const& prop); - void validate_propagation(); + void validate_propagation(); bool visit(expr* e) override; bool visited(expr* e) override; @@ -126,14 +130,19 @@ namespace user_solver { void register_eq(user_propagator::eq_eh_t& eq_eh) { m_eq_eh = eq_eh; } void register_diseq(user_propagator::eq_eh_t& diseq_eh) { m_diseq_eh = diseq_eh; } void register_created(user_propagator::created_eh_t& created_eh) { m_created_eh = created_eh; } + void register_decide(user_propagator::decide_eh_t& decide_eh) { m_decide_eh = decide_eh; } bool has_fixed() const { return (bool)m_fixed_eh; } void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* lhs, expr* const* rhs, expr* conseq) override; void register_cb(expr* e) override; + void next_split_cb(expr* e, unsigned idx, lbool phase) override; void new_fixed_eh(euf::theory_var v, expr* value, unsigned num_lits, sat::literal const* jlits); + bool decide(sat::bool_var& var, lbool& phase) override; + bool get_case_split(sat::bool_var& var, lbool &phase) override; + void asserted(sat::literal lit) override; sat::check_result check() override; void push_core() override; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 1b6088c1f..6652804ea 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1848,24 +1848,30 @@ namespace smt { } } bool_var var; - lbool phase = l_undef; - m_case_split_queue->next_case_split(var, phase); + bool is_pos; + bool used_queue = false; + + if (!has_split_candidate(var, is_pos)) { + lbool phase = l_undef; + m_case_split_queue->next_case_split(var, phase); + used_queue = true; + if (var == null_bool_var) + return false; - if (var == null_bool_var) { - return false; + TRACE_CODE({ + static unsigned counter = 0; + counter++; + if (counter % 100 == 0) { + TRACE("activity_profile", + for (unsigned i=0; iunassign_var_eh(original_choice); + if (used_queue) + m_case_split_queue->unassign_var_eh(original_choice); l = literal(var, false); } @@ -2905,8 +2911,14 @@ namespace smt { return m_user_propagator && m_user_propagator->has_fixed() && n->get_th_var(m_user_propagator->get_family_id()) != null_theory_var; } + bool context::has_split_candidate(bool_var& var, bool& is_pos) { + if (!m_user_propagator) + return false; + return m_user_propagator->get_case_split(var, is_pos); + } + bool context::decide_user_interference(bool_var& var, bool& is_pos) { - if (!m_user_propagator || !m_user_propagator->has_decide()) + if (!m_user_propagator) return false; bool_var old = var; m_user_propagator->decide(var, is_pos); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index e2fc3a35f..8d98fc60e 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1754,6 +1754,8 @@ namespace smt { bool watches_fixed(enode* n) const; + bool has_split_candidate(bool_var& var, bool& is_pos); + bool decide_user_interference(bool_var& var, bool& is_pos); void assign_fixed(enode* n, expr* val, unsigned sz, literal const* explain); diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 04bb4b248..780023fab 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -102,6 +102,17 @@ void theory_user_propagator::register_cb(expr* e) { add_expr(e, true); } +void theory_user_propagator::next_split_cb(expr* e, unsigned idx, lbool phase) { + if (e == nullptr) { // clear + m_next_split_expr = nullptr; + return; + } + ensure_enode(e); + m_next_split_expr = e; + m_next_split_idx = idx; + m_next_split_phase = phase; +} + theory * theory_user_propagator::mk_fresh(context * new_ctx) { auto* th = alloc(theory_user_propagator, *new_ctx); void* ctx; @@ -156,8 +167,24 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu } } -void theory_user_propagator::decide(bool_var& var, bool& is_pos) { +bool_var theory_user_propagator::enode_to_bool(enode* n, unsigned bit) { + if (n->is_bool()) { + // expression is a boolean + bool_var new_var = ctx.enode2bool_var(n); + if (ctx.get_assignment(new_var) == l_undef) + return new_var; + return null_bool_var; + } + // expression is a bit-vector + bv_util bv(m); + auto th_bv = (theory_bv*)ctx.get_theory(bv.get_fid()); + return th_bv->get_first_unassigned(bit, n); +} +void theory_user_propagator::decide(bool_var& var, bool& is_pos) { + if (!m_decide_eh) + return; + const bool_var_data& d = ctx.get_bdata(var); if (!d.is_enode() && !d.is_theory_atom()) @@ -216,25 +243,28 @@ void theory_user_propagator::decide(bool_var& var, bool& is_pos) { return; } - if (new_enode->is_bool()) { - // expression was set to a boolean - bool_var new_var = ctx.enode2bool_var(new_enode); - if (ctx.get_assignment(new_var) == l_undef) { - var = new_var; - } - } - else { - // expression was set to a bit-vector - auto th_bv = (theory_bv*)ctx.get_theory(bv.get_fid()); - bool_var new_var = th_bv->get_first_unassigned(new_bit, new_enode); - if (new_var != null_bool_var) - var = new_var; - } + // get unassigned variable from enode + var = enode_to_bool(new_enode, new_bit); // in case the callback did not decide on a truth value -> let Z3 decide is_pos = ctx.guess(var, phase); } +bool theory_user_propagator::get_case_split(bool_var& var, bool& is_pos){ + if (!m_next_split_expr) + return false; + enode* n = ctx.get_enode(m_next_split_expr); + + var = enode_to_bool(n, m_next_split_idx); + + if (var == null_bool_var) + return false; + + is_pos = ctx.guess(var, m_next_split_phase); + m_next_split_expr = nullptr; + return true; +} + void theory_user_propagator::push_scope_eh() { ++m_num_scopes; } diff --git a/src/smt/theory_user_propagator.h b/src/smt/theory_user_propagator.h index bf82883e4..ba9900848 100644 --- a/src/smt/theory_user_propagator.h +++ b/src/smt/theory_user_propagator.h @@ -83,6 +83,9 @@ namespace smt { expr_ref_vector m_to_add; unsigned_vector m_to_add_lim; unsigned m_to_add_qhead = 0; + expr* m_next_split_expr = nullptr; + unsigned m_next_split_idx; + lbool m_next_split_phase; expr* var2expr(theory_var v) { return m_var2expr.get(v); } theory_var expr2var(expr* e) { check_defined(e); return m_expr2var[e->get_id()]; } @@ -95,6 +98,8 @@ namespace smt { void propagate_consequence(prop_info const& prop); void propagate_new_fixed(prop_info const& prop); + + bool_var enode_to_bool(enode* n, unsigned bit); public: theory_user_propagator(context& ctx); @@ -125,13 +130,14 @@ namespace smt { void register_decide(user_propagator::decide_eh_t& decide_eh) { m_decide_eh = decide_eh; } bool has_fixed() const { return (bool)m_fixed_eh; } - bool has_decide() const { return (bool)m_decide_eh; } void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* lhs, expr* const* rhs, expr* conseq) override; void register_cb(expr* e) override; + void next_split_cb(expr* e, unsigned idx, lbool phase) override; void new_fixed_eh(theory_var v, expr* value, unsigned num_lits, literal const* jlits); void decide(bool_var& var, bool& is_pos); + bool get_case_split(bool_var& var, bool& is_pos); theory * mk_fresh(context * new_ctx) override; bool internalize_atom(app* atom, bool gate_ctx) override; @@ -154,5 +160,5 @@ namespace smt { bool can_propagate() override; void propagate() override; void display(std::ostream& out) const override {} - }; +}; }; diff --git a/src/tactic/user_propagator_base.h b/src/tactic/user_propagator_base.h index 3f4af0329..46b5eda8a 100644 --- a/src/tactic/user_propagator_base.h +++ b/src/tactic/user_propagator_base.h @@ -11,6 +11,7 @@ namespace user_propagator { virtual ~callback() = default; virtual void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* eq_lhs, expr* const* eq_rhs, expr* conseq) = 0; virtual void register_cb(expr* e) = 0; + virtual void next_split_cb(expr* e, unsigned idx, lbool phase) = 0; }; class context_obj { From 940d10ae6dded1665641b0a5531f584dee1a9064 Mon Sep 17 00:00:00 2001 From: AndreiL Date: Mon, 20 Jun 2022 19:38:38 +0100 Subject: [PATCH 248/253] Update coverage CI (#6099) Ignore errors withing `gcov` when using `gcovr`, as per https://github.com/gcovr/gcovr/issues/627. Co-authored-by: Andrei Lascu --- .github/workflows/coverage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index e46b96734..707db63d6 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -76,14 +76,14 @@ jobs: - name: Gather coverage run: | cd ${{github.workspace}} - gcovr --html coverage.html --gcov-executable "llvm-cov gcov" . + gcovr --html coverage.html --gcov-ignore-parse-errors --gcov-executable "llvm-cov gcov" . cd - - name: Gather detailed coverage run: | cd ${{github.workspace}} mkdir cov-details - gcovr --html-details ${{env.COV_DETAILS_PATH}}/coverage.html --gcov-executable "llvm-cov gcov" -r `pwd`/src --object-directory `pwd`/build + gcovr --html-details ${{env.COV_DETAILS_PATH}}/coverage.html --gcov-ignore-parse-errors --gcov-executable "llvm-cov gcov" -r `pwd`/src --object-directory `pwd`/build cd - - name: Get date From 911134b3c7fefdd41cf7fd15b1aaad8dc4eeaf48 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 18 Jun 2022 20:07:10 -0700 Subject: [PATCH 249/253] add new heuristic rc2bin (to be tested) to maxsat The rc2bin heuristic is a hybrid of rc2 and binary maxres. It follows the suggestion by Nina to use rc2 on large cores after a single maxres relaxation step; otherwise maxres (binary) on smaller cores. In the design space of possible hybrids, this variant chooses to always apply a single layer of maxres and then rc2 for large cores. --- src/opt/maxcore.cpp | 82 ++++++++++++++++++++++++++++++++++++--------- src/opt/maxcore.h | 2 ++ src/opt/maxsmt.cpp | 23 +++++-------- 3 files changed, 78 insertions(+), 29 deletions(-) diff --git a/src/opt/maxcore.cpp b/src/opt/maxcore.cpp index 46e4c5a7d..70bf38d87 100644 --- a/src/opt/maxcore.cpp +++ b/src/opt/maxcore.cpp @@ -9,10 +9,12 @@ Abstract: Core based (weighted) max-sat algorithms: - - mu: max-sat algorithm by Nina and Bacchus, AAAI 2014. - - mus-mss: based on dual refinement of bounds. - - binary: binary versino of maxres - - rc2: implementaion of rc2 heuristic using cardinality constraints + - mu: max-sat algorithm by Nina and Bacchus, AAAI 2014. + - mus-mss: based on dual refinement of bounds. + - binary: binary version of maxres + - rc2: implementaion of rc2 heuristic using cardinality constraints + - rc2-binary: hybrid of rc2 and binary maxres. Perform one step of binary maxres. + If there are more than 16 soft constraints create a cardinality constraint. MaxRes is a core-guided approach to maxsat. @@ -78,7 +80,8 @@ public: s_primal, s_primal_dual, s_primal_binary, - s_rc2 + s_rc2, + s_primal_binary_rc2 }; private: struct stats { @@ -157,6 +160,9 @@ public: case s_rc2: m_trace_id = "rc2"; break; + case s_primal_binary_rc2: + m_trace_id = "rc2bin"; + break; default: UNREACHABLE(); break; @@ -360,6 +366,7 @@ public: case s_primal: case s_primal_binary: case s_rc2: + case s_primal_binary_rc2: return mus_solver(); case s_primal_dual: return primal_dual_solver(); @@ -553,6 +560,9 @@ public: case strategy_t::s_rc2: max_resolve_rc2(core, w); break; + case strategy_t::s_primal_binary_rc2: + max_resolve_rc2bin(core, w); + break; default: max_resolve(core, w); break; @@ -717,10 +727,9 @@ public: m_defs.push_back(fml); } } - - - void bin_max_resolve(exprs const& _core, rational w) { - expr_ref_vector core(m, _core.size(), _core.data()); + + void bin_resolve(exprs const& _core, rational weight, expr_ref_vector& us) { + expr_ref_vector core(m, _core.size(), _core.data()), fmls(m); expr_ref fml(m), cls(m); for (unsigned i = 0; i + 1 < core.size(); i += 2) { expr* a = core.get(i); @@ -739,13 +748,19 @@ public: add(fml); update_model(v, cls); m_defs.push_back(fml); - new_assumption(u, w); + us.push_back(u); core.push_back(v); } - s().assert_expr(m.mk_not(core.back())); + s().assert_expr(m.mk_not(core.back())); } - + void bin_max_resolve(exprs const& _core, rational w) { + expr_ref_vector core(m, _core.size(), _core.data()), us(m); + expr_ref fml(m), cls(m); + bin_resolve(_core, w, us); + for (expr* u : us) + new_assumption(u, w); + } // rc2, using cardinality constraints @@ -785,10 +800,8 @@ public: return r; } - void max_resolve_rc2(exprs const& core, rational weight) { - expr_ref_vector ncore(m); + void weaken_bounds(exprs const& core) { for (expr* f : core) { - ncore.push_back(mk_not(m, f)); bound_info b; if (!m_bounds.find(f, b)) continue; @@ -800,6 +813,15 @@ public: new_assumption(amk, b.weight); m_unfold_upper -= b.weight; } + } + + void max_resolve_rc2(exprs const& core, rational weight) { + expr_ref_vector ncore(m); + for (expr* f : core) + ncore.push_back(mk_not(m, f)); + + weaken_bounds(core); + if (core.size() > 1) { m_unfold_upper += rational(core.size() - 2) * weight; expr* am = mk_atmost(ncore, 1, weight); @@ -807,6 +829,31 @@ public: } } + /** + * \brief hybrid of rc2 and binary resolution. + * Create us := u1, .., u_n, where core has size n + 1 + * If the core is of size at most 16 just use us as soft constraints + * Otherwise introduce a single soft constraint, the conjunction of us. + */ + + void max_resolve_rc2bin(exprs const& core, rational weight) { + weaken_bounds(core); + expr_ref_vector us(m); + bin_resolve(core, weight, us); + if (us.size() <= 15) { + for (auto* u : us) + new_assumption(u, weight); + } + else if (us.size() > 15) { + expr_ref_vector ncore(m); + for (expr* f : us) + ncore.push_back(mk_not(m, f)); + m_unfold_upper += rational(us.size() - 1) * weight; + expr* am = mk_atmost(ncore, 0, weight); + new_assumption(am, weight); + } + } + // cs is a correction set (a complement of a (maximal) satisfying assignment). void cs_max_resolve(exprs const& cs, rational const& w) { @@ -1062,6 +1109,11 @@ opt::maxsmt_solver_base* opt::mk_rc2( return alloc(maxcore, c, id, soft, maxcore::s_rc2); } +opt::maxsmt_solver_base* opt::mk_rc2bin( + maxsat_context& c, unsigned id, vector& soft) { + return alloc(maxcore, c, id, soft, maxcore::s_primal_binary_rc2); +} + opt::maxsmt_solver_base* opt::mk_maxres_binary( maxsat_context& c, unsigned id, vector& soft) { return alloc(maxcore, c, id, soft, maxcore::s_primal_binary); diff --git a/src/opt/maxcore.h b/src/opt/maxcore.h index 2dba613a7..2038c5e98 100644 --- a/src/opt/maxcore.h +++ b/src/opt/maxcore.h @@ -23,6 +23,8 @@ namespace opt { maxsmt_solver_base* mk_rc2(maxsat_context& c, unsigned id, vector& soft); + maxsmt_solver_base* mk_rc2bin(maxsat_context& c, unsigned id, vector& soft); + maxsmt_solver_base* mk_maxres(maxsat_context& c, unsigned id, vector& soft); maxsmt_solver_base* mk_maxres_binary(maxsat_context& c, unsigned id, vector& soft); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 6064ef899..3d0834472 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -185,27 +185,22 @@ namespace opt { symbol const& maxsat_engine = m_c.maxsat_engine(); IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";); TRACE("opt_verbose", s().display(tout << "maxsmt\n") << "\n";); - if (optp.maxlex_enable() && is_maxlex(m_soft)) { + if (optp.maxlex_enable() && is_maxlex(m_soft)) m_msolver = mk_maxlex(m_c, m_index, m_soft); - } - else if (m_soft.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) { + else if (m_soft.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) m_msolver = mk_maxres(m_c, m_index, m_soft); - } - else if (maxsat_engine == symbol("maxres-bin")) { + else if (maxsat_engine == symbol("maxres-bin")) m_msolver = mk_maxres_binary(m_c, m_index, m_soft); - } - else if (maxsat_engine == symbol("rc2")) { + else if (maxsat_engine == symbol("rc2")) m_msolver = mk_rc2(m_c, m_index, m_soft); - } - else if (maxsat_engine == symbol("pd-maxres")) { + else if (maxsat_engine == symbol("rc2bin")) + m_msolver = mk_rc2bin(m_c, m_index, m_soft); + else if (maxsat_engine == symbol("pd-maxres")) m_msolver = mk_primal_dual_maxres(m_c, m_index, m_soft); - } - else if (maxsat_engine == symbol("wmax")) { + else if (maxsat_engine == symbol("wmax")) m_msolver = mk_wmax(m_c, m_soft, m_index); - } - else if (maxsat_engine == symbol("sortmax")) { + else if (maxsat_engine == symbol("sortmax")) m_msolver = mk_sortmax(m_c, m_soft, m_index); - } else { auto str = maxsat_engine.str(); warning_msg("solver %s is not recognized, using default 'maxres'", str.c_str()); From 25e915fe95da228ccfc5b8b9b06fae31c32d7320 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 21 Jun 2022 16:29:09 +0100 Subject: [PATCH 250/253] fix #5990: deadlock in the scoped_timer Thanks to Felix Kohlgrueber for reporting the bug and for the analysis --- src/util/scoped_timer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index e8a72e245..b5968cc06 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -51,10 +51,9 @@ static atomic num_workers(0); static void thread_func(scoped_timer_state *s) { workers.lock(); while (true) { - s->cv.wait(workers, [=]{ return s->work > IDLE; }); + s->cv.wait(workers, [=]{ return s->work != IDLE; }); workers.unlock(); - // exiting.. if (s->work == EXITING) return; @@ -87,16 +86,17 @@ scoped_timer::scoped_timer(unsigned ms, event_handler * eh) { s = new scoped_timer_state; new_worker = true; ++num_workers; + s->work = WORKING; } else { s = available_workers.back(); available_workers.pop_back(); + s->work = WORKING; workers.unlock(); } s->ms = ms; s->eh = eh; s->m_mutex.lock(); - s->work = WORKING; if (new_worker) { s->m_thread = std::thread(thread_func, s); } From b254f4086bb3df1739d4166a0ae8a3da6050ce10 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Jun 2022 09:08:11 -0700 Subject: [PATCH 251/253] Separate out native static content for Java Make it easier to add native methods for callbacks (for user propagator) #6097 The Java User propagator wrapper should define a base class with virtual methods that can be invoked from functions defined in NativeStatic.txt --- scripts/mk_util.py | 5 ++- scripts/update_api.py | 75 +++++++-------------------------- src/api/java/CMakeLists.txt | 2 + src/api/java/NativeStatic.txt | 78 +++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 62 deletions(-) create mode 100644 src/api/java/NativeStatic.txt diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 68bb9da14..13c01567d 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -3027,10 +3027,12 @@ def mk_bindings(api_files): if is_dotnet_core_enabled(): dotnet_output_dir = os.path.join(BUILD_DIR, 'dotnet') mk_dir(dotnet_output_dir) + java_input_dir = None java_output_dir = None java_package_name = None if is_java_enabled(): java_output_dir = get_component('java').src_dir + java_input_dir = get_component('java').src_dir java_package_name = get_component('java').package_name ml_output_dir = None if is_ml_enabled(): @@ -3041,7 +3043,8 @@ def mk_bindings(api_files): api_output_dir=get_component('api').src_dir, z3py_output_dir=get_z3py_dir(), dotnet_output_dir=dotnet_output_dir, - java_output_dir=java_output_dir, + java_input_dir=java_input_dir, + java_output_dir=java_output_dir, java_package_name=java_package_name, ml_output_dir=ml_output_dir, ml_src_dir=ml_output_dir diff --git a/scripts/update_api.py b/scripts/update_api.py index 45899ddef..03aa80638 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -604,7 +604,7 @@ def java_array_element_type(p): else: return 'jlong' -def mk_java(java_dir, package_name): +def mk_java(java_src, java_dir, package_name): java_nativef = os.path.join(java_dir, 'Native.java') java_wrapperf = os.path.join(java_dir, 'Native.cpp') java_native = open(java_nativef, 'w') @@ -689,65 +689,9 @@ def mk_java(java_dir, package_name): java_native.write('}\n') java_wrapper = open(java_wrapperf, 'w') pkg_str = package_name.replace('.', '_') - java_wrapper.write('// Automatically generated file\n') - java_wrapper.write('#include\n') - java_wrapper.write('#include\n') - java_wrapper.write('#include"z3.h"\n') - java_wrapper.write('#ifdef __cplusplus\n') - java_wrapper.write('extern "C" {\n') - java_wrapper.write('#endif\n\n') - java_wrapper.write('#ifdef __GNUC__\n#if __GNUC__ >= 4\n#define DLL_VIS __attribute__ ((visibility ("default")))\n#else\n#define DLL_VIS\n#endif\n#else\n#define DLL_VIS\n#endif\n\n') - java_wrapper.write('#if defined(__LP64__) || defined(_WIN64)\n\n') - java_wrapper.write('#define GETLONGAELEMS(T,OLD,NEW) \\\n') - java_wrapper.write(' T * NEW = (OLD == 0) ? 0 : (T*) jenv->GetLongArrayElements(OLD, NULL);\n') - java_wrapper.write('#define RELEASELONGAELEMS(OLD,NEW) \\\n') - java_wrapper.write(' if (OLD != 0) jenv->ReleaseLongArrayElements(OLD, (jlong *) NEW, JNI_ABORT); \n\n') - java_wrapper.write('#define GETLONGAREGION(T,OLD,Z,SZ,NEW) \\\n') - java_wrapper.write(' jenv->GetLongArrayRegion(OLD,Z,(jsize)SZ,(jlong*)NEW); \n') - java_wrapper.write('#define SETLONGAREGION(OLD,Z,SZ,NEW) \\\n') - java_wrapper.write(' jenv->SetLongArrayRegion(OLD,Z,(jsize)SZ,(jlong*)NEW) \n\n') - java_wrapper.write('#else\n\n') - java_wrapper.write('#define GETLONGAELEMS(T,OLD,NEW) \\\n') - java_wrapper.write(' T * NEW = 0; { \\\n') - java_wrapper.write(' jlong * temp = (OLD == 0) ? 0 : jenv->GetLongArrayElements(OLD, NULL); \\\n') - java_wrapper.write(' unsigned int size = (OLD == 0) ? 0 :jenv->GetArrayLength(OLD); \\\n') - java_wrapper.write(' if (OLD != 0) { \\\n') - java_wrapper.write(' NEW = (T*) (new int[size]); \\\n') - java_wrapper.write(' for (unsigned i=0; i < size; i++) \\\n') - java_wrapper.write(' NEW[i] = reinterpret_cast(temp[i]); \\\n') - java_wrapper.write(' jenv->ReleaseLongArrayElements(OLD, temp, JNI_ABORT); \\\n') - java_wrapper.write(' } \\\n') - java_wrapper.write(' } \n\n') - java_wrapper.write('#define RELEASELONGAELEMS(OLD,NEW) \\\n') - java_wrapper.write(' delete [] NEW; \n\n') - java_wrapper.write('#define GETLONGAREGION(T,OLD,Z,SZ,NEW) \\\n') - java_wrapper.write(' { \\\n') - java_wrapper.write(' jlong * temp = new jlong[SZ]; \\\n') - java_wrapper.write(' jenv->GetLongArrayRegion(OLD,Z,(jsize)SZ,(jlong*)temp); \\\n') - java_wrapper.write(' for (int i = 0; i < (SZ); i++) \\\n') - java_wrapper.write(' NEW[i] = reinterpret_cast(temp[i]); \\\n') - java_wrapper.write(' delete [] temp; \\\n') - java_wrapper.write(' }\n\n') - java_wrapper.write('#define SETLONGAREGION(OLD,Z,SZ,NEW) \\\n') - java_wrapper.write(' { \\\n') - java_wrapper.write(' jlong * temp = new jlong[SZ]; \\\n') - java_wrapper.write(' for (int i = 0; i < (SZ); i++) \\\n') - java_wrapper.write(' temp[i] = reinterpret_cast(NEW[i]); \\\n') - java_wrapper.write(' jenv->SetLongArrayRegion(OLD,Z,(jsize)SZ,temp); \\\n') - java_wrapper.write(' delete [] temp; \\\n') - java_wrapper.write(' }\n\n') - java_wrapper.write('#endif\n\n') - java_wrapper.write('void Z3JavaErrorHandler(Z3_context c, Z3_error_code e)\n') - java_wrapper.write('{\n') - java_wrapper.write(' // Internal do-nothing error handler. This is required to avoid that Z3 calls exit()\n') - java_wrapper.write(' // upon errors, but the actual error handling is done by throwing exceptions in the\n') - java_wrapper.write(' // wrappers below.\n') - java_wrapper.write('}\n\n') - java_wrapper.write('DLL_VIS JNIEXPORT void JNICALL Java_%s_Native_setInternalErrorHandler(JNIEnv * jenv, jclass cls, jlong a0)\n' % pkg_str) - java_wrapper.write('{\n') - java_wrapper.write(' Z3_set_error_handler((Z3_context)a0, Z3JavaErrorHandler);\n') - java_wrapper.write('}\n\n') - java_wrapper.write('') + with open(f"{java_src}/NativeStatic.txt") as ins: + for line in ins: + java_wrapper.write(line) for name, result, params in _dotnet_decls: java_wrapper.write('DLL_VIS JNIEXPORT %s JNICALL Java_%s_Native_INTERNAL%s(JNIEnv * jenv, jclass cls' % (type2javaw(result), pkg_str, java_method_name(name))) i = 0 @@ -1926,6 +1870,7 @@ def generate_files(api_files, api_output_dir=None, z3py_output_dir=None, dotnet_output_dir=None, + java_input_dir=None, java_output_dir=None, java_package_name=None, ml_output_dir=None, @@ -2003,7 +1948,7 @@ def generate_files(api_files, print("Generated '{}'".format(dotnet_file.name)) if java_output_dir: - mk_java(java_output_dir, java_package_name) + mk_java(java_input_dir, java_output_dir, java_package_name) if ml_output_dir: assert not ml_src_dir is None @@ -2027,6 +1972,10 @@ def main(args): dest="dotnet_output_dir", default=None, help="Directory to emit dotnet files. If not specified no files are emitted.") + parser.add_argument("--java-input-dir", + dest="java_input_dir", + default=None, + help="Directory where Java sources reside.") parser.add_argument("--java-output-dir", dest="java_output_dir", default=None, @@ -2049,6 +1998,9 @@ def main(args): if pargs.java_package_name == None: logging.error('--java-package-name must be specified') return 1 + if pargs.java_input_dir is None: + logging.error('--java-input-dir must be specified') + return 1 if pargs.ml_output_dir: if pargs.ml_src_dir is None: @@ -2064,6 +2016,7 @@ def main(args): api_output_dir=pargs.api_output_dir, z3py_output_dir=pargs.z3py_output_dir, dotnet_output_dir=pargs.dotnet_output_dir, + java_input_dir=pargs.java_input_dir, java_output_dir=pargs.java_output_dir, java_package_name=pargs.java_package_name, ml_output_dir=pargs.ml_output_dir, diff --git a/src/api/java/CMakeLists.txt b/src/api/java/CMakeLists.txt index dd7115aaa..695c946a3 100644 --- a/src/api/java/CMakeLists.txt +++ b/src/api/java/CMakeLists.txt @@ -19,6 +19,8 @@ add_custom_command(OUTPUT "${Z3_JAVA_NATIVE_JAVA}" "${Z3_JAVA_NATIVE_CPP}" COMMAND "${PYTHON_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/scripts/update_api.py" ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} + "--java-input-dir" + "${CMAKE_CURRENT_SOURCE_DIR}" "--java-output-dir" "${CMAKE_CURRENT_BINARY_DIR}" "--java-package-name" diff --git a/src/api/java/NativeStatic.txt b/src/api/java/NativeStatic.txt new file mode 100644 index 000000000..2cd718627 --- /dev/null +++ b/src/api/java/NativeStatic.txt @@ -0,0 +1,78 @@ +// Automatically generated file +#include +#include +#include"z3.h" +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __GNUC__ +#if __GNUC__ >= 4 +#define DLL_VIS __attribute__ ((visibility ("default"))) +#else +#define DLL_VIS +#endif +#else +#define DLL_VIS +#endif + +#if defined(__LP64__) || defined(_WIN64) + +#define GETLONGAELEMS(T,OLD,NEW) \ + T * NEW = (OLD == 0) ? 0 : (T*) jenv->GetLongArrayElements(OLD, NULL); +#define RELEASELONGAELEMS(OLD,NEW) \ + if (OLD != 0) jenv->ReleaseLongArrayElements(OLD, (jlong *) NEW, JNI_ABORT); + +#define GETLONGAREGION(T,OLD,Z,SZ,NEW) \ + jenv->GetLongArrayRegion(OLD,Z,(jsize)SZ,(jlong*)NEW); +#define SETLONGAREGION(OLD,Z,SZ,NEW) \ + jenv->SetLongArrayRegion(OLD,Z,(jsize)SZ,(jlong*)NEW) + +#else + +#define GETLONGAELEMS(T,OLD,NEW) \ + T * NEW = 0; { \ + jlong * temp = (OLD == 0) ? 0 : jenv->GetLongArrayElements(OLD, NULL); \ + unsigned int size = (OLD == 0) ? 0 :jenv->GetArrayLength(OLD); \ + if (OLD != 0) { \ + NEW = (T*) (new int[size]); \ + for (unsigned i=0; i < size; i++) \ + NEW[i] = reinterpret_cast(temp[i]); \ + jenv->ReleaseLongArrayElements(OLD, temp, JNI_ABORT); \ + } \ + } + +#define RELEASELONGAELEMS(OLD,NEW) \ + delete [] NEW; + +#define GETLONGAREGION(T,OLD,Z,SZ,NEW) \ + { \ + jlong * temp = new jlong[SZ]; \ + jenv->GetLongArrayRegion(OLD,Z,(jsize)SZ,(jlong*)temp); \ + for (int i = 0; i < (SZ); i++) \ + NEW[i] = reinterpret_cast(temp[i]); \ + delete [] temp; \ + } + +#define SETLONGAREGION(OLD,Z,SZ,NEW) \ + { \ + jlong * temp = new jlong[SZ]; \ + for (int i = 0; i < (SZ); i++) \ + temp[i] = reinterpret_cast(NEW[i]); \ + jenv->SetLongArrayRegion(OLD,Z,(jsize)SZ,temp); \ + delete [] temp; \ + } + +#endif + +void Z3JavaErrorHandler(Z3_context c, Z3_error_code e) +{ + // Internal do-nothing error handler. This is required to avoid that Z3 calls exit() + // upon errors, but the actual error handling is done by throwing exceptions in the + // wrappers below. +} + +DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_setInternalErrorHandler(JNIEnv * jenv, jclass cls, jlong a0) +{ + Z3_set_error_handler((Z3_context)a0, Z3JavaErrorHandler); +} From d792d30e884423d768318cc8d631eca53625f198 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Jun 2022 09:09:31 -0700 Subject: [PATCH 252/253] Update NativeContext.cs TraceToFile does not correspond to the functionality of enable_trace. Z3_enable_trace tags a trace tag as input. It can be invoked multiple times with different tags. The debug tracing then shows logs with the corresponding tags. --- src/api/dotnet/NativeContext.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index 9f285ec84..93180e583 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -1341,13 +1341,13 @@ namespace Microsoft.Z3 #region Tracing /// - /// Enable tracint to file + /// Enable trace to file /// - /// - public void TraceToFile(string file) + /// Tag to trace + public static void EnableTrace(string tag) { - Debug.Assert(!string.IsNullOrEmpty(file)); - Native.Z3_enable_trace(file); + Debug.Assert(!string.IsNullOrEmpty(tag)); + Native.Z3_enable_trace(tag); } #endregion From 5ba8231d078d0b0275beddada46e53b480777377 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Jun 2022 09:10:38 -0700 Subject: [PATCH 253/253] make it work with old pythons Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 03aa80638..f5d935514 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -689,7 +689,7 @@ def mk_java(java_src, java_dir, package_name): java_native.write('}\n') java_wrapper = open(java_wrapperf, 'w') pkg_str = package_name.replace('.', '_') - with open(f"{java_src}/NativeStatic.txt") as ins: + with open(java_src + "/NativeStatic.txt") as ins: for line in ins: java_wrapper.write(line) for name, result, params in _dotnet_decls: