3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-05-04 14:25:46 +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
- LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo
# Debug builds
#
# Note the unit tests for the debug builds are compiled but **not**
# executed. This is because the debug build of unit tests takes a large
# amount of time to execute compared to the optimized builds. The hope is
# that just running the optimized unit tests is sufficient.
#
# 64-bit GCC 5.4 Debug
- LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug
- LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY
# 64-bit Clang Debug
- LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug
- LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY
# 32-bit GCC 5.4 RelWithDebInfo
- LINUX_BASE=ubuntu32_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=i686 Z3_BUILD_TYPE=RelWithDebInfo
@ -57,7 +64,7 @@ env:
# 64-bit GCC 4.8 RelWithDebInfo
- LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo
# 64-bit GCC 4.8 Debug
- LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug
- LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY
# macOS (a.k.a OSX) support
matrix:

View file

@ -12,9 +12,9 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z
## Build status
| Windows x86 | Windows x64 | Ubuntu x64 | Ubuntu x86 | Debian x64 | OSX | TravisCI |
| ----------- | ----------- | ---------- | ---------- | ---------- | --- | -------- |
[![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)
| 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) | [![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
[2]: #building-z3-using-make-and-gccclang

View file

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

View file

@ -31,7 +31,7 @@ the future.
* `NO_SUPPRESS_OUTPUT` - Don't suppress output of some commands (`0` or `1`)
* `PYTHON_BINDINGS` - Build and test Python API bindings (`0` or `1`)
* `RUN_SYSTEM_TESTS` - Run system tests (`0` or `1`)
* `RUN_UNIT_TESTS` - Run unit tests (`0` or `1`)
* `RUN_UNIT_TESTS` - Run unit tests (`BUILD_ONLY` or `BUILD_AND_RUN` or `SKIP`)
* `TARGET_ARCH` - Target architecture (`x86_64` or `i686`)
* `TEST_INSTALL` - Test running `install` target (`0` or `1`)
* `UBSAN_BUILD` - Do [UndefinedBehaviourSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) build (`0` or `1`)
@ -58,8 +58,9 @@ The `scripts/travis_ci_linux_entry_point.sh` script
variables (if set) into the build using the `--build-arg` argument of the `docker run`
command.
If an environemnt variable is not set a defaults value is used which can be
found in `Dockerfiles/z3_build.Dockerfile`.
The default values of the configuration environment variables
can be found in
[`scripts/ci_defaults.sh`](scripts/ci_defaults.sh).
#### Linux specific configuration variables
@ -67,8 +68,9 @@ found in `Dockerfiles/z3_build.Dockerfile`.
#### Reproducing a build locally
A build can be reproduced locally by using the `scripts/travis_ci_linux_entry_point.sh`
script and setting the appropriate environment variable.
A build can be reproduced locally by using the
`scripts/travis_ci_linux_entry_point.sh` script and setting the appropriate
environment variable.
For example lets say we wanted to reproduce the build below.
@ -104,11 +106,43 @@ feature might be removed in the future.
It may be better to just build the base image once (outside of TravisCI), upload
it to [DockerHub](https://hub.docker.com/) and have the build pull down the pre-built
image everytime.
image every time.
An [organization](https://hub.docker.com/u/z3prover/) has been created on
DockerHub for this.
### macOS
Not yet implemented.
For macOS we execute directly on TravisCI's macOS environment. The entry point
for the TravisCI builds is the
[`scripts/travis_ci_osx_entry_point.sh`](scripts/travis_ci_osx_entry_point.sh)
scripts.
#### macOS specific configuration variables
* `MACOS_SKIP_DEPS_UPDATE` - If set to `1` installing the necessary build dependencies
is skipped. This is useful for local testing if the dependencies are already installed.
* `MACOS_UPDATE_CMAKE` - If set to `1` the installed version of CMake will be upgraded.
#### Reproducing a build locally
To reproduce a build (e.g. like the one shown below)
```yaml
- os: osx
osx_image: xcode8.3
# Note: Apple Clang does not support OpenMP
env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0
```
Run the following:
```bash
TRAVIS_BUILD_DIR=$(pwd) \
Z3_BUILD_TYPE=RelWithDebInfo \
USE_OPEN_MP=0 \
contrib/ci/scripts/travis_ci_osx_entry_point.sh
```
Note this assumes that the current working directory is the root of the Z3
git repository.

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
: ${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"}
: ${RUN_UNIT_TESTS?"RUN_UNIT_TESTS must be specified"}
if [ "X${RUN_UNIT_TESTS}" != "X1" ]; then
echo "Skipping unit tests"
exit 0
fi
# Set CMake generator args
source ${SCRIPT_DIR}/set_generator_args.sh
cd "${Z3_BUILD_DIR}"
# Build and run internal tests
cmake --build $(pwd) --target test-z3 "${GENERATOR_ARGS[@]}"
# Run all tests that don't require arguments
run_quiet ./test-z3 /a
function build_unit_tests() {
# Build internal tests
cmake --build $(pwd) --target test-z3 "${GENERATOR_ARGS[@]}"
}
function run_unit_tests() {
# Run all tests that don't require arguments
run_quiet ./test-z3 /a
}
case "${RUN_UNIT_TESTS}" in
BUILD_AND_RUN)
build_unit_tests
run_unit_tests
;;
BUILD_ONLY)
build_unit_tests
;;
SKIP)
echo "RUN_UNIT_TESTS set to \"${RUN_UNIT_TESTS}\" so skipping build and run"
exit 0
;;
*)
echo "Error: RUN_UNIT_TESTS set to unhandled value \"${RUN_UNIT_TESTS}\""
exit 1
;;
esac

View file

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

View file

@ -6,26 +6,8 @@ set -x
set -e
set -o pipefail
# Set defaults
# FIXME: Refactor this so we don't need to stay in sync with
# `z3_build.Dockerfile`.
export ASAN_BUILD="${ASAN_BUILD:-0}"
export BUILD_DOCS="${BUILD_DOCS:-0}"
export C_COMPILER="${C_COMPILER:-clang}"
export CXX_COMPILER="${CXX_COMPILER:-clang++}"
export DOTNET_BINDINGS="${DOTNET_BINDINGS:-1}"
export JAVA_BINDINGS="${JAVA_BINDINGS:-1}"
export NO_SUPPRESS_OUTPUT="${NO_SUPPRESS_OUTPUT:-0}"
export PYTHON_BINDINGS="${PYTHON_BINDINGS:-1}"
export PYTHON_EXECUTABLE="$(which python)"
export RUN_SYSTEM_TESTS="${RUN_SYSTEM_TESTS:-1}"
export RUN_UNIT_TESTS="${RUN_UNIT_TESTS:-1}"
export TARGET_ARCH="${TARGET_ARCH:-x86_64}"
export TEST_INSTALL="${TEST_INSTALL:-1}"
export UBSAN_BUILD="${UBSAN_BUILD:-0}"
export USE_LIBGMP="${USE_LIBGMP:-0}"
export USE_LTO="${USE_LTO:-0}"
export USE_OPENMP="${USE_OPENMP:-1}"
# Get defaults
source "${SCRIPT_DIR}/ci_defaults.sh"
if [ -z "${TRAVIS_BUILD_DIR}" ]; then
echo "TRAVIS_BUILD_DIR must be set to root of Z3 repository"
@ -37,15 +19,12 @@ if [ ! -d "${TRAVIS_BUILD_DIR}" ]; then
exit 1
fi
# These variables are specific to the macOS TravisCI
# implementation and are not set in `ci_defaults.sh`.
export PYTHON_EXECUTABLE="${PYTHON_EXECUTABLE:-$(which python)}"
export Z3_SRC_DIR="${TRAVIS_BUILD_DIR}"
export Z3_BUILD_DIR="${Z3_SRC_DIR}/build"
export Z3_BUILD_TYPE="${Z3_BUILD_TYPE:-RelWithDebInfo}"
export Z3_CMAKE_GENERATOR="${Z3_CMAKE_GENERATOR:-Ninja}"
export Z3_INSTALL_PREFIX="${Z3_INSTALL_PREFIX:-/usr/local}"
export Z3_STATIC_BUILD="${Z3_STATIC_BUILD:-0}"
export Z3_SYSTEM_TEST_DIR="${Z3_SRC_DIR}/z3_system_test"
export Z3_WARNINGS_AS_ERRORS="${Z3_WARNINGS_AS_ERRORS:-SERIOUS_ONLY}"
export Z3_VERBOSE_BUILD_OUTPUT="${Z3_VERBOSE_BUILD_OUTPUT:-0}"
# Overwrite whatever what set in TravisCI
export CC="${C_COMPILER}"

View file

@ -188,7 +188,7 @@ try:
if Z3PY_ENABLED:
print("Z3Py documentation enabled")
doxygen_config_substitutions['PYTHON_API_FILES'] = 'z3.py'
doxygen_config_substitutions['PYTHON_API_FILES'] = 'z3*.py'
else:
print("Z3Py documentation disabled")
doxygen_config_substitutions['PYTHON_API_FILES'] = ''
@ -288,8 +288,21 @@ try:
# Put z3py at the beginning of the search path to try to avoid picking up
# an installed copy of Z3py.
sys.path.insert(0, os.path.dirname(Z3PY_PACKAGE_PATH))
pydoc.writedoc('z3')
shutil.move('z3.html', os.path.join(OUTPUT_DIRECTORY, 'html', 'z3.html'))
for modulename in (
'z3',
'z3.z3consts',
'z3.z3core',
'z3.z3num',
'z3.z3poly',
'z3.z3printer',
'z3.z3rcf',
'z3.z3types',
'z3.z3util',
):
pydoc.writedoc(modulename)
doc = modulename + '.html'
shutil.move(doc, os.path.join(OUTPUT_DIRECTORY, 'html', doc))
print("Generated pydoc Z3Py documentation.")
if ML_ENABLED:

View file

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

View file

@ -1913,7 +1913,11 @@ class MLComponent(Component):
src_dir = self.to_src_dir
mk_dir(os.path.join(BUILD_DIR, self.sub_dir))
api_src = get_component(API_COMPONENT).to_src_dir
out.write('CXXFLAGS_OCAML=$(CXXFLAGS:/GL=)\n') # remove /GL; the ocaml tools don't like it.
# remove /GL and -std=c++11; the ocaml tools don't like them.
if IS_WINDOWS:
out.write('CXXFLAGS_OCAML=$(CXXFLAGS:/GL=)\n')
else:
out.write('CXXFLAGS_OCAML=$(subst -std=c++11,,$(CXXFLAGS))\n')
if IS_WINDOWS:
prefix_lib = '-L' + os.path.abspath(BUILD_DIR).replace('\\', '\\\\')

View file

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

View file

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

View file

@ -471,6 +471,9 @@ bool compare_nodes(ast const * n1, ast const * n2) {
compare_arrays(to_quantifier(n1)->get_decl_sorts(),
to_quantifier(n2)->get_decl_sorts(),
to_quantifier(n1)->get_num_decls()) &&
compare_arrays(to_quantifier(n1)->get_decl_names(),
to_quantifier(n2)->get_decl_names(),
to_quantifier(n1)->get_num_decls()) &&
to_quantifier(n1)->get_expr() == to_quantifier(n2)->get_expr() &&
to_quantifier(n1)->get_weight() == to_quantifier(n2)->get_weight() &&
to_quantifier(n1)->get_num_patterns() == to_quantifier(n2)->get_num_patterns() &&

View file

@ -19,6 +19,7 @@ Notes:
#include "ast/expr_abstract.h"
#include "util/map.h"
#include "ast/ast_pp.h"
void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
@ -109,6 +110,9 @@ void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const*
void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
expr_abstractor abs(m);
abs(base, num_bound, bound, n, result);
TRACE("expr_abstract",
tout << expr_ref(n, m) << "\n";
tout << result << "\n";);
}
expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
@ -123,6 +127,11 @@ expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app*
}
result = m.mk_quantifier(is_forall, num_bound, sorts.c_ptr(), names.c_ptr(), result);
}
TRACE("expr_abstract",
tout << expr_ref(n, m) << "\n";
for (unsigned i = 0; i < num_bound; ++i) tout << expr_ref(bound[i], m) << " ";
tout << "\n";
tout << result << "\n";);
return result;
}

View file

@ -16,8 +16,9 @@ Author:
Notes:
--*/
#include "ast/expr_substitution.h"
#include "util/ref_util.h"
#include "ast/expr_substitution.h"
#include "ast/ast_pp.h"
typedef obj_map<expr, proof*> expr2proof;
typedef obj_map<expr, expr_dependency*> expr2expr_dependency;
@ -56,6 +57,13 @@ expr_substitution::~expr_substitution() {
reset();
}
std::ostream& expr_substitution::display(std::ostream& out) {
for (auto & kv : m_subst) {
out << mk_pp(kv.m_key, m()) << " |-> " << mk_pp(kv.m_value, m()) << "\n";
}
return out;
}
void expr_substitution::insert(expr * c, expr * def, proof * def_pr, expr_dependency * def_dep) {
obj_map<expr, expr*>::obj_map_entry * entry = m_subst.insert_if_not_there2(c, 0);
if (entry->get_data().m_value == 0) {

View file

@ -50,6 +50,8 @@ public:
bool contains(expr * s);
void reset();
void cleanup();
std::ostream& display(std::ostream& out);
};
class scoped_expr_substitution {
@ -84,6 +86,7 @@ public:
bool find(expr * s, expr * & def, proof * & def_pr, expr_dependency * & def_dep) { return m_subst.find(s, def, def_pr, def_dep); }
bool contains(expr * s) { return m_subst.contains(s); }
void cleanup() { m_subst.cleanup(); }
std::ostream& display(std::ostream& out) { return m_subst.display(out); }
};
#endif

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) {
SASSERT(num == 2);
unsigned ebits = m_util.get_ebits(f->get_range());
unsigned sbits = m_util.get_sbits(f->get_range());
expr * x = args[0], * y = args[1];
@ -1227,8 +1225,6 @@ void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args,
void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
unsigned ebits = m_util.get_ebits(f->get_range());
unsigned sbits = m_util.get_sbits(f->get_range());
expr * x = args[0], *y = args[1];
@ -3081,8 +3077,6 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const *
mk_is_nan(x, x_is_nan);
sort * fp_srt = m.get_sort(x);
unsigned ebits = m_util.get_ebits(fp_srt);
unsigned sbits = m_util.get_sbits(fp_srt);
expr_ref unspec(m);
mk_to_ieee_bv_unspecified(f, num, args, unspec);

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

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());
eq = m().mk_eq(lhs, e);
if (!ids.empty()) {
if (is_var(e)) {
ptr_vector<sort> domain;
for (expr* b : binding) domain.push_back(m().get_sort(b));
insert_macro(f->get_name(), domain.size(), domain.c_ptr(), e);
return;
}
if (!is_app(e)) {
throw cmd_exception("Z3 only supports recursive definitions that are proper terms (not binders or variables)");
}
@ -1763,6 +1769,7 @@ void cmd_context::validate_model() {
continue;
}
try {
for_each_expr(contains_underspecified, a);
for_each_expr(contains_underspecified, r);
}
catch (contains_underspecified_op_proc::found) {

View file

@ -33,9 +33,11 @@
#include <fstream>
#include <iostream>
#include <ostream>
#include <sstream>
#include "ast/expr_abstract.h"
#include "util/params.h"
#include "ast/used_vars.h"
using namespace stl_ext;
@ -938,3 +940,30 @@ void iz3mgr::get_bound_substitutes(stl_ext::hash_map<ast,bool> &memo, const ast
}
#endif
unsigned iz3mgr::num_free_variables(const ast &e){
used_vars uv;
uv(to_expr(e.raw()));
return uv.get_num_vars();
}
iz3mgr::ast iz3mgr::close_universally (ast e){
used_vars uv;
uv(to_expr(e.raw()));
std::vector<ast> bvs;
stl_ext::hash_map<ast,ast> subst_memo;
for (unsigned i = 0; i < uv.get_max_found_var_idx_plus_1(); i++){
if (uv.get(i)) {
std::ostringstream os;
os << "%%" << i;
ast c = make_var(os.str(),uv.get(i));
ast v = cook(m().mk_var(i,uv.get(i)));
subst_memo[v] = c;
bvs.push_back(c);
}
}
e = subst(subst_memo,e);
for (unsigned i = 0; i < bvs.size(); i++)
e = apply_quant(Forall,bvs[i],e);
return e;
}

View file

@ -96,7 +96,7 @@ class ast_r : public ast_i {
ast_r(const ast_r &other) : ast_i(other) {
_m = other._m;
_m->inc_ref(_ast);
if (_m) _m->inc_ref(_ast);
}
ast_r &operator=(const ast_r &other) {
@ -104,7 +104,7 @@ class ast_r : public ast_i {
_m->dec_ref(_ast);
_ast = other._ast;
_m = other._m;
_m->inc_ref(_ast);
if (_m) _m->inc_ref(_ast);
return *this;
}
@ -661,6 +661,12 @@ class iz3mgr {
ast apply_quant(opr quantifier, ast var, ast e);
// Universally quantify all the free variables in a formula.
// Makes up names for the quntifiers.
ast close_universally (ast e);
unsigned num_free_variables(const ast &e);
/** For debugging */
void show(ast);

View file

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

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(range_is_empty(rng))
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) {
decl2expr::obj_map_entry * ec = m_interp.find_core(d);
if (ec && ec->get_data().m_value != 0) {
m_manager.dec_ref(ec->get_data().m_key);
m_manager.dec_ref(ec->get_data().m_value);
auto k = ec->get_data().m_key;
auto v = ec->get_data().m_value;
m_interp.remove(d);
m_const_decls.erase(d);
m_manager.dec_ref(k);
m_manager.dec_ref(v);
return;
}
decl2finterp::obj_map_entry * ef = m_finterp.find_core(d);
if (ef && ef->get_data().m_value != 0) {
m_manager.dec_ref(ef->get_data().m_key);
dealloc(ef->get_data().m_value);
auto k = ef->get_data().m_key;
auto v = ef->get_data().m_value;
m_finterp.remove(d);
m_func_decls.erase(d);
m_manager.dec_ref(k);
dealloc(v);
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -780,7 +780,7 @@ namespace smt {
of a non linear monomial that is not satisfied by the current assignment.
if v >= l, then create the case split v >= l+1
else v <= u, then create the case split v <= u-1
else do nothing and return false.
else create the bound v = 0 and case split on it.
*/
template<typename Ext>
bool theory_arith<Ext>::branch_nl_int_var(theory_var v) {

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -83,49 +83,66 @@ expr* expr_dominators::intersect(expr* x, expr * y) {
return x;
}
void expr_dominators::compute_dominators() {
bool expr_dominators::compute_dominators() {
expr * e = m_root;
SASSERT(m_doms.empty());
m_doms.insert(e, e);
bool change = true;
unsigned iterations = 1;
while (change) {
change = false;
SASSERT(m_post2expr.back() == e);
for (unsigned i = 0; i < m_post2expr.size() - 1; ++i) {
TRACE("simplify",
for (auto & kv : m_doms) {
tout << expr_ref(kv.m_key, m) << " |-> " << expr_ref(kv.m_value, m) << "\n";
});
SASSERT(m_post2expr.empty() || m_post2expr.back() == e);
for (unsigned i = 0; i + 1 < m_post2expr.size(); ++i) {
expr * child = m_post2expr[i];
ptr_vector<expr> const& p = m_parents[child];
SASSERT(!p.empty());
expr * new_idom = p[0], * idom2 = 0;
for (unsigned j = 1; j < p.size(); ++j) {
if (m_doms.find(p[j], idom2)) {
new_idom = intersect(new_idom, idom2);
expr * new_idom = 0, *idom2 = 0;
for (expr * pred : p) {
if (m_doms.contains(pred)) {
new_idom = !new_idom ? pred : intersect(new_idom, pred);
}
}
if (!m_doms.find(child, idom2) || idom2 != new_idom) {
if (!new_idom) {
m_doms.insert(child, p[0]);
change = true;
}
else if (!m_doms.find(child, idom2) || idom2 != new_idom) {
m_doms.insert(child, new_idom);
change = true;
}
}
iterations *= 2;
if (change && iterations > m_post2expr.size()) {
return false;
}
}
return true;
}
void expr_dominators::extract_tree() {
for (auto const& kv : m_doms) {
add_edge(m_tree, kv.m_value, kv.m_key);
}
}
}
void expr_dominators::compile(expr * e) {
bool expr_dominators::compile(expr * e) {
reset();
m_root = e;
compute_post_order();
compute_dominators();
if (!compute_dominators()) return false;
extract_tree();
TRACE("simplify", display(tout););
return true;
}
void expr_dominators::compile(unsigned sz, expr * const* es) {
bool expr_dominators::compile(unsigned sz, expr * const* es) {
expr_ref e(m.mk_and(sz, es), m);
compile(e);
return compile(e);
}
void expr_dominators::reset() {
@ -137,19 +154,39 @@ void expr_dominators::reset() {
m_root.reset();
}
std::ostream& expr_dominators::display(std::ostream& out) {
return display(out, 0, m_root);
}
std::ostream& expr_dominators::display(std::ostream& out, unsigned indent, expr* r) {
for (unsigned i = 0; i < indent; ++i) out << " ";
out << expr_ref(r, m);
if (m_tree.contains(r)) {
for (expr* child : m_tree[r]) {
if (child != r)
display(out, indent + 1, child);
}
}
out << "\n";
return out;
}
// -----------------------
// dom_simplify_tactic
dom_simplify_tactic::~dom_simplify_tactic() {
dealloc(m_simplifier);
}
tactic * dom_simplify_tactic::translate(ast_manager & m) {
return alloc(dom_simplify_tactic, m, m_simplifier->translate(m), m_params);
}
void dom_simplify_tactic::operator()(
goal_ref const & in,
goal_ref_buffer & result,
model_converter_ref & mc,
goal_ref const & in,
goal_ref_buffer & result,
model_converter_ref & mc,
proof_converter_ref & pc,
expr_dependency_ref & core) {
mc = 0; pc = 0; core = 0;
@ -162,33 +199,42 @@ void dom_simplify_tactic::operator()(
}
void dom_simplify_tactic::cleanup() {
m_trail.reset();
m_args.reset();
m_args2.reset();
m_result.reset();
m_dominators.reset();
m_trail.reset();
m_args.reset();
m_result.reset();
m_dominators.reset();
}
expr_ref dom_simplify_tactic::simplify_ite(app * ite) {
expr_ref r(m);
expr * c = 0, * t = 0, * e = 0;
expr * c = 0, *t = 0, *e = 0;
VERIFY(m.is_ite(ite, c, t, e));
unsigned old_lvl = scope_level();
expr_ref new_c = simplify(c);
expr_ref new_c = simplify_arg(c);
if (m.is_true(new_c)) {
r = simplify(t);
}
r = simplify_arg(t);
}
else if (m.is_false(new_c) || !assert_expr(new_c, false)) {
r = simplify(e);
}
r = simplify_arg(e);
}
else {
expr_ref new_t = simplify(t);
for (expr * child : tree(ite)) {
if (is_subexpr(child, t) && !is_subexpr(child, e)) {
simplify_rec(child);
}
}
pop(scope_level() - old_lvl);
expr_ref new_t = simplify_arg(t);
if (!assert_expr(new_c, true)) {
return new_t;
}
expr_ref new_e = simplify(e);
for (expr * child : tree(ite)) {
if (is_subexpr(child, e) && !is_subexpr(child, t)) {
simplify_rec(child);
}
}
pop(scope_level() - old_lvl);
expr_ref new_e = simplify_arg(e);
if (c == new_c && t == new_t && e == new_e) {
r = ite;
}
@ -197,15 +243,28 @@ expr_ref dom_simplify_tactic::simplify_ite(app * ite) {
}
else {
TRACE("tactic", tout << new_c << "\n" << new_t << "\n" << new_e << "\n";);
r = m.mk_ite(new_c, new_t, new_c);
r = m.mk_ite(new_c, new_t, new_e);
}
}
return r;
}
expr_ref dom_simplify_tactic::simplify(expr * e0) {
expr_ref dom_simplify_tactic::simplify_arg(expr * e) {
expr_ref r(m);
r = get_cached(e);
(*m_simplifier)(r);
TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e, m) << " -> " << r << "\n";);
return r;
}
/**
\brief simplify e recursively.
*/
expr_ref dom_simplify_tactic::simplify_rec(expr * e0) {
expr_ref r(m);
expr* e = 0;
TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << "\n";);
if (!m_result.find(e0, e)) {
e = e0;
}
@ -224,17 +283,13 @@ expr_ref dom_simplify_tactic::simplify(expr * e0) {
r = simplify_or(to_app(e));
}
else {
expr_dominators::tree_t const& t = m_dominators.get_tree();
if (t.contains(e)) {
ptr_vector<expr> const& children = t[e];
for (expr * child : children) {
simplify(child);
}
for (expr * child : tree(e)) {
simplify_rec(child);
}
if (is_app(e)) {
m_args.reset();
for (expr* arg : *to_app(e)) {
m_args.push_back(get_cached(arg)); // TBD is cache really applied to all sub-terms?
m_args.push_back(simplify_arg(arg));
}
r = m.mk_app(to_app(e)->get_decl(), m_args.size(), m_args.c_ptr());
}
@ -246,45 +301,64 @@ expr_ref dom_simplify_tactic::simplify(expr * e0) {
cache(e0, r);
TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << " -> " << r << "\n";);
--m_depth;
m_subexpr_cache.reset();
return r;
}
expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) {
expr_ref r(m);
unsigned old_lvl = scope_level();
m_args.reset();
for (expr * arg : *e) {
r = simplify(arg);
if (!assert_expr(r, !is_and)) {
r = is_and ? m.mk_false() : m.mk_true();
auto is_subexpr_arg = [&](expr * child, expr * except) {
if (!is_subexpr(child, except))
return false;
for (expr * arg : *e) {
if (arg != except && is_subexpr(child, arg))
return false;
}
m_args.push_back(r);
return true;
};
expr_ref_vector args(m);
if (m_forward) {
for (expr * arg : *e) {
#define _SIMP_ARG(arg) \
for (expr * child : tree(arg)) { \
if (is_subexpr_arg(child, arg)) { \
simplify_rec(child); \
} \
} \
r = simplify_arg(arg); \
args.push_back(r); \
if (!assert_expr(r, !is_and)) { \
r = is_and ? m.mk_false() : m.mk_true(); \
return r; \
}
_SIMP_ARG(arg);
}
}
else {
for (unsigned i = e->get_num_args(); i > 0; ) {
--i;
expr* arg = e->get_arg(i);
_SIMP_ARG(arg);
}
args.reverse();
}
pop(scope_level() - old_lvl);
m_args.reverse();
m_args2.reset();
for (expr * arg : m_args) {
r = simplify(arg);
if (!assert_expr(r, !is_and)) {
r = is_and ? m.mk_false() : m.mk_true();
}
m_args2.push_back(r);
}
pop(scope_level() - old_lvl);
m_args2.reverse();
r = is_and ? mk_and(m_args2) : mk_or(m_args2);
r = is_and ? mk_and(args) : mk_or(args);
return r;
}
void dom_simplify_tactic::init(goal& g) {
bool dom_simplify_tactic::init(goal& g) {
expr_ref_vector args(m);
unsigned sz = g.size();
for (unsigned i = 0; i < sz; ++i) args.push_back(g.form(i));
expr_ref fml = mk_and(args);
m_result.reset();
m_trail.reset();
m_dominators.compile(fml);
return m_dominators.compile(fml);
}
void dom_simplify_tactic::simplify_goal(goal& g) {
@ -296,13 +370,15 @@ void dom_simplify_tactic::simplify_goal(goal& g) {
change = false;
// go forwards
init(g);
m_forward = true;
if (!init(g)) return;
unsigned sz = g.size();
for (unsigned i = 0; !g.inconsistent() && i < sz; ++i) {
expr_ref r = simplify(g.form(i));
expr_ref r = simplify_rec(g.form(i));
if (i < sz - 1 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) {
r = m.mk_false();
}
CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";);
change |= r != g.form(i);
proof* new_pr = 0;
if (g.proofs_enabled()) {
@ -313,15 +389,17 @@ void dom_simplify_tactic::simplify_goal(goal& g) {
pop(scope_level());
// go backwards
init(g);
m_forward = false;
if (!init(g)) return;
sz = g.size();
for (unsigned i = sz; !g.inconsistent() && i > 0; ) {
--i;
expr_ref r = simplify(g.form(i));
expr_ref r = simplify_rec(g.form(i));
if (i > 0 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) {
r = m.mk_false();
}
change |= r != g.form(i);
CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";);
proof* new_pr = 0;
if (g.proofs_enabled()) {
new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, 0));
@ -333,11 +411,41 @@ void dom_simplify_tactic::simplify_goal(goal& g) {
SASSERT(scope_level() == 0);
}
/**
\brief determine if a is dominated by b.
Walk the immediate dominators of a upwards until hitting b or a term that is deeper than b.
Save intermediary results in a cache to avoid recomputations.
*/
bool dom_simplify_tactic::is_subexpr(expr * a, expr * b) {
if (a == b)
return true;
bool r;
if (m_subexpr_cache.find(a, b, r))
return r;
if (get_depth(a) >= get_depth(b)) {
return false;
}
SASSERT(a != idom(a) && get_depth(idom(a)) > get_depth(a));
r = is_subexpr(idom(a), b);
m_subexpr_cache.insert(a, b, r);
return r;
}
ptr_vector<expr> const & dom_simplify_tactic::tree(expr * e) {
if (auto p = m_dominators.get_tree().find_core(e))
return p->get_data().get_value();
return m_empty;
}
// ----------------------
// expr_substitution_simplifier
bool expr_substitution_simplifier::assert_expr(expr * t, bool sign) {
m_scoped_substitution.push();
expr* tt;
if (!sign) {
update_substitution(t, 0);
@ -389,6 +497,8 @@ void expr_substitution_simplifier::update_substitution(expr* n, proof* pr) {
if (is_ground(n) && (m.is_eq(n, lhs, rhs) || m.is_iff(n, lhs, rhs))) {
compute_depth(lhs);
compute_depth(rhs);
m_trail.push_back(lhs);
m_trail.push_back(rhs);
if (is_gt(lhs, rhs)) {
TRACE("propagate_values", tout << "insert " << mk_pp(lhs, m) << " -> " << mk_pp(rhs, m) << "\n";);
m_scoped_substitution.insert(lhs, rhs, pr);
@ -440,3 +550,7 @@ void expr_substitution_simplifier::compute_depth(expr* e) {
m_expr2depth.insert(e, d + 1);
}
}
tactic * mk_dom_simplify_tactic(ast_manager & m, params_ref const & p) {
return clean(alloc(dom_simplify_tactic, m, alloc(expr_substitution_simplifier, m), p));
}

View file

@ -23,6 +23,8 @@ Notes:
#include "ast/ast.h"
#include "ast/expr_substitution.h"
#include "tactic/tactic.h"
#include "tactic/tactical.h"
#include "util/obj_pair_hashtable.h"
class expr_dominators {
@ -43,78 +45,92 @@ private:
void compute_post_order();
expr* intersect(expr* x, expr * y);
void compute_dominators();
bool compute_dominators();
void extract_tree();
std::ostream& display(std::ostream& out, unsigned indent, expr* r);
public:
expr_dominators(ast_manager& m): m(m), m_root(m) {}
void compile(expr * e);
void compile(unsigned sz, expr * const* es);
bool compile(expr * e);
bool compile(unsigned sz, expr * const* es);
tree_t const& get_tree() { return m_tree; }
void reset();
expr* idom(expr *e) const { return m_doms[e]; }
std::ostream& display(std::ostream& out);
};
class dom_simplifier {
public:
dom_simplifier() {}
virtual ~dom_simplifier() {}
/**
\brief assert_expr performs an implicit push
*/
virtual bool assert_expr(expr * t, bool sign) = 0;
/**
\brief apply simplification.
*/
virtual void operator()(expr_ref& r) = 0;
/**
\brief pop scopes accumulated from assertions.
*/
virtual void pop(unsigned num_scopes) = 0;
virtual dom_simplifier * translate(ast_manager & m) = 0;
};
class dom_simplify_tactic : public tactic {
public:
class simplifier {
public:
virtual ~simplifier() {}
/**
\brief assert_expr performs an implicit push
*/
virtual bool assert_expr(expr * t, bool sign) = 0;
/**
\brief apply simplification.
*/
virtual void operator()(expr_ref& r) = 0;
/**
\brief pop scopes accumulated from assertions.
*/
virtual void pop(unsigned num_scopes) = 0;
virtual simplifier * translate(ast_manager & m);
};
private:
ast_manager& m;
simplifier* m_simplifier;
dom_simplifier* m_simplifier;
params_ref m_params;
expr_ref_vector m_trail, m_args, m_args2;
expr_ref_vector m_trail, m_args;
obj_map<expr, expr*> m_result;
expr_dominators m_dominators;
unsigned m_scope_level;
unsigned m_depth;
unsigned m_max_depth;
ptr_vector<expr> m_empty;
obj_pair_map<expr, expr, bool> m_subexpr_cache;
bool m_forward;
expr_ref simplify(expr* t);
expr_ref simplify_rec(expr* t);
expr_ref simplify_arg(expr* t);
expr_ref simplify_ite(app * ite);
expr_ref simplify_and(app * ite) { return simplify_and_or(true, ite); }
expr_ref simplify_or(app * ite) { return simplify_and_or(false, ite); }
expr_ref simplify_and_or(bool is_and, app * ite);
void simplify_goal(goal& g);
expr_ref get_cached(expr* t) { expr* r = 0; if (!m_result.find(r, r)) r = t; return expr_ref(r, m); }
bool is_subexpr(expr * a, expr * b);
expr_ref get_cached(expr* t) { expr* r = 0; if (!m_result.find(t, r)) r = t; return expr_ref(r, m); }
void cache(expr *t, expr* r) { m_result.insert(t, r); m_trail.push_back(r); }
ptr_vector<expr> const & tree(expr * e);
expr* idom(expr *e) const { return m_dominators.idom(e); }
unsigned scope_level() { return m_scope_level; }
void pop(unsigned n) { SASSERT(n <= m_scope_level); m_scope_level -= n; m_simplifier->pop(n); }
bool assert_expr(expr* f, bool sign) { m_scope_level++; return m_simplifier->assert_expr(f, sign); }
void init(goal& g);
bool init(goal& g);
public:
dom_simplify_tactic(ast_manager & m, simplifier* s, params_ref const & p = params_ref()):
dom_simplify_tactic(ast_manager & m, dom_simplifier* s, params_ref const & p = params_ref()):
m(m), m_simplifier(s), m_params(p),
m_trail(m), m_args(m), m_args2(m),
m_trail(m), m_args(m),
m_dominators(m),
m_scope_level(0), m_depth(0), m_max_depth(1024) {}
m_scope_level(0), m_depth(0), m_max_depth(1024), m_forward(true) {}
virtual ~dom_simplify_tactic() {}
virtual ~dom_simplify_tactic();
virtual tactic * translate(ast_manager & m);
virtual void updt_params(params_ref const & p) {}
@ -130,11 +146,12 @@ public:
virtual void cleanup();
};
class expr_substitution_simplifier : public dom_simplify_tactic::simplifier {
class expr_substitution_simplifier : public dom_simplifier {
ast_manager& m;
expr_substitution m_subst;
scoped_expr_substitution m_scoped_substitution;
obj_map<expr, unsigned> m_expr2depth;
expr_ref_vector m_trail;
// move from asserted_formulas to here..
void compute_depth(expr* e);
@ -142,7 +159,7 @@ class expr_substitution_simplifier : public dom_simplify_tactic::simplifier {
unsigned depth(expr* e) { return m_expr2depth[e]; }
public:
expr_substitution_simplifier(ast_manager& m): m(m), m_subst(m), m_scoped_substitution(m_subst) {}
expr_substitution_simplifier(ast_manager& m): m(m), m_subst(m), m_scoped_substitution(m_subst), m_trail(m) {}
virtual ~expr_substitution_simplifier() {}
virtual bool assert_expr(expr * t, bool sign);
@ -152,12 +169,17 @@ public:
virtual void pop(unsigned num_scopes) { m_scoped_substitution.pop(num_scopes); }
virtual simplifier * translate(ast_manager & m) {
virtual dom_simplifier * translate(ast_manager & m) {
SASSERT(m_subst.empty());
return alloc(expr_substitution_simplifier, m);
}
};
tactic * mk_dom_simplify_tactic(ast_manager & m, params_ref const & p = params_ref());
/*
ADD_TACTIC("dom-simplify", "apply dominator simplification rules.", "mk_dom_simplify_tactic(m, p)")
*/
#endif

View file

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

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

View file

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

View file

@ -90,7 +90,6 @@ bool is_debug_enabled(const char * tag);
exit(-1); \
}
#define COMPILE_TIME_ASSERT(expr) static_assert(expr, "")
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_ */

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

View file

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

View file

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

View file

@ -61,7 +61,8 @@ enum lp_status {
TIME_EXHAUSTED,
ITERATIONS_EXHAUSTED,
EMPTY,
UNSTABLE
UNSTABLE,
CANCELLED
};
// when the ratio of the vector lenth to domain size to is greater than the return value we switch to solve_By_for_T_indexed_only

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -23,12 +23,14 @@ Revision History:
class reslimit {
volatile unsigned m_cancel;
bool m_suspend;
uint64 m_count;
uint64 m_limit;
svector<uint64> m_limits;
ptr_vector<reslimit> m_children;
void set_cancel(unsigned f);
friend class scoped_suspend_rlimit;
public:
reslimit();
@ -42,7 +44,7 @@ public:
uint64 count() const;
bool get_cancel_flag() const { return m_cancel > 0; }
bool get_cancel_flag() const { return m_cancel > 0 && !m_suspend; }
char const* get_cancel_msg() const;
void cancel();
void reset_cancel();
@ -61,6 +63,17 @@ public:
};
class scoped_suspend_rlimit {
reslimit & m_limit;
public:
scoped_suspend_rlimit(reslimit& r): m_limit(r) {
r.m_suspend = true;
}
~scoped_suspend_rlimit() {
m_limit.m_suspend = false;
}
};
struct scoped_limits {
reslimit& m_limit;
unsigned m_sz;

View file

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

View file

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

View file

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

View file

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