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

View file

@ -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. * ``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. * ``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. 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. 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 ## Build status
| Windows x86 | Windows x64 | Ubuntu x64 | Ubuntu x86 | Debian x64 | OSX | TravisCI | | Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | OSX | TravisCI |
| ----------- | ----------- | ---------- | ---------- | ---------- | --- | -------- | | ----------- | ----------- | ---------- | ---------- | --- | -------- |
[![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![ubuntu-x86-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/6/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=6) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3)
[1]: #building-z3-on-windows-using-visual-studio-command-prompt [1]: #building-z3-on-windows-using-visual-studio-command-prompt
[2]: #building-z3-using-make-and-gccclang [2]: #building-z3-using-make-and-gccclang
@ -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 [pkg-config](http://www.freedesktop.org/wiki/Software/pkg-config/) file
(``Microsoft.Z3.Sharp.pc``) is also installed which allows the (``Microsoft.Z3.Sharp.pc``) is also installed which allows the
[MonoDevelop](http://www.monodevelop.com/) IDE to find the bindings. Running [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. 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/) a [Python virtual environment](https://virtualenv.readthedocs.org/en/latest/)
and install Z3 there. Python packages also work for Python3. and install Z3 there. Python packages also work for Python3.
Under Windows, recall to build inside the Visual C++ native command build environment. 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 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. and it depends on ``libz3.dll`` to be in the path.
```bash ```bash
virtualenv venv virtualenv venv

View file

@ -30,6 +30,7 @@ RUN apt-get update && \
libgomp1 \ libgomp1 \
libomp5 \ libomp5 \
libomp-dev \ libomp-dev \
llvm-3.9 \
make \ make \
mono-devel \ mono-devel \
ninja-build \ ninja-build \
@ -47,4 +48,4 @@ RUN useradd -m user && \
echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers
USER user USER user
WORKDIR /home/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 \ libgmp-dev \
libgomp1 \ libgomp1 \
lib32gomp1 \ lib32gomp1 \
llvm-3.9 \
make \ make \
mono-devel \ mono-devel \
ninja-build \ ninja-build \
@ -32,4 +33,4 @@ RUN useradd -m user && \
echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers
USER user USER user
WORKDIR /home/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 \ libgomp1 \
libomp5 \ libomp5 \
libomp-dev \ libomp-dev \
llvm-3.9 \
make \ make \
mono-devel \ mono-devel \
ninja-build \ ninja-build \
@ -35,4 +36,4 @@ RUN useradd -m user && \
echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers
USER user USER user
WORKDIR /home/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} FROM ${DOCKER_IMAGE_BASE}
# Specify defaults. This can be changed when invoking # Build arguments. This can be changed when invoking
# `docker build`. # `docker build`.
ARG ASAN_BUILD=0 ARG ASAN_BUILD
ARG BUILD_DOCS=0 ARG ASAN_DSO
ARG CC=gcc ARG BUILD_DOCS
ARG CXX=g++ ARG CC
ARG DOTNET_BINDINGS=1 ARG CXX
ARG JAVA_BINDINGS=1 ARG DOTNET_BINDINGS
ARG NO_SUPPRESS_OUTPUT=0 ARG JAVA_BINDINGS
ARG PYTHON_BINDINGS=1 ARG NO_SUPPRESS_OUTPUT
ARG PYTHON_BINDINGS
ARG PYTHON_EXECUTABLE=/usr/bin/python2.7 ARG PYTHON_EXECUTABLE=/usr/bin/python2.7
ARG RUN_SYSTEM_TESTS=1 ARG RUN_API_EXAMPLES
ARG RUN_UNIT_TESTS=1 ARG RUN_SYSTEM_TESTS
ARG TARGET_ARCH=x86_64 ARG RUN_UNIT_TESTS
ARG TEST_INSTALL=1 ARG SANITIZER_PRINT_SUPPRESSIONS
ARG UBSAN_BUILD=0 ARG TARGET_ARCH
ARG USE_LIBGMP=0 ARG TEST_INSTALL
ARG USE_LTO=0 ARG UBSAN_BUILD
ARG USE_OPENMP=1 ARG USE_LIBGMP
ARG USE_LTO
ARG USE_OPENMP
ARG Z3_SRC_DIR=/home/user/z3_src ARG Z3_SRC_DIR=/home/user/z3_src
ARG Z3_BUILD_TYPE=RelWithDebInfo ARG Z3_BUILD_TYPE
ARG Z3_CMAKE_GENERATOR=Ninja ARG Z3_CMAKE_GENERATOR
ARG Z3_INSTALL_PREFIX=/usr ARG Z3_INSTALL_PREFIX
ARG Z3_STATIC_BUILD=0 ARG Z3_STATIC_BUILD
# Blank default indicates use latest.
ARG Z3_SYSTEM_TEST_GIT_REVISION ARG Z3_SYSTEM_TEST_GIT_REVISION
ARG Z3_WARNINGS_AS_ERRORS=SERIOUS_ONLY ARG Z3_WARNINGS_AS_ERRORS
ARG Z3_VERBOSE_BUILD_OUTPUT=0 ARG Z3_VERBOSE_BUILD_OUTPUT
ENV \ ENV \
ASAN_BUILD=${ASAN_BUILD} \ ASAN_BUILD=${ASAN_BUILD} \
ASAN_DSO=${ASAN_DSO} \
BUILD_DOCS=${BUILD_DOCS} \ BUILD_DOCS=${BUILD_DOCS} \
CC=${CC} \ CC=${CC} \
CXX=${CXX} \ CXX=${CXX} \
@ -41,6 +44,8 @@ ENV \
NO_SUPPRESS_OUTPUT=${NO_SUPPRESS_OUTPUT} \ NO_SUPPRESS_OUTPUT=${NO_SUPPRESS_OUTPUT} \
PYTHON_BINDINGS=${PYTHON_BINDINGS} \ PYTHON_BINDINGS=${PYTHON_BINDINGS} \
PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} \ PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} \
SANITIZER_PRINT_SUPPRESSIONS=${SANITIZER_PRINT_SUPPRESSIONS} \
RUN_API_EXAMPLES=${RUN_API_EXAMPLES} \
RUN_SYSTEM_TESTS=${RUN_SYSTEM_TESTS} \ RUN_SYSTEM_TESTS=${RUN_SYSTEM_TESTS} \
RUN_UNIT_TESTS=${RUN_UNIT_TESTS} \ RUN_UNIT_TESTS=${RUN_UNIT_TESTS} \
TARGET_ARCH=${TARGET_ARCH} \ TARGET_ARCH=${TARGET_ARCH} \
@ -51,6 +56,7 @@ ENV \
USE_OPENMP=${USE_OPENMP} \ USE_OPENMP=${USE_OPENMP} \
Z3_SRC_DIR=${Z3_SRC_DIR} \ Z3_SRC_DIR=${Z3_SRC_DIR} \
Z3_BUILD_DIR=/home/user/z3_build \ Z3_BUILD_DIR=/home/user/z3_build \
Z3_BUILD_TYPE=${Z3_BUILD_TYPE} \
Z3_CMAKE_GENERATOR=${Z3_CMAKE_GENERATOR} \ Z3_CMAKE_GENERATOR=${Z3_CMAKE_GENERATOR} \
Z3_VERBOSE_BUILD_OUTPUT=${Z3_VERBOSE_BUILD_OUTPUT} \ Z3_VERBOSE_BUILD_OUTPUT=${Z3_VERBOSE_BUILD_OUTPUT} \
Z3_STATIC_BUILD=${Z3_STATIC_BUILD} \ Z3_STATIC_BUILD=${Z3_STATIC_BUILD} \
@ -63,7 +69,8 @@ ENV \
# Build Z3 # Build Z3
RUN mkdir -p "${Z3_SRC_DIR}" && \ 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` # Deliberately leave out `contrib`
ADD /cmake ${Z3_SRC_DIR}/cmake/ ADD /cmake ${Z3_SRC_DIR}/cmake/
ADD /doc ${Z3_SRC_DIR}/doc/ ADD /doc ${Z3_SRC_DIR}/doc/
@ -74,6 +81,7 @@ ADD *.txt *.md RELEASE_NOTES ${Z3_SRC_DIR}/
ADD \ ADD \
/contrib/ci/scripts/build_z3_cmake.sh \ /contrib/ci/scripts/build_z3_cmake.sh \
/contrib/ci/scripts/ci_defaults.sh \
/contrib/ci/scripts/set_compiler_flags.sh \ /contrib/ci/scripts/set_compiler_flags.sh \
/contrib/ci/scripts/set_generator_args.sh \ /contrib/ci/scripts/set_generator_args.sh \
${Z3_SRC_DIR}/contrib/ci/scripts/ ${Z3_SRC_DIR}/contrib/ci/scripts/
@ -89,7 +97,13 @@ RUN ${Z3_SRC_DIR}/contrib/ci/scripts/test_z3_docs.sh
# Test examples # Test examples
ADD \ ADD \
/contrib/ci/scripts/test_z3_examples_cmake.sh \ /contrib/ci/scripts/test_z3_examples_cmake.sh \
/contrib/ci/scripts/sanitizer_env.sh \
${Z3_SRC_DIR}/contrib/ci/scripts/ ${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 ${Z3_SRC_DIR}/contrib/ci/scripts/test_z3_examples_cmake.sh
# Run unit tests # Run unit tests

View file

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

View file

@ -22,6 +22,7 @@ set -o pipefail
: ${USE_LTO?"USE_LTO must be specified"} : ${USE_LTO?"USE_LTO must be specified"}
: ${Z3_INSTALL_PREFIX?"Z3_INSTALL_PREFIX must be specified"} : ${Z3_INSTALL_PREFIX?"Z3_INSTALL_PREFIX must be specified"}
: ${Z3_WARNINGS_AS_ERRORS?"Z3_WARNINGS_AS_ERRORS must be specified"} : ${Z3_WARNINGS_AS_ERRORS?"Z3_WARNINGS_AS_ERRORS must be specified"}
: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"}
ADDITIONAL_Z3_OPTS=() ADDITIONAL_Z3_OPTS=()
@ -105,6 +106,16 @@ fi
# Set compiler flags # Set compiler flags
source ${SCRIPT_DIR}/set_compiler_flags.sh 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 # Sanity check
if [ ! -e "${Z3_SRC_DIR}/CMakeLists.txt" ]; then if [ ! -e "${Z3_SRC_DIR}/CMakeLists.txt" ]; then
echo "Z3_SRC_DIR is invalid" 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 fi
# Clean up # Clean up
rm "${STDOUT}" "${STDERR}" rm "${STDOUT}" "${STDERR}"
[ $( echo "${OLD_SETTINGS}" | grep -c 'e') -ne 0 ] && set -e [ "$( echo "${OLD_SETTINGS}" | grep -c 'e')" != "0" ] && set -e
[ $( echo "${OLD_SETTINGS}" | grep -c 'x') -ne 0 ] && set -x [ "$( echo "${OLD_SETTINGS}" | grep -c 'x')" != "0" ] && set -x
return ${EXIT_STATUS} return ${EXIT_STATUS}
fi 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 # scripts and should not be executed directly
: ${Z3_CMAKE_GENERATOR?"Z3_CMAKE_GENERATOR must be specified"} : ${Z3_CMAKE_GENERATOR?"Z3_CMAKE_GENERATOR must be specified"}

View file

@ -14,6 +14,13 @@ set -o pipefail
: ${PYTHON_EXECUTABLE?"PYTHON_EXECUTABLE must be specified"} : ${PYTHON_EXECUTABLE?"PYTHON_EXECUTABLE must be specified"}
: ${DOTNET_BINDINGS?"DOTNET_BINDINGS must be specified"} : ${DOTNET_BINDINGS?"DOTNET_BINDINGS must be specified"}
: ${JAVA_BINDINGS?"JAVA_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 # Set compiler flags
source ${SCRIPT_DIR}/set_compiler_flags.sh source ${SCRIPT_DIR}/set_compiler_flags.sh
@ -21,6 +28,9 @@ source ${SCRIPT_DIR}/set_compiler_flags.sh
# Set CMake generator args # Set CMake generator args
source ${SCRIPT_DIR}/set_generator_args.sh source ${SCRIPT_DIR}/set_generator_args.sh
# Sanitizer environment variables
source ${SCRIPT_DIR}/sanitizer_env.sh
cd "${Z3_BUILD_DIR}" cd "${Z3_BUILD_DIR}"
# Build and run C example # Build and run C example
@ -38,9 +48,21 @@ run_quiet examples/tptp_build_dir/z3_tptp5 -help
# Build an run c_maxsat_example # Build an run c_maxsat_example
cmake --build $(pwd) --target c_maxsat_example "${GENERATOR_ARGS[@]}" cmake --build $(pwd) --target c_maxsat_example "${GENERATOR_ARGS[@]}"
run_quiet \ # FIXME: It is known that the maxsat example leaks memory and the
examples/c_maxsat_example_build_dir/c_maxsat_example \ # the Z3 developers have stated this is "wontfix".
${Z3_SRC_DIR}/examples/maxsat/ex.smt # 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 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 # `all_interval_series.py` produces a lot of output so just throw
# away output. # away output.
# TODO: This example is slow should we remove it from testing? # TODO: This example is slow should we remove it from testing?
run_quiet ${PYTHON_EXECUTABLE} python/all_interval_series.py if [ "X${ASAN_BUILD}" = "X1" -a "X${Z3_BUILD_TYPE}" = "XDebug" ]; then
run_quiet ${PYTHON_EXECUTABLE} python/complex.py # Too slow when doing ASan Debug build
run_quiet ${PYTHON_EXECUTABLE} python/example.py 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. # FIXME: `hamiltonian.py` example is disabled because its too slow.
#${PYTHON_EXECUTABLE} python/hamiltonian.py #${PYTHON_EXECUTABLE} python/hamiltonian.py
run_quiet ${PYTHON_EXECUTABLE} python/marco.py run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/marco.py
run_quiet ${PYTHON_EXECUTABLE} python/mss.py run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/mss.py
run_quiet ${PYTHON_EXECUTABLE} python/socrates.py run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/socrates.py
run_quiet ${PYTHON_EXECUTABLE} python/visitor.py run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/visitor.py
run_quiet ${PYTHON_EXECUTABLE} python/z3test.py run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/z3test.py
fi fi
if [ "X${DOTNET_BINDINGS}" = "X1" ]; then if [ "X${DOTNET_BINDINGS}" = "X1" ]; then
@ -65,7 +92,7 @@ if [ "X${DOTNET_BINDINGS}" = "X1" ]; then
# FIXME: Move compliation step into CMake target # 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 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 .NET example
run_quiet mono ./dotnet_test.exe run_quiet run_non_native_binding mono ./dotnet_test.exe
fi fi
if [ "X${JAVA_BINDINGS}" = "X1" ]; then if [ "X${JAVA_BINDINGS}" = "X1" ]; then
@ -82,6 +109,14 @@ if [ "X${JAVA_BINDINGS}" = "X1" ]; then
# Assume Linux for now # Assume Linux for now
export LD_LIBRARY_PATH=$(pwd):${LD_LIBRARY_PATH} export LD_LIBRARY_PATH=$(pwd):${LD_LIBRARY_PATH}
fi 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 fi

View file

@ -10,12 +10,17 @@ set -o pipefail
: ${PYTHON_BINDINGS?"PYTHON_BINDINGS must be specified"} : ${PYTHON_BINDINGS?"PYTHON_BINDINGS must be specified"}
: ${PYTHON_EXECUTABLE?"PYTHON_EXECUTABLE must be specified"} : ${PYTHON_EXECUTABLE?"PYTHON_EXECUTABLE must be specified"}
: ${Z3_SYSTEM_TEST_DIR?"Z3_SYSTEM_TEST_DIR 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 if [ "X${RUN_SYSTEM_TESTS}" != "X1" ]; then
echo "Skipping system tests" echo "Skipping system tests"
exit 0 exit 0
fi 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_EXE="${Z3_BUILD_DIR}/z3"
Z3_LIB_DIR="${Z3_BUILD_DIR}" 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}" Z3_SYSTEM_TEST_GIT_URL="${Z3_GIT_URL:-https://github.com/Z3Prover/z3test.git}"
# Clone repo to destination # 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}" git clone "${Z3_SYSTEM_TEST_GIT_URL}" "${Z3_SYSTEM_TEST_DIR}"
cd "${Z3_SYSTEM_TEST_DIR}" cd "${Z3_SYSTEM_TEST_DIR}"
@ -48,7 +53,18 @@ fi
if [ "X${PYTHON_BINDINGS}" = "X1" ]; then if [ "X${PYTHON_BINDINGS}" = "X1" ]; then
# Run python binding tests # 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 fi
# FIXME: Run `scripts/test_cs.py` once it has been modified to support mono # 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"} : ${Z3_BUILD_DIR?"Z3_BUILD_DIR must be specified"}
: ${RUN_UNIT_TESTS?"RUN_UNIT_TESTS must be specified"} : ${RUN_UNIT_TESTS?"RUN_UNIT_TESTS must be specified"}
if [ "X${RUN_UNIT_TESTS}" != "X1" ]; then
echo "Skipping unit tests"
exit 0
fi
# Set CMake generator args # Set CMake generator args
source ${SCRIPT_DIR}/set_generator_args.sh source ${SCRIPT_DIR}/set_generator_args.sh
# Sanitizer environment variables
source ${SCRIPT_DIR}/sanitizer_env.sh
cd "${Z3_BUILD_DIR}" cd "${Z3_BUILD_DIR}"
# Build and run internal tests function build_unit_tests() {
cmake --build $(pwd) --target test-z3 "${GENERATOR_ARGS[@]}" # Build internal tests
# Run all tests that don't require arguments cmake --build $(pwd) --target test-z3 "${GENERATOR_ARGS[@]}"
run_quiet ./test-z3 /a }
function run_unit_tests() {
# Run all tests that don't require arguments
run_quiet ./test-z3 /a
}
case "${RUN_UNIT_TESTS}" in
BUILD_AND_RUN)
build_unit_tests
run_unit_tests
;;
BUILD_ONLY)
build_unit_tests
;;
SKIP)
echo "RUN_UNIT_TESTS set to \"${RUN_UNIT_TESTS}\" so skipping build and run"
exit 0
;;
*)
echo "Error: RUN_UNIT_TESTS set to unhandled value \"${RUN_UNIT_TESTS}\""
exit 1
;;
esac

View file

@ -11,16 +11,21 @@ DOCKER_FILE_DIR="$(cd ${SCRIPT_DIR}/../Dockerfiles; echo $PWD)"
: ${LINUX_BASE?"LINUX_BASE must be specified"} : ${LINUX_BASE?"LINUX_BASE must be specified"}
# Sanity check. Current working directory should be repo root # Sanity check. Current working directory should be repo root
if [ ! -f "./README.md" ]; then if [ ! -f "./README.md" ]; then
echo "Current working directory should be repo root" echo "Current working directory should be repo root"
exit 1 exit 1
fi fi
# Get defaults
source "${SCRIPT_DIR}/ci_defaults.sh"
BUILD_OPTS=() BUILD_OPTS=()
# Override options if they have been provided. # Pass Docker build arguments
# Otherwise the defaults in the Docker file will be used if [ -n "${Z3_BUILD_TYPE}" ]; then
BUILD_OPTS+=("--build-arg" "Z3_BUILD_TYPE=${Z3_BUILD_TYPE}")
fi
if [ -n "${Z3_CMAKE_GENERATOR}" ]; then if [ -n "${Z3_CMAKE_GENERATOR}" ]; then
BUILD_OPTS+=("--build-arg" "Z3_CMAKE_GENERATOR=${Z3_CMAKE_GENERATOR}") BUILD_OPTS+=("--build-arg" "Z3_CMAKE_GENERATOR=${Z3_CMAKE_GENERATOR}")
fi fi
@ -79,6 +84,14 @@ if [ -n "${ASAN_BUILD}" ]; then
BUILD_OPTS+=("--build-arg" "ASAN_BUILD=${ASAN_BUILD}") BUILD_OPTS+=("--build-arg" "ASAN_BUILD=${ASAN_BUILD}")
fi 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 if [ -n "${UBSAN_BUILD}" ]; then
BUILD_OPTS+=("--build-arg" "UBSAN_BUILD=${UBSAN_BUILD}") BUILD_OPTS+=("--build-arg" "UBSAN_BUILD=${UBSAN_BUILD}")
fi fi
@ -87,6 +100,10 @@ if [ -n "${TEST_INSTALL}" ]; then
BUILD_OPTS+=("--build-arg" "TEST_INSTALL=${TEST_INSTALL}") BUILD_OPTS+=("--build-arg" "TEST_INSTALL=${TEST_INSTALL}")
fi fi
if [ -n "${RUN_API_EXAMPLES}" ]; then
BUILD_OPTS+=("--build-arg" "RUN_API_EXAMPLES=${RUN_API_EXAMPLES}")
fi
if [ -n "${RUN_SYSTEM_TESTS}" ]; then if [ -n "${RUN_SYSTEM_TESTS}" ]; then
BUILD_OPTS+=("--build-arg" "RUN_SYSTEM_TESTS=${RUN_SYSTEM_TESTS}") BUILD_OPTS+=("--build-arg" "RUN_SYSTEM_TESTS=${RUN_SYSTEM_TESTS}")
fi fi

View file

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

View file

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

View file

@ -7,6 +7,30 @@ else()
set(EXTERNAL_PROJECT_BUILD_ALWAYS_ARG "") set(EXTERNAL_PROJECT_BUILD_ALWAYS_ARG "")
endif() 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 # Build example project using libz3's C API as an external project
################################################################################ ################################################################################
@ -14,7 +38,10 @@ ExternalProject_Add(c_example
DEPENDS libz3 DEPENDS libz3
# Configure step # Configure step
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/c" 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 # Build step
${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG}
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/c_example_build_dir" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/c_example_build_dir"
@ -30,7 +57,10 @@ ExternalProject_Add(c_maxsat_example
DEPENDS libz3 DEPENDS libz3
# Configure step # Configure step
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/maxsat" 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 # Build step
${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG}
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/c_maxsat_example_build_dir" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/c_maxsat_example_build_dir"
@ -47,7 +77,9 @@ ExternalProject_Add(cpp_example
DEPENDS libz3 DEPENDS libz3
# Configure step # Configure step
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/c++" 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 # Build step
${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG}
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/cpp_example_build_dir" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/cpp_example_build_dir"
@ -63,7 +95,9 @@ ExternalProject_Add(z3_tptp5
DEPENDS libz3 DEPENDS libz3
# Configure step # Configure step
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tptp" 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 # Build step
${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG}
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/tptp_build_dir" 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}") message(STATUS "Z3_DIR: ${Z3_DIR}")
add_executable(c_example test_capi.c) 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_include_directories(c_example PRIVATE ${Z3_C_INCLUDE_DIRS})
target_link_libraries(c_example PRIVATE ${Z3_LIBRARIES}) 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); longjmp(g_catch_buffer, e);
} }
/**
\brief Error handling that depends on checking an error code on the context.
*/
void nothrow_z3_error(Z3_context c, Z3_error_code e) {
// no-op
}
/** /**
\brief Create a logical context. \brief Create a logical context.
@ -1592,18 +1601,16 @@ void error_code_example1()
void error_code_example2() { void error_code_example2() {
Z3_config cfg; Z3_config cfg;
Z3_context ctx = NULL; Z3_context ctx = NULL;
int r; Z3_error_code e;
printf("\nerror_code_example2\n"); printf("\nerror_code_example2\n");
LOG_MSG("error_code_example2"); LOG_MSG("error_code_example2");
/* low tech try&catch */ if (1) {
r = setjmp(g_catch_buffer);
if (r == 0) {
Z3_ast x, y, app; Z3_ast x, y, app;
cfg = Z3_mk_config(); cfg = Z3_mk_config();
ctx = mk_context_custom(cfg, throw_z3_error); ctx = mk_context_custom(cfg, nothrow_z3_error);
Z3_del_config(cfg); Z3_del_config(cfg);
x = mk_int_var(ctx, "x"); x = mk_int_var(ctx, "x");
@ -1611,11 +1618,14 @@ void error_code_example2() {
printf("before Z3_mk_iff\n"); printf("before Z3_mk_iff\n");
/* the next call will produce an error */ /* the next call will produce an error */
app = Z3_mk_iff(ctx, x, y); app = Z3_mk_iff(ctx, x, y);
e = Z3_get_error_code(ctx);
if (e != Z3_OK) goto err;
unreachable(); unreachable();
Z3_del_context(ctx); Z3_del_context(ctx);
} }
else { else {
printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, (Z3_error_code)r)); err:
printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e));
if (ctx != NULL) { if (ctx != NULL) {
Z3_del_context(ctx); Z3_del_context(ctx);
} }
@ -1781,15 +1791,14 @@ void parser_example5() {
Z3_config cfg; Z3_config cfg;
Z3_context ctx = NULL; Z3_context ctx = NULL;
Z3_solver s = NULL; Z3_solver s = NULL;
int r; Z3_error_code e;
printf("\nparser_example5\n"); printf("\nparser_example5\n");
LOG_MSG("parser_example5"); LOG_MSG("parser_example5");
r = setjmp(g_catch_buffer); if (1) {
if (r == 0) {
cfg = Z3_mk_config(); cfg = Z3_mk_config();
ctx = mk_context_custom(cfg, throw_z3_error); ctx = mk_context_custom(cfg, nothrow_z3_error);
s = mk_solver(ctx); s = mk_solver(ctx);
Z3_del_config(cfg); Z3_del_config(cfg);
@ -1798,12 +1807,15 @@ void parser_example5() {
"(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))", "(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))",
0, 0, 0, 0, 0, 0,
0, 0, 0); 0, 0, 0);
e = Z3_get_error_code(ctx);
if (e != Z3_OK) goto err;
unreachable(); unreachable();
del_solver(ctx, s); del_solver(ctx, s);
Z3_del_context(ctx); Z3_del_context(ctx);
} }
else { else {
printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, (Z3_error_code)r)); err:
printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e));
if (ctx != NULL) { if (ctx != NULL) {
printf("Error message: '%s'.\n",Z3_get_smtlib_error(ctx)); printf("Error message: '%s'.\n",Z3_get_smtlib_error(ctx));
del_solver(ctx, s); del_solver(ctx, s);
@ -2639,6 +2651,7 @@ void smt2parser_example() {
ctx = mk_context(); 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); 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)); printf("formulas: %s\n", Z3_ast_to_string(ctx, fs));
Z3_del_context(ctx); 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_include_directories(c_maxsat_example PRIVATE ${Z3_C_INCLUDE_DIRS})
target_link_libraries(c_maxsat_example PRIVATE ${Z3_LIBRARIES}) 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") if ("${CMAKE_SYSTEM_NAME}" MATCHES "[Ww]indows")
# On Windows we need to copy the Z3 libraries # On Windows we need to copy the Z3 libraries
# into the same directory as the executable # into the same directory as the executable

View file

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

View file

@ -34,6 +34,19 @@ extern "C" {
Z3_CATCH_RETURN(0); 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_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i) {
Z3_TRY; Z3_TRY;
LOG_Z3_mk_select(c, a, i); LOG_Z3_mk_select(c, a, i);
@ -57,6 +70,35 @@ extern "C" {
Z3_CATCH_RETURN(0); 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_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v) {
Z3_TRY; Z3_TRY;
LOG_Z3_mk_store(c, a, i, v); LOG_Z3_mk_store(c, a, i, v);
@ -82,6 +124,37 @@ extern "C" {
Z3_CATCH_RETURN(0); 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_ast Z3_API Z3_mk_map(Z3_context c, Z3_func_decl f, unsigned n, Z3_ast const* args) {
Z3_TRY; Z3_TRY;
LOG_Z3_mk_map(c, f, n, args); 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_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); 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) { Z3_ast Z3_mk_set_member(Z3_context c, Z3_ast elem, Z3_ast set) {
return Z3_mk_select(c, set, elem); return Z3_mk_select(c, set, elem);
} }
@ -222,7 +307,8 @@ extern "C" {
CHECK_VALID_AST(t, 0); CHECK_VALID_AST(t, 0);
if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() &&
to_sort(t)->get_decl_kind() == ARRAY_SORT) { 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); RETURN_Z3(r);
} }
SET_ERROR_CODE(Z3_INVALID_ARG); 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_SBV: return Z3_OP_FPA_TO_SBV;
case OP_FPA_TO_REAL: return Z3_OP_FPA_TO_REAL; 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_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_BVWRAP: return Z3_OP_FPA_BVWRAP;
case OP_FPA_BV2RM: return Z3_OP_FPA_BV2RM; 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; return Z3_OP_UNINTERPRETED;
default: default:
return Z3_OP_INTERNAL; return Z3_OP_INTERNAL;

View file

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

View file

@ -56,19 +56,20 @@ extern "C" {
Z3_func_decl const decls[]) { Z3_func_decl const decls[]) {
Z3_TRY; Z3_TRY;
LOG_Z3_parse_smtlib_string(c, str, num_sorts, sort_names, sorts, num_decls, decl_names, decls); LOG_Z3_parse_smtlib_string(c, str, num_sorts, sort_names, sorts, num_decls, decl_names, decls);
std::ostringstream outs; scoped_ptr<std::ostringstream> outs = alloc(std::ostringstream);
bool ok = false; bool ok = false;
RESET_ERROR_CODE(); RESET_ERROR_CODE();
init_smtlib_parser(c, num_sorts, sort_names, sorts, num_decls, decl_names, decls); init_smtlib_parser(c, num_sorts, sort_names, sorts, num_decls, decl_names, decls);
mk_c(c)->m_smtlib_parser->set_error_stream(outs); mk_c(c)->m_smtlib_parser->set_error_stream(*outs);
try { try {
ok = mk_c(c)->m_smtlib_parser->parse_string(str); ok = mk_c(c)->m_smtlib_parser->parse_string(str);
} }
catch (...) { catch (...) {
ok = false; ok = false;
} }
mk_c(c)->m_smtlib_error_buffer = outs.str(); mk_c(c)->m_smtlib_error_buffer = outs->str();
outs = nullptr;
if (!ok) { if (!ok) {
mk_c(c)->reset_parser(); mk_c(c)->reset_parser();
SET_ERROR_CODE(Z3_PARSER_ERROR); SET_ERROR_CODE(Z3_PARSER_ERROR);
@ -88,16 +89,17 @@ extern "C" {
LOG_Z3_parse_smtlib_file(c, file_name, num_sorts, sort_names, types, num_decls, decl_names, decls); LOG_Z3_parse_smtlib_file(c, file_name, num_sorts, sort_names, types, num_decls, decl_names, decls);
bool ok = false; bool ok = false;
RESET_ERROR_CODE(); RESET_ERROR_CODE();
std::ostringstream outs; scoped_ptr<std::ostringstream> outs = alloc(std::ostringstream);
init_smtlib_parser(c, num_sorts, sort_names, types, num_decls, decl_names, decls); init_smtlib_parser(c, num_sorts, sort_names, types, num_decls, decl_names, decls);
mk_c(c)->m_smtlib_parser->set_error_stream(outs); mk_c(c)->m_smtlib_parser->set_error_stream(*outs);
try { try {
ok = mk_c(c)->m_smtlib_parser->parse_file(file_name); ok = mk_c(c)->m_smtlib_parser->parse_file(file_name);
} }
catch(...) { catch(...) {
ok = false; ok = false;
} }
mk_c(c)->m_smtlib_error_buffer = outs.str(); mk_c(c)->m_smtlib_error_buffer = outs->str();
outs = nullptr;
if (!ok) { if (!ok) {
mk_c(c)->reset_parser(); mk_c(c)->reset_parser();
SET_ERROR_CODE(Z3_PARSER_ERROR); SET_ERROR_CODE(Z3_PARSER_ERROR);
@ -260,21 +262,22 @@ extern "C" {
Z3_symbol const decl_names[], Z3_symbol const decl_names[],
Z3_func_decl const decls[]) { Z3_func_decl const decls[]) {
Z3_TRY; Z3_TRY;
cmd_context ctx(false, &(mk_c(c)->m())); scoped_ptr<cmd_context> ctx = alloc(cmd_context, false, &(mk_c(c)->m()));
ctx.set_ignore_check(true); ctx->set_ignore_check(true);
for (unsigned i = 0; i < num_decls; ++i) { 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) { for (unsigned i = 0; i < num_sorts; ++i) {
psort* ps = ctx.pm().mk_psort_cnst(to_sort(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)); 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); SET_ERROR_CODE(Z3_PARSER_ERROR);
return of_ast(mk_c(c)->m().mk_true()); return of_ast(mk_c(c)->m().mk_true());
} }
ptr_vector<expr>::const_iterator it = ctx.begin_assertions(); ptr_vector<expr>::const_iterator it = ctx->begin_assertions();
ptr_vector<expr>::const_iterator end = ctx.end_assertions(); ptr_vector<expr>::const_iterator end = ctx->end_assertions();
unsigned size = static_cast<unsigned>(end - it); unsigned size = static_cast<unsigned>(end - it);
return of_ast(mk_c(c)->mk_and(size, it)); return of_ast(mk_c(c)->mk_and(size, it));
Z3_CATCH_RETURN(0); Z3_CATCH_RETURN(0);

View file

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

View file

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

View file

@ -140,18 +140,17 @@ namespace z3 {
class context { class context {
bool m_enable_exceptions; bool m_enable_exceptions;
Z3_context m_ctx; Z3_context m_ctx;
static void error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ }
void init(config & c) { void init(config & c) {
m_ctx = Z3_mk_context_rc(c); m_ctx = Z3_mk_context_rc(c);
m_enable_exceptions = true; m_enable_exceptions = true;
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); Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT);
} }
void init_interp(config & c) { void init_interp(config & c) {
m_ctx = Z3_mk_interpolation_context(c); m_ctx = Z3_mk_interpolation_context(c);
m_enable_exceptions = true; 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); 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. 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 d, sort r);
sort array_sort(sort_vector const& d, sort r);
/** /**
\brief Return an enumeration sort: enum_names[0], ..., enum_names[n-1]. \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, \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(); } Z3_error_code check_error() const { return m_ctx->check_error(); }
friend void check_context(object const & a, object const & b); 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 { class symbol : public object {
Z3_symbol m_sym; 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::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 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) { 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); array<Z3_symbol> _enum_names(n);
for (unsigned i = 0; i < n; i++) { _enum_names[i] = Z3_mk_string_symbol(*this, enum_names[i]); } 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(); a.check_error();
return expr(a.ctx(), r); 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, 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, 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) { 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())); 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) \ #define MK_EXPR1(_fn, _arg) \
Z3_ast r = _fn(_arg.ctx(), _arg); \ Z3_ast r = _fn(_arg.ctx(), _arg); \

View file

@ -63,6 +63,13 @@ namespace Microsoft.Z3
Contract.Requires(domain != null); Contract.Requires(domain != null);
Contract.Requires(range != 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 #endregion
}; };

View file

@ -274,6 +274,20 @@ namespace Microsoft.Z3
return new ArraySort(this, domain, range); 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> /// <summary>
/// Create a new tuple sort. /// Create a new tuple sort.
/// </summary> /// </summary>
@ -2113,6 +2127,7 @@ namespace Microsoft.Z3
return (ArrayExpr)MkConst(MkSymbol(name), MkArraySort(domain, range)); return (ArrayExpr)MkConst(MkSymbol(name), MkArraySort(domain, range));
} }
/// <summary> /// <summary>
/// Array read. /// Array read.
/// </summary> /// </summary>
@ -2123,8 +2138,8 @@ namespace Microsoft.Z3
/// The node <c>a</c> must have an array sort <c>[domain -> range]</c>, /// 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>. /// and <c>i</c> must have the sort <c>domain</c>.
/// The sort of the result is <c>range</c>. /// The sort of the result is <c>range</c>.
/// <seealso cref="MkArraySort"/> /// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkStore"/> /// <seealso cref="MkStore(ArrayExpr, Expr, Expr)"/>
/// </remarks> /// </remarks>
public Expr MkSelect(ArrayExpr a, Expr i) 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)); 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> /// <summary>
/// Array update. /// Array update.
/// </summary> /// </summary>
@ -2151,8 +2190,9 @@ namespace Microsoft.Z3
/// on all indices except for <c>i</c>, where it maps to <c>v</c> /// 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 /// (and the <c>select</c> of <c>a</c> with
/// respect to <c>i</c> may be a different value). /// respect to <c>i</c> may be a different value).
/// <seealso cref="MkArraySort"/> /// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkSelect"/> /// <seealso cref="MkSelect(ArrayExpr, Expr)"/>
/// <seealso cref="MkSelect(ArrayExpr, Expr[])"/>
/// </remarks> /// </remarks>
public ArrayExpr MkStore(ArrayExpr a, Expr i, Expr v) 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)); 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> /// <summary>
/// Create a constant array. /// Create a constant array.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// The resulting term is an array, such that a <c>select</c>on an arbitrary index /// The resulting term is an array, such that a <c>select</c>on an arbitrary index
/// produces the value <c>v</c>. /// produces the value <c>v</c>.
/// <seealso cref="MkArraySort"/> /// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkSelect"/> /// <seealso cref="MkSelect(ArrayExpr, Expr)"/>
/// </remarks> /// </remarks>
public ArrayExpr MkConstArray(Sort domain, Expr v) 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>. /// 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>. /// 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>. /// <c>v</c> must have sort range. The sort of the result is <c>[domain_i -> range]</c>.
/// <seealso cref="MkArraySort"/> /// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkSelect"/> /// <seealso cref="MkSelect(ArrayExpr, Expr)"/>
/// <seealso cref="MkStore"/> /// <seealso cref="MkStore(ArrayExpr, Expr, Expr)"/>
/// </remarks> /// </remarks>
public ArrayExpr MkMap(FuncDecl f, params ArrayExpr[] args) 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(), super(ctx, Native.mkArraySort(ctx.nCtx(), domain.getNativeObject(),
range.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); 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 * 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, * that is passed in as argument is updated with value v,
* the remaining fields of t are unchanged. * 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 throws Z3Exception
{ {
return Expr.create (this, 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) public BoolExpr mkNot(BoolExpr a)
{ {
@ -1679,6 +1690,28 @@ public class Context implements AutoCloseable {
i.getNativeObject())); 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. * Array update.
* Remarks: The node {@code a} must have an array sort * Remarks: The node {@code a} must have an array sort
@ -1704,6 +1737,31 @@ public class Context implements AutoCloseable {
i.getNativeObject(), v.getNativeObject())); 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. * Create a constant array.
* Remarks: The resulting term is an array, such * Remarks: The resulting term is an array, such
@ -2104,7 +2162,7 @@ public class Context implements AutoCloseable {
/** /**
* Create a range expression. * Create a range expression.
*/ */
public ReExpr MkRange(SeqExpr lo, SeqExpr hi) public ReExpr mkRange(SeqExpr lo, SeqExpr hi)
{ {
checkContextMatch(lo, hi); checkContextMatch(lo, hi);
return (ReExpr) Expr.create(this, Native.mkReRange(nCtx(), lo.getNativeObject(), hi.getNativeObject())); return (ReExpr) Expr.create(this, Native.mkReRange(nCtx(), lo.getNativeObject(), hi.getNativeObject()));

View file

@ -120,7 +120,7 @@ def _get_args(args):
try: try:
if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)): if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)):
return args[0] 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]] return [arg for arg in args[0]]
else: else:
return args return args

View file

@ -993,18 +993,6 @@ typedef enum
3 = 011 = Z3_OP_FPA_RM_TOWARD_NEGATIVE, 3 = 011 = Z3_OP_FPA_RM_TOWARD_NEGATIVE,
4 = 100 = Z3_OP_FPA_RM_TOWARD_ZERO. 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 - Z3_OP_INTERNAL: internal (often interpreted) symbol, but no additional
information is exposed. Tools may use the string representation of the information is exposed. Tools may use the string representation of the
function declaration to obtain more information. function declaration to obtain more information.
@ -1291,13 +1279,8 @@ typedef enum {
Z3_OP_FPA_TO_IEEE_BV, Z3_OP_FPA_TO_IEEE_BV,
Z3_OP_FPA_MIN_I,
Z3_OP_FPA_MAX_I,
Z3_OP_FPA_BVWRAP, Z3_OP_FPA_BVWRAP,
Z3_OP_FPA_BV2RM, Z3_OP_FPA_BV2RM,
Z3_OP_FPA_MIN_UNSPECIFIED,
Z3_OP_FPA_MAX_UNSPECIFIED,
Z3_OP_INTERNAL, 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); 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. \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); 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. \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); 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. \brief Create the constant array.
@ -3048,6 +3059,15 @@ extern "C" {
def_API('Z3_mk_array_default', AST, (_in(CONTEXT), _in(AST))) 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); 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 */ /** @name Sets */
@ -3871,6 +3891,7 @@ extern "C" {
/** /**
\brief Return the domain of the given array sort. \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 \pre Z3_get_sort_kind(c, t) == Z3_ARRAY_SORT

View file

@ -242,7 +242,9 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) {
parameter const* parameters = s->get_parameters(); parameter const* parameters = s->get_parameters();
if (num_parameters != arity) { 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; return 0;
} }
ptr_buffer<sort> new_domain; // we need this because of coercions. 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; return 0;
} }
sort * r = to_sort(s->get_parameter(i).get_ast()); 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)); 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)); params.push_back(parameter(range));
return m_manager.mk_sort(m_fid, ARRAY_SORT, params.size(), params.c_ptr()); 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_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_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) 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_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_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); } 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()); 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(sort* dom, sort* range) { return mk_array_sort(1, &dom, range); }
sort * mk_array_sort(unsigned arity, sort* const* domain, sort* 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); 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(), compare_arrays(to_quantifier(n1)->get_decl_sorts(),
to_quantifier(n2)->get_decl_sorts(), to_quantifier(n2)->get_decl_sorts(),
to_quantifier(n1)->get_num_decls()) && to_quantifier(n1)->get_num_decls()) &&
compare_arrays(to_quantifier(n1)->get_decl_names(),
to_quantifier(n2)->get_decl_names(),
to_quantifier(n1)->get_num_decls()) &&
to_quantifier(n1)->get_expr() == to_quantifier(n2)->get_expr() && to_quantifier(n1)->get_expr() == to_quantifier(n2)->get_expr() &&
to_quantifier(n1)->get_weight() == to_quantifier(n2)->get_weight() && to_quantifier(n1)->get_weight() == to_quantifier(n2)->get_weight() &&
to_quantifier(n1)->get_num_patterns() == to_quantifier(n2)->get_num_patterns() && to_quantifier(n1)->get_num_patterns() == to_quantifier(n2)->get_num_patterns() &&
@ -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) { 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()) { if (num_parents >= cache.size()) {
cache.resize(num_parents+1, 0); cache.resize(num_parents+1);
} }
if (cache[num_parents] == 0) { if (cache[num_parents] == 0) {
cache[num_parents] = mk_proof_decl(name, k, num_parents); 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) {} explicit parameter(unsigned ext_id, bool):m_kind(PARAM_EXTERNAL), m_ext_id(ext_id) {}
parameter(parameter const&); 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();
parameter& operator=(parameter const& other); parameter& operator=(parameter const& other);

View file

@ -584,6 +584,8 @@ class smt2_printer {
string_buffer<> buf; string_buffer<> buf;
buf.append("(:var "); buf.append("(:var ");
buf.append(v->get_idx()); buf.append(v->get_idx());
//buf.append(" ");
//buf.append(v->get_sort()->get_name().str().c_str());
buf.append(")"); buf.append(")");
f = mk_string(m(), buf.c_str()); 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 { app * bv_util::mk_numeral(rational const & val, unsigned bv_size) const {
parameter p1(val); parameter p[2] = { parameter(val), parameter(static_cast<int>(bv_size)) };
parameter p[2] = { p1, parameter(static_cast<int>(bv_size)) };
return m_manager.mk_app(get_fid(), OP_BV_NUM, 2, p, 0, 0); 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 "ast/expr_abstract.h"
#include "util/map.h" #include "util/map.h"
#include "ast/ast_pp.h"
void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) { void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
@ -109,6 +110,9 @@ void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const*
void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) { void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
expr_abstractor abs(m); expr_abstractor abs(m);
abs(base, num_bound, bound, n, result); abs(base, num_bound, bound, n, result);
TRACE("expr_abstract",
tout << expr_ref(n, m) << "\n";
tout << result << "\n";);
} }
expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) { expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
@ -123,6 +127,11 @@ expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app*
} }
result = m.mk_quantifier(is_forall, num_bound, sorts.c_ptr(), names.c_ptr(), result); result = m.mk_quantifier(is_forall, num_bound, sorts.c_ptr(), names.c_ptr(), result);
} }
TRACE("expr_abstract",
tout << expr_ref(n, m) << "\n";
for (unsigned i = 0; i < num_bound; ++i) tout << expr_ref(bound[i], m) << " ";
tout << "\n";
tout << result << "\n";);
return result; return result;
} }

View file

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

View file

@ -50,6 +50,8 @@ public:
bool contains(expr * s); bool contains(expr * s);
void reset(); void reset();
void cleanup(); void cleanup();
std::ostream& display(std::ostream& out);
}; };
class scoped_expr_substitution { class scoped_expr_substitution {
@ -78,12 +80,14 @@ public:
m_trail_lim.resize(new_sz); m_trail_lim.resize(new_sz);
} }
} }
unsigned scope_level() const { return m_trail_lim.size(); }
bool empty() const { return m_subst.empty(); } 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; } 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) { 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 find(expr * s, expr * & def, proof * & def_pr, expr_dependency * & def_dep) { return m_subst.find(s, def, def_pr, def_dep); }
bool contains(expr * s) { return m_subst.contains(s); } bool contains(expr * s) { return m_subst.contains(s); }
void cleanup() { m_subst.cleanup(); } void cleanup() { m_subst.cleanup(); }
std::ostream& display(std::ostream& out) { return m_subst.display(out); }
}; };
#endif #endif

View file

@ -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_key);
m.inc_ref(it->m_value); m.inc_ref(it->m_value);
} }
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = conv.m_min_max_specials.begin(); for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = conv.m_min_max_ufs.begin();
it != conv.m_min_max_specials.end(); it != conv.m_min_max_ufs.end();
it++) { it++) {
m_specials.insert(it->m_key, it->m_value); m_specials.insert(it->m_key, it->m_value);
m.inc_ref(it->m_key); 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_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.new_float_fi = convert_func_interp(mc, am.new_float_fd, bv_f);
am.bv_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; 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); 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) { void fpa2bv_converter::mk_uf(func_decl * f, unsigned num, expr * const * 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)
{ {
TRACE("fpa2bv", tout << "UF: " << mk_ismt2_pp(f, m) << std::endl; ); 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 sbits = m_util.get_sbits(rng);
unsigned bv_sz = ebits+sbits; unsigned bv_sz = ebits+sbits;
bv_rng = m_bv_util.mk_sort(bv_sz); 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); 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), 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), 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); sort_ref bv_rng(m);
expr_ref new_eq(m); expr_ref new_eq(m);
bv_rng = m_bv_util.mk_sort(3); 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); bv_app = m.mk_app(bv_f, num, args);
flt_app = m_util.mk_bv2rm(bv_app); flt_app = m_util.mk_bv2rm(bv_app);
new_eq = m.mk_eq(fapp, flt_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) { 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); SASSERT(num == 2);
expr * x = args[0], * y = args[1]; expr * x = args[0], * y = args[1];
expr * x_sgn, * x_sig, * x_exp; expr * x_sgn, *x_sig, *x_exp;
expr * y_sgn, * y_sig, * y_exp; expr * y_sgn, *y_sig, *y_exp;
split_fp(x, x_sgn, x_exp, x_sig); split_fp(x, x_sgn, x_exp, x_sig);
split_fp(y, y_sgn, y_exp, y_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); expr_ref bv0(m), bv1(m);
mk_is_zero(x, x_is_zero); bv0 = m_bv_util.mk_numeral(0, 1);
mk_is_zero(y, y_is_zero); bv1 = m_bv_util.mk_numeral(1, 1);
m_simp.mk_and(x_is_zero, y_is_zero, both_zero);
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(x, x_is_nan);
mk_is_nan(y, y_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); expr_ref x_is_pos(m), x_is_neg(m);
sgn_eq = m.mk_eq(x_sgn, y_sgn); expr_ref y_is_pos(m), y_is_neg(m);
sgn_diff = m.mk_not(sgn_eq); 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); expr_ref unspec(m);
mk_float_lt(f, num, args, lt); unspec = mk_min_max_unspecified(f, x, y);
mk_ite(lt, x, y, result); expr_ref x_lt_y(m);
mk_ite(both_zero, y, result, result); 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(y_is_nan, x, result, result);
mk_ite(x_is_nan, y, 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. // There is no "hardware interpretation" for fp.min/fp.max.
std::pair<app*, app*> decls(0, 0); 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.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)); 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(f);
m.inc_ref(decls.first); m.inc_ref(decls.first);
m.inc_ref(decls.second); 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; 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) { void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 4); SASSERT(num == 4);
SASSERT(m_util.is_bv2rm(args[0])); 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); mk_is_nan(x, x_is_nan);
sort * fp_srt = m.get_sort(x); sort * fp_srt = m.get_sort(x);
unsigned ebits = m_util.get_ebits(fp_srt);
unsigned sbits = m_util.get_sbits(fp_srt);
expr_ref nanv(m); expr_ref unspec(m);
if (m_hi_fp_unspecified) mk_to_ieee_bv_unspecified(f, num, args, unspec);
// 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 sgn_e_s(m); expr_ref sgn_e_s(m);
join_fp(x, sgn_e_s); 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;); TRACE("fpa2bv_to_ieee_bv", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;);
SASSERT(is_well_sorted(m, result)); 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 ebits = f->get_domain()[0]->get_parameter(0).get_int();
unsigned sbits = f->get_domain()[0]->get_parameter(1).get_int(); unsigned sbits = f->get_domain()[0]->get_parameter(1).get_int();
if (m_hi_fp_unspecified) { if (m_hi_fp_unspecified)
result = m_bv_util.mk_concat(m_bv_util.mk_concat( mk_nan(f->get_range(), result);
m_bv_util.mk_numeral(0, 1),
m_bv_util.mk_numeral(-1, ebits)),
m_bv_util.mk_numeral(1, sbits-1));
}
else { else {
expr * n = args[0]; expr * n = args[0];
expr_ref n_bv(m); expr_ref n_bv(m);
join_fp(n, n_bv); join_fp(n, n_bv);
func_decl * f_bv; sort * domain[1] = { m.get_sort(n_bv) };
if (!m_uf2bvuf.find(f, f_bv)) { func_decl * f_bv = mk_bv_uf(f, domain, f->get_range());
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);
}
result = m.mk_app(f_bv, n_bv); result = m.mk_app(f_bv, n_bv);
expr_ref exp_bv(m), exp_all_ones(m); 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); expr_ref n_bv(m);
join_fp(n, n_bv); join_fp(n, n_bv);
func_decl * f_bv; sort * domain[2] = { m.get_sort(rm_bv), m.get_sort(n_bv) };
if (!m_uf2bvuf.find(f, f_bv)) { func_decl * f_bv = mk_bv_uf(f, domain, f->get_range());
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);
}
result = m.mk_app(f_bv, rm_bv, n_bv); 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); expr_ref n_bv(m);
join_fp(n, n_bv); join_fp(n, n_bv);
func_decl * f_bv; sort * domain[1] = { m.get_sort(n_bv) };
if (!m_uf2bvuf.find(f, f_bv)) { func_decl * f_bv = mk_bv_uf(f, domain, f->get_range());
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);
}
result = m.mk_app(f_bv, n_bv); 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_const2bv);
dec_ref_map_key_values(m, m_rm_const2bv); dec_ref_map_key_values(m, m_rm_const2bv);
dec_ref_map_key_values(m, m_uf2bvuf); dec_ref_map_key_values(m, m_uf2bvuf);
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_min_max_specials.begin(); for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_min_max_ufs.begin();
it != m_min_max_specials.end(); it != m_min_max_ufs.end();
it++) { it++) {
m.dec_ref(it->m_key); m.dec_ref(it->m_key);
m.dec_ref(it->m_value.first); m.dec_ref(it->m_value.first);
m.dec_ref(it->m_value.second); m.dec_ref(it->m_value.second);
} }
m_min_max_specials.reset(); m_min_max_ufs.reset();
m_extra_assertions.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_const2bv;
const2bv_t m_rm_const2bv; const2bv_t m_rm_const2bv;
uf2bvuf_t m_uf2bvuf; uf2bvuf_t m_uf2bvuf;
special_t m_min_max_specials; special_t m_min_max_ufs;
friend class fpa2bv_model_converter; friend class fpa2bv_model_converter;
friend class bv2fpa_converter; friend class bv2fpa_converter;
@ -87,7 +87,7 @@ public:
void mk_numeral(sort * s, mpf const & v, expr_ref & result); void mk_numeral(sort * s, mpf const & v, expr_ref & result);
virtual void mk_const(func_decl * f, 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_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_var(unsigned base_inx, sort * srt, expr_ref & result);
void mk_pinf(func_decl * f, 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 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(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(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 reset(void);
void dbg_decouple(const char * prefix, expr_ref & e); void dbg_decouple(const char * prefix, expr_ref & e);
expr_ref_vector m_extra_assertions; 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_const2bv() const { return m_const2bv; };
const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; }; const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; };
uf2bvuf_t const & get_uf2bvuf() const { return m_uf2bvuf; }; 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); 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: private:
void mk_nan(sort * s, expr_ref & result); void mk_nan(sort * s, expr_ref & result);
void mk_nzero(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_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); 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 #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_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_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_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_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_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; 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_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_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_BVWRAP:
case OP_FPA_BV2RM: case OP_FPA_BV2RM:
return BR_FAILED; 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)); SASSERT(!m_conv.is_float_family(f));
if (m_conv.fu().contains_floats(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; 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_REM: name = "fp.rem"; break;
case OP_FPA_MIN: name = "fp.min"; break; case OP_FPA_MIN: name = "fp.min"; break;
case OP_FPA_MAX: name = "fp.max"; 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: default:
UNREACHABLE(); UNREACHABLE();
break; break;
@ -781,12 +777,6 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
case OP_FPA_BV2RM: case OP_FPA_BV2RM:
return mk_bv2rm(k, num_parameters, parameters, arity, domain, range); 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: default:
m_manager->raise_exception("unsupported floating point operator"); m_manager->raise_exception("unsupported floating point operator");
return 0; return 0;

View file

@ -89,11 +89,6 @@ enum fpa_op_kind {
OP_FPA_BVWRAP, OP_FPA_BVWRAP,
OP_FPA_BV2RM, OP_FPA_BV2RM,
OP_FPA_MIN_I,
OP_FPA_MAX_I,
OP_FPA_MIN_UNSPECIFIED,
OP_FPA_MAX_UNSPECIFIED,
LAST_FLOAT_OP 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(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(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_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_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_bvwrap(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BVWRAP; }
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_bv2rm(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BV2RM; }
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_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_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; } 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

@ -207,8 +207,8 @@ struct nnf::imp {
unsigned m_new_child:1; unsigned m_new_child:1;
unsigned m_cache_result:1; unsigned m_cache_result:1;
unsigned m_spos; // top of the result stack, when the frame was created. 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): frame(expr_ref && n, bool pol, bool in_q, bool cache_res, unsigned spos):
m_curr(n), m_curr(std::move(n)),
m_i(0), m_i(0),
m_pol(pol), m_pol(pol),
m_in_q(in_q), m_in_q(in_q),
@ -216,6 +216,16 @@ struct nnf::imp {
m_cache_result(cache_res), m_cache_result(cache_res),
m_spos(spos) { 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: // There are four caches:
@ -324,8 +334,7 @@ struct nnf::imp {
} }
void push_frame(expr * t, bool pol, bool in_q, bool cache_res) { void push_frame(expr * t, bool pol, bool in_q, bool cache_res) {
expr_ref tr(t, m()); m_frame_stack.push_back(frame(expr_ref(t, m()), pol, in_q, cache_res, m_result_stack.size()));
m_frame_stack.push_back(frame(tr, pol, in_q, cache_res, m_result_stack.size()));
} }
static unsigned get_cache_idx(bool pol, bool in_q) { static unsigned get_cache_idx(bool pol, bool in_q) {

View file

@ -179,11 +179,11 @@ expr_pattern_match::compile(expr* q)
} }
if (m_regs.size() <= max_reg) { 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) { if (m_bound_dom.size() <= num_bound) {
m_bound_dom.resize(num_bound+1, 0); m_bound_dom.resize(num_bound+1);
m_bound_rng.resize(num_bound+1, 0); m_bound_rng.resize(num_bound+1);
} }
instr.m_kind = YIELD; 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(); zero = m().mk_false();
vector< expr_ref_vector > pps; vector< expr_ref_vector > pps;
pps.resize(sz, m()); pps.resize(sz, expr_ref_vector(m()));
for (unsigned i = 0; i < sz; i++) { for (unsigned i = 0; i < sz; i++) {
checkpoint(); 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_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_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_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; 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 & sm1 = m_fm.m_powers2(sbits - 1);
const mpz & em1 = m_fm.m_powers2(ebits); const mpz & em1 = m_fm.m_powers2(ebits);
scoped_mpq q(mpqm); const mpq & q = r1.to_mpq();
mpqm.set(q, r1.to_mpq()); SASSERT(mpzm.is_one(q.denominator()));
SASSERT(mpzm.is_one(q.get().denominator()));
scoped_mpz z(mpzm); scoped_mpz z(mpzm);
z = q.get().numerator(); z = q.numerator();
mpzm.rem(z, sm1, sig); mpzm.rem(z, sm1, sig);
mpzm.div(z, sm1, z); 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); 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_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)) 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_FAILED;
else
result = m_util.mk_min(arg1, arg2); scoped_mpf r(m_fm);
m_fm.minimum(v1, v2, r);
result = m_util.mk_value(r);
return BR_DONE; 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); 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_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)) 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_FAILED;
else
result = m_util.mk_max(arg1, arg2); scoped_mpf r(m_fm);
m_fm.maximum(v1, v2, r);
result = m_util.mk_value(r);
return BR_DONE; 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";); TRACE("ac_sharing_detail", tout << "args: "; for (unsigned i = 0; i < num_args; i++) tout << mk_pp(_args[i], m) << "\n";);
try_to_reuse: try_to_reuse:
if (num_args > 1 && num_args < MAX_NUM_ARGS_FOR_OPT) { if (num_args > 1 && num_args < MAX_NUM_ARGS_FOR_OPT) {
for (unsigned i = 0; i < num_args - 1; i++) { for (unsigned i = 0; i + 1 < num_args; i++) {
for (unsigned j = i + 1; j < num_args; j++) { for (unsigned j = i + 1; j < num_args; j++) {
if (contains(f, _args[i], _args[j])) { if (contains(f, _args[i], _args[j])) {
TRACE("ac_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";); TRACE("ac_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";);
_args[i] = m.mk_app(f, _args[i], _args[j]); _args[i] = m.mk_app(f, _args[i], _args[j]);
SASSERT(num_args > 1); SASSERT(num_args > 1);
for (unsigned w = j; w < num_args - 1; w++) { for (unsigned w = j; w + 1 < num_args; w++) {
_args[w] = _args[w+1]; _args[w] = _args[w+1];
} }
num_args--; num_args--;
@ -144,6 +144,7 @@ void maximize_ac_sharing::restore_entries(unsigned old_lim) {
while (i != old_lim) { while (i != old_lim) {
--i; --i;
entry * e = m_entries[i]; entry * e = m_entries[i];
m_cache.remove(e);
m.dec_ref(e->m_arg1); m.dec_ref(e->m_arg1);
m.dec_ref(e->m_arg2); m.dec_ref(e->m_arg2);
} }
@ -151,11 +152,7 @@ void maximize_ac_sharing::restore_entries(unsigned old_lim) {
} }
void maximize_ac_sharing::reset() { void maximize_ac_sharing::reset() {
restore_entries(0);
m_entries.reset();
m_cache.reset(); m_cache.reset();
m_region.reset();
m_scopes.reset();
} }
void maximize_bv_sharing::init_core() { void maximize_bv_sharing::init_core() {

View file

@ -42,6 +42,10 @@ void rewriter_tpl<Config>::process_var(var * v) {
unsigned index = m_bindings.size() - idx - 1; unsigned index = m_bindings.size() - idx - 1;
var * r = (var*)(m_bindings[index]); var * r = (var*)(m_bindings[index]);
if (r != 0) { 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)); SASSERT(v->get_sort() == m().get_sort(r));
if (!is_ground(r) && m_shifts[index] != m_bindings.size()) { 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(); sort * s = to_var(new_expr)->get_sort();
unsigned id = s->get_decl_id(); unsigned id = s->get_decl_id();
if (id >= m_vars.size()) if (id >= m_vars.size())
m_vars.resize(id+1, 0); m_vars.resize(id+1);
if (m_vars[id] == 0) if (m_vars[id] == 0)
m_vars[id] = alloc(var_ref_vector, m_manager); m_vars[id] = alloc(var_ref_vector, m_manager);
var_ref_vector * v = m_vars[id]; var_ref_vector * v = m_vars[id];
@ -277,7 +277,7 @@ void substitution_tree::insert(app * new_expr) {
unsigned id = d->get_decl_id(); unsigned id = d->get_decl_id();
if (id >= m_roots.size()) if (id >= m_roots.size())
m_roots.resize(id+1, 0); m_roots.resize(id+1);
if (!m_roots[id]) { if (!m_roots[id]) {
// there is no tree for the function symbol heading new_expr // 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) { if (idx >= delta) {
idx = idx - delta; idx = idx - delta;
if (idx >= m_found_vars.size()) 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(); m_found_vars[idx] = to_var(n)->get_sort();
} }
break; break;

View file

@ -202,7 +202,7 @@ func_decl * func_decls::find(unsigned arity, sort * const * domain, sort * range
if (f->get_arity() != arity) if (f->get_arity() != arity)
continue; continue;
unsigned i = 0; unsigned i = 0;
for (i = 0; i < arity; i++) { for (i = 0; domain && i < arity; i++) {
if (f->get_domain(i) != domain[i]) if (f->get_domain(i) != domain[i])
break; 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) { void cmd_context::insert(symbol const & s, func_decl * f) {
m_check_sat_result = 0;
if (!m_check_logic(f)) { if (!m_check_logic(f)) {
throw cmd_exception(m_check_logic.get_last_error()); 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) { void cmd_context::insert(symbol const & s, psort_decl * p) {
m_check_sat_result = 0;
if (m_psort_decls.contains(s)) { if (m_psort_decls.contains(s)) {
throw cmd_exception("sort already defined ", 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) { void cmd_context::insert(symbol const & s, unsigned arity, sort *const* domain, expr * t) {
expr_ref _t(t, m()); expr_ref _t(t, m());
m_check_sat_result = 0;
if (m_builtin_decls.contains(s)) { if (m_builtin_decls.contains(s)) {
throw cmd_exception("invalid macro/named expression, builtin symbol ", 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()); lhs = m().mk_app(f, binding.size(), binding.c_ptr());
eq = m().mk_eq(lhs, e); eq = m().mk_eq(lhs, e);
if (!ids.empty()) { if (!ids.empty()) {
if (is_var(e)) {
ptr_vector<sort> domain;
for (expr* b : binding) domain.push_back(m().get_sort(b));
insert_macro(f->get_name(), domain.size(), domain.c_ptr(), e);
return;
}
if (!is_app(e)) { if (!is_app(e)) {
throw cmd_exception("Z3 only supports recursive definitions that are proper terms (not binders or variables)"); throw cmd_exception("Z3 only supports recursive definitions that are proper terms (not binders or variables)");
} }
@ -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, func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices,
unsigned arity, sort * const * domain, sort * range) const { unsigned arity, sort * const * domain, sort * range) const {
builtin_decl d; builtin_decl d;
if (m_builtin_decls.find(s, d)) { if (domain && m_builtin_decls.find(s, d)) {
family_id fid = d.m_fid; family_id fid = d.m_fid;
decl_kind k = d.m_decl; decl_kind k = d.m_decl;
// Hack: if d.m_next != 0, we use domain[0] (if available) to decide which plugin we use. // 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; 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); throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s);
if (num_indices > 0) 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) { void cmd_context::display_model(model_ref& mdl) {
if (mdl) { if (mdl) {
model_params p; model_params p;
@ -1582,7 +1605,9 @@ void cmd_context::validate_check_sat_result(lbool r) {
throw cmd_exception("check annotation that says unsat"); throw cmd_exception("check annotation that says unsat");
#else #else
diagnostic_stream() << "BUG: incompleteness" << std::endl; 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 #endif
} }
break; break;
@ -1592,7 +1617,9 @@ void cmd_context::validate_check_sat_result(lbool r) {
throw cmd_exception("check annotation that says sat"); throw cmd_exception("check annotation that says sat");
#else #else
diagnostic_stream() << "BUG: unsoundness" << std::endl; 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 #endif
} }
break; break;
@ -1743,6 +1770,7 @@ void cmd_context::validate_model() {
continue; continue;
} }
try { try {
for_each_expr(contains_underspecified, a);
for_each_expr(contains_underspecified, r); for_each_expr(contains_underspecified, r);
} }
catch (contains_underspecified_op_proc::found) { catch (contains_underspecified_op_proc::found) {

View file

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

View file

@ -31,7 +31,6 @@ Notes:
#include "ast/rewriter/var_subst.h" #include "ast/rewriter/var_subst.h"
#include "util/gparams.h" #include "util/gparams.h"
#ifndef _EXTERNAL_RELEASE
BINARY_SYM_CMD(get_quantifier_body_cmd, BINARY_SYM_CMD(get_quantifier_body_cmd,
"dbg-get-qbody", "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) { 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(get_quantifier_body_cmd));
ctx.insert(alloc(set_cmd)); ctx.insert(alloc(set_cmd));
ctx.insert(alloc(pp_var_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_cmd));
ctx.insert(alloc(instantiate_nested_cmd)); ctx.insert(alloc(instantiate_nested_cmd));
ctx.insert(alloc(set_next_id)); ctx.insert(alloc(set_next_id));
#endif
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -24,6 +24,7 @@ Revision History:
#include "math/automata/symbolic_automata.h" #include "math/automata/symbolic_automata.h"
#include "util/hashtable.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 s2id.insert(set, p_state_id++); // the index to the initial state is 0
id2s.push_back(set); id2s.push_back(set);
svector<uint_set> todo; //States to visit ::vector<uint_set> todo; //States to visit
todo.push_back(set); todo.push_back(set);
uint_set state; uint_set state;

View file

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

View file

@ -31,7 +31,7 @@ Revision History:
// #define TRACE_NTH_ROOT // #define TRACE_NTH_ROOT
template<typename C> 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_minus_one, -1);
m().set(m_one, 1); m().set(m_one, 1);
m_pi_n = 0; m_pi_n = 0;

View file

@ -2632,10 +2632,14 @@ namespace algebraic_numbers {
scoped_mpz neg_n(qm()); scoped_mpz neg_n(qm());
qm().set(neg_n, v.numerator()); qm().set(neg_n, v.numerator());
qm().neg(neg_n); 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 << "("; out << "(";
upm().display(out, 2, coeffs, "#"); upm().display(out, 2, coeffs, "#");
out << ", 1)"; // first root of the polynomial d*# - n out << ", 1)"; // first root of the polynomial d*# - n
zmgr.del(coeffs[0]);
zmgr.del(coeffs[1]);
} }
else { else {
algebraic_cell * c = a.to_algebraic(); algebraic_cell * c = a.to_algebraic();
@ -2678,10 +2682,14 @@ namespace algebraic_numbers {
scoped_mpz neg_n(qm()); scoped_mpz neg_n(qm());
qm().set(neg_n, v.numerator()); qm().set(neg_n, v.numerator());
qm().neg(neg_n); 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 "; out << "(root-obj ";
upm().display_smt2(out, 2, coeffs, "x"); upm().display_smt2(out, 2, coeffs, "x");
out << " 1)"; // first root of the polynomial d*# - n out << " 1)"; // first root of the polynomial d*# - n
zmgr.del(coeffs[0]);
zmgr.del(coeffs[1]);
} }
else { else {
algebraic_cell * c = a.to_algebraic(); algebraic_cell * c = a.to_algebraic();

View file

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

View file

@ -35,7 +35,7 @@ namespace simplex {
struct row_entry { struct row_entry {
numeral m_coeff; numeral m_coeff;
var_t m_var; 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: private:
@ -61,7 +61,7 @@ namespace simplex {
int m_col_idx; int m_col_idx;
int m_next_free_row_entry_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) {} _row_entry() : row_entry(numeral(), dead_id), m_col_idx(0) {}
bool is_dead() const { return row_entry::m_var == dead_id; } 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> template<typename C>
var context_t<C>::mk_sum(numeral const & c, unsigned sz, numeral const * as, var const * xs) { 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++) { for (unsigned i = 0; i < sz; i++) {
SASSERT(xs[i] < num_vars()); SASSERT(xs[i] < num_vars());
nm().set(m_num_buffer[xs[i]], as[i]); 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))) (m_arity > 1 && (!m().is_and(c) || to_app(c)->get_num_args() != m_arity)))
return false; return false;
args.resize(m_arity, 0); args.resize(m_arity);
for (unsigned i = 0; i < m_arity; i++) { for (unsigned i = 0; i < m_arity; i++) {
expr * ci = (m_arity == 1 && i == 0) ? c : to_app(c)->get_arg(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; return;
reset_interp_cache(); reset_interp_cache();
ptr_vector<expr> args; ptr_vector<expr> args;
while (e && is_fi_entry_expr(e, args)) { while (e && is_fi_entry_expr(e, args)) {
TRACE("func_interp", tout << "fi entry expr: " << mk_ismt2_pp(e, m()) << std::endl;); 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) { void model_core::unregister_decl(func_decl * d) {
decl2expr::obj_map_entry * ec = m_interp.find_core(d); decl2expr::obj_map_entry * ec = m_interp.find_core(d);
if (ec && ec->get_data().m_value != 0) { if (ec && ec->get_data().m_value != 0) {
m_manager.dec_ref(ec->get_data().m_key); auto k = ec->get_data().m_key;
m_manager.dec_ref(ec->get_data().m_value); auto v = ec->get_data().m_value;
m_interp.remove(d); m_interp.remove(d);
m_const_decls.erase(d); m_const_decls.erase(d);
m_manager.dec_ref(k);
m_manager.dec_ref(v);
return; return;
} }
decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); decl2finterp::obj_map_entry * ef = m_finterp.find_core(d);
if (ef && ef->get_data().m_value != 0) { if (ef && ef->get_data().m_value != 0) {
m_manager.dec_ref(ef->get_data().m_key); auto k = ef->get_data().m_key;
dealloc(ef->get_data().m_value); auto v = ef->get_data().m_value;
m_finterp.remove(d); m_finterp.remove(d);
m_func_decls.erase(d); m_func_decls.erase(d);
m_manager.dec_ref(k);
dealloc(v);
} }
} }

View file

@ -453,7 +453,8 @@ namespace datalog {
return new_pred; 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_fmls.push_back(rl);
m_rule_names.push_back(name); m_rule_names.push_back(name);
m_rule_bounds.push_back(bound); m_rule_bounds.push_back(bound);

View file

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

View file

@ -189,11 +189,12 @@ public:
m_bound = bound; m_bound = bound;
m_arg_idx++; 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 prepare(cmd_context& ctx) { m_arg_idx = 0; m_name = symbol::null; m_bound = UINT_MAX; }
virtual void finalize(cmd_context & ctx) { virtual void finalize(cmd_context & ctx) {
} }
virtual void execute(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); 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) { void set_reg(reg_idx i, reg_type val) {
if (i >= m_registers.size()) { if (i >= m_registers.size()) {
check_overflow(i); check_overflow(i);
m_registers.resize(i+1,0); m_registers.resize(i+1);
} }
if (m_registers[i]) { if (m_registers[i]) {
m_registers[i]->deallocate(); m_registers[i]->deallocate();

View file

@ -465,7 +465,7 @@ namespace datalog {
unsigned sz = r.get_signature().size(); unsigned sz = r.get_signature().size();
ptr_vector<expr> subst_arg; ptr_vector<expr> subst_arg;
subst_arg.resize(sz, 0); subst_arg.resize(sz);
unsigned ofs = sz-1; unsigned ofs = sz-1;
for (unsigned i=0; i<sz; i++) { for (unsigned i=0; i<sz; i++) {
SASSERT(!r.is_undefined(i) || !contains_var(m_new_rule, 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) { void filter_interpreted(app* cond) {
rational one(1), mone(-1); rational one(1), mone(-1);
expr* e1, *e2, *en; expr* e1 = 0, *e2 = 0, *en = 0;
var* v, *w; var* v = 0, *w = 0;
rational n1, n2; rational n1, n2;
expr_ref_vector conjs(m); expr_ref_vector conjs(m);
flatten_and(cond, conjs); flatten_and(cond, conjs);

View file

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

View file

@ -66,7 +66,6 @@ class peq {
app_ref m_peq; // partial equality application app_ref m_peq; // partial equality application
app_ref m_eq; // equivalent std equality using def. of partial eq app_ref m_eq; // equivalent std equality using def. of partial eq
array_util m_arr_u; array_util m_arr_u;
ast_eq_proc m_eq_proc; // for checking if two asts are equal
public: public:
static const char* PARTIAL_EQ; static const char* PARTIAL_EQ;
@ -102,7 +101,7 @@ peq::peq (app* p, ast_manager& m):
VERIFY (is_partial_eq (p)); VERIFY (is_partial_eq (p));
SASSERT (m_arr_u.is_array (m_lhs) && SASSERT (m_arr_u.is_array (m_lhs) &&
m_arr_u.is_array (m_rhs) && 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++) { for (unsigned i = 2; i < p->get_num_args (); i++) {
m_diff_indices.push_back (p->get_arg (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) && SASSERT (m_arr_u.is_array (lhs) &&
m_arr_u.is_array (rhs) && 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; ptr_vector<sort> sorts;
sorts.push_back (m.get_sort (m_lhs)); sorts.push_back (m.get_sort (m_lhs));
sorts.push_back (m.get_sort (m_rhs)); 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) { bool mk_interp_tail_simplifier::propagate_variable_equivalences(rule * r, rule_ref& res) {
if (!m_context.get_params ().xform_tail_simplifier_pve ()) if (!m_context.get_params ().xform_tail_simplifier_pve ())
return false; return false;
unsigned u_len = r->get_uninterpreted_tail_size(); unsigned u_len = r->get_uninterpreted_tail_size();
unsigned len = r->get_tail_size(); unsigned len = r->get_tail_size();
if (u_len == len) { if (u_len == len) {

View file

@ -24,6 +24,7 @@ Revision History:
#include "ast/ast_pp.h" #include "ast/ast_pp.h"
#include "ast/well_sorted.h" #include "ast/well_sorted.h"
#include "ast/rewriter/rewriter.h" #include "ast/rewriter/rewriter.h"
#include "ast/rewriter/var_subst.h"
#include "ast/has_free_vars.h" #include "ast/has_free_vars.h"
#include "ast/ast_smt2_pp.h" #include "ast/ast_smt2_pp.h"
#include "parsers/smt2/smt2parser.h" #include "parsers/smt2/smt2parser.h"
@ -68,6 +69,7 @@ namespace smt2 {
scoped_ptr<bv_util> m_bv_util; scoped_ptr<bv_util> m_bv_util;
scoped_ptr<arith_util> m_arith_util; scoped_ptr<arith_util> m_arith_util;
scoped_ptr<datatype_util> m_datatype_util;
scoped_ptr<seq_util> m_seq_util; scoped_ptr<seq_util> m_seq_util;
scoped_ptr<pattern_validator> m_pattern_validator; scoped_ptr<pattern_validator> m_pattern_validator;
scoped_ptr<var_shifter> m_var_shifter; scoped_ptr<var_shifter> m_var_shifter;
@ -108,6 +110,7 @@ namespace smt2 {
symbol m_check_sat_assuming; symbol m_check_sat_assuming;
symbol m_define_fun_rec; symbol m_define_fun_rec;
symbol m_define_funs_rec; symbol m_define_funs_rec;
symbol m_match;
symbol m_underscore; symbol m_underscore;
typedef std::pair<symbol, expr*> named_expr; typedef std::pair<symbol, expr*> named_expr;
@ -135,7 +138,7 @@ namespace smt2 {
typedef psort_frame sort_frame; 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 { struct expr_frame {
expr_frame_kind m_kind; expr_frame_kind m_kind;
@ -172,6 +175,10 @@ namespace smt2 {
m_expr_spos(expr_spos) {} m_expr_spos(expr_spos) {}
}; };
struct match_frame : public expr_frame {
match_frame():expr_frame(EF_MATCH) {}
};
struct let_frame : public expr_frame { struct let_frame : public expr_frame {
bool m_in_decls; bool m_in_decls;
unsigned m_sym_spos; unsigned m_sym_spos;
@ -275,6 +282,12 @@ namespace smt2 {
return *(m_arith_util.get()); 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() { seq_util & sutil() {
if (m_seq_util.get() == 0) if (m_seq_util.get() == 0)
m_seq_util = alloc(seq_util, m()); 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_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_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_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_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; } 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; m_ctx.regular_stream()<< "line " << line << " column " << pos << ": " << escaped(msg, true) << "\")" << std::endl;
} }
if (m_ctx.exit_on_error()) { 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; 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) { void push_quant_frame(bool is_forall) {
SASSERT(curr_is_identifier()); SASSERT(curr_is_identifier());
SASSERT(curr_id_is_forall() || curr_id_is_exists()); 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"); 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() { symbol parse_indexed_identifier_core() {
check_underscore_next("invalid indexed identifier, '_' expected"); check_underscore_next("invalid indexed identifier, '_' expected");
check_identifier("invalid indexed identifier, symbol expected"); check_identifier("invalid indexed identifier, symbol expected");
@ -1565,7 +1795,6 @@ namespace smt2 {
m_num_expr_frames++; m_num_expr_frames++;
} }
// return true if a new frame was created.
void push_expr_frame(expr_frame * curr) { void push_expr_frame(expr_frame * curr) {
SASSERT(curr_is_lparen()); SASSERT(curr_is_lparen());
next(); next();
@ -1573,11 +1802,7 @@ namespace smt2 {
if (curr_is_identifier()) { if (curr_is_identifier()) {
TRACE("push_expr_frame", tout << "push_expr_frame(), curr_id(): " << curr_id() << "\n";); TRACE("push_expr_frame", tout << "push_expr_frame(), curr_id(): " << curr_id() << "\n";);
if (curr_id_is_let()) { if (curr_id_is_let()) {
next(); push_let_frame();
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++;
} }
else if (curr_id_is_forall()) { else if (curr_id_is_forall()) {
push_quant_frame(true); push_quant_frame(true);
@ -1586,19 +1811,17 @@ namespace smt2 {
push_quant_frame(false); push_quant_frame(false);
} }
else if (curr_id_is_bang()) { else if (curr_id_is_bang()) {
TRACE("consume_attributes", tout << "begin bang, expr_stack.size(): " << expr_stack().size() << "\n";); push_bang_frame(curr);
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++;
} }
else if (curr_id_is_as() || curr_id_is_underscore()) { 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(); parse_qualified_name();
} }
else if (curr_id_is_root_obj()) { else if (curr_id_is_root_obj()) {
parse_root_obj(); parse_root_obj();
} }
else if (curr_id_is_match()) {
push_match_frame();
}
else { else {
push_app_frame(); push_app_frame();
} }
@ -1658,6 +1881,8 @@ namespace smt2 {
// the resultant expression is on the top of the stack // the resultant expression is on the top of the stack
TRACE("let_frame", tout << "let result expr: " << mk_pp(expr_stack().back(), m()) << "\n";); TRACE("let_frame", tout << "let result expr: " << mk_pp(expr_stack().back(), m()) << "\n";);
expr_ref r(m()); expr_ref r(m());
if (expr_stack().empty())
throw parser_exception("invalid let expression");
r = expr_stack().back(); r = expr_stack().back();
expr_stack().pop_back(); expr_stack().pop_back();
// remove local declarations from the stack // remove local declarations from the stack
@ -1773,6 +1998,9 @@ namespace smt2 {
m_stack.deallocate(static_cast<let_decl_frame*>(fr)); m_stack.deallocate(static_cast<let_decl_frame*>(fr));
m_num_expr_frames--; m_num_expr_frames--;
break; break;
case EF_MATCH:
pop_match_frame(static_cast<match_frame*>(fr));
break;
case EF_QUANT: case EF_QUANT:
pop_quant_frame(static_cast<quant_frame*>(fr)); pop_quant_frame(static_cast<quant_frame*>(fr));
break; break;
@ -2232,8 +2460,10 @@ namespace smt2 {
throw cmd_exception("invalid assert command, expression required as argument"); throw cmd_exception("invalid assert command, expression required as argument");
} }
expr * f = expr_stack().back(); 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"); throw cmd_exception("invalid assert command, term is not Boolean");
}
if (f == m_last_named_expr.second) { if (f == m_last_named_expr.second) {
m_ctx.assert_expr(m_last_named_expr.first, f); m_ctx.assert_expr(m_last_named_expr.first, f);
} }
@ -2730,6 +2960,7 @@ namespace smt2 {
m_check_sat_assuming("check-sat-assuming"), m_check_sat_assuming("check-sat-assuming"),
m_define_fun_rec("define-fun-rec"), m_define_fun_rec("define-fun-rec"),
m_define_funs_rec("define-funs-rec"), m_define_funs_rec("define-funs-rec"),
m_match("match"),
m_underscore("_"), m_underscore("_"),
m_num_open_paren(0), m_num_open_paren(0),
m_current_file(filename) { m_current_file(filename) {

View file

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

View file

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

View file

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

View file

@ -114,6 +114,7 @@ namespace sat {
m_core_minimize = p.core_minimize(); m_core_minimize = p.core_minimize();
m_core_minimize_partial = p.core_minimize_partial(); m_core_minimize_partial = p.core_minimize_partial();
m_dyn_sub_res = p.dyn_sub_res(); m_dyn_sub_res = p.dyn_sub_res();
m_dimacs_display = p.dimacs_display();
} }
void config::collect_param_descrs(param_descrs & r) { void config::collect_param_descrs(param_descrs & r) {

View file

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

View file

@ -23,4 +23,5 @@ def_module_params('sat',
('core.minimize', BOOL, False, 'minimize computed core'), ('core.minimize', BOOL, False, 'minimize computed core'),
('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'),
('parallel_threads', UINT, 1, 'number of parallel threads to use'), ('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')))

View file

@ -1311,7 +1311,6 @@ namespace sat {
clause_use_list & neg_occs = m_use_list.get(neg_l); clause_use_list & neg_occs = m_use_list.get(neg_l);
unsigned num_pos = pos_occs.size() + num_bin_pos; unsigned num_pos = pos_occs.size() + num_bin_pos;
unsigned num_neg = neg_occs.size() + num_bin_neg; unsigned num_neg = neg_occs.size() + num_bin_neg;
m_elim_counter -= num_pos + num_neg;
TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << "\n";); TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << "\n";);
@ -1352,8 +1351,6 @@ namespace sat {
collect_clauses(pos_l, m_pos_cls); collect_clauses(pos_l, m_pos_cls);
collect_clauses(neg_l, m_neg_cls); collect_clauses(neg_l, m_neg_cls);
m_elim_counter -= num_pos * num_neg + before_lits;
TRACE("resolution_detail", tout << "collecting number of after_clauses\n";); TRACE("resolution_detail", tout << "collecting number of after_clauses\n";);
unsigned before_clauses = num_pos + num_neg; unsigned before_clauses = num_pos + num_neg;
unsigned after_clauses = 0; unsigned after_clauses = 0;
@ -1376,7 +1373,7 @@ namespace sat {
} }
} }
TRACE("resolution", tout << "found var to eliminate, before: " << before_clauses << " after: " << after_clauses << "\n";); TRACE("resolution", tout << "found var to eliminate, before: " << before_clauses << " after: " << after_clauses << "\n";);
m_elim_counter -= num_pos * num_neg + before_lits;
// eliminate variable // eliminate variable
model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v);

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