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" diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml index b3a17f301..8bbfd5ab0 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 @@ -18,7 +21,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Configure CMake and build run: | @@ -29,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 75a866233..707db63d6 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 @@ -18,7 +21,7 @@ jobs: COV_DETAILS_PATH: ${{github.workspace}}/cov-details steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup run: | @@ -73,27 +76,27 @@ 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 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}} diff --git a/.github/workflows/cross-build.yml b/.github/workflows/cross-build.yml index 5efd00329..83fae7a5d 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 @@ -16,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 843b1c75e..e7ca0f1b5 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 @@ -12,10 +15,10 @@ 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 + uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ secrets.DOCKER_USERNAME }} @@ -26,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: | @@ -38,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 diff --git a/.github/workflows/wasm-release.yml b/.github/workflows/wasm-release.yml index b91e06a80..376a26684 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: @@ -16,13 +18,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + 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' + node-version: "lts/*" + registry-url: "https://registry.npmjs.org" - name: Prepare for publish run: | @@ -35,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: | @@ -50,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 6ad00cc47..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: @@ -18,25 +18,25 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup node - uses: actions/setup-node@v2 + 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/.github/workflows/wip.yml b/.github/workflows/wip.yml index e0129757b..ffea6225c 100644 --- a/.github/workflows/wip.yml +++ b/.github/workflows/wip.yml @@ -7,12 +7,15 @@ on: env: BUILD_TYPE: Debug +permissions: + contents: read + jobs: build: 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}} 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/CMakeLists.txt b/CMakeLists.txt index 5fef02be9..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.16.0 LANGUAGES CXX) +project(Z3 VERSION 4.8.18.0 LANGUAGES CXX) ################################################################################ # Project version diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 8e61f55bd..e9c5c1fd7 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -10,6 +10,28 @@ 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 + 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 diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index 2ef219506..7ca47b89a 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -11,15 +11,16 @@ import getopt import pydoc import sys import subprocess -import shutil 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 @@ -29,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', @@ -47,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, @@ -105,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 @@ -133,10 +140,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): @@ -223,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( @@ -240,7 +253,7 @@ try: '{prefix}C API ' ).format( prefix=bullet_point_prefix) - + if Z3PY_ENABLED: print("Python documentation enabled") website_dox_substitutions['PYTHON_API'] = ( @@ -273,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'), @@ -338,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/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"; 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/scripts/mk_project.py b/scripts/mk_project.py index a19ce613f..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, 16, 0) + set_version(4, 8, 18, 0) # Z3 Project definition def init_project_def(): diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 97de725e9..d152b3625 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_NAME=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_NAME path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', @@ -74,6 +76,7 @@ def parse_options(): 'nodotnet', 'dotnet-key=', 'arch=', + 'os=', 'githash', 'nopython' ]) @@ -103,6 +106,8 @@ def parse_options(): mk_util.IS_ARCH_ARM64 = True else: raise MKException("Invalid architecture directive '%s'. Legal directives: arm64" % arg) + elif opt == '--os': + OS_NAME = arg else: raise MKException("Invalid command line option '%s'" % opt) set_build_dir(path) @@ -154,6 +159,8 @@ def mk_z3(): return 1 def get_os_name(): + if OS_NAME is not None: + return OS_NAME import platform basic = os.uname()[0].lower() if basic == 'linux': diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 761de8b26..13c01567d 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: @@ -2599,6 +2606,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 +2640,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 @@ -3019,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(): @@ -3033,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 @@ -3116,7 +3127,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/scripts/nightly.yaml b/scripts/nightly.yaml index 22a53ac5e..0082bff42 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -2,7 +2,7 @@ variables: Major: '4' Minor: '8' - Patch: '16' + Patch: '18' NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName) stages: @@ -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 --os=osx-11.0 - script: git clone https://github.com/z3prover/z3test z3test - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@1 @@ -86,13 +86,14 @@ stages: artifactName: 'UbuntuDoc' targetPath: $(Build.ArtifactStagingDirectory) - - job: Manylinux - displayName: "Manylinux build" + - job: ManyLinuxBuild + variables: + python: "/opt/python/cp37-cp37m/bin/python" + name: ManyLinux + displayName: "ManyLinux build" pool: vmImage: "Ubuntu-18.04" container: "quay.io/pypa/manylinux2010_x86_64:latest" - variables: - python: "/opt/python/cp37-cp37m/bin/python" steps: - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava - script: git clone https://github.com/z3prover/z3test z3test @@ -100,9 +101,29 @@ stages: - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/ - task: PublishPipelineArtifact@0 inputs: - artifactName: 'Manylinux' + 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 displayName: "Windows 32-bit build" pool: @@ -393,8 +414,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 inputs: artifactName: 'Mac' @@ -405,13 +431,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 cd860d177..20361e9ca 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -6,7 +6,7 @@ trigger: none variables: - ReleaseVersion: '4.8.16' + ReleaseVersion: '4.8.18' stages: @@ -43,6 +43,28 @@ 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 --os=osx-11.0 + - 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: @@ -107,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 @@ -138,7 +170,7 @@ stages: targetFolder: $(Build.ArtifactStagingDirectory) - task: PublishPipelineArtifact@0 inputs: - artifactName: 'ManyLinuxBuild' + artifactName: '$(name)Build' targetPath: $(Build.ArtifactStagingDirectory) - template: build-win-signed.yml @@ -378,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: @@ -389,14 +426,18 @@ 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 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 - 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)/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 - 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 @@ -429,6 +470,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: @@ -507,4 +553,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/scripts/update_api.py b/scripts/update_api.py index d4d1ab0e0..f5d935514 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 @@ -60,37 +61,46 @@ DOUBLE = 12 FLOAT = 13 CHAR = 14 CHAR_PTR = 15 +LBOOL = 16 + +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' + 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 : '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' } + BOOL : 'bool', SYMBOL : 'z3_symbol', PRINT_MODE : 'int', ERROR_CODE : 'int', CHAR : 'char', CHAR_PTR : 'string', LBOOL : 'int' } + +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 +113,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 +175,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) @@ -179,11 +210,13 @@ def param_array_size_pos(p): def param2str(p): if param_kind(p) == IN_ARRAY: - return "%s const *" % type2str(param_type(p)) + 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 "%s*" % type2str(param_type(p)) + return "%s*" % (type2str(param_type(p))) elif param_kind(p) == OUT: - return "%s*" % type2str(param_type(p)) + return "%s*" % (type2str(param_type(p))) + elif param_kind(p) == FN_PTR: + return "%s*" % (type2str(param_type(p))) else: return type2str(param_type(p)) @@ -276,6 +309,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(""" @@ -345,7 +385,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") @@ -374,11 +414,21 @@ 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") + 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 + dotnet.write(' [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n') + dotnet.write(' public delegate %s %s(%s);\n' % (ret,name,sig)) + dotnet.write(' public class LIB\n') dotnet.write(' {\n') dotnet.write(' const string Z3_DLL_NAME = \"libz3\";\n' @@ -456,7 +506,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") @@ -473,22 +523,22 @@ 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 - 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] @@ -513,6 +563,8 @@ def param2java(p): return "UIntArrayPtr" else: return "ObjArrayPtr" + elif k == FN_PTR: + return "LongPtr" else: return type2java(param_type(p)) @@ -552,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') @@ -627,7 +679,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') @@ -637,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(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 @@ -973,6 +969,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)) @@ -1070,6 +1069,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 @@ -1244,7 +1246,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 + ')' @@ -1265,7 +1267,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 + ');' @@ -1278,7 +1280,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)) @@ -1286,6 +1288,27 @@ 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_final', + 'Z3_solver_propagate_eq', + 'Z3_solver_propagate_diseq', + 'Z3_solver_propagate_created', + 'Z3_solver_propagate_decide' + ]) + def mk_ml(ml_src_dir, ml_output_dir): global Type2Str ml_nativef = os.path.join(ml_output_dir, 'z3native.ml') @@ -1299,6 +1322,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) @@ -1343,17 +1368,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' - ]) - 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') @@ -1368,6 +1382,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) @@ -1433,7 +1449,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: @@ -1559,7 +1575,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') @@ -1703,7 +1719,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') @@ -1820,28 +1835,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 @@ -1861,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, @@ -1938,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 @@ -1962,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, @@ -1984,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: @@ -1999,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/api_ast.cpp b/src/api/api_ast.cpp index 9f9039378..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" @@ -874,6 +873,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/api_ast_map.cpp b/src/api/api_ast_map.cpp index 714712faf..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" @@ -52,7 +51,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..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" @@ -47,7 +46,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_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/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/api_context.cpp b/src/api/api_context.cpp index 66a1384f5..3ba279dca 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -113,6 +113,7 @@ namespace api { } if (m_params.owns_manager()) m_manager.detach(); + } context::set_interruptable::set_interruptable(context & ctx, event_handler & i): @@ -371,8 +372,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_datatype.cpp b/src/api/api_datatype.cpp index 673ceb3c1..f1c65b626 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 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); + } + + void Z3_API Z3_mk_datatypes(Z3_context c, unsigned num_sorts, Z3_symbol const sort_names[], 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 7e2b5cd55..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" @@ -52,7 +51,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_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 a682a83da..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" @@ -67,7 +66,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..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" @@ -54,7 +53,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 +139,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_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 948064af6..8e5ebcf2a 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" @@ -207,7 +206,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 +411,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; } @@ -564,7 +562,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); } @@ -975,6 +973,22 @@ 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; + } + + 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/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 f67a373dd..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" @@ -73,7 +72,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 +102,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 +474,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; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 101fa04a3..fc0601fe5 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 @@ -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)); } @@ -1359,6 +1360,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)); } @@ -3943,11 +3945,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 +4013,16 @@ 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); + // TBD: life time of val is within the scope of this callback. + *_val = val; + } + public: user_propagator_base(context& c) : s(nullptr), c(&c) {} @@ -4119,6 +4131,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 +4155,13 @@ namespace z3 { virtual void final() { } virtual void created(expr const& /*e*/) {} + + 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/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/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/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 diff --git a/src/api/dotnet/UserPropagator.cs b/src/api/dotnet/UserPropagator.cs new file mode 100644 index 000000000..bfd7887dd --- /dev/null +++ b/src/api/dotnet/UserPropagator.cs @@ -0,0 +1,313 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + UserPropagator.cs + +Abstract: + + User Propagator plugin + +Author: + + Nikolaj Bjorner (nbjorner) 2022-05-07 + +Notes: + + +--*/ + +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); + + /// + /// Delegate type for when a new term using a registered function symbol is created internally + /// + 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; + Z3_solver_callback callback = IntPtr.Zero; + FixedEh fixed_eh; + Action final_eh; + EqEh eq_eh; + EqEh diseq_eh; + 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(() => 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(() => prop.Pop(num_scopes), cb); + } + + static voidp _fresh(voidp _ctx, Z3_context new_context) { + var gch = GCHandle.FromIntPtr(_ctx); + var prop = (UserPropagator)gch.Target; + var ctx = new Context(new_context); + var prop1 = prop.Fresh(ctx); + 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.ctx, _term); + using var value = Expr.Create(prop.ctx, _value); + 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(() => prop.final_eh(), cb); + } + + 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.ctx, a); + using var t = Expr.Create(prop.ctx, b); + prop.Callback(() => prop.eq_eh(s, t), cb); + } + + 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.ctx, a); + using var t = Expr.Create(prop.ctx, b); + 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(() => prop.created_eh(t), cb); + } + + 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; + } + + /// + /// Propagator constructor from a solver class. + /// + public UserPropagator(Solver s) + { + gch = GCHandle.Alloc(this); + solver = s; + ctx = solver.Context; + var cb = GCHandle.ToIntPtr(gch); + 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) + { + gch = GCHandle.Alloc(this); + solver = null; + ctx = _ctx; + } + + /// + /// Release provate memory. + /// + ~UserPropagator() + { + if (gch != null) + gch.Free(); + if (solver == null) + ctx.Dispose(); + } + + /// + /// 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 can be overwritten by inherited class. + /// + public virtual UserPropagator Fresh(Context ctx) { return new UserPropagator(ctx); } + + /// + /// Declare combination of assigned expressions a conflict + /// + void Conflict(params Expr[] terms) { + Propagate(terms, ctx.MkFalse()); + } + + /// + /// Propagate consequence + /// + void Propagate(Expr[] terms, Expr conseq) { + var nTerms = Z3Object.ArrayToNative(terms); + Native.Z3_solver_propagate_consequence(ctx.nCtx, this.callback, (uint)nTerms.Length, nTerms, 0u, null, null, conseq.NativeObject); + } + + + /// + /// Set fixed callback + /// + public FixedEh Fixed + { + set + { + this.fixed_eh = value; + if (solver != null) + Native.Z3_solver_propagate_fixed(ctx.nCtx, solver.NativeObject, _fixed); + } + } + + /// + /// Set final callback + /// + public Action Final + { + set + { + this.final_eh = value; + if (solver != null) + Native.Z3_solver_propagate_final(ctx.nCtx, solver.NativeObject, _final); + } + } + + /// + /// Set equality event callback + /// + public EqEh Eq + { + set + { + this.eq_eh = value; + if (solver != null) + Native.Z3_solver_propagate_eq(ctx.nCtx, solver.NativeObject, _eq); + } + } + + /// + /// Set disequality event callback + /// + public EqEh Diseq + { + set + { + this.diseq_eh = value; + 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); + } + } + + /// + /// 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 + /// + public void Register(Expr term) { + 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); + } + } + } +} 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/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); +} 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 897edabf5..e4c385680 100644 --- a/src/api/js/PUBLISHED_README.md +++ b/src/api/js/PUBLISHED_README.md @@ -1,30 +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(); +``` -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. +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');`. -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. +### Limitations -[`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 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. +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. -## Differences from the C API +## High-level -### Integers +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` + +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. @@ -54,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 { - // ... + // ... } ``` @@ -62,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[]); ``` @@ -82,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 @@ -99,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: @@ -120,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 75% rename from src/api/js/example-raw.ts rename to src/api/js/examples/low-level/example-raw.ts index 9b19e782c..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 } from './build/wrapper'; +import process from 'process'; +import { init, Z3_error_code } from '../../build/node'; // demonstrates use of the raw API @@ -47,6 +48,15 @@ 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/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 0e371fc6e..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/wrapper'; -import { init, Z3_lbool, Z3_ast_kind, Z3_sort_kind, Z3_symbol_kind } from './build/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 85fd2d24c..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/wrapper.js", - "types": "build/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 && 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 4513b7e58..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 = 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 deleted file mode 100644 index b0860e349..000000000 --- a/src/api/js/scripts/make-cc-wrapper.js +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; - -// generates c wrappers with off-thread versions of specified functions - -let path = require('path'); - -let { functions } = require('./parse-api.js'); -let asyncFns = require('./async-fns.js'); - -let wrappers = []; - -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( - ` -extern "C" void async_${fn.name}(${fn.params - .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)} -// DO NOT EDIT IT BY HAND - -#include - -#include - -#include "../../z3.h" - -template -void wrapper(Args&&... args) { - std::thread t([...args = std::forward(args)] { - try { - auto result = fn(args...); - MAIN_THREAD_ASYNC_EM_ASM({ - resolve_async($0); - }, result); - } catch (...) { - MAIN_THREAD_ASYNC_EM_ASM({ - reject_async('failed with unknown exception'); - }); - throw; - } - }); - t.detach(); -} - -template -void wrapper_str(Args&&... args) { - std::thread t([...args = std::forward(args)] { - try { - auto result = fn(args...); - MAIN_THREAD_ASYNC_EM_ASM({ - resolve_async(UTF8ToString($0)); - }, result); - } catch (...) { - MAIN_THREAD_ASYNC_EM_ASM({ - reject_async('failed with unknown exception'); - }); - throw; - } - }); - t.detach(); -} - -${wrappers.join('\n\n')}`); diff --git a/src/api/js/scripts/make-cc-wrapper.ts b/src/api/js/scripts/make-cc-wrapper.ts new file mode 100644 index 000000000..2b7ca2536 --- /dev/null +++ b/src/api/js/scripts/make-cc-wrapper.ts @@ -0,0 +1,119 @@ +// generates c wrappers with off-thread versions of specified functions + +import path from 'path'; +import { asyncFuncs } from './async-fns'; +import { functions } from './parse-api'; + +export function makeCCWrapper() { + 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}`); + } + + wrappers.push( + ` +extern "C" void async_${fn.name}(${fn.params + .map(p => `${p.isConst ? 'const ' : ''}${p.cType}${p.isPtr ? '*' : ''} ${p.name}${p.isArray ? '[]' : ''}`) + .join(', ')}) { + ${wrapper}(${fn.params.map(p => `${p.name}`).join(', ')}); +} +`.trim(), + ); + } + + return `// THIS FILE IS AUTOMATICALLY GENERATED BY ${path.basename(__filename)} +// DO NOT EDIT IT BY HAND + +#include + +#include + +#include "../../z3.h" + +template +void wrapper(Args&&... args) { + std::thread t([...args = std::forward(args)] { + try { + auto result = fn(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'); + }); + } + }); + t.detach(); +} + +template +void wrapper_str(Args&&... args) { + std::thread t([...args = std::forward(args)] { + try { + auto result = fn(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(new Error('failed with unknown exception')); + }); + } + }); + 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')} +`; +} + +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 4a51c5ec9..000000000 --- a/src/api/js/scripts/make-ts-wrapper.js +++ /dev/null @@ -1,422 +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; - -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) { - 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(); - } - - if (isAsync) { - } - - // 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 - -// @ts-ignore no-implicit-any -import initModule = require('./z3-built.js'); -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() { - 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: { - ${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 53655424f..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,18 +31,18 @@ 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 = { +const types = { __proto__: null, // these are function types I can't be bothered to parse @@ -55,11 +54,26 @@ let types = { 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; -let defApis = Object.create(null); -let functions = []; -let enums = Object.create(null); +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; +}; +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'); @@ -79,31 +93,40 @@ 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; } + // 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) { 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) { + 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; 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; } + 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') { + if (kind === 'in' || kind === 'out' || kind == 'fnptr') { ({ text, match } = expect(text, /^[A-Za-z0-9_]+/)); parsedParams.push({ kind, type: match[0] }); } else { @@ -121,7 +144,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}`); } @@ -129,15 +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; } - // 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; ) { let nextIdx = contents.indexOf('typedef enum', idx); @@ -155,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_]+/)); @@ -172,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); @@ -221,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_]+/)); @@ -302,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); } @@ -339,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)}`); @@ -359,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.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 +} diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index b904937a9..36753a4f9 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 @@ -914,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 @@ -1018,7 +1026,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 +1137,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) @@ -1258,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/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" { 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 diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 5309142f2..572b0a7a7 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 @@ -236,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() @@ -257,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' @@ -273,10 +304,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 +318,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(), diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 223b3e038..7dbef9f6e 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 @@ -225,6 +226,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 @@ -342,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 @@ -1101,6 +1106,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): @@ -5102,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) @@ -5114,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) @@ -5394,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): @@ -5459,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): @@ -5522,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): @@ -5826,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): @@ -5989,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): @@ -6108,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): @@ -6215,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): @@ -6333,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): @@ -6443,7 +6470,25 @@ class ModelRef(Z3PPObject): return None r = _to_expr_ref(_r, self.ctx) if is_as_array(r): - return self.get_interp(get_as_array_func(r)) + fi = self.get_interp(get_as_array_func(r)) + if fi is None: + return fi + e = fi.else_value() + if e is None: + return fi + if fi.arity() != 1: + return fi + srt = decl.range() + dom = srt.domain() + e = K(dom, e) + i = 0 + sz = fi.num_entries() + n = fi.arity() + while i < sz: + fe = fi.entry(i) + e = Store(e, fe.arg_value(0), fe.value()) + i += 1 + return e else: return r else: @@ -6594,6 +6639,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) @@ -6649,7 +6707,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): @@ -6842,7 +6900,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): @@ -7365,7 +7423,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): @@ -7788,7 +7846,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] @@ -8013,7 +8071,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): @@ -8118,7 +8176,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): @@ -8429,7 +8487,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): @@ -8733,8 +8791,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)() @@ -8764,6 +8826,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. @@ -9150,7 +9233,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 @@ -11249,7 +11332,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): @@ -11295,13 +11378,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: diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 1388d0ab1..8c60a09d1 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* t, unsigned* idx, Z3_lbool* phase)); /** @@ -1684,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. @@ -2093,6 +2102,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. @@ -2913,6 +2935,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. @@ -3686,7 +3718,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. @@ -3695,7 +3727,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))) */ @@ -4839,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); @@ -5260,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. @@ -6709,6 +6755,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( @@ -6724,6 +6772,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); @@ -6740,25 +6790,50 @@ 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. + \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); + + /** + \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. + 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); + + /** + 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 @@ -6817,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); @@ -6830,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[]); @@ -6851,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, @@ -6862,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_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/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/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 0757902f5..b336dd2e5 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(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)); + } case OP_ARRAY_DEFAULT: return mk_default(arity, domain); case OP_SET_UNION: @@ -587,6 +600,10 @@ void array_decl_plugin::get_op_names(svector& op_names, symbol con op_names.push_back(builtin_name("subset",OP_SET_SUBSET)); op_names.push_back(builtin_name("as-array", OP_AS_ARRAY)); op_names.push_back(builtin_name("array-ext", OP_ARRAY_EXT)); + + op_names.push_back(builtin_name("mindiff", OP_ARRAY_MINDIFF)); + op_names.push_back(builtin_name("maxdiff", OP_ARRAY_MAXDIFF)); + #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)); @@ -613,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()); @@ -687,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 7298a0e47..51f380243 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, @@ -135,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 { @@ -157,6 +162,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 +189,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 { @@ -272,6 +281,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/ast.cpp b/src/ast/ast.cpp index 65e2a5d1a..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 // ----------------------------------- @@ -498,9 +499,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 +994,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 +1010,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}; @@ -1672,12 +1673,12 @@ 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; } + void ast_manager::register_plugin(family_id id, decl_plugin * plugin) { SASSERT(m_plugins.get(id, 0) == 0); m_plugins.setx(id, plugin, 0); @@ -2413,7 +2414,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(); } diff --git a/src/ast/ast.h b/src/ast/ast.h index 3cb90193f..798280d2c 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -272,6 +272,7 @@ public: family_id get_family_id() const { return m_family_id; } decl_kind get_decl_kind() const { return m_kind; } + bool is_decl_of(family_id fid, decl_kind k) const { return m_family_id == fid && k == m_kind; } unsigned get_num_parameters() const { return m_parameters.size(); } parameter const & get_parameter(unsigned idx) const { return m_parameters[idx]; } parameter const * get_parameters() const { return m_parameters.begin(); } @@ -572,11 +573,12 @@ 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(); } decl_kind get_decl_kind() const { return m_info == nullptr ? null_decl_kind : m_info->get_decl_kind(); } + bool is_decl_of(family_id fid, decl_kind k) const { return m_info && m_info->is_decl_of(fid, k); } unsigned get_num_parameters() const { return m_info == nullptr ? 0 : m_info->get_num_parameters(); } parameter const & get_parameter(unsigned idx) const { return m_info->get_parameter(idx); } parameter const * get_parameters() const { return m_info == nullptr ? nullptr : m_info->get_parameters(); } @@ -671,6 +673,9 @@ protected: public: sort* get_sort() const; + + unsigned get_small_id() const { return get_id(); } + }; // ----------------------------------- @@ -715,7 +720,7 @@ public: unsigned get_num_parameters() const { return get_decl()->get_num_parameters(); } parameter const& get_parameter(unsigned idx) const { return get_decl()->get_parameter(idx); } parameter const* get_parameters() const { return get_decl()->get_parameters(); } - bool is_app_of(family_id fid, decl_kind k) const { return get_family_id() == fid && get_decl_kind() == k; } + bool is_app_of(family_id fid, decl_kind k) const { return m_decl->is_decl_of(fid, k); } unsigned get_num_args() const { return m_num_args; } expr * get_arg(unsigned idx) const { SASSERT(idx < m_num_args); return m_args[idx]; } expr * const * get_args() const { return m_args; } @@ -1615,7 +1620,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; } @@ -1914,9 +1919,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); @@ -2574,7 +2578,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/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_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..06ade7eed 100644 --- a/src/ast/ast_pp_util.h +++ b/src/ast/ast_pp_util.h @@ -21,21 +21,23 @@ 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; - - public: + 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) {} + 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_num_sorts = 0; m_num_decls = 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); @@ -57,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/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_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/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/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 74002bb1b..5b28bcf5e 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -423,7 +423,8 @@ func_decl * bv_decl_plugin::mk_num_decl(unsigned num_parameters, parameter const // This cannot be enforced now, since some Z3 modules try to generate these invalid numerals. // After SMT-COMP, I should find all offending modules. // For now, I will just simplify the numeral here. - parameter p0(mod(parameters[0].get_rational(), rational::power_of_two(bv_size))); + rational v = parameters[0].get_rational(); + parameter p0(mod2k(v, bv_size)); parameter ps[2] = { std::move(p0), parameters[1] }; sort * bv = get_bv_sort(bv_size); return m_manager->mk_const_decl(m_bv_sym, bv, func_decl_info(m_family_id, OP_BV_NUM, num_parameters, ps)); @@ -641,16 +642,18 @@ void bv_decl_plugin::get_offset_term(app * a, expr * & t, rational & offset) con offset = decl->get_parameter(0).get_rational(); sz = decl->get_parameter(1).get_int(); t = a->get_arg(1); - offset = mod(offset, rational::power_of_two(sz)); + offset = mod2k(offset, sz); } else { t = a; - offset = rational(0); + offset.reset(); } } bool bv_decl_plugin::are_distinct(app * a, app * b) const { -#if 1 + if (decl_plugin::are_distinct(a, b)) + return true; + // Check for a + k1 != a + k2 when k1 != k2 rational a_offset; expr * a_term; @@ -665,8 +668,7 @@ bool bv_decl_plugin::are_distinct(app * a, app * b) const { tout << "b: " << b_offset << " + " << mk_ismt2_pp(b_term, *m_manager) << "\n";); if (a_term == b_term && a_offset != b_offset) return true; -#endif - return decl_plugin::are_distinct(a, b); + return false; } void bv_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { @@ -752,9 +754,9 @@ expr * bv_decl_plugin::get_some_value(sort * s) { } rational bv_recognizers::norm(rational const & val, unsigned bv_size, bool is_signed) const { - rational r = mod(val, rational::power_of_two(bv_size)); + rational r = mod2k(val, bv_size); SASSERT(!r.is_neg()); - if (is_signed) { + if (is_signed) { if (r >= rational::power_of_two(bv_size - 1)) { r -= rational::power_of_two(bv_size); } 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/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/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) { 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/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index 3da45781f..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; @@ -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 7876d2d79..862fe6929 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;); @@ -95,7 +94,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 +123,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) { @@ -2655,7 +2666,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); @@ -2739,9 +2751,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); @@ -3248,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;); @@ -3478,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); @@ -3487,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/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/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 0e9c27655..ca2e1584d 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 @@ -271,11 +273,9 @@ 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); - } - } } } } diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 857ae0755..35b45295f 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -700,13 +700,38 @@ 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; - 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))); 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) { diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 88a0ee28e..40e3e532f 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -23,6 +23,7 @@ Notes: #include "ast/ast_ll_pp.h" #include "ast/rewriter/var_subst.h" #include "params/array_rewriter_params.hpp" +#include "util/util.h" void array_rewriter::updt_params(params_ref const & _p) { array_rewriter_params p(_p); @@ -161,7 +162,8 @@ br_status array_rewriter::mk_store_core(unsigned num_args, expr * const * args, return BR_FAILED; } - + + br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, expr_ref & result) { SASSERT(num_args >= 2); if (m_util.is_store(args[0])) { @@ -172,15 +174,33 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, result = to_app(args[0])->get_arg(num_args); return BR_DONE; case l_false: { + expr* arg0 = to_app(args[0])->get_arg(0); + while (m_util.is_store(arg0) && compare_args(num_args-1, args + 1, to_app(arg0)->get_args() + 1) == l_false) { + arg0 = to_app(arg0)->get_arg(0); + } + // select(store(a, I, v), J) --> select(a, J) if I != J ptr_buffer new_args; - new_args.push_back(to_app(args[0])->get_arg(0)); + new_args.push_back(arg0); new_args.append(num_args-1, args+1); 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 +223,7 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, } return BR_FAILED; } + } } if (m_util.is_const(args[0])) { 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; diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 1fdd7bd14..516248e24 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) { @@ -1740,7 +1736,7 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re unsigned low = 0; unsigned i = 0; while (i < sz) { - while (i < sz && mod(v1, two).is_one()) { + while (i < sz && v1.is_odd()) { i++; div(v1, two, v1); } @@ -1749,7 +1745,7 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re exs.push_back(m_util.mk_numeral(rational::power_of_two(num_sz) - numeral(1), num_sz)); low = i; } - while (i < sz && mod(v1, two).is_zero()) { + while (i < sz && v1.is_even()) { i++; div(v1, two, v1); } 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); 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() { 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; diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 9fcc35b2d..4f70b7933 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); @@ -817,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); @@ -850,6 +859,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)) { @@ -1067,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()) { @@ -1425,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; @@ -1618,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), @@ -1632,29 +1657,53 @@ 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; } + 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); + 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; } @@ -1884,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; @@ -2008,6 +2056,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. @@ -2180,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; @@ -2258,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; @@ -4890,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()); @@ -5472,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); @@ -5488,32 +5623,28 @@ 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; } 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; } /*** @@ -5522,14 +5653,70 @@ 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; + + if (sz == 0) + return { bounded, len }; + auto visit = [&](expr* e) { + expr* c, *th, *el; + 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 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 (subsz != 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* c, *th, *el; expr* e = es.back(); es.pop_back(); if (str().is_unit(e)) @@ -5541,24 +5728,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; @@ -5581,9 +5782,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); } @@ -5679,33 +5880,43 @@ 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) { 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) 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)); ls.reset(); rs.reset(); - } + } return true; } diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index f10532572..4c7c3883a 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); @@ -318,12 +322,14 @@ 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); - 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/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() { diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index f4cf2ecaa..95b9b8579 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -182,6 +182,7 @@ 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* strT = m_string; @@ -193,7 +194,7 @@ void seq_decl_plugin::init() { 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* seqAseqAseqA[3] = { seqA, seqA, seqA }; sort* seqAreAseqA[3] = { seqA, reA, seqA }; sort* seqAseqA[2] = { seqA, seqA }; @@ -209,6 +210,7 @@ void seq_decl_plugin::init() { sort* str2TintT[3] = { strT, strT, intT }; sort* seqAintT[2] = { seqA, intT }; sort* seq3A[3] = { seqA, seqA, 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); @@ -273,6 +275,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; @@ -582,6 +585,13 @@ 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: + add_map_sig(); + 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); @@ -625,13 +635,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 ddde7fa6a..29d7b08ef 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, @@ -136,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); @@ -296,6 +303,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 +344,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 +399,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); diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp index ec1a73e9b..ad289cf5e 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; @@ -451,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); @@ -461,10 +453,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 +461,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) { @@ -563,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)) @@ -572,25 +538,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 +599,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 +641,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 40532f939..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; @@ -162,7 +156,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]++; } @@ -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(); 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/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 580cc2de4..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)) { @@ -597,9 +598,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); } @@ -793,7 +793,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(); 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/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/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/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/explanation.h b/src/math/lp/explanation.h index 1b4bd9ddb..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,15 +72,17 @@ 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(); 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/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/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 + 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)); 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/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index e63e71be6..8b8f82a31 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -485,6 +485,26 @@ namespace opt { } } + model_based_opt::row& model_based_opt::row::normalize() { +#if 0 + if (m_type == t_mod) + return *this; + rational D(denominator(abs(m_coeff))); + if (D == 0) + D = 1; + for (auto const& [id, coeff] : m_vars) + if (coeff != 0) + 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; + } + // // Let // row1: t1 + a1*x <= 0 @@ -923,9 +943,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; }; diff --git a/src/math/simplex/simplex.cpp b/src/math/simplex/simplex.cpp index 6d1c4d348..643db9c5b 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 kernel(sparse_matrix& M, vector>& K) { + sparse_matrix_ops::kernel(M, K); + } 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..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" @@ -200,5 +201,7 @@ namespace simplex { }; void ensure_rational_solution(simplex& s); + + void kernel(sparse_matrix& s, vector>& K); }; diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index f18bb6f87..a33ea55bd 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(); @@ -201,19 +202,34 @@ 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(); } + unsigned num_rows() const { return m_rows.size(); } + class col_iterator { 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) { @@ -228,28 +244,84 @@ 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& 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()); } 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; + 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); } + + numeral const& get_coeff(row r, unsigned v) { + for (auto & row : get_row(r)) + if (row.m_var == v) + return row.m_coeff; + return m_zero; + } + 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_def.h b/src/math/simplex/sparse_matrix_def.h index a3170461b..dc3700f2e 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -299,6 +299,8 @@ 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 +319,9 @@ 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 new file mode 100644 index 000000000..039d2fede --- /dev/null +++ b/src/math/simplex/sparse_matrix_ops.h @@ -0,0 +1,85 @@ +/*++ +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: + template + static void kernel(sparse_matrix &M, vector> &K) { + using scoped_numeral = typename Ext::scoped_numeral; + + 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_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 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/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/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); } 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/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_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/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/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/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/opt/CMakeLists.txt b/src/opt/CMakeLists.txt index c652bcaea..9c20b7d2d 100644 --- a/src/opt/CMakeLists.txt +++ b/src/opt/CMakeLists.txt @@ -1,10 +1,11 @@ z3_add_component(opt SOURCES + maxcore.cpp maxlex.cpp - maxres.cpp 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/maxres.cpp b/src/opt/maxcore.cpp similarity index 69% rename from src/opt/maxres.cpp rename to src/opt/maxcore.cpp index 135e0f80e..70bf38d87 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxcore.cpp @@ -3,14 +3,19 @@ Copyright (c) 2014 Microsoft Corporation Module Name: - maxsres.cpp + maxcore.cpp Abstract: - - MaxRes (weighted) max-sat algorithms: - - mus: max-sat algorithm by Nina and Bacchus, AAAI 2014. - - mus-mss: based on dual refinement of bounds. + 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 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. MusMssMaxRes extends the core-guided approach by @@ -23,20 +28,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. @@ -63,16 +68,20 @@ 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/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_dual, + s_primal_binary, + s_rc2, + s_primal_binary_rc2 }; private: struct stats { @@ -84,10 +93,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); } @@ -97,38 +106,36 @@ 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_maxres m_lnsctx; + 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_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. - 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 - + 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; public: - maxres(maxsat_context& c, unsigned index, + maxcore(maxsat_context& c, unsigned index, vector& soft, strategy_t st): maxsmt_solver_base(c, soft, index), @@ -138,17 +145,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_last_index(0), - 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: @@ -157,16 +154,28 @@ public: case s_primal_dual: m_trace_id = "pd-maxres"; break; - } + case s_primal_binary: + m_trace_id = "maxres-bin"; + break; + case s_rc2: + m_trace_id = "rc2"; + break; + case s_primal_binary_rc2: + m_trace_id = "rc2bin"; + break; + default: + UNREACHABLE(); + break; + } } - ~maxres() override {} + ~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); @@ -202,7 +211,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"; ); } @@ -219,7 +228,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); @@ -227,8 +236,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";); @@ -241,7 +250,7 @@ public: m_lower = m_upper; } if (is_sat == l_undef) { - return is_sat; + return is_sat; } break; case l_undef: @@ -267,7 +276,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; @@ -283,7 +292,7 @@ public: m_lower = m_upper; } if (is_sat == l_undef) { - return is_sat; + return is_sat; } break; case l_undef: @@ -304,29 +313,27 @@ public: /** Give preference to cores that have large minimal values. */ - sort_assumptions(asms); - m_last_index = 0; + sort_assumptions(asms); + 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()); - } + } } 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); @@ -357,6 +364,9 @@ public: m_defs.reset(); switch(m_st) { 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(); @@ -365,17 +375,10 @@ 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 { - 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; @@ -403,7 +406,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 @@ -411,19 +414,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; - if (cores.size() >= m_max_num_cores) break; + 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; } @@ -446,8 +449,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); @@ -483,13 +486,16 @@ 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) + return core_rotate(); + vector cores; lbool is_sat = get_cores(cores); if (is_sat != l_true) { @@ -504,36 +510,63 @@ 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; + ++m_stats.m_num_cores; + 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) { + 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); 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_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; + } 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. @@ -545,16 +578,17 @@ 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(); - 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(); 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) { @@ -569,7 +603,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); @@ -577,25 +611,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; @@ -609,9 +639,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; } @@ -624,7 +653,7 @@ public: rational w3 = w2 - w; new_assumption(e, w3); } - } + } return w; } @@ -644,11 +673,11 @@ 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"; - } } + void max_resolve(exprs const& core, rational const& w) { SASSERT(!core.empty()); expr_ref fml(m), asum(m); @@ -658,15 +687,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]; @@ -698,6 +727,133 @@ public: m_defs.push_back(fml); } } + + 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); + 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); + us.push_back(u); + core.push_back(v); + } + 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 + + // 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; + rational m_unfold_upper; + + 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 weaken_bounds(exprs const& core) { + 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); + 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); + new_assumption(am, weight); + } + } + + /** + * \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) { @@ -711,7 +867,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 @@ -727,7 +883,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; @@ -760,7 +916,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); @@ -772,16 +928,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(0); - for (soft& s : m_soft) - if (!mdl.is_true(s.s)) - upper += s.weight; + rational upper = m_unfold_upper; + for (soft& s : m_soft) + if (!mdl.is_true(s.s)) + upper += s.weight; return upper; } @@ -789,8 +945,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) { @@ -807,7 +963,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(); @@ -816,14 +972,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(); @@ -838,17 +994,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";); @@ -859,14 +1015,14 @@ 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(); 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_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; @@ -874,15 +1030,16 @@ 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; m_found_feasible_optimum = false; - m_last_index = 0; add_upper_bound_block(); m_csmodel = nullptr; m_correction_set_size = 0; + m_unfold_upper = 0; + m_at_mostk.reset(); + m_bounds.reset(); return l_true; } @@ -890,21 +1047,20 @@ 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. } 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"; @@ -915,18 +1071,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); @@ -945,11 +1101,28 @@ 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_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); +} + + 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 52% rename from src/opt/maxres.h rename to src/opt/maxcore.h index 25ef9bf05..2038c5e98 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,8 +21,14 @@ Notes: 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); + 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 a3d5f2f45..3d0834472 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" @@ -185,21 +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("pd-maxres")) { + 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("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()); @@ -336,15 +337,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/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_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 { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 25982e89e..fcc8cdd46 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); @@ -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_cores.cpp b/src/opt/opt_cores.cpp new file mode 100644 index 000000000..124df63d7 --- /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) { + 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(); + m_best_cost = -1; + 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 5106c5492..93ecddbe4 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', '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'), @@ -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'), 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/opt/opt_preprocess.cpp b/src/opt/opt_preprocess.cpp index f65d5d09b..886d7fbb0 100644 --- a/src/opt/opt_preprocess.cpp +++ b/src/opt/opt_preprocess.cpp @@ -15,25 +15,143 @@ 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 #include "opt/opt_preprocess.h" +#include "util/max_cliques.h" namespace opt { - bool preprocess::find_mutexes(vector& softs, rational& lower) { + 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; + } + if (!m.inc()) + return false; + + 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& 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; - 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); vector mutexes; lbool is_sat = s.find_mutexes(fmls, mutexes); if (is_sat == l_false) @@ -42,6 +160,22 @@ 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)); @@ -86,7 +220,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; @@ -94,9 +228,14 @@ 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) { - return find_mutexes(soft, 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 8918e5e89..71e06eb2c 100644 --- a/src/opt/opt_preprocess.h +++ b/src/opt/opt_preprocess.h @@ -28,9 +28,14 @@ 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); + 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/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/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/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/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/sat/dimacs.cpp b/src/sat/dimacs.cpp index 9c9a40a24..629fefb7b 100644 --- a/src/sat/dimacs.cpp +++ b/src/sat/dimacs.cpp @@ -112,6 +112,29 @@ 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); + if (*in != 'p') + return; + ++in; + while (*in == ' ') + ++in; + while (true) { + if (*in == EOF) + break; + if (*in == '\n') { + ++in; + break; + } + p.push_back(*in); + ++in; + } + if (!p.empty()) + h.from_string(p); +} + + template static bool parse_dimacs_core(Buffer & in, std::ostream& err, sat::solver & solver) { sat::literal_vector lits; @@ -156,7 +179,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 +305,8 @@ namespace dimacs { try { loop: skip_whitespace(in); + m_record.m_pragma.clear(); + m_record.m_hint.reset(); switch (*in) { case EOF: return false; @@ -304,6 +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, 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 cc4b27182..7a5a66283 100644 --- a/src/sat/dimacs.h +++ b/src/sat/dimacs.h @@ -59,10 +59,12 @@ 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; + sat::proof_hint m_hint; }; struct drat_pp { 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_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_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 6d8c4d477..9cac2e5ef 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. @@ -19,20 +19,15 @@ 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 { + 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; @@ -47,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; @@ -59,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 { @@ -137,16 +130,22 @@ namespace sat { } } buffer[len++] = '0'; + if (st.get_hint()) { + buffer[len++] = ' '; + buffer[len++] = 'p'; + buffer[len++] = ' '; + auto* ps = st.get_hint(); + for (auto ch : ps->to_string()) + buffer[len++] = ch; + } 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"; } @@ -173,7 +172,8 @@ namespace sat { m_bout->write(buffer, len); len = 0; } - } while (v); + } + while (v); } buffer[len++] = 0; m_bout->write(buffer, len); @@ -183,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; @@ -208,14 +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) - assign_propagate(l); - - m_units.push_back(l); + if (m_check_unsat) { + assign_propagate(l, nullptr); + m_units.push_back({l, nullptr}); + } } void drat::append(literal l1, literal l2, status st) { @@ -226,28 +230,28 @@ 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()) 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); 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); } } @@ -276,40 +280,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]); @@ -330,12 +310,16 @@ namespace sat { } } } + + if (!m_check_unsat) + return; + switch (num_watch) { case 0: m_inconsistent = true; break; - case 1: - assign_propagate(l1); + case 1: + assign_propagate(l1, &c); break; default: { SASSERT(num_watch == 2); @@ -360,7 +344,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); @@ -378,13 +363,14 @@ 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) { - m_assignment[m_units[i].var()] = l_undef; - } - units.append(m_units.size() - num_units, m_units.data() + num_units); + for (unsigned i = num_units; i < m_units.size(); ++i) + 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; @@ -398,14 +384,607 @@ 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( - for (literal u : m_units) + for (auto const& [u,c] : m_units) SASSERT(m_assignment[u.var()] != l_undef); ); + for (unsigned i = num_units; i < m_units.size(); ++i) + m_assignment[m_units[i].first.var()] = l_undef; + + m_units.shrink(num_units); + bool ok = m_inconsistent; + m_inconsistent = false; + return ok; + } + + bool drat::is_drat(unsigned n, literal const* c) { + return false; + if (m_inconsistent || n == 0) + return true; + for (unsigned i = 0; i < n; ++i) + if (is_drat(n, c, i)) + return true; + return false; + } + + void drat::validate_propagation() const { + 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])) { + case l_false: break; + case l_true: num_true++; break; + case l_undef: num_undef++; break; + } + } + CTRACE("sat_drat", num_true == 0 && num_undef == 1, display(tout);); + SASSERT(num_true != 0 || num_undef != 1); + } + } + } + + bool drat::is_drat(unsigned n, literal const* c, unsigned pos) { + SASSERT(pos < n); + literal l = c[pos]; + literal_vector lits(n, c); + SASSERT(lits.size() == n); + 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()) { + lits.append(j, c.begin()); + lits.append(c.size() - j - 1, c.begin() + j + 1); + if (!is_drup(lits.size(), lits.data())) + return false; + lits.resize(n); + } + } + } + return true; + + } + + void drat::verify(unsigned n, literal const* c) { + if (!m_check_unsat) + return; + for (unsigned i = 0; i < n; ++i) + declare(c[i]); + if (is_drup(n, c)) { + ++m_stats.m_num_drup; + return; + } + if (is_drat(n, c)) { + ++m_stats.m_num_drat; + return; + } + + literal_vector lits(n, c); + IF_VERBOSE(0, verbose_stream() << "Verification of " << lits << " failed\n"); + // s.display(std::cout); + UNREACHABLE(); +#if 0 + SASSERT(false); + INVOKE_DEBUGGER(); + exit(0); + UNREACHABLE(); + //display(std::cout); + TRACE("sat_drat", + tout << literal_vector(n, c) << "\n"; + display(tout); + s.display(tout);); + UNREACHABLE(); +#endif + } + + bool drat::contains(literal c, justification const& j) { + if (!m_check_sat) { + return true; + } + switch (j.get_kind()) { + case justification::NONE: + 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: + return contains(c, j.get_literal1(), j.get_literal2()); + case justification::CLAUSE: + return contains(s.get_clause(j)); + default: + return true; + } + } + + bool drat::contains(unsigned n, literal const* lits) { + if (!m_check) + return true; + unsigned num_add = 0; + unsigned num_del = 0; + for (unsigned i = m_proof.size(); i-- > 0; ) { + auto const & [c, st] = m_proof[i]; + if (match(n, lits, c)) { + if (st.is_deleted()) + num_del++; + else + num_add++; + } + } + return num_add > num_del; + } + + bool drat::match(unsigned n, literal const* lits, clause const& c) const { + 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; + } + } + if (!found) + return false; + } + return true; + } + + void drat::display(std::ostream& out) const { + + 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) + out << i << ": " << v << "\n"; + } + 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 (literal lit : c) { + switch (value(lit)) { + 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, 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]; + if (!w1.empty()) { + out << i << " |-> "; + for (unsigned i = 0; i < w1.size(); ++i) out << *(m_watched_clauses[w1[i]].m_clause) << " "; + out << "\n"; + } + if (!w2.empty()) { + out << "-" << i << " |-> "; + for (unsigned i = 0; i < w2.size(); ++i) out << *(m_watched_clauses[w2[i]].m_clause) << " "; + out << "\n"; + } + } + } + + lbool drat::value(literal l) const { + lbool val = m_assignment.get(l.var(), l_undef); + return val == l_undef || !l.sign() ? val : ~val; + } + + 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";); + switch (old_value) { + case l_false: + m_inconsistent = true; + break; + case l_true: + break; + case l_undef: + m_assignment.setx(l.var(), new_value, l_undef); + m_units.push_back({l, c}); + break; + } + } + + void drat::assign_propagate(literal l, clause* c) { + if (!m_check_unsat) + return; + unsigned num_units = m_units.size(); + assign(l, c); + for (unsigned i = num_units; !m_inconsistent && i < m_units.size(); ++i) + propagate(m_units[i].first); + } + + void drat::propagate(literal l) { + watch& clauses = m_watches[l.index()]; + watch::iterator it = clauses.begin(); + watch::iterator it2 = it; + watch::iterator end = clauses.end(); + for (; it != end; ++it) { + unsigned idx = *it; + watched_clause& wc = m_watched_clauses[idx]; + clause& c = *wc.m_clause; + + //TRACE("sat_drat", tout << "Propagate " << l << " " << c << " watch: " << wc.m_l1 << " " << wc.m_l2 << "\n";); + if (wc.m_l1 == ~l) { + std::swap(wc.m_l1, wc.m_l2); + } + + SASSERT(wc.m_l2 == ~l); + if (value(wc.m_l1) == l_true) { + *it2 = *it; + it2++; + } + else { + bool done = false; + for (unsigned i = 0; !done && i < c.size(); ++i) { + literal lit = c[i]; + if (lit != wc.m_l1 && lit != wc.m_l2 && value(lit) != l_false) { + wc.m_l2 = lit; + m_watches[(~lit).index()].push_back(idx); + done = true; + } + } + if (done) { + continue; + } + else if (value(wc.m_l1) == l_false) { + m_inconsistent = true; + goto end_process_watch; + } + else { + *it2 = *it; + it2++; + assign(wc.m_l1, &c); + } + } + } + end_process_watch: + for (; it != end; ++it, ++it2) + *it2 = *it; + clauses.set_end(it2); + } + + status drat::get_status(bool learned) const { + if (learned || s.m_searching) + return status::redundant(); + return status::asserted(); + } + + void drat::add() { + ++m_stats.m_num_add; + if (m_out) (*m_out) << "0\n"; + if (m_bout) bdump(0, nullptr, status::redundant()); + if (m_check_unsat) { + verify(0, nullptr); + SASSERT(m_inconsistent); + } + } + void drat::add(literal l, bool learned) { + ++m_stats.m_num_add; + status st = get_status(learned); + if (m_out) dump(1, &l, st); + if (m_bout) bdump(1, &l, st); + if (m_check) append(l, st); + } + void drat::add(literal l1, literal l2, status st) { + if (st.is_deleted()) + ++m_stats.m_num_del; + else + ++m_stats.m_num_add; + literal ls[2] = { l1, l2 }; + if (m_out) dump(2, ls, st); + if (m_bout) bdump(2, ls, st); + if (m_check) append(l1, l2, st); + } + void drat::add(clause& c, status st) { + if (st.is_deleted()) + ++m_stats.m_num_del; + else + ++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) append(mk_clause(c), st); + } + + void drat::add(literal_vector const& lits, status st) { + add(lits.size(), lits.data(), st); + } + + void drat::add(unsigned sz, literal const* lits, status st) { + if (st.is_deleted()) + ++m_stats.m_num_del; + else + ++m_stats.m_num_add; + if (m_check) { + switch (sz) { + case 0: add(); break; + case 1: append(lits[0], st); break; + default: append(mk_clause(sz, lits, st.is_redundant()), st); break; + } + } + if (m_out) + dump(sz, lits, st); + } + + void drat::add(literal_vector const& c) { + ++m_stats.m_num_add; + 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); + switch (c.size()) { + case 0: add(); break; + case 1: append(c[0], status::redundant()); break; + default: { + verify(c.size(), c.begin()); + append(mk_clause(c.size(), c.data(), true), status::redundant()); + break; + } + } + } + } + + void drat::del(literal l) { + ++m_stats.m_num_del; + if (m_out) dump(1, &l, status::deleted()); + if (m_bout) bdump(1, &l, status::deleted()); + if (m_check) append(l, status::deleted()); + } + + void drat::del(literal l1, literal l2) { + ++m_stats.m_num_del; + literal ls[2] = { l1, l2 }; + if (m_out) dump(2, ls, status::deleted()); + if (m_bout) bdump(2, ls, status::deleted()); + if (m_check) append(l1, l2, status::deleted()); + } + + void drat::del(clause& c) { + +#if 0 + // check_duplicates: + for (literal lit : c) { + VERIFY(!m_seen[lit.index()]); + m_seen[lit.index()] = true; + } + for (literal lit : c) { + m_seen[lit.index()] = false; + } +#endif + ++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) 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) append(mk_clause(c.size(), c.begin(), true), status::deleted()); + } + + // + // placeholder for trim function. + // 1. trail contains justification for the empty clause. + // 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) { + } + + void drat::collect_statistics(statistics& st) const { + st.update("num-drup", m_stats.m_num_drup); + st.update("num-drat", m_stats.m_num_drat); + st.update("num-add", m_stats.m_num_add); + st.update("num-del", m_stats.m_num_del); + } + + + std::ostream& operator<<(std::ostream& out, sat::status const& st) { + std::function th = [&](int id) { return symbol(id); }; + return out << sat::status_pp(st, th); + } + + std::ostream& operator<<(std::ostream& out, sat::status_pp const& p) { + auto st = p.st; + if (st.is_deleted()) + out << "d"; + else if (st.is_input()) + out << "i"; + else if (st.is_asserted()) + out << "a"; + else if (st.is_redundant() && !st.is_sat()) + out << "r"; + 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::implied_eq_h: + ous << "implied_eq "; + break; + default: + UNREACHABLE(); + break; + } + for (auto const& [q, l] : m_literals) + ous << rational(q) << " * " << l << " "; + for (auto const& [a, b] : m_eqs) + ous << " = " << a << " " << b << " "; + for (auto const& [a, b] : m_diseqs) + ous << " != " << a << " " << b << " "; + return ous.str(); + } + + void proof_hint::from_string(char const* s) { + proof_hint& h = *this; + h.reset(); + h.m_ty = hint_type::null_h; + if (!s) + return; + 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; + } + if (0 == strncmp(s, "implied_eq", 10)) { + h.m_ty = hint_type::implied_eq_h; + s += 10; + 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 = [&]() { + 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 == '*') { + ++s; + ws(); + sat::literal lit = parse_literal(); + h.m_literals.push_back(std::make_pair(coeff, lit)); + return true; + } + return false; + }; + + ws(); + if (!parse_type()) + return; + ws(); + while (*s) { + if (!parse_coeff_literal()) + return; + ws(); + } + } + +#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 + + #if 0 if (!m_inconsistent) { literal_vector lits(n, c); @@ -456,447 +1035,5 @@ namespace sat { exit(0); } #endif - - for (unsigned i = num_units; i < m_units.size(); ++i) - m_assignment[m_units[i].var()] = l_undef; - - m_units.shrink(num_units); - bool ok = m_inconsistent; - m_inconsistent = false; - return ok; - } - - bool drat::is_drat(unsigned n, literal const* c) { - return false; - if (m_inconsistent || n == 0) - return true; - for (unsigned i = 0; i < n; ++i) - if (is_drat(n, c, i)) - return true; - return false; - } - - 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]; - unsigned num_undef = 0, num_true = 0; - for (unsigned j = 0; j < c.size(); ++j) { - switch (value(c[j])) { - case l_false: break; - case l_true: num_true++; break; - case l_undef: num_undef++; break; - } - } - CTRACE("sat_drat", num_true == 0 && num_undef == 1, display(tout);); - SASSERT(num_true != 0 || num_undef != 1); - } - } - } - - bool drat::is_drat(unsigned n, literal const* c, unsigned pos) { - SASSERT(pos < n); - 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]; - unsigned j = 0; - for (; j < c.size() && c[j] != ~l; ++j) {} - if (j != c.size()) { - lits.append(j, c.begin()); - lits.append(c.size() - j - 1, c.begin() + j + 1); - if (!is_drup(lits.size(), lits.data())) - return false; - lits.resize(n); - } - } - } - return true; - - } - - void drat::verify(unsigned n, literal const* c) { - if (!m_check_unsat) { - return; - } - for (unsigned i = 0; i < n; ++i) { - declare(c[i]); - } - if (is_drup(n, c)) { - ++m_stats.m_num_drup; - return; - } - if (is_drat(n, c)) { - ++m_stats.m_num_drat; - return; - } - - 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); -#if 0 - SASSERT(false); - INVOKE_DEBUGGER(); - exit(0); - UNREACHABLE(); - //display(std::cout); - TRACE("sat_drat", - tout << literal_vector(n, c) << "\n"; - display(tout); - s.display(tout);); - UNREACHABLE(); -#endif - } - - bool drat::contains(literal c, justification const& j) { - if (!m_check_sat) { - return true; - } - switch (j.get_kind()) { - case justification::NONE: - return m_units.contains(c); - case justification::BINARY: - return contains(c, j.get_literal()); - case justification::TERNARY: - return contains(c, j.get_literal1(), j.get_literal2()); - case justification::CLAUSE: - return contains(s.get_clause(j)); - default: - return true; - } - } - - bool drat::contains(unsigned n, literal const* lits) { - 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]; - if (match(n, lits, c)) { - if (st.is_deleted()) { - num_del++; - } - else { - num_add++; - } - } - } - return num_add > num_del; - } - - 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; - } - } - return true; - } - return false; - } - - 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"; - } - 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; - } - } - 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"; - } - } - for (unsigned i = 0; i < m_assignment.size(); ++i) { - watch const& w1 = m_watches[2 * i]; - watch const& w2 = m_watches[2 * i + 1]; - if (!w1.empty()) { - out << i << " |-> "; - for (unsigned i = 0; i < w1.size(); ++i) out << *(m_watched_clauses[w1[i]].m_clause) << " "; - out << "\n"; - } - if (!w2.empty()) { - out << "-" << i << " |-> "; - for (unsigned i = 0; i < w2.size(); ++i) out << *(m_watched_clauses[w2[i]].m_clause) << " "; - out << "\n"; - } - } - } - - lbool drat::value(literal l) const { - lbool val = m_assignment.get(l.var(), l_undef); - return val == l_undef || !l.sign() ? val : ~val; - } - - void drat::assign(literal l) { - 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";); - switch (old_value) { - case l_false: - m_inconsistent = true; - break; - case l_true: - break; - case l_undef: - m_assignment.setx(l.var(), new_value, l_undef); - m_units.push_back(l); - break; - } - } - - 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]); - } - } - - void drat::propagate(literal l) { - watch& clauses = m_watches[l.index()]; - watch::iterator it = clauses.begin(); - watch::iterator it2 = it; - watch::iterator end = clauses.end(); - for (; it != end; ++it) { - unsigned idx = *it; - watched_clause& wc = m_watched_clauses[idx]; - clause& c = *wc.m_clause; - - //TRACE("sat_drat", tout << "Propagate " << l << " " << c << " watch: " << wc.m_l1 << " " << wc.m_l2 << "\n";); - if (wc.m_l1 == ~l) { - std::swap(wc.m_l1, wc.m_l2); - } - - SASSERT(wc.m_l2 == ~l); - if (value(wc.m_l1) == l_true) { - *it2 = *it; - it2++; - } - else { - bool done = false; - for (unsigned i = 0; !done && i < c.size(); ++i) { - literal lit = c[i]; - if (lit != wc.m_l1 && lit != wc.m_l2 && value(lit) != l_false) { - wc.m_l2 = lit; - m_watches[(~lit).index()].push_back(idx); - done = true; - } - } - if (done) { - continue; - } - else if (value(wc.m_l1) == l_false) { - m_inconsistent = true; - goto end_process_watch; - } - else { - *it2 = *it; - it2++; - assign(wc.m_l1); - } - } - } - end_process_watch: - for (; it != end; ++it, ++it2) - *it2 = *it; - clauses.set_end(it2); - } - - status drat::get_status(bool learned) const { - if (learned || s.m_searching) - return status::redundant(); - return status::asserted(); - } - - void drat::add() { - ++m_stats.m_num_add; - if (m_out) (*m_out) << "0\n"; - if (m_bout) bdump(0, nullptr, status::redundant()); - if (m_check_unsat) { - verify(0, nullptr); - SASSERT(m_inconsistent); - } - } - void drat::add(literal l, bool learned) { - ++m_stats.m_num_add; - status st = get_status(learned); - if (m_out) dump(1, &l, st); - if (m_bout) bdump(1, &l, st); - if (m_check) append(l, st); - } - void drat::add(literal l1, literal l2, status st) { - if (st.is_deleted()) - ++m_stats.m_num_del; - else - ++m_stats.m_num_add; - literal ls[2] = { l1, l2 }; - if (m_out) dump(2, ls, st); - if (m_bout) bdump(2, ls, st); - if (m_check) append(l1, l2, st); - } - void drat::add(clause& c, status st) { - if (st.is_deleted()) - ++m_stats.m_num_del; - else - ++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); - } - } - void drat::add(literal_vector const& lits, status st) { - add(lits.size(), lits.data(), st); - } - - void drat::add(unsigned sz, literal const* lits, status st) { - if (st.is_deleted()) - ++m_stats.m_num_del; - else - ++m_stats.m_num_add; - if (m_check) { - 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; - } - } - } - if (m_out) - dump(sz, lits, st); - } - - void drat::add(literal_vector const& c) { - ++m_stats.m_num_add; - 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); - 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()); - break; - } - } - } - } - - void drat::del(literal l) { - ++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()); - } - - void drat::del(literal l1, literal l2) { - ++m_stats.m_num_del; - literal ls[2] = { l1, l2 }; - if (m_out) dump(2, ls, status::deleted()); - if (m_bout) bdump(2, ls, status::deleted()); - if (m_check) append(l1, l2, status::deleted()); - } - - void drat::del(clause& c) { - -#if 0 - // check_duplicates: - for (literal lit : c) { - VERIFY(!m_seen[lit.index()]); - m_seen[lit.index()] = true; - } - for (literal lit : c) { - m_seen[lit.index()] = false; - } -#endif - ++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()); - } - } - - 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()); - } - } - - void drat::check_model(model const& m) { - } - - void drat::collect_statistics(statistics& st) const { - st.update("num-drup", m_stats.m_num_drup); - st.update("num-drat", m_stats.m_num_drat); - st.update("num-add", m_stats.m_num_add); - st.update("num-del", m_stats.m_num_del); - } - - - std::ostream& operator<<(std::ostream& out, sat::status const& st) { - std::function th = [&](int id) { return symbol(id); }; - return out << sat::status_pp(st, th); - } - std::ostream& operator<<(std::ostream& out, sat::status_pp const& p) { - auto st = p.st; - if (st.is_deleted()) - out << "d"; - else if (st.is_input()) - out << "i"; - else if (st.is_asserted()) - out << "a"; - else if (st.is_redundant() && !st.is_sat()) - out << "r"; - if (!st.is_sat()) - out << " " << p.th(st.get_th()); - return out; - } - } diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index a9690f635..18ca7b7b8 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; - literal_vector m_units; + std::ostream* m_out = nullptr; + std::ostream* m_bout = nullptr; + svector> m_proof; + svector> 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(); @@ -102,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); @@ -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); @@ -165,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/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_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); } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 23e0d3a0c..71ac81715 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)'), 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/sat_solver.cpp b/src/sat/sat_solver.cpp index 4a254ac06..729b3c1f4 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; } @@ -946,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()); @@ -1662,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; @@ -4192,17 +4208,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); + mc.cliques2(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; } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 0f242bd4d..e5b13af98 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(); @@ -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/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 61dc53cd8..3d46ec643 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; } @@ -694,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()) @@ -708,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) { @@ -733,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);); @@ -742,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) { @@ -762,17 +786,29 @@ 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) { + 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; } @@ -886,33 +922,40 @@ 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() { - if (m_fmls_head == m_fmls.size()) { + if (m_fmls_head == m_fmls.size()) return l_true; + + lbool res; + + if (m_is_cnf) { + 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/sat_types.h b/src/sat/sat_types.h index 57300a705..fa42f0712 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,27 +94,47 @@ namespace sat { }; + enum class hint_type { + null_h, + farkas_h, + bound_h, + implied_eq_h, + }; + + struct proof_hint { + 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()); } + }; + class status { public: enum class st { input, asserted, redundant, deleted }; st m_st; int m_orig; + const proof_hint* m_hint; 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, 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) { return status(redundant ? st::redundant : st::asserted, id); } + 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; } + 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 1a60f597f..7cb6a05b6 100644 --- a/src/sat/smt/arith_axioms.cpp +++ b/src/sat/smt/arith_axioms.cpp @@ -234,44 +234,54 @@ namespace arith { if (k1 == k2 && kind1 == kind2) return; SASSERT(k1 != k2 || kind1 != kind2); + 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); + bin_clause(~l1, l2); else - add_clause(l1, ~l2); + 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); + bin_clause(~l1, ~l2); if (v_is_int && k1 == k2 + rational(1)) // k1 <= x or x <= k1-1 - add_clause(l1, l2); + 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); + bin_clause(l1, l2); else { // k1 < k2, k2 <= x => ~(x <= k1) - add_clause(~l1, ~l2); + bin_clause(~l1, ~l2); if (v_is_int && k1 == k2 - rational(1)) // x <= k1 or k1+l <= x - add_clause(l1, l2); + bin_clause(l1, l2); } } else { // kind1 == A_UPPER, kind2 == A_UPPER if (k1 >= k2) // k1 >= k2, x <= k2 => x <= k1 - add_clause(l1, ~l2); + bin_clause(l1, ~l2); else // k1 <= hi_sup , x <= k1 => x <= hi_sup - add_clause(~l1, l2); + bin_clause(~l1, l2); } } @@ -498,8 +508,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_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index 2dfd508d1..4f016746c 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -79,4 +79,58 @@ namespace arith { lp().settings().stats().collect_statistics(st); if (m_nla) m_nla->collect_statistics(st); } + + void solver::explain_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: + * 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::literal lit) { + if (!ctx.use_drat()) + return nullptr; + m_arith_hint.m_ty = ty; + explain_assumptions(); + if (lit != sat::null_literal) + 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; + 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_proof_checker.h b/src/sat/smt/arith_proof_checker.h new file mode 100644 index 000000000..c37a4f7c2 --- /dev/null +++ b/src/sat/smt/arith_proof_checker.h @@ -0,0 +1,356 @@ +/*++ +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 = 0; + } + }; + + ast_manager& m; + arith_util a; + vector> m_todo; + bool m_strict = false; + 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; + 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); + } + + 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 + */ + void linearize(row& r, rational const& mul, expr* e) { + SASSERT(m_todo.empty()); + m_todo.push_back({ mul, e }); + 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, 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({coeff, arg}); + else if (a.is_uminus(e, e1)) + m_todo.push_back({-coeff, e1}); + else if (a.is_sub(e, e1, e2)) { + m_todo.push_back({coeff, e1}); + m_todo.push_back({-coeff, e2}); + } + else if (a.is_numeral(e, coeff1)) + r.m_coeff += coeff*coeff1; + else + add(r, e, coeff); + } + m_todo.reset(); + } + + 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_gt(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_gt(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; + // display_row(std::cout << coeff << " * " << (sign?"~":"") << mk_pp(e, m) << "\n", r) << "\n"; + 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; + cut(m_ineq); + 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; + } + + // + // 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) { + if (!first) + out << " + "; + if (coeff != 1) + out << coeff << " * "; + out << mk_pp(v, m); + first = false; + } + if (r.m_coeff != 0) + out << " + " << r.m_coeff; + return out; + } + + + 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); + if (m_strict) + out << " < 0\n"; + else + out << " <= 0\n"; + } + + row& fresh(vector& rows) { + rows.push_back(row()); + return rows.back(); + } + + + public: + proof_checker(ast_manager& m): m(m), a(m) {} + + void reset() { + 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); + } + + bool add_conseq(rational const& coeff, expr* e, bool sign) { + return add_literal(m_conseq, abs(coeff), e, sign); + } + + void add_eq(expr* a, expr* b) { + 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_diseqs.empty()) + return check_diseq(); + else 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/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index e02a42979..fc3677cb9 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() { @@ -194,11 +196,14 @@ 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); + 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; } @@ -227,26 +232,23 @@ 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) { 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";); + TRACE("arith", tout << "lp bound " << lit << " bound: " << *b << " first: " << first << "\n";); lp().settings().stats().m_num_of_implied_bounds++; if (first) { @@ -260,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, m_params); + assign(lit, m_core, m_eqs, explain(sat::hint_type::bound_h, lit)); } if (should_refine_bounds() && first) @@ -297,7 +299,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,8 +320,9 @@ namespace arith { return false; reset_evidence(); for (auto ev : e) - set_evidence(ev.ci(), m_core, m_eqs); - auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, n1, n2); + set_evidence(ev.ci()); + 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; } @@ -375,7 +378,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, explain(sat::hint_type::farkas_h, bound)); } @@ -748,13 +751,14 @@ 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); + 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()); } @@ -1019,6 +1023,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; } @@ -1132,7 +1139,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; @@ -1161,13 +1172,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, explain(sat::hint_type::bound_h, lit)); lia_check = l_false; break; } @@ -1189,16 +1200,16 @@ namespace arith { return lia_check; } - void solver::assign(literal lit, literal_vector const& core, svector const& eqs, vector const& params) { + 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) 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()); } } @@ -1221,7 +1232,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"; @@ -1236,14 +1247,14 @@ 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 { 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; } @@ -1251,7 +1262,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..76bdeca9d 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -413,12 +413,18 @@ 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, sat::proof_hint const* pma); void false_case_of_check_nla(const nla::lemma& l); void dbg_finalize_model(model& mdl); + 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 explain_assumptions(); + public: solver(euf::solver& ctx, theory_id id); diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index c0f0e9a72..df1fecc49 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -59,13 +59,17 @@ 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_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: @@ -273,6 +277,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 = 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); + 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* md, app* ai) { + 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(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); + 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); } @@ -629,12 +681,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,10 +709,33 @@ namespace array { return true; if (a.is_const(e)) return true; + if (a.is_ext(e)) + return true; } 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_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/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index e1d0d4b33..68dea4d63 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,12 @@ 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)); + 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); break; @@ -169,6 +176,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; @@ -236,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_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/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 511f971a3..f2b4fb565 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 }; @@ -145,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); @@ -163,6 +165,9 @@ 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); } + 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; @@ -175,12 +180,15 @@ 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); 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; @@ -291,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/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/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/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/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_model.cpp b/src/sat/smt/euf_model.cpp index 9f7f3b938..4b7745dd7 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -128,12 +128,14 @@ 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"; } + } ); } @@ -335,8 +337,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/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 9335e283f..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(); } @@ -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/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/euf_solver.h b/src/sat/smt/euf_solver.h index 63439625b..c66109473 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, @@ -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/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 8340543ec..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()]; @@ -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/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 5f2d4a50e..29db324f9 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); @@ -611,39 +610,49 @@ 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 (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]; - 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)); + 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]; + clause& c = *m_clauses[idx]; + propagate(c, flush, propagated); } - to_remove.reset(); } m_clause_in_queue.reset(); m_node_in_queue.reset(); @@ -662,15 +671,18 @@ 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; 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 << "missed propagation\n")); + break; + } TRACE("q", tout << "no more propagation\n";); return false; 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; 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/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/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/sat/smt/sat_th.cpp b/src/sat/smt/sat_th.cpp index f72ff601a..6167d3b9b 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(sat::proof_hint 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, sat::proof_hint 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, sat::proof_hint 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,48 @@ 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, 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) { + 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; 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); + i = 0; + 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) { + 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)); + 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, 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) { - 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, sat::proof_hint 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 +309,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..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()); } }; @@ -143,15 +150,16 @@ namespace euf { region& get_region(); - sat::status mk_status(); + 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, 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) { return add_clause(lits.size(), lits.data()); } - bool add_clause(unsigned n, sat::literal* lits); + 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); @@ -213,15 +221,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 = 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); @@ -232,8 +241,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, 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); @@ -268,6 +277,8 @@ namespace euf { enode_pair eq_consequent() const { return m_eq; } + sat::proof_hint const* get_pragma() const { return nullptr; } //*m_pragma ? m_pragma : nullptr; } + }; 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/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; diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index 1dba2e768..485b1af91 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -15,6 +15,10 @@ 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" +#include "sat/smt/arith_proof_checker.h" + class smt_checker { ast_manager& m; @@ -73,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) { @@ -147,16 +152,112 @@ 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); - } + } + + bool validate_hint(expr_ref_vector const& exprs, sat::literal_vector const& lits, sat::proof_hint const& hint) { + // 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; + case sat::hint_type::bound_h: + case sat::hint_type::farkas_h: + case sat::hint_type::implied_eq_h: { + achecker.reset(); + 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) { + 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; + } + } + + // 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& [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); + std::cout << e << "\n"; + } + achecker.display(std::cout); + std::cout << "p hint not verified\n"; + return false; + } + + + std::cout << "p hint verified\n"; + break; + } + default: + UNREACHABLE(); + break; + } + return true; + } /** * Add an assertion from the source file @@ -343,13 +444,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); + 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(); 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 0e5806ec0..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" @@ -33,9 +34,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 +54,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 +70,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 +138,7 @@ static unsigned parse_opt(std::istream& in, opt_format f) { } display_statistics(); display_model(); + display_objective(); g_opt = nullptr; return 0; } diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index a90403626..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) { @@ -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]) @@ -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/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_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/smt/smt_context.cpp b/src/smt/smt_context.cpp index 377ad1f2b..6652804ea 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 { @@ -1766,6 +1767,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. @@ -1783,105 +1848,45 @@ 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; iget_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)) { + if (used_queue) + m_case_split_queue->unassign_var_eh(original_choice); + l = literal(var, false); } if (!is_pos) l.neg(); @@ -1889,7 +1894,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 +2911,20 @@ 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) + 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 +3061,8 @@ namespace smt { } } } - } else { + } + else { literal_vector new_case_split; for (unsigned i = 0; i < num_lits; ++i) { literal l = lits[i]; @@ -3161,7 +3181,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)); @@ -3730,15 +3750,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_has_lambda) { + 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(); @@ -3759,7 +3776,7 @@ namespace smt { break; } } - if (status == l_true && m_has_lambda) { + if (status == l_true && has_lambda()) { m_last_search_failure = LAMBDAS; status = l_undef; return false; @@ -3939,8 +3956,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++; @@ -4003,7 +4019,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 && has_lambda()) { m_last_search_failure = LAMBDAS; result = FC_GIVEUP; } @@ -4461,9 +4477,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. @@ -4475,6 +4490,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";); @@ -4515,6 +4532,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(); @@ -4612,9 +4635,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 +4651,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..8d98fc60e 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; } @@ -773,7 +773,12 @@ namespace smt { void internalize_quantifier(quantifier * q, bool gate_ctx); - bool m_has_lambda = false; + 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,6 +788,7 @@ namespace smt { friend class set_enode_flag_trail; public: + void set_enode_flag(bool_var v, bool is_new_var); protected: @@ -1134,6 +1140,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(); @@ -1667,7 +1675,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); @@ -1738,8 +1746,18 @@ 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 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); void assign_fixed(enode* n, expr* val, literal_vector const& explain) { 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); 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_enode.h b/src/smt/smt_enode.h index 8995f7fba..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 @@ -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 fd55d5fd0..451136351 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); } @@ -576,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()); @@ -597,15 +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); - push_trail(value_trail(m_has_lambda)); - m_has_lambda = true; + } + + 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; } /** @@ -1008,7 +1022,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); @@ -1052,7 +1066,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/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 87e5fd36d..8f442596c 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( @@ -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 77ad2559c..4fa840f5e 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 @@ -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 ad67c19d1..5064ed7ef 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( @@ -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/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/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/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_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_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_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 */ 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. 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_array_base.cpp b/src/smt/theory_array_base.cpp index 9bc0b733f..f6d4306a5 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -473,39 +473,21 @@ 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()); + 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; } -#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 +518,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. 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_bv.cpp b/src/smt/theory_bv.cpp index 341daedec..90c8cd89e 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_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 { diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index cf1d73892..67d9988ed 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 @@ -3151,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) { 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/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 {} diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index d09069ce4..e1285e749 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1455,7 +1455,7 @@ bool theory_seq::internalize_term(app* term) { if (ctx.e_internalized(term)) { mk_var(ctx.get_enode(term)); return true; - } + } if (m.is_bool(term) && (m_util.str.is_in_re(term) || m_sk.is_skolem(term))) { @@ -1484,12 +1484,21 @@ bool theory_seq::internalize_term(app* term) { mk_var(e); if (!ctx.relevancy()) { relevant_eh(term); - } - - + } return true; } +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 false; + if (p->get_arg(0)->get_root() == n->get_root()) + return true; + return false; +} + + void theory_seq::add_length(expr* l) { expr* e = nullptr; VERIFY(m_util.str.is_length(l, e)); @@ -3273,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 4b4c1d80b..cf7e9da23 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -412,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); 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: }; }; - diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index f783f22fb..780023fab 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" @@ -101,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; @@ -116,6 +128,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 +167,104 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu } } +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()) + return; + + enode* original_enode = nullptr; + unsigned original_bit = 0; + 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()); + } + } + + 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) { + // 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 + unsigned new_bit = original_bit; + lbool phase = is_pos ? l_true : l_false; + + expr* e = var2expr(v); + 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; + } + + // 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 9b271e9c3..ba9900848 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; @@ -82,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()]; } @@ -94,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); @@ -121,13 +127,17 @@ 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; } 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; @@ -150,5 +160,5 @@ namespace smt { bool can_propagate() override; void propagate() override; void display(std::ostream& out) const override {} - }; +}; }; diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index d852d9383..c6a8093ff 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -193,7 +193,7 @@ void asserted_formulas::push_scope_core() { 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 +205,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() { @@ -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/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..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(); @@ -134,7 +138,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/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/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..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) { @@ -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/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; diff --git a/src/tactic/smtlogics/qflia_tactic.h b/src/tactic/smtlogics/qflia_tactic.h index 8b4206d12..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_LRA + Tactic for QF_LIA Author: 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..46b5eda8a 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 { @@ -10,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 { @@ -17,14 +19,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 +87,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() { } 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/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; 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_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_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/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/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/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_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) { 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 713cdd31c..2e59b4171 100644 --- a/src/test/simplex.cpp +++ b/src/test/simplex.cpp @@ -11,10 +11,12 @@ 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; typedef simplex::sparse_matrix sparse_matrix; +typedef simplex::sparse_matrix qmatrix; static vector vec(int i, int j) { vector nv; @@ -24,29 +26,29 @@ 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); -// 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); @@ -131,6 +133,30 @@ static void test4() { feas(S); } +static void add(qmatrix& m, vector const& v) { + 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); +} + +static void test5() { + unsynch_mpq_manager m; + qmatrix M(m); + 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); + +} + void tst_simplex() { reslimit rl; Simplex S(rl); @@ -166,4 +192,5 @@ void tst_simplex() { test2(); test3(); test4(); + test5(); } 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() { 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/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. diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index 64a718bd1..2841db609 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -20,7 +20,8 @@ Notes: #include "util/vector.h" #include "util/uint_set.h" - +#include "util/heap.h" +#include "util/map.h" template class max_cliques : public T { @@ -37,53 +38,71 @@ 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]; - 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); - 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)) { + 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()); + } + + 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) { @@ -93,21 +112,12 @@ public: m_next[dst].push_back(src); } - 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()); + void cliques1(unsigned_vector const& ps, vector& cliques) { + 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 +128,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,9 +138,77 @@ 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& cs) { + u_map conns; + init(ps); + // compute connections using TC of implication graph + init(ps, conns); + cliques(ps, conns, cs); + } + + // 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(maxp + 1, lt); + + for (unsigned p : ps) { + todo.insert(p); + heap.insert(p); + } + + 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) { + bool all = heap.contains(x); + for (unsigned y : am1) { + if (!conns[x].contains(y)) { + all = false; + break; + } } + if (all) + am1.insert(x); + } + am1.insert(v); + + for (unsigned x : am1) { + todo.remove(x); + for (unsigned y : conns[x]) { + conns[y].remove(x); + if (heap.contains(y)) + 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); } } } 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); } } diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 159fc0ed8..bdad1ddfe 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -2248,6 +2248,9 @@ template unsigned mpz_manager::mlog2(mpz const & a) { if (is_nonneg(a)) return 0; + 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 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/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/rational.h b/src/util/rational.h index 9fadfb91f..dffcc52f3 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -232,11 +232,17 @@ public: rational::m().mod(r1.m_val, r2.m_val, r.m_val); return r; } - + friend inline void mod(rational const & r1, rational const & r2, rational & r) { rational::m().mod(r1.m_val, r2.m_val, r.m_val); } + friend inline rational mod2k(rational const & a, unsigned k) { + if (a.is_nonneg() && a.is_int() && a.bitsize() <= k) + return a; + return mod(a, power_of_two(k)); + } + friend inline rational operator%(rational const & r1, rational const & r2) { rational r; rational::m().rem(r1.m_val, r2.m_val, r.m_val); 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/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()); + } +}; 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/scoped_timer.cpp b/src/util/scoped_timer.cpp index e8a72e245..ce1b14a23 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; @@ -81,26 +80,20 @@ scoped_timer::scoped_timer(unsigned ms, event_handler * eh) { return; workers.lock(); - bool new_worker = false; if (available_workers.empty()) { + // start new thead workers.unlock(); s = new scoped_timer_state; - new_worker = true; ++num_workers; - } - else { - s = available_workers.back(); - available_workers.pop_back(); - workers.unlock(); - } - s->ms = ms; - s->eh = eh; - s->m_mutex.lock(); - s->work = WORKING; - if (new_worker) { + init_state(ms, eh); s->m_thread = std::thread(thread_func, s); } else { + // re-use existing thread + s = available_workers.back(); + available_workers.pop_back(); + init_state(ms, eh); + workers.unlock(); s->cv.notify_one(); } } @@ -148,3 +141,10 @@ void scoped_timer::finalize() { num_workers = 0; available_workers.clear(); } + +void scoped_timer::init_state(unsigned ms, event_handler * eh) { + s->ms = ms; + s->eh = eh; + s->m_mutex.lock(); + s->work = WORKING; +} diff --git a/src/util/scoped_timer.h b/src/util/scoped_timer.h index dfd97810c..2f6875d36 100644 --- a/src/util/scoped_timer.h +++ b/src/util/scoped_timer.h @@ -29,6 +29,8 @@ public: ~scoped_timer(); static void initialize(); static void finalize(); +private: + void init_state(unsigned ms, event_handler * eh); }; /* 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++) { 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(); } } 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/top_sort.h b/src/util/top_sort.h index 8f9df7d52..51a0d9733 100644 --- a/src/util/top_sort.h +++ b/src/util/top_sort.h @@ -24,39 +24,50 @@ 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); } + + + bool contains_partition(T* f) const { + return m_partition_id.get(f->get_small_id(), UINT_MAX) != 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 +76,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 +87,36 @@ 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)); + m_deps[t->get_small_id()] = nullptr; + } } 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) { + 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); } + ptr_vector const& deps() { return m_dep_keys; } + 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 +125,21 @@ 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()]; } + + 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; } + + T_set* get_dep(T* t) const { return del_tag(m_deps.get(t->get_small_id(), nullptr)); } - unsigned partition_id(T* t) const { return m_partition_id[t]; } 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; } - }; 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);