mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	merge
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
						commit
						c1b243a8e3
					
				
					 45 changed files with 1345 additions and 699 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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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('\\', '\\\\')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -120,7 +120,7 @@ def _get_args(args):
 | 
			
		|||
    try:
 | 
			
		||||
        if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)):
 | 
			
		||||
            return args[0]
 | 
			
		||||
        elif len(args) == 1 and isinstance(args[0], set):
 | 
			
		||||
        elif len(args) == 1 and (isinstance(args[0], set) or isinstance(args[0], AstVector)):
 | 
			
		||||
            return [arg for arg in args[0]]
 | 
			
		||||
        else:
 | 
			
		||||
            return args
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -151,11 +151,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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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());
 | 
			
		||||
                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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,7 @@ Author:
 | 
			
		|||
 | 
			
		||||
#include "tactic/bv/bv_bounds_tactic.h"
 | 
			
		||||
#include "tactic/core/ctx_simplify_tactic.h"
 | 
			
		||||
#include "tactic/core/dom_simplify_tactic.h"
 | 
			
		||||
#include "ast/bv_decl_plugin.h"
 | 
			
		||||
#include "ast/ast_pp.h"
 | 
			
		||||
#include <climits>
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +30,7 @@ static uint64 uMaxInt(unsigned sz) {
 | 
			
		|||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
struct interval {
 | 
			
		||||
    struct interval {
 | 
			
		||||
        // l < h: [l, h]
 | 
			
		||||
        // l > h: [0, h] U [l, UMAX_INT]
 | 
			
		||||
        uint64 l, h;
 | 
			
		||||
| 
						 | 
				
			
			@ -70,11 +71,13 @@ struct interval {
 | 
			
		|||
            if (is_wrapped()) {
 | 
			
		||||
                // l >= b.l >= b.h >= h
 | 
			
		||||
                return b.is_wrapped() && h <= b.h && l >= b.l;
 | 
			
		||||
        } else if (b.is_wrapped()) {
 | 
			
		||||
            } 
 | 
			
		||||
            else if (b.is_wrapped()) {
 | 
			
		||||
                // b.l > b.h >= h >= l
 | 
			
		||||
                // h >= l >= b.l > b.h
 | 
			
		||||
                return h <= b.h || l >= b.l;
 | 
			
		||||
        } else {
 | 
			
		||||
            } 
 | 
			
		||||
            else {
 | 
			
		||||
                // 
 | 
			
		||||
                return l >= b.l && h <= b.h;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +106,8 @@ struct interval {
 | 
			
		|||
                } else {
 | 
			
		||||
                    return b.intersect(*this, result);
 | 
			
		||||
                }
 | 
			
		||||
        } else if (b.is_wrapped()) {
 | 
			
		||||
            } 
 | 
			
		||||
            else if (b.is_wrapped()) {
 | 
			
		||||
                // ... b.h ... l ... h ... b.l ..
 | 
			
		||||
                if (h < b.l && l > b.h) {
 | 
			
		||||
                    return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -146,24 +150,24 @@ struct interval {
 | 
			
		|||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
#ifdef _TRACE
 | 
			
		||||
std::ostream& operator<<(std::ostream& o, const interval& I) {
 | 
			
		||||
    std::ostream& operator<<(std::ostream& o, const interval& I) {
 | 
			
		||||
        o << "[" << I.l << ", " << I.h << "]";
 | 
			
		||||
        return o;
 | 
			
		||||
}
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct undo_bound {
 | 
			
		||||
    struct undo_bound {
 | 
			
		||||
        expr* e;
 | 
			
		||||
        interval b;
 | 
			
		||||
        bool fresh;
 | 
			
		||||
        undo_bound(expr* e, const interval& b, bool fresh) : e(e), b(b), fresh(fresh) {}
 | 
			
		||||
};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier {
 | 
			
		||||
    class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier {
 | 
			
		||||
        typedef obj_map<expr, interval> map;
 | 
			
		||||
        typedef obj_map<expr, bool> expr_set;
 | 
			
		||||
        typedef obj_map<expr, unsigned> expr_cnt;
 | 
			
		||||
| 
						 | 
				
			
			@ -188,7 +192,7 @@ class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier {
 | 
			
		|||
 | 
			
		||||
        bool is_bound(expr *e, expr*& v, interval& b) const {
 | 
			
		||||
            uint64 n;
 | 
			
		||||
        expr *lhs, *rhs;
 | 
			
		||||
            expr *lhs = 0, *rhs = 0;
 | 
			
		||||
            unsigned sz;
 | 
			
		||||
 | 
			
		||||
            if (m_bv.is_bv_ule(e, lhs, rhs)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -204,7 +208,8 @@ class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier {
 | 
			
		|||
                    v = lhs;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
        } else if (m_bv.is_bv_sle(e, lhs, rhs)) {
 | 
			
		||||
            } 
 | 
			
		||||
            else if (m_bv.is_bv_sle(e, lhs, rhs)) {
 | 
			
		||||
                if (is_number(lhs, n, sz)) { // C sle x <=> x sge C
 | 
			
		||||
                    if (m_bv.is_numeral(rhs))
 | 
			
		||||
                        return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -293,7 +298,7 @@ class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier {
 | 
			
		|||
        }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    public:
 | 
			
		||||
        bv_bounds_simplifier(ast_manager& m, params_ref const& p) : m(m), m_params(p), m_bv(m) {
 | 
			
		||||
            updt_params(p);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -526,10 +531,284 @@ public:
 | 
			
		|||
        virtual unsigned scope_level() const {
 | 
			
		||||
            return m_scopes.size();
 | 
			
		||||
        }
 | 
			
		||||
};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class dom_bv_bounds_simplifier : public dom_simplifier {
 | 
			
		||||
        typedef obj_map<expr, interval> map;
 | 
			
		||||
        typedef obj_map<expr, bool> expr_set;
 | 
			
		||||
        typedef obj_map<expr, unsigned> expr_cnt;
 | 
			
		||||
 | 
			
		||||
        ast_manager&       m;
 | 
			
		||||
        params_ref         m_params;
 | 
			
		||||
        bool               m_propagate_eq;
 | 
			
		||||
        bv_util            m_bv;
 | 
			
		||||
        vector<undo_bound> m_scopes;
 | 
			
		||||
        map                m_bound;
 | 
			
		||||
        svector<expr_set*> m_expr_vars;
 | 
			
		||||
        svector<expr_cnt*> m_bound_exprs;
 | 
			
		||||
 | 
			
		||||
        bool is_number(expr *e, uint64& n, unsigned& sz) const {
 | 
			
		||||
            rational r;
 | 
			
		||||
            if (m_bv.is_numeral(e, r, sz) && sz <= 64) {
 | 
			
		||||
                n = r.get_uint64();
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool is_bound(expr *e, expr*& v, interval& b) const {
 | 
			
		||||
            uint64 n;
 | 
			
		||||
            expr *lhs = 0, *rhs = 0;
 | 
			
		||||
            unsigned sz = 0;
 | 
			
		||||
 | 
			
		||||
            if (m_bv.is_bv_ule(e, lhs, rhs)) {
 | 
			
		||||
                if (is_number(lhs, n, sz)) { // C ule x <=> x uge C
 | 
			
		||||
                    if (m_bv.is_numeral(rhs))
 | 
			
		||||
                        return false;
 | 
			
		||||
                    b = interval(n, uMaxInt(sz), sz, true);
 | 
			
		||||
                    v = rhs;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                if (is_number(rhs, n, sz)) { // x ule C
 | 
			
		||||
                    b = interval(0, n, sz, true);
 | 
			
		||||
                    v = lhs;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            } 
 | 
			
		||||
            else if (m_bv.is_bv_sle(e, lhs, rhs)) {
 | 
			
		||||
                if (is_number(lhs, n, sz)) { // C sle x <=> x sge C
 | 
			
		||||
                    if (m_bv.is_numeral(rhs))
 | 
			
		||||
                        return false;
 | 
			
		||||
                    b = interval(n, (1ull << (sz-1)) - 1, sz, true);
 | 
			
		||||
                    v = rhs;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                if (is_number(rhs, n, sz)) { // x sle C
 | 
			
		||||
                    b = interval(1ull << (sz-1), n, sz, true);
 | 
			
		||||
                    v = lhs;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            } else if (m.is_eq(e, lhs, rhs)) {
 | 
			
		||||
                if (is_number(lhs, n, sz)) {
 | 
			
		||||
                    if (m_bv.is_numeral(rhs))
 | 
			
		||||
                        return false;
 | 
			
		||||
                    b = interval(n, n, sz, true);
 | 
			
		||||
                    v = rhs;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                if (is_number(rhs, n, sz)) {
 | 
			
		||||
                    b = interval(n, n, sz, true);
 | 
			
		||||
                    v = lhs;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        dom_bv_bounds_simplifier(ast_manager& m, params_ref const& p) : m(m), m_params(p), m_bv(m) {
 | 
			
		||||
            updt_params(p);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual void updt_params(params_ref const & p) {
 | 
			
		||||
            m_propagate_eq = p.get_bool("propagate_eq", false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static void get_param_descrs(param_descrs& r) {
 | 
			
		||||
            r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual ~dom_bv_bounds_simplifier() {
 | 
			
		||||
            for (unsigned i = 0, e = m_expr_vars.size(); i < e; ++i) {
 | 
			
		||||
                dealloc(m_expr_vars[i]);
 | 
			
		||||
            }
 | 
			
		||||
            for (unsigned i = 0, e = m_bound_exprs.size(); i < e; ++i) {
 | 
			
		||||
                dealloc(m_bound_exprs[i]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual bool assert_expr(expr * t, bool sign) {
 | 
			
		||||
            while (m.is_not(t, t)) {
 | 
			
		||||
                sign = !sign;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            interval b;
 | 
			
		||||
            expr* t1;
 | 
			
		||||
            if (is_bound(t, t1, b)) {
 | 
			
		||||
                SASSERT(!m_bv.is_numeral(t1));
 | 
			
		||||
                if (sign)
 | 
			
		||||
                    VERIFY(b.negate(b));
 | 
			
		||||
 | 
			
		||||
                TRACE("bv", tout << (sign?"(not ":"") << mk_pp(t, m) << (sign ? ")" : "") << ": " << mk_pp(t1, m) << " in " << b << "\n";);
 | 
			
		||||
                map::obj_map_entry* e = m_bound.find_core(t1);
 | 
			
		||||
                if (e) {
 | 
			
		||||
                    interval& old = e->get_data().m_value;
 | 
			
		||||
                    interval intr;
 | 
			
		||||
                    if (!old.intersect(b, intr))
 | 
			
		||||
                        return false;
 | 
			
		||||
                    if (old == intr)
 | 
			
		||||
                        return true;
 | 
			
		||||
                    m_scopes.insert(undo_bound(t1, old, false));
 | 
			
		||||
                    old = intr;
 | 
			
		||||
                } else {
 | 
			
		||||
                    m_bound.insert(t1, b);
 | 
			
		||||
                    m_scopes.insert(undo_bound(t1, interval(), true));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual void operator()(expr_ref& r) {
 | 
			
		||||
            expr* t1, * t = r;
 | 
			
		||||
            interval b;
 | 
			
		||||
 | 
			
		||||
            if (m_bound.find(t, b) && b.is_singleton()) {
 | 
			
		||||
                r = m_bv.mk_numeral(b.l, m_bv.get_bv_size(t));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!m.is_bool(t))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            bool sign = false;
 | 
			
		||||
            while (m.is_not(t, t)) {
 | 
			
		||||
                sign = !sign;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!is_bound(t, t1, b))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (sign && b.tight) {
 | 
			
		||||
                sign = false;
 | 
			
		||||
                if (!b.negate(b)) {
 | 
			
		||||
                    r = m.mk_false();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            interval ctx, intr;
 | 
			
		||||
            bool was_updated = true;
 | 
			
		||||
            if (b.is_full() && b.tight) {
 | 
			
		||||
                r = m.mk_true();
 | 
			
		||||
            } else if (m_bound.find(t1, ctx)) {
 | 
			
		||||
                if (ctx.implies(b)) {
 | 
			
		||||
                    r = m.mk_true();
 | 
			
		||||
                } 
 | 
			
		||||
                else if (!b.intersect(ctx, intr)) {
 | 
			
		||||
                    r = m.mk_false();
 | 
			
		||||
                } 
 | 
			
		||||
                else if (m_propagate_eq && intr.is_singleton()) {
 | 
			
		||||
                    r = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()),
 | 
			
		||||
                                                    m.get_sort(t1)));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                was_updated = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            CTRACE("bv", was_updated, tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << r << "\n";);
 | 
			
		||||
            if (sign && was_updated)
 | 
			
		||||
                r = m.mk_not(r);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // check if t contains v
 | 
			
		||||
        ptr_vector<expr> todo;
 | 
			
		||||
        bool contains(expr* t, expr* v) {
 | 
			
		||||
            ast_fast_mark1 mark;
 | 
			
		||||
            todo.push_back(t);
 | 
			
		||||
            while (!todo.empty()) {
 | 
			
		||||
                t = todo.back();
 | 
			
		||||
                todo.pop_back();
 | 
			
		||||
                if (mark.is_marked(t)) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                if (t == v) {
 | 
			
		||||
                    todo.reset();
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                mark.mark(t);
 | 
			
		||||
            
 | 
			
		||||
                if (!is_app(t)) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                app* a = to_app(t);
 | 
			
		||||
                todo.append(a->get_num_args(), a->get_args());
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool contains_bound(expr* t) {
 | 
			
		||||
            ast_fast_mark1 mark1;
 | 
			
		||||
            ast_fast_mark2 mark2;
 | 
			
		||||
 | 
			
		||||
            todo.push_back(t);
 | 
			
		||||
            while (!todo.empty()) {
 | 
			
		||||
                t = todo.back();
 | 
			
		||||
                todo.pop_back();
 | 
			
		||||
                if (mark1.is_marked(t)) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                mark1.mark(t);
 | 
			
		||||
            
 | 
			
		||||
                if (!is_app(t)) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                interval b;
 | 
			
		||||
                expr* e;
 | 
			
		||||
                if (is_bound(t, e, b)) {
 | 
			
		||||
                    if (mark2.is_marked(e)) {
 | 
			
		||||
                        todo.reset();
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    mark2.mark(e);
 | 
			
		||||
                    if (m_bound.contains(e)) {
 | 
			
		||||
                        todo.reset();
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                app* a = to_app(t);
 | 
			
		||||
                todo.append(a->get_num_args(), a->get_args());
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual void pop(unsigned num_scopes) {
 | 
			
		||||
            TRACE("bv", tout << "pop: " << num_scopes << "\n";);
 | 
			
		||||
            if (m_scopes.empty())
 | 
			
		||||
                return;
 | 
			
		||||
            unsigned target = m_scopes.size() - num_scopes;
 | 
			
		||||
            if (target == 0) {
 | 
			
		||||
                m_bound.reset();
 | 
			
		||||
                m_scopes.reset();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            for (unsigned i = m_scopes.size()-1; i >= target; --i) {
 | 
			
		||||
                undo_bound& undo = m_scopes[i];
 | 
			
		||||
                SASSERT(m_bound.contains(undo.e));
 | 
			
		||||
                if (undo.fresh) {
 | 
			
		||||
                    m_bound.erase(undo.e);
 | 
			
		||||
                } else {
 | 
			
		||||
                    m_bound.insert(undo.e, undo.b);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            m_scopes.shrink(target);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        virtual dom_simplifier * translate(ast_manager & m) {
 | 
			
		||||
            return alloc(dom_bv_bounds_simplifier, m, m_params);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tactic * mk_bv_bounds_tactic(ast_manager & m, params_ref const & p) {
 | 
			
		||||
    return clean(alloc(ctx_simplify_tactic, m, alloc(bv_bounds_simplifier, m, p), p));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tactic * mk_dom_bv_bounds_tactic(ast_manager & m, params_ref const & p) {
 | 
			
		||||
    return clean(alloc(dom_simplify_tactic, m, alloc(dom_bv_bounds_simplifier, m, p), p));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,30 +83,45 @@ 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() {
 | 
			
		||||
| 
						 | 
				
			
			@ -115,17 +130,19 @@ void expr_dominators::extract_tree() {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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,11 +154,31 @@ 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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -164,31 +201,40 @@ 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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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();
 | 
			
		||||
 | 
			
		||||
    auto is_subexpr_arg = [&](expr * child, expr * except) {
 | 
			
		||||
        if (!is_subexpr(child, except))
 | 
			
		||||
            return false;
 | 
			
		||||
        for (expr * arg : *e) {
 | 
			
		||||
        r = simplify(arg);
 | 
			
		||||
        if (!assert_expr(r, !is_and)) {
 | 
			
		||||
            r = is_and ? m.mk_false() : m.mk_true();
 | 
			
		||||
            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,24 +45,28 @@ 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_simplify_tactic : public tactic {
 | 
			
		||||
public:
 | 
			
		||||
    class simplifier {
 | 
			
		||||
class dom_simplifier {
 | 
			
		||||
 public:
 | 
			
		||||
        virtual ~simplifier() {}
 | 
			
		||||
    dom_simplifier() {}
 | 
			
		||||
    
 | 
			
		||||
    virtual ~dom_simplifier() {}
 | 
			
		||||
    /**
 | 
			
		||||
       \brief assert_expr performs an implicit push
 | 
			
		||||
    */
 | 
			
		||||
| 
						 | 
				
			
			@ -76,45 +82,55 @@ public:
 | 
			
		|||
    */
 | 
			
		||||
    virtual void pop(unsigned num_scopes) = 0;
 | 
			
		||||
    
 | 
			
		||||
        virtual simplifier * translate(ast_manager & m);
 | 
			
		||||
    virtual dom_simplifier * translate(ast_manager & m) = 0;
 | 
			
		||||
    
 | 
			
		||||
    };
 | 
			
		||||
private:
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class dom_simplify_tactic : public tactic {
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -188,9 +188,18 @@ unsigned lp_primal_core_solver<T, X>::solve_with_tableau() {
 | 
			
		|||
		&&
 | 
			
		||||
		this->total_iterations() <= this->m_settings.max_total_number_of_iterations
 | 
			
		||||
		&&
 | 
			
		||||
             !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only));
 | 
			
		||||
		!(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)
 | 
			
		||||
		&&
 | 
			
		||||
		this->m_settings.get_cancel_flag() == false);
 | 
			
		||||
	
 | 
			
		||||
    SASSERT(this->get_status() == FLOATING_POINT_ERROR
 | 
			
		||||
	if (this->m_settings.get_cancel_flag()) {
 | 
			
		||||
            this->set_status(CANCELLED);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SASSERT(
 | 
			
		||||
            this->get_status() == FLOATING_POINT_ERROR
 | 
			
		||||
            ||
 | 
			
		||||
            this->get_status() == CANCELLED
 | 
			
		||||
            ||
 | 
			
		||||
            this->current_x_is_feasible() == false
 | 
			
		||||
            ||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue