diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml index 8bbfd5ab0..eec9032df 100644 --- a/.github/workflows/android-build.yml +++ b/.github/workflows/android-build.yml @@ -13,7 +13,7 @@ permissions: jobs: build: runs-on: ubuntu-latest - + strategy: fail-fast: false matrix: @@ -27,10 +27,10 @@ jobs: run: | mkdir build cd build - cmake -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=21 -DCMAKE_ANDROID_ARCH_ABI=${{ matrix.android-abi }} -DCMAKE_ANDROID_NDK=$ANDROID_NDK_HOME -DZ3_BUILD_JAVA_BINDINGS=TRUE -G "Unix Makefiles" -DJAVA_AWT_LIBRARY=NotNeeded -DJAVA_JVM_LIBRARY=NotNeeded -DJAVA_INCLUDE_PATH2=NotNeeded -DJAVA_AWT_INCLUDE_PATH=NotNeeded ../ + cmake -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=21 -DCMAKE_ANDROID_ARCH_ABI=${{ matrix.android-abi }} "-DCMAKE_ANDROID_NDK=$ANDROID_NDK_LATEST_HOME" -DZ3_BUILD_JAVA_BINDINGS=TRUE -G "Unix Makefiles" -DJAVA_AWT_LIBRARY=NotNeeded -DJAVA_JVM_LIBRARY=NotNeeded -DJAVA_INCLUDE_PATH2=NotNeeded -DJAVA_AWT_INCLUDE_PATH=NotNeeded ../ make -j $(nproc) tar -cvf z3-build-${{ matrix.android-abi }}.tar *.jar *.so - + - name: Archive production artifacts uses: actions/upload-artifact@v3 with: diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index e7ca0f1b5..04d13b1e8 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -41,7 +41,7 @@ jobs: type=edge type=sha,prefix=ubuntu-20.04-bare-z3-sha- - name: Build and push Bare Z3 Docker Image - uses: docker/build-push-action@v3.0.0 + uses: docker/build-push-action@v3.1.0 with: context: . push: true diff --git a/CMakeLists.txt b/CMakeLists.txt index cffe1a4d7..8c3d007f0 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.9.2.0 LANGUAGES CXX) +project(Z3 VERSION 4.11.0.0 LANGUAGES CXX) ################################################################################ # Project version @@ -10,13 +10,6 @@ project(Z3 VERSION 4.9.2.0 LANGUAGES CXX) set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified message(STATUS "Z3 version ${Z3_VERSION}") -################################################################################ -# Set various useful variables depending on CMake version -################################################################################ - -set(ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG "USES_TERMINAL") -set(ADD_CUSTOM_TARGET_USES_TERMINAL_ARG "USES_TERMINAL") - ################################################################################ # Message for polluted source tree sanity checks ################################################################################ @@ -185,35 +178,10 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) ################################################################################ # Platform detection ################################################################################ -if (CMAKE_SYSTEM_NAME STREQUAL "Linux") - message(STATUS "Platform: Linux") - list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_LINUX_") - if (TARGET_ARCHITECTURE STREQUAL "x86_64") - list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_USE_THREAD_LOCAL") - endif() -elseif (CMAKE_SYSTEM_NAME STREQUAL "Android") - message(STATUS "Platform: Android") - list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_ANDROID_") -elseif (CMAKE_SYSTEM_NAME MATCHES "GNU") - message(STATUS "Platform: GNU/Hurd") - list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_HURD_") -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin") +if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") if (TARGET_ARCHITECTURE STREQUAL "arm64") set(CMAKE_OSX_ARCHITECTURES "arm64") endif() - message(STATUS "Platform: Darwin") -elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") - message(STATUS "Platform: FreeBSD") - list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_FREEBSD_") -elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") - message(STATUS "Platform: NetBSD") - list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_NetBSD_") -elseif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD") - message(STATUS "Platform: OpenBSD") - list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_OPENBSD_") -elseif (CYGWIN) - message(STATUS "Platform: Cygwin") - list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_CYGWIN") elseif (WIN32) message(STATUS "Platform: Windows") list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_WINDOWS") @@ -226,8 +194,6 @@ elseif (EMSCRIPTEN) "-s DISABLE_EXCEPTION_CATCHING=0" "-s ERROR_ON_UNDEFINED_SYMBOLS=1" ) -else() - message(FATAL_ERROR "Platform \"${CMAKE_SYSTEM_NAME}\" not recognised") endif() list(APPEND Z3_COMPONENT_EXTRA_INCLUDE_DIRS @@ -286,15 +252,7 @@ endif() # FIXME: Support ARM "-mfpu=vfp -mfloat-abi=hard" if ((TARGET_ARCHITECTURE STREQUAL "x86_64") OR (TARGET_ARCHITECTURE STREQUAL "i686")) if ((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Intel")) - if (CMAKE_CXX_COMPILER_ID MATCHES "Intel") - # Intel's compiler requires linking with libiomp5 - list(APPEND Z3_DEPENDENT_LIBS "iomp5") - endif() set(SSE_FLAGS "-mfpmath=sse" "-msse" "-msse2") - elseif (CMAKE_CXX_COMPILER_ID MATCHES "Intel") - set(SSE_FLAGS "-mfpmath=sse" "-msse" "-msse2") - # Intel's compiler requires linking with libiomp5 - list(APPEND Z3_DEPENDENT_LIBS "iomp5") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(SSE_FLAGS "/arch:SSE2") else() @@ -348,14 +306,6 @@ endif() option(Z3_BUILD_LIBZ3_SHARED "Build libz3 as a shared library if true, otherwise build a static library" ON) -################################################################################ -# Symbol visibility -################################################################################ -if (NOT MSVC) - z3_add_cxx_flag("-fvisibility=hidden" REQUIRED) - z3_add_cxx_flag("-fvisibility-inlines-hidden" REQUIRED) -endif() - ################################################################################ # Tracing ################################################################################ @@ -367,20 +317,6 @@ else() list(APPEND Z3_COMPONENT_CXX_DEFINES $<$:_TRACE>) endif() -################################################################################ -# Position independent code -################################################################################ -# This is required because code built in the components will end up in a shared -# library. - -# Avoid adding -fPIC compiler switch if we compile with MSVC (which does not -# support the flag) or if we target Windows, which generally does not use -# position independent code for native code shared libraries (DLLs). -if (NOT (MSVC OR MINGW OR WIN32)) - z3_add_cxx_flag("-fPIC" REQUIRED) -endif() - - ################################################################################ # Link time optimization ################################################################################ @@ -507,7 +443,7 @@ add_custom_target(uninstall COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" COMMENT "Uninstalling..." - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL VERBATIM ) diff --git a/README.md b/README.md index 4849c33d8..2d75c73d6 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Pre-built binaries for stable and nightly releases are available from [here](htt Z3 can be built using [Visual Studio][1], a [Makefile][2] or using [CMake][3]. It provides [bindings for several programming languages][4]. -See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z3. +See the [release notes](RELEASE_NOTES.md) for notes on various stable releases of Z3. ## Build status diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index aecf10f2c..48b97583e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +1,6 @@ RELEASE NOTES -Version 4.9.next +Version 4.next ================ - Planned features - sat.euf @@ -10,6 +10,57 @@ Version 4.9.next - native word level bit-vector solving. - introduction of simple induction lemmas to handle a limited repertoire of induction proofs. +Version 4.11.0 +============== +- remove `Z3_bool`, `Z3_TRUE`, `Z3_FALSE` from the API. Use `bool`, `true`, `false` instead. +- z3++.h no longer includes `` as it did not use it. +- add solver.axioms2files + - prints negated theory axioms to files. Each file should be unsat +- add solver.lemmas2console + - prints lemmas to the console. +- remove option smt.arith.dump_lemmas. It is replaced by solver.axioms2files + +Version 4.10.2 +============== +- fix regression #6194. It broke mod/rem/div reasoning. +- fix user propagator scope management for equality callbacks. + +Version 4.10.1 +============== +- fix implementation of mk_fresh in user propagator for Python API + +Version 4.10.0 +============== +- Added API Z3_enable_concurrent_dec_ref to be set by interfaces that + use concurrent GC to manage reference counts. This feature is integrated + with the OCaml bindings and fixes a regression introduced when OCaml + transitioned to concurrent GC. Use of this feature for .Net and Java + bindings is not integrated for this release. They use external queues + that are unnecessarily complicated. +- Added pre-declared abstract datatype declarations to the context so + that Z3_eval_smtlib2_string works with List examples. +- Fixed Java linking for MacOS Arm64. +- Added missing callback handlers in tactics for user-propagator, + Thanks to Clemens Eisenhofer +- Tuning to Grobner arithmetic reasoning for smt.arith.solver=6 + (currently the default in most cases). The check for consistency + modulo multiplication was updated in the following way: + - polynomial equalities are extracted from Simplex tableau rows using + a cone of influence algorithm. Rows where the basic variables were + unbounded were previously included. Following the legacy implementation + such rows are not included when building polynomial equations. + - equations are pre-solved if they are linear and can be split + into two groups one containing a single variable that has a + lower (upper) bound, the other with more than two variables + with upper (lower) bounds. This avoids losing bounds information + during completion. + - After (partial) completion, perform constant propagation for equalities + of the form x = 0 + - After (partial) completion, perform factorization for factors of the + form x*y*p = 0 where x, are variables, p is linear. +- Added support for declaring algebraic datatypes from the C++ interface. + + Version 4.9.1 ============= - Bugfix release to ensure npm package works diff --git a/cmake/z3_add_component.cmake b/cmake/z3_add_component.cmake index c4b2dfbfe..aa5f8517f 100644 --- a/cmake/z3_add_component.cmake +++ b/cmake/z3_add_component.cmake @@ -122,7 +122,7 @@ macro(z3_add_component component_name) ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} COMMENT "Generating \"${_full_output_file_path}\" from \"${pyg_file}\"" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL VERBATIM ) list(APPEND _list_generated_headers "${_full_output_file_path}") @@ -206,6 +206,12 @@ macro(z3_add_component component_name) foreach (flag ${Z3_COMPONENT_CXX_FLAGS}) target_compile_options(${component_name} PRIVATE ${flag}) endforeach() + set_target_properties(${component_name} PROPERTIES + # Position independent code needed in shared libraries + POSITION_INDEPENDENT_CODE ON + # Symbol visibility + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON) # It's unfortunate that we have to manage dependencies ourselves. # @@ -277,7 +283,7 @@ macro(z3_add_install_tactic_rule) ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} "${CMAKE_CURRENT_BINARY_DIR}/install_tactic.deps" COMMENT "Generating \"${CMAKE_CURRENT_BINARY_DIR}/install_tactic.cpp\"" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL VERBATIM ) unset(_expanded_components) @@ -315,7 +321,7 @@ macro(z3_add_memory_initializer_rule) ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} ${_mem_init_finalize_headers} COMMENT "Generating \"${CMAKE_CURRENT_BINARY_DIR}/mem_initializer.cpp\"" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL VERBATIM ) unset(_mem_init_finalize_headers) @@ -351,7 +357,7 @@ macro(z3_add_gparams_register_modules_rule) ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} ${_register_module_header_files} COMMENT "Generating \"${CMAKE_CURRENT_BINARY_DIR}/gparams_register_modules.cpp\"" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL VERBATIM ) unset(_expanded_components) diff --git a/contrib/.travis.yml b/contrib/.travis.yml deleted file mode 100644 index 230c690a6..000000000 --- a/contrib/.travis.yml +++ /dev/null @@ -1,53 +0,0 @@ -cache: - # This persistent cache is used to cache the building of - # docker base images. - directories: - - $DOCKER_TRAVIS_CI_CACHE_DIR -sudo: required -language: cpp -services: - - docker -env: - global: - # This environment variable tells the `travis_ci_linux_entry_point.sh` - # script to look for a cached Docker image. - - DOCKER_TRAVIS_CI_CACHE_DIR=$HOME/.cache/docker - # Configurations - matrix: -############################################################################### -# Ubuntu 20.04 LTS -############################################################################### - # Note the unit tests for the debug builds are compiled but **not** - # executed. This is because the debug build of unit tests takes a large - # amount of time to execute compared to the optimized builds. - - # clang - - LINUX_BASE=ubuntu_20.04 C_COMPILER=clang CXX_COMPILER=clang++ TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug - - LINUX_BASE=ubuntu_20.04 C_COMPILER=clang CXX_COMPILER=clang++ TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Release UBSAN_BUILD=1 - - LINUX_BASE=ubuntu_20.04 C_COMPILER=clang CXX_COMPILER=clang++ TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Release ASAN_BUILD=1 DOTNET_BINDINGS=0 JAVA_BINDINGS=0 PYTHON_BINDINGS=0 - - # gcc - # ubsan/msan builds too slow - - LINUX_BASE=ubuntu_20.04 C_COMPILER=gcc CXX_COMPILER=g++ TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Release BUILD_DOCS=1 - - LINUX_BASE=ubuntu_20.04 C_COMPILER=gcc CXX_COMPILER=g++ TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug - - # GMP library - - LINUX_BASE=ubuntu_20.04 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Release USE_LIBGMP=1 - - LINUX_BASE=ubuntu_20.04 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug USE_LIBGMP=1 - - # Unix Makefile generator build - - LINUX_BASE=ubuntu_20.04 TARGET_ARCH=x86_64 Z3_CMAKE_GENERATOR="Unix Makefiles" - - # LTO build - # too slow - #- LINUX_BASE=ubuntu_20.04 C_COMPILER=gcc CXX_COMPILER=g++ TARGET_ARCH=x86_64 USE_LTO=1 RUN_UNIT_TESTS=BUILD_ONLY RUN_SYSTEM_TESTS=0 - #- LINUX_BASE=ubuntu_20.04 C_COMPILER=clang CXX_COMPILER=clang++ TARGET_ARCH=x86_64 USE_LTO=1 RUN_UNIT_TESTS=BUILD_ONLY RUN_SYSTEM_TESTS=0 - - # Static build. Note we have disable building the bindings because they won't work with a static libz3 - - LINUX_BASE=ubuntu_20.04 TARGET_ARCH=x86_64 Z3_STATIC_BUILD=1 DOTNET_BINDINGS=0 JAVA_BINDINGS=0 PYTHON_BINDINGS=0 - - -script: - # Use `travis_wait` when building because some configurations don't produce an - # output for a long time (linking & testing) - - travis_wait 55 contrib/ci/scripts/travis_ci_entry_point.sh || exit 1; diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_20.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_20.04.Dockerfile deleted file mode 100644 index 9ef85c673..000000000 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_20.04.Dockerfile +++ /dev/null @@ -1,34 +0,0 @@ -FROM ubuntu:20.04 - -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && \ - apt-get -y --no-install-recommends install \ - cmake \ - make \ - ninja-build \ - clang \ - g++ \ - curl \ - doxygen \ - default-jdk \ - git \ - graphviz \ - python3 \ - python3-setuptools \ - python-is-python3 \ - sudo - -RUN curl -SL https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb --output packages-microsoft-prod.deb && \ - dpkg -i packages-microsoft-prod.deb && \ - apt-get update && \ - apt-get -y --no-install-recommends install dotnet-sdk-2.1 - -# Create `user` user for container with password `user`. and give it -# password-less sudo access -RUN useradd -m user && \ - echo user:user | chpasswd && \ - cp /etc/sudoers /etc/sudoers.bak && \ - echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers -USER user -WORKDIR /home/user -#ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-7/bin/llvm-symbolizer diff --git a/contrib/ci/Dockerfiles/z3_build.Dockerfile b/contrib/ci/Dockerfiles/z3_build.Dockerfile deleted file mode 100644 index f6e05fcb5..000000000 --- a/contrib/ci/Dockerfiles/z3_build.Dockerfile +++ /dev/null @@ -1,121 +0,0 @@ -ARG DOCKER_IMAGE_BASE -FROM ${DOCKER_IMAGE_BASE} - - -# Build arguments. This can be changed when invoking -# `docker build`. -ARG ASAN_BUILD -ARG BUILD_DOCS -ARG CC -ARG CXX -ARG DOTNET_BINDINGS -ARG JAVA_BINDINGS -ARG NO_SUPPRESS_OUTPUT -ARG PYTHON_BINDINGS -ARG PYTHON_EXECUTABLE=/usr/bin/python -ARG RUN_API_EXAMPLES -ARG RUN_SYSTEM_TESTS -ARG RUN_UNIT_TESTS -ARG SANITIZER_PRINT_SUPPRESSIONS -ARG TARGET_ARCH -ARG TEST_INSTALL -ARG UBSAN_BUILD -ARG Z3_USE_LIBGMP -ARG USE_LTO -ARG Z3_SRC_DIR=/home/user/z3_src -ARG Z3_BUILD_TYPE -ARG Z3_CMAKE_GENERATOR -ARG Z3_INSTALL_PREFIX -ARG Z3_STATIC_BUILD -ARG Z3_SYSTEM_TEST_GIT_REVISION -ARG Z3_WARNINGS_AS_ERRORS -ARG Z3_VERBOSE_BUILD_OUTPUT - -ENV \ - ASAN_BUILD=${ASAN_BUILD} \ - BUILD_DOCS=${BUILD_DOCS} \ - CC=${CC} \ - CXX=${CXX} \ - DOTNET_BINDINGS=${DOTNET_BINDINGS} \ - JAVA_BINDINGS=${JAVA_BINDINGS} \ - NO_SUPPRESS_OUTPUT=${NO_SUPPRESS_OUTPUT} \ - PYTHON_BINDINGS=${PYTHON_BINDINGS} \ - PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} \ - SANITIZER_PRINT_SUPPRESSIONS=${SANITIZER_PRINT_SUPPRESSIONS} \ - RUN_API_EXAMPLES=${RUN_API_EXAMPLES} \ - RUN_SYSTEM_TESTS=${RUN_SYSTEM_TESTS} \ - RUN_UNIT_TESTS=${RUN_UNIT_TESTS} \ - TARGET_ARCH=${TARGET_ARCH} \ - TEST_INSTALL=${TEST_INSTALL} \ - UBSAN_BUILD=${UBSAN_BUILD} \ - Z3_USE_LIBGMP=${Z3_USE_LIBGMP} \ - USE_LTO=${USE_LTO} \ - Z3_SRC_DIR=${Z3_SRC_DIR} \ - Z3_BUILD_DIR=/home/user/z3_build \ - Z3_BUILD_TYPE=${Z3_BUILD_TYPE} \ - Z3_CMAKE_GENERATOR=${Z3_CMAKE_GENERATOR} \ - Z3_VERBOSE_BUILD_OUTPUT=${Z3_VERBOSE_BUILD_OUTPUT} \ - Z3_STATIC_BUILD=${Z3_STATIC_BUILD} \ - Z3_SYSTEM_TEST_DIR=/home/user/z3_system_test \ - Z3_SYSTEM_TEST_GIT_REVISION=${Z3_SYSTEM_TEST_GIT_REVISION} \ - Z3_WARNINGS_AS_ERRORS=${Z3_WARNINGS_AS_ERRORS} \ - Z3_INSTALL_PREFIX=${Z3_INSTALL_PREFIX} - -# We add context across incrementally to maximal cache reuse - -# Build Z3 -RUN mkdir -p "${Z3_SRC_DIR}" && \ - mkdir -p "${Z3_SRC_DIR}/contrib/ci/scripts" && \ - mkdir -p "${Z3_SRC_DIR}/contrib/suppressions/sanitizers" -# Deliberately leave out `contrib` -ADD /cmake ${Z3_SRC_DIR}/cmake/ -ADD /doc ${Z3_SRC_DIR}/doc/ -ADD /examples ${Z3_SRC_DIR}/examples/ -ADD /scripts ${Z3_SRC_DIR}/scripts/ -ADD /src ${Z3_SRC_DIR}/src/ -ADD *.txt *.md *.cmake.in RELEASE_NOTES ${Z3_SRC_DIR}/ - -ADD \ - /contrib/ci/scripts/build_z3_cmake.sh \ - /contrib/ci/scripts/ci_defaults.sh \ - /contrib/ci/scripts/set_compiler_flags.sh \ - /contrib/ci/scripts/set_generator_args.sh \ - ${Z3_SRC_DIR}/contrib/ci/scripts/ -RUN ${Z3_SRC_DIR}/contrib/ci/scripts/build_z3_cmake.sh - -# Test building docs -ADD \ - /contrib/ci/scripts/test_z3_docs.sh \ - /contrib/ci/scripts/run_quiet.sh \ - ${Z3_SRC_DIR}/contrib/ci/scripts/ -RUN ${Z3_SRC_DIR}/contrib/ci/scripts/test_z3_docs.sh - -# Test examples -ADD \ - /contrib/ci/scripts/test_z3_examples_cmake.sh \ - /contrib/ci/scripts/sanitizer_env.sh \ - ${Z3_SRC_DIR}/contrib/ci/scripts/ -ADD \ - /contrib/suppressions/sanitizers/asan.txt \ - /contrib/suppressions/sanitizers/lsan.txt \ - /contrib/suppressions/sanitizers/ubsan.txt \ - ${Z3_SRC_DIR}/contrib/suppressions/sanitizers/ -RUN ${Z3_SRC_DIR}/contrib/ci/scripts/test_z3_examples_cmake.sh - -# Run unit tests -ADD \ - /contrib/ci/scripts/test_z3_unit_tests_cmake.sh \ - ${Z3_SRC_DIR}/contrib/ci/scripts/ -RUN ${Z3_SRC_DIR}/contrib/ci/scripts/test_z3_unit_tests_cmake.sh - -# Run system tests -ADD \ - /contrib/ci/scripts/test_z3_system_tests.sh \ - ${Z3_SRC_DIR}/contrib/ci/scripts/ -RUN ${Z3_SRC_DIR}/contrib/ci/scripts/test_z3_system_tests.sh - -# Test install -ADD \ - /contrib/ci/scripts/test_z3_install_cmake.sh \ - ${Z3_SRC_DIR}/contrib/ci/scripts/ -RUN ${Z3_SRC_DIR}/contrib/ci/scripts/test_z3_install_cmake.sh diff --git a/contrib/ci/README.md b/contrib/ci/README.md deleted file mode 100644 index 9a8262e37..000000000 --- a/contrib/ci/README.md +++ /dev/null @@ -1,147 +0,0 @@ -# Continuous integration scripts - -## TravisCI - -For testing on Linux and macOS we use [TravisCI](https://travis-ci.org/) - -TravisCI consumes the `.travis.yml` file in the root of the repository -to tell it how to build and test Z3. - -However the logic for building and test Z3 is kept out of this file -and instead in a set of scripts in `scripts/`. This avoids -coupling the build to TravisCI tightly so we can migrate to another -service if required in the future. - -The scripts rely on a set of environment variables to control the configuration -of the build. The `.travis.yml` declares a list of configuration with each -configuration setting different environment variables. - -Note that the build scripts currently only support Z3 built with CMake. Support -for building Z3 using the older Python/Makefile build system might be added in -the future. - -### Configuration variables - -* `ASAN_BUILD` - Do [AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) build (`0` or `1`) -* `BUILD_DOCS` - Build API documentation (`0` or `1`) -* `C_COMPILER` - Path to C Compiler -* `CXX_COMPILER` - Path to C++ Compiler -* `DOTNET_BINDINGS` - Build and test .NET API bindings (`0` or `1`) -* `JAVA_BINDINGS` - Build and test Java API bindings (`0` or `1`) -* `NO_SUPPRESS_OUTPUT` - Don't suppress output of some commands (`0` or `1`) -* `PYTHON_BINDINGS` - Build and test Python API bindings (`0` or `1`) -* `RUN_API_EXAMPLES` - Build and run API examples (`0` or `1`) -* `RUN_SYSTEM_TESTS` - Run system tests (`0` or `1`) -* `RUN_UNIT_TESTS` - Run unit tests (`BUILD_ONLY` or `BUILD_AND_RUN` or `SKIP`) -* `SANITIZER_PRINT_SUPPRESSIONS` - Show ASan/UBSan suppressions (`0` or `1`) -* `TARGET_ARCH` - Target architecture (`x86_64` or `i686`) -* `TEST_INSTALL` - Test running `install` target (`0` or `1`) -* `UBSAN_BUILD` - Do [UndefinedBehaviourSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) build (`0` or `1`) -* `Z3_USE_LIBGMP` - Use [GNU multiple precision library](https://gmplib.org/) (`0` or `1`) -* `USE_LTO` - Link binaries using link time optimization (`0` or `1`) -* `Z3_BUILD_TYPE` - CMake build type (`RelWithDebInfo`, `Release`, `Debug`, or `MinSizeRel`) -* `Z3_CMAKE_GENERATOR` - CMake generator (`Ninja` or `Unix Makefiles`) -* `Z3_VERBOSE_BUILD_OUTPUT` - Show compile commands in CMake builds (`0` or `1`) -* `Z3_BUILD_LIBZ3_SHARED` - Build Z3 binaries and libraries dynamically/statically (`0` or `1`) -* `Z3_SYSTEM_TEST_GIT_REVISION` - Git revision of [z3test](https://github.com/Z3Prover/z3test). If empty latest revision will be used. -* `Z3_WARNINGS_AS_ERRORS` - Set the `WARNINGS_AS_ERRORS` CMake option passed to Z3 (`OFF`, `ON`, or `SERIOUS_ONLY`) - -### Linux - -For Linux we use Docker to perform the build so that it easily reproducible -on a local machine and so that we can avoid depending on TravisCI's environment -and instead use a Linux distribution of our choice. - -The `scripts/travis_ci_linux_entry_point.sh` script - -1. Creates a base image containing all the dependencies needed to build and test Z3 -2. Builds and tests Z3 using the base image propagating configuration environment - variables (if set) into the build using the `--build-arg` argument of the `docker run` - command. - -The default values of the configuration environment variables -can be found in -[`scripts/ci_defaults.sh`](scripts/ci_defaults.sh). - -#### Linux specific configuration variables - -* `LINUX_BASE` - The base docker image identifier to use (`ubuntu_16.04`, `ubuntu32_16.04`, or `ubuntu_14.04`). - -#### Reproducing a build locally - -A build can be reproduced locally by using the -`scripts/travis_ci_linux_entry_point.sh` script and setting the appropriate -environment variable. - -For example lets say we wanted to reproduce the build below. - -```yaml - - - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo -``` - -This can be done by running the command - -```bash -LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo scripts/travis_ci_linux_entry_point.sh -``` - -The `docker build` command which we use internally supports caching. What this -means in practice is that re-running the above command will re-use successfully -completed stages of the build provided they haven't changed. This requires that -the `Dockerfiles/z3_build.Dockerfile` is carefully crafted to avoid invalidating -the cache when unrelated files sent to the build context change. - -#### TravisCI docker image cache - -To improve build times the Z3 base docker images are cached using -[TravisCI's cache directory feature](https://docs.travis-ci.com/user/caching). -If the `DOCKER_TRAVIS_CI_CACHE_DIR` environment variable is set (see `.travis.yml`) -then the directory pointed to by the environment variable is used as a cache -for Docker images. - -The logic for this can be found in `scripts/travis_ci_linux_entry_point.sh`. -The build time improvements are rather modest (~ 2 minutes) and the cache is -rather large due to TravisCI giving each configuration its own cache. So this -feature might be removed in the future. - -It may be better to just build the base image once (outside of TravisCI), upload -it to [DockerHub](https://hub.docker.com/) and have the build pull down the pre-built -image every time. - -An [organization](https://hub.docker.com/u/z3prover/) has been created on -DockerHub for this. - -### macOS - -For macOS we execute directly on TravisCI's macOS environment. The entry point -for the TravisCI builds is the -[`scripts/travis_ci_osx_entry_point.sh`](scripts/travis_ci_osx_entry_point.sh) -scripts. - -#### macOS specific configuration variables - -* `MACOS_SKIP_DEPS_UPDATE` - If set to `1` installing the necessary build dependencies - is skipped. This is useful for local testing if the dependencies are already installed. -* `MACOS_UPDATE_CMAKE` - If set to `1` the installed version of CMake will be upgraded. - -#### Reproducing a build locally - -To reproduce a build (e.g. like the one shown below) - -```yaml -- os: osx - osx_image: xcode8.3 - env: Z3_BUILD_TYPE=RelWithDebInfo -``` - -Run the following: - -```bash -TRAVIS_BUILD_DIR=$(pwd) \ -Z3_BUILD_TYPE=RelWithDebInfo \ -contrib/ci/scripts/travis_ci_osx_entry_point.sh -``` - -Note this assumes that the current working directory is the root of the Z3 -git repository. diff --git a/contrib/ci/maintainers.txt b/contrib/ci/maintainers.txt deleted file mode 100644 index caa6798c6..000000000 --- a/contrib/ci/maintainers.txt +++ /dev/null @@ -1,3 +0,0 @@ -# Maintainers - -- Dan Liew (@delcypher) diff --git a/contrib/ci/scripts/build_z3_cmake.sh b/contrib/ci/scripts/build_z3_cmake.sh deleted file mode 100755 index 63b9410d8..000000000 --- a/contrib/ci/scripts/build_z3_cmake.sh +++ /dev/null @@ -1,133 +0,0 @@ -#!/bin/bash -# This script builds Z3 - -SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" - -set -x -set -e -set -o pipefail - -: ${Z3_SRC_DIR?"Z3_SRC_DIR must be specified"} -: ${Z3_BUILD_DIR?"Z3_BUILD_DIR must be specified"} -: ${Z3_BUILD_TYPE?"Z3_BUILD_TYPE must be specified"} -: ${Z3_CMAKE_GENERATOR?"Z3_CMAKE_GENERATOR must be specified"} -: ${Z3_STATIC_BUILD?"Z3_STATIC_BUILD must be specified"} -: ${Z3_USE_LIBGMP?"Z3_USE_LIBGMP must be specified"} -: ${BUILD_DOCS?"BUILD_DOCS must be specified"} -: ${PYTHON_EXECUTABLE?"PYTHON_EXECUTABLE must be specified"} -: ${PYTHON_BINDINGS?"PYTHON_BINDINGS must be specified"} -: ${DOTNET_BINDINGS?"DOTNET_BINDINGS must be specified"} -: ${JAVA_BINDINGS?"JAVA_BINDINGS must be specified"} -: ${USE_LTO?"USE_LTO must be specified"} -: ${Z3_INSTALL_PREFIX?"Z3_INSTALL_PREFIX must be specified"} -: ${Z3_WARNINGS_AS_ERRORS?"Z3_WARNINGS_AS_ERRORS must be specified"} -: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"} - -ADDITIONAL_Z3_OPTS=() - -# Static or dynamic libz3 -if [ "X${Z3_STATIC_BUILD}" = "X1" ]; then - ADDITIONAL_Z3_OPTS+=('-DZ3_BUILD_LIBZ3_SHARED=OFF') -else - ADDITIONAL_Z3_OPTS+=('-DZ3_BUILD_LIBZ3_SHARED=ON') -fi - -# Use LibGMP? -if [ "X${Z3_USE_LIBGMP}" = "X1" ]; then - ADDITIONAL_Z3_OPTS+=('-DZ3_USE_LIB_GMP=ON') -else - ADDITIONAL_Z3_OPTS+=('-DZ3_USE_LIB_GMP=OFF') -fi - -# Use link time optimziation? -if [ "X${USE_LTO}" = "X1" ]; then - ADDITIONAL_Z3_OPTS+=('-DZ3_LINK_TIME_OPTIMIZATION=ON') -else - ADDITIONAL_Z3_OPTS+=('-DZ3_LINK_TIME_OPTIMIZATION=OFF') -fi - -# Build API docs? -if [ "X${BUILD_DOCS}" = "X1" ]; then - ADDITIONAL_Z3_OPTS+=( \ - '-DZ3_BUILD_DOCUMENTATION=ON' \ - '-DZ3_ALWAYS_BUILD_DOCS=OFF' \ - ) -else - ADDITIONAL_Z3_OPTS+=('-DZ3_BUILD_DOCUMENTATION=OFF') -fi - -# Python bindings? -if [ "X${PYTHON_BINDINGS}" = "X1" ]; then - ADDITIONAL_Z3_OPTS+=( \ - '-DZ3_BUILD_PYTHON_BINDINGS=ON' \ - '-DZ3_INSTALL_PYTHON_BINDINGS=ON' \ - ) -else - ADDITIONAL_Z3_OPTS+=( \ - '-DZ3_BUILD_PYTHON_BINDINGS=OFF' \ - '-DZ3_INSTALL_PYTHON_BINDINGS=OFF' \ - ) -fi - -# .NET bindings? -if [ "X${DOTNET_BINDINGS}" = "X1" ]; then - ADDITIONAL_Z3_OPTS+=( \ - '-DZ3_BUILD_DOTNET_BINDINGS=ON' \ - '-DZ3_INSTALL_DOTNET_BINDINGS=ON' \ - ) -else - ADDITIONAL_Z3_OPTS+=( \ - '-DZ3_BUILD_DOTNET_BINDINGS=OFF' \ - '-DZ3_INSTALL_DOTNET_BINDINGS=OFF' \ - ) -fi - -# Java bindings? -if [ "X${JAVA_BINDINGS}" = "X1" ]; then - ADDITIONAL_Z3_OPTS+=( \ - '-DZ3_BUILD_JAVA_BINDINGS=ON' \ - '-DZ3_INSTALL_JAVA_BINDINGS=ON' \ - ) -else - ADDITIONAL_Z3_OPTS+=( \ - '-DZ3_BUILD_JAVA_BINDINGS=OFF' \ - '-DZ3_INSTALL_JAVA_BINDINGS=OFF' \ - ) -fi - -# Set compiler flags -source ${SCRIPT_DIR}/set_compiler_flags.sh - -if [ "X${UBSAN_BUILD}" = "X1" ]; then - # HACK: When building with UBSan the C++ linker - # must be used to avoid the following linker errors. - # undefined reference to `__ubsan_vptr_type_cache' - # undefined reference to `__ubsan_handle_dynamic_type_cache_miss' - ADDITIONAL_Z3_OPTS+=( \ - '-DZ3_C_EXAMPLES_FORCE_CXX_LINKER=ON' \ - ) -fi - -# Sanity check -if [ ! -e "${Z3_SRC_DIR}/CMakeLists.txt" ]; then - echo "Z3_SRC_DIR is invalid" - exit 1 -fi - -# Make build tree -mkdir -p "${Z3_BUILD_DIR}" -cd "${Z3_BUILD_DIR}" - -# Configure -cmake \ - -G "${Z3_CMAKE_GENERATOR}" \ - -DCMAKE_BUILD_TYPE=${Z3_BUILD_TYPE} \ - -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} \ - -DCMAKE_INSTALL_PREFIX=${Z3_INSTALL_PREFIX} \ - -DWARNINGS_AS_ERRORS=${Z3_WARNINGS_AS_ERRORS} \ - "${ADDITIONAL_Z3_OPTS[@]}" \ - "${Z3_SRC_DIR}" - -# Build -source ${SCRIPT_DIR}/set_generator_args.sh -cmake --build $(pwd) "${GENERATOR_ARGS[@]}" diff --git a/contrib/ci/scripts/ci_defaults.sh b/contrib/ci/scripts/ci_defaults.sh deleted file mode 100644 index d524503c7..000000000 --- a/contrib/ci/scripts/ci_defaults.sh +++ /dev/null @@ -1,59 +0,0 @@ -# This file should be sourced by other scripts -# and not executed directly - -# Set CI build defaults - -export ASAN_BUILD="${ASAN_BUILD:-0}" -export BUILD_DOCS="${BUILD_DOCS:-0}" -export DOTNET_BINDINGS="${DOTNET_BINDINGS:-1}" -export JAVA_BINDINGS="${JAVA_BINDINGS:-1}" -export NO_SUPPRESS_OUTPUT="${NO_SUPPRESS_OUTPUT:-0}" -export PYTHON_BINDINGS="${PYTHON_BINDINGS:-1}" -export RUN_API_EXAMPLES="${RUN_API_EXAMPLES:-1}" -export RUN_SYSTEM_TESTS="${RUN_SYSTEM_TESTS:-1}" -export RUN_UNIT_TESTS="${RUN_UNIT_TESTS:-BUILD_AND_RUN}" -# Don't print suppressions by default because that breaks the Z3 -# regression tests because they don't expect them to appear in Z3's -# output. -export SANITIZER_PRINT_SUPPRESSIONS="${SANITIZER_PRINT_SUPPRESSIONS:-0}" -export TARGET_ARCH="${TARGET_ARCH:-x86_64}" -export TEST_INSTALL="${TEST_INSTALL:-1}" -export UBSAN_BUILD="${UBSAN_BUILD:-0}" -export Z3_USE_LIBGMP="${Z3_USE_LIBGMP:-0}" -export USE_LTO="${USE_LTO:-0}" - -export Z3_BUILD_TYPE="${Z3_BUILD_TYPE:-RelWithDebInfo}" -export Z3_CMAKE_GENERATOR="${Z3_CMAKE_GENERATOR:-Ninja}" -export Z3_STATIC_BUILD="${Z3_STATIC_BUILD:-0}" -# Default is blank which means get latest revision -export Z3_SYSTEM_TEST_GIT_REVISION="${Z3_SYSTEM_TEST_GIT_REVISION:-}" -export Z3_WARNINGS_AS_ERRORS="${Z3_WARNINGS_AS_ERRORS:-SERIOUS_ONLY}" -export Z3_VERBOSE_BUILD_OUTPUT="${Z3_VERBOSE_BUILD_OUTPUT:-0}" - -# Platform specific defaults -PLATFORM="$(uname -s)" -case "${PLATFORM}" in - Linux*) - export C_COMPILER="${C_COMPILER:-gcc}" - export CXX_COMPILER="${CXX_COMPILER:-g++}" - export Z3_INSTALL_PREFIX="${Z3_INSTALL_PREFIX:-/usr}" - ;; - Darwin*) - export C_COMPILER="${C_COMPILER:-clang}" - export CXX_COMPILER="${CXX_COMPILER:-clang++}" - export Z3_INSTALL_PREFIX="${Z3_INSTALL_PREFIX:-/usr/local}" - ;; - *) - echo "Unknown platform \"${PLATFORM}\"" - exit 1 - ;; -esac -unset PLATFORM - -# NOTE: The following variables are not set here because -# they are specific to the CI implementation -# PYTHON_EXECUTABLE -# ASAN_DSO -# Z3_SRC_DIR -# Z3_BUILD_DIR -# Z3_SYSTEM_TEST_DIR diff --git a/contrib/ci/scripts/install_deps_osx.sh b/contrib/ci/scripts/install_deps_osx.sh deleted file mode 100755 index 64530e5f3..000000000 --- a/contrib/ci/scripts/install_deps_osx.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" -. ${SCRIPT_DIR}/run_quiet.sh - -set -x -set -e -set -o pipefail - -run_quiet brew update -export HOMEBREW_NO_AUTO_UPDATE=1 - -function brew_install_or_upgrade() { - if brew ls --versions "$1" > /dev/null 2>&1 ; then - brew upgrade "$1" - else - brew install "$1" - fi -} - -# FIXME: We should fix the versions of dependencies used -# so that we have reproducible builds. - -# HACK: Just use CMake version in TravisCI for now -if [ "X${MACOS_UPDATE_CMAKE}" = "X1" ]; then - brew_install_or_upgrade cmake -fi - -if [ "X${Z3_CMAKE_GENERATOR}" = "XNinja" ]; then - brew_install_or_upgrade ninja -fi - -if [ "X${Z3_USE_LIBGMP}" = "X1" ]; then - brew_install_or_upgrade gmp -fi - -if [ "X${BUILD_DOCS}" = "X1" ]; then - brew_install_or_upgrade doxygen -fi - -if [ "X${DOTNET_BINDINGS}" = "X1" ]; then - brew_install_or_upgrade mono -fi - -if [ "X${JAVA_BINDINGS}" = "X1" ]; then - brew cask install java -fi diff --git a/contrib/ci/scripts/run_quiet.sh b/contrib/ci/scripts/run_quiet.sh deleted file mode 100644 index 0f49da3be..000000000 --- a/contrib/ci/scripts/run_quiet.sh +++ /dev/null @@ -1,41 +0,0 @@ -# Simple wrapper function that runs a command suppressing -# it's output. However it's output will be shown in the -# case that `NO_SUPPRESS_OUTPUT` is set to `1` or the command -# fails. -# -# The use case for this trying to avoid large logs on TravisCI -function run_quiet() { - if [ "X${NO_SUPPRESS_OUTPUT}" = "X1" ]; then - "${@}" - else - OLD_SETTINGS="$-" - set +x - set +e - TMP_DIR="${TMP_DIR:-/tmp/}" - STDOUT="${TMP_DIR}/$$.stdout" - STDERR="${TMP_DIR}/$$.stderr" - "${@}" > "${STDOUT}" 2> "${STDERR}" - EXIT_STATUS="$?" - if [ "${EXIT_STATUS}" -ne 0 ]; then - echo "Command \"$@\" failed" - echo "EXIT CODE: ${EXIT_STATUS}" - echo "STDOUT" - echo "" - echo "\`\`\`" - cat ${STDOUT} - echo "\`\`\`" - echo "" - echo "STDERR" - echo "" - echo "\`\`\`" - cat ${STDERR} - echo "\`\`\`" - echo "" - fi - # Clean up - rm "${STDOUT}" "${STDERR}" - [ "$( echo "${OLD_SETTINGS}" | grep -c 'e')" != "0" ] && set -e - [ "$( echo "${OLD_SETTINGS}" | grep -c 'x')" != "0" ] && set -x - return ${EXIT_STATUS} - fi -} diff --git a/contrib/ci/scripts/sanitizer_env.sh b/contrib/ci/scripts/sanitizer_env.sh deleted file mode 100644 index 1a16b98a6..000000000 --- a/contrib/ci/scripts/sanitizer_env.sh +++ /dev/null @@ -1,58 +0,0 @@ -# This script is intended to be included by other -# scripts and should not be executed directly - -: ${Z3_SRC_DIR?"Z3_SRC_DIR must be specified"} -: ${ASAN_BUILD?"ASAN_BUILD must be specified"} -: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"} - -if [ "X${ASAN_BUILD}" = "X1" ]; then - # Use suppression files - export LSAN_OPTIONS="suppressions=${Z3_SRC_DIR}/contrib/suppressions/sanitizers/lsan.txt" - # NOTE: If you get bad stacktraces try using `fast_unwind_on_malloc=0` - # NOTE: `malloc_context_size` controls size of recorded stacktrace for allocations. - # If the reported stacktraces appear incomplete try increasing the value. - # leak checking disabled because it doesn't work on unpriviledged docker - export ASAN_OPTIONS="malloc_context_size=100,detect_leaks=0,suppressions=${Z3_SRC_DIR}/contrib/suppressions/sanitizers/asan.txt" - - : ${SANITIZER_PRINT_SUPPRESSIONS?"SANITIZER_PRINT_SUPPRESSIONS must be specified"} - if [ "X${SANITIZER_PRINT_SUPPRESSIONS}" = "X1" ]; then - export LSAN_OPTIONS="${LSAN_OPTIONS},print_suppressions=1" - export ASAN_OPTIONS="${ASAN_OPTIONS},print_suppressions=1" - else - export LSAN_OPTIONS="${LSAN_OPTIONS},print_suppressions=0" - export ASAN_OPTIONS="${ASAN_OPTIONS},print_suppressions=0" - fi - - #: ${ASAN_SYMBOLIZER_PATH?"ASAN_SYMBOLIZER_PATH must be specified"} - - # Run command without checking for leaks - function run_no_lsan() { - ASAN_OPTIONS="${ASAN_OPTIONS},detect_leaks=0" "${@}" - } - - function run_non_native_binding() { - "${@}" - } -else - # In non-ASan build just run directly - function run_no_lsan() { - "${@}" - } - function run_non_native_binding() { - "${@}" - } -fi - -if [ "X${UBSAN_BUILD}" = "X1" ]; then - # `halt_on_error=1,abort_on_error=1` means that on the first UBSan error - # the program will terminate by calling `abort(). Without this UBSan will - # allow execution to continue. We also use a suppression file. - export UBSAN_OPTIONS="halt_on_error=1,abort_on_error=1,suppressions=${Z3_SRC_DIR}/contrib/suppressions/sanitizers/ubsan.txt" - - : ${SANITIZER_PRINT_SUPPRESSIONS?"SANITIZER_PRINT_SUPPRESSIONS must be specified"} - if [ "X${SANITIZER_PRINT_SUPPRESSIONS}" = "X1" ]; then - export UBSAN_OPTIONS="${UBSAN_OPTIONS},print_suppressions=1" - else - export UBSAN_OPTIONS="${UBSAN_OPTIONS},print_suppressions=0" - fi -fi diff --git a/contrib/ci/scripts/set_compiler_flags.sh b/contrib/ci/scripts/set_compiler_flags.sh deleted file mode 100644 index 7efdecdac..000000000 --- a/contrib/ci/scripts/set_compiler_flags.sh +++ /dev/null @@ -1,46 +0,0 @@ -# This script should is intended to be included by other -# scripts and should not be executed directly - -: ${TARGET_ARCH?"TARGET_ARCH must be specified"} -: ${ASAN_BUILD?"ASAN_BUILD must be specified"} -: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"} -: ${CC?"CC must be specified"} -: ${CXX?"CXX must be specified"} - -case ${TARGET_ARCH} in - x86_64) - CXXFLAGS="${CXXFLAGS} -m64" - CFLAGS="${CFLAGS} -m64" - ;; - i686) - CXXFLAGS="${CXXFLAGS} -m32" - CFLAGS="${CFLAGS} -m32" - ;; - *) - echo "Unknown arch \"${TARGET_ARCH}\"" - exit 1 -esac - -if [ "X${ASAN_BUILD}" = "X1" ]; then - CXXFLAGS="${CXXFLAGS} -fsanitize=address -fno-omit-frame-pointer" - CFLAGS="${CFLAGS} -fsanitize=address -fno-omit-frame-pointer" -fi - -if [ "X${UBSAN_BUILD}" = "X1" ]; then - CXXFLAGS="${CXXFLAGS} -fsanitize=undefined" - CFLAGS="${CFLAGS} -fsanitize=undefined" -fi - -# Report flags -echo "CXXFLAGS: ${CXXFLAGS}" -echo "CFLAGS: ${CFLAGS}" - -# Report compiler -echo "CC: ${CC}" -${CC} --version -echo "CXX: ${CXX}" -${CXX} --version - -# Export the values -export CFLAGS -export CXXFLAGS diff --git a/contrib/ci/scripts/set_generator_args.sh b/contrib/ci/scripts/set_generator_args.sh deleted file mode 100644 index a704c518b..000000000 --- a/contrib/ci/scripts/set_generator_args.sh +++ /dev/null @@ -1,20 +0,0 @@ -# This script is intended to be included by other -# scripts and should not be executed directly - -: ${Z3_CMAKE_GENERATOR?"Z3_CMAKE_GENERATOR must be specified"} -: ${Z3_VERBOSE_BUILD_OUTPUT?"Z3_VERBOSE_BUILD_OUTPUT must be specified"} - -GENERATOR_ARGS=('--') -if [ "${Z3_CMAKE_GENERATOR}" = "Unix Makefiles" ]; then - GENERATOR_ARGS+=("-j$(nproc)") - if [ "X${Z3_VERBOSE_BUILD_OUTPUT}" = "X1" ]; then - GENERATOR_ARGS+=("VERBOSE=1") - fi -elif [ "${Z3_CMAKE_GENERATOR}" = "Ninja" ]; then - if [ "X${Z3_VERBOSE_BUILD_OUTPUT}" = "X1" ]; then - GENERATOR_ARGS+=("-v") - fi -else - echo "Unknown CMake generator \"${Z3_CMAKE_GENERATOR}\"" - exit 1 -fi diff --git a/contrib/ci/scripts/test_z3_docs.sh b/contrib/ci/scripts/test_z3_docs.sh deleted file mode 100755 index 6a65ffedd..000000000 --- a/contrib/ci/scripts/test_z3_docs.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" -. ${SCRIPT_DIR}/run_quiet.sh - -set -x -set -e -set -o pipefail - -: ${Z3_BUILD_DIR?"Z3_BUILD_DIR must be specified"} -: ${BUILD_DOCS?"BUILD_DOCS must be specified"} - -# Set CMake generator args -source ${SCRIPT_DIR}/set_generator_args.sh - -cd "${Z3_BUILD_DIR}" - -# Generate documentation -if [ "X${BUILD_DOCS}" = "X1" ]; then - # TODO: Make quiet once we've fixed the build - run_quiet cmake --build $(pwd) --target api_docs "${GENERATOR_ARGS[@]}" -fi - -# TODO: Test or perhaps deploy the built docs? diff --git a/contrib/ci/scripts/test_z3_examples_cmake.sh b/contrib/ci/scripts/test_z3_examples_cmake.sh deleted file mode 100755 index a149a1d83..000000000 --- a/contrib/ci/scripts/test_z3_examples_cmake.sh +++ /dev/null @@ -1,125 +0,0 @@ -#!/bin/bash - -# This script tests Z3 - -SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" -. ${SCRIPT_DIR}/run_quiet.sh - -set -x -set -e -set -o pipefail -: ${Z3_SRC_DIR?"Z3_SRC_DIR must be specified"} -: ${Z3_BUILD_DIR?"Z3_BUILD_DIR must be specified"} -: ${PYTHON_BINDINGS?"PYTHON_BINDINGS must be specified"} -: ${PYTHON_EXECUTABLE?"PYTHON_EXECUTABLE must be specified"} -: ${DOTNET_BINDINGS?"DOTNET_BINDINGS must be specified"} -: ${JAVA_BINDINGS?"JAVA_BINDINGS must be specified"} -: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"} -: ${RUN_API_EXAMPLES?"RUN_API_EXAMPLES must be specified"} - -if [ "X${RUN_API_EXAMPLES}" = "X0" ]; then - echo "Skipping run of API examples" - exit 0 -fi - -# Set compiler flags -source ${SCRIPT_DIR}/set_compiler_flags.sh - -# Set CMake generator args -source ${SCRIPT_DIR}/set_generator_args.sh - -# Sanitizer environment variables -source ${SCRIPT_DIR}/sanitizer_env.sh - -cd "${Z3_BUILD_DIR}" - -# Build and run C example -cmake --build $(pwd) --target c_example "${GENERATOR_ARGS[@]}" -run_quiet examples/c_example_build_dir/c_example - -# Build and run C++ example -cmake --build $(pwd) --target cpp_example "${GENERATOR_ARGS[@]}" -run_quiet examples/cpp_example_build_dir/cpp_example - -# Build and run tptp5 example -cmake --build $(pwd) --target z3_tptp5 "${GENERATOR_ARGS[@]}" -# FIXME: Do something more useful with example -run_quiet examples/tptp_build_dir/z3_tptp5 -help - -# Build an run c_maxsat_example -cmake --build $(pwd) --target c_maxsat_example "${GENERATOR_ARGS[@]}" -# FIXME: It is known that the maxsat example leaks memory and the -# the Z3 developers have stated this is "wontfix". -# See https://github.com/Z3Prover/z3/issues/1299 -run_no_lsan \ - run_quiet \ - examples/c_maxsat_example_build_dir/c_maxsat_example \ - ${Z3_SRC_DIR}/examples/maxsat/ex.smt - -if [ "X${UBSAN_BUILD}" = "X1" ]; then - # FIXME: We really need libz3 to link against a shared UBSan runtime. - # Right now we link against the static runtime which breaks all the - # non-native language bindings. - echo "FIXME: Can't run other examples when building with UBSan" - exit 0 -fi - - -if [ "X${PYTHON_BINDINGS}" = "X1" ]; then - # Run python examples - # `all_interval_series.py` produces a lot of output so just throw - # away output. - # TODO: This example is slow should we remove it from testing? - if [ "X${ASAN_BUILD}" = "X1" -a "X${Z3_BUILD_TYPE}" = "XDebug" ]; then - # Too slow when doing ASan Debug build - echo "Skipping all_interval_series.py under ASan Debug build" - else - run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/all_interval_series.py - fi - run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/complex.py - run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/example.py - # FIXME: `hamiltonian.py` example is disabled because its too slow. - #${PYTHON_EXECUTABLE} python/hamiltonian.py - run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/marco.py - run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/mss.py - run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/socrates.py - run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/visitor.py - run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/z3test.py -fi - -if [ "X${DOTNET_BINDINGS}" = "X1" ]; then - # Run .NET example - if [ "X${ASAN_BUILD}" = "X1" ]; then - # The dotnet test get stuck on ASAN - # so don't run it for now. - echo "Skipping .NET example under ASan build" - else - run_quiet run_non_native_binding dotnet ${Z3_BUILD_DIR}/dotnet/netcoreapp2.0/dotnet.dll - fi -fi - -if [ "X${JAVA_BINDINGS}" = "X1" ]; then - # Build Java example - # FIXME: Move compilation step into CMake target - mkdir -p examples/java - cp ${Z3_SRC_DIR}/examples/java/JavaExample.java examples/java/ - javac examples/java/JavaExample.java -classpath com.microsoft.z3.jar - # Run Java example - if [ "$(uname)" = "Darwin" ]; then - # macOS - export DYLD_LIBRARY_PATH=$(pwd):${DYLD_LIBRARY_PATH} - else - # Assume Linux for now - export LD_LIBRARY_PATH=$(pwd):${LD_LIBRARY_PATH} - fi - if [ "X${ASAN_BUILD}" = "X1" ]; then - # The JVM seems to crash (SEGV) if we pre-load ASan - # so don't run it for now. - echo "Skipping JavaExample under ASan build" - else - run_quiet \ - run_non_native_binding \ - java -cp .:examples/java:com.microsoft.z3.jar JavaExample - fi -fi - diff --git a/contrib/ci/scripts/test_z3_install_cmake.sh b/contrib/ci/scripts/test_z3_install_cmake.sh deleted file mode 100755 index 804158f6f..000000000 --- a/contrib/ci/scripts/test_z3_install_cmake.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" - -set -x -set -e -set -o pipefail - -: ${TEST_INSTALL?"TEST_INSTALL must be specified"} -: ${Z3_BUILD_DIR?"Z3_BUILD_DIR must be specified"} - -if [ "X${TEST_INSTALL}" != "X1" ]; then - echo "Skipping install" - exit 0 -fi - -# Set CMake generator args -source ${SCRIPT_DIR}/set_generator_args.sh - -cd "${Z3_BUILD_DIR}" - -sudo cmake --build $(pwd) --target install "${GENERATOR_ARGS[@]}" - -# TODO: Test the installed version in some way diff --git a/contrib/ci/scripts/test_z3_system_tests.sh b/contrib/ci/scripts/test_z3_system_tests.sh deleted file mode 100755 index 19c179268..000000000 --- a/contrib/ci/scripts/test_z3_system_tests.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash - -set -x -set -e -set -o pipefail - -: ${Z3_BUILD_DIR?"Z3_BUILD_DIR must be specified"} -: ${Z3_BUILD_TYPE?"Z3_BUILD_TYPE must be specified"} -: ${RUN_SYSTEM_TESTS?"RUN_SYSTEM_TESTS must be speicifed"} -: ${PYTHON_BINDINGS?"PYTHON_BINDINGS must be specified"} -: ${PYTHON_EXECUTABLE?"PYTHON_EXECUTABLE must be specified"} -: ${Z3_SYSTEM_TEST_DIR?"Z3_SYSTEM_TEST_DIR must be specified"} -: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"} - -if [ "X${RUN_SYSTEM_TESTS}" != "X1" ]; then - echo "Skipping system tests" - exit 0 -fi - -# Sanitizer environment variables -SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" -source ${SCRIPT_DIR}/sanitizer_env.sh - -Z3_EXE="${Z3_BUILD_DIR}/z3" -Z3_LIB_DIR="${Z3_BUILD_DIR}" - -# Set value if not already defined externally -Z3_SYSTEM_TEST_GIT_URL="${Z3_GIT_URL:-https://github.com/Z3Prover/z3test.git}" - -# Clone repo to destination -mkdir -p "${Z3_SYSTEM_TEST_DIR}" -git clone "${Z3_SYSTEM_TEST_GIT_URL}" "${Z3_SYSTEM_TEST_DIR}" -cd "${Z3_SYSTEM_TEST_DIR}" - -if [ -n "${Z3_SYSTEM_TEST_GIT_REVISION}" ]; then - # If a particular revision is requested then check it out. - # This is useful for reproducible builds - git checkout "${Z3_SYSTEM_TEST_GIT_REVISION}" -fi - -############################################################################### -# Run system tests -############################################################################### - -# SMTLIBv2 tests -${PYTHON_EXECUTABLE} scripts/test_benchmarks.py "${Z3_EXE}" regressions/smt2 - -${PYTHON_EXECUTABLE} scripts/test_benchmarks.py "${Z3_EXE}" regressions/smt2-extra - -if [ "X${Z3_BUILD_TYPE}" = "XDebug" ]; then - ${PYTHON_EXECUTABLE} scripts/test_benchmarks.py "${Z3_EXE}" regressions/smt2-debug -fi - -if [ "X${PYTHON_BINDINGS}" = "X1" ]; then - # Run python binding tests - if [ "X${UBSAN_BUILD}" = "X1" ]; then - # FIXME: We need to build libz3 with a shared UBSan runtime for the bindings - # to work. - echo "FIXME: Skipping python binding tests when building with UBSan" - elif [ "X${ASAN_BUILD}" = "X1" ]; then - # FIXME: The `test_pyscripts.py` doesn't propagate LD_PRELOAD - # so under ASan the tests fail to run - # to work. - echo "FIXME: Skipping python binding tests when building with ASan" - else - run_non_native_binding ${PYTHON_EXECUTABLE} scripts/test_pyscripts.py "${Z3_LIB_DIR}" regressions/python/ - fi -fi - -# FIXME: Run `scripts/test_cs.py` once it has been modified to support mono diff --git a/contrib/ci/scripts/test_z3_unit_tests_cmake.sh b/contrib/ci/scripts/test_z3_unit_tests_cmake.sh deleted file mode 100755 index 60c29556b..000000000 --- a/contrib/ci/scripts/test_z3_unit_tests_cmake.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" -. ${SCRIPT_DIR}/run_quiet.sh - -set -x -set -e -set -o pipefail - -: ${Z3_BUILD_DIR?"Z3_BUILD_DIR must be specified"} -: ${RUN_UNIT_TESTS?"RUN_UNIT_TESTS must be specified"} - -# Set CMake generator args -source ${SCRIPT_DIR}/set_generator_args.sh - -# Sanitizer environment variables -source ${SCRIPT_DIR}/sanitizer_env.sh - -cd "${Z3_BUILD_DIR}" - -function build_unit_tests() { - # Build internal tests - cmake --build $(pwd) --target test-z3 "${GENERATOR_ARGS[@]}" -} - -function run_unit_tests() { - # Run all tests that don't require arguments - run_quiet ./test-z3 /a -} - -case "${RUN_UNIT_TESTS}" in - BUILD_AND_RUN) - build_unit_tests - run_unit_tests - ;; - BUILD_ONLY) - build_unit_tests - ;; - SKIP) - echo "RUN_UNIT_TESTS set to \"${RUN_UNIT_TESTS}\" so skipping build and run" - exit 0 - ;; - *) - echo "Error: RUN_UNIT_TESTS set to unhandled value \"${RUN_UNIT_TESTS}\"" - exit 1 - ;; -esac diff --git a/contrib/ci/scripts/travis_ci_entry_point.sh b/contrib/ci/scripts/travis_ci_entry_point.sh deleted file mode 100755 index 41bde7230..000000000 --- a/contrib/ci/scripts/travis_ci_entry_point.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" - -set -x -set -e -set -o pipefail - -: ${TRAVIS_OS_NAME?"TRAVIS_OS_NAME should be set"} - -if [ "${TRAVIS_OS_NAME}" = "osx" ]; then - ${SCRIPT_DIR}/travis_ci_osx_entry_point.sh -elif [ "${TRAVIS_OS_NAME}" = "linux" ]; then - ${SCRIPT_DIR}/travis_ci_linux_entry_point.sh -else - echo "Unsupported OS \"${TRAVIS_OS_NAME}\"" - exit 1 -fi diff --git a/contrib/ci/scripts/travis_ci_linux_entry_point.sh b/contrib/ci/scripts/travis_ci_linux_entry_point.sh deleted file mode 100755 index 930fd9d20..000000000 --- a/contrib/ci/scripts/travis_ci_linux_entry_point.sh +++ /dev/null @@ -1,220 +0,0 @@ -#!/bin/bash - -SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" - -set -x -set -e -set -o pipefail - -DOCKER_FILE_DIR="$(cd ${SCRIPT_DIR}/../Dockerfiles; echo $PWD)" - -: ${LINUX_BASE?"LINUX_BASE must be specified"} - - -# Sanity check. Current working directory should be repo root -if [ ! -f "./README.md" ]; then - echo "Current working directory should be repo root" - exit 1 -fi - -# Get defaults -source "${SCRIPT_DIR}/ci_defaults.sh" - -BUILD_OPTS=() -# Pass Docker build arguments -if [ -n "${Z3_BUILD_TYPE}" ]; then - BUILD_OPTS+=("--build-arg" "Z3_BUILD_TYPE=${Z3_BUILD_TYPE}") -fi - -if [ -n "${Z3_CMAKE_GENERATOR}" ]; then - BUILD_OPTS+=("--build-arg" "Z3_CMAKE_GENERATOR=${Z3_CMAKE_GENERATOR}") -fi - -if [ -n "${Z3_USE_LIBGMP}" ]; then - BUILD_OPTS+=("--build-arg" "Z3_USE_LIBGMP=${Z3_USE_LIBGMP}") -fi - -if [ -n "${BUILD_DOCS}" ]; then - BUILD_OPTS+=("--build-arg" "BUILD_DOCS=${BUILD_DOCS}") -fi - -if [ -n "${PYTHON_EXECUTABLE}" ]; then - BUILD_OPTS+=("--build-arg" "PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}") -fi - -if [ -n "${PYTHON_BINDINGS}" ]; then - BUILD_OPTS+=("--build-arg" "PYTHON_BINDINGS=${PYTHON_BINDINGS}") -fi - -if [ -n "${DOTNET_BINDINGS}" ]; then - BUILD_OPTS+=("--build-arg" "DOTNET_BINDINGS=${DOTNET_BINDINGS}") -fi - -if [ -n "${JAVA_BINDINGS}" ]; then - BUILD_OPTS+=("--build-arg" "JAVA_BINDINGS=${JAVA_BINDINGS}") -fi - -if [ -n "${USE_LTO}" ]; then - BUILD_OPTS+=("--build-arg" "USE_LTO=${USE_LTO}") -fi - -if [ -n "${Z3_INSTALL_PREFIX}" ]; then - BUILD_OPTS+=("--build-arg" "Z3_INSTALL_PREFIX=${Z3_INSTALL_PREFIX}") -fi - -# TravisCI reserves CC for itself so use a different name -if [ -n "${C_COMPILER}" ]; then - BUILD_OPTS+=("--build-arg" "CC=${C_COMPILER}") -fi - -# TravisCI reserves CXX for itself so use a different name -if [ -n "${CXX_COMPILER}" ]; then - BUILD_OPTS+=("--build-arg" "CXX=${CXX_COMPILER}") -fi - -if [ -n "${TARGET_ARCH}" ]; then - BUILD_OPTS+=("--build-arg" "TARGET_ARCH=${TARGET_ARCH}") -fi - -if [ -n "${ASAN_BUILD}" ]; then - BUILD_OPTS+=("--build-arg" "ASAN_BUILD=${ASAN_BUILD}") -fi - -if [ -n "${ASAN_DSO}" ]; then - BUILD_OPTS+=("--build-arg" "ASAN_DSO=${ASAN_DSO}") -fi - -if [ -n "${SANITIZER_PRINT_SUPPRESSIONS}" ]; then - BUILD_OPTS+=("--build-arg" "SANITIZER_PRINT_SUPPRESSIONS=${SANITIZER_PRINT_SUPPRESSIONS}") -fi - -if [ -n "${UBSAN_BUILD}" ]; then - BUILD_OPTS+=("--build-arg" "UBSAN_BUILD=${UBSAN_BUILD}") -fi - -if [ -n "${TEST_INSTALL}" ]; then - BUILD_OPTS+=("--build-arg" "TEST_INSTALL=${TEST_INSTALL}") -fi - -if [ -n "${RUN_API_EXAMPLES}" ]; then - BUILD_OPTS+=("--build-arg" "RUN_API_EXAMPLES=${RUN_API_EXAMPLES}") -fi - -if [ -n "${RUN_SYSTEM_TESTS}" ]; then - BUILD_OPTS+=("--build-arg" "RUN_SYSTEM_TESTS=${RUN_SYSTEM_TESTS}") -fi - -if [ -n "${Z3_SYSTEM_TEST_GIT_REVISION}" ]; then - BUILD_OPTS+=( \ - "--build-arg" \ - "Z3_SYSTEM_TEST_GIT_REVISION=${Z3_SYSTEM_TEST_GIT_REVISION}" \ - ) -fi - -if [ -n "${RUN_UNIT_TESTS}" ]; then - BUILD_OPTS+=("--build-arg" "RUN_UNIT_TESTS=${RUN_UNIT_TESTS}") -fi - -if [ -n "${Z3_VERBOSE_BUILD_OUTPUT}" ]; then - BUILD_OPTS+=( \ - "--build-arg" \ - "Z3_VERBOSE_BUILD_OUTPUT=${Z3_VERBOSE_BUILD_OUTPUT}" \ - ) -fi - -if [ -n "${Z3_STATIC_BUILD}" ]; then - BUILD_OPTS+=("--build-arg" "Z3_STATIC_BUILD=${Z3_STATIC_BUILD}") -fi - -if [ -n "${NO_SUPPRESS_OUTPUT}" ]; then - BUILD_OPTS+=( \ - "--build-arg" \ - "NO_SUPPRESS_OUTPUT=${NO_SUPPRESS_OUTPUT}" \ - ) -fi - -if [ -n "${Z3_WARNINGS_AS_ERRORS}" ]; then - BUILD_OPTS+=( \ - "--build-arg" \ - "Z3_WARNINGS_AS_ERRORS=${Z3_WARNINGS_AS_ERRORS}" \ - ) -fi - -case ${LINUX_BASE} in - ubuntu_20.04) - BASE_DOCKER_FILE="${DOCKER_FILE_DIR}/z3_base_ubuntu_20.04.Dockerfile" - BASE_DOCKER_IMAGE_NAME="z3_base_ubuntu:20.04" - ;; - *) - echo "Unknown Linux base ${LINUX_BASE}" - exit 1 - ;; -esac - -# Initially assume that we need to build the base Docker image -MUST_BUILD=1 - -# Travis CI persistent cache. -# -# This inspired by http://rundef.com/fast-travis-ci-docker-build . -# The idea is to cache the built image for subsequent builds to -# reduce build time. -if [ -n "${DOCKER_TRAVIS_CI_CACHE_DIR}" ]; then - CHECKSUM_FILE="${DOCKER_TRAVIS_CI_CACHE_DIR}/${BASE_DOCKER_IMAGE_NAME}.chksum" - CACHED_DOCKER_IMAGE="${DOCKER_TRAVIS_CI_CACHE_DIR}/${BASE_DOCKER_IMAGE_NAME}.gz" - if [ -f "${CACHED_DOCKER_IMAGE}" ]; then - # There's a cached image to use. Check the checksums of the Dockerfile - # match. If they don't that implies we need to build a fresh image. - if [ -f "${CHECKSUM_FILE}" ]; then - CURRENT_DOCKERFILE_CHECKSUM=$(sha256sum "${BASE_DOCKER_FILE}" | awk '{ print $1 }') - CACHED_DOCKERFILE_CHECKSUM=$(cat "${CHECKSUM_FILE}") - if [ "X${CURRENT_DOCKERFILE_CHECKSUM}" = "X${CACHED_DOCKERFILE_CHECKSUM}" ]; then - # Load the cached image - MUST_BUILD=0 - gunzip --stdout "${CACHED_DOCKER_IMAGE}" | docker load - fi - fi - fi -fi - -if [ "${MUST_BUILD}" -eq 1 ]; then - # The base image contains all the dependencies we want to build - # Z3. - docker build -t "${BASE_DOCKER_IMAGE_NAME}" - < "${BASE_DOCKER_FILE}" - - if [ -n "${DOCKER_TRAVIS_CI_CACHE_DIR}" ]; then - # Write image and checksum to cache - docker save "${BASE_DOCKER_IMAGE_NAME}" | \ - gzip > "${CACHED_DOCKER_IMAGE}" - sha256sum "${BASE_DOCKER_FILE}" | awk '{ print $1 }' > \ - "${CHECKSUM_FILE}" - fi -fi - - -DOCKER_MAJOR_VERSION=$(docker info --format '{{.ServerVersion}}' | sed 's/^\([0-9]\+\)\.\([0-9]\+\).*$/\1/') -DOCKER_MINOR_VERSION=$(docker info --format '{{.ServerVersion}}' | sed 's/^\([0-9]\+\)\.\([0-9]\+\).*$/\2/') -DOCKER_BUILD_FILE="${DOCKER_FILE_DIR}/z3_build.Dockerfile" - -if [ "${DOCKER_MAJOR_VERSION}${DOCKER_MINOR_VERSION}" -lt 1705 ]; then - # Workaround limitation in older Docker versions where the FROM - # command cannot be parameterized with an ARG. - sed \ - -e '/^ARG DOCKER_IMAGE_BASE/d' \ - -e 's/${DOCKER_IMAGE_BASE}/'"${BASE_DOCKER_IMAGE_NAME}/" \ - "${DOCKER_BUILD_FILE}" > "${DOCKER_BUILD_FILE}.patched" - DOCKER_BUILD_FILE="${DOCKER_BUILD_FILE}.patched" -else - # This feature landed in Docker 17.05 - # See https://github.com/moby/moby/pull/31352 - BUILD_OPTS+=( \ - "--build-arg" \ - "DOCKER_IMAGE_BASE=${BASE_DOCKER_IMAGE_NAME}" \ - ) -fi - -# Now build Z3 and test it using the created base image -docker build \ - -f "${DOCKER_BUILD_FILE}" \ - "${BUILD_OPTS[@]}" \ - . diff --git a/contrib/ci/scripts/travis_ci_osx_entry_point.sh b/contrib/ci/scripts/travis_ci_osx_entry_point.sh deleted file mode 100755 index ad3b0c7ab..000000000 --- a/contrib/ci/scripts/travis_ci_osx_entry_point.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash - -SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" - -set -x -set -e -set -o pipefail - -# Get defaults -source "${SCRIPT_DIR}/ci_defaults.sh" - -if [ -z "${TRAVIS_BUILD_DIR}" ]; then - echo "TRAVIS_BUILD_DIR must be set to root of Z3 repository" - exit 1 -fi - -if [ ! -d "${TRAVIS_BUILD_DIR}" ]; then - echo "TRAVIS_BUILD_DIR must be a directory" - exit 1 -fi - -# These variables are specific to the macOS TravisCI -# implementation and are not set in `ci_defaults.sh`. -export PYTHON_EXECUTABLE="${PYTHON_EXECUTABLE:-$(which python)}" -export Z3_SRC_DIR="${TRAVIS_BUILD_DIR}" -export Z3_BUILD_DIR="${Z3_SRC_DIR}/build" -export Z3_SYSTEM_TEST_DIR="${Z3_SRC_DIR}/z3_system_test" - -# Overwrite whatever what set in TravisCI -export CC="${C_COMPILER}" -export CXX="${CXX_COMPILER}" - -if [ "X${MACOS_SKIP_DEPS_UPDATE}" = "X1" ]; then - # This is just for local testing to avoid updating - echo "Skipping dependency update" -else - "${SCRIPT_DIR}/install_deps_osx.sh" -fi - -# Build Z3 -"${SCRIPT_DIR}/build_z3_cmake.sh" -# Test building docs -"${SCRIPT_DIR}/test_z3_docs.sh" -# Test examples -"${SCRIPT_DIR}/test_z3_examples_cmake.sh" -# Run unit tests -"${SCRIPT_DIR}/test_z3_unit_tests_cmake.sh" -# Run system tests -"${SCRIPT_DIR}/test_z3_system_tests.sh" -# Test install -"${SCRIPT_DIR}/test_z3_install_cmake.sh" diff --git a/contrib/cmake/bootstrap.py b/contrib/cmake/bootstrap.py deleted file mode 100755 index dac08b383..000000000 --- a/contrib/cmake/bootstrap.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python -""" -This script is an artifact of compromise that was -made when the CMake build system was first introduced -(see #461). - -This script now does nothing. It remains only to not -break out-of-tree scripts that build Z3 using CMake. - -Eventually this script will be removed. -""" -import argparse -import logging -import os -import pprint -import shutil -import sys - -def main(args): - logging.basicConfig(level=logging.INFO) - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('mode', - choices=['create', 'remove'], - help='The mode to use') - parser.add_argument("-l","--log-level", - type=str, - default="info", - dest="log_level", - choices=['debug','info','warning','error'] - ) - parser.add_argument("-H", "--hard-link", - action='store_true', - default=False, - dest='hard_link', - help='When using the create mode create hard links instead of copies' - ) - pargs = parser.parse_args(args) - - logLevel = getattr(logging, pargs.log_level.upper(),None) - logging.basicConfig(level=logLevel) - logging.warning('Use of this script is deprecated. The script will be removed in the future') - logging.warning('Action "{}" ignored'.format(pargs.mode)) - if pargs.hard_link: - logging.warning('Hard link option ignored') - return 0 - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) diff --git a/contrib/cmake/maintainers.txt b/contrib/cmake/maintainers.txt deleted file mode 100644 index caa6798c6..000000000 --- a/contrib/cmake/maintainers.txt +++ /dev/null @@ -1,3 +0,0 @@ -# Maintainers - -- Dan Liew (@delcypher) diff --git a/contrib/cmake/src/test/lp/CMakeLists.txt b/contrib/cmake/src/test/lp/CMakeLists.txt deleted file mode 100644 index 6683a1758..000000000 --- a/contrib/cmake/src/test/lp/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -add_executable(lp_tst lp_main.cpp lp.cpp $ $ $ $ ) -target_compile_definitions(lp_tst PRIVATE ${Z3_COMPONENT_CXX_DEFINES}) -target_compile_options(lp_tst PRIVATE ${Z3_COMPONENT_CXX_FLAGS}) -target_include_directories(lp_tst PRIVATE ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS}) -target_link_libraries(lp_tst PRIVATE ${Z3_DEPENDENT_LIBS}) -z3_append_linker_flag_list_to_target(lp_tst ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS}) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index e37ca131f..54ba73fb0 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -69,7 +69,7 @@ add_custom_target(api_docs ${ALWAYS_BUILD_DOCS_ARG} DEPENDS ${DOC_EXTRA_DEPENDS} COMMENT "Generating documentation" - ${ADD_CUSTOM_TARGET_USES_TERMINAL_ARG} + USES_TERMINAL ) # Remove generated documentation when running `clean` target. diff --git a/doc/website.dox.in b/doc/website.dox.in index 5249f2ae0..651652ce4 100644 --- a/doc/website.dox.in +++ b/doc/website.dox.in @@ -8,5 +8,5 @@ This website hosts the automatically generated documentation for the Z3 APIs. - - \ref @C_API@ @CPP_API@ @DOTNET_API@ @JAVA_API@ @PYTHON_API@ @OCAML_API@ @JS_API@ + @C_API@ @CPP_API@ @DOTNET_API@ @JAVA_API@ @PYTHON_API@ @OCAML_API@ @JS_API@ */ diff --git a/doc/z3api.cfg.in b/doc/z3api.cfg.in index 41624b255..1c367e141 100644 --- a/doc/z3api.cfg.in +++ b/doc/z3api.cfg.in @@ -2171,7 +2171,6 @@ INCLUDE_FILE_PATTERNS = # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. PREDEFINED = Z3_ast_opt:=Z3_ast \ - Z3_bool_opt:=Z3_bool \ Z3_func_interp_opt:=Z3_func_interp \ Z3_model_opt:=Z3_model \ __out_opt:=__out diff --git a/doc/z3code.dox b/doc/z3code.dox index b6a7fb088..f69fe2bed 100644 --- a/doc/z3code.dox +++ b/doc/z3code.dox @@ -816,7 +816,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED =Z3_ast_opt:=Z3_ast Z3_bool_opt:=Z3_bool Z3_func_interp_opt:=Z3_func_interp Z3_model_opt:=Z3_model __out_opt:=__out +PREDEFINED =Z3_ast_opt:=Z3_ast Z3_func_interp_opt:=Z3_func_interp Z3_model_opt:=Z3_model __out_opt:=__out # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. @@ -825,7 +825,7 @@ PREDEFINED =Z3_ast_opt:=Z3_ast Z3_bool_opt:=Z3_bool Z3_func_interp_o EXPAND_AS_DEFINED = -# Z3_ast_opt Z3_bool_opt Z3_func_interp_opt Z3_model_opt __out_opt +# Z3_ast_opt Z3_func_interp_opt Z3_model_opt __out_opt # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index dcc21f255..07a53f8f0 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,11 +1,4 @@ include(ExternalProject) -# Unfortunately `BUILD_ALWAYS` only seems to be supported with the version of ExternalProject -# that shipped with CMake >= 3.1. -if (("${CMAKE_VERSION}" VERSION_EQUAL "3.1") OR ("${CMAKE_VERSION}" VERSION_GREATER "3.1")) - set(EXTERNAL_PROJECT_BUILD_ALWAYS_ARG BUILD_ALWAYS 1) -else() - set(EXTERNAL_PROJECT_BUILD_ALWAYS_ARG "") -endif() option(Z3_C_EXAMPLES_FORCE_CXX_LINKER "Force C++ linker when building C example projects" OFF) @@ -43,7 +36,7 @@ ExternalProject_Add(c_example "${EXTERNAL_C_PROJ_USE_CXX_LINKER_ARG}" "${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}" # Build step - ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} + BUILD_ALWAYS ON BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/c_example_build_dir" # Install Step INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "" # Dummy command @@ -62,7 +55,7 @@ ExternalProject_Add(c_maxsat_example "${EXTERNAL_C_PROJ_USE_CXX_LINKER_ARG}" "${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}" # Build step - ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} + BUILD_ALWAYS ON BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/c_maxsat_example_build_dir" # Install Step INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "" # Dummy command @@ -81,7 +74,7 @@ ExternalProject_Add(cpp_example "-DZ3_DIR=${PROJECT_BINARY_DIR}" "${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}" # Build step - ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} + BUILD_ALWAYS ON BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/cpp_example_build_dir" # Install Step INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "" # Dummy command @@ -99,7 +92,7 @@ ExternalProject_Add(z3_tptp5 "-DZ3_DIR=${PROJECT_BINARY_DIR}" "${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}" # Build step - ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} + BUILD_ALWAYS ON BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/tptp_build_dir" # Install Step INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "" # Dummy command @@ -117,7 +110,7 @@ ExternalProject_Add(userPropagator "-DZ3_DIR=${PROJECT_BINARY_DIR}" "${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}" # Build step - ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} + BUILD_ALWAYS ON BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/userPropagator_build_dir" # Install Step INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "" # Dummy command diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index c71c3ff2f..06f3ffe3e 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -5,6 +5,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ #include +#include #include #include"z3++.h" @@ -956,6 +957,55 @@ void tuple_example() { std::cout << pair2 << "\n"; } +void datatype_example() { + std::cout << "datatype example\n"; + context ctx; + constructors cs(ctx); + symbol ilist = ctx.str_symbol("ilist"); + symbol accs[2] = { ctx.str_symbol("hd"), ctx.str_symbol("tl") }; + sort sorts[2] = { ctx.int_sort(), ctx.datatype_sort(ilist) }; + cs.add(ctx.str_symbol("nil"), ctx.str_symbol("is-nil"), 0, nullptr, nullptr); + cs.add(ctx.str_symbol("cons"), ctx.str_symbol("is-cons"), 2, accs, sorts); + sort ls = ctx.datatype(ilist, cs); + std::cout << ls << "\n"; + func_decl nil(ctx), is_nil(ctx); + func_decl_vector nil_acc(ctx); + cs.query(0, nil, is_nil, nil_acc); + func_decl cons(ctx), is_cons(ctx); + func_decl_vector cons_acc(ctx); + cs.query(1, cons, is_cons, cons_acc); + std::cout << nil << " " << is_nil << " " << nil_acc << "\n"; + std::cout << cons << " " << is_cons << " " << cons_acc << "\n"; + + symbol tree = ctx.str_symbol("tree"); + symbol tlist = ctx.str_symbol("tree_list"); + symbol accs1[2] = { ctx.str_symbol("left"), ctx.str_symbol("right") }; + symbol accs2[2] = { ctx.str_symbol("hd"), ctx.str_symbol("tail") }; + sort sorts1[2] = { ctx.datatype_sort(tlist), ctx.datatype_sort(tlist) }; + sort sorts2[2] = { ctx.int_sort(), ctx.datatype_sort(tree) }; + constructors cs1(ctx), cs2(ctx); + cs1.add(ctx.str_symbol("tnil"), ctx.str_symbol("is-tnil"), 0, nullptr, nullptr); + cs1.add(ctx.str_symbol("tnode"), ctx.str_symbol("is-tnode"), 2, accs1, sorts1); + constructor_list cl1(cs1); + cs2.add(ctx.str_symbol("lnil"), ctx.str_symbol("is-lnil"), 0, nullptr, nullptr); + cs2.add(ctx.str_symbol("lcons"), ctx.str_symbol("is-lcons"), 2, accs2, sorts2); + constructor_list cl2(cs2); + symbol names[2] = { tree, tlist }; + constructor_list* cl[2] = { &cl1, &cl2 }; + sort_vector dsorts = ctx.datatypes(2, names, cl); + std::cout << dsorts << "\n"; + cs1.query(0, nil, is_nil, nil_acc); + cs1.query(1, cons, is_cons, cons_acc); + std::cout << nil << " " << is_nil << " " << nil_acc << "\n"; + std::cout << cons << " " << is_cons << " " << cons_acc << "\n"; + + cs2.query(0, nil, is_nil, nil_acc); + cs2.query(1, cons, is_cons, cons_acc); + std::cout << nil << " " << is_nil << " " << nil_acc << "\n"; + std::cout << cons << " " << is_cons << " " << cons_acc << "\n"; + +} + void expr_vector_example() { std::cout << "expr_vector example\n"; context c; @@ -1343,6 +1393,7 @@ int main() { incremental_example3(); std::cout << "\n"; enum_sort_example(); std::cout << "\n"; tuple_example(); std::cout << "\n"; + datatype_example(); std::cout << "\n"; expr_vector_example(); std::cout << "\n"; exists_expr_vector_example(); std::cout << "\n"; substitute_example(); std::cout << "\n"; diff --git a/examples/python/simplify_formula.py b/examples/python/simplify_formula.py new file mode 100644 index 000000000..4aff993b6 --- /dev/null +++ b/examples/python/simplify_formula.py @@ -0,0 +1,83 @@ +from z3 import * + +def is_atom(t): + if not is_bool(t): + return False + if not is_app(t): + return False + k = t.decl().kind() + if k == Z3_OP_AND or k == Z3_OP_OR or k == Z3_OP_IMPLIES: + return False + if k == Z3_OP_EQ and t.arg(0).is_bool(): + return False + if k == Z3_OP_TRUE or k == Z3_OP_FALSE or k == Z3_OP_XOR or k == Z3_OP_NOT: + return False + return True + +def atoms(fml): + visited = set([]) + atms = set([]) + def atoms_rec(t, visited, atms): + if t in visited: + return + visited |= { t } + if is_atom(t): + atms |= { t } + for s in t.children(): + atoms_rec(s, visited, atms) + atoms_rec(fml, visited, atms) + return atms + +def atom2literal(m, a): + if is_true(m.eval(a)): + return a + return Not(a) + +# Extract subset of atoms used to satisfy the negation +# of a formula. +# snot is a solver for Not(fml) +# s is a solver for fml +# m is a model for Not(fml) +# evaluate each atom in fml using m and create +# literals corresponding to the sign of the evaluation. +# If the model evaluates atoms to false, the literal is +# negated. +# +# +def implicant(atoms, s, snot): + m = snot.model() + lits = [atom2literal(m, a) for a in atoms] + is_sat = s.check(lits) + assert is_sat == unsat + core = s.unsat_core() + return Or([mk_not(c) for c in core]) + +# +# Extract a CNF representation of fml +# The procedure uses two solvers +# Enumerate models for Not(fml) +# Use the enumerated model to identify literals +# that imply Not(fml) +# The CNF of fml is a conjunction of the +# negation of these literals. +# + +def to_cnf(fml): + atms = atoms(fml) + s = Solver() + snot = Solver() + snot.add(Not(fml)) + s.add(fml) + + while sat == snot.check(): + clause = implicant(atms, s, snot) + yield clause + snot.add(clause) + + +a, b, c, = Bools('a b c') +fml = Or(And(a, b), And(Not(a), c)) + +for clause in to_cnf(fml): + print(clause) + diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index fac922db8..4f1d25aa9 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -15,6 +15,7 @@ Copyright (c) 2015 Microsoft Corporation #include #include #include +#include #include #include #include "z3++.h" diff --git a/examples/userPropagator/CMakeLists.txt b/examples/userPropagator/CMakeLists.txt index 384d257dc..0a5039a2b 100644 --- a/examples/userPropagator/CMakeLists.txt +++ b/examples/userPropagator/CMakeLists.txt @@ -15,9 +15,9 @@ find_package(Z3 ) ################################################################################ -# Z3 C++ API bindings require C++11 +# Z3 C++ API bindings require C++11, but this code needs later. ################################################################################ -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) message(STATUS "Z3_FOUND: ${Z3_FOUND}") diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 9f7a69b56..f4f599be2 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, 9, 2, 0) + set_version(4, 11, 0, 0) # Z3 Project definition def init_project_def(): @@ -38,7 +38,7 @@ def init_project_def(): add_lib('substitution', ['ast', 'rewriter'], 'ast/substitution') add_lib('parser_util', ['ast'], 'parsers/util') add_lib('proofs', ['rewriter', 'util'], 'ast/proofs') - add_lib('solver', ['model', 'tactic', 'proofs']) + add_lib('solver', ['params', 'model', 'tactic', 'proofs']) add_lib('cmd_context', ['solver', 'rewriter', 'params']) add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2') add_lib('pattern', ['normal_forms', 'smt2parser', 'rewriter'], 'ast/pattern') diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index d152b3625..3b1e71391 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -66,7 +66,7 @@ def display_help(): # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, OS_NAME + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, PYTHON_ENABLED, OS_NAME path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 54242dfe6..83171ab66 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1830,8 +1830,11 @@ class JavaDLLComponent(Component): if IS_WINDOWS: # On Windows, CL creates a .lib file to link against. out.write('\t$(SLINK) $(SLINK_OUT_FLAG)libz3java$(SO_EXT) $(SLINK_FLAGS) %s$(OBJ_EXT) libz3$(LIB_EXT)\n' % os.path.join('api', 'java', 'Native')) + elif IS_OSX and IS_ARCH_ARM64: + out.write('\t$(SLINK) $(SLINK_OUT_FLAG)libz3java$(SO_EXT) $(SLINK_FLAGS) -arch arm64 %s$(OBJ_EXT) libz3$(SO_EXT)\n' % + os.path.join('api', 'java', 'Native')) else: - out.write('\t$(SLINK) $(SLINK_OUT_FLAG)libz3java$(SO_EXT) $(SLINK_FLAGS) $(SLINK_EXTRA_FLAGS) %s$(OBJ_EXT) libz3$(SO_EXT)\n' % + out.write('\t$(SLINK) $(SLINK_OUT_FLAG)libz3java$(SO_EXT) $(SLINK_FLAGS) %s$(OBJ_EXT) libz3$(SO_EXT)\n' % os.path.join('api', 'java', 'Native')) out.write('%s.jar: libz3java$(SO_EXT) ' % self.package_name) deps = '' @@ -2591,46 +2594,30 @@ def mk_config(): SO_EXT = '.dylib' SLIBFLAGS = '-dynamiclib' elif sysname == 'Linux': - CXXFLAGS = '%s -D_LINUX_' % CXXFLAGS - OS_DEFINES = '-D_LINUX_' SO_EXT = '.so' SLIBFLAGS = '-shared' SLIBEXTRAFLAGS = '%s -Wl,-soname,libz3.so' % SLIBEXTRAFLAGS elif sysname == 'GNU': - CXXFLAGS = '%s -D_HURD_' % CXXFLAGS - OS_DEFINES = '-D_HURD_' SO_EXT = '.so' SLIBFLAGS = '-shared' elif sysname == 'FreeBSD': - CXXFLAGS = '%s -D_FREEBSD_' % CXXFLAGS - 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_' SO_EXT = '.so' SLIBFLAGS = '-shared' elif sysname == 'OpenBSD': - CXXFLAGS = '%s -D_OPENBSD_' % CXXFLAGS - OS_DEFINES = '-D_OPENBSD_' SO_EXT = '.so' SLIBFLAGS = '-shared' elif sysname == 'SunOS': - CXXFLAGS = '%s -D_SUNOS_' % CXXFLAGS - OS_DEFINES = '-D_SUNOS_' SO_EXT = '.so' SLIBFLAGS = '-shared' SLIBEXTRAFLAGS = '%s -mimpure-text' % SLIBEXTRAFLAGS elif sysname.startswith('CYGWIN'): - CXXFLAGS = '%s -D_CYGWIN' % CXXFLAGS - OS_DEFINES = '-D_CYGWIN' SO_EXT = '.dll' SLIBFLAGS = '-shared' elif sysname.startswith('MSYS_NT') or sysname.startswith('MINGW'): - CXXFLAGS = '%s -D_MINGW' % CXXFLAGS - OS_DEFINES = '-D_MINGW' SO_EXT = '.dll' SLIBFLAGS = '-shared' EXE_EXT = '.exe' @@ -2640,8 +2627,6 @@ 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' or sysname == 'FreeBSD': - CPPFLAGS = '%s -D_USE_THREAD_LOCAL' % CPPFLAGS elif not LINUX_X64: CXXFLAGS = '%s -m32' % CXXFLAGS LDFLAGS = '%s -m32' % LDFLAGS diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 1292646ac..221ade46b 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,8 +1,8 @@ variables: Major: '4' - Minor: '9' - Patch: '2' + Minor: '11' + Patch: '0' NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName) stages: diff --git a/scripts/release.yml b/scripts/release.yml index 419d4bc4b..f305e7c74 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -6,7 +6,7 @@ trigger: none variables: - ReleaseVersion: '4.9.2' + ReleaseVersion: '4.11.0' stages: @@ -516,8 +516,9 @@ stages: inputs: command: push nuGetFeedType: External - publishFeedCredentials: Z3Nuget + publishFeedCredentials: $(NugetZ3) packagesToPush: $(Agent.TempDirectory)/*.nupkg + # Enable on release: - job: PyPIPublish diff --git a/scripts/update_api.py b/scripts/update_api.py index 8c6275c56..37b8a31af 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -16,7 +16,6 @@ emit some of the files required for Z3's different language bindings. """ -import mk_exception import argparse import logging import re @@ -1700,8 +1699,8 @@ def def_APIs(api_files): m = pat2.match(line) if m: eval(line) - except Exception: - raise mk_exec_header.MKException("Failed to process API definition: %s" % line) + except Exception as e: + error('ERROR: While processing: %s: %s\n' % (e, line)) def write_log_h_preamble(log_h): log_h.write('// Automatically generated file\n') @@ -1854,6 +1853,7 @@ _lib.Z3_solver_propagate_final.restype = None _lib.Z3_solver_propagate_fixed.restype = None _lib.Z3_solver_propagate_eq.restype = None _lib.Z3_solver_propagate_diseq.restype = None +_lib.Z3_solver_propagate_decide.restype = None on_model_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p) _lib.Z3_optimize_register_model_eh.restype = None diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 51fafb42f..5be29c950 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -204,7 +204,7 @@ if (MSVC) ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} COMMENT "Generating \"${dll_module_exports_file}\"" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL VERBATIM ) add_custom_target(libz3_extra_depends diff --git a/src/ackermannization/ackermannize_bv_tactic.cpp b/src/ackermannization/ackermannize_bv_tactic.cpp index 79cad2fb2..5ef783c93 100644 --- a/src/ackermannization/ackermannize_bv_tactic.cpp +++ b/src/ackermannization/ackermannize_bv_tactic.cpp @@ -29,8 +29,6 @@ public: updt_params(p); } - ~ackermannize_bv_tactic() override { } - char const* name() const override { return "ackermannize_bv"; } void operator()(goal_ref const & g, goal_ref_buffer & result) override { diff --git a/src/ackermannization/ackr_model_converter.cpp b/src/ackermannization/ackr_model_converter.cpp index 78fe6bef0..a38455e03 100644 --- a/src/ackermannization/ackr_model_converter.cpp +++ b/src/ackermannization/ackr_model_converter.cpp @@ -40,8 +40,6 @@ public: fixed_model(false) { } - ~ackr_model_converter() override { } - void get_units(obj_map& units) override { units.reset(); } void operator()(model_ref & md) override { diff --git a/src/ackermannization/lackr_model_converter_lazy.cpp b/src/ackermannization/lackr_model_converter_lazy.cpp index ec54b1d19..991fbed8e 100644 --- a/src/ackermannization/lackr_model_converter_lazy.cpp +++ b/src/ackermannization/lackr_model_converter_lazy.cpp @@ -28,8 +28,6 @@ public: , model_constructor(lmc) { } - ~lackr_model_converter_lazy() override { } - void operator()(model_ref & md) override { SASSERT(md.get() == 0 || (!md->get_num_constants() && !md->get_num_functions())); SASSERT(model_constructor.get()); diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt index 983180985..08ea9ce29 100644 --- a/src/api/CMakeLists.txt +++ b/src/api/CMakeLists.txt @@ -26,10 +26,8 @@ add_custom_command(OUTPUT ${generated_files} DEPENDS "${PROJECT_SOURCE_DIR}/scripts/update_api.py" ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} - # FIXME: When update_api.py no longer uses ``mk_util`` drop this dependency - "${PROJECT_SOURCE_DIR}/scripts/mk_util.py" COMMENT "Generating ${generated_files}" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL VERBATIM ) diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index d24a4a624..ab87c4e26 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -344,7 +344,6 @@ extern "C" { scoped_anum_vector const & m_as; public: vector_var2anum(scoped_anum_vector & as):m_as(as) {} - virtual ~vector_var2anum() {} algebraic_numbers::manager & m() const override { return m_as.m(); } bool contains(polynomial::var x) const override { return static_cast(x) < m_as.size(); } algebraic_numbers::anum const & operator()(polynomial::var x) const override { return m_as.get(x); } @@ -422,7 +421,7 @@ extern "C" { Z3_TRY; LOG_Z3_algebraic_get_poly(c, a); RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC(a, 0); + CHECK_IS_ALGEBRAIC(a, nullptr); algebraic_numbers::manager & _am = am(c); algebraic_numbers::anum const & av = get_irrational(c, a); scoped_mpz_vector coeffs(_am.qm()); diff --git a/src/api/api_ast_vector.h b/src/api/api_ast_vector.h index fe6203cb9..dc1fcb8e6 100644 --- a/src/api/api_ast_vector.h +++ b/src/api/api_ast_vector.h @@ -26,7 +26,6 @@ namespace api { struct Z3_ast_vector_ref : public api::object { ast_ref_vector m_ast_vector; Z3_ast_vector_ref(api::context& c, ast_manager & m): api::object(c), m_ast_vector(m) {} - ~Z3_ast_vector_ref() override {} }; inline Z3_ast_vector_ref * to_ast_vector(Z3_ast_vector v) { return reinterpret_cast(v); } diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp index cbe89e9fb..93d4e27e1 100644 --- a/src/api/api_config_params.cpp +++ b/src/api/api_config_params.cpp @@ -47,7 +47,7 @@ extern "C" { env_params::updt_params(); } - Z3_bool Z3_API Z3_global_param_get(Z3_string param_id, Z3_string_ptr param_value) { + bool Z3_API Z3_global_param_get(Z3_string param_id, Z3_string_ptr param_value) { memory::initialize(UINT_MAX); LOG_Z3_global_param_get(param_id, param_value); *param_value = nullptr; diff --git a/src/api/api_context.h b/src/api/api_context.h index 182958b1e..3bc0d4403 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -58,7 +58,7 @@ namespace api { solver_ref s; public: seq_expr_solver(ast_manager& m, params_ref const& p): m(m), p(p) {} - lbool check_sat(expr* e) { + lbool check_sat(expr* e) override { if (!s) { s = mk_smt_solver(m, p, symbol("ALL")); } diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 8c6227d7d..19b488239 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -52,7 +52,6 @@ namespace api { m_context(m, m_register_engine, p), m_trail(m) {} - ~fixedpoint_context() override {} family_id get_family_id() const override { return const_cast(m_context).get_decl_util().get_family_id(); } void set_state(void* state) { SASSERT(!m_state); diff --git a/src/api/api_goal.h b/src/api/api_goal.h index 86f6a4331..56f48df91 100644 --- a/src/api/api_goal.h +++ b/src/api/api_goal.h @@ -23,7 +23,6 @@ Revision History: struct Z3_goal_ref : public api::object { goal_ref m_goal; Z3_goal_ref(api::context& c) : api::object(c) {} - ~Z3_goal_ref() override {} }; inline Z3_goal_ref * to_goal(Z3_goal g) { return reinterpret_cast(g); } diff --git a/src/api/api_model.h b/src/api/api_model.h index c05c86ceb..c04fc088d 100644 --- a/src/api/api_model.h +++ b/src/api/api_model.h @@ -23,7 +23,6 @@ Revision History: struct Z3_model_ref : public api::object { model_ref m_model; Z3_model_ref(api::context& c): api::object(c) {} - ~Z3_model_ref() override {} }; inline Z3_model_ref * to_model(Z3_model s) { return reinterpret_cast(s); } @@ -34,7 +33,6 @@ struct Z3_func_interp_ref : public api::object { model_ref m_model; // must have it to prevent reference to m_func_interp to be killed. func_interp * m_func_interp; Z3_func_interp_ref(api::context& c, model * m): api::object(c), m_model(m), m_func_interp(nullptr) {} - ~Z3_func_interp_ref() override {} }; inline Z3_func_interp_ref * to_func_interp(Z3_func_interp s) { return reinterpret_cast(s); } @@ -46,7 +44,6 @@ struct Z3_func_entry_ref : public api::object { func_interp * m_func_interp; func_entry const * m_func_entry; Z3_func_entry_ref(api::context& c, model * m):api::object(c), m_model(m), m_func_interp(nullptr), m_func_entry(nullptr) {} - ~Z3_func_entry_ref() override {} }; inline Z3_func_entry_ref * to_func_entry(Z3_func_entry s) { return reinterpret_cast(s); } diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 60d663638..7d8c00fbe 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -459,4 +459,33 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } +#if 0 + Z3_ast Z3_API Z3_mk_mpz_numeral(Z3_context c, bool sign, unsigned n, unsigned const nums[], Z3_sort* srt) { + LOG_TRY; + LOG_Z3_mk_mpz_numeral(c, sign, n, nums, srt); + RESET_ERROR_CODE(); + rational z; + + // todo fill in z + if (!z.size()) + z.neg(); + arith_util & a = mk_c(c)->autil(); + auto* a = mk_c(c)->mk_numeral_core(r, a.mk_int_sort()); + Z3_CATCH_RETURN(nullptr); + + } + + Z3_ast Z3_API Z3_mk_mpq_numeral1(Z3_context c, bool sign, unsigned n, unsigned const nums[], unsigned d, unsigned const dens[]) { + LOG_TRY; + LOG_Z3_mk_mpq_numeral(c, sign, n, nums, d, dens); + RESET_ERROR_CODE(); + rational q; + + if (!sign) + q.neg(); + + Z3_CATCH_RETURN(nullptr); + } +#endif + }; diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 6355642fc..3a1fe7af1 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -47,8 +47,6 @@ extern "C" { ctx->register_plist(); ctx->set_ignore_check(true); } - - ~Z3_parser_context_ref() override {} }; inline Z3_parser_context_ref * to_parser_context(Z3_parser_context pc) { return reinterpret_cast(pc); } diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index bf8a52d51..a56ca3d3c 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -36,7 +36,7 @@ Revision History: #include "smt/smt_implied_equalities.h" #include "solver/smt_logics.h" #include "solver/tactic2solver.h" -#include "solver/solver_params.hpp" +#include "params/solver_params.hpp" #include "cmd_context/cmd_context.h" #include "parsers/smt2/smt2parser.h" #include "sat/dimacs.h" diff --git a/src/api/api_solver.h b/src/api/api_solver.h index 5214d274c..71b7f9a46 100644 --- a/src/api/api_solver.h +++ b/src/api/api_solver.h @@ -51,7 +51,6 @@ struct Z3_solver_ref : public api::object { Z3_solver_ref(api::context& c, solver_factory * f): api::object(c), m_solver_factory(f), m_solver(nullptr), m_logic(symbol::null), m_eh(nullptr) {} - ~Z3_solver_ref() override {} void assert_expr(expr* e); void assert_expr(expr* e, expr* t); diff --git a/src/api/api_stats.h b/src/api/api_stats.h index 209daafdd..ff6eeeea2 100644 --- a/src/api/api_stats.h +++ b/src/api/api_stats.h @@ -23,7 +23,6 @@ Revision History: struct Z3_stats_ref : public api::object { statistics m_stats; Z3_stats_ref(api::context& c): api::object(c) {} - ~Z3_stats_ref() override {} }; inline Z3_stats_ref * to_stats(Z3_stats s) { return reinterpret_cast(s); } diff --git a/src/api/api_tactic.h b/src/api/api_tactic.h index a4d0f263e..91e2d76ab 100644 --- a/src/api/api_tactic.h +++ b/src/api/api_tactic.h @@ -28,13 +28,11 @@ namespace api { struct Z3_tactic_ref : public api::object { tactic_ref m_tactic; Z3_tactic_ref(api::context& c): api::object(c) {} - ~Z3_tactic_ref() override {} }; struct Z3_probe_ref : public api::object { probe_ref m_probe; Z3_probe_ref(api::context& c):api::object(c) {} - ~Z3_probe_ref() override {} }; inline Z3_tactic_ref * to_tactic(Z3_tactic g) { return reinterpret_cast(g); } @@ -50,7 +48,6 @@ struct Z3_apply_result_ref : public api::object { model_converter_ref m_mc; proof_converter_ref m_pc; Z3_apply_result_ref(api::context& c, ast_manager & m); - ~Z3_apply_result_ref() override {} }; inline Z3_apply_result_ref * to_apply_result(Z3_apply_result g) { return reinterpret_cast(g); } diff --git a/src/api/api_util.h b/src/api/api_util.h index 80f4f5ec7..0ff2c8ddd 100644 --- a/src/api/api_util.h +++ b/src/api/api_util.h @@ -40,7 +40,7 @@ namespace api { context& m_context; public: object(context& c); - virtual ~object() {} + virtual ~object() = default; unsigned ref_count() const { return m_ref_count; } unsigned id() const { return m_id; } void inc_ref(); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 8aaeb31ab..8d3a70b8b 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -23,7 +23,6 @@ Notes: #include #include #include -#include #include #include #include @@ -57,6 +56,8 @@ namespace z3 { class param_descrs; class ast; class sort; + class constructors; + class constructor_list; class func_decl; class expr; class solver; @@ -86,7 +87,7 @@ namespace z3 { class exception : public std::exception { std::string m_msg; public: - virtual ~exception() throw() {} + virtual ~exception() throw() = default; exception(char const * msg):m_msg(msg) {} char const * msg() const { return m_msg.c_str(); } char const * what() const throw() { return m_msg.c_str(); } @@ -313,6 +314,34 @@ namespace z3 { */ func_decl tuple_sort(char const * name, unsigned n, char const * const * names, sort const* sorts, func_decl_vector & projs); + + /** + \brief Create a recursive datatype over a single sort. + \c name is the name of the recursive datatype + \c n - the numer of constructors of the datatype + \c cs - the \c n constructors used to define the datatype + + References to the datatype can be created using \ref datatype_sort. + */ + sort datatype(symbol const& name, constructors const& cs); + + /** + \brief Create a set of mutually recursive datatypes. + \c n - number of recursive datatypes + \c names - array of names of length n + \c cons - array of constructor lists of length n + */ + sort_vector datatypes(unsigned n, symbol const* names, + constructor_list *const* cons); + + + /** + \brief a reference to a recursively defined datatype. + Expect that it gets defined as a \ref datatype. + */ + sort datatype_sort(symbol const& name); + + /** \brief create an uninterpreted sort with the name given by the string or symbol. */ @@ -3330,6 +3359,98 @@ namespace z3 { return func_decl(*this, tuple); } + class constructor_list { + context& ctx; + Z3_constructor_list clist; + public: + constructor_list(constructors const& cs); + ~constructor_list() { Z3_del_constructor_list(ctx, clist); } + operator Z3_constructor_list() const { return clist; } + }; + + class constructors { + friend class constructor_list; + context& ctx; + std::vector cons; + std::vector num_fields; + public: + constructors(context& ctx): ctx(ctx) {} + + ~constructors() { + for (auto con : cons) + Z3_del_constructor(ctx, con); + } + + void add(symbol const& name, symbol const& rec, unsigned n, symbol const* names, sort const* fields) { + array sort_refs(n); + array sorts(n); + array _names(n); + for (unsigned i = 0; i < n; ++i) sorts[i] = fields[i], _names[i] = names[i]; + cons.push_back(Z3_mk_constructor(ctx, name, rec, n, _names.ptr(), sorts.ptr(), sort_refs.ptr())); + num_fields.push_back(n); + } + + Z3_constructor operator[](unsigned i) const { return cons[i]; } + + unsigned size() const { return (unsigned)cons.size(); } + + void query(unsigned i, func_decl& constructor, func_decl& test, func_decl_vector& accs) { + Z3_func_decl _constructor; + Z3_func_decl _test; + array accessors(num_fields[i]); + accs.resize(0); + Z3_query_constructor(ctx, + cons[i], + num_fields[i], + &_constructor, + &_test, + accessors.ptr()); + constructor = func_decl(ctx, _constructor); + + test = func_decl(ctx, _test); + for (unsigned j = 0; j < num_fields[i]; ++j) + accs.push_back(func_decl(ctx, accessors[j])); + } + }; + + inline constructor_list::constructor_list(constructors const& cs): ctx(cs.ctx) { + array cons(cs.size()); + for (unsigned i = 0; i < cs.size(); ++i) + cons[i] = cs[i]; + clist = Z3_mk_constructor_list(ctx, cs.size(), cons.ptr()); + } + + inline sort context::datatype(symbol const& name, constructors const& cs) { + array _cs(cs.size()); + for (unsigned i = 0; i < cs.size(); ++i) _cs[i] = cs[i]; + Z3_sort s = Z3_mk_datatype(*this, name, cs.size(), _cs.ptr()); + check_error(); + return sort(*this, s); + } + + inline sort_vector context::datatypes( + unsigned n, symbol const* names, + constructor_list *const* cons) { + sort_vector result(*this); + array _names(n); + array _sorts(n); + array _cons(n); + for (unsigned i = 0; i < n; ++i) + _names[i] = names[i], _cons[i] = *cons[i]; + Z3_mk_datatypes(*this, n, _names.ptr(), _sorts.ptr(), _cons.ptr()); + for (unsigned i = 0; i < n; ++i) + result.push_back(sort(*this, _sorts[i])); + return result; + } + + + inline sort context::datatype_sort(symbol const& name) { + Z3_sort s = Z3_mk_datatype_sort(*this, name); + check_error(); + return sort(*this, s); + } + + inline sort context::uninterpreted_sort(char const* name) { Z3_symbol _name = Z3_mk_string_symbol(*this, name); return to_sort(*this, Z3_mk_uninterpreted_sort(*this, _name)); diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 1e9f598e7..82abfbf09 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -19,7 +19,7 @@ add_custom_command(OUTPUT "${Z3_DOTNET_NATIVE_FILE}" "${PROJECT_SOURCE_DIR}/scripts/update_api.py" ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} COMMENT "Generating ${Z3_DOTNET_NATIVE_FILE}" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL ) # Generate Enumerations.cs @@ -35,7 +35,7 @@ add_custom_command(OUTPUT "${Z3_DOTNET_CONST_FILE}" "${PROJECT_SOURCE_DIR}/scripts/mk_consts_files.py" ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} COMMENT "Generating ${Z3_DOTNET_CONST_FILE}" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL ) set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 764beb470..8896904dd 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -938,6 +938,15 @@ namespace Microsoft.Z3 return new BoolExpr(this, Native.Z3_mk_distinct(nCtx, (uint)args.Length, AST.ArrayToNative(args))); } + /// + /// Creates a distinct term. + /// + public BoolExpr MkDistinct(IEnumerable args) + { + Debug.Assert(args != null); + return MkDistinct(args.ToArray()); + } + /// /// Mk an expression representing not(a). /// diff --git a/src/api/java/CMakeLists.txt b/src/api/java/CMakeLists.txt index 695c946a3..e0d6bd0a0 100644 --- a/src/api/java/CMakeLists.txt +++ b/src/api/java/CMakeLists.txt @@ -29,10 +29,8 @@ add_custom_command(OUTPUT "${Z3_JAVA_NATIVE_JAVA}" "${Z3_JAVA_NATIVE_CPP}" ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} "${PROJECT_SOURCE_DIR}/scripts/update_api.py" ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} - # FIXME: When update_api.py no longer uses ``mk_util`` drop this dependency - "${PROJECT_SOURCE_DIR}/scripts/mk_util.py" COMMENT "Generating \"${Z3_JAVA_NATIVE_JAVA}\" and \"${Z3_JAVA_NATIVE_CPP}\"" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL ) # Add rule to build native code that provides a bridge between @@ -88,7 +86,7 @@ add_custom_command(OUTPUT ${Z3_JAVA_ENUMERATION_PACKAGE_FILES_FULL_PATH} "${PROJECT_SOURCE_DIR}/scripts/mk_consts_files.py" ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} COMMENT "Generating ${Z3_JAVA_PACKAGE_NAME}.enumerations package" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL ) set(Z3_JAVA_JAR_SOURCE_FILES diff --git a/src/api/js/PUBLISHED_README.md b/src/api/js/PUBLISHED_README.md index e4c385680..42d58a916 100644 --- a/src/api/js/PUBLISHED_README.md +++ b/src/api/js/PUBLISHED_README.md @@ -103,7 +103,7 @@ function rcf_get_numerator_denominator(c: Z3_context, a: Z3_rcf_num): { n: Z3_rc When there is only a single out parameter, and the return value is not otherwise of interest, the parameter is not wrapped. For example, the C declaration ```c -Z3_bool Z3_model_eval(Z3_context c, Z3_model m, Z3_ast t, bool model_completion, Z3_ast * v); +bool Z3_model_eval(Z3_context c, Z3_model m, Z3_ast t, bool model_completion, Z3_ast * v); ``` is represented in the TS bindings as diff --git a/src/api/js/scripts/parse-api.ts b/src/api/js/scripts/parse-api.ts index 3c8b37be0..cee61ca29 100644 --- a/src/api/js/scripts/parse-api.ts +++ b/src/api/js/scripts/parse-api.ts @@ -16,7 +16,6 @@ const files = [ const aliases = { __proto__: null, - Z3_bool: 'boolean', Z3_string: 'string', bool: 'boolean', signed: 'int', diff --git a/src/api/js/src/high-level/high-level.ts b/src/api/js/src/high-level/high-level.ts index 489d4acdb..a5e27429b 100644 --- a/src/api/js/src/high-level/high-level.ts +++ b/src/api/js/src/high-level/high-level.ts @@ -498,6 +498,15 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return result; } + /////////////////////////////// + // expression simplification // + /////////////////////////////// + + async function simplify(e : Expr) { + const result = await Z3.simplify(contextPtr, e.ast) + return _toExpr(check(result)); + } + ///////////// // Objects // ///////////// @@ -1050,6 +1059,10 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return check(Z3.model_to_string(contextPtr, this.ptr)); } + toString() { + return this.sexpr(); + } + eval(expr: Bool, modelCompletion?: boolean): Bool; eval(expr: Arith, modelCompletion?: boolean): Arith; eval(expr: Expr, modelCompletion: boolean = false) { diff --git a/src/api/js/src/jest.ts b/src/api/js/src/jest.ts index 2de6cdab1..9cbab31f1 100644 --- a/src/api/js/src/jest.ts +++ b/src/api/js/src/jest.ts @@ -3,7 +3,7 @@ // @ts-ignore no-implicit-any import { createApi, Z3HighLevel } from './high-level'; import { init as initWrapper, Z3LowLevel } from './low-level'; -import initModule = require('../z3-built'); +import initModule = require('../build/z3-built'); export * from './high-level/types'; export { Z3Core, Z3LowLevel } from './low-level'; diff --git a/src/api/julia/z3jl.cpp b/src/api/julia/z3jl.cpp index 73e4356b2..755911f6c 100644 --- a/src/api/julia/z3jl.cpp +++ b/src/api/julia/z3jl.cpp @@ -1,4 +1,5 @@ #include "jlcxx/jlcxx.hpp" +#include #include "z3++.h" using namespace z3; diff --git a/src/api/python/CMakeLists.txt b/src/api/python/CMakeLists.txt index 067a25e8c..f5e449ea8 100644 --- a/src/api/python/CMakeLists.txt +++ b/src/api/python/CMakeLists.txt @@ -43,7 +43,7 @@ add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/z3core.py" "${PROJECT_SOURCE_DIR}/scripts/update_api.py" ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} COMMENT "Generating z3core.py" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL ) list(APPEND build_z3_python_bindings_target_depends "${z3py_bindings_build_dest}/z3/z3core.py") @@ -59,7 +59,7 @@ add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/z3consts.py" "${PROJECT_SOURCE_DIR}/scripts/mk_consts_files.py" ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} COMMENT "Generating z3consts.py" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL ) list(APPEND build_z3_python_bindings_target_depends "${z3py_bindings_build_dest}/z3/z3consts.py") diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 572b0a7a7..f78963344 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -129,6 +129,15 @@ def _configure_z3(): for key, val in cmake_options.items(): if type(val) is bool: cmake_options[key] = str(val).upper() + + # Allow command-line arguments to add and override Z3_ options + for i in range(len(sys.argv) - 1): + key = sys.argv[i] + if key.startswith("Z3_"): + val = sys.argv[i + 1].upper() + if val == "TRUE" or val == "FALSE": + cmake_options[key] = val + cmake_args = [ '-D' + key + '=' + value for key,value in cmake_options.items() ] args = [ 'cmake', *cmake_args, SRC_DIR ] if subprocess.call(args, env=build_env, cwd=BUILD_DIR) != 0: diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 5d728e594..8f227649c 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -204,12 +204,13 @@ class Context: Z3_set_param_value(conf, str(prev), _to_param_value(a)) prev = None self.ctx = Z3_mk_context_rc(conf) + self.owner = True self.eh = Z3_set_error_handler(self.ctx, z3_error_handler) Z3_set_ast_print_mode(self.ctx, Z3_PRINT_SMTLIB2_COMPLIANT) Z3_del_config(conf) def __del__(self): - if Z3_del_context is not None: + if Z3_del_context is not None and self.owner: Z3_del_context(self.ctx) self.ctx = None self.eh = None @@ -5345,6 +5346,10 @@ class DatatypeRef(ExprRef): """Return the datatype sort of the datatype expression `self`.""" return DatatypeSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx) +def DatatypeSort(name, ctx = None): + """Create a reference to a sort that was declared, or will be declared, as a recursive datatype""" + ctx = _get_ctx(ctx) + return DatatypeSortRef(Z3_mk_datatype_sort(ctx.ref(), to_symbol(name, ctx)), ctx) def TupleSort(name, sorts, ctx=None): """Create a named tuple sort base on a set of underlying sorts @@ -11353,13 +11358,24 @@ def user_prop_pop(ctx, cb, num_scopes): prop.cb = cb prop.pop(num_scopes) +def to_ContextObj(ptr,): + ctx = ContextObj(ptr) + super(ctypes.c_void_p, ctx).__init__(ptr) + return ctx -def user_prop_fresh(id, ctx): + +def user_prop_fresh(ctx, _new_ctx): _prop_closures.set_threaded() - prop = _prop_closures.get(id) - new_prop = prop.fresh() + prop = _prop_closures.get(ctx) + nctx = Context() + Z3_del_context(nctx.ctx) + new_ctx = to_ContextObj(_new_ctx) + nctx.ctx = new_ctx + nctx.eh = Z3_set_error_handler(new_ctx, z3_error_handler) + nctx.owner = False + new_prop = prop.fresh(nctx) _prop_closures.set(new_prop.id, new_prop) - return ctypes.c_void_p(new_prop.id) + return new_prop.id def to_Ast(ptr,): ast = Ast(ptr) @@ -11374,6 +11390,13 @@ def user_prop_fixed(ctx, cb, id, value): prop.fixed(id, value) prop.cb = None +def user_prop_created(ctx, cb, id): + prop = _prop_closures.get(ctx) + prop.cb = cb + id = _to_expr_ref(to_Ast(id), prop.ctx()) + prop.created(id) + prop.cb = None + def user_prop_final(ctx, cb): prop = _prop_closures.get(ctx) prop.cb = cb @@ -11396,15 +11419,50 @@ def user_prop_diseq(ctx, cb, x, y): prop.diseq(x, y) prop.cb = None +# TODO The decision callback is not fully implemented. +# It needs to handle the ast*, unsigned* idx, and Z3_lbool* +def user_prop_decide(ctx, cb, t_ref, idx_ref, phase_ref): + prop = _prop_closures.get(ctx) + prop.cb = cb + t = _to_expr_ref(to_Ast(t_ref), prop.ctx()) + t, idx, phase = prop.decide(t, idx, phase) + t_ref = t + idx_ref = idx + phase_ref = phase + prop.cb = None + _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_created = Z3_created_eh(user_prop_created) _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) +_user_prop_decide = Z3_decide_eh(user_prop_decide) +def PropagateFunction(name, *sig): + """Create a function that gets tracked by user propagator. + Every term headed by this function symbol is tracked. + If a term is fixed and the fixed callback is registered a + callback is invoked that the term headed by this function is fixed. + """ + sig = _get_args(sig) + if z3_debug(): + _z3_assert(len(sig) > 0, "At least two arguments expected") + arity = len(sig) - 1 + rng = sig[arity] + if z3_debug(): + _z3_assert(is_sort(rng), "Z3 sort expected") + dom = (Sort * arity)() + for i in range(arity): + if z3_debug(): + _z3_assert(is_sort(sig[i]), "Z3 sort expected") + dom[i] = sig[i].ast + ctx = rng.ctx + return FuncDeclRef(Z3_solver_propagate_declare(ctx.ref(), to_symbol(name, ctx), arity, dom, rng.ast), ctx) + class UserPropagateBase: @@ -11420,19 +11478,16 @@ class UserPropagateBase: ensure_prop_closures() self.solver = s self._ctx = None + self.fresh_ctx = None self.cb = None self.id = _prop_closures.insert(self) self.fixed = None self.final = None self.eq = None self.diseq = None + self.created = None if ctx: - # TBD fresh is broken: ctx is not of the right type when we reach here. - self._ctx = Context() - #Z3_del_context(self._ctx.ctx) - #self._ctx.ctx = ctx - #self._ctx.eh = Z3_set_error_handler(ctx, z3_error_handler) - #Z3_set_ast_print_mode(ctx, Z3_PRINT_SMTLIB2_COMPLIANT) + self.fresh_ctx = ctx if s: Z3_solver_propagate_init(self.ctx_ref(), s.solver, @@ -11446,8 +11501,8 @@ class UserPropagateBase: self._ctx.ctx = None def ctx(self): - if self._ctx: - return self._ctx + if self.fresh_ctx: + return self.fresh_ctx else: return self.solver.ctx @@ -11457,41 +11512,69 @@ class UserPropagateBase: def add_fixed(self, fixed): assert not self.fixed assert not self._ctx - Z3_solver_propagate_fixed(self.ctx_ref(), self.solver.solver, _user_prop_fixed) + if self.solver: + Z3_solver_propagate_fixed(self.ctx_ref(), self.solver.solver, _user_prop_fixed) self.fixed = fixed + def add_created(self, created): + assert not self.created + assert not self._ctx + if self.solver: + Z3_solver_propagate_created(self.ctx_ref(), self.solver.solver, _user_prop_created) + self.created = created + def add_final(self, final): assert not self.final assert not self._ctx - Z3_solver_propagate_final(self.ctx_ref(), self.solver.solver, _user_prop_final) + if self.solver: + Z3_solver_propagate_final(self.ctx_ref(), self.solver.solver, _user_prop_final) self.final = final def add_eq(self, eq): assert not self.eq assert not self._ctx - Z3_solver_propagate_eq(self.ctx_ref(), self.solver.solver, _user_prop_eq) + if self.solver: + Z3_solver_propagate_eq(self.ctx_ref(), self.solver.solver, _user_prop_eq) self.eq = eq def add_diseq(self, diseq): assert not self.diseq assert not self._ctx - Z3_solver_propagate_diseq(self.ctx_ref(), self.solver.solver, _user_prop_diseq) + if self.solver: + Z3_solver_propagate_diseq(self.ctx_ref(), self.solver.solver, _user_prop_diseq) self.diseq = diseq + def add_decide(self, decide): + assert not self.decide + assert not self._ctx + if self.solver: + Z3_solver_propagate_decide(self.ctx_ref(), self.solver.solver, _user_prop_decide) + self.decide = decide + def push(self): raise Z3Exception("push needs to be overwritten") def pop(self, num_scopes): raise Z3Exception("pop needs to be overwritten") - def fresh(self): + def fresh(self, new_ctx): raise Z3Exception("fresh needs to be overwritten") def add(self, e): - assert self.solver assert not self._ctx - Z3_solver_propagate_register(self.ctx_ref(), self.solver.solver, e.ast) - + if self.solver: + Z3_solver_propagate_register(self.ctx_ref(), self.solver.solver, e.ast) + else: + Z3_solver_propagate_register_cb(self.ctx_ref(), ctypes.c_void_p(self.cb), e.ast) + + # + # Tell the solver to perform the next split on a given term + # If the term is a bit-vector the index idx specifies the index of the Boolean variable being + # split on. A phase of true = 1/false = -1/undef = 0 = let solver decide is the last argument. + # + def next_split(self, t, idx, phase): + Z3_solver_next_split(self.ctx_ref(), ctypes.c_void_p(self.cb), t.ast, idx, phase) + # # Propagation can only be invoked as during a fixed or final callback. # @@ -11503,5 +11586,5 @@ class UserPropagateBase: Z3_solver_propagate_consequence(e.ctx.ref(), ctypes.c_void_p( self.cb), num_fixed, _ids, num_eqs, _lhs, _rhs, e.ast) - def conflict(self, deps): - self.propagate(BoolVal(False, self.ctx()), deps, eqs=[]) + def conflict(self, deps = [], eqs = []): + self.propagate(BoolVal(False, self.ctx()), deps, eqs) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 2820205b9..9955f91be 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -75,11 +75,6 @@ DEFINE_TYPE(Z3_rcf_num); - \c Z3_stats: statistical data for a solver. */ -/** - \brief Z3 Boolean type. It is just an alias for \c bool. -*/ -typedef bool Z3_bool; - /** \brief Z3 string type. It is just an alias for \ccode{const char *}. */ @@ -87,16 +82,6 @@ typedef const char * Z3_string; typedef char const* Z3_char_ptr; typedef Z3_string * Z3_string_ptr; -/** - \brief True value. It is just an alias for \c true. -*/ -#define Z3_TRUE true - -/** - \brief False value. It is just an alias for \c false. -*/ -#define Z3_FALSE false - /** \brief Lifted Boolean type: \c false, \c undefined, \c true. */ @@ -1528,7 +1513,7 @@ extern "C" { def_API('Z3_global_param_get', BOOL, (_in(STRING), _out(STRING))) */ - Z3_bool Z3_API Z3_global_param_get(Z3_string param_id, Z3_string_ptr param_value); + bool Z3_API Z3_global_param_get(Z3_string param_id, Z3_string_ptr param_value); /**@}*/ @@ -3387,6 +3372,39 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_numeral(Z3_context c, Z3_string numeral, Z3_sort ty); +#if 0 + /** + \brief Create an integer numeral from a vector of unsigned numerals. + + \param c - context + \param sign - true if positive, false if negative + \param n - length of array of numerals + \param nums - array of numerals + \param s - sort of numeral (int, real, bit-vector). + + future_('Z3_mk_mpz_numeral', AST, (_in(CONTEXT), _in(BOOL), _in(UINT), _in_array(2, UINT), _in(SORT))) + */ + + Z3_ast Z3_mk_mpz_numeral(Z3_context c, bool sign, unsigned n, unsigned const nums[], Z3_sort s); + + /** + \brief Create a rational numeral from a vector of unsigned numerals. + + \param c - context + \param sign - true if positive, false if negative + \param n - length of array of nominator numerals + \param nums - array of numerator numerals + \param d - length of array of denominator numerals + \param dens - array of denominator numerals + + The sort of returned numeral is Real. + + future_('Z3_mk_mpq_numeral', AST, (_in(CONTEXT), _in(BOOL), _in(UINT), _in_array(2, UINT), _in(UINT), _in_array(4, UINT))) + */ + + Z3_ast Z3_mk_mpq_numeral(Z3_context c, bool sign, unsigned n, unsigned const nums[], unsigned d, unsigned const dens[]); +#endif + /** \brief Create a real from a fraction. @@ -4407,7 +4425,7 @@ extern "C" { def_API('Z3_get_finite_domain_sort_size', BOOL, (_in(CONTEXT), _in(SORT), _out(UINT64))) */ - Z3_bool Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, uint64_t* r); + bool Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, uint64_t* r); /** \brief Return the domain of the given array sort. @@ -4822,6 +4840,8 @@ extern "C" { \brief Return the number of argument of an application. If \c t is an constant, then the number of arguments is 0. + \sa Z3_get_app_arg + def_API('Z3_get_app_num_args', UINT, (_in(CONTEXT), _in(APP))) */ unsigned Z3_API Z3_get_app_num_args(Z3_context c, Z3_app a); @@ -4831,6 +4851,8 @@ extern "C" { \pre i < Z3_get_app_num_args(c, a) + \sa Z3_get_app_num_args + def_API('Z3_get_app_arg', AST, (_in(CONTEXT), _in(APP), _in(UINT))) */ Z3_ast Z3_API Z3_get_app_arg(Z3_context c, Z3_app a, unsigned i); @@ -5376,7 +5398,7 @@ extern "C" { def_API('Z3_model_eval', BOOL, (_in(CONTEXT), _in(MODEL), _in(AST), _in(BOOL), _out(AST))) */ - Z3_bool Z3_API Z3_model_eval(Z3_context c, Z3_model m, Z3_ast t, bool model_completion, Z3_ast * v); + bool Z3_API Z3_model_eval(Z3_context c, Z3_model m, Z3_ast t, bool model_completion, Z3_ast * v); /** \brief Return the interpretation (i.e., assignment) of constant \c a in the model \c m. @@ -5425,6 +5447,7 @@ extern "C" { \pre i < Z3_model_get_num_consts(c, m) \sa Z3_model_eval + \sa Z3_model_get_num_consts def_API('Z3_model_get_const_decl', FUNC_DECL, (_in(CONTEXT), _in(MODEL), _in(UINT))) */ @@ -5436,6 +5459,8 @@ extern "C" { A function interpretation is represented as a finite map and an 'else' value. Each entry in the finite map represents the value of a function given a set of arguments. + \sa Z3_model_get_func_decl + def_API('Z3_model_get_num_funcs', UINT, (_in(CONTEXT), _in(MODEL))) */ unsigned Z3_API Z3_model_get_num_funcs(Z3_context c, Z3_model m); @@ -5561,6 +5586,8 @@ extern "C" { Each entry in the finite map represents the value of a function given a set of arguments. This procedure return the number of element in the finite map of \c f. + \sa Z3_func_interp_get_entry + def_API('Z3_func_interp_get_num_entries', UINT, (_in(CONTEXT), _in(FUNC_INTERP))) */ unsigned Z3_API Z3_func_interp_get_num_entries(Z3_context c, Z3_func_interp f); @@ -5649,6 +5676,7 @@ extern "C" { /** \brief Return the number of arguments in a \c Z3_func_entry object. + \sa Z3_func_entry_get_arg \sa Z3_func_interp_get_entry def_API('Z3_func_entry_get_num_args', UINT, (_in(CONTEXT), _in(FUNC_ENTRY))) @@ -5660,6 +5688,7 @@ extern "C" { \pre i < Z3_func_entry_get_num_args(c, e) + \sa Z3_func_entry_get_num_args \sa Z3_func_interp_get_entry def_API('Z3_func_entry_get_arg', AST, (_in(CONTEXT), _in(FUNC_ENTRY), _in(UINT))) @@ -5672,6 +5701,9 @@ extern "C" { /** \brief Log interaction to a file. + \sa Z3_append_log + \sa Z3_close_log + extra_API('Z3_open_log', INT, (_in(STRING),)) */ bool Z3_API Z3_open_log(Z3_string filename); @@ -5679,10 +5711,13 @@ extern "C" { /** \brief Append user-defined string to interaction log. - The interaction log is opened using Z3_open_log. + The interaction log is opened using #Z3_open_log. It contains the formulas that are checked using Z3. You can use this command to append comments, for instance. + \sa Z3_open_log + \sa Z3_close_log + extra_API('Z3_append_log', VOID, (_in(STRING),)) */ void Z3_API Z3_append_log(Z3_string string); @@ -5690,6 +5725,9 @@ extern "C" { /** \brief Close interaction log. + \sa Z3_open_log + \sa Z3_append_log + extra_API('Z3_close_log', VOID, ()) */ void Z3_API Z3_close_log(void); @@ -6388,6 +6426,8 @@ extern "C" { /** \brief Return the number of builtin tactics available in Z3. + \sa Z3_get_tactic_name + def_API('Z3_get_num_tactics', UINT, (_in(CONTEXT),)) */ unsigned Z3_API Z3_get_num_tactics(Z3_context c); @@ -6397,6 +6437,8 @@ extern "C" { \pre i < Z3_get_num_tactics(c) + \sa Z3_get_num_tactics + def_API('Z3_get_tactic_name', STRING, (_in(CONTEXT), _in(UINT))) */ Z3_string Z3_API Z3_get_tactic_name(Z3_context c, unsigned i); @@ -6404,6 +6446,8 @@ extern "C" { /** \brief Return the number of builtin probes available in Z3. + \sa Z3_get_probe_name + def_API('Z3_get_num_probes', UINT, (_in(CONTEXT),)) */ unsigned Z3_API Z3_get_num_probes(Z3_context c); @@ -6413,6 +6457,8 @@ extern "C" { \pre i < Z3_get_num_probes(c) + \sa Z3_get_num_probes + def_API('Z3_get_probe_name', STRING, (_in(CONTEXT), _in(UINT))) */ Z3_string Z3_API Z3_get_probe_name(Z3_context c, unsigned i); @@ -6456,6 +6502,8 @@ extern "C" { /** \brief Apply tactic \c t to the goal \c g. + \sa Z3_tactic_apply_ex + def_API('Z3_tactic_apply', APPLY_RESULT, (_in(CONTEXT), _in(TACTIC), _in(GOAL))) */ Z3_apply_result Z3_API Z3_tactic_apply(Z3_context c, Z3_tactic t, Z3_goal g); @@ -6463,6 +6511,8 @@ extern "C" { /** \brief Apply tactic \c t to the goal \c g using the parameter set \c p. + \sa Z3_tactic_apply + def_API('Z3_tactic_apply_ex', APPLY_RESULT, (_in(CONTEXT), _in(TACTIC), _in(GOAL), _in(PARAMS))) */ Z3_apply_result Z3_API Z3_tactic_apply_ex(Z3_context c, Z3_tactic t, Z3_goal g, Z3_params p); @@ -6491,6 +6541,8 @@ extern "C" { /** \brief Return the number of subgoals in the \c Z3_apply_result object returned by #Z3_tactic_apply. + \sa Z3_apply_result_get_subgoal + def_API('Z3_apply_result_get_num_subgoals', UINT, (_in(CONTEXT), _in(APPLY_RESULT))) */ unsigned Z3_API Z3_apply_result_get_num_subgoals(Z3_context c, Z3_apply_result r); @@ -6500,6 +6552,8 @@ extern "C" { \pre i < Z3_apply_result_get_num_subgoals(c, r) + \sa Z3_apply_result_get_num_subgoals + def_API('Z3_apply_result_get_subgoal', GOAL, (_in(CONTEXT), _in(APPLY_RESULT), _in(UINT))) */ Z3_goal Z3_API Z3_apply_result_get_subgoal(Z3_context c, Z3_apply_result r, unsigned i); @@ -6542,6 +6596,10 @@ extern "C" { \remark User must use #Z3_solver_inc_ref and #Z3_solver_dec_ref to manage solver objects. Even if the context was created using #Z3_mk_context instead of #Z3_mk_context_rc. + \sa Z3_mk_simple_solver + \sa Z3_mk_solver_for_logic + \sa Z3_mk_solver_from_tactic + def_API('Z3_mk_solver', SOLVER, (_in(CONTEXT),)) */ Z3_solver Z3_API Z3_mk_solver(Z3_context c); @@ -6569,6 +6627,10 @@ extern "C" { \remark User must use #Z3_solver_inc_ref and #Z3_solver_dec_ref to manage solver objects. Even if the context was created using #Z3_mk_context instead of #Z3_mk_context_rc. + \sa Z3_mk_solver + \sa Z3_mk_solver_for_logic + \sa Z3_mk_solver_from_tactic + def_API('Z3_mk_simple_solver', SOLVER, (_in(CONTEXT),)) */ Z3_solver Z3_API Z3_mk_simple_solver(Z3_context c); @@ -6580,6 +6642,10 @@ extern "C" { \remark User must use #Z3_solver_inc_ref and #Z3_solver_dec_ref to manage solver objects. Even if the context was created using #Z3_mk_context instead of #Z3_mk_context_rc. + \sa Z3_mk_solver + \sa Z3_mk_simple_solver + \sa Z3_mk_solver_from_tactic + def_API('Z3_mk_solver_for_logic', SOLVER, (_in(CONTEXT), _in(SYMBOL))) */ Z3_solver Z3_API Z3_mk_solver_for_logic(Z3_context c, Z3_symbol logic); @@ -6592,6 +6658,10 @@ extern "C" { \remark User must use #Z3_solver_inc_ref and #Z3_solver_dec_ref to manage solver objects. Even if the context was created using #Z3_mk_context instead of #Z3_mk_context_rc. + \sa Z3_mk_solver + \sa Z3_mk_simple_solver + \sa Z3_mk_solver_for_logic + def_API('Z3_mk_solver_from_tactic', SOLVER, (_in(CONTEXT), _in(TACTIC))) */ Z3_solver Z3_API Z3_mk_solver_from_tactic(Z3_context c, Z3_tactic t); @@ -6899,7 +6969,7 @@ extern "C" { /** Create uninterpreted function declaration for the user propagator. When expressions using the function are created by the solver invoke a callback - to \ref \Z3_solver_propagate_created with arguments + to \ref Z3_solver_propagate_created with arguments 1. context and callback solve 2. declared_expr: expression using function that was used as the top-level symbol 3. declared_id: a unique identifier (unique within the current scope) to track the expression. diff --git a/src/api/z3_logger.h b/src/api/z3_logger.h index 646209575..2c95e18ca 100644 --- a/src/api/z3_logger.h +++ b/src/api/z3_logger.h @@ -16,6 +16,8 @@ Author: Notes: --*/ +#pragma once + #include "util/symbol.h" void R(); diff --git a/src/api/z3_macros.h b/src/api/z3_macros.h index 08756cf15..5f8659379 100644 --- a/src/api/z3_macros.h +++ b/src/api/z3_macros.h @@ -3,7 +3,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ - +#pragma once #ifndef Z3_API # ifdef __GNUC__ diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 51f380243..6fe2c7657 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -107,7 +107,6 @@ class array_decl_plugin : public decl_plugin { bool is_array_sort(sort* s) const; public: array_decl_plugin(); - ~array_decl_plugin() override {} decl_plugin * mk_fresh() override { return alloc(array_decl_plugin); diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 473bd82b5..c51ea4e32 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1429,7 +1429,7 @@ ast_manager::~ast_manager() { } m_plugins.reset(); while (!m_ast_table.empty()) { - DEBUG_CODE(IF_VERBOSE(0, verbose_stream() << "ast_manager LEAKED: " << m_ast_table.size() << std::endl);); + DEBUG_CODE(IF_VERBOSE(1, verbose_stream() << "ast_manager LEAKED: " << m_ast_table.size() << std::endl);); ptr_vector roots; ast_mark mark; for (ast * n : m_ast_table) { @@ -1465,22 +1465,21 @@ ast_manager::~ast_manager() { break; } } - for (ast * n : m_ast_table) { - if (!mark.is_marked(n)) { + for (ast * n : m_ast_table) + if (!mark.is_marked(n)) roots.push_back(n); - } - } + SASSERT(!roots.empty()); for (unsigned i = 0; i < roots.size(); ++i) { ast* a = roots[i]; DEBUG_CODE( - std::cout << "Leaked: "; - if (is_sort(a)) { - std::cout << to_sort(a)->get_name() << "\n"; - } - else { - std::cout << mk_ll_pp(a, *this, false) << "id: " << a->get_id() << "\n"; - }); + IF_VERBOSE(1, + verbose_stream() << "Leaked: "; + if (is_sort(a)) + verbose_stream() << to_sort(a)->get_name() << "\n"; + else + verbose_stream() << mk_ll_pp(a, *this, false) << "id: " << a->get_id() << "\n"; + );); a->m_ref_count = 0; delete_node(a); } diff --git a/src/ast/ast.h b/src/ast/ast.h index 798280d2c..d8eb072e3 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1024,7 +1024,7 @@ protected: friend class ast_manager; public: - virtual ~decl_plugin() {} + virtual ~decl_plugin() = default; virtual void finalize() {} @@ -2582,7 +2582,7 @@ class ast_mark { obj_mark m_expr_marks; obj_mark m_decl_marks; public: - virtual ~ast_mark() {} + virtual ~ast_mark() = default; bool is_marked(ast * n) const; virtual void mark(ast * n, bool flag); virtual void reset(); diff --git a/src/ast/ast_pp_util.cpp b/src/ast/ast_pp_util.cpp index 008a7cc9a..c895b8fe8 100644 --- a/src/ast/ast_pp_util.cpp +++ b/src/ast/ast_pp_util.cpp @@ -64,6 +64,17 @@ void ast_pp_util::display_decls(std::ostream& out) { m_rec_decls = n; } +void ast_pp_util::display_skolem_decls(std::ostream& out) { + ast_smt_pp pp(m); + unsigned n = coll.get_num_decls(); + 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) && f->is_skolem()) + ast_smt2_pp(out, f, m_env) << "\n"; + } + m_decls = n; +} + void ast_pp_util::remove_decl(func_decl* f) { m_removed.insert(f); } diff --git a/src/ast/ast_pp_util.h b/src/ast/ast_pp_util.h index 06ade7eed..6b5c5103e 100644 --- a/src/ast/ast_pp_util.h +++ b/src/ast/ast_pp_util.h @@ -50,6 +50,8 @@ class ast_pp_util { void display_decls(std::ostream& out); + void display_skolem_decls(std::ostream& out); + void display_asserts(std::ostream& out, expr_ref_vector const& fmls, bool neat = true); void display_assert(std::ostream& out, expr* f, bool neat = true); diff --git a/src/ast/ast_printer.cpp b/src/ast/ast_printer.cpp index 7f717df96..46f39ffde 100644 --- a/src/ast/ast_printer.cpp +++ b/src/ast/ast_printer.cpp @@ -26,7 +26,6 @@ class simple_ast_printer_context : public ast_printer_context { smt2_pp_environment_dbg & env() const { return *(m_env.get()); } public: simple_ast_printer_context(ast_manager & m):m_manager(m) { m_env = alloc(smt2_pp_environment_dbg, m); } - ~simple_ast_printer_context() override {} ast_manager & m() const { return m_manager; } ast_manager & get_ast_manager() override { return m_manager; } void display(std::ostream & out, sort * s, unsigned indent = 0) const override { out << mk_ismt2_pp(s, m(), indent); } diff --git a/src/ast/ast_printer.h b/src/ast/ast_printer.h index d57a9b845..bea01e826 100644 --- a/src/ast/ast_printer.h +++ b/src/ast/ast_printer.h @@ -24,7 +24,7 @@ Revision History: class ast_printer { public: - virtual ~ast_printer() {} + virtual ~ast_printer() = default; virtual void pp(sort * s, format_ns::format_ref & r) const { UNREACHABLE(); } virtual void pp(func_decl * f, format_ns::format_ref & r) const { UNREACHABLE(); } virtual void pp(expr * n, unsigned num_vars, char const * var_prefix, format_ns::format_ref & r, sbuffer & var_names) const { UNREACHABLE(); } @@ -45,7 +45,6 @@ public: class ast_printer_context : public ast_printer { public: - ~ast_printer_context() override {} virtual ast_manager & get_ast_manager() = 0; virtual std::ostream & regular_stream(); virtual std::ostream & diagnostic_stream(); diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index dbf9340ad..47649b9b2 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -46,7 +46,7 @@ protected: format_ns::format * pp_as(format_ns::format * fname, sort * s); format_ns::format * pp_signature(format_ns::format * f_name, func_decl * f); public: - virtual ~smt2_pp_environment() {} + virtual ~smt2_pp_environment() = default; virtual ast_manager & get_manager() const = 0; virtual arith_util & get_autil() = 0; virtual bv_util & get_bvutil() = 0; diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index 25c68819a..60efc73a9 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -241,7 +241,6 @@ protected: public: bv_decl_plugin(); - ~bv_decl_plugin() override {} void finalize() override; decl_plugin * mk_fresh() override { return alloc(bv_decl_plugin); } @@ -343,6 +342,14 @@ public: bool is_bv_not(expr const * e) const { return is_app_of(e, get_fid(), OP_BNOT); } bool is_bv_ule(expr const * e) const { return is_app_of(e, get_fid(), OP_ULEQ); } bool is_bv_sle(expr const * e) const { return is_app_of(e, get_fid(), OP_SLEQ); } + bool is_ule(expr const * e) const { return is_app_of(e, get_fid(), OP_ULEQ); } + bool is_sle(expr const * e) const { return is_app_of(e, get_fid(), OP_SLEQ); } + bool is_ult(expr const * e) const { return is_app_of(e, get_fid(), OP_ULT); } + bool is_slt(expr const * e) const { return is_app_of(e, get_fid(), OP_SLT); } + bool is_ugt(expr const * e) const { return is_app_of(e, get_fid(), OP_UGT); } + bool is_sgt(expr const * e) const { return is_app_of(e, get_fid(), OP_SGT); } + bool is_uge(expr const * e) const { return is_app_of(e, get_fid(), OP_UGEQ); } + bool is_sge(expr const * e) const { return is_app_of(e, get_fid(), OP_SGEQ); } bool is_bit2bool(expr const * e) const { return is_app_of(e, get_fid(), OP_BIT2BOOL); } bool is_bv2int(expr const* e) const { return is_app_of(e, get_fid(), OP_BV2INT); } bool is_int2bv(expr const* e) const { return is_app_of(e, get_fid(), OP_INT2BV); } @@ -356,9 +363,19 @@ public: MATCH_UNARY(is_bv_not); MATCH_BINARY(is_bv_add); + MATCH_BINARY(is_bv_sub); MATCH_BINARY(is_bv_mul); MATCH_BINARY(is_bv_sle); MATCH_BINARY(is_bv_ule); + MATCH_BINARY(is_ule); + MATCH_BINARY(is_sle); + MATCH_BINARY(is_ult); + MATCH_BINARY(is_slt); + MATCH_BINARY(is_uge); + MATCH_BINARY(is_sge); + MATCH_BINARY(is_ugt); + MATCH_BINARY(is_sgt); + MATCH_BINARY(is_bv_umul_no_ovfl); MATCH_BINARY(is_bv_ashr); MATCH_BINARY(is_bv_lshr); MATCH_BINARY(is_bv_shl); diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 0698bf821..310175781 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -105,7 +105,7 @@ namespace datatype { class size { unsigned m_ref{ 0 }; public: - virtual ~size() { } + virtual ~size() = default; void inc_ref() { ++m_ref; } void dec_ref(); static size* mk_offset(sort_size const& s); diff --git a/src/ast/dl_decl_plugin.h b/src/ast/dl_decl_plugin.h index 39cdbf835..c1cf08719 100644 --- a/src/ast/dl_decl_plugin.h +++ b/src/ast/dl_decl_plugin.h @@ -101,7 +101,6 @@ namespace datalog { public: dl_decl_plugin(); - ~dl_decl_plugin() override {} decl_plugin * mk_fresh() override { return alloc(dl_decl_plugin); } diff --git a/src/ast/expr_functors.h b/src/ast/expr_functors.h index 4e87fb39e..af669f48e 100644 --- a/src/ast/expr_functors.h +++ b/src/ast/expr_functors.h @@ -27,14 +27,14 @@ Revision History: class i_expr_pred { public: virtual bool operator()(expr* e) = 0; - virtual ~i_expr_pred() {} + virtual ~i_expr_pred() = default; }; class i_sort_pred { public: virtual bool operator()(sort* s) = 0; - virtual ~i_sort_pred() {} + virtual ~i_sort_pred() = default; }; diff --git a/src/ast/format.cpp b/src/ast/format.cpp index 4aeaf183d..a14d4b758 100644 --- a/src/ast/format.cpp +++ b/src/ast/format.cpp @@ -52,8 +52,6 @@ namespace format_ns { m_line_break_ext("cr++") { } - ~format_decl_plugin() override {} - void finalize() override { if (m_format_sort) m_manager->dec_ref(m_format_sort); diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index c541f72d0..597ab9ca6 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -326,12 +326,12 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * } 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); + func_decl_ref to_real_i(m.mk_func_decl(fid, OP_FPA_TO_REAL_I, 0, nullptr, 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); + func_decl_ref to_ieee_bv_i(m.mk_func_decl(fid, OP_FPA_TO_IEEE_BV_I, 0, nullptr, 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); } diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index d663fda95..19315129a 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -239,7 +239,6 @@ class fpa2bv_converter_wrapped : public fpa2bv_converter { fpa2bv_converter_wrapped(ast_manager & m, th_rewriter& rw) : fpa2bv_converter(m), m_rw(rw) {} - virtual ~fpa2bv_converter_wrapped() {} void mk_const(func_decl * f, expr_ref & result) override; void mk_rm_const(func_decl * f, expr_ref & result) override; app_ref wrap(expr * e); diff --git a/src/ast/macros/quantifier_macro_info.h b/src/ast/macros/quantifier_macro_info.h index 82790e937..646b31c88 100644 --- a/src/ast/macros/quantifier_macro_info.h +++ b/src/ast/macros/quantifier_macro_info.h @@ -39,7 +39,7 @@ protected: void collect_macro_candidates(quantifier* q); public: quantifier_macro_info(ast_manager& m, quantifier* q); - virtual ~quantifier_macro_info() {} + virtual ~quantifier_macro_info() = default; bool is_auf() const { return m_is_auf; } quantifier* get_flat_q() const { return m_flat_q; } bool has_cond_macros() const { return !m_cond_macros.empty(); } diff --git a/src/ast/normal_forms/elim_term_ite.h b/src/ast/normal_forms/elim_term_ite.h index 60f2ad8f7..36302ad1e 100644 --- a/src/ast/normal_forms/elim_term_ite.h +++ b/src/ast/normal_forms/elim_term_ite.h @@ -31,7 +31,7 @@ public: elim_term_ite_cfg(ast_manager & m, defined_names & d): m(m), m_defined_names(d) { // TBD enable_ac_support(false); } - virtual ~elim_term_ite_cfg() {} + virtual ~elim_term_ite_cfg() = default; vector const& new_defs() const { return m_new_defs; } br_status reduce_app(func_decl* f, unsigned n, expr *const* args, expr_ref& result, proof_ref& result_pr); void push() { m_lim.push_back(m_new_defs.size()); } diff --git a/src/ast/normal_forms/name_exprs.cpp b/src/ast/normal_forms/name_exprs.cpp index bb2543b3e..c500d92bd 100644 --- a/src/ast/normal_forms/name_exprs.cpp +++ b/src/ast/normal_forms/name_exprs.cpp @@ -77,9 +77,6 @@ public: m_rw(m, m.proofs_enabled(), m_cfg) { } - ~name_exprs_core() override { - } - void operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & p) override { m_cfg.m_def_exprs = &new_defs; m_cfg.m_def_proofs = &new_def_proofs; @@ -113,9 +110,6 @@ public: name_exprs_core(m, n, m_pred), m_pred(m) { } - - ~name_quantifier_labels() override { - } }; name_exprs * mk_quantifier_label_namer(ast_manager & m, defined_names & n) { @@ -145,9 +139,6 @@ public: m_pred(m) { } - ~name_nested_formulas() override { - } - void operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & p) override { m_pred.m_root = n; TRACE("name_exprs", tout << "operator()\n";); diff --git a/src/ast/normal_forms/name_exprs.h b/src/ast/normal_forms/name_exprs.h index 268df8821..4f652bce8 100644 --- a/src/ast/normal_forms/name_exprs.h +++ b/src/ast/normal_forms/name_exprs.h @@ -29,7 +29,7 @@ public: class name_exprs { public: - virtual ~name_exprs() {} + virtual ~name_exprs() = default; virtual void operator()(expr * n, // [IN] expression that contain the sub-expressions to be named expr_ref_vector & new_defs, // [OUT] new definitions proof_ref_vector & new_def_proofs, // [OUT] proofs of the new definitions diff --git a/src/ast/pattern/CMakeLists.txt b/src/ast/pattern/CMakeLists.txt index 8d0cf0cb4..7393b7110 100644 --- a/src/ast/pattern/CMakeLists.txt +++ b/src/ast/pattern/CMakeLists.txt @@ -15,7 +15,7 @@ add_custom_command(OUTPUT "database.h" DEPENDS "${PROJECT_SOURCE_DIR}/scripts/mk_pat_db.py" ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} COMMENT "Generating \"database.h\"" - ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} + USES_TERMINAL VERBATIM ) diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index 09f583df4..d751a1388 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -106,7 +106,7 @@ pattern_inference_cfg::pattern_inference_cfg(ast_manager & m, pattern_inference_ m_params(params), m_bfid(m.get_basic_family_id()), m_afid(m.mk_family_id("arith")), - m_le(m), + m_le(), m_nested_arith_only(true), m_block_loop_patterns(params.m_pi_block_loop_patterns), m_candidates(m), diff --git a/src/ast/pattern/pattern_inference.h b/src/ast/pattern/pattern_inference.h index d036ad789..bb4cf4238 100644 --- a/src/ast/pattern/pattern_inference.h +++ b/src/ast/pattern/pattern_inference.h @@ -37,7 +37,6 @@ Revision History: every instance of f(g(X)) is also an instance of f(X). */ class smaller_pattern { - ast_manager & m; ptr_vector m_bindings; typedef std::pair expr_pair; @@ -48,13 +47,11 @@ class smaller_pattern { void save(expr * p1, expr * p2); bool process(expr * p1, expr * p2); - smaller_pattern & operator=(smaller_pattern const &); - public: - smaller_pattern(ast_manager & m): - m(m) { - } + smaller_pattern() = default; + + smaller_pattern & operator=(smaller_pattern const &) = delete; bool operator()(unsigned num_bindings, expr * p1, expr * p2); }; diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index 372e7b06f..89f566263 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -52,7 +52,6 @@ class pb_decl_plugin : public decl_plugin { func_decl * mk_eq(unsigned arity, rational const* coeffs, int k); public: pb_decl_plugin(); - ~pb_decl_plugin() override {} sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override { UNREACHABLE(); diff --git a/src/ast/proofs/proof_checker.h b/src/ast/proofs/proof_checker.h index 27f872d25..591fb1157 100644 --- a/src/ast/proofs/proof_checker.h +++ b/src/ast/proofs/proof_checker.h @@ -52,8 +52,6 @@ class proof_checker { public: hyp_decl_plugin(); - ~hyp_decl_plugin() override {} - void finalize() override; decl_plugin * mk_fresh() override { return alloc(hyp_decl_plugin); } diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index bbc4e5810..dcff35e82 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -49,7 +49,7 @@ namespace recfun { class replace { public: - virtual ~replace() {} + virtual ~replace() = default; virtual void reset() = 0; virtual void insert(expr* d, expr* r) = 0; virtual expr_ref operator()(expr* e) = 0; diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 40e3e532f..dd0e7e869 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -86,12 +86,11 @@ br_status array_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c // l_true -- all equal // l_false -- at least one disequal // l_undef -- don't know -template lbool array_rewriter::compare_args(unsigned num_args, expr * const * args1, expr * const * args2) { for (unsigned i = 0; i < num_args; i++) { if (args1[i] == args2[i]) continue; - if (CHECK_DISEQ && m().are_distinct(args1[i], args2[i])) + if (m().are_distinct(args1[i], args2[i])) return l_false; return l_undef; } @@ -102,9 +101,7 @@ br_status array_rewriter::mk_store_core(unsigned num_args, expr * const * args, SASSERT(num_args >= 3); if (m_util.is_store(args[0])) { - lbool r = m_sort_store ? - compare_args(num_args - 2, args + 1, to_app(args[0])->get_args() + 1) : - compare_args(num_args - 2, args + 1, to_app(args[0])->get_args() + 1); + lbool r = compare_args(num_args - 2, args + 1, to_app(args[0])->get_args() + 1); switch (r) { case l_true: { // @@ -118,12 +115,11 @@ br_status array_rewriter::mk_store_core(unsigned num_args, expr * const * args, return BR_DONE; } case l_false: - SASSERT(m_sort_store); // // store(store(a,i,v),j,w) -> store(store(a,j,w),i,v) // if i, j are different, lt(i,j) - // - if (lex_lt(num_args-2, args+1, to_app(args[0])->get_args() + 1)) { + // + if (m_sort_store && lex_lt(num_args-2, args+1, to_app(args[0])->get_args() + 1)) { ptr_buffer new_args; new_args.push_back(to_app(args[0])->get_arg(0)); new_args.append(num_args-1, args+1); @@ -134,6 +130,9 @@ br_status array_rewriter::mk_store_core(unsigned num_args, expr * const * args, result = m().mk_app(get_fid(), OP_STORE, num_args, new_args.data()); return BR_REWRITE2; } + if (squash_store(num_args, args, result)) + return BR_REWRITE2; + break; case l_undef: break; @@ -155,7 +154,7 @@ br_status array_rewriter::mk_store_core(unsigned num_args, expr * const * args, // store(a, i, select(a, i)) --> a // if (m_util.is_select(v) && - compare_args(num_args-1, args, to_app(v)->get_args())) { + l_true == compare_args(num_args-1, args, to_app(v)->get_args())) { result = args[0]; return BR_DONE; } @@ -163,19 +162,52 @@ br_status array_rewriter::mk_store_core(unsigned num_args, expr * const * args, return BR_FAILED; } +bool array_rewriter::squash_store(unsigned n, expr* const* args, expr_ref& result) { + ptr_buffer parents, sargs; + expr* a = args[0]; + while (m_util.is_store(a)) { + lbool r = compare_args(n - 2, args + 1, to_app(a)->get_args() + 1); + switch (r) { + case l_undef: + return false; + case l_true: + result = to_app(a)->get_arg(0); + for (unsigned i = parents.size(); i-- > 0; ) { + expr* p = parents[i]; + sargs.reset(); + sargs.push_back(result); + for (unsigned j = 1; j < to_app(p)->get_num_args(); ++j) + sargs.push_back(to_app(p)->get_arg(j)); + result = m_util.mk_store(sargs.size(), sargs.data()); + } + sargs.reset(); + sargs.push_back(result); + for (unsigned j = 1; j < n; ++j) + sargs.push_back(args[j]); + result = m_util.mk_store(sargs.size(), sargs.data()); + return true; + case l_false: + parents.push_back(a); + a = to_app(a)->get_arg(0); + break; + } + } + return false; +} + 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])) { SASSERT(to_app(args[0])->get_num_args() == num_args+1); - switch (compare_args(num_args - 1, args+1, to_app(args[0])->get_args()+1)) { + switch (compare_args(num_args - 1, args+1, to_app(args[0])->get_args()+1)) { case l_true: // select(store(a, I, v), I) --> v 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) { + 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); } diff --git a/src/ast/rewriter/array_rewriter.h b/src/ast/rewriter/array_rewriter.h index 943cae4e5..4e52b237e 100644 --- a/src/ast/rewriter/array_rewriter.h +++ b/src/ast/rewriter/array_rewriter.h @@ -28,13 +28,13 @@ Notes: */ class array_rewriter { array_util m_util; - bool m_sort_store { false }; - bool m_blast_select_store { false }; - bool m_expand_select_store { false }; - bool m_expand_store_eq { false }; - bool m_expand_select_ite { false }; - bool m_expand_nested_stores { false }; - template + bool m_sort_store = false; + bool m_blast_select_store = false; + bool m_expand_select_store = false; + bool m_expand_store_eq = false; + bool m_expand_select_ite = false; + bool m_expand_nested_stores = false; + lbool compare_args(unsigned num_args, expr * const * args1, expr * const * args2); void mk_eq(expr* e, expr* lhs, expr* rhs, expr_ref_vector& fmls); @@ -45,6 +45,8 @@ class array_rewriter { bool is_expandable_store(expr* s); expr_ref expand_store(expr* s); + bool squash_store(unsigned n, expr* const* args, expr_ref& result); + public: array_rewriter(ast_manager & m, params_ref const & p = params_ref()): m_util(m) { 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 ae125a0ad..dc1df22a3 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -16,6 +16,8 @@ Author: Revision History: --*/ +#pragma once + #include "util/rational.h" #include "util/common_msgs.h" #include "ast/rewriter/bit_blaster/bit_blaster_tpl.h" diff --git a/src/ast/rewriter/elim_bounds.h b/src/ast/rewriter/elim_bounds.h index 378ac20cc..99d002f98 100644 --- a/src/ast/rewriter/elim_bounds.h +++ b/src/ast/rewriter/elim_bounds.h @@ -68,8 +68,6 @@ public: rewriter_tpl(m, m.proofs_enabled(), m_cfg), m_cfg(m) {} - - ~elim_bounds_rw() override {} }; diff --git a/src/ast/rewriter/expr_replacer.cpp b/src/ast/rewriter/expr_replacer.cpp index e822c1775..4fa83bed0 100644 --- a/src/ast/rewriter/expr_replacer.cpp +++ b/src/ast/rewriter/expr_replacer.cpp @@ -129,8 +129,6 @@ public: m_r(m, p) { } - ~th_rewriter2expr_replacer() override {} - ast_manager & m() const override { return m_r.m(); } void set_substitution(expr_substitution * s) override { m_r.set_substitution(s); } diff --git a/src/ast/rewriter/expr_replacer.h b/src/ast/rewriter/expr_replacer.h index e587faad7..82982adff 100644 --- a/src/ast/rewriter/expr_replacer.h +++ b/src/ast/rewriter/expr_replacer.h @@ -28,7 +28,7 @@ Notes: class expr_replacer { struct scoped_set_subst; public: - virtual ~expr_replacer() {} + virtual ~expr_replacer() = default; virtual ast_manager & m() const = 0; virtual void set_substitution(expr_substitution * s) = 0; diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index eb72ddd67..0a17fc375 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -16,6 +16,7 @@ Author: Notes: --*/ +#pragma once #include "util/container_util.h" #include "ast/rewriter/poly_rewriter.h" diff --git a/src/ast/rewriter/push_app_ite.h b/src/ast/rewriter/push_app_ite.h index a2e18dd25..67c48c7ae 100644 --- a/src/ast/rewriter/push_app_ite.h +++ b/src/ast/rewriter/push_app_ite.h @@ -49,7 +49,6 @@ protected: bool is_target(func_decl * decl, unsigned num_args, expr * const * args) override; public: ng_push_app_ite_cfg(ast_manager& m): push_app_ite_cfg(m) {} - virtual ~ng_push_app_ite_cfg() {} }; struct push_app_ite_rw : public rewriter_tpl { diff --git a/src/ast/rewriter/recfun_replace.h b/src/ast/rewriter/recfun_replace.h index 09ee3c60d..edc0283a8 100644 --- a/src/ast/rewriter/recfun_replace.h +++ b/src/ast/rewriter/recfun_replace.h @@ -32,7 +32,6 @@ class recfun_replace : public recfun::replace { expr_safe_replace m_replace; public: recfun_replace(ast_manager& m): m(m), m_replace(m) {} - ~recfun_replace() override {} void reset() override { m_replace.reset(); } void insert(expr* s, expr* t) override { m_replace.insert(s, t); } expr_ref operator()(expr* e) override { expr_ref r(m); m_replace(e, r); return r; } diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 4bf829be6..e9b9c316a 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -16,6 +16,8 @@ Author: Notes: --*/ +#pragma once + #include "ast/rewriter/rewriter.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_ll_pp.h" diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 4c7c3883a..cb00938d7 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -83,7 +83,7 @@ public: class expr_solver { public: - virtual ~expr_solver() {} + virtual ~expr_solver() = default; virtual lbool check_sat(expr* e) = 0; }; diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index bf377df43..54ef58e32 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -1107,6 +1107,31 @@ unsigned seq_util::rex::max_length(expr* r) const { return UINT_MAX; } +/** + \brief determine if \c n is a range regular expression where the lower and upper bounds + are given by single characters. + Range expressions where lower and upper bounds are not single characters are either + the empty language (when a bound is a string but not a single character) or symbolic + (when both bounds are not ground strings). The general is_range can be used to process + range expressions for these cases, but they don't correspond to mainstream regex usage. + */ +bool seq_util::rex::is_range(expr const* n, unsigned& lo, unsigned& hi) const { + expr* _lo, *_hi; + zstring los, his; + if (!is_range(n, _lo, _hi)) + return false; + if (!u.str.is_string(_lo, los)) + return false; + if (!u.str.is_string(_hi, his)) + return false; + if (los.length() != 1 || his.length() != 1) + return false; + lo = los[0]; + hi = his[0]; + return true; +} + + sort* seq_util::rex::to_seq(sort* re) { (void)u; SASSERT(u.is_re(re)); diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index b0c3ab3c6..30b4a9fb3 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -448,7 +448,7 @@ public: info() {} /* - Used for constructing either an invalid info that is only used to indicate uninitialzed entry, or valid but unknown info value. + Used for constructing either an invalid info that is only used to indicate uninitialized entry, or valid but unknown info value. */ info(lbool is_known) : known(is_known) {} @@ -545,6 +545,7 @@ public: bool is_plus(expr const* n) const { return is_app_of(n, m_fid, OP_RE_PLUS); } bool is_opt(expr const* n) const { return is_app_of(n, m_fid, OP_RE_OPTION); } bool is_range(expr const* n) const { return is_app_of(n, m_fid, OP_RE_RANGE); } + bool is_range(expr const* n, unsigned& lo, unsigned& hi) const; bool is_loop(expr const* n) const { return is_app_of(n, m_fid, OP_RE_LOOP); } bool is_empty(expr const* n) const { return is_app_of(n, m_fid, OP_RE_EMPTY_SET); } bool is_full_char(expr const* n) const { return is_app_of(n, m_fid, OP_RE_FULL_CHAR_SET); } diff --git a/src/ast/special_relations_decl_plugin.h b/src/ast/special_relations_decl_plugin.h index d804fa179..daff802e7 100644 --- a/src/ast/special_relations_decl_plugin.h +++ b/src/ast/special_relations_decl_plugin.h @@ -40,8 +40,6 @@ class special_relations_decl_plugin : public decl_plugin { public: special_relations_decl_plugin(); - ~special_relations_decl_plugin() override {} - decl_plugin * mk_fresh() override { return alloc(special_relations_decl_plugin); } diff --git a/src/ast/substitution/substitution_tree.h b/src/ast/substitution/substitution_tree.h index c94bb4eea..13993c171 100644 --- a/src/ast/substitution/substitution_tree.h +++ b/src/ast/substitution/substitution_tree.h @@ -29,7 +29,7 @@ protected: substitution & m_subst; public: st_visitor(substitution & s):m_subst(s) {} - virtual ~st_visitor() {} + virtual ~st_visitor() = default; substitution & get_substitution() { return m_subst; } virtual bool operator()(expr * e) { return true; } }; diff --git a/src/ast/value_generator.cpp b/src/ast/value_generator.cpp index ef21f2444..6e52afba3 100644 --- a/src/ast/value_generator.cpp +++ b/src/ast/value_generator.cpp @@ -99,7 +99,7 @@ public: datatype_value_generator(value_generator& g, ast_manager& m): m(m), g(g), dt(m), m_sorts(m) {} - ~datatype_value_generator() { + ~datatype_value_generator() override { for (auto& kv : m_values) dealloc(kv.m_value); } diff --git a/src/ast/value_generator.h b/src/ast/value_generator.h index 7b77b144e..f3a459389 100644 --- a/src/ast/value_generator.h +++ b/src/ast/value_generator.h @@ -23,7 +23,7 @@ class value_generator_core { public: - virtual ~value_generator_core() {} + virtual ~value_generator_core() = default; virtual family_id get_fid() const = 0; virtual expr_ref get_value(sort* s, unsigned index) = 0; }; diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index dc8836138..b17bc3641 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -379,8 +379,6 @@ public: m_int_real_coercions(":int-real-coercions"), m_reproducible_resource_limit(":reproducible-resource-limit") { } - ~set_get_option_cmd() override {} - }; class set_option_cmd : public set_get_option_cmd { diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 32dd6aee5..644bf5c7b 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -493,7 +493,6 @@ protected: public: pp_env(cmd_context & o):m_owner(o), m_autil(o.m()), m_bvutil(o.m()), m_arutil(o.m()), m_futil(o.m()), m_sutil(o.m()), m_dtutil(o.m()), m_dlutil(o.m()) {} - ~pp_env() override {} ast_manager & get_manager() const override { return m_owner.m(); } arith_util & get_autil() override { return m_autil; } bv_util & get_bvutil() override { return m_bvutil; } diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 3dc49624b..d54a90143 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -96,7 +96,7 @@ public: class object_ref { unsigned m_ref_count = 0; public: - virtual ~object_ref() {} + virtual ~object_ref() = default; virtual void finalize(cmd_context & ctx) = 0; void inc_ref(cmd_context & ctx) { m_ref_count++; diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 5a628ce58..c6f0b479a 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -377,8 +377,8 @@ public: }; class get_interpolant_cmd : public cmd { - expr* m_a; - expr* m_b; + scoped_ptr m_a; + scoped_ptr m_b; public: get_interpolant_cmd():cmd("get-interpolant") {} char const * get_usage() const override { return " "; } @@ -388,17 +388,24 @@ public: return CPK_EXPR; } void set_next_arg(cmd_context& ctx, expr * arg) override { - if (m_a == nullptr) - m_a = arg; + ast_manager& m = ctx.m(); + if (!m.is_bool(arg)) + throw default_exception("argument to interpolation is not Boolean"); + if (!m_a) + m_a = alloc(expr_ref, arg, m); else - m_b = arg; + m_b = alloc(expr_ref, arg, m); } void prepare(cmd_context & ctx) override { m_a = nullptr; m_b = nullptr; } void execute(cmd_context & ctx) override { ast_manager& m = ctx.m(); qe::interpolator mbi(m); + if (!m_a || !m_b) + throw default_exception("interpolation requires two arguments"); + if (!m.is_bool(*m_a) || !m.is_bool(*m_b)) + throw default_exception("interpolation requires two Boolean arguments"); expr_ref itp(m); - mbi.pogo(ctx.get_solver_factory(), m_a, m_b, itp); + mbi.pogo(ctx.get_solver_factory(), *m_a, *m_b, itp); ctx.regular_stream() << itp << "\n"; } }; diff --git a/src/cmd_context/extra_cmds/subpaving_cmds.h b/src/cmd_context/extra_cmds/subpaving_cmds.h index 33ed347b7..651d5b161 100644 --- a/src/cmd_context/extra_cmds/subpaving_cmds.h +++ b/src/cmd_context/extra_cmds/subpaving_cmds.h @@ -15,6 +15,7 @@ Author: Notes: --*/ +#pragma once class cmd_context; diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 1545487c7..b8dd01aea 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -147,7 +147,6 @@ class psort_sort : public psort { sort * get_sort() const { return m_sort; } sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override { return m_sort; } public: - ~psort_sort() override {} bool is_sort_wrapper() const override { return true; } char const * hcons_kind() const override { return "psort_sort"; } unsigned hcons_hash() const override { return m_sort->get_id(); } @@ -171,7 +170,6 @@ class psort_var : public psort { } size_t obj_size() const override { return sizeof(psort_var); } public: - ~psort_var() override {} char const * hcons_kind() const override { return "psort_var"; } unsigned hcons_hash() const override { return hash_u_u(m_num_params, m_idx); } bool hcons_eq(psort const * other) const override { @@ -233,7 +231,6 @@ class psort_app : public psort { } public: - ~psort_app() override {} char const * hcons_kind() const override { return "psort_app"; } unsigned hcons_hash() const override { return get_composite_hash(const_cast(this), m_args.size()); @@ -784,7 +781,7 @@ struct pdecl_manager::sort_info { m_decl(d) { m.inc_ref(d); } - virtual ~sort_info() {} + virtual ~sort_info() = default; virtual unsigned obj_size() const { return sizeof(sort_info); } virtual void finalize(pdecl_manager & m) { m.dec_ref(m_decl); } virtual void display(std::ostream & out, pdecl_manager const & m) const = 0; @@ -800,8 +797,6 @@ struct pdecl_manager::app_sort_info : public pdecl_manager::sort_info { m.m().inc_array_ref(n, s); } - ~app_sort_info() override {} - unsigned obj_size() const override { return sizeof(app_sort_info); } void finalize(pdecl_manager & m) override { @@ -843,8 +838,6 @@ struct pdecl_manager::indexed_sort_info : public pdecl_manager::sort_info { m_indices(n, s) { } - ~indexed_sort_info() override {} - unsigned obj_size() const override { return sizeof(indexed_sort_info); } void display(std::ostream & out, pdecl_manager const & m) const override { diff --git a/src/cmd_context/pdecl.h b/src/cmd_context/pdecl.h index 4f9c56825..a55f782f0 100644 --- a/src/cmd_context/pdecl.h +++ b/src/cmd_context/pdecl.h @@ -38,7 +38,7 @@ protected: virtual size_t obj_size() const { UNREACHABLE(); return sizeof(*this); } pdecl(unsigned id, unsigned num_params):m_id(id), m_num_params(num_params), m_ref_count(0) {} virtual void finalize(pdecl_manager & m) {} - virtual ~pdecl() {} + virtual ~pdecl() = default; public: virtual bool check_num_params(pdecl * other) const { return m_num_params == other->m_num_params; } unsigned get_num_params() const { return m_num_params; } @@ -66,7 +66,6 @@ protected: psort(unsigned id, unsigned num_params):pdecl(id, num_params), m_inst_cache(nullptr) {} bool is_psort() const override { return true; } void finalize(pdecl_manager & m) override; - ~psort() override {} virtual void cache(pdecl_manager & m, sort * const * s, sort * r); virtual sort * find(sort * const * s) const; public: @@ -98,7 +97,6 @@ protected: sort * find(sort * const * s); psort_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n); void finalize(pdecl_manager & m) override; - ~psort_decl() override {} public: virtual sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) = 0; virtual sort * instantiate(pdecl_manager & m, unsigned n, unsigned const * s) { return nullptr; } @@ -120,7 +118,6 @@ protected: psort_user_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, psort * p); size_t obj_size() const override { return sizeof(psort_user_decl); } void finalize(pdecl_manager & m) override; - ~psort_user_decl() override {} public: sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; std::ostream& display(std::ostream & out) const override; @@ -133,7 +130,6 @@ protected: decl_kind m_kind; psort_builtin_decl(unsigned id, pdecl_manager & m, symbol const & n, family_id fid, decl_kind k); size_t obj_size() const override { return sizeof(psort_builtin_decl); } - ~psort_builtin_decl() override {} public: sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; sort * instantiate(pdecl_manager & m, unsigned n, unsigned const * s) override; @@ -145,7 +141,6 @@ protected: friend class pdecl_manager; psort_dt_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n); size_t obj_size() const override { return sizeof(psort_dt_decl); } - ~psort_dt_decl() override {} public: sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; std::ostream& display(std::ostream & out) const override; @@ -196,7 +191,6 @@ class paccessor_decl : public pdecl { accessor_decl * instantiate_decl(pdecl_manager & m, unsigned n, sort * const * s); symbol const & get_name() const { return m_name; } ptype const & get_type() const { return m_type; } - ~paccessor_decl() override {} public: std::ostream& display(std::ostream & out) const override { pdecl::display(out); return out; } void display(std::ostream & out, pdatatype_decl const * const * dts) const; @@ -217,7 +211,6 @@ class pconstructor_decl : public pdecl { symbol const & get_name() const { return m_name; } symbol const & get_recognizer_name() const { return m_recogniser_name; } constructor_decl * instantiate_decl(pdecl_manager & m, unsigned n, sort * const * s); - ~pconstructor_decl() override {} public: std::ostream& display(std::ostream & out) const override { pdecl::display(out); return out; } void display(std::ostream & out, pdatatype_decl const * const * dts) const; @@ -234,7 +227,6 @@ class pdatatype_decl : public psort_decl { size_t obj_size() const override { return sizeof(pdatatype_decl); } bool fix_missing_refs(dictionary const & symbol2idx, symbol & missing); datatype_decl * instantiate_decl(pdecl_manager & m, unsigned n, sort * const * s); - ~pdatatype_decl() override {} public: sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; std::ostream& display(std::ostream & out) const override; @@ -255,7 +247,6 @@ class pdatatypes_decl : public pdecl { size_t obj_size() const override { return sizeof(pdatatypes_decl); } bool fix_missing_refs(symbol & missing); bool instantiate(pdecl_manager & m, sort * const * s); - ~pdatatypes_decl() override {} public: pdatatype_decl const * const * children() const { return m_datatypes.data(); } pdatatype_decl * const * begin() const { return m_datatypes.begin(); } @@ -266,7 +257,7 @@ public: class new_datatype_eh { public: - virtual ~new_datatype_eh() {} + virtual ~new_datatype_eh() = default; virtual void operator()(sort * dt, pdecl* pd) = 0; }; diff --git a/src/cmd_context/simplify_cmd.cpp b/src/cmd_context/simplify_cmd.cpp index 0c389a78a..d5200374c 100644 --- a/src/cmd_context/simplify_cmd.cpp +++ b/src/cmd_context/simplify_cmd.cpp @@ -46,10 +46,7 @@ public: p.insert("print_proofs", CPK_BOOL, "(default: false) print a proof showing the original term is equal to the resultant one."); p.insert("print_statistics", CPK_BOOL, "(default: false) print statistics."); } - - ~simplify_cmd() override { - } - + void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); m_target = nullptr; diff --git a/src/math/automata/boolean_algebra.h b/src/math/automata/boolean_algebra.h index 4bd80af4b..a642ceb41 100644 --- a/src/math/automata/boolean_algebra.h +++ b/src/math/automata/boolean_algebra.h @@ -25,7 +25,7 @@ Revision History: template class positive_boolean_algebra { public: - virtual ~positive_boolean_algebra() {} + virtual ~positive_boolean_algebra() = default; virtual T mk_false() = 0; virtual T mk_true() = 0; virtual T mk_and(T x, T y) = 0; @@ -38,7 +38,6 @@ public: template class boolean_algebra : public positive_boolean_algebra { public: - ~boolean_algebra() override {} virtual T mk_not(T x) = 0; }; diff --git a/src/math/dd/CMakeLists.txt b/src/math/dd/CMakeLists.txt index ac9d28b0d..3f25a8406 100644 --- a/src/math/dd/CMakeLists.txt +++ b/src/math/dd/CMakeLists.txt @@ -1,6 +1,7 @@ z3_add_component(dd SOURCES dd_bdd.cpp + dd_fdd.cpp dd_pdd.cpp COMPONENT_DEPENDENCIES util diff --git a/src/math/dd/dd_bdd.cpp b/src/math/dd/dd_bdd.cpp index 86f2b9408..ee0f1600c 100644 --- a/src/math/dd/dd_bdd.cpp +++ b/src/math/dd/dd_bdd.cpp @@ -142,6 +142,8 @@ namespace dd { if (a == b) return false_bdd; if (is_false(a)) return b; if (is_false(b)) return a; + if (is_true(a)) return mk_not_rec(b); + if (is_true(b)) return mk_not_rec(a); break; default: UNREACHABLE(); @@ -571,7 +573,63 @@ namespace dd { e1->m_result = r; return r; } + + /** + * co-factor a using b. + * b must be a variable bdd (it can be generalized to a cube) + */ + + bdd bdd_manager::mk_cofactor(bdd const& a, bdd const& b) { + bool first = true; + scoped_push _sp(*this); + SASSERT(!b.is_const() && b.lo().is_const() && b.hi().is_const()); + while (true) { + try { + return bdd(mk_cofactor_rec(a.root, b.root), this); + } + catch (const mem_out &) { + if (!first) throw; + try_reorder(); + first = false; + } + } + } + + bdd_manager::BDD bdd_manager::mk_cofactor_rec(BDD a, BDD b) { + if (is_const(a)) return a; + if (is_const(b)) return a; + unsigned la = level(a), lb = level(b); + // cases where b is a single literal + if (la == lb && is_const(lo(b)) && is_const(hi(b))) + return is_true(hi(b)) ? hi(a) : lo(a); + if (la < lb && is_const(lo(b)) && is_const(hi(b))) + return a; + // cases where b is a proper cube (with more than one literal + if (la == lb) { + if (is_false(lo(b))) + a = hi(a), b = hi(b); + else + a = lo(a), b = lo(b); + return mk_cofactor_rec(a, b); + } + if (la < lb) + return mk_cofactor_rec(a, is_false(lo(b)) ? hi(b) : lo(b)); + + op_entry* e1 = pop_entry(a, b, bdd_cofactor_op); + op_entry const* e2 = m_op_cache.insert_if_not_there(e1); + if (check_result(e1, e2, a, b, bdd_cofactor_op)) + return e2->m_result; + + SASSERT(la > lb); + push(mk_cofactor_rec(lo(a), b)); + push(mk_cofactor_rec(hi(a), b)); + BDD r = make_node(la, read(2), read(1)); + pop(2); + e1->m_result = r; + return r; + } + bdd bdd_manager::mk_ite(bdd const& c, bdd const& t, bdd const& e) { bool first = true; scoped_push _sp(*this); @@ -587,14 +645,15 @@ namespace dd { } } + bdd_manager::BDD bdd_manager::mk_ite_rec(BDD a, BDD b, BDD c) { if (is_true(a)) return b; if (is_false(a)) return c; if (b == c) return b; - if (is_true(b)) return apply(a, c, bdd_or_op); - if (is_false(c)) return apply(a, b, bdd_and_op); - if (is_false(b)) return apply(mk_not_rec(a), c, bdd_and_op); - if (is_true(c)) return apply(mk_not_rec(a), b, bdd_or_op); + if (is_true(b)) return apply_rec(a, c, bdd_or_op); + if (is_false(c)) return apply_rec(a, b, bdd_and_op); + if (is_false(b)) return apply_rec(mk_not_rec(a), c, bdd_and_op); + if (is_true(c)) return apply_rec(mk_not_rec(a), b, bdd_or_op); SASSERT(!is_const(a) && !is_const(b) && !is_const(c)); op_entry * e1 = pop_entry(a, b, c); op_entry const* e2 = m_op_cache.insert_if_not_there(e1); @@ -644,6 +703,7 @@ namespace dd { bdd_manager::BDD bdd_manager::mk_quant(unsigned n, unsigned const* vars, BDD b, bdd_op op) { BDD result = b; + // TODO: should this method catch mem_out like the other non-rec mk_ methods? for (unsigned i = 0; i < n; ++i) { result = mk_quant_rec(m_var2level[vars[i]], result, op); } @@ -895,4 +955,299 @@ namespace dd { bdd& bdd::operator=(bdd const& other) { unsigned r1 = root; root = other.root; m->inc_ref(root); m->dec_ref(r1); return *this; } std::ostream& operator<<(std::ostream& out, bdd const& b) { return b.display(out); } + + bdd bdd_manager::mk_eq(bddv const& a, bddv const& b) { + SASSERT(a.size() == b.size()); + bdd eq = mk_true(); + for (unsigned i = 0; i < a.size(); ++i) + eq &= !(a[i] ^ b[i]); + return eq; + } + + bdd bdd_manager::mk_eq(bddv const& a, rational const& n) { + SASSERT(n.is_int() && n >= 0 && n < rational(2).expt(a.size())); + bdd b = mk_true(); + for (unsigned i = 0; i < a.size(); ++i) + b &= n.get_bit(i) ? a[i] : !a[i]; + return b; + } + + bdd bdd_manager::mk_eq(unsigned_vector const& vars, rational const& n) { + SASSERT(n.is_int() && n >= 0 && n < rational(2).expt(vars.size())); + bdd b = mk_true(); + for (unsigned i = 0; i < vars.size(); ++i) + b &= n.get_bit(i) ? mk_var(vars[i]) : mk_nvar(vars[i]); + return b; + } + + bdd bdd_manager::mk_ule(bddv const& a, bddv const& b) { + SASSERT(a.size() == b.size()); + bdd lt = mk_false(); + bdd eq = mk_true(); + for (unsigned i = a.size(); i-- > 0 && !eq.is_false(); ) { + lt |= eq && (!a[i] && b[i]); + eq &= !(a[i] ^ b[i]); + } + return lt || eq; + } + bdd bdd_manager::mk_uge(bddv const& a, bddv const& b) { return mk_ule(b, a); } + bdd bdd_manager::mk_ult(bddv const& a, bddv const& b) { return mk_ule(a, b) && !mk_eq(a, b); } + bdd bdd_manager::mk_ugt(bddv const& a, bddv const& b) { return mk_ult(b, a); } + + bdd bdd_manager::mk_sle(bddv const& a, bddv const& b) { + SASSERT(a.size() == b.size()); + // Note: sle can be reduced to ule by flipping the sign bits of both arguments + bdd lt = mk_false(); + bdd eq = mk_true(); + unsigned const sz = a.size(); + if (sz > 0) { + lt = a[sz - 1] && !b[sz - 1]; + eq = !(a[sz - 1] ^ b[sz - 1]); + for (unsigned i = sz - 1; i-- > 0; ) { + lt |= eq && (!a[i] && b[i]); + eq &= !(a[i] ^ b[i]); + } + } + return lt || eq; + } + bdd bdd_manager::mk_sge(bddv const& a, bddv const& b) { return mk_sle(b, a); } + bdd bdd_manager::mk_slt(bddv const& a, bddv const& b) { return mk_sle(a, b) && !mk_eq(a, b); } + bdd bdd_manager::mk_sgt(bddv const& a, bddv const& b) { return mk_slt(b, a); } + + bddv bdd_manager::mk_add(bddv const& a, bddv const& b) { + SASSERT(a.size() == b.size()); + bdd carry = mk_false(); + bddv result(this); +#if 0 + for (unsigned i = 0; i < a.size(); ++i) { + result.push_back(carry ^ a[i] ^ b[i]); + carry = (carry && a[i]) || (carry && b[i]) || (a[i] && b[i]); + } +#else + if (a.size() > 0) + result.push_back(a[0] ^ b[0]); + for (unsigned i = 1; i < a.size(); ++i) { + carry = (carry && a[i-1]) || (carry && b[i-1]) || (a[i-1] && b[i-1]); + result.push_back(carry ^ a[i] ^ b[i]); + } +#endif + return result; + } + + bddv bdd_manager::mk_add(bddv const& a, std::function& b) { + bdd carry = mk_false(); + bddv result(this); + if (a.size() > 0) + result.push_back(a[0] ^ b(0)); + for (unsigned i = 1; i < a.size(); ++i) { + auto bi1 = b(i-1); + carry = (carry && a[i-1]) || (carry && bi1) || (a[i-1] && bi1); + result.push_back(carry ^ a[i] ^ b(i)); + } + return result; + } + + + bddv bdd_manager::mk_sub(bddv const& a, bddv const& b) { + SASSERT(a.size() == b.size()); + bdd carry = mk_false(); + bddv result(this); + if (a.size() > 0) + result.push_back(a[0] ^ b[0]); + for (unsigned i = 1; i < a.size(); ++i) { + // carry = (a[i-1] && b[i-1] && carry) || (!a[i-1] && (b[i-1] || carry)); + carry = mk_ite(a[i-1], b[i-1] && carry, b[i-1] || carry); + result.push_back(carry ^ a[i] ^ b[i]); + } + return result; + } + + bddv bdd_manager::mk_usub(bddv const& a) { + bddv result(this); + bdd carry = mk_false(); + result.push_back(a[0]); + for (unsigned i = 1; i < a.size(); ++i) { + carry = a[i-1] || carry; + result.push_back(carry ^ a[i]); + } + return result; + } + + bool_vector bdd_manager::mk_usub(bool_vector const& b) { + bool_vector result; + if (b.empty()) + return result; + bool carry = false; + result.push_back(b[0]); + for (unsigned i = 1; i < b.size(); ++i) { + carry = carry || b[i-1]; + result.push_back(carry ^ b[i]); + } + return result; + } + + + bddv bdd_manager::mk_mul(bddv const& a, bddv const& b) { + SASSERT(a.size() == b.size()); + bddv result = mk_zero(a.size()); + for (unsigned i = 0; i < b.size(); ++i) { + std::function get_a = [&](unsigned k) { + if (k < i) + return mk_false(); + else + return a[k - i] && b[i]; + }; + result = mk_add(result, get_a); + } + return result; + } + + bddv bdd_manager::mk_mul(bddv const& a, rational const& val) { + SASSERT(val.is_int() && val >= 0 && val < rational::power_of_two(a.size())); + bool_vector b; + for (unsigned i = 0; i < a.size(); ++i) + b.push_back(val.get_bit(i)); + return mk_mul(a, b); + } + + bddv bdd_manager::mk_mul(bddv const& a, bool_vector const& b) { + SASSERT(a.size() == b.size()); + bddv result = mk_zero(a.size()); + + // use identity (bvmul a b) == (bvneg (bvmul (bvneg a) b)) + unsigned cnt = 0; + for (auto v : b) if (v) cnt++; + if (cnt*2 > b.size()+1) + return mk_usub(mk_mul(a, mk_usub(b))); + + for (unsigned i = 0; i < a.size(); ++i) { + std::function get_a = [&](unsigned k) { + if (k < i) + return mk_false(); + else + return a[k - i]; + }; + if (b[i]) + result = mk_add(result, get_a); + } + return result; + } + + bddv bdd_manager::mk_concat(bddv const& a, bddv const& b) { + bddv result = a; + result.m_bits.append(b.m_bits); + return result; + } + + + /** + * Quotient remainder + * + * rem, div have size 2*|a| = worksize. + * Initialization: + * rem := a ++ false + * div := false ++ b + */ + void bdd_manager::mk_quot_rem(bddv const& a, bddv const& b, bddv& quot, bddv& rem) { + SASSERT(a.size() == b.size()); + quot = mk_zero(a.size()); + unsigned worksize = a.size() + b.size(); + rem = a.append(mk_zero(b.size())); + bddv div = mk_zero(a.size()).append(b); + // + // Keep shifting divisor to the right and subtract whenever it is + // smaller than the remaining value + // + for (unsigned i = 0; i <= b.size(); ++i) { + bdd divLteRem = div <= rem; + bddv remSubDiv = rem - div; + + for (unsigned j = 0; j < worksize; ++j) + rem[j] = mk_ite(divLteRem, remSubDiv[j], rem[j]); + + if (i > 0) + quot[b.size() - i] = divLteRem; + + div.shr(); + } + rem.m_bits.shrink(b.size()); + } + + bddv bdd_manager::mk_num(rational const& n, unsigned num_bits) { + SASSERT(n.is_int() && n >= 0 && n < rational::power_of_two(num_bits)); + bddv result(this); + for (unsigned i = 0; i < num_bits; ++i) + result.push_back(n.get_bit(i) ? mk_true() : mk_false()); + return result; + } + + bddv bdd_manager::mk_ones(unsigned num_bits) { + bddv result(this); + for (unsigned i = 0; i < num_bits; ++i) + result.push_back(mk_true()); + return result; + } + + bddv bdd_manager::mk_zero(unsigned num_bits) { + bddv result(this); + for (unsigned i = 0; i < num_bits; ++i) + result.push_back(mk_false()); + return result; + } + + bddv bdd_manager::mk_var(unsigned num_bits, unsigned const* vars) { + bddv result(this); + for (unsigned i = 0; i < num_bits; ++i) + result.push_back(mk_var(vars[i])); + return result; + } + + bddv bdd_manager::mk_var(unsigned_vector const& vars) { + return mk_var(vars.size(), vars.data()); + } + + bool bdd_manager::is_constv(bddv const& a) { + for (bdd const& bit : a.bits()) + if (!is_const(bit.root)) + return false; + return true; + } + + rational bdd_manager::to_val(bddv const& a) { + rational result = rational::zero(); + for (unsigned i = 0; i < a.size(); ++i) { + bdd const &bit = a[i]; + SASSERT(is_const(bit.root)); + if (bit.is_true()) + result += rational::power_of_two(i); + } + return result; + } + + void bddv::shl() { + for (unsigned j = size(); j-- > 1;) + m_bits[j] = m_bits[j - 1]; + m_bits[0] = m->mk_false(); + } + + void bddv::shr() { + for (unsigned j = 1; j < size(); ++j) + m_bits[j - 1] = m_bits[j]; + m_bits[size() - 1] = m->mk_false(); + } + + bdd bddv::all0() const { + bdd r = m->mk_true(); + for (unsigned i = 0; i < size() && !r.is_false(); ++i) + r &= !m_bits[i]; + return r; + } + + bdd bddv::all1() const { + bdd r = m->mk_true(); + for (unsigned i = 0; i < size() && !r.is_false(); ++i) + r &= m_bits[i]; + return r; + } + } diff --git a/src/math/dd/dd_bdd.h b/src/math/dd/dd_bdd.h index 1892c5317..109f3dc19 100644 --- a/src/math/dd/dd_bdd.h +++ b/src/math/dd/dd_bdd.h @@ -21,13 +21,18 @@ Revision History: #include "util/vector.h" #include "util/map.h" #include "util/small_object_allocator.h" +#include "util/rational.h" namespace dd { class bdd; + class bddv; + class test_bdd; class bdd_manager { friend bdd; + friend bddv; + friend test_bdd; typedef unsigned BDD; @@ -40,7 +45,8 @@ namespace dd { bdd_not_op = 5, bdd_and_proj_op = 6, bdd_or_proj_op = 7, - bdd_no_op = 8, + bdd_cofactor_op = 8, + bdd_no_op = 9, }; struct bdd_node { @@ -141,6 +147,7 @@ namespace dd { BDD mk_not_rec(BDD b); BDD mk_ite_rec(BDD a, BDD b, BDD c); BDD mk_quant_rec(unsigned lvl, BDD b, bdd_op op); + BDD mk_cofactor_rec(BDD a, BDD b); void push(BDD b); void pop(unsigned num_scopes); @@ -188,6 +195,7 @@ namespace dd { bdd mk_and(bdd const& a, bdd const& b); bdd mk_or(bdd const& a, bdd const& b); bdd mk_xor(bdd const& a, bdd const& b); + bdd mk_cofactor(bdd const& a, bdd const& b); void reserve_var(unsigned v); bool well_formed(); @@ -199,10 +207,13 @@ namespace dd { ~scoped_push() { m.m_bdd_stack.shrink(m_size); } }; + bool_vector mk_usub(bool_vector const& b); + + public: struct mem_out {}; - bdd_manager(unsigned nodes); + bdd_manager(unsigned num_vars); ~bdd_manager(); void set_max_num_nodes(unsigned n) { m_max_num_bdd_nodes = n; } @@ -219,6 +230,39 @@ namespace dd { bdd mk_forall(unsigned v, bdd const& b); bdd mk_ite(bdd const& c, bdd const& t, bdd const& e); + /* BDD vector operations + * - Fixed-width arithmetic, i.e., modulo 2^size + * - The lowest index is the LSB + */ + bdd mk_ule(bddv const& a, bddv const& b); + bdd mk_uge(bddv const& a, bddv const& b); // { return mk_ule(b, a); } + bdd mk_ult(bddv const& a, bddv const& b); // { return mk_ule(a, b) && !mk_eq(a, b); } + bdd mk_ugt(bddv const& a, bddv const& b); // { return mk_ult(b, a); } + bdd mk_sle(bddv const& a, bddv const& b); + bdd mk_sge(bddv const& a, bddv const& b); // { return mk_sle(b, a); } + bdd mk_slt(bddv const& a, bddv const& b); // { return mk_sle(a, b) && !mk_eq(a, b); } + bdd mk_sgt(bddv const& a, bddv const& b); // { return mk_slt(b, a); } + bdd mk_eq(bddv const& a, bddv const& b); + bdd mk_eq(bddv const& a, rational const& v); + bdd mk_eq(unsigned_vector const& vars, rational const& v); + bddv mk_num(rational const& n, unsigned num_bits); + bddv mk_ones(unsigned num_bits); + bddv mk_zero(unsigned num_bits); + bddv mk_var(unsigned num_bits, unsigned const* vars); + bddv mk_var(unsigned_vector const& vars); + bddv mk_add(bddv const& a, bddv const& b); + bddv mk_add(bddv const& a, std::function& get_bit); + bddv mk_sub(bddv const& a, bddv const& b); + bddv mk_usub(bddv const& a); + bddv mk_mul(bddv const& a, bddv const& b); + bddv mk_mul(bddv const& a, bool_vector const& b); + bddv mk_mul(bddv const& a, rational const& val); + bddv mk_concat(bddv const& a, bddv const& b); + void mk_quot_rem(bddv const& a, bddv const& b, bddv& quot, bddv& rem); + bool is_constv(bddv const& a); + rational to_val(bddv const& a); + + std::ostream& display(std::ostream& out); std::ostream& display(std::ostream& out, bdd const& b); @@ -242,14 +286,16 @@ namespace dd { unsigned var() const { return m->var(root); } bool is_true() const { return root == bdd_manager::true_bdd; } - bool is_false() const { return root == bdd_manager::false_bdd; } + bool is_false() const { return root == bdd_manager::false_bdd; } + bool is_const() const { return is_false() || is_true(); } - bdd operator!() { return m->mk_not(*this); } - bdd operator&&(bdd const& other) { return m->mk_and(*this, other); } - bdd operator||(bdd const& other) { return m->mk_or(*this, other); } - bdd operator^(bdd const& other) { return m->mk_xor(*this, other); } + bdd operator!() const { return m->mk_not(*this); } + bdd operator&&(bdd const& other) const { return m->mk_and(*this, other); } + bdd operator||(bdd const& other) const { return m->mk_or(*this, other); } + bdd operator^(bdd const& other) const { return m->mk_xor(*this, other); } bdd operator|=(bdd const& other) { return *this = *this || other; } bdd operator&=(bdd const& other) { return *this = *this && other; } + bdd cofactor(bdd const& cube) { return m->mk_cofactor(*this, cube); } std::ostream& display(std::ostream& out) const { return m->display(out, *this); } bool operator==(bdd const& other) const { return root == other.root; } bool operator!=(bdd const& other) const { return root != other.root; } @@ -260,6 +306,79 @@ namespace dd { std::ostream& operator<<(std::ostream& out, bdd const& b); + class bddv { + friend bdd_manager; + + vector m_bits; + bdd_manager* m; + + bddv(vector const& bits, bdd_manager* m): m_bits(bits), m(m) { SASSERT(m); } + bddv(vector&& bits, bdd_manager* m): m_bits(std::move(bits)), m(m) { SASSERT(m); } + + bddv(bdd_manager* m): m_bits(), m(m) { SASSERT(m); } + bdd const& operator[](unsigned i) const { return m_bits[i]; } + bdd& operator[](unsigned i) { return m_bits[i]; } + void push_back(bdd const& a) { m_bits.push_back(a); } + void push_back(bdd&& a) { m_bits.push_back(std::move(a)); } + void shl(); + void shr(); + + public: + unsigned size() const { return m_bits.size(); } + vector const& bits() const { return m_bits; } + + /* unsigned comparison operators */ + bdd operator<=(bddv const& other) const { return m->mk_ule(*this, other); } ///< unsigned comparison + bdd operator>=(bddv const& other) const { return m->mk_uge(*this, other); } ///< unsigned comparison + bdd operator< (bddv const& other) const { return m->mk_ult(*this, other); } ///< unsigned comparison + bdd operator> (bddv const& other) const { return m->mk_ugt(*this, other); } ///< unsigned comparison + bdd operator<=(rational const& other) const { return m->mk_ule(*this, m->mk_num(other, size())); } ///< unsigned comparison + bdd operator>=(rational const& other) const { return m->mk_uge(*this, m->mk_num(other, size())); } ///< unsigned comparison + bdd operator< (rational const& other) const { return m->mk_ult(*this, m->mk_num(other, size())); } ///< unsigned comparison + bdd operator> (rational const& other) const { return m->mk_ugt(*this, m->mk_num(other, size())); } ///< unsigned comparison + + /* signed comparison operators */ + bdd sle(bddv const& other) const { return m->mk_sle(*this, other); } + bdd sge(bddv const& other) const { return m->mk_sge(*this, other); } + bdd slt(bddv const& other) const { return m->mk_slt(*this, other); } + bdd sgt(bddv const& other) const { return m->mk_sgt(*this, other); } + + bdd all0() const; + bdd all1() const; + + bdd operator==(bddv const& other) const { return m->mk_eq(*this, other); } + bdd operator==(rational const& other) const { return m->mk_eq(*this, other); } + bdd operator!=(bddv const& other) const { return !m->mk_eq(*this, other); } + bdd operator!=(rational const& other) const { return !m->mk_eq(*this, other); } + + bddv operator+(bddv const& other) const { return m->mk_add(*this, other); } + bddv operator+(rational const& other) const { return m->mk_add(*this, m->mk_num(other, size())); } + bddv operator-(bddv const& other) const { return m->mk_sub(*this, other); } + bddv operator-(rational const& other) const { return m->mk_sub(*this, m->mk_num(other, size())); } + bddv rev_sub(rational const& other) const { return m->mk_sub(m->mk_num(other, size()), *this); } + bddv operator*(bddv const& other) const { return m->mk_mul(*this, other); } + bddv operator*(rational const& other) const { return m->mk_mul(*this, other); } + bddv operator*(bool_vector const& other) const { return m->mk_mul(*this, other); } + bddv append(bddv const& other) const { return m->mk_concat(*this, other); } + void quot_rem(bddv const& divisor, bddv& quot, bddv& rem) const { m->mk_quot_rem(*this, divisor, quot, rem); } + + bool is_const() const { return m->is_constv(*this); } + rational to_val() const { return m->to_val(*this); } + }; + + inline bdd operator<=(rational const& r, bddv const& a) { return a >= r; } ///< unsigned comparison + inline bdd operator>=(rational const& r, bddv const& a) { return a <= r; } ///< unsigned comparison + inline bdd operator< (rational const& r, bddv const& a) { return a > r; } ///< unsigned comparison + inline bdd operator> (rational const& r, bddv const& a) { return a < r; } ///< unsigned comparison + inline bdd operator==(rational const& r, bddv const& a) { return a == r; } + inline bdd operator!=(rational const& r, bddv const& a) { return a != r; } + inline bddv operator*(rational const& r, bddv const& a) { return a * r; } + inline bddv operator+(rational const& r, bddv const& a) { return a + r; } + inline bddv operator-(rational const& r, bddv const& a) { return a.rev_sub(r); } + inline bdd operator<=(int i, bddv const& a) { return a >= rational(i); } + inline bdd operator<=(bddv const& a, int i) { return a <= rational(i); } + + } diff --git a/src/math/dd/dd_fdd.cpp b/src/math/dd/dd_fdd.cpp new file mode 100644 index 000000000..21ec82fd1 --- /dev/null +++ b/src/math/dd/dd_fdd.cpp @@ -0,0 +1,366 @@ +/*++ +Copyright (c) 2021 Microsoft Corporation + +Module Name: + + dd_fdd + +Abstract: + + Finite domain abstraction for using BDDs as sets of integers, inspired by BuDDy's fdd module. + +Author: + + Nikolaj Bjorner (nbjorner) 2021-04-20 + Jakob Rath 2021-04-20 + +--*/ + +#include "math/dd/dd_fdd.h" + +namespace dd { + + fdd::fdd(bdd_manager& manager, unsigned_vector&& vars) + : m_pos2var(std::move(vars)) + , m_var2pos() + , m(&manager) + , m_var(manager.mk_var(m_pos2var)) + { + for (unsigned pos = 0; pos < m_pos2var.size(); ++pos) { + unsigned const var = m_pos2var[pos]; + while (var >= m_var2pos.size()) + m_var2pos.push_back(UINT_MAX); + m_var2pos[var] = pos; + } + } + + bdd fdd::non_zero() const { + bdd non_zero = m->mk_false(); + for (unsigned var : m_pos2var) { + non_zero |= m->mk_var(var); + } + return non_zero; + } + + unsigned fdd::var2pos(unsigned var) const { + return var < m_var2pos.size() ? m_var2pos[var] : UINT_MAX; + } + + bool fdd::contains(bdd b, rational const& val) const { + while (!b.is_const()) { + unsigned const pos = var2pos(b.var()); + SASSERT(pos != UINT_MAX && "Unexpected BDD variable"); + b = val.get_bit(pos) ? b.hi() : b.lo(); + } + return b.is_true(); + } + + find_t fdd::find(bdd b, rational& out_val) const { + return find_hint(b, rational::zero(), out_val); + } + + find_t fdd::find_hint(bdd b, rational const& hint, rational& out_val) const { + out_val = 0; + if (b.is_false()) + return find_t::empty; + bool is_unique = true; + bool hint_ok = !hint.is_zero(); // since we choose the 'lo' branch by default, we don't need to check the hint when it is 0. + unsigned num_vars = 0; + while (!b.is_true()) { + ++num_vars; + unsigned const pos = var2pos(b.var()); + SASSERT(pos != UINT_MAX && "Unexpected BDD variable"); + + bool go_hi = false; + if (b.lo().is_false()) { + go_hi = true; + if (hint_ok && !hint.get_bit(pos)) + hint_ok = false; + } + else if (b.hi().is_false()) { + if (hint_ok && hint.get_bit(pos)) + hint_ok = false; + } + else { + // This is the only case where we have a choice + // => follow the hint + SASSERT(!b.lo().is_false() && !b.hi().is_false()); + is_unique = false; + if (hint_ok && hint.get_bit(pos)) + go_hi = true; + } + + if (go_hi) { + out_val += rational::power_of_two(pos); + b = b.hi(); + } + else + b = b.lo(); + } + if (num_vars != num_bits()) + is_unique = false; + // If a variable corresponding to a 1-bit in hint does not appear in the BDD, + // out_val is wrong at this point, so we set it explicitly. + if (hint_ok) + out_val = hint; + // TODO: instead of computing out_val incrementally, we could mark the visited 'hi'-positions and only compute out_val from the marks when !hint_ok. + return is_unique ? find_t::singleton : find_t::multiple; + } + + std::ostream& operator<<(std::ostream& out, find_t x) { + switch (x) { + case find_t::empty: + return out << "empty"; + case find_t::singleton: + return out << "singleton"; + case find_t::multiple: + return out << "multiple"; + } + UNREACHABLE(); + return out; + } + + bool fdd::contains(bdd const& x, bool_vector const& value) const { + bdd b = x; + while (!b.is_true()) { + unsigned const pos = var2pos(b.var()); + SASSERT(pos != UINT_MAX && "Unexpected BDD variable"); + if (value[pos] && b.hi().is_false()) + return false; + if (!value[pos] && b.lo().is_false()) + return false; + if (value[pos]) + b = b.hi(); + else + b = b.lo(); + } + return true; + } + + + // subtract one from x + static void dec(bool_vector& x) { + for (auto& b : x) { + b = !b; + if (!b) + break; + } + } + + // add one to x + static void inc(bool_vector& x) { + for (auto& b : x) { + b = !b; + if (b) + break; + } + } + + static void reset(bool_vector& x, bool value) { + for (auto& b : x) + b = value; + } + + + bool fdd::sup(bdd const& x, bool_vector& lo) const { + SASSERT(lo.size() == num_bits()); + // + // Assumption: common case is that high-order bits are before lower-order bits also + // after re-ordering. Then co-factoring is relatively cheap. + // + + if (!contains(x, lo)) + return false; + + // + // find minimal index where b is false for some + // value larger than lo. + // + // Let ua(x lo) be shorthand for "unbounded-above" of variable + // x with bit-string lo. + // + // we have the following identities: + // ua(_ []) = true + // ua(x 1 ++ lo) = hi(x) = T or ua(hi(x), lo) + // ua(x 0 ++ lo) = hi(x) = T and ua(lo(x), lo) + // + // the least significant bit where ua is false + // represents the position where the smallest number above + // lo resides that violates x. + + unsigned idx = UINT_MAX; + vector trail; + bdd b = x; + for (unsigned i = lo.size(); i-- > 0; ) { + trail.push_back(b); + unsigned v = m_pos2var[i]; + bdd w = m->mk_var(v); + bdd hi = b.cofactor(w); + if (lo[i]) { + if (hi.is_true()) + break; + SASSERT(!hi.is_false()); + b = hi; + } + else { + if (!hi.is_true()) + idx = i; + b = b.cofactor(m->mk_nvar(v)); + } + } + if (idx == UINT_MAX) { + // all values above lo satisfy x + reset(lo, true); + return true; + } + + SASSERT(!lo[idx]); + lo[idx] = true; + unsigned v = m_pos2var[idx]; + b = trail[lo.size() - idx - 1].cofactor(m->mk_var(v)); + for (unsigned i = idx; i-- > 0; ) { + SASSERT(!b.is_true()); + if (b.is_false()) { + for (unsigned j = 0; j <= i; ++j) + lo[j] = false; + break; + } + lo[i] = b.lo().is_true(); + if (lo[i]) + b = b.hi(); + else + b = b.lo(); + } + + dec(lo); + + return true; + } + + bool fdd::inf(bdd const& x, bool_vector& hi) const { + SASSERT(hi.size() == num_bits()); + if (!contains(x, hi)) + return false; + + // Let ub(x hi) be shorthand for "unbounded-below" of variable + // x with bit-string hi. + // + // we have the following identities: + // ub(_ []) = true + // ub(x 0 ++ hi) = lo(x) = T or ub(lo(x), hi) + // ub(x 1 ++ hi) = lo(x) = T and ub(hi(x), hi) + // + + unsigned idx = UINT_MAX; + vector trail; + bdd b = x; + for (unsigned i = hi.size(); i-- > 0; ) { + trail.push_back(b); + unsigned v = m_pos2var[i]; + bdd nw = m->mk_nvar(v); + bdd lo = b.cofactor(nw); + if (!hi[i]) { + if (lo.is_true()) + break; + SASSERT(!lo.is_false()); + b = lo; + } + else { + if (!lo.is_true()) + idx = i; + b = b.cofactor(m->mk_var(v)); + } + } + if (idx == UINT_MAX) { + // all values below hi satisfy x + reset(hi, false); + return true; + } + + SASSERT(hi[idx]); + hi[idx] = false; + unsigned v = m_pos2var[idx]; + b = trail[hi.size() - idx - 1].cofactor(m->mk_nvar(v)); + + for (unsigned i = idx; i-- > 0; ) { + SASSERT(!b.is_true()); + if (b.is_false()) { + for (unsigned j = 0; j <= i; ++j) + hi[j] = true; + break; + } + hi[i] = !b.hi().is_true(); + if (!hi[i]) + b = b.lo(); + else + b = b.hi(); + } + + inc(hi); + + return true; + } + + bool_vector fdd::rational2bits(rational const& r) const { + bool_vector result; + for (unsigned i = 0; i < num_bits(); ++i) + result.push_back(r.get_bit(i)); + return result; + } + + rational fdd::bits2rational(bool_vector const& v) const { + rational result(0); + for (unsigned i = 0; i < num_bits(); ++i) + if (v[i]) + result += rational::power_of_two(i); + return result; + } + + bool fdd::sup(bdd const& b, rational& _lo) const { + bool_vector lo = rational2bits(_lo); + if (!sup(b, lo)) + return false; + _lo = bits2rational(lo); + return true; + } + + bool fdd::inf(bdd const& b, rational& _hi) const { + bool_vector hi = rational2bits(_hi); + if (!inf(b, hi)) + return false; + _hi = bits2rational(hi); + return true; + } + + rational fdd::max(bdd b) const { + SASSERT(!b.is_false()); + rational result(0); + for (unsigned i = num_bits(); i-- > 0; ) { + unsigned v = m_pos2var[i]; + bdd w = m->mk_var(v); + bdd hi = b.cofactor(w); + if (!hi.is_false()) { + b = hi; + result += rational::power_of_two(i); + } + } + return result; + } + + rational fdd::min(bdd b) const { + SASSERT(!b.is_false()); + rational result(0); + for (unsigned i = num_bits(); i-- > 0; ) { + unsigned v = m_pos2var[i]; + bdd nw = m->mk_nvar(v); + bdd lo = b.cofactor(nw); + if (lo.is_false()) + result += rational::power_of_two(i); + else + b = lo; + } + return result; + } + + +} diff --git a/src/math/dd/dd_fdd.h b/src/math/dd/dd_fdd.h new file mode 100644 index 000000000..e17233aa4 --- /dev/null +++ b/src/math/dd/dd_fdd.h @@ -0,0 +1,108 @@ +/*++ +Copyright (c) 2021 Microsoft Corporation + +Module Name: + + dd_fdd + +Abstract: + + Finite domain abstraction for using BDDs as sets of integers, inspired by BuDDy's fdd module. + +Author: + + Jakob Rath 2021-04-20 + Nikolaj Bjorner (nbjorner) 2021-04-20 + +--*/ +#pragma once + +#include "math/dd/dd_bdd.h" +#include "util/vector.h" +#include "util/rational.h" + +namespace dd { + + enum class find_t { empty, singleton, multiple }; + std::ostream& operator<<(std::ostream& out, find_t x); + + /** + * Finite domain abstraction over BDDs. + */ + class fdd { + unsigned_vector m_pos2var; // pos -> BDD var + unsigned_vector m_var2pos; // var -> pos (pos = place number in the bit representation, 0 is LSB's place) + bdd_manager* m; + bddv m_var; + + static unsigned_vector seq(unsigned count, unsigned start = 0, unsigned step = 1) { + unsigned_vector result; + unsigned k = start; + for (unsigned i = 0; i < count; ++i, k += step) + result.push_back(k); + return result; + } + + unsigned var2pos(unsigned var) const; + + bool contains(bdd const& b, bool_vector const& value) const; + + rational bits2rational(bool_vector const& v) const; + + bool_vector rational2bits(rational const& r) const; + + public: + /** Initialize FDD using BDD variables from 0 to num_bits-1. */ + fdd(bdd_manager& manager, unsigned num_bits, unsigned start = 0, unsigned step = 1) : fdd(manager, seq(num_bits, start, step)) { } + fdd(bdd_manager& manager, unsigned_vector const& vars) : fdd(manager, unsigned_vector(vars)) { } + fdd(bdd_manager& manager, unsigned_vector&& vars); + + unsigned num_bits() const { return m_pos2var.size(); } + unsigned_vector const& bdd_vars() const { return m_pos2var; } + + bddv const& var() const { return m_var; } + + /** Equivalent to var() != 0 */ + bdd non_zero() const; + + /** Checks whether the integer val is contained in the BDD when viewed as set of integers. + * Precondition: the bdd only contains variables managed by this fdd. + */ + bool contains(bdd b, rational const& val) const; + + /** Returns an integer contained in the BDD, if any, and whether the BDD is a singleton. + * Precondition: the bdd only contains variables managed by this fdd. + */ + find_t find(bdd b, rational& out_val) const; + + /** Like find, but returns hint if it is contained in the BDD. */ + find_t find_hint(bdd b, rational const& hint, rational& out_val) const; + + /* + * find largest value at lo or above such that bdd b evaluates to true + * at lo and all values between. + * dually, find smallest value below hi that evaluates b to true + * and all values between the value and hi also evaluate b to true. + * \param b - a bdd using variables from this + * \param lo/hi - bound to be traversed. + * \return false if b is false at lo/hi + * \pre variables in b are a subset of variables from the fdd + */ + bool sup(bdd const& b, bool_vector& lo) const; + + bool inf(bdd const& b, bool_vector& hi) const; + + bool sup(bdd const& b, rational& lo) const; + + bool inf(bdd const& b, rational& hi) const; + + /* + * Find the min-max satisfying assignment. + * \pre b is not false. + */ + rational max(bdd b) const; + + rational min(bdd b) const; + }; + +} diff --git a/src/math/dd/dd_pdd.cpp b/src/math/dd/dd_pdd.cpp index b8946ebf6..cca2d5e04 100644 --- a/src/math/dd/dd_pdd.cpp +++ b/src/math/dd/dd_pdd.cpp @@ -34,6 +34,7 @@ namespace dd { s = mod2_e; m_semantics = s; m_mod2N = rational::power_of_two(power_of_2); + m_max_value = m_mod2N - 1; m_power_of_2 = power_of_2; unsigned_vector l2v; for (unsigned i = 0; i < num_vars; ++i) l2v.push_back(i); @@ -50,6 +51,7 @@ namespace dd { void pdd_manager::reset(unsigned_vector const& level2var) { reset_op_cache(); + m_factor_cache.reset(); m_node_table.reset(); m_nodes.reset(); m_free_nodes.reset(); @@ -126,7 +128,7 @@ namespace dd { * Example: 2^4*x + 2 is non-zero for every x. */ - bool pdd_manager::is_non_zero(PDD p) { + bool pdd_manager::is_never_zero(PDD p) { if (is_val(p)) return !is_zero(p); if (m_semantics != mod2N_e) @@ -163,7 +165,11 @@ namespace dd { return true; } - pdd pdd_manager::subst_val(pdd const& p, vector> const& _s) { + pdd pdd_manager::subst_val(pdd const& p, pdd const& s) { + return pdd(apply(p.root, s.root, pdd_subst_val_op), this); + } + + pdd pdd_manager::subst_val0(pdd const& p, vector> const& _s) { typedef std::pair pr; vector s(_s); std::function compare_level = @@ -171,10 +177,16 @@ namespace dd { std::sort(s.begin(), s.end(), compare_level); pdd r(one()); for (auto const& q : s) - r = (r*mk_var(q.first)) + q.second; - return pdd(apply(p.root, r.root, pdd_subst_val_op), this); + r = (r * mk_var(q.first)) + q.second; + return subst_val(p, r); } + pdd pdd_manager::subst_add(pdd const& s, unsigned v, rational const& val) { + pdd v_val = mk_var(v) + val; + return pdd(apply(s.root, v_val.root, pdd_subst_add_op), this); + } + + pdd_manager::PDD pdd_manager::apply(PDD arg1, PDD arg2, pdd_op op) { bool first = true; SASSERT(well_formed()); @@ -216,6 +228,7 @@ namespace dd { if (is_val(p) && is_val(q)) return imk_val(val(p) - val(q)); if (m_semantics != mod2_e) break; op = pdd_add_op; + Z3_fallthrough; case pdd_add_op: if (is_zero(p)) return q; if (is_zero(q)) return p; @@ -239,12 +252,16 @@ namespace dd { break; case pdd_subst_val_op: while (!is_val(q) && !is_val(p)) { - if (level(p) == level(q)) break; - if (level(p) < level(q)) q = lo(q); - else p = lo(p); + if (level(p) < level(q)) q = hi(q); + else break; } if (is_val(p) || is_val(q)) return p; break; + case pdd_subst_add_op: + if (is_one(p)) return q; + SASSERT(!is_val(p)); + SASSERT(!is_val(q)); + break; default: UNREACHABLE(); break; @@ -345,7 +362,8 @@ namespace dd { push(make_node(level_p, lo(n), read(1))); r = make_node(level_p, bd, read(1)); npop = 7; - } else { + } + else { push(make_node(level_p, n, ac)); r = make_node(level_p, bd, read(1)); npop = 6; @@ -387,12 +405,33 @@ namespace dd { case pdd_subst_val_op: SASSERT(!is_val(p)); SASSERT(!is_val(q)); - SASSERT(level_p == level_q); + SASSERT(level_p >= level_q); push(apply_rec(lo(p), q, pdd_subst_val_op)); // lo := subst(lo(p), s) push(apply_rec(hi(p), q, pdd_subst_val_op)); // hi := subst(hi(p), s) - push(apply_rec(lo(q), read(1), pdd_mul_op)); // hi := hi*s[var(p)] - r = apply_rec(read(1), read(3), pdd_add_op); // r := hi + lo := subst(lo(p),s) + s[var(p)]*subst(hi(p),s) - npop = 3; + + if (level_p > level_q) { + r = make_node(level_p, read(2), read(1)); + npop = 2; + } + else { + push(apply_rec(lo(q), read(1), pdd_mul_op)); // hi := hi*s[var(p)] + r = apply_rec(read(1), read(3), pdd_add_op); // r := hi + lo := subst(lo(p),s) + s[var(p)]*subst(hi(p),s) + npop = 3; + } + break; + case pdd_subst_add_op: + SASSERT(!is_val(p)); + SASSERT(!is_val(q)); + SASSERT(level_p != level_q); + if (level_p < level_q) { + r = make_node(level_q, lo(q), p); // p*hi(q) + lo(q) + npop = 0; + } + else { + push(apply_rec(hi(p), q, pdd_subst_add_op)); // hi := add_subst(hi(p), q) + r = make_node(level_p, lo(p), read(1)); // r := hi*var(p) + lo(p) + npop = 1; + } break; default: r = null_pdd; @@ -405,6 +444,7 @@ namespace dd { return r; } + pdd pdd_manager::minus(pdd const& a) { if (m_semantics == mod2_e) { return a; @@ -442,6 +482,113 @@ namespace dd { return r; } + /** + * Divide PDD by a constant value. + * + * IMPORTANT: Performs regular numerical division. + * For semantics 'mod2N_e', this means that 'c' must be an integer + * and all coefficients of 'a' must be divisible by 'c'. + * + * NOTE: Why do we not just use 'mul(a, inv(c))' instead? + * In case of semantics 'mod2N_e', an invariant is that all PDDs have integer coefficients. + * But such a multiplication would create nodes with non-integral coefficients. + */ + pdd pdd_manager::div(pdd const& a, rational const& c) { + pdd res(zero_pdd, this); + VERIFY(try_div(a, c, res)); + return res; + } + + bool pdd_manager::try_div(pdd const& a, rational const& c, pdd& out_result) { + if (m_semantics == free_e) { + // Don't cache separately for the free semantics; + // use 'mul' so we can share results for a/c and a*(1/c). + out_result = mul(inv(c), a); + return true; + } + SASSERT(c.is_int()); + bool first = true; + SASSERT(well_formed()); + scoped_push _sp(*this); + while (true) { + try { + PDD res = div_rec(a.root, c, null_pdd); + if (res != null_pdd) + out_result = pdd(res, this); + SASSERT(well_formed()); + return res != null_pdd; + } + catch (const mem_out &) { + try_gc(); + if (!first) throw; + first = false; + } + } + } + + /// Returns null_pdd if one of the coefficients is not divisible by c. + pdd_manager::PDD pdd_manager::div_rec(PDD a, rational const& c, PDD c_pdd) { + SASSERT(m_semantics != free_e); + SASSERT(c.is_int()); + if (is_zero(a)) + return zero_pdd; + if (is_val(a)) { + rational r = val(a) / c; + if (r.is_int()) + return imk_val(r); + else + return null_pdd; + } + if (c_pdd == null_pdd) + c_pdd = imk_val(c); + op_entry* e1 = pop_entry(a, c_pdd, pdd_div_const_op); + op_entry const* e2 = m_op_cache.insert_if_not_there(e1); + if (check_result(e1, e2, a, c_pdd, pdd_div_const_op)) + return e2->m_result; + push(div_rec(lo(a), c, c_pdd)); + push(div_rec(hi(a), c, c_pdd)); + PDD l = read(2); + PDD h = read(1); + PDD res = null_pdd; + if (l != null_pdd && h != null_pdd) + res = make_node(level(a), l, h); + pop(2); + e1->m_result = res; + return res; + } + + pdd pdd_manager::pow(pdd const &p, unsigned j) { + return pdd(pow(p.root, j), this); + } + + pdd_manager::PDD pdd_manager::pow(PDD p, unsigned j) { + if (j == 0) + return one_pdd; + else if (j == 1) + return p; + else if (is_zero(p)) + return zero_pdd; + else if (is_one(p)) + return one_pdd; + else if (is_val(p)) + return imk_val(power(val(p), j)); + else + return pow_rec(p, j); + } + + pdd_manager::PDD pdd_manager::pow_rec(PDD p, unsigned j) { + SASSERT(j > 0); + if (j == 1) + return p; + // j even: pow(p,2*j') = pow(p*p,j') + // j odd: pow(p,2*j'+1) = p*pow(p*p,j') + PDD q = pow_rec(apply(p, p, pdd_mul_op), j / 2); + if (j & 1) { + q = apply(q, p, pdd_mul_op); + } + return q; + } + // // produce polynomial where a is reduced by b. // all monomials in a that are divisible by lm(b) @@ -691,27 +838,37 @@ namespace dd { * factor p into lc*v^degree + rest * such that degree(rest, v) < degree * Initial implementation is very naive - * - memoize intermediary results */ void pdd_manager::factor(pdd const& p, unsigned v, unsigned degree, pdd& lc, pdd& rest) { unsigned level_v = m_var2level[v]; if (degree == 0) { - lc = p; - rest = zero(); - } - else if (level(p.root) < level_v) { lc = zero(); rest = p; + return; } - else if (level(p.root) > level_v) { + if (level(p.root) < level_v) { + lc = zero(); + rest = p; + return; + } + // Memoize nontrivial cases + auto* et = m_factor_cache.insert_if_not_there2({p.root, v, degree}); + factor_entry* e = &et->get_data(); + if (e->is_valid()) { + lc = pdd(e->m_lc, this); + rest = pdd(e->m_rest, this); + return; + } + + if (level(p.root) > level_v) { pdd lc1 = zero(), rest1 = zero(); pdd vv = mk_var(p.var()); factor(p.hi(), v, degree, lc, rest); factor(p.lo(), v, degree, lc1, rest1); - lc += lc1; - rest += rest1; lc *= vv; rest *= vv; + lc += lc1; + rest += rest1; } else { unsigned d = 0; @@ -733,8 +890,228 @@ namespace dd { rest = p; } } + et = m_factor_cache.insert_if_not_there2({p.root, v, degree}); + e = &et->get_data(); + e->m_lc = lc.root; + e->m_rest = rest.root; } + bool pdd_manager::factor(pdd const& p, unsigned v, unsigned degree, pdd& lc) { + pdd rest = lc; + factor(p, v, degree, lc, rest); + return rest.is_zero(); + } + + /** + * Apply function f to all coefficients of the polynomial. + * The function should be of type + * rational const& -> rational + * rational const& -> unsigned + * and should always return integers. + * + * NOTE: the operation is not cached. + */ + template + pdd pdd_manager::map_coefficients(pdd const& p, Fn f) { + if (p.is_val()) { + return mk_val(rational(f(p.val()))); + } else { + pdd x = mk_var(p.var()); + pdd lo = map_coefficients(p.lo(), f); + pdd hi = map_coefficients(p.hi(), f); + return x*hi + lo; + } + } + + /** + * Perform S-polynomial reduction on p by q, + * treating monomial with v as leading. + * + * p = a v^l + b = a' 2^j v^l + b + * q = c v^m + d = c' 2^j v^m + d + * such that + * deg(v, p) = l, i.e., v does not divide a and there is no v^l in b + * deg(v, q) = m, i.e., v does not divide c and there is no v^m in d + * l >= m + * j maximal, i.e., not both of a', c' are divisible by 2 + * + * Then we reduce p by q: + * + * r = c' p - a' v^(l-m) q + * = b c' - a' d v^(l-m) + */ + bool pdd_manager::resolve(unsigned v, pdd const& p, pdd const& q, pdd& r) { + unsigned const l = p.degree(v); + unsigned const m = q.degree(v); + // no reduction + if (l < m || m == 0) + return false; + + pdd a = zero(); + pdd b = zero(); + pdd c = zero(); + pdd d = zero(); + p.factor(v, l, a, b); + q.factor(v, m, c, d); + unsigned const j = std::min(max_pow2_divisor(a), max_pow2_divisor(c)); + SASSERT(j != UINT_MAX); // should only be possible when both l and m are 0 + rational const pow2j = rational::power_of_two(j); + pdd const aa = div(a, pow2j); + pdd const cc = div(c, pow2j); + pdd vv = pow(mk_var(v), l - m); + r = b * cc - aa * d * vv; + return true; + } + + /** + * Reduce polynomial a with respect to b by eliminating terms using v + * + * a := a1*v^l + a2 + * b := b1*v^m + b2 + * l >= m + * q, r := quot_rem(a1, b1) + * that is: + * q * b1 + r = a1 + * r = 0 + * result := reduce(v, q*b2*v^{l-m}, b) + reduce(v, a2, b) + */ + pdd pdd_manager::reduce(unsigned v, pdd const& a, pdd const& b) { + unsigned const m = b.degree(v); + // no reduction + if (m == 0) + return a; + + pdd b1 = zero(); + pdd b2 = zero(); + b.factor(v, m, b1, b2); + + // TODO - generalize this case to when leading coefficient is not a value + if (m_semantics == mod2N_e && b1.is_val() && b1.val().is_odd() && !b1.is_one()) { + rational b_inv; + VERIFY(b1.val().mult_inverse(m_power_of_2, b_inv)); + b1 = 1; + b2 *= b_inv; + } + + return reduce(v, a, m, b1, b2); + } + + pdd pdd_manager::reduce(unsigned v, pdd const& a, unsigned m, pdd const& b1, pdd const& b2) { + SASSERT(m > 0); + unsigned const l = a.degree(v); + if (l < m) + return a; + + pdd a1 = zero(); + pdd a2 = zero(); + pdd q = zero(); + pdd r = zero(); + a.factor(v, l, a1, a2); + + quot_rem(a1, b1, q, r); + if (r.is_zero()) { + SASSERT(q * b1 == a1); + a1 = -q * b2; + if (l > m) + a1 = reduce(v, a1 * pow(mk_var(v), l - m), m, b1, b2); + } + else + a1 = a1 * pow(mk_var(v), l); + a2 = reduce(v, a2, m, b1, b2); + + return a1 + a2; + } + + /** + * quotient/remainder of 'a' divided by 'b' + * a := x*hi + lo + * x > level(b): + * hi = q1*b + r1 + * lo = q2*b + r2 + * x*hi + lo = (x*q1 + q2)*b + (x*r1 + r2) + * q := x*q1 + q2 + * r := x*r1 + r2 + * Some special cases. + * General multi-variable polynomial division is TBD. + */ + void pdd_manager::quot_rem(pdd const& a, pdd const& b, pdd& q, pdd& r) { + if (level(a.root) > level(b.root)) { + pdd q1(*this), q2(*this), r1(*this), r2(*this); + quot_rem(a.hi(), b, q1, r1); + quot_rem(a.lo(), b, q2, r2); + q = mk_var(a.var()) * q1 + q2; + r = mk_var(a.var()) * r1 + r2; + } + else if (level(a.root) < level(b.root)) { + q = zero(); + r = a; + } + else if (a == b) { + q = one(); + r = zero(); + } + else if (a.is_val() && b.is_val() && divides(b.val(), a.val())) { + q = mk_val(a.val() / b.val()); + r = zero(); + } + else if (a.is_val() || b.is_val()) { + q = zero(); + r = a; + } + else { + SASSERT(level(a.root) == level(b.root)); + pdd q1(*this), q2(*this), r1(*this), r2(*this); + quot_rem(a.hi(), b.hi(), q1, r1); + quot_rem(a.lo(), b.lo(), q2, r2); + if (q1 == q2 && r1.is_zero() && r2.is_zero()) { + q = q1; + r = zero(); + } + else { + q = zero(); + r = a; + } + } + } + + /** + * Returns the largest j such that 2^j divides p. + */ + unsigned pdd_manager::max_pow2_divisor(PDD p) { + init_mark(); + unsigned min_j = UINT_MAX; + m_todo.push_back(p); + while (!m_todo.empty()) { + PDD r = m_todo.back(); + m_todo.pop_back(); + if (is_marked(r)) { + continue; + } + set_mark(r); + if (is_zero(r)) { + // skip + } + else if (is_val(r)) { + rational const& c = val(r); + if (c.is_odd()) { + m_todo.reset(); + return 0; + } else { + unsigned j = c.trailing_zeros(); + min_j = std::min(j, min_j); + } + } + else { + m_todo.push_back(lo(r)); + m_todo.push_back(hi(r)); + } + } + return min_j; + } + + unsigned pdd_manager::max_pow2_divisor(pdd const& p) { + return max_pow2_divisor(p.root); + } bool pdd_manager::is_linear(pdd const& p) { return is_linear(p.root); @@ -764,6 +1141,32 @@ namespace dd { } } + /** Determine whether p contains at most one variable. */ + bool pdd_manager::is_univariate(PDD p) { + unsigned const lvl = level(p); + while (!is_val(p)) { + if (!is_val(lo(p))) + return false; + if (level(p) != lvl) + return false; + p = hi(p); + } + return true; + } + + /** + * Push coefficients of univariate polynomial in order of ascending degree. + * Example: a*x^2 + b*x + c ==> [ c, b, a ] + */ + void pdd_manager::get_univariate_coefficients(PDD p, vector& coeff) { + SASSERT(is_univariate(p)); + while (!is_val(p)) { + coeff.push_back(val(lo(p))); + p = hi(p); + } + coeff.push_back(val(p)); + } + /* \brief determine if v occurs as a leaf variable. */ @@ -832,9 +1235,8 @@ namespace dd { if (m_semantics == mod2N_e && (r < 0 || r >= m_mod2N)) return imk_val(mod(r, m_mod2N)); const_info info; - if (!m_mpq_table.find(r, info)) { + if (!m_mpq_table.find(r, info)) init_value(info, r); - } return info.m_node_index; } @@ -1005,7 +1407,7 @@ namespace dd { unsigned pdd_manager::degree(PDD p, unsigned v) { init_mark(); - unsigned level_v = level(v); + unsigned level_v = m_var2level[v]; unsigned max_d = 0, d = 0; m_todo.push_back(p); while (!m_todo.empty()) { @@ -1017,15 +1419,17 @@ namespace dd { else if (level(r) < level_v) m_todo.pop_back(); else if (level(r) == level_v) { - d = 1; - while (!is_val(hi(r)) && level(hi(r)) == level_v) { + d = 0; + do { ++d; + set_mark(r); r = hi(r); - } + } while (!is_val(r) && level(r) == level_v); max_d = std::max(d, max_d); m_todo.pop_back(); } else { + set_mark(r); m_todo.push_back(lo(r)); m_todo.push_back(hi(r)); } @@ -1128,6 +1532,7 @@ namespace dd { } void pdd_manager::gc() { + m_gc_generation++; init_dmark(); m_free_nodes.reset(); SASSERT(well_formed()); @@ -1167,6 +1572,8 @@ namespace dd { m_op_cache.insert(e); } + m_factor_cache.reset(); + m_node_table.reset(); // re-populate node cache for (unsigned i = m_nodes.size(); i-- > 2; ) { @@ -1221,14 +1628,32 @@ namespace dd { rational c = abs(m.first); m.second.reverse(); if (!c.is_one() || m.second.empty()) { - out << c; + if (m_semantics == mod2N_e && mod(-c, m_mod2N) < c) + out << -mod(-c, m_mod2N); + else + out << c; if (!m.second.empty()) out << "*"; } - bool f = true; + unsigned v_prev = UINT_MAX; + unsigned pow = 0; for (unsigned v : m.second) { - if (!f) out << "*"; - f = false; - out << "v" << v; + if (v == v_prev) { + pow++; + continue; + } + if (v_prev != UINT_MAX) { + out << "v" << v_prev; + if (pow > 1) + out << "^" << pow; + out << "*"; + } + pow = 1; + v_prev = v; + } + if (v_prev != UINT_MAX) { + out << "v" << v_prev; + if (pow > 1) + out << "^" << pow; } } if (first) out << "0"; @@ -1291,6 +1716,30 @@ namespace dd { return *this; } + pdd& pdd::operator=(unsigned k) { + m.dec_ref(root); + root = m.mk_val(k).root; + m.inc_ref(root); + return *this; + } + + pdd& pdd::operator=(rational const& k) { + m.dec_ref(root); + root = m.mk_val(k).root; + m.inc_ref(root); + return *this; + } + + rational const& pdd::leading_coefficient() const { + pdd p = *this; + while (!p.is_val()) + p = p.hi(); + return p.val(); + } + + pdd pdd::shl(unsigned n) const { + return (*this) * rational::power_of_two(n); + } /** * \brief substitute variable v by r. diff --git a/src/math/dd/dd_pdd.h b/src/math/dd/dd_pdd.h index 9cd454698..aef0eb6f7 100644 --- a/src/math/dd/dd_pdd.h +++ b/src/math/dd/dd_pdd.h @@ -23,6 +23,11 @@ Abstract: - try_spoly(a, b, c) returns true if lt(a) and lt(b) have a non-trivial overlap. c is the resolvent (S polynomial). + - reduce(v, a, b) reduces 'a' using b = 0 with respect to eliminating v. + Given b = v^l*b1 + b2, where l is the leading coefficient of v in b + Given a = v^m*a1 + b2, where m >= l is the leading coefficient of v in b. + reduce(a1, b1)*v^{m - l} + reduce(v, a2, b); + Author: Nikolaj Bjorner (nbjorner) 2019-12-17 @@ -63,7 +68,9 @@ namespace dd { pdd_mul_op = 5, pdd_reduce_op = 6, pdd_subst_val_op = 7, - pdd_no_op = 8 + pdd_subst_add_op = 8, + pdd_div_const_op = 9, + pdd_no_op = 10 }; struct node { @@ -140,9 +147,44 @@ namespace dd { typedef ptr_hashtable op_table; + struct factor_entry { + factor_entry(PDD p, unsigned v, unsigned degree): + m_p(p), + m_v(v), + m_degree(degree), + m_lc(UINT_MAX), + m_rest(UINT_MAX) + {} + + factor_entry(): m_p(0), m_v(0), m_degree(0), m_lc(UINT_MAX), m_rest(UINT_MAX) {} + + PDD m_p; // input + unsigned m_v; // input + unsigned m_degree; // input + PDD m_lc; // output + PDD m_rest; // output + + bool is_valid() { return m_lc != UINT_MAX; } + + unsigned hash() const { return mk_mix(m_p, m_v, m_degree); } + }; + + struct hash_factor_entry { + unsigned operator()(factor_entry const& e) const { return e.hash(); } + }; + + struct eq_factor_entry { + bool operator()(factor_entry const& a, factor_entry const& b) const { + return a.m_p == b.m_p && a.m_v == b.m_v && a.m_degree == b.m_degree; + } + }; + + typedef hashtable factor_table; + svector m_nodes; vector m_values; op_table m_op_cache; + factor_table m_factor_cache; node_table m_node_table; mpq_table m_mpq_table; svector m_pdd_stack; @@ -164,7 +206,9 @@ namespace dd { unsigned_vector m_free_values; rational m_freeze_value; rational m_mod2N; - unsigned m_power_of_2 { 0 }; + unsigned m_power_of_2 = 0; + rational m_max_value; + unsigned m_gc_generation = 0; ///< will be incremented on each GC void reset_op_cache(); void init_nodes(unsigned_vector const& l2v); @@ -177,6 +221,9 @@ namespace dd { PDD apply(PDD arg1, PDD arg2, pdd_op op); PDD apply_rec(PDD arg1, PDD arg2, pdd_op op); PDD minus_rec(PDD p); + PDD div_rec(PDD p, rational const& c, PDD c_pdd); + PDD pow(PDD p, unsigned j); + PDD pow_rec(PDD p, unsigned j); PDD reduce_on_match(PDD a, PDD b); bool lm_occurs(PDD p, PDD q) const; @@ -206,7 +253,8 @@ namespace dd { inline bool is_one(PDD p) const { return p == one_pdd; } inline bool is_val(PDD p) const { return m_nodes[p].is_val(); } inline bool is_internal(PDD p) const { return m_nodes[p].is_internal(); } - bool is_non_zero(PDD p); + inline bool is_var(PDD p) const { return !is_val(p) && is_zero(lo(p)) && is_one(hi(p)); } + bool is_never_zero(PDD p); inline unsigned level(PDD p) const { return m_nodes[p].m_level; } inline unsigned var(PDD p) const { return m_level2var[level(p)]; } inline PDD lo(PDD p) const { return m_nodes[p].m_lo; } @@ -226,8 +274,14 @@ namespace dd { unsigned degree(pdd const& p) const; unsigned degree(PDD p) const; unsigned degree(PDD p, unsigned v); + unsigned max_pow2_divisor(PDD p); + unsigned max_pow2_divisor(pdd const& p); + template pdd map_coefficients(pdd const& p, Fn f); void factor(pdd const& p, unsigned v, unsigned degree, pdd& lc, pdd& rest); + bool factor(pdd const& p, unsigned v, unsigned degree, pdd& lc); + + pdd reduce(unsigned v, pdd const& a, unsigned m, pdd const& b1, pdd const& b2); bool var_is_leaf(PDD p, unsigned v); @@ -258,7 +312,7 @@ namespace dd { struct mem_out {}; - pdd_manager(unsigned nodes, semantics s = free_e, unsigned power_of_2 = 0); + pdd_manager(unsigned num_vars, semantics s = free_e, unsigned power_of_2 = 0); ~pdd_manager(); semantics get_semantics() const { return m_semantics; } @@ -278,13 +332,21 @@ namespace dd { pdd sub(pdd const& a, pdd const& b); pdd mul(pdd const& a, pdd const& b); pdd mul(rational const& c, pdd const& b); + pdd div(pdd const& a, rational const& c); + bool try_div(pdd const& a, rational const& c, pdd& out_result); pdd mk_or(pdd const& p, pdd const& q); pdd mk_xor(pdd const& p, pdd const& q); pdd mk_xor(pdd const& p, unsigned q); pdd mk_not(pdd const& p); pdd reduce(pdd const& a, pdd const& b); - pdd subst_val(pdd const& a, vector> const& s); + pdd subst_val0(pdd const& a, vector> const& s); pdd subst_val(pdd const& a, unsigned v, rational const& val); + pdd subst_val(pdd const& a, pdd const& s); + pdd subst_add(pdd const& s, unsigned v, rational const& val); + bool resolve(unsigned v, pdd const& p, pdd const& q, pdd& r); + pdd reduce(unsigned v, pdd const& a, pdd const& b); + void quot_rem(pdd const& a, pdd const& b, pdd& q, pdd& r); + pdd pow(pdd const& p, unsigned j); bool is_linear(PDD p) { return degree(p) == 1; } bool is_linear(pdd const& p); @@ -294,6 +356,9 @@ namespace dd { bool is_monomial(PDD p); + bool is_univariate(PDD p); + void get_univariate_coefficients(PDD p, vector& coeff); + // create an spoly r if leading monomials of a and b overlap bool try_spoly(pdd const& a, pdd const& b, pdd& r); @@ -308,6 +373,8 @@ namespace dd { unsigned num_vars() const { return m_var2pdd.size(); } unsigned power_of_2() const { return m_power_of_2; } + rational const& max_value() const { return m_max_value; } + rational const& two_to_N() const { return m_mod2N; } unsigned_vector const& free_vars(pdd const& p); @@ -330,21 +397,30 @@ namespace dd { pdd(pdd const& other): root(other.root), m(other.m) { m.inc_ref(root); } pdd(pdd && other) noexcept : root(0), m(other.m) { std::swap(root, other.root); } pdd& operator=(pdd const& other); + pdd& operator=(unsigned k); + pdd& operator=(rational const& k); ~pdd() { m.dec_ref(root); } pdd lo() const { return pdd(m.lo(root), m); } pdd hi() const { return pdd(m.hi(root), m); } unsigned index() const { return root; } unsigned var() const { return m.var(root); } rational const& val() const { SASSERT(is_val()); return m.val(root); } + rational const& leading_coefficient() const; bool is_val() const { return m.is_val(root); } 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_var() const { return m.is_var(root); } + /** Polynomial is of the form a * x + b for numerals a, b. */ + bool is_unilinear() const { return !is_val() && lo().is_val() && 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); } + bool is_univariate() const { return m.is_univariate(root); } + void get_univariate_coefficients(vector& coeff) const { m.get_univariate_coefficients(root, coeff); } + vector get_univariate_coefficients() const { vector coeff; m.get_univariate_coefficients(root, coeff); return coeff; } + bool is_never_zero() const { return m.is_never_zero(root); } bool var_is_leaf(unsigned v) const { return m.var_is_leaf(root, v); } pdd operator-() const { return m.minus(*this); } @@ -359,20 +435,28 @@ namespace dd { pdd operator*(rational const& other) const { return m.mul(other, *this); } pdd operator+(rational const& other) const { return m.add(other, *this); } pdd operator~() const { return m.mk_not(*this); } + pdd shl(unsigned n) const; pdd rev_sub(rational const& r) const { return m.sub(m.mk_val(r), *this); } + pdd div(rational const& other) const { return m.div(*this, other); } + bool try_div(rational const& other, pdd& out_result) const { return m.try_div(*this, other, out_result); } + pdd pow(unsigned j) const { return m.pow(*this, j); } pdd reduce(pdd const& other) const { return m.reduce(*this, other); } bool different_leading_term(pdd const& other) const { return m.different_leading_term(*this, other); } - void factor(unsigned v, unsigned degree, pdd& lc, pdd& rest) { m.factor(*this, v, degree, lc, rest); } + void factor(unsigned v, unsigned degree, pdd& lc, pdd& rest) const { m.factor(*this, v, degree, lc, rest); } + bool factor(unsigned v, unsigned degree, pdd& lc) const { return m.factor(*this, v, degree, lc); } + bool resolve(unsigned v, pdd const& other, pdd& result) { return m.resolve(v, *this, other, result); } + pdd reduce(unsigned v, pdd const& other) const { return m.reduce(v, *this, other); } /** * \brief factor out variables */ std::pair var_factors() const; - pdd subst_val(vector> const& s) const { return m.subst_val(*this, s); } + pdd subst_val0(vector> const& s) const { return m.subst_val0(*this, s); } + pdd subst_val(pdd const& s) const { return m.subst_val(*this, s); } pdd subst_val(unsigned v, rational const& val) const { return m.subst_val(*this, v, val); } + pdd subst_add(unsigned var, rational const& val) { return m.subst_add(*this, var, val); } - /** * \brief substitute variable v by r. */ @@ -381,6 +465,7 @@ namespace dd { std::ostream& display(std::ostream& out) const { return m.display(out, *this); } bool operator==(pdd const& other) const { return root == other.root; } bool operator!=(pdd const& other) const { return root != other.root; } + unsigned hash() const { return root; } unsigned power_of_2() const { return m.power_of_2(); } @@ -388,11 +473,15 @@ namespace dd { double tree_size() const { return m.tree_size(*this); } unsigned degree() const { return m.degree(*this); } unsigned degree(unsigned v) const { return m.degree(root, v); } + unsigned max_pow2_divisor() const { return m.max_pow2_divisor(root); } unsigned_vector const& free_vars() const { return m.free_vars(*this); } + void swap(pdd& other) { std::swap(root, other.root); } pdd_iterator begin() const; pdd_iterator end() const; + + pdd_manager& manager() const { return m; } }; inline pdd operator*(rational const& r, pdd const& b) { return b * r; } @@ -403,23 +492,25 @@ namespace dd { inline pdd operator+(int x, pdd const& b) { return b + rational(x); } inline pdd operator+(pdd const& b, int x) { return b + rational(x); } - inline pdd operator^(unsigned x, pdd const& b) { return b + x; } - inline pdd operator^(bool x, pdd const& b) { return b + x; } + inline pdd operator^(unsigned x, pdd const& b) { return b ^ x; } + inline pdd operator^(bool x, pdd const& b) { return b ^ x; } inline pdd operator-(rational const& r, pdd const& b) { return b.rev_sub(r); } inline pdd operator-(int x, pdd const& b) { return rational(x) - b; } inline pdd operator-(pdd const& b, int x) { return b + (-rational(x)); } inline pdd operator-(pdd const& b, rational const& r) { return b + (-r); } - + inline pdd& operator&=(pdd & p, pdd const& q) { p = p & q; return p; } inline pdd& operator^=(pdd & p, pdd const& q) { p = p ^ q; return p; } - inline pdd& operator*=(pdd & p, pdd const& q) { p = p * q; return p; } inline pdd& operator|=(pdd & p, pdd const& q) { p = p | q; return p; } + inline pdd& operator*=(pdd & p, pdd const& q) { p = p * q; return p; } inline pdd& operator-=(pdd & p, pdd const& q) { p = p - q; return p; } inline pdd& operator+=(pdd & p, pdd const& q) { p = p + q; return p; } - inline pdd& operator+=(pdd & p, rational const& v) { p = p + v; return p; } - inline pdd& operator-=(pdd & p, rational const& v) { p = p - v; return p; } - inline pdd& operator*=(pdd & p, rational const& v) { p = p * v; return p; } + inline pdd& operator*=(pdd & p, rational const& q) { p = p * q; return p; } + inline pdd& operator-=(pdd & p, rational const& q) { p = p - q; return p; } + inline pdd& operator+=(pdd & p, rational const& q) { p = p + q; return p; } + + inline void swap(pdd& p, pdd& q) { p.swap(q); } std::ostream& operator<<(std::ostream& out, pdd const& b); diff --git a/src/math/dd/pdd_eval.h b/src/math/dd/pdd_eval.h index f7682927f..9872935cf 100644 --- a/src/math/dd/pdd_eval.h +++ b/src/math/dd/pdd_eval.h @@ -17,6 +17,8 @@ Author: Revision History: --*/ +#pragma once + #include "math/dd/dd_pdd.h" namespace dd { diff --git a/src/math/dd/pdd_interval.h b/src/math/dd/pdd_interval.h index d8e2b8db1..c5b4c9e1c 100644 --- a/src/math/dd/pdd_interval.h +++ b/src/math/dd/pdd_interval.h @@ -17,6 +17,8 @@ Author: Revision History: --*/ +#pragma once + #include "math/dd/dd_pdd.h" #include "math/interval/dep_intervals.h" diff --git a/src/math/grobner/pdd_simplifier.cpp b/src/math/grobner/pdd_simplifier.cpp index e8b10ad80..4a8140681 100644 --- a/src/math/grobner/pdd_simplifier.cpp +++ b/src/math/grobner/pdd_simplifier.cpp @@ -19,7 +19,7 @@ Extended Linear Simplification (as exploited in Bosphorus AAAI 2019): - multiply each polynomial by one variable from their orbits. - - The orbit of a varible are the variables that occur in the same monomial as it in some polynomial. + - The orbit of a variable are the variables that occur in the same monomial as it in some polynomial. - The extended set of polynomials is fed to a linear Gauss Jordan Eliminator that extracts additional linear equalities. - Bosphorus uses M4RI to perform efficient GJE to scale on large bit-matrices. @@ -32,7 +32,7 @@ The method seems rather specific to hardware multipliers so not clear it is useful to generalize. - find monomials that contain pairs of vanishing polynomials, transitively - withtout actually inlining. + without actually inlining. Then color polynomial variables w by p, resp, q if they occur in polynomial equalities w - r = 0, such that all paths in r contain a node colored by p, resp q. polynomial variables that get colored by both p and q can be set to 0. diff --git a/src/math/grobner/pdd_solver.cpp b/src/math/grobner/pdd_solver.cpp index aefe5d6dc..63c5ad835 100644 --- a/src/math/grobner/pdd_solver.cpp +++ b/src/math/grobner/pdd_solver.cpp @@ -61,8 +61,7 @@ namespace dd { solver::solver(reslimit& lim, pdd_manager& m) : m(m), - m_limit(lim), - m_conflict(nullptr) + m_limit(lim) {} solver::~solver() { @@ -179,9 +178,8 @@ namespace dd { set[i]->set_index(j++); } ~scoped_update() { - for (; i < sz; ++i) { + for (; i < sz; ++i) nextj(); - } set.shrink(j); } }; @@ -191,23 +189,24 @@ namespace dd { equation& target = *set[sr.i]; bool changed_leading_term = false; bool simplified = true; - simplified = !done() && simplifier(target, changed_leading_term); + simplified = !done() && simplifier(target, changed_leading_term); + - if (simplified && is_trivial(target)) { + if (simplified && is_trivial(target)) retire(&target); - } else if (simplified && check_conflict(target)) { // pushed to solved } else if (simplified && changed_leading_term) { - push_equation(to_simplify, target); - if (!m_var2level.empty()) { + if (&m_to_simplify == &set) + sr.nextj(); + else + push_equation(to_simplify, target); + if (!m_var2level.empty()) m_levelp1 = std::max(m_var2level[target.poly().var()]+1, m_levelp1); - } } - else { + else sr.nextj(); - } } } diff --git a/src/math/grobner/pdd_solver.h b/src/math/grobner/pdd_solver.h index 0069eadf3..40f8fdce2 100644 --- a/src/math/grobner/pdd_solver.h +++ b/src/math/grobner/pdd_solver.h @@ -121,7 +121,7 @@ private: vector> m_subst; mutable u_dependency_manager m_dep_manager; equation_vector m_all_eqs; - equation* m_conflict; + equation* m_conflict = nullptr; bool m_too_complex; public: solver(reslimit& lim, pdd_manager& m); diff --git a/src/math/hilbert/heap_trie.h b/src/math/hilbert/heap_trie.h index 7d4179de8..b492fb7ee 100644 --- a/src/math/hilbert/heap_trie.h +++ b/src/math/hilbert/heap_trie.h @@ -66,7 +66,7 @@ class heap_trie { unsigned m_ref; public: node(node_t t): m_type(t), m_ref(0) {} - virtual ~node() {} + virtual ~node() = default; node_t type() const { return m_type; } void inc_ref() { ++m_ref; } void dec_ref() { SASSERT(m_ref > 0); --m_ref; } @@ -80,7 +80,6 @@ class heap_trie { Value m_value; public: leaf(): node(leaf_t) {} - ~leaf() override {} Value const& get_value() const { return m_value; } void set_value(Value const& v) { m_value = v; } void display(std::ostream& out, unsigned indent) const override { @@ -98,9 +97,6 @@ class heap_trie { public: trie(): node(trie_t) {} - ~trie() override { - } - node* find_or_insert(Key k, node* n) { for (unsigned i = 0; i < m_nodes.size(); ++i) { if (m_nodes[i].first == k) { diff --git a/src/math/lp/binary_heap_priority_queue_def.h b/src/math/lp/binary_heap_priority_queue_def.h index c17d70fb2..0e640d949 100644 --- a/src/math/lp/binary_heap_priority_queue_def.h +++ b/src/math/lp/binary_heap_priority_queue_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include "util/vector.h" #include "math/lp/binary_heap_priority_queue.h" namespace lp { diff --git a/src/math/lp/binary_heap_upair_queue_def.h b/src/math/lp/binary_heap_upair_queue_def.h index a74f9e46a..65485a6eb 100644 --- a/src/math/lp/binary_heap_upair_queue_def.h +++ b/src/math/lp/binary_heap_upair_queue_def.h @@ -17,6 +17,7 @@ Revision History: --*/ +#pragma once #include #include "math/lp/lp_utils.h" diff --git a/src/math/lp/core_solver_pretty_printer_def.h b/src/math/lp/core_solver_pretty_printer_def.h index 2f54b175a..23417b691 100644 --- a/src/math/lp/core_solver_pretty_printer_def.h +++ b/src/math/lp/core_solver_pretty_printer_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include #include #include diff --git a/src/math/lp/dense_matrix_def.h b/src/math/lp/dense_matrix_def.h index f781dbf8f..8eb9ad5dd 100644 --- a/src/math/lp/dense_matrix_def.h +++ b/src/math/lp/dense_matrix_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include "math/lp/lp_settings.h" #ifdef Z3DEBUG #include "util/vector.h" diff --git a/src/math/lp/emonics.cpp b/src/math/lp/emonics.cpp index 5b3ae64f0..0f1956a2b 100644 --- a/src/math/lp/emonics.cpp +++ b/src/math/lp/emonics.cpp @@ -518,7 +518,7 @@ std::ostream& emonics::display(std::ostream& out, cell* c) const { bool emonics::invariant() const { TRACE("nla_solver_mons", display(tout);); - // the varible index contains exactly the active monomials + // the variable index contains exactly the active monomials unsigned mons = 0; for (lpvar v = 0; v < m_var2index.size(); v++) { if (is_monic_var(v)) { diff --git a/src/math/lp/factorization_factory_imp.h b/src/math/lp/factorization_factory_imp.h index b404d5f14..599039094 100644 --- a/src/math/lp/factorization_factory_imp.h +++ b/src/math/lp/factorization_factory_imp.h @@ -28,8 +28,8 @@ namespace nla { const monic& m_rm; factorization_factory_imp(const monic& rm, const core& s); - bool find_canonical_monic_of_vars(const svector& vars, unsigned & i) const; - virtual bool canonize_sign(const monic& m) const; - virtual bool canonize_sign(const factorization& m) const; + bool find_canonical_monic_of_vars(const svector& vars, unsigned & i) const override; + bool canonize_sign(const monic& m) const override; + bool canonize_sign(const factorization& m) const override; }; } diff --git a/src/math/lp/hnf_cutter.cpp b/src/math/lp/hnf_cutter.cpp index 70a9222e4..c1f93c9d8 100644 --- a/src/math/lp/hnf_cutter.cpp +++ b/src/math/lp/hnf_cutter.cpp @@ -20,7 +20,7 @@ namespace lp { lra(lia.lra), m_settings(lia.settings()), m_abs_max(zero_of_type()), - m_var_register(0) {} + m_var_register(false) {} bool hnf_cutter::is_full() const { return diff --git a/src/math/lp/indexed_vector_def.h b/src/math/lp/indexed_vector_def.h index 443ca160e..0e25ee271 100644 --- a/src/math/lp/indexed_vector_def.h +++ b/src/math/lp/indexed_vector_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include "util/vector.h" #include "math/lp/indexed_vector.h" #include "math/lp/lp_settings.h" diff --git a/src/math/lp/lar_constraints.h b/src/math/lp/lar_constraints.h index 3bcd62d00..8e6311683 100644 --- a/src/math/lp/lar_constraints.h +++ b/src/math/lp/lar_constraints.h @@ -57,7 +57,7 @@ public: virtual vector> coeffs() const = 0; lar_base_constraint(unsigned j, lconstraint_kind kind, const mpq& right_side) :m_kind(kind), m_right_side(right_side), m_active(false), m_j(j) {} - virtual ~lar_base_constraint() {} + virtual ~lar_base_constraint() = default; lconstraint_kind kind() const { return m_kind; } mpq const& rhs() const { return m_right_side; } diff --git a/src/math/lp/lar_core_solver_def.h b/src/math/lp/lar_core_solver_def.h index f20aa7e6b..939a05114 100644 --- a/src/math/lp/lar_core_solver_def.h +++ b/src/math/lp/lar_core_solver_def.h @@ -9,6 +9,8 @@ Revision History: --*/ +#pragma once + #include #include "util/vector.h" #include "math/lp/lar_core_solver.h" diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index f1cbd3370..cce63855d 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -543,7 +543,7 @@ public: void get_model(std::unordered_map & variable_values) const; void get_rid_of_inf_eps(); void get_model_do_not_care_about_diff_vars(std::unordered_map & variable_values) const; - std::string get_variable_name(var_index vi) const; + std::string get_variable_name(var_index vi) const override; void set_variable_name(var_index vi, std::string); inline unsigned number_of_vars() const { return m_var_register.size(); } inline bool is_base(unsigned j) const { return m_mpq_lar_core_solver.m_r_heading[j] >= 0; } @@ -651,7 +651,7 @@ public: lar_solver(); void set_track_pivoted_rows(bool v); bool get_track_pivoted_rows() const; - virtual ~lar_solver(); + ~lar_solver() override; const vector& r_x() const { return m_mpq_lar_core_solver.m_r_x; } bool column_is_int(unsigned j) const; inline bool column_value_is_int(unsigned j) const { return m_mpq_lar_core_solver.m_r_x[j].is_int(); } diff --git a/src/math/lp/lp_api.h b/src/math/lp/lp_api.h index 8c05f8354..2a4e5058d 100644 --- a/src/math/lp/lp_api.h +++ b/src/math/lp/lp_api.h @@ -49,7 +49,7 @@ namespace lp_api { m_constraints[1] = ct; } - virtual ~bound() {} + virtual ~bound() = default; theory_var get_var() const { return m_var; } diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 42c2ddcf7..c1b64492b 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include #include #include "util/vector.h" diff --git a/src/math/lp/lp_dual_core_solver_def.h b/src/math/lp/lp_dual_core_solver_def.h index 4a847fe85..b42d644af 100644 --- a/src/math/lp/lp_dual_core_solver_def.h +++ b/src/math/lp/lp_dual_core_solver_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include #include #include "util/vector.h" diff --git a/src/math/lp/lp_dual_simplex_def.h b/src/math/lp/lp_dual_simplex_def.h index c21429c88..8af9d87c1 100644 --- a/src/math/lp/lp_dual_simplex_def.h +++ b/src/math/lp/lp_dual_simplex_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include "math/lp/lp_dual_simplex.h" namespace lp{ diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 75eff208a..7b5dec945 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include #include "util/vector.h" #include diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index 03f07115b..46297a63e 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + // this is a part of lp_primal_core_solver that deals with the tableau #include "math/lp/lp_primal_core_solver.h" namespace lp { diff --git a/src/math/lp/lp_primal_simplex_def.h b/src/math/lp/lp_primal_simplex_def.h index e805ecc88..7ffe819b2 100644 --- a/src/math/lp/lp_primal_simplex_def.h +++ b/src/math/lp/lp_primal_simplex_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include #include "util/vector.h" #include "math/lp/lp_primal_simplex.h" diff --git a/src/math/lp/lp_settings_def.h b/src/math/lp/lp_settings_def.h index 4c783049c..2aba35946 100644 --- a/src/math/lp/lp_settings_def.h +++ b/src/math/lp/lp_settings_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include #include #include "util/vector.h" diff --git a/src/math/lp/lp_solver.h b/src/math/lp/lp_solver.h index 68beca06f..ab16a686f 100644 --- a/src/math/lp/lp_solver.h +++ b/src/math/lp/lp_solver.h @@ -149,7 +149,7 @@ public: } - virtual ~lp_solver(); + ~lp_solver() override; void flip_costs(); diff --git a/src/math/lp/lp_solver_def.h b/src/math/lp/lp_solver_def.h index 4b5bc6db7..191832a24 100644 --- a/src/math/lp/lp_solver_def.h +++ b/src/math/lp/lp_solver_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include #include #include "util/vector.h" diff --git a/src/math/lp/lu_def.h b/src/math/lp/lu_def.h index df0f53730..80c9cdf0e 100644 --- a/src/math/lp/lu_def.h +++ b/src/math/lp/lu_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include #include #include diff --git a/src/math/lp/matrix.h b/src/math/lp/matrix.h index 80ddb1228..88a405614 100644 --- a/src/math/lp/matrix.h +++ b/src/math/lp/matrix.h @@ -22,7 +22,7 @@ public: virtual void set_number_of_rows(unsigned m) = 0; virtual void set_number_of_columns(unsigned n) = 0; - virtual ~matrix() {} + virtual ~matrix() = default; bool is_equal(const matrix& other); bool operator == (matrix const & other) { diff --git a/src/math/lp/matrix_def.h b/src/math/lp/matrix_def.h index 8dba9d0b8..95810bd5a 100644 --- a/src/math/lp/matrix_def.h +++ b/src/math/lp/matrix_def.h @@ -17,6 +17,7 @@ Revision History: --*/ +#pragma once #include #include diff --git a/src/math/lp/mps_reader.h b/src/math/lp/mps_reader.h index f0fa074cc..f2cf2d320 100644 --- a/src/math/lp/mps_reader.h +++ b/src/math/lp/mps_reader.h @@ -20,7 +20,7 @@ Revision History: #pragma once -// reads an MPS file reperesenting a Mixed Integer Program +// reads an MPS file representing a Mixed Integer Program #include #include #include diff --git a/src/math/lp/nex.h b/src/math/lp/nex.h index 083b935a4..e4087a407 100644 --- a/src/math/lp/nex.h +++ b/src/math/lp/nex.h @@ -85,7 +85,7 @@ public: bool is_scalar() const { return type() == expr_type::SCALAR; } virtual bool is_pure_monomial() const { return false; } std::string str() const { std::stringstream ss; print(ss); return ss.str(); } - virtual ~nex() {} + virtual ~nex() = default; virtual bool contains(lpvar j) const { return false; } virtual unsigned get_degree() const = 0; // simplifies the expression and also assigns the address of "this" to *e diff --git a/src/math/lp/permutation_matrix_def.h b/src/math/lp/permutation_matrix_def.h index c6ad20a39..703830ffc 100644 --- a/src/math/lp/permutation_matrix_def.h +++ b/src/math/lp/permutation_matrix_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include "util/vector.h" #include "math/lp/permutation_matrix.h" namespace lp { diff --git a/src/math/lp/random_updater_def.h b/src/math/lp/random_updater_def.h index 25ef6f82f..7d167a4a0 100644 --- a/src/math/lp/random_updater_def.h +++ b/src/math/lp/random_updater_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include "math/lp/random_updater.h" #include "math/lp/static_matrix.h" #include "math/lp/lar_solver.h" diff --git a/src/math/lp/row_eta_matrix_def.h b/src/math/lp/row_eta_matrix_def.h index 817d39481..faac5c6fe 100644 --- a/src/math/lp/row_eta_matrix_def.h +++ b/src/math/lp/row_eta_matrix_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include "util/vector.h" #include "math/lp/row_eta_matrix.h" namespace lp { diff --git a/src/math/lp/scaler_def.h b/src/math/lp/scaler_def.h index c05b25a16..8604a67a1 100644 --- a/src/math/lp/scaler_def.h +++ b/src/math/lp/scaler_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include #include "math/lp/scaler.h" #include "math/lp/numeric_pair.h" diff --git a/src/math/lp/square_dense_submatrix_def.h b/src/math/lp/square_dense_submatrix_def.h index 8b565f92e..3a9006b4d 100644 --- a/src/math/lp/square_dense_submatrix_def.h +++ b/src/math/lp/square_dense_submatrix_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include "util/vector.h" #include "math/lp/square_dense_submatrix.h" namespace lp { diff --git a/src/math/lp/square_sparse_matrix_def.h b/src/math/lp/square_sparse_matrix_def.h index 0a2cffd61..3533ba066 100644 --- a/src/math/lp/square_sparse_matrix_def.h +++ b/src/math/lp/square_sparse_matrix_def.h @@ -17,6 +17,7 @@ Revision History: --*/ +#pragma once #include "util/vector.h" #include "math/lp/square_sparse_matrix.h" diff --git a/src/math/lp/static_matrix_def.h b/src/math/lp/static_matrix_def.h index 45d5d6d89..af2eac360 100644 --- a/src/math/lp/static_matrix_def.h +++ b/src/math/lp/static_matrix_def.h @@ -17,6 +17,8 @@ Revision History: --*/ +#pragma once + #include "util/vector.h" #include #include diff --git a/src/math/lp/tail_matrix.h b/src/math/lp/tail_matrix.h index 2047e8c7e..9fa1a4a47 100644 --- a/src/math/lp/tail_matrix.h +++ b/src/math/lp/tail_matrix.h @@ -37,7 +37,7 @@ public: virtual void apply_from_left(vector & w, lp_settings & settings) = 0; virtual void apply_from_right(vector & w) = 0; virtual void apply_from_right(indexed_vector & w) = 0; - virtual ~tail_matrix() {} + virtual ~tail_matrix() = default; virtual bool is_dense() const = 0; struct ref_row { const tail_matrix & m_A; diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 8b8f82a31..0223e8bff 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -981,7 +981,7 @@ namespace opt { lub_rows.reset(); glb_rows.reset(); mod_rows.reset(); - bool lub_is_unit = false, glb_is_unit = false; + bool lub_is_unit = true, glb_is_unit = true; unsigned eq_row = UINT_MAX; // select the lub and glb. for (unsigned row_id : row_ids) { diff --git a/src/math/simplex/network_flow.h b/src/math/simplex/network_flow.h index 9be3b1191..b2c9cd9b3 100644 --- a/src/math/simplex/network_flow.h +++ b/src/math/simplex/network_flow.h @@ -87,7 +87,7 @@ namespace smt { m_states(states), m_enter_id(enter_id) { } - virtual ~pivot_rule_impl() {} + virtual ~pivot_rule_impl() = default; virtual bool choose_entering_edge() = 0; virtual pivot_rule rule() const = 0; }; diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index a33ea55bd..ecba27af5 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -36,6 +36,8 @@ namespace simplex { numeral m_coeff; var_t m_var; row_entry(numeral && c, var_t v) : m_coeff(std::move(c)), m_var(v) {} + inline numeral const& coeff() const { return m_coeff; } + inline var_t var() const { return m_var; } }; private: @@ -202,17 +204,17 @@ 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 { + class row_entries_t { friend class sparse_matrix; sparse_matrix& s; row r; - row_vars(sparse_matrix& s, row r): s(s), r(r) {} + row_entries_t(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); } + row_entries_t get_row(row r) { return row_entries_t(*this, r); } unsigned column_size(var_t v) const { return m_columns[v].size(); } @@ -247,7 +249,8 @@ namespace simplex { row get_row() const { return row(m_col.m_entries[m_curr].m_row_id); } - row_entry& get_row_entry() { + + row_entry& get_row_entry() const { col_entry const& c = m_col.m_entries[m_curr]; int row_id = c.m_row_id; return m_rows[row_id].m_entries[c.m_row_idx]; @@ -263,6 +266,18 @@ namespace simplex { 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 col_entries_t { + friend class sparse_matrix; + sparse_matrix& m; + int v; + col_entries_t(sparse_matrix& m, int v): m(m), v(v) {} + public: + col_iterator begin() { return m.col_begin(v); } + col_iterator end() { return m.col_end(v); } + }; + + col_entries_t get_col(int v) { return col_entries_t(*this, v); } + class var_rows { friend class sparse_matrix; sparse_matrix& s; diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index dc3700f2e..255e62f11 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -98,7 +98,7 @@ namespace simplex { if (!t1.is_dead()) { if (i != j) { _row_entry & t2 = m_entries[j]; - t2.m_coeff.swap(t1.m_coeff); + m.swap(t2.m_coeff, t1.m_coeff); t2.m_var = t1.m_var; t2.m_col_idx = t1.m_col_idx; SASSERT(!t2.is_dead()); diff --git a/src/math/subpaving/subpaving.cpp b/src/math/subpaving/subpaving.cpp index 19dd661c6..e9c72e2d7 100644 --- a/src/math/subpaving/subpaving.cpp +++ b/src/math/subpaving/subpaving.cpp @@ -38,7 +38,6 @@ namespace subpaving { CTX m_ctx; public: context_wrapper(reslimit& lim, typename CTX::numeral_manager & m, params_ref const & p, small_object_allocator * a):m_ctx(lim, m, p, a) {} - ~context_wrapper() override {} unsigned num_vars() const override { return m_ctx.num_vars(); } var mk_var(bool is_int) override { return m_ctx.mk_var(is_int); } bool is_int(var x) const override { return m_ctx.is_int(x); } @@ -66,8 +65,6 @@ namespace subpaving { m_as(m) {} - ~context_mpq_wrapper() override {} - unsynch_mpq_manager & qm() const override { return m_ctx.nm(); } var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) override { @@ -108,8 +105,6 @@ namespace subpaving { m_q2(m_qm) { } - ~context_mpf_wrapper() override {} - unsynch_mpq_manager & qm() const override { return m_qm; } var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) override { @@ -165,8 +160,6 @@ namespace subpaving { m_qm(qm) { } - ~context_hwf_wrapper() override {} - unsynch_mpq_manager & qm() const override { return m_qm; } var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) override { @@ -223,8 +216,6 @@ namespace subpaving { m_z2(m_qm) { } - ~context_fpoint_wrapper() override {} - unsynch_mpq_manager & qm() const override { return m_qm; } var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) override { diff --git a/src/math/subpaving/subpaving.h b/src/math/subpaving/subpaving.h index 96d05f4de..b76f5e831 100644 --- a/src/math/subpaving/subpaving.h +++ b/src/math/subpaving/subpaving.h @@ -39,7 +39,7 @@ namespace subpaving { class context { public: - virtual ~context() {} + virtual ~context() = default; virtual unsynch_mpq_manager & qm() const = 0; diff --git a/src/math/subpaving/subpaving_t.h b/src/math/subpaving/subpaving_t.h index cfe3aea70..7300e3da3 100644 --- a/src/math/subpaving/subpaving_t.h +++ b/src/math/subpaving/subpaving_t.h @@ -385,7 +385,7 @@ public: context_t * m_ctx; public: node_selector(context_t * ctx):m_ctx(ctx) {} - virtual ~node_selector() {} + virtual ~node_selector() = default; context_t * ctx() const { return m_ctx; } @@ -403,7 +403,7 @@ public: context_t * m_ctx; public: var_selector(context_t * ctx):m_ctx(ctx) {} - virtual ~var_selector() {} + virtual ~var_selector() = default; context_t * ctx() const { return m_ctx; } @@ -436,7 +436,7 @@ public: context_t * m_ctx; public: node_splitter(context_t * ctx):m_ctx(ctx) {} - virtual ~node_splitter() {} + virtual ~node_splitter() = default; context_t * ctx() const { return m_ctx; } node * mk_node(node * p) { return ctx()->mk_node(p); } diff --git a/src/math/subpaving/subpaving_t_def.h b/src/math/subpaving/subpaving_t_def.h index c31e920ab..89f6dad0f 100644 --- a/src/math/subpaving/subpaving_t_def.h +++ b/src/math/subpaving/subpaving_t_def.h @@ -16,6 +16,8 @@ Author: Revision History: --*/ +#pragma once + #include "math/subpaving/subpaving_t.h" #include "math/interval/interval_def.h" #include "util/buffer.h" diff --git a/src/math/subpaving/tactic/subpaving_tactic.cpp b/src/math/subpaving/tactic/subpaving_tactic.cpp index cdd8bac0a..639528a7f 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.cpp +++ b/src/math/subpaving/tactic/subpaving_tactic.cpp @@ -37,8 +37,6 @@ class subpaving_tactic : public tactic { e2v.mk_inv(m_inv); } - virtual ~display_var_proc() {} - ast_manager & m() const { return m_inv.get_manager(); } void operator()(std::ostream & out, subpaving::var x) const override { diff --git a/src/model/array_factory.h b/src/model/array_factory.h index c4bfc05df..c77e619c9 100644 --- a/src/model/array_factory.h +++ b/src/model/array_factory.h @@ -32,8 +32,6 @@ class array_factory : public struct_factory { public: array_factory(ast_manager & m, model_core & md); - ~array_factory() override {} - expr * get_some_value(sort * s) override; bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) override; diff --git a/src/model/datatype_factory.cpp b/src/model/datatype_factory.cpp index 56312839a..c01b385d7 100644 --- a/src/model/datatype_factory.cpp +++ b/src/model/datatype_factory.cpp @@ -87,7 +87,7 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) { return val; } // Traverse constructors, and try to invoke get_fresh_value of one of the arguments (if the argument is not a sibling datatype of s). - // If the argumet is a sibling datatype of s, then + // If the argument is a sibling datatype of s, then // use get_last_fresh_value. ptr_vector const & constructors = *m_util.get_datatype_constructors(s); for (func_decl * constructor : constructors) { diff --git a/src/model/datatype_factory.h b/src/model/datatype_factory.h index 8ee4170e3..b2a6b75d3 100644 --- a/src/model/datatype_factory.h +++ b/src/model/datatype_factory.h @@ -32,7 +32,6 @@ class datatype_factory : public struct_factory { public: datatype_factory(ast_manager & m, model_core & md); - ~datatype_factory() override {} expr * get_some_value(sort * s) override; expr * get_fresh_value(sort * s) override; }; diff --git a/src/model/fpa_factory.h b/src/model/fpa_factory.h index ff2f18e35..1c2c98b25 100644 --- a/src/model/fpa_factory.h +++ b/src/model/fpa_factory.h @@ -34,8 +34,6 @@ class fpa_value_factory : public value_factory { value_factory(m, fid), m_util(m) {} - ~fpa_value_factory() override {} - expr * get_some_value(sort * s) override { mpf_manager & mpfm = m_util.fm(); diff --git a/src/model/model_macro_solver.h b/src/model/model_macro_solver.h index 1c04f8ec1..8070b4ada 100644 --- a/src/model/model_macro_solver.h +++ b/src/model/model_macro_solver.h @@ -20,7 +20,7 @@ Author: class quantifier2macro_infos { public: - virtual ~quantifier2macro_infos() {} + virtual ~quantifier2macro_infos() = default; virtual quantifier_macro_info* operator()(quantifier* q) = 0; }; @@ -48,7 +48,7 @@ public: m_model(nullptr) { } - virtual ~base_macro_solver() {} + virtual ~base_macro_solver() = default; /** \brief Try to satisfy quantifiers in qs by using macro definitions. diff --git a/src/model/numeral_factory.h b/src/model/numeral_factory.h index 6d805dd90..174ea8757 100644 --- a/src/model/numeral_factory.h +++ b/src/model/numeral_factory.h @@ -25,7 +25,6 @@ Revision History: class numeral_factory : public simple_factory { public: numeral_factory(ast_manager & m, family_id fid):simple_factory(m, fid) {} - ~numeral_factory() override {} }; class arith_factory : public numeral_factory { diff --git a/src/model/value_factory.h b/src/model/value_factory.h index 8df61c181..cf56439d9 100644 --- a/src/model/value_factory.h +++ b/src/model/value_factory.h @@ -230,7 +230,6 @@ class user_sort_factory : public simple_factory { app * mk_value_core(unsigned const & val, sort * s) override; public: user_sort_factory(ast_manager & m); - ~user_sort_factory() override {} /** \brief Make the universe of \c s finite, by preventing new diff --git a/src/muz/base/dl_boogie_proof.h b/src/muz/base/dl_boogie_proof.h index ed2f5a801..5107d9529 100644 --- a/src/muz/base/dl_boogie_proof.h +++ b/src/muz/base/dl_boogie_proof.h @@ -3,6 +3,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ +#pragma once /** diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 01523e8d2..4efe79dd3 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -53,7 +53,7 @@ namespace datalog { m_limited_size = ctx.get_decl_util().try_get_size(s, m_size); } public: - virtual ~sort_domain() {} + virtual ~sort_domain() = default; sort_kind get_kind() const { return m_kind; } virtual unsigned get_constant_count() const = 0; @@ -159,8 +159,6 @@ namespace datalog { public: restore_rules(context& ctx, rule_set& r): ctx(ctx), m_old_rules(alloc(rule_set, r)) {} - ~restore_rules() override {} - void undo() override { ctx.replace_rules(*m_old_rules); reset(); @@ -173,7 +171,6 @@ namespace datalog { unsigned m_old_size; public: restore_vec_size_trail(Vec& v): m_vector(v), m_old_size(v.size()) {} - ~restore_vec_size_trail() override {} void undo() override { m_vector.shrink(m_old_size); } }; diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index c35cfd58a..eae846835 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -105,7 +105,6 @@ namespace datalog { class rel_context_base : public engine_base { public: rel_context_base(ast_manager& m, char const* name): engine_base(m, name) {} - ~rel_context_base() override {} virtual relation_manager & get_rmanager() = 0; virtual const relation_manager & get_rmanager() const = 0; virtual relation_base & get_relation(func_decl * pred) = 0; @@ -141,7 +140,6 @@ namespace datalog { context const& ctx; public: contains_pred(context& ctx): ctx(ctx) {} - ~contains_pred() override {} bool operator()(expr* e) override { return ctx.is_predicate(e); @@ -307,7 +305,7 @@ namespace datalog { void register_predicate(func_decl * pred, bool named); /** - Restrict reltaions to set of predicates. + Restrict relations to set of predicates. */ void restrict_predicates(func_decl_set const& preds); diff --git a/src/muz/base/dl_costs.h b/src/muz/base/dl_costs.h index 333dac996..ea3efcda9 100644 --- a/src/muz/base/dl_costs.h +++ b/src/muz/base/dl_costs.h @@ -80,10 +80,8 @@ namespace datalog { bool passes_output_thresholds(context & ctx) const; void output_profile(std::ostream & out) const; - private: - //private and undefined copy constructor and operator= to avoid the default ones - accounted_object(const accounted_object &); - accounted_object& operator=(const accounted_object &); + accounted_object(const accounted_object &) = delete; + accounted_object& operator=(const accounted_object &) = delete; }; diff --git a/src/muz/base/dl_engine_base.h b/src/muz/base/dl_engine_base.h index fcf45abf9..64218f7d6 100644 --- a/src/muz/base/dl_engine_base.h +++ b/src/muz/base/dl_engine_base.h @@ -42,7 +42,7 @@ namespace datalog { std::string m_name; public: engine_base(ast_manager& m, char const* name): m(m), m_name(name) {} - virtual ~engine_base() {} + virtual ~engine_base() = default; virtual expr_ref get_answer() = 0; virtual expr_ref get_ground_sat_answer () { diff --git a/src/muz/base/dl_rule_subsumption_index.h b/src/muz/base/dl_rule_subsumption_index.h index 02f373377..9c29683b3 100644 --- a/src/muz/base/dl_rule_subsumption_index.h +++ b/src/muz/base/dl_rule_subsumption_index.h @@ -25,10 +25,6 @@ Revision History: namespace datalog { class rule_subsumption_index { - //private and undefined copy constroctor - rule_subsumption_index(rule_subsumption_index const&); - //private and undefined operator= - rule_subsumption_index& operator=(rule_subsumption_index const&); typedef obj_hashtable app_set; @@ -53,6 +49,8 @@ namespace datalog { reset_dealloc_values(m_unconditioned_heads); } + rule_subsumption_index(rule_subsumption_index const&) = delete; + rule_subsumption_index& operator=(rule_subsumption_index const&) = delete; void add(rule * r); bool is_subsumed(rule * r); bool is_subsumed(app * query); diff --git a/src/muz/base/dl_rule_transformer.h b/src/muz/base/dl_rule_transformer.h index 59eb24f55..c446593bd 100644 --- a/src/muz/base/dl_rule_transformer.h +++ b/src/muz/base/dl_rule_transformer.h @@ -89,7 +89,7 @@ namespace datalog { m_can_destratify_negation(can_destratify_negation), m_transformer(nullptr) {} public: - virtual ~plugin() {} + virtual ~plugin() = default; unsigned get_priority() { return m_priority; } bool can_destratify_negation() const { return m_can_destratify_negation; } diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index c0c3d839c..cf759c76e 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -25,7 +25,7 @@ Revision History: #include "muz/base/dl_context.h" #include "ast/scoped_proof.h" #include "ast/bv_decl_plugin.h" -#include "muz/rel/tbv.h" +#include "util/tbv.h" #include namespace datalog { diff --git a/src/muz/fp/datalog_parser.h b/src/muz/fp/datalog_parser.h index 2369f1d84..e836cbaec 100644 --- a/src/muz/fp/datalog_parser.h +++ b/src/muz/fp/datalog_parser.h @@ -27,7 +27,7 @@ namespace datalog { public: static parser * create(context& ctx, ast_manager & ast_manager); - virtual ~parser() {} + virtual ~parser() = default; virtual bool parse_file(char const * path) = 0; virtual bool parse_string(char const * string) = 0; @@ -37,7 +37,7 @@ namespace datalog { public: static wpa_parser * create(context& ctx, ast_manager & ast_manager); - virtual ~wpa_parser() {} + virtual ~wpa_parser() = default; virtual bool parse_directory(char const * path) = 0; }; diff --git a/src/muz/rel/CMakeLists.txt b/src/muz/rel/CMakeLists.txt index f03a90406..1129b6dd9 100644 --- a/src/muz/rel/CMakeLists.txt +++ b/src/muz/rel/CMakeLists.txt @@ -23,7 +23,6 @@ z3_add_component(rel doc.cpp karr_relation.cpp rel_context.cpp - tbv.cpp udoc_relation.cpp COMPONENT_DEPENDENCIES muz diff --git a/src/muz/rel/aig_exporter.cpp b/src/muz/rel/aig_exporter.cpp index c8ef1321f..e708c1457 100644 --- a/src/muz/rel/aig_exporter.cpp +++ b/src/muz/rel/aig_exporter.cpp @@ -35,7 +35,7 @@ namespace datalog { // reserve pred id = 0 for initialization purposes unsigned num_preds = (unsigned)predicates.size() + 1; - // poor's man round-up log2 + // poor man's round-up log2 unsigned preds_bitsize = log2(num_preds); if ((1U << preds_bitsize) < num_preds) ++preds_bitsize; diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index ff2210610..24b109f35 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -190,7 +190,6 @@ namespace datalog { const unsigned * cols1, const unsigned * cols2) : convenient_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2), m_join(j) {} - ~join_fn() override {} relation_base * operator()(const relation_base & r1, const relation_base & r2) override { check_relation const& t1 = get(r1); check_relation const& t2 = get(r2); @@ -219,7 +218,6 @@ namespace datalog { : convenient_join_project_fn(o1_sig, o2_sig, col_cnt, cols1, cols2, removed_col_cnt, removed_cols), m_join(j) {} - ~join_project_fn() override {} relation_base * operator()(const relation_base & r1, const relation_base & r2) override { check_relation const& t1 = get(r1); check_relation const& t2 = get(r2); @@ -527,8 +525,6 @@ namespace datalog { m_filter(f) { } - ~filter_identical_fn() override {} - void operator()(relation_base & _r) override { check_relation& r = get(_r); check_relation_plugin& p = r.get_plugin(); @@ -563,8 +559,6 @@ namespace datalog { m_condition(condition) { } - ~filter_interpreted_fn() override {} - void operator()(relation_base & tb) override { check_relation& r = get(tb); check_relation_plugin& p = r.get_plugin(); @@ -590,8 +584,6 @@ namespace datalog { m_project(p) { } - ~project_fn() override {} - relation_base * operator()(const relation_base & tb) override { check_relation const& t = get(tb); check_relation_plugin& p = t.get_plugin(); @@ -618,8 +610,6 @@ namespace datalog { m_permute(permute) { } - ~rename_fn() override {} - relation_base * operator()(const relation_base & _t) override { check_relation const& t = get(_t); check_relation_plugin& p = t.get_plugin(); @@ -647,7 +637,6 @@ namespace datalog { m_val(val), m_col(col) {} - ~filter_equal_fn() override { } void operator()(relation_base & tb) override { check_relation & t = get(tb); check_relation_plugin& p = t.get_plugin(); @@ -760,8 +749,6 @@ namespace datalog { m_cond(cond), m_xform(xform) {} - - ~filter_proj_fn() override {} relation_base* operator()(const relation_base & tb) override { check_relation const & t = get(tb); diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index 909539a85..ea317ca45 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -73,7 +73,7 @@ namespace datalog { /** - Termplate class containing common infrastructure for relations and tables + Template class containing common infrastructure for relations and tables */ template struct tr_infrastructure { @@ -179,11 +179,10 @@ namespace datalog { class base_fn { public: base_fn() = default; - virtual ~base_fn() {} - private: - //private and undefined copy constructor and operator= to avoid copying - base_fn(const base_fn &); - base_fn& operator=(const base_fn &); + virtual ~base_fn() = default; + + base_fn(const base_fn &) = delete; + base_fn& operator=(const base_fn &) = delete; }; class join_fn : public base_fn { @@ -261,7 +260,7 @@ namespace datalog { */ bool check_kind(base_object const& r) const { return &r.get_plugin()==this; } public: - virtual ~plugin_object() {} + virtual ~plugin_object() = default; virtual void initialize(family_id fid) { m_kind = fid; } @@ -424,7 +423,7 @@ namespace datalog { } #endif - virtual ~base_ancestor() {} + virtual ~base_ancestor() = default; void set_kind(family_id kind) { SASSERT(kind>=0); m_kind = kind; } @@ -799,7 +798,6 @@ namespace datalog { protected: relation_base(relation_plugin & plugin, const relation_signature & s) : base_ancestor(plugin, s) {} - ~relation_base() override {} public: virtual relation_base * complement(func_decl* p) const = 0; @@ -867,7 +865,7 @@ namespace datalog { class table_row_mutator_fn { public: - virtual ~table_row_mutator_fn() {} + virtual ~table_row_mutator_fn() = default; /** \brief The function is called for a particular table row. The \c func_columns contains a pointer to an array of functional column values that can be modified. If the function @@ -881,9 +879,9 @@ namespace datalog { class table_row_pair_reduce_fn { public: - virtual ~table_row_pair_reduce_fn() {} + virtual ~table_row_pair_reduce_fn() = default; /** - \brief The function is called for pair of table rows that became duplicit due to projection. + \brief The function is called for pair of table rows that became duplicated due to projection. The values that are in the first array after return from the function will be used for the resulting row. @@ -1040,7 +1038,6 @@ namespace datalog { protected: table_base(table_plugin & plugin, const table_signature & s) : base_ancestor(plugin, s) {} - ~table_base() override {} public: table_base * clone() const override; virtual table_base * complement(func_decl* p, const table_element * func_columns = nullptr) const; @@ -1098,7 +1095,10 @@ namespace datalog { unsigned m_ref_cnt; public: iterator_core() : m_ref_cnt(0) {} - virtual ~iterator_core() {} + virtual ~iterator_core() = default; + + iterator_core(const iterator_core &) = delete; + iterator_core & operator=(const iterator_core &) = delete; void inc_ref() { m_ref_cnt++; } void dec_ref() { @@ -1118,17 +1118,16 @@ namespace datalog { //the equality with the end() iterator return is_finished() && it.is_finished(); } - private: - //private and undefined copy constructor and assignment operator - iterator_core(const iterator_core &); - iterator_core & operator=(const iterator_core &); }; struct row_iterator_core { unsigned m_ref_cnt; public: row_iterator_core() : m_ref_cnt(0) {} - virtual ~row_iterator_core() {} + virtual ~row_iterator_core() = default; + + row_iterator_core(const row_iterator_core &) = delete; + row_iterator_core & operator=(const row_iterator_core &) = delete; void inc_ref() { m_ref_cnt++; } void dec_ref() { @@ -1148,10 +1147,6 @@ namespace datalog { //the equality with the end() iterator return is_finished() && it.is_finished(); } - private: - //private and undefined copy constructor and assignment operator - row_iterator_core(const row_iterator_core &); - row_iterator_core & operator=(const row_iterator_core &); }; public: @@ -1210,7 +1205,7 @@ namespace datalog { typedef row_iterator const_iterator; row_interface(const table_base & parent_table) : m_parent_table(parent_table) {} - virtual ~row_interface() {} + virtual ~row_interface() = default; virtual table_element operator[](unsigned col) const = 0; diff --git a/src/muz/rel/dl_external_relation.h b/src/muz/rel/dl_external_relation.h index 4b5689465..17e9a2364 100644 --- a/src/muz/rel/dl_external_relation.h +++ b/src/muz/rel/dl_external_relation.h @@ -26,7 +26,7 @@ namespace datalog { class external_relation_context { public: - virtual ~external_relation_context() {} + virtual ~external_relation_context() = default; virtual family_id get_family_id() const = 0; diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index 07921a3be..a991c9e6c 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -794,8 +794,6 @@ namespace datalog { m_delta_indexes(delta_indexes), m_delta_rels(delta_rels) {} - ~union_mapper() override {} - bool operator()(table_element * func_columns) override { relation_base & otgt_orig = m_tgt.get_inner_rel(func_columns[0]); const relation_base & osrc = m_src.get_inner_rel(func_columns[1]); diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h index 1edacc94f..a008c2b73 100644 --- a/src/muz/rel/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -317,7 +317,7 @@ namespace datalog { class instruction_block { public: struct instruction_observer { - virtual ~instruction_observer() {} + virtual ~instruction_observer() = default; virtual void notify(instruction * i) {} }; private: diff --git a/src/muz/rel/dl_lazy_table.h b/src/muz/rel/dl_lazy_table.h index f9a846c3a..9f88e6aa2 100644 --- a/src/muz/rel/dl_lazy_table.h +++ b/src/muz/rel/dl_lazy_table.h @@ -107,7 +107,7 @@ namespace datalog { public: lazy_table_ref(lazy_table_plugin& p, table_signature const& sig): m_plugin(p), m_signature(sig), m_ref(0) {} - virtual ~lazy_table_ref() {} + virtual ~lazy_table_ref() = default; void inc_ref() { ++m_ref; } void dec_ref() { --m_ref; if (0 == m_ref) dealloc(this); } void release_table() { m_table.release(); } @@ -128,8 +128,6 @@ namespace datalog { m_ref(t) {} - ~lazy_table() override {} - lazy_table_plugin& get_lplugin() const { return dynamic_cast(table_base::get_plugin()); } @@ -164,7 +162,6 @@ namespace datalog { m_table = table; // SASSERT(&p.m_plugin == &table->get_lplugin()); } - ~lazy_table_base() override {} lazy_table_kind kind() const override { return LAZY_TABLE_BASE; } table_base* force() override { return m_table.get(); } }; @@ -183,7 +180,6 @@ namespace datalog { m_cols2(col_cnt, cols2), m_t1(t1.get_ref()), m_t2(t2.get_ref()) { } - ~lazy_table_join() override {} lazy_table_kind kind() const override { return LAZY_TABLE_JOIN; } unsigned_vector const& cols1() const { return m_cols1; } unsigned_vector const& cols2() const { return m_cols2; } @@ -201,7 +197,6 @@ namespace datalog { : lazy_table_ref(src.get_lplugin(), sig), m_cols(col_cnt, cols), m_src(src.get_ref()) {} - ~lazy_table_project() override {} lazy_table_kind kind() const override { return LAZY_TABLE_PROJECT; } unsigned_vector const& cols() const { return m_cols; } @@ -217,8 +212,7 @@ namespace datalog { : lazy_table_ref(src.get_lplugin(), sig), m_cols(col_cnt, cols), m_src(src.get_ref()) {} - ~lazy_table_rename() override {} - + lazy_table_kind kind() const override { return LAZY_TABLE_RENAME; } unsigned_vector const& cols() const { return m_cols; } lazy_table_ref* src() const { return m_src.get(); } @@ -231,8 +225,7 @@ namespace datalog { public: lazy_table_filter_identical(unsigned col_cnt, const unsigned * cols, lazy_table const& src) : lazy_table_ref(src.get_lplugin(), src.get_signature()), m_cols(col_cnt, cols), m_src(src.get_ref()) {} - ~lazy_table_filter_identical() override {} - + lazy_table_kind kind() const override { return LAZY_TABLE_FILTER_IDENTICAL; } unsigned_vector const& cols() const { return m_cols; } lazy_table_ref* src() const { return m_src.get(); } @@ -249,8 +242,7 @@ namespace datalog { m_col(col), m_value(value), m_src(src.get_ref()) {} - ~lazy_table_filter_equal() override {} - + lazy_table_kind kind() const override { return LAZY_TABLE_FILTER_EQUAL; } unsigned col() const { return m_col; } table_element value() const { return m_value; } @@ -265,8 +257,7 @@ namespace datalog { lazy_table_filter_interpreted(lazy_table const& src, app* condition) : lazy_table_ref(src.get_lplugin(), src.get_signature()), m_condition(condition, src.get_lplugin().get_ast_manager()), m_src(src.get_ref()) {} - ~lazy_table_filter_interpreted() override {} - + lazy_table_kind kind() const override { return LAZY_TABLE_FILTER_INTERPRETED; } app* condition() const { return m_condition; } lazy_table_ref* src() const { return m_src.get(); } @@ -287,7 +278,6 @@ namespace datalog { m_src(src.get_ref()), m_cols1(c1), m_cols2(c2) {} - ~lazy_table_filter_by_negation() override {} lazy_table_kind kind() const override { return LAZY_TABLE_FILTER_BY_NEGATION; } lazy_table_ref* tgt() const { return m_tgt.get(); } lazy_table_ref* src() const { return m_src.get(); } diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index 3fa52ae2f..37fd3ef36 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -56,6 +56,7 @@ namespace datalog { pair_info() {} + pair_info & operator=(const pair_info &) = delete; bool can_be_joined() const { return m_consumers > 0; } @@ -110,8 +111,6 @@ namespace datalog { SASSERT(!m_rules.empty() || m_consumers == 0); return m_rules.empty(); } - private: - pair_info & operator=(const pair_info &); //to avoid the implicit one }; typedef std::pair app_pair; typedef pair_hash, obj_ptr_hash > app_pair_hash; diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 3b32a1532..9410e2ab0 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -999,7 +999,7 @@ namespace datalog { class relation_manager::auxiliary_table_transformer_fn { table_fact m_row; public: - virtual ~auxiliary_table_transformer_fn() {} + virtual ~auxiliary_table_transformer_fn() = default; virtual const table_signature & get_result_signature() const = 0; virtual void modify_fact(table_fact & f) const = 0; @@ -1230,18 +1230,18 @@ namespace datalog { /** - An auixiliary class for functors that perform filtering. It performs the table traversal + An auxiliary class for functors that perform filtering. It performs the table traversal and only asks for each individual row whether it should be removed. When using this class in multiple inheritance, this class should not be inherited publicly - and should be mentioned as last. This should ensure that deteletion of the object will + and should be mentioned as last. This should ensure that deletion of the object will go well when initiated from a pointer to the first ancestor. */ class relation_manager::auxiliary_table_filter_fn { table_fact m_row; svector m_to_remove; public: - virtual ~auxiliary_table_filter_fn() {} + virtual ~auxiliary_table_filter_fn() = default; virtual bool should_remove(const table_fact & f) const = 0; void operator()(table_base & r) { @@ -1589,8 +1589,6 @@ namespace datalog { m_union_fn = plugin.mk_union_fn(t, *m_aux_table, static_cast(nullptr)); } - ~default_table_map_fn() override {} - void operator()(table_base & t) override { SASSERT(t.get_signature()==m_aux_table->get_signature()); if(!m_aux_table->empty()) { @@ -1644,8 +1642,6 @@ namespace datalog { m_former_row.resize(get_result_signature().size()); } - ~default_table_project_with_reduce_fn() override {} - virtual void modify_fact(table_fact & f) const { unsigned ofs=1; unsigned r_i=1; diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp index 1481b5184..6c2373d54 100644 --- a/src/muz/rel/dl_sparse_table.cpp +++ b/src/muz/rel/dl_sparse_table.cpp @@ -274,7 +274,7 @@ namespace datalog { key_indexer(unsigned key_len, const unsigned * key_cols) : m_key_cols(key_len, key_cols) {} - virtual ~key_indexer() {} + virtual ~key_indexer() = default; virtual void update(const sparse_table & t) {} @@ -406,8 +406,6 @@ namespace datalog { m_key_fact.resize(t.get_signature().size()); } - ~full_signature_key_indexer() override {} - query_result get_matching_offsets(const key_value & key) const override { unsigned key_len = m_key_cols.size(); for (unsigned i=0; i class union_bvec; @@ -101,6 +101,8 @@ private: void project_rename(expr_ref& fml, bit_vector const& to_delete); void project_expand(expr_ref& fml, bit_vector const& to_delete); expr_ref to_formula(ast_manager& m, doc const& src); + expr_ref to_formula(ast_manager& m, tbv const& src); + expr_ref mk_var(ast_manager& m, unsigned i); void check_equiv(ast_manager& m, expr* fml1, expr* fml2); }; diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index b62da0766..6ef56c737 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -857,7 +857,7 @@ protected: context& m_ctx; public: lemma_generalizer(context& ctx): m_ctx(ctx) {} - virtual ~lemma_generalizer() {} + virtual ~lemma_generalizer() = default; virtual void operator()(lemma_ref &lemma) = 0; virtual void collect_statistics(statistics& st) const {} virtual void reset_statistics() {} diff --git a/src/muz/spacer/spacer_generalizers.h b/src/muz/spacer/spacer_generalizers.h index daa9dfbf2..ae1e53259 100644 --- a/src/muz/spacer/spacer_generalizers.h +++ b/src/muz/spacer/spacer_generalizers.h @@ -29,7 +29,6 @@ namespace spacer { class lemma_sanity_checker : public lemma_generalizer { public: lemma_sanity_checker(context &ctx) : lemma_generalizer(ctx) {} - ~lemma_sanity_checker() override {} void operator()(lemma_ref &lemma) override; }; @@ -59,7 +58,6 @@ class lemma_bool_inductive_generalizer : public lemma_generalizer { bool array_only = false) : lemma_generalizer(ctx), m_failure_limit(failure_limit), m_array_only(array_only) {} - ~lemma_bool_inductive_generalizer() override {} void operator()(lemma_ref &lemma) override; void collect_statistics(statistics &st) const override; @@ -83,7 +81,6 @@ class unsat_core_generalizer : public lemma_generalizer { public: unsat_core_generalizer(context &ctx) : lemma_generalizer(ctx) {} - ~unsat_core_generalizer() override {} void operator()(lemma_ref &lemma) override; void collect_statistics(statistics &st) const override; @@ -96,14 +93,12 @@ class lemma_array_eq_generalizer : public lemma_generalizer { public: lemma_array_eq_generalizer(context &ctx) : lemma_generalizer(ctx) {} - ~lemma_array_eq_generalizer() override {} void operator()(lemma_ref &lemma) override; }; class lemma_eq_generalizer : public lemma_generalizer { public: lemma_eq_generalizer(context &ctx) : lemma_generalizer(ctx) {} - ~lemma_eq_generalizer() override {} void operator()(lemma_ref &lemma) override; }; @@ -130,7 +125,6 @@ class lemma_quantifier_generalizer : public lemma_generalizer { public: lemma_quantifier_generalizer(context &ctx, bool normalize_cube = true); - ~lemma_quantifier_generalizer() override {} void operator()(lemma_ref &lemma) override; void collect_statistics(statistics &st) const override; @@ -174,7 +168,6 @@ class limit_num_generalizer : public lemma_generalizer { public: limit_num_generalizer(context &ctx, unsigned failure_limit); - ~limit_num_generalizer() override {} void operator()(lemma_ref &lemma) override; diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index 739588c6b..8b75adf88 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -88,8 +88,6 @@ public: m_old_hyp_reducer(old_hyp_reducer) {} - ~iuc_solver() override {} - /* iuc solver specific */ virtual void get_iuc(expr_ref_vector &core); void set_split_literals(bool v) { m_split_literals = v; } diff --git a/src/muz/spacer/spacer_legacy_frames.h b/src/muz/spacer/spacer_legacy_frames.h index 7ff4b6fad..cb78ec6a9 100644 --- a/src/muz/spacer/spacer_legacy_frames.h +++ b/src/muz/spacer/spacer_legacy_frames.h @@ -5,6 +5,7 @@ Notes: this file is included from the middle of spacer_context.h */ +#pragma once class legacy_frames { diff --git a/src/muz/spacer/spacer_unsat_core_plugin.h b/src/muz/spacer/spacer_unsat_core_plugin.h index 581a877cf..a7ea4c89b 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.h +++ b/src/muz/spacer/spacer_unsat_core_plugin.h @@ -31,7 +31,7 @@ namespace spacer { ast_manager& m; public: unsat_core_plugin(unsat_core_learner& learner); - virtual ~unsat_core_plugin() {}; + virtual ~unsat_core_plugin() = default; virtual void compute_partial_core(proof* step) = 0; virtual void finalize(){}; diff --git a/src/muz/transforms/dl_mk_karr_invariants.cpp b/src/muz/transforms/dl_mk_karr_invariants.cpp index 4436368ce..18d67f549 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.cpp +++ b/src/muz/transforms/dl_mk_karr_invariants.cpp @@ -105,8 +105,6 @@ namespace datalog { add_invariant_model_converter(ast_manager& m): m(m), a(m), m_funcs(m), m_invs(m) {} - ~add_invariant_model_converter() override { } - void add(func_decl* p, expr* inv) { if (!m.is_true(inv)) { m_funcs.push_back(p); diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index a0ceb8c73..b8a68a443 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -46,8 +46,6 @@ namespace datalog { qa_model_converter(ast_manager& m): m(m), m_old_funcs(m), m_new_funcs(m) {} - ~qa_model_converter() override {} - model_converter * translate(ast_translation & translator) override { return alloc(qa_model_converter, m); } diff --git a/src/muz/transforms/dl_mk_rule_inliner.h b/src/muz/transforms/dl_mk_rule_inliner.h index feae5405b..c0693fde0 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.h +++ b/src/muz/transforms/dl_mk_rule_inliner.h @@ -195,7 +195,6 @@ namespace datalog { m_head_visitor(ctx, m_subst), m_tail_visitor(ctx, m_subst) {} - ~mk_rule_inliner() override { } rule_set * operator()(rule_set const & source) override; }; diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index efa932fec..38305a04e 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -30,8 +30,6 @@ namespace datalog { public: scale_model_converter(ast_manager& m): m(m), m_trail(m), a(m) {} - ~scale_model_converter() override {} - void add_new2old(func_decl* new_f, func_decl* old_f) { m_trail.push_back(old_f); m_trail.push_back(new_f); diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index 28cbf638e..eda00b64d 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -111,8 +111,6 @@ namespace datalog { rule_unifier m_unifier; - slice_proof_converter(slice_proof_converter const& other); - void init_form2rule() { if (!m_sliceform2rule.empty()) { return; @@ -271,6 +269,8 @@ namespace datalog { m_renaming.insert(orig_rule, unsigned_vector(sz, renaming)); } + slice_proof_converter(slice_proof_converter const& other) = delete; + proof_ref operator()(ast_manager& m, unsigned num_source, proof * const * source) override { SASSERT(num_source == 1); proof_ref result(source[0], m); diff --git a/src/muz/transforms/dl_mk_slice.h b/src/muz/transforms/dl_mk_slice.h index 4a6d707f0..807c6dac4 100644 --- a/src/muz/transforms/dl_mk_slice.h +++ b/src/muz/transforms/dl_mk_slice.h @@ -99,8 +99,6 @@ namespace datalog { */ mk_slice(context & ctx); - ~mk_slice() override { } - rule_set * operator()(rule_set const & source) override; func_decl* get_predicate(func_decl* p) { func_decl* q = p; m_predicates.find(p, q); return q; } diff --git a/src/nlsat/nlsat_assignment.h b/src/nlsat/nlsat_assignment.h index 11e82fd30..6729b73cd 100644 --- a/src/nlsat/nlsat_assignment.h +++ b/src/nlsat/nlsat_assignment.h @@ -32,7 +32,6 @@ namespace nlsat { bool_vector m_assigned; public: assignment(anum_manager & _m):m_values(_m) {} - virtual ~assignment() {} anum_manager & am() const { return m_values.m(); } void swap(assignment & other) { m_values.swap(other.m_values); diff --git a/src/opt/maxcore.cpp b/src/opt/maxcore.cpp index 20cc028aa..d29da86f7 100644 --- a/src/opt/maxcore.cpp +++ b/src/opt/maxcore.cpp @@ -12,8 +12,8 @@ Abstract: - 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 - - rc2t: implementaion of rc2 heuristic using totalizerx + - rc2: implementation of rc2 heuristic using cardinality constraints + - rc2t: implementation of rc2 heuristic using totalizerx - 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. @@ -27,7 +27,7 @@ Abstract: constraints the approach works like max-res. Given a (maximal) satisfying subset of the soft constraints the approach updates the upper bound if the current assignment - improves the current best assignmet. + improves the current best assignment. Furthermore, take the soft constraints that are complements to the current satisfying subset. E.g, if F are the hard constraints and @@ -44,7 +44,7 @@ Abstract: 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 + In summary: any assignment to the new clauses that satisfies F has the same cost. Claim: If there are no satisfying assignments to F, then the current best assignment @@ -100,7 +100,6 @@ private: 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); } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 2f8992e01..ac39d7891 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -42,7 +42,7 @@ namespace opt { class maxsmt_solver { public: - virtual ~maxsmt_solver() {} + virtual ~maxsmt_solver() = default; virtual lbool operator()() = 0; virtual rational get_lower() const = 0; virtual rational get_upper() const = 0; @@ -85,7 +85,6 @@ namespace opt { public: maxsmt_solver_base(maxsat_context& c, vector& soft, unsigned index); - ~maxsmt_solver_base() override {} rational get_lower() const override { return m_lower; } rational get_upper() const override { return m_upper; } bool get_assignment(unsigned index) const override { return m_soft[index].is_true(); } diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 41f7bedb3..1daed0e3b 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -56,9 +56,6 @@ public: m_opt(opt) {} - ~assert_soft_cmd() override { - } - void reset(cmd_context & ctx) override { m_idx = 0; m_formula = nullptr; diff --git a/src/opt/opt_lns.h b/src/opt/opt_lns.h index 8e16ec5c8..1bc27f9b1 100644 --- a/src/opt/opt_lns.h +++ b/src/opt/opt_lns.h @@ -28,7 +28,7 @@ namespace opt { class lns_context { public: - virtual ~lns_context() {} + virtual ~lns_context() = default; virtual void update_model(model_ref& mdl) = 0; virtual void relax_cores(vector const& cores) = 0; virtual rational cost(model& mdl) = 0; diff --git a/src/opt/opt_pareto.h b/src/opt/opt_pareto.h index a814ac0f8..105f4007f 100644 --- a/src/opt/opt_pareto.h +++ b/src/opt/opt_pareto.h @@ -52,7 +52,7 @@ namespace opt { m_solver(s), m_params(p) { } - virtual ~pareto_base() {} + virtual ~pareto_base() = default; virtual void updt_params(params_ref & p) { m_solver->updt_params(p); m_params.copy(p); @@ -87,7 +87,6 @@ namespace opt { params_ref & p): pareto_base(m, cb, s, p) { } - ~gia_pareto() override {} lbool operator()() override; }; @@ -101,7 +100,6 @@ namespace opt { params_ref & p): pareto_base(m, cb, s, p) { } - ~oia_pareto() override {} lbool operator()() override; }; diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 5256dd47a..2867f52a3 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -55,7 +55,7 @@ namespace opt { { updt_params(p); } - virtual ~sls_solver() {} + virtual ~sls_solver() = default; virtual void updt_params(params_ref & p) { m_solver->updt_params(p); diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index 962369bf2..da25e2285 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -39,8 +39,6 @@ namespace opt { sortmax(maxsat_context& c, vector& s, unsigned index): maxsmt_solver_base(c, s, index), m_sort(*this), m_trail(m), m_fresh(m) {} - ~sortmax() override {} - lbool operator()() override { if (!init()) return l_undef; diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 1fbd26cb8..1fb6c05dd 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -49,8 +49,6 @@ namespace opt { m_trail(m), m_defs(m) {} - ~wmax() override {} - lbool operator()() override { TRACE("opt", tout << "weighted maxsat\n";); scoped_ensure_theory wth(*this); diff --git a/src/params/CMakeLists.txt b/src/params/CMakeLists.txt index ca6268157..f420ddd6d 100644 --- a/src/params/CMakeLists.txt +++ b/src/params/CMakeLists.txt @@ -15,6 +15,7 @@ z3_add_component(params poly_rewriter_params.pyg rewriter_params.pyg seq_rewriter_params.pyg + solver_params.pyg EXTRA_REGISTER_MODULE_HEADERS context_params.h ) diff --git a/src/solver/solver_params.pyg b/src/params/solver_params.pyg similarity index 69% rename from src/solver/solver_params.pyg rename to src/params/solver_params.pyg index 21d0ab530..768509b5b 100644 --- a/src/solver/solver_params.pyg +++ b/src/params/solver_params.pyg @@ -5,5 +5,7 @@ def_module_params('solver', params=(('smtlib2_log', SYMBOL, '', "file to save solver interaction"), ('cancel_backup_file', SYMBOL, '', "file to save partial search state if search is canceled"), ('timeout', UINT, UINT_MAX, "timeout on the solver object; overwrites a global timeout"), + ('lemmas2console', BOOL, False, 'print lemmas during search'), + ('axioms2files', BOOL, False, 'print negated theory axioms to separate files during search'), )) diff --git a/src/qe/mbp/mbp_plugin.h b/src/qe/mbp/mbp_plugin.h index 12b592960..4f73b92e6 100644 --- a/src/qe/mbp/mbp_plugin.h +++ b/src/qe/mbp/mbp_plugin.h @@ -59,7 +59,7 @@ namespace mbp { public: project_plugin(ast_manager& m) :m(m), m_cache(m), m_args(m), m_pure_eqs(m) {} - virtual ~project_plugin() {} + virtual ~project_plugin() = default; virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { return false; } /** \brief partial solver. diff --git a/src/qe/mbp/mbp_solve_plugin.h b/src/qe/mbp/mbp_solve_plugin.h index 27e7f85a8..2450eab4f 100644 --- a/src/qe/mbp/mbp_solve_plugin.h +++ b/src/qe/mbp/mbp_solve_plugin.h @@ -36,7 +36,7 @@ namespace mbp { bool is_variable(expr* e) const { return m_is_var(e); } public: solve_plugin(ast_manager& m, family_id fid, is_variable_proc& is_var) : m(m), m_id(fid), m_is_var(is_var) {} - virtual ~solve_plugin() {} + virtual ~solve_plugin() = default; family_id get_family_id() const { return m_id; } /// Process (and potentially augment) a literal expr_ref operator() (expr *lit); diff --git a/src/qe/nlarith_util.cpp b/src/qe/nlarith_util.cpp index 4a4997de6..e86e42091 100644 --- a/src/qe/nlarith_util.cpp +++ b/src/qe/nlarith_util.cpp @@ -1616,7 +1616,6 @@ namespace nlarith { public: simple_branch(ast_manager& m, app* cnstr): m_cnstr(cnstr, m), m_atoms(m) {} - ~simple_branch() override {} app* get_constraint() override { return m_cnstr.get(); } void get_updates(ptr_vector& atoms, svector& updates) override { for (unsigned i = 0; i < m_atoms.size(); ++i) { @@ -1636,7 +1635,6 @@ namespace nlarith { public: ins_rem_branch(ast_manager& m, app* a, app* r, app* cnstr): simple_branch(m, cnstr) { insert(a); remove(r); } - ~ins_rem_branch() override {} }; /** diff --git a/src/qe/nlarith_util.h b/src/qe/nlarith_util.h index acbe4889e..dccc4f606 100644 --- a/src/qe/nlarith_util.h +++ b/src/qe/nlarith_util.h @@ -116,7 +116,7 @@ namespace nlarith { class eval { public: - virtual ~eval() {} + virtual ~eval() = default; virtual lbool operator()(app* a) = 0; }; @@ -124,7 +124,7 @@ namespace nlarith { class branch { public: - virtual ~branch() {} + virtual ~branch() = default; virtual app* get_constraint() = 0; virtual void get_updates(ptr_vector& atoms, svector& updates) = 0; }; diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index 37924496a..3a1fa19c6 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -835,9 +835,6 @@ namespace qe { m_nftactic = mk_tseitin_cnf_tactic(m); } - ~nlqsat() override { - } - char const* name() const override { return "nlqsat"; } void updt_params(params_ref const & p) override { diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 509b73835..d859880d8 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -877,7 +877,7 @@ namespace qe { class quant_elim { public: - virtual ~quant_elim() {} + virtual ~quant_elim() = default; virtual lbool eliminate_exists( unsigned num_vars, app* const* vars, diff --git a/src/qe/qe.h b/src/qe/qe.h index a5152522f..55729d0b5 100644 --- a/src/qe/qe.h +++ b/src/qe/qe.h @@ -149,7 +149,7 @@ namespace qe { m_ctx(ctx) {} - virtual ~qe_solver_plugin() {} + virtual ~qe_solver_plugin() = default; family_id get_family_id() { return m_fid; } diff --git a/src/qe/qe_array_plugin.cpp b/src/qe/qe_array_plugin.cpp index 43d2f9686..ce0e61d02 100644 --- a/src/qe/qe_array_plugin.cpp +++ b/src/qe/qe_array_plugin.cpp @@ -27,9 +27,6 @@ namespace qe { { } - ~array_plugin() override {} - - void assign(contains_app& x, expr* fml, rational const& vl) override { UNREACHABLE(); } diff --git a/src/qe/qe_cmd.cpp b/src/qe/qe_cmd.cpp index f708d5223..12605defd 100644 --- a/src/qe/qe_cmd.cpp +++ b/src/qe/qe_cmd.cpp @@ -26,9 +26,6 @@ public: p.insert("print_statistics", CPK_BOOL, "(default: false) print statistics."); } - ~qe_cmd() override { - } - void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); m_target = nullptr; diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 0261ad979..b261e44be 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -536,6 +536,7 @@ namespace qe { th_rewriter rewrite(m); rewrite(a); rewrite(b); + TRACE("interpolator", tout << a << " " << b << "\n"); solver_ref sA = sf(m, p, false /* no proofs */, true, true, symbol::null); solver_ref sB = sf(m, p, false /* no proofs */, true, true, symbol::null); solver_ref sNotA = sf(m, p, false /* no proofs */, true, true, symbol::null); diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index d7b825fcd..70c0f98bb 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -43,7 +43,7 @@ namespace qe { lbool is_shared_cached(expr* e); public: mbi_plugin(ast_manager& m): m(m), m_shared_trail(m) {} - virtual ~mbi_plugin() {} + virtual ~mbi_plugin() = default; /** * Set the shared symbols. @@ -106,7 +106,6 @@ namespace qe { solver_ref m_solver; public: prop_mbi_plugin(solver* s); - ~prop_mbi_plugin() override {} mbi_result operator()(expr_ref_vector& lits, model_ref& mdl) override; void block(expr_ref_vector const& lits) override; }; @@ -134,7 +133,6 @@ namespace qe { expr_ref_vector& uflits); public: uflia_mbi(solver* s, solver* emptySolver); - ~uflia_mbi() override {} mbi_result operator()(expr_ref_vector& lits, model_ref& mdl) override; void project(model_ref& mdl, expr_ref_vector& lits); void block(expr_ref_vector const& lits) override; diff --git a/src/sat/sat_cut_simplifier.cpp b/src/sat/sat_cut_simplifier.cpp index d43219f25..71a98ba05 100644 --- a/src/sat/sat_cut_simplifier.cpp +++ b/src/sat/sat_cut_simplifier.cpp @@ -179,7 +179,7 @@ namespace sat { for (; m_config.m_enable_units && m_trail_size < s.init_trail_size(); ++m_trail_size) { literal lit = s.trail_literal(m_trail_size); - m_aig_cuts.add_node(lit, and_op, 0, 0); + m_aig_cuts.add_node(lit, and_op, 0, nullptr); } clause_vector clauses(s.clauses()); diff --git a/src/sat/sat_cutset_compute_shift.h b/src/sat/sat_cutset_compute_shift.h index 7a9aff612..45d2e1de8 100644 --- a/src/sat/sat_cutset_compute_shift.h +++ b/src/sat/sat_cutset_compute_shift.h @@ -18,6 +18,7 @@ The truth table covers up to 6 inputs, which fits in 64 bits. --*/ +#pragma once static uint64_t compute_shift(uint64_t x, unsigned code) { switch (code) { diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 1bb37b7d7..ffcb95587 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -70,7 +70,7 @@ namespace sat { solver* m_solver { nullptr }; public: extension(symbol const& name, int id): m_id(id), m_name(name) { } - virtual ~extension() {} + virtual ~extension() = default; int get_id() const { return m_id; } void set_solver(solver* s) { m_solver = s; } solver& s() { return *m_solver; } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 409d03652..97405fb32 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1812,9 +1812,9 @@ namespace sat { CTRACE("resolve_bug", !c1.contains(l) || !c2.contains(~l), tout << c1 << "\n" << c2 << "\nl: " << l << "\n";); if (m_visited.size() <= 2*s.num_vars()) m_visited.resize(2*s.num_vars(), false); - if (c1.was_removed()) + if (c1.was_removed() && !c1.contains(l)) return false; - if (c2.was_removed()) + if (c2.was_removed() && !c2.contains(~l)) return false; SASSERT(c1.contains(l)); SASSERT(c2.contains(~l)); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 3d46ec643..57531ef8a 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -115,8 +115,6 @@ public: return m_solver.get_config().m_incremental; } - ~inc_sat_solver() override {} - solver* translate(ast_manager& dst_m, params_ref const& p) override { if (m_num_scopes > 0) { throw default_exception("Cannot translate sat solver at non-base level"); @@ -659,7 +657,8 @@ public: } euf::solver* ensure_euf() { - auto* ext = dynamic_cast(m_solver.get_extension()); + m_goal2sat.init(m, m_params, m_solver, m_map, m_dep2asm, is_incremental()); + auto* ext = m_goal2sat.ensure_euf(); return ext; } diff --git a/src/sat/sat_solver_core.h b/src/sat/sat_solver_core.h index 407deae5c..5c8b7e315 100644 --- a/src/sat/sat_solver_core.h +++ b/src/sat/sat_solver_core.h @@ -31,7 +31,7 @@ namespace sat { reslimit& m_rlimit; public: solver_core(reslimit& l) : m_rlimit(l) {} - virtual ~solver_core() {} + virtual ~solver_core() = default; // add clauses virtual void add_clause(unsigned n, literal* lits, status st) = 0; diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index fa42f0712..db13db054 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -80,7 +80,7 @@ namespace sat { class i_local_search { public: - virtual ~i_local_search() {} + virtual ~i_local_search() = default; virtual void add(solver const& s) = 0; virtual void updt_params(params_ref const& p) = 0; virtual void set_seed(unsigned s) = 0; diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index df1fecc49..e824b01ad 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -265,7 +265,8 @@ namespace array { args1.push_back(e1); args2.push_back(e2); for (func_decl* f : funcs) { - expr* k = m.mk_app(f, e1, e2); + expr_ref k(m.mk_app(f, e1, e2), m); + rewrite(k); args1.push_back(k); args2.push_back(k); } diff --git a/src/sat/smt/bv_internalize.cpp b/src/sat/smt/bv_internalize.cpp index 8fb6ff95d..9d4719544 100644 --- a/src/sat/smt/bv_internalize.cpp +++ b/src/sat/smt/bv_internalize.cpp @@ -137,7 +137,9 @@ namespace bv { return true; SASSERT(!n || !n->is_attached_to(get_id())); - bool suppress_args = !reflect() && !m.is_considered_uninterpreted(a->get_decl()); + bool suppress_args = !reflect() + && !m.is_considered_uninterpreted(a->get_decl()) + && !bv.is_int2bv(e) && !bv.is_bv2int(e); if (!n) n = mk_enode(e, suppress_args); diff --git a/src/sat/smt/bv_solver.h b/src/sat/smt/bv_solver.h index b72754f4f..5920f70f6 100644 --- a/src/sat/smt/bv_solver.h +++ b/src/sat/smt/bv_solver.h @@ -313,7 +313,6 @@ namespace bv { public: solver(euf::solver& ctx, theory_id id); - ~solver() override {} void set_lookahead(sat::lookahead* s) override { } void init_search() override {} double get_reward(literal l, sat::ext_constraint_idx idx, sat::literal_occs_fun& occs) const override; diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 12e066437..d5cf08383 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -778,7 +778,7 @@ namespace euf { } for (auto const& thv : enode_th_vars(n)) { auto* th = m_id2solver.get(thv.get_id(), nullptr); - if (th && !th->is_fixed(thv.get_var(), val, explain)) + if (th && th->is_fixed(thv.get_var(), val, explain)) return true; } return false; @@ -1067,10 +1067,7 @@ namespace euf { user_propagator::fresh_eh_t& fresh_eh) { m_user_propagator = alloc(user_solver::solver, *this); m_user_propagator->add(ctx, push_eh, pop_eh, fresh_eh); - for (unsigned i = m_scopes.size(); i-- > 0; ) - m_user_propagator->push(); - m_solvers.push_back(m_user_propagator); - m_id2solver.setx(m_user_propagator->get_id(), m_user_propagator, nullptr); + add_solver(m_user_propagator); } bool solver::watches_fixed(enode* n) const { diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index c92efdb7d..13d3e02e4 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -1795,9 +1795,9 @@ namespace pb { } if (c.lit() != sat::null_literal && value(c.lit()) != l_true) return true; SASSERT(c.lit() == sat::null_literal || lvl(c.lit()) == 0 || (c.is_watched(*this, c.lit()) && c.is_watched(*this, ~c.lit()))); - if (eval(c) == l_true) { + if (eval(c) == l_true) return true; - } + literal_vector lits(c.literals()); for (literal l : lits) { if (lvl(l) == 0) continue; @@ -1823,6 +1823,8 @@ namespace pb { } bool solver::validate_watch(pbc const& p, literal alit) const { + if (p.lit() == sat::null_literal || value(p.lit()) != l_true) + return true; for (unsigned i = 0; i < p.size(); ++i) { literal l = p[i].second; if (l != alit && lvl(l) != 0 && p.is_watched(*this, l) != (i < p.num_watch())) { @@ -1833,9 +1835,8 @@ namespace pb { } } unsigned slack = 0; - for (unsigned i = 0; i < p.num_watch(); ++i) { - slack += p[i].first; - } + for (unsigned i = 0; i < p.num_watch(); ++i) + slack += p[i].first; if (slack != p.slack()) { IF_VERBOSE(0, display(verbose_stream(), p, true);); UNREACHABLE(); diff --git a/src/sat/smt/q_mam.cpp b/src/sat/smt/q_mam.cpp index 4be554633..91f19806a 100644 --- a/src/sat/smt/q_mam.cpp +++ b/src/sat/smt/q_mam.cpp @@ -1961,7 +1961,7 @@ namespace q { for (unsigned i = 0; i < num_args; i++) m_args[i] = m_registers[pc->m_iregs[i]]->get_root(); for (enode* n : euf::enode_class(r)) { - if (n->get_decl() == f) { + if (n->get_decl() == f && num_args == n->num_args()) { unsigned i = 0; for (; i < num_args; i++) { if (n->get_arg(i)->get_root() != m_args[i]) @@ -3744,9 +3744,6 @@ namespace q { reset_pp_pc(); } - ~mam_impl() override { - } - void add_pattern(quantifier * qa, app * mp) override { SASSERT(m.is_pattern(mp)); TRACE("trigger_bug", tout << "adding pattern\n" << mk_ismt2_pp(qa, m) << "\n" << mk_ismt2_pp(mp, m) << "\n";); diff --git a/src/sat/smt/q_mam.h b/src/sat/smt/q_mam.h index c396a319b..9fc6d18f1 100644 --- a/src/sat/smt/q_mam.h +++ b/src/sat/smt/q_mam.h @@ -45,7 +45,7 @@ namespace q { static mam * mk(euf::solver& ctx, ematch& em); - virtual ~mam() {} + virtual ~mam() = default; virtual void add_pattern(quantifier * q, app * mp) = 0; diff --git a/src/sat/smt/q_model_fixer.cpp b/src/sat/smt/q_model_fixer.cpp index 52d1a064c..37e2424ce 100644 --- a/src/sat/smt/q_model_fixer.cpp +++ b/src/sat/smt/q_model_fixer.cpp @@ -45,7 +45,6 @@ namespace q { arith_util a; public: arith_projection(ast_manager& m) : projection_function(m), a(m) {} - ~arith_projection() override {} bool operator()(expr* e1, expr* e2) const override { return lt(a, e1, e2); } expr* mk_lt(expr* x, expr* y) override { return a.mk_lt(x, y); } }; @@ -54,7 +53,6 @@ namespace q { bv_util bvu; public: ubv_projection(ast_manager& m) : projection_function(m), bvu(m) {} - ~ubv_projection() override {} bool operator()(expr* e1, expr* e2) const override { return lt(bvu, e1, e2); } expr* mk_lt(expr* x, expr* y) override { return m.mk_not(bvu.mk_ule(y, x)); } }; diff --git a/src/sat/smt/q_model_fixer.h b/src/sat/smt/q_model_fixer.h index a843d3825..2c16504c6 100644 --- a/src/sat/smt/q_model_fixer.h +++ b/src/sat/smt/q_model_fixer.h @@ -43,7 +43,7 @@ namespace q { ast_manager& m; public: projection_function(ast_manager& m) : m(m) {} - virtual ~projection_function() {} + virtual ~projection_function() = default; virtual expr* mk_lt(expr* a, expr* b) = 0; expr* mk_le(expr* a, expr* b) { return m.mk_not(mk_lt(b, a)); } virtual bool operator()(expr* a, expr* b) const = 0; @@ -95,7 +95,6 @@ namespace q { public: model_fixer(euf::solver& ctx, solver& qs); - ~model_fixer() override {} /** * Update model in order to best satisfy quantifiers. diff --git a/src/sat/smt/q_solver.h b/src/sat/smt/q_solver.h index 5d6a52c8f..32025888b 100644 --- a/src/sat/smt/q_solver.h +++ b/src/sat/smt/q_solver.h @@ -65,7 +65,6 @@ namespace q { public: solver(euf::solver& ctx, family_id fid); - ~solver() override {} bool is_external(sat::bool_var v) override { return false; } void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) override; void asserted(sat::literal l) override; diff --git a/src/sat/smt/sat_internalizer.h b/src/sat/smt/sat_internalizer.h index 43413a893..e7d0d9b43 100644 --- a/src/sat/smt/sat_internalizer.h +++ b/src/sat/smt/sat_internalizer.h @@ -21,7 +21,7 @@ Author: namespace sat { class sat_internalizer { public: - virtual ~sat_internalizer() {} + virtual ~sat_internalizer() = default; virtual bool is_bool_op(expr* e) const = 0; virtual literal internalize(expr* e, bool learned) = 0; virtual bool_var to_bool_var(expr* e) = 0; diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index 4484a7717..833b6c05e 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -39,7 +39,7 @@ namespace euf { virtual bool post_visit(expr* e, bool sign, bool root) { return false; } public: - virtual ~th_internalizer() {} + virtual ~th_internalizer() = default; virtual sat::literal internalize(expr* e, bool sign, bool root, bool redundant) = 0; @@ -60,7 +60,7 @@ namespace euf { class th_decompile { public: - virtual ~th_decompile() {} + virtual ~th_decompile() = default; virtual bool to_formulas(std::function& lit2expr, expr_ref_vector& fmls) { return false; } }; @@ -68,7 +68,7 @@ namespace euf { class th_model_builder { public: - virtual ~th_model_builder() {} + virtual ~th_model_builder() = default; /** \brief compute the value for enode \c n and store the value in \c values @@ -189,7 +189,6 @@ namespace euf { public: th_euf_solver(euf::solver& ctx, symbol const& name, euf::theory_id id); - virtual ~th_euf_solver() {} virtual theory_var mk_var(enode* n); unsigned get_num_vars() const { return m_var2enode.size(); } euf::enode* e_internalize(expr* e); diff --git a/src/sat/smt/user_solver.cpp b/src/sat/smt/user_solver.cpp index 9e2ea3eab..494e69e55 100644 --- a/src/sat/smt/user_solver.cpp +++ b/src/sat/smt/user_solver.cpp @@ -131,6 +131,21 @@ namespace user_solver { m_id2justification.setx(v, lits, sat::literal_vector()); m_fixed_eh(m_user_context, this, var2expr(v), lit.sign() ? m.mk_false() : m.mk_true()); } + + void solver::new_eq_eh(euf::th_eq const& eq) { + if (!m_eq_eh) + return; + force_push(); + m_eq_eh(m_user_context, this, var2expr(eq.v1()), var2expr(eq.v2())); + } + + void solver::new_diseq_eh(euf::th_eq const& de) { + if (!m_diseq_eh) + return; + force_push(); + m_diseq_eh(m_user_context, this, var2expr(de.v1()), var2expr(de.v2())); + } + void solver::push_core() { th_euf_solver::push_core(); diff --git a/src/sat/smt/user_solver.h b/src/sat/smt/user_solver.h index 951b97fb6..28528b9a1 100644 --- a/src/sat/smt/user_solver.h +++ b/src/sat/smt/user_solver.h @@ -144,6 +144,10 @@ namespace user_solver { bool get_case_split(sat::bool_var& var, lbool &phase) override; void asserted(sat::literal lit) override; + bool use_diseqs() const override { return (bool)m_diseq_eh; } + void new_eq_eh(euf::th_eq const& eq) override; + void new_diseq_eh(euf::th_eq const& de) override; + sat::check_result check() override; void push_core() override; void pop_core(unsigned n) override; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 73d8561df..1e44c6c21 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -93,10 +93,6 @@ struct goal2sat::imp : public sat::sat_internalizer { updt_params(p); } - ~imp() override { - } - - sat::cut_simplifier* aig() { return m_solver.get_cut_simplifier(); } @@ -1017,6 +1013,11 @@ goal2sat::~goal2sat() { dealloc(m_imp); } +euf::solver* goal2sat::ensure_euf() { + return m_imp->ensure_euf(); +} + + void goal2sat::collect_param_descrs(param_descrs & r) { insert_max_memory(r); r.insert("ite_extra", CPK_BOOL, "(default: true) add redundant clauses (that improve unit propagation) when encoding if-then-else formulas"); diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index 08fd5f088..5f85d59ce 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -33,6 +33,10 @@ Notes: #include "sat/smt/atom2bool_var.h" #include "sat/smt/sat_internalizer.h" +namespace euf { + class solver; +} + class goal2sat { public: typedef obj_map dep2asm_map; @@ -41,7 +45,6 @@ private: imp * m_imp; 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(); @@ -66,6 +69,9 @@ public: 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 init(ast_manager& m, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external); + + 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); @@ -82,4 +88,6 @@ public: void user_pop(unsigned n); + euf::solver* ensure_euf(); + }; diff --git a/src/sat/tactic/sat2goal.h b/src/sat/tactic/sat2goal.h index b911f7b47..1e1dfcd5e 100644 --- a/src/sat/tactic/sat2goal.h +++ b/src/sat/tactic/sat2goal.h @@ -51,7 +51,6 @@ public: public: mc(ast_manager& m); - ~mc() override {} // flush model converter from SAT solver to this structure. void flush_smc(sat::solver& s, atom2bool_var const& map); void operator()(sat::model& m); diff --git a/src/shell/CMakeLists.txt b/src/shell/CMakeLists.txt index d55626d05..d9b74f162 100644 --- a/src/shell/CMakeLists.txt +++ b/src/shell/CMakeLists.txt @@ -34,6 +34,14 @@ add_executable(shell # we don't want (I think). ${shell_object_files} ) + +set_target_properties(shell PROPERTIES + # Position independent code needed in shared libraries + POSITION_INDEPENDENT_CODE ON + # Symbol visibility + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON) + z3_add_install_tactic_rule(${shell_deps}) z3_add_memory_initializer_rule(${shell_deps}) z3_add_gparams_register_modules_rule(${shell_deps}) diff --git a/src/shell/options.h b/src/shell/options.h index ee1de00fb..39fe2fe8f 100644 --- a/src/shell/options.h +++ b/src/shell/options.h @@ -3,6 +3,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ +#pragma once /** diff --git a/src/smt/.#smt_justification.h b/src/smt/.#smt_justification.h new file mode 100644 index 000000000..0852723f4 --- /dev/null +++ b/src/smt/.#smt_justification.h @@ -0,0 +1 @@ +nbjorner@DESKTOP-7DPTQP8.49008:1659539981 \ No newline at end of file diff --git a/src/smt/arith_eq_adapter.cpp b/src/smt/arith_eq_adapter.cpp index f251d01ae..b77a38927 100644 --- a/src/smt/arith_eq_adapter.cpp +++ b/src/smt/arith_eq_adapter.cpp @@ -67,8 +67,6 @@ namespace smt { m_ge(ge) { } - ~arith_eq_relevancy_eh() override {} - void operator()(relevancy_propagator & rp) override { if (!rp.is_relevant(m_n1)) return; diff --git a/src/smt/database.h b/src/smt/database.h index 3edb87f1f..f1ce25f26 100644 --- a/src/smt/database.h +++ b/src/smt/database.h @@ -3,6 +3,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ +#pragma once static char const g_pattern_database[] = "(benchmark patterns \n" diff --git a/src/smt/dyn_ack.cpp b/src/smt/dyn_ack.cpp index 42844f575..978f1fbe3 100644 --- a/src/smt/dyn_ack.cpp +++ b/src/smt/dyn_ack.cpp @@ -346,7 +346,6 @@ namespace smt { dyn_ack_clause_del_eh(dyn_ack_manager & m): m(m) { } - ~dyn_ack_clause_del_eh() override {} void operator()(ast_manager & _m, clause * cls) override { m.del_clause_eh(cls); dealloc(this); diff --git a/src/smt/mam.h b/src/smt/mam.h index bf23b24a6..e7051b3f7 100644 --- a/src/smt/mam.h +++ b/src/smt/mam.h @@ -37,8 +37,7 @@ namespace smt { m_context(ctx) { } - virtual ~mam() { - } + virtual ~mam() = default; virtual void add_pattern(quantifier * q, app * mp) = 0; diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp index ab5ee9a98..704ff213e 100644 --- a/src/smt/params/smt_params.cpp +++ b/src/smt/params/smt_params.cpp @@ -19,6 +19,7 @@ Revision History: #include "smt/params/smt_params.h" #include "smt/params/smt_params_helper.hpp" #include "util/gparams.h" +#include "params/solver_params.hpp" void smt_params::updt_local_params(params_ref const & _p) { smt_params_helper p(_p); @@ -59,6 +60,9 @@ void smt_params::updt_local_params(params_ref const & _p) { m_dump_benchmarks = false; m_dump_min_time = 0.5; m_dump_recheck = false; + solver_params sp(_p); + m_axioms2files = sp.axioms2files(); + m_lemmas2console = sp.lemmas2console(); } void smt_params::updt_params(params_ref const & p) { @@ -150,7 +154,8 @@ void smt_params::display(std::ostream & out) const { DISPLAY_PARAM(m_old_clause_relevancy); DISPLAY_PARAM(m_inv_clause_decay); - DISPLAY_PARAM(m_smtlib_dump_lemmas); + DISPLAY_PARAM(m_axioms2files); + DISPLAY_PARAM(m_lemmas2console); DISPLAY_PARAM(m_logic); DISPLAY_PARAM(m_string_solver); diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index 5a13c69ac..29a5f94b4 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -82,144 +82,145 @@ struct smt_params : public preprocessor_params, public theory_seq_params, public theory_pb_params, public theory_datatype_params { - bool m_display_proof; - bool m_display_dot_proof; - bool m_display_unsat_core; - bool m_check_proof; - bool m_eq_propagation; - bool m_binary_clause_opt; - unsigned m_relevancy_lvl; - bool m_relevancy_lemma; - unsigned m_random_seed; - double m_random_var_freq; - double m_inv_decay; + bool m_display_proof = false; + bool m_display_dot_proof = false; + bool m_display_unsat_core = false; + bool m_check_proof = false; + bool m_eq_propagation = true; + bool m_binary_clause_opt = true; + unsigned m_relevancy_lvl = 2; + bool m_relevancy_lemma = false; + unsigned m_random_seed = 0; + double m_random_var_freq = 1.052; + double m_inv_decay = 1; unsigned m_clause_decay; - initial_activity m_random_initial_activity; - phase_selection m_phase_selection; - unsigned m_phase_caching_on; - unsigned m_phase_caching_off; - bool m_minimize_lemmas; - unsigned m_max_conflicts; + initial_activity m_random_initial_activity = initial_activity::IA_RANDOM_WHEN_SEARCHING; + phase_selection m_phase_selection = phase_selection::PS_CACHING_CONSERVATIVE; + unsigned m_phase_caching_on = 700; + unsigned m_phase_caching_off = 100; + bool m_minimize_lemmas = true; + unsigned m_max_conflicts = UINT_MAX; unsigned m_restart_max; - unsigned m_cube_depth; - unsigned m_threads; - unsigned m_threads_max_conflicts; - unsigned m_threads_cube_frequency; - bool m_simplify_clauses; - unsigned m_tick; - bool m_display_features; - bool m_new_core2th_eq; - bool m_ematching; - bool m_induction; - bool m_clause_proof; + unsigned m_cube_depth = 1; + unsigned m_threads = 1; + unsigned m_threads_max_conflicts = UINT_MAX; + unsigned m_threads_cube_frequency = 2; + bool m_simplify_clauses = true; + unsigned m_tick = 1000; + bool m_display_features = false; + bool m_new_core2th_eq = true; + bool m_ematching = true; + bool m_induction = false; + bool m_clause_proof = false; // ----------------------------------- // // Case split strategy // // ----------------------------------- - case_split_strategy m_case_split_strategy; - unsigned m_rel_case_split_order; - bool m_lookahead_diseq; - bool m_theory_case_split; - bool m_theory_aware_branching; + case_split_strategy m_case_split_strategy = case_split_strategy::CS_ACTIVITY_DELAY_NEW; + unsigned m_rel_case_split_order = 0; + bool m_lookahead_diseq = false; + bool m_theory_case_split = false; + bool m_theory_aware_branching = false; // ----------------------------------- // // Delay units... // // ----------------------------------- - bool m_delay_units; - unsigned m_delay_units_threshold; + bool m_delay_units = false; + unsigned m_delay_units_threshold = 32; // ----------------------------------- // // Conflict resolution // // ----------------------------------- - bool m_theory_resolve; + bool m_theory_resolve = false; // ----------------------------------- // // Restart // // ----------------------------------- - restart_strategy m_restart_strategy; - unsigned m_restart_initial; - double m_restart_factor; - bool m_restart_adaptive; - double m_agility_factor; - double m_restart_agility_threshold; + restart_strategy m_restart_strategy = restart_strategy::RS_IN_OUT_GEOMETRIC; + unsigned m_restart_initial = 100; + double m_restart_factor = 1.1; + bool m_restart_adaptive = true; + double m_agility_factor = 0.9999; + double m_restart_agility_threshold = 0.18; // ----------------------------------- // // Lemma garbage collection // // ----------------------------------- - lemma_gc_strategy m_lemma_gc_strategy; - bool m_lemma_gc_half; - unsigned m_recent_lemmas_size; - unsigned m_lemma_gc_initial; - double m_lemma_gc_factor; - unsigned m_new_old_ratio; //!< the ratio of new and old clauses. - unsigned m_new_clause_activity; - unsigned m_old_clause_activity; - unsigned m_new_clause_relevancy; //!< Max. number of unassigned literals to be considered relevant. - unsigned m_old_clause_relevancy; //!< Max. number of unassigned literals to be considered relevant. - double m_inv_clause_decay; //!< clause activity decay + lemma_gc_strategy m_lemma_gc_strategy = lemma_gc_strategy::LGC_FIXED; + bool m_lemma_gc_half = false; + unsigned m_recent_lemmas_size = 100; + unsigned m_lemma_gc_initial = 5000; + double m_lemma_gc_factor = 1.1; + unsigned m_new_old_ratio = 16; //!< the ratio of new and old clauses. + unsigned m_new_clause_activity = 10; + unsigned m_old_clause_activity = 500; + unsigned m_new_clause_relevancy = 45; //!< Max. number of unassigned literals to be considered relevant. + unsigned m_old_clause_relevancy = 6; //!< Max. number of unassigned literals to be considered relevant. + double m_inv_clause_decay = 1; //!< clause activity decay // ----------------------------------- // // SMT-LIB (debug) pretty printer // // ----------------------------------- - bool m_smtlib_dump_lemmas; - symbol m_logic; + bool m_axioms2files = false; + bool m_lemmas2console = false; + symbol m_logic = symbol::null; // ----------------------------------- // // Statistics for Profiling // // ----------------------------------- - bool m_profile_res_sub; - bool m_display_bool_var2expr; - bool m_display_ll_bool_var2expr; + bool m_profile_res_sub = false; + bool m_display_bool_var2expr = false; + bool m_display_ll_bool_var2expr = false; // ----------------------------------- // // Model generation // // ----------------------------------- - bool m_model; - bool m_model_on_timeout; - bool m_model_on_final_check; + bool m_model = true; + bool m_model_on_timeout = false; + bool m_model_on_final_check = false; // ----------------------------------- // // Progress sampling // // ----------------------------------- - unsigned m_progress_sampling_freq; + unsigned m_progress_sampling_freq = 0; // ----------------------------------- // // Debugging goodies // // ----------------------------------- - bool m_core_validate; + bool m_core_validate = false; // ----------------------------------- // // From front_end_params // // ----------------------------------- - bool m_preprocess; // temporary hack for disabling all preprocessing.. - bool m_user_theory_preprocess_axioms; - bool m_user_theory_persist_axioms; - bool m_at_labels_cex; // only use labels which contains the @ symbol when building multiple counterexamples. - bool m_check_at_labels; // check that @ labels are inserted to generate unique counter-examples. - bool m_dump_goal_as_smt; - bool m_auto_config; + bool m_preprocess = true; // temporary hack for disabling all preprocessing.. + bool m_user_theory_preprocess_axioms = false; + bool m_user_theory_persist_axioms = false; + bool m_at_labels_cex = false; // only use labels which contains the @ symbol when building multiple counterexamples. + bool m_check_at_labels = false; // check that @ labels are inserted to generate unique counter-examples. + bool m_dump_goal_as_smt = false; + bool m_auto_config = true; // ----------------------------------- // @@ -238,77 +239,6 @@ struct smt_params : public preprocessor_params, symbol m_string_solver; smt_params(params_ref const & p = params_ref()): - m_display_proof(false), - m_display_dot_proof(false), - m_display_unsat_core(false), - m_check_proof(false), - m_eq_propagation(true), - m_binary_clause_opt(true), - m_relevancy_lvl(2), - m_relevancy_lemma(false), - m_random_seed(0), - m_random_var_freq(0.01), - m_inv_decay(1.052), - m_clause_decay(1), - m_random_initial_activity(initial_activity::IA_RANDOM_WHEN_SEARCHING), - m_phase_selection(phase_selection::PS_CACHING_CONSERVATIVE), - m_phase_caching_on(700), - m_phase_caching_off(100), - m_minimize_lemmas(true), - m_max_conflicts(UINT_MAX), - m_cube_depth(1), - m_threads(1), - m_threads_max_conflicts(UINT_MAX), - m_threads_cube_frequency(2), - m_simplify_clauses(true), - m_tick(1000), - m_display_features(false), - m_new_core2th_eq(true), - m_ematching(true), - m_induction(false), - m_clause_proof(false), - m_case_split_strategy(case_split_strategy::CS_ACTIVITY_DELAY_NEW), - m_rel_case_split_order(0), - m_lookahead_diseq(false), - m_theory_case_split(false), - m_theory_aware_branching(false), - m_delay_units(false), - m_delay_units_threshold(32), - m_theory_resolve(false), - m_restart_strategy(restart_strategy::RS_IN_OUT_GEOMETRIC), - m_restart_initial(100), - m_restart_factor(1.1), - m_restart_adaptive(true), - m_agility_factor(0.9999), - m_restart_agility_threshold(0.18), - m_lemma_gc_strategy(lemma_gc_strategy::LGC_FIXED), - m_lemma_gc_half(false), - m_recent_lemmas_size(100), - m_lemma_gc_initial(5000), - m_lemma_gc_factor(1.1), - m_new_old_ratio(16), - m_new_clause_activity(10), - m_old_clause_activity(500), - m_new_clause_relevancy(45), - m_old_clause_relevancy(6), - m_inv_clause_decay(1), - m_smtlib_dump_lemmas(false), - m_logic(symbol::null), - m_profile_res_sub(false), - m_display_bool_var2expr(false), - m_display_ll_bool_var2expr(false), - m_model(true), - m_model_on_timeout(false), - m_model_on_final_check(false), - m_progress_sampling_freq(0), - m_core_validate(false), - m_preprocess(true), // temporary hack for disabling all preprocessing.. - m_user_theory_preprocess_axioms(false), - m_user_theory_persist_axioms(false), - m_at_labels_cex(false), - m_check_at_labels(false), - m_dump_goal_as_smt(false), - m_auto_config(true), m_string_solver(symbol("auto")){ updt_local_params(p); } diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 2cf29ffa8..3b32d7602 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -105,6 +105,7 @@ def_module_params(module_name='smt', ('core.validate', BOOL, False, '[internal] validate unsat core produced by SMT context. This option is intended for debugging'), ('seq.split_w_len', BOOL, True, 'enable splitting guided by length constraints'), ('seq.validate', BOOL, False, 'enable self-validation of theory axioms created by seq theory'), + ('seq.max_unfolding', UINT, 1000000000, 'maximal unfolding depth for checking string equations and regular expressions'), ('str.strong_arrangements', BOOL, True, 'assert equivalences instead of implications when generating string arrangement axioms'), ('str.aggressive_length_testing', BOOL, False, 'prioritize testing concrete length values over generating more options'), ('str.aggressive_value_testing', BOOL, False, 'prioritize testing concrete string constant values over generating more options'), diff --git a/src/smt/params/theory_arith_params.cpp b/src/smt/params/theory_arith_params.cpp index deec4e4da..565000ebe 100644 --- a/src/smt/params/theory_arith_params.cpp +++ b/src/smt/params/theory_arith_params.cpp @@ -34,7 +34,6 @@ void theory_arith_params::updt_params(params_ref const & _p) { m_arith_int_eq_branching = p.arith_int_eq_branch(); m_arith_ignore_int = p.arith_ignore_int(); m_arith_bound_prop = static_cast(p.arith_propagation_mode()); - m_arith_dump_lemmas = p.arith_dump_lemmas(); m_arith_eager_eq_axioms = p.arith_eager_eq_axioms(); m_arith_auto_config_simplex = p.arith_auto_config_simplex(); @@ -67,7 +66,6 @@ void theory_arith_params::display(std::ostream & out) const { DISPLAY_PARAM(m_arith_adaptive); DISPLAY_PARAM(m_arith_adaptive_assertion_threshold); DISPLAY_PARAM(m_arith_adaptive_propagation_threshold); - DISPLAY_PARAM(m_arith_dump_lemmas); DISPLAY_PARAM(m_arith_eager_eq_axioms); DISPLAY_PARAM(m_arith_branch_cut_ratio); DISPLAY_PARAM(m_arith_int_eq_branching); diff --git a/src/smt/params/theory_arith_params.h b/src/smt/params/theory_arith_params.h index d45a902db..526cb6f09 100644 --- a/src/smt/params/theory_arith_params.h +++ b/src/smt/params/theory_arith_params.h @@ -72,7 +72,6 @@ struct theory_arith_params { bool m_arith_adaptive = false; double m_arith_adaptive_assertion_threshold = 0.2; double m_arith_adaptive_propagation_threshold = 0.4; - bool m_arith_dump_lemmas = false; bool m_arith_eager_eq_axioms = true; unsigned m_arith_branch_cut_ratio = 2; bool m_arith_int_eq_branching = false; diff --git a/src/smt/params/theory_seq_params.cpp b/src/smt/params/theory_seq_params.cpp index 68cce6e66..196faf387 100644 --- a/src/smt/params/theory_seq_params.cpp +++ b/src/smt/params/theory_seq_params.cpp @@ -21,4 +21,5 @@ void theory_seq_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); m_split_w_len = p.seq_split_w_len(); m_seq_validate = p.seq_validate(); + m_seq_max_unfolding = p.seq_max_unfolding(); } diff --git a/src/smt/params/theory_seq_params.h b/src/smt/params/theory_seq_params.h index 84437fa15..845411039 100644 --- a/src/smt/params/theory_seq_params.h +++ b/src/smt/params/theory_seq_params.h @@ -24,6 +24,7 @@ struct theory_seq_params { */ bool m_split_w_len = false; bool m_seq_validate = false; + unsigned m_seq_max_unfolding = UINT_MAX/4; theory_seq_params(params_ref const & p = params_ref()) { updt_params(p); diff --git a/src/smt/proto_model/proto_model.h b/src/smt/proto_model/proto_model.h index d0c1b97f2..f069e0a60 100644 --- a/src/smt/proto_model/proto_model.h +++ b/src/smt/proto_model/proto_model.h @@ -59,7 +59,6 @@ class proto_model : public model_core { public: proto_model(ast_manager & m, params_ref const & p = params_ref()); - ~proto_model() override {} void register_factory(value_factory * f) { m_factories.register_plugin(f); } diff --git a/src/smt/seq_axioms.cpp b/src/smt/seq_axioms.cpp index fee223612..bd4d8dec2 100644 --- a/src/smt/seq_axioms.cpp +++ b/src/smt/seq_axioms.cpp @@ -86,7 +86,7 @@ void seq_axioms::add_clause(expr_ref_vector const& clause) { justification* js = ctx().mk_justification( ext_theory_eq_propagation_justification( - th.get_id(), ctx().get_region(), 0, nullptr, 0, nullptr, n1, n2)); + th.get_id(), ctx(), 0, nullptr, 0, nullptr, n1, n2)); ctx().assign_eq(n1, n2, eq_justification(js)); return; } diff --git a/src/smt/smt_case_split_queue.cpp b/src/smt/smt_case_split_queue.cpp index 2189b64e0..9f5bdb0d4 100644 --- a/src/smt/smt_case_split_queue.cpp +++ b/src/smt/smt_case_split_queue.cpp @@ -150,8 +150,6 @@ namespace { if (!first) out << "\n"; } - - ~act_case_split_queue() override {}; }; /** @@ -1244,8 +1242,6 @@ namespace { out << "\n"; } - - ~theory_aware_branching_queue() override {}; }; } diff --git a/src/smt/smt_case_split_queue.h b/src/smt/smt_case_split_queue.h index 91f7fc036..a84b5ea4f 100644 --- a/src/smt/smt_case_split_queue.h +++ b/src/smt/smt_case_split_queue.h @@ -45,7 +45,7 @@ namespace smt { virtual void pop_scope(unsigned num_scopes) = 0; virtual void next_case_split(bool_var & next, lbool & phase) = 0; virtual void display(std::ostream & out) = 0; - virtual ~case_split_queue() {} + virtual ~case_split_queue() = default; // theory-aware branching hint virtual void add_theory_aware_branching_info(bool_var v, double priority, lbool phase) {} diff --git a/src/smt/smt_clause.h b/src/smt/smt_clause.h index 950d0e17c..89d8f2d66 100644 --- a/src/smt/smt_clause.h +++ b/src/smt/smt_clause.h @@ -33,7 +33,7 @@ namespace smt { */ class clause_del_eh { public: - virtual ~clause_del_eh() {} + virtual ~clause_del_eh() = default; virtual void operator()(ast_manager & m, clause * cls) = 0; }; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 6652804ea..b4f6a2309 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -80,7 +80,8 @@ namespace smt { m_unsat_core(m), m_mk_bool_var_trail(*this), m_mk_enode_trail(*this), - m_mk_lambda_trail(*this) { + m_mk_lambda_trail(*this), + m_lemma_visitor(m) { SASSERT(m_scope_lvl == 0); SASSERT(m_base_lvl == 0); @@ -821,6 +822,8 @@ namespace smt { SASSERT(t2 != null_theory_id); theory_var v1 = m_fparams.m_new_core2th_eq ? get_closest_var(n1, t2) : r1->get_th_var(t2); + TRACE("merge_theory_vars", tout << get_theory(t2)->get_name() << ": " << v2 << " == " << v1 << "\n"); + if (v1 != null_theory_var) { // only send the equality to the theory, if the equality was not propagated by it. if (t2 != from_th) @@ -839,6 +842,7 @@ namespace smt { SASSERT(v1 != null_theory_var); SASSERT(t1 != null_theory_id); theory_var v2 = r2->get_th_var(t1); + TRACE("merge_theory_vars", tout << get_theory(t1)->get_name() << ": " << v2 << " == " << v1 << "\n"); if (v2 == null_theory_var) { r2->add_th_var(v1, t1, m_region); push_new_th_diseqs(r2, v1, get_theory(t1)); @@ -2557,7 +2561,7 @@ namespace smt { justification * js = cls.get_justification(); justification * new_js = nullptr; if (js->in_region()) - new_js = mk_justification(unit_resolution_justification(m_region, + new_js = mk_justification(unit_resolution_justification(*this, js, simp_lits.size(), simp_lits.data())); @@ -2615,7 +2619,7 @@ namespace smt { if (!cls_js || cls_js->in_region()) { // If cls_js is 0 or is allocated in a region, then // we can allocate the new justification in a region too. - js = mk_justification(unit_resolution_justification(m_region, + js = mk_justification(unit_resolution_justification(*this, cls_js, simp_lits.size(), simp_lits.data())); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 8d98fc60e..f91878632 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -892,6 +892,10 @@ namespace smt { void remove_lit_occs(clause const& cls, unsigned num_bool_vars); void add_lit_occs(clause const& cls); + + ast_pp_util m_lemma_visitor; + void dump_lemma(unsigned n, literal const* lits); + void dump_axiom(unsigned n, literal const* lits); public: void ensure_internalized(expr* e); diff --git a/src/smt/smt_for_each_relevant_expr.h b/src/smt/smt_for_each_relevant_expr.h index ef687ae01..20be165c6 100644 --- a/src/smt/smt_for_each_relevant_expr.h +++ b/src/smt/smt_for_each_relevant_expr.h @@ -65,7 +65,7 @@ namespace smt { public: for_each_relevant_expr(context & ctx); - virtual ~for_each_relevant_expr() {} + virtual ~for_each_relevant_expr() = default; /** \brief Visit the relevant sub-expressions of n. That is, only subexpressions m of n, such that m_context.is_relevant(m). @@ -92,7 +92,6 @@ namespace smt { for_each_relevant_expr(ctx), m_buffer(b) { } - ~collect_relevant_label_lits() override {} void operator()(expr * n) override; }; @@ -103,7 +102,6 @@ namespace smt { for_each_relevant_expr(ctx), m_buffer(b) { } - ~collect_relevant_labels() override {} void operator()(expr * n) override; }; diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 092bc0127..d86594f0f 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -24,6 +24,8 @@ Revision History: #include "smt/smt_model_finder.h" #include "ast/for_each_expr.h" +#include + namespace smt { /** @@ -1372,8 +1374,10 @@ namespace smt { TRACE("mk_clause", display_literals_verbose(tout << "creating clause: " << literal_vector(num_lits, lits) << "\n", num_lits, lits) << "\n";); m_clause_proof.add(num_lits, lits, k, j); switch (k) { - case CLS_AUX: - case CLS_TH_AXIOM: { + case CLS_TH_AXIOM: + dump_axiom(num_lits, lits); + Z3_fallthrough; + case CLS_AUX: { literal_buffer simp_lits; if (!simplify_aux_clause_literals(num_lits, lits, simp_lits)) { if (j && !j->in_region()) { @@ -1384,11 +1388,12 @@ namespace smt { } DEBUG_CODE(for (literal lit : simp_lits) SASSERT(get_assignment(lit) == l_true);); if (!simp_lits.empty()) { - j = mk_justification(unit_resolution_justification(m_region, j, simp_lits.size(), simp_lits.data())); + j = mk_justification(unit_resolution_justification(*this, j, simp_lits.size(), simp_lits.data())); } break; } - case CLS_TH_LEMMA: + case CLS_TH_LEMMA: + dump_lemma(num_lits, lits); if (!simplify_aux_lemma_literals(num_lits, lits)) { if (j && !j->in_region()) { j->del_eh(m); @@ -1398,7 +1403,10 @@ namespace smt { } // simplify_aux_lemma_literals does not delete literals assigned to false, so // it is not necessary to create a unit_resolution_justification - break; + break; + case CLS_LEARNED: + dump_lemma(num_lits, lits); + break; default: break; } @@ -1503,6 +1511,30 @@ namespace smt { }} } + void context::dump_axiom(unsigned n, literal const* lits) { + if (m_fparams.m_axioms2files) { + literal_buffer tmp; + neg_literals(n, lits, tmp); + SASSERT(tmp.size() == n); + display_lemma_as_smt_problem(tmp.size(), tmp.data(), false_literal, m_fparams.m_logic); + } + } + + void context::dump_lemma(unsigned n, literal const* lits) { + + if (m_fparams.m_lemmas2console) { + expr_ref fml(m); + expr_ref_vector fmls(m); + for (unsigned i = 0; i < n; ++i) + fmls.push_back(literal2expr(lits[i])); + fml = mk_or(fmls); + m_lemma_visitor.collect(fml); + m_lemma_visitor.display_skolem_decls(std::cout); + m_lemma_visitor.display_assert(std::cout, fml.get(), true); + } + + } + void context::mk_clause(literal l1, literal l2, justification * j) { literal ls[2] = { l1, l2 }; mk_clause(2, ls, j); @@ -1518,13 +1550,7 @@ namespace smt { TRACE("mk_th_axiom", display_literals_verbose(tout, num_lits, lits) << "\n";); if (m.proofs_enabled()) { - js = mk_justification(theory_axiom_justification(tid, m_region, num_lits, lits, num_params, params)); - } - if (m_fparams.m_smtlib_dump_lemmas) { - literal_buffer tmp; - neg_literals(num_lits, lits, tmp); - SASSERT(tmp.size() == num_lits); - display_lemma_as_smt_problem(tmp.size(), tmp.data(), false_literal, m_fparams.m_logic); + js = mk_justification(theory_axiom_justification(tid, *this, num_lits, lits, num_params, params)); } mk_clause(num_lits, lits, js, k); } diff --git a/src/smt/smt_justification.cpp b/src/smt/smt_justification.cpp index acdf03222..0124a1810 100644 --- a/src/smt/smt_justification.cpp +++ b/src/smt/smt_justification.cpp @@ -40,13 +40,14 @@ namespace smt { return m_proof; } - unit_resolution_justification::unit_resolution_justification(region & r, + unit_resolution_justification::unit_resolution_justification(context& ctx, justification * js, unsigned num_lits, literal const * lits): m_antecedent(js), m_num_literals(num_lits) { SASSERT(!js || js->in_region()); + auto& r = ctx.get_region(); m_literals = new (r) literal[num_lits]; memcpy(m_literals, lits, sizeof(literal) * num_lits); TRACE("unit_resolution_justification_bug", tout << literal_vector(num_lits, lits) << "\n";); @@ -101,6 +102,7 @@ namespace smt { return m.mk_unit_resolution(prs.size(), prs.data()); } + void eq_conflict_justification::get_antecedents(conflict_resolution & cr) { SASSERT(m_node1->get_root()->is_interpreted()); SASSERT(m_node2->get_root()->is_interpreted()); @@ -235,8 +237,9 @@ namespace smt { return nullptr; } - simple_justification::simple_justification(region & r, unsigned num_lits, literal const * lits): + simple_justification::simple_justification(context& ctx, unsigned num_lits, literal const * lits): m_num_literals(num_lits) { + region& r = ctx.get_region(); if (num_lits != 0) { m_literals = new (r) literal[num_lits]; memcpy(m_literals, lits, sizeof(literal) * num_lits); @@ -291,6 +294,12 @@ namespace smt { return m.mk_th_lemma(m_th_id, fact, prs.size(), prs.data(), m_params.size(), m_params.data()); } + void theory_propagation_justification::log(context& ctx) { + if (ctx.get_fparams().m_axioms2files) + ctx.display_lemma_as_smt_problem(m_num_literals, m_literals, m_consequent); + } + + proof * theory_conflict_justification::mk_proof(conflict_resolution & cr) { ptr_buffer prs; if (!antecedent2proof(cr, prs)) @@ -299,9 +308,16 @@ namespace smt { return m.mk_th_lemma(m_th_id, m.mk_false(), prs.size(), prs.data(), m_params.size(), m_params.data()); } - ext_simple_justification::ext_simple_justification(region & r, unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs): - simple_justification(r, num_lits, lits), + void theory_conflict_justification::log(context& ctx) { + if (ctx.get_fparams().m_axioms2files) + ctx.display_lemma_as_smt_problem(m_num_literals, m_literals); + } + + + ext_simple_justification::ext_simple_justification(context& ctx, unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs): + simple_justification(ctx, num_lits, lits), m_num_eqs(num_eqs) { + region& r = ctx.get_region(); m_eqs = new (r) enode_pair[num_eqs]; std::uninitialized_copy(eqs, eqs + num_eqs, m_eqs); DEBUG_CODE({ @@ -342,6 +358,13 @@ namespace smt { ctx.literal2expr(m_consequent, fact); return m.mk_th_lemma(m_th_id, fact, prs.size(), prs.data(), m_params.size(), m_params.data()); } + + void ext_theory_propagation_justification::log(context& ctx) { + if (ctx.get_fparams().m_axioms2files) + ctx.display_lemma_as_smt_problem(m_num_literals, m_literals, m_num_eqs, m_eqs, m_consequent); + + } + proof * ext_theory_conflict_justification::mk_proof(conflict_resolution & cr) { ptr_buffer prs; @@ -351,6 +374,12 @@ namespace smt { return m.mk_th_lemma(m_th_id, m.mk_false(), prs.size(), prs.data(), m_params.size(), m_params.data()); } + void ext_theory_conflict_justification::log(context& ctx) { + if (ctx.get_fparams().m_axioms2files) + ctx.display_lemma_as_smt_problem(m_num_literals, m_literals); + } + + proof * ext_theory_eq_propagation_justification::mk_proof(conflict_resolution & cr) { ptr_buffer prs; if (!antecedent2proof(cr, prs)) @@ -361,6 +390,9 @@ namespace smt { return m.mk_th_lemma(m_th_id, fact, prs.size(), prs.data(), m_params.size(), m_params.data()); } + void ext_theory_eq_propagation_justification::log(context& ctx) { + } + theory_lemma_justification::theory_lemma_justification(family_id fid, context & ctx, unsigned num_lits, literal const * lits, unsigned num_params, parameter* params): diff --git a/src/smt/smt_justification.h b/src/smt/smt_justification.h index 48987e746..161ffe839 100644 --- a/src/smt/smt_justification.h +++ b/src/smt/smt_justification.h @@ -49,7 +49,7 @@ namespace smt { unsigned m_in_region:1; // true if the object was allocated in a region. public: justification(bool in_region = true):m_mark(false), m_in_region(in_region) {} - virtual ~justification() {} + virtual ~justification() = default; /** \brief This method should return true if the method del_eh needs to be invoked @@ -95,6 +95,7 @@ namespace smt { virtual char const * get_name() const { return "unknown"; } virtual void display_debug_info(conflict_resolution & cr, std::ostream & out) { /* do nothing */ } + }; class justification_proof_wrapper : public justification { @@ -118,7 +119,7 @@ namespace smt { unsigned m_num_literals; literal * m_literals; public: - unit_resolution_justification(region & r, justification * js, unsigned num_lits, literal const * lits); + unit_resolution_justification(context& ctx, justification * js, unsigned num_lits, literal const * lits); unit_resolution_justification(justification * js, unsigned num_lits, literal const * lits); @@ -137,6 +138,7 @@ namespace smt { proof * mk_proof(conflict_resolution & cr) override; char const * get_name() const override { return "unit-resolution"; } + }; class eq_conflict_justification : public justification { @@ -218,7 +220,7 @@ namespace smt { bool antecedent2proof(conflict_resolution & cr, ptr_buffer & result); public: - simple_justification(region & r, unsigned num_lits, literal const * lits); + simple_justification(context& ctx, unsigned num_lits, literal const * lits); void get_antecedents(conflict_resolution & cr) override; @@ -234,12 +236,11 @@ namespace smt { vector m_params; public: simple_theory_justification( - family_id fid, region & r, + family_id fid, context& ctx, unsigned num_lits, literal const * lits, unsigned num_params, parameter* params): - simple_justification(r, num_lits, lits), + simple_justification(ctx, num_lits, lits), m_th_id(fid), m_params(num_params, params) {} - ~simple_theory_justification() override {} bool has_del_eh() const override { return !m_params.empty(); } @@ -252,10 +253,10 @@ namespace smt { class theory_axiom_justification : public simple_theory_justification { public: - theory_axiom_justification(family_id fid, region & r, + theory_axiom_justification(family_id fid, context& ctx, unsigned num_lits, literal const * lits, unsigned num_params = 0, parameter* params = nullptr): - simple_theory_justification(fid, r, num_lits, lits, num_params, params) {} + simple_theory_justification(fid, ctx, num_lits, lits, num_params, params) {} void get_antecedents(conflict_resolution & cr) override {} @@ -266,10 +267,11 @@ namespace smt { class theory_propagation_justification : public simple_theory_justification { literal m_consequent; + void log(context& ctx); public: - theory_propagation_justification(family_id fid, region & r, unsigned num_lits, literal const * lits, literal consequent, + theory_propagation_justification(family_id fid, context& ctx, unsigned num_lits, literal const * lits, literal consequent, unsigned num_params = 0, parameter* params = nullptr): - simple_theory_justification(fid, r, num_lits, lits, num_params, params), m_consequent(consequent) {} + simple_theory_justification(fid, ctx, num_lits, lits, num_params, params), m_consequent(consequent) { log(ctx); } proof * mk_proof(conflict_resolution & cr) override; @@ -279,10 +281,11 @@ namespace smt { }; class theory_conflict_justification : public simple_theory_justification { + void log(context& ctx); public: - theory_conflict_justification(family_id fid, region & r, unsigned num_lits, literal const * lits, + theory_conflict_justification(family_id fid, context& ctx, unsigned num_lits, literal const * lits, unsigned num_params = 0, parameter* params = nullptr): - simple_theory_justification(fid, r, num_lits, lits, num_params, params) {} + simple_theory_justification(fid, ctx, num_lits, lits, num_params, params) { log(ctx); } proof * mk_proof(conflict_resolution & cr) override; @@ -300,7 +303,7 @@ namespace smt { bool antecedent2proof(conflict_resolution & cr, ptr_buffer & result); public: - ext_simple_justification(region & r, unsigned num_lits, literal const * lits, + ext_simple_justification(context& ctx, unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs); void get_antecedents(conflict_resolution & cr) override; @@ -319,12 +322,10 @@ namespace smt { vector m_params; public: - ext_theory_simple_justification(family_id fid, region & r, unsigned num_lits, literal const * lits, + ext_theory_simple_justification(family_id fid, context& ctx, unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, unsigned num_params = 0, parameter* params = nullptr): - ext_simple_justification(r, num_lits, lits, num_eqs, eqs), m_th_id(fid), m_params(num_params, params) {} - - ~ext_theory_simple_justification() override {} + ext_simple_justification(ctx, num_lits, lits, num_eqs, eqs), m_th_id(fid), m_params(num_params, params) {} bool has_del_eh() const override { return !m_params.empty(); } @@ -335,26 +336,33 @@ namespace smt { class ext_theory_propagation_justification : public ext_theory_simple_justification { literal m_consequent; + void log(context& ctx); public: - ext_theory_propagation_justification(family_id fid, region & r, + ext_theory_propagation_justification(family_id fid, context & ctx, unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, literal consequent, unsigned num_params = 0, parameter* params = nullptr): - ext_theory_simple_justification(fid, r, num_lits, lits, num_eqs, eqs, num_params, params), - m_consequent(consequent) {} + ext_theory_simple_justification(fid, ctx, num_lits, lits, num_eqs, eqs, num_params, params), + m_consequent(consequent) { + log(ctx); + } proof * mk_proof(conflict_resolution & cr) override; char const * get_name() const override { return "ext-theory-propagation"; } + }; class ext_theory_conflict_justification : public ext_theory_simple_justification { + void log(context& ctx); public: - ext_theory_conflict_justification(family_id fid, region & r, unsigned num_lits, literal const * lits, + ext_theory_conflict_justification(family_id fid, context& ctx, unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, unsigned num_params = 0, parameter* params = nullptr): - ext_theory_simple_justification(fid, r, num_lits, lits, num_eqs, eqs, num_params, params) {} + ext_theory_simple_justification(fid, ctx, num_lits, lits, num_eqs, eqs, num_params, params) { + log(ctx); + } proof * mk_proof(conflict_resolution & cr) override; @@ -364,19 +372,20 @@ namespace smt { class ext_theory_eq_propagation_justification : public ext_theory_simple_justification { enode * m_lhs; enode * m_rhs; + void log(context& ctx); public: ext_theory_eq_propagation_justification( - family_id fid, region & r, + family_id fid, context& ctx, unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, enode * lhs, enode * rhs, unsigned num_params = 0, parameter* params = nullptr): - ext_theory_simple_justification(fid, r, num_lits, lits, num_eqs, eqs, num_params, params), m_lhs(lhs), m_rhs(rhs) {} + ext_theory_simple_justification(fid, ctx, num_lits, lits, num_eqs, eqs, num_params, params), m_lhs(lhs), m_rhs(rhs) { log(ctx); } ext_theory_eq_propagation_justification( - family_id fid, region & r, + family_id fid, context& ctx, enode * lhs, enode * rhs): - ext_theory_simple_justification(fid, r, 0, nullptr, 0, nullptr, 0, nullptr), m_lhs(lhs), m_rhs(rhs) {} + ext_theory_simple_justification(fid, ctx, 0, nullptr, 0, nullptr, 0, nullptr), m_lhs(lhs), m_rhs(rhs) { log(ctx); } proof * mk_proof(conflict_resolution & cr) override; diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 18a290d0a..039416f73 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -395,12 +395,14 @@ namespace smt { m_fparams = alloc(smt_params, m_context->get_fparams()); m_fparams->m_relevancy_lvl = 0; // no relevancy since the model checking problems are quantifier free m_fparams->m_case_split_strategy = CS_ACTIVITY; // avoid warning messages about smt.case_split >= 3. - m_fparams->m_arith_dump_lemmas = false; + m_fparams->m_axioms2files = false; + m_fparams->m_lemmas2console = false; } if (!m_aux_context) { symbol logic; params_ref p; - p.set_bool("arith.dump_lemmas", false); + p.set_bool("solver.axioms2files", false); + p.set_bool("solver.lemmas2console", false); m_aux_context = m_context->mk_fresh(&logic, m_fparams.get(), p); } } diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 34f323695..94a0992f3 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -464,7 +464,7 @@ namespace smt { m.limit().inc(); } - virtual ~auf_solver() { + ~auf_solver() override { flush_nodes(); reset_eval_cache(); } @@ -1157,7 +1157,7 @@ namespace smt { ast_manager& m; public: qinfo(ast_manager& m) :m(m) {} - virtual ~qinfo() {} + virtual ~qinfo() = default; virtual char const* get_kind() const = 0; virtual bool is_equal(qinfo const* qi) const = 0; virtual void display(std::ostream& out) const { out << "[" << get_kind() << "]"; } @@ -1180,7 +1180,6 @@ namespace smt { unsigned m_var_j; public: f_var(ast_manager& m, func_decl* f, unsigned i, unsigned j) : qinfo(m), m_f(f), m_arg_i(i), m_var_j(j) {} - ~f_var() override {} char const* get_kind() const override { return "f_var"; @@ -1261,7 +1260,6 @@ namespace smt { f_var(m, f, i, j), m_offset(offset, m) { } - ~f_var_plus_offset() override {} char const* get_kind() const override { return "f_var_plus_offset"; @@ -1427,7 +1425,6 @@ namespace smt { public: select_var(ast_manager& m, app* s, unsigned i, unsigned j) :qinfo(m), m_array(m), m_select(s), m_arg_i(i), m_var_j(j) {} - ~select_var() override {} char const* get_kind() const override { return "select_var"; @@ -1497,8 +1494,6 @@ namespace smt { std::swap(m_var_i, m_var_j); } - ~var_pair() override {} - bool is_equal(qinfo const* qi) const override { if (qi->get_kind() != get_kind()) return false; @@ -1577,7 +1572,6 @@ namespace smt { var_expr_pair(ast_manager& m, unsigned i, expr* t) : qinfo(m), m_var_i(i), m_t(t, m) {} - ~var_expr_pair() override {} bool is_equal(qinfo const* qi) const override { if (qi->get_kind() != get_kind()) diff --git a/src/smt/smt_model_generator.h b/src/smt/smt_model_generator.h index 80bd59799..632557e98 100644 --- a/src/smt/smt_model_generator.h +++ b/src/smt/smt_model_generator.h @@ -136,7 +136,7 @@ namespace smt { */ class model_value_proc { public: - virtual ~model_value_proc() {} + virtual ~model_value_proc() = default; /** \brief Fill result with the dependencies of this functor. That is, to invoke mk_value, the dependencies in result must be constructed. diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index b67599a99..b0696049b 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -606,9 +606,6 @@ namespace smt { m_active(false) { } - ~default_qm_plugin() override { - } - void set_manager(quantifier_manager & qm) override { SASSERT(m_qm == nullptr); m_qm = &qm; diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index d9a43ddea..abb3cac7c 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -106,7 +106,7 @@ namespace smt { class quantifier_manager_plugin { public: - virtual ~quantifier_manager_plugin() {} + virtual ~quantifier_manager_plugin() = default; virtual void set_manager(quantifier_manager & qm) = 0; diff --git a/src/smt/smt_relevancy.cpp b/src/smt/smt_relevancy.cpp index 4b787561d..649d75737 100644 --- a/src/smt/smt_relevancy.cpp +++ b/src/smt/smt_relevancy.cpp @@ -52,7 +52,6 @@ namespace smt { app * m_parent; public: and_relevancy_eh(app * p):m_parent(p) {} - ~and_relevancy_eh() override {} void operator()(relevancy_propagator & rp) override; }; @@ -60,7 +59,6 @@ namespace smt { app * m_parent; public: or_relevancy_eh(app * p):m_parent(p) {} - ~or_relevancy_eh() override {} void operator()(relevancy_propagator & rp) override; }; @@ -68,7 +66,6 @@ namespace smt { app * m_parent; public: ite_relevancy_eh(app * p):m_parent(p) {} - ~ite_relevancy_eh() override {} void operator()(relevancy_propagator & rp) override; }; @@ -78,7 +75,6 @@ namespace smt { app * m_else_eq; public: ite_term_relevancy_eh(app * p, app * then_eq, app * else_eq):m_parent(p), m_then_eq(then_eq), m_else_eq(else_eq) {} - ~ite_term_relevancy_eh() override {} void operator()(relevancy_propagator & rp) override; }; diff --git a/src/smt/smt_relevancy.h b/src/smt/smt_relevancy.h index 87cc3847c..f64b7d059 100644 --- a/src/smt/smt_relevancy.h +++ b/src/smt/smt_relevancy.h @@ -29,7 +29,7 @@ namespace smt { void mark_as_relevant(relevancy_propagator & rp, expr * n); void mark_args_as_relevant(relevancy_propagator & rp, app * n); public: - virtual ~relevancy_eh() {} + virtual ~relevancy_eh() = default; /** \brief This method is invoked when n is marked as relevant. */ @@ -87,7 +87,7 @@ namespace smt { context & m_context; public: relevancy_propagator(context & ctx); - virtual ~relevancy_propagator() {} + virtual ~relevancy_propagator() = default; context & get_context() { return m_context; } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index a1054423a..07709666b 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -294,7 +294,7 @@ namespace smt { m_bound_kind(k), m_atom(a) { } - virtual ~bound() {} + virtual ~bound() = default; theory_var get_var() const { return m_var; } bound_kind get_bound_kind() const { return static_cast(m_bound_kind); } bool is_atom() const { return m_atom; } @@ -319,7 +319,6 @@ namespace smt { public: atom(bool_var bv, theory_var v, inf_numeral const & k, atom_kind kind); atom_kind get_atom_kind() const { return static_cast(m_atom_kind); } - ~atom() override {} inline inf_numeral const & get_k() const { return m_k; } bool_var get_bool_var() const { return m_bvar; } bool is_true() const { return m_is_true; } @@ -341,7 +340,6 @@ namespace smt { m_rhs(rhs) { SASSERT(m_lhs->get_root() == m_rhs->get_root()); } - ~eq_bound() override {} bool has_justification() const override { return true; } void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled) override { SASSERT(m_lhs->get_root() == m_rhs->get_root()); @@ -357,7 +355,6 @@ namespace smt { friend class theory_arith; public: derived_bound(theory_var v, inf_numeral const & val, bound_kind k):bound(v, val, k, false) {} - ~derived_bound() override {} literal_vector const& lits() const { return m_lits; } eq_vector const& eqs() const { return m_eqs; } bool has_justification() const override { return true; } @@ -374,7 +371,6 @@ namespace smt { friend class theory_arith; public: justified_derived_bound(theory_var v, inf_numeral const & val, bound_kind k):derived_bound(v, val, k) {} - ~justified_derived_bound() override {} bool has_justification() const override { return true; } void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled) override; void push_lit(literal l, numeral const& coeff) override; @@ -548,9 +544,6 @@ namespace smt { unsigned small_lemma_size() const { return m_params.m_arith_small_lemma_size; } bool relax_bounds() const { return m_params.m_arith_stronger_lemmas; } bool skip_big_coeffs() const { return m_params.m_arith_skip_rows_with_big_coeffs; } - bool dump_lemmas() const { return m_params.m_arith_dump_lemmas; } - void dump_lemmas(literal l, antecedents const& ante); - void dump_lemmas(literal l, derived_bound const& ante); bool process_atoms() const; unsigned get_num_conflicts() const { return m_num_conflicts; } var_kind get_var_kind(theory_var v) const { return m_data[v].kind(); } diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 012ad695b..3ad2831cb 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -563,7 +563,7 @@ namespace smt { if (!m_util.is_zero(divisor)) { // if divisor is zero, then idiv and mod are uninterpreted functions. expr_ref div(m), mod(m), zero(m), abs_divisor(m), one(m); - expr_ref eqz(m), eq(m), lower(m), upper(m), qr(m); + expr_ref eqz(m), eq(m), lower(m), upper(m), qr(m), le(m), ge(m); div = m_util.mk_idiv(dividend, divisor); mod = m_util.mk_mod(dividend, divisor); zero = m_util.mk_int(0); @@ -581,12 +581,16 @@ namespace smt { tout << "lower: " << lower << "\n"; tout << "upper: " << upper << "\n";); + le = m_util.mk_le(m_util.mk_sub(qr, dividend), zero); + ge = m_util.mk_ge(m_util.mk_sub(qr, dividend), zero); + mk_axiom(eqz, le, false); + mk_axiom(eqz, ge, false); mk_axiom(eqz, eq, false); mk_axiom(eqz, lower, false); mk_axiom(eqz, upper, !m_util.is_numeral(abs_divisor)); rational k; - m_arith_eq_adapter.mk_axioms(ensure_enode(qr), ensure_enode(mod)); + //m_arith_eq_adapter.mk_axioms(ensure_enode(qr), ensure_enode(dividend)); if (m_util.is_zero(dividend)) { mk_axiom(eqz, m.mk_eq(div, zero)); @@ -2978,23 +2982,7 @@ namespace smt { } } - template - void theory_arith::dump_lemmas(literal l, antecedents const& ante) { - if (dump_lemmas()) { - TRACE("arith", ante.display(tout) << " --> "; ctx.display_detailed_literal(tout, l); tout << "\n";); - ctx.display_lemma_as_smt_problem(ante.lits().size(), ante.lits().data(), - ante.eqs().size(), ante.eqs().data(), l); - } - } - - template - void theory_arith::dump_lemmas(literal l, derived_bound const& ante) { - if (dump_lemmas()) { - ctx.display_lemma_as_smt_problem(ante.lits().size(), ante.lits().data(), - ante.eqs().size(), ante.eqs().data(), l); - } - } template void theory_arith::assign_bound_literal(literal l, row const & r, unsigned idx, bool is_lower, inf_numeral & delta) { @@ -3006,7 +2994,6 @@ namespace smt { ante.display(tout) << " --> "; ctx.display_detailed_literal(tout, l); tout << "\n";); - dump_lemmas(l, ante); if (ante.lits().size() < small_lemma_size() && ante.eqs().empty()) { literal_vector & lits = m_tmp_literal_vector2; @@ -3024,10 +3011,9 @@ namespace smt { ctx.mk_clause(lits.size(), lits.data(), js, CLS_TH_LEMMA, nullptr); } else { - region & r = ctx.get_region(); ctx.assign(l, ctx.mk_justification( ext_theory_propagation_justification( - get_id(), r, ante.lits().size(), ante.lits().data(), + get_id(), ctx, ante.lits().size(), ante.lits().data(), ante.eqs().size(), ante.eqs().data(), l, ante.num_params(), ante.params("assign-bounds")))); } @@ -3090,13 +3076,11 @@ namespace smt { template void theory_arith::set_conflict(antecedents const& ante, antecedents& bounds, char const* proof_rule) { set_conflict(ante.lits().size(), ante.lits().data(), ante.eqs().size(), ante.eqs().data(), bounds, proof_rule); - dump_lemmas(false_literal, ante); } template void theory_arith::set_conflict(derived_bound const& ante, antecedents& bounds, char const* proof_rule) { set_conflict(ante.lits().size(), ante.lits().data(), ante.eqs().size(), ante.eqs().data(), bounds, proof_rule); - dump_lemmas(false_literal, ante); } template @@ -3130,7 +3114,7 @@ namespace smt { record_conflict(num_literals, lits, num_eqs, eqs, bounds.num_params(), bounds.params(proof_rule)); ctx.set_conflict( ctx.mk_justification( - ext_theory_conflict_justification(get_id(), ctx.get_region(), num_literals, lits, num_eqs, eqs, + ext_theory_conflict_justification(get_id(), ctx, num_literals, lits, num_eqs, eqs, bounds.num_params(), bounds.params(proof_rule)))); } diff --git a/src/smt/theory_arith_eq.h b/src/smt/theory_arith_eq.h index 0b8e41e20..fabdb6abd 100644 --- a/src/smt/theory_arith_eq.h +++ b/src/smt/theory_arith_eq.h @@ -336,7 +336,7 @@ namespace smt { justification * js = ctx.mk_justification( ext_theory_eq_propagation_justification( - get_id(), r, + get_id(), ctx, lits.size(), lits.data(), eqs.size(), eqs.data(), _x, _y, diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index f6a713d0d..56fbd4ecf 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -487,13 +487,13 @@ namespace smt { template class theory_arith::gomory_cut_justification : public ext_theory_propagation_justification { public: - gomory_cut_justification(family_id fid, region & r, + gomory_cut_justification(family_id fid, context& ctx, unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, antecedents& bounds, literal consequent): - ext_theory_propagation_justification(fid, r, num_lits, lits, num_eqs, eqs, consequent, - bounds.num_params(), bounds.params("gomory-cut")) { + ext_theory_propagation_justification(fid, ctx, num_lits, lits, num_eqs, eqs, consequent, + bounds.num_params(), bounds.params("gomory-cut")) { } // Remark: the assignment must be propagated back to arith theory_id get_from_theory() const override { return null_theory_id; } @@ -676,19 +676,16 @@ namespace smt { l = ctx.get_literal(bound); IF_VERBOSE(10, verbose_stream() << "cut " << bound << "\n"); ctx.mark_as_relevant(l); - dump_lemmas(l, ante); auto js = ctx.mk_justification( gomory_cut_justification( - get_id(), ctx.get_region(), + get_id(), ctx, ante.lits().size(), ante.lits().data(), ante.eqs().size(), ante.eqs().data(), ante, l)); - if (l == false_literal) { + if (l == false_literal) ctx.mk_clause(0, nullptr, js, CLS_TH_LEMMA, nullptr); - } - else { + else ctx.assign(l, js); - } return true; } @@ -760,7 +757,7 @@ namespace smt { ctx.set_conflict( ctx.mk_justification( ext_theory_conflict_justification( - get_id(), ctx.get_region(), ante.lits().size(), ante.lits().data(), + get_id(), ctx, ante.lits().size(), ante.lits().data(), ante.eqs().size(), ante.eqs().data(), ante.num_params(), ante.params("gcd-test")))); return false; @@ -840,7 +837,7 @@ namespace smt { ctx.set_conflict( ctx.mk_justification( ext_theory_conflict_justification( - get_id(), ctx.get_region(), + get_id(), ctx, ante.lits().size(), ante.lits().data(), ante.eqs().size(), ante.eqs().data(), ante.num_params(), ante.params("gcd-test")))); return false; @@ -858,11 +855,9 @@ namespace smt { return true; if (m_eager_gcd) return true; - typename vector::const_iterator it = m_rows.begin(); - typename vector::const_iterator end = m_rows.end(); - for (; it != end; ++it) { - theory_var v = it->get_base_var(); - if (v != null_theory_var && is_int(v) && !get_value(v).is_int() && !gcd_test(*it)) { + for (auto const& e : m_rows) { + theory_var v = e.get_base_var(); + if (v != null_theory_var && is_int(v) && !get_value(v).is_int() && !gcd_test(e)) { if (m_params.m_arith_adaptive_gcd) m_eager_gcd = true; return false; @@ -883,10 +878,8 @@ namespace smt { for (;;) { vars.reset(); // Collect infeasible integer variables. - typename vector::const_iterator it = m_rows.begin(); - typename vector::const_iterator end = m_rows.end(); - for (; it != end; ++it) { - theory_var v = it->get_base_var(); + for (auto const& e : m_rows) { + theory_var v = e.get_base_var(); if (v != null_theory_var && is_int(v) && !get_value(v).is_int() && !is_bounded(v) && !already_processed.contains(v)) { vars.push_back(v); already_processed.insert(v); @@ -1056,15 +1049,13 @@ namespace smt { TRACE("arith_int_rows", unsigned num = 0; - typename vector::const_iterator it = m_rows.begin(); - typename vector::const_iterator end = m_rows.end(); - for (; it != end; ++it) { - theory_var v = it->get_base_var(); + for (auto const& e : m_rows) { + theory_var v = e.get_base_var(); if (v == null_theory_var) continue; if (is_int(v) && !get_value(v).is_int()) { num++; - display_simplified_row(tout, *it); + display_simplified_row(tout, e); tout << "\n"; } } diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index 9d3e93839..1f842c2ed 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -91,9 +91,9 @@ namespace smt { d->m_parent_selects.push_back(s); TRACE("array", tout << v << " " << mk_pp(s->get_expr(), m) << " " << mk_pp(get_enode(v)->get_expr(), m) << "\n";); m_trail_stack.push(push_back_trail(d->m_parent_selects)); - for (enode* n : d->m_stores) { + for (enode* n : d->m_stores) instantiate_axiom2a(s, n); - } + if (!m_params.m_array_delay_exp_axiom && d->m_prop_upward) { for (enode* store : d->m_parent_stores) { SASSERT(is_store(store)); diff --git a/src/smt/theory_array_bapa.cpp b/src/smt/theory_array_bapa.cpp index 9379c939f..988f3fdad 100644 --- a/src/smt/theory_array_bapa.cpp +++ b/src/smt/theory_array_bapa.cpp @@ -450,7 +450,6 @@ namespace smt { app* m_obj; public: remove_sz(ast_manager& m, obj_map& tab, app* t): m(m), m_table(tab), m_obj(t) { } - ~remove_sz() override {} void undo() override { m.dec_ref(m_obj); dealloc(m_table[m_obj]); m_table.remove(m_obj); } }; diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index f6d4306a5..e71630fa4 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -54,6 +54,20 @@ namespace smt { return r; } + app * theory_array_base::mk_select_reduce(unsigned num_args, expr * * args) { + array_util util(m); + while (util.is_store(args[0])) { + bool are_distinct = false; + for (unsigned i = 1; i < num_args && !are_distinct; ++i) + are_distinct |= m.are_distinct(args[i], to_app(args[0])->get_arg(i)); + if (!are_distinct) + break; + args[0] = to_app(to_app(args[0])->get_arg(0)); + } + return mk_select(num_args, args); + } + + app * theory_array_base::mk_store(unsigned num_args, expr * const * args) { return m.mk_app(get_family_id(), OP_STORE, 0, nullptr, num_args, args); } @@ -101,7 +115,7 @@ namespace smt { SASSERT(num_args >= 3); sel_args.push_back(n); for (unsigned i = 1; i < num_args - 1; ++i) { - sel_args.push_back(to_app(n->get_arg(i))); + sel_args.push_back(n->get_arg(i)); } expr_ref sel(m); sel = mk_select(sel_args.size(), sel_args.data()); @@ -179,6 +193,12 @@ namespace smt { conseq_expr = ctx.bool_var2expr(conseq.var()); } + if (m.are_distinct(idx1->get_expr(), idx2->get_expr())) { + ctx.mark_as_relevant(conseq); + assert_axiom(conseq); + continue; + } + literal ante = mk_eq(idx1->get_expr(), idx2->get_expr(), true); ctx.mark_as_relevant(ante); // ctx.force_phase(ante); @@ -890,8 +910,6 @@ namespace smt { m_unspecified_else(true) { } - ~array_value_proc() override {} - void add_entry(unsigned num_args, enode * const * args, enode * value) { SASSERT(num_args > 0); SASSERT(m_dim == 0 || m_dim == num_args); diff --git a/src/smt/theory_array_base.h b/src/smt/theory_array_base.h index f0d698f26..58d143ff1 100644 --- a/src/smt/theory_array_base.h +++ b/src/smt/theory_array_base.h @@ -62,6 +62,7 @@ namespace smt { bool is_select_arg(enode* r); app * mk_select(unsigned num_args, expr * const * args); + app * mk_select_reduce(unsigned num_args, expr * * args); app * mk_select(expr_ref_vector const& args) { return mk_select(args.size(), args.data()); } app * mk_store(unsigned num_args, expr * const * args); app * mk_default(expr* a); diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 196f49281..556391250 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -1510,7 +1510,7 @@ namespace smt { eqs.push_back({n1, p->get_arg(0) }); eqs.push_back({n1, bv2int}); justification * js = ctx.mk_justification( - ext_theory_eq_propagation_justification(get_id(), ctx.get_region(), 0, nullptr, eqs.size(), eqs.data(), p, bv2int_arg)); + ext_theory_eq_propagation_justification(get_id(), ctx, 0, nullptr, eqs.size(), eqs.data(), p, bv2int_arg)); ctx.assign_eq(p, bv2int_arg, eq_justification(js)); break; } diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index d73b7a008..5a5e1e6f2 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -42,7 +42,7 @@ namespace smt { class atom { public: - virtual ~atom() {} + virtual ~atom() = default; virtual bool is_bit() const = 0; }; @@ -56,7 +56,6 @@ namespace smt { struct bit_atom : public atom { var_pos_occ * m_occs; bit_atom():m_occs(nullptr) {} - ~bit_atom() override {} bool is_bit() const override { return true; } }; @@ -64,7 +63,6 @@ namespace smt { literal m_var; literal m_def; le_atom(literal v, literal d):m_var(v), m_def(d) {} - ~le_atom() override {} bool is_bit() const override { return false; } }; diff --git a/src/smt/theory_char.cpp b/src/smt/theory_char.cpp index 772438986..dc41dfec5 100644 --- a/src/smt/theory_char.cpp +++ b/src/smt/theory_char.cpp @@ -138,7 +138,7 @@ namespace smt { enode* n2 = ensure_enode(bits2char); justification* j = ctx.mk_justification( - ext_theory_eq_propagation_justification(get_id(), ctx.get_region(), n1, n2)); + ext_theory_eq_propagation_justification(get_id(), ctx, n1, n2)); ctx.assign_eq(n1, n2, eq_justification(j)); } ++m_stats.m_num_blast; @@ -267,7 +267,7 @@ namespace smt { enode* n2 = ensure_enode(sum_bits); justification* j = ctx.mk_justification( - ext_theory_eq_propagation_justification(get_id(), ctx.get_region(), n1, n2)); + ext_theory_eq_propagation_justification(get_id(), ctx, n1, n2)); ctx.assign_eq(n1, n2, eq_justification(j)); } diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index d11172691..d1216c171 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -31,8 +31,8 @@ namespace smt { class dt_eq_justification : public ext_theory_eq_propagation_justification { public: - dt_eq_justification(family_id fid, region & r, literal antecedent, enode * lhs, enode * rhs): - ext_theory_eq_propagation_justification(fid, r, 1, &antecedent, 0, nullptr, lhs, rhs) { + dt_eq_justification(family_id fid, context& ctx, literal antecedent, enode * lhs, enode * rhs): + ext_theory_eq_propagation_justification(fid, ctx, 1, &antecedent, 0, nullptr, lhs, rhs) { } // Remark: the assignment must be propagated back to the datatype theory. theory_id get_from_theory() const override { return null_theory_id; } @@ -122,9 +122,8 @@ namespace smt { } else { SASSERT(ctx.get_assignment(antecedent) == l_true); - region & r = ctx.get_region(); enode * _rhs = ctx.get_enode(rhs); - justification * js = ctx.mk_justification(dt_eq_justification(get_id(), r, antecedent, lhs, _rhs)); + justification * js = ctx.mk_justification(dt_eq_justification(get_id(), ctx, antecedent, lhs, _rhs)); TRACE("datatype", tout << "assigning... #" << lhs->get_owner_id() << " #" << _rhs->get_owner_id() << "\n"; tout << "v" << lhs->get_th_var(get_id()) << " v" << _rhs->get_th_var(get_id()) << "\n";); TRACE("datatype_detail", display(tout);); @@ -209,9 +208,8 @@ namespace smt { l.neg(); SASSERT(ctx.get_assignment(l) == l_true); enode_pair p(c, r->get_arg(0)); - region & reg = ctx.get_region(); clear_mark(); - ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), reg, 1, &l, 1, &p))); + ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), ctx, 1, &l, 1, &p))); } /** @@ -732,9 +730,8 @@ namespace smt { if (res) { // m_used_eqs should contain conflict - region & r = ctx.get_region(); clear_mark(); - ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), r, 0, nullptr, m_used_eqs.size(), m_used_eqs.data()))); + ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), ctx, 0, nullptr, m_used_eqs.size(), m_used_eqs.data()))); } return res; } @@ -823,7 +820,6 @@ namespace smt { public: datatype_value_proc(func_decl * d):m_constructor(d) {} void add_dependency(enode * n) { m_dependencies.push_back(model_value_dependency(n)); } - ~datatype_value_proc() override {} void get_dependencies(buffer & result) override { result.append(m_dependencies.size(), m_dependencies.data()); } @@ -860,10 +856,9 @@ namespace smt { var_data * d2 = m_var_data[v2]; if (d2->m_constructor != nullptr) { if (d1->m_constructor != nullptr && d1->m_constructor->get_decl() != d2->m_constructor->get_decl()) { - region & r = ctx.get_region(); enode_pair p(d1->m_constructor, d2->m_constructor); SASSERT(d1->m_constructor->get_root() == d2->m_constructor->get_root()); - ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), r, 0, nullptr, 1, &p))); + ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), ctx, 0, nullptr, 1, &p))); } if (d1->m_constructor == nullptr) { m_trail_stack.push(set_ptr_trail(d1->m_constructor)); @@ -973,14 +968,13 @@ namespace smt { if (num_unassigned == 0) { // conflict SASSERT(!lits.empty()); - region & reg = ctx.get_region(); TRACE("datatype_conflict", tout << mk_ismt2_pp(recognizer->get_expr(), m) << "\n"; for (literal l : lits) ctx.display_detailed_literal(tout, l) << "\n"; for (auto const& p : eqs) tout << enode_eq_pp(p, ctx); ); - ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), reg, lits.size(), lits.data(), eqs.size(), eqs.data()))); + ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), ctx, lits.size(), lits.data(), eqs.size(), eqs.data()))); } else if (num_unassigned == 1) { // propagate remaining recognizer @@ -998,9 +992,8 @@ namespace smt { consequent = literal(ctx.enode2bool_var(r)); } ctx.mark_as_relevant(consequent); - region & reg = ctx.get_region(); ctx.assign(consequent, - ctx.mk_justification(ext_theory_propagation_justification(get_id(), reg, lits.size(), lits.data(), + ctx.mk_justification(ext_theory_propagation_justification(get_id(), ctx, lits.size(), lits.data(), eqs.size(), eqs.data(), consequent))); } else { diff --git a/src/smt/theory_dense_diff_logic.h b/src/smt/theory_dense_diff_logic.h index 8ab091a27..0a2987f8d 100644 --- a/src/smt/theory_dense_diff_logic.h +++ b/src/smt/theory_dense_diff_logic.h @@ -238,7 +238,6 @@ namespace smt { void flush_eh() override; void reset_eh() override; - bool dump_lemmas() const { return m_params.m_arith_dump_lemmas; } void display(std::ostream & out) const override; virtual void display_atom(std::ostream & out, atom * a) const; diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index 3a19b1c19..46d2b0119 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -539,7 +539,7 @@ namespace smt { literal_vector & antecedents = m_tmp_literals; antecedents.reset(); get_antecedents(source, target, antecedents); - ctx.assign(l, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), antecedents.size(), antecedents.data(), l))); + ctx.assign(l, ctx.mk_justification(theory_propagation_justification(get_id(), ctx, antecedents.size(), antecedents.data(), l))); } template @@ -592,11 +592,7 @@ namespace smt { if (l != null_literal) antecedents.push_back(l); region & r = ctx.get_region(); - ctx.set_conflict(ctx.mk_justification(theory_conflict_justification(get_id(), r, antecedents.size(), antecedents.data()))); - - if (dump_lemmas()) { - ctx.display_lemma_as_smt_problem(antecedents.size(), antecedents.data(), false_literal); - } + ctx.set_conflict(ctx.mk_justification(theory_conflict_justification(get_id(), ctx, antecedents.size(), antecedents.data()))); return; } @@ -1011,7 +1007,7 @@ namespace smt { expr_ref tmp(m); core.reset(); for (; it != end; ++it) { - unsigned v = it->m_var; + unsigned v = it->var(); if (num_nodes <= v && v < num_nodes + num_edges) { unsigned edge_id = v - num_nodes; literal lit = m_edges[edge_id].m_justification; diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 99e70bd74..a613c8012 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -350,8 +350,6 @@ namespace smt { bool propagate_eqs() const { return m_params.m_arith_propagate_eqs; } - bool dump_lemmas() const { return m_params.m_arith_dump_lemmas; } - theory_var expand(bool pos, theory_var v, rational & k); void new_eq_or_diseq(bool is_eq, theory_var v1, theory_var v2, justification& eq_just); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index e9747c4ae..807eb6cb6 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -665,10 +665,6 @@ void theory_diff_logic::new_edge(dl_var src, dl_var dst, unsigned num_edges params.size(), params.data()); } ctx.mk_clause(lits.size(), lits.data(), js, CLS_TH_LEMMA, nullptr); - if (dump_lemmas()) { - symbol logic(m_lia_or_lra == is_lia ? "QF_LIA" : "QF_LRA"); - ctx.display_lemma_as_smt_problem(lits.size(), lits.data(), false_literal, logic); - } #if 0 TRACE("arith", @@ -707,11 +703,6 @@ void theory_diff_logic::set_neg_cycle_conflict() { for (literal lit : lits) ctx.display_literal_info(tout, lit); tout << "\n";); - if (dump_lemmas()) { - symbol logic(m_lia_or_lra == is_lia ? "QF_LIA" : "QF_LRA"); - ctx.display_lemma_as_smt_problem(lits.size(), lits.data(), false_literal, logic); - } - vector params; if (m.proofs_enabled()) { params.push_back(parameter(symbol("farkas"))); @@ -723,7 +714,7 @@ void theory_diff_logic::set_neg_cycle_conflict() { ctx.set_conflict( ctx.mk_justification( ext_theory_conflict_justification( - get_id(), ctx.get_region(), + get_id(), ctx, lits.size(), lits.data(), 0, nullptr, params.size(), params.data()))); } @@ -1283,7 +1274,7 @@ theory_diff_logic::maximize(theory_var v, expr_ref& blocker, bool& has_shar expr_ref tmp(m); core.reset(); for (; it != end; ++it) { - unsigned v = it->m_var; + unsigned v = it->var(); if (is_simplex_edge(v)) { unsigned edge_id = simplex2edge(v); literal lit = m_graph.get_explanation(edge_id); diff --git a/src/smt/theory_dummy.h b/src/smt/theory_dummy.h index 6f2e641fd..817d1fda1 100644 --- a/src/smt/theory_dummy.h +++ b/src/smt/theory_dummy.h @@ -46,7 +46,6 @@ namespace smt { public: theory_dummy(context& ctx, family_id fid, char const * name); - ~theory_dummy() override {} theory * mk_fresh(context * new_ctx) override { return alloc(theory_dummy, *new_ctx, get_family_id(), m_name); } diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 9d5df855e..9aa70d9bf 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -47,8 +47,6 @@ namespace smt { m_th(*th), m(th->get_manager()), m_fu(th->m_fpa_util), m_bu(th->m_bv_util), m_ebits(ebits), m_sbits(sbits) {} - ~fpa_value_proc() override {} - void add_dependency(enode * e) { m_deps.push_back(model_value_dependency(e)); } void get_dependencies(buffer & result) override { @@ -75,7 +73,6 @@ namespace smt { result.append(m_deps); } - ~fpa_rm_value_proc() override {} app * mk_value(model_generator & mg, expr_ref_vector const & values) override; }; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 75f9cb997..b8001174e 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -607,7 +607,7 @@ class theory_lra::imp { return v; } - bool const has_int() const { return lp().has_int_var(); } + bool has_int() const { return lp().has_int_var(); } lpvar register_theory_var_in_lar_solver(theory_var v) { lpvar lpv = lp().external_to_local(v); @@ -1113,7 +1113,7 @@ public: } { scoped_trace_stream ts(th, dgez, neg); - mk_axiom( dgez, neg); + mk_axiom( dgez, neg); } } @@ -1224,7 +1224,6 @@ public: return; } expr_ref mod_r(a.mk_add(a.mk_mul(q, div), mod), m); - ctx().get_rewriter()(mod_r); expr_ref eq_r(th.mk_eq_atom(mod_r, p), m); ctx().internalize(eq_r, false); literal eq = ctx().get_literal(eq_r); @@ -2332,7 +2331,6 @@ public: literal_vector m_core2; void assign(literal lit, literal_vector const& core, svector const& eqs, vector const& params) { - dump_assign(lit, core, eqs); if (core.size() < small_lemma_size() && eqs.empty()) { m_core2.reset(); for (auto const& c : core) { @@ -2350,7 +2348,7 @@ public: ctx().assign( lit, ctx().mk_justification( ext_theory_propagation_justification( - get_id(), ctx().get_region(), core.size(), core.data(), + get_id(), ctx(), core.size(), core.data(), eqs.size(), eqs.data(), lit, params.size(), params.data()))); } } @@ -2943,8 +2941,6 @@ public: } - bool dump_lemmas() const { return params().m_arith_dump_lemmas; } - bool propagate_eqs() const { return params().m_arith_propagate_eqs && m_num_conflicts < params().m_arith_propagation_threshold; } bound_prop_mode propagation_mode() const { return m_num_conflicts < params().m_arith_propagation_threshold ? params().m_arith_bound_prop : bound_prop_mode::BP_NONE; } @@ -3080,7 +3076,7 @@ public: justification* js = ctx().mk_justification( ext_theory_eq_propagation_justification( - get_id(), ctx().get_region(), m_core.size(), m_core.data(), m_eqs.size(), m_eqs.data(), x, y)); + get_id(), ctx(), m_core.size(), m_core.data(), m_eqs.size(), m_eqs.data(), x, y)); TRACE("arith", for (auto c : m_core) @@ -3204,12 +3200,11 @@ public: set_evidence(ev.ci(), m_core, m_eqs); // SASSERT(validate_conflict(m_core, m_eqs)); - dump_conflict(m_core, m_eqs); if (is_conflict) { ctx().set_conflict( ctx().mk_justification( ext_theory_conflict_justification( - get_id(), ctx().get_region(), + get_id(), ctx(), m_core.size(), m_core.data(), m_eqs.size(), m_eqs.data(), m_params.size(), m_params.data()))); } @@ -3415,11 +3410,6 @@ public: } }; - void dump_conflict(literal_vector const& core, svector const& eqs) { - if (dump_lemmas()) { - ctx().display_lemma_as_smt_problem(core.size(), core.data(), eqs.size(), eqs.data(), false_literal); - } - } bool validate_conflict(literal_vector const& core, svector const& eqs) { if (params().m_arith_mode != arith_solver_id::AS_NEW_ARITH) return true; @@ -3433,13 +3423,6 @@ public: return result; } - void dump_assign(literal lit, literal_vector const& core, svector const& eqs) { - if (dump_lemmas()) { - unsigned id = ctx().display_lemma_as_smt_problem(core.size(), core.data(), eqs.size(), eqs.data(), lit); - (void)id; - } - } - bool validate_assign(literal lit, literal_vector const& core, svector const& eqs) { if (params().m_arith_mode != arith_solver_id::AS_NEW_ARITH) return true; scoped_arith_mode _sa(ctx().get_fparams()); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index f24e4746d..db076ef8c 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1106,7 +1106,7 @@ namespace smt { \brief propagate assignment to inequality. This is a basic, non-optimized implementation based on the assumption that inequalities are mostly units - and/or relatively few compared to number of argumets. + and/or relatively few compared to number of arguments. */ void theory_pb::assign_ineq(ineq& c, bool is_true) { m_mpz_trail.push_back(c.m_max_sum); @@ -1486,9 +1486,9 @@ namespace smt { class theory_pb::pb_justification : public theory_propagation_justification { ineq& m_ineq; public: - pb_justification(ineq& c, family_id fid, region & r, + pb_justification(ineq& c, family_id fid, context& ctx, unsigned num_lits, literal const * lits, literal consequent): - theory_propagation_justification(fid, r, num_lits, lits, consequent), + theory_propagation_justification(fid, ctx, num_lits, lits, consequent), m_ineq(c) {} ineq& get_ineq() { return m_ineq; } @@ -1504,7 +1504,7 @@ namespace smt { SASSERT(validate_antecedents(lits)); ctx.assign(l, ctx.mk_justification( pb_justification( - c, get_id(), ctx.get_region(), lits.size(), lits.data(), l))); + c, get_id(), ctx, lits.size(), lits.data(), l))); } @@ -2008,7 +2008,7 @@ namespace smt { SASSERT(validate_antecedents(m_antecedents)); TRACE("pb", tout << "assign " << m_antecedents << " ==> " << alit << "\n";); - ctx.assign(alit, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.data(), alit, 0, nullptr))); + ctx.assign(alit, ctx.mk_justification(theory_propagation_justification(get_id(), ctx, m_antecedents.size(), m_antecedents.data(), alit, 0, nullptr))); DEBUG_CODE( m_antecedents.push_back(~alit); @@ -2029,7 +2029,7 @@ namespace smt { literal lits[2] = { l1, l2 }; justification* js = nullptr; if (proofs_enabled()) { - js = ctx.mk_justification(theory_axiom_justification(get_id(), ctx.get_region(), 2, lits)); + js = ctx.mk_justification(theory_axiom_justification(get_id(), ctx, 2, lits)); } return js; } @@ -2037,7 +2037,7 @@ namespace smt { justification* theory_pb::justify(literal_vector const& lits) { justification* js = nullptr; if (proofs_enabled()) { - js = ctx.mk_justification(theory_axiom_justification(get_id(), ctx.get_region(), lits.size(), lits.data())); + js = ctx.mk_justification(theory_axiom_justification(get_id(), ctx, lits.size(), lits.data())); } return js; } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 2d62bb7ac..f713877b3 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -19,6 +19,7 @@ Notes: It performs unit propagation and switches to creating sorting circuits if it keeps having to propagate (create new clauses). --*/ +#pragma once #include "smt/smt_theory.h" #include "ast/pb_decl_plugin.h" diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 00b607fbc..de6742ec8 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -783,7 +783,7 @@ bool theory_seq::propagate_lit(dependency* dep, unsigned n, literal const* _lits justification* js = ctx.mk_justification( ext_theory_propagation_justification( - get_id(), ctx.get_region(), lits.size(), lits.data(), eqs.size(), eqs.data(), lit)); + get_id(), ctx, lits.size(), lits.data(), eqs.size(), eqs.data(), lit)); m_new_propagation = true; ctx.assign(lit, js); @@ -804,7 +804,7 @@ void theory_seq::set_conflict(enode_pair_vector const& eqs, literal_vector const ctx.set_conflict( ctx.mk_justification( ext_theory_conflict_justification( - get_id(), ctx.get_region(), lits.size(), lits.data(), eqs.size(), eqs.data(), 0, nullptr))); + get_id(), ctx, lits.size(), lits.data(), eqs.size(), eqs.data(), 0, nullptr))); validate_conflict(eqs, lits); } @@ -829,7 +829,7 @@ bool theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) { justification* js = ctx.mk_justification( ext_theory_eq_propagation_justification( - get_id(), ctx.get_region(), lits.size(), lits.data(), eqs.size(), eqs.data(), n1, n2)); + get_id(), ctx, lits.size(), lits.data(), eqs.size(), eqs.data(), n1, n2)); { std::function fn = [&]() { return m.mk_eq(n1->get_expr(), n2->get_expr()); }; @@ -1923,7 +1923,6 @@ public: seq_value_proc(theory_seq& th, enode* n, sort* s): th(th), m_node(n), m_sort(s) { (void)m_node; } - ~seq_value_proc() override {} void add_unit(enode* n) { m_dependencies.push_back(model_value_dependency(n)); m_source.push_back(unit_source); @@ -2955,7 +2954,7 @@ bool theory_seq::propagate_eq(dependency* deps, literal_vector const& _lits, exp justification* js = ctx.mk_justification( ext_theory_eq_propagation_justification( - get_id(), ctx.get_region(), lits.size(), lits.data(), eqs.size(), eqs.data(), n1, n2)); + get_id(), ctx, lits.size(), lits.data(), eqs.size(), eqs.data(), n1, n2)); m_new_propagation = true; @@ -3070,9 +3069,13 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { } else if (m_util.str.is_is_digit(e)) { + } + else if (m_util.str.is_foldl(e) || m_util.str.is_foldli(e)) { + } else { TRACE("seq", tout << mk_pp(e, m) << "\n";); + IF_VERBOSE(0, verbose_stream() << mk_pp(e, m) << "\n"); UNREACHABLE(); } } @@ -3273,7 +3276,7 @@ bool theory_seq::should_research(expr_ref_vector & unsat_core) { } } - if (k_min < UINT_MAX/4) { + if (k_min < get_fparams().m_seq_max_unfolding) { m_max_unfolding_depth++; k_min *= 2; if (m_util.is_seq(s_min)) @@ -3287,7 +3290,7 @@ bool theory_seq::should_research(expr_ref_vector & unsat_core) { IF_VERBOSE(1, verbose_stream() << "(smt.seq :increase-depth " << m_max_unfolding_depth << ")\n"); return true; } - else if (k_min != UINT_MAX && k_min >= UINT_MAX/4) { + else if (k_min != UINT_MAX && k_min >= get_fparams().m_seq_max_unfolding) { throw default_exception("reached max unfolding"); } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index cf7e9da23..48acb6ad8 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -222,7 +222,7 @@ namespace smt { class apply { public: - virtual ~apply() {} + virtual ~apply() = default; virtual void operator()(theory_seq& th) = 0; }; @@ -230,7 +230,6 @@ namespace smt { expr_ref m_e; public: replay_length_coherence(ast_manager& m, expr* e) : m_e(e, m) {} - ~replay_length_coherence() override {} void operator()(theory_seq& th) override { th.check_length_coherence(m_e); m_e.reset(); @@ -241,7 +240,6 @@ namespace smt { expr_ref m_e; public: replay_fixed_length(ast_manager& m, expr* e) : m_e(e, m) {} - ~replay_fixed_length() override {} void operator()(theory_seq& th) override { th.fixed_length(m_e, false, false); m_e.reset(); @@ -252,7 +250,6 @@ namespace smt { expr_ref m_e; public: replay_axiom(ast_manager& m, expr* e) : m_e(e, m) {} - ~replay_axiom() override {} void operator()(theory_seq& th) override { th.enque_axiom(m_e); m_e.reset(); @@ -264,7 +261,6 @@ namespace smt { bool m_sign; public: replay_unit_literal(ast_manager& m, expr* e, bool sign) : m_e(e, m), m_sign(sign) {} - ~replay_unit_literal() override {} void operator()(theory_seq& th) override { literal lit = th.mk_literal(m_e); if (m_sign) lit.neg(); @@ -278,7 +274,6 @@ namespace smt { expr_ref m_e; public: replay_is_axiom(ast_manager& m, expr* e) : m_e(e, m) {} - ~replay_is_axiom() override {} void operator()(theory_seq& th) override { th.check_int_string(m_e); m_e.reset(); diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 40f94cdbc..9113f189e 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -135,7 +135,7 @@ namespace smt { bool theory_special_relations::internalize_atom(app * atm, bool gate_ctx) { SASSERT(m_util.is_special_relation(atm)); - relation* r = 0; + relation* r = nullptr; ast_manager& m = get_manager(); if (!m_relations.find(atm->get_decl(), r)) { r = alloc(relation, m_util.get_property(atm), atm->get_decl(), m); @@ -279,7 +279,7 @@ namespace smt { enode* tcn = ensure_enode(tc_app); if (ctx.get_assignment(tcn) != l_true) { literal consequent = ctx.get_literal(tc_app); - justification* j = ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), 1, &lit, consequent)); + justification* j = ctx.mk_justification(theory_propagation_justification(get_id(), ctx, 1, &lit, consequent)); TRACE("special_relations", tout << "propagate: " << tc_app << "\n";); ctx.assign(consequent, j); new_assertion = true; @@ -469,8 +469,8 @@ namespace smt { ctx.set_conflict( ctx.mk_justification( ext_theory_conflict_justification( - get_id(), ctx.get_region(), - lits.size(), lits.data(), 0, 0, params.size(), params.data()))); + get_id(), ctx, + lits.size(), lits.data(), 0, nullptr, params.size(), params.data()))); } lbool theory_special_relations::final_check(relation& r) { @@ -532,7 +532,7 @@ namespace smt { literal_vector const& lits = r.m_explanation; TRACE("special_relations", ctx.display_literals_verbose(tout << mk_pp(x->get_expr(), m) << " = " << mk_pp(y->get_expr(), m) << "\n", lits) << "\n";); IF_VERBOSE(20, ctx.display_literals_verbose(verbose_stream() << mk_pp(x->get_expr(), m) << " = " << mk_pp(y->get_expr(), m) << "\n", lits) << "\n";); - eq_justification js(ctx.mk_justification(ext_theory_eq_propagation_justification(get_id(), ctx.get_region(), lits.size(), lits.data(), 0, nullptr, + eq_justification js(ctx.mk_justification(ext_theory_eq_propagation_justification(get_id(), ctx, lits.size(), lits.data(), 0, nullptr, x, y))); ctx.assign_eq(x, y, js); } @@ -1149,8 +1149,8 @@ namespace smt { void theory_special_relations::get_specrels(func_decl_set& rels) const { - for (auto [f, r] : m_relations) - rels.insert(m_util.get_relation(r->m_decl)); + for (auto [f, r] : m_relations) + rels.insert(r->m_decl); } } diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 090a5fe36..27ee97c97 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -51,7 +51,6 @@ public: str_value_factory(ast_manager & m, family_id fid) : value_factory(m, fid), u(m), delim("!"), m_next(0) {} - ~str_value_factory() override {} expr * get_some_value(sort * s) override { return u.str.mk_string("some value"); } @@ -93,7 +92,6 @@ class binary_search_trail : public trail { public: binary_search_trail(obj_map > & target, expr * entry) : target(target), entry(entry) {} - ~binary_search_trail() override {} void undo() override { TRACE("t_str_binary_search", tout << "in binary_search_trail::undo()" << std::endl;); if (target.contains(entry)) { diff --git a/src/smt/theory_str_regex.cpp b/src/smt/theory_str_regex.cpp index 57ed89588..0fb5f92df 100644 --- a/src/smt/theory_str_regex.cpp +++ b/src/smt/theory_str_regex.cpp @@ -724,8 +724,7 @@ namespace smt { unsigned cx = estimate_regex_complexity(sub1); return _qadd(lo, cx); } else if (u.re.is_range(re, sub1, sub2)) { - SASSERT(u.str.is_string(sub1)); - SASSERT(u.str.is_string(sub2)); + if (!u.re.is_range(re, lo, hi)) throw default_exception("regular expressions must be built from string literals"); zstring str1, str2; u.str.is_string(sub1, str1); u.str.is_string(sub2, str2); @@ -767,8 +766,7 @@ namespace smt { unsigned cx = estimate_regex_complexity_under_complement(sub1); return _qmul(2, cx); } else if (u.re.is_range(re, sub1, sub2)) { - SASSERT(u.str.is_string(sub1)); - SASSERT(u.str.is_string(sub2)); + if (!u.re.is_range(re, lo, hi)) throw default_exception("regular expressions must be built from string literals"); zstring str1, str2; u.str.is_string(sub1, str1); u.str.is_string(sub2, str2); @@ -874,8 +872,7 @@ namespace smt { // this is bad -- term generation requires this not to appear lens.reset(); } else if (u.re.is_range(re, sub1, sub2)) { - SASSERT(u.str.is_string(sub1)); - SASSERT(u.str.is_string(sub2)); + if (!u.re.is_range(re, lo, hi)) throw default_exception("regular expressions must be built from string literals"); zstring str1, str2; u.str.is_string(sub1, str1); u.str.is_string(sub2, str2); @@ -1006,8 +1003,7 @@ namespace smt { SASSERT(retval); return retval; } else if (u.re.is_range(re, sub1, sub2)) { - SASSERT(u.str.is_string(sub1)); - SASSERT(u.str.is_string(sub2)); + if (!u.re.is_range(re, lo, hi)) throw default_exception("regular expressions must be built from string literals"); zstring str1, str2; u.str.is_string(sub1, str1); u.str.is_string(sub2, str2); diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 911d1715e..b8efea851 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -146,7 +146,9 @@ final_check_status theory_user_propagator::final_check_eh() { catch (...) { throw default_exception("Exception thrown in \"final\"-callback"); } + CTRACE("user_propagate", can_propagate(), tout << "can propagate\n"); propagate(); + CTRACE("user_propagate", ctx.inconsistent(), tout << "inconsistent\n"); // check if it became inconsistent or something new was propagated/registered bool done = (sz1 == m_prop.size()) && (sz2 == m_expr2var.size()) && !ctx.inconsistent(); return done ? FC_DONE : FC_CONTINUE; @@ -298,18 +300,22 @@ void theory_user_propagator::propagate_consequence(prop_info const& prop) { m_eqs.reset(); for (expr* id : prop.m_ids) m_lits.append(m_id2justification[expr2var(id)]); - for (auto const& p : prop.m_eqs) - m_eqs.push_back(enode_pair(get_enode(expr2var(p.first)), get_enode(expr2var(p.second)))); - DEBUG_CODE(for (auto const& p : m_eqs) VERIFY(p.first->get_root() == p.second->get_root());); + for (auto const& [a,b] : prop.m_eqs) + if (a != b) + m_eqs.push_back(enode_pair(get_enode(expr2var(a)), get_enode(expr2var(b)))); + DEBUG_CODE(for (auto const& [a, b] : m_eqs) VERIFY(a->get_root() == b->get_root());); DEBUG_CODE(for (expr* e : prop.m_ids) VERIFY(m_fixed.contains(expr2var(e)));); DEBUG_CODE(for (literal lit : m_lits) VERIFY(ctx.get_assignment(lit) == l_true);); - TRACE("user_propagate", tout << "propagating #" << prop.m_conseq->get_id() << ": " << prop.m_conseq << "\n"); + TRACE("user_propagate", tout << "propagating #" << prop.m_conseq->get_id() << ": " << prop.m_conseq << "\n"; + for (auto const& [a,b] : m_eqs) tout << enode_pp(a, ctx) << " == " << enode_pp(b, ctx) << "\n"; + for (expr* e : prop.m_ids) tout << mk_pp(e, m) << "\n"; + for (literal lit : m_lits) tout << lit << "\n"); if (m.is_false(prop.m_conseq)) { js = ctx.mk_justification( ext_theory_conflict_justification( - get_id(), ctx.get_region(), m_lits.size(), m_lits.data(), m_eqs.size(), m_eqs.data(), 0, nullptr)); + get_id(), ctx, m_lits.size(), m_lits.data(), m_eqs.size(), m_eqs.data(), 0, nullptr)); ctx.set_conflict(js); } else { @@ -341,9 +347,9 @@ void theory_user_propagator::propagate_new_fixed(prop_info const& prop) { void theory_user_propagator::propagate() { - TRACE("user_propagate", tout << "propagating queue head: " << m_qhead << " prop queue: " << m_prop.size() << "\n"); if (m_qhead == m_prop.size() && m_to_add_qhead == m_to_add.size()) return; + TRACE("user_propagate", tout << "propagating queue head: " << m_qhead << " prop queue: " << m_prop.size() << "\n"); force_push(); unsigned qhead = m_to_add_qhead; diff --git a/src/smt/theory_user_propagator.h b/src/smt/theory_user_propagator.h index ba9900848..2ed1acbdf 100644 --- a/src/smt/theory_user_propagator.h +++ b/src/smt/theory_user_propagator.h @@ -140,10 +140,11 @@ namespace smt { bool get_case_split(bool_var& var, bool& is_pos); theory * mk_fresh(context * new_ctx) override; + char const* get_name() const override { return "user_propagate"; } bool internalize_atom(app* atom, bool gate_ctx) override; bool internalize_term(app* term) override; - void new_eq_eh(theory_var v1, theory_var v2) override { if (m_eq_eh) m_eq_eh(m_user_context, this, var2expr(v1), var2expr(v2)); } - void new_diseq_eh(theory_var v1, theory_var v2) override { if (m_diseq_eh) m_diseq_eh(m_user_context, this, var2expr(v1), var2expr(v2)); } + void new_eq_eh(theory_var v1, theory_var v2) override { if (m_eq_eh) force_push(), m_eq_eh(m_user_context, this, var2expr(v1), var2expr(v2)); } + void new_diseq_eh(theory_var v1, theory_var v2) override { if (m_diseq_eh) force_push(), m_diseq_eh(m_user_context, this, var2expr(v1), var2expr(v2)); } bool use_diseqs() const override { return ((bool)m_diseq_eh); } bool build_models() const override { return false; } final_check_status final_check_eh() override; diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index b43c8a57d..d4c6d684c 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -204,12 +204,7 @@ namespace smt { inc_conflicts(); literal_vector const& lits = m_nc_functor.get_lits(); IF_VERBOSE(20, ctx.display_literals_smt2(verbose_stream() << "conflict:\n", lits)); - TRACE("utvpi", ctx.display_literals_smt2(tout << "conflict:\n", lits);); - - if (m_params.m_arith_dump_lemmas) { - symbol logic(m_lra ? (m_lia?"QF_LIRA":"QF_LRA") : "QF_LIA"); - ctx.display_lemma_as_smt_problem(lits.size(), lits.data(), false_literal, logic); - } + TRACE("utvpi", ctx.display_literals_smt2(tout << "conflict:\n", lits);); vector params; if (m.proofs_enabled()) { @@ -222,7 +217,7 @@ namespace smt { ctx.set_conflict( ctx.mk_justification( ext_theory_conflict_justification( - get_id(), ctx.get_region(), + get_id(), ctx, lits.size(), lits.data(), 0, nullptr, params.size(), params.data()))); m_nc_functor.reset(); diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index d6c6793e1..c5960a7b9 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -283,7 +283,7 @@ namespace smt { ctx.set_conflict( ctx.mk_justification( - ext_theory_conflict_justification(get_id(), ctx.get_region(), lits.size(), lits.data(), 0, nullptr, 0, nullptr))); + ext_theory_conflict_justification(get_id(), ctx, lits.size(), lits.data(), 0, nullptr, 0, nullptr))); } bool theory_wmaxsat::max_unassigned_is_blocked() { @@ -328,10 +328,9 @@ namespace smt { ctx.display_literals_verbose(tout, lits.size(), lits.data()); ctx.display_literal_verbose(tout << " --> ", lit);); - region& r = ctx.get_region(); ctx.assign(lit, ctx.mk_justification( ext_theory_propagation_justification( - get_id(), r, lits.size(), lits.data(), 0, nullptr, lit, 0, nullptr))); + get_id(), ctx, lits.size(), lits.data(), 0, nullptr, lit, 0, nullptr))); } diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index 236f56bee..03a205ca6 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -74,10 +74,7 @@ namespace smt { m_old_values(old) { old.push_back(value); } - - ~numeral_trail() override { - } - + void undo() override { m_value = m_old_values.back(); m_old_values.shrink(m_old_values.size() - 1); diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index 67549c46b..e259adc3e 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -17,7 +17,5 @@ z3_add_component(solver PYG_FILES combined_solver_params.pyg parallel_params.pyg - PYG_FILES - solver_params.pyg ) diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index c6a8093ff..e1345fe92 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -154,6 +154,7 @@ void asserted_formulas::assert_expr(expr * e, proof * _in_pr) { force_push(); proof_ref in_pr(_in_pr, m), pr(_in_pr, m); expr_ref r(e, m); + SASSERT(m.is_bool(e)); if (inconsistent()) return; diff --git a/src/solver/check_sat_result.h b/src/solver/check_sat_result.h index 53ffd2a1d..86941f590 100644 --- a/src/solver/check_sat_result.h +++ b/src/solver/check_sat_result.h @@ -45,7 +45,7 @@ protected: double m_time; public: check_sat_result():m_ref_count(0), m_status(l_undef), m_time(0) {} - virtual ~check_sat_result() {} + virtual ~check_sat_result() = default; void inc_ref() { m_ref_count++; } void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); } lbool set_status(lbool r) { return m_status = r; } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 29a5c0a8f..6e414816f 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -398,7 +398,6 @@ class combined_solver_factory : public solver_factory { scoped_ptr m_f2; public: combined_solver_factory(solver_factory * f1, solver_factory * f2):m_f1(f1), m_f2(f2) {} - ~combined_solver_factory() override {} solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) override { return mk_combined_solver((*m_f1)(m, p, proofs_enabled, models_enabled, unsat_core_enabled, logic), diff --git a/src/solver/progress_callback.h b/src/solver/progress_callback.h index e8c463609..f49609daf 100644 --- a/src/solver/progress_callback.h +++ b/src/solver/progress_callback.h @@ -20,7 +20,7 @@ Revision History: class progress_callback { public: - virtual ~progress_callback() {} + virtual ~progress_callback() = default; // Called on every check for resource limit exceeded (much more frequent). virtual void fast_progress_sample() {} diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index d14648058..d582ec2db 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -24,7 +24,7 @@ Notes: #include "ast/display_dimacs.h" #include "tactic/model_converter.h" #include "solver/solver.h" -#include "solver/solver_params.hpp" +#include "params/solver_params.hpp" #include "model/model_evaluator.h" #include "model/model_params.hpp" diff --git a/src/solver/solver.h b/src/solver/solver.h index dde4ccbe0..8b7d56a8c 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -29,7 +29,7 @@ class model_converter; class solver_factory { public: - virtual ~solver_factory() {} + virtual ~solver_factory() = default; virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) = 0; }; @@ -53,7 +53,6 @@ class solver : public check_sat_result, public user_propagator::core { symbol m_cancel_backup_file; public: solver() {} - ~solver() override {} /** \brief Creates a clone of the solver. @@ -114,7 +113,7 @@ public: virtual void set_phase(expr* e) = 0; virtual void move_to_front(expr* e) = 0; - class phase { public: virtual ~phase() {} }; + class phase { public: virtual ~phase() = default; }; virtual phase* get_phase() = 0; diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 09ede0c35..b178929bd 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -357,9 +357,7 @@ class tactic2solver_factory : public solver_factory { public: tactic2solver_factory(tactic * t):m_tactic(t) { } - - ~tactic2solver_factory() override {} - + solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) override { return mk_tactic2solver(m, m_tactic.get(), p, proofs_enabled, models_enabled, unsat_core_enabled, logic); } diff --git a/src/tactic/arith/add_bounds_tactic.cpp b/src/tactic/arith/add_bounds_tactic.cpp index 33ffbf282..a544c6810 100644 --- a/src/tactic/arith/add_bounds_tactic.cpp +++ b/src/tactic/arith/add_bounds_tactic.cpp @@ -51,7 +51,6 @@ public: result operator()(goal const & g) override { return is_unbounded(g); } - ~is_unbounded_probe() override {} }; probe * mk_is_unbounded_probe() { diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 3cc7436d1..25c5620c2 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -39,9 +39,6 @@ public: return alloc(card2bv_tactic, m, m_params); } - ~card2bv_tactic() override { - } - char const* name() const override { return "card2bv"; } void updt_params(params_ref const & p) override { diff --git a/src/tactic/arith/eq2bv_tactic.cpp b/src/tactic/arith/eq2bv_tactic.cpp index a1a1a56cc..1711a34ac 100644 --- a/src/tactic/arith/eq2bv_tactic.cpp +++ b/src/tactic/arith/eq2bv_tactic.cpp @@ -165,10 +165,6 @@ public: m_bounds(m) { } - ~eq2bv_tactic() override { - } - - void updt_params(params_ref const & p) override { } diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index 569dbff21..d0564139a 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -61,7 +61,8 @@ class fm_tactic : public tactic { return m.is_false(val); } - r_kind process(func_decl * x, expr * cls, arith_util & u, model& ev, rational & r) { + r_kind process(func_decl * x, expr * cls, arith_util & u, model& ev, rational & r, expr_ref& r_e) { + r_e = nullptr; unsigned num_lits; expr * const * lits; if (m.is_or(cls)) { @@ -93,6 +94,7 @@ class fm_tactic : public tactic { expr * lhs = to_app(l)->get_arg(0); expr * rhs = to_app(l)->get_arg(1); rational c; + expr_ref c_e(m); if (!u.is_numeral(rhs, c)) return NONE; if (neg) @@ -133,27 +135,41 @@ class fm_tactic : public tactic { expr_ref val(m); val = ev(monomial); rational tmp; - if (!u.is_numeral(val, tmp)) - return NONE; - if (neg) - tmp.neg(); - c -= tmp; + if (u.is_numeral(val, tmp)) { + if (neg) + tmp.neg(); + c -= tmp; + } + else { + // this happens for algebraic numerals + if (neg) + val = u.mk_uminus(val); + if (!c_e) + c_e = u.mk_uminus(val); + else + c_e = u.mk_sub(c_e, val); + } } } if (u.is_int(x->get_range()) && strict) { // a*x < c --> a*x <= c-1 SASSERT(c.is_int()); c--; + SASSERT(!c_e); } is_lower = a_val.is_neg(); c /= a_val; + if (c_e) + c_e = u.mk_div(c_e, u.mk_numeral(a_val, false)); if (u.is_int(x->get_range())) { + SASSERT(!c_e); if (is_lower) c = ceil(c); else c = floor(c); } r = c; + r_e = c_e; } } (void)found; @@ -187,6 +203,12 @@ class fm_tactic : public tactic { //model_evaluator ev(*(md.get())); //ev.set_model_completion(true); arith_util u(m); + auto mk_max = [&](expr* a, expr* b) { + return expr_ref(m.mk_ite(u.mk_ge(a, b), a, b), m); + }; + auto mk_min = [&](expr* a, expr* b) { + return expr_ref(m.mk_ite(u.mk_ge(a, b), b, a), m); + }; unsigned i = m_xs.size(); while (i > 0) { --i; @@ -194,44 +216,67 @@ class fm_tactic : public tactic { rational lower; rational upper; rational val; - bool has_lower = false; - bool has_upper = false; + expr_ref val_e(m), val_upper_e(m), val_lower_e(m); + bool has_lower = false, has_upper = false; TRACE("fm_mc", tout << "processing " << x->get_name() << "\n";); - clauses::iterator it = m_clauses[i].begin(); - clauses::iterator end = m_clauses[i].end(); - for (; it != end; ++it) { + for (expr* cl : m_clauses[i]) { if (!m.inc()) throw tactic_exception(m.limit().get_cancel_msg()); - switch (process(x, *it, u, *md, val)) { + switch (process(x, cl, u, *md, val, val_e)) { case NONE: - TRACE("fm_mc", tout << "no bound for:\n" << mk_ismt2_pp(*it, m) << "\n";); + TRACE("fm_mc", tout << "no bound for:\n" << mk_ismt2_pp(cl, m) << "\n";); break; case LOWER: - TRACE("fm_mc", tout << "lower bound: " << val << " for:\n" << mk_ismt2_pp(*it, m) << "\n";); - if (!has_lower || val > lower) - lower = val; - has_lower = true; + TRACE("fm_mc", tout << "lower bound: " << val << " for:\n" << mk_ismt2_pp(cl, m) << "\n";); + if (val_e) + val_lower_e = val_lower_e != nullptr ? mk_max(val_lower_e, val_e) : val_e; + else if (!has_lower || val > lower) + lower = val, has_lower = true; break; case UPPER: - TRACE("fm_mc", tout << "upper bound: " << val << " for:\n" << mk_ismt2_pp(*it, m) << "\n";); - if (!has_upper || val < upper) - upper = val; - has_upper = true; + TRACE("fm_mc", tout << "upper bound: " << val << " for:\n" << mk_ismt2_pp(cl, m) << "\n";); + if (val_e) + val_upper_e = val_upper_e != nullptr ? mk_min(val_upper_e, val_e) : val_e; + else if (!has_upper || val < upper) + upper = val, has_upper = true; break; } } expr * x_val; + if (u.is_int(x->get_range())) { - if (has_lower) + if (val_lower_e) { + x_val = val_lower_e; + if (has_lower) + x_val = mk_max(x_val, u.mk_numeral(lower, true)); + } + else if (val_upper_e) { + x_val = val_upper_e; + if (has_upper) + x_val = mk_min(x_val, u.mk_numeral(upper, true)); + } + else if (has_lower) x_val = u.mk_numeral(lower, true); else if (has_upper) x_val = u.mk_numeral(upper, true); else x_val = u.mk_numeral(rational(0), true); + } else { - if (has_lower && has_upper) + if (val_lower_e && has_lower) + val_lower_e = mk_max(val_lower_e, u.mk_numeral(lower, false)); + if (val_upper_e && has_upper) + val_upper_e = mk_min(val_upper_e, u.mk_numeral(upper, false)); + + if (val_lower_e && val_upper_e) + x_val = u.mk_div(u.mk_add(val_lower_e, val_upper_e), u.mk_real(2)); + else if (val_lower_e) + x_val = u.mk_add(val_lower_e, u.mk_real(1)); + else if (val_upper_e) + x_val = u.mk_sub(val_upper_e, u.mk_real(1)); + else if (has_lower && has_upper) x_val = u.mk_numeral((upper + lower)/rational(2), false); else if (has_lower) x_val = u.mk_numeral(lower + rational(1), false); @@ -1168,18 +1213,12 @@ class fm_tactic : public tactic { } // x_cost_lt is not a total order on variables std::stable_sort(x_cost_vector.begin(), x_cost_vector.end(), x_cost_lt(m_is_int)); - TRACE("fm", - svector::iterator it2 = x_cost_vector.begin(); - svector::iterator end2 = x_cost_vector.end(); - for (; it2 != end2; ++it2) { - tout << "(" << mk_ismt2_pp(m_var2expr.get(it2->first), m) << " " << it2->second << ") "; - } + TRACE("fm", + for (auto const& [v,c] : x_cost_vector) + tout << "(" << mk_ismt2_pp(m_var2expr.get(v), m) << " " << c << ") "; tout << "\n";); - svector::iterator it2 = x_cost_vector.begin(); - svector::iterator end2 = x_cost_vector.end(); - for (; it2 != end2; ++it2) { - xs.push_back(it2->first); - } + for (auto const& [v, c] : x_cost_vector) + xs.push_back(v); } void cleanup_constraints(constraints & cs) { @@ -1215,11 +1254,9 @@ class fm_tactic : public tactic { void analyze(constraints const & cs, var x, bool & all_int, bool & unit_coeff) const { all_int = true; unit_coeff = true; - constraints::const_iterator it = cs.begin(); - constraints::const_iterator end = cs.end(); - for (; it != end; ++it) { + for (auto const * c : cs) { bool curr_unit_coeff; - analyze(*(*it), x, all_int, curr_unit_coeff); + analyze(*c, x, all_int, curr_unit_coeff); if (!all_int) return; if (!curr_unit_coeff) @@ -1243,12 +1280,8 @@ class fm_tactic : public tactic { } void copy_constraints(constraints const & s, clauses & t) { - constraints::const_iterator it = s.begin(); - constraints::const_iterator end = s.end(); - for (; it != end; ++it) { - app * c = to_expr(*(*it)); - t.push_back(c); - } + for (auto const* cp : s) + t.push_back(to_expr(*cp)); } clauses tmp_clauses; @@ -1262,10 +1295,8 @@ class fm_tactic : public tactic { } void mark_constraints_dead(constraints const & cs) { - constraints::const_iterator it = cs.begin(); - constraints::const_iterator end = cs.end(); - for (; it != end; ++it) - (*it)->m_dead = true; + for (auto* cp : cs) + cp->m_dead = true; } void mark_constraints_dead(var x) { @@ -1514,14 +1545,8 @@ class fm_tactic : public tactic { } void copy_remaining(vector & v2cs) { - vector::iterator it = v2cs.begin(); - vector::iterator end = v2cs.end(); - for (; it != end; ++it) { - constraints & cs = *it; - constraints::iterator it2 = cs.begin(); - constraints::iterator end2 = cs.end(); - for (; it2 != end2; ++it2) { - constraint * c = *it2; + for (constraints& cs : v2cs) { + for (constraint* c : cs) { if (!c->m_dead) { c->m_dead = true; expr * new_f = to_expr(*c); @@ -1604,11 +1629,9 @@ class fm_tactic : public tactic { } void display_constraints(std::ostream & out, constraints const & cs) const { - constraints::const_iterator it = cs.begin(); - constraints::const_iterator end = cs.end(); - for (; it != end; ++it) { + for (auto const* cp : cs) { out << " "; - display(out, *(*it)); + display(out, *cp); out << "\n"; } } diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 560b7b265..36df89da5 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -434,9 +434,6 @@ public: return alloc(nla2bv_tactic, m_params); } - ~nla2bv_tactic() override { - } - char const* name() const override { return "nla2bv"; } void updt_params(params_ref const & p) override { diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 843d32828..afcecd7d3 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -902,9 +902,6 @@ public: tactic * translate(ast_manager & m) override { return alloc(purify_arith_tactic, m, m_params); } - - ~purify_arith_tactic() override { - } char const* name() const override { return "purify_arith"; } diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index fe3294e4c..5c26fb2b5 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -50,10 +50,7 @@ struct bit_blaster_model_converter : public model_converter { for (func_decl* f : newbits) m_newbits.push_back(f); } - - ~bit_blaster_model_converter() override { - } - + void collect_bits(obj_hashtable & bits) { unsigned sz = m_bits.size(); for (unsigned i = 0; i < sz; i++) { diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index 7ea7c0a69..3a2f85831 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -109,8 +109,6 @@ struct bv_bound_chk_rewriter : public rewriter_tpl { updt_params(p); } - ~bv_bound_chk_rewriter() override {} - void updt_params(params_ref const & _p) { m_cfg.updt_params(_p); } @@ -149,7 +147,7 @@ public: imp(ast_manager & m, params_ref const & p, bv_bound_chk_stats& stats) : m_rw(m, p, stats) { } - virtual ~imp() { } + virtual ~imp() = default; ast_manager& m() { return m_rw.m(); } diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 4f9ae6e9d..650095207 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -93,7 +93,6 @@ class dt2bv_tactic : public tactic { struct sort_pred : public i_sort_pred { dt2bv_tactic& m_t; sort_pred(dt2bv_tactic& t): m_t(t) {} - ~sort_pred() override {} bool operator()(sort* s) override { return m_t.m_fd_sorts.contains(s); } diff --git a/src/tactic/converter.h b/src/tactic/converter.h index 3146058bb..bbd30c351 100644 --- a/src/tactic/converter.h +++ b/src/tactic/converter.h @@ -26,7 +26,7 @@ class converter { unsigned m_ref_count; public: converter():m_ref_count(0) {} - virtual ~converter() {} + virtual ~converter() = default; void inc_ref() { ++m_ref_count; } @@ -57,8 +57,6 @@ protected: public: concat_converter(T * c1, T * c2):m_c1(c1), m_c2(c2) {} - - ~concat_converter() override {} void cancel() override { m_c2->cancel(); diff --git a/src/tactic/core/cofactor_term_ite_tactic.cpp b/src/tactic/core/cofactor_term_ite_tactic.cpp index 234b7262c..b65fd8353 100644 --- a/src/tactic/core/cofactor_term_ite_tactic.cpp +++ b/src/tactic/core/cofactor_term_ite_tactic.cpp @@ -50,7 +50,6 @@ public: return alloc(cofactor_term_ite_tactic, m, m_params); } - ~cofactor_term_ite_tactic() override {} char const* name() const override { return "cofactor"; } void updt_params(params_ref const & p) override { m_params.append(p); m_elim_ite.updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { m_elim_ite.collect_param_descrs(r); } diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index 04750a7c3..b02adad6e 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -52,8 +52,6 @@ public: m_params(p) { } - ~collect_statistics_tactic() override {} - char const* name() const override { return "collect_statistics"; } tactic * translate(ast_manager & m_) override { diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 47b2fa389..9ef1cf224 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -32,7 +32,6 @@ class ctx_propagate_assertions : public ctx_simplify_tactic::simplifier { void assert_eq_core(expr * t, app * val); public: ctx_propagate_assertions(ast_manager& m); - ~ctx_propagate_assertions() override {} bool assert_expr(expr * t, bool sign) override; bool simplify(expr* t, expr_ref& result) override; void push(); diff --git a/src/tactic/core/ctx_simplify_tactic.h b/src/tactic/core/ctx_simplify_tactic.h index 0beced06e..c8e34f33d 100644 --- a/src/tactic/core/ctx_simplify_tactic.h +++ b/src/tactic/core/ctx_simplify_tactic.h @@ -26,7 +26,7 @@ public: class simplifier { goal_num_occurs* m_occs; public: - virtual ~simplifier() {} + virtual ~simplifier() = default; virtual bool assert_expr(expr * t, bool sign) = 0; virtual bool simplify(expr* t, expr_ref& result) = 0; virtual bool may_simplify(expr* t) { return true; } diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 1dda062c8..9bf70ab16 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -541,7 +541,6 @@ class expr_substitution_simplifier : public dom_simplifier { public: expr_substitution_simplifier(ast_manager& m): m(m), m_subst(m), m_scoped_substitution(m_subst), m_trail(m) {} - ~expr_substitution_simplifier() override {} bool assert_expr(expr * t, bool sign) override { expr* tt; diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index b5d5e1ce9..43e13d961 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -64,7 +64,7 @@ public: class dom_simplifier { public: - virtual ~dom_simplifier() {} + virtual ~dom_simplifier() = default; /** \brief assert_expr performs an implicit push */ diff --git a/src/tactic/core/nnf_tactic.cpp b/src/tactic/core/nnf_tactic.cpp index fccfdf53e..959a1fc18 100644 --- a/src/tactic/core/nnf_tactic.cpp +++ b/src/tactic/core/nnf_tactic.cpp @@ -47,8 +47,6 @@ public: return alloc(nnf_tactic, m_params); } - ~nnf_tactic() override {} - char const* name() const override { return "nnf"; } void updt_params(params_ref const & p) override { m_params.append(p); } diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 0313899ac..2c4b80b93 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -102,8 +102,6 @@ public: pb_preprocess_tactic(ast_manager& m, params_ref const& p = params_ref()): m(m), m_trail(m), pb(m), m_r(m) {} - ~pb_preprocess_tactic() override {} - tactic * translate(ast_manager & m) override { return alloc(pb_preprocess_tactic, m); } diff --git a/src/tactic/core/reduce_invertible_tactic.cpp b/src/tactic/core/reduce_invertible_tactic.cpp index cfcc42482..df3de8219 100644 --- a/src/tactic/core/reduce_invertible_tactic.cpp +++ b/src/tactic/core/reduce_invertible_tactic.cpp @@ -45,8 +45,6 @@ public: m_arith(m) {} - ~reduce_invertible_tactic() override { } - char const* name() const override { return "reduce_invertible"; } tactic * translate(ast_manager & m) override { diff --git a/src/tactic/core/special_relations_tactic.h b/src/tactic/core/special_relations_tactic.h index dae38304a..85fa8ed24 100644 --- a/src/tactic/core/special_relations_tactic.h +++ b/src/tactic/core/special_relations_tactic.h @@ -47,8 +47,6 @@ public: special_relations_tactic(ast_manager & m, params_ref const & ref = params_ref()): m(m), m_params(ref), m_pm(m) {} - ~special_relations_tactic() override {} - void updt_params(params_ref const & p) override { m_params.append(p); } void collect_param_descrs(param_descrs & r) override { } diff --git a/src/tactic/core/split_clause_tactic.cpp b/src/tactic/core/split_clause_tactic.cpp index 12b76b638..99a69395b 100644 --- a/src/tactic/core/split_clause_tactic.cpp +++ b/src/tactic/core/split_clause_tactic.cpp @@ -52,8 +52,6 @@ class split_clause_tactic : public tactic { split_pc(ast_manager & m, app * cls, proof * pr):m_clause(cls, m), m_clause_pr(pr, m) { } - ~split_pc() override { } - proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { // Let m_clause be of the form (l_0 or ... or l_{num_source - 1}) // Each source[i] proof is a proof for "false" using l_i as a hypothesis @@ -87,9 +85,6 @@ public: t->m_largest_clause = m_largest_clause; return t; } - - ~split_clause_tactic() override { - } char const* name() const override { return "split_clause"; } diff --git a/src/tactic/equiv_proof_converter.h b/src/tactic/equiv_proof_converter.h index 4a479a7ae..87a8f7131 100644 --- a/src/tactic/equiv_proof_converter.h +++ b/src/tactic/equiv_proof_converter.h @@ -32,8 +32,6 @@ public: equiv_proof_converter(ast_manager& m): m(m), m_replace(m) {} - ~equiv_proof_converter() override {} - proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { return m_replace(m, num_source, source); } diff --git a/src/tactic/fd_solver/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp index cb136ad9f..5322b523d 100644 --- a/src/tactic/fd_solver/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -46,8 +46,6 @@ public: solver::updt_params(p); } - ~enum2bv_solver() override {} - solver* translate(ast_manager& dst_m, params_ref const& p) override { solver* result = alloc(enum2bv_solver, dst_m, p, m_solver->translate(dst_m, p)); model_converter_ref mc = external_model_converter(); diff --git a/src/tactic/fd_solver/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp index cd19b0dca..ee4a03d31 100644 --- a/src/tactic/fd_solver/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -46,8 +46,6 @@ public: solver::updt_params(p); } - ~pb2bv_solver() override {} - solver* translate(ast_manager& dst_m, params_ref const& p) override { flush_assertions(); solver* result = alloc(pb2bv_solver, dst_m, p, m_solver->translate(dst_m, p)); diff --git a/src/tactic/fd_solver/smtfd_solver.cpp b/src/tactic/fd_solver/smtfd_solver.cpp index 18b97d116..f653e22e2 100644 --- a/src/tactic/fd_solver/smtfd_solver.cpp +++ b/src/tactic/fd_solver/smtfd_solver.cpp @@ -1867,9 +1867,7 @@ namespace smtfd { updt_params(p); add_toggle(m.mk_true()); } - - ~solver() override {} - + ::solver* translate(ast_manager& dst_m, params_ref const& p) override { solver* result = alloc(solver, m_indent, dst_m, p); if (m_fd_sat_solver) result->m_fd_sat_solver = m_fd_sat_solver->translate(dst_m, p); diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp index a9294471e..9595cc606 100644 --- a/src/tactic/fpa/qffp_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -70,7 +70,6 @@ public: result operator()(goal const & g) override { return !test(g); } - ~is_fp_qfnra_probe() override {} }; probe * mk_is_fp_qfnra_probe() { @@ -145,8 +144,6 @@ public: result operator()(goal const & g) override { return !test(g); } - - ~is_qffp_probe() override {} }; probe * mk_is_qffp_probe() { diff --git a/src/tactic/fpa/qffplra_tactic.cpp b/src/tactic/fpa/qffplra_tactic.cpp index 0fdad5943..711eadc8f 100644 --- a/src/tactic/fpa/qffplra_tactic.cpp +++ b/src/tactic/fpa/qffplra_tactic.cpp @@ -82,8 +82,6 @@ public: test(g) && !test(g); } - - ~is_qffplra_probe() override {} }; probe * mk_is_qffplra_probe() { diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 55b7b27b4..5c08da76f 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -136,8 +136,6 @@ public: model2mc(model * m, labels_vec const & r):m_model(m), m_labels(r) {} - ~model2mc() override {} - void operator()(model_ref & m) override { if (!m || !m_model) { m = m_model; diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 0c304aa3f..483be4cca 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -130,8 +130,7 @@ class smt_strategic_solver_factory : public solver_factory { symbol m_logic; public: smt_strategic_solver_factory(symbol const & logic):m_logic(logic) {} - - ~smt_strategic_solver_factory() override {} + solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) override { symbol l; if (m_logic != symbol::null) diff --git a/src/tactic/portfolio/solver_subsumption_tactic.cpp b/src/tactic/portfolio/solver_subsumption_tactic.cpp index c92968c8c..96458c711 100644 --- a/src/tactic/portfolio/solver_subsumption_tactic.cpp +++ b/src/tactic/portfolio/solver_subsumption_tactic.cpp @@ -131,8 +131,6 @@ public: return alloc(solver_subsumption_tactic, other_m, m_params); } - ~solver_subsumption_tactic() override {} - char const* name() const override { return "solver_subsumption"; } void updt_params(params_ref const& p) override { diff --git a/src/tactic/probe.h b/src/tactic/probe.h index ae2879163..4d1af66a8 100644 --- a/src/tactic/probe.h +++ b/src/tactic/probe.h @@ -44,7 +44,7 @@ private: public: probe():m_ref_count(0) {} - virtual ~probe() {} + virtual ~probe() = default; void inc_ref() { ++m_ref_count; } void dec_ref() { SASSERT(m_ref_count > 0); --m_ref_count; if (m_ref_count == 0) dealloc(this); } diff --git a/src/tactic/proof_converter.cpp b/src/tactic/proof_converter.cpp index b876f1216..d1905b383 100644 --- a/src/tactic/proof_converter.cpp +++ b/src/tactic/proof_converter.cpp @@ -86,7 +86,6 @@ class proof2pc : public proof_converter { proof_ref m_pr; public: proof2pc(ast_manager & m, proof * pr):m_pr(pr, m) {} - ~proof2pc() override {} proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { SASSERT(num_source == 0); diff --git a/src/tactic/proof_converter.h b/src/tactic/proof_converter.h index fd4df7311..88152ce5b 100644 --- a/src/tactic/proof_converter.h +++ b/src/tactic/proof_converter.h @@ -25,7 +25,6 @@ class goal; class proof_converter : public converter { public: - ~proof_converter() override { } virtual proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) = 0; virtual proof_converter * translate(ast_translation & translator) = 0; }; diff --git a/src/tactic/replace_proof_converter.h b/src/tactic/replace_proof_converter.h index cc9a9c6c2..37bbf55b3 100644 --- a/src/tactic/replace_proof_converter.h +++ b/src/tactic/replace_proof_converter.h @@ -31,8 +31,6 @@ public: replace_proof_converter(ast_manager& _m): m(_m), m_proofs(m) {} - ~replace_proof_converter() override {} - proof_ref operator()(ast_manager & _m, unsigned num_source, proof * const * source) override; proof_converter * translate(ast_translation & translator) override; diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index 57c6ae99a..d93a17ce1 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -51,8 +51,6 @@ public: , m_inc_use_sat(false) {} - ~qfufbv_ackr_tactic() override { } - char const* name() const override { return "qfufbv_ackr"; } void operator()(goal_ref const & g, goal_ref_buffer & result) override { diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index af8b24b2f..d919f51ee 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -35,7 +35,6 @@ class tactic : public user_propagator::core { unsigned m_ref_count; public: tactic():m_ref_count(0) {} - virtual ~tactic() {} void inc_ref() { m_ref_count++; } void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); } diff --git a/src/tactic/tactic_exception.h b/src/tactic/tactic_exception.h index f230d417b..c6be82daa 100644 --- a/src/tactic/tactic_exception.h +++ b/src/tactic/tactic_exception.h @@ -26,7 +26,6 @@ protected: std::string m_msg; public: tactic_exception(std::string && msg) : m_msg(std::move(msg)) {} - ~tactic_exception() override {} char const * msg() const override { return m_msg.c_str(); } }; diff --git a/src/tactic/user_propagator_base.h b/src/tactic/user_propagator_base.h index 46b5eda8a..18d71b514 100644 --- a/src/tactic/user_propagator_base.h +++ b/src/tactic/user_propagator_base.h @@ -53,7 +53,7 @@ namespace user_propagator { class core { public: - virtual ~core() {} + virtual ~core() = default; virtual void user_propagate_init( void* ctx, diff --git a/src/test/api.cpp b/src/test/api.cpp index 2b6cda0ea..ccbbef6ea 100644 --- a/src/test/api.cpp +++ b/src/test/api.cpp @@ -4,7 +4,6 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#ifdef _WINDOWS #include "api/z3.h" #include "api/z3_private.h" #include @@ -112,7 +111,3 @@ void tst_api() { test_bvneg(); test_mk_distinct(); } -#else -void tst_api() { -} -#endif diff --git a/src/test/bdd.cpp b/src/test/bdd.cpp index d08d10a11..12d5b27d8 100644 --- a/src/test/bdd.cpp +++ b/src/test/bdd.cpp @@ -1,7 +1,12 @@ #include "math/dd/dd_bdd.h" +#include "math/dd/dd_fdd.h" #include namespace dd { + +class test_bdd { +public: + static void test1() { bdd_manager m(20); bdd v0 = m.mk_var(0); @@ -10,13 +15,13 @@ namespace dd { bdd c1 = v0 && v1 && v2; bdd c2 = v2 && v0 && v1; std::cout << c1 << "\n"; - SASSERT(c1 == c2); + VERIFY(c1 == c2); std::cout << "cnf size: " << c1.cnf_size() << "\n"; c1 = v0 || v1 || v2; c2 = v2 || v1 || v0; std::cout << c1 << "\n"; - SASSERT(c1 == c2); + VERIFY(c1 == c2); std::cout << "cnf size: " << c1.cnf_size() << "\n"; } @@ -25,14 +30,14 @@ namespace dd { bdd v0 = m.mk_var(0); bdd v1 = m.mk_var(1); bdd v2 = m.mk_var(2); - SASSERT(m.mk_ite(v0,v0,v1) == (v0 || v1)); - SASSERT(m.mk_ite(v0,v1,v1) == v1); - SASSERT(m.mk_ite(v1,v0,v1) == (v0 && v1)); - SASSERT(m.mk_ite(v1,v0,v0) == v0); - SASSERT(m.mk_ite(v0,!v0,v1) == (!v0 && v1)); - SASSERT(m.mk_ite(v0,v1,!v0) == (!v0 || v1)); - SASSERT((!(v0 && v1)) == (!v0 || !v1)); - SASSERT((!(v0 || v1)) == (!v0 && !v1)); + VERIFY(m.mk_ite(v0,v0,v1) == (v0 || v1)); + VERIFY(m.mk_ite(v0,v1,v1) == v1); + VERIFY(m.mk_ite(v1,v0,v1) == (v0 && v1)); + VERIFY(m.mk_ite(v1,v0,v0) == v0); + VERIFY(m.mk_ite(v0,!v0,v1) == (!v0 && v1)); + VERIFY(m.mk_ite(v0,v1,!v0) == (!v0 || v1)); + VERIFY((!(v0 && v1)) == (!v0 || !v1)); + VERIFY((!(v0 || v1)) == (!v0 && !v1)); } static void test3() { @@ -44,19 +49,19 @@ namespace dd { bdd c2 = m.mk_exists(0, c1); std::cout << c1 << "\n"; std::cout << c2 << "\n"; - SASSERT(c2 == (v1 || v2)); + VERIFY(c2 == (v1 || v2)); c2 = m.mk_exists(1, c1); - SASSERT(c2 == (v0 || v2)); + VERIFY(c2 == (v0 || v2)); c2 = m.mk_exists(2, c1); - SASSERT(c2.is_true()); - SASSERT(m.mk_exists(3, c1) == c1); + VERIFY(c2.is_true()); + VERIFY(m.mk_exists(3, c1) == c1); c1 = (v0 && v1) || (v1 && v2) || (!v0 && !v2); c2 = m.mk_exists(0, c1); - SASSERT(c2 == (v1 || (v1 && v2) || !v2)); + VERIFY(c2 == (v1 || (v1 && v2) || !v2)); c2 = m.mk_exists(1, c1); - SASSERT(c2 == (v0 || v2 || (!v0 && !v2))); + VERIFY(c2 == (v0 || v2 || (!v0 && !v2))); c2 = m.mk_exists(2, c1); - SASSERT(c2 == ((v0 && v1) || v1 || !v0)); + VERIFY(c2 == ((v0 && v1) || v1 || !v0)); } static void test4() { @@ -74,11 +79,457 @@ namespace dd { std::cout << c1 << "\n"; std::cout << c1.bdd_size() << "\n"; } + + static void test_xor() { + bdd_manager m(4); + bdd v0 = m.mk_var(0); + bdd v1 = m.mk_var(0); + VERIFY((m.mk_false() ^ v0) == v0); + VERIFY((v0 ^ m.mk_false()) == v0); + VERIFY((m.mk_true() ^ v0) == !v0); + VERIFY((v0 ^ m.mk_true()) == !v0); + VERIFY((v0 ^ v1) == ((v0 && !v1) || (!v0 && v1))); + } + + static void test_bddv_ops_on_constants() { + std::cout << "test_bddv_ops_on_constants\n"; + unsigned const num_bits = 3; + rational const modulus = rational::power_of_two(num_bits); + bdd_manager m(num_bits); + + VERIFY_EQ(m.to_val(m.mk_zero(num_bits)), rational(0)); + VERIFY_EQ(m.to_val(m.mk_ones(num_bits)), modulus - 1); + + for (unsigned n = 0; n < 8; ++n) { + rational const nr(n); + VERIFY_EQ(m.to_val(m.mk_num(nr, num_bits)), nr); + } + + for (unsigned n = 0; n < 8; ++n) { + for (unsigned k = 0; k < 8; ++k) { + rational const nr(n); + rational const kr(k); + bddv const nv = m.mk_num(nr, num_bits); + bddv const kv = m.mk_num(kr, num_bits); + VERIFY_EQ((nv + kv).to_val(), (nr + kr) % modulus); + VERIFY_EQ((nv - kv).to_val(), (nr - kr + modulus) % modulus); + VERIFY_EQ((nv * kr).to_val(), (nr * kr) % modulus); + VERIFY_EQ((nv * kv).to_val(), (nr * kr) % modulus); + bdd eq = m.mk_eq(nv, kv); + VERIFY(eq.is_const() && (eq.is_true() == (n == k))); + eq = m.mk_eq(nv, kr); + VERIFY(eq.is_const() && (eq.is_true() == (n == k))); + + VERIFY(m.mk_usub(nv).to_val() == (m.mk_zero(num_bits) - nv).to_val()); + + bdd cmp = nv <= kv; + VERIFY(cmp.is_const() && (cmp.is_true() == (nr <= kr))); + cmp = nv >= kv; + VERIFY(cmp.is_const() && (cmp.is_true() == (nr >= kr))); + cmp = nv < kv; + VERIFY(cmp.is_const() && (cmp.is_true() == (nr < kr))); + cmp = nv > kv; + VERIFY(cmp.is_const() && (cmp.is_true() == (nr > kr))); + + // signed versions + rational const nrs = (nr < modulus / 2) ? nr : nr - modulus; + rational const krs = (kr < modulus / 2) ? kr : kr - modulus; + cmp = nv.sle(kv); + VERIFY(cmp.is_const() && (cmp.is_true() == (nrs <= krs))); + cmp = nv.sge(kv); + VERIFY(cmp.is_const() && (cmp.is_true() == (nrs >= krs))); + cmp = nv.slt(kv); + VERIFY(cmp.is_const() && (cmp.is_true() == (nrs < krs))); + cmp = nv.sgt(kv); + VERIFY(cmp.is_const() && (cmp.is_true() == (nrs > krs))); + + bddv quotv = m.mk_zero(num_bits); + bddv remv = m.mk_zero(num_bits); + nv.quot_rem(kv, quotv, remv); + if (k != 0) { + VERIFY_EQ(quotv.to_val(), rational(n / k)); + VERIFY_EQ(remv.to_val(), rational(n % k)); + } else { + // std::cout << "n=" << n << " k=" << k << "\n"; + // std::cout << " quot: " << quotv.to_val() << "\n"; + // std::cout << " rem: " << remv.to_val() << "\n"; + } + } + } + } + + static void test_bddv_eqfind_small() { + std::cout << "test_bddv_eqfind_small\n"; + bdd_manager m(4); + fdd const x_dom(m, 1); + bddv const x = x_dom.var(); + bdd x_is_one = (x == rational(1)); + std::cout << "x_is_one:\n" << x_is_one << "\n"; + rational r; + auto res = x_dom.find(x_is_one, r); + VERIFY_EQ(res, find_t::singleton); + VERIFY_EQ(r, rational(1)); + } + + static void test_bddv_eqfind() { + std::cout << "test_bddv_eqfind\n"; + bdd_manager m(4); + + unsigned_vector bits; + bits.push_back(0); + bits.push_back(1); + bits.push_back(4); + bits.push_back(27); + + fdd const x_dom(m, bits); + bddv const x = x_dom.var(); + bddv const zero = m.mk_zero(x_dom.num_bits()); + bddv const one = m.mk_num(rational(1), x_dom.num_bits()); + bddv const five = m.mk_num(rational(5), x_dom.num_bits()); + + VERIFY((one == rational(1)).is_true()); + VERIFY((five == rational(5)).is_true()); + VERIFY((five == rational(4)).is_false()); + VERIFY((five == five).is_true()); + VERIFY((five == one).is_false()); + + // Test the three different mk_eq overloads + { + bdd const x_is_five = m.mk_eq(x, rational(5)); + rational r; + auto res = x_dom.find(x_is_five, r); + VERIFY_EQ(res, find_t::singleton); + VERIFY_EQ(r, 5); + } + + { + bdd const x_is_five = m.mk_eq(bits, rational(5)); + rational r; + auto res = x_dom.find(x_is_five, r); + VERIFY_EQ(res, find_t::singleton); + VERIFY_EQ(r, 5); + } + + { + bdd const x_is_five = m.mk_eq(x, five); + rational r; + auto res = x_dom.find(x_is_five, r); + VERIFY_EQ(res, find_t::singleton); + VERIFY_EQ(r, 5); + } + } + + static void test_bddv_addsub() { + std::cout << "test_bddv_addsub\n"; + unsigned_vector bits; + bits.push_back(0); + bits.push_back(1); + bits.push_back(2); + bdd_manager m(bits.size()); + bddv const x = m.mk_var(bits); + VERIFY_EQ(x - rational(3) == rational(2), x == rational(5)); + VERIFY_EQ(x + rational(3) == rational(5), x == rational(2)); + VERIFY_EQ(x - rational(3) == rational(6), x == rational(1)); + VERIFY_EQ(x + rational(3) == rational(2), x == rational(7)); + } + + static void test_bddv_mul() { + std::cout << "test_bddv_mul\n"; + unsigned const num_bits = 4; + bdd_manager m(num_bits); + + unsigned_vector bits; + bits.push_back(0); + bits.push_back(1); + bits.push_back(4); + bits.push_back(27); + + bddv const x = m.mk_var(bits); + bddv const zero = m.mk_zero(num_bits); + bddv const one = m.mk_num(rational(1), num_bits); + bddv const five = m.mk_num(rational(5), num_bits); + bddv const six = m.mk_num(rational(6), num_bits); + + // 5*x == 1 (mod 16) => x == 13 (mod 16) + bdd const five_inv = x * five == one; + VERIFY_EQ(five_inv, x == rational(13)); + + // 6*x == 1 (mod 16) => no solution for x + bdd const six_inv = x * six == one; + VERIFY(six_inv.is_false()); + + // 6*x == 0 (mod 16) => x is either 0 or 8 (mod 16) + bdd const b = six * x == zero; + VERIFY_EQ(b, x == rational(0) || x == rational(8)); + VERIFY((b && (x != rational(0)) && (x != rational(8))).is_false()); + VERIFY_EQ(b && (x != rational(0)), x == rational(8)); + + VERIFY_EQ((x * zero).bits(), (x * rational(0)).bits()); + VERIFY_EQ((x * one).bits(), (x * rational(1)).bits()); + VERIFY_EQ((x * five).bits(), (x * rational(5)).bits()); + VERIFY_EQ((x * six).bits(), (x * rational(6)).bits()); + } + + static void test_bddv_ule() { + std::cout << "test_bddv_ule\n"; + unsigned const num_bits = 4; + bdd_manager m(num_bits); + + unsigned_vector bits; + bits.push_back(0); + bits.push_back(1); + bits.push_back(2); + bits.push_back(3); + + bddv const x = m.mk_var(bits); + bddv const three = m.mk_num(rational(3), num_bits); + bddv const four = m.mk_num(rational(4), num_bits); + bddv const five = m.mk_num(rational(5), num_bits); + + VERIFY_EQ(x >= four && x < five, x == four); + VERIFY_EQ(four <= x && x < five, x == four); + VERIFY_EQ(three < x && x < five, x == four); + VERIFY_EQ(three < x && x <= four, x == four); + VERIFY_EQ(three <= x && x < five, x == four || x == three); + } + + static void test_fdd3() { + std::cout << "test_fdd3\n"; + unsigned const w = 3; // bit width + bdd_manager m(w); + + fdd const x_dom(m, w); + bddv const& x = x_dom.var(); + + // Encodes the values x satisfying a*x + b == 0 (mod 2^w) as BDD. + auto mk_affine = [] (unsigned a, bddv const& x, unsigned b) { + return (rational(a)*x + rational(b) == rational(0)); + }; + + vector num; + for (unsigned n = 0; n < (1< num; + for (unsigned n = 0; n < (1ul << x_dom.num_bits()); ++n) { + num.push_back(x == rational(n)); + VERIFY(x_dom.contains(num[n], rational(n))); + rational r; + VERIFY_EQ(x_dom.find(num[n], r), find_t::singleton); + VERIFY_EQ(r, n); + } + + // need something extra to skew costs and trigger a reorder + bdd atleast3 = (x >= rational(3)); + VERIFY(x_dom.contains(atleast3, rational(3))); + + auto const old_levels = m.m_var2level; + std::cout << "old levels: " << old_levels << "\n"; + m.gc(); + m.try_reorder(); + std::cout << "new levels: " << m.m_var2level << "\n"; + VERIFY(old_levels != m.m_var2level); // ensure that reorder actually did something. + + // Should still give the correct answer after reordering + for (unsigned n = 0; n < (1ul << x_dom.num_bits()); ++n) { + VERIFY(x_dom.contains(num[n], rational(n))); + rational r; + VERIFY_EQ(x_dom.find(num[n], r), find_t::singleton); + VERIFY_EQ(r, n); + } + } + + static void test_fdd_twovars() { + std::cout << "test_fdd_twovars\n"; + bdd_manager m(6); + fdd const x_dom(m, 3, 0, 2); + fdd const y_dom(m, 3, 1, 2); + bddv const& x = x_dom.var(); + bddv const& y = y_dom.var(); + VERIFY_EQ(x - y <= rational(0), x == y); + } + + static void test_fdd_find_hint() { + std::cout << "test_fdd_find_hint\n"; + bdd_manager m(4); + fdd const x_dom(m, 4); + bddv const& x = x_dom.var(); + + bdd s358 = x == rational(3) || x == rational(5) || x == rational(8); + rational r; + VERIFY_EQ(x_dom.find_hint(s358, rational(8), r), find_t::multiple); + VERIFY_EQ(r, 8); + VERIFY_EQ(x_dom.find_hint(s358, rational(5), r), find_t::multiple); + VERIFY_EQ(r, 5); + VERIFY_EQ(x_dom.find_hint(s358, rational(3), r), find_t::multiple); + VERIFY_EQ(r, 3); + VERIFY_EQ(x_dom.find_hint(s358, rational(7), r), find_t::multiple); + VERIFY(r == 3 || r == 5 || r == 8); + + VERIFY_EQ(x_dom.find_hint(x == rational(5), rational(3), r), find_t::singleton); + VERIFY_EQ(r, 5); + VERIFY_EQ(x_dom.find_hint(x == rational(5), rational(5), r), find_t::singleton); + VERIFY_EQ(r, 5); + + VERIFY_EQ(x_dom.find_hint(s358 && (x == rational(4)), rational(5), r), find_t::empty); + } + + static void test_cofactor() { + std::cout << "test_cofactor\n"; + bdd_manager m(20); + bdd v0 = m.mk_var(0); + bdd v1 = m.mk_var(1); + bdd v2 = m.mk_var(2); + bdd c1 = v0 && v1 && v2; + VERIFY(c1.cofactor(v0) == (v1 && v2)); + VERIFY(c1.cofactor(v1) == (v0 && v2)); + VERIFY(c1.cofactor(v2) == (v0 && v1)); + VERIFY(c1.cofactor(!v1) == m.mk_false()); + } + + static void inc(bool_vector& x) { + for (auto& b : x) { + b = !b; + if (b) + break; + } + } + + static void dec(bool_vector& x) { + for (auto& b : x) { + b = !b; + if (!b) + break; + } + } + + static unsigned value(bool_vector const& x) { + unsigned p = 1; + unsigned v = 0; + for (auto b : x) { + v += p*b; + p <<= 1; + } + return v; + } + + static void test_sup() { + std::cout << "test_sup\n"; + bdd_manager m(20); + fdd const x_dom(m, 10); + bddv const& x = x_dom.var(); + bdd c = (1 <= x && x <= 5) || (11 <= x && x <= 13) || (29 <= x && x <= 33); + bool_vector lo(10, false); + for (unsigned i = 0; i < 20; ++i) { + unsigned v = value(lo); + bool found = x_dom.sup(c, lo); + std::cout << found << ": " << v << " - " << value(lo) << "\n"; + if (found) + std::cout << x_dom.sup(c, lo) << ": " << value(lo) << "\n"; + c = !c; + inc(lo); + } + } + + static void test_inf() { + std::cout << "test_inf\n"; + bdd_manager m(20); + fdd const x_dom(m, 10); + bddv const& x = x_dom.var(); + bdd c = (1 <= x && x <= 5) || (11 <= x && x <= 13) || (29 <= x && x <= 33); + bool_vector hi(10, true); + for (unsigned i = 0; i < 10; ++i) { + bool found = x_dom.inf(c, hi); + std::cout << found << ": " << value(hi) << "\n"; + if (found) { + std::cout << x_dom.inf(c, hi) << ": " << value(hi) << "\n"; + VERIFY(value(hi) == 0 || value(hi) == 1 || value(hi) == 5 || value(hi) == 6 || + value(hi) == 10 || value(hi) == 11 || + value(hi) == 13 || value(hi) == 14 || + value(hi) == 28 || value(hi) == 29 || + value(hi) == 33 || value(hi) == 34 || value(hi) == 1023); + } + c = !c; + dec(hi); + } + } + + + +}; + } void tst_bdd() { - dd::test1(); - dd::test2(); - dd::test3(); - dd::test4(); + dd::test_bdd::test1(); + dd::test_bdd::test2(); + dd::test_bdd::test3(); + dd::test_bdd::test4(); + dd::test_bdd::test_xor(); + dd::test_bdd::test_bddv_ops_on_constants(); + dd::test_bdd::test_bddv_eqfind_small(); + dd::test_bdd::test_bddv_eqfind(); + dd::test_bdd::test_bddv_addsub(); + dd::test_bdd::test_bddv_mul(); + dd::test_bdd::test_bddv_ule(); + dd::test_bdd::test_fdd3(); + dd::test_bdd::test_fdd4(); + dd::test_bdd::test_fdd_reorder(); + dd::test_bdd::test_fdd_twovars(); + dd::test_bdd::test_fdd_find_hint(); + dd::test_bdd::test_cofactor(); + dd::test_bdd::test_inf(); + dd::test_bdd::test_sup(); } diff --git a/src/test/ddnf.cpp b/src/test/ddnf.cpp index b1bb624a2..c62adb4f9 100644 --- a/src/test/ddnf.cpp +++ b/src/test/ddnf.cpp @@ -4,7 +4,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ #include "muz/ddnf/ddnf.h" -#include "muz/rel/tbv.h" +#include "util/tbv.h" #include #include #include diff --git a/src/test/dl_product_relation.cpp b/src/test/dl_product_relation.cpp index e418d5ea0..942714560 100644 --- a/src/test/dl_product_relation.cpp +++ b/src/test/dl_product_relation.cpp @@ -4,7 +4,6 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#ifdef _WINDOWS #include "ast/reg_decl_plugins.h" #include "muz/base/dl_context.h" #include "muz/fp/dl_register_engine.h" @@ -23,7 +22,7 @@ namespace datalog { public: collector_of_reduced(idx_set & accumulator) : m_acc(accumulator) {} - virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) { + void operator()(table_element * func_columns, const table_element * merged_func_columns) override { m_acc.insert(static_cast(merged_func_columns[0])); } }; @@ -352,6 +351,7 @@ namespace datalog { using namespace datalog; +#ifdef _WINDOWS void tst_dl_product_relation() { smt_params fparams; params_ref params; @@ -363,6 +363,6 @@ void tst_dl_product_relation() { } #else -void tst_dl_product_relation() { -} +void tst_dl_product_relation() {} + #endif diff --git a/src/test/dl_relation.cpp b/src/test/dl_relation.cpp index a69e44cd2..9969ada2f 100644 --- a/src/test/dl_relation.cpp +++ b/src/test/dl_relation.cpp @@ -4,8 +4,6 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#ifdef _WINDOWS - #include "ast/reg_decl_plugins.h" #include "muz/base/dl_context.h" #include "muz/fp/dl_register_engine.h" @@ -38,7 +36,7 @@ namespace datalog { sig.push_back(int_sort); interval_relation& i1 = dynamic_cast(*ip.mk_empty(sig)); - interval_relation& i2 = dynamic_cast(*ip.mk_full(0, sig)); + interval_relation& i2 = dynamic_cast(*ip.mk_full(nullptr, sig)); i1.display(std::cout); i2.display(std::cout); @@ -143,7 +141,7 @@ namespace datalog { sig.push_back(int_sort); bound_relation& i1 = dynamic_cast(*br.mk_empty(sig)); - bound_relation& i2 = dynamic_cast(*br.mk_full(0, sig)); + bound_relation& i2 = dynamic_cast(*br.mk_full(nullptr, sig)); i1.display(std::cout << "empty:\n"); i2.display(std::cout << "full:\n"); @@ -214,8 +212,8 @@ namespace datalog { // test that equivalence classes are expanded. // { x1 = x3, x0 < x1 x1 < x2} u { x2 = x3, x0 < x3 } = { x0 < x3 } { - relation_base* b1 = br.mk_full(0, sig); - relation_base* b2 = br.mk_full(0, sig); + relation_base* b1 = br.mk_full(nullptr, sig); + relation_base* b2 = br.mk_full(nullptr, sig); unsigned x1x3[2] = { 1, 3 }; unsigned x2x3[2] = { 2, 3 }; scoped_ptr id1 = br.mk_filter_identical_fn(*b1, 2, x1x3); @@ -231,10 +229,10 @@ namespace datalog { b2->display(std::cout << "b2:\n"); (*ltx0x3)(*b2); b2->display(std::cout << "b2:\n"); - scoped_ptr u = br.mk_union_fn(*b1, *b2, 0); + scoped_ptr u = br.mk_union_fn(*b1, *b2, nullptr); b1->display(std::cout << "b1:\n"); b2->display(std::cout << "b2:\n"); - (*u)(*b1, *b2, 0); + (*u)(*b1, *b2, nullptr); b1->display(std::cout << "b1 u b2:\n"); @@ -247,8 +245,8 @@ namespace datalog { // test that equivalence classes are expanded. // { x1 = x2 = x3, x0 < x1} u { x1 = x3, x0 < x3, x0 < x2 } = { x0 < x2, x0 < x3 } { - relation_base* b1 = br.mk_full(0, sig); - relation_base* b2 = br.mk_full(0, sig); + relation_base* b1 = br.mk_full(nullptr, sig); + relation_base* b2 = br.mk_full(nullptr, sig); unsigned x0x3[2] = { 0, 3 }; unsigned x1x3[2] = { 1, 3 }; unsigned x2x3[2] = { 2, 3 }; @@ -264,10 +262,10 @@ namespace datalog { (*id3)(*b2); (*ltx0x2)(*b2); (*ltx0x3)(*b2); - scoped_ptr u = br.mk_union_fn(*b1, *b2, 0); + scoped_ptr u = br.mk_union_fn(*b1, *b2, nullptr); b1->display(std::cout << "b1:\n"); b2->display(std::cout << "b2:\n"); - (*u)(*b1, *b2, 0); + (*u)(*b1, *b2, nullptr); b1->display(std::cout << "b1 u b2:\n"); // TBD check property; @@ -296,8 +294,3 @@ void tst_dl_relation() { datalog::test_interval_relation(); datalog::test_bound_relation(); } - -#else -void tst_dl_relation() { -} -#endif diff --git a/src/test/ex.cpp b/src/test/ex.cpp index 444431475..10b5f8a90 100644 --- a/src/test/ex.cpp +++ b/src/test/ex.cpp @@ -21,7 +21,7 @@ Revision History: class ex { public: - virtual ~ex() {} + virtual ~ex() = default; virtual char const * msg() const = 0; }; diff --git a/src/test/lp/argument_parser.h b/src/test/lp/argument_parser.h index f2a74f122..12ab02831 100644 --- a/src/test/lp/argument_parser.h +++ b/src/test/lp/argument_parser.h @@ -17,6 +17,7 @@ Revision History: --*/ +#pragma once #include #include diff --git a/src/test/lp/gomory_test.h b/src/test/lp/gomory_test.h index c7b0002cd..890ff90e3 100644 --- a/src/test/lp/gomory_test.h +++ b/src/test/lp/gomory_test.h @@ -1,3 +1,5 @@ +#pragma once + namespace lp { #include "math/lp/lp_utils.h" struct gomory_test { diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index d7329309c..04afd8f96 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -19,7 +19,7 @@ --*/ #include -#if _LINUX_ +#ifndef _WINDOWS #include #endif #include @@ -1735,7 +1735,7 @@ void random_test() { } } -#if _LINUX_ +#ifndef _WINDOWS void fill_file_names(vector &file_names, std::set & minimums) { char *home_dir = getenv("HOME"); if (home_dir == nullptr) { @@ -1885,7 +1885,7 @@ void test_out_dir(std::string out_dir) { void find_dir_and_file_name(std::string a, std::string & dir, std::string& fn) { // todo: make it system independent - size_t last_slash_pos = a.find_last_of("/"); + size_t last_slash_pos = a.find_last_of('/'); if (last_slash_pos >= a.size()) { std::cout << "cannot find file name in " << a << std::endl; throw; @@ -4072,7 +4072,7 @@ void test_lp_local(int argn, char**argv) { } if (args_parser.option_is_used("--solve_some_mps")) { -#if _LINUX_ +#ifndef _WINDOWS solve_some_mps(args_parser); #endif ret = 0; diff --git a/src/test/lp/smt_reader.h b/src/test/lp/smt_reader.h index e641410db..2ab0c1ea6 100644 --- a/src/test/lp/smt_reader.h +++ b/src/test/lp/smt_reader.h @@ -20,7 +20,7 @@ Revision History: #pragma once -// reads an MPS file reperesenting a Mixed Integer Program +// reads an MPS file representing a Mixed Integer Program #include #include #include diff --git a/src/test/matcher.cpp b/src/test/matcher.cpp index 6d5576714..1d1c517fe 100644 --- a/src/test/matcher.cpp +++ b/src/test/matcher.cpp @@ -16,7 +16,6 @@ Author: Revision History: --*/ -#ifdef _WINDOWS #include "ast/substitution/matcher.h" #include "ast/ast_pp.h" #include "ast/reg_decl_plugins.h" @@ -110,7 +109,3 @@ void tst1() { void tst_matcher() { tst1(); } -#else -void tst_matcher() { -} -#endif diff --git a/src/test/memory.cpp b/src/test/memory.cpp index 48ba35b78..9a8d12b5d 100644 --- a/src/test/memory.cpp +++ b/src/test/memory.cpp @@ -4,7 +4,6 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#ifdef _WINDOWS #include "api/z3.h" #include "api/z3_private.h" #include @@ -59,8 +58,3 @@ void tst_memory() { Z3_reset_memory(); } - -#else -void tst_memory() { -} -#endif diff --git a/src/test/no_overflow.cpp b/src/test/no_overflow.cpp index eb26866a5..dd826bad8 100644 --- a/src/test/no_overflow.cpp +++ b/src/test/no_overflow.cpp @@ -16,7 +16,6 @@ Author: Revision History: --*/ -#ifdef _WINDOWS #include "api/z3.h" #include "util/trace.h" @@ -112,7 +111,7 @@ void test_add(unsigned bvsize, bool is_signed) { t1 = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx,"x"), bv); t2 = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx,"y"), bv); test_ovfl = Z3_mk_bvadd_no_overflow(ctx, t1, t2, is_signed); - test_udfl = is_signed ? Z3_mk_bvadd_no_underflow(ctx, t1, t2) : NULL; + test_udfl = is_signed ? Z3_mk_bvadd_no_underflow(ctx, t1, t2) : nullptr; Z3_solver_push(ctx, s); Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, t1, Z3_mk_numeral(ctx, "0", bv))); @@ -197,7 +196,7 @@ void test_sub(unsigned bvsize, bool is_signed) { t1 = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx,"x"), bv); t2 = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx,"y"), bv); - test_ovfl = is_signed ? Z3_mk_bvsub_no_overflow(ctx, t1, t2) : NULL; + test_ovfl = is_signed ? Z3_mk_bvsub_no_overflow(ctx, t1, t2) : nullptr; test_udfl = Z3_mk_bvsub_no_underflow(ctx, t1, t2, is_signed); Z3_solver_push(ctx, s); @@ -359,7 +358,7 @@ void test_mul(unsigned bvsize, bool is_signed) { t1 = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx,"x"), bv); t2 = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx,"y"), bv); test_ovfl = Z3_mk_bvmul_no_overflow(ctx, t1, t2, is_signed); - test_udfl = is_signed ? Z3_mk_bvmul_no_underflow(ctx, t1, t2) : NULL; + test_udfl = is_signed ? Z3_mk_bvmul_no_underflow(ctx, t1, t2) : nullptr; Z3_solver_push(ctx, s); Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, t1, Z3_mk_numeral(ctx, "1", bv))); @@ -586,7 +585,7 @@ void test_equiv(Equivalence_params params, unsigned bvsize, bool is_signed) { Z3_ast t2 = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx,"y"), bv); Z3_ast real_test = (*params.no_overflow_func)(ctx, t1, t2, is_signed); - Z3_ast cond = NULL; + Z3_ast cond = nullptr; if (params.non_zero) { cond = Z3_mk_not(ctx, Z3_mk_eq(ctx, t2, Z3_mk_int(ctx, 0, bv))); @@ -625,7 +624,7 @@ void test_equiv(Equivalence_params params, unsigned bvsize, bool is_signed) { Z3_solver_push(ctx, s); Z3_ast equiv = Z3_mk_iff(ctx, real_test, check); - if (cond != NULL) + if (cond != nullptr) { equiv = Z3_mk_implies(ctx, cond, equiv); } @@ -724,7 +723,3 @@ void tst_no_overflow() { } } } -#else -void tst_no_overflow() { -} -#endif diff --git a/src/test/pdd.cpp b/src/test/pdd.cpp index 9139e499f..a0946d81d 100644 --- a/src/test/pdd.cpp +++ b/src/test/pdd.cpp @@ -4,7 +4,7 @@ namespace dd { class test { -public : +public: static void hello_world() { pdd_manager m(3); @@ -310,17 +310,288 @@ public : sub1.push_back(std::make_pair(va, rational(1))); sub2.push_back(std::make_pair(va, rational(2))); sub3.push_back(std::make_pair(va, rational(3))); - std::cout << "sub 0 " << p.subst_val(sub0) << "\n"; - std::cout << "sub 1 " << p.subst_val(sub1) << "\n"; - std::cout << "sub 2 " << p.subst_val(sub2) << "\n"; - std::cout << "sub 3 " << p.subst_val(sub3) << "\n"; + std::cout << "sub 0 " << p.subst_val0(sub0) << "\n"; + std::cout << "sub 1 " << p.subst_val0(sub1) << "\n"; + std::cout << "sub 2 " << p.subst_val0(sub2) << "\n"; + std::cout << "sub 3 " << p.subst_val0(sub3) << "\n"; - std::cout << "expect 1 " << (2*a + 1).is_non_zero() << "\n"; - std::cout << "expect 1 " << (2*a*b + 2*b + 1).is_non_zero() << "\n"; - std::cout << "expect 0 " << (2*a + 2).is_non_zero() << "\n"; - SASSERT((2*a + 1).is_non_zero()); - SASSERT((2*a + 2*b + 1).is_non_zero()); - SASSERT(!(2*a*b + 3*b + 2).is_non_zero()); + std::cout << "expect 1 " << (2*a + 1).is_never_zero() << "\n"; + std::cout << "expect 1 " << (2*a*b + 2*b + 1).is_never_zero() << "\n"; + std::cout << "expect 0 " << (2*a + 2).is_never_zero() << "\n"; + VERIFY((2*a + 1).is_never_zero()); + VERIFY((2*a + 2*b + 1).is_never_zero()); + VERIFY(!(2*a*b + 3*b + 2).is_never_zero()); + } + + static void degree_of_variables() { + std::cout << "degree of variables\n"; + pdd_manager m(4, pdd_manager::mod2N_e, 3); + unsigned va = 0; + unsigned vb = 1; + unsigned vc = 2; + pdd a = m.mk_var(va); + pdd b = m.mk_var(vb); + pdd c = m.mk_var(vc); + + VERIFY(a.var() == va); + VERIFY(b.var() == vb); + + VERIFY(a.degree(va) == 1); + VERIFY(a.degree(vb) == 0); + VERIFY(a.degree(vc) == 0); + VERIFY(c.degree(vc) == 1); + VERIFY(c.degree(vb) == 0); + VERIFY(c.degree(va) == 0); + + { + pdd p = a * a * a; + VERIFY(p.degree(va) == 3); + VERIFY(p.degree(vb) == 0); + } + + { + pdd p = b * a; + VERIFY(p.degree(va) == 1); + VERIFY(p.degree(vb) == 1); + VERIFY(p.degree(vc) == 0); + } + + { + pdd p = (a*a*b + b*a*b + b + a*c)*a + b*b*c; + VERIFY(p.degree(va) == 3); + VERIFY(p.degree(vb) == 2); + VERIFY(p.degree(vc) == 1); + } + + { + // check that skipping marked nodes works (1) + pdd p = b*a + c*a*a*a; + VERIFY(p.degree(va) == 3); + } + + { + // check that skipping marked nodes works (2) + pdd p = (b+c)*(a*a*a); + VERIFY(p.degree(va) == 3); + } + + { + // check that skipping marked nodes works (3) + pdd p = a*a*a*b*b*b*c + a*a*a*b*b*b; + VERIFY(p.degree(va) == 3); + } + } + + static void factor() { + std::cout << "factor\n"; + pdd_manager m(4, pdd_manager::mod2N_e, 3); + + unsigned const va = 0; + unsigned const vb = 1; + unsigned const vc = 2; + unsigned const vd = 3; + pdd const a = m.mk_var(va); + pdd const b = m.mk_var(vb); + pdd const c = m.mk_var(vc); + pdd const d = m.mk_var(vd); + + auto test_one = [&m](pdd const& p, unsigned v, unsigned d) { + pdd lc = m.zero(); + pdd rest = m.zero(); + std::cout << "Factoring p = " << p << " by v" << v << "^" << d << "\n"; + p.factor(v, d, lc, rest); + std::cout << " lc = " << lc << "\n"; + std::cout << " rest = " << rest << "\n"; + pdd x = m.mk_var(v); + pdd x_pow_d = m.one(); + for (unsigned i = 0; i < d; ++i) { + x_pow_d *= x; + } + VERIFY( p == lc * x_pow_d + rest ); + VERIFY( d == 0 || rest.degree(v) < d ); + VERIFY( d != 0 || lc.is_zero() ); + }; + + auto test_multiple = [=](pdd const& p) { + for (auto v : {va, vb, vc, vd}) { + for (unsigned d = 0; d <= 5; ++d) { + test_one(p, v, d); + } + } + }; + + test_multiple( b ); + test_multiple( b*b*b ); + test_multiple( b + c ); + test_multiple( a*a*a*a*a + a*a*a*b + a*a*b*b + c ); + test_multiple( c*c*c*c*c + b*b*b*c + 3*b*c*c + a ); + test_multiple( (a + b) * (b + c) * (c + d) * (d + a) ); + } + + static void max_pow2_divisor() { + std::cout << "max_pow2_divisor\n"; + pdd_manager m(4, pdd_manager::mod2N_e, 256); + + unsigned const va = 0; + unsigned const vb = 1; + pdd const a = m.mk_var(va); + pdd const b = m.mk_var(vb); + + VERIFY(m.zero().max_pow2_divisor() == UINT_MAX); + VERIFY(m.one().max_pow2_divisor() == 0); + pdd p = (1 << 20)*a*b + 1024*b*b*b; + std::cout << p << " divided by 2^" << p.max_pow2_divisor() << "\n"; + VERIFY(p.max_pow2_divisor() == 10); + VERIFY(p.div(rational::power_of_two(10)) == 1024*a*b + b*b*b); + VERIFY((p + p).max_pow2_divisor() == 11); + VERIFY((p * p).max_pow2_divisor() == 20); + VERIFY((p + 2*b).max_pow2_divisor() == 1); + VERIFY((p + b*b*b).max_pow2_divisor() == 0); + } + + static void try_div() { + std::cout << "try_div\n"; + pdd_manager m(4, pdd_manager::mod2N_e, 256); + pdd const a = m.mk_var(0); + pdd const b = m.mk_var(1); + + pdd const p = 5*a + 15*a*b; + VERIFY_EQ(p.div(rational(5)), a + 3*a*b); + pdd res = a; + VERIFY(!p.try_div(rational(3), res)); + } + + static void binary_resolve() { + std::cout << "binary resolve\n"; + pdd_manager m(4, pdd_manager::mod2N_e, 4); + + unsigned const va = 0; + unsigned const vb = 1; + unsigned const vc = 2; + pdd const a = m.mk_var(va); + pdd const b = m.mk_var(vb); + pdd const c = m.mk_var(vc); + + pdd r = m.zero(); + + pdd p = a*a*b - a*a; + pdd q = a*b*b - b*b; + VERIFY(m.resolve(va, p, q, r)); + VERIFY(r == a*b*b*b - a*b*b); + VERIFY(!m.resolve(va, q, p, r)); + VERIFY(!m.resolve(vb, p, q, r)); + VERIFY(m.resolve(vb, q, p, r)); + VERIFY(r == a*a*a*b - a*a*b); + VERIFY(!m.resolve(vc, p, q, r)); + + p = 2*a*a*b + 13*a*a; + q = 6*a*b*b*b + 14*b*b*b; + VERIFY(m.resolve(va, p, q, r)); + VERIFY(r == (2*b+13)*2*b*b*b*a); + VERIFY(!m.resolve(va, q, p, r)); + VERIFY(!m.resolve(vb, p, q, r)); + VERIFY(m.resolve(vb, q, p, r)); + VERIFY(r == 9*a*a*a*b*b + 5*a*a*b*b); + + p = a*a*b - a*a + 4*a*c + 2; + q = 3*b*b - b*b*b + 8*b*c; + VERIFY(!m.resolve(va, p, q, r)); + VERIFY(!m.resolve(va, q, p, r)); + VERIFY(!m.resolve(vb, p, q, r)); + VERIFY(m.resolve(vb, q, p, r)); + VERIFY(r == 2*a*a*b*b + 8*a*a*b*c + 4*a*b*b*c + 2*b*b); + VERIFY(m.resolve(vc, p, q, r)); + VERIFY(r == 2*a*a*b*b - 2*a*a*b - 3*a*b*b + a*b*b*b + 4*b); + VERIFY(m.resolve(vc, q, p, r)); + VERIFY(r == -(2*a*a*b*b - 2*a*a*b - 3*a*b*b + a*b*b*b + 4*b)); + } + + static void pow() { + std::cout << "pow\n"; + pdd_manager m(4, pdd_manager::mod2N_e, 5); + + unsigned const va = 0; + unsigned const vb = 1; + pdd const a = m.mk_var(va); + pdd const b = m.mk_var(vb); + + VERIFY(a.pow(0) == m.one()); + VERIFY(a.pow(1) == a); + VERIFY(a.pow(2) == a*a); + VERIFY(a.pow(7) == a*a*a*a*a*a*a); + VERIFY((3*a*b).pow(3) == 27*a*a*a*b*b*b); + } + + static void subst_val() { + std::cout << "subst_val\n"; + pdd_manager m(4, pdd_manager::mod2N_e, 2); + + unsigned const va = 0; + unsigned const vb = 1; + unsigned const vc = 2; + unsigned const vd = 3; + pdd const a = m.mk_var(va); + pdd const b = m.mk_var(vb); + pdd const c = m.mk_var(vc); + pdd const d = m.mk_var(vd); + + { + pdd const p = 2*a + b + 1; + VERIFY(p.subst_val(va, rational(0)) == b + 1); + } + + { + pdd const p = a + 2*b; + VERIFY(p.subst_val(va, rational(0)) == 2*b); + VERIFY(p.subst_val(va, rational(2)) == 2*b + 2); + VERIFY(p.subst_val(vb, rational(0)) == a); + VERIFY(p.subst_val(vb, rational(1)) == a + 2); + VERIFY(p.subst_val(vb, rational(2)) == a); + VERIFY(p.subst_val(vb, rational(3)) == a + 2); + VERIFY(p.subst_val(va, rational(0)).subst_val(vb, rational(3)) == 2*m.one()); + } + + { + pdd const p = a + b + c + d; + vector> sub; + sub.push_back({vb, rational(2)}); + sub.push_back({vc, rational(3)}); + VERIFY(p.subst_val0(sub) == a + d + 1); + } + + { + pdd const p = (a + b) * (b + c) * (c + d); + vector> sub; + sub.push_back({vb, rational(2)}); + sub.push_back({vc, rational(3)}); + VERIFY(p.subst_val0(sub) == (a + 2) * (d + 3)); + sub.push_back({va, rational(3)}); + sub.push_back({vd, rational(2)}); + VERIFY(p.subst_val0(sub) == m.one()); + } + } + + static void univariate() { + std::cout << "univariate\n"; + pdd_manager m(4, pdd_manager::mod2N_e, 4); + + unsigned const va = 0; + unsigned const vb = 1; + pdd const a = m.mk_var(va); + pdd const b = m.mk_var(vb); + + pdd p = a*a*b - a*a; + VERIFY(!p.is_univariate()); + + pdd q = 3*a*a*a + 1*a + 2; + VERIFY(q.is_univariate()); + vector coeff; + q.get_univariate_coefficients(coeff); + VERIFY_EQ(coeff.size(), 4); + VERIFY_EQ(coeff[0], 2); + VERIFY_EQ(coeff[1], 1); + VERIFY_EQ(coeff[2], 0); + VERIFY_EQ(coeff[3], 3); } static void factors() { @@ -393,5 +664,13 @@ void tst_pdd() { dd::test::order(); dd::test::order_lm(); dd::test::mod4_operations(); + dd::test::degree_of_variables(); + dd::test::factor(); + dd::test::max_pow2_divisor(); + dd::test::try_div(); + dd::test::binary_resolve(); + dd::test::pow(); + dd::test::subst_val(); + dd::test::univariate(); dd::test::factors(); } diff --git a/src/test/simplifier.cpp b/src/test/simplifier.cpp index a42ed86b1..d716a1268 100644 --- a/src/test/simplifier.cpp +++ b/src/test/simplifier.cpp @@ -4,7 +4,6 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#ifdef _WINDOWS #include "api/z3.h" #include "api/z3_private.h" #include @@ -94,7 +93,7 @@ static void test_datatypes() { int_list = Z3_mk_list_sort(ctx, Z3_mk_string_symbol(ctx, "int_list"), int_ty, &nil_decl, &is_nil_decl, &cons_decl, &is_cons_decl, &head_decl, &tail_decl); - nil = Z3_mk_app(ctx, nil_decl, 0, 0); + nil = Z3_mk_app(ctx, nil_decl, 0, nullptr); Z3_ast a = Z3_simplify(ctx, Z3_mk_app(ctx, is_nil_decl, 1, &nil)); ENSURE(a == Z3_mk_true(ctx)); @@ -133,7 +132,7 @@ static void test_skolemize_bug() { Z3_ast args[2] = { Z3_mk_eq(ctx, Z3_mk_add(ctx, 2, args1), xp), Z3_mk_ge(ctx, Z3_mk_add(ctx, 2, args2), n0) }; Z3_ast f = Z3_mk_and(ctx, 2, args); - Z3_ast f2 = Z3_mk_exists(ctx, 0, 0, 0, 1, &Real, &x_name, f); + Z3_ast f2 = Z3_mk_exists(ctx, 0, 0, nullptr, 1, &Real, &x_name, f); std::cout << Z3_ast_to_string(ctx, f2) << "\n"; Z3_ast f3 = Z3_simplify(ctx, f2); std::cout << Z3_ast_to_string(ctx, f3) << "\n"; @@ -214,8 +213,3 @@ void tst_simplifier() { test_bool(); test_skolemize_bug(); } - -#else -void tst_simplifier() { -} -#endif diff --git a/src/test/tbv.cpp b/src/test/tbv.cpp index 6107fad85..fe33baba5 100644 --- a/src/test/tbv.cpp +++ b/src/test/tbv.cpp @@ -4,7 +4,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "muz/rel/tbv.h" +#include "util/tbv.h" #include static void tst1(unsigned num_bits) { diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 35727bce2..c2a7e8296 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -54,6 +54,7 @@ z3_add_component(util state_graph.cpp statistics.cpp symbol.cpp + tbv.cpp timeit.cpp timeout.cpp trace.cpp diff --git a/src/util/array.h b/src/util/array.h index 6c04c10d2..a4c2aa2c7 100644 --- a/src/util/array.h +++ b/src/util/array.h @@ -37,8 +37,6 @@ private: char * raw_ptr() const { return reinterpret_cast(reinterpret_cast(m_data) - 1); } - array & operator=(array const & source); - void set_data(void * mem, unsigned sz) { size_t * _mem = static_cast(mem); *_mem = sz; @@ -115,6 +113,8 @@ public: destroy_elements(); } + array & operator=(array const & source) = delete; + // Free the memory used to store the array. template void finalize(Allocator & a) { diff --git a/src/util/cmd_context_types.h b/src/util/cmd_context_types.h index 80e284d90..b8c3d4758 100644 --- a/src/util/cmd_context_types.h +++ b/src/util/cmd_context_types.h @@ -78,7 +78,7 @@ typedef std::pair sorted_var; /** \brief Command abstract class. - Commands may have variable number of argumets. + Commands may have variable number of arguments. */ class cmd { symbol m_name; @@ -87,7 +87,7 @@ protected: int m_pos; public: cmd(char const * n):m_name(n), m_line(0), m_pos(0) {} - virtual ~cmd() {} + virtual ~cmd() = default; virtual void reset(cmd_context & ctx) {} virtual void finalize(cmd_context & ctx) {} virtual symbol get_name() const { return m_name; } diff --git a/src/util/debug.h b/src/util/debug.h index 9ad55a7c2..795976eac 100644 --- a/src/util/debug.h +++ b/src/util/debug.h @@ -63,6 +63,13 @@ bool is_debug_enabled(const char * tag); #define CASSERT(TAG, COND) DEBUG_CODE(if (assertions_enabled() && is_debug_enabled(TAG) && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); INVOKE_DEBUGGER(); }) #define XASSERT(COND, EXTRA_CODE) DEBUG_CODE(if (assertions_enabled() && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); { EXTRA_CODE } INVOKE_DEBUGGER(); }) +#define SASSERT_EQ(LHS, RHS) \ + DEBUG_CODE(if (assertions_enabled() && !((LHS) == (RHS))) { \ + notify_assertion_violation(__FILE__, __LINE__, #LHS " == " #RHS); \ + std::cerr << "LHS value: " << (LHS) << "\nRHS value: " << (RHS) << "\n"; \ + INVOKE_DEBUGGER(); \ + }) + #ifdef Z3DEBUG # define UNREACHABLE() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "UNEXPECTED CODE WAS REACHED."); INVOKE_DEBUGGER();) #else @@ -78,7 +85,14 @@ bool is_debug_enabled(const char * tag); #define VERIFY(_x_) if (!(_x_)) { \ notify_assertion_violation(__FILE__, __LINE__, "Failed to verify: " #_x_ "\n"); \ exit(ERR_UNREACHABLE); \ - } + } + +#define VERIFY_EQ(LHS, RHS) \ + if (!((LHS) == (RHS))) { \ + notify_assertion_violation(__FILE__, __LINE__, "Failed to verify: " #LHS " == " #RHS "\n"); \ + std::cerr << "LHS value: " << (LHS) << "\nRHS value: " << (RHS) << "\n"; \ + exit(ERR_UNREACHABLE); \ + } #define ENSURE(_x_) VERIFY(_x_) diff --git a/src/util/dlist.h b/src/util/dlist.h index df28217c0..7efe5bb53 100644 --- a/src/util/dlist.h +++ b/src/util/dlist.h @@ -40,6 +40,22 @@ public: remove_from(list, head); return head; } + + void insert_after(T* elem) { + T* next = this->m_next; + elem->m_prev = next->m_prev; + elem->m_next = next; + this->m_next = elem; + next->m_prev = elem; + } + + void insert_before(T* elem) { + T* prev = this->m_prev; + elem->m_next = prev->m_next; + elem->m_prev = prev; + prev->m_next = elem; + this->m_prev = elem; + } static void remove_from(T*& list, T* elem) { if (list->m_next == list) { diff --git a/src/util/env_params.cpp b/src/util/env_params.cpp index 3ba6df735..80a1195aa 100644 --- a/src/util/env_params.cpp +++ b/src/util/env_params.cpp @@ -29,6 +29,9 @@ void env_params::updt_params() { memory::set_max_size(megabytes_to_bytes(p.get_uint("memory_max_size", 0))); memory::set_max_alloc_count(p.get_uint("memory_max_alloc_count", 0)); memory::set_high_watermark(p.get_uint("memory_high_watermark", 0)); + unsigned mb = p.get_uint("memory_high_watermark_mb", 0); + if (mb > 0) + memory::set_high_watermark(megabytes_to_bytes(mb)); } void env_params::collect_param_descrs(param_descrs & d) { @@ -36,5 +39,6 @@ void env_params::collect_param_descrs(param_descrs & d) { d.insert("warning", CPK_BOOL, "enable/disable warning messages", "true"); d.insert("memory_max_size", CPK_UINT, "set hard upper limit for memory consumption (in megabytes), if 0 then there is no limit", "0"); d.insert("memory_max_alloc_count", CPK_UINT, "set hard upper limit for memory allocations, if 0 then there is no limit", "0"); - d.insert("memory_high_watermark", CPK_UINT, "set high watermark for memory consumption (in megabytes), if 0 then there is no limit", "0"); + d.insert("memory_high_watermark", CPK_UINT, "set high watermark for memory consumption (in bytes), if 0 then there is no limit", "0"); + d.insert("memory_high_watermark_mb", CPK_UINT, "set high watermark for memory consumption (in megabytes), if 0 then there is no limit", "0"); } diff --git a/src/util/event_handler.h b/src/util/event_handler.h index 8993162e6..cabbca4c9 100644 --- a/src/util/event_handler.h +++ b/src/util/event_handler.h @@ -31,7 +31,7 @@ protected: event_handler_caller_t m_caller_id; public: event_handler(): m_caller_id(UNSET_EH_CALLER) {} - virtual ~event_handler() {} + virtual ~event_handler() = default; virtual void operator()(event_handler_caller_t caller_id) = 0; event_handler_caller_t caller_id() const { return m_caller_id; } }; diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index 30ef36d3e..b1f0c3cbe 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -312,13 +312,7 @@ void hwf_manager::round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o } void hwf_manager::rem(hwf const & x, hwf const & y, hwf & o) { -#if defined(_WINDOWS) && _MSC_VER <= 1700 - o.value = fmod(x.value, y.value); - if (o.value >= (y.value/2.0)) - o.value -= y.value; -#else o.value = remainder(x.value, y.value); -#endif } void hwf_manager::maximum(hwf const & x, hwf const & y, hwf & o) { diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index 2841db609..de68b6b10 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -17,6 +17,7 @@ Notes: --*/ +#pragma once #include "util/vector.h" #include "util/uint_set.h" diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 4fdf20c3a..67f5b82b3 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -215,7 +215,7 @@ void * memory::allocate(char const* file, int line, char const* obj, size_t s) { } #endif -#if !defined(SINGLE_THREAD) && (defined(_WINDOWS) || defined(_USE_THREAD_LOCAL)) +#if !defined(SINGLE_THREAD) // ================================== // ================================== // THREAD LOCAL VERSION @@ -271,7 +271,7 @@ void memory::deallocate(void * p) { void * memory::allocate(size_t s) { s = s + sizeof(size_t); // we allocate an extra field! void * r = malloc(s); - if (r == 0) { + if (r == nullptr) { throw_out_of_memory(); return nullptr; } @@ -298,7 +298,7 @@ void* memory::reallocate(void *p, size_t s) { } void *r = realloc(real_p, s); - if (r == 0) { + if (r == nullptr) { throw_out_of_memory(); return nullptr; } diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index ebbf235fb..6841031c3 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1630,11 +1630,7 @@ std::string mpf_manager::to_string_hexfloat(mpf const & x) { std::ios_base::showpoint | std::ios_base::showpos); ss.setf(ff); ss.precision(13); -#if defined(_WIN32) && _MSC_VER >= 1800 ss << std::hexfloat << to_double(x); -#else - ss << std::hex << (*reinterpret_cast(&(x))); -#endif return ss.str(); } diff --git a/src/util/mpf.h b/src/util/mpf.h index fb5f2a022..466d23ea5 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -88,6 +88,8 @@ public: void neg(mpf & o); void neg(mpf const & x, mpf & o); + + void swap(mpf& a, mpf& b) { a.swap(b); } bool is_zero(mpf const & x); bool is_neg(mpf const & x); diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 736b401b8..316a1bba1 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -41,7 +41,6 @@ Revision History: #if defined(_MP_GMP) // Use LEHMER only if not using GMP -// LEHMER assumes 32-bit digits, so it cannot be used with MSBIGNUM library + 64-bit binary #define EUCLID_GCD #else #define LEHMER_GCD @@ -50,7 +49,7 @@ Revision History: #if defined(__GNUC__) #define _trailing_zeros32(X) __builtin_ctz(X) -#elif defined(_WINDOWS) && !defined(_M_ARM) && !defined(_M_ARM64) && !defined(__MINGW32__) +#elif defined(_WINDOWS) && (defined(_M_X86) || (defined(_M_X64) && !defined(_M_ARM64EC))) // This is needed for _tzcnt_u32 and friends. #include #define _trailing_zeros32(X) _tzcnt_u32(X) @@ -62,7 +61,7 @@ static uint32_t _trailing_zeros32(uint32_t x) { } #endif -#if (defined(__LP64__) || defined(_WIN64)) && !defined(_M_ARM) && !defined(_M_ARM64) +#if (defined(__LP64__) || defined(_WIN64)) && defined(_M_X64) && !defined(_M_ARM64EC) #if defined(__GNUC__) #define _trailing_zeros64(X) __builtin_ctzll(X) #else @@ -76,6 +75,13 @@ static uint64_t _trailing_zeros64(uint64_t x) { } #endif +unsigned trailing_zeros(uint32_t x) { + return static_cast(_trailing_zeros32(x)); +} + +unsigned trailing_zeros(uint64_t x) { + return static_cast(_trailing_zeros64(x)); +} #define _bit_min(x, y) (y + ((x - y) & ((int)(x - y) >> 31))) #define _bit_max(x, y) (x - ((x - y) & ((int)(x - y) >> 31))) diff --git a/src/util/mpz.h b/src/util/mpz.h index f3c3b19b9..a1bb19395 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -29,6 +29,9 @@ Revision History: unsigned u_gcd(unsigned u, unsigned v); uint64_t u64_gcd(uint64_t u, uint64_t v); +unsigned trailing_zeros(uint64_t); +unsigned trailing_zeros(uint32_t); + #ifdef _MP_GMP typedef unsigned digit_t; @@ -41,7 +44,7 @@ typedef unsigned digit_t; template class mpz_manager; template class mpq_manager; -#if !defined(_MP_GMP) && !defined(_MP_MSBIGNUM) && !defined(_MP_INTERNAL) +#if !defined(_MP_GMP) && !defined(_MP_INTERNAL) #ifdef _WINDOWS #define _MP_INTERNAL #else @@ -49,13 +52,8 @@ template class mpq_manager; #endif #endif -#if defined(_MP_MSBIGNUM) -typedef size_t digit_t; -#elif defined(_MP_INTERNAL) -typedef unsigned int digit_t; -#endif - #ifndef _MP_GMP +typedef unsigned int digit_t; class mpz_cell { unsigned m_size; unsigned m_capacity; diff --git a/src/util/params.h b/src/util/params.h index da05dff90..7ad152a59 100644 --- a/src/util/params.h +++ b/src/util/params.h @@ -35,13 +35,14 @@ class params_ref { params * m_params; void init(); void copy_core(params const * p); - params_ref& operator=(params_ref const& p) = delete; void set(params_ref const& p); public: params_ref():m_params(nullptr) {} params_ref(params_ref const & p); ~params_ref(); + params_ref& operator=(params_ref const& p) = delete; + static params_ref const & get_empty() { return g_empty_params_ref; } diff --git a/src/util/parray.h b/src/util/parray.h index f8f2d7e54..bc3c4adbe 100644 --- a/src/util/parray.h +++ b/src/util/parray.h @@ -310,17 +310,15 @@ public: } void check_size(cell* c) const { - [[maybe_unused]] unsigned r; while (c) { switch (c->kind()) { case SET: break; case PUSH_BACK: - r = size(c->next()); + // ? SASSERT(c->idx() == size(c->next())); break; case POP_BACK: - r = size(c->next()); - SASSERT(c->idx() == r); + SASSERT(c->idx() == size(c->next())); break; case ROOT: return; diff --git a/src/util/rational.cpp b/src/util/rational.cpp index bb443935a..af3c89ced 100644 --- a/src/util/rational.cpp +++ b/src/util/rational.cpp @@ -130,7 +130,7 @@ bool rational::limit_denominator(rational &num, rational const& limit) { return false; } -bool rational::mult_inverse(unsigned num_bits, rational & result) { +bool rational::mult_inverse(unsigned num_bits, rational & result) const { rational const& n = *this; if (n.is_one()) { result = n; diff --git a/src/util/rational.h b/src/util/rational.h index f28a502ef..cffd0083c 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -157,6 +157,12 @@ public: friend inline rational numerator(rational const & r) { rational result; m().get_numerator(r.m_val, result.m_val); return result; } friend inline rational denominator(rational const & r) { rational result; m().get_denominator(r.m_val, result.m_val); return result; } + + friend inline rational inv(rational const & r) { + rational result; + m().inv(r.m_val, result.m_val); + return result; + } rational & operator+=(rational const & r) { m().add(m_val, r.m_val, m_val); @@ -346,8 +352,13 @@ public: bool is_power_of_two(unsigned & shift) const { return m().is_power_of_two(m_val, shift); } + + bool is_power_of_two() const { + unsigned shift = 0; + return m().is_power_of_two(m_val, shift); + } - bool mult_inverse(unsigned num_bits, rational & result); + bool mult_inverse(unsigned num_bits, rational & result) const; static rational const & zero() { return m_zero; diff --git a/src/util/scoped_numeral.h b/src/util/scoped_numeral.h index 3b35a1bd8..65b75053d 100644 --- a/src/util/scoped_numeral.h +++ b/src/util/scoped_numeral.h @@ -61,11 +61,11 @@ public: } void swap(_scoped_numeral & n) { - m_num.swap(n.m_num); + m().swap(m_num, n.m_num); } void swap(numeral & n) { - m_num.swap(n); + m().swap(m_num, n); } _scoped_numeral & operator+=(numeral const & a) { diff --git a/src/util/scoped_numeral_buffer.h b/src/util/scoped_numeral_buffer.h index 86181f761..81d10ba40 100644 --- a/src/util/scoped_numeral_buffer.h +++ b/src/util/scoped_numeral_buffer.h @@ -24,13 +24,14 @@ template class _scoped_numeral_buffer : public sbuffer { typedef sbuffer super; Manager & m_manager; - _scoped_numeral_buffer(_scoped_numeral_buffer const & v); public: _scoped_numeral_buffer(Manager & m):m_manager(m) {} ~_scoped_numeral_buffer() { reset(); } + _scoped_numeral_buffer(_scoped_numeral_buffer const & v) = delete; + void reset() { unsigned sz = this->size(); for (unsigned i = 0; i < sz; i++) { diff --git a/src/util/scoped_ptr_vector.h b/src/util/scoped_ptr_vector.h index fee80d584..3c33cc708 100644 --- a/src/util/scoped_ptr_vector.h +++ b/src/util/scoped_ptr_vector.h @@ -26,9 +26,25 @@ template class scoped_ptr_vector { ptr_vector m_vector; public: + scoped_ptr_vector() = default; ~scoped_ptr_vector() { reset(); } + scoped_ptr_vector(scoped_ptr_vector& other) = delete; + scoped_ptr_vector& operator=(scoped_ptr_vector& other) = delete; + + scoped_ptr_vector(scoped_ptr_vector&& other) noexcept { + m_vector.swap(other.m_vector); + } + scoped_ptr_vector& operator=(scoped_ptr_vector&& other) { + if (this == &other) + return *this; + reset(); + m_vector.swap(other.m_vector); + return *this; + } + void reset() { std::for_each(m_vector.begin(), m_vector.end(), delete_proc()); m_vector.reset(); } void push_back(T * ptr) { m_vector.push_back(ptr); } + void push_back(scoped_ptr&& ptr) { push_back(ptr.detach()); } void pop_back() { SASSERT(!empty()); set(size()-1, nullptr); m_vector.pop_back(); } T * back() const { return m_vector.back(); } T * operator[](unsigned idx) const { return m_vector[idx]; } @@ -39,6 +55,7 @@ public: dealloc(m_vector[idx]); m_vector[idx] = ptr; } + void swap(unsigned i, unsigned j) { std::swap(m_vector[i], m_vector[j]); } unsigned size() const { return m_vector.size(); } bool empty() const { return m_vector.empty(); } void resize(unsigned sz) { @@ -64,7 +81,24 @@ public: ptr = m_vector.back(); m_vector[m_vector.size()-1] = tmp; } - typename ptr_vector::const_iterator begin() const { return m_vector.begin(); } - typename ptr_vector::const_iterator end() const { return m_vector.end(); } + + T* detach_back() { + SASSERT(!empty()); + T* tmp = m_vector.back(); + m_vector.back() = nullptr; + return tmp; + } + + ptr_vector detach() { + ptr_vector tmp(std::move(m_vector)); + SASSERT(m_vector.empty()); + return tmp; + } + + T* const* data() const { return m_vector.data(); } + + using const_iterator = typename ptr_vector::const_iterator; + const_iterator begin() const { return m_vector.begin(); } + const_iterator end() const { return m_vector.end(); } }; diff --git a/src/muz/rel/tbv.cpp b/src/util/tbv.cpp similarity index 91% rename from src/muz/rel/tbv.cpp rename to src/util/tbv.cpp index 289e43b4e..017ca0eb7 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/util/tbv.cpp @@ -18,9 +18,8 @@ Revision History: --*/ -#include "muz/rel/tbv.h" +#include "util/tbv.h" #include "util/hashtable.h" -#include "ast/ast_util.h" static bool s_debug_alloc = false; @@ -301,26 +300,3 @@ std::ostream& tbv_manager::display(std::ostream& out, tbv const& b) const { if (num_tbits() == 0) return out << "[]"; return display(out, b, num_tbits()-1, 0); } - -expr_ref tbv_manager::to_formula(ast_manager& m, tbv const& src) { - expr_ref result(m); - expr_ref_vector conj(m); - for (unsigned i = 0; i < num_tbits(); ++i) { - switch (src[i]) { - case BIT_0: - conj.push_back(m.mk_not(m.mk_const(symbol(i), m.mk_bool_sort()))); - break; - case BIT_1: - conj.push_back(m.mk_const(symbol(i), m.mk_bool_sort())); - break; - default: - break; - } - } - result = mk_and(m, conj.size(), conj.data()); - return result; -} - -expr_ref tbv_manager::mk_var(ast_manager& m, unsigned i) { - return expr_ref(m.mk_const(symbol(i), m.mk_bool_sort()), m); -} diff --git a/src/muz/rel/tbv.h b/src/util/tbv.h similarity index 96% rename from src/muz/rel/tbv.h rename to src/util/tbv.h index a8aaea234..2a337be1f 100644 --- a/src/muz/rel/tbv.h +++ b/src/util/tbv.h @@ -21,8 +21,8 @@ Revision History: #pragma once #include "util/fixed_bit_vector.h" +#include "util/bit_vector.h" #include "util/rational.h" -#include "ast/ast.h" class tbv; @@ -84,10 +84,7 @@ public: void set(tbv& dst, tbv const& other, unsigned hi, unsigned lo); void set(tbv& dst, unsigned index, tbit value); - static void debug_alloc(); - expr_ref to_formula(ast_manager& m, tbv const& src); - expr_ref mk_var(ast_manager& m, unsigned i); }; class tbv: private fixed_bit_vector { diff --git a/src/util/trail.h b/src/util/trail.h index 969c4a746..20a525cf7 100644 --- a/src/util/trail.h +++ b/src/util/trail.h @@ -26,7 +26,7 @@ Revision History: class trail { public: - virtual ~trail() {} + virtual ~trail() = default; virtual void undo() = 0; }; @@ -243,7 +243,7 @@ public: m_value(m_vector.back()) { } - virtual void undo() { + void undo() override { m_vector.push_back(m_value); } }; diff --git a/src/util/uint_set.h b/src/util/uint_set.h index 2b7e36360..6e64cc7ae 100644 --- a/src/util/uint_set.h +++ b/src/util/uint_set.h @@ -192,7 +192,7 @@ public: m_set(&s), m_index(at_end?s.get_max_elem():0), m_last(s.get_max_elem()) { scan(); SASSERT(invariant()); - } + } unsigned operator*() const { return m_index; } bool operator==(iterator const& it) const { return m_index == it.m_index; } bool operator!=(iterator const& it) const { return m_index != it.m_index; } diff --git a/src/util/union_find.h b/src/util/union_find.h index c82d25857..7e42e1bba 100644 --- a/src/util/union_find.h +++ b/src/util/union_find.h @@ -93,6 +93,11 @@ public: return r; } + void reserve(unsigned v) { + while (get_num_vars() <= v) + mk_var(); + } + unsigned get_num_vars() const { return m_find.size(); } diff --git a/src/util/var_queue.h b/src/util/var_queue.h index e5a21d9a4..62df77784 100644 --- a/src/util/var_queue.h +++ b/src/util/var_queue.h @@ -52,7 +52,7 @@ public: void mk_var_eh(var v) { m_queue.reserve(v+1); - m_queue.insert(v); + unassign_var_eh(v); } void del_var_eh(var v) { @@ -76,5 +76,21 @@ public: var min_var() { SASSERT(!empty()); return m_queue.min_value(); } bool more_active(var v1, var v2) const { return m_queue.less_than(v1, v2); } + + std::ostream& display(std::ostream& out) const { + bool first = true; + for (auto v : m_queue) { + if (first) { + first = false; + } else { + out << " "; + } + out << v; + } + return out; + } }; +inline std::ostream& operator<<(std::ostream& out, var_queue const& queue) { + return queue.display(out); +} diff --git a/src/util/z3_exception.h b/src/util/z3_exception.h index cb0a58e37..b6875257c 100644 --- a/src/util/z3_exception.h +++ b/src/util/z3_exception.h @@ -22,7 +22,7 @@ Notes: class z3_exception { public: - virtual ~z3_exception() {} + virtual ~z3_exception() = default; virtual char const * msg() const = 0; virtual unsigned error_code() const; bool has_error_code() const; @@ -42,7 +42,6 @@ public: struct fmt {}; default_exception(std::string && msg) : m_msg(std::move(msg)) {} default_exception(fmt, char const* msg, ...); - ~default_exception() override {} char const * msg() const override; };