3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-26 07:43:41 +00:00
This commit is contained in:
Miguel Neves 2017-10-12 15:34:56 -07:00
commit bdce957ac8
83 changed files with 2596 additions and 1126 deletions

View file

@ -22,10 +22,17 @@ env:
# 64-bit Clang 3.9 RelWithDebInfo # 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 - 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 # 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 # 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 # 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 - 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 # 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 - 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 # 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 # macOS (a.k.a OSX) support
matrix: matrix:

View file

@ -12,9 +12,9 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z
## Build status ## Build status
| Windows x86 | Windows x64 | Ubuntu x64 | Ubuntu x86 | Debian x64 | OSX | TravisCI | | Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | OSX | TravisCI |
| ----------- | ----------- | ---------- | ---------- | ---------- | --- | -------- | | ----------- | ----------- | ---------- | ---------- | --- | -------- |
[![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![ubuntu-x86-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/6/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=6) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3)
[1]: #building-z3-on-windows-using-visual-studio-command-prompt [1]: #building-z3-on-windows-using-visual-studio-command-prompt
[2]: #building-z3-using-make-and-gccclang [2]: #building-z3-using-make-and-gccclang

View file

@ -2,34 +2,33 @@ ARG DOCKER_IMAGE_BASE
FROM ${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`. # `docker build`.
ARG ASAN_BUILD=0 ARG ASAN_BUILD
ARG BUILD_DOCS=0 ARG BUILD_DOCS
ARG CC=gcc ARG CC
ARG CXX=g++ ARG CXX
ARG DOTNET_BINDINGS=1 ARG DOTNET_BINDINGS
ARG JAVA_BINDINGS=1 ARG JAVA_BINDINGS
ARG NO_SUPPRESS_OUTPUT=0 ARG NO_SUPPRESS_OUTPUT
ARG PYTHON_BINDINGS=1 ARG PYTHON_BINDINGS
ARG PYTHON_EXECUTABLE=/usr/bin/python2.7 ARG PYTHON_EXECUTABLE=/usr/bin/python2.7
ARG RUN_SYSTEM_TESTS=1 ARG RUN_SYSTEM_TESTS
ARG RUN_UNIT_TESTS=1 ARG RUN_UNIT_TESTS
ARG TARGET_ARCH=x86_64 ARG TARGET_ARCH
ARG TEST_INSTALL=1 ARG TEST_INSTALL
ARG UBSAN_BUILD=0 ARG UBSAN_BUILD
ARG USE_LIBGMP=0 ARG USE_LIBGMP
ARG USE_LTO=0 ARG USE_LTO
ARG USE_OPENMP=1 ARG USE_OPENMP
ARG Z3_SRC_DIR=/home/user/z3_src ARG Z3_SRC_DIR=/home/user/z3_src
ARG Z3_BUILD_TYPE=RelWithDebInfo ARG Z3_BUILD_TYPE
ARG Z3_CMAKE_GENERATOR=Ninja ARG Z3_CMAKE_GENERATOR
ARG Z3_INSTALL_PREFIX=/usr ARG Z3_INSTALL_PREFIX
ARG Z3_STATIC_BUILD=0 ARG Z3_STATIC_BUILD
# Blank default indicates use latest.
ARG Z3_SYSTEM_TEST_GIT_REVISION ARG Z3_SYSTEM_TEST_GIT_REVISION
ARG Z3_WARNINGS_AS_ERRORS=SERIOUS_ONLY ARG Z3_WARNINGS_AS_ERRORS
ARG Z3_VERBOSE_BUILD_OUTPUT=0 ARG Z3_VERBOSE_BUILD_OUTPUT
ENV \ ENV \
ASAN_BUILD=${ASAN_BUILD} \ ASAN_BUILD=${ASAN_BUILD} \
@ -74,6 +73,7 @@ ADD *.txt *.md RELEASE_NOTES ${Z3_SRC_DIR}/
ADD \ ADD \
/contrib/ci/scripts/build_z3_cmake.sh \ /contrib/ci/scripts/build_z3_cmake.sh \
/contrib/ci/scripts/ci_defaults.sh \
/contrib/ci/scripts/set_compiler_flags.sh \ /contrib/ci/scripts/set_compiler_flags.sh \
/contrib/ci/scripts/set_generator_args.sh \ /contrib/ci/scripts/set_generator_args.sh \
${Z3_SRC_DIR}/contrib/ci/scripts/ ${Z3_SRC_DIR}/contrib/ci/scripts/

View file

@ -31,7 +31,7 @@ the future.
* `NO_SUPPRESS_OUTPUT` - Don't suppress output of some commands (`0` or `1`) * `NO_SUPPRESS_OUTPUT` - Don't suppress output of some commands (`0` or `1`)
* `PYTHON_BINDINGS` - Build and test Python API bindings (`0` or `1`) * `PYTHON_BINDINGS` - Build and test Python API bindings (`0` or `1`)
* `RUN_SYSTEM_TESTS` - Run system tests (`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`) * `TARGET_ARCH` - Target architecture (`x86_64` or `i686`)
* `TEST_INSTALL` - Test running `install` target (`0` or `1`) * `TEST_INSTALL` - Test running `install` target (`0` or `1`)
* `UBSAN_BUILD` - Do [UndefinedBehaviourSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) build (`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` variables (if set) into the build using the `--build-arg` argument of the `docker run`
command. command.
If an environemnt variable is not set a defaults value is used which can be The default values of the configuration environment variables
found in `Dockerfiles/z3_build.Dockerfile`. can be found in
[`scripts/ci_defaults.sh`](scripts/ci_defaults.sh).
#### Linux specific configuration variables #### Linux specific configuration variables
@ -67,8 +68,9 @@ found in `Dockerfiles/z3_build.Dockerfile`.
#### Reproducing a build locally #### Reproducing a build locally
A build can be reproduced locally by using the `scripts/travis_ci_linux_entry_point.sh` A build can be reproduced locally by using the
script and setting the appropriate environment variable. `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. 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 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 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 An [organization](https://hub.docker.com/u/z3prover/) has been created on
DockerHub for this. DockerHub for this.
### macOS ### 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.

View 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

View file

@ -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 # scripts and should not be executed directly
: ${Z3_CMAKE_GENERATOR?"Z3_CMAKE_GENERATOR must be specified"} : ${Z3_CMAKE_GENERATOR?"Z3_CMAKE_GENERATOR must be specified"}

View file

@ -10,17 +10,35 @@ set -o pipefail
: ${Z3_BUILD_DIR?"Z3_BUILD_DIR must be specified"} : ${Z3_BUILD_DIR?"Z3_BUILD_DIR must be specified"}
: ${RUN_UNIT_TESTS?"RUN_UNIT_TESTS 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 # Set CMake generator args
source ${SCRIPT_DIR}/set_generator_args.sh source ${SCRIPT_DIR}/set_generator_args.sh
cd "${Z3_BUILD_DIR}" cd "${Z3_BUILD_DIR}"
# Build and run internal tests function build_unit_tests() {
cmake --build $(pwd) --target test-z3 "${GENERATOR_ARGS[@]}" # Build internal tests
# Run all tests that don't require arguments cmake --build $(pwd) --target test-z3 "${GENERATOR_ARGS[@]}"
run_quiet ./test-z3 /a }
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

View file

@ -11,16 +11,21 @@ DOCKER_FILE_DIR="$(cd ${SCRIPT_DIR}/../Dockerfiles; echo $PWD)"
: ${LINUX_BASE?"LINUX_BASE must be specified"} : ${LINUX_BASE?"LINUX_BASE must be specified"}
# Sanity check. Current working directory should be repo root # Sanity check. Current working directory should be repo root
if [ ! -f "./README.md" ]; then if [ ! -f "./README.md" ]; then
echo "Current working directory should be repo root" echo "Current working directory should be repo root"
exit 1 exit 1
fi fi
# Get defaults
source "${SCRIPT_DIR}/ci_defaults.sh"
BUILD_OPTS=() BUILD_OPTS=()
# Override options if they have been provided. # Pass Docker build arguments
# Otherwise the defaults in the Docker file will be used if [ -n "${Z3_BUILD_TYPE}" ]; then
BUILD_OPTS+=("--build-arg" "Z3_BUILD_TYPE=${Z3_BUILD_TYPE}")
fi
if [ -n "${Z3_CMAKE_GENERATOR}" ]; then if [ -n "${Z3_CMAKE_GENERATOR}" ]; then
BUILD_OPTS+=("--build-arg" "Z3_CMAKE_GENERATOR=${Z3_CMAKE_GENERATOR}") BUILD_OPTS+=("--build-arg" "Z3_CMAKE_GENERATOR=${Z3_CMAKE_GENERATOR}")
fi fi

View file

@ -6,26 +6,8 @@ set -x
set -e set -e
set -o pipefail set -o pipefail
# Set defaults # Get defaults
# FIXME: Refactor this so we don't need to stay in sync with source "${SCRIPT_DIR}/ci_defaults.sh"
# `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}"
if [ -z "${TRAVIS_BUILD_DIR}" ]; then if [ -z "${TRAVIS_BUILD_DIR}" ]; then
echo "TRAVIS_BUILD_DIR must be set to root of Z3 repository" echo "TRAVIS_BUILD_DIR must be set to root of Z3 repository"
@ -37,15 +19,12 @@ if [ ! -d "${TRAVIS_BUILD_DIR}" ]; then
exit 1 exit 1
fi 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_SRC_DIR="${TRAVIS_BUILD_DIR}"
export Z3_BUILD_DIR="${Z3_SRC_DIR}/build" 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_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 # Overwrite whatever what set in TravisCI
export CC="${C_COMPILER}" export CC="${C_COMPILER}"

View file

@ -188,7 +188,7 @@ try:
if Z3PY_ENABLED: if Z3PY_ENABLED:
print("Z3Py documentation enabled") print("Z3Py documentation enabled")
doxygen_config_substitutions['PYTHON_API_FILES'] = 'z3.py' doxygen_config_substitutions['PYTHON_API_FILES'] = 'z3*.py'
else: else:
print("Z3Py documentation disabled") print("Z3Py documentation disabled")
doxygen_config_substitutions['PYTHON_API_FILES'] = '' 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 # Put z3py at the beginning of the search path to try to avoid picking up
# an installed copy of Z3py. # an installed copy of Z3py.
sys.path.insert(0, os.path.dirname(Z3PY_PACKAGE_PATH)) sys.path.insert(0, os.path.dirname(Z3PY_PACKAGE_PATH))
pydoc.writedoc('z3') for modulename in (
shutil.move('z3.html', os.path.join(OUTPUT_DIRECTORY, 'html', 'z3.html')) '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.") print("Generated pydoc Z3Py documentation.")
if ML_ENABLED: if ML_ENABLED:

View file

@ -65,6 +65,15 @@ void throw_z3_error(Z3_context c, Z3_error_code e)
longjmp(g_catch_buffer, e); longjmp(g_catch_buffer, e);
} }
/**
\brief Error handling that depends on checking an error code on the context.
*/
void nothrow_z3_error(Z3_context c, Z3_error_code e) {
// no-op
}
/** /**
\brief Create a logical context. \brief Create a logical context.
@ -1592,18 +1601,16 @@ void error_code_example1()
void error_code_example2() { void error_code_example2() {
Z3_config cfg; Z3_config cfg;
Z3_context ctx = NULL; Z3_context ctx = NULL;
int r; Z3_error_code e;
printf("\nerror_code_example2\n"); printf("\nerror_code_example2\n");
LOG_MSG("error_code_example2"); LOG_MSG("error_code_example2");
/* low tech try&catch */ if (1) {
r = setjmp(g_catch_buffer);
if (r == 0) {
Z3_ast x, y, app; Z3_ast x, y, app;
cfg = Z3_mk_config(); cfg = Z3_mk_config();
ctx = mk_context_custom(cfg, throw_z3_error); ctx = mk_context_custom(cfg, nothrow_z3_error);
Z3_del_config(cfg); Z3_del_config(cfg);
x = mk_int_var(ctx, "x"); x = mk_int_var(ctx, "x");
@ -1611,11 +1618,14 @@ void error_code_example2() {
printf("before Z3_mk_iff\n"); printf("before Z3_mk_iff\n");
/* the next call will produce an error */ /* the next call will produce an error */
app = Z3_mk_iff(ctx, x, y); app = Z3_mk_iff(ctx, x, y);
e = Z3_get_error_code(ctx);
if (e != Z3_OK) goto err;
unreachable(); unreachable();
Z3_del_context(ctx); Z3_del_context(ctx);
} }
else { else {
printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, (Z3_error_code)r)); err:
printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e));
if (ctx != NULL) { if (ctx != NULL) {
Z3_del_context(ctx); Z3_del_context(ctx);
} }
@ -1781,15 +1791,14 @@ void parser_example5() {
Z3_config cfg; Z3_config cfg;
Z3_context ctx = NULL; Z3_context ctx = NULL;
Z3_solver s = NULL; Z3_solver s = NULL;
int r; Z3_error_code e;
printf("\nparser_example5\n"); printf("\nparser_example5\n");
LOG_MSG("parser_example5"); LOG_MSG("parser_example5");
r = setjmp(g_catch_buffer); if (1) {
if (r == 0) {
cfg = Z3_mk_config(); cfg = Z3_mk_config();
ctx = mk_context_custom(cfg, throw_z3_error); ctx = mk_context_custom(cfg, nothrow_z3_error);
s = mk_solver(ctx); s = mk_solver(ctx);
Z3_del_config(cfg); Z3_del_config(cfg);
@ -1798,12 +1807,15 @@ void parser_example5() {
"(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))", "(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))",
0, 0, 0, 0, 0, 0,
0, 0, 0); 0, 0, 0);
e = Z3_get_error_code(ctx);
if (e != Z3_OK) goto err;
unreachable(); unreachable();
del_solver(ctx, s); del_solver(ctx, s);
Z3_del_context(ctx); Z3_del_context(ctx);
} }
else { else {
printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, (Z3_error_code)r)); err:
printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e));
if (ctx != NULL) { if (ctx != NULL) {
printf("Error message: '%s'.\n",Z3_get_smtlib_error(ctx)); printf("Error message: '%s'.\n",Z3_get_smtlib_error(ctx));
del_solver(ctx, s); del_solver(ctx, s);

View file

@ -1913,7 +1913,11 @@ class MLComponent(Component):
src_dir = self.to_src_dir src_dir = self.to_src_dir
mk_dir(os.path.join(BUILD_DIR, self.sub_dir)) mk_dir(os.path.join(BUILD_DIR, self.sub_dir))
api_src = get_component(API_COMPONENT).to_src_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: if IS_WINDOWS:
prefix_lib = '-L' + os.path.abspath(BUILD_DIR).replace('\\', '\\\\') prefix_lib = '-L' + os.path.abspath(BUILD_DIR).replace('\\', '\\\\')

View file

@ -57,19 +57,20 @@ extern "C" {
Z3_func_decl const decls[]) { Z3_func_decl const decls[]) {
Z3_TRY; Z3_TRY;
LOG_Z3_parse_smtlib_string(c, str, num_sorts, sort_names, sorts, num_decls, decl_names, decls); LOG_Z3_parse_smtlib_string(c, str, num_sorts, sort_names, sorts, num_decls, decl_names, decls);
std::ostringstream outs; std::ostringstream* outs = alloc(std::ostringstream);
bool ok = false; bool ok = false;
RESET_ERROR_CODE(); RESET_ERROR_CODE();
init_smtlib_parser(c, num_sorts, sort_names, sorts, num_decls, decl_names, decls); init_smtlib_parser(c, num_sorts, sort_names, sorts, num_decls, decl_names, decls);
mk_c(c)->m_smtlib_parser->set_error_stream(outs); mk_c(c)->m_smtlib_parser->set_error_stream(*outs);
try { try {
ok = mk_c(c)->m_smtlib_parser->parse_string(str); ok = mk_c(c)->m_smtlib_parser->parse_string(str);
} }
catch (...) { catch (...) {
ok = false; ok = false;
} }
mk_c(c)->m_smtlib_error_buffer = outs.str(); mk_c(c)->m_smtlib_error_buffer = outs->str();
dealloc(outs);
if (!ok) { if (!ok) {
mk_c(c)->reset_parser(); mk_c(c)->reset_parser();
SET_ERROR_CODE(Z3_PARSER_ERROR); SET_ERROR_CODE(Z3_PARSER_ERROR);
@ -89,16 +90,17 @@ extern "C" {
LOG_Z3_parse_smtlib_file(c, file_name, num_sorts, sort_names, types, num_decls, decl_names, decls); LOG_Z3_parse_smtlib_file(c, file_name, num_sorts, sort_names, types, num_decls, decl_names, decls);
bool ok = false; bool ok = false;
RESET_ERROR_CODE(); RESET_ERROR_CODE();
std::ostringstream outs; std::ostringstream* outs = alloc(std::ostringstream);
init_smtlib_parser(c, num_sorts, sort_names, types, num_decls, decl_names, decls); init_smtlib_parser(c, num_sorts, sort_names, types, num_decls, decl_names, decls);
mk_c(c)->m_smtlib_parser->set_error_stream(outs); mk_c(c)->m_smtlib_parser->set_error_stream(*outs);
try { try {
ok = mk_c(c)->m_smtlib_parser->parse_file(file_name); ok = mk_c(c)->m_smtlib_parser->parse_file(file_name);
} }
catch(...) { catch(...) {
ok = false; ok = false;
} }
mk_c(c)->m_smtlib_error_buffer = outs.str(); mk_c(c)->m_smtlib_error_buffer = outs->str();
dealloc(outs);
if (!ok) { if (!ok) {
mk_c(c)->reset_parser(); mk_c(c)->reset_parser();
SET_ERROR_CODE(Z3_PARSER_ERROR); SET_ERROR_CODE(Z3_PARSER_ERROR);

View file

@ -140,7 +140,7 @@ namespace z3 {
class context { class context {
bool m_enable_exceptions; bool m_enable_exceptions;
Z3_context m_ctx; Z3_context m_ctx;
static void error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ } static void Z3_API error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ }
void init(config & c) { void init(config & c) {
m_ctx = Z3_mk_context_rc(c); m_ctx = Z3_mk_context_rc(c);
m_enable_exceptions = true; m_enable_exceptions = true;

View file

@ -471,6 +471,9 @@ bool compare_nodes(ast const * n1, ast const * n2) {
compare_arrays(to_quantifier(n1)->get_decl_sorts(), compare_arrays(to_quantifier(n1)->get_decl_sorts(),
to_quantifier(n2)->get_decl_sorts(), to_quantifier(n2)->get_decl_sorts(),
to_quantifier(n1)->get_num_decls()) && 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_expr() == to_quantifier(n2)->get_expr() &&
to_quantifier(n1)->get_weight() == to_quantifier(n2)->get_weight() && to_quantifier(n1)->get_weight() == to_quantifier(n2)->get_weight() &&
to_quantifier(n1)->get_num_patterns() == to_quantifier(n2)->get_num_patterns() && to_quantifier(n1)->get_num_patterns() == to_quantifier(n2)->get_num_patterns() &&

View file

@ -19,6 +19,7 @@ Notes:
#include "ast/expr_abstract.h" #include "ast/expr_abstract.h"
#include "util/map.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) { 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) { void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
expr_abstractor abs(m); expr_abstractor abs(m);
abs(base, num_bound, bound, n, result); 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) { 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); 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; return result;
} }

View file

@ -16,8 +16,9 @@ Author:
Notes: Notes:
--*/ --*/
#include "ast/expr_substitution.h"
#include "util/ref_util.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, proof*> expr2proof;
typedef obj_map<expr, expr_dependency*> expr2expr_dependency; typedef obj_map<expr, expr_dependency*> expr2expr_dependency;
@ -56,6 +57,13 @@ expr_substitution::~expr_substitution() {
reset(); 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) { 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); obj_map<expr, expr*>::obj_map_entry * entry = m_subst.insert_if_not_there2(c, 0);
if (entry->get_data().m_value == 0) { if (entry->get_data().m_value == 0) {

View file

@ -50,6 +50,8 @@ public:
bool contains(expr * s); bool contains(expr * s);
void reset(); void reset();
void cleanup(); void cleanup();
std::ostream& display(std::ostream& out);
}; };
class scoped_expr_substitution { 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 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); } bool contains(expr * s) { return m_subst.contains(s); }
void cleanup() { m_subst.cleanup(); } void cleanup() { m_subst.cleanup(); }
std::ostream& display(std::ostream& out) { return m_subst.display(out); }
}; };
#endif #endif

View file

@ -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) { void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2); 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]; 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) { void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2); 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]; 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); mk_is_nan(x, x_is_nan);
sort * fp_srt = m.get_sort(x); 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); expr_ref unspec(m);
mk_to_ieee_bv_unspecified(f, num, args, unspec); mk_to_ieee_bv_unspecified(f, num, args, unspec);

View file

@ -54,13 +54,13 @@ br_status maximize_ac_sharing::reduce_app(func_decl * f, unsigned num_args, expr
TRACE("ac_sharing_detail", tout << "args: "; for (unsigned i = 0; i < num_args; i++) tout << mk_pp(_args[i], m) << "\n";); TRACE("ac_sharing_detail", tout << "args: "; for (unsigned i = 0; i < num_args; i++) tout << mk_pp(_args[i], m) << "\n";);
try_to_reuse: try_to_reuse:
if (num_args > 1 && num_args < MAX_NUM_ARGS_FOR_OPT) { if (num_args > 1 && num_args < MAX_NUM_ARGS_FOR_OPT) {
for (unsigned i = 0; i < num_args - 1; i++) { for (unsigned i = 0; i + 1 < num_args; i++) {
for (unsigned j = i + 1; j < num_args; j++) { for (unsigned j = i + 1; j < num_args; j++) {
if (contains(f, _args[i], _args[j])) { if (contains(f, _args[i], _args[j])) {
TRACE("ac_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";); TRACE("ac_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";);
_args[i] = m.mk_app(f, _args[i], _args[j]); _args[i] = m.mk_app(f, _args[i], _args[j]);
SASSERT(num_args > 1); SASSERT(num_args > 1);
for (unsigned w = j; w < num_args - 1; w++) { for (unsigned w = j; w + 1 < num_args; w++) {
_args[w] = _args[w+1]; _args[w] = _args[w+1];
} }
num_args--; num_args--;
@ -144,6 +144,7 @@ void maximize_ac_sharing::restore_entries(unsigned old_lim) {
while (i != old_lim) { while (i != old_lim) {
--i; --i;
entry * e = m_entries[i]; entry * e = m_entries[i];
m_cache.remove(e);
m.dec_ref(e->m_arg1); m.dec_ref(e->m_arg1);
m.dec_ref(e->m_arg2); m.dec_ref(e->m_arg2);
} }
@ -151,11 +152,7 @@ void maximize_ac_sharing::restore_entries(unsigned old_lim) {
} }
void maximize_ac_sharing::reset() { void maximize_ac_sharing::reset() {
restore_entries(0);
m_entries.reset();
m_cache.reset(); m_cache.reset();
m_region.reset();
m_scopes.reset();
} }
void maximize_bv_sharing::init_core() { void maximize_bv_sharing::init_core() {

View file

@ -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()); lhs = m().mk_app(f, binding.size(), binding.c_ptr());
eq = m().mk_eq(lhs, e); eq = m().mk_eq(lhs, e);
if (!ids.empty()) { 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)) { if (!is_app(e)) {
throw cmd_exception("Z3 only supports recursive definitions that are proper terms (not binders or variables)"); 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; continue;
} }
try { try {
for_each_expr(contains_underspecified, a);
for_each_expr(contains_underspecified, r); for_each_expr(contains_underspecified, r);
} }
catch (contains_underspecified_op_proc::found) { catch (contains_underspecified_op_proc::found) {

View file

@ -33,9 +33,11 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <ostream> #include <ostream>
#include <sstream>
#include "ast/expr_abstract.h" #include "ast/expr_abstract.h"
#include "util/params.h" #include "util/params.h"
#include "ast/used_vars.h"
using namespace stl_ext; using namespace stl_ext;
@ -938,3 +940,30 @@ void iz3mgr::get_bound_substitutes(stl_ext::hash_map<ast,bool> &memo, const ast
} }
#endif #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;
}

View file

@ -96,7 +96,7 @@ class ast_r : public ast_i {
ast_r(const ast_r &other) : ast_i(other) { ast_r(const ast_r &other) : ast_i(other) {
_m = other._m; _m = other._m;
_m->inc_ref(_ast); if (_m) _m->inc_ref(_ast);
} }
ast_r &operator=(const ast_r &other) { ast_r &operator=(const ast_r &other) {
@ -104,7 +104,7 @@ class ast_r : public ast_i {
_m->dec_ref(_ast); _m->dec_ref(_ast);
_ast = other._ast; _ast = other._ast;
_m = other._m; _m = other._m;
_m->inc_ref(_ast); if (_m) _m->inc_ref(_ast);
return *this; return *this;
} }
@ -661,6 +661,12 @@ class iz3mgr {
ast apply_quant(opr quantifier, ast var, ast e); 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 */ /** For debugging */
void show(ast); void show(ast);

View file

@ -2968,9 +2968,9 @@ class iz3proof_itp_impl : public iz3proof_itp {
ast interpolate(const node &pf){ ast interpolate(const node &pf){
// proof of false must be a formula, with quantified symbols // proof of false must be a formula, with quantified symbols
#ifndef BOGUS_QUANTS #ifndef BOGUS_QUANTS
return add_quants(z3_simplify(pf)); return close_universally(add_quants(z3_simplify(pf)));
#else #else
return z3_simplify(pf); return close_universally(z3_simplify(pf));
#endif #endif
} }

View file

@ -234,6 +234,11 @@ public:
} }
} }
// if(!range_is_empty(rng)){
// if (num_free_variables(con) > 0)
// rng = range_empty();
// }
if(res == INT_MAX){ if(res == INT_MAX){
if(range_is_empty(rng)) if(range_is_empty(rng))
res = -1; res = -1;

View file

@ -86,18 +86,22 @@ void model_core::register_decl(func_decl * d, func_interp * fi) {
void model_core::unregister_decl(func_decl * d) { void model_core::unregister_decl(func_decl * d) {
decl2expr::obj_map_entry * ec = m_interp.find_core(d); decl2expr::obj_map_entry * ec = m_interp.find_core(d);
if (ec && ec->get_data().m_value != 0) { if (ec && ec->get_data().m_value != 0) {
m_manager.dec_ref(ec->get_data().m_key); auto k = ec->get_data().m_key;
m_manager.dec_ref(ec->get_data().m_value); auto v = ec->get_data().m_value;
m_interp.remove(d); m_interp.remove(d);
m_const_decls.erase(d); m_const_decls.erase(d);
m_manager.dec_ref(k);
m_manager.dec_ref(v);
return; return;
} }
decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); decl2finterp::obj_map_entry * ef = m_finterp.find_core(d);
if (ef && ef->get_data().m_value != 0) { if (ef && ef->get_data().m_value != 0) {
m_manager.dec_ref(ef->get_data().m_key); auto k = ef->get_data().m_key;
dealloc(ef->get_data().m_value); auto v = ef->get_data().m_value;
m_finterp.remove(d); m_finterp.remove(d);
m_func_decls.erase(d); m_func_decls.erase(d);
m_manager.dec_ref(k);
dealloc(v);
} }
} }

View file

@ -192,10 +192,15 @@ namespace datalog {
for (unsigned i = 0; i < new_tbvs.size(); ++i) { for (unsigned i = 0; i < new_tbvs.size(); ++i) {
tbv const& nt = *new_tbvs[i]; tbv const& nt = *new_tbvs[i];
IF_VERBOSE(10, m_tbv.display(verbose_stream() << "insert: ", nt); verbose_stream() << "\n";); IF_VERBOSE(10, m_tbv.display(verbose_stream() << "insert: ", nt); verbose_stream() << "\n";);
if (contains(nt)) continue; ddnf_node* n;
ddnf_node* n = alloc(ddnf_node, *this, m_tbv, nt, m_noderefs.size()); if (contains(nt)) {
m_noderefs.push_back(n); n = find(nt);
m_nodes.insert(n); }
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); insert(*m_root, n, new_tbvs);
} }
return find(t); return find(t);
@ -275,13 +280,17 @@ namespace datalog {
void insert(ddnf_node& root, ddnf_node* new_n, ptr_vector<tbv const>& new_intersections) { void insert(ddnf_node& root, ddnf_node* new_n, ptr_vector<tbv const>& new_intersections) {
tbv const& new_tbv = new_n->get_tbv(); 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)); 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; ++m_stats.m_num_inserts;
bool inserted = false; bool inserted = false;
for (unsigned i = 0; i < root.num_children(); ++i) { for (unsigned i = 0; i < root.num_children(); ++i) {
ddnf_node& child = *(root[i]); ddnf_node& child = *(root[i]);
++m_stats.m_num_comparisons; ++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)) { if (m_tbv.contains(child.get_tbv(), new_tbv)) {
inserted = true; inserted = true;
insert(child, new_n, new_intersections); insert(child, new_n, new_intersections);
@ -299,11 +308,13 @@ namespace datalog {
// checking for subset // checking for subset
if (m_tbv.contains(new_tbv, child.get_tbv())) { if (m_tbv.contains(new_tbv, child.get_tbv())) {
subset_children.push_back(&child); 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; ++m_stats.m_num_comparisons;
} }
else if (m_tbv.intersect(child.get_tbv(), new_tbv, *intr)) { else if (m_tbv.intersect(child.get_tbv(), new_tbv, *intr)) {
// this means there is a non-full intersection // this means there is a non-full intersection
new_intersections.push_back(intr); 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(); intr = m_tbv.allocate();
m_stats.m_num_comparisons += 2; m_stats.m_num_comparisons += 2;
} }

View file

@ -111,8 +111,8 @@ namespace datalog {
void filter_interpreted(app* cond) { void filter_interpreted(app* cond) {
rational one(1), mone(-1); rational one(1), mone(-1);
expr* e1, *e2, *en; expr* e1 = 0, *e2 = 0, *en = 0;
var* v, *w; var* v = 0, *w = 0;
rational n1, n2; rational n1, n2;
expr_ref_vector conjs(m); expr_ref_vector conjs(m);
flatten_and(cond, conjs); flatten_and(cond, conjs);

View file

@ -74,8 +74,7 @@ tbv* tbv_manager::allocate(tbv const& bv) {
} }
tbv* tbv_manager::allocate(uint64 val) { tbv* tbv_manager::allocate(uint64 val) {
tbv* v = allocate0(); tbv* v = allocate0();
for (unsigned bit = num_tbits(); bit > 0;) { for (unsigned bit = std::min(64u, num_tbits()); bit-- > 0;) {
--bit;
if (val & (1ULL << bit)) { if (val & (1ULL << bit)) {
set(*v, bit, BIT_1); set(*v, bit, BIT_1);
} else { } else {

View file

@ -398,8 +398,8 @@ namespace datalog {
} }
bool mk_interp_tail_simplifier::propagate_variable_equivalences(rule * r, rule_ref& res) { bool mk_interp_tail_simplifier::propagate_variable_equivalences(rule * r, rule_ref& res) {
if (!m_context.get_params ().xform_tail_simplifier_pve ()) if (!m_context.get_params ().xform_tail_simplifier_pve ())
return false; return false;
unsigned u_len = r->get_uninterpreted_tail_size(); unsigned u_len = r->get_uninterpreted_tail_size();
unsigned len = r->get_tail_size(); unsigned len = r->get_tail_size();
if (u_len == len) { if (u_len == len) {

View file

@ -124,7 +124,7 @@ namespace smt2 {
next(); next();
bool is_float = false; bool is_float = false;
while (true) { while (!m_at_eof) {
char c = curr(); char c = curr();
if ('0' <= c && c <= '9') { if ('0' <= c && c <= '9') {
m_number = rational(10)*m_number + rational(c - '0'); m_number = rational(10)*m_number + rational(c - '0');

File diff suppressed because it is too large Load diff

View file

@ -79,7 +79,7 @@ namespace sat {
void set_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; } void set_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; }
void update_literal(literal l) { m_lit = l; } void update_literal(literal l) { m_lit = l; }
bool was_removed() const { return m_removed; } bool was_removed() const { return m_removed; }
void remove() { m_removed = true; } void set_removed() { m_removed = true; }
void nullify_literal() { m_lit = null_literal; } void nullify_literal() { m_lit = null_literal; }
unsigned glue() const { return m_glue; } unsigned glue() const { return m_glue; }
void set_glue(unsigned g) { m_glue = g; } void set_glue(unsigned g) { m_glue = g; }
@ -199,7 +199,7 @@ namespace sat {
svector<uint64> m_coeffs; svector<uint64> m_coeffs;
uint64 m_k; uint64 m_k;
void reset(uint64 k) { m_lits.reset(); m_coeffs.reset(); m_k = k; } void reset(uint64 k) { m_lits.reset(); m_coeffs.reset(); m_k = k; }
void push(literal l, unsigned c) { m_lits.push_back(l); m_coeffs.push_back(c); } void push(literal l, uint64 c) { m_lits.push_back(l); m_coeffs.push_back(c); }
}; };
solver* m_solver; solver* m_solver;
@ -286,7 +286,7 @@ namespace sat {
void cleanup_constraints(); void cleanup_constraints();
void cleanup_constraints(ptr_vector<constraint>& cs, bool learned); void cleanup_constraints(ptr_vector<constraint>& cs, bool learned);
void ensure_external(constraint const& c); void ensure_external(constraint const& c);
void remove_constraint(constraint& c); void remove_constraint(constraint& c, char const* reason);
// constraints // constraints
constraint& index2constraint(size_t idx) const { return *reinterpret_cast<constraint*>(idx); } constraint& index2constraint(size_t idx) const { return *reinterpret_cast<constraint*>(idx); }
@ -304,6 +304,7 @@ namespace sat {
void nullify_tracking_literal(constraint& c); void nullify_tracking_literal(constraint& c);
void set_conflict(constraint& c, literal lit); void set_conflict(constraint& c, literal lit);
void assign(constraint& c, literal lit); void assign(constraint& c, literal lit);
bool assigned_above(literal above, literal below);
void get_antecedents(literal l, constraint const& c, literal_vector & r); void get_antecedents(literal l, constraint const& c, literal_vector & r);
bool validate_conflict(constraint const& c) const; bool validate_conflict(constraint const& c) const;
bool validate_unit_propagation(constraint const& c, literal alit) const; bool validate_unit_propagation(constraint const& c, literal alit) const;
@ -368,7 +369,7 @@ namespace sat {
inline watch_list const& get_wlist(literal l) const { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } inline watch_list const& get_wlist(literal l) const { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); }
inline void assign(literal l, justification j) { if (m_lookahead) m_lookahead->assign(l); else m_solver->assign(l, j); } inline void assign(literal l, justification j) { if (m_lookahead) m_lookahead->assign(l); else m_solver->assign(l, j); }
inline void set_conflict(justification j, literal l) { if (m_lookahead) m_lookahead->set_conflict(); else m_solver->set_conflict(j, l); } inline void set_conflict(justification j, literal l) { if (m_lookahead) m_lookahead->set_conflict(); else m_solver->set_conflict(j, l); }
inline config const& get_config() const { return m_solver->get_config(); } inline config const& get_config() const { return m_lookahead ? m_lookahead->get_config() : m_solver->get_config(); }
inline void drat_add(literal_vector const& c, svector<drat::premise> const& premises) { m_solver->m_drat.add(c, premises); } inline void drat_add(literal_vector const& c, svector<drat::premise> const& premises) { m_solver->m_drat.add(c, premises); }
@ -402,8 +403,13 @@ namespace sat {
bool validate_watch_literals() const; bool validate_watch_literals() const;
bool validate_watch_literal(literal lit) const; bool validate_watch_literal(literal lit) const;
bool validate_watched_constraint(constraint const& c) const; bool validate_watched_constraint(constraint const& c) const;
bool validate_watch(pb const& p) const; bool validate_watch(pb const& p, literal alit) const;
bool is_watching(literal lit, constraint const& c) const; bool is_watching(literal lit, constraint const& c) const;
literal translate_to_sat(solver& s, u_map<bool_var>& translation, ineq const& pb);
literal translate_to_sat(solver& s, u_map<bool_var>& translation, ineq& a, ineq& b);
literal translate_to_sat(solver& s, u_map<bool_var>& translation, literal lit);
ineq negate(ineq const& a) const;
void push_lit(literal_vector& lits, literal lit);
ineq m_A, m_B, m_C; ineq m_A, m_B, m_C;
void active2pb(ineq& p); void active2pb(ineq& p);
@ -422,6 +428,7 @@ namespace sat {
constraint* add_pb_ge(literal l, svector<wliteral> const& wlits, unsigned k, bool learned); constraint* add_pb_ge(literal l, svector<wliteral> const& wlits, unsigned k, bool learned);
constraint* add_xor(literal l, literal_vector const& lits, bool learned); constraint* add_xor(literal l, literal_vector const& lits, bool learned);
void copy_core(ba_solver* result);
public: public:
ba_solver(); ba_solver();
virtual ~ba_solver(); virtual ~ba_solver();
@ -447,6 +454,7 @@ namespace sat {
virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const; virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const;
virtual void collect_statistics(statistics& st) const; virtual void collect_statistics(statistics& st) const;
virtual extension* copy(solver* s); virtual extension* copy(solver* s);
virtual extension* copy(lookahead* s);
virtual void find_mutexes(literal_vector& lits, vector<literal_vector> & mutexes); virtual void find_mutexes(literal_vector& lits, vector<literal_vector> & mutexes);
virtual void pop_reinit(); virtual void pop_reinit();
virtual void gc(); virtual void gc();

View file

@ -272,7 +272,8 @@ namespace sat {
void drat::verify(unsigned n, literal const* c) { void drat::verify(unsigned n, literal const* c) {
if (!is_drup(n, c) && !is_drat(n, c)) { if (!is_drup(n, c) && !is_drat(n, c)) {
std::cout << "Verification failed\n"; std::cout << "Verification failed\n";
display(std::cout); UNREACHABLE();
//display(std::cout);
TRACE("sat", TRACE("sat",
tout << literal_vector(n, c) << "\n"; tout << literal_vector(n, c) << "\n";
display(tout); display(tout);

View file

@ -96,17 +96,18 @@ namespace sat {
if (!c.frozen()) if (!c.frozen())
m_solver.detach_clause(c); m_solver.detach_clause(c);
// apply substitution // apply substitution
for (i = 0; i < sz; i++) { for (i = 0; i < sz; i++) {
SASSERT(!m_solver.was_eliminated(c[i].var()));
c[i] = norm(roots, c[i]); c[i] = norm(roots, c[i]);
VERIFY(!m_solver.was_eliminated(c[i].var()));
} }
std::sort(c.begin(), c.end()); std::sort(c.begin(), c.end());
for (literal l : c) VERIFY(l == norm(roots, l));
TRACE("sats", tout << "after normalization/sorting: " << c << "\n"; tout.flush();); TRACE("sats", tout << "after normalization/sorting: " << c << "\n"; tout.flush(););
DEBUG_CODE({ DEBUG_CODE({
for (unsigned i = 0; i < sz; i++) { for (literal l : c) {
CTRACE("sats", c[i] != norm(roots, c[i]), tout << c[i] << " " << norm(roots, c[i]) << "\n"; tout.flush();); CTRACE("sat", l != norm(roots, l), tout << l << " " << norm(roots, l) << "\n"; tout.flush(););
SASSERT(c[i] == norm(roots, c[i])); SASSERT(l == norm(roots, l));
} }); } });
// remove duplicates, and check if it is a tautology // remove duplicates, and check if it is a tautology
literal l_prev = null_literal; literal l_prev = null_literal;
unsigned j = 0; unsigned j = 0;
@ -122,13 +123,11 @@ namespace sat {
break; // clause was satisfied break; // clause was satisfied
if (val == l_false) if (val == l_false)
continue; // skip continue; // skip
if (i != j) { c[j] = l;
std::swap(c[i], c[j]);
}
j++; j++;
} }
if (i < sz) { if (i < sz) {
// clause is a tautology or was simplified // clause is a tautology or was simplified to true
m_solver.del_clause(c); m_solver.del_clause(c);
continue; continue;
} }
@ -164,10 +163,7 @@ namespace sat {
else else
c.update_approx(); c.update_approx();
DEBUG_CODE({ DEBUG_CODE(for (literal l : c) VERIFY(l == norm(roots, l)););
for (unsigned i = 0; i < j; i++) {
SASSERT(c[i] == norm(roots, c[i]));
} });
*it2 = *it; *it2 = *it;
it2++; it2++;
@ -187,7 +183,6 @@ namespace sat {
literal r = roots[v]; literal r = roots[v];
SASSERT(v != r.var()); SASSERT(v != r.var());
if (m_solver.is_external(v) && !m_solver.set_root(l, r)) { if (m_solver.is_external(v) && !m_solver.set_root(l, r)) {
std::cout << "skip: " << l << " == " << r << "\n";
// cannot really eliminate v, since we have to notify extension of future assignments // cannot really eliminate v, since we have to notify extension of future assignments
m_solver.mk_bin_clause(~l, r, false); m_solver.mk_bin_clause(~l, r, false);
m_solver.mk_bin_clause(l, ~r, false); m_solver.mk_bin_clause(l, ~r, false);
@ -199,29 +194,33 @@ namespace sat {
mc.insert(e, ~l, r); mc.insert(e, ~l, r);
mc.insert(e, l, ~r); mc.insert(e, l, ~r);
} }
m_solver.flush_roots();
} }
m_solver.flush_roots();
} }
bool elim_eqs::check_clauses(literal_vector const & roots) const { bool elim_eqs::check_clause(clause const& c, literal_vector const& roots) const {
clause_vector * vs[2] = { &m_solver.m_clauses, &m_solver.m_learned }; for (literal l : c) {
for (unsigned i = 0; i < 2; i++) { CTRACE("elim_eqs_bug", m_solver.was_eliminated(l.var()), tout << "lit: " << l << " " << norm(roots, l) << "\n";
clause_vector & cs = *(vs[i]); tout << c << "\n";);
clause_vector::iterator it = cs.begin(); if (m_solver.was_eliminated(l.var())) {
clause_vector::iterator end = cs.end(); IF_VERBOSE(0, verbose_stream() << c << " contains eliminated literal " << l << " " << norm(roots, l) << "\n";);
for (; it != end; ++it) { UNREACHABLE();
clause & c = *(*it);
unsigned sz = c.size();
for (unsigned i = 0; i < sz; i++) {
CTRACE("elim_eqs_bug", m_solver.was_eliminated(c[i].var()), tout << "lit: " << c[i] << " " << norm(roots, c[i]) << "\n";
tout << c << "\n";);
SASSERT(!m_solver.was_eliminated(c[i].var()));
}
} }
} }
return true; return true;
} }
bool elim_eqs::check_clauses(literal_vector const & roots) const {
for (clause * cp : m_solver.m_clauses)
if (!check_clause(*cp, roots))
return false;
for (clause * cp : m_solver.m_learned)
if (!check_clause(*cp, roots))
return false;
return true;
}
void elim_eqs::operator()(literal_vector const & roots, bool_var_vector const & to_elim) { void elim_eqs::operator()(literal_vector const & roots, bool_var_vector const & to_elim) {
cleanup_bin_watches(roots); cleanup_bin_watches(roots);
TRACE("elim_eqs", tout << "after bin cleanup\n"; m_solver.display(tout);); TRACE("elim_eqs", tout << "after bin cleanup\n"; m_solver.display(tout););

View file

@ -30,6 +30,7 @@ namespace sat {
void cleanup_clauses(literal_vector const & roots, clause_vector & cs); void cleanup_clauses(literal_vector const & roots, clause_vector & cs);
void cleanup_bin_watches(literal_vector const & roots); void cleanup_bin_watches(literal_vector const & roots);
bool check_clauses(literal_vector const & roots) const; bool check_clauses(literal_vector const & roots) const;
bool check_clause(clause const& c, literal_vector const& roots) const;
public: public:
elim_eqs(solver & s); elim_eqs(solver & s);
void operator()(literal_vector const & roots, bool_var_vector const & to_elim); void operator()(literal_vector const & roots, bool_var_vector const & to_elim);

View file

@ -71,6 +71,7 @@ namespace sat {
virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0; virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0;
virtual void collect_statistics(statistics& st) const = 0; virtual void collect_statistics(statistics& st) const = 0;
virtual extension* copy(solver* s) = 0; virtual extension* copy(solver* s) = 0;
virtual extension* copy(lookahead* s) = 0;
virtual void find_mutexes(literal_vector& lits, vector<literal_vector> & mutexes) = 0; virtual void find_mutexes(literal_vector& lits, vector<literal_vector> & mutexes) = 0;
virtual void gc() = 0; virtual void gc() = 0;
virtual void pop_reinit() = 0; virtual void pop_reinit() = 0;

View file

@ -92,7 +92,7 @@ namespace sat {
// TRACE("sat", display(tout << "Delete " << to_literal(idx) << "\n");); // TRACE("sat", display(tout << "Delete " << to_literal(idx) << "\n"););
literal_vector & lits = m_binary[idx]; literal_vector & lits = m_binary[idx];
SASSERT(!lits.empty()); SASSERT(!lits.empty());
literal l = lits.back(); literal l = lits.back();
lits.pop_back(); lits.pop_back();
SASSERT(!m_binary[(~l).index()].empty()); SASSERT(!m_binary[(~l).index()].empty());
IF_VERBOSE(0, if (m_binary[(~l).index()].back() != ~to_literal(idx)) verbose_stream() << "pop bad literal: " << idx << " " << (~l).index() << "\n";); IF_VERBOSE(0, if (m_binary[(~l).index()].back() != ~to_literal(idx)) verbose_stream() << "pop bad literal: " << idx << " " << (~l).index() << "\n";);
@ -112,7 +112,6 @@ namespace sat {
} }
} }
void lookahead::inc_bstamp() { void lookahead::inc_bstamp() {
++m_bstamp_id; ++m_bstamp_id;
if (m_bstamp_id == 0) { if (m_bstamp_id == 0) {
@ -120,6 +119,7 @@ namespace sat {
m_bstamp.fill(0); m_bstamp.fill(0);
} }
} }
void lookahead::inc_istamp() { void lookahead::inc_istamp() {
++m_istamp_id; ++m_istamp_id;
if (m_istamp_id == 0) { if (m_istamp_id == 0) {
@ -204,13 +204,13 @@ namespace sat {
void lookahead::pre_select() { void lookahead::pre_select() {
IF_VERBOSE(10, verbose_stream() << "freevars: " << m_freevars.size() << "\n";);
m_lookahead.reset(); m_lookahead.reset();
for (bool_var x : m_freevars) { // tree lookahead may leave some literals fixed in lower truth levels for (bool_var x : m_freevars) { // tree lookahead leaves literals fixed in lower truth levels
literal l(x, false); literal l(x, false);
set_undef(l); set_undef(l);
set_undef(~l); set_undef(~l);
} }
//printf("m_freevars.size() = %d\n", m_freevars.size());
if (select(scope_lvl())) { if (select(scope_lvl())) {
get_scc(); get_scc();
if (inconsistent()) return; if (inconsistent()) return;
@ -276,6 +276,7 @@ namespace sat {
sift_down(0, i); sift_down(0, i);
} }
} }
SASSERT(validate_heap_sort());
} }
void lookahead::heapify() { void lookahead::heapify() {
@ -299,6 +300,17 @@ namespace sat {
if (i > j) m_candidates[i] = c; if (i > j) m_candidates[i] = c;
} }
/**
* \brief validate that the result of heap sort sorts the candidates
* in descending order of their rating.
*/
bool lookahead::validate_heap_sort() {
for (unsigned i = 0; i + 1 < m_candidates.size(); ++i)
if (m_candidates[i].m_rating < m_candidates[i + 1].m_rating)
return false;
return true;
}
double lookahead::init_candidates(unsigned level, bool newbies) { double lookahead::init_candidates(unsigned level, bool newbies) {
m_candidates.reset(); m_candidates.reset();
double sum = 0; double sum = 0;
@ -328,25 +340,14 @@ namespace sat {
} }
bool lookahead::is_unsat() const { bool lookahead::is_unsat() const {
bool all_false = true;
bool first = true;
// check if there is a clause whose literals are false. // check if there is a clause whose literals are false.
// every clause is terminated by a null-literal. // every clause is terminated by a null-literal.
for (unsigned l_idx : m_nary_literals) { for (nary* n : m_nary_clauses) {
literal l = to_literal(l_idx); bool all_false = true;
if (first) { for (literal l : *n) {
// skip the first entry, the length indicator.
first = false;
}
else if (l == null_literal) {
// when reaching the end of a clause check if all entries are false
if (all_false) return true;
all_false = true;
first = true;
}
else {
all_false &= is_false(l); all_false &= is_false(l);
} }
if (all_false) return true;
} }
// check if there is a ternary whose literals are false. // check if there is a ternary whose literals are false.
for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { for (unsigned idx = 0; idx < m_ternary.size(); ++idx) {
@ -382,24 +383,14 @@ namespace sat {
} }
} }
} }
bool no_true = true;
bool first = true;
// check if there is a clause whose literals are false. // check if there is a clause whose literals are false.
// every clause is terminated by a null-literal. // every clause is terminated by a null-literal.
for (unsigned l_idx : m_nary_literals) { for (nary * n : m_nary_clauses) {
literal l = to_literal(l_idx); bool no_true = true;
if (first) { for (literal l : *n) {
// skip the first entry, the length indicator.
first = false;
}
else if (l == null_literal) {
if (no_true) return false;
no_true = true;
first = true;
}
else {
no_true &= !is_true(l); no_true &= !is_true(l);
} }
if (no_true) return false;
} }
// check if there is a ternary whose literals are false. // check if there is a ternary whose literals are false.
for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { for (unsigned idx = 0; idx < m_ternary.size(); ++idx) {
@ -476,17 +467,15 @@ namespace sat {
sum += (literal_occs(b.m_u) + literal_occs(b.m_v)) / 8.0; sum += (literal_occs(b.m_u) + literal_occs(b.m_v)) / 8.0;
} }
sz = m_nary_count[(~l).index()]; sz = m_nary_count[(~l).index()];
for (unsigned idx : m_nary[(~l).index()]) { for (nary * n : m_nary[(~l).index()]) {
if (sz-- == 0) break; if (sz-- == 0) break;
literal lit;
unsigned j = idx;
double to_add = 0; double to_add = 0;
while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { for (literal lit : *n) {
if (!is_fixed(lit) && lit != ~l) { if (!is_fixed(lit) && lit != ~l) {
to_add += literal_occs(lit); to_add += literal_occs(lit);
} }
} }
unsigned len = m_nary_literals[idx]; unsigned len = n->size();
sum += pow(0.5, len) * to_add / len; sum += pow(0.5, len) * to_add / len;
} }
return sum; return sum;
@ -507,9 +496,9 @@ namespace sat {
} }
sum += 0.25 * m_ternary_count[(~l).index()]; sum += 0.25 * m_ternary_count[(~l).index()];
unsigned sz = m_nary_count[(~l).index()]; unsigned sz = m_nary_count[(~l).index()];
for (unsigned cls_idx : m_nary[(~l).index()]) { for (nary * n : m_nary[(~l).index()]) {
if (sz-- == 0) break; if (sz-- == 0) break;
sum += pow(0.5, m_nary_literals[cls_idx]); sum += pow(0.5, n->size());
} }
return sum; return sum;
} }
@ -616,18 +605,18 @@ namespace sat {
void lookahead::init_arcs(literal l) { void lookahead::init_arcs(literal l) {
literal_vector lits; literal_vector lits;
literal_vector const& succ = m_binary[l.index()]; literal_vector const& succ = m_binary[l.index()];
for (unsigned i = 0; i < succ.size(); ++i) { for (literal u : succ) {
literal u = succ[i];
SASSERT(u != l); SASSERT(u != l);
// l => u
if (u.index() > l.index() && is_stamped(u)) { if (u.index() > l.index() && is_stamped(u)) {
add_arc(~l, ~u); add_arc(~l, ~u);
add_arc( u, l); add_arc( u, l);
} }
} }
for (auto w : m_watches[l.index()]) { for (auto w : m_watches[l.index()]) {
if (w.is_ext_constraint() && m_s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), lits)) { if (w.is_ext_constraint() && m_s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), lits)) {
for (literal u : lits) { for (literal u : lits) {
if (u.index() > l.index() && is_stamped(u)) { if (u.index() > (~l).index() && is_stamped(u)) {
add_arc(~l, ~u); add_arc(~l, ~u);
add_arc( u, l); add_arc( u, l);
} }
@ -901,8 +890,8 @@ namespace sat {
m_ternary.push_back(svector<binary>()); m_ternary.push_back(svector<binary>());
m_ternary_count.push_back(0); m_ternary_count.push_back(0);
m_ternary_count.push_back(0); m_ternary_count.push_back(0);
m_nary.push_back(unsigned_vector()); m_nary.push_back(ptr_vector<nary>());
m_nary.push_back(unsigned_vector()); m_nary.push_back(ptr_vector<nary>());
m_nary_count.push_back(0); m_nary_count.push_back(0);
m_nary_count.push_back(0); m_nary_count.push_back(0);
m_bstamp.push_back(0); m_bstamp.push_back(0);
@ -958,14 +947,8 @@ namespace sat {
} }
} }
// copy externals: if (m_s.m_ext) {
for (unsigned idx = 0; idx < m_s.m_watches.size(); ++idx) { m_ext = m_s.m_ext->copy(this);
watch_list const& wl = m_s.m_watches[idx];
for (watched const& w : wl) {
if (w.is_ext_constraint()) {
m_watches[idx].push_back(w);
}
}
} }
propagate(); propagate();
m_qhead = m_trail.size(); m_qhead = m_trail.size();
@ -1328,17 +1311,14 @@ namespace sat {
// new n-ary clause managment // new n-ary clause managment
void lookahead::add_clause(clause const& c) { void lookahead::add_clause(clause const& c) {
unsigned sz = c.size(); SASSERT(c.size() > 3);
SASSERT(sz > 3); void * mem = m_allocator.allocate(nary::get_obj_size(c.size()));
unsigned idx = m_nary_literals.size(); nary * n = new (mem) nary(c.size(), c.begin());
m_nary_literals.push_back(sz); m_nary_clauses.push_back(n);
for (literal l : c) { for (literal l : c) {
m_nary_literals.push_back(l.index()); m_nary[l.index()].push_back(n);
m_nary_count[l.index()]++; m_nary_count[l.index()]++;
m_nary[l.index()].push_back(idx);
SASSERT(m_nary_count[l.index()] == m_nary[l.index()].size());
} }
m_nary_literals.push_back(null_literal.index());
} }
@ -1347,18 +1327,17 @@ namespace sat {
unsigned sz = m_nary_count[(~l).index()]; unsigned sz = m_nary_count[(~l).index()];
literal lit; literal lit;
SASSERT(m_search_mode == lookahead_mode::searching); SASSERT(m_search_mode == lookahead_mode::searching);
for (unsigned idx : m_nary[(~l).index()]) { for (nary * n : m_nary[(~l).index()]) {
if (sz-- == 0) break; if (sz-- == 0) break;
unsigned len = --m_nary_literals[idx]; unsigned len = n->dec_size();
if (m_inconsistent) continue; if (m_inconsistent) continue;
if (len <= 1) continue; // already processed if (len <= 1) continue; // already processed
// find the two unassigned literals, if any // find the two unassigned literals, if any
if (len == 2) { if (len == 2) {
literal l1 = null_literal; literal l1 = null_literal;
literal l2 = null_literal; literal l2 = null_literal;
unsigned j = idx;
bool found_true = false; bool found_true = false;
while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { for (literal lit : *n) {
if (!is_fixed(lit)) { if (!is_fixed(lit)) {
if (l1 == null_literal) { if (l1 == null_literal) {
l1 = lit; l1 = lit;
@ -1370,7 +1349,7 @@ namespace sat {
} }
} }
else if (is_true(lit)) { else if (is_true(lit)) {
// can't swap with idx. std::swap(m_nary_literals[j], m_nary_literals[idx]); n->set_head(lit);
found_true = true; found_true = true;
break; break;
} }
@ -1398,9 +1377,9 @@ namespace sat {
} }
// clauses where l is positive: // clauses where l is positive:
sz = m_nary_count[l.index()]; sz = m_nary_count[l.index()];
for (unsigned idx : m_nary[l.index()]) { for (nary* n : m_nary[l.index()]) {
if (sz-- == 0) break; if (sz-- == 0) break;
remove_clause_at(l, idx); remove_clause_at(l, *n);
} }
} }
@ -1411,14 +1390,17 @@ namespace sat {
SASSERT(m_search_mode == lookahead_mode::lookahead1 || SASSERT(m_search_mode == lookahead_mode::lookahead1 ||
m_search_mode == lookahead_mode::lookahead2); m_search_mode == lookahead_mode::lookahead2);
for (unsigned idx : m_nary[(~l).index()]) { for (nary* n : m_nary[(~l).index()]) {
if (sz-- == 0) break; if (sz-- == 0) break;
if (is_true(n->get_head())) {
continue;
}
literal l1 = null_literal; literal l1 = null_literal;
literal l2 = null_literal; literal l2 = null_literal;
unsigned j = idx; bool skip_clause = false;
bool found_true = false;
unsigned nonfixed = 0; unsigned nonfixed = 0;
while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { for (literal lit : *n) {
if (!is_fixed(lit)) { if (!is_fixed(lit)) {
++nonfixed; ++nonfixed;
if (l1 == null_literal) { if (l1 == null_literal) {
@ -1427,14 +1409,19 @@ namespace sat {
else if (l2 == null_literal) { else if (l2 == null_literal) {
l2 = lit; l2 = lit;
} }
else if (m_search_mode == lookahead_mode::lookahead2) {
skip_clause = true;
break;
}
} }
else if (is_true(lit)) { else if (is_true(lit)) {
found_true = true; n->set_head(lit);
skip_clause = true;
break; break;
} }
} }
if (found_true) { if (skip_clause) {
// skip, the clause will be removed when propagating on 'lit' // skip, the clause
} }
else if (l1 == null_literal) { else if (l1 == null_literal) {
set_conflict(); set_conflict();
@ -1443,20 +1430,16 @@ namespace sat {
else if (l2 == null_literal) { else if (l2 == null_literal) {
propagated(l1); propagated(l1);
} }
else if (m_search_mode == lookahead_mode::lookahead2) {
continue;
}
else { else {
SASSERT(nonfixed >= 2); SASSERT(nonfixed >= 2);
SASSERT(m_search_mode == lookahead_mode::lookahead1); SASSERT(m_search_mode == lookahead_mode::lookahead1);
switch (m_config.m_reward_type) { switch (m_config.m_reward_type) {
case heule_schur_reward: { case heule_schur_reward: {
j = idx;
double to_add = 0; double to_add = 0;
while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { for (literal lit : *n) {
if (!is_fixed(lit)) { if (!is_fixed(lit)) {
to_add += literal_occs(lit); to_add += literal_occs(lit);
} }
} }
m_lookahead_reward += pow(0.5, nonfixed) * to_add / nonfixed; m_lookahead_reward += pow(0.5, nonfixed) * to_add / nonfixed;
break; break;
@ -1464,9 +1447,6 @@ namespace sat {
case heule_unit_reward: case heule_unit_reward:
m_lookahead_reward += pow(0.5, nonfixed); m_lookahead_reward += pow(0.5, nonfixed);
break; break;
case march_cu_reward:
m_lookahead_reward += 3.3 * pow(0.5, nonfixed - 2);
break;
case ternary_reward: case ternary_reward:
if (nonfixed == 2) { if (nonfixed == 2) {
m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()];
@ -1482,23 +1462,20 @@ namespace sat {
} }
} }
void lookahead::remove_clause_at(literal l, nary& n) {
void lookahead::remove_clause_at(literal l, unsigned clause_idx) { for (literal lit : n) {
unsigned j = clause_idx;
literal lit;
while ((lit = to_literal(m_nary_literals[++j])) != null_literal) {
if (lit != l) { if (lit != l) {
remove_clause(lit, clause_idx); remove_clause(lit, n);
} }
} }
} }
void lookahead::remove_clause(literal l, unsigned clause_idx) { void lookahead::remove_clause(literal l, nary& n) {
unsigned_vector& pclauses = m_nary[l.index()]; ptr_vector<nary>& pclauses = m_nary[l.index()];
unsigned sz = m_nary_count[l.index()]--; unsigned sz = m_nary_count[l.index()]--;
for (unsigned i = sz; i > 0; ) { for (unsigned i = sz; i > 0; ) {
--i; --i;
if (clause_idx == pclauses[i]) { if (&n == pclauses[i]) {
std::swap(pclauses[i], pclauses[sz-1]); std::swap(pclauses[i], pclauses[sz-1]);
return; return;
} }
@ -1508,33 +1485,29 @@ namespace sat {
void lookahead::restore_clauses(literal l) { void lookahead::restore_clauses(literal l) {
SASSERT(m_search_mode == lookahead_mode::searching); SASSERT(m_search_mode == lookahead_mode::searching);
// increase the length of clauses where l is negative // increase the length of clauses where l is negative
unsigned sz = m_nary_count[(~l).index()]; unsigned sz = m_nary_count[(~l).index()];
for (unsigned idx : m_nary[(~l).index()]) { for (nary* n : m_nary[(~l).index()]) {
if (sz-- == 0) break; if (sz-- == 0) break;
++m_nary_literals[idx]; n->inc_size();
} }
// add idx back to clause list where l is positive // add idx back to clause list where l is positive
// add them back in the same order as they were inserted // add them back in the same order as they were inserted
// in this way we can check that the clauses are the same. // in this way we can check that the clauses are the same.
sz = m_nary_count[l.index()]; sz = m_nary_count[l.index()];
unsigned_vector const& pclauses = m_nary[l.index()]; ptr_vector<nary>& pclauses = m_nary[l.index()];
for (unsigned i = sz; i > 0; ) { for (unsigned i = sz; i-- > 0; ) {
--i; for (literal lit : *pclauses[i]) {
unsigned j = pclauses[i];
literal lit;
while ((lit = to_literal(m_nary_literals[++j])) != null_literal) {
if (lit != l) { if (lit != l) {
SASSERT(m_nary[lit.index()][m_nary_count[lit.index()]] == pclauses[i]); SASSERT(m_nary[lit.index()][m_nary_count[lit.index()]] == pclauses[i]);
m_nary_count[lit.index()]++; m_nary_count[lit.index()]++;
} }
} }
} }
} }
void lookahead::propagate_clauses(literal l) { void lookahead::propagate_clauses(literal l) {
SASSERT(is_true(l));
propagate_ternary(l); propagate_ternary(l);
switch (m_search_mode) { switch (m_search_mode) {
case lookahead_mode::searching: case lookahead_mode::searching:
@ -1545,9 +1518,7 @@ namespace sat {
break; break;
} }
propagate_external(l); propagate_external(l);
} }
void lookahead::update_binary_clause_reward(literal l1, literal l2) { void lookahead::update_binary_clause_reward(literal l1, literal l2) {
SASSERT(!is_false(l1)); SASSERT(!is_false(l1));
@ -1610,7 +1581,6 @@ namespace sat {
// FIXME: counts occurences of ~l; misleading // FIXME: counts occurences of ~l; misleading
double lookahead::literal_occs(literal l) { double lookahead::literal_occs(literal l) {
double result = m_binary[l.index()].size(); double result = m_binary[l.index()].size();
//unsigned_vector const& nclauses = m_nary[(~l).index()];
result += literal_big_occs(l); result += literal_big_occs(l);
return result; return result;
} }
@ -1651,12 +1621,18 @@ namespace sat {
TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n"););
} }
#define CHECK_FAILED_LITERAL 0
void lookahead::compute_lookahead_reward() { void lookahead::compute_lookahead_reward() {
TRACE("sat", display_lookahead(tout); ); TRACE("sat", display_lookahead(tout); );
m_delta_decrease = pow(m_config.m_delta_rho, 1.0 / (double)m_lookahead.size()); m_delta_decrease = pow(m_config.m_delta_rho, 1.0 / (double)m_lookahead.size());
unsigned base = 2; unsigned base = 2;
bool change = true; bool change = true;
literal last_changed = null_literal; literal last_changed = null_literal;
#if CHECK_FAILED_LITERAL
unsigned_vector assigns;
literal_vector assigns_lits;
#endif
while (change && !inconsistent()) { while (change && !inconsistent()) {
change = false; change = false;
for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) {
@ -1677,7 +1653,6 @@ namespace sat {
reset_lookahead_reward(lit); reset_lookahead_reward(lit);
unsigned num_units = push_lookahead1(lit, level); unsigned num_units = push_lookahead1(lit, level);
update_lookahead_reward(lit, level); update_lookahead_reward(lit, level);
unsigned old_trail_sz = m_trail.size();
unsigned dl_lvl = level; unsigned dl_lvl = level;
num_units += do_double(lit, dl_lvl); num_units += do_double(lit, dl_lvl);
if (dl_lvl > level) { if (dl_lvl > level) {
@ -1688,6 +1663,10 @@ namespace sat {
if (unsat) { if (unsat) {
TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";);
lookahead_backtrack(); lookahead_backtrack();
#if CHECK_FAILED_LITERAL
assigns.push_back(m_trail.size());
assigns_lits.push_back(~lit);
#endif
assign(~lit); assign(~lit);
propagate(); propagate();
change = true; change = true;
@ -1701,6 +1680,12 @@ namespace sat {
base += 2 * m_lookahead.size(); base += 2 * m_lookahead.size();
} }
lookahead_backtrack(); lookahead_backtrack();
#if CHECK_FAILED_LITERAL
for (unsigned i = 0; i < assigns.size(); ++i) {
std::cout << "check trail: " << m_trail[assigns[i]] << " " << assigns_lits[i] << "\n";
VERIFY(m_trail[assigns[i]] == assigns_lits[i]);
}
#endif
TRACE("sat", display_lookahead(tout); ); TRACE("sat", display_lookahead(tout); );
} }
@ -1754,7 +1739,7 @@ namespace sat {
return false; return false;
#if 0 #if 0
// no propagations are allowed to reduce clauses. // no propagations are allowed to reduce clauses.
for (clause * cp : m_full_watches[l.index()]) { for (nary * cp : m_nary[(~l).index()]) {
clause& c = *cp; clause& c = *cp;
unsigned sz = c.size(); unsigned sz = c.size();
bool found = false; bool found = false;
@ -1993,8 +1978,10 @@ namespace sat {
lbool lookahead::cube() { lbool lookahead::cube() {
literal_vector lits; literal_vector lits;
bool_var_vector vars;
for (bool_var v : m_freevars) vars.push_back(v);
while (true) { while (true) {
lbool result = cube(lits); lbool result = cube(vars, lits);
if (lits.empty() || result != l_undef) { if (lits.empty() || result != l_undef) {
return l_undef; return l_undef;
} }
@ -2003,8 +1990,13 @@ namespace sat {
return l_undef; return l_undef;
} }
lbool lookahead::cube(literal_vector& lits) { lbool lookahead::cube(bool_var_vector const& vars, literal_vector& lits) {
scoped_ext _scoped_ext(*this);
lits.reset(); lits.reset();
m_select_lookahead_vars.reset();
for (auto v : vars) {
m_select_lookahead_vars.insert(v);
}
bool is_first = m_cube_state.m_first; bool is_first = m_cube_state.m_first;
if (is_first) { if (is_first) {
init_search(); init_search();
@ -2111,20 +2103,9 @@ namespace sat {
} }
} }
for (unsigned l_idx : m_nary_literals) { for (nary * n : m_nary_clauses) {
literal l = to_literal(l_idx); for (literal l : *n) out << l << " ";
if (first) { out << "\n";
// the first entry is a length indicator of non-false literals.
out << l_idx << ": ";
first = false;
}
else if (l == null_literal) {
first = true;
out << "\n";
}
else {
out << l << " ";
}
} }
return out; return out;
@ -2219,6 +2200,7 @@ namespace sat {
\brief simplify set of clauses by extracting units from a lookahead at base level. \brief simplify set of clauses by extracting units from a lookahead at base level.
*/ */
void lookahead::simplify() { void lookahead::simplify() {
scoped_ext _scoped_ext(*this);
SASSERT(m_prefix == 0); SASSERT(m_prefix == 0);
SASSERT(m_watches.empty()); SASSERT(m_watches.empty());
m_search_mode = lookahead_mode::searching; m_search_mode = lookahead_mode::searching;

View file

@ -20,6 +20,7 @@ Notes:
#ifndef _SAT_LOOKAHEAD_H_ #ifndef _SAT_LOOKAHEAD_H_
#define _SAT_LOOKAHEAD_H_ #define _SAT_LOOKAHEAD_H_
// #define OLD_NARY 0
#include "sat_elim_eqs.h" #include "sat_elim_eqs.h"
@ -89,8 +90,7 @@ namespace sat {
m_min_cutoff = 30; m_min_cutoff = 30;
m_preselect = false; m_preselect = false;
m_level_cand = 600; m_level_cand = 600;
//m_delta_rho = (double)0.25; m_delta_rho = (double)0.25;
m_delta_rho = (double)0.5;
m_dl_max_iterations = 2; m_dl_max_iterations = 2;
m_tc1_limit = 10000000; m_tc1_limit = 10000000;
m_reward_type = ternary_reward; m_reward_type = ternary_reward;
@ -132,6 +132,36 @@ namespace sat {
literal m_u, m_v; literal m_u, m_v;
}; };
class nary {
unsigned m_size; // number of non-false literals
size_t m_obj_size; // object size (counting all literals)
literal m_head; // head literal
literal m_literals[0]; // list of literals, put any true literal in head.
size_t num_lits() const {
return (m_obj_size - sizeof(nary)) / sizeof(literal);
}
public:
static size_t get_obj_size(unsigned sz) { return sizeof(nary) + sz * sizeof(literal); }
size_t obj_size() const { return m_obj_size; }
nary(unsigned sz, literal const* lits):
m_size(sz),
m_obj_size(get_obj_size(sz)) {
for (unsigned i = 0; i < sz; ++i) m_literals[i] = lits[i];
m_head = lits[0];
}
unsigned size() const { return m_size; }
unsigned dec_size() { SASSERT(m_size > 0); return --m_size; }
void inc_size() { SASSERT(m_size < num_lits()); ++m_size; }
literal get_head() const { return m_head; }
void set_head(literal l) { m_head = l; }
literal operator[](unsigned i) { SASSERT(i < num_lits()); return m_literals[i]; }
literal const* begin() const { return m_literals; }
literal const* end() const { return m_literals + num_lits(); }
// swap the true literal to the head.
// void swap(unsigned i, unsigned j) { SASSERT(i < num_lits() && j < num_lits()); std::swap(m_literals[i], m_literals[j]); }
};
struct cube_state { struct cube_state {
bool m_first; bool m_first;
svector<bool> m_is_decision; svector<bool> m_is_decision;
@ -164,10 +194,10 @@ namespace sat {
vector<svector<binary>> m_ternary; // lit |-> vector of ternary clauses vector<svector<binary>> m_ternary; // lit |-> vector of ternary clauses
unsigned_vector m_ternary_count; // lit |-> current number of active ternary clauses for lit unsigned_vector m_ternary_count; // lit |-> current number of active ternary clauses for lit
vector<unsigned_vector> m_nary; // lit |-> vector of clause_id small_object_allocator m_allocator;
unsigned_vector m_nary_count; // lit |-> number of valid clause_id in m_clauses2[lit] vector<ptr_vector<nary>> m_nary; // lit |-> vector of nary clauses
unsigned_vector m_nary_literals; // the actual literals, clauses start at offset clause_id, ptr_vector<nary> m_nary_clauses; // vector of all nary clauses
// the first entry is the current length, clauses are separated by a null_literal unsigned_vector m_nary_count; // lit |-> number of valid clause_id in m_nary[lit]
unsigned m_num_tc1; unsigned m_num_tc1;
unsigned_vector m_num_tc1_lim; unsigned_vector m_num_tc1_lim;
@ -196,6 +226,7 @@ namespace sat {
stats m_stats; stats m_stats;
model m_model; model m_model;
cube_state m_cube_state; cube_state m_cube_state;
scoped_ptr<extension> m_ext;
// --------------------------------------- // ---------------------------------------
// truth values // truth values
@ -293,10 +324,10 @@ namespace sat {
double get_rating(bool_var v) const { return m_rating[v]; } double get_rating(bool_var v) const { return m_rating[v]; }
double get_rating(literal l) const { return get_rating(l.var()); } double get_rating(literal l) const { return get_rating(l.var()); }
bool select(unsigned level); bool select(unsigned level);
//void sift_up(unsigned j);
void heap_sort(); void heap_sort();
void heapify(); void heapify();
void sift_down(unsigned j, unsigned sz); void sift_down(unsigned j, unsigned sz);
bool validate_heap_sort();
double init_candidates(unsigned level, bool newbies); double init_candidates(unsigned level, bool newbies);
std::ostream& display_candidates(std::ostream& out) const; std::ostream& display_candidates(std::ostream& out) const;
bool is_unsat() const; bool is_unsat() const;
@ -419,15 +450,15 @@ namespace sat {
void propagate_clauses_searching(literal l); void propagate_clauses_searching(literal l);
void propagate_clauses_lookahead(literal l); void propagate_clauses_lookahead(literal l);
void restore_clauses(literal l); void restore_clauses(literal l);
void remove_clause(literal l, unsigned clause_idx); void remove_clause(literal l, nary& n);
void remove_clause_at(literal l, unsigned clause_idx); void remove_clause_at(literal l, nary& n);
// ------------------------------------ // ------------------------------------
// initialization // initialization
void init_var(bool_var v); void init_var(bool_var v);
void init(); void init();
void copy_clauses(clause_vector const& clauses, bool learned); void copy_clauses(clause_vector const& clauses, bool learned);
nary * copy_clause(clause const& c);
// ------------------------------------ // ------------------------------------
// search // search
@ -510,6 +541,9 @@ namespace sat {
~lookahead() { ~lookahead() {
m_s.rlimit().pop_child(); m_s.rlimit().pop_child();
for (nary* n : m_nary_clauses) {
m_allocator.deallocate(n->obj_size(), n);
}
} }
@ -524,9 +558,10 @@ namespace sat {
If cut-depth != 0, then it is used to control the depth of cuts. If cut-depth != 0, then it is used to control the depth of cuts.
Otherwise, cut-fraction gives an adaptive threshold for creating cuts. Otherwise, cut-fraction gives an adaptive threshold for creating cuts.
*/ */
lbool cube(); lbool cube();
lbool cube(literal_vector& lits); lbool cube(bool_var_vector const& vars, literal_vector& lits);
literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars);
/** /**
@ -557,6 +592,8 @@ namespace sat {
double literal_occs(literal l); double literal_occs(literal l);
double literal_big_occs(literal l); double literal_big_occs(literal l);
sat::config const& get_config() const { return m_s.get_config(); }
}; };
} }

View file

@ -162,6 +162,7 @@ namespace sat {
m_user_scope_literals.append(src.m_user_scope_literals); m_user_scope_literals.append(src.m_user_scope_literals);
m_mc = src.m_mc; m_mc = src.m_mc;
m_stats.m_units = init_trail_size();
} }
// ----------------------- // -----------------------
@ -837,11 +838,11 @@ namespace sat {
return lh.select_lookahead(assumptions, vars); return lh.select_lookahead(assumptions, vars);
} }
lbool solver::cube(literal_vector& lits) { lbool solver::cube(bool_var_vector const& vars, literal_vector& lits) {
if (!m_cuber) { if (!m_cuber) {
m_cuber = alloc(lookahead, *this); m_cuber = alloc(lookahead, *this);
} }
lbool result = m_cuber->cube(lits); lbool result = m_cuber->cube(vars, lits);
if (result == l_false) { if (result == l_false) {
dealloc(m_cuber); dealloc(m_cuber);
m_cuber = nullptr; m_cuber = nullptr;
@ -858,6 +859,7 @@ namespace sat {
lbool solver::check(unsigned num_lits, literal const* lits) { lbool solver::check(unsigned num_lits, literal const* lits) {
init_reason_unknown(); init_reason_unknown();
pop_to_base_level(); pop_to_base_level();
m_stats.m_units = init_trail_size();
IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";);
SASSERT(at_base_lvl()); SASSERT(at_base_lvl());
if (m_config.m_dimacs_display) { if (m_config.m_dimacs_display) {
@ -1468,11 +1470,14 @@ namespace sat {
lh.simplify(); lh.simplify();
lh.collect_statistics(m_aux_stats); lh.collect_statistics(m_aux_stats);
} }
#if 0
// Buggy
{ {
lookahead lh(*this); lookahead lh(*this);
lh.scc(); lh.scc();
lh.collect_statistics(m_aux_stats); lh.collect_statistics(m_aux_stats);
} }
#endif
} }
@ -2823,6 +2828,7 @@ namespace sat {
pop(num_scopes); pop(num_scopes);
exchange_par(); exchange_par();
reinit_assumptions(); reinit_assumptions();
m_stats.m_units = init_trail_size();
} }
void solver::pop(unsigned num_scopes) { void solver::pop(unsigned num_scopes) {
@ -3048,7 +3054,6 @@ namespace sat {
m_probing.updt_params(p); m_probing.updt_params(p);
m_scc.updt_params(p); m_scc.updt_params(p);
m_rand.set_seed(m_config.m_random_seed); m_rand.set_seed(m_config.m_random_seed);
m_step_size = m_config.m_step_size_init; m_step_size = m_config.m_step_size_init;
} }
@ -4032,25 +4037,11 @@ namespace sat {
st.update("minimized lits", m_minimized_lits); st.update("minimized lits", m_minimized_lits);
st.update("dyn subsumption resolution", m_dyn_sub_res); st.update("dyn subsumption resolution", m_dyn_sub_res);
st.update("blocked correction sets", m_blocked_corr_sets); st.update("blocked correction sets", m_blocked_corr_sets);
st.update("units", m_units);
} }
void stats::reset() { void stats::reset() {
m_mk_var = 0; memset(this, 0, sizeof(*this));
m_mk_bin_clause = 0;
m_mk_ter_clause = 0;
m_mk_clause = 0;
m_conflict = 0;
m_propagate = 0;
m_bin_propagate = 0;
m_ter_propagate = 0;
m_decision = 0;
m_restart = 0;
m_gc_clause = 0;
m_del_clause = 0;
m_minimized_lits = 0;
m_dyn_sub_res = 0;
m_non_learned_generation = 0;
m_blocked_corr_sets = 0;
} }
void mk_stat::display(std::ostream & out) const { void mk_stat::display(std::ostream & out) const {

View file

@ -67,6 +67,7 @@ namespace sat {
unsigned m_dyn_sub_res; unsigned m_dyn_sub_res;
unsigned m_non_learned_generation; unsigned m_non_learned_generation;
unsigned m_blocked_corr_sets; unsigned m_blocked_corr_sets;
unsigned m_units;
stats() { reset(); } stats() { reset(); }
void reset(); void reset();
void collect_statistics(statistics & st) const; void collect_statistics(statistics & st) const;
@ -364,7 +365,7 @@ namespace sat {
char const* get_reason_unknown() const { return m_reason_unknown.c_str(); } char const* get_reason_unknown() const { return m_reason_unknown.c_str(); }
literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars);
lbool cube(literal_vector& lits); lbool cube(bool_var_vector const& vars, literal_vector& lits);
protected: protected:
unsigned m_conflicts_since_init; unsigned m_conflicts_since_init;

View file

@ -353,8 +353,12 @@ public:
m_internalized = true; m_internalized = true;
} }
convert_internalized(); convert_internalized();
sat::bool_var_vector vars;
for (auto& kv : m_map) {
vars.push_back(kv.m_value);
}
sat::literal_vector lits; sat::literal_vector lits;
lbool result = m_solver.cube(lits); lbool result = m_solver.cube(vars, lits);
if (result == l_false || lits.empty()) { if (result == l_false || lits.empty()) {
return expr_ref(m.mk_false(), m); return expr_ref(m.mk_false(), m);
} }

View file

@ -109,10 +109,10 @@ namespace sat {
bool operator!=(watched const & w) const { return !operator==(w); } bool operator!=(watched const & w) const { return !operator==(w); }
}; };
COMPILE_TIME_ASSERT(0 <= watched::BINARY && watched::BINARY <= 3); static_assert(0 <= watched::BINARY && watched::BINARY <= 3, "");
COMPILE_TIME_ASSERT(0 <= watched::TERNARY && watched::TERNARY <= 3); static_assert(0 <= watched::TERNARY && watched::TERNARY <= 3, "");
COMPILE_TIME_ASSERT(0 <= watched::CLAUSE && watched::CLAUSE <= 3); static_assert(0 <= watched::CLAUSE && watched::CLAUSE <= 3, "");
COMPILE_TIME_ASSERT(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 3); static_assert(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 3, "");
struct watched_lt { struct watched_lt {
bool operator()(watched const & w1, watched const & w2) const { bool operator()(watched const & w1, watched const & w2) const {

View file

@ -120,7 +120,7 @@ struct goal2sat::imp {
sat::bool_var mk_true() { sat::bool_var mk_true() {
if (m_true == sat::null_bool_var) { if (m_true == sat::null_bool_var) {
// create fake variable to represent true; // create fake variable to represent true;
m_true = m_solver.mk_var(); m_true = m_solver.mk_var(false);
mk_clause(sat::literal(m_true, false)); // v is true mk_clause(sat::literal(m_true, false)); // v is true
} }
return m_true; return m_true;

View file

@ -170,7 +170,7 @@ void asserted_formulas::get_assertions(ptr_vector<expr> & result) const {
void asserted_formulas::push_scope() { void asserted_formulas::push_scope() {
SASSERT(inconsistent() || m_qhead == m_formulas.size() || m.canceled()); 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_scoped_substitution.push();
m_scopes.push_back(scope()); m_scopes.push_back(scope());
scope & s = m_scopes.back(); scope & s = m_scopes.back();
@ -181,10 +181,11 @@ void asserted_formulas::push_scope() {
m_bv_sharing.push_scope(); m_bv_sharing.push_scope();
m_macro_manager.push_scope(); m_macro_manager.push_scope();
commit(); commit();
TRACE("asserted_formulas_scopes", tout << "after push: " << m_scopes.size() << "\n";);
} }
void asserted_formulas::pop_scope(unsigned num_scopes) { 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_bv_sharing.pop_scope(num_scopes);
m_macro_manager.pop_scope(num_scopes); m_macro_manager.pop_scope(num_scopes);
unsigned new_lvl = m_scopes.size() - 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_qhead = s.m_formulas_lim;
m_scopes.shrink(new_lvl); m_scopes.shrink(new_lvl);
flush_cache(); 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() { void asserted_formulas::reset() {

View file

@ -487,6 +487,7 @@ namespace smt {
*/ */
void context::add_eq(enode * n1, enode * n2, eq_justification js) { void context::add_eq(enode * n1, enode * n2, eq_justification js) {
unsigned old_trail_size = m_trail_stack.size(); unsigned old_trail_size = m_trail_stack.size();
scoped_suspend_rlimit _suspend_cancel(m_manager.limit());
try { try {
TRACE("add_eq", tout << "assigning: #" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n";); TRACE("add_eq", tout << "assigning: #" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n";);
@ -541,10 +542,14 @@ namespace smt {
mark_as_relevant(r1); mark_as_relevant(r1);
} }
TRACE("add_eq", tout << "to trail\n";);
push_trail(add_eq_trail(r1, n1, r2->get_num_parents())); 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); m_qmanager->add_eq_eh(r1, r2);
TRACE("add_eq", tout << "merge theory_vars\n";);
merge_theory_vars(n2, n1, js); merge_theory_vars(n2, n1, js);
// 'Proof' tree // 'Proof' tree
@ -577,6 +582,7 @@ namespace smt {
#endif #endif
TRACE("add_eq", tout << "remove_parents_from_cg_table\n";);
remove_parents_from_cg_table(r1); remove_parents_from_cg_table(r1);
enode * curr = r1; enode * curr = r1;
@ -588,8 +594,10 @@ namespace smt {
SASSERT(r1->get_root() == r2); 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); reinsert_parents_into_cg_table(r1, r2, n1, n2, js);
TRACE("add_eq", tout << "propagate_bool_enode_assignment\n";);
if (n2->is_bool()) if (n2->is_bool())
propagate_bool_enode_assignment(r1, r2, n1, n2); propagate_bool_enode_assignment(r1, r2, n1, n2);
@ -604,6 +612,7 @@ namespace smt {
catch (...) { catch (...) {
// Restore trail size since procedure was interrupted in the middle. // 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. // 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); m_trail_stack.shrink(old_trail_size);
throw; throw;
} }
@ -972,7 +981,7 @@ namespace smt {
enode * parent = *it; enode * parent = *it;
if (parent->is_cgc_enabled()) { if (parent->is_cgc_enabled()) {
TRACE("add_eq_parents", tout << "removing: #" << parent->get_owner_id() << "\n";); 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: #" << tout << "old num_parents: " << r2_num_parents << ", num_parents: " << r2->m_parents.size() << ", parent: #" <<
parent->get_owner_id() << ", parents: \n"; parent->get_owner_id() << ", parents: \n";
for (unsigned i = 0; i < r2->m_parents.size(); i++) { for (unsigned i = 0; i < r2->m_parents.size(); i++) {

View file

@ -284,7 +284,7 @@ namespace smt {
} }
lbool reduce_cond(model_ref& model, expr* e) { 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 (m.is_eq(e, e1, e2) && m_array_util.is_as_array(e1) && m_array_util.is_as_array(e2)) {
if (e1 == e2) { if (e1 == e2) {
return l_true; return l_true;

View file

@ -54,7 +54,7 @@ namespace smt {
ptr_vector<theory>::const_iterator it = m_context->begin_theories(); ptr_vector<theory>::const_iterator it = m_context->begin_theories();
ptr_vector<theory>::const_iterator end = m_context->end_theories(); ptr_vector<theory>::const_iterator end = m_context->end_theories();
for (; it != end; ++it) { 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); (*it)->init_model(*this);
} }
} }
@ -91,7 +91,7 @@ namespace smt {
sort * s = m_manager.get_sort(r->get_owner()); sort * s = m_manager.get_sort(r->get_owner());
model_value_proc * proc = 0; model_value_proc * proc = 0;
if (m_manager.is_bool(s)) { 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";); tout << mk_pp(r->get_owner(), m_manager) << "\n";);
SASSERT(m_context->get_assignment(r) != l_undef); SASSERT(m_context->get_assignment(r) != l_undef);
if (m_context->get_assignment(r) == l_true) if (m_context->get_assignment(r) == l_true)
@ -108,7 +108,7 @@ namespace smt {
SASSERT(proc); SASSERT(proc);
} }
else { 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()))); 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)) { if (!m_manager.is_model_value(n)) {
sort * s = m_manager.get_sort(r->get_owner()); sort * s = m_manager.get_sort(r->get_owner());
n = m_model->get_fresh_value(s); 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 << mk_pp(r->get_owner(), m_manager) << "\nsort:\n" << mk_pp(s, m_manager) << "\n";
tout << "is_finite: " << m_model->is_finite(s) << "\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 { bool model_generator::include_func_interp(func_decl * f) const {
family_id fid = f->get_family_id(); 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 == null_family_id) return !m_hidden_ufs.contains(f);
if (fid == m_manager.get_basic_family_id()) return false; if (fid == m_manager.get_basic_family_id()) return false;
theory * th = m_context->get_theory(fid); theory * th = m_context->get_theory(fid);
TRACE("model", tout << th << "\n";);
if (!th) return true; if (!th) return true;
return th->include_func_interp(f); return th->include_func_interp(f);
} }
@ -444,7 +446,7 @@ namespace smt {
SASSERT(m_model->has_interpretation(f)); SASSERT(m_model->has_interpretation(f));
SASSERT(m_model->get_func_interp(f) == fi); SASSERT(m_model->get_func_interp(f) == fi);
// The entry must be new because n->get_cg() == n // 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: "; tout << "insert new entry for:\n" << mk_ismt2_pp(n->get_owner(), m_manager) << "\nargs: ";
for (unsigned i = 0; i < num_args; i++) { for (unsigned i = 0; i < num_args; i++) {
tout << "#" << n->get_arg(i)->get_owner_id() << " "; tout << "#" << n->get_arg(i)->get_owner_id() << " ";
@ -508,20 +510,20 @@ namespace smt {
void model_generator::register_macros() { void model_generator::register_macros() {
unsigned num = m_context->get_num_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); expr_ref v(m_manager);
for (unsigned i = 0; i < num; i++) { for (unsigned i = 0; i < num; i++) {
func_decl * f = m_context->get_macro_interpretation(i, v); func_decl * f = m_context->get_macro_interpretation(i, v);
func_interp * fi = alloc(func_interp, m_manager, f->get_arity()); func_interp * fi = alloc(func_interp, m_manager, f->get_arity());
fi->set_else(v); 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); m_model->register_decl(f, fi);
} }
} }
proto_model * model_generator::mk_model() { proto_model * model_generator::mk_model() {
SASSERT(!m_model); SASSERT(!m_model);
TRACE("func_interp_bug", m_context->display(tout);); TRACE("model", m_context->display(tout););
init_model(); init_model();
register_existing_model_values(); register_existing_model_values();
mk_bool_model(); mk_bool_model();

View file

@ -216,6 +216,7 @@ namespace smt {
void setup::setup_QF_DT() { void setup::setup_QF_DT() {
setup_QF_UF(); setup_QF_UF();
setup_datatypes();
} }
void setup::setup_QF_BVRE() { void setup::setup_QF_BVRE() {

View file

@ -67,9 +67,9 @@ namespace smt {
}; };
// 32 bit machine // 32 bit machine
COMPILE_TIME_ASSERT(sizeof(expr*) != 4 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int)); static_assert(sizeof(expr*) != 4 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int), "32 bit");
// 64 bit machine // 64 bit machine
COMPILE_TIME_ASSERT(sizeof(expr*) != 8 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int) + /* a structure must be aligned */ sizeof(int)); static_assert(sizeof(expr*) != 8 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int) + /* a structure must be aligned */ sizeof(int), "64 bit");
}; };
#endif /* SMT_THEORY_VAR_LIST_H_ */ #endif /* SMT_THEORY_VAR_LIST_H_ */

View file

@ -780,7 +780,7 @@ namespace smt {
of a non linear monomial that is not satisfied by the current assignment. of a non linear monomial that is not satisfied by the current assignment.
if v >= l, then create the case split v >= l+1 if v >= l, then create the case split v >= l+1
else v <= u, then create the case split v <= u-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> template<typename Ext>
bool theory_arith<Ext>::branch_nl_int_var(theory_var v) { bool theory_arith<Ext>::branch_nl_int_var(theory_var v) {

View file

@ -689,7 +689,7 @@ namespace smt {
SASSERT(!ctx().b_internalized(atom)); SASSERT(!ctx().b_internalized(atom));
bool_var bv = ctx().mk_bool_var(atom); bool_var bv = ctx().mk_bool_var(atom);
ctx().set_var_theory(bv, get_id()); ctx().set_var_theory(bv, get_id());
expr* n1, *n2; expr* n1 = 0, *n2 = 0;
rational r; rational r;
lra_lp::bound_kind k; lra_lp::bound_kind k;
theory_var v = null_theory_var; theory_var v = null_theory_var;
@ -721,7 +721,7 @@ namespace smt {
SASSERT(!ctx().b_internalized(atom)); SASSERT(!ctx().b_internalized(atom));
bool_var bv = ctx().mk_bool_var(atom); bool_var bv = ctx().mk_bool_var(atom);
ctx().set_var_theory(bv, get_id()); ctx().set_var_theory(bv, get_id());
expr* n1, *n2; expr* n1 = 0, *n2 = 0;
rational r; rational r;
lra_lp::bound_kind k; lra_lp::bound_kind k;
theory_var v = null_theory_var; theory_var v = null_theory_var;
@ -862,7 +862,7 @@ namespace smt {
void relevant_eh(app* n) { void relevant_eh(app* n) {
TRACE("arith", tout << mk_pp(n, m) << "\n";); TRACE("arith", tout << mk_pp(n, m) << "\n";);
expr* n1, *n2; expr* n1 = 0, *n2 = 0;
if (a.is_mod(n, n1, n2)) if (a.is_mod(n, n1, n2))
mk_idiv_mod_axioms(n1, n2); mk_idiv_mod_axioms(n1, n2);
else if (a.is_rem(n, n1, n2)) else if (a.is_rem(n, n1, n2))

View file

@ -474,7 +474,6 @@ namespace smt {
if (pb.is_aux_bool(atom)) { if (pb.is_aux_bool(atom)) {
bool_var abv = ctx.mk_bool_var(atom); bool_var abv = ctx.mk_bool_var(atom);
ctx.set_var_theory(abv, get_id()); ctx.set_var_theory(abv, get_id());
std::cout << "aux bool " << ctx.get_scope_level() << " " << mk_pp(atom, get_manager()) << " " << literal(abv) << "\n";
return true; return true;
} }

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,7 @@ z3_add_component(core_tactics
ctx_simplify_tactic.cpp ctx_simplify_tactic.cpp
der_tactic.cpp der_tactic.cpp
distribute_forall_tactic.cpp distribute_forall_tactic.cpp
dom_simplify_tactic.cpp
elim_term_ite_tactic.cpp elim_term_ite_tactic.cpp
elim_uncnstr_tactic.cpp elim_uncnstr_tactic.cpp
injectivity_tactic.cpp injectivity_tactic.cpp
@ -32,6 +33,7 @@ z3_add_component(core_tactics
ctx_simplify_tactic.h ctx_simplify_tactic.h
der_tactic.h der_tactic.h
distribute_forall_tactic.h distribute_forall_tactic.h
dom_simplify_tactic.h
elim_term_ite_tactic.h elim_term_ite_tactic.h
elim_uncnstr_tactic.h elim_uncnstr_tactic.h
injectivity_tactic.h injectivity_tactic.h

View file

@ -83,49 +83,66 @@ expr* expr_dominators::intersect(expr* x, expr * y) {
return x; return x;
} }
void expr_dominators::compute_dominators() { bool expr_dominators::compute_dominators() {
expr * e = m_root; expr * e = m_root;
SASSERT(m_doms.empty()); SASSERT(m_doms.empty());
m_doms.insert(e, e); m_doms.insert(e, e);
bool change = true; bool change = true;
unsigned iterations = 1;
while (change) { while (change) {
change = false; change = false;
SASSERT(m_post2expr.back() == e); TRACE("simplify",
for (unsigned i = 0; i < m_post2expr.size() - 1; ++i) { 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]; expr * child = m_post2expr[i];
ptr_vector<expr> const& p = m_parents[child]; ptr_vector<expr> const& p = m_parents[child];
SASSERT(!p.empty()); expr * new_idom = 0, *idom2 = 0;
expr * new_idom = p[0], * idom2 = 0;
for (unsigned j = 1; j < p.size(); ++j) { for (expr * pred : p) {
if (m_doms.find(p[j], idom2)) { if (m_doms.contains(pred)) {
new_idom = intersect(new_idom, idom2); 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); m_doms.insert(child, new_idom);
change = true; change = true;
} }
} }
iterations *= 2;
if (change && iterations > m_post2expr.size()) {
return false;
}
} }
return true;
} }
void expr_dominators::extract_tree() { void expr_dominators::extract_tree() {
for (auto const& kv : m_doms) { for (auto const& kv : m_doms) {
add_edge(m_tree, kv.m_value, kv.m_key); add_edge(m_tree, kv.m_value, kv.m_key);
} }
} }
void expr_dominators::compile(expr * e) { bool expr_dominators::compile(expr * e) {
reset(); reset();
m_root = e; m_root = e;
compute_post_order(); compute_post_order();
compute_dominators(); if (!compute_dominators()) return false;
extract_tree(); 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); expr_ref e(m.mk_and(sz, es), m);
compile(e); return compile(e);
} }
void expr_dominators::reset() { void expr_dominators::reset() {
@ -137,19 +154,39 @@ void expr_dominators::reset() {
m_root.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::~dom_simplify_tactic() {
dealloc(m_simplifier);
}
tactic * dom_simplify_tactic::translate(ast_manager & m) { tactic * dom_simplify_tactic::translate(ast_manager & m) {
return alloc(dom_simplify_tactic, m, m_simplifier->translate(m), m_params); return alloc(dom_simplify_tactic, m, m_simplifier->translate(m), m_params);
} }
void dom_simplify_tactic::operator()( void dom_simplify_tactic::operator()(
goal_ref const & in, goal_ref const & in,
goal_ref_buffer & result, goal_ref_buffer & result,
model_converter_ref & mc, model_converter_ref & mc,
proof_converter_ref & pc, proof_converter_ref & pc,
expr_dependency_ref & core) { expr_dependency_ref & core) {
mc = 0; pc = 0; core = 0; mc = 0; pc = 0; core = 0;
@ -162,33 +199,42 @@ void dom_simplify_tactic::operator()(
} }
void dom_simplify_tactic::cleanup() { void dom_simplify_tactic::cleanup() {
m_trail.reset(); m_trail.reset();
m_args.reset(); m_args.reset();
m_args2.reset(); m_result.reset();
m_result.reset(); m_dominators.reset();
m_dominators.reset();
} }
expr_ref dom_simplify_tactic::simplify_ite(app * ite) { expr_ref dom_simplify_tactic::simplify_ite(app * ite) {
expr_ref r(m); 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)); VERIFY(m.is_ite(ite, c, t, e));
unsigned old_lvl = scope_level(); unsigned old_lvl = scope_level();
expr_ref new_c = simplify(c); expr_ref new_c = simplify_arg(c);
if (m.is_true(new_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)) { else if (m.is_false(new_c) || !assert_expr(new_c, false)) {
r = simplify(e); r = simplify_arg(e);
} }
else { 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); pop(scope_level() - old_lvl);
expr_ref new_t = simplify_arg(t);
if (!assert_expr(new_c, true)) { if (!assert_expr(new_c, true)) {
return new_t; 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); pop(scope_level() - old_lvl);
expr_ref new_e = simplify_arg(e);
if (c == new_c && t == new_t && e == new_e) { if (c == new_c && t == new_t && e == new_e) {
r = ite; r = ite;
} }
@ -197,15 +243,28 @@ expr_ref dom_simplify_tactic::simplify_ite(app * ite) {
} }
else { else {
TRACE("tactic", tout << new_c << "\n" << new_t << "\n" << new_e << "\n";); 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; 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_ref r(m);
expr* e = 0; expr* e = 0;
TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << "\n";);
if (!m_result.find(e0, e)) { if (!m_result.find(e0, e)) {
e = e0; e = e0;
} }
@ -224,17 +283,13 @@ expr_ref dom_simplify_tactic::simplify(expr * e0) {
r = simplify_or(to_app(e)); r = simplify_or(to_app(e));
} }
else { else {
expr_dominators::tree_t const& t = m_dominators.get_tree(); for (expr * child : tree(e)) {
if (t.contains(e)) { simplify_rec(child);
ptr_vector<expr> const& children = t[e];
for (expr * child : children) {
simplify(child);
}
} }
if (is_app(e)) { if (is_app(e)) {
m_args.reset(); m_args.reset();
for (expr* arg : *to_app(e)) { 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()); 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); cache(e0, r);
TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << " -> " << r << "\n";); TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << " -> " << r << "\n";);
--m_depth; --m_depth;
m_subexpr_cache.reset();
return r; return r;
} }
expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) { expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) {
expr_ref r(m); expr_ref r(m);
unsigned old_lvl = scope_level(); unsigned old_lvl = scope_level();
m_args.reset();
for (expr * arg : *e) { auto is_subexpr_arg = [&](expr * child, expr * except) {
r = simplify(arg); if (!is_subexpr(child, except))
if (!assert_expr(r, !is_and)) { return false;
r = is_and ? m.mk_false() : m.mk_true(); for (expr * arg : *e) {
if (arg != except && is_subexpr(child, arg))
return false;
} }
m_args.push_back(r); return true;
};
expr_ref_vector args(m);
if (m_forward) {
for (expr * arg : *e) {
#define _SIMP_ARG(arg) \
for (expr * child : tree(arg)) { \
if (is_subexpr_arg(child, arg)) { \
simplify_rec(child); \
} \
} \
r = simplify_arg(arg); \
args.push_back(r); \
if (!assert_expr(r, !is_and)) { \
r = is_and ? m.mk_false() : m.mk_true(); \
return r; \
}
_SIMP_ARG(arg);
}
}
else {
for (unsigned i = e->get_num_args(); i > 0; ) {
--i;
expr* arg = e->get_arg(i);
_SIMP_ARG(arg);
}
args.reverse();
} }
pop(scope_level() - old_lvl); pop(scope_level() - old_lvl);
m_args.reverse(); r = is_and ? mk_and(args) : mk_or(args);
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);
return r; return r;
} }
void dom_simplify_tactic::init(goal& g) { bool dom_simplify_tactic::init(goal& g) {
expr_ref_vector args(m); expr_ref_vector args(m);
unsigned sz = g.size(); unsigned sz = g.size();
for (unsigned i = 0; i < sz; ++i) args.push_back(g.form(i)); for (unsigned i = 0; i < sz; ++i) args.push_back(g.form(i));
expr_ref fml = mk_and(args); expr_ref fml = mk_and(args);
m_result.reset(); m_result.reset();
m_trail.reset(); m_trail.reset();
m_dominators.compile(fml); return m_dominators.compile(fml);
} }
void dom_simplify_tactic::simplify_goal(goal& g) { void dom_simplify_tactic::simplify_goal(goal& g) {
@ -296,13 +370,15 @@ void dom_simplify_tactic::simplify_goal(goal& g) {
change = false; change = false;
// go forwards // go forwards
init(g); m_forward = true;
if (!init(g)) return;
unsigned sz = g.size(); unsigned sz = g.size();
for (unsigned i = 0; !g.inconsistent() && i < sz; ++i) { 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)) { 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(); r = m.mk_false();
} }
CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";);
change |= r != g.form(i); change |= r != g.form(i);
proof* new_pr = 0; proof* new_pr = 0;
if (g.proofs_enabled()) { if (g.proofs_enabled()) {
@ -313,15 +389,17 @@ void dom_simplify_tactic::simplify_goal(goal& g) {
pop(scope_level()); pop(scope_level());
// go backwards // go backwards
init(g); m_forward = false;
if (!init(g)) return;
sz = g.size(); sz = g.size();
for (unsigned i = sz; !g.inconsistent() && i > 0; ) { for (unsigned i = sz; !g.inconsistent() && i > 0; ) {
--i; --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)) { 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(); r = m.mk_false();
} }
change |= r != g.form(i); change |= r != g.form(i);
CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";);
proof* new_pr = 0; proof* new_pr = 0;
if (g.proofs_enabled()) { if (g.proofs_enabled()) {
new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, 0)); 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); 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 // expr_substitution_simplifier
bool expr_substitution_simplifier::assert_expr(expr * t, bool sign) { bool expr_substitution_simplifier::assert_expr(expr * t, bool sign) {
m_scoped_substitution.push();
expr* tt; expr* tt;
if (!sign) { if (!sign) {
update_substitution(t, 0); 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))) { if (is_ground(n) && (m.is_eq(n, lhs, rhs) || m.is_iff(n, lhs, rhs))) {
compute_depth(lhs); compute_depth(lhs);
compute_depth(rhs); compute_depth(rhs);
m_trail.push_back(lhs);
m_trail.push_back(rhs);
if (is_gt(lhs, rhs)) { if (is_gt(lhs, rhs)) {
TRACE("propagate_values", tout << "insert " << mk_pp(lhs, m) << " -> " << mk_pp(rhs, m) << "\n";); TRACE("propagate_values", tout << "insert " << mk_pp(lhs, m) << " -> " << mk_pp(rhs, m) << "\n";);
m_scoped_substitution.insert(lhs, rhs, pr); 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); 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));
}

View file

@ -23,6 +23,8 @@ Notes:
#include "ast/ast.h" #include "ast/ast.h"
#include "ast/expr_substitution.h" #include "ast/expr_substitution.h"
#include "tactic/tactic.h" #include "tactic/tactic.h"
#include "tactic/tactical.h"
#include "util/obj_pair_hashtable.h"
class expr_dominators { class expr_dominators {
@ -43,78 +45,92 @@ private:
void compute_post_order(); void compute_post_order();
expr* intersect(expr* x, expr * y); expr* intersect(expr* x, expr * y);
void compute_dominators(); bool compute_dominators();
void extract_tree(); void extract_tree();
std::ostream& display(std::ostream& out, unsigned indent, expr* r);
public: public:
expr_dominators(ast_manager& m): m(m), m_root(m) {} expr_dominators(ast_manager& m): m(m), m_root(m) {}
void compile(expr * e); bool compile(expr * e);
void compile(unsigned sz, expr * const* es); bool compile(unsigned sz, expr * const* es);
tree_t const& get_tree() { return m_tree; } tree_t const& get_tree() { return m_tree; }
void reset(); void reset();
expr* idom(expr *e) const { return m_doms[e]; }
std::ostream& display(std::ostream& out);
};
class dom_simplifier {
public:
dom_simplifier() {}
virtual ~dom_simplifier() {}
/**
\brief assert_expr performs an implicit push
*/
virtual bool assert_expr(expr * t, bool sign) = 0;
/**
\brief apply simplification.
*/
virtual void operator()(expr_ref& r) = 0;
/**
\brief pop scopes accumulated from assertions.
*/
virtual void pop(unsigned num_scopes) = 0;
virtual dom_simplifier * translate(ast_manager & m) = 0;
}; };
class dom_simplify_tactic : public tactic { class dom_simplify_tactic : public tactic {
public:
class simplifier {
public:
virtual ~simplifier() {}
/**
\brief assert_expr performs an implicit push
*/
virtual bool assert_expr(expr * t, bool sign) = 0;
/**
\brief apply simplification.
*/
virtual void operator()(expr_ref& r) = 0;
/**
\brief pop scopes accumulated from assertions.
*/
virtual void pop(unsigned num_scopes) = 0;
virtual simplifier * translate(ast_manager & m);
};
private:
ast_manager& m; ast_manager& m;
simplifier* m_simplifier; dom_simplifier* m_simplifier;
params_ref m_params; 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; obj_map<expr, expr*> m_result;
expr_dominators m_dominators; expr_dominators m_dominators;
unsigned m_scope_level; unsigned m_scope_level;
unsigned m_depth; unsigned m_depth;
unsigned m_max_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_ite(app * ite);
expr_ref simplify_and(app * ite) { return simplify_and_or(true, 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_or(app * ite) { return simplify_and_or(false, ite); }
expr_ref simplify_and_or(bool is_and, app * ite); expr_ref simplify_and_or(bool is_and, app * ite);
void simplify_goal(goal& g); 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); } 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; } unsigned scope_level() { return m_scope_level; }
void pop(unsigned n) { SASSERT(n <= m_scope_level); m_scope_level -= n; m_simplifier->pop(n); } 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); } 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: 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(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_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 tactic * translate(ast_manager & m);
virtual void updt_params(params_ref const & p) {} virtual void updt_params(params_ref const & p) {}
@ -130,11 +146,12 @@ public:
virtual void cleanup(); virtual void cleanup();
}; };
class expr_substitution_simplifier : public dom_simplify_tactic::simplifier { class expr_substitution_simplifier : public dom_simplifier {
ast_manager& m; ast_manager& m;
expr_substitution m_subst; expr_substitution m_subst;
scoped_expr_substitution m_scoped_substitution; scoped_expr_substitution m_scoped_substitution;
obj_map<expr, unsigned> m_expr2depth; obj_map<expr, unsigned> m_expr2depth;
expr_ref_vector m_trail;
// move from asserted_formulas to here.. // move from asserted_formulas to here..
void compute_depth(expr* e); 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]; } unsigned depth(expr* e) { return m_expr2depth[e]; }
public: 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 ~expr_substitution_simplifier() {}
virtual bool assert_expr(expr * t, bool sign); 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 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()); SASSERT(m_subst.empty());
return alloc(expr_substitution_simplifier, m); 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 #endif

View file

@ -1,11 +1,13 @@
z3_add_component(portfolio z3_add_component(portfolio
SOURCES SOURCES
bounded_int2bv_solver.cpp
default_tactic.cpp default_tactic.cpp
enum2bv_solver.cpp enum2bv_solver.cpp
pb2bv_solver.cpp
bounded_int2bv_solver.cpp
fd_solver.cpp fd_solver.cpp
parallel_tactic.cpp
pb2bv_solver.cpp
smt_strategic_solver.cpp smt_strategic_solver.cpp
solver2lookahead.cpp
COMPONENT_DEPENDENCIES COMPONENT_DEPENDENCIES
aig_tactic aig_tactic
fp fp
@ -19,4 +21,5 @@ z3_add_component(portfolio
TACTIC_HEADERS TACTIC_HEADERS
default_tactic.h default_tactic.h
fd_solver.h fd_solver.h
parallel_tactic.h
) )

View file

@ -0,0 +1,448 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
parallel_tactic.cpp
Abstract:
Parallel tactic in the style of Treengeling.
It assumes a solver that supports good lookaheads.
Author:
Nikolaj Bjorner (nbjorner) 2017-10-9
Notes:
--*/
#include "util/scoped_ptr_vector.h"
#include "ast/ast_util.h"
#include "solver/solver.h"
#include "solver/solver2tactic.h"
#include "tactic/tactic.h"
#include "tactic/portfolio/fd_solver.h"
class parallel_tactic : public tactic {
class solver_state {
params_ref m_params;
scoped_ptr<ast_manager> m_manager;
ref<solver> m_solver;
expr_ref_vector m_cube;
unsigned m_units;
public:
solver_state(ast_manager* m, solver* s, params_ref const& p):
m_params(p),
m_manager(m),
m_solver(s),
m_cube(s->get_manager()),
m_units(0) {}
void update_units() {
m_units = 0;
statistics st;
m_solver->collect_statistics(st);
std::string units("units");
for (unsigned i = st.size(); i-- > 0; ) {
if (st.get_key(i) == units) {
m_units = st.get_uint_value(i);
std::cout << "value for " << i << " is " << m_units << "\n";
break;
}
}
}
expr_ref cube() { return mk_and(m_cube); }
void add_cube(expr* c) { m_cube.push_back(c); }
unsigned num_units() const { return m_units; }
solver& get_solver() { return *m_solver; }
solver const& get_solver() const { return *m_solver; }
params_ref const& params() const { return m_params; }
solver_state* clone(params_ref const& p, expr* cube) {
ast_manager& m = m_solver->get_manager();
ast_manager* new_m = alloc(ast_manager, m, !m.proof_mode());
solver* s = m_solver->translate(*new_m, p);
solver_state* st = alloc(solver_state, new_m, s, m_params);
ast_translation translate(m, *new_m);
for (expr* c : m_cube) {
st->m_cube.push_back(translate(c));
}
expr_ref cube1(translate(cube), *new_m);
st->m_cube.push_back(cube1);
s->assert_expr(cube1);
return st;
}
};
public:
bool operator()(solver_state* s1, solver_state* s2) const {
return s1->num_units() > s2->num_units();
}
private:
ast_manager& m_manager;
params_ref m_params;
// parameters
unsigned m_conflicts_lower_bound;
unsigned m_conflicts_upper_bound;
unsigned m_conflicts_growth_rate;
unsigned m_conflicts_decay_rate;
unsigned m_num_threads;
double m_progress;
unsigned m_max_conflicts;
statistics m_stats;
vector<solver_state*> m_solvers;
void init() {
m_conflicts_lower_bound = 1000;
m_conflicts_upper_bound = 10000;
m_conflicts_growth_rate = 150;
m_conflicts_decay_rate = 75;
m_max_conflicts = m_conflicts_lower_bound;
m_progress = 0;
m_num_threads = omp_get_num_procs(); // TBD adjust by possible threads used inside each solver.
}
unsigned get_max_conflicts() {
return m_max_conflicts;
}
void set_max_conflicts(unsigned c) {
m_max_conflicts = c;
}
bool should_increase_conflicts() {
return m_progress < 0;
}
void update_progress(bool b) {
m_progress = 0.9 * m_progress + (b ? 1 : -1);
if (b) {
m_stats.update("closed", 1u);
}
}
int pick_solvers() {
// order solvers by number of units in descending order
for (solver_state* s : m_solvers) s->update_units();
std::sort(m_solvers.c_ptr(), m_solvers.c_ptr() + m_solvers.size(), *this);
TRACE("parallel_tactic", display(tout););
return std::min(m_num_threads, m_solvers.size());
}
int max_num_splits() {
if (m_solvers.empty()) {
return m_num_threads;
}
uint64 max_mem = memory::get_max_memory_size();
uint64 cur_mem = memory::get_allocation_size();
uint64 sol_sz = cur_mem / m_solvers.size();
TRACE("parallel_tactic", tout << "max mem: " << max_mem << " cur mem: " << cur_mem << " num solvers: " << m_solvers.size() << "\n";);
if (max_mem <= cur_mem) {
return 0;
}
if (cur_mem == 0) {
return m_num_threads;
}
uint64 extra_solvers = (max_mem - cur_mem) / (2 * sol_sz);
if (extra_solvers > m_num_threads) {
return m_num_threads;
}
return static_cast<int>(extra_solvers);
}
void update_max_conflicts() {
if (should_increase_conflicts()) {
set_max_conflicts(std::min(m_conflicts_upper_bound, m_conflicts_growth_rate * get_max_conflicts() / 100));
}
else {
set_max_conflicts(std::max(m_conflicts_lower_bound, m_conflicts_decay_rate * get_max_conflicts() / 100));
}
}
lbool simplify(solver& s) {
params_ref p;
p.copy(m_params);
p.set_uint("max_conflicts", 10);
p.set_bool("lookahead_simplify", true);
s.updt_params(p);
lbool is_sat = s.check_sat(0,0);
p.set_uint("max_conflicts", get_max_conflicts());
p.set_bool("lookahead_simplify", false);
s.updt_params(p);
return is_sat;
}
lbool cube(solver_state& s) {
ast_manager& m = s.get_solver().get_manager();
expr_ref_vector cubes(m);
params_ref p;
p.copy(s.params());
p.set_uint("lookahead.cube.cutoff", 1);
s.get_solver().updt_params(p);
SASSERT(&m == &cubes.get_manager());
while (true) {
expr_ref c = s.get_solver().cube();
VERIFY(c);
if (m.is_false(c)) {
break;
}
if (m.is_true(c)) {
cubes.reset();
return l_undef;
}
cubes.push_back(c);
}
IF_VERBOSE(1, verbose_stream() << "cubes: " << cubes << "\n";);
if (cubes.empty()) {
return l_false;
}
for (unsigned j = 1; j < cubes.size(); ++j) {
solver_state* s1 = s.clone(s.params(), cubes[j].get());
#pragma omp critical (parallel_tactic)
{
m_solvers.push_back(s1);
}
}
expr* cube0 = cubes[0].get();
s.add_cube(cube0);
s.get_solver().assert_expr(cube0);
return l_undef;
}
lbool solve(solver& s) {
params_ref p;
p.copy(m_params);
p.set_uint("max_conflicts", get_max_conflicts());
s.updt_params(p);
return s.check_sat(0, 0);
}
void remove_unsat(svector<int>& unsat) {
std::sort(unsat.begin(), unsat.end());
unsat.reverse();
DEBUG_CODE(for (unsigned i = 0; i + 1 < unsat.size(); ++i) SASSERT(unsat[i] > unsat[i+1]););
for (int i : unsat) {
m_solvers[i]->get_solver().collect_statistics(m_stats);
dealloc(m_solvers[i]);
for (unsigned j = i + 1; j < m_solvers.size(); ++j) {
m_solvers[j - 1] = m_solvers[j];
}
m_solvers.shrink(m_solvers.size() - 1);
update_progress(true);
}
unsat.reset();
}
void get_model(model_ref& mdl, int sat_index) {
SASSERT(sat_index != -1);
m_solvers[sat_index]->get_solver().get_model(mdl);
ast_translation translate(m_solvers[sat_index]->get_solver().get_manager(), m_manager);
mdl = mdl->translate(translate);
}
lbool solve(model_ref& mdl) {
while (true) {
int sz = pick_solvers();
if (sz == 0) {
return l_false;
}
svector<int> unsat;
int sat_index = -1;
// Simplify phase.
IF_VERBOSE(1, verbose_stream() << "(solver.parallel :simplify " << sz << ")\n";);
IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";);
#pragma omp parallel for
for (int i = 0; i < sz; ++i) {
lbool is_sat = simplify(m_solvers[i]->get_solver());
switch (is_sat) {
case l_false:
#pragma omp critical (parallel_tactic)
{
unsat.push_back(i);
}
break;
case l_true:
sat_index = i;
break;
case l_undef:
break;
}
}
if (sat_index != -1) {
get_model(mdl, sat_index);
return l_true;
}
sz -= unsat.size();
remove_unsat(unsat);
if (sz == 0) continue;
// Solve phase.
IF_VERBOSE(1, verbose_stream() << "(solver.parallel :solve " << sz << ")\n";);
IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";);
#pragma omp parallel for
for (int i = 0; i < sz; ++i) {
lbool is_sat = solve(m_solvers[i]->get_solver());
switch (is_sat) {
case l_false:
#pragma omp critical (parallel_tactic)
{
unsat.push_back(i);
}
break;
case l_true:
sat_index = i;
break;
case l_undef:
break;
}
}
if (sat_index != -1) {
get_model(mdl, sat_index);
return l_true;
}
sz -= unsat.size();
remove_unsat(unsat);
sz = std::min(max_num_splits(), sz);
if (sz == 0) continue;
// Split phase.
IF_VERBOSE(1, verbose_stream() << "(solver.parallel :split " << sz << ")\n";);
IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";);
#pragma omp parallel for
for (int i = 0; i < sz; ++i) {
switch (cube(*m_solvers[i])) {
case l_false:
#pragma omp critical (parallel_tactic)
{
unsat.push_back(i);
}
break;
default:
#pragma omp critical (parallel_tactic)
{
update_progress(false);
}
break;
}
}
remove_unsat(unsat);
update_max_conflicts();
}
return l_undef;
}
std::ostream& display(std::ostream& out) {
for (solver_state* s : m_solvers) {
out << "solver units " << s->num_units() << "\n";
out << "cube " << s->cube() << "\n";
}
m_stats.display(out);
return out;
}
public:
parallel_tactic(ast_manager& m, params_ref const& p) :
m_manager(m),
m_params(p) {
init();
}
void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) {
ast_manager& m = g->m();
solver* s = mk_fd_solver(m, m_params);
m_solvers.push_back(alloc(solver_state, 0, s, m_params));
expr_ref_vector clauses(m);
ptr_vector<expr> assumptions;
obj_map<expr, expr*> bool2dep;
ref<filter_model_converter> fmc;
extract_clauses_and_dependencies(g, clauses, assumptions, bool2dep, fmc);
for (expr * clause : clauses) {
s->assert_expr(clause);
}
SASSERT(assumptions.empty());
model_ref mdl;
lbool is_sat = solve(mdl);
switch (is_sat) {
case l_true:
if (g->models_enabled()) {
mc = model2model_converter(mdl.get());
mc = concat(fmc.get(), mc.get());
}
g->reset();
break;
case l_false:
SASSERT(!g->proofs_enabled());
SASSERT(!g->unsat_core_enabled());
g->assert_expr(m.mk_false(), nullptr, nullptr);
break;
case l_undef:
if (m.canceled()) {
throw tactic_exception(Z3_CANCELED_MSG);
}
break;
}
result.push_back(g.get());
}
void cleanup() {
for (solver_state * s : m_solvers) dealloc(s);
m_solvers.reset();
init();
}
tactic* translate(ast_manager& m) {
return alloc(parallel_tactic, m, m_params);
}
virtual void updt_params(params_ref const & p) {
m_params.copy(p);
}
virtual void collect_param_descrs(param_descrs & r) {
// TBD
}
virtual void collect_statistics(statistics & st) const {
for (solver_state const * s : m_solvers) {
s->get_solver().collect_statistics(st);
}
st.copy(m_stats);
}
virtual void reset_statistics() {
m_stats.reset();
}
};
tactic * mk_parallel_tactic(ast_manager& m, params_ref const& p) {
return alloc(parallel_tactic, m, p);
}

View file

@ -0,0 +1,31 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
parallel_tactic.h
Abstract:
Parallel tactic in the style of Treengeling.
Author:
Nikolaj Bjorner (nbjorner) 2017-10-9
Notes:
--*/
#ifndef PARALLEL_TACTIC_H_
#define PARALLEL_TACTIC_H_
class solver;
class tactic;
tactic * mk_parallel_tactic(ast_manager& m, params_ref const& p);
/*
ADD_TACTIC("qffdp", "builtin strategy for solving QF_FD problems in parallel.", "mk_parallel_tactic(m, p)")
*/
#endif

View file

@ -0,0 +1,24 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
solver2lookahead.cpp
Abstract:
Lookahead wrapper for arbitrary solver.
Author:
Nikolaj Bjorner (nbjorner) 2017-10-9
Notes:
--*/
#include "sat/sat_solver/inc_sat_solver.h"
#include "solver/solver.h"
solver * mk_solver2lookahead(solver* s) {
return 0;
}

View file

@ -0,0 +1,26 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
solver2lookahead.h
Abstract:
Lookahead wrapper for arbitrary solver.
Author:
Nikolaj Bjorner (nbjorner) 2017-10-9
Notes:
--*/
#ifndef SOLVER2LOOKAHEAD_H_
#define SOLVER2LOOKAHEAD_H_
class solver;
solver * mk_solver2lookahead(solver* s);
#endif

View file

@ -214,6 +214,10 @@ void tst_ddnf1() {
ddnf.insert(*tX1); ddnf.insert(*tX1);
ddnf.insert(*t1X); ddnf.insert(*t1X);
ddnf.display(std::cout); ddnf.display(std::cout);
tbvm.deallocate(tXX);
tbvm.deallocate(t1X);
tbvm.deallocate(tX1);
tbvm.deallocate(t11);
} }

View file

@ -29,7 +29,7 @@ public:
static const unsigned long long zero = 0ull; static const unsigned long long zero = 0ull;
static const unsigned long long one = 1ull; static const unsigned long long one = 1ull;
}; };
COMPILE_TIME_ASSERT(sizeof(unsigned long long) == 8); static_assert(sizeof(unsigned long long) == 8, "");
template <> class approx_set_traits<unsigned> { template <> class approx_set_traits<unsigned> {
public: public:
@ -37,7 +37,7 @@ public:
static const unsigned zero = 0; static const unsigned zero = 0;
static const unsigned one = 1; static const unsigned one = 1;
}; };
COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); static_assert(sizeof(unsigned) == 4, "unsigned are 4 bytes");
template<typename T, typename T2U_Proc, typename R=unsigned long long> template<typename T, typename T2U_Proc, typename R=unsigned long long>
class approx_set_tpl : private T2U_Proc { class approx_set_tpl : private T2U_Proc {

View file

@ -24,7 +24,7 @@ Revision History:
#include "util/vector.h" #include "util/vector.h"
#include "util/memory_manager.h" #include "util/memory_manager.h"
COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); static_assert(sizeof(unsigned) == 4, "unsigned are 4 bytes");
#define BV_DEFAULT_CAPACITY 2 #define BV_DEFAULT_CAPACITY 2
class bit_vector { class bit_vector {

View file

@ -90,7 +90,6 @@ bool is_debug_enabled(const char * tag);
exit(-1); \ exit(-1); \
} }
#define COMPILE_TIME_ASSERT(expr) static_assert(expr, "")
void finalize_debug(); void finalize_debug();
/* /*

View file

@ -97,7 +97,7 @@ public:
} }
}; };
COMPILE_TIME_ASSERT(sizeof(uint64) == sizeof(double)); static_assert(sizeof(uint64) == sizeof(double), "");
#endif /* DOUBLE_MANAGER_H_ */ #endif /* DOUBLE_MANAGER_H_ */

View file

@ -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<mpq>::set_value(const mpq&, unsigned int);
template void indexed_vector<unsigned>::set_value(const unsigned&, unsigned int); template void indexed_vector<unsigned>::set_value(const unsigned&, unsigned int);
#ifdef Z3DEBUG #ifdef Z3DEBUG
template bool indexed_vector<unsigned>::is_OK() const;
template bool indexed_vector<double>::is_OK() const; template bool indexed_vector<double>::is_OK() const;
template bool indexed_vector<mpq>::is_OK() const; template bool indexed_vector<mpq>::is_OK() const;
template bool indexed_vector<lp::numeric_pair<mpq> >::is_OK() const; template bool indexed_vector<lp::numeric_pair<mpq> >::is_OK() const;

View file

@ -417,6 +417,8 @@ public:
for (unsigned i : m_rows_with_changed_bounds.m_index) { for (unsigned i : m_rows_with_changed_bounds.m_index) {
calculate_implied_bounds_for_row(i, bp); calculate_implied_bounds_for_row(i, bp);
if (settings().get_cancel_flag())
return;
} }
m_rows_with_changed_bounds.clear(); m_rows_with_changed_bounds.clear();
if (!use_tableau()) { if (!use_tableau()) {

View file

@ -176,25 +176,34 @@ unsigned lp_primal_core_solver<T, X>::solve_with_tableau() {
default: default:
break; // do nothing break; // do nothing
} }
} while (this->get_status() != FLOATING_POINT_ERROR } while (this->get_status() != FLOATING_POINT_ERROR
&& &&
this->get_status() != UNBOUNDED this->get_status() != UNBOUNDED
&& &&
this->get_status() != OPTIMAL this->get_status() != OPTIMAL
&& &&
this->get_status() != INFEASIBLE this->get_status() != INFEASIBLE
&& &&
this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements
&& &&
this->total_iterations() <= this->m_settings.max_total_number_of_iterations this->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);
if (this->m_settings.get_cancel_flag()) {
this->set_status(CANCELLED);
}
SASSERT(this->get_status() == FLOATING_POINT_ERROR SASSERT(
|| this->get_status() == FLOATING_POINT_ERROR
this->current_x_is_feasible() == false ||
|| this->get_status() == CANCELLED
this->calc_current_x_is_feasible_include_non_basis()); ||
this->current_x_is_feasible() == false
||
this->calc_current_x_is_feasible_include_non_basis());
return this->total_iterations(); return this->total_iterations();
} }

View file

@ -61,7 +61,8 @@ enum lp_status {
TIME_EXHAUSTED, TIME_EXHAUSTED,
ITERATIONS_EXHAUSTED, ITERATIONS_EXHAUSTED,
EMPTY, 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 // 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

View file

@ -58,9 +58,10 @@ static void throw_out_of_memory() {
g_memory_out_of_memory = true; g_memory_out_of_memory = true;
} }
__assume(0);
if (g_exit_when_out_of_memory) { if (g_exit_when_out_of_memory) {
std::cerr << g_out_of_memory_msg << "\n"; std::cerr << g_out_of_memory_msg << "\n";
__assume(0);
exit(ERR_MEMOUT); exit(ERR_MEMOUT);
} }
else { else {
@ -181,6 +182,23 @@ unsigned long long memory::get_max_used_memory() {
return r; return r;
} }
#if defined(_WINDOWS)
#include "Windows.h"
#endif
unsigned long long memory::get_max_memory_size() {
#if defined(_WINDOWS)
MEMORYSTATUSEX statex;
statex.dwLength = sizeof (statex);
GlobalMemoryStatusEx (&statex);
return statex.ullTotalPhys;
#else
NOT_IMPLEMENTED_YET();
// two GB
return 1 << 31;
#endif
}
unsigned long long memory::get_allocation_count() { unsigned long long memory::get_allocation_count() {
return g_memory_alloc_count; return g_memory_alloc_count;
} }

View file

@ -67,6 +67,7 @@ public:
static unsigned long long get_allocation_size(); static unsigned long long get_allocation_size();
static unsigned long long get_max_used_memory(); static unsigned long long get_max_used_memory();
static unsigned long long get_allocation_count(); static unsigned long long get_allocation_count();
static unsigned long long get_max_memory_size();
// temporary hack to avoid out-of-memory crash in z3.exe // temporary hack to avoid out-of-memory crash in z3.exe
static void exit_when_out_of_memory(bool flag, char const * msg); static void exit_when_out_of_memory(bool flag, char const * msg);
}; };

View file

@ -73,7 +73,7 @@ mpf_manager::~mpf_manager() {
} }
void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, int value) { void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, int value) {
COMPILE_TIME_ASSERT(sizeof(int) == 4); static_assert(sizeof(int) == 4, "assume integers are 4 bytes");
o.sign = false; o.sign = false;
o.ebits = ebits; o.ebits = ebits;
@ -119,7 +119,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode
void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, double value) { void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, double value) {
// double === mpf(11, 53) // double === mpf(11, 53)
COMPILE_TIME_ASSERT(sizeof(double) == 8); static_assert(sizeof(double) == 8, "doubles are 8 bytes");
uint64 raw; uint64 raw;
memcpy(&raw, &value, sizeof(double)); memcpy(&raw, &value, sizeof(double));
@ -155,7 +155,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, double value) {
void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, float value) { void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, float value) {
// single === mpf(8, 24) // single === mpf(8, 24)
COMPILE_TIME_ASSERT(sizeof(float) == 4); static_assert(sizeof(float) == 4, "floats are 4 bytes");
unsigned int raw; unsigned int raw;
memcpy(&raw, &value, sizeof(float)); memcpy(&raw, &value, sizeof(float));

View file

@ -27,8 +27,8 @@ Revision History:
#include "util/bit_util.h" #include "util/bit_util.h"
#include "util/trace.h" #include "util/trace.h"
COMPILE_TIME_ASSERT(sizeof(mpn_digit) == sizeof(unsigned)); static_assert(sizeof(mpn_digit) == sizeof(unsigned), "");
COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); static_assert(sizeof(unsigned) == 4, "unsigned haven't changed size for a while");
// MIN_MSW is an shorthand for 0x8000..00, i.e., the minimal most significand word. // MIN_MSW is an shorthand for 0x8000..00, i.e., the minimal most significand word.
#define MIN_MSW (1u << (sizeof(unsigned) * 8 - 1)) #define MIN_MSW (1u << (sizeof(unsigned) * 8 - 1))

View file

@ -24,7 +24,7 @@ Revision History:
#define max(a,b) (((a) > (b)) ? (a) : (b)) #define max(a,b) (((a) > (b)) ? (a) : (b))
typedef uint64 mpn_double_digit; typedef uint64 mpn_double_digit;
COMPILE_TIME_ASSERT(sizeof(mpn_double_digit) == 2 * sizeof(mpn_digit)); static_assert(sizeof(mpn_double_digit) == 2 * sizeof(mpn_digit), "size alignment");
const mpn_digit mpn_manager::zero = 0; const mpn_digit mpn_manager::zero = 0;

View file

@ -558,14 +558,13 @@ void mpz_manager<SYNCH>::big_rem(mpz const & a, mpz const & b, mpz & c) {
template<bool SYNCH> template<bool SYNCH>
void mpz_manager<SYNCH>::gcd(mpz const & a, mpz const & b, mpz & c) { void mpz_manager<SYNCH>::gcd(mpz const & a, mpz const & b, mpz & c) {
if (is_small(a) && is_small(b)) { static_assert(sizeof(a.m_val) == sizeof(int), "size mismatch");
if (is_small(a) && is_small(b) && a.m_val != INT_MIN && b.m_val != INT_MIN) {
int _a = a.m_val; int _a = a.m_val;
int _b = b.m_val; int _b = b.m_val;
if (_a < 0) _a = -_a; if (_a < 0) _a = -_a;
if (_b < 0) _b = -_b; if (_b < 0) _b = -_b;
unsigned r = u_gcd(_a, _b); unsigned r = u_gcd(_a, _b);
// Remark: r is (INT_MAX + 1)
// If a == b == INT_MIN
set(c, r); set(c, r);
} }
else { else {
@ -725,7 +724,7 @@ void mpz_manager<SYNCH>::gcd(mpz const & a, mpz const & b, mpz & c) {
#ifdef LEHMER_GCD #ifdef LEHMER_GCD
// For now, it only works if sizeof(digit_t) == sizeof(unsigned) // For now, it only works if sizeof(digit_t) == sizeof(unsigned)
COMPILE_TIME_ASSERT(sizeof(digit_t) == sizeof(unsigned)); static_assert(sizeof(digit_t) == sizeof(unsigned), "");
int64 a_hat, b_hat, A, B, C, D, T, q, a_sz, b_sz; int64 a_hat, b_hat, A, B, C, D, T, q, a_sz, b_sz;
mpz a1, b1, t, r, tmp; mpz a1, b1, t, r, tmp;
@ -1755,7 +1754,7 @@ void mpz_manager<SYNCH>::mul2k(mpz & a, unsigned k) {
} }
#ifndef _MP_GMP #ifndef _MP_GMP
COMPILE_TIME_ASSERT(sizeof(digit_t) == 4 || sizeof(digit_t) == 8); static_assert(sizeof(digit_t) == 4 || sizeof(digit_t) == 8, "");
#endif #endif
template<bool SYNCH> template<bool SYNCH>
@ -1822,7 +1821,7 @@ unsigned mpz_manager<SYNCH>::log2(mpz const & a) {
if (is_small(a)) if (is_small(a))
return ::log2((unsigned)a.m_val); return ::log2((unsigned)a.m_val);
#ifndef _MP_GMP #ifndef _MP_GMP
COMPILE_TIME_ASSERT(sizeof(digit_t) == 8 || sizeof(digit_t) == 4); static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, "");
mpz_cell * c = a.m_ptr; mpz_cell * c = a.m_ptr;
unsigned sz = c->m_size; unsigned sz = c->m_size;
digit_t * ds = c->m_digits; digit_t * ds = c->m_digits;
@ -1844,7 +1843,7 @@ unsigned mpz_manager<SYNCH>::mlog2(mpz const & a) {
if (is_small(a)) if (is_small(a))
return ::log2((unsigned)-a.m_val); return ::log2((unsigned)-a.m_val);
#ifndef _MP_GMP #ifndef _MP_GMP
COMPILE_TIME_ASSERT(sizeof(digit_t) == 8 || sizeof(digit_t) == 4); static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, "");
mpz_cell * c = a.m_ptr; mpz_cell * c = a.m_ptr;
unsigned sz = c->m_size; unsigned sz = c->m_size;
digit_t * ds = c->m_digits; digit_t * ds = c->m_digits;

View file

@ -21,6 +21,7 @@ Revision History:
reslimit::reslimit(): reslimit::reslimit():
m_cancel(0), m_cancel(0),
m_suspend(false),
m_count(0), m_count(0),
m_limit(0) { m_limit(0) {
} }
@ -31,12 +32,12 @@ uint64 reslimit::count() const {
bool reslimit::inc() { bool reslimit::inc() {
++m_count; ++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) { bool reslimit::inc(unsigned offset) {
m_count += 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) { void reslimit::push(unsigned delta_limit) {

View file

@ -23,12 +23,14 @@ Revision History:
class reslimit { class reslimit {
volatile unsigned m_cancel; volatile unsigned m_cancel;
bool m_suspend;
uint64 m_count; uint64 m_count;
uint64 m_limit; uint64 m_limit;
svector<uint64> m_limits; svector<uint64> m_limits;
ptr_vector<reslimit> m_children; ptr_vector<reslimit> m_children;
void set_cancel(unsigned f); void set_cancel(unsigned f);
friend class scoped_suspend_rlimit;
public: public:
reslimit(); reslimit();
@ -42,7 +44,7 @@ public:
uint64 count() const; 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; char const* get_cancel_msg() const;
void cancel(); void cancel();
void reset_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 { struct scoped_limits {
reslimit& m_limit; reslimit& m_limit;
unsigned m_sz; unsigned m_sz;

View file

@ -469,7 +469,9 @@ Notes:
} }
literal mk_ordered_1(bool full, bool is_eq, unsigned n, literal const* xs) { literal mk_ordered_1(bool full, bool is_eq, unsigned n, literal const* xs) {
if (n <= 1 && !is_eq) return ctx.mk_true(); if (n <= 1 && !is_eq) {
return ctx.mk_true();
}
if (n == 0) { if (n == 0) {
return ctx.mk_false(); return ctx.mk_false();
} }
@ -477,6 +479,8 @@ Notes:
return xs[0]; return xs[0];
} }
SASSERT(n > 1);
// y0 -> y1 // y0 -> y1
// x0 -> y0 // x0 -> y0
// x1 -> y1 // x1 -> y1

View file

@ -22,7 +22,6 @@ Revision History:
#include "util/util.h" #include "util/util.h"
#include "util/vector.h" #include "util/vector.h"
COMPILE_TIME_ASSERT(sizeof(unsigned) == 4);
class uint_set : unsigned_vector { class uint_set : unsigned_vector {

View file

@ -34,13 +34,13 @@ Revision History:
typedef unsigned long long uint64; typedef unsigned long long uint64;
#endif #endif
COMPILE_TIME_ASSERT(sizeof(uint64) == 8); static_assert(sizeof(uint64) == 8, "64 bits please");
#ifndef int64 #ifndef int64
typedef long long int64; typedef long long int64;
#endif #endif
COMPILE_TIME_ASSERT(sizeof(int64) == 8); static_assert(sizeof(int64) == 8, "64 bits");
#ifndef INT64_MIN #ifndef INT64_MIN
#define INT64_MIN static_cast<int64>(0x8000000000000000ull) #define INT64_MIN static_cast<int64>(0x8000000000000000ull)
@ -112,7 +112,7 @@ inline unsigned next_power_of_two(unsigned v) {
unsigned log2(unsigned v); unsigned log2(unsigned v);
unsigned uint64_log2(uint64 v); unsigned uint64_log2(uint64 v);
COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); static_assert(sizeof(unsigned) == 4, "unsigned are 32 bits");
// Return the number of 1 bits in v. // Return the number of 1 bits in v.
static inline unsigned get_num_1bits(unsigned v) { static inline unsigned get_num_1bits(unsigned v) {

View file

@ -72,6 +72,7 @@ class vector {
SZ new_capacity = (3 * old_capacity + 1) >> 1; SZ new_capacity = (3 * old_capacity + 1) >> 1;
SZ new_capacity_T = sizeof(T) * new_capacity + sizeof(SZ) * 2; SZ new_capacity_T = sizeof(T) * new_capacity + sizeof(SZ) * 2;
if (new_capacity <= old_capacity || new_capacity_T <= old_capacity_T) { if (new_capacity <= old_capacity || new_capacity_T <= old_capacity_T) {
UNREACHABLE();
throw default_exception("Overflow encountered when expanding vector"); throw default_exception("Overflow encountered when expanding vector");
} }
SZ *mem = (SZ*)memory::reallocate(reinterpret_cast<SZ*>(m_data)-2, new_capacity_T); SZ *mem = (SZ*)memory::reallocate(reinterpret_cast<SZ*>(m_data)-2, new_capacity_T);