3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-14 21:08:46 +00:00

Merge remote-tracking branch 'upstream/master' into fix-length-testing

This commit is contained in:
Murphy Berzish 2017-10-23 17:59:54 -04:00
commit 5e19e905fa
178 changed files with 3204 additions and 1694 deletions

View file

@ -17,15 +17,31 @@ env:
###############################################################################
# Ubuntu 16.04 LTS
###############################################################################
# 64-bit UBSan Debug build
- 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 UBSAN_BUILD=1 RUN_UNIT_TESTS=SKIP
# 64-bit ASan Debug build
- 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 ASAN_BUILD=1 RUN_UNIT_TESTS=SKIP ASAN_DSO=/usr/lib/clang/3.9/lib/linux/libclang_rt.asan-x86_64.so
# Build for running unit tests under ASan/UBSan
# FIXME: We should really be doing a debug build but the unit tests run too
# slowly when we do that.
- 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 ASAN_BUILD=1 RUN_UNIT_TESTS=BUILD_AND_RUN ASAN_DSO=/usr/lib/clang/3.9/lib/linux/libclang_rt.asan-x86_64.so UBSAN_BUILD=1 RUN_API_EXAMPLES=0 RUN_SYSTEM_TESTS=0 DOTNET_BINDINGS=0 JAVA_BINDINGS=0 PYTHON_BINDINGS=0
# 64-bit GCC 5.4 RelWithDebInfo
- LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo
# 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 +73,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

@ -270,6 +270,7 @@ The following useful options can be passed to CMake whilst configuring.
* ``API_LOG_SYNC`` - BOOL. If set to ``TRUE`` will enable experimental API log sync feature.
* ``WARNINGS_AS_ERRORS`` - STRING. If set to ``TRUE`` compiler warnings will be treated as errors. If set to ``False`` compiler warnings will not be treated as errors.
If set to ``SERIOUS_ONLY`` a subset of compiler warnings will be treated as errors.
* ``Z3_C_EXAMPLES_FORCE_CXX_LINKER`` - BOOL. If set to ``TRUE`` the C API examples will request that the C++ linker is used rather than the C linker.
On the command line these can be passed to ``cmake`` using the ``-D`` option. In ``ccmake`` and ``cmake-gui`` these can be set in the user interface.

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
@ -124,7 +124,7 @@ utility is used to install ``Microsoft.Z3.dll`` into the
[pkg-config](http://www.freedesktop.org/wiki/Software/pkg-config/) file
(``Microsoft.Z3.Sharp.pc``) is also installed which allows the
[MonoDevelop](http://www.monodevelop.com/) IDE to find the bindings. Running
``make uninstall`` will remove the dll from the GAC and the pkg-config file.
``make uninstall`` will remove the dll from the GAC and the ``pkg-config`` file.
See [``examples/dotnet``](examples/dotnet) for examples.
@ -170,8 +170,8 @@ If you do need to install to a non standard prefix a better approach is to use
a [Python virtual environment](https://virtualenv.readthedocs.org/en/latest/)
and install Z3 there. Python packages also work for Python3.
Under Windows, recall to build inside the Visual C++ native command build environment.
Note that the buit/python/z3 directory should be accessible from where python is used with Z3
and it depends on libz3.dll to be in the path.
Note that the ``build/python/z3`` directory should be accessible from where python is used with Z3
and it depends on ``libz3.dll`` to be in the path.
```bash
virtualenv venv

View file

@ -30,6 +30,7 @@ RUN apt-get update && \
libgomp1 \
libomp5 \
libomp-dev \
llvm-3.9 \
make \
mono-devel \
ninja-build \
@ -47,4 +48,4 @@ RUN useradd -m user && \
echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers
USER user
WORKDIR /home/user
ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.9/bin/llvm-symbolizer

View file

@ -16,6 +16,7 @@ RUN apt-get update && \
libgmp-dev \
libgomp1 \
lib32gomp1 \
llvm-3.9 \
make \
mono-devel \
ninja-build \
@ -32,4 +33,4 @@ RUN useradd -m user && \
echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers
USER user
WORKDIR /home/user
ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.9/bin/llvm-symbolizer

View file

@ -18,6 +18,7 @@ RUN apt-get update && \
libgomp1 \
libomp5 \
libomp-dev \
llvm-3.9 \
make \
mono-devel \
ninja-build \
@ -35,4 +36,4 @@ RUN useradd -m user && \
echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers
USER user
WORKDIR /home/user
ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.9/bin/llvm-symbolizer

View file

@ -2,37 +2,40 @@ 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 ASAN_DSO
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_API_EXAMPLES
ARG RUN_SYSTEM_TESTS
ARG RUN_UNIT_TESTS
ARG SANITIZER_PRINT_SUPPRESSIONS
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} \
ASAN_DSO=${ASAN_DSO} \
BUILD_DOCS=${BUILD_DOCS} \
CC=${CC} \
CXX=${CXX} \
@ -41,6 +44,8 @@ ENV \
NO_SUPPRESS_OUTPUT=${NO_SUPPRESS_OUTPUT} \
PYTHON_BINDINGS=${PYTHON_BINDINGS} \
PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} \
SANITIZER_PRINT_SUPPRESSIONS=${SANITIZER_PRINT_SUPPRESSIONS} \
RUN_API_EXAMPLES=${RUN_API_EXAMPLES} \
RUN_SYSTEM_TESTS=${RUN_SYSTEM_TESTS} \
RUN_UNIT_TESTS=${RUN_UNIT_TESTS} \
TARGET_ARCH=${TARGET_ARCH} \
@ -51,6 +56,7 @@ ENV \
USE_OPENMP=${USE_OPENMP} \
Z3_SRC_DIR=${Z3_SRC_DIR} \
Z3_BUILD_DIR=/home/user/z3_build \
Z3_BUILD_TYPE=${Z3_BUILD_TYPE} \
Z3_CMAKE_GENERATOR=${Z3_CMAKE_GENERATOR} \
Z3_VERBOSE_BUILD_OUTPUT=${Z3_VERBOSE_BUILD_OUTPUT} \
Z3_STATIC_BUILD=${Z3_STATIC_BUILD} \
@ -63,7 +69,8 @@ ENV \
# Build Z3
RUN mkdir -p "${Z3_SRC_DIR}" && \
mkdir -p "${Z3_SRC_DIR}/contrib/ci/scripts"
mkdir -p "${Z3_SRC_DIR}/contrib/ci/scripts" && \
mkdir -p "${Z3_SRC_DIR}/contrib/suppressions/sanitizers"
# Deliberately leave out `contrib`
ADD /cmake ${Z3_SRC_DIR}/cmake/
ADD /doc ${Z3_SRC_DIR}/doc/
@ -74,6 +81,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/
@ -89,7 +97,13 @@ RUN ${Z3_SRC_DIR}/contrib/ci/scripts/test_z3_docs.sh
# Test examples
ADD \
/contrib/ci/scripts/test_z3_examples_cmake.sh \
/contrib/ci/scripts/sanitizer_env.sh \
${Z3_SRC_DIR}/contrib/ci/scripts/
ADD \
/contrib/suppressions/sanitizers/asan.txt \
/contrib/suppressions/sanitizers/lsan.txt \
/contrib/suppressions/sanitizers/ubsan.txt \
${Z3_SRC_DIR}/contrib/suppressions/sanitizers/
RUN ${Z3_SRC_DIR}/contrib/ci/scripts/test_z3_examples_cmake.sh
# Run unit tests

View file

@ -30,8 +30,10 @@ the future.
* `JAVA_BINDINGS` - Build and test Java API bindings (`0` or `1`)
* `NO_SUPPRESS_OUTPUT` - Don't suppress output of some commands (`0` or `1`)
* `PYTHON_BINDINGS` - Build and test Python API bindings (`0` or `1`)
* `RUN_API_EXAMPLES` - Build and run API examples (`0` or `1`)
* `RUN_SYSTEM_TESTS` - Run system tests (`0` or `1`)
* `RUN_UNIT_TESTS` - Run unit tests (`0` or `1`)
* `RUN_UNIT_TESTS` - Run unit tests (`BUILD_ONLY` or `BUILD_AND_RUN` or `SKIP`)
* `SANITIZER_PRINT_SUPPRESSIONS` - Show ASan/UBSan suppressions (`0` or `1`)
* `TARGET_ARCH` - Target architecture (`x86_64` or `i686`)
* `TEST_INSTALL` - Test running `install` target (`0` or `1`)
* `UBSAN_BUILD` - Do [UndefinedBehaviourSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) build (`0` or `1`)
@ -58,8 +60,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 +70,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 +108,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

@ -22,6 +22,7 @@ set -o pipefail
: ${USE_LTO?"USE_LTO must be specified"}
: ${Z3_INSTALL_PREFIX?"Z3_INSTALL_PREFIX must be specified"}
: ${Z3_WARNINGS_AS_ERRORS?"Z3_WARNINGS_AS_ERRORS must be specified"}
: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"}
ADDITIONAL_Z3_OPTS=()
@ -105,6 +106,16 @@ fi
# Set compiler flags
source ${SCRIPT_DIR}/set_compiler_flags.sh
if [ "X${UBSAN_BUILD}" = "X1" ]; then
# HACK: When building with UBSan the C++ linker
# must be used to avoid the following linker errors.
# undefined reference to `__ubsan_vptr_type_cache'
# undefined reference to `__ubsan_handle_dynamic_type_cache_miss'
ADDITIONAL_Z3_OPTS+=( \
'-DZ3_C_EXAMPLES_FORCE_CXX_LINKER=ON' \
)
fi
# Sanity check
if [ ! -e "${Z3_SRC_DIR}/CMakeLists.txt" ]; then
echo "Z3_SRC_DIR is invalid"

View file

@ -0,0 +1,60 @@
# This file should be sourced by other scripts
# and not executed directly
# Set CI build defaults
export ASAN_BUILD="${ASAN_BUILD:-0}"
export BUILD_DOCS="${BUILD_DOCS:-0}"
export DOTNET_BINDINGS="${DOTNET_BINDINGS:-1}"
export JAVA_BINDINGS="${JAVA_BINDINGS:-1}"
export NO_SUPPRESS_OUTPUT="${NO_SUPPRESS_OUTPUT:-0}"
export PYTHON_BINDINGS="${PYTHON_BINDINGS:-1}"
export RUN_API_EXAMPLES="${RUN_API_EXAMPLES:-1}"
export RUN_SYSTEM_TESTS="${RUN_SYSTEM_TESTS:-1}"
export RUN_UNIT_TESTS="${RUN_UNIT_TESTS:-BUILD_AND_RUN}"
# Don't print suppressions by default because that breaks the Z3
# regression tests because they don't expect them to appear in Z3's
# output.
export SANITIZER_PRINT_SUPPRESSIONS="${SANITIZER_PRINT_SUPPRESSIONS:-0}"
export TARGET_ARCH="${TARGET_ARCH:-x86_64}"
export TEST_INSTALL="${TEST_INSTALL:-1}"
export UBSAN_BUILD="${UBSAN_BUILD:-0}"
export 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
# ASAN_DSO
# Z3_SRC_DIR
# Z3_BUILD_DIR
# Z3_SYSTEM_TEST_DIR

View file

@ -34,8 +34,8 @@ function run_quiet() {
fi
# Clean up
rm "${STDOUT}" "${STDERR}"
[ $( echo "${OLD_SETTINGS}" | grep -c 'e') -ne 0 ] && set -e
[ $( echo "${OLD_SETTINGS}" | grep -c 'x') -ne 0 ] && set -x
[ "$( echo "${OLD_SETTINGS}" | grep -c 'e')" != "0" ] && set -e
[ "$( echo "${OLD_SETTINGS}" | grep -c 'x')" != "0" ] && set -x
return ${EXIT_STATUS}
fi
}

View file

@ -0,0 +1,82 @@
# This script is intended to be included by other
# scripts and should not be executed directly
: ${Z3_SRC_DIR?"Z3_SRC_DIR must be specified"}
: ${ASAN_BUILD?"ASAN_BUILD must be specified"}
: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"}
if [ "X${ASAN_BUILD}" = "X1" ]; then
# Use suppression files
export LSAN_OPTIONS="suppressions=${Z3_SRC_DIR}/contrib/suppressions/sanitizers/lsan.txt"
# NOTE: If you get bad stacktraces try using `fast_unwind_on_malloc=0`
# NOTE: `malloc_context_size` controls size of recorded stacktrace for allocations.
# If the reported stacktraces appear incomplete try increasing the value.
export ASAN_OPTIONS="malloc_context_size=100,suppressions=${Z3_SRC_DIR}/contrib/suppressions/sanitizers/asan.txt"
: ${SANITIZER_PRINT_SUPPRESSIONS?"SANITIZER_PRINT_SUPPRESSIONS must be specified"}
if [ "X${SANITIZER_PRINT_SUPPRESSIONS}" = "X1" ]; then
export LSAN_OPTIONS="${LSAN_OPTIONS},print_suppressions=1"
export ASAN_OPTIONS="${ASAN_OPTIONS},print_suppressions=1"
else
export LSAN_OPTIONS="${LSAN_OPTIONS},print_suppressions=0"
export ASAN_OPTIONS="${ASAN_OPTIONS},print_suppressions=0"
fi
: ${ASAN_SYMBOLIZER_PATH?"ASAN_SYMBOLIZER_PATH must be specified"}
# Run command without checking for leaks
function run_no_lsan() {
ASAN_OPTIONS="${ASAN_OPTIONS},detect_leaks=0" "${@}"
}
# Check path to ASan DSO
: ${ASAN_DSO?"ASAN_DSO must be specified"}
if [ ! -e "${ASAN_DSO}" ]; then
echo "ASAN_DSO (${ASAN_DSO}) does not exist"
exit 1
fi
# FIXME: We'll need to refactor this when we can do UBSan builds
# against a UBSan DSO.
function run_non_native_binding() {
# We need to preload the ASan DSO that libz3
# will have undefined references to.
# Don't run leak checking because we get lots reported leaks
# in the language runtime (e.g. python).
PLATFORM="$(uname -s)"
case "${PLATFORM}" in
Linux*)
LD_PRELOAD="${ASAN_DSO}" run_no_lsan "${@}"
;;
Darwin*)
DYLD_INSERT_LIBRARIES="${ASAN_DSO}" run_no_lsan "${@}"
;;
*)
echo "Unknown platform \"${PLATFORM}\""
exit 1
;;
esac
unset PLATFORM
}
else
# In non-ASan build just run directly
function run_no_lsan() {
"${@}"
}
function run_non_native_binding() {
"${@}"
}
fi
if [ "X${UBSAN_BUILD}" = "X1" ]; then
# `halt_on_error=1,abort_on_error=1` means that on the first UBSan error
# the program will terminate by calling `abort(). Without this UBSan will
# allow execution to continue. We also use a suppression file.
export UBSAN_OPTIONS="halt_on_error=1,abort_on_error=1,suppressions=${Z3_SRC_DIR}/contrib/suppressions/sanitizers/ubsan.txt"
: ${SANITIZER_PRINT_SUPPRESSIONS?"SANITIZER_PRINT_SUPPRESSIONS must be specified"}
if [ "X${SANITIZER_PRINT_SUPPRESSIONS}" = "X1" ]; then
export UBSAN_OPTIONS="${UBSAN_OPTIONS},print_suppressions=1"
else
export UBSAN_OPTIONS="${UBSAN_OPTIONS},print_suppressions=0"
fi
fi

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

@ -14,6 +14,13 @@ set -o pipefail
: ${PYTHON_EXECUTABLE?"PYTHON_EXECUTABLE must be specified"}
: ${DOTNET_BINDINGS?"DOTNET_BINDINGS must be specified"}
: ${JAVA_BINDINGS?"JAVA_BINDINGS must be specified"}
: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"}
: ${RUN_API_EXAMPLES?"RUN_API_EXAMPLES must be specified"}
if [ "X${RUN_API_EXAMPLES}" = "X0" ]; then
echo "Skipping run of API examples"
exit 0
fi
# Set compiler flags
source ${SCRIPT_DIR}/set_compiler_flags.sh
@ -21,6 +28,9 @@ source ${SCRIPT_DIR}/set_compiler_flags.sh
# Set CMake generator args
source ${SCRIPT_DIR}/set_generator_args.sh
# Sanitizer environment variables
source ${SCRIPT_DIR}/sanitizer_env.sh
cd "${Z3_BUILD_DIR}"
# Build and run C example
@ -38,9 +48,21 @@ run_quiet examples/tptp_build_dir/z3_tptp5 -help
# Build an run c_maxsat_example
cmake --build $(pwd) --target c_maxsat_example "${GENERATOR_ARGS[@]}"
run_quiet \
examples/c_maxsat_example_build_dir/c_maxsat_example \
${Z3_SRC_DIR}/examples/maxsat/ex.smt
# FIXME: It is known that the maxsat example leaks memory and the
# the Z3 developers have stated this is "wontfix".
# See https://github.com/Z3Prover/z3/issues/1299
run_no_lsan \
run_quiet \
examples/c_maxsat_example_build_dir/c_maxsat_example \
${Z3_SRC_DIR}/examples/maxsat/ex.smt
if [ "X${UBSAN_BUILD}" = "X1" ]; then
# FIXME: We really need libz3 to link against a shared UBSan runtime.
# Right now we link against the static runtime which breaks all the
# non-native language bindings.
echo "FIXME: Can't run other examples when building with UBSan"
exit 0
fi
if [ "X${PYTHON_BINDINGS}" = "X1" ]; then
@ -48,16 +70,21 @@ if [ "X${PYTHON_BINDINGS}" = "X1" ]; then
# `all_interval_series.py` produces a lot of output so just throw
# away output.
# TODO: This example is slow should we remove it from testing?
run_quiet ${PYTHON_EXECUTABLE} python/all_interval_series.py
run_quiet ${PYTHON_EXECUTABLE} python/complex.py
run_quiet ${PYTHON_EXECUTABLE} python/example.py
if [ "X${ASAN_BUILD}" = "X1" -a "X${Z3_BUILD_TYPE}" = "XDebug" ]; then
# Too slow when doing ASan Debug build
echo "Skipping all_interval_series.py under ASan Debug build"
else
run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/all_interval_series.py
fi
run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/complex.py
run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/example.py
# FIXME: `hamiltonian.py` example is disabled because its too slow.
#${PYTHON_EXECUTABLE} python/hamiltonian.py
run_quiet ${PYTHON_EXECUTABLE} python/marco.py
run_quiet ${PYTHON_EXECUTABLE} python/mss.py
run_quiet ${PYTHON_EXECUTABLE} python/socrates.py
run_quiet ${PYTHON_EXECUTABLE} python/visitor.py
run_quiet ${PYTHON_EXECUTABLE} python/z3test.py
run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/marco.py
run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/mss.py
run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/socrates.py
run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/visitor.py
run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/z3test.py
fi
if [ "X${DOTNET_BINDINGS}" = "X1" ]; then
@ -65,7 +92,7 @@ if [ "X${DOTNET_BINDINGS}" = "X1" ]; then
# FIXME: Move compliation step into CMake target
mcs ${Z3_SRC_DIR}/examples/dotnet/Program.cs /target:exe /out:dotnet_test.exe /reference:Microsoft.Z3.dll /r:System.Numerics.dll
# Run .NET example
run_quiet mono ./dotnet_test.exe
run_quiet run_non_native_binding mono ./dotnet_test.exe
fi
if [ "X${JAVA_BINDINGS}" = "X1" ]; then
@ -82,6 +109,14 @@ if [ "X${JAVA_BINDINGS}" = "X1" ]; then
# Assume Linux for now
export LD_LIBRARY_PATH=$(pwd):${LD_LIBRARY_PATH}
fi
run_quiet java -cp .:examples/java:com.microsoft.z3.jar JavaExample
if [ "X${ASAN_BUILD}" = "X1" ]; then
# The JVM seems to crash (SEGV) if we pre-load ASan
# so don't run it for now.
echo "Skipping JavaExample under ASan build"
else
run_quiet \
run_non_native_binding \
java -cp .:examples/java:com.microsoft.z3.jar JavaExample
fi
fi

View file

@ -10,12 +10,17 @@ set -o pipefail
: ${PYTHON_BINDINGS?"PYTHON_BINDINGS must be specified"}
: ${PYTHON_EXECUTABLE?"PYTHON_EXECUTABLE must be specified"}
: ${Z3_SYSTEM_TEST_DIR?"Z3_SYSTEM_TEST_DIR must be specified"}
: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"}
if [ "X${RUN_SYSTEM_TESTS}" != "X1" ]; then
echo "Skipping system tests"
exit 0
fi
# Sanitizer environment variables
SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )"
source ${SCRIPT_DIR}/sanitizer_env.sh
Z3_EXE="${Z3_BUILD_DIR}/z3"
Z3_LIB_DIR="${Z3_BUILD_DIR}"
@ -23,7 +28,7 @@ Z3_LIB_DIR="${Z3_BUILD_DIR}"
Z3_SYSTEM_TEST_GIT_URL="${Z3_GIT_URL:-https://github.com/Z3Prover/z3test.git}"
# Clone repo to destination
mkdir -p "${Z3_SYSTEM_TEST_GIT_URL}"
mkdir -p "${Z3_SYSTEM_TEST_DIR}"
git clone "${Z3_SYSTEM_TEST_GIT_URL}" "${Z3_SYSTEM_TEST_DIR}"
cd "${Z3_SYSTEM_TEST_DIR}"
@ -48,7 +53,18 @@ fi
if [ "X${PYTHON_BINDINGS}" = "X1" ]; then
# Run python binding tests
${PYTHON_EXECUTABLE} scripts/test_pyscripts.py "${Z3_LIB_DIR}" regressions/python/
if [ "X${UBSAN_BUILD}" = "X1" ]; then
# FIXME: We need to build libz3 with a shared UBSan runtime for the bindings
# to work.
echo "FIXME: Skipping python binding tests when building with UBSan"
elif [ "X${ASAN_BUILD}" = "X1" ]; then
# FIXME: The `test_pyscripts.py` doesn't propagate LD_PRELOAD
# so under ASan the tests fail to run
# to work.
echo "FIXME: Skipping python binding tests when building with ASan"
else
run_non_native_binding ${PYTHON_EXECUTABLE} scripts/test_pyscripts.py "${Z3_LIB_DIR}" regressions/python/
fi
fi
# FIXME: Run `scripts/test_cs.py` once it has been modified to support mono

View file

@ -10,17 +10,38 @@ 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
# Sanitizer environment variables
source ${SCRIPT_DIR}/sanitizer_env.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
@ -79,6 +84,14 @@ if [ -n "${ASAN_BUILD}" ]; then
BUILD_OPTS+=("--build-arg" "ASAN_BUILD=${ASAN_BUILD}")
fi
if [ -n "${ASAN_DSO}" ]; then
BUILD_OPTS+=("--build-arg" "ASAN_DSO=${ASAN_DSO}")
fi
if [ -n "${SANITIZER_PRINT_SUPPRESSIONS}" ]; then
BUILD_OPTS+=("--build-arg" "SANITIZER_PRINT_SUPPRESSIONS=${SANITIZER_PRINT_SUPPRESSIONS}")
fi
if [ -n "${UBSAN_BUILD}" ]; then
BUILD_OPTS+=("--build-arg" "UBSAN_BUILD=${UBSAN_BUILD}")
fi
@ -87,6 +100,10 @@ if [ -n "${TEST_INSTALL}" ]; then
BUILD_OPTS+=("--build-arg" "TEST_INSTALL=${TEST_INSTALL}")
fi
if [ -n "${RUN_API_EXAMPLES}" ]; then
BUILD_OPTS+=("--build-arg" "RUN_API_EXAMPLES=${RUN_API_EXAMPLES}")
fi
if [ -n "${RUN_SYSTEM_TESTS}" ]; then
BUILD_OPTS+=("--build-arg" "RUN_SYSTEM_TESTS=${RUN_SYSTEM_TESTS}")
fi

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

@ -0,0 +1,7 @@
# Suppression files
This directory contains suppression files used by various
program analysis tools.
Suppression files tell a program analysis tool to suppress
various warnings/errors.

View file

@ -0,0 +1,3 @@
# Maintainers
- Dan Liew (@delcypher)

View file

@ -0,0 +1,4 @@
# Sanitizer supression files
This directory contains files used to suppress
ASan/LSan/UBSan warnings/errors.

View file

@ -0,0 +1 @@
# AddressSanitizer suppression file

View file

@ -0,0 +1,5 @@
# LeakSanitizer suppression file
# Ignore Clang OpenMP leaks.
# See https://github.com/Z3Prover/z3/issues/1308
leak:___kmp_allocate

View file

@ -0,0 +1,7 @@
# UndefinedBehavior sanitizer suppression file
# FIXME: UBSan doesn't usually have false positives so we need to fix all of these!
# Occurs when running tptp example
# See https://github.com/Z3Prover/z3/issues/964
null:rational.h
null:mpq.h

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

@ -7,6 +7,30 @@ else()
set(EXTERNAL_PROJECT_BUILD_ALWAYS_ARG "")
endif()
option(Z3_C_EXAMPLES_FORCE_CXX_LINKER
"Force C++ linker when building C example projects" OFF)
if (Z3_C_EXAMPLES_FORCE_CXX_LINKER)
# HACK: This is a workaround for UBSan.
message(STATUS "Forcing C++ linker to be used when building example C projects")
set(EXTERNAL_C_PROJ_USE_CXX_LINKER_ARG
"-DFORCE_CXX_LINKER=ON"
)
else()
set(EXTERNAL_C_PROJ_USE_CXX_LINKER_ARG "")
endif()
if (DEFINED CMAKE_CONFIGURATION_TYPES)
message(WARNING
"Cannot set built type of external project when building with a "
"multi-configuration generator")
set(EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG "")
else()
set(EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG
"-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}"
)
endif()
################################################################################
# Build example project using libz3's C API as an external project
################################################################################
@ -14,7 +38,10 @@ ExternalProject_Add(c_example
DEPENDS libz3
# Configure step
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/c"
CMAKE_ARGS "-DZ3_DIR=${CMAKE_BINARY_DIR}"
CMAKE_ARGS
"-DZ3_DIR=${CMAKE_BINARY_DIR}"
"${EXTERNAL_C_PROJ_USE_CXX_LINKER_ARG}"
"${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}"
# Build step
${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG}
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/c_example_build_dir"
@ -30,7 +57,10 @@ ExternalProject_Add(c_maxsat_example
DEPENDS libz3
# Configure step
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/maxsat"
CMAKE_ARGS "-DZ3_DIR=${CMAKE_BINARY_DIR}"
CMAKE_ARGS
"-DZ3_DIR=${CMAKE_BINARY_DIR}"
"${EXTERNAL_C_PROJ_USE_CXX_LINKER_ARG}"
"${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}"
# Build step
${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG}
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/c_maxsat_example_build_dir"
@ -47,7 +77,9 @@ ExternalProject_Add(cpp_example
DEPENDS libz3
# Configure step
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/c++"
CMAKE_ARGS "-DZ3_DIR=${CMAKE_BINARY_DIR}"
CMAKE_ARGS
"-DZ3_DIR=${CMAKE_BINARY_DIR}"
"${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}"
# Build step
${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG}
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/cpp_example_build_dir"
@ -63,7 +95,9 @@ ExternalProject_Add(z3_tptp5
DEPENDS libz3
# Configure step
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tptp"
CMAKE_ARGS "-DZ3_DIR=${CMAKE_BINARY_DIR}"
CMAKE_ARGS
"-DZ3_DIR=${CMAKE_BINARY_DIR}"
"${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}"
# Build step
${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG}
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/tptp_build_dir"

View file

@ -22,6 +22,17 @@ message(STATUS "Found Z3 ${Z3_VERSION_STRING}")
message(STATUS "Z3_DIR: ${Z3_DIR}")
add_executable(c_example test_capi.c)
option(FORCE_CXX_LINKER "Force linker with C++ linker" OFF)
if (FORCE_CXX_LINKER)
# This is a hack for avoiding UBSan linking errors
message(STATUS "Forcing use of C++ linker")
set_target_properties(c_example
PROPERTIES
LINKER_LANGUAGE CXX
)
endif()
target_include_directories(c_example PRIVATE ${Z3_C_INCLUDE_DIRS})
target_link_libraries(c_example PRIVATE ${Z3_LIBRARIES})

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);
@ -2639,6 +2651,7 @@ void smt2parser_example() {
ctx = mk_context();
fs = Z3_parse_smtlib2_string(ctx, "(declare-fun a () (_ BitVec 8)) (assert (bvuge a #x10)) (assert (bvule a #xf0))", 0, 0, 0, 0, 0, 0);
printf("formulas: %s\n", Z3_ast_to_string(ctx, fs));
Z3_del_context(ctx);
}

View file

@ -25,6 +25,16 @@ add_executable(c_maxsat_example maxsat.c)
target_include_directories(c_maxsat_example PRIVATE ${Z3_C_INCLUDE_DIRS})
target_link_libraries(c_maxsat_example PRIVATE ${Z3_LIBRARIES})
option(FORCE_CXX_LINKER "Force linker with C++ linker" OFF)
if (FORCE_CXX_LINKER)
# This is a hack for avoiding UBSan linking errors
message(STATUS "Forcing use of C++ linker")
set_target_properties(c_maxsat_example
PROPERTIES
LINKER_LANGUAGE CXX
)
endif()
if ("${CMAKE_SYSTEM_NAME}" MATCHES "[Ww]indows")
# On Windows we need to copy the Z3 libraries
# into the same directory as the executable

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

@ -34,6 +34,19 @@ extern "C" {
Z3_CATCH_RETURN(0);
}
Z3_sort Z3_API Z3_mk_array_sort_n(Z3_context c, unsigned n, Z3_sort const* domain, Z3_sort range) {
Z3_TRY;
LOG_Z3_mk_array_sort_n(c, n, domain, range);
RESET_ERROR_CODE();
vector<parameter> params;
for (unsigned i = 0; i < n; ++i) params.push_back(parameter(to_sort(domain[i])));
params.push_back(parameter(to_sort(range)));
sort * ty = mk_c(c)->m().mk_sort(mk_c(c)->get_array_fid(), ARRAY_SORT, params.size(), params.c_ptr());
mk_c(c)->save_ast_trail(ty);
RETURN_Z3(of_sort(ty));
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i) {
Z3_TRY;
LOG_Z3_mk_select(c, a, i);
@ -57,6 +70,35 @@ extern "C" {
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_mk_select_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs) {
Z3_TRY;
LOG_Z3_mk_select_n(c, a, n, idxs);
RESET_ERROR_CODE();
ast_manager & m = mk_c(c)->m();
expr * _a = to_expr(a);
// expr * _i = to_expr(i);
sort * a_ty = m.get_sort(_a);
// sort * i_ty = m.get_sort(_i);
if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) {
SET_ERROR_CODE(Z3_SORT_ERROR);
RETURN_Z3(0);
}
ptr_vector<sort> domain;
ptr_vector<expr> args;
args.push_back(_a);
domain.push_back(a_ty);
for (unsigned i = 0; i < n; ++i) {
args.push_back(to_expr(idxs[i]));
domain.push_back(m.get_sort(to_expr(idxs[i])));
}
func_decl * d = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_SELECT, 2, a_ty->get_parameters(), domain.size(), domain.c_ptr());
app * r = m.mk_app(d, args.size(), args.c_ptr());
mk_c(c)->save_ast_trail(r);
check_sorts(c, r);
RETURN_Z3(of_ast(r));
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v) {
Z3_TRY;
LOG_Z3_mk_store(c, a, i, v);
@ -82,6 +124,37 @@ extern "C" {
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_mk_store_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs, Z3_ast v) {
Z3_TRY;
LOG_Z3_mk_store_n(c, a, n, idxs, v);
RESET_ERROR_CODE();
ast_manager & m = mk_c(c)->m();
expr * _a = to_expr(a);
expr * _v = to_expr(v);
sort * a_ty = m.get_sort(_a);
sort * v_ty = m.get_sort(_v);
if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) {
SET_ERROR_CODE(Z3_SORT_ERROR);
RETURN_Z3(0);
}
ptr_vector<sort> domain;
ptr_vector<expr> args;
args.push_back(_a);
domain.push_back(a_ty);
for (unsigned i = 0; i < n; ++i) {
args.push_back(to_expr(idxs[i]));
domain.push_back(m.get_sort(to_expr(idxs[i])));
}
args.push_back(_v);
domain.push_back(v_ty);
func_decl * d = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_STORE, 2, a_ty->get_parameters(), domain.size(), domain.c_ptr());
app * r = m.mk_app(d, args.size(), args.c_ptr());
mk_c(c)->save_ast_trail(r);
check_sorts(c, r);
RETURN_Z3(of_ast(r));
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_mk_map(Z3_context c, Z3_func_decl f, unsigned n, Z3_ast const* args) {
Z3_TRY;
LOG_Z3_mk_map(c, f, n, args);
@ -188,6 +261,18 @@ extern "C" {
MK_BINARY(Z3_mk_set_subset, mk_c(c)->get_array_fid(), OP_SET_SUBSET, SKIP);
MK_BINARY(Z3_mk_array_ext, mk_c(c)->get_array_fid(), OP_ARRAY_EXT, SKIP);
Z3_ast Z3_API Z3_mk_as_array(Z3_context c, Z3_func_decl f) {
Z3_TRY;
LOG_Z3_mk_as_array(c, f);
RESET_ERROR_CODE();
ast_manager & m = mk_c(c)->m();
array_util a(m);
app * r = a.mk_as_array(to_func_decl(f));
mk_c(c)->save_ast_trail(r);
return of_ast(r);
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_mk_set_member(Z3_context c, Z3_ast elem, Z3_ast set) {
return Z3_mk_select(c, set, elem);
}
@ -222,7 +307,8 @@ extern "C" {
CHECK_VALID_AST(t, 0);
if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() &&
to_sort(t)->get_decl_kind() == ARRAY_SORT) {
Z3_sort r = reinterpret_cast<Z3_sort>(to_sort(t)->get_parameter(1).get_ast());
unsigned n = to_sort(t)->get_num_parameters();
Z3_sort r = reinterpret_cast<Z3_sort>(to_sort(t)->get_parameter(n-1).get_ast());
RETURN_Z3(r);
}
SET_ERROR_CODE(Z3_INVALID_ARG);

View file

@ -1204,12 +1204,8 @@ extern "C" {
case OP_FPA_TO_SBV: return Z3_OP_FPA_TO_SBV;
case OP_FPA_TO_REAL: return Z3_OP_FPA_TO_REAL;
case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV;
case OP_FPA_MIN_I: return Z3_OP_FPA_MIN_I;
case OP_FPA_MAX_I: return Z3_OP_FPA_MAX_I;
case OP_FPA_BVWRAP: return Z3_OP_FPA_BVWRAP;
case OP_FPA_BV2RM: return Z3_OP_FPA_BV2RM;
case OP_FPA_MIN_UNSPECIFIED: return Z3_OP_FPA_MIN_UNSPECIFIED;
case OP_FPA_MAX_UNSPECIFIED: return Z3_OP_FPA_MAX_UNSPECIFIED;
return Z3_OP_UNINTERPRETED;
default:
return Z3_OP_INTERNAL;

View file

@ -283,15 +283,16 @@ extern "C" {
Z3_optimize opt,
std::istream& s) {
ast_manager& m = mk_c(c)->m();
cmd_context ctx(false, &m);
install_opt_cmds(ctx, to_optimize_ptr(opt));
ctx.set_ignore_check(true);
if (!parse_smt2_commands(ctx, s)) {
scoped_ptr<cmd_context> ctx = alloc(cmd_context, false, &m);
install_opt_cmds(*ctx.get(), to_optimize_ptr(opt));
ctx->set_ignore_check(true);
if (!parse_smt2_commands(*ctx.get(), s)) {
ctx = nullptr;
SET_ERROR_CODE(Z3_PARSER_ERROR);
return;
}
ptr_vector<expr>::const_iterator it = ctx.begin_assertions();
ptr_vector<expr>::const_iterator end = ctx.end_assertions();
ptr_vector<expr>::const_iterator it = ctx->begin_assertions();
ptr_vector<expr>::const_iterator end = ctx->end_assertions();
for (; it != end; ++it) {
to_optimize_ptr(opt)->add_hard_constraint(*it);
}
@ -320,9 +321,6 @@ extern "C" {
std::ostringstream strm;
strm << "Could not open file " << s;
throw default_exception(strm.str());
SET_ERROR_CODE(Z3_PARSER_ERROR);
return;
}
Z3_optimize_from_stream(c, d, is);
Z3_CATCH;

View file

@ -56,19 +56,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;
scoped_ptr<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();
outs = nullptr;
if (!ok) {
mk_c(c)->reset_parser();
SET_ERROR_CODE(Z3_PARSER_ERROR);
@ -88,16 +89,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;
scoped_ptr<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();
outs = nullptr;
if (!ok) {
mk_c(c)->reset_parser();
SET_ERROR_CODE(Z3_PARSER_ERROR);
@ -260,21 +262,22 @@ extern "C" {
Z3_symbol const decl_names[],
Z3_func_decl const decls[]) {
Z3_TRY;
cmd_context ctx(false, &(mk_c(c)->m()));
ctx.set_ignore_check(true);
scoped_ptr<cmd_context> ctx = alloc(cmd_context, false, &(mk_c(c)->m()));
ctx->set_ignore_check(true);
for (unsigned i = 0; i < num_decls; ++i) {
ctx.insert(to_symbol(decl_names[i]), to_func_decl(decls[i]));
ctx->insert(to_symbol(decl_names[i]), to_func_decl(decls[i]));
}
for (unsigned i = 0; i < num_sorts; ++i) {
psort* ps = ctx.pm().mk_psort_cnst(to_sort(sorts[i]));
ctx.insert(ctx.pm().mk_psort_user_decl(0, to_symbol(sort_names[i]), ps));
psort* ps = ctx->pm().mk_psort_cnst(to_sort(sorts[i]));
ctx->insert(ctx->pm().mk_psort_user_decl(0, to_symbol(sort_names[i]), ps));
}
if (!parse_smt2_commands(ctx, is)) {
if (!parse_smt2_commands(*ctx.get(), is)) {
ctx = nullptr;
SET_ERROR_CODE(Z3_PARSER_ERROR);
return of_ast(mk_c(c)->m().mk_true());
}
ptr_vector<expr>::const_iterator it = ctx.begin_assertions();
ptr_vector<expr>::const_iterator end = ctx.end_assertions();
ptr_vector<expr>::const_iterator it = ctx->begin_assertions();
ptr_vector<expr>::const_iterator end = ctx->end_assertions();
unsigned size = static_cast<unsigned>(end - it);
return of_ast(mk_c(c)->mk_and(size, it));
Z3_CATCH_RETURN(0);

View file

@ -63,9 +63,11 @@ extern "C" {
RESET_ERROR_CODE();
if (!mk_c(c)->m().is_bool(to_expr(body))) {
SET_ERROR_CODE(Z3_SORT_ERROR);
return nullptr;
}
if (num_patterns > 0 && num_no_patterns > 0) {
SET_ERROR_CODE(Z3_INVALID_USAGE);
return nullptr;
}
expr * const* ps = reinterpret_cast<expr * const*>(patterns);
expr * const* no_ps = reinterpret_cast<expr * const*>(no_patterns);
@ -76,7 +78,7 @@ extern "C" {
for (unsigned i = 0; i < num_patterns; i++) {
if (!v(num_decls, ps[i], 0, 0)) {
SET_ERROR_CODE(Z3_INVALID_PATTERN);
return 0;
return nullptr;
}
}
}

View file

@ -442,6 +442,7 @@ extern "C" {
unsigned sz = __assumptions.size();
for (unsigned i = 0; i < sz; ++i) {
if (!is_expr(__assumptions[i])) {
_assumptions.finalize(); _consequences.finalize(); _variables.finalize();
SET_ERROR_CODE(Z3_INVALID_USAGE);
return Z3_L_UNDEF;
}
@ -451,6 +452,7 @@ extern "C" {
sz = __variables.size();
for (unsigned i = 0; i < sz; ++i) {
if (!is_expr(__variables[i])) {
_assumptions.finalize(); _consequences.finalize(); _variables.finalize();
SET_ERROR_CODE(Z3_INVALID_USAGE);
return Z3_L_UNDEF;
}
@ -471,6 +473,7 @@ extern "C" {
}
catch (z3_exception & ex) {
to_solver_ref(s)->set_reason_unknown(eh);
_assumptions.finalize(); _consequences.finalize(); _variables.finalize();
mk_c(c)->handle_exception(ex);
return Z3_L_UNDEF;
}

View file

@ -140,18 +140,17 @@ 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 */ }
void init(config & c) {
m_ctx = Z3_mk_context_rc(c);
m_enable_exceptions = true;
Z3_set_error_handler(m_ctx, error_handler);
Z3_set_error_handler(m_ctx, 0);
Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT);
}
void init_interp(config & c) {
m_ctx = Z3_mk_interpolation_context(c);
m_enable_exceptions = true;
Z3_set_error_handler(m_ctx, error_handler);
Z3_set_error_handler(m_ctx, 0);
Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT);
}
@ -251,6 +250,8 @@ namespace z3 {
Example: Given a context \c c, <tt>c.array_sort(c.int_sort(), c.bool_sort())</tt> is an array sort from integer to Boolean.
*/
sort array_sort(sort d, sort r);
sort array_sort(sort_vector const& d, sort r);
/**
\brief Return an enumeration sort: enum_names[0], ..., enum_names[n-1].
\c cs and \c ts are output parameters. The method stores in \c cs the constants corresponding to the enumerated elements,
@ -354,7 +355,7 @@ namespace z3 {
Z3_error_code check_error() const { return m_ctx->check_error(); }
friend void check_context(object const & a, object const & b);
};
inline void check_context(object const & a, object const & b) { assert(a.m_ctx == b.m_ctx); }
inline void check_context(object const & a, object const & b) { (void)a; (void)b; assert(a.m_ctx == b.m_ctx); }
class symbol : public object {
Z3_symbol m_sym;
@ -2328,6 +2329,11 @@ namespace z3 {
inline sort context::re_sort(sort& s) { Z3_sort r = Z3_mk_re_sort(m_ctx, s); check_error(); return sort(*this, r); }
inline sort context::array_sort(sort d, sort r) { Z3_sort s = Z3_mk_array_sort(m_ctx, d, r); check_error(); return sort(*this, s); }
inline sort context::array_sort(sort_vector const& d, sort r) {
array<Z3_sort> dom(d);
Z3_sort s = Z3_mk_array_sort_n(m_ctx, dom.size(), dom.ptr(), r); check_error(); return sort(*this, s);
}
inline sort context::enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts) {
array<Z3_symbol> _enum_names(n);
for (unsigned i = 0; i < n; i++) { _enum_names[i] = Z3_mk_string_symbol(*this, enum_names[i]); }
@ -2574,11 +2580,32 @@ namespace z3 {
a.check_error();
return expr(a.ctx(), r);
}
inline expr select(expr const & a, expr_vector const & i) {
check_context(a, i);
array<Z3_ast> idxs(i);
Z3_ast r = Z3_mk_select_n(a.ctx(), a, idxs.size(), idxs.ptr());
a.check_error();
return expr(a.ctx(), r);
}
inline expr store(expr const & a, int i, expr const & v) { return store(a, a.ctx().num_val(i, a.get_sort().array_domain()), v); }
inline expr store(expr const & a, expr i, int v) { return store(a, i, a.ctx().num_val(v, a.get_sort().array_range())); }
inline expr store(expr const & a, int i, int v) {
return store(a, a.ctx().num_val(i, a.get_sort().array_domain()), a.ctx().num_val(v, a.get_sort().array_range()));
}
inline expr store(expr const & a, expr_vector const & i, expr const & v) {
check_context(a, i); check_context(a, v);
array<Z3_ast> idxs(i);
Z3_ast r = Z3_mk_store_n(a.ctx(), a, idxs.size(), idxs.ptr(), v);
a.check_error();
return expr(a.ctx(), r);
}
inline expr as_array(func_decl & f) {
Z3_ast r = Z3_mk_as_array(f.ctx(), f);
f.check_error();
return expr(f.ctx(), r);
}
#define MK_EXPR1(_fn, _arg) \
Z3_ast r = _fn(_arg.ctx(), _arg); \

View file

@ -63,6 +63,13 @@ namespace Microsoft.Z3
Contract.Requires(domain != null);
Contract.Requires(range != null);
}
internal ArraySort(Context ctx, Sort[] domain, Sort range)
: base(ctx, Native.Z3_mk_array_sort_n(ctx.nCtx, (uint)domain.Length, AST.ArrayToNative(domain), range.NativeObject))
{
Contract.Requires(ctx != null);
Contract.Requires(domain != null);
Contract.Requires(range != null);
}
#endregion
};

View file

@ -274,6 +274,20 @@ namespace Microsoft.Z3
return new ArraySort(this, domain, range);
}
/// <summary>
/// Create a new n-ary array sort.
/// </summary>
public ArraySort MkArraySort(Sort[] domain, Sort range)
{
Contract.Requires(domain != null);
Contract.Requires(range != null);
Contract.Ensures(Contract.Result<ArraySort>() != null);
CheckContextMatch<Sort>(domain);
CheckContextMatch(range);
return new ArraySort(this, domain, range);
}
/// <summary>
/// Create a new tuple sort.
/// </summary>
@ -2113,6 +2127,7 @@ namespace Microsoft.Z3
return (ArrayExpr)MkConst(MkSymbol(name), MkArraySort(domain, range));
}
/// <summary>
/// Array read.
/// </summary>
@ -2123,8 +2138,8 @@ namespace Microsoft.Z3
/// The node <c>a</c> must have an array sort <c>[domain -> range]</c>,
/// and <c>i</c> must have the sort <c>domain</c>.
/// The sort of the result is <c>range</c>.
/// <seealso cref="MkArraySort"/>
/// <seealso cref="MkStore"/>
/// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkStore(ArrayExpr, Expr, Expr)"/>
/// </remarks>
public Expr MkSelect(ArrayExpr a, Expr i)
{
@ -2137,6 +2152,30 @@ namespace Microsoft.Z3
return Expr.Create(this, Native.Z3_mk_select(nCtx, a.NativeObject, i.NativeObject));
}
/// <summary>
/// Array read.
/// </summary>
/// <remarks>
/// The argument <c>a</c> is the array and <c>args</c> are the indices
/// of the array that gets read.
///
/// The node <c>a</c> must have an array sort <c>[domain1,..,domaink -> range]</c>,
/// and <c>args</c> must have the sort <c>domain1,..,domaink</c>.
/// The sort of the result is <c>range</c>.
/// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkStore(ArrayExpr, Expr, Expr)"/>
/// </remarks>
public Expr MkSelect(ArrayExpr a, params Expr[] args)
{
Contract.Requires(a != null);
Contract.Requires(args != null && Contract.ForAll(args, n => n != null));
Contract.Ensures(Contract.Result<Expr>() != null);
CheckContextMatch(a);
CheckContextMatch<Expr>(args);
return Expr.Create(this, Native.Z3_mk_select_n(nCtx, a.NativeObject, AST.ArrayLength(args), AST.ArrayToNative(args)));
}
/// <summary>
/// Array update.
/// </summary>
@ -2151,8 +2190,9 @@ namespace Microsoft.Z3
/// on all indices except for <c>i</c>, where it maps to <c>v</c>
/// (and the <c>select</c> of <c>a</c> with
/// respect to <c>i</c> may be a different value).
/// <seealso cref="MkArraySort"/>
/// <seealso cref="MkSelect"/>
/// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkSelect(ArrayExpr, Expr)"/>
/// <seealso cref="MkSelect(ArrayExpr, Expr[])"/>
/// </remarks>
public ArrayExpr MkStore(ArrayExpr a, Expr i, Expr v)
{
@ -2167,14 +2207,45 @@ namespace Microsoft.Z3
return new ArrayExpr(this, Native.Z3_mk_store(nCtx, a.NativeObject, i.NativeObject, v.NativeObject));
}
/// <summary>
/// Array update.
/// </summary>
/// <remarks>
/// The node <c>a</c> must have an array sort <c>[domain1,..,domaink -> range]</c>,
/// <c>args</c> must have sort <c>domain1,..,domaink</c>,
/// <c>v</c> must have sort range. The sort of the result is <c>[domain -> range]</c>.
/// The semantics of this function is given by the theory of arrays described in the SMT-LIB
/// standard. See http://smtlib.org for more details.
/// The result of this function is an array that is equal to <c>a</c>
/// (with respect to <c>select</c>)
/// on all indices except for <c>args</c>, where it maps to <c>v</c>
/// (and the <c>select</c> of <c>a</c> with
/// respect to <c>args</c> may be a different value).
/// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkSelect(ArrayExpr, Expr)"/>
/// <seealso cref="MkSelect(ArrayExpr, Expr[])"/>
/// </remarks>
public ArrayExpr MkStore(ArrayExpr a, Expr[] args, Expr v)
{
Contract.Requires(a != null);
Contract.Requires(args != null);
Contract.Requires(v != null);
Contract.Ensures(Contract.Result<ArrayExpr>() != null);
CheckContextMatch<Expr>(args);
CheckContextMatch(a);
CheckContextMatch(v);
return new ArrayExpr(this, Native.Z3_mk_store_n(nCtx, a.NativeObject, AST.ArrayLength(args), AST.ArrayToNative(args), v.NativeObject));
}
/// <summary>
/// Create a constant array.
/// </summary>
/// <remarks>
/// The resulting term is an array, such that a <c>select</c>on an arbitrary index
/// produces the value <c>v</c>.
/// <seealso cref="MkArraySort"/>
/// <seealso cref="MkSelect"/>
/// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkSelect(ArrayExpr, Expr)"/>
/// </remarks>
public ArrayExpr MkConstArray(Sort domain, Expr v)
{
@ -2194,9 +2265,9 @@ namespace Microsoft.Z3
/// Eeach element of <c>args</c> must be of an array sort <c>[domain_i -> range_i]</c>.
/// The function declaration <c>f</c> must have type <c> range_1 .. range_n -> range</c>.
/// <c>v</c> must have sort range. The sort of the result is <c>[domain_i -> range]</c>.
/// <seealso cref="MkArraySort"/>
/// <seealso cref="MkSelect"/>
/// <seealso cref="MkStore"/>
/// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkSelect(ArrayExpr, Expr)"/>
/// <seealso cref="MkStore(ArrayExpr, Expr, Expr)"/>
/// </remarks>
public ArrayExpr MkMap(FuncDecl f, params ArrayExpr[] args)
{

View file

@ -56,4 +56,10 @@ public class ArraySort extends Sort
super(ctx, Native.mkArraySort(ctx.nCtx(), domain.getNativeObject(),
range.getNativeObject()));
}
ArraySort(Context ctx, Sort[] domains, Sort range)
{
super(ctx, Native.mkArraySortN(ctx.nCtx(), domains.length, AST.arrayToNative(domains),
range.getNativeObject()));
}
};

View file

@ -224,6 +224,17 @@ public class Context implements AutoCloseable {
return new ArraySort(this, domain, range);
}
/**
* Create a new array sort.
**/
public ArraySort mkArraySort(Sort[] domains, Sort range)
{
checkContextMatch(domains);
checkContextMatch(range);
return new ArraySort(this, domains, range);
}
/**
* Create a new string sort
**/
@ -414,7 +425,7 @@ public class Context implements AutoCloseable {
* that is passed in as argument is updated with value v,
* the remaining fields of t are unchanged.
**/
public Expr MkUpdateField(FuncDecl field, Expr t, Expr v)
public Expr mkUpdateField(FuncDecl field, Expr t, Expr v)
throws Z3Exception
{
return Expr.create (this,
@ -706,7 +717,7 @@ public class Context implements AutoCloseable {
}
/**
* Mk an expression representing {@code not(a)}.
* Create an expression representing {@code not(a)}.
**/
public BoolExpr mkNot(BoolExpr a)
{
@ -1679,6 +1690,28 @@ public class Context implements AutoCloseable {
i.getNativeObject()));
}
/**
* Array read.
* Remarks: The argument {@code a} is the array and
* {@code args} are the indices of the array that gets read.
*
* The node {@code a} must have an array sort
* {@code [domains -> range]}, and {@code args} must have the sorts
* {@code domains}. The sort of the result is {@code range}.
*
* @see #mkArraySort
* @see #mkStore
**/
public Expr mkSelect(ArrayExpr a, Expr[] args)
{
checkContextMatch(a);
checkContextMatch(args);
return Expr.create(
this,
Native.mkSelectN(nCtx(), a.getNativeObject(), args.length, AST.arrayToNative(args)));
}
/**
* Array update.
* Remarks: The node {@code a} must have an array sort
@ -1704,6 +1737,31 @@ public class Context implements AutoCloseable {
i.getNativeObject(), v.getNativeObject()));
}
/**
* Array update.
* Remarks: The node {@code a} must have an array sort
* {@code [domains -> range]}, {@code i} must have sort
* {@code domain}, {@code v} must have sort range. The sort of the
* result is {@code [domains -> range]}. The semantics of this function
* is given by the theory of arrays described in the SMT-LIB standard. See
* http://smtlib.org for more details. The result of this function is an
* array that is equal to {@code a} (with respect to
* {@code select}) on all indices except for {@code args}, where it
* maps to {@code v} (and the {@code select} of {@code a}
* with respect to {@code args} may be a different value).
* @see #mkArraySort
* @see #mkSelect
**/
public ArrayExpr mkStore(ArrayExpr a, Expr[] args, Expr v)
{
checkContextMatch(a);
checkContextMatch(args);
checkContextMatch(v);
return new ArrayExpr(this, Native.mkStoreN(nCtx(), a.getNativeObject(),
args.length, AST.arrayToNative(args), v.getNativeObject()));
}
/**
* Create a constant array.
* Remarks: The resulting term is an array, such
@ -2104,7 +2162,7 @@ public class Context implements AutoCloseable {
/**
* Create a range expression.
*/
public ReExpr MkRange(SeqExpr lo, SeqExpr hi)
public ReExpr mkRange(SeqExpr lo, SeqExpr hi)
{
checkContextMatch(lo, hi);
return (ReExpr) Expr.create(this, Native.mkReRange(nCtx(), lo.getNativeObject(), hi.getNativeObject()));

View file

@ -120,7 +120,7 @@ def _get_args(args):
try:
if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)):
return args[0]
elif len(args) == 1 and isinstance(args[0], set):
elif len(args) == 1 and (isinstance(args[0], set) or isinstance(args[0], AstVector)):
return [arg for arg in args[0]]
else:
return args

View file

@ -993,18 +993,6 @@ typedef enum
3 = 011 = Z3_OP_FPA_RM_TOWARD_NEGATIVE,
4 = 100 = Z3_OP_FPA_RM_TOWARD_ZERO.
- Z3_OP_FPA_MIN_I: The same as Z3_OP_FPA_MIN, but the arguments are
expected not to be zeroes with different signs.
- Z3_OP_FPA_MAX_I: The same as Z3_OP_FPA_MAX, but the arguments are
expected not to be zeroes with different signs.
- Z3_OP_FPA_MIN_UNSPECIFIED: The same as Z3_OP_FPA_MIN, but the
arguments are expected to be zeroes with different signs.
- Z3_OP_FPA_MAX_UNSPECIFIED: The same as Z3_OP_FPA_MAX, but the
arguments are expected to be zeroes with different signs.
- Z3_OP_INTERNAL: internal (often interpreted) symbol, but no additional
information is exposed. Tools may use the string representation of the
function declaration to obtain more information.
@ -1291,13 +1279,8 @@ typedef enum {
Z3_OP_FPA_TO_IEEE_BV,
Z3_OP_FPA_MIN_I,
Z3_OP_FPA_MAX_I,
Z3_OP_FPA_BVWRAP,
Z3_OP_FPA_BV2RM,
Z3_OP_FPA_MIN_UNSPECIFIED,
Z3_OP_FPA_MAX_UNSPECIFIED,
Z3_OP_INTERNAL,
@ -1898,6 +1881,17 @@ extern "C" {
*/
Z3_sort Z3_API Z3_mk_array_sort(Z3_context c, Z3_sort domain, Z3_sort range);
/**
\brief Create an array type with N arguments
\sa Z3_mk_select_n
\sa Z3_mk_store_n
def_API('Z3_mk_array_sort_n', SORT, (_in(CONTEXT), _in(UINT), _in_array(1, SORT), _in(SORT)))
*/
Z3_sort Z3_API Z3_mk_array_sort_n(Z3_context c, unsigned n, Z3_sort const * domain, Z3_sort range);
/**
\brief Create a tuple type.
@ -2990,6 +2984,15 @@ extern "C" {
*/
Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i);
/**
\brief n-ary Array read.
The argument \c a is the array and \c idxs are the indices of the array that gets read.
def_API('Z3_mk_select_n', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST)))
*/
Z3_ast Z3_API Z3_mk_select_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs);
/**
\brief Array update.
@ -3008,6 +3011,14 @@ extern "C" {
*/
Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v);
/**
\brief n-ary Array update.
def_API('Z3_mk_store_n', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST), _in(AST)))
*/
Z3_ast Z3_API Z3_mk_store_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs, Z3_ast v);
/**
\brief Create the constant array.
@ -3048,6 +3059,15 @@ extern "C" {
def_API('Z3_mk_array_default', AST, (_in(CONTEXT), _in(AST)))
*/
Z3_ast Z3_API Z3_mk_array_default(Z3_context c, Z3_ast array);
/**
\brief Create array with the same interpretation as a function.
The array satisfies the property (f x) = (select (_ as-array f) x)
for every argument x.
def_API('Z3_mk_as_array', AST, (_in(CONTEXT), _in(FUNC_DECL)))
*/
Z3_ast Z3_API Z3_mk_as_array(Z3_context c, Z3_func_decl f);
/*@}*/
/** @name Sets */
@ -3871,6 +3891,7 @@ extern "C" {
/**
\brief Return the domain of the given array sort.
In the case of a multi-dimensional array, this function returns the sort of the first dimension.
\pre Z3_get_sort_kind(c, t) == Z3_ARRAY_SORT

View file

@ -197,4 +197,4 @@ extern "C" {
}
#endif // __cplusplus
#endif
#endif

View file

@ -242,7 +242,9 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) {
parameter const* parameters = s->get_parameters();
if (num_parameters != arity) {
m_manager->raise_exception("select requires as many arguments as the size of the domain");
std::stringstream strm;
strm << "select requires " << num_parameters << " arguments, but was provided with " << arity << " arguments";
m_manager->raise_exception(strm.str().c_str());
return 0;
}
ptr_buffer<sort> new_domain; // we need this because of coercions.
@ -314,7 +316,7 @@ func_decl * array_decl_plugin::mk_array_ext(unsigned arity, sort * const * domai
return 0;
}
sort * r = to_sort(s->get_parameter(i).get_ast());
parameter param(s);
parameter param(i);
return m_manager->mk_func_decl(m_array_ext_sym, arity, domain, r, func_decl_info(m_family_id, OP_ARRAY_EXT, 1, &param));
}
@ -592,3 +594,9 @@ sort * array_util::mk_array_sort(unsigned arity, sort* const* domain, sort* rang
params.push_back(parameter(range));
return m_manager.mk_sort(m_fid, ARRAY_SORT, params.size(), params.c_ptr());
}
func_decl* array_util::mk_array_ext(sort *domain, unsigned i) {
sort * domains[2] = { domain, domain };
parameter p(i);
return m_manager.mk_func_decl(m_fid, OP_ARRAY_EXT, 1, &p, 2, domains);
}

View file

@ -143,6 +143,7 @@ public:
bool is_const(expr* n) const { return is_app_of(n, m_fid, OP_CONST_ARRAY); }
bool is_map(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_MAP); }
bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); }
bool is_as_array(expr * n, func_decl*& f) const { return is_as_array(n) && (f = get_as_array_func_decl(n), true); }
bool is_select(func_decl* f) const { return is_decl_of(f, m_fid, OP_SELECT); }
bool is_store(func_decl* f) const { return is_decl_of(f, m_fid, OP_STORE); }
bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); }
@ -182,13 +183,15 @@ public:
return mk_const_array(s, m_manager.mk_true());
}
func_decl * mk_array_ext(sort* domain, unsigned i);
sort * mk_array_sort(sort* dom, sort* range) { return mk_array_sort(1, &dom, range); }
sort * mk_array_sort(unsigned arity, sort* const* domain, sort* range);
app * mk_as_array(sort * s, func_decl * f) {
app * mk_as_array(func_decl * f) {
parameter param(f);
return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, &param, 0, 0, s);
return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, &param, 0, 0, 0);
}
};

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() &&
@ -765,7 +768,7 @@ func_decl * basic_decl_plugin::mk_compressed_proof_decl(char const * name, basic
func_decl * basic_decl_plugin::mk_proof_decl(char const * name, basic_op_kind k, unsigned num_parents, ptr_vector<func_decl> & cache) {
if (num_parents >= cache.size()) {
cache.resize(num_parents+1, 0);
cache.resize(num_parents+1);
}
if (cache[num_parents] == 0) {
cache[num_parents] = mk_proof_decl(name, k, num_parents);

View file

@ -121,6 +121,20 @@ public:
explicit parameter(unsigned ext_id, bool):m_kind(PARAM_EXTERNAL), m_ext_id(ext_id) {}
parameter(parameter const&);
parameter(parameter && other) : m_kind(other.m_kind) {
switch (other.m_kind) {
case PARAM_INT: m_int = other.get_int(); break;
case PARAM_AST: m_ast = other.get_ast(); break;
case PARAM_SYMBOL: m_symbol = other.m_symbol; break;
case PARAM_RATIONAL: m_rational = 0; std::swap(m_rational, other.m_rational); break;
case PARAM_DOUBLE: m_dval = other.m_dval; break;
case PARAM_EXTERNAL: m_ext_id = other.m_ext_id; break;
default:
UNREACHABLE();
break;
}
}
~parameter();
parameter& operator=(parameter const& other);

View file

@ -584,6 +584,8 @@ class smt2_printer {
string_buffer<> buf;
buf.append("(:var ");
buf.append(v->get_idx());
//buf.append(" ");
//buf.append(v->get_sort()->get_name().str().c_str());
buf.append(")");
f = mk_string(m(), buf.c_str());
}

View file

@ -863,8 +863,7 @@ app * bv_util::mk_numeral(rational const & val, sort* s) const {
}
app * bv_util::mk_numeral(rational const & val, unsigned bv_size) const {
parameter p1(val);
parameter p[2] = { p1, parameter(static_cast<int>(bv_size)) };
parameter p[2] = { parameter(val), parameter(static_cast<int>(bv_size)) };
return m_manager.mk_app(get_fid(), OP_BV_NUM, 2, p, 0, 0);
}

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 {
@ -78,12 +80,14 @@ public:
m_trail_lim.resize(new_sz);
}
}
unsigned scope_level() const { return m_trail_lim.size(); }
bool empty() const { return m_subst.empty(); }
expr* find(expr * e) { proof* pr; expr* d = 0; if (find(e, d, pr)) return d; else return e; }
bool find(expr * s, expr * & def, proof * & def_pr) { return m_subst.find(s, def, def_pr); }
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

@ -62,8 +62,8 @@ bv2fpa_converter::bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv) :
m.inc_ref(it->m_key);
m.inc_ref(it->m_value);
}
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = conv.m_min_max_specials.begin();
it != conv.m_min_max_specials.end();
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = conv.m_min_max_ufs.begin();
it != conv.m_min_max_ufs.end();
it++) {
m_specials.insert(it->m_key, it->m_value);
m.inc_ref(it->m_key);
@ -250,7 +250,7 @@ bv2fpa_converter::array_model bv2fpa_converter::convert_array_func_interp(model_
am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng);
am.new_float_fi = convert_func_interp(mc, am.new_float_fd, bv_f);
am.bv_fd = bv_f;
am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd);
am.result = arr_util.mk_as_array(am.new_float_fd);
return am;
}

View file

@ -230,39 +230,7 @@ void fpa2bv_converter::mk_var(unsigned base_inx, sort * srt, expr_ref & result)
result = m_util.mk_fp(sgn, e, s);
}
void fpa2bv_converter::mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result) {
if (m_util.is_float(rng)) {
unsigned ebits = m_util.get_ebits(rng);
unsigned sbits = m_util.get_sbits(rng);
unsigned bv_sz = ebits + sbits;
app_ref na(m);
na = m.mk_app(fbv, fbv->get_arity(), new_args);
result = m_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, na),
m_bv_util.mk_extract(bv_sz - 2, sbits - 1, na),
m_bv_util.mk_extract(sbits - 2, 0, na));
}
else if (m_util.is_rm(rng)) {
app_ref na(m);
na = m.mk_app(fbv, fbv->get_arity(), new_args);
result = m_util.mk_bv2rm(na);
}
else
result = m.mk_app(fbv, fbv->get_arity(), new_args);
}
func_decl * fpa2bv_converter::get_bv_uf(func_decl * f, sort * bv_rng, unsigned arity) {
func_decl * res;
if (!m_uf2bvuf.find(f, res)) {
res = m.mk_fresh_func_decl(f->get_name(), symbol("bv"), arity, f->get_domain(), bv_rng);
m_uf2bvuf.insert(f, res);
m.inc_ref(f);
m.inc_ref(res);
TRACE("fpa2bv", tout << "New UF func_decl: " << std::endl << mk_ismt2_pp(res, m) << std::endl;);
}
return res;
}
void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result)
void fpa2bv_converter::mk_uf(func_decl * f, unsigned num, expr * const * args, expr_ref & result)
{
TRACE("fpa2bv", tout << "UF: " << mk_ismt2_pp(f, m) << std::endl; );
@ -278,7 +246,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a
unsigned sbits = m_util.get_sbits(rng);
unsigned bv_sz = ebits+sbits;
bv_rng = m_bv_util.mk_sort(bv_sz);
func_decl * bv_f = get_bv_uf(f, bv_rng, num);
func_decl * bv_f = mk_bv_uf(f, f->get_domain(), bv_rng);
bv_app = m.mk_app(bv_f, num, args);
flt_app = m_util.mk_fp(m_bv_util.mk_extract(bv_sz-1, bv_sz-1, bv_app),
m_bv_util.mk_extract(sbits+ebits-2, sbits-1, bv_app),
@ -291,7 +259,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a
sort_ref bv_rng(m);
expr_ref new_eq(m);
bv_rng = m_bv_util.mk_sort(3);
func_decl * bv_f = get_bv_uf(f, bv_rng, num);
func_decl * bv_f = mk_bv_uf(f, f->get_domain(), bv_rng);
bv_app = m.mk_app(bv_f, num, args);
flt_app = m_util.mk_bv2rm(bv_app);
new_eq = m.mk_eq(fapp, flt_app);
@ -1211,61 +1179,85 @@ 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) {
expr_ref x(m), y(m);
x = args[0];
y = args[1];
expr_ref x_is_zero(m), y_is_zero(m), both_are_zero(m);
x_is_zero = m_util.mk_is_zero(x);
y_is_zero = m_util.mk_is_zero(y);
both_are_zero = m.mk_and(x_is_zero, y_is_zero);
expr_ref x_is_positive(m), x_is_negative(m), y_is_positive(m), y_is_negative(m), pn(m), np(m), pn_or_np(m);
x_is_positive = m_util.mk_is_positive(x);
x_is_negative = m_util.mk_is_negative(x);
y_is_positive = m_util.mk_is_positive(y);
y_is_negative = m_util.mk_is_negative(y);
pn = m.mk_and(x_is_positive, y_is_negative);
np = m.mk_and(x_is_negative, y_is_positive);
pn_or_np = m.mk_or(pn, np);
expr_ref c(m), v(m);
c = m.mk_and(both_are_zero, pn_or_np);
v = m.mk_app(m_util.get_family_id(), OP_FPA_MIN_UNSPECIFIED, x, y);
// Note: This requires BR_REWRITE_FULL afterwards.
expr_ref min_i(m);
min_i = m.mk_app(m_util.get_family_id(), OP_FPA_MIN_I, x, y);
m_simp.mk_ite(c, v, min_i, result);
}
void fpa2bv_converter::mk_min_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
expr * x = args[0], * y = args[1];
expr * x_sgn, * x_sig, * x_exp;
expr * y_sgn, * y_sig, * y_exp;
expr * x_sgn, *x_sig, *x_exp;
expr * y_sgn, *y_sig, *y_exp;
split_fp(x, x_sgn, x_exp, x_sig);
split_fp(y, y_sgn, y_exp, y_sig);
expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), both_zero(m), pzero(m);
mk_is_zero(x, x_is_zero);
mk_is_zero(y, y_is_zero);
m_simp.mk_and(x_is_zero, y_is_zero, both_zero);
expr_ref bv0(m), bv1(m);
bv0 = m_bv_util.mk_numeral(0, 1);
bv1 = m_bv_util.mk_numeral(1, 1);
expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), xy_are_zero(m);
mk_is_nan(x, x_is_nan);
mk_is_nan(y, y_is_nan);
mk_pzero(f, pzero);
mk_is_zero(x, x_is_zero);
mk_is_zero(y, y_is_zero);
xy_are_zero = m.mk_and(x_is_zero, y_is_zero);
expr_ref sgn_eq(m), sgn_diff(m);
sgn_eq = m.mk_eq(x_sgn, y_sgn);
sgn_diff = m.mk_not(sgn_eq);
expr_ref x_is_pos(m), x_is_neg(m);
expr_ref y_is_pos(m), y_is_neg(m);
expr_ref pn(m), np(m), pn_or_np_zeros(m);
mk_is_pos(x, x_is_pos);
mk_is_pos(y, y_is_pos);
mk_is_neg(x, x_is_neg);
mk_is_neg(y, y_is_neg);
pn_or_np_zeros = m.mk_and(xy_are_zero, m.mk_not(m.mk_eq(x_sgn, y_sgn)));
expr_ref lt(m);
mk_float_lt(f, num, args, lt);
expr_ref unspec(m);
unspec = mk_min_max_unspecified(f, x, y);
mk_ite(lt, x, y, result);
mk_ite(both_zero, y, result, result);
expr_ref x_lt_y(m);
mk_float_lt(f, num, args, x_lt_y);
mk_ite(x_lt_y, x, y, result);
mk_ite(xy_are_zero, y, result, result);
mk_ite(pn_or_np_zeros, unspec, result, result);
mk_ite(y_is_nan, x, result, result);
mk_ite(x_is_nan, y, result, result);
SASSERT(is_well_sorted(m, result));
}
void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
expr * x = args[0], *y = args[1];
expr * x_sgn, *x_sig, *x_exp;
expr * y_sgn, *y_sig, *y_exp;
split_fp(x, x_sgn, x_exp, x_sig);
split_fp(y, y_sgn, y_exp, y_sig);
expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), xy_are_zero(m);
mk_is_nan(x, x_is_nan);
mk_is_nan(y, y_is_nan);
mk_is_zero(x, x_is_zero);
mk_is_zero(y, y_is_zero);
xy_are_zero = m.mk_and(x_is_zero, y_is_zero);
expr_ref x_is_pos(m), x_is_neg(m);
expr_ref y_is_pos(m), y_is_neg(m);
expr_ref pn(m), np(m), pn_or_np_zeros(m);
mk_is_pos(x, x_is_pos);
mk_is_pos(y, y_is_pos);
mk_is_neg(x, x_is_neg);
mk_is_neg(y, y_is_neg);
pn_or_np_zeros = m.mk_and(xy_are_zero, m.mk_not(m.mk_eq(x_sgn, y_sgn)));
expr_ref unspec(m);
unspec = mk_min_max_unspecified(f, x, y);
expr_ref x_gt_y(m);
mk_float_gt(f, num, args, x_gt_y);
mk_ite(x_gt_y, x, y, result);
mk_ite(xy_are_zero, y, result, result);
mk_ite(pn_or_np_zeros, unspec, result, result);
mk_ite(y_is_nan, x, result, result);
mk_ite(x_is_nan, y, result, result);
@ -1281,10 +1273,10 @@ expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr
// There is no "hardware interpretation" for fp.min/fp.max.
std::pair<app*, app*> decls(0, 0);
if (!m_min_max_specials.find(f, decls)) {
if (!m_min_max_ufs.find(f, decls)) {
decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
m_min_max_specials.insert(f, decls);
m_min_max_ufs.insert(f, decls);
m.inc_ref(f);
m.inc_ref(decls.first);
m.inc_ref(decls.second);
@ -1303,68 +1295,6 @@ expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr
return res;
}
void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
expr_ref x(m), y(m);
x = args[0];
y = args[1];
expr_ref x_is_zero(m), y_is_zero(m), both_are_zero(m);
x_is_zero = m_util.mk_is_zero(x);
y_is_zero = m_util.mk_is_zero(y);
both_are_zero = m.mk_and(x_is_zero, y_is_zero);
expr_ref x_is_positive(m), x_is_negative(m), y_is_positive(m), y_is_negative(m), pn(m), np(m), pn_or_np(m);
x_is_positive = m_util.mk_is_positive(x);
x_is_negative = m_util.mk_is_negative(x);
y_is_positive = m_util.mk_is_positive(y);
y_is_negative = m_util.mk_is_negative(y);
pn = m.mk_and(x_is_positive, y_is_negative);
np = m.mk_and(x_is_negative, y_is_positive);
pn_or_np = m.mk_or(pn, np);
expr_ref c(m), v(m);
c = m.mk_and(both_are_zero, pn_or_np);
v = m.mk_app(m_util.get_family_id(), OP_FPA_MAX_UNSPECIFIED, x, y);
// Note: This requires BR_REWRITE_FULL afterwards.
expr_ref max_i(m);
max_i = m.mk_app(m_util.get_family_id(), OP_FPA_MAX_I, x, y);
m_simp.mk_ite(c, v, max_i, result);
}
void fpa2bv_converter::mk_max_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
expr * x = args[0], *y = args[1];
expr * x_sgn, *x_sig, *x_exp;
expr * y_sgn, *y_sig, *y_exp;
split_fp(x, x_sgn, x_exp, x_sig);
split_fp(y, y_sgn, y_exp, y_sig);
expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), both_zero(m), pzero(m);
mk_is_zero(x, x_is_zero);
mk_is_zero(y, y_is_zero);
m_simp.mk_and(x_is_zero, y_is_zero, both_zero);
mk_is_nan(x, x_is_nan);
mk_is_nan(y, y_is_nan);
mk_pzero(f, pzero);
expr_ref sgn_diff(m), sgn_eq(m);
sgn_eq = m.mk_eq(x_sgn, y_sgn);
sgn_diff = m.mk_not(sgn_eq);
expr_ref gt(m);
mk_float_gt(f, num, args, gt);
mk_ite(gt, x, y, result);
mk_ite(both_zero, y, result, result);
mk_ite(y_is_nan, x, result, result);
mk_ite(x_is_nan, y, result, result);
SASSERT(is_well_sorted(m, result));
}
void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 4);
SASSERT(m_util.is_bv2rm(args[0]));
@ -3147,22 +3077,13 @@ 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 nanv(m);
if (m_hi_fp_unspecified)
// The "hardware interpretation" is 01...10...01.
nanv = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1),
m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits),
m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2),
m_bv_util.mk_numeral(1, 1))));
else
mk_to_ieee_bv_unspecified(f, num, args, nanv);
expr_ref unspec(m);
mk_to_ieee_bv_unspecified(f, num, args, unspec);
expr_ref sgn_e_s(m);
join_fp(x, sgn_e_s);
m_simp.mk_ite(x_is_nan, nanv, sgn_e_s, result);
m_simp.mk_ite(x_is_nan, unspec, sgn_e_s, result);
TRACE("fpa2bv_to_ieee_bv", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;);
SASSERT(is_well_sorted(m, result));
@ -3174,26 +3095,15 @@ void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, ex
unsigned ebits = f->get_domain()[0]->get_parameter(0).get_int();
unsigned sbits = f->get_domain()[0]->get_parameter(1).get_int();
if (m_hi_fp_unspecified) {
result = m_bv_util.mk_concat(m_bv_util.mk_concat(
m_bv_util.mk_numeral(0, 1),
m_bv_util.mk_numeral(-1, ebits)),
m_bv_util.mk_numeral(1, sbits-1));
}
if (m_hi_fp_unspecified)
mk_nan(f->get_range(), result);
else {
expr * n = args[0];
expr_ref n_bv(m);
join_fp(n, n_bv);
func_decl * f_bv;
if (!m_uf2bvuf.find(f, f_bv)) {
sort * domain[2] = { m.get_sort(n_bv) };
f_bv = m.mk_fresh_func_decl(0, 1, domain, f->get_range());
m_uf2bvuf.insert(f, f_bv);
m.inc_ref(f);
m.inc_ref(f_bv);
}
sort * domain[1] = { m.get_sort(n_bv) };
func_decl * f_bv = mk_bv_uf(f, domain, f->get_range());
result = m.mk_app(f_bv, n_bv);
expr_ref exp_bv(m), exp_all_ones(m);
@ -3382,14 +3292,8 @@ void fpa2bv_converter::mk_to_bv_unspecified(func_decl * f, unsigned num, expr *
expr_ref n_bv(m);
join_fp(n, n_bv);
func_decl * f_bv;
if (!m_uf2bvuf.find(f, f_bv)) {
sort * domain[2] = { m.get_sort(rm_bv), m.get_sort(n_bv) };
f_bv = m.mk_fresh_func_decl(0, 2, domain, f->get_range());
m_uf2bvuf.insert(f, f_bv);
m.inc_ref(f);
m.inc_ref(f_bv);
}
sort * domain[2] = { m.get_sort(rm_bv), m.get_sort(n_bv) };
func_decl * f_bv = mk_bv_uf(f, domain, f->get_range());
result = m.mk_app(f_bv, rm_bv, n_bv);
}
@ -3407,14 +3311,8 @@ void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr
expr_ref n_bv(m);
join_fp(n, n_bv);
func_decl * f_bv;
if (!m_uf2bvuf.find(f, f_bv)) {
sort * domain[2] = { m.get_sort(n_bv) };
f_bv = m.mk_fresh_func_decl(0, 1, domain, f->get_range());
m_uf2bvuf.insert(f, f_bv);
m.inc_ref(f);
m.inc_ref(f_bv);
}
sort * domain[1] = { m.get_sort(n_bv) };
func_decl * f_bv = mk_bv_uf(f, domain, f->get_range());
result = m.mk_app(f_bv, n_bv);
}
}
@ -4190,13 +4088,25 @@ void fpa2bv_converter::reset(void) {
dec_ref_map_key_values(m, m_const2bv);
dec_ref_map_key_values(m, m_rm_const2bv);
dec_ref_map_key_values(m, m_uf2bvuf);
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_min_max_specials.begin();
it != m_min_max_specials.end();
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_min_max_ufs.begin();
it != m_min_max_ufs.end();
it++) {
m.dec_ref(it->m_key);
m.dec_ref(it->m_value.first);
m.dec_ref(it->m_value.second);
}
m_min_max_specials.reset();
m_min_max_ufs.reset();
m_extra_assertions.reset();
}
func_decl * fpa2bv_converter::mk_bv_uf(func_decl * f, sort * const * domain, sort * range) {
func_decl * res;
if (!m_uf2bvuf.find(f, res)) {
res = m.mk_fresh_func_decl(0, f->get_arity(), domain, range);
m_uf2bvuf.insert(f, res);
m.inc_ref(f);
m.inc_ref(res);
TRACE("fpa2bv", tout << "New UF func_decl: " << std::endl << mk_ismt2_pp(res, m) << std::endl;);
}
return res;
}

View file

@ -53,7 +53,7 @@ protected:
const2bv_t m_const2bv;
const2bv_t m_rm_const2bv;
uf2bvuf_t m_uf2bvuf;
special_t m_min_max_specials;
special_t m_min_max_ufs;
friend class fpa2bv_model_converter;
friend class bv2fpa_converter;
@ -87,7 +87,7 @@ public:
void mk_numeral(sort * s, mpf const & v, expr_ref & result);
virtual void mk_const(func_decl * f, expr_ref & result);
virtual void mk_rm_const(func_decl * f, expr_ref & result);
virtual void mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
virtual void mk_uf(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_var(unsigned base_inx, sort * srt, expr_ref & result);
void mk_pinf(func_decl * f, expr_ref & result);
@ -147,18 +147,15 @@ public:
void set_unspecified_fp_hi(bool v) { m_hi_fp_unspecified = v; }
void mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_min_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
virtual expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y);
void mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_max_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y);
void reset(void);
void dbg_decouple(const char * prefix, expr_ref & e);
expr_ref_vector m_extra_assertions;
special_t const & get_min_max_specials() const { return m_min_max_specials; };
special_t const & get_min_max_specials() const { return m_min_max_ufs; };
const2bv_t const & get_const2bv() const { return m_const2bv; };
const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; };
uf2bvuf_t const & get_uf2bvuf() const { return m_uf2bvuf; };
@ -202,12 +199,6 @@ protected:
void mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result);
sort_ref replace_float_sorts(sort * s);
func_decl_ref replace_function(func_decl * f);
expr_ref replace_float_arg(expr * a);
void mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result);
func_decl * get_bv_uf(func_decl * f, sort * bv_rng, unsigned arity);
private:
void mk_nan(sort * s, expr_ref & result);
void mk_nzero(sort * s, expr_ref & result);
@ -226,6 +217,8 @@ private:
void mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & x, expr_ref & result);
void mk_to_fp_float(sort * s, expr * rm, expr * x, expr_ref & result);
func_decl * mk_bv_uf(func_decl * f, sort * const * domain, sort * range);
};
#endif

View file

@ -124,6 +124,8 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
case OP_FPA_DIV: m_conv.mk_div(f, num, args, result); return BR_DONE;
case OP_FPA_REM: m_conv.mk_rem(f, num, args, result); return BR_DONE;
case OP_FPA_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE;
case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_DONE;
case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_DONE;
case OP_FPA_FMA: m_conv.mk_fma(f, num, args, result); return BR_DONE;
case OP_FPA_SQRT: m_conv.mk_sqrt(f, num, args, result); return BR_DONE;
case OP_FPA_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, num, args, result); return BR_DONE;
@ -147,14 +149,6 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
case OP_FPA_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE;
case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE;
case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_REWRITE_FULL;
case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_REWRITE_FULL;
case OP_FPA_MIN_UNSPECIFIED:
case OP_FPA_MAX_UNSPECIFIED: result = m_conv.mk_min_max_unspecified(f, args[0], args[1]); return BR_DONE;
case OP_FPA_MIN_I: m_conv.mk_min_i(f, num, args, result); return BR_DONE;
case OP_FPA_MAX_I: m_conv.mk_max_i(f, num, args, result); return BR_DONE;
case OP_FPA_BVWRAP:
case OP_FPA_BV2RM:
return BR_FAILED;
@ -169,7 +163,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
{
SASSERT(!m_conv.is_float_family(f));
if (m_conv.fu().contains_floats(f)) {
m_conv.mk_function(f, num, args, result);
m_conv.mk_uf(f, num, args, result);
return BR_DONE;
}
}

View file

@ -361,10 +361,6 @@ func_decl * fpa_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_parameters
case OP_FPA_REM: name = "fp.rem"; break;
case OP_FPA_MIN: name = "fp.min"; break;
case OP_FPA_MAX: name = "fp.max"; break;
case OP_FPA_MIN_I: name = "fp.min_i"; break;
case OP_FPA_MAX_I: name = "fp.max_i"; break;
case OP_FPA_MIN_UNSPECIFIED: name = "fp.min_unspecified"; break;
case OP_FPA_MAX_UNSPECIFIED: name = "fp.max_unspecified"; break;
default:
UNREACHABLE();
break;
@ -781,12 +777,6 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
case OP_FPA_BV2RM:
return mk_bv2rm(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_MIN_I:
case OP_FPA_MAX_I:
case OP_FPA_MIN_UNSPECIFIED:
case OP_FPA_MAX_UNSPECIFIED:
return mk_binary_decl(k, num_parameters, parameters, arity, domain, range);
default:
m_manager->raise_exception("unsupported floating point operator");
return 0;

View file

@ -89,11 +89,6 @@ enum fpa_op_kind {
OP_FPA_BVWRAP,
OP_FPA_BV2RM,
OP_FPA_MIN_I,
OP_FPA_MAX_I,
OP_FPA_MIN_UNSPECIFIED,
OP_FPA_MAX_UNSPECIFIED,
LAST_FLOAT_OP
};
@ -351,21 +346,12 @@ public:
}
bool is_bvwrap(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_BVWRAP); }
bool is_bvwrap(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BVWRAP; }
bool is_bv2rm(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_BV2RM); }
bool is_bv2rm(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BV2RM; }
bool is_min_interpreted(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_MIN_I); }
bool is_min_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_MIN_UNSPECIFIED); }
bool is_max_interpreted(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_MAX_I); }
bool is_max_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_MAX_UNSPECIFIED); }
bool is_to_ubv(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_TO_UBV); }
bool is_to_sbv(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_TO_SBV); }
bool is_min_interpreted(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_MIN_I; }
bool is_min_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_MIN_UNSPECIFIED; }
bool is_max_interpreted(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_MAX_I; }
bool is_max_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_MAX_UNSPECIFIED; }
bool is_bvwrap(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BVWRAP; }
bool is_bv2rm(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BV2RM; }
bool is_to_ubv(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_TO_UBV; }
bool is_to_sbv(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_TO_SBV; }

View file

@ -40,7 +40,7 @@ enum nnf_mode {
transformation will be in skolem normal form.
If a formula is too expensive to be put into NNF,
then nested quantifiers and labels are renamed.
This mode is sufficient when using E-matching.
*/
NNF_QUANT, /* A subformula is put into NNF if it contains
@ -48,7 +48,7 @@ enum nnf_mode {
quantifier. The result of the transformation will be
in skolem normal form, and the body of quantifiers
will be in NNF. If a ground formula is too expensive to
be put into NNF, then nested quantifiers and labels
be put into NNF, then nested quantifiers and labels
are renamed.
This mode is sufficient when using Superposition
@ -89,7 +89,7 @@ class skolemizer {
}
TRACE("skolemizer", tout << "skid: " << q->get_skid() << "\n";);
expr_ref_vector substitution(m());
unsigned num_decls = q->get_num_decls();
for (unsigned i = num_decls; i > 0; ) {
@ -111,7 +111,7 @@ class skolemizer {
substitution.push_back(0);
}
//
// (VAR num_decls) ... (VAR num_decls+sz-1)
// (VAR num_decls) ... (VAR num_decls+sz-1)
// are in positions num_decls .. num_decls+sz-1
//
std::reverse(substitution.c_ptr(), substitution.c_ptr() + substitution.size());
@ -139,7 +139,7 @@ class skolemizer {
s(body, substitution.size(), substitution.c_ptr(), r);
p = 0;
if (m().proofs_enabled()) {
if (q->is_forall())
if (q->is_forall())
p = m().mk_skolemization(m().mk_not(q), m().mk_not(r));
else
p = m().mk_skolemization(q, r);
@ -175,7 +175,7 @@ public:
m_cache_pr.insert(q, p);
}
}
bool is_sk_hack(expr * p) const {
SASSERT(m().is_pattern(p));
if (to_app(p)->get_num_args() != 1)
@ -204,11 +204,11 @@ struct nnf::imp {
unsigned m_i:28;
unsigned m_pol:1; // pos/neg polarity
unsigned m_in_q:1; // true if m_curr is nested in a quantifier
unsigned m_new_child:1;
unsigned m_new_child:1;
unsigned m_cache_result:1;
unsigned m_spos; // top of the result stack, when the frame was created.
frame(expr_ref& n, bool pol, bool in_q, bool cache_res, unsigned spos):
m_curr(n),
frame(expr_ref && n, bool pol, bool in_q, bool cache_res, unsigned spos):
m_curr(std::move(n)),
m_i(0),
m_pol(pol),
m_in_q(in_q),
@ -216,6 +216,16 @@ struct nnf::imp {
m_cache_result(cache_res),
m_spos(spos) {
}
frame(frame && other):
m_curr(std::move(other.m_curr)),
m_i(other.m_i),
m_pol(other.m_pol),
m_in_q(other.m_in_q),
m_new_child(other.m_new_child),
m_cache_result(other.m_cache_result),
m_spos(other.m_spos) {
}
};
// There are four caches:
@ -223,22 +233,22 @@ struct nnf::imp {
#define POS_NQ_CIDX 1 // positive polarity and not nested in a quantifier
#define NEG_Q_CIDX 2 // negative polarity and nested in a quantifier
#define POS_Q_CIDX 3 // positive polarity and nested in a quantifier
ast_manager & m_manager;
vector<frame> m_frame_stack;
expr_ref_vector m_result_stack;
typedef act_cache cache;
cache * m_cache[4];
expr_ref_vector m_todo_defs;
proof_ref_vector m_todo_proofs;
// proof generation goodness ----
proof_ref_vector m_result_pr_stack;
cache * m_cache_pr[4];
// ------------------------------
skolemizer m_skolemizer;
// configuration ----------------
@ -249,7 +259,7 @@ struct nnf::imp {
name_exprs * m_name_nested_formulas;
name_exprs * m_name_quant;
unsigned long long m_max_memory; // in bytes
imp(ast_manager & m, defined_names & n, params_ref const & p):
@ -292,9 +302,9 @@ struct nnf::imp {
m_mode = NNF_FULL;
else if (mode_sym == "quantifiers")
m_mode = NNF_QUANT;
else
else
throw nnf_params_exception("invalid NNF mode");
TRACE("nnf", tout << "nnf-mode: " << m_mode << " " << mode_sym << "\n" << _p << "\n";);
m_ignore_labels = p.ignore_labels();
@ -324,12 +334,11 @@ struct nnf::imp {
}
void push_frame(expr * t, bool pol, bool in_q, bool cache_res) {
expr_ref tr(t, m());
m_frame_stack.push_back(frame(tr, pol, in_q, cache_res, m_result_stack.size()));
m_frame_stack.push_back(frame(expr_ref(t, m()), pol, in_q, cache_res, m_result_stack.size()));
}
static unsigned get_cache_idx(bool pol, bool in_q) {
return static_cast<unsigned>(in_q) * 2 + static_cast<unsigned>(pol);
static unsigned get_cache_idx(bool pol, bool in_q) {
return static_cast<unsigned>(in_q) * 2 + static_cast<unsigned>(pol);
}
void cache_result(expr * t, bool pol, bool in_q, expr * v, proof * pr) {
@ -339,8 +348,8 @@ struct nnf::imp {
m_cache_pr[idx]->insert(t, pr);
}
expr * get_cached(expr * t, bool pol, bool in_q) const {
return m_cache[get_cache_idx(pol, in_q)]->find(t);
expr * get_cached(expr * t, bool pol, bool in_q) const {
return m_cache[get_cache_idx(pol, in_q)]->find(t);
}
proof * get_cached_pr(expr * t, bool pol, bool in_q) const {
@ -368,12 +377,12 @@ struct nnf::imp {
return false;
}
void checkpoint() {
cooperate("nnf");
if (memory::get_allocation_size() > m_max_memory)
throw nnf_exception(Z3_MAX_MEMORY_MSG);
if (m().canceled())
if (m().canceled())
throw nnf_exception(m().limit().get_cancel_msg());
}
@ -382,11 +391,11 @@ struct nnf::imp {
m_frame_stack.back().m_new_child = true;
}
void set_new_child_flag(expr * old_t, expr * new_t) {
if (old_t != new_t)
set_new_child_flag();
void set_new_child_flag(expr * old_t, expr * new_t) {
if (old_t != new_t)
set_new_child_flag();
}
void skip(expr * t, bool pol) {
expr * r = pol ? t : m().mk_not(t);
m_result_stack.push_back(r);
@ -448,10 +457,10 @@ struct nnf::imp {
if (pol) {
if (old_e->get_decl() == new_e->get_decl())
return m().mk_oeq_congruence(old_e, new_e, num_parents, parents);
else
else
return m().mk_nnf_pos(old_e, new_e, num_parents, parents);
}
else
else
return m().mk_nnf_neg(old_e, new_e, num_parents, parents);
}
@ -468,7 +477,7 @@ struct nnf::imp {
r = m().mk_and(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
else
r = m().mk_or(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
m_result_stack.shrink(fr.m_spos);
m_result_stack.push_back(r);
if (proofs_enabled()) {
@ -520,7 +529,7 @@ struct nnf::imp {
r = m().mk_or(2, m_result_stack.c_ptr() + fr.m_spos);
else
r = m().mk_and(2, m_result_stack.c_ptr() + fr.m_spos);
m_result_stack.shrink(fr.m_spos);
m_result_stack.push_back(r);
if (proofs_enabled()) {
@ -554,7 +563,7 @@ struct nnf::imp {
default:
break;
}
expr * const * rs = m_result_stack.c_ptr() + fr.m_spos;
expr * _cond = rs[0];
expr * _not_cond = rs[1];
@ -574,7 +583,7 @@ struct nnf::imp {
}
bool is_eq(app * t) const { return m().is_eq(t) || m().is_iff(t); }
bool process_iff_xor(app * t, frame & fr) {
SASSERT(t->get_num_args() == 2);
switch (fr.m_i) {
@ -605,7 +614,7 @@ struct nnf::imp {
expr * not_rhs = rs[3];
app * r;
if (is_eq(t) == fr.m_pol)
if (is_eq(t) == fr.m_pol)
r = m().mk_and(m().mk_or(not_lhs, rhs), m().mk_or(lhs, not_rhs));
else
r = m().mk_and(m().mk_or(lhs, rhs), m().mk_or(not_lhs, not_rhs));
@ -626,7 +635,7 @@ struct nnf::imp {
else
return process_default(t, fr);
}
bool process_default(app * t, frame & fr) {
SASSERT(fr.m_i == 0);
if (m_mode == NNF_FULL || t->has_quantifiers() || t->has_labels()) {
@ -636,10 +645,10 @@ struct nnf::imp {
m_name_nested_formulas->operator()(t, m_todo_defs, m_todo_proofs, n2, pr2);
else
m_name_quant->operator()(t, m_todo_defs, m_todo_proofs, n2, pr2);
if (!fr.m_pol)
n2 = m().mk_not(n2);
m_result_stack.push_back(n2);
if (proofs_enabled()) {
if (!fr.m_pol) {
@ -666,10 +675,10 @@ struct nnf::imp {
expr * arg = m_result_stack.back();
proof * arg_pr = proofs_enabled() ? m_result_pr_stack.back() : 0;
if (m_ignore_labels && !proofs_enabled())
if (m_ignore_labels && !proofs_enabled())
return true; // the result is already on the stack
buffer<symbol> names;
bool pos;
m().is_label(t, pos, names);
@ -684,7 +693,7 @@ struct nnf::imp {
pr = m().mk_transitivity(mk_proof(fr.m_pol, 1, &arg_pr, t, to_app(aux)),
m().mk_iff_oeq(m().mk_rewrite(aux, r)));
}
}
}
else {
r = arg;
if (proofs_enabled()) {
@ -692,7 +701,7 @@ struct nnf::imp {
pr = m().mk_transitivity(p1, arg_pr);
}
}
m_result_stack.pop_back();
m_result_stack.push_back(r);
if (proofs_enabled()) {
@ -729,7 +738,7 @@ struct nnf::imp {
if (m().is_label(t)) {
return process_label(t, fr);
}
return process_default(t, fr);
}
@ -737,7 +746,7 @@ struct nnf::imp {
skip(v, fr.m_pol);
return true;
}
bool process_quantifier(quantifier * q, frame & fr) {
expr_ref r(m());
proof_ref pr(m());
@ -757,7 +766,7 @@ struct nnf::imp {
if (q->is_forall() == fr.m_pol || !m_skolemize) {
expr * new_expr = m_result_stack.back();
proof * new_expr_pr = proofs_enabled() ? m_result_pr_stack.back() : 0;
ptr_buffer<expr> new_patterns;
if (q->is_forall() == fr.m_pol) {
@ -773,7 +782,7 @@ struct nnf::imp {
// New quantifier has existential force.
// So, ignore patterns
}
quantifier * new_q = 0;
proof * new_q_pr = 0;
if (fr.m_pol) {
@ -786,7 +795,7 @@ struct nnf::imp {
if (proofs_enabled())
new_q_pr = m().mk_nnf_neg(q, new_q, 1, &new_expr_pr);
}
m_result_stack.pop_back();
m_result_stack.push_back(new_q);
if (proofs_enabled()) {
@ -809,7 +818,7 @@ struct nnf::imp {
}
return true;
}
void recover_result(expr * t, expr_ref & result, proof_ref & result_pr) {
// recover result from the top of the stack.
result = m_result_stack.back();
@ -873,7 +882,7 @@ struct nnf::imp {
process(n, r, pr);
unsigned old_sz1 = new_defs.size();
unsigned old_sz2 = new_def_proofs.size();
for (unsigned i = 0; i < m_todo_defs.size(); i++) {
expr_ref dr(m());
proof_ref dpr(m());
@ -881,7 +890,7 @@ struct nnf::imp {
new_defs.push_back(dr);
if (proofs_enabled()) {
proof * new_pr = m().mk_modus_ponens(m_todo_proofs.get(i), dpr);
new_def_proofs.push_back(new_pr);
new_def_proofs.push_back(new_pr);
}
}
std::reverse(new_defs.c_ptr() + old_sz1, new_defs.c_ptr() + new_defs.size());
@ -898,7 +907,7 @@ nnf::nnf(ast_manager & m, defined_names & n, params_ref const & p) {
nnf::~nnf() {
dealloc(m_imp);
}
void nnf::operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & p) {
m_imp->operator()(n, new_defs, new_def_proofs, r, p);
TRACE("nnf_result", tout << mk_ismt2_pp(n, m_imp->m()) << "\nNNF result:\n" << mk_ismt2_pp(r, m_imp->m()) << "\n";);

View file

@ -179,11 +179,11 @@ expr_pattern_match::compile(expr* q)
}
if (m_regs.size() <= max_reg) {
m_regs.resize(max_reg+1, 0);
m_regs.resize(max_reg+1);
}
if (m_bound_dom.size() <= num_bound) {
m_bound_dom.resize(num_bound+1, 0);
m_bound_rng.resize(num_bound+1, 0);
m_bound_dom.resize(num_bound+1);
m_bound_rng.resize(num_bound+1);
}
instr.m_kind = YIELD;

View file

@ -272,7 +272,7 @@ void bit_blaster_tpl<Cfg>::mk_multiplier(unsigned sz, expr * const * a_bits, exp
zero = m().mk_false();
vector< expr_ref_vector > pps;
pps.resize(sz, m());
pps.resize(sz, expr_ref_vector(m()));
for (unsigned i = 0; i < sz; i++) {
checkpoint();

View file

@ -94,12 +94,6 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
case OP_FPA_TO_IEEE_BV: SASSERT(num_args == 1); st = mk_to_ieee_bv(f, args[0], result); break;
case OP_FPA_TO_REAL: SASSERT(num_args == 1); st = mk_to_real(args[0], result); break;
case OP_FPA_MIN_I:SASSERT(num_args == 2); st = mk_min_i(f, args[0], args[1], result); break;
case OP_FPA_MAX_I: SASSERT(num_args == 2); st = mk_max_i(f, args[0], args[1], result); break;
case OP_FPA_MIN_UNSPECIFIED:
case OP_FPA_MAX_UNSPECIFIED:
SASSERT(num_args == 2); st = BR_FAILED; break;
case OP_FPA_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break;
case OP_FPA_BV2RM: SASSERT(num_args == 1); st = mk_bv2rm(args[0], result); break;
@ -131,11 +125,10 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const
const mpz & sm1 = m_fm.m_powers2(sbits - 1);
const mpz & em1 = m_fm.m_powers2(ebits);
scoped_mpq q(mpqm);
mpqm.set(q, r1.to_mpq());
SASSERT(mpzm.is_one(q.get().denominator()));
const mpq & q = r1.to_mpq();
SASSERT(mpzm.is_one(q.denominator()));
scoped_mpz z(mpzm);
z = q.get().numerator();
z = q.numerator();
mpzm.rem(z, sm1, sig);
mpzm.div(z, sm1, z);
@ -385,38 +378,13 @@ br_status fpa_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) {
}
scoped_mpf v1(m_fm), v2(m_fm);
if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2)) {
result = m().mk_app(get_fid(), OP_FPA_MIN_UNSPECIFIED, arg1, arg2);
return BR_REWRITE1;
}
else {
scoped_mpf r(m_fm);
m_fm.minimum(v1, v2, r);
result = m_util.mk_value(r);
return BR_DONE;
}
}
else {
expr_ref c(m()), v(m());
c = m().mk_and(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)),
m().mk_or(m().mk_and(m_util.mk_is_positive(arg1), m_util.mk_is_negative(arg2)),
m().mk_and(m_util.mk_is_negative(arg1), m_util.mk_is_positive(arg2))));
v = m().mk_app(get_fid(), OP_FPA_MIN_UNSPECIFIED, arg1, arg2);
result = m().mk_ite(c, v, m().mk_app(get_fid(), OP_FPA_MIN_I, arg1, arg2));
return BR_REWRITE_FULL;
}
}
br_status fpa_rewriter::mk_min_i(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) {
scoped_mpf v1(m_fm), v2(m_fm);
if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2))
result = m().mk_app(get_fid(), OP_FPA_MIN_UNSPECIFIED, arg1, arg2);
else
result = m_util.mk_min(arg1, arg2);
return BR_FAILED;
scoped_mpf r(m_fm);
m_fm.minimum(v1, v2, r);
result = m_util.mk_value(r);
return BR_DONE;
}
@ -434,38 +402,13 @@ br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) {
}
scoped_mpf v1(m_fm), v2(m_fm);
if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2)) {
result = m().mk_app(get_fid(), OP_FPA_MAX_UNSPECIFIED, arg1, arg2);
return BR_REWRITE1;
}
else {
scoped_mpf r(m_fm);
m_fm.maximum(v1, v2, r);
result = m_util.mk_value(r);
return BR_DONE;
}
}
else {
expr_ref c(m()), v(m());
c = m().mk_and(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)),
m().mk_or(m().mk_and(m_util.mk_is_positive(arg1), m_util.mk_is_negative(arg2)),
m().mk_and(m_util.mk_is_negative(arg1), m_util.mk_is_positive(arg2))));
v = m().mk_app(get_fid(), OP_FPA_MAX_UNSPECIFIED, arg1, arg2);
result = m().mk_ite(c, v, m().mk_app(get_fid(), OP_FPA_MAX_I, arg1, arg2));
return BR_REWRITE_FULL;
}
}
br_status fpa_rewriter::mk_max_i(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) {
scoped_mpf v1(m_fm), v2(m_fm);
if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2))
result = m().mk_app(get_fid(), OP_FPA_MIN_UNSPECIFIED, arg1, arg2);
else
result = m_util.mk_max(arg1, arg2);
return BR_FAILED;
scoped_mpf r(m_fm);
m_fm.maximum(v1, v2, r);
result = m_util.mk_value(r);
return BR_DONE;
}

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

@ -42,6 +42,10 @@ void rewriter_tpl<Config>::process_var(var * v) {
unsigned index = m_bindings.size() - idx - 1;
var * r = (var*)(m_bindings[index]);
if (r != 0) {
CTRACE("rewriter", v->get_sort() != m().get_sort(r),
tout << expr_ref(v, m()) << ":" << sort_ref(v->get_sort(), m()) << " != " << expr_ref(r, m()) << ":" << sort_ref(m().get_sort(r), m());
tout << "index " << index << " bindings " << m_bindings.size() << "\n";
display_bindings(tout););
SASSERT(v->get_sort() == m().get_sort(r));
if (!is_ground(r) && m_shifts[index] != m_bindings.size()) {

View file

@ -256,7 +256,7 @@ void substitution_tree::insert(expr * new_expr) {
sort * s = to_var(new_expr)->get_sort();
unsigned id = s->get_decl_id();
if (id >= m_vars.size())
m_vars.resize(id+1, 0);
m_vars.resize(id+1);
if (m_vars[id] == 0)
m_vars[id] = alloc(var_ref_vector, m_manager);
var_ref_vector * v = m_vars[id];
@ -277,7 +277,7 @@ void substitution_tree::insert(app * new_expr) {
unsigned id = d->get_decl_id();
if (id >= m_roots.size())
m_roots.resize(id+1, 0);
m_roots.resize(id+1);
if (!m_roots[id]) {
// there is no tree for the function symbol heading new_expr

View file

@ -58,7 +58,7 @@ void used_vars::process(expr * n, unsigned delta) {
if (idx >= delta) {
idx = idx - delta;
if (idx >= m_found_vars.size())
m_found_vars.resize(idx + 1, 0);
m_found_vars.resize(idx + 1);
m_found_vars[idx] = to_var(n)->get_sort();
}
break;

View file

@ -202,7 +202,7 @@ func_decl * func_decls::find(unsigned arity, sort * const * domain, sort * range
if (f->get_arity() != arity)
continue;
unsigned i = 0;
for (i = 0; i < arity; i++) {
for (i = 0; domain && i < arity; i++) {
if (f->get_domain(i) != domain[i])
break;
}
@ -774,7 +774,6 @@ bool cmd_context::is_func_decl(symbol const & s) const {
}
void cmd_context::insert(symbol const & s, func_decl * f) {
m_check_sat_result = 0;
if (!m_check_logic(f)) {
throw cmd_exception(m_check_logic.get_last_error());
}
@ -805,7 +804,6 @@ void cmd_context::insert(symbol const & s, func_decl * f) {
}
void cmd_context::insert(symbol const & s, psort_decl * p) {
m_check_sat_result = 0;
if (m_psort_decls.contains(s)) {
throw cmd_exception("sort already defined ", s);
}
@ -819,7 +817,6 @@ void cmd_context::insert(symbol const & s, psort_decl * p) {
void cmd_context::insert(symbol const & s, unsigned arity, sort *const* domain, expr * t) {
expr_ref _t(t, m());
m_check_sat_result = 0;
if (m_builtin_decls.contains(s)) {
throw cmd_exception("invalid macro/named expression, builtin symbol ", s);
}
@ -870,6 +867,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)");
}
@ -937,7 +940,7 @@ static builtin_decl const & peek_builtin_decl(builtin_decl const & first, family
func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices,
unsigned arity, sort * const * domain, sort * range) const {
builtin_decl d;
if (m_builtin_decls.find(s, d)) {
if (domain && m_builtin_decls.find(s, d)) {
family_id fid = d.m_fid;
decl_kind k = d.m_decl;
// Hack: if d.m_next != 0, we use domain[0] (if available) to decide which plugin we use.
@ -961,7 +964,7 @@ func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices,
return f;
}
if (contains_macro(s, arity, domain))
if (domain && contains_macro(s, arity, domain))
throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s);
if (num_indices > 0)
@ -1545,6 +1548,26 @@ void cmd_context::reset_assertions() {
}
void cmd_context::display_dimacs() {
if (m_solver) {
try {
gparams::set("sat.dimacs.display", "true");
params_ref p;
m_solver->updt_params(p);
m_solver->check_sat(0, nullptr);
}
catch (...) {
gparams::set("sat.dimacs.display", "false");
params_ref p;
m_solver->updt_params(p);
throw;
}
gparams::set("sat.dimacs.display", "false");
params_ref p;
m_solver->updt_params(p);
}
}
void cmd_context::display_model(model_ref& mdl) {
if (mdl) {
model_params p;
@ -1582,7 +1605,9 @@ void cmd_context::validate_check_sat_result(lbool r) {
throw cmd_exception("check annotation that says unsat");
#else
diagnostic_stream() << "BUG: incompleteness" << std::endl;
exit(ERR_INCOMPLETENESS);
// WORKAROUND: `exit()` causes LSan to be invoked and produce
// many false positives.
_Exit(ERR_INCOMPLETENESS);
#endif
}
break;
@ -1592,7 +1617,9 @@ void cmd_context::validate_check_sat_result(lbool r) {
throw cmd_exception("check annotation that says sat");
#else
diagnostic_stream() << "BUG: unsoundness" << std::endl;
exit(ERR_UNSOUNDNESS);
// WORKAROUND: `exit()` causes LSan to be invoked and produce
// many false positives.
_Exit(ERR_UNSOUNDNESS);
#endif
}
break;
@ -1743,6 +1770,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

@ -419,6 +419,7 @@ public:
void display_assertions();
void display_statistics(bool show_total_time = false, double total_time = 0.0);
void display_dimacs();
void reset(bool finalize = false);
void assert_expr(expr * t);
void assert_expr(symbol const & name, expr * t);

View file

@ -31,7 +31,6 @@ Notes:
#include "ast/rewriter/var_subst.h"
#include "util/gparams.h"
#ifndef _EXTERNAL_RELEASE
BINARY_SYM_CMD(get_quantifier_body_cmd,
"dbg-get-qbody",
@ -343,10 +342,19 @@ public:
}
};
#endif
class print_dimacs_cmd : public cmd {
public:
print_dimacs_cmd():cmd("display-dimacs") {}
virtual char const * get_usage() const { return ""; }
virtual char const * get_descr(cmd_context & ctx) const { return "print benchmark in DIMACS format"; }
virtual unsigned get_arity() const { return 0; }
virtual void prepare(cmd_context & ctx) {}
virtual void execute(cmd_context & ctx) { ctx.display_dimacs(); }
};
void install_dbg_cmds(cmd_context & ctx) {
#ifndef _EXTERNAL_RELEASE
ctx.insert(alloc(print_dimacs_cmd));
ctx.insert(alloc(get_quantifier_body_cmd));
ctx.insert(alloc(set_cmd));
ctx.insert(alloc(pp_var_cmd));
@ -369,5 +377,4 @@ void install_dbg_cmds(cmd_context & ctx) {
ctx.insert(alloc(instantiate_cmd));
ctx.insert(alloc(instantiate_nested_cmd));
ctx.insert(alloc(set_next_id));
#endif
}

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

@ -24,6 +24,7 @@ Revision History:
#include "math/automata/symbolic_automata.h"
#include "util/hashtable.h"
#include "util/vector.h"
@ -311,7 +312,7 @@ symbolic_automata<T, M>::mk_determinstic_param(automaton_t& a, bool flip_accepta
s2id.insert(set, p_state_id++); // the index to the initial state is 0
id2s.push_back(set);
svector<uint_set> todo; //States to visit
::vector<uint_set> todo; //States to visit
todo.push_back(set);
uint_set state;

View file

@ -162,7 +162,7 @@ private:
void checkpoint();
public:
interval_manager(reslimit& lim, C const & c);
interval_manager(reslimit& lim, C && c);
~interval_manager();
numeral_manager & m() const { return m_c.m(); }

View file

@ -31,7 +31,7 @@ Revision History:
// #define TRACE_NTH_ROOT
template<typename C>
interval_manager<C>::interval_manager(reslimit& lim, C const & c): m_limit(lim), m_c(c) {
interval_manager<C>::interval_manager(reslimit& lim, C && c): m_limit(lim), m_c(std::move(c)) {
m().set(m_minus_one, -1);
m().set(m_one, 1);
m_pi_n = 0;

View file

@ -2632,10 +2632,14 @@ namespace algebraic_numbers {
scoped_mpz neg_n(qm());
qm().set(neg_n, v.numerator());
qm().neg(neg_n);
mpz const coeffs[2] = { neg_n.get(), v.denominator() };
unsynch_mpz_manager zmgr;
// FIXME: remove these copies
mpz coeffs[2] = { zmgr.dup(neg_n.get()), zmgr.dup(v.denominator()) };
out << "(";
upm().display(out, 2, coeffs, "#");
out << ", 1)"; // first root of the polynomial d*# - n
zmgr.del(coeffs[0]);
zmgr.del(coeffs[1]);
}
else {
algebraic_cell * c = a.to_algebraic();
@ -2678,10 +2682,14 @@ namespace algebraic_numbers {
scoped_mpz neg_n(qm());
qm().set(neg_n, v.numerator());
qm().neg(neg_n);
mpz const coeffs[2] = { neg_n.get(), v.denominator() };
unsynch_mpz_manager zmgr;
// FIXME: remove these copies
mpz coeffs[2] = { zmgr.dup(neg_n.get()), zmgr.dup(v.denominator()) };
out << "(root-obj ";
upm().display_smt2(out, 2, coeffs, "x");
out << " 1)"; // first root of the polynomial d*# - n
zmgr.del(coeffs[0]);
zmgr.del(coeffs[1]);
}
else {
algebraic_cell * c = a.to_algebraic();

View file

@ -3536,10 +3536,11 @@ namespace polynomial {
iccp(p, max_var(p), i, c, pp);
}
void pp(polynomial const * p, var x, polynomial_ref & pp) {
polynomial_ref pp(polynomial const * p, var x) {
scoped_numeral i(m_manager);
polynomial_ref c(pm());
iccp(p, x, i, c, pp);
polynomial_ref c(pm()), result(pm());
iccp(p, x, i, c, result);
return result;
}
bool is_primitive(polynomial const * p, var x) {
@ -3598,7 +3599,7 @@ namespace polynomial {
if (is_zero(rem)) {
TRACE("polynomial", tout << "rem is zero...\npp_v: " << pp_v << "\n";);
flip_sign_if_lm_neg(pp_v);
pp(pp_v, x, r);
r = pp(pp_v, x);
r = mul(d_a, d_r, r);
return;
}
@ -3849,7 +3850,7 @@ namespace polynomial {
TRACE("mgcd", tout << "new combined:\n" << C_star << "\n";);
}
}
pp(C_star, x, candidate);
candidate = pp(C_star, x);
TRACE("mgcd", tout << "candidate:\n" << candidate << "\n";);
scoped_numeral lc_candidate(m());
lc_candidate = univ_coeff(candidate, degree(candidate, x));
@ -4821,10 +4822,9 @@ namespace polynomial {
polynomial * mk_x_minus_y(var x, var y) {
numeral zero(0);
numeral one(1);
numeral minus_one; // It is not safe to initialize with -1 when numeral_manager is GF_2
m_manager.set(minus_one, -1);
numeral as[2] = { one, minus_one };
numeral as[2] = { numeral(1), std::move(minus_one) };
var xs[2] = { x, y };
return mk_linear(2, as, xs, zero);
}
@ -4844,8 +4844,7 @@ namespace polynomial {
polynomial * mk_x_plus_y(var x, var y) {
numeral zero(0);
numeral one(1);
numeral as[2] = { one, one };
numeral as[2] = { numeral(1), numeral(1) };
var xs[2] = { x, y };
return mk_linear(2, as, xs, zero);
}
@ -6619,8 +6618,8 @@ namespace polynomial {
polynomial_ref cf1(pm()); m_wrapper.content(f1, x, cf1);
polynomial_ref cf2(pm()); m_wrapper.content(f2, x, cf2);
tout << "content(f1): " << cf1 << "\ncontent(f2): " << cf2 << "\n";);
pp(f1, x, f1);
pp(f2, x, f2);
f1 = pp(f1, x);
f2 = pp(f2, x);
TRACE("factor", tout << "f1: " << f1 << "\nf2: " << f2 << "\n";);
DEBUG_CODE({
polynomial_ref f1f2(pm());
@ -7150,7 +7149,7 @@ namespace polynomial {
}
void manager::primitive(polynomial const * p, var x, polynomial_ref & pp) {
m_imp->pp(p, x, pp);
pp = m_imp->pp(p, x);
}
void manager::icpp(polynomial const * p, var x, numeral & i, polynomial_ref & c, polynomial_ref & pp) {

View file

@ -45,7 +45,7 @@ namespace upolynomial {
for (unsigned i = 0; i < p.size(); ++ i) {
numeral p_i; // no need to delete, we keep it pushed in zp_p
zp_nm.set(p_i, p[i]);
zp_p.push_back(p_i);
zp_p.push_back(std::move(p_i));
}
zp_upm.trim(zp_p);
}

View file

@ -35,7 +35,7 @@ namespace simplex {
struct row_entry {
numeral m_coeff;
var_t m_var;
row_entry(numeral const& c, var_t v): m_coeff(c), m_var(v) {}
row_entry(numeral && c, var_t v) : m_coeff(std::move(c)), m_var(v) {}
};
private:
@ -61,7 +61,7 @@ namespace simplex {
int m_col_idx;
int m_next_free_row_entry_idx;
};
_row_entry(numeral const & c, var_t v): row_entry(c, v), m_col_idx(0) {}
_row_entry(numeral && c, var_t v) : row_entry(std::move(c), v), m_col_idx(0) {}
_row_entry() : row_entry(numeral(), dead_id), m_col_idx(0) {}
bool is_dead() const { return row_entry::m_var == dead_id; }
};

View file

@ -739,7 +739,7 @@ void context_t<C>::del_sum(polynomial * p) {
template<typename C>
var context_t<C>::mk_sum(numeral const & c, unsigned sz, numeral const * as, var const * xs) {
m_num_buffer.reserve(num_vars(), numeral());
m_num_buffer.reserve(num_vars());
for (unsigned i = 0; i < sz; i++) {
SASSERT(xs[i] < num_vars());
nm().set(m_num_buffer[xs[i]], as[i]);

View file

@ -117,7 +117,7 @@ bool func_interp::is_fi_entry_expr(expr * e, ptr_vector<expr> & args) {
(m_arity > 1 && (!m().is_and(c) || to_app(c)->get_num_args() != m_arity)))
return false;
args.resize(m_arity, 0);
args.resize(m_arity);
for (unsigned i = 0; i < m_arity; i++) {
expr * ci = (m_arity == 1 && i == 0) ? c : to_app(c)->get_arg(i);
@ -140,7 +140,6 @@ void func_interp::set_else(expr * e) {
return;
reset_interp_cache();
ptr_vector<expr> args;
while (e && is_fi_entry_expr(e, args)) {
TRACE("func_interp", tout << "fi entry expr: " << mk_ismt2_pp(e, m()) << std::endl;);

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

@ -453,7 +453,8 @@ namespace datalog {
return new_pred;
}
void context::add_rule(expr* rl, symbol const& name, unsigned bound) {
void context::add_rule(expr* rl, symbol const& name, unsigned bound) {
SASSERT(rl);
m_rule_fmls.push_back(rl);
m_rule_names.push_back(name);
m_rule_bounds.push_back(bound);

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

@ -189,11 +189,12 @@ public:
m_bound = bound;
m_arg_idx++;
}
virtual void reset(cmd_context & ctx) { m_dl_ctx->reset(); prepare(ctx); }
virtual void reset(cmd_context & ctx) { m_dl_ctx->reset(); prepare(ctx); m_t = nullptr; }
virtual void prepare(cmd_context& ctx) { m_arg_idx = 0; m_name = symbol::null; m_bound = UINT_MAX; }
virtual void finalize(cmd_context & ctx) {
}
virtual void execute(cmd_context & ctx) {
if (!m_t) throw cmd_exception("invalid rule, expected formula");
m_dl_ctx->add_rule(m_t, m_name, m_bound);
}
};

View file

@ -128,7 +128,7 @@ namespace datalog {
void set_reg(reg_idx i, reg_type val) {
if (i >= m_registers.size()) {
check_overflow(i);
m_registers.resize(i+1,0);
m_registers.resize(i+1);
}
if (m_registers[i]) {
m_registers[i]->deallocate();

View file

@ -465,7 +465,7 @@ namespace datalog {
unsigned sz = r.get_signature().size();
ptr_vector<expr> subst_arg;
subst_arg.resize(sz, 0);
subst_arg.resize(sz);
unsigned ofs = sz-1;
for (unsigned i=0; i<sz; i++) {
SASSERT(!r.is_undefined(i) || !contains_var(m_new_rule, i));

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

@ -66,7 +66,6 @@ class peq {
app_ref m_peq; // partial equality application
app_ref m_eq; // equivalent std equality using def. of partial eq
array_util m_arr_u;
ast_eq_proc m_eq_proc; // for checking if two asts are equal
public:
static const char* PARTIAL_EQ;
@ -102,7 +101,7 @@ peq::peq (app* p, ast_manager& m):
VERIFY (is_partial_eq (p));
SASSERT (m_arr_u.is_array (m_lhs) &&
m_arr_u.is_array (m_rhs) &&
m_eq_proc (m.get_sort (m_lhs), m.get_sort (m_rhs)));
ast_eq_proc() (m.get_sort (m_lhs), m.get_sort (m_rhs)));
for (unsigned i = 2; i < p->get_num_args (); i++) {
m_diff_indices.push_back (p->get_arg (i));
}
@ -121,7 +120,7 @@ peq::peq (expr* lhs, expr* rhs, unsigned num_indices, expr * const * diff_indice
{
SASSERT (m_arr_u.is_array (lhs) &&
m_arr_u.is_array (rhs) &&
m_eq_proc (m.get_sort (lhs), m.get_sort (rhs)));
ast_eq_proc() (m.get_sort (lhs), m.get_sort (rhs)));
ptr_vector<sort> sorts;
sorts.push_back (m.get_sort (m_lhs));
sorts.push_back (m.get_sort (m_rhs));

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

@ -24,6 +24,7 @@ Revision History:
#include "ast/ast_pp.h"
#include "ast/well_sorted.h"
#include "ast/rewriter/rewriter.h"
#include "ast/rewriter/var_subst.h"
#include "ast/has_free_vars.h"
#include "ast/ast_smt2_pp.h"
#include "parsers/smt2/smt2parser.h"
@ -68,6 +69,7 @@ namespace smt2 {
scoped_ptr<bv_util> m_bv_util;
scoped_ptr<arith_util> m_arith_util;
scoped_ptr<datatype_util> m_datatype_util;
scoped_ptr<seq_util> m_seq_util;
scoped_ptr<pattern_validator> m_pattern_validator;
scoped_ptr<var_shifter> m_var_shifter;
@ -108,6 +110,7 @@ namespace smt2 {
symbol m_check_sat_assuming;
symbol m_define_fun_rec;
symbol m_define_funs_rec;
symbol m_match;
symbol m_underscore;
typedef std::pair<symbol, expr*> named_expr;
@ -135,7 +138,7 @@ namespace smt2 {
typedef psort_frame sort_frame;
enum expr_frame_kind { EF_APP, EF_LET, EF_LET_DECL, EF_QUANT, EF_ATTR_EXPR, EF_PATTERN };
enum expr_frame_kind { EF_APP, EF_LET, EF_LET_DECL, EF_MATCH, EF_QUANT, EF_ATTR_EXPR, EF_PATTERN };
struct expr_frame {
expr_frame_kind m_kind;
@ -172,6 +175,10 @@ namespace smt2 {
m_expr_spos(expr_spos) {}
};
struct match_frame : public expr_frame {
match_frame():expr_frame(EF_MATCH) {}
};
struct let_frame : public expr_frame {
bool m_in_decls;
unsigned m_sym_spos;
@ -275,6 +282,12 @@ namespace smt2 {
return *(m_arith_util.get());
}
datatype_util & dtutil() {
if (m_datatype_util.get() == 0)
m_datatype_util = alloc(datatype_util, m());
return *(m_datatype_util.get());
}
seq_util & sutil() {
if (m_seq_util.get() == 0)
m_seq_util = alloc(seq_util, m());
@ -389,6 +402,7 @@ namespace smt2 {
bool curr_id_is_underscore() const { SASSERT(curr_is_identifier()); return curr_id() == m_underscore; }
bool curr_id_is_as() const { SASSERT(curr_is_identifier()); return curr_id() == m_as; }
bool curr_id_is_match() const { SASSERT(curr_is_identifier()); return curr_id() == m_match; }
bool curr_id_is_forall() const { SASSERT(curr_is_identifier()); return curr_id() == m_forall; }
bool curr_id_is_exists() const { SASSERT(curr_is_identifier()); return curr_id() == m_exists; }
bool curr_id_is_bang() const { SASSERT(curr_is_identifier()); return curr_id() == m_bang; }
@ -430,7 +444,10 @@ namespace smt2 {
m_ctx.regular_stream()<< "line " << line << " column " << pos << ": " << escaped(msg, true) << "\")" << std::endl;
}
if (m_ctx.exit_on_error()) {
exit(1);
// WORKAROUND: ASan's LeakSanitizer reports many false positives when
// calling `exit()` so call `_Exit()` instead which avoids invoking leak
// checking.
_Exit(1);
}
}
@ -1258,6 +1275,23 @@ namespace smt2 {
return num;
}
void push_let_frame() {
next();
check_lparen_next("invalid let declaration, '(' expected");
void * mem = m_stack.allocate(sizeof(let_frame));
new (mem) let_frame(symbol_stack().size(), expr_stack().size());
m_num_expr_frames++;
}
void push_bang_frame(expr_frame * curr) {
TRACE("consume_attributes", tout << "begin bang, expr_stack.size(): " << expr_stack().size() << "\n";);
next();
void * mem = m_stack.allocate(sizeof(attr_expr_frame));
new (mem) attr_expr_frame(curr, symbol_stack().size(), expr_stack().size());
m_num_expr_frames++;
}
void push_quant_frame(bool is_forall) {
SASSERT(curr_is_identifier());
SASSERT(curr_id_is_forall() || curr_id_is_exists());
@ -1273,6 +1307,202 @@ namespace smt2 {
throw parser_exception("invalid quantifier, list of sorted variables is empty");
}
/**
* SMT-LIB 2.6 pattern matches are of the form
* (match t ((p1 t1) ... (pm+1 tm+1)))
*/
void push_match_frame() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_match);
next();
void * mem = m_stack.allocate(sizeof(match_frame));
new (mem) match_frame();
unsigned num_frames = m_num_expr_frames;
parse_expr();
expr_ref t(expr_stack().back(), m());
expr_stack().pop_back();
expr_ref_vector patterns(m()), cases(m());
sort* srt = m().get_sort(t);
check_lparen_next("pattern bindings should be enclosed in a parenthesis");
while (!curr_is_rparen()) {
m_env.begin_scope();
unsigned num_bindings = m_num_bindings;
check_lparen_next("invalid pattern binding, '(' expected");
parse_match_pattern(srt);
patterns.push_back(expr_stack().back());
expr_stack().pop_back();
parse_expr();
cases.push_back(expr_stack().back());
expr_stack().pop_back();
m_num_bindings = num_bindings;
m_env.end_scope();
check_rparen_next("invalid pattern binding, ')' expected");
}
next();
m_num_expr_frames = num_frames + 1;
expr_stack().push_back(compile_patterns(t, patterns, cases));
}
void pop_match_frame(match_frame* fr) {
m_stack.deallocate(fr);
m_num_expr_frames--;
}
expr_ref compile_patterns(expr* t, expr_ref_vector const& patterns, expr_ref_vector const& cases) {
expr_ref result(m());
var_subst sub(m(), false);
TRACE("parse_expr", tout << "term\n" << expr_ref(t, m()) << "\npatterns\n" << patterns << "\ncases\n" << cases << "\n";);
check_patterns(patterns, m().get_sort(t));
for (unsigned i = patterns.size(); i > 0; ) {
--i;
expr_ref_vector subst(m());
expr_ref cond = bind_match(t, patterns[i], subst);
expr_ref new_case(m());
if (subst.empty()) {
new_case = cases[i];
}
else {
sub(cases[i], subst.size(), subst.c_ptr(), new_case);
inv_var_shifter inv(m());
inv(new_case, subst.size(), new_case);
}
if (result) {
result = m().mk_ite(cond, new_case, result);
}
else {
// pattern match binding is ignored.
result = new_case;
}
}
TRACE("parse_expr", tout << result << "\n";);
return result;
}
void check_patterns(expr_ref_vector const& patterns, sort* s) {
if (!dtutil().is_datatype(s))
throw parser_exception("pattern matching is only supported for algebraic datatypes");
ptr_vector<func_decl> const& cons = *dtutil().get_datatype_constructors(s);
for (expr * arg : patterns) if (is_var(arg)) return;
if (patterns.size() < cons.size())
throw parser_exception("non-exhaustive pattern match");
ast_fast_mark1 marked;
for (expr * arg : patterns)
marked.mark(to_app(arg)->get_decl(), true);
for (func_decl * f : cons)
if (!marked.is_marked(f))
throw parser_exception("a constructor is missing from pattern match");
}
// compute match condition and substitution
// t is shifted by size of subst.
expr_ref bind_match(expr* t, expr* pattern, expr_ref_vector& subst) {
expr_ref tsh(m());
if (is_var(pattern)) {
shifter()(t, 1, tsh);
subst.push_back(tsh);
return expr_ref(m().mk_true(), m());
}
else {
SASSERT(is_app(pattern));
func_decl * f = to_app(pattern)->get_decl();
func_decl * r = dtutil().get_constructor_recognizer(f);
ptr_vector<func_decl> const * acc = dtutil().get_constructor_accessors(f);
shifter()(t, acc->size(), tsh);
for (func_decl* a : *acc) {
subst.push_back(m().mk_app(a, tsh));
}
return expr_ref(m().mk_app(r, t), m());
}
}
/**
* parse a match pattern
* (C x1 .... xn)
* C
* _
* x
*/
bool parse_constructor_pattern(sort * srt) {
if (!curr_is_lparen()) {
return false;
}
next();
svector<symbol> vars;
expr_ref_vector args(m());
symbol C(check_identifier_next("constructor symbol expected"));
while (!curr_is_rparen()) {
symbol v(check_identifier_next("variable symbol expected"));
if (v != m_underscore && vars.contains(v)) {
throw parser_exception("unexpected repeated variable in pattern expression");
}
vars.push_back(v);
}
next();
// now have C, vars
// look up constructor C,
// create bound variables based on constructor type.
// store expression in expr_stack().
// ensure that bound variables are adjusted to vars
func_decl* f = m_ctx.find_func_decl(C, 0, nullptr, vars.size(), nullptr, srt);
if (!f) {
throw parser_exception("expecting a constructor that has been declared");
}
if (!dtutil().is_constructor(f)) {
throw parser_exception("expecting a constructor");
}
if (f->get_arity() != vars.size()) {
throw parser_exception("mismatching number of variables supplied to constructor");
}
m_num_bindings += vars.size();
for (unsigned i = 0; i < vars.size(); ++i) {
var * v = m().mk_var(i, f->get_domain(i));
args.push_back(v);
if (vars[i] != m_underscore) {
m_env.insert(vars[i], local(v, m_num_bindings));
}
}
expr_stack().push_back(m().mk_app(f, args.size(), args.c_ptr()));
return true;
}
void parse_match_pattern(sort* srt) {
if (parse_constructor_pattern(srt)) {
// done
}
else if (curr_id() == m_underscore) {
// we have a wild-card.
// store dummy variable in expr_stack()
next();
var* v = m().mk_var(0, srt);
expr_stack().push_back(v);
}
else {
symbol xC(check_identifier_next("constructor symbol or variable expected"));
// check if xC is a constructor, otherwise make it a variable
// of sort srt.
try {
func_decl* f = m_ctx.find_func_decl(xC, 0, nullptr, 0, nullptr, srt);
if (!dtutil().is_constructor(f)) {
throw parser_exception("expecting a constructor, got a previously declared function");
}
if (f->get_arity() > 0) {
throw parser_exception("constructor expects arguments, but no arguments were supplied in pattern");
}
expr_stack().push_back(m().mk_const(f));
}
catch (cmd_exception &) {
var* v = m().mk_var(0, srt);
expr_stack().push_back(v);
m_env.insert(xC, local(v, m_num_bindings++));
}
}
}
symbol parse_indexed_identifier_core() {
check_underscore_next("invalid indexed identifier, '_' expected");
check_identifier("invalid indexed identifier, symbol expected");
@ -1564,8 +1794,7 @@ namespace smt2 {
new (mem) app_frame(f, expr_spos, param_spos, has_as);
m_num_expr_frames++;
}
// return true if a new frame was created.
void push_expr_frame(expr_frame * curr) {
SASSERT(curr_is_lparen());
next();
@ -1573,11 +1802,7 @@ namespace smt2 {
if (curr_is_identifier()) {
TRACE("push_expr_frame", tout << "push_expr_frame(), curr_id(): " << curr_id() << "\n";);
if (curr_id_is_let()) {
next();
check_lparen_next("invalid let declaration, '(' expected");
void * mem = m_stack.allocate(sizeof(let_frame));
new (mem) let_frame(symbol_stack().size(), expr_stack().size());
m_num_expr_frames++;
push_let_frame();
}
else if (curr_id_is_forall()) {
push_quant_frame(true);
@ -1586,19 +1811,17 @@ namespace smt2 {
push_quant_frame(false);
}
else if (curr_id_is_bang()) {
TRACE("consume_attributes", tout << "begin bang, expr_stack.size(): " << expr_stack().size() << "\n";);
next();
void * mem = m_stack.allocate(sizeof(attr_expr_frame));
new (mem) attr_expr_frame(curr, symbol_stack().size(), expr_stack().size());
m_num_expr_frames++;
push_bang_frame(curr);
}
else if (curr_id_is_as() || curr_id_is_underscore()) {
TRACE("push_expr_frame", tout << "push_expr_frame(): parse_qualified_name\n";);
parse_qualified_name();
}
else if (curr_id_is_root_obj()) {
parse_root_obj();
}
else if (curr_id_is_match()) {
push_match_frame();
}
else {
push_app_frame();
}
@ -1658,6 +1881,8 @@ namespace smt2 {
// the resultant expression is on the top of the stack
TRACE("let_frame", tout << "let result expr: " << mk_pp(expr_stack().back(), m()) << "\n";);
expr_ref r(m());
if (expr_stack().empty())
throw parser_exception("invalid let expression");
r = expr_stack().back();
expr_stack().pop_back();
// remove local declarations from the stack
@ -1773,6 +1998,9 @@ namespace smt2 {
m_stack.deallocate(static_cast<let_decl_frame*>(fr));
m_num_expr_frames--;
break;
case EF_MATCH:
pop_match_frame(static_cast<match_frame*>(fr));
break;
case EF_QUANT:
pop_quant_frame(static_cast<quant_frame*>(fr));
break;
@ -2232,8 +2460,10 @@ namespace smt2 {
throw cmd_exception("invalid assert command, expression required as argument");
}
expr * f = expr_stack().back();
if (!m().is_bool(f))
if (!m().is_bool(f)) {
TRACE("smt2parser", tout << expr_ref(f, m()) << "\n";);
throw cmd_exception("invalid assert command, term is not Boolean");
}
if (f == m_last_named_expr.second) {
m_ctx.assert_expr(m_last_named_expr.first, f);
}
@ -2730,6 +2960,7 @@ namespace smt2 {
m_check_sat_assuming("check-sat-assuming"),
m_define_fun_rec("define-fun-rec"),
m_define_funs_rec("define-funs-rec"),
m_match("match"),
m_underscore("_"),
m_num_open_paren(0),
m_current_file(filename) {

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');

View file

@ -1272,7 +1272,7 @@ namespace qe {
family_id fid = p->get_family_id();
SASSERT(fid != null_family_id);
if (static_cast<int>(m_plugins.size()) <= fid) {
m_plugins.resize(fid+1,0);
m_plugins.resize(fid+1);
}
SASSERT(!m_plugins[fid]);
m_plugins[fid] = p;

View file

@ -105,10 +105,10 @@ namespace qe {
rational r;
app* alit = to_app(lit);
vector<std::pair<expr*,rational> > nums;
for (unsigned i = 0; i < alit->get_num_args(); ++i) {
val = eval(alit->get_arg(i));
for (expr* arg : *alit) {
val = eval(arg);
if (!a.is_numeral(val, r)) return false;
nums.push_back(std::make_pair(alit->get_arg(i), r));
nums.push_back(std::make_pair(arg, r));
}
std::sort(nums.begin(), nums.end(), compare_second());
for (unsigned i = 0; i + 1 < nums.size(); ++i) {
@ -168,8 +168,8 @@ namespace qe {
}
else if (a.is_add(t)) {
app* ap = to_app(t);
for (unsigned i = 0; i < ap->get_num_args(); ++i) {
linearize(mbo, eval, mul, ap->get_arg(i), c, fmls, ts, tids);
for (expr* arg : *ap) {
linearize(mbo, eval, mul, arg, c, fmls, ts, tids);
}
}
else if (a.is_sub(t, t1, t2)) {
@ -226,16 +226,16 @@ namespace qe {
else if (a.is_mul(t)) {
app* ap = to_app(t);
r = rational(1);
for (unsigned i = 0; i < ap->get_num_args(); ++i) {
if (!is_numeral(ap->get_arg(i), r1)) return false;
for (expr * arg : *ap) {
if (!is_numeral(arg, r1)) return false;
r *= r1;
}
}
else if (a.is_add(t)) {
app* ap = to_app(t);
r = rational(0);
for (unsigned i = 0; i < ap->get_num_args(); ++i) {
if (!is_numeral(ap->get_arg(i), r1)) return false;
for (expr * arg : *ap) {
if (!is_numeral(arg, r1)) return false;
r += r1;
}
}
@ -297,6 +297,7 @@ namespace qe {
opt::model_based_opt mbo;
obj_map<expr, unsigned> tids;
expr_ref_vector pinned(m);
unsigned j = 0;
for (unsigned i = 0; i < fmls.size(); ++i) {
expr* fml = fmls[i].get();
@ -308,6 +309,7 @@ namespace qe {
}
else {
TRACE("qe", tout << mk_pp(fml, m) << "\n";);
pinned.push_back(fml);
}
}
fmls.resize(j);
@ -321,8 +323,7 @@ namespace qe {
// return those to fmls.
expr_mark var_mark, fmls_mark;
for (unsigned i = 0; i < vars.size(); ++i) {
app* v = vars[i].get();
for (app * v : vars) {
var_mark.mark(v);
if (is_arith(v) && !tids.contains(v)) {
rational r;
@ -332,17 +333,16 @@ namespace qe {
tids.insert(v, mbo.add_var(r, a.is_int(v)));
}
}
for (unsigned i = 0; i < fmls.size(); ++i) {
fmls_mark.mark(fmls[i].get());
for (expr* fml : fmls) {
fmls_mark.mark(fml);
}
obj_map<expr, unsigned>::iterator it = tids.begin(), end = tids.end();
ptr_vector<expr> index2expr;
for (; it != end; ++it) {
expr* e = it->m_key;
for (auto& kv : tids) {
expr* e = kv.m_key;
if (!var_mark.is_marked(e)) {
mark_rec(fmls_mark, e);
}
index2expr.setx(it->m_value, e, 0);
index2expr.setx(kv.m_value, e, 0);
}
j = 0;
unsigned_vector real_vars;
@ -360,8 +360,7 @@ namespace qe {
}
vars.resize(j);
TRACE("qe", tout << "remaining vars: " << vars << "\n";
for (unsigned i = 0; i < real_vars.size(); ++i) {
unsigned v = real_vars[i];
for (unsigned v : real_vars) {
tout << "v" << v << " " << mk_pp(index2expr[v], m) << "\n";
}
mbo.display(tout););
@ -449,8 +448,8 @@ namespace qe {
// extract linear constraints
for (unsigned i = 0; i < fmls.size(); ++i) {
linearize(mbo, eval, fmls[i].get(), fmls, tids);
for (expr * fml : fmls) {
linearize(mbo, eval, fml, fmls, tids);
}
// find optimal value
@ -459,11 +458,10 @@ namespace qe {
// update model to use new values that satisfy optimality
ptr_vector<expr> vars;
obj_map<expr, unsigned>::iterator it = tids.begin(), end = tids.end();
for (; it != end; ++it) {
expr* e = it->m_key;
for (auto& kv : tids) {
expr* e = kv.m_key;
if (is_uninterp_const(e)) {
unsigned id = it->m_value;
unsigned id = kv.m_value;
func_decl* f = to_app(e)->get_decl();
expr_ref val(a.mk_numeral(mbo.get_value(id), false), m);
mdl.register_decl(f, val);
@ -509,10 +507,9 @@ namespace qe {
void extract_coefficients(opt::model_based_opt& mbo, model_evaluator& eval, obj_map<expr, rational> const& ts, obj_map<expr, unsigned>& tids, vars& coeffs) {
coeffs.reset();
eval.set_model_completion(true);
obj_map<expr, rational>::iterator it = ts.begin(), end = ts.end();
for (; it != end; ++it) {
for (auto& kv : ts) {
unsigned id;
expr* v = it->m_key;
expr* v = kv.m_key;
if (!tids.find(v, id)) {
rational r;
expr_ref val = eval(v);
@ -520,9 +517,9 @@ namespace qe {
id = mbo.add_var(r, a.is_int(v));
tids.insert(v, id);
}
CTRACE("qe", it->m_value.is_zero(), tout << mk_pp(v, m) << " has coefficeint 0\n";);
if (!it->m_value.is_zero()) {
coeffs.push_back(var(id, it->m_value));
CTRACE("qe", kv.m_value.is_zero(), tout << mk_pp(v, m) << " has coefficeint 0\n";);
if (!kv.m_value.is_zero()) {
coeffs.push_back(var(id, kv.m_value));
}
}
}

View file

@ -35,7 +35,7 @@ namespace sat {
m_glue("glue"),
m_glue_psm("glue_psm"),
m_psm_glue("psm_glue") {
m_num_parallel = 1;
m_num_parallel = 1;
updt_params(p);
}
@ -114,6 +114,7 @@ namespace sat {
m_core_minimize = p.core_minimize();
m_core_minimize_partial = p.core_minimize_partial();
m_dyn_sub_res = p.dyn_sub_res();
m_dimacs_display = p.dimacs_display();
}
void config::collect_param_descrs(param_descrs & r) {

View file

@ -74,6 +74,7 @@ namespace sat {
bool m_core_minimize;
bool m_core_minimize_partial;
bool m_dimacs_display;
symbol m_always_true;
symbol m_always_false;

View file

@ -23,4 +23,5 @@ def_module_params('sat',
('core.minimize', BOOL, False, 'minimize computed core'),
('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'),
('parallel_threads', UINT, 1, 'number of parallel threads to use'),
('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks')))
('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'),
('dimacs.display', BOOL, False, 'display SAT instance in DIMACS format and return unknown instead of solving')))

Some files were not shown because too many files have changed in this diff Show more