mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 03:32:28 +00:00 
			
		
		
		
	Merge branch 'opt' of https://github.com/NikolajBjorner/z3 into opt
This commit is contained in:
		
						commit
						bdce957ac8
					
				
					 83 changed files with 2596 additions and 1126 deletions
				
			
		
							
								
								
									
										13
									
								
								.travis.yml
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								.travis.yml
									
										
									
									
									
								
							|  | @ -22,10 +22,17 @@ env: | |||
|     # 64-bit Clang 3.9 RelWithDebInfo | ||||
|     - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo | ||||
| 
 | ||||
|     # Debug builds | ||||
|     # | ||||
|     # 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. The hope is | ||||
|     # that just running the optimized unit tests is sufficient. | ||||
|     # | ||||
|     # 64-bit GCC 5.4 Debug | ||||
|     - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug | ||||
|     - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY | ||||
|     # 64-bit Clang Debug | ||||
|     - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug | ||||
|     - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY | ||||
| 
 | ||||
|     # 32-bit GCC 5.4 RelWithDebInfo | ||||
|     - LINUX_BASE=ubuntu32_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=i686 Z3_BUILD_TYPE=RelWithDebInfo | ||||
|  | @ -57,7 +64,7 @@ env: | |||
|     # 64-bit GCC 4.8 RelWithDebInfo | ||||
|     - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo | ||||
|     # 64-bit GCC 4.8 Debug | ||||
|     - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug | ||||
|     - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY | ||||
| 
 | ||||
| # macOS (a.k.a OSX) support | ||||
| matrix: | ||||
|  |  | |||
|  | @ -12,9 +12,9 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z | |||
| 
 | ||||
| ## Build status | ||||
| 
 | ||||
| | Windows x86 | Windows x64 | Ubuntu x64 | Ubuntu x86 | Debian x64 | OSX | TravisCI | | ||||
| | ----------- | ----------- | ---------- | ---------- | ---------- | --- | -------- | | ||||
| [](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [](https://cz3.visualstudio.com/Z3/_build/index?definitionId=6) | [](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [](https://travis-ci.org/Z3Prover/z3) | ||||
| | Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | OSX | TravisCI | | ||||
| | ----------- | ----------- | ---------- | ---------- | --- | -------- | | ||||
| [](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [](https://travis-ci.org/Z3Prover/z3) | ||||
| 
 | ||||
| [1]: #building-z3-on-windows-using-visual-studio-command-prompt | ||||
| [2]: #building-z3-using-make-and-gccclang | ||||
|  |  | |||
|  | @ -2,34 +2,33 @@ ARG DOCKER_IMAGE_BASE | |||
| FROM ${DOCKER_IMAGE_BASE} | ||||
| 
 | ||||
| 
 | ||||
| # Specify defaults. This can be changed when invoking | ||||
| # Build arguments. This can be changed when invoking | ||||
| # `docker build`. | ||||
| ARG ASAN_BUILD=0 | ||||
| ARG BUILD_DOCS=0 | ||||
| ARG CC=gcc | ||||
| ARG CXX=g++ | ||||
| ARG DOTNET_BINDINGS=1 | ||||
| ARG JAVA_BINDINGS=1 | ||||
| ARG NO_SUPPRESS_OUTPUT=0 | ||||
| ARG PYTHON_BINDINGS=1 | ||||
| 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/python2.7 | ||||
| ARG RUN_SYSTEM_TESTS=1 | ||||
| ARG RUN_UNIT_TESTS=1 | ||||
| ARG TARGET_ARCH=x86_64 | ||||
| ARG TEST_INSTALL=1 | ||||
| ARG UBSAN_BUILD=0 | ||||
| ARG USE_LIBGMP=0 | ||||
| ARG USE_LTO=0 | ||||
| ARG USE_OPENMP=1 | ||||
| ARG RUN_SYSTEM_TESTS | ||||
| ARG RUN_UNIT_TESTS | ||||
| ARG TARGET_ARCH | ||||
| ARG TEST_INSTALL | ||||
| ARG UBSAN_BUILD | ||||
| ARG USE_LIBGMP | ||||
| ARG USE_LTO | ||||
| ARG USE_OPENMP | ||||
| ARG Z3_SRC_DIR=/home/user/z3_src | ||||
| ARG Z3_BUILD_TYPE=RelWithDebInfo | ||||
| ARG Z3_CMAKE_GENERATOR=Ninja | ||||
| ARG Z3_INSTALL_PREFIX=/usr | ||||
| ARG Z3_STATIC_BUILD=0 | ||||
| # Blank default indicates use latest. | ||||
| 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=SERIOUS_ONLY | ||||
| ARG Z3_VERBOSE_BUILD_OUTPUT=0 | ||||
| ARG Z3_WARNINGS_AS_ERRORS | ||||
| ARG Z3_VERBOSE_BUILD_OUTPUT | ||||
| 
 | ||||
| ENV \ | ||||
|   ASAN_BUILD=${ASAN_BUILD} \ | ||||
|  | @ -74,6 +73,7 @@ ADD *.txt *.md 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/ | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ the future. | |||
| * `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_SYSTEM_TESTS` - Run system tests (`0` or `1`) | ||||
| * `RUN_UNIT_TESTS` - Run unit tests (`0` or `1`) | ||||
| * `RUN_UNIT_TESTS` - Run unit tests (`BUILD_ONLY` or `BUILD_AND_RUN` or `SKIP`) | ||||
| * `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`) | ||||
|  | @ -58,8 +58,9 @@ The `scripts/travis_ci_linux_entry_point.sh` script | |||
|    variables (if set) into the build using the `--build-arg` argument of the `docker run` | ||||
|    command. | ||||
| 
 | ||||
| If an environemnt variable is not set a defaults value is used which can be | ||||
| found in `Dockerfiles/z3_build.Dockerfile`. | ||||
| The default values of the configuration environment variables | ||||
| can be found in | ||||
| [`scripts/ci_defaults.sh`](scripts/ci_defaults.sh). | ||||
| 
 | ||||
| #### Linux specific configuration variables | ||||
| 
 | ||||
|  | @ -67,8 +68,9 @@ found in `Dockerfiles/z3_build.Dockerfile`. | |||
| 
 | ||||
| #### 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. | ||||
| 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. | ||||
| 
 | ||||
|  | @ -104,11 +106,43 @@ 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 everytime. | ||||
| image every time. | ||||
| 
 | ||||
| An [organization](https://hub.docker.com/u/z3prover/) has been created on | ||||
| DockerHub for this. | ||||
| 
 | ||||
| ### macOS | ||||
| 
 | ||||
| Not yet implemented. | ||||
| 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 | ||||
|   # Note: Apple Clang does not support OpenMP | ||||
|   env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 | ||||
| ``` | ||||
| 
 | ||||
| Run the following: | ||||
| 
 | ||||
| ```bash | ||||
| TRAVIS_BUILD_DIR=$(pwd) \ | ||||
| Z3_BUILD_TYPE=RelWithDebInfo \ | ||||
| USE_OPEN_MP=0 \ | ||||
| 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. | ||||
|  |  | |||
							
								
								
									
										54
									
								
								contrib/ci/scripts/ci_defaults.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								contrib/ci/scripts/ci_defaults.sh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | |||
| # 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_SYSTEM_TESTS="${RUN_SYSTEM_TESTS:-1}" | ||||
| export RUN_UNIT_TESTS="${RUN_UNIT_TESTS:-BUILD_AND_RUN}" | ||||
| export TARGET_ARCH="${TARGET_ARCH:-x86_64}" | ||||
| export TEST_INSTALL="${TEST_INSTALL:-1}" | ||||
| export UBSAN_BUILD="${UBSAN_BUILD:-0}" | ||||
| export USE_LIBGMP="${USE_LIBGMP:-0}" | ||||
| export USE_LTO="${USE_LTO:-0}" | ||||
| export USE_OPENMP="${USE_OPENMP:-1}" | ||||
| 
 | ||||
| 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 | ||||
| # Z3_SRC_DIR | ||||
| # Z3_BUILD_DIR | ||||
| # Z3_SYSTEM_TEST_DIR | ||||
|  | @ -1,4 +1,4 @@ | |||
| # This script should is intended to be included by other | ||||
| # 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"} | ||||
|  |  | |||
|  | @ -10,17 +10,35 @@ set -o pipefail | |||
| : ${Z3_BUILD_DIR?"Z3_BUILD_DIR must be specified"} | ||||
| : ${RUN_UNIT_TESTS?"RUN_UNIT_TESTS must be specified"} | ||||
| 
 | ||||
| if [ "X${RUN_UNIT_TESTS}" != "X1" ]; then | ||||
|   echo "Skipping unit tests" | ||||
|   exit 0 | ||||
| fi | ||||
| 
 | ||||
| # Set CMake generator args | ||||
| source ${SCRIPT_DIR}/set_generator_args.sh | ||||
| 
 | ||||
| cd "${Z3_BUILD_DIR}" | ||||
| 
 | ||||
| # Build and run internal tests | ||||
| cmake --build $(pwd) --target test-z3 "${GENERATOR_ARGS[@]}" | ||||
| # Run all tests that don't require arguments | ||||
| run_quiet ./test-z3 /a | ||||
| 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 | ||||
|  |  | |||
|  | @ -11,16 +11,21 @@ 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=() | ||||
| # Override options if they have been provided. | ||||
| # Otherwise the defaults in the Docker file will be used | ||||
| # 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 | ||||
|  |  | |||
|  | @ -6,26 +6,8 @@ set -x | |||
| set -e | ||||
| set -o pipefail | ||||
| 
 | ||||
| # Set defaults | ||||
| # FIXME: Refactor this so we don't need to stay in sync with | ||||
| # `z3_build.Dockerfile`. | ||||
| export ASAN_BUILD="${ASAN_BUILD:-0}" | ||||
| export BUILD_DOCS="${BUILD_DOCS:-0}" | ||||
| export C_COMPILER="${C_COMPILER:-clang}" | ||||
| export CXX_COMPILER="${CXX_COMPILER:-clang++}" | ||||
| 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 PYTHON_EXECUTABLE="$(which python)" | ||||
| export RUN_SYSTEM_TESTS="${RUN_SYSTEM_TESTS:-1}" | ||||
| export RUN_UNIT_TESTS="${RUN_UNIT_TESTS:-1}" | ||||
| export TARGET_ARCH="${TARGET_ARCH:-x86_64}" | ||||
| export TEST_INSTALL="${TEST_INSTALL:-1}" | ||||
| export UBSAN_BUILD="${UBSAN_BUILD:-0}" | ||||
| export USE_LIBGMP="${USE_LIBGMP:-0}" | ||||
| export USE_LTO="${USE_LTO:-0}" | ||||
| export USE_OPENMP="${USE_OPENMP:-1}" | ||||
| # 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" | ||||
|  | @ -37,15 +19,12 @@ if [ ! -d "${TRAVIS_BUILD_DIR}" ]; then | |||
|   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_BUILD_TYPE="${Z3_BUILD_TYPE:-RelWithDebInfo}" | ||||
| export Z3_CMAKE_GENERATOR="${Z3_CMAKE_GENERATOR:-Ninja}" | ||||
| export Z3_INSTALL_PREFIX="${Z3_INSTALL_PREFIX:-/usr/local}" | ||||
| export Z3_STATIC_BUILD="${Z3_STATIC_BUILD:-0}" | ||||
| export Z3_SYSTEM_TEST_DIR="${Z3_SRC_DIR}/z3_system_test" | ||||
| export Z3_WARNINGS_AS_ERRORS="${Z3_WARNINGS_AS_ERRORS:-SERIOUS_ONLY}" | ||||
| export Z3_VERBOSE_BUILD_OUTPUT="${Z3_VERBOSE_BUILD_OUTPUT:-0}" | ||||
| 
 | ||||
| # Overwrite whatever what set in TravisCI | ||||
| export CC="${C_COMPILER}" | ||||
|  |  | |||
|  | @ -188,7 +188,7 @@ try: | |||
| 
 | ||||
|     if Z3PY_ENABLED: | ||||
|         print("Z3Py documentation enabled") | ||||
|         doxygen_config_substitutions['PYTHON_API_FILES'] = 'z3.py' | ||||
|         doxygen_config_substitutions['PYTHON_API_FILES'] = 'z3*.py' | ||||
|     else: | ||||
|         print("Z3Py documentation disabled") | ||||
|         doxygen_config_substitutions['PYTHON_API_FILES'] = '' | ||||
|  | @ -288,8 +288,21 @@ try: | |||
|         # Put z3py at the beginning of the search path to try to avoid picking up | ||||
|         # an installed copy of Z3py. | ||||
|         sys.path.insert(0, os.path.dirname(Z3PY_PACKAGE_PATH)) | ||||
|         pydoc.writedoc('z3') | ||||
|         shutil.move('z3.html', os.path.join(OUTPUT_DIRECTORY, 'html', 'z3.html')) | ||||
|         for modulename in ( | ||||
|                 'z3', | ||||
|                 'z3.z3consts', | ||||
|                 'z3.z3core', | ||||
|                 'z3.z3num', | ||||
|                 'z3.z3poly', | ||||
|                 'z3.z3printer', | ||||
|                 'z3.z3rcf', | ||||
|                 'z3.z3types', | ||||
|                 'z3.z3util', | ||||
|                 ): | ||||
|             pydoc.writedoc(modulename) | ||||
|             doc = modulename + '.html' | ||||
|             shutil.move(doc, os.path.join(OUTPUT_DIRECTORY, 'html', doc)) | ||||
| 
 | ||||
|         print("Generated pydoc Z3Py documentation.") | ||||
| 
 | ||||
|     if ML_ENABLED: | ||||
|  |  | |||
|  | @ -65,6 +65,15 @@ void throw_z3_error(Z3_context c, Z3_error_code e) | |||
|     longjmp(g_catch_buffer, e); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|    \brief Error handling that depends on checking an error code on the context. | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| void nothrow_z3_error(Z3_context c, Z3_error_code e) { | ||||
|     // no-op
 | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|    \brief Create a logical context. | ||||
| 
 | ||||
|  | @ -1592,18 +1601,16 @@ void error_code_example1() | |||
| void error_code_example2() { | ||||
|     Z3_config cfg; | ||||
|     Z3_context ctx = NULL; | ||||
|     int r; | ||||
|     Z3_error_code e; | ||||
| 
 | ||||
|     printf("\nerror_code_example2\n"); | ||||
|     LOG_MSG("error_code_example2"); | ||||
| 
 | ||||
|     /* low tech try&catch */ | ||||
|     r = setjmp(g_catch_buffer); | ||||
|     if (r == 0) { | ||||
|     if (1) { | ||||
|         Z3_ast x, y, app; | ||||
| 
 | ||||
|         cfg = Z3_mk_config(); | ||||
|         ctx = mk_context_custom(cfg, throw_z3_error); | ||||
|         ctx = mk_context_custom(cfg, nothrow_z3_error); | ||||
|         Z3_del_config(cfg); | ||||
| 
 | ||||
|         x   = mk_int_var(ctx, "x"); | ||||
|  | @ -1611,11 +1618,14 @@ void error_code_example2() { | |||
|         printf("before Z3_mk_iff\n"); | ||||
|         /* the next call will produce an error */ | ||||
|         app = Z3_mk_iff(ctx, x, y); | ||||
|         e = Z3_get_error_code(ctx); | ||||
|         if (e != Z3_OK) goto err; | ||||
|         unreachable(); | ||||
|         Z3_del_context(ctx); | ||||
|     } | ||||
|     else { | ||||
|       printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, (Z3_error_code)r)); | ||||
|     err: | ||||
|         printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e)); | ||||
|         if (ctx != NULL) { | ||||
|             Z3_del_context(ctx); | ||||
|         } | ||||
|  | @ -1781,15 +1791,14 @@ void parser_example5() { | |||
|     Z3_config  cfg; | ||||
|     Z3_context ctx = NULL; | ||||
|     Z3_solver s = NULL; | ||||
|     int r; | ||||
|     Z3_error_code e; | ||||
| 
 | ||||
|     printf("\nparser_example5\n"); | ||||
|     LOG_MSG("parser_example5"); | ||||
| 
 | ||||
|     r = setjmp(g_catch_buffer); | ||||
|     if (r == 0) { | ||||
|     if (1) { | ||||
|         cfg = Z3_mk_config(); | ||||
|         ctx = mk_context_custom(cfg, throw_z3_error); | ||||
|         ctx = mk_context_custom(cfg, nothrow_z3_error); | ||||
|         s   = mk_solver(ctx); | ||||
|         Z3_del_config(cfg); | ||||
| 
 | ||||
|  | @ -1798,12 +1807,15 @@ void parser_example5() { | |||
|                                "(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))", | ||||
|                                0, 0, 0, | ||||
|                                0, 0, 0); | ||||
|         e = Z3_get_error_code(ctx); | ||||
|         if (e != Z3_OK) goto err; | ||||
|         unreachable(); | ||||
| 	del_solver(ctx, s); | ||||
|         Z3_del_context(ctx); | ||||
|     } | ||||
|     else { | ||||
|       printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, (Z3_error_code)r)); | ||||
|     err: | ||||
|         printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e)); | ||||
|         if (ctx != NULL) { | ||||
|             printf("Error message: '%s'.\n",Z3_get_smtlib_error(ctx)); | ||||
| 	    del_solver(ctx, s); | ||||
|  |  | |||
|  | @ -1913,7 +1913,11 @@ class MLComponent(Component): | |||
|             src_dir = self.to_src_dir | ||||
|             mk_dir(os.path.join(BUILD_DIR, self.sub_dir)) | ||||
|             api_src = get_component(API_COMPONENT).to_src_dir | ||||
|             out.write('CXXFLAGS_OCAML=$(CXXFLAGS:/GL=)\n') # remove /GL; the ocaml tools don't like it. | ||||
|             # remove /GL and -std=c++11; the ocaml tools don't like them. | ||||
|             if IS_WINDOWS:                 | ||||
|                 out.write('CXXFLAGS_OCAML=$(CXXFLAGS:/GL=)\n') | ||||
|             else: | ||||
|                 out.write('CXXFLAGS_OCAML=$(subst -std=c++11,,$(CXXFLAGS))\n') | ||||
| 
 | ||||
|             if IS_WINDOWS: | ||||
|                 prefix_lib = '-L' + os.path.abspath(BUILD_DIR).replace('\\', '\\\\') | ||||
|  |  | |||
|  | @ -57,19 +57,20 @@ extern "C" { | |||
|                                        Z3_func_decl const decls[]) { | ||||
|         Z3_TRY; | ||||
|         LOG_Z3_parse_smtlib_string(c, str, num_sorts, sort_names, sorts, num_decls, decl_names, decls); | ||||
|         std::ostringstream outs; | ||||
|         std::ostringstream* outs = alloc(std::ostringstream); | ||||
|         bool ok = false; | ||||
| 
 | ||||
|         RESET_ERROR_CODE(); | ||||
|         init_smtlib_parser(c, num_sorts, sort_names, sorts, num_decls, decl_names, decls); | ||||
|         mk_c(c)->m_smtlib_parser->set_error_stream(outs); | ||||
|         mk_c(c)->m_smtlib_parser->set_error_stream(*outs); | ||||
|         try { | ||||
|             ok = mk_c(c)->m_smtlib_parser->parse_string(str);         | ||||
|         } | ||||
|         catch (...) { | ||||
|             ok = false; | ||||
|         } | ||||
|         mk_c(c)->m_smtlib_error_buffer = outs.str(); | ||||
|         mk_c(c)->m_smtlib_error_buffer = outs->str(); | ||||
|         dealloc(outs); | ||||
|         if (!ok) { | ||||
|             mk_c(c)->reset_parser(); | ||||
|             SET_ERROR_CODE(Z3_PARSER_ERROR); | ||||
|  | @ -89,16 +90,17 @@ extern "C" { | |||
|         LOG_Z3_parse_smtlib_file(c, file_name, num_sorts, sort_names, types, num_decls, decl_names, decls); | ||||
|         bool ok = false; | ||||
|         RESET_ERROR_CODE(); | ||||
|         std::ostringstream outs; | ||||
|         std::ostringstream* outs = alloc(std::ostringstream); | ||||
|         init_smtlib_parser(c, num_sorts, sort_names, types, num_decls, decl_names, decls); | ||||
|         mk_c(c)->m_smtlib_parser->set_error_stream(outs); | ||||
|         mk_c(c)->m_smtlib_parser->set_error_stream(*outs); | ||||
|         try { | ||||
|             ok = mk_c(c)->m_smtlib_parser->parse_file(file_name); | ||||
|         } | ||||
|         catch(...) { | ||||
|             ok = false; | ||||
|         } | ||||
|         mk_c(c)->m_smtlib_error_buffer = outs.str(); | ||||
|         mk_c(c)->m_smtlib_error_buffer = outs->str(); | ||||
|         dealloc(outs); | ||||
|         if (!ok) { | ||||
|             mk_c(c)->reset_parser(); | ||||
|             SET_ERROR_CODE(Z3_PARSER_ERROR); | ||||
|  |  | |||
|  | @ -140,7 +140,7 @@ namespace z3 { | |||
|     class context { | ||||
|         bool       m_enable_exceptions; | ||||
|         Z3_context m_ctx; | ||||
|         static void error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ } | ||||
|         static void Z3_API error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ } | ||||
|         void init(config & c) { | ||||
|             m_ctx = Z3_mk_context_rc(c); | ||||
|             m_enable_exceptions = true; | ||||
|  |  | |||
|  | @ -471,6 +471,9 @@ bool compare_nodes(ast const * n1, ast const * n2) { | |||
|             compare_arrays(to_quantifier(n1)->get_decl_sorts(), | ||||
|                            to_quantifier(n2)->get_decl_sorts(), | ||||
|                            to_quantifier(n1)->get_num_decls()) && | ||||
|             compare_arrays(to_quantifier(n1)->get_decl_names(), | ||||
|                            to_quantifier(n2)->get_decl_names(), | ||||
|                            to_quantifier(n1)->get_num_decls()) && | ||||
|             to_quantifier(n1)->get_expr()            == to_quantifier(n2)->get_expr() && | ||||
|             to_quantifier(n1)->get_weight()          == to_quantifier(n2)->get_weight() && | ||||
|             to_quantifier(n1)->get_num_patterns() == to_quantifier(n2)->get_num_patterns() && | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ Notes: | |||
| 
 | ||||
| #include "ast/expr_abstract.h" | ||||
| #include "util/map.h" | ||||
| #include "ast/ast_pp.h" | ||||
| 
 | ||||
| void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) { | ||||
|      | ||||
|  | @ -109,6 +110,9 @@ void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* | |||
| void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref&  result) { | ||||
|     expr_abstractor abs(m); | ||||
|     abs(base, num_bound, bound, n, result); | ||||
|     TRACE("expr_abstract", | ||||
|           tout << expr_ref(n, m) << "\n"; | ||||
|           tout << result << "\n";); | ||||
| } | ||||
| 
 | ||||
| expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) { | ||||
|  | @ -123,6 +127,11 @@ expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* | |||
|         } | ||||
|         result = m.mk_quantifier(is_forall, num_bound, sorts.c_ptr(), names.c_ptr(), result); | ||||
|     } | ||||
|     TRACE("expr_abstract", | ||||
|           tout << expr_ref(n, m) << "\n"; | ||||
|           for (unsigned i = 0; i < num_bound; ++i) tout << expr_ref(bound[i], m) << " "; | ||||
|           tout << "\n"; | ||||
|           tout << result << "\n";); | ||||
|     return result; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -16,8 +16,9 @@ Author: | |||
| Notes: | ||||
| 
 | ||||
| --*/ | ||||
| #include "ast/expr_substitution.h" | ||||
| #include "util/ref_util.h" | ||||
| #include "ast/expr_substitution.h" | ||||
| #include "ast/ast_pp.h" | ||||
| 
 | ||||
| typedef obj_map<expr, proof*> expr2proof; | ||||
| typedef obj_map<expr, expr_dependency*> expr2expr_dependency; | ||||
|  | @ -56,6 +57,13 @@ expr_substitution::~expr_substitution() { | |||
|     reset(); | ||||
| } | ||||
| 
 | ||||
| std::ostream& expr_substitution::display(std::ostream& out) { | ||||
|     for (auto & kv : m_subst) { | ||||
|         out << mk_pp(kv.m_key, m()) << " |-> " << mk_pp(kv.m_value, m()) << "\n"; | ||||
|     } | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| void expr_substitution::insert(expr * c, expr * def, proof * def_pr, expr_dependency * def_dep) { | ||||
|     obj_map<expr, expr*>::obj_map_entry * entry = m_subst.insert_if_not_there2(c, 0);  | ||||
|     if (entry->get_data().m_value == 0) { | ||||
|  |  | |||
|  | @ -50,6 +50,8 @@ public: | |||
|     bool contains(expr * s); | ||||
|     void reset(); | ||||
|     void cleanup(); | ||||
| 
 | ||||
|     std::ostream& display(std::ostream& out); | ||||
| }; | ||||
| 
 | ||||
| class scoped_expr_substitution { | ||||
|  | @ -84,6 +86,7 @@ public: | |||
|     bool find(expr * s, expr * & def, proof * & def_pr, expr_dependency * & def_dep) { return m_subst.find(s, def, def_pr, def_dep); } | ||||
|     bool contains(expr * s) { return m_subst.contains(s); } | ||||
|     void cleanup() { m_subst.cleanup(); } | ||||
|     std::ostream& display(std::ostream& out) { return m_subst.display(out); } | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -1180,8 +1180,6 @@ void fpa2bv_converter::mk_abs(sort * s, expr_ref & x, expr_ref & result) { | |||
| 
 | ||||
| void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { | ||||
|     SASSERT(num == 2); | ||||
|     unsigned ebits = m_util.get_ebits(f->get_range()); | ||||
|     unsigned sbits = m_util.get_sbits(f->get_range()); | ||||
| 
 | ||||
|     expr * x = args[0], * y = args[1]; | ||||
| 
 | ||||
|  | @ -1227,8 +1225,6 @@ void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, | |||
| 
 | ||||
| void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { | ||||
|     SASSERT(num == 2); | ||||
|     unsigned ebits = m_util.get_ebits(f->get_range()); | ||||
|     unsigned sbits = m_util.get_sbits(f->get_range()); | ||||
| 
 | ||||
|     expr * x = args[0], *y = args[1]; | ||||
| 
 | ||||
|  | @ -3081,8 +3077,6 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * | |||
|     mk_is_nan(x, x_is_nan); | ||||
| 
 | ||||
|     sort * fp_srt = m.get_sort(x); | ||||
|     unsigned ebits = m_util.get_ebits(fp_srt); | ||||
|     unsigned sbits = m_util.get_sbits(fp_srt); | ||||
| 
 | ||||
|     expr_ref unspec(m); | ||||
|     mk_to_ieee_bv_unspecified(f, num, args, unspec); | ||||
|  |  | |||
|  | @ -54,13 +54,13 @@ br_status maximize_ac_sharing::reduce_app(func_decl * f, unsigned num_args, expr | |||
|     TRACE("ac_sharing_detail", tout << "args: "; for (unsigned i = 0; i < num_args; i++) tout << mk_pp(_args[i], m) << "\n";); | ||||
|     try_to_reuse: | ||||
|     if (num_args > 1 && num_args < MAX_NUM_ARGS_FOR_OPT) { | ||||
|         for (unsigned i = 0; i < num_args - 1; i++) { | ||||
|         for (unsigned i = 0; i + 1 < num_args; i++) { | ||||
|             for (unsigned j = i + 1; j < num_args; j++) { | ||||
|                 if (contains(f, _args[i], _args[j])) { | ||||
|                     TRACE("ac_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";); | ||||
|                     _args[i] = m.mk_app(f, _args[i], _args[j]); | ||||
|                     SASSERT(num_args > 1); | ||||
|                     for (unsigned w = j; w < num_args - 1; w++) { | ||||
|                     for (unsigned w = j; w + 1 < num_args; w++) { | ||||
|                         _args[w] = _args[w+1]; | ||||
|                     } | ||||
|                     num_args--; | ||||
|  | @ -144,6 +144,7 @@ void maximize_ac_sharing::restore_entries(unsigned old_lim) { | |||
|     while (i != old_lim) { | ||||
|         --i; | ||||
|         entry * e = m_entries[i]; | ||||
|         m_cache.remove(e); | ||||
|         m.dec_ref(e->m_arg1); | ||||
|         m.dec_ref(e->m_arg2); | ||||
|     } | ||||
|  | @ -151,11 +152,7 @@ void maximize_ac_sharing::restore_entries(unsigned old_lim) { | |||
| } | ||||
| 
 | ||||
| void maximize_ac_sharing::reset() { | ||||
|     restore_entries(0); | ||||
|     m_entries.reset(); | ||||
|     m_cache.reset(); | ||||
|     m_region.reset(); | ||||
|     m_scopes.reset(); | ||||
| } | ||||
| 
 | ||||
| void maximize_bv_sharing::init_core() { | ||||
|  |  | |||
|  | @ -870,6 +870,12 @@ void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, s | |||
|     lhs = m().mk_app(f, binding.size(), binding.c_ptr()); | ||||
|     eq  = m().mk_eq(lhs, e); | ||||
|     if (!ids.empty()) { | ||||
|         if (is_var(e)) { | ||||
|             ptr_vector<sort> domain; | ||||
|             for (expr* b : binding) domain.push_back(m().get_sort(b)); | ||||
|             insert_macro(f->get_name(), domain.size(), domain.c_ptr(), e); | ||||
|             return; | ||||
|         } | ||||
|         if (!is_app(e)) { | ||||
|             throw cmd_exception("Z3 only supports recursive definitions that are proper terms (not binders or variables)"); | ||||
|         } | ||||
|  | @ -1763,6 +1769,7 @@ void cmd_context::validate_model() { | |||
|                     continue; | ||||
|                 } | ||||
|                 try { | ||||
|                     for_each_expr(contains_underspecified, a); | ||||
|                     for_each_expr(contains_underspecified, r); | ||||
|                 } | ||||
|                 catch (contains_underspecified_op_proc::found) { | ||||
|  |  | |||
|  | @ -33,9 +33,11 @@ | |||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <ostream> | ||||
| #include <sstream> | ||||
| 
 | ||||
| #include "ast/expr_abstract.h" | ||||
| #include "util/params.h" | ||||
| #include "ast/used_vars.h" | ||||
| 
 | ||||
| 
 | ||||
| using namespace stl_ext; | ||||
|  | @ -938,3 +940,30 @@ void iz3mgr::get_bound_substitutes(stl_ext::hash_map<ast,bool> &memo, const ast | |||
|   | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
| unsigned  iz3mgr::num_free_variables(const ast &e){ | ||||
|     used_vars uv; | ||||
|     uv(to_expr(e.raw())); | ||||
|     return uv.get_num_vars(); | ||||
| } | ||||
| 
 | ||||
| iz3mgr::ast iz3mgr::close_universally (ast e){ | ||||
|    used_vars uv; | ||||
|    uv(to_expr(e.raw())); | ||||
|    std::vector<ast> bvs; | ||||
|    stl_ext::hash_map<ast,ast> subst_memo; | ||||
|    for (unsigned i = 0; i < uv.get_max_found_var_idx_plus_1(); i++){ | ||||
|        if (uv.get(i)) { | ||||
|            std::ostringstream os; | ||||
|            os << "%%" << i; | ||||
|            ast c = make_var(os.str(),uv.get(i)); | ||||
|            ast v = cook(m().mk_var(i,uv.get(i))); | ||||
|            subst_memo[v] = c; | ||||
|            bvs.push_back(c); | ||||
|        } | ||||
|    } | ||||
|    e = subst(subst_memo,e); | ||||
|    for (unsigned i = 0; i < bvs.size(); i++) | ||||
|        e = apply_quant(Forall,bvs[i],e); | ||||
|    return e; | ||||
| } | ||||
|  |  | |||
|  | @ -96,7 +96,7 @@ class ast_r : public ast_i { | |||
| 
 | ||||
|  ast_r(const ast_r &other) : ast_i(other) { | ||||
|         _m = other._m; | ||||
|         _m->inc_ref(_ast); | ||||
|         if (_m) _m->inc_ref(_ast); | ||||
|     } | ||||
| 
 | ||||
|     ast_r &operator=(const ast_r &other) { | ||||
|  | @ -104,7 +104,7 @@ class ast_r : public ast_i { | |||
|             _m->dec_ref(_ast); | ||||
|         _ast = other._ast; | ||||
|         _m = other._m; | ||||
|         _m->inc_ref(_ast); | ||||
|         if (_m) _m->inc_ref(_ast); | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|  | @ -661,6 +661,12 @@ class iz3mgr  { | |||
| 
 | ||||
|     ast apply_quant(opr quantifier, ast var, ast e); | ||||
| 
 | ||||
|     // Universally quantify all the free variables in a formula.
 | ||||
|     // Makes up names for the quntifiers.
 | ||||
| 
 | ||||
|     ast close_universally (ast e); | ||||
| 
 | ||||
|     unsigned num_free_variables(const ast &e); | ||||
| 
 | ||||
|     /** For debugging */ | ||||
|     void show(ast); | ||||
|  |  | |||
|  | @ -2968,9 +2968,9 @@ class iz3proof_itp_impl : public iz3proof_itp { | |||
|     ast interpolate(const node &pf){ | ||||
|         // proof of false must be a formula, with quantified symbols
 | ||||
| #ifndef BOGUS_QUANTS | ||||
|         return add_quants(z3_simplify(pf)); | ||||
|         return close_universally(add_quants(z3_simplify(pf))); | ||||
| #else | ||||
|         return z3_simplify(pf); | ||||
|         return close_universally(z3_simplify(pf)); | ||||
| #endif | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -234,6 +234,11 @@ public: | |||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // if(!range_is_empty(rng)){
 | ||||
|             //     if (num_free_variables(con) > 0)
 | ||||
|             //         rng = range_empty();
 | ||||
|             // }
 | ||||
| 
 | ||||
|             if(res == INT_MAX){ | ||||
|                 if(range_is_empty(rng)) | ||||
|                     res = -1; | ||||
|  |  | |||
|  | @ -86,18 +86,22 @@ void model_core::register_decl(func_decl * d, func_interp * fi) { | |||
| void model_core::unregister_decl(func_decl * d) { | ||||
|     decl2expr::obj_map_entry * ec = m_interp.find_core(d); | ||||
|     if (ec && ec->get_data().m_value != 0) { | ||||
|         m_manager.dec_ref(ec->get_data().m_key); | ||||
|         m_manager.dec_ref(ec->get_data().m_value); | ||||
|         auto k = ec->get_data().m_key; | ||||
|         auto v = ec->get_data().m_value; | ||||
|         m_interp.remove(d); | ||||
|         m_const_decls.erase(d); | ||||
|         m_manager.dec_ref(k); | ||||
|         m_manager.dec_ref(v); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); | ||||
|     if (ef && ef->get_data().m_value != 0) { | ||||
|         m_manager.dec_ref(ef->get_data().m_key); | ||||
|         dealloc(ef->get_data().m_value); | ||||
|         auto k = ef->get_data().m_key; | ||||
|         auto v = ef->get_data().m_value; | ||||
|         m_finterp.remove(d); | ||||
|         m_func_decls.erase(d); | ||||
|         m_manager.dec_ref(k); | ||||
|         dealloc(v); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -192,10 +192,15 @@ namespace datalog { | |||
|             for (unsigned i = 0; i < new_tbvs.size(); ++i) { | ||||
|                 tbv const& nt = *new_tbvs[i]; | ||||
|                 IF_VERBOSE(10, m_tbv.display(verbose_stream() << "insert: ", nt); verbose_stream() << "\n";); | ||||
|                 if (contains(nt)) continue; | ||||
|                 ddnf_node* n = alloc(ddnf_node, *this, m_tbv, nt, m_noderefs.size()); | ||||
|                 m_noderefs.push_back(n); | ||||
|                 m_nodes.insert(n); | ||||
|                 ddnf_node* n; | ||||
|                 if (contains(nt)) { | ||||
|                     n = find(nt); | ||||
|                 } | ||||
|                 else { | ||||
|                     n = alloc(ddnf_node, *this, m_tbv, nt, m_noderefs.size()); | ||||
|                     m_noderefs.push_back(n); | ||||
|                     m_nodes.insert(n); | ||||
|                 } | ||||
|                 insert(*m_root, n, new_tbvs); | ||||
|             } | ||||
|             return find(t); | ||||
|  | @ -275,13 +280,17 @@ namespace datalog { | |||
|         void insert(ddnf_node& root, ddnf_node* new_n, ptr_vector<tbv const>& new_intersections) { | ||||
|             tbv const& new_tbv = new_n->get_tbv(); | ||||
|              | ||||
|             IF_VERBOSE(10, m_tbv.display(verbose_stream() << "root: ", root.get_tbv());  | ||||
|                        m_tbv.display(verbose_stream() << " new node ", new_tbv); verbose_stream() << "\n";); | ||||
|             SASSERT(m_tbv.contains(root.get_tbv(), new_tbv)); | ||||
|             if (&root == new_n) return; | ||||
|             if (m_eq(&root, new_n)) return; | ||||
|             ++m_stats.m_num_inserts; | ||||
|             bool inserted = false; | ||||
|             for (unsigned i = 0; i < root.num_children(); ++i) { | ||||
|                 ddnf_node& child = *(root[i]); | ||||
|                 ++m_stats.m_num_comparisons; | ||||
|                 IF_VERBOSE(10, m_tbv.display(verbose_stream() << "child ", child.get_tbv());  | ||||
|                            verbose_stream() << " contains: " << m_tbv.contains(child.get_tbv(), new_tbv) << "\n";); | ||||
|                 if (m_tbv.contains(child.get_tbv(), new_tbv)) { | ||||
|                     inserted = true; | ||||
|                     insert(child, new_n, new_intersections); | ||||
|  | @ -299,11 +308,13 @@ namespace datalog { | |||
|                 // checking for subset
 | ||||
|                 if (m_tbv.contains(new_tbv, child.get_tbv())) { | ||||
|                     subset_children.push_back(&child); | ||||
|                     IF_VERBOSE(10, m_tbv.display(verbose_stream() << "contains child", child.get_tbv()); verbose_stream() << "\n";); | ||||
|                     ++m_stats.m_num_comparisons; | ||||
|                 } | ||||
|                 else if (m_tbv.intersect(child.get_tbv(), new_tbv, *intr)) { | ||||
|                     // this means there is a non-full intersection
 | ||||
|                     new_intersections.push_back(intr); | ||||
|                     IF_VERBOSE(10, m_tbv.display(verbose_stream() << "intersect child ", child.get_tbv()); verbose_stream() << "\n";); | ||||
|                     intr = m_tbv.allocate(); | ||||
|                     m_stats.m_num_comparisons += 2; | ||||
|                 } | ||||
|  |  | |||
|  | @ -111,8 +111,8 @@ namespace datalog { | |||
| 
 | ||||
|         void filter_interpreted(app* cond) { | ||||
|             rational one(1), mone(-1); | ||||
|             expr* e1, *e2, *en; | ||||
|             var* v, *w; | ||||
|             expr* e1 = 0, *e2 = 0, *en = 0; | ||||
|             var* v = 0, *w = 0; | ||||
|             rational n1, n2; | ||||
|             expr_ref_vector conjs(m); | ||||
|             flatten_and(cond, conjs); | ||||
|  |  | |||
|  | @ -74,8 +74,7 @@ tbv* tbv_manager::allocate(tbv const& bv) { | |||
| } | ||||
| tbv* tbv_manager::allocate(uint64 val) { | ||||
|     tbv* v = allocate0(); | ||||
|     for (unsigned bit = num_tbits(); bit > 0;) { | ||||
|         --bit; | ||||
|     for (unsigned bit = std::min(64u, num_tbits()); bit-- > 0;) { | ||||
|         if (val & (1ULL << bit)) {                         | ||||
|             set(*v, bit, BIT_1); | ||||
|         } else { | ||||
|  |  | |||
|  | @ -398,8 +398,8 @@ namespace datalog { | |||
|     } | ||||
| 
 | ||||
|     bool mk_interp_tail_simplifier::propagate_variable_equivalences(rule * r, rule_ref& res) { | ||||
|       if (!m_context.get_params ().xform_tail_simplifier_pve ()) | ||||
|         return false; | ||||
|         if (!m_context.get_params ().xform_tail_simplifier_pve ()) | ||||
|             return false; | ||||
|         unsigned u_len = r->get_uninterpreted_tail_size(); | ||||
|         unsigned len = r->get_tail_size(); | ||||
|         if (u_len == len) { | ||||
|  |  | |||
|  | @ -124,7 +124,7 @@ namespace smt2 { | |||
|         next(); | ||||
|         bool is_float = false; | ||||
| 
 | ||||
|         while (true) { | ||||
|         while (!m_at_eof) { | ||||
|             char c = curr(); | ||||
|             if ('0' <= c && c <= '9') { | ||||
|                 m_number = rational(10)*m_number + rational(c - '0'); | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -79,7 +79,7 @@ namespace sat { | |||
|             void set_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; } | ||||
|             void update_literal(literal l) { m_lit = l; } | ||||
|             bool was_removed() const { return m_removed; } | ||||
|             void remove() { m_removed = true; } | ||||
|             void set_removed() { m_removed = true; } | ||||
|             void nullify_literal() { m_lit = null_literal; } | ||||
|             unsigned glue() const { return m_glue; } | ||||
|             void set_glue(unsigned g) { m_glue = g; }           | ||||
|  | @ -199,7 +199,7 @@ namespace sat { | |||
|             svector<uint64> m_coeffs; | ||||
|             uint64        m_k; | ||||
|             void reset(uint64 k) { m_lits.reset(); m_coeffs.reset(); m_k = k; } | ||||
|             void push(literal l, unsigned c) { m_lits.push_back(l); m_coeffs.push_back(c); } | ||||
|             void push(literal l, uint64 c) { m_lits.push_back(l); m_coeffs.push_back(c); } | ||||
|         }; | ||||
| 
 | ||||
|         solver*                m_solver; | ||||
|  | @ -286,7 +286,7 @@ namespace sat { | |||
|         void cleanup_constraints(); | ||||
|         void cleanup_constraints(ptr_vector<constraint>& cs, bool learned); | ||||
|         void ensure_external(constraint const& c); | ||||
|         void remove_constraint(constraint& c); | ||||
|         void remove_constraint(constraint& c, char const* reason); | ||||
| 
 | ||||
|         // constraints
 | ||||
|         constraint& index2constraint(size_t idx) const { return *reinterpret_cast<constraint*>(idx); }         | ||||
|  | @ -304,6 +304,7 @@ namespace sat { | |||
|         void nullify_tracking_literal(constraint& c); | ||||
|         void set_conflict(constraint& c, literal lit); | ||||
|         void assign(constraint& c, literal lit); | ||||
|         bool assigned_above(literal above, literal below); | ||||
|         void get_antecedents(literal l, constraint const& c, literal_vector & r); | ||||
|         bool validate_conflict(constraint const& c) const; | ||||
|         bool validate_unit_propagation(constraint const& c, literal alit) const; | ||||
|  | @ -368,7 +369,7 @@ namespace sat { | |||
|         inline watch_list const& get_wlist(literal l) const { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } | ||||
|         inline void assign(literal l, justification j) { if (m_lookahead) m_lookahead->assign(l); else m_solver->assign(l, j); } | ||||
|         inline void set_conflict(justification j, literal l) { if (m_lookahead) m_lookahead->set_conflict(); else m_solver->set_conflict(j, l); } | ||||
|         inline config const& get_config() const { return m_solver->get_config(); } | ||||
|         inline config const& get_config() const { return m_lookahead ? m_lookahead->get_config() : m_solver->get_config(); } | ||||
|         inline void drat_add(literal_vector const& c, svector<drat::premise> const& premises) { m_solver->m_drat.add(c, premises); } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -402,8 +403,13 @@ namespace sat { | |||
|         bool validate_watch_literals() const; | ||||
|         bool validate_watch_literal(literal lit) const; | ||||
|         bool validate_watched_constraint(constraint const& c) const; | ||||
|         bool validate_watch(pb const& p) const; | ||||
|         bool validate_watch(pb const& p, literal alit) const; | ||||
|         bool is_watching(literal lit, constraint const& c) const; | ||||
|         literal translate_to_sat(solver& s, u_map<bool_var>& translation, ineq const& pb); | ||||
|         literal translate_to_sat(solver& s, u_map<bool_var>& translation, ineq& a, ineq& b); | ||||
|         literal translate_to_sat(solver& s, u_map<bool_var>& translation, literal lit); | ||||
|         ineq negate(ineq const& a) const; | ||||
|         void push_lit(literal_vector& lits, literal lit); | ||||
| 
 | ||||
|         ineq m_A, m_B, m_C; | ||||
|         void active2pb(ineq& p); | ||||
|  | @ -422,6 +428,7 @@ namespace sat { | |||
|         constraint* add_pb_ge(literal l, svector<wliteral> const& wlits, unsigned k, bool learned); | ||||
|         constraint* add_xor(literal l, literal_vector const& lits, bool learned); | ||||
| 
 | ||||
|         void copy_core(ba_solver* result); | ||||
|     public: | ||||
|         ba_solver(); | ||||
|         virtual ~ba_solver(); | ||||
|  | @ -447,6 +454,7 @@ namespace sat { | |||
|         virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const; | ||||
|         virtual void collect_statistics(statistics& st) const; | ||||
|         virtual extension* copy(solver* s); | ||||
|         virtual extension* copy(lookahead* s); | ||||
|         virtual void find_mutexes(literal_vector& lits, vector<literal_vector> & mutexes); | ||||
|         virtual void pop_reinit(); | ||||
|         virtual void gc();  | ||||
|  |  | |||
|  | @ -272,7 +272,8 @@ namespace sat { | |||
|     void drat::verify(unsigned n, literal const* c) { | ||||
|         if (!is_drup(n, c) && !is_drat(n, c)) { | ||||
|             std::cout << "Verification failed\n"; | ||||
|             display(std::cout); | ||||
|             UNREACHABLE(); | ||||
|             //display(std::cout);
 | ||||
|             TRACE("sat",  | ||||
|                   tout << literal_vector(n, c) << "\n"; | ||||
|                   display(tout);  | ||||
|  |  | |||
|  | @ -96,17 +96,18 @@ namespace sat { | |||
|             if (!c.frozen()) | ||||
|                 m_solver.detach_clause(c); | ||||
|             // apply substitution
 | ||||
|             for (i = 0; i < sz; i++) { | ||||
|                 SASSERT(!m_solver.was_eliminated(c[i].var())); | ||||
|             for (i = 0; i < sz; i++) {                 | ||||
|                 c[i] = norm(roots, c[i]); | ||||
|                 VERIFY(!m_solver.was_eliminated(c[i].var())); | ||||
|             } | ||||
|             std::sort(c.begin(), c.end()); | ||||
|             for (literal l : c) VERIFY(l == norm(roots, l)); | ||||
|             TRACE("sats", tout << "after normalization/sorting: " << c << "\n"; tout.flush();); | ||||
|             DEBUG_CODE({ | ||||
|                 for (unsigned i = 0; i < sz; i++) { | ||||
|                     CTRACE("sats", c[i] != norm(roots, c[i]), tout << c[i] << " " << norm(roots, c[i]) << "\n"; tout.flush();); | ||||
|                     SASSERT(c[i] == norm(roots, c[i])); | ||||
|                 } }); | ||||
|                     for (literal l : c) { | ||||
|                         CTRACE("sat", l != norm(roots, l), tout << l << " " << norm(roots, l) << "\n"; tout.flush();); | ||||
|                         SASSERT(l == norm(roots, l)); | ||||
|                     } }); | ||||
|             // remove duplicates, and check if it is a tautology
 | ||||
|             literal l_prev = null_literal; | ||||
|             unsigned j = 0; | ||||
|  | @ -122,13 +123,11 @@ namespace sat { | |||
|                     break; // clause was satisfied
 | ||||
|                 if (val == l_false) | ||||
|                     continue; // skip
 | ||||
|                 if (i != j) { | ||||
|                     std::swap(c[i], c[j]); | ||||
|                 } | ||||
|                 c[j] = l;                 | ||||
|                 j++; | ||||
|             } | ||||
|             if (i < sz) { | ||||
|                 // clause is a tautology or was simplified
 | ||||
|                 // clause is a tautology or was simplified to true
 | ||||
|                 m_solver.del_clause(c); | ||||
|                 continue;  | ||||
|             } | ||||
|  | @ -164,10 +163,7 @@ namespace sat { | |||
|                 else | ||||
|                     c.update_approx(); | ||||
| 
 | ||||
|                 DEBUG_CODE({ | ||||
|                         for (unsigned i = 0; i < j; i++) { | ||||
|                             SASSERT(c[i] == norm(roots, c[i])); | ||||
|                         } }); | ||||
|                 DEBUG_CODE(for (literal l : c) VERIFY(l == norm(roots, l));); | ||||
|                  | ||||
|                 *it2 = *it; | ||||
|                 it2++; | ||||
|  | @ -187,7 +183,6 @@ namespace sat { | |||
|             literal r  = roots[v]; | ||||
|             SASSERT(v != r.var()); | ||||
|             if (m_solver.is_external(v) && !m_solver.set_root(l, r)) { | ||||
|                 std::cout << "skip: " << l << " == " << r << "\n"; | ||||
|                 // cannot really eliminate v, since we have to notify extension of future assignments
 | ||||
|                 m_solver.mk_bin_clause(~l, r, false); | ||||
|                 m_solver.mk_bin_clause(l, ~r, false); | ||||
|  | @ -199,29 +194,33 @@ namespace sat { | |||
|                 mc.insert(e, ~l, r); | ||||
|                 mc.insert(e,  l, ~r); | ||||
|             } | ||||
|             m_solver.flush_roots(); | ||||
|         } | ||||
|         m_solver.flush_roots(); | ||||
|     } | ||||
| 
 | ||||
|     bool elim_eqs::check_clauses(literal_vector const & roots) const { | ||||
|         clause_vector * vs[2] = { &m_solver.m_clauses, &m_solver.m_learned }; | ||||
|         for (unsigned i = 0; i < 2; i++) { | ||||
|             clause_vector & cs  = *(vs[i]); | ||||
|             clause_vector::iterator it  = cs.begin(); | ||||
|             clause_vector::iterator end = cs.end(); | ||||
|             for (; it != end; ++it) { | ||||
|                 clause & c  = *(*it); | ||||
|                 unsigned sz = c.size(); | ||||
|                 for (unsigned i = 0; i < sz; i++) { | ||||
|                     CTRACE("elim_eqs_bug", m_solver.was_eliminated(c[i].var()), tout << "lit: " << c[i] << " " << norm(roots, c[i]) << "\n"; | ||||
|                            tout << c << "\n";); | ||||
|                     SASSERT(!m_solver.was_eliminated(c[i].var())); | ||||
|                 } | ||||
|     bool elim_eqs::check_clause(clause const& c, literal_vector const& roots) const { | ||||
|         for (literal l : c) { | ||||
|             CTRACE("elim_eqs_bug", m_solver.was_eliminated(l.var()), tout << "lit: " << l << " " << norm(roots, l) << "\n"; | ||||
|                    tout << c << "\n";); | ||||
|             if (m_solver.was_eliminated(l.var())) { | ||||
|                 IF_VERBOSE(0, verbose_stream() << c << " contains eliminated literal " << l << " " << norm(roots, l) << "\n";); | ||||
|                 UNREACHABLE(); | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     bool elim_eqs::check_clauses(literal_vector const & roots) const { | ||||
|         for (clause * cp : m_solver.m_clauses) | ||||
|             if (!check_clause(*cp, roots))  | ||||
|                 return false; | ||||
|         for (clause * cp : m_solver.m_learned) | ||||
|             if (!check_clause(*cp, roots))  | ||||
|                 return false; | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     void elim_eqs::operator()(literal_vector const & roots, bool_var_vector const & to_elim) { | ||||
|         cleanup_bin_watches(roots); | ||||
|         TRACE("elim_eqs", tout << "after bin cleanup\n"; m_solver.display(tout);); | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ namespace sat { | |||
|         void cleanup_clauses(literal_vector const & roots, clause_vector & cs); | ||||
|         void cleanup_bin_watches(literal_vector const & roots); | ||||
|         bool check_clauses(literal_vector const & roots) const; | ||||
|         bool check_clause(clause const& c, literal_vector const& roots) const; | ||||
|     public: | ||||
|         elim_eqs(solver & s); | ||||
|         void operator()(literal_vector const & roots, bool_var_vector const & to_elim); | ||||
|  |  | |||
|  | @ -71,6 +71,7 @@ namespace sat { | |||
|         virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0; | ||||
|         virtual void collect_statistics(statistics& st) const = 0; | ||||
|         virtual extension* copy(solver* s) = 0;        | ||||
|         virtual extension* copy(lookahead* s) = 0;        | ||||
|         virtual void find_mutexes(literal_vector& lits, vector<literal_vector> & mutexes) = 0; | ||||
|         virtual void gc() = 0; | ||||
|         virtual void pop_reinit() = 0; | ||||
|  |  | |||
|  | @ -92,7 +92,7 @@ namespace sat { | |||
|         // TRACE("sat", display(tout << "Delete " << to_literal(idx) << "\n"););
 | ||||
|         literal_vector & lits = m_binary[idx]; | ||||
|         SASSERT(!lits.empty()); | ||||
|         literal l = lits.back();			 | ||||
|         literal l = lits.back(); | ||||
|         lits.pop_back();             | ||||
|         SASSERT(!m_binary[(~l).index()].empty()); | ||||
|         IF_VERBOSE(0, if (m_binary[(~l).index()].back() != ~to_literal(idx)) verbose_stream() << "pop bad literal: " << idx << " " << (~l).index() << "\n";); | ||||
|  | @ -112,7 +112,6 @@ namespace sat { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void lookahead::inc_bstamp() { | ||||
|         ++m_bstamp_id; | ||||
|         if (m_bstamp_id == 0) { | ||||
|  | @ -120,6 +119,7 @@ namespace sat { | |||
|             m_bstamp.fill(0); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void lookahead::inc_istamp() { | ||||
|         ++m_istamp_id; | ||||
|         if (m_istamp_id == 0) { | ||||
|  | @ -204,13 +204,13 @@ namespace sat { | |||
|      | ||||
| 
 | ||||
|     void lookahead::pre_select() { | ||||
|         IF_VERBOSE(10, verbose_stream() << "freevars: " << m_freevars.size() << "\n";); | ||||
|         m_lookahead.reset(); | ||||
|         for (bool_var x : m_freevars) { // tree lookahead may leave some literals fixed in lower truth levels
 | ||||
|         for (bool_var x : m_freevars) { // tree lookahead leaves literals fixed in lower truth levels
 | ||||
|             literal l(x, false); | ||||
|             set_undef(l); | ||||
|             set_undef(~l); | ||||
|         } | ||||
| //printf("m_freevars.size() = %d\n", m_freevars.size());
 | ||||
|         if (select(scope_lvl())) { | ||||
|             get_scc(); | ||||
|             if (inconsistent()) return; | ||||
|  | @ -276,6 +276,7 @@ namespace sat { | |||
|                 sift_down(0, i); | ||||
|             } | ||||
|         } | ||||
|         SASSERT(validate_heap_sort()); | ||||
|     } | ||||
| 
 | ||||
|     void lookahead::heapify() { | ||||
|  | @ -299,6 +300,17 @@ namespace sat { | |||
|         if (i > j) m_candidates[i] = c; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * \brief validate that the result of heap sort sorts the candidates | ||||
|      * in descending order of their rating. | ||||
|      */ | ||||
|     bool lookahead::validate_heap_sort() { | ||||
|         for (unsigned i = 0; i + 1 < m_candidates.size(); ++i) | ||||
|             if (m_candidates[i].m_rating < m_candidates[i + 1].m_rating)  | ||||
|                 return false; | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     double lookahead::init_candidates(unsigned level, bool newbies) { | ||||
|         m_candidates.reset(); | ||||
|         double sum = 0; | ||||
|  | @ -328,25 +340,14 @@ namespace sat { | |||
|     } | ||||
| 
 | ||||
|     bool lookahead::is_unsat() const { | ||||
|         bool all_false = true; | ||||
|         bool first = true; | ||||
|         // check if there is a clause whose literals are false.
 | ||||
|         // every clause is terminated by a null-literal.
 | ||||
|         for (unsigned l_idx : m_nary_literals) { | ||||
|             literal l = to_literal(l_idx); | ||||
|             if (first) { | ||||
|                 // skip the first entry, the length indicator.
 | ||||
|                 first = false; | ||||
|             } | ||||
|             else if (l == null_literal) { | ||||
|                 // when reaching the end of a clause check if all entries are false
 | ||||
|                 if (all_false) return true; | ||||
|                 all_false = true; | ||||
|                 first = true; | ||||
|             } | ||||
|             else { | ||||
|         for (nary* n : m_nary_clauses) { | ||||
|             bool all_false = true; | ||||
|             for (literal l : *n) { | ||||
|                 all_false &= is_false(l); | ||||
|             } | ||||
|             if (all_false) return true; | ||||
|         } | ||||
|         // check if there is a ternary whose literals are false.
 | ||||
|         for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { | ||||
|  | @ -382,24 +383,14 @@ namespace sat { | |||
|                 } | ||||
|             } | ||||
|         } | ||||
|         bool no_true = true; | ||||
|         bool first = true; | ||||
|         // check if there is a clause whose literals are false.
 | ||||
|         // every clause is terminated by a null-literal.
 | ||||
|         for (unsigned l_idx : m_nary_literals) { | ||||
|             literal l = to_literal(l_idx); | ||||
|             if (first) { | ||||
|                 // skip the first entry, the length indicator.
 | ||||
|                 first = false; | ||||
|             } | ||||
|             else if (l == null_literal) { | ||||
|                 if (no_true) return false; | ||||
|                 no_true = true; | ||||
|                 first = true; | ||||
|             } | ||||
|             else { | ||||
|         for (nary * n : m_nary_clauses) { | ||||
|             bool no_true = true; | ||||
|             for (literal l : *n) { | ||||
|                 no_true &= !is_true(l); | ||||
|             } | ||||
|             if (no_true) return false; | ||||
|         } | ||||
|         // check if there is a ternary whose literals are false.
 | ||||
|         for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { | ||||
|  | @ -476,17 +467,15 @@ namespace sat { | |||
|             sum += (literal_occs(b.m_u) + literal_occs(b.m_v)) / 8.0;             | ||||
|         } | ||||
|         sz = m_nary_count[(~l).index()]; | ||||
|         for (unsigned idx : m_nary[(~l).index()]) { | ||||
|         for (nary * n : m_nary[(~l).index()]) { | ||||
|             if (sz-- == 0) break; | ||||
|             literal lit; | ||||
|             unsigned j = idx; | ||||
|             double to_add = 0; | ||||
|             while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { | ||||
|             for (literal lit : *n) { | ||||
|                 if (!is_fixed(lit) && lit != ~l) { | ||||
|                     to_add += literal_occs(lit); | ||||
|                 } | ||||
|             } | ||||
|             unsigned len = m_nary_literals[idx]; | ||||
|             unsigned len = n->size(); | ||||
|             sum += pow(0.5, len) * to_add / len;             | ||||
|         } | ||||
|         return sum; | ||||
|  | @ -507,9 +496,9 @@ namespace sat { | |||
|         } | ||||
|         sum += 0.25 * m_ternary_count[(~l).index()]; | ||||
|         unsigned sz = m_nary_count[(~l).index()]; | ||||
|         for (unsigned cls_idx : m_nary[(~l).index()]) { | ||||
|         for (nary * n : m_nary[(~l).index()]) { | ||||
|             if (sz-- == 0) break; | ||||
|             sum += pow(0.5, m_nary_literals[cls_idx]); | ||||
|             sum += pow(0.5, n->size()); | ||||
|         } | ||||
|         return sum; | ||||
|     } | ||||
|  | @ -616,18 +605,18 @@ namespace sat { | |||
|     void lookahead::init_arcs(literal l) { | ||||
|         literal_vector lits; | ||||
|         literal_vector const& succ = m_binary[l.index()]; | ||||
|         for (unsigned i = 0; i < succ.size(); ++i) { | ||||
|             literal u = succ[i]; | ||||
|         for (literal u : succ) { | ||||
|             SASSERT(u != l); | ||||
|             // l => u
 | ||||
|             if (u.index() > l.index() && is_stamped(u)) { | ||||
|                 add_arc(~l, ~u); | ||||
|                 add_arc( u,  l); | ||||
|             } | ||||
|         } | ||||
|         for (auto w : m_watches[l.index()]) { | ||||
|             if (w.is_ext_constraint() && m_s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), lits)) { | ||||
|             if (w.is_ext_constraint() && m_s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), lits)) {  | ||||
|                 for (literal u : lits) { | ||||
|                     if (u.index() > l.index() && is_stamped(u)) { | ||||
|                     if (u.index() > (~l).index() && is_stamped(u)) { | ||||
|                         add_arc(~l, ~u); | ||||
|                         add_arc( u,  l); | ||||
|                     } | ||||
|  | @ -901,8 +890,8 @@ namespace sat { | |||
|         m_ternary.push_back(svector<binary>()); | ||||
|         m_ternary_count.push_back(0); | ||||
|         m_ternary_count.push_back(0); | ||||
|         m_nary.push_back(unsigned_vector()); | ||||
|         m_nary.push_back(unsigned_vector()); | ||||
|         m_nary.push_back(ptr_vector<nary>()); | ||||
|         m_nary.push_back(ptr_vector<nary>()); | ||||
|         m_nary_count.push_back(0); | ||||
|         m_nary_count.push_back(0); | ||||
|         m_bstamp.push_back(0); | ||||
|  | @ -958,14 +947,8 @@ namespace sat { | |||
|             } | ||||
|         } | ||||
|          | ||||
|         // copy externals:
 | ||||
|         for (unsigned idx = 0; idx < m_s.m_watches.size(); ++idx) { | ||||
|             watch_list const& wl = m_s.m_watches[idx]; | ||||
|             for (watched const& w : wl) { | ||||
|                 if (w.is_ext_constraint()) { | ||||
|                     m_watches[idx].push_back(w); | ||||
|                 } | ||||
|             } | ||||
|         if (m_s.m_ext) { | ||||
|             m_ext = m_s.m_ext->copy(this); | ||||
|         } | ||||
|         propagate(); | ||||
|         m_qhead = m_trail.size(); | ||||
|  | @ -1328,17 +1311,14 @@ namespace sat { | |||
|     // new n-ary clause managment
 | ||||
| 
 | ||||
|     void lookahead::add_clause(clause const& c) { | ||||
|         unsigned sz = c.size();         | ||||
|         SASSERT(sz > 3); | ||||
|         unsigned idx = m_nary_literals.size(); | ||||
|         m_nary_literals.push_back(sz); | ||||
|         SASSERT(c.size() > 3); | ||||
|         void * mem = m_allocator.allocate(nary::get_obj_size(c.size())); | ||||
|         nary * n = new (mem) nary(c.size(), c.begin()); | ||||
|         m_nary_clauses.push_back(n); | ||||
|         for (literal l : c) { | ||||
|             m_nary_literals.push_back(l.index()); | ||||
|             m_nary[l.index()].push_back(n); | ||||
|             m_nary_count[l.index()]++; | ||||
|             m_nary[l.index()].push_back(idx); | ||||
|             SASSERT(m_nary_count[l.index()] == m_nary[l.index()].size()); | ||||
|         } | ||||
|         m_nary_literals.push_back(null_literal.index());         | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -1347,18 +1327,17 @@ namespace sat { | |||
|         unsigned sz = m_nary_count[(~l).index()]; | ||||
|         literal lit; | ||||
|         SASSERT(m_search_mode == lookahead_mode::searching); | ||||
|         for (unsigned idx : m_nary[(~l).index()]) { | ||||
|         for (nary * n : m_nary[(~l).index()]) { | ||||
|             if (sz-- == 0) break; | ||||
|             unsigned len = --m_nary_literals[idx]; | ||||
|             unsigned len = n->dec_size(); | ||||
|             if (m_inconsistent) continue; | ||||
|             if (len <= 1) continue; // already processed
 | ||||
|             // find the two unassigned literals, if any
 | ||||
|             if (len == 2) { | ||||
|                 literal l1 = null_literal; | ||||
|                 literal l2 = null_literal; | ||||
|                 unsigned j = idx; | ||||
|                 bool found_true = false; | ||||
|                 while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { | ||||
|                 for (literal lit : *n) { | ||||
|                     if (!is_fixed(lit)) { | ||||
|                         if (l1 == null_literal) { | ||||
|                             l1 = lit; | ||||
|  | @ -1370,7 +1349,7 @@ namespace sat { | |||
|                         } | ||||
|                     } | ||||
|                     else if (is_true(lit)) { | ||||
|                         // can't swap with idx. std::swap(m_nary_literals[j], m_nary_literals[idx]);
 | ||||
|                         n->set_head(lit); | ||||
|                         found_true = true; | ||||
|                         break; | ||||
|                     } | ||||
|  | @ -1398,9 +1377,9 @@ namespace sat { | |||
|         } | ||||
|         // clauses where l is positive:
 | ||||
|         sz = m_nary_count[l.index()]; | ||||
|         for (unsigned idx : m_nary[l.index()]) { | ||||
|         for (nary* n : m_nary[l.index()]) { | ||||
|             if (sz-- == 0) break; | ||||
|             remove_clause_at(l, idx); | ||||
|             remove_clause_at(l, *n); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -1411,14 +1390,17 @@ namespace sat { | |||
|         SASSERT(m_search_mode == lookahead_mode::lookahead1 || | ||||
|                 m_search_mode == lookahead_mode::lookahead2); | ||||
|          | ||||
|         for (unsigned idx : m_nary[(~l).index()]) { | ||||
|         for (nary* n : m_nary[(~l).index()]) { | ||||
|             if (sz-- == 0) break; | ||||
| 
 | ||||
|             if (is_true(n->get_head())) { | ||||
|                 continue; | ||||
|             } | ||||
|             literal l1 = null_literal; | ||||
|             literal l2 = null_literal; | ||||
|             unsigned j = idx; | ||||
|             bool found_true = false; | ||||
|             bool skip_clause = false; | ||||
|             unsigned nonfixed = 0; | ||||
|             while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { | ||||
|             for (literal lit : *n) { | ||||
|                 if (!is_fixed(lit)) { | ||||
|                     ++nonfixed; | ||||
|                     if (l1 == null_literal) { | ||||
|  | @ -1427,14 +1409,19 @@ namespace sat { | |||
|                     else if (l2 == null_literal) { | ||||
|                         l2 = lit; | ||||
|                     } | ||||
|                     else if (m_search_mode == lookahead_mode::lookahead2) { | ||||
|                         skip_clause = true; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|                 else if (is_true(lit)) { | ||||
|                     found_true = true; | ||||
|                     n->set_head(lit); | ||||
|                     skip_clause = true; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             if (found_true) { | ||||
|                 // skip, the clause will be removed when propagating on 'lit'
 | ||||
|             if (skip_clause) { | ||||
|                 // skip, the clause 
 | ||||
|             } | ||||
|             else if (l1 == null_literal) { | ||||
|                 set_conflict(); | ||||
|  | @ -1443,20 +1430,16 @@ namespace sat { | |||
|             else if (l2 == null_literal) { | ||||
|                 propagated(l1); | ||||
|             } | ||||
|             else if (m_search_mode == lookahead_mode::lookahead2) { | ||||
|                 continue; | ||||
|             } | ||||
|             else { | ||||
|                 SASSERT(nonfixed >= 2); | ||||
|                 SASSERT(m_search_mode == lookahead_mode::lookahead1); | ||||
|                 switch (m_config.m_reward_type) { | ||||
|                 case heule_schur_reward: { | ||||
|                     j = idx; | ||||
|                     double to_add = 0; | ||||
|                     while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { | ||||
|                     for (literal lit : *n) { | ||||
|                         if (!is_fixed(lit)) { | ||||
|                             to_add += literal_occs(lit); | ||||
|                         } | ||||
|                         }                         | ||||
|                     } | ||||
|                     m_lookahead_reward += pow(0.5, nonfixed) * to_add / nonfixed;                     | ||||
|                     break; | ||||
|  | @ -1464,9 +1447,6 @@ namespace sat { | |||
|                 case heule_unit_reward: | ||||
|                     m_lookahead_reward += pow(0.5, nonfixed); | ||||
|                     break; | ||||
|                 case march_cu_reward: | ||||
|                     m_lookahead_reward += 3.3 * pow(0.5, nonfixed - 2); | ||||
|                     break; | ||||
|                 case ternary_reward: | ||||
|                     if (nonfixed == 2) { | ||||
|                         m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; | ||||
|  | @ -1482,23 +1462,20 @@ namespace sat { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void lookahead::remove_clause_at(literal l, unsigned clause_idx) { | ||||
|         unsigned j = clause_idx; | ||||
|         literal lit; | ||||
|         while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { | ||||
|     void lookahead::remove_clause_at(literal l, nary& n) { | ||||
|         for (literal lit : n) { | ||||
|             if (lit != l) { | ||||
|                 remove_clause(lit, clause_idx); | ||||
|                 remove_clause(lit, n); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void lookahead::remove_clause(literal l, unsigned clause_idx) { | ||||
|         unsigned_vector& pclauses = m_nary[l.index()]; | ||||
|     void lookahead::remove_clause(literal l, nary& n) { | ||||
|         ptr_vector<nary>& pclauses = m_nary[l.index()]; | ||||
|         unsigned sz = m_nary_count[l.index()]--; | ||||
|         for (unsigned i = sz; i > 0; ) { | ||||
|             --i; | ||||
|             if (clause_idx == pclauses[i]) { | ||||
|             if (&n == pclauses[i]) { | ||||
|                 std::swap(pclauses[i], pclauses[sz-1]); | ||||
|                 return; | ||||
|             } | ||||
|  | @ -1508,33 +1485,29 @@ namespace sat { | |||
| 
 | ||||
|     void lookahead::restore_clauses(literal l) { | ||||
|         SASSERT(m_search_mode == lookahead_mode::searching); | ||||
| 
 | ||||
|         // increase the length of clauses where l is negative
 | ||||
|         unsigned sz = m_nary_count[(~l).index()]; | ||||
|         for (unsigned idx : m_nary[(~l).index()]) { | ||||
|         for (nary* n : m_nary[(~l).index()]) { | ||||
|             if (sz-- == 0) break; | ||||
|             ++m_nary_literals[idx];  | ||||
|             n->inc_size(); | ||||
|         } | ||||
| 
 | ||||
|         // add idx back to clause list where l is positive
 | ||||
|         // add them back in the same order as they were inserted
 | ||||
|         // in this way we can check that the clauses are the same.
 | ||||
|         sz = m_nary_count[l.index()]; | ||||
|         unsigned_vector const& pclauses = m_nary[l.index()]; | ||||
|         for (unsigned i = sz; i > 0; ) { | ||||
|             --i; | ||||
|             unsigned j = pclauses[i]; | ||||
|             literal lit; | ||||
|             while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { | ||||
|         ptr_vector<nary>& pclauses = m_nary[l.index()]; | ||||
|         for (unsigned i = sz; i-- > 0; ) { | ||||
|             for (literal lit : *pclauses[i]) { | ||||
|                 if (lit != l) { | ||||
|                     SASSERT(m_nary[lit.index()][m_nary_count[lit.index()]] == pclauses[i]); | ||||
|                     m_nary_count[lit.index()]++; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         }         | ||||
|     } | ||||
| 
 | ||||
|     void lookahead::propagate_clauses(literal l) { | ||||
|         SASSERT(is_true(l)); | ||||
|         propagate_ternary(l); | ||||
|         switch (m_search_mode) { | ||||
|         case lookahead_mode::searching: | ||||
|  | @ -1545,9 +1518,7 @@ namespace sat { | |||
|             break; | ||||
|         } | ||||
|         propagate_external(l); | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     }    | ||||
| 
 | ||||
|     void lookahead::update_binary_clause_reward(literal l1, literal l2) { | ||||
|         SASSERT(!is_false(l1)); | ||||
|  | @ -1610,7 +1581,6 @@ namespace sat { | |||
|     // FIXME: counts occurences of ~l; misleading
 | ||||
|     double lookahead::literal_occs(literal l) { | ||||
|         double result = m_binary[l.index()].size(); | ||||
|         //unsigned_vector const& nclauses = m_nary[(~l).index()];
 | ||||
|         result += literal_big_occs(l); | ||||
|         return result; | ||||
|     } | ||||
|  | @ -1651,12 +1621,18 @@ namespace sat { | |||
|         TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); | ||||
|     } | ||||
| 
 | ||||
| #define CHECK_FAILED_LITERAL 0 | ||||
| 
 | ||||
|     void lookahead::compute_lookahead_reward() { | ||||
|         TRACE("sat", display_lookahead(tout); ); | ||||
|         m_delta_decrease = pow(m_config.m_delta_rho, 1.0 / (double)m_lookahead.size()); | ||||
|         unsigned base = 2; | ||||
|         bool change = true; | ||||
|         literal last_changed = null_literal; | ||||
| #if CHECK_FAILED_LITERAL | ||||
|         unsigned_vector assigns; | ||||
|         literal_vector assigns_lits; | ||||
| #endif | ||||
|         while (change && !inconsistent()) { | ||||
|             change = false; | ||||
|             for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { | ||||
|  | @ -1677,7 +1653,6 @@ namespace sat { | |||
|                 reset_lookahead_reward(lit); | ||||
|                 unsigned num_units = push_lookahead1(lit, level); | ||||
|                 update_lookahead_reward(lit, level); | ||||
|                 unsigned old_trail_sz = m_trail.size(); | ||||
|                 unsigned dl_lvl = level; | ||||
|                 num_units += do_double(lit, dl_lvl); | ||||
|                 if (dl_lvl > level) { | ||||
|  | @ -1688,6 +1663,10 @@ namespace sat { | |||
|                 if (unsat) { | ||||
|                     TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); | ||||
|                     lookahead_backtrack(); | ||||
| #if CHECK_FAILED_LITERAL | ||||
|                     assigns.push_back(m_trail.size()); | ||||
|                     assigns_lits.push_back(~lit); | ||||
| #endif | ||||
|                     assign(~lit); | ||||
|                     propagate(); | ||||
|                     change = true; | ||||
|  | @ -1701,6 +1680,12 @@ namespace sat { | |||
|             base += 2 * m_lookahead.size(); | ||||
|         } | ||||
|         lookahead_backtrack(); | ||||
| #if CHECK_FAILED_LITERAL | ||||
|         for (unsigned i = 0; i < assigns.size(); ++i) { | ||||
|             std::cout << "check trail: " << m_trail[assigns[i]] << " " << assigns_lits[i] << "\n"; | ||||
|             VERIFY(m_trail[assigns[i]] == assigns_lits[i]); | ||||
|         } | ||||
| #endif | ||||
|         TRACE("sat", display_lookahead(tout); ); | ||||
|     } | ||||
| 
 | ||||
|  | @ -1754,7 +1739,7 @@ namespace sat { | |||
|         return false; | ||||
| #if 0 | ||||
|         // no propagations are allowed to reduce clauses.
 | ||||
|         for (clause * cp : m_full_watches[l.index()]) { | ||||
|         for (nary * cp : m_nary[(~l).index()]) { | ||||
|             clause& c = *cp; | ||||
|             unsigned sz = c.size(); | ||||
|             bool found = false;                 | ||||
|  | @ -1993,8 +1978,10 @@ namespace sat { | |||
| 
 | ||||
|     lbool lookahead::cube() { | ||||
|         literal_vector lits; | ||||
|         bool_var_vector vars; | ||||
|         for (bool_var v : m_freevars) vars.push_back(v); | ||||
|         while (true) { | ||||
|             lbool result = cube(lits); | ||||
|             lbool result = cube(vars, lits); | ||||
|             if (lits.empty() || result != l_undef) { | ||||
|                 return l_undef; | ||||
|             } | ||||
|  | @ -2003,8 +1990,13 @@ namespace sat { | |||
|         return l_undef; | ||||
|     } | ||||
| 
 | ||||
|     lbool lookahead::cube(literal_vector& lits) { | ||||
|     lbool lookahead::cube(bool_var_vector const& vars, literal_vector& lits) { | ||||
|         scoped_ext _scoped_ext(*this); | ||||
|         lits.reset(); | ||||
|         m_select_lookahead_vars.reset(); | ||||
|         for (auto v : vars) { | ||||
|             m_select_lookahead_vars.insert(v); | ||||
|         } | ||||
|         bool is_first = m_cube_state.m_first; | ||||
|         if (is_first) { | ||||
|             init_search(); | ||||
|  | @ -2111,20 +2103,9 @@ namespace sat { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for (unsigned l_idx : m_nary_literals) { | ||||
|             literal l = to_literal(l_idx); | ||||
|             if (first) { | ||||
|                 // the first entry is a length indicator of non-false literals.
 | ||||
|                 out << l_idx << ": "; | ||||
|                 first = false; | ||||
|             } | ||||
|             else if (l == null_literal) { | ||||
|                 first = true; | ||||
|                 out << "\n"; | ||||
|             } | ||||
|             else { | ||||
|                 out << l << " "; | ||||
|             } | ||||
|         for (nary * n : m_nary_clauses) { | ||||
|             for (literal l : *n) out << l << " "; | ||||
|             out << "\n"; | ||||
|         } | ||||
| 
 | ||||
|         return out; | ||||
|  | @ -2219,6 +2200,7 @@ namespace sat { | |||
|        \brief simplify set of clauses by extracting units from a lookahead at base level. | ||||
|     */ | ||||
|     void lookahead::simplify() { | ||||
|         scoped_ext _scoped_ext(*this); | ||||
|         SASSERT(m_prefix == 0); | ||||
|         SASSERT(m_watches.empty()); | ||||
|         m_search_mode = lookahead_mode::searching; | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ Notes: | |||
| #ifndef _SAT_LOOKAHEAD_H_ | ||||
| #define _SAT_LOOKAHEAD_H_ | ||||
| 
 | ||||
| // #define OLD_NARY 0
 | ||||
| 
 | ||||
| #include "sat_elim_eqs.h" | ||||
| 
 | ||||
|  | @ -89,8 +90,7 @@ namespace sat { | |||
|                 m_min_cutoff = 30; | ||||
|                 m_preselect = false; | ||||
|                 m_level_cand = 600; | ||||
|                 //m_delta_rho = (double)0.25;
 | ||||
|                 m_delta_rho = (double)0.5; | ||||
|                 m_delta_rho = (double)0.25; | ||||
|                 m_dl_max_iterations = 2; | ||||
|                 m_tc1_limit = 10000000; | ||||
|                 m_reward_type = ternary_reward; | ||||
|  | @ -132,6 +132,36 @@ namespace sat { | |||
|             literal m_u, m_v; | ||||
|         }; | ||||
| 
 | ||||
|         class nary {             | ||||
|             unsigned m_size;         // number of non-false literals
 | ||||
|             size_t   m_obj_size;     // object size (counting all literals)
 | ||||
|             literal  m_head;         // head literal
 | ||||
|             literal  m_literals[0];  // list of literals, put any true literal in head.
 | ||||
|             size_t num_lits() const { | ||||
|                 return (m_obj_size - sizeof(nary)) / sizeof(literal); | ||||
|             } | ||||
|         public: | ||||
|             static size_t get_obj_size(unsigned sz) { return sizeof(nary) + sz * sizeof(literal); } | ||||
|             size_t obj_size() const { return m_obj_size; } | ||||
|             nary(unsigned sz, literal const* lits): | ||||
|                 m_size(sz), | ||||
|                 m_obj_size(get_obj_size(sz)) { | ||||
|                 for (unsigned i = 0; i < sz; ++i) m_literals[i] = lits[i]; | ||||
|                 m_head = lits[0]; | ||||
|             } | ||||
|             unsigned size() const { return m_size; } | ||||
|             unsigned dec_size() { SASSERT(m_size > 0); return --m_size; } | ||||
|             void inc_size() { SASSERT(m_size < num_lits()); ++m_size; } | ||||
|             literal get_head() const { return m_head; } | ||||
|             void set_head(literal l) { m_head = l; } | ||||
| 
 | ||||
|             literal operator[](unsigned i) { SASSERT(i < num_lits()); return m_literals[i]; } | ||||
|             literal const* begin() const { return m_literals; } | ||||
|             literal const* end() const { return m_literals + num_lits(); } | ||||
|             // swap the true literal to the head.
 | ||||
|             // void swap(unsigned i, unsigned j) { SASSERT(i < num_lits() && j < num_lits()); std::swap(m_literals[i], m_literals[j]); }
 | ||||
|         }; | ||||
| 
 | ||||
|         struct cube_state { | ||||
|             bool           m_first; | ||||
|             svector<bool>  m_is_decision; | ||||
|  | @ -164,10 +194,10 @@ namespace sat { | |||
|         vector<svector<binary>> m_ternary;        // lit |-> vector of ternary clauses
 | ||||
|         unsigned_vector         m_ternary_count;  // lit |-> current number of active ternary clauses for lit
 | ||||
| 
 | ||||
|         vector<unsigned_vector> m_nary;           // lit |-> vector of clause_id
 | ||||
|         unsigned_vector         m_nary_count;     // lit |-> number of valid clause_id in m_clauses2[lit]
 | ||||
|         unsigned_vector         m_nary_literals;  // the actual literals, clauses start at offset clause_id, 
 | ||||
|                                                   // the first entry is the current length, clauses are separated by a null_literal
 | ||||
|         small_object_allocator    m_allocator; | ||||
|         vector<ptr_vector<nary>>  m_nary;        // lit |-> vector of nary clauses
 | ||||
|         ptr_vector<nary>          m_nary_clauses; // vector of all nary clauses
 | ||||
|         unsigned_vector           m_nary_count;     // lit |-> number of valid clause_id in m_nary[lit]
 | ||||
| 
 | ||||
|         unsigned               m_num_tc1; | ||||
|         unsigned_vector        m_num_tc1_lim; | ||||
|  | @ -196,6 +226,7 @@ namespace sat { | |||
|         stats                  m_stats; | ||||
|         model                  m_model;  | ||||
|         cube_state             m_cube_state; | ||||
|         scoped_ptr<extension>   m_ext; | ||||
|   | ||||
|         // ---------------------------------------
 | ||||
|         // truth values
 | ||||
|  | @ -293,10 +324,10 @@ namespace sat { | |||
|         double get_rating(bool_var v) const { return m_rating[v]; } | ||||
|         double get_rating(literal l) const { return get_rating(l.var()); } | ||||
|         bool select(unsigned level); | ||||
|         //void sift_up(unsigned j);
 | ||||
|         void heap_sort(); | ||||
|         void heapify(); | ||||
|         void heapify();         | ||||
|         void sift_down(unsigned j, unsigned sz); | ||||
|         bool validate_heap_sort(); | ||||
|         double init_candidates(unsigned level, bool newbies); | ||||
|         std::ostream& display_candidates(std::ostream& out) const; | ||||
|         bool is_unsat() const; | ||||
|  | @ -419,15 +450,15 @@ namespace sat { | |||
|         void propagate_clauses_searching(literal l); | ||||
|         void propagate_clauses_lookahead(literal l); | ||||
|         void restore_clauses(literal l); | ||||
|         void remove_clause(literal l, unsigned clause_idx); | ||||
|         void remove_clause_at(literal l, unsigned clause_idx); | ||||
| 
 | ||||
|         void remove_clause(literal l, nary& n); | ||||
|         void remove_clause_at(literal l, nary& n); | ||||
|         // ------------------------------------
 | ||||
|         // initialization
 | ||||
|          | ||||
|         void init_var(bool_var v); | ||||
|         void init(); | ||||
|         void copy_clauses(clause_vector const& clauses, bool learned); | ||||
|         nary * copy_clause(clause const& c); | ||||
| 
 | ||||
|         // ------------------------------------
 | ||||
|         // search
 | ||||
|  | @ -510,6 +541,9 @@ namespace sat { | |||
| 
 | ||||
|         ~lookahead() { | ||||
|             m_s.rlimit().pop_child(); | ||||
|             for (nary* n : m_nary_clauses) {  | ||||
|                 m_allocator.deallocate(n->obj_size(), n); | ||||
|             } | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|  | @ -524,9 +558,10 @@ namespace sat { | |||
|            If cut-depth != 0, then it is used to control the depth of cuts. | ||||
|            Otherwise, cut-fraction gives an adaptive threshold for creating cuts. | ||||
|         */ | ||||
| 
 | ||||
|         lbool cube(); | ||||
| 
 | ||||
|         lbool cube(literal_vector& lits); | ||||
|         lbool cube(bool_var_vector const& vars, literal_vector& lits); | ||||
| 
 | ||||
|         literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); | ||||
|         /**
 | ||||
|  | @ -557,6 +592,8 @@ namespace sat { | |||
| 
 | ||||
|         double literal_occs(literal l); | ||||
|         double literal_big_occs(literal l); | ||||
| 
 | ||||
|         sat::config const& get_config() const { return m_s.get_config(); } | ||||
|                | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -162,6 +162,7 @@ namespace sat { | |||
|         m_user_scope_literals.append(src.m_user_scope_literals); | ||||
| 
 | ||||
|         m_mc = src.m_mc; | ||||
|         m_stats.m_units = init_trail_size(); | ||||
|     } | ||||
| 
 | ||||
|     // -----------------------
 | ||||
|  | @ -837,11 +838,11 @@ namespace sat { | |||
|         return lh.select_lookahead(assumptions, vars); | ||||
|     } | ||||
| 
 | ||||
|     lbool  solver::cube(literal_vector& lits) { | ||||
|     lbool  solver::cube(bool_var_vector const& vars, literal_vector& lits) { | ||||
|         if (!m_cuber) { | ||||
|             m_cuber = alloc(lookahead, *this); | ||||
|         } | ||||
|         lbool result = m_cuber->cube(lits); | ||||
|         lbool result = m_cuber->cube(vars, lits); | ||||
|         if (result == l_false) { | ||||
|             dealloc(m_cuber); | ||||
|             m_cuber = nullptr; | ||||
|  | @ -858,6 +859,7 @@ namespace sat { | |||
|     lbool solver::check(unsigned num_lits, literal const* lits) { | ||||
|         init_reason_unknown(); | ||||
|         pop_to_base_level(); | ||||
|         m_stats.m_units = init_trail_size(); | ||||
|         IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); | ||||
|         SASSERT(at_base_lvl()); | ||||
|         if (m_config.m_dimacs_display) { | ||||
|  | @ -1468,11 +1470,14 @@ namespace sat { | |||
|                 lh.simplify(); | ||||
|                 lh.collect_statistics(m_aux_stats); | ||||
|             } | ||||
| #if 0 | ||||
| 			// Buggy
 | ||||
|             { | ||||
|                 lookahead lh(*this); | ||||
|                 lh.scc(); | ||||
|                 lh.collect_statistics(m_aux_stats); | ||||
|             } | ||||
| #endif | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -2823,6 +2828,7 @@ namespace sat { | |||
|         pop(num_scopes); | ||||
|         exchange_par(); | ||||
|         reinit_assumptions(); | ||||
|         m_stats.m_units = init_trail_size(); | ||||
|     } | ||||
| 
 | ||||
|     void solver::pop(unsigned num_scopes) { | ||||
|  | @ -3048,7 +3054,6 @@ namespace sat { | |||
|         m_probing.updt_params(p); | ||||
|         m_scc.updt_params(p); | ||||
|         m_rand.set_seed(m_config.m_random_seed); | ||||
| 
 | ||||
|         m_step_size = m_config.m_step_size_init; | ||||
|     } | ||||
| 
 | ||||
|  | @ -4032,25 +4037,11 @@ namespace sat { | |||
|         st.update("minimized lits", m_minimized_lits); | ||||
|         st.update("dyn subsumption resolution", m_dyn_sub_res); | ||||
|         st.update("blocked correction sets", m_blocked_corr_sets); | ||||
|         st.update("units", m_units); | ||||
|     } | ||||
| 
 | ||||
|     void stats::reset() { | ||||
|         m_mk_var = 0; | ||||
|         m_mk_bin_clause = 0; | ||||
|         m_mk_ter_clause = 0; | ||||
|         m_mk_clause = 0; | ||||
|         m_conflict = 0; | ||||
|         m_propagate = 0; | ||||
|         m_bin_propagate = 0; | ||||
|         m_ter_propagate = 0; | ||||
|         m_decision = 0; | ||||
|         m_restart = 0; | ||||
|         m_gc_clause = 0; | ||||
|         m_del_clause = 0; | ||||
|         m_minimized_lits = 0; | ||||
|         m_dyn_sub_res = 0; | ||||
|         m_non_learned_generation = 0; | ||||
|         m_blocked_corr_sets = 0; | ||||
|         memset(this, 0, sizeof(*this)); | ||||
|     } | ||||
| 
 | ||||
|     void mk_stat::display(std::ostream & out) const { | ||||
|  |  | |||
|  | @ -67,6 +67,7 @@ namespace sat { | |||
|         unsigned m_dyn_sub_res; | ||||
|         unsigned m_non_learned_generation; | ||||
|         unsigned m_blocked_corr_sets; | ||||
|         unsigned m_units; | ||||
|         stats() { reset(); } | ||||
|         void reset(); | ||||
|         void collect_statistics(statistics & st) const; | ||||
|  | @ -364,7 +365,7 @@ namespace sat { | |||
|         char const* get_reason_unknown() const { return m_reason_unknown.c_str(); } | ||||
| 
 | ||||
|         literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); | ||||
|         lbool  cube(literal_vector& lits); | ||||
|         lbool  cube(bool_var_vector const& vars, literal_vector& lits); | ||||
| 
 | ||||
|     protected: | ||||
|         unsigned m_conflicts_since_init; | ||||
|  |  | |||
|  | @ -353,8 +353,12 @@ public: | |||
|             m_internalized = true; | ||||
|         } | ||||
|         convert_internalized(); | ||||
|         sat::bool_var_vector vars; | ||||
|         for (auto& kv : m_map) { | ||||
|             vars.push_back(kv.m_value); | ||||
|         } | ||||
|         sat::literal_vector lits; | ||||
|         lbool result = m_solver.cube(lits); | ||||
|         lbool result = m_solver.cube(vars, lits); | ||||
|         if (result == l_false || lits.empty()) { | ||||
|             return expr_ref(m.mk_false(), m); | ||||
|         } | ||||
|  |  | |||
|  | @ -109,10 +109,10 @@ namespace sat { | |||
|         bool operator!=(watched const & w) const { return !operator==(w); } | ||||
|     }; | ||||
| 
 | ||||
|     COMPILE_TIME_ASSERT(0 <= watched::BINARY && watched::BINARY <= 3); | ||||
|     COMPILE_TIME_ASSERT(0 <= watched::TERNARY && watched::TERNARY <= 3); | ||||
|     COMPILE_TIME_ASSERT(0 <= watched::CLAUSE && watched::CLAUSE <= 3); | ||||
|     COMPILE_TIME_ASSERT(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 3); | ||||
|     static_assert(0 <= watched::BINARY && watched::BINARY <= 3, ""); | ||||
|     static_assert(0 <= watched::TERNARY && watched::TERNARY <= 3, ""); | ||||
|     static_assert(0 <= watched::CLAUSE && watched::CLAUSE <= 3, ""); | ||||
|     static_assert(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 3, ""); | ||||
| 
 | ||||
|     struct watched_lt { | ||||
|         bool operator()(watched const & w1, watched const & w2) const { | ||||
|  |  | |||
|  | @ -120,7 +120,7 @@ struct goal2sat::imp { | |||
|     sat::bool_var mk_true() { | ||||
|         if (m_true == sat::null_bool_var) { | ||||
|             // create fake variable to represent true;
 | ||||
|             m_true = m_solver.mk_var(); | ||||
|             m_true = m_solver.mk_var(false); | ||||
|             mk_clause(sat::literal(m_true, false)); // v is true
 | ||||
|         } | ||||
|         return m_true; | ||||
|  |  | |||
|  | @ -170,7 +170,7 @@ void asserted_formulas::get_assertions(ptr_vector<expr> & result) const { | |||
| 
 | ||||
| void asserted_formulas::push_scope() { | ||||
|     SASSERT(inconsistent() || m_qhead == m_formulas.size() || m.canceled()); | ||||
|     TRACE("asserted_formulas_scopes", tout << "push:\n"; display(tout););     | ||||
|     TRACE("asserted_formulas_scopes", tout << "before push: " << m_scopes.size() << "\n";); | ||||
|     m_scoped_substitution.push(); | ||||
|     m_scopes.push_back(scope()); | ||||
|     scope & s = m_scopes.back(); | ||||
|  | @ -181,10 +181,11 @@ void asserted_formulas::push_scope() { | |||
|     m_bv_sharing.push_scope(); | ||||
|     m_macro_manager.push_scope(); | ||||
|     commit(); | ||||
|     TRACE("asserted_formulas_scopes", tout << "after push: " << m_scopes.size() << "\n";); | ||||
| } | ||||
|   | ||||
| void asserted_formulas::pop_scope(unsigned num_scopes) { | ||||
|     TRACE("asserted_formulas_scopes", tout << "before pop " << num_scopes << "\n"; display(tout);); | ||||
|     TRACE("asserted_formulas_scopes", tout << "before pop " << num_scopes << " of " << m_scopes.size() << "\n";); | ||||
|     m_bv_sharing.pop_scope(num_scopes); | ||||
|     m_macro_manager.pop_scope(num_scopes); | ||||
|     unsigned new_lvl    = m_scopes.size() - num_scopes; | ||||
|  | @ -196,7 +197,7 @@ void asserted_formulas::pop_scope(unsigned num_scopes) { | |||
|     m_qhead    = s.m_formulas_lim; | ||||
|     m_scopes.shrink(new_lvl); | ||||
|     flush_cache(); | ||||
|     TRACE("asserted_formulas_scopes", tout << "after pop " << num_scopes << "\n"; display(tout);); | ||||
|     TRACE("asserted_formulas_scopes", tout << "after pop " << num_scopes << "\n";); | ||||
| } | ||||
| 
 | ||||
| void asserted_formulas::reset() { | ||||
|  |  | |||
|  | @ -487,6 +487,7 @@ namespace smt { | |||
|     */ | ||||
|     void context::add_eq(enode * n1, enode * n2, eq_justification js) { | ||||
|         unsigned old_trail_size = m_trail_stack.size(); | ||||
|         scoped_suspend_rlimit _suspend_cancel(m_manager.limit()); | ||||
| 
 | ||||
|         try { | ||||
|             TRACE("add_eq", tout << "assigning: #" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n";); | ||||
|  | @ -541,10 +542,14 @@ namespace smt { | |||
|                 mark_as_relevant(r1); | ||||
|             } | ||||
| 
 | ||||
|             TRACE("add_eq", tout << "to trail\n";); | ||||
| 
 | ||||
|             push_trail(add_eq_trail(r1, n1, r2->get_num_parents())); | ||||
| 
 | ||||
|             TRACE("add_eq", tout << "qmanager add_eq\n";); | ||||
|             m_qmanager->add_eq_eh(r1, r2); | ||||
| 
 | ||||
|             TRACE("add_eq", tout << "merge theory_vars\n";); | ||||
|             merge_theory_vars(n2, n1, js); | ||||
| 
 | ||||
|             // 'Proof' tree
 | ||||
|  | @ -577,6 +582,7 @@ namespace smt { | |||
| #endif | ||||
| 
 | ||||
| 
 | ||||
|             TRACE("add_eq", tout << "remove_parents_from_cg_table\n";); | ||||
|             remove_parents_from_cg_table(r1); | ||||
| 
 | ||||
|             enode * curr = r1; | ||||
|  | @ -588,8 +594,10 @@ namespace smt { | |||
| 
 | ||||
|             SASSERT(r1->get_root() == r2); | ||||
| 
 | ||||
|             TRACE("add_eq", tout << "reinsert_parents_into_cg_table\n";); | ||||
|             reinsert_parents_into_cg_table(r1, r2, n1, n2, js); | ||||
| 
 | ||||
|             TRACE("add_eq", tout << "propagate_bool_enode_assignment\n";); | ||||
|             if (n2->is_bool()) | ||||
|                 propagate_bool_enode_assignment(r1, r2, n1, n2); | ||||
| 
 | ||||
|  | @ -604,6 +612,7 @@ namespace smt { | |||
|         catch (...) { | ||||
|             // Restore trail size since procedure was interrupted in the middle.
 | ||||
|             // If the add_eq_trail remains on the trail stack, then Z3 may crash when the destructor is invoked.
 | ||||
|             TRACE("add_eq", tout << "add_eq interrupted. This is unsafe " << m_manager.limit().get_cancel_flag() << "\n";); | ||||
|             m_trail_stack.shrink(old_trail_size); | ||||
|             throw; | ||||
|         } | ||||
|  | @ -972,7 +981,7 @@ namespace smt { | |||
|             enode * parent = *it; | ||||
|             if (parent->is_cgc_enabled()) { | ||||
|                 TRACE("add_eq_parents", tout << "removing: #" << parent->get_owner_id() << "\n";); | ||||
|                 CTRACE("add_eq", !parent->is_cgr(), | ||||
|                 CTRACE("add_eq", !parent->is_cgr() || !m_cg_table.contains_ptr(parent), | ||||
|                        tout << "old num_parents: " << r2_num_parents << ", num_parents: " << r2->m_parents.size() << ", parent: #" << | ||||
|                        parent->get_owner_id() << ", parents: \n"; | ||||
|                        for (unsigned i = 0; i < r2->m_parents.size(); i++) { | ||||
|  |  | |||
|  | @ -284,7 +284,7 @@ namespace smt { | |||
|         } | ||||
| 
 | ||||
|         lbool reduce_cond(model_ref& model, expr* e) { | ||||
|             expr* e1, *e2; | ||||
|             expr* e1 = 0, *e2 = 0; | ||||
|             if (m.is_eq(e, e1, e2) && m_array_util.is_as_array(e1) && m_array_util.is_as_array(e2)) { | ||||
|                 if (e1 == e2) { | ||||
|                     return l_true; | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ namespace smt { | |||
|         ptr_vector<theory>::const_iterator it  = m_context->begin_theories(); | ||||
|         ptr_vector<theory>::const_iterator end = m_context->end_theories(); | ||||
|         for (; it != end; ++it) { | ||||
|             TRACE("model_generator_bug", tout << "init_model for theory: " << (*it)->get_name() << "\n";); | ||||
|             TRACE("model", tout << "init_model for theory: " << (*it)->get_name() << "\n";); | ||||
|             (*it)->init_model(*this); | ||||
|         } | ||||
|     } | ||||
|  | @ -91,7 +91,7 @@ namespace smt { | |||
|                 sort * s      = m_manager.get_sort(r->get_owner()); | ||||
|                 model_value_proc * proc = 0; | ||||
|                 if (m_manager.is_bool(s)) { | ||||
|                     CTRACE("func_interp_bug", m_context->get_assignment(r) == l_undef,  | ||||
|                     CTRACE("model", m_context->get_assignment(r) == l_undef,  | ||||
|                            tout << mk_pp(r->get_owner(), m_manager) << "\n";); | ||||
|                     SASSERT(m_context->get_assignment(r) != l_undef); | ||||
|                     if (m_context->get_assignment(r) == l_true) | ||||
|  | @ -108,7 +108,7 @@ namespace smt { | |||
|                             SASSERT(proc); | ||||
|                         } | ||||
|                         else { | ||||
|                             TRACE("model_bug", tout << "creating fresh value for #" << r->get_owner_id() << "\n";); | ||||
|                             TRACE("model", tout << "creating fresh value for #" << r->get_owner_id() << "\n";); | ||||
|                             proc = alloc(fresh_value_proc, mk_extra_fresh_value(m_manager.get_sort(r->get_owner()))); | ||||
|                         } | ||||
|                     } | ||||
|  | @ -130,7 +130,7 @@ namespace smt { | |||
|         if (!m_manager.is_model_value(n)) { | ||||
|             sort * s = m_manager.get_sort(r->get_owner()); | ||||
|             n = m_model->get_fresh_value(s); | ||||
|             CTRACE("model_generator_bug", n == 0,  | ||||
|             CTRACE("model", n == 0,  | ||||
|                    tout << mk_pp(r->get_owner(), m_manager) << "\nsort:\n" << mk_pp(s, m_manager) << "\n"; | ||||
|                    tout << "is_finite: " << m_model->is_finite(s) << "\n";); | ||||
|         } | ||||
|  | @ -407,9 +407,11 @@ namespace smt { | |||
|     */ | ||||
|     bool model_generator::include_func_interp(func_decl * f) const { | ||||
|         family_id fid = f->get_family_id(); | ||||
|         TRACE("model", tout << f->get_name() << " " << fid << "\n";); | ||||
|         if (fid == null_family_id) return !m_hidden_ufs.contains(f);  | ||||
|         if (fid == m_manager.get_basic_family_id()) return false; | ||||
|         theory * th = m_context->get_theory(fid); | ||||
|         TRACE("model", tout << th << "\n";); | ||||
|         if (!th) return true; | ||||
|         return th->include_func_interp(f); | ||||
|     } | ||||
|  | @ -444,7 +446,7 @@ namespace smt { | |||
|                 SASSERT(m_model->has_interpretation(f)); | ||||
|                 SASSERT(m_model->get_func_interp(f) == fi); | ||||
|                 // The entry must be new because n->get_cg() == n
 | ||||
|                 TRACE("func_interp_bug",  | ||||
|                 TRACE("model",  | ||||
|                       tout << "insert new entry for:\n" << mk_ismt2_pp(n->get_owner(), m_manager) << "\nargs: "; | ||||
|                       for (unsigned i = 0; i < num_args; i++) { | ||||
|                           tout << "#" << n->get_arg(i)->get_owner_id() << " "; | ||||
|  | @ -508,20 +510,20 @@ namespace smt { | |||
| 
 | ||||
|     void model_generator::register_macros() { | ||||
|         unsigned num = m_context->get_num_macros(); | ||||
|         TRACE("register_macros", tout << "num. macros: " << num << "\n";); | ||||
|         TRACE("model", tout << "num. macros: " << num << "\n";); | ||||
|         expr_ref v(m_manager); | ||||
|         for (unsigned i = 0; i < num; i++) { | ||||
|             func_decl * f    = m_context->get_macro_interpretation(i, v); | ||||
|             func_interp * fi = alloc(func_interp, m_manager, f->get_arity()); | ||||
|             fi->set_else(v); | ||||
|             TRACE("register_macros", tout << f->get_name() << "\n" << mk_pp(v, m_manager) << "\n";); | ||||
|             TRACE("model", tout << f->get_name() << "\n" << mk_pp(v, m_manager) << "\n";); | ||||
|             m_model->register_decl(f, fi); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     proto_model * model_generator::mk_model() { | ||||
|         SASSERT(!m_model); | ||||
|         TRACE("func_interp_bug", m_context->display(tout);); | ||||
|         TRACE("model", m_context->display(tout);); | ||||
|         init_model(); | ||||
|         register_existing_model_values(); | ||||
|         mk_bool_model(); | ||||
|  |  | |||
|  | @ -216,6 +216,7 @@ namespace smt { | |||
| 
 | ||||
|     void setup::setup_QF_DT() { | ||||
|         setup_QF_UF(); | ||||
|         setup_datatypes(); | ||||
|     } | ||||
| 
 | ||||
|     void setup::setup_QF_BVRE() { | ||||
|  |  | |||
|  | @ -67,9 +67,9 @@ namespace smt { | |||
|     }; | ||||
| 
 | ||||
|     // 32 bit machine
 | ||||
|     COMPILE_TIME_ASSERT(sizeof(expr*) != 4 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int));  | ||||
|     static_assert(sizeof(expr*) != 4 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int), "32 bit");  | ||||
|     // 64 bit machine
 | ||||
|     COMPILE_TIME_ASSERT(sizeof(expr*) != 8 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int) + /* a structure must be aligned */ sizeof(int));  | ||||
|     static_assert(sizeof(expr*) != 8 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int) + /* a structure must be aligned */ sizeof(int), "64 bit");  | ||||
| }; | ||||
| 
 | ||||
| #endif /* SMT_THEORY_VAR_LIST_H_ */ | ||||
|  |  | |||
|  | @ -780,7 +780,7 @@ namespace smt { | |||
|        of a non linear monomial that is not satisfied by the current assignment. | ||||
|        if v >= l, then create the case split v >= l+1 | ||||
|        else v <= u, then create the case split v <= u-1 | ||||
|        else do nothing and return false. | ||||
|        else create the bound v = 0 and case split on it. | ||||
|     */ | ||||
|     template<typename Ext> | ||||
|     bool theory_arith<Ext>::branch_nl_int_var(theory_var v) { | ||||
|  |  | |||
|  | @ -689,7 +689,7 @@ namespace smt { | |||
|             SASSERT(!ctx().b_internalized(atom)); | ||||
|             bool_var bv = ctx().mk_bool_var(atom); | ||||
|             ctx().set_var_theory(bv, get_id()); | ||||
|             expr* n1, *n2; | ||||
|             expr* n1 = 0, *n2 = 0; | ||||
|             rational r; | ||||
|             lra_lp::bound_kind k; | ||||
|             theory_var v = null_theory_var; | ||||
|  | @ -721,7 +721,7 @@ namespace smt { | |||
|             SASSERT(!ctx().b_internalized(atom)); | ||||
|             bool_var bv = ctx().mk_bool_var(atom); | ||||
|             ctx().set_var_theory(bv, get_id()); | ||||
|             expr* n1, *n2; | ||||
|             expr* n1 = 0, *n2 = 0; | ||||
|             rational r; | ||||
|             lra_lp::bound_kind k; | ||||
|             theory_var v = null_theory_var; | ||||
|  | @ -862,7 +862,7 @@ namespace smt { | |||
| 
 | ||||
|         void relevant_eh(app* n) { | ||||
|             TRACE("arith", tout << mk_pp(n, m) << "\n";); | ||||
|             expr* n1, *n2; | ||||
|             expr* n1 = 0, *n2 = 0; | ||||
|             if (a.is_mod(n, n1, n2)) | ||||
|                 mk_idiv_mod_axioms(n1, n2); | ||||
|             else if (a.is_rem(n, n1, n2)) | ||||
|  |  | |||
|  | @ -474,7 +474,6 @@ namespace smt { | |||
|         if (pb.is_aux_bool(atom)) { | ||||
|             bool_var abv = ctx.mk_bool_var(atom); | ||||
|             ctx.set_var_theory(abv, get_id()); | ||||
|             std::cout << "aux bool " << ctx.get_scope_level() << " " << mk_pp(atom, get_manager()) << " " << literal(abv) << "\n"; | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -7,6 +7,7 @@ z3_add_component(core_tactics | |||
|     ctx_simplify_tactic.cpp | ||||
|     der_tactic.cpp | ||||
|     distribute_forall_tactic.cpp | ||||
|     dom_simplify_tactic.cpp | ||||
|     elim_term_ite_tactic.cpp | ||||
|     elim_uncnstr_tactic.cpp | ||||
|     injectivity_tactic.cpp | ||||
|  | @ -32,6 +33,7 @@ z3_add_component(core_tactics | |||
|     ctx_simplify_tactic.h | ||||
|     der_tactic.h | ||||
|     distribute_forall_tactic.h | ||||
|     dom_simplify_tactic.h | ||||
|     elim_term_ite_tactic.h | ||||
|     elim_uncnstr_tactic.h | ||||
|     injectivity_tactic.h | ||||
|  |  | |||
|  | @ -83,49 +83,66 @@ expr* expr_dominators::intersect(expr* x, expr * y) { | |||
|     return x; | ||||
| } | ||||
| 
 | ||||
| void expr_dominators::compute_dominators() { | ||||
| bool expr_dominators::compute_dominators() { | ||||
|     expr * e = m_root; | ||||
|     SASSERT(m_doms.empty()); | ||||
|     m_doms.insert(e, e); | ||||
|     bool change = true; | ||||
|     unsigned iterations = 1; | ||||
|     while (change) { | ||||
|         change = false; | ||||
|         SASSERT(m_post2expr.back() == e); | ||||
|         for (unsigned i = 0; i < m_post2expr.size() - 1; ++i) { | ||||
|         TRACE("simplify",  | ||||
|               for (auto & kv : m_doms) { | ||||
|                   tout << expr_ref(kv.m_key, m) << " |-> " << expr_ref(kv.m_value, m) << "\n"; | ||||
|               }); | ||||
| 
 | ||||
|         SASSERT(m_post2expr.empty() || m_post2expr.back() == e); | ||||
|         for (unsigned i = 0; i + 1 < m_post2expr.size(); ++i) { | ||||
|             expr * child = m_post2expr[i]; | ||||
|             ptr_vector<expr> const& p = m_parents[child]; | ||||
|             SASSERT(!p.empty()); | ||||
|             expr * new_idom = p[0], * idom2 = 0; | ||||
|             for (unsigned j = 1; j < p.size(); ++j) { | ||||
|                 if (m_doms.find(p[j], idom2)) { | ||||
|                     new_idom = intersect(new_idom, idom2); | ||||
|             expr * new_idom = 0, *idom2 = 0; | ||||
| 
 | ||||
|             for (expr * pred : p) { | ||||
|                 if (m_doms.contains(pred)) { | ||||
|                     new_idom = !new_idom ? pred : intersect(new_idom, pred); | ||||
|                 } | ||||
|             } | ||||
|             if (!m_doms.find(child, idom2) || idom2 != new_idom) { | ||||
|             if (!new_idom) { | ||||
|                 m_doms.insert(child, p[0]); | ||||
|                 change = true; | ||||
|             } | ||||
|             else if (!m_doms.find(child, idom2) || idom2 != new_idom) { | ||||
|                 m_doms.insert(child, new_idom); | ||||
|                 change = true; | ||||
|             } | ||||
|         } | ||||
|         iterations *= 2;         | ||||
|         if (change && iterations > m_post2expr.size()) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void expr_dominators::extract_tree() { | ||||
|     for (auto const& kv : m_doms) { | ||||
|         add_edge(m_tree, kv.m_value, kv.m_key); | ||||
|     } | ||||
| }     | ||||
| } | ||||
| 
 | ||||
| void expr_dominators::compile(expr * e) { | ||||
| bool expr_dominators::compile(expr * e) { | ||||
|     reset(); | ||||
|     m_root = e; | ||||
|     compute_post_order(); | ||||
|     compute_dominators(); | ||||
|     if (!compute_dominators()) return false; | ||||
|     extract_tree(); | ||||
|     TRACE("simplify", display(tout);); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void expr_dominators::compile(unsigned sz, expr * const* es) { | ||||
| bool expr_dominators::compile(unsigned sz, expr * const* es) { | ||||
|     expr_ref e(m.mk_and(sz, es), m); | ||||
|     compile(e); | ||||
|     return compile(e); | ||||
| } | ||||
| 
 | ||||
| void expr_dominators::reset() { | ||||
|  | @ -137,19 +154,39 @@ void expr_dominators::reset() { | |||
|     m_root.reset(); | ||||
| } | ||||
| 
 | ||||
| std::ostream& expr_dominators::display(std::ostream& out) { | ||||
|     return display(out, 0, m_root); | ||||
| } | ||||
| 
 | ||||
| std::ostream& expr_dominators::display(std::ostream& out, unsigned indent, expr* r) { | ||||
|     for (unsigned i = 0; i < indent; ++i) out << " "; | ||||
|     out << expr_ref(r, m); | ||||
|     if (m_tree.contains(r)) { | ||||
|         for (expr* child : m_tree[r]) { | ||||
|             if (child != r)  | ||||
|                 display(out, indent + 1, child); | ||||
|         } | ||||
|     } | ||||
|     out << "\n"; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // -----------------------
 | ||||
| // dom_simplify_tactic
 | ||||
| 
 | ||||
| dom_simplify_tactic::~dom_simplify_tactic() { | ||||
|     dealloc(m_simplifier); | ||||
| } | ||||
| 
 | ||||
| tactic * dom_simplify_tactic::translate(ast_manager & m) { | ||||
|     return alloc(dom_simplify_tactic, m, m_simplifier->translate(m), m_params); | ||||
| } | ||||
| 
 | ||||
| void dom_simplify_tactic::operator()( | ||||
|     goal_ref const & in,  | ||||
|     goal_ref_buffer & result,  | ||||
|     model_converter_ref & mc,  | ||||
|     goal_ref const & in, | ||||
|     goal_ref_buffer & result, | ||||
|     model_converter_ref & mc, | ||||
|     proof_converter_ref & pc, | ||||
|     expr_dependency_ref & core) { | ||||
|     mc = 0; pc = 0; core = 0; | ||||
|  | @ -162,33 +199,42 @@ void dom_simplify_tactic::operator()( | |||
| } | ||||
| 
 | ||||
| void dom_simplify_tactic::cleanup() { | ||||
|     m_trail.reset();  | ||||
|     m_args.reset();  | ||||
|     m_args2.reset();  | ||||
|     m_result.reset();  | ||||
|     m_dominators.reset();  | ||||
|     m_trail.reset(); | ||||
|     m_args.reset(); | ||||
|     m_result.reset(); | ||||
|     m_dominators.reset(); | ||||
| } | ||||
| 
 | ||||
| expr_ref dom_simplify_tactic::simplify_ite(app * ite) { | ||||
|     expr_ref r(m); | ||||
|     expr * c = 0, * t = 0, * e = 0; | ||||
|     expr * c = 0, *t = 0, *e = 0; | ||||
|     VERIFY(m.is_ite(ite, c, t, e)); | ||||
|     unsigned old_lvl = scope_level(); | ||||
|     expr_ref new_c = simplify(c); | ||||
|     expr_ref new_c = simplify_arg(c); | ||||
|     if (m.is_true(new_c)) { | ||||
|         r = simplify(t); | ||||
|     } | ||||
|         r = simplify_arg(t); | ||||
|     }  | ||||
|     else if (m.is_false(new_c) || !assert_expr(new_c, false)) { | ||||
|         r = simplify(e); | ||||
|     } | ||||
|         r = simplify_arg(e); | ||||
|     }  | ||||
|     else { | ||||
|         expr_ref new_t = simplify(t); | ||||
|         for (expr * child : tree(ite)) { | ||||
|             if (is_subexpr(child, t) && !is_subexpr(child, e)) { | ||||
|                 simplify_rec(child); | ||||
|             } | ||||
|         } | ||||
|         pop(scope_level() - old_lvl); | ||||
|         expr_ref new_t = simplify_arg(t); | ||||
|         if (!assert_expr(new_c, true)) { | ||||
|             return new_t; | ||||
|         } | ||||
|         expr_ref new_e = simplify(e); | ||||
|         for (expr * child : tree(ite)) { | ||||
|             if (is_subexpr(child, e) && !is_subexpr(child, t)) { | ||||
|                 simplify_rec(child); | ||||
|             } | ||||
|         } | ||||
|         pop(scope_level() - old_lvl); | ||||
|         expr_ref new_e = simplify_arg(e); | ||||
|         if (c == new_c && t == new_t && e == new_e) { | ||||
|             r = ite; | ||||
|         } | ||||
|  | @ -197,15 +243,28 @@ expr_ref dom_simplify_tactic::simplify_ite(app * ite) { | |||
|         } | ||||
|         else { | ||||
|             TRACE("tactic", tout << new_c << "\n" << new_t << "\n" << new_e << "\n";); | ||||
|             r = m.mk_ite(new_c, new_t, new_c); | ||||
|             r = m.mk_ite(new_c, new_t, new_e); | ||||
|         }         | ||||
|     }     | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| expr_ref dom_simplify_tactic::simplify(expr * e0) { | ||||
| expr_ref dom_simplify_tactic::simplify_arg(expr * e) { | ||||
|     expr_ref r(m);     | ||||
|     r = get_cached(e); | ||||
|     (*m_simplifier)(r); | ||||
|     TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e, m) << " -> " << r << "\n";); | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|    \brief simplify e recursively. | ||||
| */ | ||||
| expr_ref dom_simplify_tactic::simplify_rec(expr * e0) { | ||||
|     expr_ref r(m); | ||||
|     expr* e = 0; | ||||
| 
 | ||||
|     TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << "\n";); | ||||
|     if (!m_result.find(e0, e)) { | ||||
|         e = e0; | ||||
|     } | ||||
|  | @ -224,17 +283,13 @@ expr_ref dom_simplify_tactic::simplify(expr * e0) { | |||
|         r = simplify_or(to_app(e)); | ||||
|     } | ||||
|     else { | ||||
|         expr_dominators::tree_t const& t = m_dominators.get_tree(); | ||||
|         if (t.contains(e)) { | ||||
|             ptr_vector<expr> const& children = t[e]; | ||||
|             for (expr * child : children) { | ||||
|                 simplify(child); | ||||
|             } | ||||
|         for (expr * child : tree(e)) { | ||||
|             simplify_rec(child); | ||||
|         } | ||||
|         if (is_app(e)) { | ||||
|             m_args.reset(); | ||||
|             for (expr* arg : *to_app(e)) { | ||||
|                 m_args.push_back(get_cached(arg)); // TBD is cache really applied to all sub-terms?
 | ||||
|                 m_args.push_back(simplify_arg(arg));  | ||||
|             } | ||||
|             r = m.mk_app(to_app(e)->get_decl(), m_args.size(), m_args.c_ptr()); | ||||
|         } | ||||
|  | @ -246,45 +301,64 @@ expr_ref dom_simplify_tactic::simplify(expr * e0) { | |||
|     cache(e0, r); | ||||
|     TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << " -> " << r << "\n";); | ||||
|     --m_depth; | ||||
|     m_subexpr_cache.reset(); | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) { | ||||
|     expr_ref r(m); | ||||
|     unsigned old_lvl = scope_level(); | ||||
|     m_args.reset(); | ||||
|     for (expr * arg : *e) { | ||||
|         r = simplify(arg); | ||||
|         if (!assert_expr(r, !is_and)) { | ||||
|             r = is_and ? m.mk_false() : m.mk_true(); | ||||
| 
 | ||||
|     auto is_subexpr_arg = [&](expr * child, expr * except) { | ||||
|         if (!is_subexpr(child, except)) | ||||
|             return false; | ||||
|         for (expr * arg : *e) { | ||||
|             if (arg != except && is_subexpr(child, arg)) | ||||
|                 return false; | ||||
|         } | ||||
|         m_args.push_back(r); | ||||
|         return true; | ||||
|     }; | ||||
| 
 | ||||
|     expr_ref_vector args(m); | ||||
|     if (m_forward) { | ||||
|         for (expr * arg : *e) { | ||||
| #define _SIMP_ARG(arg)                                          \ | ||||
|             for (expr * child : tree(arg)) {                    \ | ||||
|                 if (is_subexpr_arg(child, arg)) {               \ | ||||
|                     simplify_rec(child);                        \ | ||||
|                 }                                               \ | ||||
|             }                                                   \ | ||||
|             r = simplify_arg(arg);                              \ | ||||
|             args.push_back(r);                                  \ | ||||
|             if (!assert_expr(r, !is_and)) {                     \ | ||||
|                 r = is_and ? m.mk_false() : m.mk_true();        \ | ||||
|                 return r;                                       \ | ||||
|             }                                                    | ||||
|             _SIMP_ARG(arg); | ||||
|         }                                                                   | ||||
|     } | ||||
|     else {         | ||||
|         for (unsigned i = e->get_num_args(); i > 0; ) { | ||||
|             --i; | ||||
|             expr* arg = e->get_arg(i); | ||||
|             _SIMP_ARG(arg); | ||||
|         } | ||||
|         args.reverse(); | ||||
|     } | ||||
|     pop(scope_level() - old_lvl); | ||||
|     m_args.reverse(); | ||||
|     m_args2.reset(); | ||||
|     for (expr * arg : m_args) { | ||||
|         r = simplify(arg); | ||||
|         if (!assert_expr(r, !is_and)) { | ||||
|             r = is_and ? m.mk_false() : m.mk_true(); | ||||
|         } | ||||
|         m_args2.push_back(r); | ||||
|     } | ||||
|     pop(scope_level() - old_lvl); | ||||
|     m_args2.reverse(); | ||||
|     r = is_and ? mk_and(m_args2) : mk_or(m_args2); | ||||
|     r = is_and ? mk_and(args) : mk_or(args); | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void dom_simplify_tactic::init(goal& g) { | ||||
| bool dom_simplify_tactic::init(goal& g) { | ||||
|     expr_ref_vector args(m); | ||||
|     unsigned sz = g.size(); | ||||
|     for (unsigned i = 0; i < sz; ++i) args.push_back(g.form(i)); | ||||
|     expr_ref fml = mk_and(args); | ||||
|     m_result.reset(); | ||||
|     m_trail.reset(); | ||||
|     m_dominators.compile(fml); | ||||
|     return m_dominators.compile(fml); | ||||
| } | ||||
| 
 | ||||
| void dom_simplify_tactic::simplify_goal(goal& g) { | ||||
|  | @ -296,13 +370,15 @@ void dom_simplify_tactic::simplify_goal(goal& g) { | |||
|         change = false; | ||||
| 
 | ||||
|         // go forwards
 | ||||
|         init(g); | ||||
|         m_forward = true; | ||||
|         if (!init(g)) return; | ||||
|         unsigned sz = g.size(); | ||||
|         for (unsigned i = 0; !g.inconsistent() && i < sz; ++i) { | ||||
|             expr_ref r = simplify(g.form(i)); | ||||
|             expr_ref r = simplify_rec(g.form(i)); | ||||
|             if (i < sz - 1 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) { | ||||
|                 r = m.mk_false(); | ||||
|             } | ||||
|             CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";); | ||||
|             change |= r != g.form(i); | ||||
|             proof* new_pr = 0; | ||||
|             if (g.proofs_enabled()) { | ||||
|  | @ -313,15 +389,17 @@ void dom_simplify_tactic::simplify_goal(goal& g) { | |||
|         pop(scope_level()); | ||||
|          | ||||
|         // go backwards
 | ||||
|         init(g); | ||||
|         m_forward = false; | ||||
|         if (!init(g)) return; | ||||
|         sz = g.size(); | ||||
|         for (unsigned i = sz; !g.inconsistent() && i > 0; ) { | ||||
|             --i; | ||||
|             expr_ref r = simplify(g.form(i)); | ||||
|             expr_ref r = simplify_rec(g.form(i)); | ||||
|             if (i > 0 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) { | ||||
|                 r = m.mk_false(); | ||||
|             } | ||||
|             change |= r != g.form(i); | ||||
|             CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";); | ||||
|             proof* new_pr = 0; | ||||
|             if (g.proofs_enabled()) { | ||||
|                 new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, 0));  | ||||
|  | @ -333,11 +411,41 @@ void dom_simplify_tactic::simplify_goal(goal& g) { | |||
|     SASSERT(scope_level() == 0); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|    \brief determine if a is dominated by b.  | ||||
|    Walk the immediate dominators of a upwards until hitting b or a term that is deeper than b. | ||||
|    Save intermediary results in a cache to avoid recomputations. | ||||
| */ | ||||
| 
 | ||||
| bool dom_simplify_tactic::is_subexpr(expr * a, expr * b) { | ||||
|     if (a == b) | ||||
|         return true; | ||||
| 
 | ||||
|     bool r; | ||||
|     if (m_subexpr_cache.find(a, b, r)) | ||||
|         return r; | ||||
| 
 | ||||
|     if (get_depth(a) >= get_depth(b)) { | ||||
|         return false; | ||||
|     } | ||||
|     SASSERT(a != idom(a) && get_depth(idom(a)) > get_depth(a)); | ||||
|     r = is_subexpr(idom(a), b); | ||||
|     m_subexpr_cache.insert(a, b, r);    | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| ptr_vector<expr> const & dom_simplify_tactic::tree(expr * e) { | ||||
|     if (auto p = m_dominators.get_tree().find_core(e)) | ||||
|         return p->get_data().get_value(); | ||||
|     return m_empty; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // ----------------------
 | ||||
| // expr_substitution_simplifier
 | ||||
| 
 | ||||
| bool expr_substitution_simplifier::assert_expr(expr * t, bool sign) { | ||||
|     m_scoped_substitution.push(); | ||||
|     expr* tt;     | ||||
|     if (!sign) { | ||||
|         update_substitution(t, 0); | ||||
|  | @ -389,6 +497,8 @@ void expr_substitution_simplifier::update_substitution(expr* n, proof* pr) { | |||
|     if (is_ground(n) && (m.is_eq(n, lhs, rhs) || m.is_iff(n, lhs, rhs))) { | ||||
|         compute_depth(lhs); | ||||
|         compute_depth(rhs); | ||||
|         m_trail.push_back(lhs); | ||||
|         m_trail.push_back(rhs); | ||||
|         if (is_gt(lhs, rhs)) { | ||||
|             TRACE("propagate_values", tout << "insert " << mk_pp(lhs, m) << " -> " << mk_pp(rhs, m) << "\n";); | ||||
|             m_scoped_substitution.insert(lhs, rhs, pr); | ||||
|  | @ -440,3 +550,7 @@ void expr_substitution_simplifier::compute_depth(expr* e) { | |||
|         m_expr2depth.insert(e, d + 1); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| tactic * mk_dom_simplify_tactic(ast_manager & m, params_ref const & p) { | ||||
|     return clean(alloc(dom_simplify_tactic, m, alloc(expr_substitution_simplifier, m), p)); | ||||
| } | ||||
|  |  | |||
|  | @ -23,6 +23,8 @@ Notes: | |||
| #include "ast/ast.h" | ||||
| #include "ast/expr_substitution.h" | ||||
| #include "tactic/tactic.h" | ||||
| #include "tactic/tactical.h" | ||||
| #include "util/obj_pair_hashtable.h" | ||||
| 
 | ||||
| 
 | ||||
| class expr_dominators { | ||||
|  | @ -43,78 +45,92 @@ private: | |||
| 
 | ||||
|     void compute_post_order(); | ||||
|     expr* intersect(expr* x, expr * y); | ||||
|     void compute_dominators(); | ||||
|     bool compute_dominators(); | ||||
|     void extract_tree(); | ||||
| 
 | ||||
|     std::ostream& display(std::ostream& out, unsigned indent, expr* r); | ||||
| 
 | ||||
| public: | ||||
|     expr_dominators(ast_manager& m): m(m), m_root(m) {} | ||||
| 
 | ||||
|     void compile(expr * e); | ||||
|     void compile(unsigned sz, expr * const* es); | ||||
|     bool compile(expr * e); | ||||
|     bool compile(unsigned sz, expr * const* es); | ||||
|     tree_t const& get_tree() { return m_tree; } | ||||
|     void reset(); | ||||
|     expr* idom(expr *e) const { return m_doms[e]; } | ||||
| 
 | ||||
|     std::ostream& display(std::ostream& out); | ||||
| }; | ||||
| 
 | ||||
| class dom_simplifier { | ||||
|  public: | ||||
|     dom_simplifier() {} | ||||
|      | ||||
|     virtual ~dom_simplifier() {} | ||||
|     /**
 | ||||
|        \brief assert_expr performs an implicit push | ||||
|     */ | ||||
|     virtual bool assert_expr(expr * t, bool sign) = 0; | ||||
|      | ||||
|     /**
 | ||||
|        \brief apply simplification. | ||||
|     */ | ||||
|     virtual void operator()(expr_ref& r) = 0; | ||||
|      | ||||
|     /**
 | ||||
|        \brief pop scopes accumulated from assertions. | ||||
|     */ | ||||
|     virtual void pop(unsigned num_scopes) = 0; | ||||
|      | ||||
|     virtual dom_simplifier * translate(ast_manager & m) = 0; | ||||
|      | ||||
| }; | ||||
| 
 | ||||
| class dom_simplify_tactic : public tactic { | ||||
| public: | ||||
|     class simplifier { | ||||
|     public: | ||||
|         virtual ~simplifier() {} | ||||
|         /**
 | ||||
|            \brief assert_expr performs an implicit push | ||||
|          */ | ||||
|         virtual bool assert_expr(expr * t, bool sign) = 0; | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief apply simplification. | ||||
|         */ | ||||
|         virtual void operator()(expr_ref& r) = 0; | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief pop scopes accumulated from assertions. | ||||
|          */ | ||||
|         virtual void pop(unsigned num_scopes) = 0; | ||||
| 
 | ||||
|         virtual simplifier * translate(ast_manager & m); | ||||
| 
 | ||||
|     }; | ||||
| private: | ||||
|     ast_manager&         m; | ||||
|     simplifier*          m_simplifier; | ||||
|     dom_simplifier*      m_simplifier; | ||||
|     params_ref           m_params; | ||||
|     expr_ref_vector      m_trail, m_args, m_args2; | ||||
|     expr_ref_vector      m_trail, m_args; | ||||
|     obj_map<expr, expr*> m_result; | ||||
|     expr_dominators      m_dominators; | ||||
|     unsigned             m_scope_level; | ||||
|     unsigned             m_depth; | ||||
|     unsigned             m_max_depth; | ||||
|     ptr_vector<expr>     m_empty; | ||||
|     obj_pair_map<expr, expr, bool> m_subexpr_cache; | ||||
|     bool                 m_forward; | ||||
| 
 | ||||
|     expr_ref simplify(expr* t); | ||||
|     expr_ref simplify_rec(expr* t); | ||||
|     expr_ref simplify_arg(expr* t); | ||||
|     expr_ref simplify_ite(app * ite); | ||||
|     expr_ref simplify_and(app * ite) { return simplify_and_or(true, ite); } | ||||
|     expr_ref simplify_or(app * ite) { return simplify_and_or(false, ite); } | ||||
|     expr_ref simplify_and_or(bool is_and, app * ite); | ||||
|     void simplify_goal(goal& g); | ||||
| 
 | ||||
|     expr_ref get_cached(expr* t) { expr* r = 0; if (!m_result.find(r, r)) r = t; return expr_ref(r, m); } | ||||
|     bool is_subexpr(expr * a, expr * b); | ||||
| 
 | ||||
|     expr_ref get_cached(expr* t) { expr* r = 0; if (!m_result.find(t, r)) r = t; return expr_ref(r, m); } | ||||
|     void cache(expr *t, expr* r) { m_result.insert(t, r); m_trail.push_back(r); } | ||||
| 
 | ||||
|     ptr_vector<expr> const & tree(expr * e); | ||||
|     expr* idom(expr *e) const { return m_dominators.idom(e); } | ||||
| 
 | ||||
|     unsigned scope_level() { return m_scope_level; } | ||||
|     void pop(unsigned n) { SASSERT(n <= m_scope_level); m_scope_level -= n; m_simplifier->pop(n); } | ||||
|     bool assert_expr(expr* f, bool sign) { m_scope_level++; return m_simplifier->assert_expr(f, sign); } | ||||
| 
 | ||||
|     void init(goal& g); | ||||
|     bool init(goal& g); | ||||
| 
 | ||||
| public: | ||||
|     dom_simplify_tactic(ast_manager & m, simplifier* s, params_ref const & p = params_ref()): | ||||
|     dom_simplify_tactic(ast_manager & m, dom_simplifier* s, params_ref const & p = params_ref()): | ||||
|         m(m), m_simplifier(s), m_params(p),  | ||||
|         m_trail(m), m_args(m), m_args2(m),  | ||||
|         m_trail(m), m_args(m),  | ||||
|         m_dominators(m),  | ||||
|         m_scope_level(0), m_depth(0), m_max_depth(1024) {} | ||||
|         m_scope_level(0), m_depth(0), m_max_depth(1024), m_forward(true) {} | ||||
| 
 | ||||
| 
 | ||||
|     virtual ~dom_simplify_tactic() {} | ||||
|     virtual ~dom_simplify_tactic(); | ||||
| 
 | ||||
|     virtual tactic * translate(ast_manager & m); | ||||
|     virtual void updt_params(params_ref const & p) {} | ||||
|  | @ -130,11 +146,12 @@ public: | |||
|     virtual void cleanup(); | ||||
| }; | ||||
| 
 | ||||
| class expr_substitution_simplifier : public dom_simplify_tactic::simplifier { | ||||
| class expr_substitution_simplifier : public dom_simplifier { | ||||
|     ast_manager&             m; | ||||
|     expr_substitution        m_subst; | ||||
|     scoped_expr_substitution m_scoped_substitution; | ||||
|     obj_map<expr, unsigned>  m_expr2depth; | ||||
|     expr_ref_vector          m_trail; | ||||
| 
 | ||||
|     // move from asserted_formulas to here..
 | ||||
|     void compute_depth(expr* e); | ||||
|  | @ -142,7 +159,7 @@ class expr_substitution_simplifier : public dom_simplify_tactic::simplifier { | |||
|     unsigned depth(expr* e) { return m_expr2depth[e]; } | ||||
| 
 | ||||
| public: | ||||
|     expr_substitution_simplifier(ast_manager& m): m(m), m_subst(m), m_scoped_substitution(m_subst) {} | ||||
|     expr_substitution_simplifier(ast_manager& m): m(m), m_subst(m), m_scoped_substitution(m_subst), m_trail(m) {} | ||||
|     virtual ~expr_substitution_simplifier() {} | ||||
|     virtual bool assert_expr(expr * t, bool sign); | ||||
| 
 | ||||
|  | @ -152,12 +169,17 @@ public: | |||
|      | ||||
|     virtual void pop(unsigned num_scopes) { m_scoped_substitution.pop(num_scopes); } | ||||
|      | ||||
|     virtual simplifier * translate(ast_manager & m) { | ||||
|     virtual dom_simplifier * translate(ast_manager & m) { | ||||
|         SASSERT(m_subst.empty()); | ||||
|         return alloc(expr_substitution_simplifier, m); | ||||
|     } | ||||
| 
 | ||||
|      | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| tactic * mk_dom_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()); | ||||
| 
 | ||||
| /*
 | ||||
| ADD_TACTIC("dom-simplify", "apply dominator simplification rules.", "mk_dom_simplify_tactic(m, p)") | ||||
| */ | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -1,11 +1,13 @@ | |||
| z3_add_component(portfolio | ||||
|   SOURCES | ||||
|     bounded_int2bv_solver.cpp | ||||
|     default_tactic.cpp | ||||
|     enum2bv_solver.cpp | ||||
|     pb2bv_solver.cpp | ||||
|     bounded_int2bv_solver.cpp | ||||
|     fd_solver.cpp | ||||
|     parallel_tactic.cpp | ||||
|     pb2bv_solver.cpp | ||||
|     smt_strategic_solver.cpp | ||||
|     solver2lookahead.cpp | ||||
|   COMPONENT_DEPENDENCIES | ||||
|     aig_tactic | ||||
|     fp | ||||
|  | @ -19,4 +21,5 @@ z3_add_component(portfolio | |||
|   TACTIC_HEADERS | ||||
|     default_tactic.h | ||||
|     fd_solver.h | ||||
|     parallel_tactic.h | ||||
| ) | ||||
|  |  | |||
							
								
								
									
										448
									
								
								src/tactic/portfolio/parallel_tactic.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										448
									
								
								src/tactic/portfolio/parallel_tactic.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,448 @@ | |||
| /*++
 | ||||
| Copyright (c) 2017 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     parallel_tactic.cpp | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Parallel tactic in the style of Treengeling. | ||||
| 
 | ||||
|     It assumes a solver that supports good lookaheads. | ||||
|      | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2017-10-9 | ||||
| 
 | ||||
| Notes: | ||||
|     | ||||
| --*/ | ||||
| 
 | ||||
| #include "util/scoped_ptr_vector.h" | ||||
| #include "ast/ast_util.h" | ||||
| #include "solver/solver.h" | ||||
| #include "solver/solver2tactic.h" | ||||
| #include "tactic/tactic.h" | ||||
| #include "tactic/portfolio/fd_solver.h" | ||||
| 
 | ||||
| class parallel_tactic : public tactic { | ||||
| 
 | ||||
|     class solver_state { | ||||
|         params_ref      m_params; | ||||
|         scoped_ptr<ast_manager> m_manager; | ||||
|         ref<solver>     m_solver; | ||||
|         expr_ref_vector m_cube; | ||||
|         unsigned        m_units; | ||||
|     public: | ||||
|         solver_state(ast_manager* m, solver* s, params_ref const& p):  | ||||
|             m_params(p), | ||||
|             m_manager(m),  | ||||
|             m_solver(s),  | ||||
|             m_cube(s->get_manager()),  | ||||
|             m_units(0) {} | ||||
| 
 | ||||
|         void update_units() { | ||||
|             m_units = 0; | ||||
|             statistics st; | ||||
|             m_solver->collect_statistics(st); | ||||
|             std::string units("units"); | ||||
|             for (unsigned i = st.size(); i-- > 0; ) { | ||||
|                 if (st.get_key(i) == units) { | ||||
|                     m_units = st.get_uint_value(i); | ||||
|                     std::cout << "value for " << i << " is " << m_units << "\n"; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         }         | ||||
| 
 | ||||
|         expr_ref cube() { return mk_and(m_cube); } | ||||
| 
 | ||||
|         void add_cube(expr* c) { m_cube.push_back(c); } | ||||
| 
 | ||||
|         unsigned num_units() const { return m_units; } | ||||
| 
 | ||||
|         solver& get_solver() { return *m_solver; } | ||||
| 
 | ||||
|         solver const& get_solver() const { return *m_solver; } | ||||
| 
 | ||||
|         params_ref const& params() const { return m_params; } | ||||
| 
 | ||||
|         solver_state* clone(params_ref const& p, expr* cube) { | ||||
|             ast_manager& m = m_solver->get_manager(); | ||||
|             ast_manager* new_m = alloc(ast_manager, m, !m.proof_mode()); | ||||
|             solver* s = m_solver->translate(*new_m, p); | ||||
|             solver_state* st = alloc(solver_state, new_m, s, m_params); | ||||
|             ast_translation translate(m, *new_m); | ||||
|             for (expr* c : m_cube) { | ||||
|                 st->m_cube.push_back(translate(c)); | ||||
|             }			 | ||||
|             expr_ref cube1(translate(cube), *new_m); | ||||
|             st->m_cube.push_back(cube1); | ||||
|             s->assert_expr(cube1); | ||||
|             return st; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| public: | ||||
|     bool operator()(solver_state* s1, solver_state* s2) const { | ||||
|         return s1->num_units() > s2->num_units(); | ||||
|     } | ||||
| private: | ||||
| 
 | ||||
|     ast_manager& m_manager; | ||||
|     params_ref   m_params; | ||||
| 
 | ||||
|     // parameters
 | ||||
|     unsigned m_conflicts_lower_bound; | ||||
|     unsigned m_conflicts_upper_bound; | ||||
|     unsigned m_conflicts_growth_rate; | ||||
|     unsigned m_conflicts_decay_rate; | ||||
|     unsigned m_num_threads; | ||||
|      | ||||
|     double     m_progress; | ||||
|     unsigned   m_max_conflicts;     | ||||
|     statistics m_stats; | ||||
| 
 | ||||
|     vector<solver_state*> m_solvers; | ||||
| 
 | ||||
|     void init() { | ||||
|         m_conflicts_lower_bound = 1000; | ||||
|         m_conflicts_upper_bound = 10000; | ||||
|         m_conflicts_growth_rate = 150; | ||||
|         m_conflicts_decay_rate = 75; | ||||
|         m_max_conflicts = m_conflicts_lower_bound; | ||||
|         m_progress = 0; | ||||
|         m_num_threads = omp_get_num_procs();  // TBD adjust by possible threads used inside each solver.
 | ||||
|     } | ||||
| 
 | ||||
|     unsigned get_max_conflicts() {  | ||||
|         return m_max_conflicts; | ||||
|     } | ||||
| 
 | ||||
|     void set_max_conflicts(unsigned c) { | ||||
|         m_max_conflicts = c; | ||||
|     } | ||||
| 
 | ||||
|     bool should_increase_conflicts() { | ||||
|         return m_progress < 0; | ||||
|     } | ||||
| 
 | ||||
|     void update_progress(bool b) { | ||||
|         m_progress = 0.9 * m_progress + (b ? 1 : -1); | ||||
|         if (b) { | ||||
|             m_stats.update("closed", 1u); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     int pick_solvers() { | ||||
|         // order solvers by number of units in descending order
 | ||||
|         for (solver_state* s : m_solvers) s->update_units(); | ||||
|         std::sort(m_solvers.c_ptr(), m_solvers.c_ptr() + m_solvers.size(), *this); | ||||
|         TRACE("parallel_tactic", display(tout);); | ||||
|         return std::min(m_num_threads, m_solvers.size()); | ||||
|     } | ||||
| 
 | ||||
|     int max_num_splits() { | ||||
|         if (m_solvers.empty()) { | ||||
|             return m_num_threads; | ||||
|         } | ||||
|         uint64 max_mem = memory::get_max_memory_size(); | ||||
|         uint64 cur_mem = memory::get_allocation_size(); | ||||
|         uint64 sol_sz = cur_mem / m_solvers.size(); | ||||
| 
 | ||||
|         TRACE("parallel_tactic", tout << "max mem: " << max_mem << " cur mem: " << cur_mem << " num solvers: " << m_solvers.size() << "\n";); | ||||
|         if (max_mem <= cur_mem) { | ||||
|             return 0; | ||||
|         } | ||||
|         if (cur_mem == 0) { | ||||
|             return m_num_threads; | ||||
|         } | ||||
|         uint64 extra_solvers = (max_mem - cur_mem) / (2 * sol_sz); | ||||
|         if (extra_solvers > m_num_threads) { | ||||
|             return m_num_threads; | ||||
|         } | ||||
|         return static_cast<int>(extra_solvers); | ||||
|     } | ||||
| 
 | ||||
|     void update_max_conflicts() { | ||||
|         if (should_increase_conflicts()) { | ||||
|             set_max_conflicts(std::min(m_conflicts_upper_bound, m_conflicts_growth_rate * get_max_conflicts() / 100)); | ||||
|         } | ||||
|         else { | ||||
|             set_max_conflicts(std::max(m_conflicts_lower_bound, m_conflicts_decay_rate * get_max_conflicts() / 100)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     lbool simplify(solver& s) { | ||||
|         params_ref p; | ||||
|         p.copy(m_params); | ||||
|         p.set_uint("max_conflicts", 10); | ||||
|         p.set_bool("lookahead_simplify", true); | ||||
|         s.updt_params(p); | ||||
|         lbool is_sat = s.check_sat(0,0); | ||||
|         p.set_uint("max_conflicts", get_max_conflicts()); | ||||
|         p.set_bool("lookahead_simplify", false); | ||||
|         s.updt_params(p); | ||||
|         return is_sat; | ||||
|     } | ||||
| 
 | ||||
|     lbool cube(solver_state& s) { | ||||
|         ast_manager& m = s.get_solver().get_manager(); | ||||
|         expr_ref_vector cubes(m); | ||||
|         params_ref p;		 | ||||
|         p.copy(s.params()); | ||||
|         p.set_uint("lookahead.cube.cutoff", 1); | ||||
|         s.get_solver().updt_params(p); | ||||
|         SASSERT(&m == &cubes.get_manager()); | ||||
|         while (true) { | ||||
|             expr_ref c = s.get_solver().cube(); | ||||
|             VERIFY(c); | ||||
|             if (m.is_false(c)) {                 | ||||
|                 break; | ||||
|             } | ||||
|             if (m.is_true(c)) { | ||||
|                 cubes.reset(); | ||||
|                 return l_undef; | ||||
|             } | ||||
|             cubes.push_back(c);             | ||||
|         } | ||||
| 
 | ||||
|         IF_VERBOSE(1, verbose_stream() << "cubes: " << cubes << "\n";); | ||||
| 
 | ||||
|         if (cubes.empty()) { | ||||
|             return l_false; | ||||
|         } | ||||
|         for (unsigned j = 1; j < cubes.size(); ++j) { | ||||
|             solver_state* s1 = s.clone(s.params(), cubes[j].get()); | ||||
|             #pragma omp critical (parallel_tactic) | ||||
|             { | ||||
|                 m_solvers.push_back(s1); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         expr* cube0 = cubes[0].get(); | ||||
|         s.add_cube(cube0); | ||||
|         s.get_solver().assert_expr(cube0); | ||||
|         return l_undef; | ||||
|     } | ||||
| 
 | ||||
|     lbool solve(solver& s) { | ||||
|         params_ref p; | ||||
|         p.copy(m_params); | ||||
|         p.set_uint("max_conflicts", get_max_conflicts()); | ||||
|         s.updt_params(p); | ||||
|         return s.check_sat(0, 0); | ||||
|     } | ||||
| 
 | ||||
|     void remove_unsat(svector<int>& unsat) { | ||||
|         std::sort(unsat.begin(), unsat.end()); | ||||
|         unsat.reverse(); | ||||
|         DEBUG_CODE(for (unsigned i = 0; i + 1 < unsat.size(); ++i) SASSERT(unsat[i] > unsat[i+1]);); | ||||
|         for (int i : unsat) { | ||||
|             m_solvers[i]->get_solver().collect_statistics(m_stats); | ||||
|             dealloc(m_solvers[i]); | ||||
|             for (unsigned j = i + 1; j < m_solvers.size(); ++j) { | ||||
|                 m_solvers[j - 1] = m_solvers[j]; | ||||
|             } | ||||
|             m_solvers.shrink(m_solvers.size() - 1); | ||||
|             update_progress(true);  | ||||
|         } | ||||
|         unsat.reset(); | ||||
|     } | ||||
| 
 | ||||
|     void get_model(model_ref& mdl, int sat_index) { | ||||
|         SASSERT(sat_index != -1); | ||||
|         m_solvers[sat_index]->get_solver().get_model(mdl); | ||||
|         ast_translation translate(m_solvers[sat_index]->get_solver().get_manager(), m_manager); | ||||
|         mdl = mdl->translate(translate); | ||||
|     } | ||||
| 
 | ||||
|     lbool solve(model_ref& mdl) {         | ||||
|         while (true) { | ||||
|             int sz = pick_solvers(); | ||||
| 
 | ||||
| 
 | ||||
|             if (sz == 0) { | ||||
|                 return l_false; | ||||
|             } | ||||
|             svector<int> unsat; | ||||
|             int sat_index = -1; | ||||
| 
 | ||||
|             // Simplify phase.
 | ||||
|             IF_VERBOSE(1, verbose_stream() << "(solver.parallel :simplify " << sz << ")\n";); | ||||
|             IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";); | ||||
| 
 | ||||
|             #pragma omp parallel for | ||||
|             for (int i = 0; i < sz; ++i) { | ||||
|                 lbool is_sat = simplify(m_solvers[i]->get_solver()); | ||||
|                 switch (is_sat) { | ||||
|                 case l_false:  | ||||
|                     #pragma omp critical (parallel_tactic) | ||||
|                     { | ||||
|                         unsat.push_back(i);  | ||||
|                     } | ||||
|                     break; | ||||
|                 case l_true:  | ||||
|                     sat_index = i;  | ||||
|                     break; | ||||
|                 case l_undef:  | ||||
|                     break;  | ||||
|                 } | ||||
|             } | ||||
|             if (sat_index != -1) { | ||||
|                 get_model(mdl, sat_index); | ||||
|                 return l_true;  | ||||
|             } | ||||
|             sz -= unsat.size(); | ||||
|             remove_unsat(unsat); | ||||
|             if (sz == 0) continue; | ||||
|              | ||||
|             // Solve phase.
 | ||||
|             IF_VERBOSE(1, verbose_stream() << "(solver.parallel :solve " << sz << ")\n";); | ||||
|             IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";); | ||||
| 
 | ||||
|             #pragma omp parallel for | ||||
|             for (int i = 0; i < sz; ++i) { | ||||
|                 lbool is_sat = solve(m_solvers[i]->get_solver()); | ||||
|                 switch (is_sat) { | ||||
|                 case l_false:  | ||||
|                     #pragma omp critical (parallel_tactic) | ||||
|                     { | ||||
|                         unsat.push_back(i);  | ||||
|                     } | ||||
|                     break; | ||||
|                 case l_true:  | ||||
|                     sat_index = i;  | ||||
|                     break; | ||||
|                 case l_undef:  | ||||
|                     break;  | ||||
|                 } | ||||
|             } | ||||
|             if (sat_index != -1) { | ||||
|                 get_model(mdl, sat_index); | ||||
|                 return l_true;  | ||||
|             } | ||||
|             sz -= unsat.size(); | ||||
|             remove_unsat(unsat); | ||||
| 
 | ||||
|             sz = std::min(max_num_splits(), sz); | ||||
|             if (sz == 0) continue; | ||||
|              | ||||
| 
 | ||||
|             // Split phase.            
 | ||||
|             IF_VERBOSE(1, verbose_stream() << "(solver.parallel :split " << sz << ")\n";); | ||||
|             IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";); | ||||
| 
 | ||||
|             #pragma omp parallel for | ||||
|             for (int i = 0; i < sz; ++i) {                 | ||||
|                 switch (cube(*m_solvers[i])) { | ||||
|                 case l_false: | ||||
|                     #pragma omp critical (parallel_tactic) | ||||
|                     { | ||||
|                         unsat.push_back(i);  | ||||
|                     } | ||||
|                     break; | ||||
|                 default: | ||||
|                     #pragma omp critical (parallel_tactic) | ||||
|                     { | ||||
|                         update_progress(false);  | ||||
|                     } | ||||
|                     break;                     | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             remove_unsat(unsat); | ||||
|             update_max_conflicts(); | ||||
|         } | ||||
|         return l_undef; | ||||
|     } | ||||
| 
 | ||||
|     std::ostream& display(std::ostream& out) { | ||||
|         for (solver_state* s : m_solvers) { | ||||
|             out << "solver units " << s->num_units() << "\n"; | ||||
|             out << "cube " << s->cube() << "\n"; | ||||
|         } | ||||
|         m_stats.display(out); | ||||
|         return out; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| public: | ||||
|     parallel_tactic(ast_manager& m, params_ref const& p) : | ||||
|         m_manager(m), | ||||
|         m_params(p) { | ||||
|         init(); | ||||
|     } | ||||
| 
 | ||||
|     void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) { | ||||
|         ast_manager& m = g->m(); | ||||
|         solver* s = mk_fd_solver(m, m_params); | ||||
|         m_solvers.push_back(alloc(solver_state, 0, s, m_params)); | ||||
|         expr_ref_vector clauses(m); | ||||
|         ptr_vector<expr> assumptions; | ||||
|         obj_map<expr, expr*> bool2dep; | ||||
|         ref<filter_model_converter> fmc; | ||||
|         extract_clauses_and_dependencies(g, clauses, assumptions, bool2dep, fmc); | ||||
|         for (expr * clause : clauses) { | ||||
|             s->assert_expr(clause); | ||||
|         } | ||||
|         SASSERT(assumptions.empty()); | ||||
|         model_ref mdl; | ||||
|         lbool is_sat = solve(mdl); | ||||
|         switch (is_sat) { | ||||
|         case l_true: | ||||
|             if (g->models_enabled()) { | ||||
|                 mc = model2model_converter(mdl.get()); | ||||
|                 mc = concat(fmc.get(), mc.get()); | ||||
|             } | ||||
|             g->reset(); | ||||
|             break; | ||||
|         case l_false: | ||||
|             SASSERT(!g->proofs_enabled()); | ||||
|             SASSERT(!g->unsat_core_enabled()); | ||||
|             g->assert_expr(m.mk_false(), nullptr, nullptr); | ||||
|             break; | ||||
|         case l_undef: | ||||
|             if (m.canceled()) { | ||||
|                 throw tactic_exception(Z3_CANCELED_MSG); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
|         result.push_back(g.get()); | ||||
|     } | ||||
| 
 | ||||
|     void cleanup() { | ||||
|         for (solver_state * s : m_solvers) dealloc(s); | ||||
|         m_solvers.reset(); | ||||
|         init(); | ||||
|     } | ||||
| 
 | ||||
|     tactic* translate(ast_manager& m) { | ||||
|         return alloc(parallel_tactic, m, m_params); | ||||
|     } | ||||
| 
 | ||||
|     virtual void updt_params(params_ref const & p) { | ||||
|         m_params.copy(p); | ||||
|     } | ||||
|     virtual void collect_param_descrs(param_descrs & r) { | ||||
|         // TBD
 | ||||
|     } | ||||
| 
 | ||||
|     virtual void collect_statistics(statistics & st) const { | ||||
|         for (solver_state const * s : m_solvers) { | ||||
|             s->get_solver().collect_statistics(st); | ||||
|         } | ||||
|         st.copy(m_stats); | ||||
|     } | ||||
|     virtual void reset_statistics() { | ||||
|         m_stats.reset(); | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| tactic * mk_parallel_tactic(ast_manager& m, params_ref const& p) { | ||||
|     return alloc(parallel_tactic, m, p); | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										31
									
								
								src/tactic/portfolio/parallel_tactic.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/tactic/portfolio/parallel_tactic.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | |||
| /*++
 | ||||
| Copyright (c) 2017 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     parallel_tactic.h | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Parallel tactic in the style of Treengeling. | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2017-10-9 | ||||
| 
 | ||||
| Notes: | ||||
|     | ||||
| --*/ | ||||
| #ifndef PARALLEL_TACTIC_H_ | ||||
| #define PARALLEL_TACTIC_H_ | ||||
| 
 | ||||
| class solver; | ||||
| class tactic; | ||||
| 
 | ||||
| tactic * mk_parallel_tactic(ast_manager& m, params_ref const& p); | ||||
| 
 | ||||
| /*
 | ||||
|     ADD_TACTIC("qffdp", "builtin strategy for solving QF_FD problems in parallel.", "mk_parallel_tactic(m, p)") | ||||
| */ | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										24
									
								
								src/tactic/portfolio/solver2lookahead.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/tactic/portfolio/solver2lookahead.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| /*++
 | ||||
| Copyright (c) 2017 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     solver2lookahead.cpp | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Lookahead wrapper for arbitrary solver. | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2017-10-9 | ||||
| 
 | ||||
| Notes: | ||||
|     | ||||
| --*/ | ||||
| #include "sat/sat_solver/inc_sat_solver.h" | ||||
| #include "solver/solver.h" | ||||
| 
 | ||||
| solver * mk_solver2lookahead(solver* s) { | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										26
									
								
								src/tactic/portfolio/solver2lookahead.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/tactic/portfolio/solver2lookahead.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| /*++
 | ||||
| Copyright (c) 2017 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     solver2lookahead.h | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Lookahead wrapper for arbitrary solver. | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2017-10-9 | ||||
| 
 | ||||
| Notes: | ||||
|     | ||||
| --*/ | ||||
| #ifndef SOLVER2LOOKAHEAD_H_ | ||||
| #define SOLVER2LOOKAHEAD_H_ | ||||
| 
 | ||||
| class solver; | ||||
| 
 | ||||
| solver * mk_solver2lookahead(solver* s); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -214,6 +214,10 @@ void tst_ddnf1() { | |||
|     ddnf.insert(*tX1); | ||||
|     ddnf.insert(*t1X);  | ||||
|     ddnf.display(std::cout); | ||||
|     tbvm.deallocate(tXX); | ||||
|     tbvm.deallocate(t1X); | ||||
|     tbvm.deallocate(tX1); | ||||
|     tbvm.deallocate(t11); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ public: | |||
|     static const unsigned long long zero = 0ull; | ||||
|     static const unsigned long long one  = 1ull; | ||||
| }; | ||||
| COMPILE_TIME_ASSERT(sizeof(unsigned long long) == 8); | ||||
| static_assert(sizeof(unsigned long long) == 8, ""); | ||||
| 
 | ||||
| template <> class approx_set_traits<unsigned> { | ||||
| public: | ||||
|  | @ -37,7 +37,7 @@ public: | |||
|     static const unsigned zero = 0; | ||||
|     static const unsigned one  = 1; | ||||
| }; | ||||
| COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); | ||||
| static_assert(sizeof(unsigned) == 4, "unsigned are 4 bytes"); | ||||
| 
 | ||||
| template<typename T, typename T2U_Proc, typename R=unsigned long long> | ||||
| class approx_set_tpl : private T2U_Proc { | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ Revision History: | |||
| #include "util/vector.h" | ||||
| #include "util/memory_manager.h" | ||||
| 
 | ||||
| COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); | ||||
| static_assert(sizeof(unsigned) == 4, "unsigned are 4 bytes"); | ||||
| #define BV_DEFAULT_CAPACITY 2 | ||||
| 
 | ||||
| class bit_vector { | ||||
|  |  | |||
|  | @ -90,7 +90,6 @@ bool is_debug_enabled(const char * tag); | |||
|         exit(-1);                                           \ | ||||
|     } | ||||
| 
 | ||||
| #define COMPILE_TIME_ASSERT(expr) static_assert(expr, "") | ||||
| 
 | ||||
| void finalize_debug(); | ||||
| /*
 | ||||
|  |  | |||
|  | @ -97,7 +97,7 @@ public: | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| COMPILE_TIME_ASSERT(sizeof(uint64) == sizeof(double)); | ||||
| static_assert(sizeof(uint64) == sizeof(double), ""); | ||||
| 
 | ||||
| #endif /* DOUBLE_MANAGER_H_ */ | ||||
| 
 | ||||
|  |  | |||
|  | @ -33,6 +33,7 @@ template void indexed_vector<unsigned>::resize(unsigned int); | |||
| template void indexed_vector<mpq>::set_value(const mpq&, unsigned int); | ||||
| template void indexed_vector<unsigned>::set_value(const unsigned&, unsigned int); | ||||
| #ifdef Z3DEBUG | ||||
| template bool indexed_vector<unsigned>::is_OK() const; | ||||
| template bool indexed_vector<double>::is_OK() const; | ||||
| template bool indexed_vector<mpq>::is_OK() const; | ||||
| template bool indexed_vector<lp::numeric_pair<mpq> >::is_OK() const; | ||||
|  |  | |||
|  | @ -417,6 +417,8 @@ public: | |||
| 
 | ||||
|         for (unsigned i : m_rows_with_changed_bounds.m_index) { | ||||
|             calculate_implied_bounds_for_row(i, bp); | ||||
|             if (settings().get_cancel_flag()) | ||||
|                 return; | ||||
|         } | ||||
|         m_rows_with_changed_bounds.clear(); | ||||
|         if (!use_tableau()) { | ||||
|  |  | |||
|  | @ -176,25 +176,34 @@ unsigned lp_primal_core_solver<T, X>::solve_with_tableau() { | |||
|         default: | ||||
|             break; // do nothing
 | ||||
|         } | ||||
|     } while (this->get_status() != FLOATING_POINT_ERROR | ||||
|              && | ||||
|              this->get_status() != UNBOUNDED | ||||
|              && | ||||
|              this->get_status() != OPTIMAL | ||||
|              && | ||||
|              this->get_status() != INFEASIBLE | ||||
|              && | ||||
|              this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements | ||||
|              && | ||||
|              this->total_iterations() <= this->m_settings.max_total_number_of_iterations | ||||
|              && | ||||
|              !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)); | ||||
| 	} while (this->get_status() != FLOATING_POINT_ERROR | ||||
| 		&& | ||||
| 		this->get_status() != UNBOUNDED | ||||
| 		&& | ||||
| 		this->get_status() != OPTIMAL | ||||
| 		&& | ||||
| 		this->get_status() != INFEASIBLE | ||||
| 		&& | ||||
| 		this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements | ||||
| 		&& | ||||
| 		this->total_iterations() <= this->m_settings.max_total_number_of_iterations | ||||
| 		&& | ||||
| 		!(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) | ||||
| 		&& | ||||
| 		this->m_settings.get_cancel_flag() == false); | ||||
| 	 | ||||
| 	if (this->m_settings.get_cancel_flag()) { | ||||
|             this->set_status(CANCELLED); | ||||
| 	} | ||||
| 
 | ||||
|     SASSERT(this->get_status() == FLOATING_POINT_ERROR | ||||
|                 || | ||||
|                 this->current_x_is_feasible() == false | ||||
|                 || | ||||
|                 this->calc_current_x_is_feasible_include_non_basis()); | ||||
| 	SASSERT( | ||||
|             this->get_status() == FLOATING_POINT_ERROR | ||||
|             || | ||||
|             this->get_status() == CANCELLED | ||||
|             || | ||||
|             this->current_x_is_feasible() == false | ||||
|             || | ||||
|             this->calc_current_x_is_feasible_include_non_basis()); | ||||
|     return this->total_iterations(); | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -61,7 +61,8 @@ enum lp_status { | |||
|     TIME_EXHAUSTED, | ||||
|     ITERATIONS_EXHAUSTED, | ||||
|     EMPTY, | ||||
|     UNSTABLE | ||||
|     UNSTABLE, | ||||
|     CANCELLED | ||||
| }; | ||||
| 
 | ||||
| // when the ratio of the vector lenth to domain size to is greater than the return value we switch to solve_By_for_T_indexed_only
 | ||||
|  |  | |||
|  | @ -58,9 +58,10 @@ static void throw_out_of_memory() { | |||
|         g_memory_out_of_memory = true; | ||||
|     } | ||||
| 
 | ||||
|     __assume(0); | ||||
| 
 | ||||
|     if (g_exit_when_out_of_memory) { | ||||
|         std::cerr << g_out_of_memory_msg << "\n"; | ||||
|         __assume(0); | ||||
|         exit(ERR_MEMOUT); | ||||
|     } | ||||
|     else { | ||||
|  | @ -181,6 +182,23 @@ unsigned long long memory::get_max_used_memory() { | |||
|     return r; | ||||
| } | ||||
| 
 | ||||
| #if defined(_WINDOWS) | ||||
| #include "Windows.h" | ||||
| #endif | ||||
| 
 | ||||
| unsigned long long memory::get_max_memory_size() { | ||||
| #if defined(_WINDOWS)     | ||||
|     MEMORYSTATUSEX statex;     | ||||
|     statex.dwLength = sizeof (statex);     | ||||
|     GlobalMemoryStatusEx (&statex); | ||||
|     return statex.ullTotalPhys; | ||||
| #else | ||||
|     NOT_IMPLEMENTED_YET(); | ||||
|     // two GB
 | ||||
|     return 1 << 31; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| unsigned long long memory::get_allocation_count() { | ||||
|     return g_memory_alloc_count; | ||||
| } | ||||
|  |  | |||
|  | @ -67,6 +67,7 @@ public: | |||
|     static unsigned long long get_allocation_size(); | ||||
|     static unsigned long long get_max_used_memory(); | ||||
|     static unsigned long long get_allocation_count(); | ||||
|     static unsigned long long get_max_memory_size(); | ||||
|     // temporary hack to avoid out-of-memory crash in z3.exe
 | ||||
|     static void exit_when_out_of_memory(bool flag, char const * msg); | ||||
| }; | ||||
|  |  | |||
|  | @ -73,7 +73,7 @@ mpf_manager::~mpf_manager() { | |||
| } | ||||
| 
 | ||||
| void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, int value) { | ||||
|     COMPILE_TIME_ASSERT(sizeof(int) == 4); | ||||
|     static_assert(sizeof(int) == 4, "assume integers are 4 bytes"); | ||||
| 
 | ||||
|     o.sign = false; | ||||
|     o.ebits = ebits; | ||||
|  | @ -119,7 +119,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode | |||
| 
 | ||||
| void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, double value) { | ||||
|     // double === mpf(11, 53)
 | ||||
|     COMPILE_TIME_ASSERT(sizeof(double) == 8); | ||||
|     static_assert(sizeof(double) == 8, "doubles are 8 bytes"); | ||||
| 
 | ||||
|     uint64 raw; | ||||
|     memcpy(&raw, &value, sizeof(double)); | ||||
|  | @ -155,7 +155,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, double value) { | |||
| 
 | ||||
| void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, float value) { | ||||
|     // single === mpf(8, 24)
 | ||||
|     COMPILE_TIME_ASSERT(sizeof(float) == 4); | ||||
|     static_assert(sizeof(float) == 4, "floats are 4 bytes"); | ||||
| 
 | ||||
|     unsigned int raw; | ||||
|     memcpy(&raw, &value, sizeof(float)); | ||||
|  |  | |||
|  | @ -27,8 +27,8 @@ Revision History: | |||
| #include "util/bit_util.h" | ||||
| #include "util/trace.h" | ||||
| 
 | ||||
| COMPILE_TIME_ASSERT(sizeof(mpn_digit) == sizeof(unsigned)); | ||||
| COMPILE_TIME_ASSERT(sizeof(unsigned)  == 4); | ||||
| static_assert(sizeof(mpn_digit) == sizeof(unsigned), ""); | ||||
| static_assert(sizeof(unsigned)  == 4, "unsigned haven't changed size for a while"); | ||||
| 
 | ||||
| // MIN_MSW is an shorthand for 0x8000..00, i.e., the minimal most significand word.
 | ||||
| #define MIN_MSW (1u << (sizeof(unsigned) * 8 - 1)) | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ Revision History: | |||
| #define max(a,b)    (((a) > (b)) ? (a) : (b)) | ||||
| 
 | ||||
| typedef uint64 mpn_double_digit; | ||||
| COMPILE_TIME_ASSERT(sizeof(mpn_double_digit) == 2 * sizeof(mpn_digit)); | ||||
| static_assert(sizeof(mpn_double_digit) == 2 * sizeof(mpn_digit), "size alignment"); | ||||
| 
 | ||||
| const mpn_digit mpn_manager::zero = 0; | ||||
| 
 | ||||
|  |  | |||
|  | @ -558,14 +558,13 @@ void mpz_manager<SYNCH>::big_rem(mpz const & a, mpz const & b, mpz & c) { | |||
| 
 | ||||
| template<bool SYNCH> | ||||
| void mpz_manager<SYNCH>::gcd(mpz const & a, mpz const & b, mpz & c) { | ||||
|     if (is_small(a) && is_small(b)) { | ||||
|     static_assert(sizeof(a.m_val) == sizeof(int), "size mismatch"); | ||||
|     if (is_small(a) && is_small(b) && a.m_val != INT_MIN && b.m_val != INT_MIN) { | ||||
|         int _a = a.m_val; | ||||
|         int _b = b.m_val; | ||||
|         if (_a < 0) _a = -_a; | ||||
|         if (_b < 0) _b = -_b; | ||||
|         unsigned r = u_gcd(_a, _b); | ||||
|         // Remark: r is (INT_MAX + 1)
 | ||||
|         // If a == b == INT_MIN
 | ||||
|         set(c, r); | ||||
|     } | ||||
|     else { | ||||
|  | @ -725,7 +724,7 @@ void mpz_manager<SYNCH>::gcd(mpz const & a, mpz const & b, mpz & c) { | |||
| 
 | ||||
| #ifdef LEHMER_GCD | ||||
|         // For now, it only works if sizeof(digit_t) == sizeof(unsigned)
 | ||||
|         COMPILE_TIME_ASSERT(sizeof(digit_t) == sizeof(unsigned)); | ||||
|         static_assert(sizeof(digit_t) == sizeof(unsigned), ""); | ||||
|          | ||||
|         int64 a_hat, b_hat, A, B, C, D, T, q, a_sz, b_sz; | ||||
|         mpz a1, b1, t, r, tmp; | ||||
|  | @ -1755,7 +1754,7 @@ void mpz_manager<SYNCH>::mul2k(mpz & a, unsigned k) { | |||
| } | ||||
| 
 | ||||
| #ifndef _MP_GMP | ||||
| COMPILE_TIME_ASSERT(sizeof(digit_t) == 4 || sizeof(digit_t) == 8); | ||||
| static_assert(sizeof(digit_t) == 4 || sizeof(digit_t) == 8, ""); | ||||
| #endif | ||||
| 
 | ||||
| template<bool SYNCH> | ||||
|  | @ -1822,7 +1821,7 @@ unsigned mpz_manager<SYNCH>::log2(mpz const & a) { | |||
|     if (is_small(a)) | ||||
|         return ::log2((unsigned)a.m_val); | ||||
| #ifndef _MP_GMP | ||||
|     COMPILE_TIME_ASSERT(sizeof(digit_t) == 8 || sizeof(digit_t) == 4); | ||||
|     static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, ""); | ||||
|     mpz_cell * c     = a.m_ptr; | ||||
|     unsigned sz      = c->m_size; | ||||
|     digit_t * ds     = c->m_digits;  | ||||
|  | @ -1844,7 +1843,7 @@ unsigned mpz_manager<SYNCH>::mlog2(mpz const & a) { | |||
|     if (is_small(a)) | ||||
|         return ::log2((unsigned)-a.m_val); | ||||
| #ifndef _MP_GMP | ||||
|     COMPILE_TIME_ASSERT(sizeof(digit_t) == 8 || sizeof(digit_t) == 4); | ||||
|     static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, ""); | ||||
|     mpz_cell * c     = a.m_ptr; | ||||
|     unsigned sz      = c->m_size; | ||||
|     digit_t * ds     = c->m_digits;  | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ Revision History: | |||
| 
 | ||||
| reslimit::reslimit(): | ||||
|     m_cancel(0), | ||||
|     m_suspend(false), | ||||
|     m_count(0), | ||||
|     m_limit(0) { | ||||
| } | ||||
|  | @ -31,12 +32,12 @@ uint64 reslimit::count() const { | |||
| 
 | ||||
| bool reslimit::inc() { | ||||
|     ++m_count; | ||||
|     return m_cancel == 0 && (m_limit == 0 || m_count <= m_limit); | ||||
|     return (m_cancel == 0 && (m_limit == 0 || m_count <= m_limit)) || m_suspend; | ||||
| } | ||||
| 
 | ||||
| bool reslimit::inc(unsigned offset) { | ||||
|     m_count += offset; | ||||
|     return m_cancel == 0 && (m_limit == 0 || m_count <= m_limit); | ||||
|     return (m_cancel == 0 && (m_limit == 0 || m_count <= m_limit)) || m_suspend; | ||||
| } | ||||
| 
 | ||||
| void reslimit::push(unsigned delta_limit) { | ||||
|  |  | |||
|  | @ -23,12 +23,14 @@ Revision History: | |||
| 
 | ||||
| class reslimit { | ||||
|     volatile unsigned   m_cancel; | ||||
|     bool            m_suspend; | ||||
|     uint64          m_count; | ||||
|     uint64          m_limit; | ||||
|     svector<uint64> m_limits; | ||||
|     ptr_vector<reslimit> m_children; | ||||
| 
 | ||||
|     void set_cancel(unsigned f); | ||||
|     friend class scoped_suspend_rlimit; | ||||
| 
 | ||||
| public: | ||||
|     reslimit(); | ||||
|  | @ -42,7 +44,7 @@ public: | |||
|     uint64 count() const; | ||||
| 
 | ||||
| 
 | ||||
|     bool get_cancel_flag() const { return m_cancel > 0; } | ||||
|     bool get_cancel_flag() const { return m_cancel > 0 && !m_suspend; } | ||||
|     char const* get_cancel_msg() const; | ||||
|     void cancel(); | ||||
|     void reset_cancel(); | ||||
|  | @ -61,6 +63,17 @@ public: | |||
| 
 | ||||
| }; | ||||
| 
 | ||||
| class scoped_suspend_rlimit { | ||||
|     reslimit & m_limit; | ||||
| public: | ||||
|     scoped_suspend_rlimit(reslimit& r): m_limit(r) { | ||||
|         r.m_suspend = true; | ||||
|     } | ||||
|     ~scoped_suspend_rlimit() { | ||||
|         m_limit.m_suspend = false; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| struct scoped_limits { | ||||
|     reslimit&  m_limit; | ||||
|     unsigned   m_sz; | ||||
|  |  | |||
|  | @ -469,7 +469,9 @@ Notes: | |||
|         } | ||||
| 
 | ||||
|         literal mk_ordered_1(bool full, bool is_eq, unsigned n, literal const* xs) { | ||||
|             if (n <= 1 && !is_eq) return ctx.mk_true(); | ||||
|             if (n <= 1 && !is_eq) { | ||||
|                 return ctx.mk_true(); | ||||
|             } | ||||
|             if (n == 0) { | ||||
|                 return ctx.mk_false(); | ||||
|             } | ||||
|  | @ -477,6 +479,8 @@ Notes: | |||
|                 return xs[0]; | ||||
|             } | ||||
| 
 | ||||
|             SASSERT(n > 1); | ||||
| 
 | ||||
|             // y0 -> y1
 | ||||
|             // x0 -> y0
 | ||||
|             // x1 -> y1
 | ||||
|  |  | |||
|  | @ -22,7 +22,6 @@ Revision History: | |||
| #include "util/util.h" | ||||
| #include "util/vector.h" | ||||
| 
 | ||||
| COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); | ||||
| 
 | ||||
| class uint_set : unsigned_vector { | ||||
|      | ||||
|  |  | |||
|  | @ -34,13 +34,13 @@ Revision History: | |||
| typedef unsigned long long uint64; | ||||
| #endif | ||||
| 
 | ||||
| COMPILE_TIME_ASSERT(sizeof(uint64) == 8); | ||||
| static_assert(sizeof(uint64) == 8, "64 bits please"); | ||||
| 
 | ||||
| #ifndef int64 | ||||
| typedef long long int64; | ||||
| #endif | ||||
| 
 | ||||
| COMPILE_TIME_ASSERT(sizeof(int64) == 8); | ||||
| static_assert(sizeof(int64) == 8, "64 bits"); | ||||
| 
 | ||||
| #ifndef INT64_MIN | ||||
| #define INT64_MIN static_cast<int64>(0x8000000000000000ull) | ||||
|  | @ -112,7 +112,7 @@ inline unsigned next_power_of_two(unsigned v) { | |||
| unsigned log2(unsigned v); | ||||
| unsigned uint64_log2(uint64 v); | ||||
| 
 | ||||
| COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); | ||||
| static_assert(sizeof(unsigned) == 4, "unsigned are 32 bits"); | ||||
| 
 | ||||
| // Return the number of 1 bits in v.
 | ||||
| static inline unsigned get_num_1bits(unsigned v) { | ||||
|  |  | |||
|  | @ -72,6 +72,7 @@ class vector { | |||
|             SZ new_capacity = (3 * old_capacity + 1) >> 1; | ||||
|             SZ new_capacity_T = sizeof(T) * new_capacity + sizeof(SZ) * 2; | ||||
|             if (new_capacity <= old_capacity || new_capacity_T <= old_capacity_T) { | ||||
|                 UNREACHABLE(); | ||||
|                 throw default_exception("Overflow encountered when expanding vector"); | ||||
|             } | ||||
|             SZ *mem = (SZ*)memory::reallocate(reinterpret_cast<SZ*>(m_data)-2, new_capacity_T); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue