diff --git a/.travis.yml b/.travis.yml index e8e207466..a3ffb221e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,15 +17,31 @@ env: ############################################################################### # Ubuntu 16.04 LTS ############################################################################### + # 64-bit UBSan Debug build + - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug UBSAN_BUILD=1 RUN_UNIT_TESTS=SKIP + # 64-bit ASan Debug build + - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug ASAN_BUILD=1 RUN_UNIT_TESTS=SKIP ASAN_DSO=/usr/lib/clang/3.9/lib/linux/libclang_rt.asan-x86_64.so + # Build for running unit tests under ASan/UBSan + # FIXME: We should really be doing a debug build but the unit tests run too + # slowly when we do that. + - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo ASAN_BUILD=1 RUN_UNIT_TESTS=BUILD_AND_RUN ASAN_DSO=/usr/lib/clang/3.9/lib/linux/libclang_rt.asan-x86_64.so UBSAN_BUILD=1 RUN_API_EXAMPLES=0 RUN_SYSTEM_TESTS=0 DOTNET_BINDINGS=0 JAVA_BINDINGS=0 PYTHON_BINDINGS=0 + # 64-bit GCC 5.4 RelWithDebInfo - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo # 64-bit Clang 3.9 RelWithDebInfo - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo + # Debug builds + # + # Note the unit tests for the debug builds are compiled but **not** + # executed. This is because the debug build of unit tests takes a large + # amount of time to execute compared to the optimized builds. The hope is + # that just running the optimized unit tests is sufficient. + # # 64-bit GCC 5.4 Debug - - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug + - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY # 64-bit Clang Debug - - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug + - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY # 32-bit GCC 5.4 RelWithDebInfo - LINUX_BASE=ubuntu32_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=i686 Z3_BUILD_TYPE=RelWithDebInfo @@ -57,12 +73,24 @@ env: # 64-bit GCC 4.8 RelWithDebInfo - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo # 64-bit GCC 4.8 Debug - - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug + - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY -# TODO: OSX support -#matrix: -# include: -# - os: osx -# osx_image: xcode 8.2 +# macOS (a.k.a OSX) support +matrix: + include: + # For now just test a single configuration. macOS builds on TravisCI are + # very slow so we should keep the number of configurations we test on this + # OS to a minimum. + - os: osx + osx_image: xcode8.3 + # Note: Apple Clang does not support OpenMP + env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 script: - - contrib/ci/scripts/travis_ci_entry_point.sh + # Use `travis_wait` when doing LTO builds because this configuration will + # have long link times during which it will not show any output which + # TravisCI might kill due to perceived inactivity. + - if [ "X${USE_LTO}" = "X1" ]; then + travis_wait 45 contrib/ci/scripts/travis_ci_entry_point.sh || exit 1; + else + contrib/ci/scripts/travis_ci_entry_point.sh || exit 1; + fi diff --git a/CMakeLists.txt b/CMakeLists.txt index c8ecb5295..715679957 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,22 +234,18 @@ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") if ("${TARGET_ARCHITECTURE}" STREQUAL "x86_64") list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_USE_THREAD_LOCAL") endif() - z3_add_cxx_flag("-fno-strict-aliasing" REQUIRED) elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") # Does OSX really not need any special flags? message(STATUS "Platform: Darwin") elseif ("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") message(STATUS "Platform: FreeBSD") list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_FREEBSD_") - z3_add_cxx_flag("-fno-strict-aliasing" REQUIRED) elseif ("${CMAKE_SYSTEM_NAME}" MATCHES "OpenBSD") message(STATUS "Platform: OpenBSD") list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_OPENBSD_") - z3_add_cxx_flag("-fno-strict-aliasing" REQUIRED) elseif (CYGWIN) message(STATUS "Platform: Cygwin") list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_CYGWIN") - z3_add_cxx_flag("-fno-strict-aliasing" REQUIRED) elseif (WIN32) message(STATUS "Platform: Windows") list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_WINDOWS") @@ -257,8 +253,10 @@ else() message(FATAL_ERROR "Platform \"${CMAKE_SYSTEM_NAME}\" not recognised") endif() -list(APPEND Z3_COMPONENT_EXTRA_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/src") - +list(APPEND Z3_COMPONENT_EXTRA_INCLUDE_DIRS + "${CMAKE_BINARY_DIR}/src" + "${CMAKE_SOURCE_DIR}/src" +) ################################################################################ # GNU multiple precision library support ################################################################################ @@ -279,33 +277,37 @@ endif() ################################################################################ # OpenMP support ################################################################################ -option(USE_OPENMP "Use OpenMP" ON) -set(OPENMP_FOUND FALSE) -if (USE_OPENMP) - # Because this is on by default we make the configure succeed with a warning - # if OpenMP support is not detected. - find_package(OpenMP) - if (NOT OPENMP_FOUND) - message(WARNING "OpenMP support was requested but your compiler doesn't support it") - endif() -endif() - +find_package(OpenMP) if (OPENMP_FOUND) - list(APPEND Z3_COMPONENT_CXX_FLAGS ${OpenMP_CXX_FLAGS}) - # GCC and Clang need to have additional flags passed to the linker. - # We can't do ``target_link_libraries(libz3 INTERFACE ${OpenMP_CXX_FLAGS})`` - # because ``/openmp`` is interpreted as file name rather than a linker - # flag by MSVC and breaks the build - if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR - ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")) - list(APPEND Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS ${OpenMP_CXX_FLAGS}) - endif() - unset(CMAKE_REQUIRED_FLAGS) - message(STATUS "Using OpenMP") + set(USE_OPENMP_DEFAULT ON) +else() + set(USE_OPENMP_DEFAULT OFF) +endif() +# By setting `USE_OPENMP` this way configuration will fail during the first +# configure if the user explicitly passes `-DUSE_OPENMP=ON` and the compiler +# does not support OpenMP. However if the option is not set explicitly during +# the first configure OpenMP support will be automatically enabled/disabled +# depending on whether OpenMP is available. +option(USE_OPENMP "Use OpenMP" ${USE_OPENMP_DEFAULT}) + +if (USE_OPENMP) + if (NOT OPENMP_FOUND) + message(FATAL_ERROR "USE_OPENMP is ON but your compiler does not support OpenMP") + endif() + + list(APPEND Z3_COMPONENT_CXX_FLAGS ${OpenMP_CXX_FLAGS}) + # GCC and Clang need to have additional flags passed to the linker. + # We can't do ``target_link_libraries(libz3 INTERFACE ${OpenMP_CXX_FLAGS})`` + # because ``/openmp`` is interpreted as file name rather than a linker + # flag by MSVC and breaks the build + if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR + ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")) + list(APPEND Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS ${OpenMP_CXX_FLAGS}) + endif() + message(STATUS "Using OpenMP") else() list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_NO_OMP_") message(STATUS "Not using OpenMP") - set(USE_OPENMP OFF CACHE BOOL "Use OpenMP" FORCE) endif() ################################################################################ @@ -411,6 +413,38 @@ endif() ################################################################################ include(${CMAKE_SOURCE_DIR}/cmake/compiler_lto.cmake) +################################################################################ +# Control flow integrity +################################################################################ +option(ENABLE_CFI "Enable control flow integrity checking" OFF) +if (ENABLE_CFI) + set(build_types_with_cfi "RELEASE" "RELWITHDEBINFO") + if (NOT LINK_TIME_OPTIMIZATION) + message(FATAL_ERROR "Cannot enable control flow integrity checking without link-time optimization." + "You should set LINK_TIME_OPTIMIZATION to ON or ENABLE_CFI to OFF.") + endif() + if (DEFINED CMAKE_CONFIGURATION_TYPES) + # Multi configuration generator + message(STATUS "Note CFI is only enabled for the following configurations: ${build_types_with_cfi}") + # No need for else because this is the same as the set that LTO requires. + endif() + if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + z3_add_cxx_flag("-fsanitize=cfi" REQUIRED) + z3_add_cxx_flag("-fsanitize-cfi-cross-dso" REQUIRED) + elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") + z3_add_cxx_flag("/guard:cf" REQUIRED) + message(STATUS "Enabling CFI for MSVC") + foreach (_build_type ${build_types_with_cfi}) + message(STATUS "Enabling CFI for MSVC") + string(APPEND CMAKE_EXE_LINKER_FLAGS_${_build_type} " /GUARD:CF") + string(APPEND CMAKE_SHARED_LINKER_FLAGS_${_build_type} " /GUARD:CF") + endforeach() + else() + message(FATAL_ERROR "Can't enable control flow integrity for compiler \"${CMAKE_CXX_COMPILER_ID}\"." + "You should set ENABLE_CFI to OFF or use Clang or MSVC to compile.") + endif() +endif() + ################################################################################ # MSVC specific flags inherited from old build system ################################################################################ diff --git a/README-CMake.md b/README-CMake.md index 715cacad2..0d323e08f 100644 --- a/README-CMake.md +++ b/README-CMake.md @@ -265,9 +265,12 @@ The following useful options can be passed to CMake whilst configuring. * ``ALWAYS_BUILD_DOCS`` - BOOL. If set to ``TRUE`` and ``BUILD_DOCUMENTATION`` is ``TRUE`` then documentation for API bindings will always be built. Disabling this is useful for faster incremental builds. The documentation can be manually built by invoking the ``api_docs`` target. * ``LINK_TIME_OPTIMIZATION`` - BOOL. If set to ``TRUE`` link time optimization will be enabled. +* ``ENABLE_CFI`` - BOOL. If set to ``TRUE`` will enable Control Flow Integrity security checks. This is only supported by MSVC and Clang and will + fail on other compilers. This requires LINK_TIME_OPTIMIZATION to also be enabled. * ``API_LOG_SYNC`` - BOOL. If set to ``TRUE`` will enable experimental API log sync feature. * ``WARNINGS_AS_ERRORS`` - STRING. If set to ``TRUE`` compiler warnings will be treated as errors. If set to ``False`` compiler warnings will not be treated as errors. If set to ``SERIOUS_ONLY`` a subset of compiler warnings will be treated as errors. +* ``Z3_C_EXAMPLES_FORCE_CXX_LINKER`` - BOOL. If set to ``TRUE`` the C API examples will request that the C++ linker is used rather than the C linker. On the command line these can be passed to ``cmake`` using the ``-D`` option. In ``ccmake`` and ``cmake-gui`` these can be set in the user interface. diff --git a/README.md b/README.md index 197928877..70956d439 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z ## Build status -| Windows x86 | Windows x64 | Ubuntu x64 | Ubuntu x86 | Debian x64 | OSX | TravisCI | -| ----------- | ----------- | ---------- | ---------- | ---------- | --- | -------- | -[![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![ubuntu-x86-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/6/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=6) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) +| Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | OSX | TravisCI | +| ----------- | ----------- | ---------- | ---------- | --- | -------- | +[![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang @@ -124,7 +124,7 @@ utility is used to install ``Microsoft.Z3.dll`` into the [pkg-config](http://www.freedesktop.org/wiki/Software/pkg-config/) file (``Microsoft.Z3.Sharp.pc``) is also installed which allows the [MonoDevelop](http://www.monodevelop.com/) IDE to find the bindings. Running -``make uninstall`` will remove the dll from the GAC and the pkg-config file. +``make uninstall`` will remove the dll from the GAC and the ``pkg-config`` file. See [``examples/dotnet``](examples/dotnet) for examples. @@ -170,8 +170,8 @@ If you do need to install to a non standard prefix a better approach is to use a [Python virtual environment](https://virtualenv.readthedocs.org/en/latest/) and install Z3 there. Python packages also work for Python3. Under Windows, recall to build inside the Visual C++ native command build environment. -Note that the buit/python/z3 directory should be accessible from where python is used with Z3 -and it depends on libz3.dll to be in the path. +Note that the ``build/python/z3`` directory should be accessible from where python is used with Z3 +and it depends on ``libz3.dll`` to be in the path. ```bash virtualenv venv diff --git a/cmake/git_utils.cmake b/cmake/git_utils.cmake index f98aca205..dbc95d8df 100644 --- a/cmake/git_utils.cmake +++ b/cmake/git_utils.cmake @@ -4,23 +4,55 @@ # of the git directory changes CMake will be forced to re-run. This useful # for fetching the current git hash and including it in the build. # -# `GIT_DIR` is the path to the git directory (i.e. the `.git` directory) +# `GIT_DOT_FILE` is the path to the git directory (i.e. the `.git` directory) or +# `.git` file used by a git worktree. # `SUCCESS_VAR` is the name of the variable to set. It will be set to TRUE # if the dependency was successfully added and FALSE otherwise. -function(add_git_dir_dependency GIT_DIR SUCCESS_VAR) +function(add_git_dir_dependency GIT_DOT_FILE SUCCESS_VAR) if (NOT "${ARGC}" EQUAL 2) message(FATAL_ERROR "Invalid number (${ARGC}) of arguments") endif() - if (NOT IS_ABSOLUTE "${GIT_DIR}") - message(FATAL_ERROR "GIT_DIR (\"${GIT_DIR}\") is not an absolute path") + if (NOT IS_ABSOLUTE "${GIT_DOT_FILE}") + message(FATAL_ERROR "GIT_DOT_FILE (\"${GIT_DOT_FILE}\") is not an absolute path") endif() - if (NOT IS_DIRECTORY "${GIT_DIR}") - message(FATAL_ERROR "GIT_DIR (\"${GIT_DIR}\") is not a directory") + if (NOT EXISTS "${GIT_DOT_FILE}") + message(FATAL_ERROR "GIT_DOT_FILE (\"${GIT_DOT_FILE}\") does not exist") endif() - set(GIT_HEAD_FILE "${GIT_DIR}/HEAD") + if (NOT IS_DIRECTORY "${GIT_DOT_FILE}") + # Might be a git worktree. In this case we need parse out the worktree + # git directory + file(READ "${GIT_DOT_FILE}" GIT_DOT_FILE_DATA LIMIT 512) + string(STRIP "${GIT_DOT_FILE_DATA}" GIT_DOT_FILE_DATA_STRIPPED) + if ("${GIT_DOT_FILE_DATA_STRIPPED}" MATCHES "^gitdir:[ ]*(.+)$") + # Git worktree + message(STATUS "Found git worktree") + set(GIT_WORKTREE_DIR "${CMAKE_MATCH_1}") + set(GIT_HEAD_FILE "${GIT_WORKTREE_DIR}/HEAD") + # Figure out where real git directory lives + set(GIT_COMMON_DIR_FILE "${GIT_WORKTREE_DIR}/commondir") + if (NOT EXISTS "${GIT_COMMON_DIR_FILE}") + message(FATAL_ERROR "Found git worktree dir but could not find \"${GIT_COMMON_DIR_FILE}\"") + endif() + file(READ "${GIT_COMMON_DIR_FILE}" GIT_COMMON_DIR_FILE_DATA LIMIT 512) + string(STRIP "${GIT_COMMON_DIR_FILE_DATA}" GIT_COMMON_DIR_FILE_DATA_STRIPPED) + get_filename_component(GIT_DIR "${GIT_WORKTREE_DIR}/${GIT_COMMON_DIR_FILE_DATA_STRIPPED}" ABSOLUTE) + if (NOT IS_DIRECTORY "${GIT_DIR}") + message(FATAL_ERROR "Failed to compute path to git directory from git worktree") + endif() + else() + message(FATAL_ERROR "GIT_DOT_FILE (\"${GIT_DOT_FILE}\") is not a directory or a pointer to git worktree directory") + endif() + else() + # Just a normal `.git` directory + message(STATUS "Found simple git working directory") + set(GIT_HEAD_FILE "${GIT_DOT_FILE}/HEAD") + set(GIT_DIR "${GIT_DOT_FILE}") + endif() + message(STATUS "Found git directory \"${GIT_DIR}\"") + if (NOT EXISTS "${GIT_HEAD_FILE}") message(AUTHOR_WARNING "Git head file \"${GIT_HEAD_FILE}\" cannot be found") set(${SUCCESS_VAR} FALSE PARENT_SCOPE) @@ -79,24 +111,25 @@ function(add_git_dir_dependency GIT_DIR SUCCESS_VAR) set(${SUCCESS_VAR} TRUE PARENT_SCOPE) endfunction() -# get_git_head_hash(GIT_DIR OUTPUT_VAR) +# get_git_head_hash(GIT_DOT_FILE OUTPUT_VAR) # -# Retrieve the current commit hash for a git working directory where `GIT_DIR` -# is the `.git` directory in the root of the git working directory. +# Retrieve the current commit hash for a git working directory where +# `GIT_DOT_FILE` is the `.git` directory or `.git` pointer file in a git +# worktree in the root of the git working directory. # # `OUTPUT_VAR` should be the name of the variable to put the result in. If this # function fails then either a fatal error will be raised or `OUTPUT_VAR` will # contain a string with the suffix `NOTFOUND` which can be used in CMake `if()` # commands. -function(get_git_head_hash GIT_DIR OUTPUT_VAR) +function(get_git_head_hash GIT_DOT_FILE OUTPUT_VAR) if (NOT "${ARGC}" EQUAL 2) message(FATAL_ERROR "Invalid number of arguments") endif() - if (NOT IS_DIRECTORY "${GIT_DIR}") - message(FATAL_ERROR "\"${GIT_DIR}\" is not a directory") + if (NOT EXISTS "${GIT_DOT_FILE}") + message(FATAL_ERROR "\"${GIT_DOT_FILE}\" does not exist") endif() - if (NOT IS_ABSOLUTE "${GIT_DIR}") - message(FATAL_ERROR \""${GIT_DIR}\" is not an absolute path") + if (NOT IS_ABSOLUTE "${GIT_DOT_FILE}") + message(FATAL_ERROR \""${GIT_DOT_FILE}\" is not an absolute path") endif() find_package(Git) # NOTE: Use `GIT_FOUND` rather than `Git_FOUND` which was only @@ -105,7 +138,7 @@ function(get_git_head_hash GIT_DIR OUTPUT_VAR) set(${OUTPUT_VAR} "GIT-NOTFOUND" PARENT_SCOPE) return() endif() - get_filename_component(GIT_WORKING_DIR "${GIT_DIR}" DIRECTORY) + get_filename_component(GIT_WORKING_DIR "${GIT_DOT_FILE}" DIRECTORY) execute_process( COMMAND "${GIT_EXECUTABLE}" @@ -128,24 +161,25 @@ function(get_git_head_hash GIT_DIR OUTPUT_VAR) set(${OUTPUT_VAR} "${Z3_GIT_HASH}" PARENT_SCOPE) endfunction() -# get_git_head_describe(GIT_DIR OUTPUT_VAR) +# get_git_head_describe(GIT_DOT_FILE OUTPUT_VAR) # # Retrieve the output of `git describe` for a git working directory where -# `GIT_DIR` is the `.git` directory in the root of the git working directory. +# `GIT_DOT_FILE` is the `.git` directory or `.git` pointer file in a git +# worktree in the root of the git working directory. # # `OUTPUT_VAR` should be the name of the variable to put the result in. If this # function fails then either a fatal error will be raised or `OUTPUT_VAR` will # contain a string with the suffix `NOTFOUND` which can be used in CMake `if()` # commands. -function(get_git_head_describe GIT_DIR OUTPUT_VAR) +function(get_git_head_describe GIT_DOT_FILE OUTPUT_VAR) if (NOT "${ARGC}" EQUAL 2) message(FATAL_ERROR "Invalid number of arguments") endif() - if (NOT IS_DIRECTORY "${GIT_DIR}") - message(FATAL_ERROR "\"${GIT_DIR}\" is not a directory") + if (NOT EXISTS "${GIT_DOT_FILE}") + message(FATAL_ERROR "\"${GIT_DOT_FILE}\" does not exist") endif() - if (NOT IS_ABSOLUTE "${GIT_DIR}") - message(FATAL_ERROR \""${GIT_DIR}\" is not an absolute path") + if (NOT IS_ABSOLUTE "${GIT_DOT_FILE}") + message(FATAL_ERROR \""${GIT_DOT_FILE}\" is not an absolute path") endif() find_package(Git) # NOTE: Use `GIT_FOUND` rather than `Git_FOUND` which was only @@ -154,7 +188,7 @@ function(get_git_head_describe GIT_DIR OUTPUT_VAR) set(${OUTPUT_VAR} "GIT-NOTFOUND" PARENT_SCOPE) return() endif() - get_filename_component(GIT_WORKING_DIR "${GIT_DIR}" DIRECTORY) + get_filename_component(GIT_WORKING_DIR "${GIT_DOT_FILE}" DIRECTORY) execute_process( COMMAND "${GIT_EXECUTABLE}" diff --git a/cmake/msvc_legacy_quirks.cmake b/cmake/msvc_legacy_quirks.cmake index 2ca20277c..36fe82bb3 100644 --- a/cmake/msvc_legacy_quirks.cmake +++ b/cmake/msvc_legacy_quirks.cmake @@ -184,7 +184,12 @@ foreach (_build_type ${_build_types_as_upper}) # Address space layout randomization # See https://msdn.microsoft.com/en-us/library/bb384887.aspx string(APPEND CMAKE_EXE_LINKER_FLAGS_${_build_type} " /DYNAMICBASE") - string(APPEND CMAKE_SHARED_LINKER_FLAGS_${_build_type} " /DYNAMICBASE:NO") + if(ENABLE_CFI) + # CFI requires /DYNAMICBASE to be enabled. + string(APPEND CMAKE_SHARED_LINKER_FLAGS_${_build_type} " /DYNAMICBASE") + else() + string(APPEND CMAKE_SHARED_LINKER_FLAGS_${_build_type} " /DYNAMICBASE:NO") + endif() # FIXME: This is not necessary. This is MSVC's default. # Indicate that the executable is compatible with DEP diff --git a/cmake/z3_add_component.cmake b/cmake/z3_add_component.cmake index b70838750..d87ffbe61 100644 --- a/cmake/z3_add_component.cmake +++ b/cmake/z3_add_component.cmake @@ -36,15 +36,8 @@ function(z3_add_component_dependencies_to_target target_name) # Remaing args should be component names set(_expanded_deps ${ARGN}) foreach (dependency ${_expanded_deps}) - # FIXME: Adding these include paths wouldn't be necessary if the sources - # used include paths rooted in the ``src`` directory. - get_property(_dep_include_dirs GLOBAL PROPERTY Z3_${dependency}_INCLUDES) - foreach (inc_dir ${_dep_include_dirs}) - target_include_directories(${target_name} PRIVATE "${inc_dir}") - endforeach() - unset(_dep_include_dirs) # Ensure this component's dependencies are built before this component. - # This important because we might need the generated header files in + # This is important because we might need the generated header files in # other components. add_dependencies(${target_name} ${dependency}) endforeach() @@ -214,18 +207,14 @@ macro(z3_add_component component_name) target_compile_options(${component_name} PRIVATE ${flag}) endforeach() - # It's unfortunate that we have to manage the include directories and dependencies ourselves. + # It's unfortunate that we have to manage dependencies ourselves. # # If we weren't building "object" libraries we could use # ``` - # target_include_directories(${component_name} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") # target_link_libraries(${component_name} INTERFACE ${Z3_MOD_COMPONENT_DEPENDENCIES}) # ``` # but we can't do that with "object" libraries. - # Record this component's include directories - set_property(GLOBAL PROPERTY Z3_${component_name}_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}") - set_property(GLOBAL APPEND PROPERTY Z3_${component_name}_INCLUDES "${CMAKE_CURRENT_BINARY_DIR}") set_property(GLOBAL PROPERTY Z3_${component_name}_DEPS "") # Record this component's dependencies foreach (dependency ${Z3_MOD_COMPONENT_DEPENDENCIES}) @@ -243,12 +232,6 @@ macro(z3_add_component component_name) endif() #message(STATUS "Component \"${component_name}\" has the following dependencies ${_expanded_deps}") - # For any generated header files for this component - target_include_directories(${component_name} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") - # So that any generated header files can refer to source files in the component's - # source tree - target_include_directories(${component_name} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") - # Add any extra include directories foreach (extra_include ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS}) target_include_directories(${component_name} PRIVATE "${extra_include}") @@ -283,7 +266,6 @@ macro(z3_add_install_tactic_rule) endforeach() unset(_component_tactic_header_files) - list(APPEND _search_paths "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") add_custom_command(OUTPUT "install_tactic.cpp" COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/scripts/mk_install_tactic_cpp.py" @@ -311,13 +293,6 @@ macro(z3_add_memory_initializer_rule) ) endif() z3_expand_dependencies(_expanded_components ${ARGN}) - # Get paths to search - set(_search_paths "") - foreach (dependency ${_expanded_components}) - get_property(_dep_include_dirs GLOBAL PROPERTY Z3_${dependency}_INCLUDES) - list(APPEND _search_paths ${_dep_include_dirs}) - endforeach() - list(APPEND _search_paths "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") # Get header files that declare initializers and finalizers set(_mem_init_finalize_headers "") diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile index d8a32edea..87e3c8d67 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile @@ -30,6 +30,7 @@ RUN apt-get update && \ libgomp1 \ libomp5 \ libomp-dev \ + llvm-3.9 \ make \ mono-devel \ ninja-build \ @@ -47,4 +48,4 @@ RUN useradd -m user && \ echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers USER user WORKDIR /home/user - +ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.9/bin/llvm-symbolizer diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile index c28e59e97..c963ce255 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile @@ -16,6 +16,7 @@ RUN apt-get update && \ libgmp-dev \ libgomp1 \ lib32gomp1 \ + llvm-3.9 \ make \ mono-devel \ ninja-build \ @@ -32,4 +33,4 @@ RUN useradd -m user && \ echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers USER user WORKDIR /home/user - +ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.9/bin/llvm-symbolizer diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile index 98a5a3e09..08686e275 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile @@ -18,6 +18,7 @@ RUN apt-get update && \ libgomp1 \ libomp5 \ libomp-dev \ + llvm-3.9 \ make \ mono-devel \ ninja-build \ @@ -35,4 +36,4 @@ RUN useradd -m user && \ echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers USER user WORKDIR /home/user - +ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.9/bin/llvm-symbolizer diff --git a/contrib/ci/Dockerfiles/z3_build.Dockerfile b/contrib/ci/Dockerfiles/z3_build.Dockerfile index 2d16d5394..eb2e03a43 100644 --- a/contrib/ci/Dockerfiles/z3_build.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_build.Dockerfile @@ -2,37 +2,40 @@ ARG DOCKER_IMAGE_BASE FROM ${DOCKER_IMAGE_BASE} -# Specify defaults. This can be changed when invoking +# Build arguments. This can be changed when invoking # `docker build`. -ARG ASAN_BUILD=0 -ARG BUILD_DOCS=0 -ARG CC=gcc -ARG CXX=g++ -ARG DOTNET_BINDINGS=1 -ARG JAVA_BINDINGS=1 -ARG NO_SUPPRESS_OUTPUT=0 -ARG PYTHON_BINDINGS=1 +ARG ASAN_BUILD +ARG ASAN_DSO +ARG BUILD_DOCS +ARG CC +ARG CXX +ARG DOTNET_BINDINGS +ARG JAVA_BINDINGS +ARG NO_SUPPRESS_OUTPUT +ARG PYTHON_BINDINGS ARG PYTHON_EXECUTABLE=/usr/bin/python2.7 -ARG RUN_SYSTEM_TESTS=1 -ARG RUN_UNIT_TESTS=1 -ARG TARGET_ARCH=x86_64 -ARG TEST_INSTALL=1 -ARG UBSAN_BUILD=0 -ARG USE_LIBGMP=0 -ARG USE_LTO=0 -ARG USE_OPENMP=1 +ARG RUN_API_EXAMPLES +ARG RUN_SYSTEM_TESTS +ARG RUN_UNIT_TESTS +ARG SANITIZER_PRINT_SUPPRESSIONS +ARG TARGET_ARCH +ARG TEST_INSTALL +ARG UBSAN_BUILD +ARG USE_LIBGMP +ARG USE_LTO +ARG USE_OPENMP ARG Z3_SRC_DIR=/home/user/z3_src -ARG Z3_BUILD_TYPE=RelWithDebInfo -ARG Z3_CMAKE_GENERATOR=Ninja -ARG Z3_INSTALL_PREFIX=/usr -ARG Z3_STATIC_BUILD=0 -# Blank default indicates use latest. +ARG Z3_BUILD_TYPE +ARG Z3_CMAKE_GENERATOR +ARG Z3_INSTALL_PREFIX +ARG Z3_STATIC_BUILD ARG Z3_SYSTEM_TEST_GIT_REVISION -ARG Z3_WARNINGS_AS_ERRORS=SERIOUS_ONLY -ARG Z3_VERBOSE_BUILD_OUTPUT=0 +ARG Z3_WARNINGS_AS_ERRORS +ARG Z3_VERBOSE_BUILD_OUTPUT ENV \ ASAN_BUILD=${ASAN_BUILD} \ + ASAN_DSO=${ASAN_DSO} \ BUILD_DOCS=${BUILD_DOCS} \ CC=${CC} \ CXX=${CXX} \ @@ -41,6 +44,8 @@ ENV \ NO_SUPPRESS_OUTPUT=${NO_SUPPRESS_OUTPUT} \ PYTHON_BINDINGS=${PYTHON_BINDINGS} \ PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} \ + SANITIZER_PRINT_SUPPRESSIONS=${SANITIZER_PRINT_SUPPRESSIONS} \ + RUN_API_EXAMPLES=${RUN_API_EXAMPLES} \ RUN_SYSTEM_TESTS=${RUN_SYSTEM_TESTS} \ RUN_UNIT_TESTS=${RUN_UNIT_TESTS} \ TARGET_ARCH=${TARGET_ARCH} \ @@ -51,6 +56,7 @@ ENV \ USE_OPENMP=${USE_OPENMP} \ Z3_SRC_DIR=${Z3_SRC_DIR} \ Z3_BUILD_DIR=/home/user/z3_build \ + Z3_BUILD_TYPE=${Z3_BUILD_TYPE} \ Z3_CMAKE_GENERATOR=${Z3_CMAKE_GENERATOR} \ Z3_VERBOSE_BUILD_OUTPUT=${Z3_VERBOSE_BUILD_OUTPUT} \ Z3_STATIC_BUILD=${Z3_STATIC_BUILD} \ @@ -63,7 +69,8 @@ ENV \ # Build Z3 RUN mkdir -p "${Z3_SRC_DIR}" && \ - mkdir -p "${Z3_SRC_DIR}/contrib/ci/scripts" + mkdir -p "${Z3_SRC_DIR}/contrib/ci/scripts" && \ + mkdir -p "${Z3_SRC_DIR}/contrib/suppressions/sanitizers" # Deliberately leave out `contrib` ADD /cmake ${Z3_SRC_DIR}/cmake/ ADD /doc ${Z3_SRC_DIR}/doc/ @@ -74,6 +81,7 @@ ADD *.txt *.md RELEASE_NOTES ${Z3_SRC_DIR}/ ADD \ /contrib/ci/scripts/build_z3_cmake.sh \ + /contrib/ci/scripts/ci_defaults.sh \ /contrib/ci/scripts/set_compiler_flags.sh \ /contrib/ci/scripts/set_generator_args.sh \ ${Z3_SRC_DIR}/contrib/ci/scripts/ @@ -89,7 +97,13 @@ RUN ${Z3_SRC_DIR}/contrib/ci/scripts/test_z3_docs.sh # Test examples ADD \ /contrib/ci/scripts/test_z3_examples_cmake.sh \ + /contrib/ci/scripts/sanitizer_env.sh \ ${Z3_SRC_DIR}/contrib/ci/scripts/ +ADD \ + /contrib/suppressions/sanitizers/asan.txt \ + /contrib/suppressions/sanitizers/lsan.txt \ + /contrib/suppressions/sanitizers/ubsan.txt \ + ${Z3_SRC_DIR}/contrib/suppressions/sanitizers/ RUN ${Z3_SRC_DIR}/contrib/ci/scripts/test_z3_examples_cmake.sh # Run unit tests diff --git a/contrib/ci/README.md b/contrib/ci/README.md index 2e117c8b1..bd1c52792 100644 --- a/contrib/ci/README.md +++ b/contrib/ci/README.md @@ -30,8 +30,10 @@ the future. * `JAVA_BINDINGS` - Build and test Java API bindings (`0` or `1`) * `NO_SUPPRESS_OUTPUT` - Don't suppress output of some commands (`0` or `1`) * `PYTHON_BINDINGS` - Build and test Python API bindings (`0` or `1`) +* `RUN_API_EXAMPLES` - Build and run API examples (`0` or `1`) * `RUN_SYSTEM_TESTS` - Run system tests (`0` or `1`) -* `RUN_UNIT_TESTS` - Run unit tests (`0` or `1`) +* `RUN_UNIT_TESTS` - Run unit tests (`BUILD_ONLY` or `BUILD_AND_RUN` or `SKIP`) +* `SANITIZER_PRINT_SUPPRESSIONS` - Show ASan/UBSan suppressions (`0` or `1`) * `TARGET_ARCH` - Target architecture (`x86_64` or `i686`) * `TEST_INSTALL` - Test running `install` target (`0` or `1`) * `UBSAN_BUILD` - Do [UndefinedBehaviourSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) build (`0` or `1`) @@ -58,8 +60,9 @@ The `scripts/travis_ci_linux_entry_point.sh` script variables (if set) into the build using the `--build-arg` argument of the `docker run` command. -If an environemnt variable is not set a defaults value is used which can be -found in `Dockerfiles/z3_build.Dockerfile`. +The default values of the configuration environment variables +can be found in +[`scripts/ci_defaults.sh`](scripts/ci_defaults.sh). #### Linux specific configuration variables @@ -67,8 +70,9 @@ found in `Dockerfiles/z3_build.Dockerfile`. #### Reproducing a build locally -A build can be reproduced locally by using the `scripts/travis_ci_linux_entry_point.sh` -script and setting the appropriate environment variable. +A build can be reproduced locally by using the +`scripts/travis_ci_linux_entry_point.sh` script and setting the appropriate +environment variable. For example lets say we wanted to reproduce the build below. @@ -104,11 +108,43 @@ feature might be removed in the future. It may be better to just build the base image once (outside of TravisCI), upload it to [DockerHub](https://hub.docker.com/) and have the build pull down the pre-built -image everytime. +image every time. An [organization](https://hub.docker.com/u/z3prover/) has been created on DockerHub for this. ### macOS -Not yet implemented. +For macOS we execute directly on TravisCI's macOS environment. The entry point +for the TravisCI builds is the +[`scripts/travis_ci_osx_entry_point.sh`](scripts/travis_ci_osx_entry_point.sh) +scripts. + +#### macOS specific configuration variables + +* `MACOS_SKIP_DEPS_UPDATE` - If set to `1` installing the necessary build dependencies + is skipped. This is useful for local testing if the dependencies are already installed. +* `MACOS_UPDATE_CMAKE` - If set to `1` the installed version of CMake will be upgraded. + +#### Reproducing a build locally + +To reproduce a build (e.g. like the one shown below) + +```yaml +- os: osx + osx_image: xcode8.3 + # Note: Apple Clang does not support OpenMP + env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 +``` + +Run the following: + +```bash +TRAVIS_BUILD_DIR=$(pwd) \ +Z3_BUILD_TYPE=RelWithDebInfo \ +USE_OPEN_MP=0 \ +contrib/ci/scripts/travis_ci_osx_entry_point.sh +``` + +Note this assumes that the current working directory is the root of the Z3 +git repository. diff --git a/contrib/ci/scripts/build_z3_cmake.sh b/contrib/ci/scripts/build_z3_cmake.sh index 76fd0fb84..c1014d5d5 100755 --- a/contrib/ci/scripts/build_z3_cmake.sh +++ b/contrib/ci/scripts/build_z3_cmake.sh @@ -22,6 +22,7 @@ set -o pipefail : ${USE_LTO?"USE_LTO must be specified"} : ${Z3_INSTALL_PREFIX?"Z3_INSTALL_PREFIX must be specified"} : ${Z3_WARNINGS_AS_ERRORS?"Z3_WARNINGS_AS_ERRORS must be specified"} +: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"} ADDITIONAL_Z3_OPTS=() @@ -105,6 +106,16 @@ fi # Set compiler flags source ${SCRIPT_DIR}/set_compiler_flags.sh +if [ "X${UBSAN_BUILD}" = "X1" ]; then + # HACK: When building with UBSan the C++ linker + # must be used to avoid the following linker errors. + # undefined reference to `__ubsan_vptr_type_cache' + # undefined reference to `__ubsan_handle_dynamic_type_cache_miss' + ADDITIONAL_Z3_OPTS+=( \ + '-DZ3_C_EXAMPLES_FORCE_CXX_LINKER=ON' \ + ) +fi + # Sanity check if [ ! -e "${Z3_SRC_DIR}/CMakeLists.txt" ]; then echo "Z3_SRC_DIR is invalid" diff --git a/contrib/ci/scripts/ci_defaults.sh b/contrib/ci/scripts/ci_defaults.sh new file mode 100644 index 000000000..7a4434bd5 --- /dev/null +++ b/contrib/ci/scripts/ci_defaults.sh @@ -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 diff --git a/contrib/ci/scripts/install_deps_osx.sh b/contrib/ci/scripts/install_deps_osx.sh new file mode 100755 index 000000000..f9eb5a844 --- /dev/null +++ b/contrib/ci/scripts/install_deps_osx.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" +. ${SCRIPT_DIR}/run_quiet.sh + +set -x +set -e +set -o pipefail + +run_quiet brew update +export HOMEBREW_NO_AUTO_UPDATE=1 + +function brew_install_or_upgrade() { + if brew ls --versions "$1" > /dev/null 2>&1 ; then + brew upgrade "$1" + else + brew install "$1" + fi +} + +# FIXME: We should fix the versions of dependencies used +# so that we have reproducible builds. + +# HACK: Just use CMake version in TravisCI for now +if [ "X${MACOS_UPDATE_CMAKE}" = "X1" ]; then + brew_install_or_upgrade cmake +fi + +if [ "X${Z3_CMAKE_GENERATOR}" = "XNinja" ]; then + brew_install_or_upgrade ninja +fi + +if [ "X${USE_LIBGMP}" = "X1" ]; then + brew_install_or_upgrade gmp +fi + +if [ "X${BUILD_DOCS}" = "X1" ]; then + brew_install_or_upgrade doxygen +fi + +if [ "X${DOTNET_BINDINGS}" = "X1" ]; then + brew_install_or_upgrade mono +fi + +if [ "X${JAVA_BINDINGS}" = "X1" ]; then + brew cask install java +fi diff --git a/contrib/ci/scripts/run_quiet.sh b/contrib/ci/scripts/run_quiet.sh index 5abc910e8..0f49da3be 100644 --- a/contrib/ci/scripts/run_quiet.sh +++ b/contrib/ci/scripts/run_quiet.sh @@ -34,8 +34,8 @@ function run_quiet() { fi # Clean up rm "${STDOUT}" "${STDERR}" - [ $( echo "${OLD_SETTINGS}" | grep -c 'e') -ne 0 ] && set -e - [ $( echo "${OLD_SETTINGS}" | grep -c 'x') -ne 0 ] && set -x + [ "$( echo "${OLD_SETTINGS}" | grep -c 'e')" != "0" ] && set -e + [ "$( echo "${OLD_SETTINGS}" | grep -c 'x')" != "0" ] && set -x return ${EXIT_STATUS} fi } diff --git a/contrib/ci/scripts/sanitizer_env.sh b/contrib/ci/scripts/sanitizer_env.sh new file mode 100644 index 000000000..f1fa87442 --- /dev/null +++ b/contrib/ci/scripts/sanitizer_env.sh @@ -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 diff --git a/contrib/ci/scripts/set_generator_args.sh b/contrib/ci/scripts/set_generator_args.sh index 0ef7b76aa..a704c518b 100644 --- a/contrib/ci/scripts/set_generator_args.sh +++ b/contrib/ci/scripts/set_generator_args.sh @@ -1,4 +1,4 @@ -# This script should is intended to be included by other +# This script is intended to be included by other # scripts and should not be executed directly : ${Z3_CMAKE_GENERATOR?"Z3_CMAKE_GENERATOR must be specified"} diff --git a/contrib/ci/scripts/test_z3_examples_cmake.sh b/contrib/ci/scripts/test_z3_examples_cmake.sh index 2eda3de7b..687efebb4 100755 --- a/contrib/ci/scripts/test_z3_examples_cmake.sh +++ b/contrib/ci/scripts/test_z3_examples_cmake.sh @@ -14,6 +14,13 @@ set -o pipefail : ${PYTHON_EXECUTABLE?"PYTHON_EXECUTABLE must be specified"} : ${DOTNET_BINDINGS?"DOTNET_BINDINGS must be specified"} : ${JAVA_BINDINGS?"JAVA_BINDINGS must be specified"} +: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"} +: ${RUN_API_EXAMPLES?"RUN_API_EXAMPLES must be specified"} + +if [ "X${RUN_API_EXAMPLES}" = "X0" ]; then + echo "Skipping run of API examples" + exit 0 +fi # Set compiler flags source ${SCRIPT_DIR}/set_compiler_flags.sh @@ -21,6 +28,9 @@ source ${SCRIPT_DIR}/set_compiler_flags.sh # Set CMake generator args source ${SCRIPT_DIR}/set_generator_args.sh +# Sanitizer environment variables +source ${SCRIPT_DIR}/sanitizer_env.sh + cd "${Z3_BUILD_DIR}" # Build and run C example @@ -38,9 +48,21 @@ run_quiet examples/tptp_build_dir/z3_tptp5 -help # Build an run c_maxsat_example cmake --build $(pwd) --target c_maxsat_example "${GENERATOR_ARGS[@]}" -run_quiet \ - examples/c_maxsat_example_build_dir/c_maxsat_example \ - ${Z3_SRC_DIR}/examples/maxsat/ex.smt +# FIXME: It is known that the maxsat example leaks memory and the +# the Z3 developers have stated this is "wontfix". +# See https://github.com/Z3Prover/z3/issues/1299 +run_no_lsan \ + run_quiet \ + examples/c_maxsat_example_build_dir/c_maxsat_example \ + ${Z3_SRC_DIR}/examples/maxsat/ex.smt + +if [ "X${UBSAN_BUILD}" = "X1" ]; then + # FIXME: We really need libz3 to link against a shared UBSan runtime. + # Right now we link against the static runtime which breaks all the + # non-native language bindings. + echo "FIXME: Can't run other examples when building with UBSan" + exit 0 +fi if [ "X${PYTHON_BINDINGS}" = "X1" ]; then @@ -48,16 +70,21 @@ if [ "X${PYTHON_BINDINGS}" = "X1" ]; then # `all_interval_series.py` produces a lot of output so just throw # away output. # TODO: This example is slow should we remove it from testing? - run_quiet ${PYTHON_EXECUTABLE} python/all_interval_series.py - run_quiet ${PYTHON_EXECUTABLE} python/complex.py - run_quiet ${PYTHON_EXECUTABLE} python/example.py + if [ "X${ASAN_BUILD}" = "X1" -a "X${Z3_BUILD_TYPE}" = "XDebug" ]; then + # Too slow when doing ASan Debug build + echo "Skipping all_interval_series.py under ASan Debug build" + else + run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/all_interval_series.py + fi + run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/complex.py + run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/example.py # FIXME: `hamiltonian.py` example is disabled because its too slow. #${PYTHON_EXECUTABLE} python/hamiltonian.py - run_quiet ${PYTHON_EXECUTABLE} python/marco.py - run_quiet ${PYTHON_EXECUTABLE} python/mss.py - run_quiet ${PYTHON_EXECUTABLE} python/socrates.py - run_quiet ${PYTHON_EXECUTABLE} python/visitor.py - run_quiet ${PYTHON_EXECUTABLE} python/z3test.py + run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/marco.py + run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/mss.py + run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/socrates.py + run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/visitor.py + run_quiet run_non_native_binding ${PYTHON_EXECUTABLE} python/z3test.py fi if [ "X${DOTNET_BINDINGS}" = "X1" ]; then @@ -65,7 +92,7 @@ if [ "X${DOTNET_BINDINGS}" = "X1" ]; then # FIXME: Move compliation step into CMake target mcs ${Z3_SRC_DIR}/examples/dotnet/Program.cs /target:exe /out:dotnet_test.exe /reference:Microsoft.Z3.dll /r:System.Numerics.dll # Run .NET example - run_quiet mono ./dotnet_test.exe + run_quiet run_non_native_binding mono ./dotnet_test.exe fi if [ "X${JAVA_BINDINGS}" = "X1" ]; then @@ -82,6 +109,14 @@ if [ "X${JAVA_BINDINGS}" = "X1" ]; then # Assume Linux for now export LD_LIBRARY_PATH=$(pwd):${LD_LIBRARY_PATH} fi - run_quiet java -cp .:examples/java:com.microsoft.z3.jar JavaExample + if [ "X${ASAN_BUILD}" = "X1" ]; then + # The JVM seems to crash (SEGV) if we pre-load ASan + # so don't run it for now. + echo "Skipping JavaExample under ASan build" + else + run_quiet \ + run_non_native_binding \ + java -cp .:examples/java:com.microsoft.z3.jar JavaExample + fi fi diff --git a/contrib/ci/scripts/test_z3_system_tests.sh b/contrib/ci/scripts/test_z3_system_tests.sh index dfb1084a4..19c179268 100755 --- a/contrib/ci/scripts/test_z3_system_tests.sh +++ b/contrib/ci/scripts/test_z3_system_tests.sh @@ -10,12 +10,17 @@ set -o pipefail : ${PYTHON_BINDINGS?"PYTHON_BINDINGS must be specified"} : ${PYTHON_EXECUTABLE?"PYTHON_EXECUTABLE must be specified"} : ${Z3_SYSTEM_TEST_DIR?"Z3_SYSTEM_TEST_DIR must be specified"} +: ${UBSAN_BUILD?"UBSAN_BUILD must be specified"} if [ "X${RUN_SYSTEM_TESTS}" != "X1" ]; then echo "Skipping system tests" exit 0 fi +# Sanitizer environment variables +SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" +source ${SCRIPT_DIR}/sanitizer_env.sh + Z3_EXE="${Z3_BUILD_DIR}/z3" Z3_LIB_DIR="${Z3_BUILD_DIR}" @@ -23,7 +28,7 @@ Z3_LIB_DIR="${Z3_BUILD_DIR}" Z3_SYSTEM_TEST_GIT_URL="${Z3_GIT_URL:-https://github.com/Z3Prover/z3test.git}" # Clone repo to destination -mkdir -p "${Z3_SYSTEM_TEST_GIT_URL}" +mkdir -p "${Z3_SYSTEM_TEST_DIR}" git clone "${Z3_SYSTEM_TEST_GIT_URL}" "${Z3_SYSTEM_TEST_DIR}" cd "${Z3_SYSTEM_TEST_DIR}" @@ -48,7 +53,18 @@ fi if [ "X${PYTHON_BINDINGS}" = "X1" ]; then # Run python binding tests - ${PYTHON_EXECUTABLE} scripts/test_pyscripts.py "${Z3_LIB_DIR}" regressions/python/ + if [ "X${UBSAN_BUILD}" = "X1" ]; then + # FIXME: We need to build libz3 with a shared UBSan runtime for the bindings + # to work. + echo "FIXME: Skipping python binding tests when building with UBSan" + elif [ "X${ASAN_BUILD}" = "X1" ]; then + # FIXME: The `test_pyscripts.py` doesn't propagate LD_PRELOAD + # so under ASan the tests fail to run + # to work. + echo "FIXME: Skipping python binding tests when building with ASan" + else + run_non_native_binding ${PYTHON_EXECUTABLE} scripts/test_pyscripts.py "${Z3_LIB_DIR}" regressions/python/ + fi fi # FIXME: Run `scripts/test_cs.py` once it has been modified to support mono diff --git a/contrib/ci/scripts/test_z3_unit_tests_cmake.sh b/contrib/ci/scripts/test_z3_unit_tests_cmake.sh index 0d8e59b0f..60c29556b 100755 --- a/contrib/ci/scripts/test_z3_unit_tests_cmake.sh +++ b/contrib/ci/scripts/test_z3_unit_tests_cmake.sh @@ -1,6 +1,7 @@ #!/bin/bash SCRIPT_DIR="$( cd ${BASH_SOURCE[0]%/*} ; echo $PWD )" +. ${SCRIPT_DIR}/run_quiet.sh set -x set -e @@ -9,16 +10,38 @@ set -o pipefail : ${Z3_BUILD_DIR?"Z3_BUILD_DIR must be specified"} : ${RUN_UNIT_TESTS?"RUN_UNIT_TESTS must be specified"} -if [ "X${RUN_UNIT_TESTS}" != "X1" ]; then - echo "Skipping unit tests" - exit 0 -fi - # Set CMake generator args source ${SCRIPT_DIR}/set_generator_args.sh +# Sanitizer environment variables +source ${SCRIPT_DIR}/sanitizer_env.sh + cd "${Z3_BUILD_DIR}" -# Build and run internal tests -cmake --build $(pwd) --target test-z3 "${GENERATOR_ARGS[@]}" -./test-z3 +function build_unit_tests() { + # Build internal tests + cmake --build $(pwd) --target test-z3 "${GENERATOR_ARGS[@]}" +} + +function run_unit_tests() { + # Run all tests that don't require arguments + run_quiet ./test-z3 /a +} + +case "${RUN_UNIT_TESTS}" in + BUILD_AND_RUN) + build_unit_tests + run_unit_tests + ;; + BUILD_ONLY) + build_unit_tests + ;; + SKIP) + echo "RUN_UNIT_TESTS set to \"${RUN_UNIT_TESTS}\" so skipping build and run" + exit 0 + ;; + *) + echo "Error: RUN_UNIT_TESTS set to unhandled value \"${RUN_UNIT_TESTS}\"" + exit 1 + ;; +esac diff --git a/contrib/ci/scripts/travis_ci_linux_entry_point.sh b/contrib/ci/scripts/travis_ci_linux_entry_point.sh index 84b2dd400..731ea9ff0 100755 --- a/contrib/ci/scripts/travis_ci_linux_entry_point.sh +++ b/contrib/ci/scripts/travis_ci_linux_entry_point.sh @@ -11,16 +11,21 @@ DOCKER_FILE_DIR="$(cd ${SCRIPT_DIR}/../Dockerfiles; echo $PWD)" : ${LINUX_BASE?"LINUX_BASE must be specified"} - # Sanity check. Current working directory should be repo root if [ ! -f "./README.md" ]; then echo "Current working directory should be repo root" exit 1 fi +# Get defaults +source "${SCRIPT_DIR}/ci_defaults.sh" + BUILD_OPTS=() -# Override options if they have been provided. -# Otherwise the defaults in the Docker file will be used +# Pass Docker build arguments +if [ -n "${Z3_BUILD_TYPE}" ]; then + BUILD_OPTS+=("--build-arg" "Z3_BUILD_TYPE=${Z3_BUILD_TYPE}") +fi + if [ -n "${Z3_CMAKE_GENERATOR}" ]; then BUILD_OPTS+=("--build-arg" "Z3_CMAKE_GENERATOR=${Z3_CMAKE_GENERATOR}") fi @@ -79,6 +84,14 @@ if [ -n "${ASAN_BUILD}" ]; then BUILD_OPTS+=("--build-arg" "ASAN_BUILD=${ASAN_BUILD}") fi +if [ -n "${ASAN_DSO}" ]; then + BUILD_OPTS+=("--build-arg" "ASAN_DSO=${ASAN_DSO}") +fi + +if [ -n "${SANITIZER_PRINT_SUPPRESSIONS}" ]; then + BUILD_OPTS+=("--build-arg" "SANITIZER_PRINT_SUPPRESSIONS=${SANITIZER_PRINT_SUPPRESSIONS}") +fi + if [ -n "${UBSAN_BUILD}" ]; then BUILD_OPTS+=("--build-arg" "UBSAN_BUILD=${UBSAN_BUILD}") fi @@ -87,6 +100,10 @@ if [ -n "${TEST_INSTALL}" ]; then BUILD_OPTS+=("--build-arg" "TEST_INSTALL=${TEST_INSTALL}") fi +if [ -n "${RUN_API_EXAMPLES}" ]; then + BUILD_OPTS+=("--build-arg" "RUN_API_EXAMPLES=${RUN_API_EXAMPLES}") +fi + if [ -n "${RUN_SYSTEM_TESTS}" ]; then BUILD_OPTS+=("--build-arg" "RUN_SYSTEM_TESTS=${RUN_SYSTEM_TESTS}") fi diff --git a/contrib/ci/scripts/travis_ci_osx_entry_point.sh b/contrib/ci/scripts/travis_ci_osx_entry_point.sh index 03be81647..ad3b0c7ab 100755 --- a/contrib/ci/scripts/travis_ci_osx_entry_point.sh +++ b/contrib/ci/scripts/travis_ci_osx_entry_point.sh @@ -6,5 +6,46 @@ set -x set -e set -o pipefail -echo "Not implemented" -exit 1 +# Get defaults +source "${SCRIPT_DIR}/ci_defaults.sh" + +if [ -z "${TRAVIS_BUILD_DIR}" ]; then + echo "TRAVIS_BUILD_DIR must be set to root of Z3 repository" + exit 1 +fi + +if [ ! -d "${TRAVIS_BUILD_DIR}" ]; then + echo "TRAVIS_BUILD_DIR must be a directory" + exit 1 +fi + +# These variables are specific to the macOS TravisCI +# implementation and are not set in `ci_defaults.sh`. +export PYTHON_EXECUTABLE="${PYTHON_EXECUTABLE:-$(which python)}" +export Z3_SRC_DIR="${TRAVIS_BUILD_DIR}" +export Z3_BUILD_DIR="${Z3_SRC_DIR}/build" +export Z3_SYSTEM_TEST_DIR="${Z3_SRC_DIR}/z3_system_test" + +# Overwrite whatever what set in TravisCI +export CC="${C_COMPILER}" +export CXX="${CXX_COMPILER}" + +if [ "X${MACOS_SKIP_DEPS_UPDATE}" = "X1" ]; then + # This is just for local testing to avoid updating + echo "Skipping dependency update" +else + "${SCRIPT_DIR}/install_deps_osx.sh" +fi + +# Build Z3 +"${SCRIPT_DIR}/build_z3_cmake.sh" +# Test building docs +"${SCRIPT_DIR}/test_z3_docs.sh" +# Test examples +"${SCRIPT_DIR}/test_z3_examples_cmake.sh" +# Run unit tests +"${SCRIPT_DIR}/test_z3_unit_tests_cmake.sh" +# Run system tests +"${SCRIPT_DIR}/test_z3_system_tests.sh" +# Test install +"${SCRIPT_DIR}/test_z3_install_cmake.sh" diff --git a/contrib/suppressions/README.md b/contrib/suppressions/README.md new file mode 100644 index 000000000..90df39084 --- /dev/null +++ b/contrib/suppressions/README.md @@ -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. diff --git a/contrib/suppressions/maintainers.txt b/contrib/suppressions/maintainers.txt new file mode 100644 index 000000000..caa6798c6 --- /dev/null +++ b/contrib/suppressions/maintainers.txt @@ -0,0 +1,3 @@ +# Maintainers + +- Dan Liew (@delcypher) diff --git a/contrib/suppressions/sanitizers/README.md b/contrib/suppressions/sanitizers/README.md new file mode 100644 index 000000000..f76f920b2 --- /dev/null +++ b/contrib/suppressions/sanitizers/README.md @@ -0,0 +1,4 @@ +# Sanitizer supression files + +This directory contains files used to suppress +ASan/LSan/UBSan warnings/errors. diff --git a/contrib/suppressions/sanitizers/asan.txt b/contrib/suppressions/sanitizers/asan.txt new file mode 100644 index 000000000..f058adfe2 --- /dev/null +++ b/contrib/suppressions/sanitizers/asan.txt @@ -0,0 +1 @@ +# AddressSanitizer suppression file diff --git a/contrib/suppressions/sanitizers/lsan.txt b/contrib/suppressions/sanitizers/lsan.txt new file mode 100644 index 000000000..1480b7c09 --- /dev/null +++ b/contrib/suppressions/sanitizers/lsan.txt @@ -0,0 +1,5 @@ +# LeakSanitizer suppression file + +# Ignore Clang OpenMP leaks. +# See https://github.com/Z3Prover/z3/issues/1308 +leak:___kmp_allocate diff --git a/contrib/suppressions/sanitizers/ubsan.txt b/contrib/suppressions/sanitizers/ubsan.txt new file mode 100644 index 000000000..4d19e40be --- /dev/null +++ b/contrib/suppressions/sanitizers/ubsan.txt @@ -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 diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index 234dd670c..ab4d32d39 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -188,7 +188,7 @@ try: if Z3PY_ENABLED: print("Z3Py documentation enabled") - doxygen_config_substitutions['PYTHON_API_FILES'] = 'z3.py' + doxygen_config_substitutions['PYTHON_API_FILES'] = 'z3*.py' else: print("Z3Py documentation disabled") doxygen_config_substitutions['PYTHON_API_FILES'] = '' @@ -288,8 +288,21 @@ try: # Put z3py at the beginning of the search path to try to avoid picking up # an installed copy of Z3py. sys.path.insert(0, os.path.dirname(Z3PY_PACKAGE_PATH)) - pydoc.writedoc('z3') - shutil.move('z3.html', os.path.join(OUTPUT_DIRECTORY, 'html', 'z3.html')) + for modulename in ( + 'z3', + 'z3.z3consts', + 'z3.z3core', + 'z3.z3num', + 'z3.z3poly', + 'z3.z3printer', + 'z3.z3rcf', + 'z3.z3types', + 'z3.z3util', + ): + pydoc.writedoc(modulename) + doc = modulename + '.html' + shutil.move(doc, os.path.join(OUTPUT_DIRECTORY, 'html', doc)) + print("Generated pydoc Z3Py documentation.") if ML_ENABLED: diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ba7f6ee59..6c50320ed 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -7,6 +7,30 @@ else() set(EXTERNAL_PROJECT_BUILD_ALWAYS_ARG "") endif() +option(Z3_C_EXAMPLES_FORCE_CXX_LINKER + "Force C++ linker when building C example projects" OFF) + +if (Z3_C_EXAMPLES_FORCE_CXX_LINKER) + # HACK: This is a workaround for UBSan. + message(STATUS "Forcing C++ linker to be used when building example C projects") + set(EXTERNAL_C_PROJ_USE_CXX_LINKER_ARG + "-DFORCE_CXX_LINKER=ON" + ) +else() + set(EXTERNAL_C_PROJ_USE_CXX_LINKER_ARG "") +endif() + +if (DEFINED CMAKE_CONFIGURATION_TYPES) + message(WARNING + "Cannot set built type of external project when building with a " + "multi-configuration generator") + set(EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG "") +else() + set(EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG + "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}" + ) +endif() + ################################################################################ # Build example project using libz3's C API as an external project ################################################################################ @@ -14,7 +38,10 @@ ExternalProject_Add(c_example DEPENDS libz3 # Configure step SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/c" - CMAKE_ARGS "-DZ3_DIR=${CMAKE_BINARY_DIR}" + CMAKE_ARGS + "-DZ3_DIR=${CMAKE_BINARY_DIR}" + "${EXTERNAL_C_PROJ_USE_CXX_LINKER_ARG}" + "${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}" # Build step ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/c_example_build_dir" @@ -30,7 +57,10 @@ ExternalProject_Add(c_maxsat_example DEPENDS libz3 # Configure step SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/maxsat" - CMAKE_ARGS "-DZ3_DIR=${CMAKE_BINARY_DIR}" + CMAKE_ARGS + "-DZ3_DIR=${CMAKE_BINARY_DIR}" + "${EXTERNAL_C_PROJ_USE_CXX_LINKER_ARG}" + "${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}" # Build step ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/c_maxsat_example_build_dir" @@ -47,7 +77,9 @@ ExternalProject_Add(cpp_example DEPENDS libz3 # Configure step SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/c++" - CMAKE_ARGS "-DZ3_DIR=${CMAKE_BINARY_DIR}" + CMAKE_ARGS + "-DZ3_DIR=${CMAKE_BINARY_DIR}" + "${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}" # Build step ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/cpp_example_build_dir" @@ -63,7 +95,9 @@ ExternalProject_Add(z3_tptp5 DEPENDS libz3 # Configure step SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tptp" - CMAKE_ARGS "-DZ3_DIR=${CMAKE_BINARY_DIR}" + CMAKE_ARGS + "-DZ3_DIR=${CMAKE_BINARY_DIR}" + "${EXTERNAL_PROJECT_CMAKE_BUILD_TYPE_ARG}" # Build step ${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG} BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/tptp_build_dir" diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 2d7d051c5..035d032bc 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -470,7 +470,7 @@ void unsat_core_example2() { // The solver s already contains p1 => F // To disable F, we add (not p1) as an additional assumption qs.push_back(!p1); - std::cout << s.check(qs.size(), &qs[0]) << "\n"; + std::cout << s.check((unsigned)qs.size(), &qs[0]) << "\n"; expr_vector core2 = s.unsat_core(); std::cout << core2 << "\n"; std::cout << "size: " << core2.size() << "\n"; diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index dd8fa6328..c47a4947a 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -7,6 +7,19 @@ # the C++ standard library in resulting in a link failure. project(Z3_C_EXAMPLE C CXX) cmake_minimum_required(VERSION 2.8.12) + +# Set C version required to C99 +if ("${CMAKE_VERSION}" VERSION_LESS "3.1") + if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR + ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 ") + endif() +else() + set(CMAKE_C_STANDARD_REQUIRED ON) + set(CMAKE_C_STANDARD 99) + set(CMAKE_C_EXTENSIONS OFF) +endif() + find_package(Z3 REQUIRED CONFIG @@ -22,6 +35,17 @@ message(STATUS "Found Z3 ${Z3_VERSION_STRING}") message(STATUS "Z3_DIR: ${Z3_DIR}") add_executable(c_example test_capi.c) + +option(FORCE_CXX_LINKER "Force linker with C++ linker" OFF) +if (FORCE_CXX_LINKER) + # This is a hack for avoiding UBSan linking errors + message(STATUS "Forcing use of C++ linker") + set_target_properties(c_example + PROPERTIES + LINKER_LANGUAGE CXX + ) +endif() + target_include_directories(c_example PRIVATE ${Z3_C_INCLUDE_DIRS}) target_link_libraries(c_example PRIVATE ${Z3_LIBRARIES}) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 88fdaa1cf..f6d515389 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -65,6 +65,15 @@ void throw_z3_error(Z3_context c, Z3_error_code e) longjmp(g_catch_buffer, e); } +/** + \brief Error handling that depends on checking an error code on the context. + +*/ + +void nothrow_z3_error(Z3_context c, Z3_error_code e) { + // no-op +} + /** \brief Create a logical context. @@ -1592,18 +1601,16 @@ void error_code_example1() void error_code_example2() { Z3_config cfg; Z3_context ctx = NULL; - int r; + Z3_error_code e; printf("\nerror_code_example2\n"); LOG_MSG("error_code_example2"); - /* low tech try&catch */ - r = setjmp(g_catch_buffer); - if (r == 0) { + if (1) { Z3_ast x, y, app; cfg = Z3_mk_config(); - ctx = mk_context_custom(cfg, throw_z3_error); + ctx = mk_context_custom(cfg, nothrow_z3_error); Z3_del_config(cfg); x = mk_int_var(ctx, "x"); @@ -1611,11 +1618,14 @@ void error_code_example2() { printf("before Z3_mk_iff\n"); /* the next call will produce an error */ app = Z3_mk_iff(ctx, x, y); + e = Z3_get_error_code(ctx); + if (e != Z3_OK) goto err; unreachable(); Z3_del_context(ctx); } else { - printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, (Z3_error_code)r)); + err: + printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e)); if (ctx != NULL) { Z3_del_context(ctx); } @@ -1781,15 +1791,14 @@ void parser_example5() { Z3_config cfg; Z3_context ctx = NULL; Z3_solver s = NULL; - int r; + Z3_error_code e; printf("\nparser_example5\n"); LOG_MSG("parser_example5"); - r = setjmp(g_catch_buffer); - if (r == 0) { + if (1) { cfg = Z3_mk_config(); - ctx = mk_context_custom(cfg, throw_z3_error); + ctx = mk_context_custom(cfg, nothrow_z3_error); s = mk_solver(ctx); Z3_del_config(cfg); @@ -1798,12 +1807,15 @@ void parser_example5() { "(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))", 0, 0, 0, 0, 0, 0); + e = Z3_get_error_code(ctx); + if (e != Z3_OK) goto err; unreachable(); del_solver(ctx, s); Z3_del_context(ctx); } else { - printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, (Z3_error_code)r)); + err: + printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e)); if (ctx != NULL) { printf("Error message: '%s'.\n",Z3_get_smtlib_error(ctx)); del_solver(ctx, s); @@ -2639,6 +2651,7 @@ void smt2parser_example() { ctx = mk_context(); fs = Z3_parse_smtlib2_string(ctx, "(declare-fun a () (_ BitVec 8)) (assert (bvuge a #x10)) (assert (bvule a #xf0))", 0, 0, 0, 0, 0, 0); printf("formulas: %s\n", Z3_ast_to_string(ctx, fs)); + Z3_del_context(ctx); } @@ -2756,80 +2769,279 @@ void fpa_example() { double_sort = Z3_mk_fpa_sort(ctx, 11, 53); rm_sort = Z3_mk_fpa_rounding_mode_sort(ctx); - // Show that there are x, y s.t. (x + y) = 42.0 (with rounding mode). - s_rm = Z3_mk_string_symbol(ctx, "rm"); - rm = Z3_mk_const(ctx, s_rm, rm_sort); - s_x = Z3_mk_string_symbol(ctx, "x"); - s_y = Z3_mk_string_symbol(ctx, "y"); - x = Z3_mk_const(ctx, s_x, double_sort); - y = Z3_mk_const(ctx, s_y, double_sort); - n = Z3_mk_fpa_numeral_double(ctx, 42.0, double_sort); - - s_x_plus_y = Z3_mk_string_symbol(ctx, "x_plus_y"); - x_plus_y = Z3_mk_const(ctx, s_x_plus_y, double_sort); - c1 = Z3_mk_eq(ctx, x_plus_y, Z3_mk_fpa_add(ctx, rm, x, y)); - - args[0] = c1; - args[1] = Z3_mk_eq(ctx, x_plus_y, n); - c2 = Z3_mk_and(ctx, 2, (Z3_ast*)&args); - - args2[0] = c2; - args2[1] = Z3_mk_not(ctx, Z3_mk_eq(ctx, rm, Z3_mk_fpa_rtz(ctx))); - c3 = Z3_mk_and(ctx, 2, (Z3_ast*)&args2); - - and_args[0] = Z3_mk_not(ctx, Z3_mk_fpa_is_zero(ctx, y)); - and_args[1] = Z3_mk_not(ctx, Z3_mk_fpa_is_nan(ctx, y)); - and_args[2] = Z3_mk_not(ctx, Z3_mk_fpa_is_infinite(ctx, y)); - args3[0] = c3; - args3[1] = Z3_mk_and(ctx, 3, and_args); - c4 = Z3_mk_and(ctx, 2, (Z3_ast*)&args3); - - printf("c4: %s\n", Z3_ast_to_string(ctx, c4)); - Z3_solver_push(ctx, s); - Z3_solver_assert(ctx, s, c4); - check(ctx, s, Z3_L_TRUE); - Z3_solver_pop(ctx, s, 1); - - // Show that the following are equal: - // (fp #b0 #b10000000001 #xc000000000000) - // ((_ to_fp 11 53) #x401c000000000000)) - // ((_ to_fp 11 53) RTZ 1.75 2))) - // ((_ to_fp 11 53) RTZ 7.0))) - - Z3_solver_push(ctx, s); - c1 = Z3_mk_fpa_fp(ctx, - Z3_mk_numeral(ctx, "0", Z3_mk_bv_sort(ctx, 1)), - Z3_mk_numeral(ctx, "1025", Z3_mk_bv_sort(ctx, 11)), + // Show that there are x, y s.t. (x + y) = 42.0 (with rounding mode). + s_rm = Z3_mk_string_symbol(ctx, "rm"); + rm = Z3_mk_const(ctx, s_rm, rm_sort); + s_x = Z3_mk_string_symbol(ctx, "x"); + s_y = Z3_mk_string_symbol(ctx, "y"); + x = Z3_mk_const(ctx, s_x, double_sort); + y = Z3_mk_const(ctx, s_y, double_sort); + n = Z3_mk_fpa_numeral_double(ctx, 42.0, double_sort); + + s_x_plus_y = Z3_mk_string_symbol(ctx, "x_plus_y"); + x_plus_y = Z3_mk_const(ctx, s_x_plus_y, double_sort); + c1 = Z3_mk_eq(ctx, x_plus_y, Z3_mk_fpa_add(ctx, rm, x, y)); + + args[0] = c1; + args[1] = Z3_mk_eq(ctx, x_plus_y, n); + c2 = Z3_mk_and(ctx, 2, (Z3_ast*)&args); + + args2[0] = c2; + args2[1] = Z3_mk_not(ctx, Z3_mk_eq(ctx, rm, Z3_mk_fpa_rtz(ctx))); + c3 = Z3_mk_and(ctx, 2, (Z3_ast*)&args2); + + and_args[0] = Z3_mk_not(ctx, Z3_mk_fpa_is_zero(ctx, y)); + and_args[1] = Z3_mk_not(ctx, Z3_mk_fpa_is_nan(ctx, y)); + and_args[2] = Z3_mk_not(ctx, Z3_mk_fpa_is_infinite(ctx, y)); + args3[0] = c3; + args3[1] = Z3_mk_and(ctx, 3, and_args); + c4 = Z3_mk_and(ctx, 2, (Z3_ast*)&args3); + + printf("c4: %s\n", Z3_ast_to_string(ctx, c4)); + Z3_solver_push(ctx, s); + Z3_solver_assert(ctx, s, c4); + check(ctx, s, Z3_L_TRUE); + Z3_solver_pop(ctx, s, 1); + + // Show that the following are equal: + // (fp #b0 #b10000000001 #xc000000000000) + // ((_ to_fp 11 53) #x401c000000000000)) + // ((_ to_fp 11 53) RTZ 1.75 2))) + // ((_ to_fp 11 53) RTZ 7.0))) + + Z3_solver_push(ctx, s); + c1 = Z3_mk_fpa_fp(ctx, + Z3_mk_numeral(ctx, "0", Z3_mk_bv_sort(ctx, 1)), + Z3_mk_numeral(ctx, "1025", Z3_mk_bv_sort(ctx, 11)), Z3_mk_numeral(ctx, "3377699720527872", Z3_mk_bv_sort(ctx, 52))); - c2 = Z3_mk_fpa_to_fp_bv(ctx, - Z3_mk_numeral(ctx, "4619567317775286272", Z3_mk_bv_sort(ctx, 64)), - Z3_mk_fpa_sort(ctx, 11, 53)); + c2 = Z3_mk_fpa_to_fp_bv(ctx, + Z3_mk_numeral(ctx, "4619567317775286272", Z3_mk_bv_sort(ctx, 64)), + Z3_mk_fpa_sort(ctx, 11, 53)); c3 = Z3_mk_fpa_to_fp_int_real(ctx, Z3_mk_fpa_rtz(ctx), - Z3_mk_numeral(ctx, "2", Z3_mk_int_sort(ctx)), /* exponent */ + Z3_mk_numeral(ctx, "2", Z3_mk_int_sort(ctx)), /* exponent */ Z3_mk_numeral(ctx, "1.75", Z3_mk_real_sort(ctx)), /* significand */ Z3_mk_fpa_sort(ctx, 11, 53)); c4 = Z3_mk_fpa_to_fp_real(ctx, - Z3_mk_fpa_rtz(ctx), - Z3_mk_numeral(ctx, "7.0", Z3_mk_real_sort(ctx)), - Z3_mk_fpa_sort(ctx, 11, 53)); - args3[0] = Z3_mk_eq(ctx, c1, c2); - args3[1] = Z3_mk_eq(ctx, c1, c3); - args3[2] = Z3_mk_eq(ctx, c1, c4); - c5 = Z3_mk_and(ctx, 3, args3); - - printf("c5: %s\n", Z3_ast_to_string(ctx, c5)); - Z3_solver_assert(ctx, s, c5); - check(ctx, s, Z3_L_TRUE); - Z3_solver_pop(ctx, s, 1); - + Z3_mk_fpa_rtz(ctx), + Z3_mk_numeral(ctx, "7.0", Z3_mk_real_sort(ctx)), + Z3_mk_fpa_sort(ctx, 11, 53)); + args3[0] = Z3_mk_eq(ctx, c1, c2); + args3[1] = Z3_mk_eq(ctx, c1, c3); + args3[2] = Z3_mk_eq(ctx, c1, c4); + c5 = Z3_mk_and(ctx, 3, args3); + + printf("c5: %s\n", Z3_ast_to_string(ctx, c5)); + Z3_solver_assert(ctx, s, c5); + check(ctx, s, Z3_L_TRUE); + Z3_solver_pop(ctx, s, 1); + del_solver(ctx, s); Z3_del_context(ctx); } +/** + \brief Demonstrates some basic features of model construction +*/ + +void mk_model_example() { + Z3_context ctx; + Z3_model m; + Z3_sort intSort; + Z3_symbol aSymbol, bSymbol, cSymbol; + Z3_func_decl aFuncDecl, bFuncDecl, cFuncDecl; + Z3_ast aApp, bApp, cApp; + Z3_sort int2intArraySort; + Z3_ast zeroNumeral, oneNumeral, twoNumeral, threeNumeral, fourNumeral; + Z3_sort arrayDomain[1]; + Z3_func_decl cAsFuncDecl; + Z3_func_interp cAsFuncInterp; + Z3_ast_vector zeroArgs; + Z3_ast_vector oneArgs; + Z3_ast cFuncDeclAsArray; + Z3_string modelAsString; + + printf("\nmk_model_example\n"); + ctx = mk_context(); + // Construct empty model + m = Z3_mk_model(ctx); + Z3_model_inc_ref(ctx, m); + + // Create constants "a" and "b" + intSort = Z3_mk_int_sort(ctx); + aSymbol = Z3_mk_string_symbol(ctx, "a"); + aFuncDecl = Z3_mk_func_decl(ctx, aSymbol, + /*domain_size=*/0, + /*domain=*/NULL, + /*range=*/intSort); + aApp = Z3_mk_app(ctx, aFuncDecl, + /*num_args=*/0, + /*args=*/NULL); + bSymbol = Z3_mk_string_symbol(ctx, "b"); + bFuncDecl = Z3_mk_func_decl(ctx, bSymbol, + /*domain_size=*/0, + /*domain=*/NULL, + /*range=*/intSort); + bApp = Z3_mk_app(ctx, bFuncDecl, + /*num_args=*/0, + /*args=*/NULL); + + // Create array "c" that maps int to int. + cSymbol = Z3_mk_string_symbol(ctx, "c"); + int2intArraySort = Z3_mk_array_sort(ctx, + /*domain=*/intSort, + /*range=*/intSort); + cFuncDecl = Z3_mk_func_decl(ctx, cSymbol, + /*domain_size=*/0, + /*domain=*/NULL, + /*range=*/int2intArraySort); + cApp = Z3_mk_app(ctx, cFuncDecl, + /*num_args=*/0, + /*args=*/NULL); + + // Create numerals to be used in model + zeroNumeral = Z3_mk_int(ctx, 0, intSort); + oneNumeral = Z3_mk_int(ctx, 1, intSort); + twoNumeral = Z3_mk_int(ctx, 2, intSort); + threeNumeral = Z3_mk_int(ctx, 3, intSort); + fourNumeral = Z3_mk_int(ctx, 4, intSort); + + // Add assignments to model + // a == 1 + Z3_add_const_interp(ctx, m, aFuncDecl, oneNumeral); + // b == 2 + Z3_add_const_interp(ctx, m, bFuncDecl, twoNumeral); + + // Create a fresh function that represents + // reading from array. + arrayDomain[0] = intSort; + cAsFuncDecl = Z3_mk_fresh_func_decl(ctx, + /*prefix=*/"", + /*domain_size*/ 1, + /*domain=*/arrayDomain, + /*sort=*/intSort); + // Create function interpretation with default + // value of "0". + cAsFuncInterp = + Z3_add_func_interp(ctx, m, cAsFuncDecl, + /*default_value=*/zeroNumeral); + Z3_func_interp_inc_ref(ctx, cAsFuncInterp); + // Add [0] = 3 + zeroArgs = Z3_mk_ast_vector(ctx); + Z3_ast_vector_inc_ref(ctx, zeroArgs); + Z3_ast_vector_push(ctx, zeroArgs, zeroNumeral); + Z3_func_interp_add_entry(ctx, cAsFuncInterp, zeroArgs, threeNumeral); + // Add [1] = 4 + oneArgs = Z3_mk_ast_vector(ctx); + Z3_ast_vector_inc_ref(ctx, oneArgs); + Z3_ast_vector_push(ctx, oneArgs, oneNumeral); + Z3_func_interp_add_entry(ctx, cAsFuncInterp, oneArgs, fourNumeral); + + // Now use the `(_ as_array)` to associate + // the `cAsFuncInterp` with the `cFuncDecl` + // in the model + cFuncDeclAsArray = Z3_mk_as_array(ctx, cAsFuncDecl); + Z3_add_const_interp(ctx, m, cFuncDecl, cFuncDeclAsArray); + + // Print the model + modelAsString = Z3_model_to_string(ctx, m); + printf("Model:\n%s\n", modelAsString); + + // Check the interpretations we expect to be present + // are. + { + Z3_func_decl expectedInterpretations[3] = {aFuncDecl, bFuncDecl, cFuncDecl}; + int index; + for (index = 0; + index < sizeof(expectedInterpretations) / sizeof(Z3_func_decl); + ++index) { + Z3_func_decl d = expectedInterpretations[index]; + if (Z3_model_has_interp(ctx, m, d)) { + printf("Found interpretation for \"%s\"\n", + Z3_ast_to_string(ctx, Z3_func_decl_to_ast(ctx, d))); + } else { + printf("Missing interpretation"); + exit(1); + } + } + } + + { + // Evaluate a + b under model + Z3_ast addArgs[] = {aApp, bApp}; + Z3_ast aPlusB = Z3_mk_add(ctx, + /*num_args=*/2, + /*args=*/addArgs); + Z3_ast aPlusBEval = NULL; + Z3_bool aPlusBEvalSuccess = + Z3_model_eval(ctx, m, aPlusB, + /*model_completion=*/Z3_FALSE, &aPlusBEval); + if (aPlusBEvalSuccess != Z3_TRUE) { + printf("Failed to evaluate model\n"); + exit(1); + } + + { + int aPlusBValue = 0; + Z3_bool getAPlusBValueSuccess = + Z3_get_numeral_int(ctx, aPlusBEval, &aPlusBValue); + if (getAPlusBValueSuccess != Z3_TRUE) { + printf("Failed to get integer value for a+b\n"); + exit(1); + } + printf("Evaluated a + b = %d\n", aPlusBValue); + if (aPlusBValue != 3) { + printf("a+b did not evaluate to expected value\n"); + exit(1); + } + } + } + + { + // Evaluate c[0] + c[1] + c[2] under model + Z3_ast c0 = Z3_mk_select(ctx, cApp, zeroNumeral); + Z3_ast c1 = Z3_mk_select(ctx, cApp, oneNumeral); + Z3_ast c2 = Z3_mk_select(ctx, cApp, twoNumeral); + Z3_ast arrayAddArgs[] = {c0, c1, c2}; + Z3_ast arrayAdd = Z3_mk_add(ctx, + /*num_args=*/3, + /*args=*/arrayAddArgs); + Z3_ast arrayAddEval = NULL; + Z3_bool arrayAddEvalSuccess = + Z3_model_eval(ctx, m, arrayAdd, + /*model_completion=*/Z3_FALSE, &arrayAddEval); + if (arrayAddEvalSuccess != Z3_TRUE) { + printf("Failed to evaluate model\n"); + exit(1); + } + { + int arrayAddValue = 0; + Z3_bool getArrayAddValueSuccess = + Z3_get_numeral_int(ctx, arrayAddEval, &arrayAddValue); + if (getArrayAddValueSuccess != Z3_TRUE) { + printf("Failed to get integer value for c[0] + c[1] + c[2]\n"); + exit(1); + } + printf("Evaluated c[0] + c[1] + c[2] = %d\n", arrayAddValue); + if (arrayAddValue != 7) { + printf("c[0] + c[1] + c[2] did not evaluate to expected value\n"); + exit(1); + } + } + } + + Z3_ast_vector_dec_ref(ctx, oneArgs); + Z3_ast_vector_dec_ref(ctx, zeroArgs); + Z3_func_interp_dec_ref(ctx, cAsFuncInterp); + Z3_model_dec_ref(ctx, m); + Z3_del_context(ctx); +} + /*@}*/ /*@}*/ + + int main() { #ifdef LOG_Z3_CALLS Z3_open_log("z3.log"); @@ -2873,5 +3085,6 @@ int main() { substitute_example(); substitute_vars_example(); fpa_example(); + mk_model_example(); return 0; } diff --git a/examples/maxsat/CMakeLists.txt b/examples/maxsat/CMakeLists.txt index b48e167ea..019243ecf 100644 --- a/examples/maxsat/CMakeLists.txt +++ b/examples/maxsat/CMakeLists.txt @@ -25,6 +25,16 @@ add_executable(c_maxsat_example maxsat.c) target_include_directories(c_maxsat_example PRIVATE ${Z3_C_INCLUDE_DIRS}) target_link_libraries(c_maxsat_example PRIVATE ${Z3_LIBRARIES}) +option(FORCE_CXX_LINKER "Force linker with C++ linker" OFF) +if (FORCE_CXX_LINKER) + # This is a hack for avoiding UBSan linking errors + message(STATUS "Forcing use of C++ linker") + set_target_properties(c_maxsat_example + PROPERTIES + LINKER_LANGUAGE CXX + ) +endif() + if ("${CMAKE_SYSTEM_NAME}" MATCHES "[Ww]indows") # On Windows we need to copy the Z3 libraries # into the same directory as the executable diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index 21771cc04..2e0bbe2ca 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -587,6 +587,14 @@ def mk_def_file_internal(defname, dll_name, export_header_files): ############################################################################### # Functions for generating ``gparams_register_modules.cpp`` ############################################################################### + +def path_after_src(h_file): + h_file = h_file.replace("\\","/") + idx = h_file.rfind("src/") + if idx == -1: + return h_file + return h_file[idx + 4:] + def mk_gparams_register_modules_internal(h_files_full_path, path): """ Generate a ``gparams_register_modules.cpp`` file in the directory ``path``. @@ -608,7 +616,7 @@ def mk_gparams_register_modules_internal(h_files_full_path, path): fullname = os.path.join(path, 'gparams_register_modules.cpp') fout = open(fullname, 'w') fout.write('// Automatically generated file.\n') - fout.write('#include"gparams.h"\n') + fout.write('#include "util/gparams.h"\n') reg_pat = re.compile('[ \t]*REG_PARAMS\(\'([^\']*)\'\)') reg_mod_pat = re.compile('[ \t]*REG_MODULE_PARAMS\(\'([^\']*)\', *\'([^\']*)\'\)') reg_mod_descr_pat = re.compile('[ \t]*REG_MODULE_DESCRIPTION\(\'([^\']*)\', *\'([^\']*)\'\)') @@ -620,13 +628,13 @@ def mk_gparams_register_modules_internal(h_files_full_path, path): if m: if not added_include: added_include = True - fout.write('#include"%s"\n' % os.path.basename(h_file)) + fout.write('#include "%s"\n' % path_after_src(h_file)) cmds.append((m.group(1))) m = reg_mod_pat.match(line) if m: if not added_include: added_include = True - fout.write('#include"%s"\n' % os.path.basename(h_file)) + fout.write('#include "%s"\n' % path_after_src(h_file)) mod_cmds.append((m.group(1), m.group(2))) m = reg_mod_descr_pat.match(line) if m: @@ -680,9 +688,9 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path): fullname = os.path.join(path, 'install_tactic.cpp') fout = open(fullname, 'w') fout.write('// Automatically generated file.\n') - fout.write('#include"tactic.h"\n') - fout.write('#include"tactic_cmds.h"\n') - fout.write('#include"cmd_context.h"\n') + fout.write('#include "tactic/tactic.h"\n') + fout.write('#include "cmd_context/tactic_cmds.h"\n') + fout.write('#include "cmd_context/cmd_context.h"\n') tactic_pat = re.compile('[ \t]*ADD_TACTIC\(.*\)') probe_pat = re.compile('[ \t]*ADD_PROBE\(.*\)') for h_file in sorted_headers_by_component(h_files_full_path): @@ -691,8 +699,8 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path): for line in fin: if tactic_pat.match(line): if not added_include: - added_include = True - fout.write('#include"%s"\n' % os.path.basename(h_file)) + added_include = True + fout.write('#include "%s"\n' % path_after_src(h_file)) try: eval(line.strip('\n '), eval_globals, None) except Exception as e: @@ -702,7 +710,7 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path): if probe_pat.match(line): if not added_include: added_include = True - fout.write('#include"%s"\n' % os.path.basename(h_file)) + fout.write('#include "%s"\n' % path_after_src(h_file)) try: eval(line.strip('\n '), eval_globals, None) except Exception as e: @@ -764,19 +772,19 @@ def mk_mem_initializer_cpp_internal(h_files_full_path, path): if m: if not added_include: added_include = True - fout.write('#include"%s"\n' % os.path.basename(h_file)) + fout.write('#include "%s"\n' % path_after_src(h_file)) initializer_cmds.append((m.group(1), 0)) m = initializer_prio_pat.match(line) if m: if not added_include: added_include = True - fout.write('#include"%s"\n' % os.path.basename(h_file)) + fout.write('#include "%s"\n' % path_after_src(h_file)) initializer_cmds.append((m.group(1), int(m.group(2)))) m = finalizer_pat.match(line) if m: if not added_include: added_include = True - fout.write('#include"%s"\n' % os.path.basename(h_file)) + fout.write('#include "%s"\n' % path_after_src(h_file)) finalizer_cmds.append(m.group(1)) initializer_cmds.sort(key=lambda tup: tup[1]) fout.write('void mem_initialize() {\n') @@ -881,9 +889,9 @@ def mk_hpp_from_pyg(pyg_file, output_dir): out.write('// Automatically generated file\n') out.write('#ifndef __%s_HPP_\n' % class_name.upper()) out.write('#define __%s_HPP_\n' % class_name.upper()) - out.write('#include"params.h"\n') + out.write('#include "util/params.h"\n') if export: - out.write('#include"gparams.h"\n') + out.write('#include "util/gparams.h"\n') out.write('struct %s {\n' % class_name) out.write(' params_ref const & p;\n') if export: diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 8655346f2..05190f217 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -23,6 +23,7 @@ def init_project_def(): add_lib('subpaving', ['interval'], 'math/subpaving') add_lib('ast', ['util', 'polynomial']) add_lib('rewriter', ['ast', 'polynomial', 'automata'], 'ast/rewriter') + add_lib('macros', ['rewriter'], 'ast/macros') add_lib('normal_forms', ['rewriter'], 'ast/normal_forms') add_lib('model', ['rewriter']) add_lib('tactic', ['ast', 'model']) @@ -30,30 +31,26 @@ def init_project_def(): add_lib('parser_util', ['ast'], 'parsers/util') add_lib('grobner', ['ast'], 'math/grobner') add_lib('euclid', ['util'], 'math/euclid') - add_lib('core_tactics', ['tactic', 'normal_forms'], 'tactic/core') + add_lib('core_tactics', ['tactic', 'macros', 'normal_forms', 'rewriter'], 'tactic/core') add_lib('sat_tactic', ['tactic', 'sat'], 'sat/tactic') add_lib('arith_tactics', ['core_tactics', 'sat'], 'tactic/arith') add_lib('nlsat_tactic', ['nlsat', 'sat_tactic', 'arith_tactics'], 'nlsat/tactic') add_lib('subpaving_tactic', ['core_tactics', 'subpaving'], 'math/subpaving/tactic') add_lib('aig_tactic', ['tactic'], 'tactic/aig') - add_lib('solver', ['model', 'tactic']) + add_lib('proofs', ['rewriter', 'util'], 'ast/proofs') + add_lib('solver', ['model', 'tactic', 'proofs']) add_lib('ackermannization', ['model', 'rewriter', 'ast', 'solver', 'tactic'], 'ackermannization') add_lib('interp', ['solver']) add_lib('cmd_context', ['solver', 'rewriter', 'interp']) add_lib('extra_cmds', ['cmd_context', 'subpaving_tactic', 'arith_tactics'], 'cmd_context/extra_cmds') add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2') - add_lib('proof_checker', ['rewriter'], 'ast/proof_checker') - # Simplifier module will be deleted in the future. - # It has been replaced with rewriter module. - add_lib('simplifier', ['rewriter'], 'ast/simplifier') - add_lib('fpa', ['ast', 'util', 'simplifier', 'model'], 'ast/fpa') - add_lib('macros', ['simplifier'], 'ast/macros') - add_lib('pattern', ['normal_forms', 'smt2parser', 'simplifier'], 'ast/pattern') - add_lib('bit_blaster', ['rewriter', 'simplifier'], 'ast/rewriter/bit_blaster') - add_lib('smt_params', ['ast', 'simplifier', 'pattern', 'bit_blaster'], 'smt/params') - add_lib('proto_model', ['model', 'simplifier', 'smt_params'], 'smt/proto_model') + add_lib('fpa', ['ast', 'util', 'rewriter', 'model'], 'ast/fpa') + add_lib('pattern', ['normal_forms', 'smt2parser', 'rewriter'], 'ast/pattern') + add_lib('bit_blaster', ['rewriter', 'rewriter'], 'ast/rewriter/bit_blaster') + add_lib('smt_params', ['ast', 'rewriter', 'pattern', 'bit_blaster'], 'smt/params') + add_lib('proto_model', ['model', 'rewriter', 'smt_params'], 'smt/proto_model') add_lib('smt', ['bit_blaster', 'macros', 'normal_forms', 'cmd_context', 'proto_model', - 'substitution', 'grobner', 'euclid', 'simplex', 'proof_checker', 'pattern', 'parser_util', 'fpa', 'lp']) + 'substitution', 'grobner', 'euclid', 'simplex', 'proofs', 'pattern', 'parser_util', 'fpa', 'lp']) add_lib('bv_tactics', ['tactic', 'bit_blaster', 'core_tactics'], 'tactic/bv') add_lib('fuzzing', ['ast'], 'test/fuzzing') add_lib('smt_tactic', ['smt'], 'smt/tactic') @@ -65,12 +62,13 @@ def init_project_def(): add_lib('transforms', ['muz', 'hilbert', 'dataflow'], 'muz/transforms') add_lib('rel', ['muz', 'transforms'], 'muz/rel') add_lib('pdr', ['muz', 'transforms', 'arith_tactics', 'core_tactics', 'smt_tactic'], 'muz/pdr') + add_lib('spacer', ['muz', 'transforms', 'arith_tactics', 'smt_tactic'], 'muz/spacer') add_lib('clp', ['muz', 'transforms'], 'muz/clp') add_lib('tab', ['muz', 'transforms'], 'muz/tab') add_lib('bmc', ['muz', 'transforms'], 'muz/bmc') add_lib('ddnf', ['muz', 'transforms', 'rel'], 'muz/ddnf') add_lib('duality_intf', ['muz', 'transforms', 'duality'], 'muz/duality') - add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf', 'ddnf'], 'muz/fp') + add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf', 'ddnf', 'spacer'], 'muz/fp') add_lib('nlsat_smt_tactic', ['nlsat_tactic', 'smt_tactic'], 'tactic/nlsat_smt') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') add_lib('sat_solver', ['solver', 'core_tactics', 'aig_tactic', 'bv_tactics', 'arith_tactics', 'sat_tactic'], 'sat/sat_solver') @@ -79,7 +77,7 @@ def init_project_def(): add_lib('portfolio', ['smtlogic_tactics', 'sat_solver', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') add_lib('smtparser', ['portfolio'], 'parsers/smt') add_lib('opt', ['smt', 'smtlogic_tactics', 'sls_tactic', 'sat_solver'], 'opt') - API_files = ['z3_api.h', 'z3_ast_containers.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_fixedpoint.h', 'z3_optimization.h', 'z3_interp.h', 'z3_fpa.h'] + API_files = ['z3_api.h', 'z3_ast_containers.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_fixedpoint.h', 'z3_optimization.h', 'z3_interp.h', 'z3_fpa.h', 'z3_spacer.h'] add_lib('api', ['portfolio', 'smtparser', 'realclosure', 'interp', 'opt'], includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files) add_exe('shell', ['api', 'sat', 'extra_cmds','opt'], exe_name='z3') diff --git a/scripts/mk_util.py b/scripts/mk_util.py index a5f75fd1c..6f3052f6e 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1913,7 +1913,11 @@ class MLComponent(Component): src_dir = self.to_src_dir mk_dir(os.path.join(BUILD_DIR, self.sub_dir)) api_src = get_component(API_COMPONENT).to_src_dir - out.write('CXXFLAGS_OCAML=$(CXXFLAGS:/GL=)\n') # remove /GL; the ocaml tools don't like it. + # remove /GL and -std=c++11; the ocaml tools don't like them. + if IS_WINDOWS: + out.write('CXXFLAGS_OCAML=$(CXXFLAGS:/GL=)\n') + else: + out.write('CXXFLAGS_OCAML=$(subst -std=c++11,,$(CXXFLAGS))\n') if IS_WINDOWS: prefix_lib = '-L' + os.path.abspath(BUILD_DIR).replace('\\', '\\\\') @@ -2443,26 +2447,26 @@ def mk_config(): SO_EXT = '.dylib' SLIBFLAGS = '-dynamiclib' elif sysname == 'Linux': - CXXFLAGS = '%s -fno-strict-aliasing -D_LINUX_' % CXXFLAGS + CXXFLAGS = '%s -D_LINUX_' % CXXFLAGS OS_DEFINES = '-D_LINUX_' SO_EXT = '.so' LDFLAGS = '%s -lrt' % LDFLAGS SLIBFLAGS = '-shared' SLIBEXTRAFLAGS = '%s -lrt' % SLIBEXTRAFLAGS elif sysname == 'FreeBSD': - CXXFLAGS = '%s -fno-strict-aliasing -D_FREEBSD_' % CXXFLAGS + CXXFLAGS = '%s -D_FREEBSD_' % CXXFLAGS OS_DEFINES = '-D_FREEBSD_' SO_EXT = '.so' LDFLAGS = '%s -lrt' % LDFLAGS SLIBFLAGS = '-shared' SLIBEXTRAFLAGS = '%s -lrt' % SLIBEXTRAFLAGS elif sysname == 'OpenBSD': - CXXFLAGS = '%s -fno-strict-aliasing -D_OPENBSD_' % CXXFLAGS + CXXFLAGS = '%s -D_OPENBSD_' % CXXFLAGS OS_DEFINES = '-D_OPENBSD_' SO_EXT = '.so' SLIBFLAGS = '-shared' elif sysname[:6] == 'CYGWIN': - CXXFLAGS = '%s -D_CYGWIN -fno-strict-aliasing' % CXXFLAGS + CXXFLAGS = '%s -D_CYGWIN' % CXXFLAGS OS_DEFINES = '-D_CYGWIN' SO_EXT = '.dll' SLIBFLAGS = '-shared' @@ -3046,6 +3050,7 @@ def mk_vs_proj_cl_compile(f, name, components, debug): else: f.write(';') f.write(get_component(dep).to_src_dir) + f.write(';%s\n' % os.path.join(REV_BUILD_DIR, SRC_DIR)) f.write('\n') f.write(' \n') diff --git a/scripts/update_api.py b/scripts/update_api.py index cc96bd425..67a1b8a33 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -321,16 +321,19 @@ def mk_py_wrappers(): core_py.write("def %s(" % name) display_args(num) core_py.write("):\n") + core_py.write(" _lib = lib()\n") + core_py.write(" if _lib is None or _lib.%s is None:\n" % name) + core_py.write(" return\n") if result != VOID: - core_py.write(" r = lib().%s(" % name) + core_py.write(" r = _lib.%s(" % name) else: - core_py.write(" lib().%s(" % name) + core_py.write(" _lib.%s(" % name) display_args_to_z3(params) core_py.write(")\n") if len(params) > 0 and param_type(params[0]) == CONTEXT: - core_py.write(" err = lib().Z3_get_error_code(a0)\n") + core_py.write(" err = _lib.Z3_get_error_code(a0)\n") core_py.write(" if err != Z3_OK:\n") - core_py.write(" raise Z3Exception(lib().Z3_get_error_msg(a0, err))\n") + core_py.write(" raise Z3Exception(_lib.Z3_get_error_msg(a0, err))\n") if result == STRING: core_py.write(" return _to_pystr(r)\n") elif result != VOID: @@ -765,12 +768,12 @@ def mk_log_macro(file, name, params): cap = param_array_capacity_pos(p) if cap not in auxs: auxs.add(cap) - file.write("unsigned _Z3_UNUSED Z3ARG%s; " % cap) + file.write("unsigned _Z3_UNUSED Z3ARG%s = 0; " % cap) sz = param_array_size_pos(p) if sz not in auxs: auxs.add(sz) - file.write("unsigned * _Z3_UNUSED Z3ARG%s; " % sz) - file.write("%s _Z3_UNUSED Z3ARG%s; " % (param2str(p), i)) + file.write("unsigned * _Z3_UNUSED Z3ARG%s = 0; " % sz) + file.write("%s _Z3_UNUSED Z3ARG%s = 0; " % (param2str(p), i)) i = i + 1 file.write("if (_LOG_CTX.enabled()) { log_%s(" % name) i = 0 @@ -1570,7 +1573,7 @@ def def_APIs(api_files): def write_log_h_preamble(log_h): log_h.write('// Automatically generated file\n') - log_h.write('#include\"z3.h\"\n') + log_h.write('#include\"api/z3.h\"\n') log_h.write('#ifdef __GNUC__\n') log_h.write('#define _Z3_UNUSED __attribute__((unused))\n') log_h.write('#else\n') @@ -1589,17 +1592,22 @@ def write_log_h_preamble(log_h): def write_log_c_preamble(log_c): log_c.write('// Automatically generated file\n') log_c.write('#include\n') - log_c.write('#include\"z3.h\"\n') - log_c.write('#include\"api_log_macros.h\"\n') - log_c.write('#include\"z3_logger.h\"\n') + log_c.write('#include\"api/z3.h\"\n') + log_c.write('#include\"api/api_log_macros.h\"\n') + log_c.write('#include\"api/z3_logger.h\"\n') def write_exe_c_preamble(exe_c): exe_c.write('// Automatically generated file\n') - exe_c.write('#include\"z3.h\"\n') - exe_c.write('#include\"z3_replayer.h\"\n') + exe_c.write('#include\"api/z3.h\"\n') + exe_c.write('#include\"api/z3_replayer.h\"\n') # exe_c.write('void Z3_replayer_error_handler(Z3_context ctx, Z3_error_code c) { printf("[REPLAYER ERROR HANDLER]: %s\\n", Z3_get_error_msg(ctx, c)); }\n') +def write_core_py_post(core_py): + core_py.write(""" + +""") + def write_core_py_preamble(core_py): core_py.write('# Automatically generated file\n') core_py.write('import sys, os\n') @@ -1612,18 +1620,19 @@ def write_core_py_preamble(core_py): _ext = 'dll' if sys.platform in ('win32', 'cygwin') else 'dylib' if sys.platform == 'darwin' else 'so' _lib = None + def lib(): global _lib if _lib is None: - _dirs = ['.', os.path.dirname(os.path.abspath(__file__)), pkg_resources.resource_filename('z3', 'lib'), os.path.join(sys.prefix, 'lib'), None] - for _dir in _dirs: - try: - init(_dir) - break - except: - pass - if _lib is None: - raise Z3Exception("init(Z3_LIBRARY_PATH) must be invoked before using Z3-python") + _dirs = ['.', os.path.dirname(os.path.abspath(__file__)), pkg_resources.resource_filename('z3', 'lib'), os.path.join(sys.prefix, 'lib'), None] + for _dir in _dirs: + try: + init(_dir) + break + except: + pass + if _lib is None: + raise Z3Exception("init(Z3_LIBRARY_PATH) must be invoked before using Z3-python") return _lib def _to_ascii(s): @@ -1728,6 +1737,7 @@ def generate_files(api_files, def_APIs(api_files) mk_bindings(exe_c) mk_py_wrappers() + write_core_py_post(core_py) if mk_util.is_verbose(): print("Generated '{}'".format(log_h.name)) diff --git a/scripts/update_include.py b/scripts/update_include.py new file mode 100644 index 000000000..15e510041 --- /dev/null +++ b/scripts/update_include.py @@ -0,0 +1,69 @@ +# Copyright (c) 2017 Microsoft Corporation + +import os +import re + +is_include = re.compile("#include \"(.*)\"") +is_include2 = re.compile("#include\"(.*)\"") + + +def fix_include(file, paths): + tmp = "%s.tmp" % file + ins = open(file) + ous = open(tmp,'w') + line = ins.readline() + found = False + while line: + m = is_include.search(line) + if m and m.group(1) in paths: + ous.write("#include \"") + ous.write(paths[m.group(1)]) + ous.write("\"\n") + found = True + line = ins.readline() + continue + m = is_include2.search(line) + if m and m.group(1) in paths: + ous.write("#include \"") + ous.write(paths[m.group(1)]) + ous.write("\"\n") + found = True + line = ins.readline() + continue + ous.write(line) + line = ins.readline() + ins.close() + ous.close() + if found: + print(file) + os.system("move %s %s" % (tmp, file)) + else: + os.system("del %s" % tmp) + +def find_paths(dir): + paths = {} + for root, dirs, files in os.walk(dir): + root1 = root.replace("\\","/")[4:] + for f in files: + if f.endswith('.h') or f.endswith('.hpp') or f.endswith('.cpp'): + path = "%s/%s" % (root1, f) + paths[f] = path + if f.endswith('.pyg'): + f = f.replace("pyg","hpp") + path = "%s/%s" % (root1, f) + paths[f] = path + return paths + +paths = find_paths('src') + +def fixup(dir): + for root, dirs, files in os.walk(dir): + for f in files: + if f == "z3.h": + continue + if f.endswith('.h') or f.endswith('.cpp'): + path = "%s\\%s" % (root, f) + fix_include(path, paths) + + +fixup('src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dd440b34d..cfe6e5265 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,7 @@ set(Z3_API_HEADER_FILES_TO_SCAN z3_optimization.h z3_interp.h z3_fpa.h + z3_spacer.h ) set(Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN "") foreach (header_file ${Z3_API_HEADER_FILES_TO_SCAN}) @@ -66,10 +67,7 @@ add_subdirectory(interp) add_subdirectory(cmd_context) add_subdirectory(cmd_context/extra_cmds) add_subdirectory(parsers/smt2) -add_subdirectory(ast/proof_checker) -## Simplifier module will be deleted in the future. -## It has been replaced with rewriter component. -add_subdirectory(ast/simplifier) +add_subdirectory(ast/proofs) add_subdirectory(ast/fpa) add_subdirectory(ast/macros) add_subdirectory(ast/pattern) @@ -92,6 +90,7 @@ add_subdirectory(muz/tab) add_subdirectory(muz/bmc) add_subdirectory(muz/ddnf) add_subdirectory(muz/duality) +add_subdirectory(muz/spacer) add_subdirectory(muz/fp) add_subdirectory(tactic/nlsat_smt) add_subdirectory(tactic/ufbv) @@ -168,6 +167,7 @@ set (libz3_public_headers z3_polynomial.h z3_rcf.h z3_v1.h + z3_spacer.h ) foreach (header ${libz3_public_headers}) set_property(TARGET libz3 APPEND PROPERTY diff --git a/src/ackermannization/ackermannize_bv_model_converter.cpp b/src/ackermannization/ackermannize_bv_model_converter.cpp index d47735a56..360714c8b 100644 --- a/src/ackermannization/ackermannize_bv_model_converter.cpp +++ b/src/ackermannization/ackermannize_bv_model_converter.cpp @@ -14,8 +14,8 @@ Revision History: --*/ -#include"ackr_model_converter.h" -#include"ackermannize_bv_model_converter.h" +#include "ackermannization/ackr_model_converter.h" +#include "ackermannization/ackermannize_bv_model_converter.h" model_converter * mk_ackermannize_bv_model_converter(ast_manager & m, const ackr_info_ref& info) { return mk_ackr_model_converter(m, info); diff --git a/src/ackermannization/ackermannize_bv_model_converter.h b/src/ackermannization/ackermannize_bv_model_converter.h index e51792bad..d0255a0d4 100644 --- a/src/ackermannization/ackermannize_bv_model_converter.h +++ b/src/ackermannization/ackermannize_bv_model_converter.h @@ -17,8 +17,8 @@ #ifndef ACKERMANNIZE_BV_MODEL_CONVERTER_H_ #define ACKERMANNIZE_BV_MODEL_CONVERTER_H_ -#include"model_converter.h" -#include"ackr_info.h" +#include "tactic/model_converter.h" +#include "ackermannization/ackr_info.h" model_converter * mk_ackermannize_bv_model_converter(ast_manager & m, const ackr_info_ref& info); diff --git a/src/ackermannization/ackermannize_bv_tactic.cpp b/src/ackermannization/ackermannize_bv_tactic.cpp index 70230e346..82ef19274 100644 --- a/src/ackermannization/ackermannize_bv_tactic.cpp +++ b/src/ackermannization/ackermannize_bv_tactic.cpp @@ -13,12 +13,12 @@ Mikolas Janota Revision History: --*/ -#include"ackermannize_bv_tactic.h" -#include"tactical.h" -#include"lackr.h" -#include"model_smt2_pp.h" -#include"ackermannize_bv_tactic_params.hpp" -#include"ackermannize_bv_model_converter.h" +#include "ackermannization/ackermannize_bv_tactic.h" +#include "tactic/tactical.h" +#include "ackermannization/lackr.h" +#include "model/model_smt2_pp.h" +#include "ackermannization/ackermannize_bv_tactic_params.hpp" +#include "ackermannization/ackermannize_bv_model_converter.h" class ackermannize_bv_tactic : public tactic { diff --git a/src/ackermannization/ackermannize_bv_tactic.h b/src/ackermannization/ackermannize_bv_tactic.h index 3e3d5636c..803defb06 100644 --- a/src/ackermannization/ackermannize_bv_tactic.h +++ b/src/ackermannization/ackermannize_bv_tactic.h @@ -16,7 +16,7 @@ Revision History: #ifndef _ACKERMANNIZE_TACTIC_H_ #define _ACKERMANNIZE_TACTIC_H_ -#include"tactical.h" +#include "tactic/tactical.h" tactic * mk_ackermannize_bv_tactic(ast_manager & m, params_ref const & p); diff --git a/src/ackermannization/ackr_bound_probe.cpp b/src/ackermannization/ackr_bound_probe.cpp index 5cb8e9448..50b9cc092 100644 --- a/src/ackermannization/ackr_bound_probe.cpp +++ b/src/ackermannization/ackr_bound_probe.cpp @@ -14,9 +14,9 @@ Revision History: --*/ -#include"ackr_helper.h" -#include"ackr_bound_probe.h" -#include"ast_smt2_pp.h" +#include "ackermannization/ackr_helper.h" +#include "ackermannization/ackr_bound_probe.h" +#include "ast/ast_smt2_pp.h" /* For each function f, calculate the number of its occurrences o_f and compute "o_f choose 2". diff --git a/src/ackermannization/ackr_bound_probe.h b/src/ackermannization/ackr_bound_probe.h index 6c0a66605..169b3068e 100644 --- a/src/ackermannization/ackr_bound_probe.h +++ b/src/ackermannization/ackr_bound_probe.h @@ -18,7 +18,7 @@ #ifndef ACKR_BOUND_PROBE_H_ #define ACKR_BOUND_PROBE_H_ -#include"probe.h" +#include "tactic/probe.h" probe * mk_ackr_bound_probe(); diff --git a/src/ackermannization/ackr_helper.cpp b/src/ackermannization/ackr_helper.cpp index 803fc3c54..2e0fda687 100644 --- a/src/ackermannization/ackr_helper.cpp +++ b/src/ackermannization/ackr_helper.cpp @@ -14,7 +14,7 @@ Revision History: --*/ -#include"ackr_helper.h" +#include "ackermannization/ackr_helper.h" double ackr_helper::calculate_lemma_bound(ackr_helper::fun2terms_map& occurrences) { fun2terms_map::iterator it = occurrences.begin(); diff --git a/src/ackermannization/ackr_helper.h b/src/ackermannization/ackr_helper.h index 327763da4..651b25b12 100644 --- a/src/ackermannization/ackr_helper.h +++ b/src/ackermannization/ackr_helper.h @@ -17,7 +17,7 @@ #ifndef ACKR_HELPER_H_ #define ACKR_HELPER_H_ -#include"bv_decl_plugin.h" +#include "ast/bv_decl_plugin.h" class ackr_helper { public: diff --git a/src/ackermannization/ackr_info.h b/src/ackermannization/ackr_info.h index 76be45e2b..0b67e144f 100644 --- a/src/ackermannization/ackr_info.h +++ b/src/ackermannization/ackr_info.h @@ -16,11 +16,11 @@ Revision History: #ifndef ACKR_INFO_H_ #define ACKR_INFO_H_ -#include"obj_hashtable.h" -#include"ast.h" -#include"ref.h" -#include"expr_replacer.h" -#include"ast_translation.h" +#include "util/obj_hashtable.h" +#include "ast/ast.h" +#include "util/ref.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/ast_translation.h" /** \brief Information about how a formula is being converted into diff --git a/src/ackermannization/ackr_model_converter.cpp b/src/ackermannization/ackr_model_converter.cpp index ea4f858ad..a7c021913 100644 --- a/src/ackermannization/ackr_model_converter.cpp +++ b/src/ackermannization/ackr_model_converter.cpp @@ -3,27 +3,27 @@ Copyright (c) 2015 Microsoft Corporation Module Name: -ackr_model_converter.cpp + ackr_model_converter.cpp Abstract: Author: -Mikolas Janota + Mikolas Janota Revision History: --*/ -#include"ackr_model_converter.h" -#include"model_evaluator.h" -#include"ast_smt2_pp.h" -#include"ackr_info.h" +#include "ackermannization/ackr_model_converter.h" +#include "model/model_evaluator.h" +#include "ast/ast_smt2_pp.h" +#include "ackermannization/ackr_info.h" class ackr_model_converter : public model_converter { public: ackr_model_converter(ast_manager & m, - const ackr_info_ref& info, - model_ref& abstr_model) + const ackr_info_ref& info, + model_ref& abstr_model) : m(m) , info(info) , abstr_model(abstr_model) @@ -31,7 +31,7 @@ public: { } ackr_model_converter(ast_manager & m, - const ackr_info_ref& info) + const ackr_info_ref& info) : m(m) , info(info) , fixed_model(false) @@ -51,8 +51,6 @@ public: virtual void operator()(model_ref & md) { operator()(md, 0); } - //void display(std::ostream & out); - virtual model_converter * translate(ast_translation & translator) { ackr_info_ref retv_info = info->translate(translator); if (fixed_model) { @@ -63,42 +61,45 @@ public: return alloc(ackr_model_converter, translator.to(), retv_info); } } + protected: - ast_manager& m; + ast_manager & m; const ackr_info_ref info; model_ref abstr_model; bool fixed_model; void convert(model * source, model * destination); void add_entry(model_evaluator & evaluator, - app* term, expr* value, - obj_map& interpretations); + app* term, expr* value, + obj_map& interpretations); void convert_constants(model * source, model * destination); }; void ackr_model_converter::convert(model * source, model * destination) { destination->copy_func_interps(*source); destination->copy_usort_interps(*source); - convert_constants(source,destination); + convert_constants(source, destination); } void ackr_model_converter::convert_constants(model * source, model * destination) { TRACE("ackr_model", tout << "converting constants\n";); obj_map interpretations; model_evaluator evaluator(*source); + evaluator.set_model_completion(true); for (unsigned i = 0; i < source->get_num_constants(); i++) { func_decl * const c = source->get_constant(i); app * const term = info->find_term(c); expr * value = source->get_const_interp(c); - if(!term) { + if (!term) { destination->register_decl(c, value); - } else { + } + else { add_entry(evaluator, term, value, interpretations); } } obj_map::iterator e = interpretations.end(); for (obj_map::iterator i = interpretations.begin(); - i!=e; ++i) { + i != e; ++i) { func_decl* const fd = i->m_key; func_interp* const fi = i->get_value(); fi->set_else(m.get_some_value(fd->get_range())); @@ -107,34 +108,40 @@ void ackr_model_converter::convert_constants(model * source, model * destination } void ackr_model_converter::add_entry(model_evaluator & evaluator, - app* term, expr* value, - obj_map& interpretations) { + app* term, expr* value, + obj_map& interpretations) { TRACE("ackr_model", tout << "add_entry" - << mk_ismt2_pp(term, m, 2) - << "->" - << mk_ismt2_pp(value, m, 2) << "\n"; + << mk_ismt2_pp(term, m, 2) + << "->" + << mk_ismt2_pp(value, m, 2) << "\n"; ); - func_interp* fi = 0; + func_interp * fi = 0; func_decl * const declaration = term->get_decl(); const unsigned sz = declaration->get_arity(); SASSERT(sz == term->get_num_args()); - if (!interpretations.find(declaration, fi)) { - fi = alloc(func_interp,m,sz); - interpretations.insert(declaration, fi); + if (!interpretations.find(declaration, fi)) { + fi = alloc(func_interp, m, sz); + interpretations.insert(declaration, fi); } expr_ref_vector args(m); for (unsigned gi = 0; gi < sz; ++gi) { - expr * const arg = term->get_arg(gi); - expr_ref aarg(m); - info->abstract(arg, aarg); - expr_ref arg_value(m); - evaluator(aarg,arg_value); - args.push_back(arg_value); + expr * const arg = term->get_arg(gi); + expr_ref aarg(m); + info->abstract(arg, aarg); + expr_ref arg_value(m); + evaluator(aarg, arg_value); + args.push_back(arg_value); } if (fi->get_entry(args.c_ptr()) == 0) { + TRACE("ackr_model", + tout << mk_ismt2_pp(declaration, m) << " args: " << std::endl; + for (unsigned i = 0; i < args.size(); i++) + tout << mk_ismt2_pp(args.get(i), m) << std::endl; + tout << " -> " << mk_ismt2_pp(value, m) << "\n"; ); fi->insert_new_entry(args.c_ptr(), value); - } else { + } + else { TRACE("ackr_model", tout << "entry already present\n";); } } diff --git a/src/ackermannization/ackr_model_converter.h b/src/ackermannization/ackr_model_converter.h index 2c1f0c78c..659b45926 100644 --- a/src/ackermannization/ackr_model_converter.h +++ b/src/ackermannization/ackr_model_converter.h @@ -3,23 +3,23 @@ Copyright (c) 2015 Microsoft Corporation Module Name: -ackr_model_converter.h + ackr_model_converter.h Abstract: Author: -Mikolas Janota + Mikolas Janota Revision History: --*/ #ifndef ACKR_MODEL_CONVERTER_H_ #define ACKR_MODEL_CONVERTER_H_ -#include"model_converter.h" -#include"ackr_info.h" +#include "tactic/model_converter.h" +#include "ackermannization/ackr_info.h" -model_converter * mk_ackr_model_converter(ast_manager & m, const ackr_info_ref& info, model_ref& abstr_model); -model_converter * mk_ackr_model_converter(ast_manager & m, const ackr_info_ref& info); +model_converter * mk_ackr_model_converter(ast_manager & m, const ackr_info_ref & info, model_ref & abstr_model); +model_converter * mk_ackr_model_converter(ast_manager & m, const ackr_info_ref & info); #endif /* LACKR_MODEL_CONVERTER_H_ */ diff --git a/src/ackermannization/lackr.cpp b/src/ackermannization/lackr.cpp index 461d2080f..aac98d7dc 100644 --- a/src/ackermannization/lackr.cpp +++ b/src/ackermannization/lackr.cpp @@ -15,13 +15,13 @@ Revision History: --*/ -#include"lackr.h" -#include"ackermannization_params.hpp" -#include"tactic.h" -#include"lackr_model_constructor.h" -#include"ackr_info.h" -#include"for_each_expr.h" -#include"model_smt2_pp.h" +#include "ackermannization/lackr.h" +#include "ackermannization/ackermannization_params.hpp" +#include "tactic/tactic.h" +#include "ackermannization/lackr_model_constructor.h" +#include "ackermannization/ackr_info.h" +#include "ast/for_each_expr.h" +#include "model/model_smt2_pp.h" lackr::lackr(ast_manager& m, params_ref p, lackr_stats& st, expr_ref_vector& formulas, solver * uffree_solver) diff --git a/src/ackermannization/lackr.h b/src/ackermannization/lackr.h index 4bf1d6965..554ad6ef8 100644 --- a/src/ackermannization/lackr.h +++ b/src/ackermannization/lackr.h @@ -17,17 +17,17 @@ #ifndef LACKR_H_ #define LACKR_H_ -#include"ackr_info.h" -#include"ackr_helper.h" -#include"th_rewriter.h" -#include"cooperate.h" -#include"bv_decl_plugin.h" -#include"lbool.h" -#include"model.h" -#include"solver.h" -#include"util.h" -#include"tactic_exception.h" -#include"goal.h" +#include "ackermannization/ackr_info.h" +#include "ackermannization/ackr_helper.h" +#include "ast/rewriter/th_rewriter.h" +#include "util/cooperate.h" +#include "ast/bv_decl_plugin.h" +#include "util/lbool.h" +#include "model/model.h" +#include "solver/solver.h" +#include "util/util.h" +#include "tactic/tactic_exception.h" +#include "tactic/goal.h" struct lackr_stats { lackr_stats() : m_it(0), m_ackrs_sz(0) {} diff --git a/src/ackermannization/lackr_model_constructor.cpp b/src/ackermannization/lackr_model_constructor.cpp index 8e99fe2a2..641c70cbc 100644 --- a/src/ackermannization/lackr_model_constructor.cpp +++ b/src/ackermannization/lackr_model_constructor.cpp @@ -14,13 +14,13 @@ Revision History: --*/ -#include"lackr_model_constructor.h" -#include"model_evaluator.h" -#include"ast_smt2_pp.h" -#include"ackr_info.h" -#include"for_each_expr.h" -#include"bv_rewriter.h" -#include"bool_rewriter.h" +#include "ackermannization/lackr_model_constructor.h" +#include "model/model_evaluator.h" +#include "ast/ast_smt2_pp.h" +#include "ackermannization/ackr_info.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/bv_rewriter.h" +#include "ast/rewriter/bool_rewriter.h" struct lackr_model_constructor::imp { public: diff --git a/src/ackermannization/lackr_model_constructor.h b/src/ackermannization/lackr_model_constructor.h index 71c9c0710..d5847a24c 100644 --- a/src/ackermannization/lackr_model_constructor.h +++ b/src/ackermannization/lackr_model_constructor.h @@ -18,10 +18,10 @@ #ifndef LACKR_MODEL_CONSTRUCTOR_H_ #define LACKR_MODEL_CONSTRUCTOR_H_ -#include"ast.h" -#include"ackr_info.h" -#include"ackr_helper.h" -#include"model.h" +#include "ast/ast.h" +#include "ackermannization/ackr_info.h" +#include "ackermannization/ackr_helper.h" +#include "model/model.h" class lackr_model_constructor { public: diff --git a/src/ackermannization/lackr_model_converter_lazy.cpp b/src/ackermannization/lackr_model_converter_lazy.cpp index 5a0d1c4be..2a7adb839 100644 --- a/src/ackermannization/lackr_model_converter_lazy.cpp +++ b/src/ackermannization/lackr_model_converter_lazy.cpp @@ -14,11 +14,11 @@ Revision History: --*/ -#include"lackr_model_converter_lazy.h" -#include"model_evaluator.h" -#include"ast_smt2_pp.h" -#include"ackr_info.h" -#include"lackr_model_constructor.h" +#include "ackermannization/lackr_model_converter_lazy.h" +#include "model/model_evaluator.h" +#include "ast/ast_smt2_pp.h" +#include "ackermannization/ackr_info.h" +#include "ackermannization/lackr_model_constructor.h" class lackr_model_converter_lazy : public model_converter { public: diff --git a/src/ackermannization/lackr_model_converter_lazy.h b/src/ackermannization/lackr_model_converter_lazy.h index c9b3eac80..0581976a9 100644 --- a/src/ackermannization/lackr_model_converter_lazy.h +++ b/src/ackermannization/lackr_model_converter_lazy.h @@ -17,8 +17,8 @@ #ifndef LACKR_MODEL_CONVERTER_LAZY_H_ #define LACKR_MODEL_CONVERTER_LAZY_H_ -#include"model_converter.h" -#include"ackr_info.h" +#include "tactic/model_converter.h" +#include "ackermannization/ackr_info.h" model_converter * mk_lackr_model_converter_lazy(ast_manager & m, const ackr_info_ref& info, model_ref& abstr_model); diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt index 79c5fc1c9..a413376ac 100644 --- a/src/api/CMakeLists.txt +++ b/src/api/CMakeLists.txt @@ -57,6 +57,7 @@ z3_add_component(api api_parsers.cpp api_pb.cpp api_polynomial.cpp + api_qe.cpp api_quant.cpp api_rcf.cpp api_seq.cpp diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index c4e4dac5d..96d8392ba 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -17,14 +17,14 @@ Author: Notes: --*/ -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_ast_vector.h" -#include"algebraic_numbers.h" -#include"expr2polynomial.h" -#include"cancel_eh.h" -#include"scoped_timer.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_ast_vector.h" +#include "math/polynomial/algebraic_numbers.h" +#include "ast/expr2polynomial.h" +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" #define CHECK_IS_ALGEBRAIC(ARG, RET) { \ diff --git a/src/api/api_arith.cpp b/src/api/api_arith.cpp index 51aea9676..8fbed6f46 100644 --- a/src/api/api_arith.cpp +++ b/src/api/api_arith.cpp @@ -15,12 +15,12 @@ Author: Revision History: --*/ -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_util.h" -#include"arith_decl_plugin.h" -#include"algebraic_numbers.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "ast/arith_decl_plugin.h" +#include "math/polynomial/algebraic_numbers.h" #define MK_ARITH_OP(NAME, OP) MK_NARY(NAME, mk_c(c)->get_arith_fid(), OP, SKIP) #define MK_BINARY_ARITH_OP(NAME, OP) MK_BINARY(NAME, mk_c(c)->get_arith_fid(), OP, SKIP) diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index ed431882e..5e6764dff 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -15,11 +15,11 @@ Author: Revision History: --*/ -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_util.h" -#include"array_decl_plugin.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "ast/array_decl_plugin.h" extern "C" { @@ -34,6 +34,19 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_sort Z3_API Z3_mk_array_sort_n(Z3_context c, unsigned n, Z3_sort const* domain, Z3_sort range) { + Z3_TRY; + LOG_Z3_mk_array_sort_n(c, n, domain, range); + RESET_ERROR_CODE(); + vector params; + for (unsigned i = 0; i < n; ++i) params.push_back(parameter(to_sort(domain[i]))); + params.push_back(parameter(to_sort(range))); + sort * ty = mk_c(c)->m().mk_sort(mk_c(c)->get_array_fid(), ARRAY_SORT, params.size(), params.c_ptr()); + mk_c(c)->save_ast_trail(ty); + RETURN_Z3(of_sort(ty)); + Z3_CATCH_RETURN(0); + } + Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i) { Z3_TRY; LOG_Z3_mk_select(c, a, i); @@ -57,6 +70,35 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_ast Z3_API Z3_mk_select_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs) { + Z3_TRY; + LOG_Z3_mk_select_n(c, a, n, idxs); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + expr * _a = to_expr(a); + // expr * _i = to_expr(i); + sort * a_ty = m.get_sort(_a); + // sort * i_ty = m.get_sort(_i); + if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { + SET_ERROR_CODE(Z3_SORT_ERROR); + RETURN_Z3(0); + } + ptr_vector domain; + ptr_vector args; + args.push_back(_a); + domain.push_back(a_ty); + for (unsigned i = 0; i < n; ++i) { + args.push_back(to_expr(idxs[i])); + domain.push_back(m.get_sort(to_expr(idxs[i]))); + } + func_decl * d = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_SELECT, 2, a_ty->get_parameters(), domain.size(), domain.c_ptr()); + app * r = m.mk_app(d, args.size(), args.c_ptr()); + mk_c(c)->save_ast_trail(r); + check_sorts(c, r); + RETURN_Z3(of_ast(r)); + Z3_CATCH_RETURN(0); + } + Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v) { Z3_TRY; LOG_Z3_mk_store(c, a, i, v); @@ -82,6 +124,37 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_ast Z3_API Z3_mk_store_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs, Z3_ast v) { + Z3_TRY; + LOG_Z3_mk_store_n(c, a, n, idxs, v); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + expr * _a = to_expr(a); + expr * _v = to_expr(v); + sort * a_ty = m.get_sort(_a); + sort * v_ty = m.get_sort(_v); + if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { + SET_ERROR_CODE(Z3_SORT_ERROR); + RETURN_Z3(0); + } + ptr_vector domain; + ptr_vector args; + args.push_back(_a); + domain.push_back(a_ty); + for (unsigned i = 0; i < n; ++i) { + args.push_back(to_expr(idxs[i])); + domain.push_back(m.get_sort(to_expr(idxs[i]))); + } + args.push_back(_v); + domain.push_back(v_ty); + func_decl * d = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_STORE, 2, a_ty->get_parameters(), domain.size(), domain.c_ptr()); + app * r = m.mk_app(d, args.size(), args.c_ptr()); + mk_c(c)->save_ast_trail(r); + check_sorts(c, r); + RETURN_Z3(of_ast(r)); + Z3_CATCH_RETURN(0); + } + Z3_ast Z3_API Z3_mk_map(Z3_context c, Z3_func_decl f, unsigned n, Z3_ast const* args) { Z3_TRY; LOG_Z3_mk_map(c, f, n, args); @@ -188,6 +261,18 @@ extern "C" { MK_BINARY(Z3_mk_set_subset, mk_c(c)->get_array_fid(), OP_SET_SUBSET, SKIP); MK_BINARY(Z3_mk_array_ext, mk_c(c)->get_array_fid(), OP_ARRAY_EXT, SKIP); + Z3_ast Z3_API Z3_mk_as_array(Z3_context c, Z3_func_decl f) { + Z3_TRY; + LOG_Z3_mk_as_array(c, f); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + array_util a(m); + app * r = a.mk_as_array(to_func_decl(f)); + mk_c(c)->save_ast_trail(r); + return of_ast(r); + Z3_CATCH_RETURN(0); + } + Z3_ast Z3_mk_set_member(Z3_context c, Z3_ast elem, Z3_ast set) { return Z3_mk_select(c, set, elem); } @@ -222,7 +307,8 @@ extern "C" { CHECK_VALID_AST(t, 0); if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && to_sort(t)->get_decl_kind() == ARRAY_SORT) { - Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(1).get_ast()); + unsigned n = to_sort(t)->get_num_parameters(); + Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(n-1).get_ast()); RETURN_Z3(r); } SET_ERROR_CODE(Z3_INVALID_ARG); diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index d34cad2f4..e22603225 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -16,28 +16,28 @@ Revision History: --*/ #include -#include"api_log_macros.h" -#include"api_context.h" -#include"api_util.h" -#include"well_sorted.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"datatype_decl_plugin.h" -#include"array_decl_plugin.h" -#include"pb_decl_plugin.h" -#include"ast_translation.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"ast_smt_pp.h" -#include"ast_smt2_pp.h" -#include"th_rewriter.h" -#include"var_subst.h" -#include"expr_safe_replace.h" -#include"pp.h" -#include"scoped_ctrl_c.h" -#include"cancel_eh.h" -#include"scoped_timer.h" -#include"pp_params.hpp" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "ast/well_sorted.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/pb_decl_plugin.h" +#include "ast/ast_translation.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt_pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/pp.h" +#include "util/scoped_ctrl_c.h" +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" +#include "ast/pp_params.hpp" extern bool is_numeral_sort(Z3_context c, Z3_sort ty); @@ -1204,16 +1204,8 @@ extern "C" { case OP_FPA_TO_SBV: return Z3_OP_FPA_TO_SBV; case OP_FPA_TO_REAL: return Z3_OP_FPA_TO_REAL; case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV; - case OP_FPA_INTERNAL_MIN_I: return Z3_OP_FPA_MIN_I; - case OP_FPA_INTERNAL_MAX_I: return Z3_OP_FPA_MAX_I; - case OP_FPA_INTERNAL_BV2RM: - case OP_FPA_INTERNAL_BVWRAP: - case OP_FPA_INTERNAL_MIN_UNSPECIFIED: - case OP_FPA_INTERNAL_MAX_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: + case OP_FPA_BVWRAP: return Z3_OP_FPA_BVWRAP; + case OP_FPA_BV2RM: return Z3_OP_FPA_BV2RM; return Z3_OP_UNINTERPRETED; default: return Z3_OP_INTERNAL; diff --git a/src/api/api_ast_map.cpp b/src/api/api_ast_map.cpp index aa52faa98..d0388b97a 100644 --- a/src/api/api_ast_map.cpp +++ b/src/api/api_ast_map.cpp @@ -16,13 +16,13 @@ Revision History: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_ast_map.h" -#include"api_ast_vector.h" -#include"ast_smt2_pp.h" -#include"dec_ref_util.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_ast_map.h" +#include "api/api_ast_vector.h" +#include "ast/ast_smt2_pp.h" +#include "util/dec_ref_util.h" Z3_ast_map_ref::~Z3_ast_map_ref() { dec_ref_key_values(m, m_map); diff --git a/src/api/api_ast_map.h b/src/api/api_ast_map.h index dc1cf90ad..3dacc54f1 100644 --- a/src/api/api_ast_map.h +++ b/src/api/api_ast_map.h @@ -18,8 +18,8 @@ Revision History: #ifndef API_AST_MAP_H_ #define API_AST_MAP_H_ -#include"api_util.h" -#include"obj_hashtable.h" +#include "api/api_util.h" +#include "util/obj_hashtable.h" struct Z3_ast_map_ref : public api::object { ast_manager & m; diff --git a/src/api/api_ast_vector.cpp b/src/api/api_ast_vector.cpp index 40df13708..471a308b6 100644 --- a/src/api/api_ast_vector.cpp +++ b/src/api/api_ast_vector.cpp @@ -16,12 +16,12 @@ Revision History: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_ast_vector.h" -#include"ast_translation.h" -#include"ast_smt2_pp.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_ast_vector.h" +#include "ast/ast_translation.h" +#include "ast/ast_smt2_pp.h" extern "C" { diff --git a/src/api/api_ast_vector.h b/src/api/api_ast_vector.h index 4fcf8ffb8..ced20481e 100644 --- a/src/api/api_ast_vector.h +++ b/src/api/api_ast_vector.h @@ -18,7 +18,7 @@ Revision History: #ifndef API_AST_VECTOR_H_ #define API_AST_VECTOR_H_ -#include"api_util.h" +#include "api/api_util.h" namespace api { class context; diff --git a/src/api/api_bv.cpp b/src/api/api_bv.cpp index ff090ef54..3b5d60be3 100644 --- a/src/api/api_bv.cpp +++ b/src/api/api_bv.cpp @@ -15,11 +15,11 @@ Author: Revision History: --*/ -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_util.h" -#include"bv_decl_plugin.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "ast/bv_decl_plugin.h" extern "C" { diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp index a04a9f12c..460101d34 100644 --- a/src/api/api_config_params.cpp +++ b/src/api/api_config_params.cpp @@ -15,16 +15,16 @@ Author: Revision History: --*/ -#include"z3.h" -#include"api_context.h" -#include"pp.h" -#include"api_log_macros.h" -#include"api_util.h" -#include"cmd_context.h" -#include"symbol.h" -#include"gparams.h" -#include"env_params.h" -#include"context_params.h" +#include "api/z3.h" +#include "api/api_context.h" +#include "ast/pp.h" +#include "api/api_log_macros.h" +#include "api/api_util.h" +#include "cmd_context/cmd_context.h" +#include "util/symbol.h" +#include "util/gparams.h" +#include "util/env_params.h" +#include "cmd_context/context_params.h" extern "C" { void Z3_API Z3_global_param_set(Z3_string param_id, Z3_string param_value) { diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index bcd3c60f2..1e3f7a0a4 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -18,15 +18,15 @@ Revision History: --*/ #include -#include"api_context.h" -#include"smtparser.h" -#include"version.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"api_log_macros.h" -#include"api_util.h" -#include"reg_decl_plugins.h" -#include"realclosure.h" +#include "api/api_context.h" +#include "parsers/smt/smtparser.h" +#include "util/version.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "api/api_log_macros.h" +#include "api/api_util.h" +#include "ast/reg_decl_plugins.h" +#include "math/realclosure/realclosure.h" // The install_tactics procedure is automatically generated void install_tactics(tactic_manager & ctx); @@ -142,7 +142,7 @@ namespace api { #pragma omp critical (set_interruptable) { if (m_interruptable) - (*m_interruptable)(); + (*m_interruptable)(API_INTERRUPT_EH_CALLER); m_limit.cancel(); m().limit().cancel(); } @@ -150,8 +150,9 @@ namespace api { void context::set_error_code(Z3_error_code err) { m_error_code = err; - if (err != Z3_OK) + if (err != Z3_OK) { invoke_error_handler(err); + } } void context::check_searching() { diff --git a/src/api/api_context.h b/src/api/api_context.h index 4685fd04e..6f8dc43f6 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -20,22 +20,22 @@ Revision History: #ifndef API_CONTEXT_H_ #define API_CONTEXT_H_ -#include"z3.h" -#include"ast.h" -#include"api_util.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"seq_decl_plugin.h" -#include"datatype_decl_plugin.h" -#include"dl_decl_plugin.h" -#include"fpa_decl_plugin.h" -#include"smt_kernel.h" -#include"smt_params.h" -#include"event_handler.h" -#include"tactic_manager.h" -#include"context_params.h" -#include"api_polynomial.h" -#include"hashtable.h" +#include "api/z3.h" +#include "ast/ast.h" +#include "api/api_util.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/seq_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/dl_decl_plugin.h" +#include "ast/fpa_decl_plugin.h" +#include "smt/smt_kernel.h" +#include "smt/params/smt_params.h" +#include "util/event_handler.h" +#include "cmd_context/tactic_manager.h" +#include "cmd_context/context_params.h" +#include "api/api_polynomial.h" +#include "util/hashtable.h" namespace smtlib { class parser; diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 8843256c6..397e2a8af 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -15,24 +15,24 @@ Author: Revision History: --*/ -#include"api_datalog.h" -#include"api_context.h" -#include"api_util.h" -#include"ast_pp.h" -#include"api_ast_vector.h" -#include"api_log_macros.h" -#include"api_stats.h" -#include"datalog_parser.h" -#include"cancel_eh.h" -#include"scoped_timer.h" -#include"dl_cmds.h" -#include"cmd_context.h" -#include"smt2parser.h" -#include"dl_context.h" -#include"dl_register_engine.h" -#include"dl_external_relation.h" -#include"dl_decl_plugin.h" -#include"rel_context.h" +#include "api/api_datalog.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "ast/ast_pp.h" +#include "api/api_ast_vector.h" +#include "api/api_log_macros.h" +#include "api/api_stats.h" +#include "muz/fp/datalog_parser.h" +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" +#include "muz/fp/dl_cmds.h" +#include "cmd_context/cmd_context.h" +#include "parsers/smt2/smt2parser.h" +#include "muz/base/dl_context.h" +#include "muz/fp/dl_register_engine.h" +#include "muz/rel/dl_external_relation.h" +#include "ast/dl_decl_plugin.h" +#include "muz/rel/rel_context.h" namespace api { @@ -605,5 +605,6 @@ extern "C" { } +#include "api_datalog_spacer.inc" }; diff --git a/src/api/api_datalog.h b/src/api/api_datalog.h index 8c095d546..c8dbc4180 100644 --- a/src/api/api_datalog.h +++ b/src/api/api_datalog.h @@ -19,11 +19,11 @@ Revision History: #ifndef API_DATALOG_H_ #define API_DATALOG_H_ -#include"z3.h" -#include"ast.h" -#include"smt_params.h" -#include"smt_kernel.h" -#include"api_util.h" +#include "api/z3.h" +#include "ast/ast.h" +#include "smt/params/smt_params.h" +#include "smt/smt_kernel.h" +#include "api/api_util.h" typedef void (*reduce_app_callback_fptr)(void*, func_decl*, unsigned, expr*const*, expr**); typedef void (*reduce_assign_callback_fptr)(void*, func_decl*, unsigned, expr*const*, unsigned, expr*const*); diff --git a/src/api/api_datalog_spacer.inc b/src/api/api_datalog_spacer.inc new file mode 100644 index 000000000..871d2be63 --- /dev/null +++ b/src/api/api_datalog_spacer.inc @@ -0,0 +1,113 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + api_datalog_spacer.inc + +Abstract: + + Spacer-specific datalog API + +Author: + + Arie Gurfinkel (arie) + +Notes: + this file is included at the bottom of api_datalog.cpp + +--*/ + Z3_lbool Z3_API Z3_fixedpoint_query_from_lvl (Z3_context c, Z3_fixedpoint d, Z3_ast q, unsigned lvl) { + Z3_TRY; + LOG_Z3_fixedpoint_query_from_lvl (c, d, q, lvl); + RESET_ERROR_CODE(); + lbool r = l_undef; + unsigned timeout = to_fixedpoint(d)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); + unsigned rlimit = to_fixedpoint(d)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); + { + scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); + cancel_eh eh(mk_c(c)->m().limit()); + api::context::set_interruptable si(*(mk_c(c)), eh); + scoped_timer timer(timeout, &eh); + try { + r = to_fixedpoint_ref(d)->ctx().query_from_lvl (to_expr(q), lvl); + } + catch (z3_exception& ex) { + mk_c(c)->handle_exception(ex); + r = l_undef; + } + to_fixedpoint_ref(d)->ctx().cleanup(); + } + return of_lbool(r); + Z3_CATCH_RETURN(Z3_L_UNDEF); + } + + Z3_ast Z3_API Z3_fixedpoint_get_ground_sat_answer(Z3_context c, Z3_fixedpoint d) { + Z3_TRY; + LOG_Z3_fixedpoint_get_ground_sat_answer(c, d); + RESET_ERROR_CODE(); + expr* e = to_fixedpoint_ref(d)->ctx().get_ground_sat_answer(); + mk_c(c)->save_ast_trail(e); + RETURN_Z3(of_expr(e)); + Z3_CATCH_RETURN(0); + } + + Z3_ast_vector Z3_API Z3_fixedpoint_get_rules_along_trace( + Z3_context c, + Z3_fixedpoint d) + { + Z3_TRY; + LOG_Z3_fixedpoint_get_rules_along_trace(c, d); + ast_manager& m = mk_c(c)->m(); + Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, *mk_c(c), m); + mk_c(c)->save_object(v); + expr_ref_vector rules(m); + svector names; + + to_fixedpoint_ref(d)->ctx().get_rules_along_trace_as_formulas(rules, names); + for (unsigned i = 0; i < rules.size(); ++i) { + v->m_ast_vector.push_back(rules[i].get()); + } + RETURN_Z3(of_ast_vector(v)); + Z3_CATCH_RETURN(0); + } + + Z3_symbol Z3_API Z3_fixedpoint_get_rule_names_along_trace( + Z3_context c, + Z3_fixedpoint d) + { + Z3_TRY; + LOG_Z3_fixedpoint_get_rule_names_along_trace(c, d); + ast_manager& m = mk_c(c)->m(); + Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, *mk_c(c), m); + mk_c(c)->save_object(v); + expr_ref_vector rules(m); + svector names; + std::stringstream ss; + + to_fixedpoint_ref(d)->ctx().get_rules_along_trace_as_formulas(rules, names); + for (unsigned i = 0; i < names.size(); ++i) { + ss << ";" << names[i].str(); + } + RETURN_Z3(of_symbol(symbol(ss.str().substr(1).c_str()))); + Z3_CATCH_RETURN(0); + } + + void Z3_API Z3_fixedpoint_add_invariant(Z3_context c, Z3_fixedpoint d, Z3_func_decl pred, Z3_ast property) { + Z3_TRY; + LOG_Z3_fixedpoint_add_invariant(c, d, pred, property); + RESET_ERROR_CODE(); + to_fixedpoint_ref(d)->ctx ().add_invariant(to_func_decl(pred), to_expr(property)); + Z3_CATCH; + } + + Z3_ast Z3_API Z3_fixedpoint_get_reachable(Z3_context c, Z3_fixedpoint d, Z3_func_decl pred) { + Z3_TRY; + LOG_Z3_fixedpoint_get_reachable(c, d, pred); + RESET_ERROR_CODE(); + expr_ref r = to_fixedpoint_ref(d)->ctx().get_reachable(to_func_decl(pred)); + mk_c(c)->save_ast_trail(r); + RETURN_Z3(of_expr(r.get())); + Z3_CATCH_RETURN(0); + } + diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 647cdc581..d667a7428 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -15,11 +15,11 @@ Author: Revision History: --*/ -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_util.h" -#include"datatype_decl_plugin.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "ast/datatype_decl_plugin.h" extern "C" { @@ -45,13 +45,13 @@ extern "C" { ptr_vector acc; for (unsigned i = 0; i < num_fields; ++i) { - acc.push_back(mk_accessor_decl(to_symbol(field_names[i]), type_ref(to_sort(field_sorts[i])))); + acc.push_back(mk_accessor_decl(m, to_symbol(field_names[i]), type_ref(to_sort(field_sorts[i])))); } constructor_decl* constrs[1] = { mk_constructor_decl(to_symbol(name), recognizer, acc.size(), acc.c_ptr()) }; { - datatype_decl * dt = mk_datatype_decl(to_symbol(name), 1, constrs); + datatype_decl * dt = mk_datatype_decl(dt_util, to_symbol(name), 0, nullptr, 1, constrs); bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, 0, 0, tuples); del_datatype_decl(dt); @@ -69,18 +69,13 @@ extern "C" { // create constructor SASSERT(dt_util.is_datatype(tuple)); SASSERT(!dt_util.is_recursive(tuple)); - ptr_vector const * decls = dt_util.get_datatype_constructors(tuple); - func_decl* decl = (*decls)[0]; + ptr_vector const & decls = *dt_util.get_datatype_constructors(tuple); + func_decl* decl = (decls)[0]; mk_c(c)->save_multiple_ast_trail(decl); *mk_tuple_decl = of_func_decl(decl); // Create projections - ptr_vector const * accs = dt_util.get_constructor_accessors(decl); - if (!accs) { - SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); - } - ptr_vector const & _accs = *accs; + ptr_vector const & _accs = *dt_util.get_constructor_accessors(decl); SASSERT(_accs.size() == num_fields); for (unsigned i = 0; i < _accs.size(); i++) { mk_c(c)->save_multiple_ast_trail(_accs[i]); @@ -118,7 +113,7 @@ extern "C" { { - datatype_decl * dt = mk_datatype_decl(to_symbol(name), n, constrs.c_ptr()); + datatype_decl * dt = mk_datatype_decl(dt_util, to_symbol(name), 0, 0, n, constrs.c_ptr()); bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, 0, 0, sorts); del_datatype_decl(dt); @@ -136,10 +131,10 @@ extern "C" { // create constructor SASSERT(dt_util.is_datatype(e)); SASSERT(!dt_util.is_recursive(e)); - ptr_vector const * decls = dt_util.get_datatype_constructors(e); - SASSERT(decls && decls->size() == n); + ptr_vector const & decls = *dt_util.get_datatype_constructors(e); + SASSERT(decls.size() == n); for (unsigned i = 0; i < n; ++i) { - func_decl* decl = (*decls)[i]; + func_decl* decl = (decls)[i]; mk_c(c)->save_multiple_ast_trail(decl); enum_consts[i] = of_func_decl(decl); decl = dt_util.get_constructor_recognizer(decl); @@ -165,11 +160,12 @@ extern "C" { LOG_Z3_mk_list_sort(c, name, elem_sort, nil_decl, is_nil_decl, cons_decl, is_cons_decl, head_decl, tail_decl); RESET_ERROR_CODE(); ast_manager& m = mk_c(c)->m(); + datatype_util& dt_util = mk_c(c)->dtutil(); mk_c(c)->reset_last_result(); datatype_util data_util(m); accessor_decl* head_tail[2] = { - mk_accessor_decl(symbol("head"), type_ref(to_sort(elem_sort))), - mk_accessor_decl(symbol("tail"), type_ref(0)) + mk_accessor_decl(m, symbol("head"), type_ref(to_sort(elem_sort))), + mk_accessor_decl(m, symbol("tail"), type_ref(0)) }; constructor_decl* constrs[2] = { mk_constructor_decl(symbol("nil"), symbol("is_nil"), 0, 0), @@ -179,7 +175,7 @@ extern "C" { sort_ref_vector sorts(m); { - datatype_decl * decl = mk_datatype_decl(to_symbol(name), 2, constrs); + datatype_decl * decl = mk_datatype_decl(dt_util, to_symbol(name), 0, nullptr, 2, constrs); bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &decl, 0, 0, sorts); del_datatype_decl(decl); @@ -215,18 +211,16 @@ extern "C" { *is_cons_decl = of_func_decl(f); } if (head_decl) { - ptr_vector const* acc = data_util.get_constructor_accessors(cnstrs[1]); - SASSERT(acc); - SASSERT(acc->size() == 2); - f = (*acc)[0]; + ptr_vector const& acc = *data_util.get_constructor_accessors(cnstrs[1]); + SASSERT(acc.size() == 2); + f = (acc)[0]; mk_c(c)->save_multiple_ast_trail(f); *head_decl = of_func_decl(f); } if (tail_decl) { - ptr_vector const* acc = data_util.get_constructor_accessors(cnstrs[1]); - SASSERT(acc); - SASSERT(acc->size() == 2); - f = (*acc)[1]; + ptr_vector const& acc = *data_util.get_constructor_accessors(cnstrs[1]); + SASSERT(acc.size() == 2); + f = (acc)[1]; mk_c(c)->save_multiple_ast_trail(f); *tail_decl = of_func_decl(f); } @@ -301,13 +295,9 @@ extern "C" { *tester = of_func_decl(f2); } - ptr_vector const* accs = data_util.get_constructor_accessors(f); - if (!accs && num_fields > 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); - return; - } + ptr_vector const& accs = *data_util.get_constructor_accessors(f); for (unsigned i = 0; i < num_fields; ++i) { - func_decl* f2 = (*accs)[i]; + func_decl* f2 = (accs)[i]; mk_c(c)->save_multiple_ast_trail(f2); accessors[i] = of_func_decl(f2); } @@ -327,21 +317,23 @@ extern "C" { Z3_symbol name, unsigned num_constructors, Z3_constructor constructors[]) { + datatype_util& dt_util = mk_c(c)->dtutil(); + ast_manager& m = mk_c(c)->m(); ptr_vector constrs; for (unsigned i = 0; i < num_constructors; ++i) { constructor* cn = reinterpret_cast(constructors[i]); ptr_vector acc; for (unsigned j = 0; j < cn->m_sorts.size(); ++j) { if (cn->m_sorts[j].get()) { - acc.push_back(mk_accessor_decl(cn->m_field_names[j], type_ref(cn->m_sorts[j].get()))); + acc.push_back(mk_accessor_decl(m, cn->m_field_names[j], type_ref(cn->m_sorts[j].get()))); } else { - acc.push_back(mk_accessor_decl(cn->m_field_names[j], type_ref(cn->m_sort_refs[j]))); + acc.push_back(mk_accessor_decl(m, cn->m_field_names[j], type_ref(cn->m_sort_refs[j]))); } } constrs.push_back(mk_constructor_decl(cn->m_name, cn->m_tester, acc.size(), acc.c_ptr())); } - return mk_datatype_decl(to_symbol(name), num_constructors, constrs.c_ptr()); + return mk_datatype_decl(dt_util, to_symbol(name), 0, nullptr, num_constructors, constrs.c_ptr()); } Z3_sort Z3_API Z3_mk_datatype(Z3_context c, @@ -368,11 +360,11 @@ extern "C" { sort * s = sorts.get(0); mk_c(c)->save_ast_trail(s); - ptr_vector const* cnstrs = data_util.get_datatype_constructors(s); + ptr_vector const& cnstrs = *data_util.get_datatype_constructors(s); for (unsigned i = 0; i < num_constructors; ++i) { constructor* cn = reinterpret_cast(constructors[i]); - cn->m_constructor = (*cnstrs)[i]; + cn->m_constructor = cnstrs[i]; } RETURN_Z3_mk_datatype(of_sort(s)); Z3_CATCH_RETURN(0); @@ -417,7 +409,7 @@ extern "C" { ptr_vector datas; for (unsigned i = 0; i < num_sorts; ++i) { constructor_list* cl = reinterpret_cast(constructor_lists[i]); - datas.push_back(mk_datatype_decl(c,sort_names[i], cl->size(), reinterpret_cast(cl->c_ptr()))); + datas.push_back(mk_datatype_decl(c, sort_names[i], cl->size(), reinterpret_cast(cl->c_ptr()))); } sort_ref_vector _sorts(m); bool ok = mk_c(c)->get_dt_plugin()->mk_datatypes(datas.size(), datas.c_ptr(), 0, 0, _sorts); @@ -434,10 +426,10 @@ extern "C" { mk_c(c)->save_multiple_ast_trail(s); sorts[i] = of_sort(s); constructor_list* cl = reinterpret_cast(constructor_lists[i]); - ptr_vector const* cnstrs = data_util.get_datatype_constructors(s); + ptr_vector const& cnstrs = *data_util.get_datatype_constructors(s); for (unsigned j = 0; j < cl->size(); ++j) { constructor* cn = (*cl)[j]; - cn->m_constructor = (*cnstrs)[j]; + cn->m_constructor = cnstrs[j]; } } RETURN_Z3_mk_datatypes; @@ -456,12 +448,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - ptr_vector const * decls = dt_util.get_datatype_constructors(_t); - if (!decls) { - SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; - } - return decls->size(); + return dt_util.get_datatype_constructors(_t)->size(); Z3_CATCH_RETURN(0); } @@ -474,12 +461,12 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - ptr_vector const * decls = dt_util.get_datatype_constructors(_t); - if (!decls || idx >= decls->size()) { + ptr_vector const & decls = *dt_util.get_datatype_constructors(_t); + if (idx >= decls.size()) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - func_decl* decl = (*decls)[idx]; + func_decl* decl = (decls)[idx]; mk_c(c)->save_ast_trail(decl); return of_func_decl(decl); } @@ -504,12 +491,12 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector const * decls = dt_util.get_datatype_constructors(_t); - if (!decls || idx >= decls->size()) { + ptr_vector const & decls = *dt_util.get_datatype_constructors(_t); + if (idx >= decls.size()) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - func_decl* decl = (*decls)[idx]; + func_decl* decl = (decls)[idx]; decl = dt_util.get_constructor_recognizer(decl); mk_c(c)->save_ast_trail(decl); RETURN_Z3(of_func_decl(decl)); @@ -527,23 +514,23 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector const * decls = dt_util.get_datatype_constructors(_t); - if (!decls || idx_c >= decls->size()) { + ptr_vector const & decls = *dt_util.get_datatype_constructors(_t); + if (idx_c >= decls.size()) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - func_decl* decl = (*decls)[idx_c]; + func_decl* decl = (decls)[idx_c]; if (decl->get_arity() <= idx_a) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector const * accs = dt_util.get_constructor_accessors(decl); - SASSERT(accs && accs->size() == decl->get_arity()); - if (!accs || accs->size() <= idx_a) { + ptr_vector const & accs = *dt_util.get_constructor_accessors(decl); + SASSERT(accs.size() == decl->get_arity()); + if (accs.size() <= idx_a) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - decl = (*accs)[idx_a]; + decl = (accs)[idx_a]; mk_c(c)->save_ast_trail(decl); RETURN_Z3(of_func_decl(decl)); Z3_CATCH_RETURN(0); @@ -574,16 +561,13 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - ptr_vector const * decls = dt_util.get_datatype_constructors(tuple); - if (!decls || decls->size() != 1) { + ptr_vector const & decls = *dt_util.get_datatype_constructors(tuple); + if (decls.size() != 1) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - ptr_vector const * accs = dt_util.get_constructor_accessors((*decls)[0]); - if (!accs) { - return 0; - } - return accs->size(); + ptr_vector const & accs = *dt_util.get_constructor_accessors(decls[0]); + return accs.size(); Z3_CATCH_RETURN(0); } @@ -597,21 +581,17 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector const * decls = dt_util.get_datatype_constructors(tuple); - if (!decls || decls->size() != 1) { + ptr_vector const & decls = *dt_util.get_datatype_constructors(tuple); + if (decls.size() != 1) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector const * accs = dt_util.get_constructor_accessors((*decls)[0]); - if (!accs) { - SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); - } - if (accs->size() <= i) { + ptr_vector const & accs = *dt_util.get_constructor_accessors((decls)[0]); + if (accs.size() <= i) { SET_ERROR_CODE(Z3_IOB); RETURN_Z3(0); } - func_decl* acc = (*accs)[i]; + func_decl* acc = (accs)[i]; mk_c(c)->save_ast_trail(acc); RETURN_Z3(of_func_decl(acc)); Z3_CATCH_RETURN(0); diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 6dad5048f..484cb3d76 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -17,10 +17,10 @@ Notes: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"fpa_decl_plugin.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "ast/fpa_decl_plugin.h" bool is_fp_sort(Z3_context c, Z3_sort s) { return mk_c(c)->fpautil().is_float(to_sort(s)); diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index 295e1d939..0f1b9056b 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -16,11 +16,11 @@ Revision History: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_goal.h" -#include"ast_translation.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_goal.h" +#include "ast/ast_translation.h" extern "C" { diff --git a/src/api/api_goal.h b/src/api/api_goal.h index 1e47b832a..4e9729df5 100644 --- a/src/api/api_goal.h +++ b/src/api/api_goal.h @@ -18,8 +18,8 @@ Revision History: #ifndef API_GOAL_H_ #define API_GOAL_H_ -#include"api_util.h" -#include"goal.h" +#include "api/api_util.h" +#include "tactic/goal.h" struct Z3_goal_ref : public api::object { goal_ref m_goal; diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index 10aa06568..416c71adf 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -17,27 +17,27 @@ --*/ #include #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_tactic.h" -#include"api_solver.h" -#include"api_model.h" -#include"api_stats.h" -#include"api_ast_vector.h" -#include"tactic2solver.h" -#include"scoped_ctrl_c.h" -#include"cancel_eh.h" -#include"scoped_timer.h" -#include"smt_strategic_solver.h" -#include"smt_solver.h" -#include"smt_implied_equalities.h" -#include"iz3interp.h" -#include"iz3profiling.h" -#include"iz3hash.h" -#include"iz3pp.h" -#include"iz3checker.h" -#include"scoped_proof.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_tactic.h" +#include "api/api_solver.h" +#include "api/api_model.h" +#include "api/api_stats.h" +#include "api/api_ast_vector.h" +#include "solver/tactic2solver.h" +#include "util/scoped_ctrl_c.h" +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" +#include "tactic/portfolio/smt_strategic_solver.h" +#include "smt/smt_solver.h" +#include "smt/smt_implied_equalities.h" +#include "interp/iz3interp.h" +#include "interp/iz3profiling.h" +#include "interp/iz3hash.h" +#include "interp/iz3pp.h" +#include "interp/iz3checker.h" +#include "ast/scoped_proof.h" using namespace stl_ext; @@ -249,7 +249,7 @@ extern "C" { params_ref _p; _p.set_bool("proof", true); // this is currently useless - scoped_proof_mode spm(mk_c(c)->m(), PGM_FINE); + scoped_proof_mode spm(mk_c(c)->m(), PGM_ENABLED); scoped_ptr sf = mk_smt_solver_factory(); scoped_ptr m_solver((*sf)(mk_c(c)->m(), _p, true, true, true, ::symbol::null)); m_solver.get()->updt_params(_p); // why do we have to do this? diff --git a/src/api/api_log.cpp b/src/api/api_log.cpp index 43ed98986..410110d9a 100644 --- a/src/api/api_log.cpp +++ b/src/api/api_log.cpp @@ -16,10 +16,10 @@ Revision History: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"util.h" -#include"version.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "util/util.h" +#include "util/version.h" std::ostream * g_z3_log = 0; bool g_z3_log_enabled = false; diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 67c0f2f08..bda33f186 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -16,20 +16,31 @@ Revision History: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_model.h" -#include"api_ast_vector.h" -#include"array_decl_plugin.h" -#include"model.h" -#include"model_v2_pp.h" -#include"model_smt2_pp.h" -#include"model_params.hpp" -#include"model_evaluator_params.hpp" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_model.h" +#include "api/api_ast_vector.h" +#include "ast/array_decl_plugin.h" +#include "model/model.h" +#include "model/model_v2_pp.h" +#include "model/model_smt2_pp.h" +#include "model/model_params.hpp" +#include "model/model_evaluator_params.hpp" extern "C" { + Z3_model Z3_API Z3_mk_model(Z3_context c) { + Z3_TRY; + LOG_Z3_mk_model(c); + RESET_ERROR_CODE(); + Z3_model_ref * m_ref = alloc(Z3_model_ref, *mk_c(c)); + m_ref->m_model = alloc(model, mk_c(c)->m()); + mk_c(c)->save_object(m_ref); + RETURN_Z3(of_model(m_ref)); + Z3_CATCH_RETURN(0); + } + void Z3_API Z3_model_inc_ref(Z3_context c, Z3_model m) { Z3_TRY; LOG_Z3_model_inc_ref(c, m); @@ -224,6 +235,36 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_func_interp Z3_API Z3_add_func_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast else_val) { + Z3_TRY; + LOG_Z3_add_func_interp(c, m, f, else_val); + RESET_ERROR_CODE(); + func_decl* d = to_func_decl(f); + model* mdl = to_model_ref(m); + Z3_func_interp_ref * f_ref = alloc(Z3_func_interp_ref, *mk_c(c), mdl); + f_ref->m_func_interp = alloc(func_interp, mk_c(c)->m(), d->get_arity()); + mk_c(c)->save_object(f_ref); + mdl->register_decl(d, f_ref->m_func_interp); + f_ref->m_func_interp->set_else(to_expr(else_val)); + RETURN_Z3(of_func_interp(f_ref)); + Z3_CATCH_RETURN(0); + } + + void Z3_API Z3_add_const_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast a) { + Z3_TRY; + LOG_Z3_add_const_interp(c, m, f, a); + RESET_ERROR_CODE(); + func_decl* d = to_func_decl(f); + if (d->get_arity() != 0) { + SET_ERROR_CODE(Z3_INVALID_ARG); + } + else { + model* mdl = to_model_ref(m); + mdl->register_decl(d, to_expr(a)); + } + Z3_CATCH; + } + void Z3_API Z3_func_interp_inc_ref(Z3_context c, Z3_func_interp f) { Z3_TRY; LOG_Z3_func_interp_inc_ref(c, f); @@ -283,6 +324,15 @@ extern "C" { Z3_CATCH_RETURN(0); } + void Z3_API Z3_func_interp_set_else(Z3_context c, Z3_func_interp f, Z3_ast else_value) { + Z3_TRY; + LOG_Z3_func_interp_set_else(c, f, else_value); + RESET_ERROR_CODE(); + // CHECK_NON_NULL(f, 0); + to_func_interp_ref(f)->set_else(to_expr(else_value)); + Z3_CATCH; + } + unsigned Z3_API Z3_func_interp_get_arity(Z3_context c, Z3_func_interp f) { Z3_TRY; LOG_Z3_func_interp_get_arity(c, f); @@ -292,6 +342,24 @@ extern "C" { Z3_CATCH_RETURN(0); } + void Z3_API Z3_func_interp_add_entry(Z3_context c, Z3_func_interp fi, Z3_ast_vector args, Z3_ast value) { + Z3_TRY; + LOG_Z3_func_interp_add_entry(c, fi, args, value); + //CHECK_NON_NULL(fi, void); + //CHECK_NON_NULL(args, void); + //CHECK_NON_NULL(value, void); + func_interp* _fi = to_func_interp_ref(fi); + expr* _value = to_expr(value); + if (to_ast_vector_ref(args).size() != _fi->get_arity()) { + SET_ERROR_CODE(Z3_IOB); + return; + } + // check sorts of value + expr* const* _args = (expr* const*) to_ast_vector_ref(args).c_ptr(); + _fi->insert_entry(_args, _value); + Z3_CATCH; + } + void Z3_API Z3_func_entry_inc_ref(Z3_context c, Z3_func_entry e) { Z3_TRY; LOG_Z3_func_entry_inc_ref(c, e); diff --git a/src/api/api_model.h b/src/api/api_model.h index 9a53b59bc..64427cfb8 100644 --- a/src/api/api_model.h +++ b/src/api/api_model.h @@ -18,8 +18,8 @@ Revision History: #ifndef API_MODEL_H_ #define API_MODEL_H_ -#include"api_util.h" -#include"model.h" +#include "api/api_util.h" +#include "model/model.h" struct Z3_model_ref : public api::object { model_ref m_model; diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 40ebcf652..95bc0bef9 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -16,14 +16,14 @@ Revision History: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_util.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"algebraic_numbers.h" -#include"fpa_decl_plugin.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "math/polynomial/algebraic_numbers.h" +#include "ast/fpa_decl_plugin.h" bool is_numeral_sort(Z3_context c, Z3_sort ty) { sort * _ty = to_sort(ty); diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 0d1b4ef8d..9f5f7dd5d 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -16,18 +16,18 @@ Revision History: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_stats.h" -#include"api_context.h" -#include"api_util.h" -#include"api_model.h" -#include"opt_context.h" -#include"opt_cmds.h" -#include"cancel_eh.h" -#include"scoped_timer.h" -#include"smt2parser.h" -#include"api_ast_vector.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_stats.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "api/api_model.h" +#include "opt/opt_context.h" +#include "opt/opt_cmds.h" +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" +#include "parsers/smt2/smt2parser.h" +#include "api/api_ast_vector.h" extern "C" { @@ -283,15 +283,16 @@ extern "C" { Z3_optimize opt, std::istream& s) { ast_manager& m = mk_c(c)->m(); - cmd_context ctx(false, &m); - install_opt_cmds(ctx, to_optimize_ptr(opt)); - ctx.set_ignore_check(true); - if (!parse_smt2_commands(ctx, s)) { + scoped_ptr ctx = alloc(cmd_context, false, &m); + install_opt_cmds(*ctx.get(), to_optimize_ptr(opt)); + ctx->set_ignore_check(true); + if (!parse_smt2_commands(*ctx.get(), s)) { + ctx = nullptr; SET_ERROR_CODE(Z3_PARSER_ERROR); return; } - ptr_vector::const_iterator it = ctx.begin_assertions(); - ptr_vector::const_iterator end = ctx.end_assertions(); + ptr_vector::const_iterator it = ctx->begin_assertions(); + ptr_vector::const_iterator end = ctx->end_assertions(); for (; it != end; ++it) { to_optimize_ptr(opt)->add_hard_constraint(*it); } @@ -320,9 +321,6 @@ extern "C" { std::ostringstream strm; strm << "Could not open file " << s; throw default_exception(strm.str()); - - SET_ERROR_CODE(Z3_PARSER_ERROR); - return; } Z3_optimize_from_stream(c, d, is); Z3_CATCH; diff --git a/src/api/api_params.cpp b/src/api/api_params.cpp index 1efaffca8..3f3cbed1d 100644 --- a/src/api/api_params.cpp +++ b/src/api/api_params.cpp @@ -18,11 +18,11 @@ Revision History: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_util.h" -#include"params.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "util/params.h" extern "C" { diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 8f6eb1125..b3252281b 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -16,14 +16,14 @@ Revision History: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_util.h" -#include"cmd_context.h" -#include"smt2parser.h" -#include"smtparser.h" -#include"solver_na2as.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "cmd_context/cmd_context.h" +#include "parsers/smt2/smt2parser.h" +#include "parsers/smt/smtparser.h" +#include "solver/solver_na2as.h" extern "C" { @@ -56,19 +56,20 @@ extern "C" { Z3_func_decl const decls[]) { Z3_TRY; LOG_Z3_parse_smtlib_string(c, str, num_sorts, sort_names, sorts, num_decls, decl_names, decls); - std::ostringstream outs; + scoped_ptr outs = alloc(std::ostringstream); bool ok = false; RESET_ERROR_CODE(); init_smtlib_parser(c, num_sorts, sort_names, sorts, num_decls, decl_names, decls); - mk_c(c)->m_smtlib_parser->set_error_stream(outs); + mk_c(c)->m_smtlib_parser->set_error_stream(*outs); try { ok = mk_c(c)->m_smtlib_parser->parse_string(str); } catch (...) { ok = false; } - mk_c(c)->m_smtlib_error_buffer = outs.str(); + mk_c(c)->m_smtlib_error_buffer = outs->str(); + outs = nullptr; if (!ok) { mk_c(c)->reset_parser(); SET_ERROR_CODE(Z3_PARSER_ERROR); @@ -88,16 +89,17 @@ extern "C" { LOG_Z3_parse_smtlib_file(c, file_name, num_sorts, sort_names, types, num_decls, decl_names, decls); bool ok = false; RESET_ERROR_CODE(); - std::ostringstream outs; + scoped_ptr outs = alloc(std::ostringstream); init_smtlib_parser(c, num_sorts, sort_names, types, num_decls, decl_names, decls); - mk_c(c)->m_smtlib_parser->set_error_stream(outs); + mk_c(c)->m_smtlib_parser->set_error_stream(*outs); try { ok = mk_c(c)->m_smtlib_parser->parse_file(file_name); } catch(...) { ok = false; } - mk_c(c)->m_smtlib_error_buffer = outs.str(); + mk_c(c)->m_smtlib_error_buffer = outs->str(); + outs = nullptr; if (!ok) { mk_c(c)->reset_parser(); SET_ERROR_CODE(Z3_PARSER_ERROR); @@ -260,21 +262,22 @@ extern "C" { Z3_symbol const decl_names[], Z3_func_decl const decls[]) { Z3_TRY; - cmd_context ctx(false, &(mk_c(c)->m())); - ctx.set_ignore_check(true); + scoped_ptr ctx = alloc(cmd_context, false, &(mk_c(c)->m())); + ctx->set_ignore_check(true); for (unsigned i = 0; i < num_decls; ++i) { - ctx.insert(to_symbol(decl_names[i]), to_func_decl(decls[i])); + ctx->insert(to_symbol(decl_names[i]), to_func_decl(decls[i])); } for (unsigned i = 0; i < num_sorts; ++i) { - psort* ps = ctx.pm().mk_psort_cnst(to_sort(sorts[i])); - ctx.insert(ctx.pm().mk_psort_user_decl(0, to_symbol(sort_names[i]), ps)); + psort* ps = ctx->pm().mk_psort_cnst(to_sort(sorts[i])); + ctx->insert(ctx->pm().mk_psort_user_decl(0, to_symbol(sort_names[i]), ps)); } - if (!parse_smt2_commands(ctx, is)) { + if (!parse_smt2_commands(*ctx.get(), is)) { + ctx = nullptr; SET_ERROR_CODE(Z3_PARSER_ERROR); return of_ast(mk_c(c)->m().mk_true()); } - ptr_vector::const_iterator it = ctx.begin_assertions(); - ptr_vector::const_iterator end = ctx.end_assertions(); + ptr_vector::const_iterator it = ctx->begin_assertions(); + ptr_vector::const_iterator end = ctx->end_assertions(); unsigned size = static_cast(end - it); return of_ast(mk_c(c)->mk_and(size, it)); Z3_CATCH_RETURN(0); diff --git a/src/api/api_pb.cpp b/src/api/api_pb.cpp index bb4a40c9a..e6f8f77b4 100644 --- a/src/api/api_pb.cpp +++ b/src/api/api_pb.cpp @@ -15,11 +15,11 @@ Author: Revision History: --*/ -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_util.h" -#include"pb_decl_plugin.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "ast/pb_decl_plugin.h" extern "C" { diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp index eebe36717..9be73289f 100644 --- a/src/api/api_polynomial.cpp +++ b/src/api/api_polynomial.cpp @@ -16,15 +16,15 @@ Author: Notes: --*/ -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_polynomial.h" -#include"api_ast_vector.h" -#include"expr2polynomial.h" -#include"cancel_eh.h" -#include"scoped_timer.h" -#include"expr2var.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_polynomial.h" +#include "api/api_ast_vector.h" +#include "ast/expr2polynomial.h" +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" +#include "ast/expr2var.h" namespace api { diff --git a/src/api/api_polynomial.h b/src/api/api_polynomial.h index b93372ca9..fbb1e7e13 100644 --- a/src/api/api_polynomial.h +++ b/src/api/api_polynomial.h @@ -19,7 +19,7 @@ Notes: #ifndef API_POLYNOMIAL_H_ #define API_POLYNOMIAL_H_ -#include"polynomial.h" +#include "math/polynomial/polynomial.h" namespace api { diff --git a/src/api/api_qe.cpp b/src/api/api_qe.cpp new file mode 100644 index 000000000..34f21d64b --- /dev/null +++ b/src/api/api_qe.cpp @@ -0,0 +1,173 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + api_qe.cpp + +Abstract: + + Model-based Projection (MBP) and Quantifier Elimination (QE) API + +Author: + + Arie Gurfinkel (arie) + +Notes: + +--*/ + +#include +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "api/api_model.h" +#include "api/api_ast_map.h" +#include "api/api_ast_vector.h" +#include "qe/qe_vartest.h" +#include "qe/qe_lite.h" +#include "muz/spacer/spacer_util.h" +#include "ast/expr_map.h" + +extern "C" +{ + + static bool to_apps(unsigned n, Z3_app const es[], app_ref_vector& result) { + for (unsigned i = 0; i < n; ++i) { + if (!is_app(to_app(es[i]))) { + return false; + } + result.push_back (to_app (es [i])); + } + return true; + } + + Z3_ast Z3_API Z3_qe_model_project (Z3_context c, + Z3_model m, + unsigned num_bounds, + Z3_app const bound[], + Z3_ast body) + { + Z3_TRY; + LOG_Z3_qe_model_project (c, m, num_bounds, bound, body); + RESET_ERROR_CODE(); + + app_ref_vector vars(mk_c(c)->m ()); + if (!to_apps(num_bounds, bound, vars)) { + SET_ERROR_CODE (Z3_INVALID_ARG); + RETURN_Z3(0); + } + + expr_ref result (mk_c(c)->m ()); + result = to_expr (body); + model_ref model (to_model_ref (m)); + spacer::qe_project (mk_c(c)->m (), vars, result, model); + mk_c(c)->save_ast_trail (result.get ()); + + return of_expr (result.get ()); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_qe_model_project_skolem (Z3_context c, + Z3_model m, + unsigned num_bounds, + Z3_app const bound[], + Z3_ast body, + Z3_ast_map map) + { + Z3_TRY; + LOG_Z3_qe_model_project_skolem (c, m, num_bounds, bound, body, map); + RESET_ERROR_CODE(); + + ast_manager& man = mk_c(c)->m (); + app_ref_vector vars(man); + if (!to_apps(num_bounds, bound, vars)) { + RETURN_Z3(0); + } + + expr_ref result (mk_c(c)->m ()); + result = to_expr (body); + model_ref model (to_model_ref (m)); + expr_map emap (man); + + spacer::qe_project (mk_c(c)->m (), vars, result, model, emap); + mk_c(c)->save_ast_trail (result.get ()); + + obj_map &map_z3 = to_ast_map_ref(map); + + for (expr_map::iterator it = emap.begin(), end = emap.end(); it != end; ++it){ + man.inc_ref(&(it->get_key())); + man.inc_ref(it->get_value()); + map_z3.insert(&(it->get_key()), it->get_value()); + } + + return of_expr (result.get ()); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_model_extrapolate (Z3_context c, + Z3_model m, + Z3_ast fml) + { + Z3_TRY; + LOG_Z3_model_extrapolate (c, m, fml); + RESET_ERROR_CODE(); + + model_ref model (to_model_ref (m)); + expr_ref_vector facts (mk_c(c)->m ()); + facts.push_back (to_expr (fml)); + flatten_and (facts); + + spacer::model_evaluator_util mev (mk_c(c)->m()); + mev.set_model (*model); + + expr_ref_vector lits (mk_c(c)->m()); + spacer::compute_implicant_literals (mev, facts, lits); + + expr_ref result (mk_c(c)->m ()); + result = mk_and (lits); + mk_c(c)->save_ast_trail (result.get ()); + + return of_expr (result.get ()); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_qe_lite (Z3_context c, Z3_ast_vector vars, Z3_ast body) + { + Z3_TRY; + LOG_Z3_qe_lite (c, vars, body); + RESET_ERROR_CODE(); + ast_ref_vector &vVars = to_ast_vector_ref (vars); + + app_ref_vector vApps (mk_c(c)->m()); + for (unsigned i = 0; i < vVars.size (); ++i) { + app *a = to_app (vVars.get (i)); + if (a->get_kind () != AST_APP) { + SET_ERROR_CODE (Z3_INVALID_ARG); + RETURN_Z3(0); + } + vApps.push_back (a); + } + + expr_ref result (mk_c(c)->m ()); + result = to_expr (body); + + params_ref p; + qe_lite qe (mk_c(c)->m (), p); + qe (vApps, result); + + // -- copy back variables that were not eliminated + if (vApps.size () < vVars.size ()) { + vVars.reset (); + for (app* v : vApps) { + vVars.push_back (v); + } + } + + mk_c(c)->save_ast_trail (result.get ()); + return of_expr (result); + Z3_CATCH_RETURN(0); + } + +} diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index e87b9446f..e56505e6d 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -15,12 +15,12 @@ Author: Revision History: --*/ -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_util.h" -#include"pattern_validation.h" -#include"expr_abstract.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "parsers/util/pattern_validation.h" +#include "ast/expr_abstract.h" extern "C" { @@ -63,9 +63,11 @@ extern "C" { RESET_ERROR_CODE(); if (!mk_c(c)->m().is_bool(to_expr(body))) { SET_ERROR_CODE(Z3_SORT_ERROR); + return nullptr; } if (num_patterns > 0 && num_no_patterns > 0) { SET_ERROR_CODE(Z3_INVALID_USAGE); + return nullptr; } expr * const* ps = reinterpret_cast(patterns); expr * const* no_ps = reinterpret_cast(no_patterns); @@ -76,7 +78,7 @@ extern "C" { for (unsigned i = 0; i < num_patterns; i++) { if (!v(num_decls, ps[i], 0, 0)) { SET_ERROR_CODE(Z3_INVALID_PATTERN); - return 0; + return nullptr; } } } diff --git a/src/api/api_rcf.cpp b/src/api/api_rcf.cpp index a4770c56c..84c250114 100644 --- a/src/api/api_rcf.cpp +++ b/src/api/api_rcf.cpp @@ -20,10 +20,10 @@ Notes: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"realclosure.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "math/realclosure/realclosure.h" static rcmanager & rcfm(Z3_context c) { return mk_c(c)->rcfm(); diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 986e6f497..44003a5fb 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_util.h" -#include"ast_pp.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_util.h" +#include "ast/ast_pp.h" extern "C" { diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 6dc41efb2..2030c5210 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -17,22 +17,22 @@ Revision History: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_tactic.h" -#include"api_solver.h" -#include"api_model.h" -#include"api_stats.h" -#include"api_ast_vector.h" -#include"tactic2solver.h" -#include"scoped_ctrl_c.h" -#include"cancel_eh.h" -#include"scoped_timer.h" -#include"smt_strategic_solver.h" -#include"smt_solver.h" -#include"smt_implied_equalities.h" -#include"smt_logics.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_tactic.h" +#include "api/api_solver.h" +#include "api/api_model.h" +#include "api/api_stats.h" +#include "api/api_ast_vector.h" +#include "solver/tactic2solver.h" +#include "util/scoped_ctrl_c.h" +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" +#include "tactic/portfolio/smt_strategic_solver.h" +#include "smt/smt_solver.h" +#include "smt/smt_implied_equalities.h" +#include "solver/smt_logics.h" extern "C" { @@ -296,10 +296,14 @@ extern "C" { result = to_solver_ref(s)->check_sat(num_assumptions, _assumptions); } catch (z3_exception & ex) { + to_solver_ref(s)->set_reason_unknown(eh); mk_c(c)->handle_exception(ex); return Z3_L_UNDEF; } } + if (result == l_undef) { + to_solver_ref(s)->set_reason_unknown(eh); + } return static_cast(result); } @@ -438,6 +442,7 @@ extern "C" { unsigned sz = __assumptions.size(); for (unsigned i = 0; i < sz; ++i) { if (!is_expr(__assumptions[i])) { + _assumptions.finalize(); _consequences.finalize(); _variables.finalize(); SET_ERROR_CODE(Z3_INVALID_USAGE); return Z3_L_UNDEF; } @@ -447,6 +452,7 @@ extern "C" { sz = __variables.size(); for (unsigned i = 0; i < sz; ++i) { if (!is_expr(__variables[i])) { + _assumptions.finalize(); _consequences.finalize(); _variables.finalize(); SET_ERROR_CODE(Z3_INVALID_USAGE); return Z3_L_UNDEF; } @@ -466,10 +472,15 @@ extern "C" { result = to_solver_ref(s)->get_consequences(_assumptions, _variables, _consequences); } catch (z3_exception & ex) { + to_solver_ref(s)->set_reason_unknown(eh); + _assumptions.finalize(); _consequences.finalize(); _variables.finalize(); mk_c(c)->handle_exception(ex); return Z3_L_UNDEF; } } + if (result == l_undef) { + to_solver_ref(s)->set_reason_unknown(eh); + } for (unsigned i = 0; i < _consequences.size(); ++i) { to_ast_vector_ref(consequences).push_back(_consequences[i].get()); } diff --git a/src/api/api_solver.h b/src/api/api_solver.h index ea59ccf33..4f344a00d 100644 --- a/src/api/api_solver.h +++ b/src/api/api_solver.h @@ -18,8 +18,8 @@ Revision History: #ifndef API_SOLVER_H_ #define API_SOLVER_H_ -#include"api_util.h" -#include"solver.h" +#include "api/api_util.h" +#include "solver/solver.h" struct Z3_solver_ref : public api::object { scoped_ptr m_solver_factory; diff --git a/src/api/api_stats.cpp b/src/api/api_stats.cpp index b39c8368a..a92b908dc 100644 --- a/src/api/api_stats.cpp +++ b/src/api/api_stats.cpp @@ -16,10 +16,10 @@ Revision History: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_stats.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_stats.h" extern "C" { diff --git a/src/api/api_stats.h b/src/api/api_stats.h index 1c0c0c82e..5ce616084 100644 --- a/src/api/api_stats.h +++ b/src/api/api_stats.h @@ -18,8 +18,8 @@ Revision History: #ifndef API_STATS_H_ #define API_STATS_H_ -#include"api_util.h" -#include"statistics.h" +#include "api/api_util.h" +#include "util/statistics.h" struct Z3_stats_ref : public api::object { statistics m_stats; diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index 7068619c1..ccb1ce597 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -16,14 +16,14 @@ Revision History: --*/ #include -#include"z3.h" -#include"api_log_macros.h" -#include"api_context.h" -#include"api_tactic.h" -#include"api_model.h" -#include"scoped_ctrl_c.h" -#include"cancel_eh.h" -#include"scoped_timer.h" +#include "api/z3.h" +#include "api/api_log_macros.h" +#include "api/api_context.h" +#include "api/api_tactic.h" +#include "api/api_model.h" +#include "util/scoped_ctrl_c.h" +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" Z3_apply_result_ref::Z3_apply_result_ref(api::context& c, ast_manager & m): api::object(c), m_core(m) { } diff --git a/src/api/api_tactic.h b/src/api/api_tactic.h index 373b85b39..fd2f05185 100644 --- a/src/api/api_tactic.h +++ b/src/api/api_tactic.h @@ -18,8 +18,8 @@ Revision History: #ifndef API_TACTIC_H_ #define API_TACTIC_H_ -#include"api_goal.h" -#include"tactical.h" +#include "api/api_goal.h" +#include "tactic/tactical.h" namespace api { class context; diff --git a/src/api/api_util.h b/src/api/api_util.h index 7857e7c38..bc6781c2c 100644 --- a/src/api/api_util.h +++ b/src/api/api_util.h @@ -18,9 +18,9 @@ Revision History: #ifndef API_UTIL_H_ #define API_UTIL_H_ -#include"params.h" -#include"lbool.h" -#include"ast.h" +#include "util/params.h" +#include "util/lbool.h" +#include "ast/ast.h" #define Z3_TRY try { #define Z3_CATCH_CORE(CODE) } catch (z3_exception & ex) { mk_c(c)->handle_exception(ex); CODE } diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 42db6f352..23a7bd22e 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -140,18 +140,17 @@ namespace z3 { class context { bool m_enable_exceptions; Z3_context m_ctx; - static void error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ } void init(config & c) { m_ctx = Z3_mk_context_rc(c); m_enable_exceptions = true; - Z3_set_error_handler(m_ctx, error_handler); + Z3_set_error_handler(m_ctx, 0); Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); } void init_interp(config & c) { m_ctx = Z3_mk_interpolation_context(c); m_enable_exceptions = true; - Z3_set_error_handler(m_ctx, error_handler); + Z3_set_error_handler(m_ctx, 0); Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); } @@ -251,6 +250,8 @@ namespace z3 { Example: Given a context \c c, c.array_sort(c.int_sort(), c.bool_sort()) is an array sort from integer to Boolean. */ sort array_sort(sort d, sort r); + sort array_sort(sort_vector const& d, sort r); + /** \brief Return an enumeration sort: enum_names[0], ..., enum_names[n-1]. \c cs and \c ts are output parameters. The method stores in \c cs the constants corresponding to the enumerated elements, @@ -354,7 +355,7 @@ namespace z3 { Z3_error_code check_error() const { return m_ctx->check_error(); } friend void check_context(object const & a, object const & b); }; - inline void check_context(object const & a, object const & b) { assert(a.m_ctx == b.m_ctx); } + inline void check_context(object const & a, object const & b) { (void)a; (void)b; assert(a.m_ctx == b.m_ctx); } class symbol : public object { Z3_symbol m_sym; @@ -1731,6 +1732,14 @@ namespace z3 { expr else_value() const { Z3_ast r = Z3_func_interp_get_else(ctx(), m_interp); check_error(); return expr(ctx(), r); } unsigned num_entries() const { unsigned r = Z3_func_interp_get_num_entries(ctx(), m_interp); check_error(); return r; } func_entry entry(unsigned i) const { Z3_func_entry e = Z3_func_interp_get_entry(ctx(), m_interp, i); check_error(); return func_entry(ctx(), e); } + void add_entry(expr_vector const& args, expr& value) { + Z3_func_interp_add_entry(ctx(), m_interp, args, value); + check_error(); + } + void set_else(expr& value) { + Z3_func_interp_set_else(ctx(), m_interp, value); + check_error(); + } }; class model : public object { @@ -1740,6 +1749,7 @@ namespace z3 { Z3_model_inc_ref(ctx(), m); } public: + model(context & c):object(c) { init(Z3_mk_model(c)); } model(context & c, Z3_model m):object(c) { init(m); } model(model const & s):object(s) { init(s.m_model); } ~model() { Z3_model_dec_ref(ctx(), m_model); } @@ -1795,6 +1805,17 @@ namespace z3 { return 0 != Z3_model_has_interp(ctx(), m_model, f); } + func_interp add_func_interp(func_decl& f, expr& else_val) { + Z3_func_interp r = Z3_add_func_interp(ctx(), m_model, f, else_val); + check_error(); + return func_interp(ctx(), r); + } + + void add_const_interp(func_decl& f, expr& value) { + Z3_add_const_interp(ctx(), m_model, f, value); + check_error(); + } + friend std::ostream & operator<<(std::ostream & out, model const & m); }; inline std::ostream & operator<<(std::ostream & out, model const & m) { out << Z3_model_to_string(m.ctx(), m); return out; } @@ -2308,6 +2329,11 @@ namespace z3 { inline sort context::re_sort(sort& s) { Z3_sort r = Z3_mk_re_sort(m_ctx, s); check_error(); return sort(*this, r); } inline sort context::array_sort(sort d, sort r) { Z3_sort s = Z3_mk_array_sort(m_ctx, d, r); check_error(); return sort(*this, s); } + inline sort context::array_sort(sort_vector const& d, sort r) { + array dom(d); + Z3_sort s = Z3_mk_array_sort_n(m_ctx, dom.size(), dom.ptr(), r); check_error(); return sort(*this, s); + } + inline sort context::enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts) { array _enum_names(n); for (unsigned i = 0; i < n; i++) { _enum_names[i] = Z3_mk_string_symbol(*this, enum_names[i]); } @@ -2554,11 +2580,32 @@ namespace z3 { a.check_error(); return expr(a.ctx(), r); } + inline expr select(expr const & a, expr_vector const & i) { + check_context(a, i); + array idxs(i); + Z3_ast r = Z3_mk_select_n(a.ctx(), a, idxs.size(), idxs.ptr()); + a.check_error(); + return expr(a.ctx(), r); + } + inline expr store(expr const & a, int i, expr const & v) { return store(a, a.ctx().num_val(i, a.get_sort().array_domain()), v); } inline expr store(expr const & a, expr i, int v) { return store(a, i, a.ctx().num_val(v, a.get_sort().array_range())); } inline expr store(expr const & a, int i, int v) { return store(a, a.ctx().num_val(i, a.get_sort().array_domain()), a.ctx().num_val(v, a.get_sort().array_range())); } + inline expr store(expr const & a, expr_vector const & i, expr const & v) { + check_context(a, i); check_context(a, v); + array idxs(i); + Z3_ast r = Z3_mk_store_n(a.ctx(), a, idxs.size(), idxs.ptr(), v); + a.check_error(); + return expr(a.ctx(), r); + } + + inline expr as_array(func_decl & f) { + Z3_ast r = Z3_mk_as_array(f.ctx(), f); + f.check_error(); + return expr(f.ctx(), r); + } #define MK_EXPR1(_fn, _arg) \ Z3_ast r = _fn(_arg.ctx(), _arg); \ diff --git a/src/api/dll/dll.cpp b/src/api/dll/dll.cpp index a0bd25d2e..74dc48153 100644 --- a/src/api/dll/dll.cpp +++ b/src/api/dll/dll.cpp @@ -15,16 +15,16 @@ Copyright (c) 2015 Microsoft Corporation BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved - ) + ) { - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - case DLL_PROCESS_DETACH: - break; - } + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } return TRUE; } diff --git a/src/api/dotnet/ArraySort.cs b/src/api/dotnet/ArraySort.cs index ddd27785c..47a73ae1f 100644 --- a/src/api/dotnet/ArraySort.cs +++ b/src/api/dotnet/ArraySort.cs @@ -63,6 +63,13 @@ namespace Microsoft.Z3 Contract.Requires(domain != null); Contract.Requires(range != null); } + internal ArraySort(Context ctx, Sort[] domain, Sort range) + : base(ctx, Native.Z3_mk_array_sort_n(ctx.nCtx, (uint)domain.Length, AST.ArrayToNative(domain), range.NativeObject)) + { + Contract.Requires(ctx != null); + Contract.Requires(domain != null); + Contract.Requires(range != null); + } #endregion }; diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 93f5929d9..add1b0ded 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -43,78 +43,78 @@ add_custom_command(OUTPUT "${Z3_DOTNET_CONST_FILE}" ) set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE - AlgebraicNum.cs - ApplyResult.cs - ArithExpr.cs - ArithSort.cs - ArrayExpr.cs - ArraySort.cs - AST.cs - ASTMap.cs - ASTVector.cs - BitVecExpr.cs - BitVecNum.cs - BitVecSort.cs - BoolExpr.cs - BoolSort.cs - Constructor.cs - ConstructorList.cs - Context.cs - DatatypeExpr.cs - DatatypeSort.cs - Deprecated.cs - EnumSort.cs - Expr.cs - FiniteDomainExpr.cs - FiniteDomainNum.cs - FiniteDomainSort.cs - Fixedpoint.cs - FPExpr.cs - FPNum.cs - FPRMExpr.cs - FPRMNum.cs - FPRMSort.cs - FPSort.cs - FuncDecl.cs - FuncInterp.cs - Global.cs - Goal.cs - IDecRefQueue.cs - InterpolationContext.cs - IntExpr.cs - IntNum.cs - IntSort.cs - IntSymbol.cs - ListSort.cs - Log.cs - Model.cs - Optimize.cs - ParamDescrs.cs - Params.cs - Pattern.cs - Probe.cs - Quantifier.cs - RatNum.cs - RealExpr.cs - RealSort.cs - ReExpr.cs - RelationSort.cs - ReSort.cs - SeqExpr.cs - SeqSort.cs - SetSort.cs - Solver.cs - Sort.cs - Statistics.cs - Status.cs - StringSymbol.cs - Symbol.cs - Tactic.cs - TupleSort.cs - UninterpretedSort.cs - Version.cs - Z3Exception.cs - Z3Object.cs + AlgebraicNum.cs + ApplyResult.cs + ArithExpr.cs + ArithSort.cs + ArrayExpr.cs + ArraySort.cs + AST.cs + ASTMap.cs + ASTVector.cs + BitVecExpr.cs + BitVecNum.cs + BitVecSort.cs + BoolExpr.cs + BoolSort.cs + Constructor.cs + ConstructorList.cs + Context.cs + DatatypeExpr.cs + DatatypeSort.cs + Deprecated.cs + EnumSort.cs + Expr.cs + FiniteDomainExpr.cs + FiniteDomainNum.cs + FiniteDomainSort.cs + Fixedpoint.cs + FPExpr.cs + FPNum.cs + FPRMExpr.cs + FPRMNum.cs + FPRMSort.cs + FPSort.cs + FuncDecl.cs + FuncInterp.cs + Global.cs + Goal.cs + IDecRefQueue.cs + InterpolationContext.cs + IntExpr.cs + IntNum.cs + IntSort.cs + IntSymbol.cs + ListSort.cs + Log.cs + Model.cs + Optimize.cs + ParamDescrs.cs + Params.cs + Pattern.cs + Probe.cs + Quantifier.cs + RatNum.cs + RealExpr.cs + RealSort.cs + ReExpr.cs + RelationSort.cs + ReSort.cs + SeqExpr.cs + SeqSort.cs + SetSort.cs + Solver.cs + Sort.cs + Statistics.cs + Status.cs + StringSymbol.cs + Symbol.cs + Tactic.cs + TupleSort.cs + UninterpretedSort.cs + Version.cs + Z3Exception.cs + Z3Object.cs ) set(Z3_DOTNET_ASSEMBLY_SOURCES "") diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index a656be3eb..27711be81 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -126,7 +126,7 @@ namespace Microsoft.Z3 private BoolSort m_boolSort = null; private IntSort m_intSort = null; private RealSort m_realSort = null; - private SeqSort m_stringSort = null; + private SeqSort m_stringSort = null; /// /// Retrieves the Boolean sort of the context. @@ -274,6 +274,20 @@ namespace Microsoft.Z3 return new ArraySort(this, domain, range); } + /// + /// Create a new n-ary array sort. + /// + public ArraySort MkArraySort(Sort[] domain, Sort range) + { + Contract.Requires(domain != null); + Contract.Requires(range != null); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(domain); + CheckContextMatch(range); + return new ArraySort(this, domain, range); + } + /// /// Create a new tuple sort. /// @@ -2113,6 +2127,7 @@ namespace Microsoft.Z3 return (ArrayExpr)MkConst(MkSymbol(name), MkArraySort(domain, range)); } + /// /// Array read. /// @@ -2123,8 +2138,8 @@ namespace Microsoft.Z3 /// The node a must have an array sort [domain -> range], /// and i must have the sort domain. /// The sort of the result is range. - /// - /// + /// + /// /// 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)); } + /// + /// Array read. + /// + /// + /// The argument a is the array and args are the indices + /// of the array that gets read. + /// + /// The node a must have an array sort [domain1,..,domaink -> range], + /// and args must have the sort domain1,..,domaink. + /// The sort of the result is range. + /// + /// + /// + 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() != null); + + CheckContextMatch(a); + CheckContextMatch(args); + return Expr.Create(this, Native.Z3_mk_select_n(nCtx, a.NativeObject, AST.ArrayLength(args), AST.ArrayToNative(args))); + } + /// /// Array update. /// @@ -2151,8 +2190,9 @@ namespace Microsoft.Z3 /// on all indices except for i, where it maps to v /// (and the select of a with /// respect to i may be a different value). - /// - /// + /// + /// + /// /// 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)); } + /// + /// Array update. + /// + /// + /// The node a must have an array sort [domain1,..,domaink -> range], + /// args must have sort domain1,..,domaink, + /// v must have sort range. The sort of the result is [domain -> 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 a + /// (with respect to select) + /// on all indices except for args, where it maps to v + /// (and the select of a with + /// respect to args may be a different value). + /// + /// + /// + /// + 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() != null); + + CheckContextMatch(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)); + } + /// /// Create a constant array. /// /// /// The resulting term is an array, such that a selecton an arbitrary index /// produces the value v. - /// - /// + /// + /// /// public ArrayExpr MkConstArray(Sort domain, Expr v) { @@ -2194,9 +2265,9 @@ namespace Microsoft.Z3 /// Eeach element of args must be of an array sort [domain_i -> range_i]. /// The function declaration f must have type range_1 .. range_n -> range. /// v must have sort range. The sort of the result is [domain_i -> range]. - /// - /// - /// + /// + /// + /// /// public ArrayExpr MkMap(FuncDecl f, params ArrayExpr[] args) { @@ -2426,7 +2497,7 @@ namespace Microsoft.Z3 public SeqExpr IntToString(Expr e) { Contract.Requires(e != null); - Contract.Requires(e is ArithExpr); + Contract.Requires(e is ArithExpr); Contract.Ensures(Contract.Result() != null); return new SeqExpr(this, Native.Z3_mk_int_to_str(nCtx, e.NativeObject)); } @@ -2690,7 +2761,7 @@ namespace Microsoft.Z3 /// /// Create a range expression. /// - public ReExpr MkRange(SeqExpr lo, SeqExpr hi) + public ReExpr MkRange(SeqExpr lo, SeqExpr hi) { Contract.Requires(lo != null); Contract.Requires(hi != null); diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 6c52b83c8..4fd306052 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -809,55 +809,55 @@ namespace Microsoft.Z3 /// Check whether expression is a concatentation. /// /// a Boolean - public bool IsConcat { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_CONCAT; } } + public bool IsConcat { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_CONCAT; } } /// /// Check whether expression is a prefix. /// /// a Boolean - public bool IsPrefix { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_PREFIX; } } + public bool IsPrefix { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_PREFIX; } } /// /// Check whether expression is a suffix. /// /// a Boolean - public bool IsSuffix { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_SUFFIX; } } + public bool IsSuffix { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_SUFFIX; } } /// /// Check whether expression is a contains. /// /// a Boolean - public bool IsContains { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_CONTAINS; } } + public bool IsContains { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_CONTAINS; } } /// /// Check whether expression is an extract. /// /// a Boolean - public bool IsExtract { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_EXTRACT; } } + public bool IsExtract { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_EXTRACT; } } /// /// Check whether expression is a replace. /// /// a Boolean - public bool IsReplace { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_REPLACE; } } + public bool IsReplace { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_REPLACE; } } /// /// Check whether expression is an at. /// /// a Boolean - public bool IsAt { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_AT; } } + public bool IsAt { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_AT; } } /// /// Check whether expression is a sequence length. /// /// a Boolean - public bool IsLength { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_LENGTH; } } + public bool IsLength { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_LENGTH; } } /// /// Check whether expression is a sequence index. /// /// a Boolean - public bool IsIndex { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_INDEX; } } + public bool IsIndex { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_INDEX; } } #endregion diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index 99dd9aac0..9d0636425 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -123,7 +123,7 @@ namespace Microsoft.Z3 /// /// Retrieve a lower bound for the objective handle. - /// + /// public ArithExpr Lower { get { return opt.GetLower(handle); } @@ -131,7 +131,7 @@ namespace Microsoft.Z3 /// /// Retrieve an upper bound for the objective handle. - /// + /// public ArithExpr Upper { get { return opt.GetUpper(handle); } @@ -139,7 +139,7 @@ namespace Microsoft.Z3 /// /// Retrieve the value of an objective. - /// + /// public ArithExpr Value { get { return Lower; } @@ -147,7 +147,7 @@ namespace Microsoft.Z3 /// /// Retrieve a lower bound for the objective handle. - /// + /// public ArithExpr[] LowerAsVector { get { return opt.GetLowerAsVector(handle); } @@ -155,7 +155,7 @@ namespace Microsoft.Z3 /// /// Retrieve an upper bound for the objective handle. - /// + /// public ArithExpr[] UpperAsVector { get { return opt.GetUpperAsVector(handle); } @@ -240,7 +240,7 @@ namespace Microsoft.Z3 /// Declare an arithmetical maximization objective. /// Return a handle to the objective. The handle is used as /// to retrieve the values of objectives after calling Check. - /// + /// public Handle MkMaximize(ArithExpr e) { return new Handle(this, Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject)); @@ -249,7 +249,7 @@ namespace Microsoft.Z3 /// /// Declare an arithmetical minimization objective. /// Similar to MkMaximize. - /// + /// public Handle MkMinimize(ArithExpr e) { return new Handle(this, Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject)); @@ -257,7 +257,7 @@ namespace Microsoft.Z3 /// /// Retrieve a lower bound for the objective handle. - /// + /// private ArithExpr GetLower(uint index) { return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); @@ -266,7 +266,7 @@ namespace Microsoft.Z3 /// /// Retrieve an upper bound for the objective handle. - /// + /// private ArithExpr GetUpper(uint index) { return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index)); @@ -274,7 +274,7 @@ namespace Microsoft.Z3 /// /// Retrieve a lower bound for the objective handle. - /// + /// private ArithExpr[] GetLowerAsVector(uint index) { ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_lower_as_vector(Context.nCtx, NativeObject, index)); @@ -284,29 +284,29 @@ namespace Microsoft.Z3 /// /// Retrieve an upper bound for the objective handle. - /// + /// private ArithExpr[] GetUpperAsVector(uint index) { ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_upper_as_vector(Context.nCtx, NativeObject, index)); return v.ToArithExprArray(); } - /// - /// Return a string the describes why the last to check returned unknown - /// - public String ReasonUnknown - { + /// + /// Return a string the describes why the last to check returned unknown + /// + public String ReasonUnknown + { get { Contract.Ensures(Contract.Result() != null); return Native.Z3_optimize_get_reason_unknown(Context.nCtx, NativeObject); } - } + } /// /// Print the context to a string (SMT-LIB parseable benchmark). - /// + /// public override string ToString() { return Native.Z3_optimize_to_string(Context.nCtx, NativeObject); diff --git a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln index b6e252684..1e33f136e 100644 --- a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln +++ b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln @@ -8,41 +8,41 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{2A8E577B-7B6D-4CA9-832A-CA2EEC314812}" EndProject Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.ActiveCfg = Debug|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.Build.0 = Debug|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.ActiveCfg = Debug|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.Build.0 = Debug|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.Build.0 = Release|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.ActiveCfg = Release|x64 - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.Build.0 = Release|x64 - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.ActiveCfg = Release|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.Build.0 = Release|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.ActiveCfg = Debug|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.Build.0 = Debug|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.ActiveCfg = Debug|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.Build.0 = Debug|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.Build.0 = Release|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.ActiveCfg = Release|x64 - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.Build.0 = Release|x64 - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.ActiveCfg = Release|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.ActiveCfg = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.Build.0 = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.ActiveCfg = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.Build.0 = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.Build.0 = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.ActiveCfg = Release|x64 + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.Build.0 = Release|x64 + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.ActiveCfg = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.Build.0 = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.ActiveCfg = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.Build.0 = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.ActiveCfg = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.Build.0 = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.Build.0 = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.ActiveCfg = Release|x64 + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.Build.0 = Release|x64 + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.ActiveCfg = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection EndGlobal diff --git a/src/api/java/ASTVector.java b/src/api/java/ASTVector.java index 4d9ab291a..b78f714b2 100644 --- a/src/api/java/ASTVector.java +++ b/src/api/java/ASTVector.java @@ -131,7 +131,7 @@ public class ASTVector extends Z3Object { Expr[] res = new Expr[n]; for (int i = 0; i < n; i++) res[i] = Expr.create(getContext(), get(i).getNativeObject()); - return res; + return res; } /** diff --git a/src/api/java/AlgebraicNum.java b/src/api/java/AlgebraicNum.java index 6725d3937..7369e06e3 100644 --- a/src/api/java/AlgebraicNum.java +++ b/src/api/java/AlgebraicNum.java @@ -22,57 +22,57 @@ package com.microsoft.z3; **/ public class AlgebraicNum extends ArithExpr { - /** - * Return a upper bound for a given real algebraic number. The interval - * isolating the number is smaller than 1/10^{@code precision}. - * - * @see Expr#isAlgebraicNumber - * @param precision the precision of the result - * - * @return A numeral Expr of sort Real - * @throws Z3Exception on error - **/ - public RatNum toUpper(int precision) - { + /** + * Return a upper bound for a given real algebraic number. The interval + * isolating the number is smaller than 1/10^{@code precision}. + * + * @see Expr#isAlgebraicNumber + * @param precision the precision of the result + * + * @return A numeral Expr of sort Real + * @throws Z3Exception on error + **/ + public RatNum toUpper(int precision) + { - return new RatNum(getContext(), Native.getAlgebraicNumberUpper(getContext() - .nCtx(), getNativeObject(), precision)); - } + return new RatNum(getContext(), Native.getAlgebraicNumberUpper(getContext() + .nCtx(), getNativeObject(), precision)); + } - /** - * Return a lower bound for the given real algebraic number. The interval - * isolating the number is smaller than 1/10^{@code precision}. - * - * @see Expr#isAlgebraicNumber - * @param precision precision - * - * @return A numeral Expr of sort Real - * @throws Z3Exception on error - **/ - public RatNum toLower(int precision) - { + /** + * Return a lower bound for the given real algebraic number. The interval + * isolating the number is smaller than 1/10^{@code precision}. + * + * @see Expr#isAlgebraicNumber + * @param precision precision + * + * @return A numeral Expr of sort Real + * @throws Z3Exception on error + **/ + public RatNum toLower(int precision) + { - return new RatNum(getContext(), Native.getAlgebraicNumberLower(getContext() - .nCtx(), getNativeObject(), precision)); - } + return new RatNum(getContext(), Native.getAlgebraicNumberLower(getContext() + .nCtx(), getNativeObject(), precision)); + } - /** - * Returns a string representation in decimal notation. - * Remarks: The result has at most {@code precision} decimal places. - * @param precision precision - * @return String - * @throws Z3Exception on error - **/ - public String toDecimal(int precision) - { + /** + * Returns a string representation in decimal notation. + * Remarks: The result has at most {@code precision} decimal places. + * @param precision precision + * @return String + * @throws Z3Exception on error + **/ + public String toDecimal(int precision) + { - return Native.getNumeralDecimalString(getContext().nCtx(), getNativeObject(), - precision); - } + return Native.getNumeralDecimalString(getContext().nCtx(), getNativeObject(), + precision); + } - AlgebraicNum(Context ctx, long obj) - { - super(ctx, obj); + AlgebraicNum(Context ctx, long obj) + { + super(ctx, obj); - } + } } diff --git a/src/api/java/ArraySort.java b/src/api/java/ArraySort.java index 1574823d1..db4d992ed 100644 --- a/src/api/java/ArraySort.java +++ b/src/api/java/ArraySort.java @@ -56,4 +56,10 @@ public class ArraySort extends Sort super(ctx, Native.mkArraySort(ctx.nCtx(), domain.getNativeObject(), range.getNativeObject())); } + + ArraySort(Context ctx, Sort[] domains, Sort range) + { + super(ctx, Native.mkArraySortN(ctx.nCtx(), domains.length, AST.arrayToNative(domains), + range.getNativeObject())); + } }; diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 2609dbb29..76303d670 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -224,6 +224,17 @@ public class Context implements AutoCloseable { return new ArraySort(this, domain, range); } + + /** + * Create a new array sort. + **/ + public ArraySort mkArraySort(Sort[] domains, Sort range) + { + checkContextMatch(domains); + checkContextMatch(range); + return new ArraySort(this, domains, range); + } + /** * Create a new string sort **/ @@ -414,7 +425,7 @@ public class Context implements AutoCloseable { * that is passed in as argument is updated with value v, * the remaining fields of t are unchanged. **/ - public Expr MkUpdateField(FuncDecl field, Expr t, Expr v) + public Expr mkUpdateField(FuncDecl field, Expr t, Expr v) throws Z3Exception { return Expr.create (this, @@ -706,7 +717,7 @@ public class Context implements AutoCloseable { } /** - * Mk an expression representing {@code not(a)}. + * Create an expression representing {@code not(a)}. **/ public BoolExpr mkNot(BoolExpr a) { @@ -1679,6 +1690,28 @@ public class Context implements AutoCloseable { i.getNativeObject())); } + /** + * Array read. + * Remarks: The argument {@code a} is the array and + * {@code args} are the indices of the array that gets read. + * + * The node {@code a} must have an array sort + * {@code [domains -> range]}, and {@code args} must have the sorts + * {@code domains}. The sort of the result is {@code range}. + * + * @see #mkArraySort + * @see #mkStore + + **/ + public Expr mkSelect(ArrayExpr a, Expr[] args) + { + checkContextMatch(a); + checkContextMatch(args); + return Expr.create( + this, + Native.mkSelectN(nCtx(), a.getNativeObject(), args.length, AST.arrayToNative(args))); + } + /** * Array update. * Remarks: The node {@code a} must have an array sort @@ -1704,6 +1737,31 @@ public class Context implements AutoCloseable { i.getNativeObject(), v.getNativeObject())); } + /** + * Array update. + * Remarks: The node {@code a} must have an array sort + * {@code [domains -> range]}, {@code i} must have sort + * {@code domain}, {@code v} must have sort range. The sort of the + * result is {@code [domains -> range]}. The semantics of this function + * is given by the theory of arrays described in the SMT-LIB standard. See + * http://smtlib.org for more details. The result of this function is an + * array that is equal to {@code a} (with respect to + * {@code select}) on all indices except for {@code args}, where it + * maps to {@code v} (and the {@code select} of {@code a} + * with respect to {@code args} may be a different value). + * @see #mkArraySort + * @see #mkSelect + + **/ + public ArrayExpr mkStore(ArrayExpr a, Expr[] args, Expr v) + { + checkContextMatch(a); + checkContextMatch(args); + checkContextMatch(v); + return new ArrayExpr(this, Native.mkStoreN(nCtx(), a.getNativeObject(), + args.length, AST.arrayToNative(args), v.getNativeObject())); + } + /** * Create a constant array. * Remarks: The resulting term is an array, such @@ -1898,8 +1956,8 @@ public class Context implements AutoCloseable { */ public SeqExpr mkEmptySeq(Sort s) { - checkContextMatch(s); - return (SeqExpr) Expr.create(this, Native.mkSeqEmpty(nCtx(), s.getNativeObject())); + checkContextMatch(s); + return (SeqExpr) Expr.create(this, Native.mkSeqEmpty(nCtx(), s.getNativeObject())); } /** @@ -1907,8 +1965,8 @@ public class Context implements AutoCloseable { */ public SeqExpr mkUnit(Expr elem) { - checkContextMatch(elem); - return (SeqExpr) Expr.create(this, Native.mkSeqUnit(nCtx(), elem.getNativeObject())); + checkContextMatch(elem); + return (SeqExpr) Expr.create(this, Native.mkSeqUnit(nCtx(), elem.getNativeObject())); } /** @@ -1916,7 +1974,7 @@ public class Context implements AutoCloseable { */ public SeqExpr mkString(String s) { - return (SeqExpr) Expr.create(this, Native.mkString(nCtx(), s)); + return (SeqExpr) Expr.create(this, Native.mkString(nCtx(), s)); } /** @@ -1924,8 +1982,8 @@ public class Context implements AutoCloseable { */ public SeqExpr mkConcat(SeqExpr... t) { - checkContextMatch(t); - return (SeqExpr) Expr.create(this, Native.mkSeqConcat(nCtx(), t.length, AST.arrayToNative(t))); + checkContextMatch(t); + return (SeqExpr) Expr.create(this, Native.mkSeqConcat(nCtx(), t.length, AST.arrayToNative(t))); } @@ -1934,8 +1992,8 @@ public class Context implements AutoCloseable { */ public IntExpr mkLength(SeqExpr s) { - checkContextMatch(s); - return (IntExpr) Expr.create(this, Native.mkSeqLength(nCtx(), s.getNativeObject())); + checkContextMatch(s); + return (IntExpr) Expr.create(this, Native.mkSeqLength(nCtx(), s.getNativeObject())); } /** @@ -1943,8 +2001,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkPrefixOf(SeqExpr s1, SeqExpr s2) { - checkContextMatch(s1, s2); - return (BoolExpr) Expr.create(this, Native.mkSeqPrefix(nCtx(), s1.getNativeObject(), s2.getNativeObject())); + checkContextMatch(s1, s2); + return (BoolExpr) Expr.create(this, Native.mkSeqPrefix(nCtx(), s1.getNativeObject(), s2.getNativeObject())); } /** @@ -1952,8 +2010,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkSuffixOf(SeqExpr s1, SeqExpr s2) { - checkContextMatch(s1, s2); - return (BoolExpr)Expr.create(this, Native.mkSeqSuffix(nCtx(), s1.getNativeObject(), s2.getNativeObject())); + checkContextMatch(s1, s2); + return (BoolExpr)Expr.create(this, Native.mkSeqSuffix(nCtx(), s1.getNativeObject(), s2.getNativeObject())); } /** @@ -1961,8 +2019,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkContains(SeqExpr s1, SeqExpr s2) { - checkContextMatch(s1, s2); - return (BoolExpr) Expr.create(this, Native.mkSeqContains(nCtx(), s1.getNativeObject(), s2.getNativeObject())); + checkContextMatch(s1, s2); + return (BoolExpr) Expr.create(this, Native.mkSeqContains(nCtx(), s1.getNativeObject(), s2.getNativeObject())); } /** @@ -1970,8 +2028,8 @@ public class Context implements AutoCloseable { */ public SeqExpr mkAt(SeqExpr s, IntExpr index) { - checkContextMatch(s, index); - return (SeqExpr) Expr.create(this, Native.mkSeqAt(nCtx(), s.getNativeObject(), index.getNativeObject())); + checkContextMatch(s, index); + return (SeqExpr) Expr.create(this, Native.mkSeqAt(nCtx(), s.getNativeObject(), index.getNativeObject())); } /** @@ -1979,8 +2037,8 @@ public class Context implements AutoCloseable { */ public SeqExpr mkExtract(SeqExpr s, IntExpr offset, IntExpr length) { - checkContextMatch(s, offset, length); - return (SeqExpr) Expr.create(this, Native.mkSeqExtract(nCtx(), s.getNativeObject(), offset.getNativeObject(), length.getNativeObject())); + checkContextMatch(s, offset, length); + return (SeqExpr) Expr.create(this, Native.mkSeqExtract(nCtx(), s.getNativeObject(), offset.getNativeObject(), length.getNativeObject())); } /** @@ -1988,8 +2046,8 @@ public class Context implements AutoCloseable { */ public IntExpr mkIndexOf(SeqExpr s, SeqExpr substr, ArithExpr offset) { - checkContextMatch(s, substr, offset); - return (IntExpr)Expr.create(this, Native.mkSeqIndex(nCtx(), s.getNativeObject(), substr.getNativeObject(), offset.getNativeObject())); + checkContextMatch(s, substr, offset); + return (IntExpr)Expr.create(this, Native.mkSeqIndex(nCtx(), s.getNativeObject(), substr.getNativeObject(), offset.getNativeObject())); } /** @@ -1997,8 +2055,8 @@ public class Context implements AutoCloseable { */ public SeqExpr mkReplace(SeqExpr s, SeqExpr src, SeqExpr dst) { - checkContextMatch(s, src, dst); - return (SeqExpr) Expr.create(this, Native.mkSeqReplace(nCtx(), s.getNativeObject(), src.getNativeObject(), dst.getNativeObject())); + checkContextMatch(s, src, dst); + return (SeqExpr) Expr.create(this, Native.mkSeqReplace(nCtx(), s.getNativeObject(), src.getNativeObject(), dst.getNativeObject())); } /** @@ -2006,8 +2064,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkToRe(SeqExpr s) { - checkContextMatch(s); - return (ReExpr) Expr.create(this, Native.mkSeqToRe(nCtx(), s.getNativeObject())); + checkContextMatch(s); + return (ReExpr) Expr.create(this, Native.mkSeqToRe(nCtx(), s.getNativeObject())); } @@ -2016,8 +2074,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkInRe(SeqExpr s, ReExpr re) { - checkContextMatch(s, re); - return (BoolExpr) Expr.create(this, Native.mkSeqInRe(nCtx(), s.getNativeObject(), re.getNativeObject())); + checkContextMatch(s, re); + return (BoolExpr) Expr.create(this, Native.mkSeqInRe(nCtx(), s.getNativeObject(), re.getNativeObject())); } /** @@ -2025,8 +2083,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkStar(ReExpr re) { - checkContextMatch(re); - return (ReExpr) Expr.create(this, Native.mkReStar(nCtx(), re.getNativeObject())); + checkContextMatch(re); + return (ReExpr) Expr.create(this, Native.mkReStar(nCtx(), re.getNativeObject())); } /** @@ -2034,7 +2092,7 @@ public class Context implements AutoCloseable { */ public ReExpr mkLoop(ReExpr re, int lo, int hi) { - return (ReExpr) Expr.create(this, Native.mkReLoop(nCtx(), re.getNativeObject(), lo, hi)); + return (ReExpr) Expr.create(this, Native.mkReLoop(nCtx(), re.getNativeObject(), lo, hi)); } /** @@ -2042,7 +2100,7 @@ public class Context implements AutoCloseable { */ public ReExpr mkLoop(ReExpr re, int lo) { - return (ReExpr) Expr.create(this, Native.mkReLoop(nCtx(), re.getNativeObject(), lo, 0)); + return (ReExpr) Expr.create(this, Native.mkReLoop(nCtx(), re.getNativeObject(), lo, 0)); } @@ -2051,8 +2109,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkPlus(ReExpr re) { - checkContextMatch(re); - return (ReExpr) Expr.create(this, Native.mkRePlus(nCtx(), re.getNativeObject())); + checkContextMatch(re); + return (ReExpr) Expr.create(this, Native.mkRePlus(nCtx(), re.getNativeObject())); } /** @@ -2060,8 +2118,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkOption(ReExpr re) { - checkContextMatch(re); - return (ReExpr) Expr.create(this, Native.mkReOption(nCtx(), re.getNativeObject())); + checkContextMatch(re); + return (ReExpr) Expr.create(this, Native.mkReOption(nCtx(), re.getNativeObject())); } @@ -2070,8 +2128,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkComplement(ReExpr re) { - checkContextMatch(re); - return (ReExpr) Expr.create(this, Native.mkReComplement(nCtx(), re.getNativeObject())); + checkContextMatch(re); + return (ReExpr) Expr.create(this, Native.mkReComplement(nCtx(), re.getNativeObject())); } /** @@ -2079,8 +2137,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkConcat(ReExpr... t) { - checkContextMatch(t); - return (ReExpr) Expr.create(this, Native.mkReConcat(nCtx(), t.length, AST.arrayToNative(t))); + checkContextMatch(t); + return (ReExpr) Expr.create(this, Native.mkReConcat(nCtx(), t.length, AST.arrayToNative(t))); } /** @@ -2088,8 +2146,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkUnion(ReExpr... t) { - checkContextMatch(t); - return (ReExpr) Expr.create(this, Native.mkReUnion(nCtx(), t.length, AST.arrayToNative(t))); + checkContextMatch(t); + return (ReExpr) Expr.create(this, Native.mkReUnion(nCtx(), t.length, AST.arrayToNative(t))); } /** @@ -2097,17 +2155,17 @@ public class Context implements AutoCloseable { */ public ReExpr mkIntersect(ReExpr... t) { - checkContextMatch(t); - return (ReExpr) Expr.create(this, Native.mkReIntersect(nCtx(), t.length, AST.arrayToNative(t))); + checkContextMatch(t); + return (ReExpr) Expr.create(this, Native.mkReIntersect(nCtx(), t.length, AST.arrayToNative(t))); } /** * Create a range expression. */ - public ReExpr MkRange(SeqExpr lo, SeqExpr hi) + public ReExpr mkRange(SeqExpr lo, SeqExpr hi) { - checkContextMatch(lo, hi); - return (ReExpr) Expr.create(this, Native.mkReRange(nCtx(), lo.getNativeObject(), hi.getNativeObject())); + checkContextMatch(lo, hi); + return (ReExpr) Expr.create(this, Native.mkReRange(nCtx(), lo.getNativeObject(), hi.getNativeObject())); } @@ -2116,8 +2174,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkAtMost(BoolExpr[] args, int k) { - checkContextMatch(args); - return (BoolExpr) Expr.create(this, Native.mkAtmost(nCtx(), args.length, AST.arrayToNative(args), k)); + checkContextMatch(args); + return (BoolExpr) Expr.create(this, Native.mkAtmost(nCtx(), args.length, AST.arrayToNative(args), k)); } /** @@ -2125,8 +2183,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkAtLeast(BoolExpr[] args, int k) { - checkContextMatch(args); - return (BoolExpr) Expr.create(this, Native.mkAtleast(nCtx(), args.length, AST.arrayToNative(args), k)); + checkContextMatch(args); + return (BoolExpr) Expr.create(this, Native.mkAtleast(nCtx(), args.length, AST.arrayToNative(args), k)); } /** @@ -2134,8 +2192,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkPBLe(int[] coeffs, BoolExpr[] args, int k) { - checkContextMatch(args); - return (BoolExpr) Expr.create(this, Native.mkPble(nCtx(), args.length, AST.arrayToNative(args), coeffs, k)); + checkContextMatch(args); + return (BoolExpr) Expr.create(this, Native.mkPble(nCtx(), args.length, AST.arrayToNative(args), coeffs, k)); } /** @@ -2143,8 +2201,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkPBGe(int[] coeffs, BoolExpr[] args, int k) { - checkContextMatch(args); - return (BoolExpr) Expr.create(this, Native.mkPbge(nCtx(), args.length, AST.arrayToNative(args), coeffs, k)); + checkContextMatch(args); + return (BoolExpr) Expr.create(this, Native.mkPbge(nCtx(), args.length, AST.arrayToNative(args), coeffs, k)); } /** @@ -2152,8 +2210,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkPBEq(int[] coeffs, BoolExpr[] args, int k) { - checkContextMatch(args); - return (BoolExpr) Expr.create(this, Native.mkPbeq(nCtx(), args.length, AST.arrayToNative(args), coeffs, k)); + checkContextMatch(args); + return (BoolExpr) Expr.create(this, Native.mkPbeq(nCtx(), args.length, AST.arrayToNative(args), coeffs, k)); } @@ -3988,15 +4046,15 @@ public class Context implements AutoCloseable { void checkContextMatch(Z3Object other1, Z3Object other2) { - checkContextMatch(other1); - checkContextMatch(other2); + checkContextMatch(other1); + checkContextMatch(other2); } void checkContextMatch(Z3Object other1, Z3Object other2, Z3Object other3) { - checkContextMatch(other1); - checkContextMatch(other2); - checkContextMatch(other3); + checkContextMatch(other1); + checkContextMatch(other2); + checkContextMatch(other3); } void checkContextMatch(Z3Object[] arr) diff --git a/src/api/java/EnumSort.java b/src/api/java/EnumSort.java index ce2f8d578..e0bd0f617 100644 --- a/src/api/java/EnumSort.java +++ b/src/api/java/EnumSort.java @@ -65,7 +65,7 @@ public class EnumSort extends Sort **/ public Expr getConst(int inx) { - return getContext().mkApp(getConstDecl(inx)); + return getContext().mkApp(getConstDecl(inx)); } /** diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index 6cabbb1b8..d3793a24b 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -1287,7 +1287,7 @@ public class Expr extends AST */ public String getString() { - return Native.getString(getContext().nCtx(), getNativeObject()); + return Native.getString(getContext().nCtx(), getNativeObject()); } /** diff --git a/src/api/java/Model.java b/src/api/java/Model.java index 60abb001d..9c7013aca 100644 --- a/src/api/java/Model.java +++ b/src/api/java/Model.java @@ -200,7 +200,7 @@ public class Model extends Z3Object { * Remarks: This function may fail if {@code t} contains * quantifiers, is partial (MODEL_PARTIAL enabled), or if {@code t} is not well-sorted. In this case a * {@code ModelEvaluationFailedException} is thrown. - * @param t the expression to evaluate + * @param t the expression to evaluate * @param completion An expression {@code completion} When this flag * is enabled, a model value will be assigned to any constant or function * that does not have an interpretation in the model. diff --git a/src/api/java/Optimize.java b/src/api/java/Optimize.java index 5e4535ac4..3edbff73e 100644 --- a/src/api/java/Optimize.java +++ b/src/api/java/Optimize.java @@ -213,7 +213,7 @@ public class Optimize extends Z3Object { * Declare an arithmetical maximization objective. * Return a handle to the objective. The handle is used as * to retrieve the values of objectives after calling Check. - **/ + **/ public Handle MkMaximize(ArithExpr e) { return new Handle(this, Native.optimizeMaximize(getContext().nCtx(), getNativeObject(), e.getNativeObject())); @@ -285,8 +285,7 @@ public class Optimize extends Z3Object { **/ public String getReasonUnknown() { - return Native.optimizeGetReasonUnknown(getContext().nCtx(), - getNativeObject()); + return Native.optimizeGetReasonUnknown(getContext().nCtx(), getNativeObject()); } /** @@ -298,6 +297,24 @@ public class Optimize extends Z3Object { return Native.optimizeToString(getContext().nCtx(), getNativeObject()); } + /** + * Parse an SMT-LIB2 file with optimization objectives and constraints. + * The parsed constraints and objectives are added to the optimization context. + */ + public void fromFile(String file) + { + Native.optimizeFromFile(getContext().nCtx(), getNativeObject(), file); + } + + /** + * Similar to FromFile. Instead it takes as argument a string. + */ + public void fromString(String s) + { + Native.optimizeFromString(getContext().nCtx(), getNativeObject(), s); + } + + /** * Optimize statistics. **/ diff --git a/src/api/java/ParamDescrs.java b/src/api/java/ParamDescrs.java index 0008515e3..fdaf29647 100644 --- a/src/api/java/ParamDescrs.java +++ b/src/api/java/ParamDescrs.java @@ -49,7 +49,7 @@ public class ParamDescrs extends Z3Object { public String getDocumentation(Symbol name) { - return Native.paramDescrsGetDocumentation(getContext().nCtx(), getNativeObject(), name.getNativeObject()); + return Native.paramDescrsGetDocumentation(getContext().nCtx(), getNativeObject(), name.getNativeObject()); } /** diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index a98fcbf94..19f3b01da 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -302,7 +302,7 @@ public class Solver extends Z3Object { */ public Solver translate(Context ctx) { - return new Solver(ctx, Native.solverTranslate(getContext().nCtx(), getNativeObject(), ctx.nCtx())); + return new Solver(ctx, Native.solverTranslate(getContext().nCtx(), getNativeObject(), ctx.nCtx())); } /** diff --git a/src/api/java/Sort.java b/src/api/java/Sort.java index e7a186ad2..a89417059 100644 --- a/src/api/java/Sort.java +++ b/src/api/java/Sort.java @@ -35,12 +35,8 @@ public class Sort extends AST if (!(o instanceof Sort)) return false; Sort other = (Sort) o; - return (getContext().nCtx() == other.getContext().nCtx()) && - (Native.isEqSort( - getContext().nCtx(), - getNativeObject(), - other.getNativeObject() - )); + return (getContext().nCtx() == other.getContext().nCtx()) && + (Native.isEqSort(getContext().nCtx(), getNativeObject(), other.getNativeObject())); } /** diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 41d2226c5..46fe5bd6d 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1215,6 +1215,44 @@ struct let mk_numeral ctx v size = Z3native.mk_numeral ctx v (mk_sort ctx size) end +module Seq = +struct + let mk_seq_sort = Z3native.mk_seq_sort + let is_seq_sort = Z3native.is_seq_sort + let mk_re_sort = Z3native.mk_re_sort + let is_re_sort = Z3native.is_re_sort + let mk_string_sort = Z3native.mk_string_sort + let is_string_sort = Z3native.is_string_sort + let mk_string = Z3native.mk_string + let is_string = Z3native.is_string + let get_string = Z3native.get_string + let mk_seq_empty = Z3native.mk_seq_empty + let mk_seq_unit = Z3native.mk_seq_unit + let mk_seq_concat ctx args = Z3native.mk_seq_concat ctx (List.length args) args + let mk_seq_prefix = Z3native.mk_seq_prefix + let mk_seq_suffix = Z3native.mk_seq_suffix + let mk_seq_contains = Z3native.mk_seq_contains + let mk_seq_extract = Z3native.mk_seq_extract + let mk_seq_replace = Z3native.mk_seq_replace + let mk_seq_at = Z3native.mk_seq_at + let mk_seq_length = Z3native.mk_seq_length + let mk_seq_index = Z3native.mk_seq_index + let mk_str_to_int = Z3native.mk_str_to_int + let mk_int_to_str = Z3native.mk_int_to_str + let mk_seq_to_re = Z3native.mk_seq_to_re + let mk_seq_in_re = Z3native.mk_seq_in_re + let mk_re_plus = Z3native.mk_re_plus + let mk_re_star = Z3native.mk_re_star + let mk_re_option = Z3native.mk_re_option + let mk_re_union ctx args = Z3native.mk_re_union ctx (List.length args) args + let mk_re_concat ctx args = Z3native.mk_re_concat ctx (List.length args) args + let mk_re_range = Z3native.mk_re_range + let mk_re_loop = Z3native.mk_re_loop + let mk_re_intersect = Z3native.mk_re_intersect + let mk_re_complement = Z3native.mk_re_complement + let mk_re_empty = Z3native.mk_re_empty + let mk_re_full = Z3native.mk_re_full +end module FloatingPoint = struct @@ -1926,7 +1964,7 @@ struct let from_file (x:optimize) (s:string) = Z3native.optimize_from_file (gc x) x s let from_string (x:optimize) (s:string) = Z3native.optimize_from_string (gc x) x s let get_assertions (x:optimize) = AST.ASTVector.to_expr_list (Z3native.optimize_get_assertions (gc x) x) - let get_objectives (x:optimize) = AST.ASTVector.to_expr_list (Z3native.optimize_get_statistics (gc x) x) + let get_objectives (x:optimize) = AST.ASTVector.to_expr_list (Z3native.optimize_get_objectives (gc x) x) end diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 818a635f7..4f10b275a 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -1825,6 +1825,116 @@ sig val mk_numeral : context -> string -> int -> Expr.expr end +(** Sequences, Strings and Regular Expressions **) +module Seq : +sig + (* create a sequence sort *) + val mk_seq_sort : context -> Sort.sort -> Sort.sort + + (* test if sort is a sequence sort *) + val is_seq_sort : context -> Sort.sort -> bool + + (* create regular expression sorts over sequences of the argument sort *) + val mk_re_sort : context -> Sort.sort -> Sort.sort + + (* test if sort is a regular expression sort *) + val is_re_sort : context -> Sort.sort -> bool + + (* create string sort *) + val mk_string_sort : context -> Sort.sort + + (* test if sort is a string sort (a sequence of 8-bit bit-vectors) *) + val is_string_sort : context -> Sort.sort -> bool + + (* create a string literal *) + val mk_string : context -> string -> Expr.expr + + (* test if expression is a string *) + val is_string : context -> Expr.expr -> bool + + (* retrieve string from string Expr.expr *) + val get_string : context -> Expr.expr -> string + + (* the empty sequence over base sort *) + val mk_seq_empty : context -> Sort.sort -> Expr.expr + + (* a unit sequence *) + val mk_seq_unit : context -> Expr.expr -> Expr.expr + + (* sequence concatenation *) + val mk_seq_concat : context -> Expr.expr list -> Expr.expr + + (* predicate if the first argument is a prefix of the second *) + val mk_seq_prefix : context -> Expr.expr -> Expr.expr -> Expr.expr + + (* predicate if the first argument is a suffix of the second *) + val mk_seq_suffix : context -> Expr.expr -> Expr.expr -> Expr.expr + + (* predicate if the first argument contains the second *) + val mk_seq_contains : context -> Expr.expr -> Expr.expr -> Expr.expr + + (* extract sub-sequence starting at index given by second argument and of length provided by third argument *) + val mk_seq_extract : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr + + (* replace first occurrence of second argument by third *) + val mk_seq_replace : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr + + (* a unit sequence at index provided by second argument *) + val mk_seq_at : context -> Expr.expr -> Expr.expr -> Expr.expr + + (* length of a sequence *) + val mk_seq_length : context -> Expr.expr -> Expr.expr + + (* index of the first occurrence of the second argument in the first *) + val mk_seq_index : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr + + (* retrieve integer expression encoded in string *) + val mk_str_to_int : context -> Expr.expr -> Expr.expr + + (* convert an integer expression to a string *) + val mk_int_to_str : context -> Expr.expr -> Expr.expr + + (* create regular expression that accepts the argument sequence *) + val mk_seq_to_re : context -> Expr.expr -> Expr.expr + + (* regular expression membership predicate *) + val mk_seq_in_re : context -> Expr.expr -> Expr.expr -> Expr.expr + + (* regular expression plus *) + val mk_re_plus : context -> Expr.expr -> Expr.expr + + (* regular expression star *) + val mk_re_star : context -> Expr.expr -> Expr.expr + + (* optional regular expression *) + val mk_re_option : context -> Expr.expr -> Expr.expr + + (* union of regular expressions *) + val mk_re_union : context -> Expr.expr list -> Expr.expr + + (* concatenation of regular expressions *) + val mk_re_concat : context -> Expr.expr list -> Expr.expr + + (* regular expression for the range between two characters *) + val mk_re_range : context -> Expr.expr -> Expr.expr -> Expr.expr + + (* bounded loop regular expression *) + val mk_re_loop : context -> Expr.expr -> int -> int -> Expr.expr + + (* intersection of regular expressions *) + val mk_re_intersect : context -> int -> Expr.expr list -> Expr.expr + + (* the regular expression complement *) + val mk_re_complement : context -> Expr.expr -> Expr.expr + + (* the regular expression that accepts no sequences *) + val mk_re_empty : context -> Sort.sort -> Expr.expr + + (* the regular expression that accepts all sequences *) + val mk_re_full : context -> Sort.sort -> Expr.expr + +end + (** Floating-Point Arithmetic *) module FloatingPoint : sig diff --git a/src/api/ml/z3native_stubs.c.pre b/src/api/ml/z3native_stubs.c.pre index 5960d5095..c1c772c85 100644 --- a/src/api/ml/z3native_stubs.c.pre +++ b/src/api/ml/z3native_stubs.c.pre @@ -25,31 +25,34 @@ extern "C" { #include #define CAMLlocal6(X1,X2,X3,X4,X5,X6) \ - CAMLlocal5(X1,X2,X3,X4,X5); \ + CAMLlocal5(X1,X2,X3,X4,X5); \ CAMLlocal1(X6) -#define CAMLlocal7(X1,X2,X3,X4,X5,X6,X7) \ - CAMLlocal5(X1,X2,X3,X4,X5); \ +#define CAMLlocal7(X1,X2,X3,X4,X5,X6,X7) \ + CAMLlocal5(X1,X2,X3,X4,X5); \ CAMLlocal2(X6,X7) -#define CAMLlocal8(X1,X2,X3,X4,X5,X6,X7,X8) \ - CAMLlocal5(X1,X2,X3,X4,X5); \ +#define CAMLlocal8(X1,X2,X3,X4,X5,X6,X7,X8) \ + CAMLlocal5(X1,X2,X3,X4,X5); \ CAMLlocal3(X6,X7,X8) -#define CAMLparam7(X1,X2,X3,X4,X5,X6,X7) \ - CAMLparam5(X1,X2,X3,X4,X5); \ +#define CAMLparam6(X1,X2,X3,X4,X5,X6) \ + CAMLparam5(X1,X2,X3,X4,X5); \ + CAMLxparam1(X6) +#define CAMLparam7(X1,X2,X3,X4,X5,X6,X7) \ + CAMLparam5(X1,X2,X3,X4,X5); \ CAMLxparam2(X6,X7) -#define CAMLparam8(X1,X2,X3,X4,X5,X6,X7,X8) \ - CAMLparam5(X1,X2,X3,X4,X5); \ +#define CAMLparam8(X1,X2,X3,X4,X5,X6,X7,X8) \ + CAMLparam5(X1,X2,X3,X4,X5); \ CAMLxparam3(X6,X7,X8) -#define CAMLparam9(X1,X2,X3,X4,X5,X6,X7,X8,X9) \ - CAMLparam5(X1,X2,X3,X4,X5); \ +#define CAMLparam9(X1,X2,X3,X4,X5,X6,X7,X8,X9) \ + CAMLparam5(X1,X2,X3,X4,X5); \ CAMLxparam4(X6,X7,X8,X9) -#define CAMLparam12(X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12) \ - CAMLparam5(X1,X2,X3,X4,X5); \ - CAMLxparam5(X6,X7,X8,X9,X10); \ +#define CAMLparam12(X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12) \ + CAMLparam5(X1,X2,X3,X4,X5); \ + CAMLxparam5(X6,X7,X8,X9,X10); \ CAMLxparam2(X11,X12) -#define CAMLparam13(X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13) \ - CAMLparam5(X1,X2,X3,X4,X5); \ - CAMLxparam5(X6,X7,X8,X9,X10); \ +#define CAMLparam13(X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13) \ + CAMLparam5(X1,X2,X3,X4,X5); \ + CAMLxparam5(X6,X7,X8,X9,X10); \ CAMLxparam3(X11,X12,X13) diff --git a/src/api/ml/z3native_stubs.h b/src/api/ml/z3native_stubs.h index ef81ac239..ec498dafe 100644 --- a/src/api/ml/z3native_stubs.h +++ b/src/api/ml/z3native_stubs.h @@ -36,5 +36,5 @@ Notes: #define DLL_LOCAL #endif #endif - + #endif diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index a16c1b92b..a521c5169 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -120,7 +120,7 @@ def _get_args(args): try: if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)): return args[0] - elif len(args) == 1 and isinstance(args[0], set): + elif len(args) == 1 and (isinstance(args[0], set) or isinstance(args[0], AstVector)): return [arg for arg in args[0]] else: return args @@ -6536,6 +6536,22 @@ class Fixedpoint(Z3PPObject): r = Z3_fixedpoint_query(self.ctx.ref(), self.fixedpoint, query.as_ast()) return CheckSatResult(r) + def query_from_lvl (self, lvl, *query): + """Query the fixedpoint engine whether formula is derivable starting at the given query level. + """ + query = _get_args(query) + sz = len(query) + if sz >= 1 and isinstance(query[0], FuncDecl): + _z3_assert (False, "unsupported") + else: + if sz == 1: + query = query[0] + else: + query = And(query) + query = self.abstract(query, False) + r = Z3_fixedpoint_query_from_lvl (self.ctx.ref(), self.fixedpoint, query.as_ast(), lvl) + return CheckSatResult(r) + def push(self): """create a backtracking point for added rules, facts and assertions""" Z3_fixedpoint_push(self.ctx.ref(), self.fixedpoint) @@ -6558,6 +6574,23 @@ class Fixedpoint(Z3PPObject): r = Z3_fixedpoint_get_answer(self.ctx.ref(), self.fixedpoint) return _to_expr_ref(r, self.ctx) + def get_ground_sat_answer(self): + """Retrieve a ground cex from last query call.""" + r = Z3_fixedpoint_get_ground_sat_answer(self.ctx.ref(), self.fixedpoint) + return _to_expr_ref(r, self.ctx) + + def get_rules_along_trace(self): + """retrieve rules along the counterexample trace""" + return AstVector(Z3_fixedpoint_get_rules_along_trace(self.ctx.ref(), self.fixedpoint), self.ctx) + + def get_rule_names_along_trace(self): + """retrieve rule names along the counterexample trace""" + # this is a hack as I don't know how to return a list of symbols from C++; + # obtain names as a single string separated by semicolons + names = _symbol2py (self.ctx, Z3_fixedpoint_get_rule_names_along_trace(self.ctx.ref(), self.fixedpoint)) + # split into individual names + return names.split (';') + def get_num_levels(self, predicate): """Retrieve number of levels used for predicate in PDR engine""" return Z3_fixedpoint_get_num_levels(self.ctx.ref(), self.fixedpoint, predicate.ast) @@ -8152,9 +8185,9 @@ def sequence_interpolant(v,p=None,ctx=None): If parameters p are supplied, these are used in creating the solver that determines satisfiability. - >>> x = Int('x') - >>> y = Int('y') - >>> print(sequence_interpolant([x < 0, y == x , y > 2])) + x = Int('x') + y = Int('y') + print(sequence_interpolant([x < 0, y == x , y > 2])) [Not(x >= 0), Not(y >= 0)] """ f = v[0] diff --git a/src/api/z3.h b/src/api/z3.h index ffa200807..99929f33b 100644 --- a/src/api/z3.h +++ b/src/api/z3.h @@ -22,16 +22,16 @@ Notes: #define Z3_H_ #include -#include"z3_macros.h" -#include"z3_api.h" -#include"z3_ast_containers.h" -#include"z3_algebraic.h" -#include"z3_polynomial.h" -#include"z3_rcf.h" -#include"z3_fixedpoint.h" -#include"z3_optimization.h" -#include"z3_interp.h" -#include"z3_fpa.h" - +#include "z3_macros.h" +#include "z3_api.h" +#include "z3_ast_containers.h" +#include "z3_algebraic.h" +#include "z3_polynomial.h" +#include "z3_rcf.h" +#include "z3_fixedpoint.h" +#include "z3_optimization.h" +#include "z3_interp.h" +#include "z3_fpa.h" +#include "z3_spacer.h" #endif diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 8d53c9255..9f155b45e 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -397,23 +397,23 @@ typedef enum (xor3 l1 l2 l3) <=> (xor (xor l1 l2) l3) - Z3_OP_BSMUL_NO_OVFL: a predicate to check that bit-wise signed multiplication does not overflow. - Signed multiplication overflows if the operands have the same sign and the result of multiplication + Signed multiplication overflows if the operands have the same sign and the result of multiplication does not fit within the available bits. \sa Z3_mk_bvmul_no_overflow. - Z3_OP_BUMUL_NO_OVFL: check that bit-wise unsigned multiplication does not overflow. Unsigned multiplication overflows if the result does not fit within the available bits. \sa Z3_mk_bvmul_no_overflow. - + - Z3_OP_BSMUL_NO_UDFL: check that bit-wise signed multiplication does not underflow. Signed multiplication underflows if the operands have opposite signs and the result of multiplication does not fit within the avaialble bits. Z3_mk_bvmul_no_underflow. - - - Z3_OP_BSDIV_I: Binary signed division. + + - Z3_OP_BSDIV_I: Binary signed division. It has the same semantics as Z3_OP_BSDIV, but created in a context where the second operand can be assumed to be non-zero. - Z3_OP_BUDIV_I: Binary unsigned division. It has the same semantics as Z3_OP_BUDIV, but created in a context where the second operand can be assumed to be non-zero. - + - Z3_OP_BSREM_I: Binary signed remainder. It has the same semantics as Z3_OP_BSREM, but created in a context where the second operand can be assumed to be non-zero. @@ -979,7 +979,23 @@ typedef enum - Z3_OP_FPA_TO_IEEE_BV: Floating-point conversion to IEEE-754 bit-vector - - Z3_OP_INTERNAL: internal (often interpreted) symbol, but no additional information is exposed. Tools may use the string representation of the function declaration to obtain more information. + - Z3_OP_FPA_BVWRAP: (Implicitly) represents the internal bitvector- + representation of a floating-point term (used for the lazy encoding + of non-relevant terms in theory_fpa) + + - Z3_OP_FPA_BV2RM: Conversion of a 3-bit bit-vector term to a + floating-point rouding-mode term + + The conversion uses the following values: + 0 = 000 = Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN, + 1 = 001 = Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY, + 2 = 010 = Z3_OP_FPA_RM_TOWARD_POSITIVE, + 3 = 011 = Z3_OP_FPA_RM_TOWARD_NEGATIVE, + 4 = 100 = Z3_OP_FPA_RM_TOWARD_ZERO. + + - Z3_OP_INTERNAL: internal (often interpreted) symbol, but no additional + information is exposed. Tools may use the string representation of the + function declaration to obtain more information. - Z3_OP_UNINTERPRETED: kind used for uninterpreted symbols. */ @@ -1263,8 +1279,8 @@ typedef enum { Z3_OP_FPA_TO_IEEE_BV, - Z3_OP_FPA_MIN_I, - Z3_OP_FPA_MAX_I, + Z3_OP_FPA_BVWRAP, + Z3_OP_FPA_BV2RM, Z3_OP_INTERNAL, @@ -1530,7 +1546,7 @@ extern "C" { In contrast to #Z3_mk_context_rc, the life time of Z3_ast objects are determined by the scope level of #Z3_solver_push and #Z3_solver_pop. In other words, a Z3_ast object remains valid until there is a - call to Z3_pop that takes the current scope below the level where + call to Z3_solver_pop that takes the current scope below the level where the object was created. Note that all other reference counted objects, including Z3_model, @@ -1865,6 +1881,17 @@ extern "C" { */ Z3_sort Z3_API Z3_mk_array_sort(Z3_context c, Z3_sort domain, Z3_sort range); + /** + \brief Create an array type with N arguments + + \sa Z3_mk_select_n + \sa Z3_mk_store_n + + def_API('Z3_mk_array_sort_n', SORT, (_in(CONTEXT), _in(UINT), _in_array(1, SORT), _in(SORT))) + */ + Z3_sort Z3_API Z3_mk_array_sort_n(Z3_context c, unsigned n, Z3_sort const * domain, Z3_sort range); + + /** \brief Create a tuple type. @@ -2957,6 +2984,15 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i); + /** + \brief n-ary Array read. + The argument \c a is the array and \c idxs are the indices of the array that gets read. + + def_API('Z3_mk_select_n', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST))) + + */ + Z3_ast Z3_API Z3_mk_select_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs); + /** \brief Array update. @@ -2975,6 +3011,14 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v); + /** + \brief n-ary Array update. + + def_API('Z3_mk_store_n', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST), _in(AST))) + + */ + Z3_ast Z3_API Z3_mk_store_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs, Z3_ast v); + /** \brief Create the constant array. @@ -3015,6 +3059,15 @@ extern "C" { def_API('Z3_mk_array_default', AST, (_in(CONTEXT), _in(AST))) */ Z3_ast Z3_API Z3_mk_array_default(Z3_context c, Z3_ast array); + + /** + \brief Create array with the same interpretation as a function. + The array satisfies the property (f x) = (select (_ as-array f) x) + for every argument x. + + def_API('Z3_mk_as_array', AST, (_in(CONTEXT), _in(FUNC_DECL))) + */ + Z3_ast Z3_API Z3_mk_as_array(Z3_context c, Z3_func_decl f); /*@}*/ /** @name Sets */ @@ -3361,7 +3414,7 @@ extern "C" { \brief Convert string to integer. def_API('Z3_mk_str_to_int' ,AST ,(_in(CONTEXT), _in(AST))) - */ + */ Z3_ast Z3_API Z3_mk_str_to_int(Z3_context c, Z3_ast s); @@ -3369,7 +3422,7 @@ extern "C" { \brief Integer to string conversion. def_API('Z3_mk_int_to_str' ,AST ,(_in(CONTEXT), _in(AST))) - */ + */ Z3_ast Z3_API Z3_mk_int_to_str(Z3_context c, Z3_ast s); /** @@ -3838,6 +3891,7 @@ extern "C" { /** \brief Return the domain of the given array sort. + In the case of a multi-dimensional array, this function returns the sort of the first dimension. \pre Z3_get_sort_kind(c, t) == Z3_ARRAY_SORT @@ -4680,6 +4734,14 @@ extern "C" { /** @name Models */ /*@{*/ + + /** + \brief Create a fresh model object. It has reference count 0. + + def_API('Z3_mk_model', MODEL, (_in(CONTEXT),)) + */ + Z3_model Z3_API Z3_mk_model(Z3_context c); + /** \brief Increment the reference counter of the given model. @@ -4850,6 +4912,26 @@ extern "C" { */ Z3_func_decl Z3_API Z3_get_as_array_func_decl(Z3_context c, Z3_ast a); + /** + \brief Create a fresh func_interp object, add it to a model for a specified function. + It has reference count 0. + + \param c context + \param m model + \param f function declaration + \param default_value default value for function interpretation + + def_API('Z3_add_func_interp', FUNC_INTERP, (_in(CONTEXT), _in(MODEL), _in(FUNC_DECL), _in(AST))) + */ + Z3_func_interp Z3_API Z3_add_func_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast default_value); + + /** + \brief Add a constant interpretation. + + def_API('Z3_add_const_interp', VOID, (_in(CONTEXT), _in(MODEL), _in(FUNC_DECL), _in(AST))) + */ + void Z3_API Z3_add_const_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast a); + /** \brief Increment the reference counter of the given Z3_func_interp object. @@ -4897,6 +4979,16 @@ extern "C" { */ Z3_ast Z3_API Z3_func_interp_get_else(Z3_context c, Z3_func_interp f); + /** + \brief Return the 'else' value of the given function interpretation. + + A function interpretation is represented as a finite map and an 'else' value. + This procedure can be used to update the 'else' value. + + def_API('Z3_func_interp_set_else', VOID, (_in(CONTEXT), _in(FUNC_INTERP), _in(AST))) + */ + void Z3_API Z3_func_interp_set_else(Z3_context c, Z3_func_interp f, Z3_ast else_value); + /** \brief Return the arity (number of arguments) of the given function interpretation. @@ -4904,6 +4996,22 @@ extern "C" { */ unsigned Z3_API Z3_func_interp_get_arity(Z3_context c, Z3_func_interp f); + /** + \brief add a function entry to a function interpretation. + + \param c logical context + \param fi a function interpregation to be updated. + \param args list of arguments. They should be constant values (such as integers) and be of the same types as the domain of the function. + \param value value of the function when the parameters match args. + + It is assumed that entries added to a function cover disjoint arguments. + If an two entries are added with the same arguments, only the second insertion survives and the + first inserted entry is removed. + + def_API('Z3_func_interp_add_entry', VOID, (_in(CONTEXT), _in(FUNC_INTERP), _in(AST_VECTOR), _in(AST))) + */ + void Z3_API Z3_func_interp_add_entry(Z3_context c, Z3_func_interp fi, Z3_ast_vector args, Z3_ast value); + /** \brief Increment the reference counter of the given Z3_func_entry object. diff --git a/src/api/z3_ast_containers.h b/src/api/z3_ast_containers.h index 027976c07..c423a3286 100644 --- a/src/api/z3_ast_containers.h +++ b/src/api/z3_ast_containers.h @@ -197,4 +197,4 @@ extern "C" { } #endif // __cplusplus -#endif \ No newline at end of file +#endif diff --git a/src/api/z3_logger.h b/src/api/z3_logger.h index 4d83f90c2..dd2816bff 100644 --- a/src/api/z3_logger.h +++ b/src/api/z3_logger.h @@ -17,7 +17,7 @@ Notes: --*/ #include -#include"symbol.h" +#include "util/symbol.h" struct ll_escaped { char const * m_str; ll_escaped(char const * str):m_str(str) {} }; static std::ostream & operator<<(std::ostream & out, ll_escaped const & d); diff --git a/src/api/z3_private.h b/src/api/z3_private.h index e5fe4b521..7b60a6ab9 100644 --- a/src/api/z3_private.h +++ b/src/api/z3_private.h @@ -19,8 +19,8 @@ Notes: --*/ #include -#include"rational.h" -#include"z3_macros.h" +#include "util/rational.h" +#include "api/z3_macros.h" #ifndef Z3_PRIVATE_H_ #define Z3_PRIVATE_H_ diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 68f279e3d..84dcfc363 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -16,12 +16,12 @@ Author: Notes: --*/ -#include"vector.h" -#include"map.h" -#include"z3_replayer.h" -#include"stream_buffer.h" -#include"symbol.h" -#include"trace.h" +#include "util/vector.h" +#include "util/map.h" +#include "api/z3_replayer.h" +#include "util/stream_buffer.h" +#include "util/symbol.h" +#include "util/trace.h" #include #include diff --git a/src/api/z3_replayer.h b/src/api/z3_replayer.h index 88654363d..e1b32af75 100644 --- a/src/api/z3_replayer.h +++ b/src/api/z3_replayer.h @@ -20,8 +20,8 @@ Notes: #define Z3_REPLAYER_H_ #include -#include"z3.h" -#include"z3_exception.h" +#include "api/z3.h" +#include "util/z3_exception.h" class z3_replayer; diff --git a/src/api/z3_spacer.h b/src/api/z3_spacer.h new file mode 100644 index 000000000..88129d095 --- /dev/null +++ b/src/api/z3_spacer.h @@ -0,0 +1,143 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + z3_spacer.h + +Abstract: + + Spacer API + +Author: + + Arie Gurfinkel (arie) + +Notes: + +--*/ +#ifndef Z3_SPACER_H_ +#define Z3_SPACER_H_ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + /** \defgroup capi C API */ + /*@{*/ + + /** @name Spacer facilities */ + /*@{*/ + /** + \brief Pose a query against the asserted rules at the given level. + + \code + query ::= (exists (bound-vars) query) + | literals + \endcode + + query returns + - Z3_L_FALSE if the query is unsatisfiable. + - Z3_L_TRUE if the query is satisfiable. Obtain the answer by calling #Z3_fixedpoint_get_answer. + - Z3_L_UNDEF if the query was interrupted, timed out or otherwise failed. + + def_API('Z3_fixedpoint_query_from_lvl', INT, (_in(CONTEXT), _in(FIXEDPOINT), _in(AST), _in(UINT))) + */ + Z3_lbool Z3_API Z3_fixedpoint_query_from_lvl (Z3_context c,Z3_fixedpoint d, Z3_ast query, unsigned lvl); + + /** + \brief Retrieve a bottom-up (from query) sequence of ground facts + + The previous call to Z3_fixedpoint_query must have returned Z3_L_TRUE. + + def_API('Z3_fixedpoint_get_ground_sat_answer', AST, (_in(CONTEXT), _in(FIXEDPOINT))) + */ + Z3_ast Z3_API Z3_fixedpoint_get_ground_sat_answer(Z3_context c,Z3_fixedpoint d); + + /** + \brief Obtain the list of rules along the counterexample trace. + + def_API('Z3_fixedpoint_get_rules_along_trace', AST_VECTOR, (_in(CONTEXT), _in(FIXEDPOINT))) + */ + Z3_ast_vector Z3_API Z3_fixedpoint_get_rules_along_trace(Z3_context c,Z3_fixedpoint d); + + /** + \brief Obtain the list of rules along the counterexample trace. + + def_API('Z3_fixedpoint_get_rule_names_along_trace', SYMBOL, (_in(CONTEXT), _in(FIXEDPOINT))) + */ + Z3_symbol Z3_API Z3_fixedpoint_get_rule_names_along_trace(Z3_context c,Z3_fixedpoint d); + + /** + \brief Add an invariant for the predicate \c pred. + Add an assumed invariant of predicate \c pred. + + Note: this functionality is Spacer specific. + + def_API('Z3_fixedpoint_add_invariant', VOID, (_in(CONTEXT), _in(FIXEDPOINT), _in(FUNC_DECL), _in(AST))) + */ + void Z3_API Z3_fixedpoint_add_invariant(Z3_context c, Z3_fixedpoint d, Z3_func_decl pred, Z3_ast property); + + + /** + Retrieve reachable states of a predicate. + Note: this functionality is Spacer specific. + + def_API('Z3_fixedpoint_get_reachable', AST, (_in(CONTEXT), _in(FIXEDPOINT), _in(FUNC_DECL))) + */ + Z3_ast Z3_API Z3_fixedpoint_get_reachable(Z3_context c, Z3_fixedpoint d, Z3_func_decl pred); + + /** + \brief Project variables given a model + + def_API('Z3_qe_model_project', AST, (_in(CONTEXT), _in(MODEL), _in(UINT), _in_array(2, APP), _in(AST))) + */ + Z3_ast Z3_API Z3_qe_model_project + (Z3_context c, + Z3_model m, + unsigned num_bounds, + Z3_app const bound[], + Z3_ast body); + + + /** + \brief Project variables given a model + + def_API('Z3_qe_model_project_skolem', AST, (_in(CONTEXT), _in(MODEL), _in(UINT), _in_array(2, APP), _in(AST), _in(AST_MAP))) + */ + Z3_ast Z3_API Z3_qe_model_project_skolem + (Z3_context c, + Z3_model m, + unsigned num_bounds, + Z3_app const bound[], + Z3_ast body, + Z3_ast_map map); + + /** + \brief Extrapolates a model of a formula + + def_API('Z3_model_extrapolate', AST, (_in(CONTEXT), _in(MODEL), _in(AST))) + */ + Z3_ast Z3_API Z3_model_extrapolate + (Z3_context c, + Z3_model m, + Z3_ast fml); + + /** + \brief Best-effort quantifier elimination + + def_API ('Z3_qe_lite', AST, (_in(CONTEXT), _in(AST_VECTOR), _in(AST))) + */ + Z3_ast Z3_API Z3_qe_lite + (Z3_context c, + Z3_ast_vector vars, + Z3_ast body); + + /*@}*/ + /*@}*/ + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif diff --git a/src/api/z3_v1.h b/src/api/z3_v1.h index 11f492d88..66de943c2 100644 --- a/src/api/z3_v1.h +++ b/src/api/z3_v1.h @@ -21,7 +21,7 @@ Notes: #ifndef Z3_V1_H_ #define Z3_V1_H_ -#include"z3.h" +#include "api/z3.h" // Backwards compatibility #define Z3_type_ast Z3_sort diff --git a/src/ast/CMakeLists.txt b/src/ast/CMakeLists.txt index de0e4bdaf..4dcdd2a35 100644 --- a/src/ast/CMakeLists.txt +++ b/src/ast/CMakeLists.txt @@ -10,6 +10,7 @@ z3_add_component(ast ast_printer.cpp ast_smt2_pp.cpp ast_smt_pp.cpp + ast_pp_dot.cpp ast_translation.cpp ast_util.cpp bv_decl_plugin.cpp @@ -23,6 +24,7 @@ z3_add_component(ast expr_map.cpp expr_stat.cpp expr_substitution.cpp + factor_equivs.cpp for_each_ast.cpp for_each_expr.cpp format.cpp diff --git a/src/ast/act_cache.cpp b/src/ast/act_cache.cpp index 1d1341184..74a7d6fca 100644 --- a/src/ast/act_cache.cpp +++ b/src/ast/act_cache.cpp @@ -17,7 +17,7 @@ Author: Notes: --*/ -#include"act_cache.h" +#include "ast/act_cache.h" #define MIN_MAX_UNUSED 1024 #define INITIAL_CAPACITY 128 diff --git a/src/ast/act_cache.h b/src/ast/act_cache.h index b3567dec2..67c5cf050 100644 --- a/src/ast/act_cache.h +++ b/src/ast/act_cache.h @@ -20,9 +20,9 @@ Notes: #ifndef ACT_CACHE_H_ #define ACT_CACHE_H_ -#include"ast.h" -#include"obj_hashtable.h" -#include"chashtable.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "util/chashtable.h" class act_cache { ast_manager & m_manager; diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index 1c01496cf..03ee77458 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include"arith_decl_plugin.h" -#include"warning.h" -#include"algebraic_numbers.h" -#include"id_gen.h" -#include"ast_smt2_pp.h" +#include "ast/arith_decl_plugin.h" +#include "util/warning.h" +#include "math/polynomial/algebraic_numbers.h" +#include "util/id_gen.h" +#include "ast/ast_smt2_pp.h" struct arith_decl_plugin::algebraic_numbers_wrapper { unsynch_mpq_manager m_qmanager; @@ -81,8 +81,9 @@ app * arith_decl_plugin::mk_numeral(algebraic_numbers::anum const & val, bool is return mk_numeral(rval, is_int); } else { - if (is_int) + if (is_int) { m_manager->raise_exception("invalid irrational value passed as an integer"); + } unsigned idx = aw().mk_id(val); parameter p(idx, true); SASSERT(p.is_external()); @@ -214,18 +215,8 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) { m_e = m->mk_const(e_decl); m->inc_ref(m_e); - func_decl * z_pw_z_int = m->mk_const_decl(symbol("0^0-int"), i, func_decl_info(id, OP_0_PW_0_INT)); - m_0_pw_0_int = m->mk_const(z_pw_z_int); - m->inc_ref(m_0_pw_0_int); - - func_decl * z_pw_z_real = m->mk_const_decl(symbol("0^0-real"), r, func_decl_info(id, OP_0_PW_0_REAL)); - m_0_pw_0_real = m->mk_const(z_pw_z_real); - m->inc_ref(m_0_pw_0_real); MK_OP(m_neg_root_decl, "neg-root", OP_NEG_ROOT, r); - MK_UNARY(m_div_0_decl, "/0", OP_DIV_0, r); - MK_UNARY(m_idiv_0_decl, "div0", OP_IDIV_0, i); - MK_UNARY(m_mod_0_decl, "mod0", OP_MOD_0, i); MK_UNARY(m_u_asin_decl, "asin-u", OP_U_ASIN, r); MK_UNARY(m_u_acos_decl, "acos-u", OP_U_ACOS, r); } @@ -278,12 +269,7 @@ arith_decl_plugin::arith_decl_plugin(): m_atanh_decl(0), m_pi(0), m_e(0), - m_0_pw_0_int(0), - m_0_pw_0_real(0), m_neg_root_decl(0), - m_div_0_decl(0), - m_idiv_0_decl(0), - m_mod_0_decl(0), m_u_asin_decl(0), m_u_acos_decl(0), m_convert_int_numerals_to_real(false) { @@ -338,12 +324,7 @@ void arith_decl_plugin::finalize() { DEC_REF(m_atanh_decl); DEC_REF(m_pi); DEC_REF(m_e); - DEC_REF(m_0_pw_0_int); - DEC_REF(m_0_pw_0_real); DEC_REF(m_neg_root_decl); - DEC_REF(m_div_0_decl); - DEC_REF(m_idiv_0_decl); - DEC_REF(m_mod_0_decl); DEC_REF(m_u_asin_decl); DEC_REF(m_u_acos_decl); m_manager->dec_array_ref(m_small_ints.size(), m_small_ints.c_ptr()); @@ -391,18 +372,24 @@ inline func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, bool is_real) { case OP_ATANH: return m_atanh_decl; case OP_PI: return m_pi->get_decl(); case OP_E: return m_e->get_decl(); - case OP_0_PW_0_INT: return m_0_pw_0_int->get_decl(); - case OP_0_PW_0_REAL: return m_0_pw_0_real->get_decl(); + //case OP_0_PW_0_INT: return m_0_pw_0_int->get_decl(); + //case OP_0_PW_0_REAL: return m_0_pw_0_real->get_decl(); case OP_NEG_ROOT: return m_neg_root_decl; - case OP_DIV_0: return m_div_0_decl; - case OP_IDIV_0: return m_idiv_0_decl; - case OP_MOD_0: return m_mod_0_decl; + //case OP_DIV_0: return m_div_0_decl; + //case OP_IDIV_0: return m_idiv_0_decl; + //case OP_MOD_0: return m_mod_0_decl; case OP_U_ASIN: return m_u_asin_decl; case OP_U_ACOS: return m_u_acos_decl; default: return 0; } } +void arith_decl_plugin::check_arity(unsigned arity, unsigned expected_arity) { + if (arity != expected_arity) { + m_manager->raise_exception("invalid number of arguments passed to function"); + } +} + inline decl_kind arith_decl_plugin::fix_kind(decl_kind k, unsigned arity) { if (k == OP_SUB && arity == 1) { return OP_UMINUS; @@ -482,9 +469,9 @@ static bool has_real_arg(ast_manager * m, unsigned num_args, expr * const * args static bool is_const_op(decl_kind k) { return k == OP_PI || - k == OP_E || - k == OP_0_PW_0_INT || - k == OP_0_PW_0_REAL; + k == OP_E; + //k == OP_0_PW_0_INT || + //k == OP_0_PW_0_REAL; } func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 6d6da9ed5..4b24ea5e6 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -19,7 +19,7 @@ Revision History: #ifndef ARITH_DECL_PLUGIN_H_ #define ARITH_DECL_PLUGIN_H_ -#include"ast.h" +#include "ast/ast.h" class sexpr; namespace algebraic_numbers { @@ -70,12 +70,7 @@ enum arith_op_kind { OP_PI, OP_E, // under-specified symbols - OP_0_PW_0_INT, // 0^0 for integers - OP_0_PW_0_REAL, // 0^0 for reals OP_NEG_ROOT, // x^n when n is even and x is negative - OP_DIV_0, // x/0 - OP_IDIV_0, // x div 0 - OP_MOD_0, // x mod 0 OP_U_ASIN, // asin(x) for x < -1 or x > 1 OP_U_ACOS, // acos(x) for x < -1 or x > 1 LAST_ARITH_OP @@ -141,12 +136,7 @@ protected: app * m_pi; app * m_e; - app * m_0_pw_0_int; - app * m_0_pw_0_real; func_decl * m_neg_root_decl; - func_decl * m_div_0_decl; - func_decl * m_idiv_0_decl; - func_decl * m_mod_0_decl; func_decl * m_u_asin_decl; func_decl * m_u_acos_decl; ptr_vector m_small_ints; @@ -157,6 +147,7 @@ protected: func_decl * mk_func_decl(decl_kind k, bool is_real); virtual void set_manager(ast_manager * m, family_id id); decl_kind fix_kind(decl_kind k, unsigned arity); + void check_arity(unsigned arity, unsigned expected_arity); func_decl * mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity); public: @@ -206,10 +197,6 @@ public: app * mk_e() const { return m_e; } - app * mk_0_pw_0_int() const { return m_0_pw_0_int; } - - app * mk_0_pw_0_real() const { return m_0_pw_0_real; } - virtual expr * get_some_value(sort * s); virtual bool is_considered_uninterpreted(func_decl * f) { @@ -217,12 +204,7 @@ public: return false; switch (f->get_decl_kind()) { - case OP_0_PW_0_INT: - case OP_0_PW_0_REAL: case OP_NEG_ROOT: - case OP_DIV_0: - case OP_IDIV_0: - case OP_MOD_0: case OP_U_ASIN: case OP_U_ACOS: return true; @@ -275,9 +257,9 @@ public: bool is_uminus(expr const * n) const { return is_app_of(n, m_afid, OP_UMINUS); } bool is_mul(expr const * n) const { return is_app_of(n, m_afid, OP_MUL); } bool is_div(expr const * n) const { return is_app_of(n, m_afid, OP_DIV); } - bool is_div0(expr const * n) const { return is_app_of(n, m_afid, OP_DIV_0); } + //bool is_div0(expr const * n) const { return is_app_of(n, m_afid, OP_DIV_0); } bool is_idiv(expr const * n) const { return is_app_of(n, m_afid, OP_IDIV); } - bool is_idiv0(expr const * n) const { return is_app_of(n, m_afid, OP_IDIV_0); } + //bool is_idiv0(expr const * n) const { return is_app_of(n, m_afid, OP_IDIV_0); } bool is_mod(expr const * n) const { return is_app_of(n, m_afid, OP_MOD); } bool is_rem(expr const * n) const { return is_app_of(n, m_afid, OP_REM); } bool is_to_real(expr const * n) const { return is_app_of(n, m_afid, OP_TO_REAL); } @@ -388,16 +370,16 @@ public: app * mk_lt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LT, arg1, arg2); } app * mk_gt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_GT, arg1, arg2); } - app * mk_add(unsigned num_args, expr * const * args) { return m_manager.mk_app(m_afid, OP_ADD, num_args, args); } - app * mk_add(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2); } - app * mk_add(expr * arg1, expr * arg2, expr* arg3) { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2, arg3); } + app * mk_add(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_ADD, num_args, args); } + app * mk_add(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2); } + app * mk_add(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2, arg3); } - app * mk_sub(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_SUB, arg1, arg2); } - app * mk_sub(unsigned num_args, expr * const * args) { return m_manager.mk_app(m_afid, OP_SUB, num_args, args); } - app * mk_mul(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2); } - app * mk_mul(expr * arg1, expr * arg2, expr* arg3) { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2, arg3); } - app * mk_mul(unsigned num_args, expr * const * args) { return m_manager.mk_app(m_afid, OP_MUL, num_args, args); } - app * mk_uminus(expr * arg) { return m_manager.mk_app(m_afid, OP_UMINUS, arg); } + app * mk_sub(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_SUB, arg1, arg2); } + app * mk_sub(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_SUB, num_args, args); } + app * mk_mul(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2); } + app * mk_mul(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2, arg3); } + app * mk_mul(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_MUL, num_args, args); } + app * mk_uminus(expr * arg) const { return m_manager.mk_app(m_afid, OP_UMINUS, arg); } app * mk_div(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_DIV, arg1, arg2); } app * mk_idiv(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_IDIV, arg1, arg2); } app * mk_rem(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_REM, arg1, arg2); } @@ -424,11 +406,6 @@ public: app * mk_pi() { return plugin().mk_pi(); } app * mk_e() { return plugin().mk_e(); } - app * mk_0_pw_0_int() { return plugin().mk_0_pw_0_int(); } - app * mk_0_pw_0_real() { return plugin().mk_0_pw_0_real(); } - app * mk_div0(expr * arg) { return m_manager.mk_app(m_afid, OP_DIV_0, arg); } - app * mk_idiv0(expr * arg) { return m_manager.mk_app(m_afid, OP_IDIV_0, arg); } - app * mk_mod0(expr * arg) { return m_manager.mk_app(m_afid, OP_MOD_0, arg); } app * mk_neg_root(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_NEG_ROOT, arg1, arg2); } app * mk_u_asin(expr * arg) { return m_manager.mk_app(m_afid, OP_U_ASIN, arg); } app * mk_u_acos(expr * arg) { return m_manager.mk_app(m_afid, OP_U_ACOS, arg); } diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index ab21c4c88..0cc4f6031 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -17,10 +17,10 @@ Revision History: --*/ #include -#include"array_decl_plugin.h" -#include"warning.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" +#include "ast/array_decl_plugin.h" +#include "util/warning.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" array_decl_plugin::array_decl_plugin(): m_store_sym("store"), @@ -242,7 +242,9 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) { parameter const* parameters = s->get_parameters(); if (num_parameters != arity) { - m_manager->raise_exception("select requires as many arguments as the size of the domain"); + std::stringstream strm; + strm << "select requires " << num_parameters << " arguments, but was provided with " << arity << " arguments"; + m_manager->raise_exception(strm.str().c_str()); return 0; } ptr_buffer new_domain; // we need this because of coercions. @@ -314,7 +316,7 @@ func_decl * array_decl_plugin::mk_array_ext(unsigned arity, sort * const * domai return 0; } sort * r = to_sort(s->get_parameter(i).get_ast()); - parameter param(s); + parameter param(i); return m_manager->mk_func_decl(m_array_ext_sym, arity, domain, r, func_decl_info(m_family_id, OP_ARRAY_EXT, 1, ¶m)); } @@ -546,7 +548,7 @@ expr * array_decl_plugin::get_some_value(sort * s) { return m_manager->mk_app(m_family_id, OP_CONST_ARRAY, 1, &p, 1, &v); } -bool array_decl_plugin::is_fully_interp(sort const * s) const { +bool array_decl_plugin::is_fully_interp(sort * s) const { SASSERT(s->is_sort_of(m_family_id, ARRAY_SORT)); unsigned sz = get_array_arity(s); for (unsigned i = 0; i < sz; i++) { @@ -556,9 +558,9 @@ bool array_decl_plugin::is_fully_interp(sort const * s) const { return m_manager->is_fully_interp(get_array_range(s)); } -func_decl * array_recognizers::get_as_array_func_decl(app * n) const { +func_decl * array_recognizers::get_as_array_func_decl(expr * n) const { SASSERT(is_as_array(n)); - return to_func_decl(n->get_decl()->get_parameter(0).get_ast()); + return to_func_decl(to_app(n)->get_decl()->get_parameter(0).get_ast()); } array_util::array_util(ast_manager& m): @@ -592,3 +594,9 @@ sort * array_util::mk_array_sort(unsigned arity, sort* const* domain, sort* rang params.push_back(parameter(range)); return m_manager.mk_sort(m_fid, ARRAY_SORT, params.size(), params.c_ptr()); } + +func_decl* array_util::mk_array_ext(sort *domain, unsigned i) { + sort * domains[2] = { domain, domain }; + parameter p(i); + return m_manager.mk_func_decl(m_fid, OP_ARRAY_EXT, 1, &p, 2, domains); +} diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 36a8d50a5..911bb3f27 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -19,7 +19,7 @@ Revision History: #ifndef ARRAY_DECL_PLUGIN_H_ #define ARRAY_DECL_PLUGIN_H_ -#include"ast.h" +#include "ast/ast.h" inline sort* get_array_range(sort const * s) { @@ -127,7 +127,7 @@ class array_decl_plugin : public decl_plugin { virtual expr * get_some_value(sort * s); - virtual bool is_fully_interp(sort const * s) const; + virtual bool is_fully_interp(sort * s) const; }; class array_recognizers { @@ -143,12 +143,13 @@ public: bool is_const(expr* n) const { return is_app_of(n, m_fid, OP_CONST_ARRAY); } bool is_map(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_MAP); } bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); } + bool is_as_array(expr * n, func_decl*& f) const { return is_as_array(n) && (f = get_as_array_func_decl(n), true); } bool is_select(func_decl* f) const { return is_decl_of(f, m_fid, OP_SELECT); } bool is_store(func_decl* f) const { return is_decl_of(f, m_fid, OP_STORE); } bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); } bool is_map(func_decl* f) const { return is_decl_of(f, m_fid, OP_ARRAY_MAP); } bool is_as_array(func_decl* f) const { return is_decl_of(f, m_fid, OP_AS_ARRAY); } - func_decl * get_as_array_func_decl(app * n) const; + func_decl * get_as_array_func_decl(expr * n) const; }; class array_util : public array_recognizers { @@ -182,13 +183,15 @@ public: return mk_const_array(s, m_manager.mk_true()); } + func_decl * mk_array_ext(sort* domain, unsigned i); + sort * mk_array_sort(sort* dom, sort* range) { return mk_array_sort(1, &dom, range); } sort * mk_array_sort(unsigned arity, sort* const* domain, sort* range); - app * mk_as_array(sort * s, func_decl * f) { + app * mk_as_array(func_decl * f) { parameter param(f); - return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, ¶m, 0, 0, s); + return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, ¶m, 0, 0, 0); } }; diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 5f2de5170..3dbd0bc69 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -18,14 +18,14 @@ Revision History: --*/ #include #include -#include"ast.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"buffer.h" -#include"warning.h" -#include"string_buffer.h" -#include"ast_util.h" -#include"ast_smt2_pp.h" +#include "ast/ast.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "util/buffer.h" +#include "util/warning.h" +#include "util/string_buffer.h" +#include "ast/ast_util.h" +#include "ast/ast_smt2_pp.h" // ----------------------------------- // @@ -35,7 +35,7 @@ Revision History: parameter::~parameter() { if (m_kind == PARAM_RATIONAL) { - reinterpret_cast(m_rational)->~rational(); + dealloc(m_rational); } } @@ -50,14 +50,14 @@ parameter& parameter::operator=(parameter const& other) { return *this; } if (m_kind == PARAM_RATIONAL) { - reinterpret_cast(m_rational)->~rational(); + dealloc(m_rational); } 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: new (m_symbol) symbol(other.get_symbol()); break; - case PARAM_RATIONAL: new (m_rational) rational(other.get_rational()); break; + case PARAM_SYMBOL: m_symbol = other.m_symbol; break; + case PARAM_RATIONAL: m_rational = alloc(rational, other.get_rational()); break; case PARAM_DOUBLE: m_dval = other.m_dval; break; case PARAM_EXTERNAL: m_ext_id = other.m_ext_id; break; default: @@ -188,18 +188,14 @@ decl_info::decl_info(decl_info const& other) : void decl_info::init_eh(ast_manager & m) { - vector::iterator it = m_parameters.begin(); - vector::iterator end = m_parameters.end(); - for (; it != end; ++it) { - it->init_eh(m); + for (parameter & p : m_parameters) { + p.init_eh(m); } } void decl_info::del_eh(ast_manager & m) { - vector::iterator it = m_parameters.begin(); - vector::iterator end = m_parameters.end(); - for (; it != end; ++it) { - it->del_eh(m, m_family_id); + for (parameter & p : m_parameters) { + p.del_eh(m, m_family_id); } } @@ -475,6 +471,9 @@ bool compare_nodes(ast const * n1, ast const * n2) { compare_arrays(to_quantifier(n1)->get_decl_sorts(), to_quantifier(n2)->get_decl_sorts(), to_quantifier(n1)->get_num_decls()) && + compare_arrays(to_quantifier(n1)->get_decl_names(), + to_quantifier(n2)->get_decl_names(), + to_quantifier(n1)->get_num_decls()) && to_quantifier(n1)->get_expr() == to_quantifier(n2)->get_expr() && to_quantifier(n1)->get_weight() == to_quantifier(n2)->get_weight() && to_quantifier(n1)->get_num_patterns() == to_quantifier(n2)->get_num_patterns() && @@ -769,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 & cache) { if (num_parents >= cache.size()) { - cache.resize(num_parents+1, 0); + cache.resize(num_parents+1); } if (cache[num_parents] == 0) { cache[num_parents] = mk_proof_decl(name, k, num_parents); @@ -806,7 +805,6 @@ func_decl * basic_decl_plugin::mk_proof_decl(char const* name, basic_op_kind k, } func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_parents) { - SASSERT(k == PR_UNDEF || m_manager->proofs_enabled()); switch (static_cast(k)) { // // A description of the semantics of the proof @@ -1291,10 +1289,8 @@ decl_kind user_sort_plugin::register_name(symbol s) { decl_plugin * user_sort_plugin::mk_fresh() { user_sort_plugin * p = alloc(user_sort_plugin); - svector::iterator it = m_sort_names.begin(); - svector::iterator end = m_sort_names.end(); - for (; it != end; ++it) - p->register_name(*it); + for (symbol const& s : m_sort_names) + p->register_name(s); return p; } @@ -1414,26 +1410,20 @@ ast_manager::~ast_manager() { dec_ref(m_true); dec_ref(m_false); dec_ref(m_undef_proof); - ptr_vector::iterator it = m_plugins.begin(); - ptr_vector::iterator end = m_plugins.end(); - for (; it != end; ++it) { - if (*it) - (*it)->finalize(); + for (decl_plugin* p : m_plugins) { + if (p) + p->finalize(); } - it = m_plugins.begin(); - for (; it != end; ++it) { - if (*it) - dealloc(*it); + for (decl_plugin* p : m_plugins) { + if (p) + dealloc(p); } m_plugins.reset(); while (!m_ast_table.empty()) { DEBUG_CODE(std::cout << "ast_manager LEAKED: " << m_ast_table.size() << std::endl;); ptr_vector roots; ast_mark mark; - ast_table::iterator it_a = m_ast_table.begin(); - ast_table::iterator end_a = m_ast_table.end(); - for (; it_a != end_a; ++it_a) { - ast* n = (*it_a); + for (ast * n : m_ast_table) { switch (n->get_kind()) { case AST_SORT: { sort_info* info = to_sort(n)->get_info(); @@ -1466,9 +1456,7 @@ ast_manager::~ast_manager() { break; } } - it_a = m_ast_table.begin(); - for (; it_a != end_a; ++it_a) { - ast* n = *it_a; + for (ast * n : m_ast_table) { if (!mark.is_marked(n)) { roots.push_back(n); } @@ -1543,12 +1531,15 @@ void ast_manager::raise_exception(char const * msg) { throw ast_exception(msg); } +#include "ast/ast_translation.h" + void ast_manager::copy_families_plugins(ast_manager const & from) { TRACE("copy_families_plugins", tout << "target:\n"; for (family_id fid = 0; m_family_manager.has_family(fid); fid++) { tout << "fid: " << fid << " fidname: " << get_family_name(fid) << "\n"; }); + ast_translation trans(const_cast(from), *this, false); for (family_id fid = 0; from.m_family_manager.has_family(fid); fid++) { SASSERT(from.is_builtin_family_id(fid) == is_builtin_family_id(fid)); SASSERT(!from.is_builtin_family_id(fid) || m_family_manager.has_family(fid)); @@ -1569,6 +1560,9 @@ void ast_manager::copy_families_plugins(ast_manager const & from) { SASSERT(new_p->get_family_id() == fid); SASSERT(has_plugin(fid)); } + if (from.has_plugin(fid)) { + get_plugin(fid)->inherit(from.get_plugin(fid), trans); + } SASSERT(from.m_family_manager.has_family(fid) == m_family_manager.has_family(fid)); SASSERT(from.get_family_id(fid_name) == get_family_id(fid_name)); SASSERT(!from.has_plugin(fid) || has_plugin(fid)); @@ -1663,11 +1657,8 @@ bool ast_manager::is_bool(expr const * n) const { #ifdef Z3DEBUG bool ast_manager::slow_not_contains(ast const * n) { - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); unsigned num = 0; - for (; it != end; ++it) { - ast * curr = *it; + for (ast * curr : m_ast_table) { if (compare_nodes(curr, n)) { TRACE("nondet_bug", tout << "id1: " << curr->get_id() << ", id2: " << n->get_id() << "\n"; @@ -1725,8 +1716,14 @@ ast * ast_manager::register_node_core(ast * n) { SASSERT(m_ast_table.contains(n)); } + n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk(); + static unsigned count = 0; + if (n->m_id == 404) { + ++count; + //if (count == 2) SASSERT(false); + } TRACE("ast", tout << "Object " << n->m_id << " was created.\n";); TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";); @@ -1936,6 +1933,35 @@ sort * ast_manager::mk_sort(symbol const & name, sort_info * info) { return register_node(new_node); } +sort * ast_manager::substitute(sort* s, unsigned n, sort * const * src, sort * const * dst) { + for (unsigned i = 0; i < n; ++i) { + if (s == src[i]) return dst[i]; + } + + vector ps; + bool change = false; + sort_ref_vector sorts(*this); + for (unsigned i = 0; i < s->get_num_parameters(); ++i) { + parameter const& p = s->get_parameter(i); + if (p.is_ast()) { + SASSERT(is_sort(p.get_ast())); + change = true; + sorts.push_back(substitute(to_sort(p.get_ast()), n, src, dst)); + ps.push_back(parameter(sorts.back())); + } + else { + ps.push_back(p); + } + } + if (!change) { + return s; + } + decl_info dinfo(s->get_family_id(), s->get_decl_kind(), ps.size(), ps.c_ptr(), s->private_parameters()); + sort_info sinfo(dinfo, s->get_num_elements()); + return mk_sort(s->get_name(), &sinfo); +} + + sort * ast_manager::mk_uninterpreted_sort(symbol const & name, unsigned num_parameters, parameter const * parameters) { user_sort_plugin * plugin = get_user_sort_plugin(); decl_kind kind = plugin->register_name(name); @@ -2178,7 +2204,10 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar throw ast_exception(buffer.str().c_str()); } app * r = 0; - if (num_args > 2 && !decl->is_flat_associative()) { + if (num_args == 1 && decl->is_chainable() && decl->get_arity() == 2) { + r = mk_true(); + } + else if (num_args > 2 && !decl->is_flat_associative()) { if (decl->is_right_associative()) { unsigned j = num_args - 1; r = mk_app_core(decl, args[j-1], args[j]); @@ -2207,7 +2236,7 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar r = mk_app_core(decl, num_args, args); } SASSERT(r != 0); - TRACE("app_ground", tout << "ground: " << r->is_ground() << "\n" << mk_ll_pp(r, *this) << "\n";); + TRACE("app_ground", tout << "ground: " << r->is_ground() << " id: " << r->get_id() << "\n" << mk_ll_pp(r, *this) << "\n";); return r; } @@ -2352,6 +2381,7 @@ quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort * SASSERT(num_decls > 0); DEBUG_CODE({ for (unsigned i = 0; i < num_patterns; ++i) { + TRACE("ast", tout << i << " " << mk_pp(patterns[i], *this) << "\n";); SASSERT(is_pattern(patterns[i])); }}); unsigned sz = quantifier::get_obj_size(num_decls, num_patterns, num_no_patterns); @@ -2577,7 +2607,7 @@ expr * ast_manager::get_some_value(sort * s) { return mk_model_value(0, s); } -bool ast_manager::is_fully_interp(sort const * s) const { +bool ast_manager::is_fully_interp(sort * s) const { if (is_uninterp(s)) return false; family_id fid = s->get_family_id(); @@ -2595,7 +2625,7 @@ bool ast_manager::is_fully_interp(sort const * s) const { // ----------------------------------- proof * ast_manager::mk_proof(family_id fid, decl_kind k, unsigned num_args, expr * const * args) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(fid, k, num_args, args); } @@ -2631,8 +2661,7 @@ proof * ast_manager::mk_goal(expr * f) { } proof * ast_manager::mk_modus_ponens(proof * p1, proof * p2) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; + if (!p1 || !p2) return nullptr; SASSERT(has_fact(p1)); SASSERT(has_fact(p2)); CTRACE("mk_modus_ponens", !(is_implies(get_fact(p2)) || is_iff(get_fact(p2)) || is_oeq(get_fact(p2))), @@ -2653,14 +2682,10 @@ proof * ast_manager::mk_modus_ponens(proof * p1, proof * p2) { } proof * ast_manager::mk_reflexivity(expr * e) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; return mk_app(m_basic_family_id, PR_REFLEXIVITY, mk_eq(e, e)); } proof * ast_manager::mk_oeq_reflexivity(expr * e) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; return mk_app(m_basic_family_id, PR_REFLEXIVITY, mk_oeq(e, e)); } @@ -2674,8 +2699,7 @@ proof * ast_manager::mk_commutativity(app * f) { \brief Given a proof of p, return a proof of (p <=> true) */ proof * ast_manager::mk_iff_true(proof * pr) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; + if (!pr) return pr; SASSERT(has_fact(pr)); SASSERT(is_bool(get_fact(pr))); return mk_app(m_basic_family_id, PR_IFF_TRUE, pr, mk_iff(get_fact(pr), mk_true())); @@ -2685,8 +2709,7 @@ proof * ast_manager::mk_iff_true(proof * pr) { \brief Given a proof of (not p), return a proof of (p <=> false) */ proof * ast_manager::mk_iff_false(proof * pr) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; + if (!pr) return pr; SASSERT(has_fact(pr)); SASSERT(is_not(get_fact(pr))); expr * p = to_app(get_fact(pr))->get_arg(0); @@ -2694,10 +2717,7 @@ proof * ast_manager::mk_iff_false(proof * pr) { } proof * ast_manager::mk_symmetry(proof * p) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; - if (!p) - return p; + if (!p) return p; if (is_reflexivity(p)) return p; if (is_symmetry(p)) @@ -2710,8 +2730,6 @@ proof * ast_manager::mk_symmetry(proof * p) { } proof * ast_manager::mk_transitivity(proof * p1, proof * p2) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; if (!p1) return p2; if (!p2) @@ -2756,8 +2774,6 @@ proof * ast_manager::mk_transitivity(proof * p1, proof * p2, proof * p3, proof * } proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; SASSERT(num_proofs > 0); proof * r = proofs[0]; for (unsigned i = 1; i < num_proofs; i++) @@ -2766,11 +2782,8 @@ proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs } proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs, expr * n1, expr * n2) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; - if (fine_grain_proofs()) - return mk_transitivity(num_proofs, proofs); - SASSERT(num_proofs > 0); + if (num_proofs == 0) + return nullptr; if (num_proofs == 1) return proofs[0]; DEBUG_CODE({ @@ -2786,8 +2799,6 @@ proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs } proof * ast_manager::mk_monotonicity(func_decl * R, app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; SASSERT(f1->get_num_args() == f2->get_num_args()); SASSERT(f1->get_decl() == f2->get_decl()); ptr_buffer args; @@ -2797,8 +2808,6 @@ proof * ast_manager::mk_monotonicity(func_decl * R, app * f1, app * f2, unsigned } proof * ast_manager::mk_congruence(app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; SASSERT(get_sort(f1) == get_sort(f2)); sort * s = get_sort(f1); sort * d[2] = { s, s }; @@ -2806,8 +2815,6 @@ proof * ast_manager::mk_congruence(app * f1, app * f2, unsigned num_proofs, proo } proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; SASSERT(get_sort(f1) == get_sort(f2)); sort * s = get_sort(f1); sort * d[2] = { s, s }; @@ -2815,11 +2822,7 @@ proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs, } proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; - if (!p) { - return 0; - } + if (!p) return nullptr; SASSERT(q1->get_num_decls() == q2->get_num_decls()); SASSERT(has_fact(p)); SASSERT(is_iff(get_fact(p))); @@ -2827,8 +2830,7 @@ proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) } proof * ast_manager::mk_oeq_quant_intro(quantifier * q1, quantifier * q2, proof * p) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; + if (!p) return nullptr; SASSERT(q1->get_num_decls() == q2->get_num_decls()); SASSERT(has_fact(p)); SASSERT(is_oeq(get_fact(p))); @@ -2836,25 +2838,26 @@ proof * ast_manager::mk_oeq_quant_intro(quantifier * q1, quantifier * q2, proof } proof * ast_manager::mk_distributivity(expr * s, expr * r) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; return mk_app(m_basic_family_id, PR_DISTRIBUTIVITY, mk_eq(s, r)); } proof * ast_manager::mk_rewrite(expr * s, expr * t) { - if (m_proof_mode == PGM_DISABLED) + SASSERT(proofs_enabled()); + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_REWRITE, mk_eq(s, t)); } proof * ast_manager::mk_oeq_rewrite(expr * s, expr * t) { - if (m_proof_mode == PGM_DISABLED) + SASSERT(proofs_enabled()); + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_REWRITE, mk_oeq(s, t)); } proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + SASSERT(proofs_enabled()); + if (proofs_disabled()) return m_undef_proof; ptr_buffer args; args.append(num_proofs, (expr**) proofs); @@ -2863,37 +2866,43 @@ proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, pr } proof * ast_manager::mk_pull_quant(expr * e, quantifier * q) { - if (m_proof_mode == PGM_DISABLED) + SASSERT(proofs_enabled()); + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_PULL_QUANT, mk_iff(e, q)); } proof * ast_manager::mk_pull_quant_star(expr * e, quantifier * q) { - if (m_proof_mode == PGM_DISABLED) + SASSERT(proofs_enabled()); + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_PULL_QUANT_STAR, mk_iff(e, q)); } proof * ast_manager::mk_push_quant(quantifier * q, expr * e) { - if (m_proof_mode == PGM_DISABLED) + SASSERT(proofs_enabled()); + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_PUSH_QUANT, mk_iff(q, e)); } proof * ast_manager::mk_elim_unused_vars(quantifier * q, expr * e) { - if (m_proof_mode == PGM_DISABLED) + SASSERT(proofs_enabled()); + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_ELIM_UNUSED_VARS, mk_iff(q, e)); } proof * ast_manager::mk_der(quantifier * q, expr * e) { - if (m_proof_mode == PGM_DISABLED) + SASSERT(proofs_enabled()); + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_DER, mk_iff(q, e)); } proof * ast_manager::mk_quant_inst(expr * not_q_or_i, unsigned num_bind, expr* const* binding) { - if (m_proof_mode == PGM_DISABLED) + SASSERT(proofs_enabled()); + if (proofs_disabled()) return m_undef_proof; vector params; for (unsigned i = 0; i < num_bind; ++i) { @@ -2928,7 +2937,8 @@ bool ast_manager::is_rewrite(expr const* e, expr*& r1, expr*& r2) const { } proof * ast_manager::mk_def_axiom(expr * ax) { - if (m_proof_mode == PGM_DISABLED) + SASSERT(proofs_enabled()); + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_DEF_AXIOM, ax); } @@ -2970,7 +2980,7 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro new_lits.push_back(lit); } DEBUG_CODE({ - for (unsigned i = 1; m_proof_mode == PGM_FINE && i < num_proofs; i++) { + for (unsigned i = 1; proofs_enabled() && i < num_proofs; i++) { CTRACE("mk_unit_resolution_bug", !found.get(i, false), for (unsigned j = 0; j < num_proofs; j++) { if (j == i) tout << "Index " << i << " was not found:\n"; @@ -3049,14 +3059,11 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro } proof * ast_manager::mk_hypothesis(expr * h) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; return mk_app(m_basic_family_id, PR_HYPOTHESIS, h); } proof * ast_manager::mk_lemma(proof * p, expr * lemma) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; + if (!p) return p; SASSERT(has_fact(p)); CTRACE("mk_lemma", !is_false(get_fact(p)), tout << mk_ll_pp(p, *this) << "\n";); SASSERT(is_false(get_fact(p))); @@ -3069,7 +3076,7 @@ proof * ast_manager::mk_def_intro(expr * new_def) { } proof * ast_manager::mk_apply_defs(expr * n, expr * def, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; ptr_buffer args; args.append(num_proofs, (expr**) proofs); @@ -3078,10 +3085,7 @@ proof * ast_manager::mk_apply_defs(expr * n, expr * def, unsigned num_proofs, pr } proof * ast_manager::mk_iff_oeq(proof * p) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; - if (!p) - return p; + if (!p) return p; SASSERT(has_fact(p)); SASSERT(is_iff(get_fact(p)) || is_oeq(get_fact(p))); @@ -3105,7 +3109,7 @@ bool ast_manager::check_nnf_proof_parents(unsigned num_proofs, proof * const * p } proof * ast_manager::mk_nnf_pos(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; check_nnf_proof_parents(num_proofs, proofs); ptr_buffer args; @@ -3115,7 +3119,7 @@ proof * ast_manager::mk_nnf_pos(expr * s, expr * t, unsigned num_proofs, proof * } proof * ast_manager::mk_nnf_neg(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; check_nnf_proof_parents(num_proofs, proofs); ptr_buffer args; @@ -3125,7 +3129,7 @@ proof * ast_manager::mk_nnf_neg(expr * s, expr * t, unsigned num_proofs, proof * } proof * ast_manager::mk_nnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; ptr_buffer args; args.append(num_proofs, (expr**) proofs); @@ -3134,7 +3138,7 @@ proof * ast_manager::mk_nnf_star(expr * s, expr * t, unsigned num_proofs, proof } proof * ast_manager::mk_skolemization(expr * q, expr * e) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; SASSERT(is_bool(q)); SASSERT(is_bool(e)); @@ -3142,7 +3146,7 @@ proof * ast_manager::mk_skolemization(expr * q, expr * e) { } proof * ast_manager::mk_cnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; ptr_buffer args; args.append(num_proofs, (expr**) proofs); @@ -3151,7 +3155,7 @@ proof * ast_manager::mk_cnf_star(expr * s, expr * t, unsigned num_proofs, proof } proof * ast_manager::mk_and_elim(proof * p, unsigned i) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; SASSERT(has_fact(p)); SASSERT(is_and(get_fact(p))); @@ -3162,7 +3166,7 @@ proof * ast_manager::mk_and_elim(proof * p, unsigned i) { } proof * ast_manager::mk_not_or_elim(proof * p, unsigned i) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; SASSERT(has_fact(p)); SASSERT(is_not(get_fact(p))); @@ -3185,7 +3189,7 @@ proof * ast_manager::mk_th_lemma( unsigned num_params, parameter const* params ) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; ptr_buffer args; diff --git a/src/ast/ast.h b/src/ast/ast.h index f71d5135c..2d06d03de 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -19,32 +19,32 @@ Revision History: #ifndef AST_H_ #define AST_H_ -#include"vector.h" -#include"hashtable.h" -#include"buffer.h" -#include"symbol.h" -#include"rational.h" -#include"hash.h" -#include"optional.h" -#include"trace.h" -#include"bit_vector.h" -#include"symbol_table.h" -#include"tptr.h" -#include"memory_manager.h" -#include"small_object_allocator.h" -#include"obj_ref.h" -#include"ref_vector.h" -#include"ref_buffer.h" -#include"obj_mark.h" -#include"obj_hashtable.h" -#include"id_gen.h" -#include"map.h" -#include"parray.h" -#include"dictionary.h" -#include"chashtable.h" -#include"z3_exception.h" -#include"dependency.h" -#include"rlimit.h" +#include "util/vector.h" +#include "util/hashtable.h" +#include "util/buffer.h" +#include "util/symbol.h" +#include "util/rational.h" +#include "util/hash.h" +#include "util/optional.h" +#include "util/trace.h" +#include "util/bit_vector.h" +#include "util/symbol_table.h" +#include "util/tptr.h" +#include "util/memory_manager.h" +#include "util/small_object_allocator.h" +#include "util/obj_ref.h" +#include "util/ref_vector.h" +#include "util/ref_buffer.h" +#include "util/obj_mark.h" +#include "util/obj_hashtable.h" +#include "util/id_gen.h" +#include "util/map.h" +#include "util/parray.h" +#include "util/dictionary.h" +#include "util/chashtable.h" +#include "util/z3_exception.h" +#include "util/dependency.h" +#include "util/rlimit.h" #define RECYCLE_FREE_AST_INDICES @@ -102,8 +102,8 @@ private: union { int m_int; // for PARAM_INT ast* m_ast; // for PARAM_AST - char m_symbol[sizeof(symbol)]; // for PARAM_SYMBOL - char m_rational[sizeof(rational)]; // for PARAM_RATIONAL + void const* m_symbol; // for PARAM_SYMBOL + rational* m_rational; // for PARAM_RATIONAL double m_dval; // for PARAM_DOUBLE (remark: this is not used in float_decl_plugin) unsigned m_ext_id; // for PARAM_EXTERNAL }; @@ -114,15 +114,27 @@ public: explicit parameter(int val): m_kind(PARAM_INT), m_int(val) {} explicit parameter(unsigned val): m_kind(PARAM_INT), m_int(val) {} explicit parameter(ast * p): m_kind(PARAM_AST), m_ast(p) {} - explicit parameter(symbol const & s): m_kind(PARAM_SYMBOL) { new (m_symbol) symbol(s); } - explicit parameter(rational const & r): m_kind(PARAM_RATIONAL) { new (m_rational) rational(r); } + explicit parameter(symbol const & s): m_kind(PARAM_SYMBOL), m_symbol(s.c_ptr()) {} + explicit parameter(rational const & r): m_kind(PARAM_RATIONAL), m_rational(alloc(rational, r)) {} explicit parameter(double d):m_kind(PARAM_DOUBLE), m_dval(d) {} - explicit parameter(const char *s):m_kind(PARAM_SYMBOL) { - new (m_symbol) symbol(s); - } + explicit parameter(const char *s):m_kind(PARAM_SYMBOL), m_symbol(symbol(s).c_ptr()) {} explicit parameter(unsigned ext_id, bool):m_kind(PARAM_EXTERNAL), m_ext_id(ext_id) {} parameter(parameter const&); + parameter(parameter && other) : m_kind(other.m_kind) { + switch (other.m_kind) { + case PARAM_INT: m_int = other.get_int(); break; + case PARAM_AST: m_ast = other.get_ast(); break; + case PARAM_SYMBOL: m_symbol = other.m_symbol; break; + case PARAM_RATIONAL: m_rational = 0; std::swap(m_rational, other.m_rational); break; + case PARAM_DOUBLE: m_dval = other.m_dval; break; + case PARAM_EXTERNAL: m_ext_id = other.m_ext_id; break; + default: + UNREACHABLE(); + break; + } + } + ~parameter(); parameter& operator=(parameter const& other); @@ -156,8 +168,8 @@ public: int get_int() const { SASSERT(is_int()); return m_int; } ast * get_ast() const { SASSERT(is_ast()); return m_ast; } - symbol const & get_symbol() const { SASSERT(is_symbol()); return *(reinterpret_cast(m_symbol)); } - rational const & get_rational() const { SASSERT(is_rational()); return *(reinterpret_cast(m_rational)); } + symbol get_symbol() const { SASSERT(is_symbol()); return symbol::mk_symbol_from_c_ptr(m_symbol); } + rational const & get_rational() const { SASSERT(is_rational()); return *m_rational; } double get_double() const { SASSERT(is_double()); return m_dval; } unsigned get_ext_id() const { SASSERT(is_external()); return m_ext_id; } @@ -337,13 +349,17 @@ public: unsigned num_parameters = 0, parameter const * parameters = 0, bool private_parameters = false): decl_info(family_id, k, num_parameters, parameters, private_parameters), m_num_elements(num_elements) { } - sort_info(sort_info const& other) : decl_info(other), m_num_elements(other.m_num_elements) { + sort_info(sort_info const& other) : decl_info(other), m_num_elements(other.m_num_elements) { } + sort_info(decl_info const& di, sort_size const& num_elements) : + decl_info(di), m_num_elements(num_elements) {} + ~sort_info() {} bool is_infinite() const { return m_num_elements.is_infinite(); } bool is_very_big() const { return m_num_elements.is_very_big(); } sort_size const & get_num_elements() const { return m_num_elements; } + void set_num_elements(sort_size const& s) { m_num_elements = s; } }; std::ostream & operator<<(std::ostream & out, sort_info const & info); @@ -569,6 +585,7 @@ public: bool is_very_big() const { return get_info() == 0 || get_info()->is_very_big(); } bool is_sort_of(family_id fid, decl_kind k) const { return get_family_id() == fid && get_decl_kind() == k; } sort_size const & get_num_elements() const { return get_info()->get_num_elements(); } + void set_num_elements(sort_size const& s) { get_info()->set_num_elements(s); } unsigned get_size() const { return get_obj_size(); } }; @@ -892,6 +909,8 @@ struct ast_eq_proc { } }; +class ast_translation; + class ast_table : public chashtable, ast_eq_proc> { public: void erase(ast * n); @@ -927,6 +946,8 @@ protected: m_family_id = id; } + virtual void inherit(decl_plugin* other_p, ast_translation& ) { } + friend class ast_manager; public: @@ -990,7 +1011,7 @@ public: // Return true if the interpreted sort s does not depend on uninterpreted sorts. // This may be the case, for example, for array and datatype sorts. - virtual bool is_fully_interp(sort const * s) const { return true; } + virtual bool is_fully_interp(sort * s) const { return true; } // Event handlers for deleting/translating PARAM_EXTERNAL virtual void del(parameter const & p) {} @@ -1375,8 +1396,7 @@ public: enum proof_gen_mode { PGM_DISABLED, - PGM_COARSE, - PGM_FINE + PGM_ENABLED }; // ----------------------------------- @@ -1657,6 +1677,8 @@ public: sort * mk_sort(family_id fid, decl_kind k, unsigned num_parameters = 0, parameter const * parameters = 0); + sort * substitute(sort* s, unsigned n, sort * const * src, sort * const * dst); + sort * mk_bool_sort() const { return m_bool_sort; } sort * mk_proof_sort() const { return m_proof_sort; } @@ -1669,7 +1691,7 @@ public: \brief A sort is "fully" interpreted if it is interpreted, and doesn't depend on other uninterpreted sorts. */ - bool is_fully_interp(sort const * s) const; + bool is_fully_interp(sort * s) const; func_decl * mk_func_decl(family_id fid, decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range = 0); @@ -2021,8 +2043,8 @@ public: app * mk_not(expr * n) { return mk_app(m_basic_family_id, OP_NOT, n); } app * mk_distinct(unsigned num_args, expr * const * args); app * mk_distinct_expanded(unsigned num_args, expr * const * args); - app * mk_true() { return m_true; } - app * mk_false() { return m_false; } + app * mk_true() const { return m_true; } + app * mk_false() const { return m_false; } app * mk_bool_val(bool b) { return b?m_true:m_false; } app * mk_interp(expr * arg) { return mk_app(m_basic_family_id, OP_INTERP, arg); } @@ -2065,15 +2087,14 @@ protected: proof * mk_proof(family_id fid, decl_kind k, expr * arg1, expr * arg2); proof * mk_proof(family_id fid, decl_kind k, expr * arg1, expr * arg2, expr * arg3); + proof * mk_undef_proof() const { return m_undef_proof; } + public: bool proofs_enabled() const { return m_proof_mode != PGM_DISABLED; } bool proofs_disabled() const { return m_proof_mode == PGM_DISABLED; } - bool coarse_grain_proofs() const { return m_proof_mode == PGM_COARSE; } - bool fine_grain_proofs() const { return m_proof_mode == PGM_FINE; } proof_gen_mode proof_mode() const { return m_proof_mode; } void toggle_proof_mode(proof_gen_mode m) { m_proof_mode = m; } // APIs for creating proof objects return [undef] - proof * mk_undef_proof() const { return m_undef_proof; } bool is_proof(expr const * n) const { return is_app(n) && to_app(n)->get_decl()->get_range() == m_proof_sort; } @@ -2472,6 +2493,7 @@ public: void operator()(AST * n) { m_manager.inc_ref(n); } }; + #endif /* AST_H_ */ diff --git a/src/ast/ast_ll_pp.cpp b/src/ast/ast_ll_pp.cpp index 3dc660681..c00053780 100644 --- a/src/ast/ast_ll_pp.cpp +++ b/src/ast/ast_ll_pp.cpp @@ -18,8 +18,8 @@ Revision History: --*/ #include -#include"for_each_ast.h" -#include"arith_decl_plugin.h" +#include "ast/for_each_ast.h" +#include "ast/arith_decl_plugin.h" // #define AST_LL_PP_SHOW_FAMILY_NAME diff --git a/src/ast/ast_ll_pp.h b/src/ast/ast_ll_pp.h index 7fc527833..19d5679b6 100644 --- a/src/ast/ast_ll_pp.h +++ b/src/ast/ast_ll_pp.h @@ -19,7 +19,7 @@ Revision History: #ifndef AST_LL_PP_H_ #define AST_LL_PP_H_ -#include"ast.h" +#include "ast/ast.h" #include void ast_ll_pp(std::ostream & out, ast_manager & m, ast * n, bool only_exprs=true, bool compact=true); diff --git a/src/ast/ast_lt.cpp b/src/ast/ast_lt.cpp index 2fba4f7a6..b6b52966e 100644 --- a/src/ast/ast_lt.cpp +++ b/src/ast/ast_lt.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"ast.h" +#include "ast/ast.h" #define check_symbol(S1,S2) if (S1 != S2) return lt(S1,S2) #define check_value(V1,V2) if (V1 != V2) return V1 < V2 diff --git a/src/ast/ast_pp.h b/src/ast/ast_pp.h index ecd7e3b13..997b1a6e0 100644 --- a/src/ast/ast_pp.h +++ b/src/ast/ast_pp.h @@ -21,7 +21,7 @@ Revision History: #ifndef AST_PP_H_ #define AST_PP_H_ -#include"ast_smt2_pp.h" +#include "ast/ast_smt2_pp.h" struct mk_pp : public mk_ismt2_pp { mk_pp(ast * t, ast_manager & m, params_ref const & p, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = 0): diff --git a/src/ast/ast_pp_dot.cpp b/src/ast/ast_pp_dot.cpp new file mode 100644 index 000000000..1dfbe9aae --- /dev/null +++ b/src/ast/ast_pp_dot.cpp @@ -0,0 +1,133 @@ +/*++ + +Abstract: Pretty-printer for proofs in Graphviz format + +--*/ + +#include "util/util.h" +#include "util/map.h" +#include "ast/ast_pp_dot.h" + +// string escaping for DOT +std::string escape_dot(std::string const & s) { + std::string res; + res.reserve(s.size()); // preallocate + for (auto c : s) { + if (c == '\n') + res.append("\\l"); + else + res.push_back(c); + } + return res; +} + +// map from proofs to unique IDs +typedef obj_map expr2id; + +// temporary structure for traversing the proof and printing it +struct ast_pp_dot_st { + ast_manager & m_manager; + std::ostream & m_out; + const ast_pp_dot * m_pp; + unsigned m_next_id; + expr2id m_id_map; + obj_hashtable m_printed; + svector m_to_print; + bool m_first; + + ast_pp_dot_st(const ast_pp_dot * pp, std::ostream & out) : + m_manager(pp->get_manager()), + m_out(out), + m_pp(pp), + m_next_id(0), + m_id_map(), + m_printed(), + m_to_print(), + m_first(true) {} + + ~ast_pp_dot_st() {}; + + void push_term(const expr * a) { m_to_print.push_back(a); } + + void pp_loop() { + // DFS traversal + while (!m_to_print.empty()) { + const expr * a = m_to_print.back(); + m_to_print.pop_back(); + if (!m_printed.contains(a)) { + m_printed.insert(a); + if (m().is_proof(a)) + pp_step(to_app(a)); + else + pp_atomic_step(a); + } + } + } + +private: + + inline ast_manager & m() const { return m_manager; } + + // label for an expression + std::string label_of_expr(const expr * e) const { + expr_ref er((expr*)e, m()); + std::ostringstream out; + out << er << std::flush; + return escape_dot(out.str()); + } + + void pp_atomic_step(const expr * e) { + unsigned id = get_id(e); + m_out << "node_" << id << " [shape=box,color=\"yellow\",style=\"filled\",label=\"" << label_of_expr(e) << "\"] ;" << std::endl; + } + + void pp_step(const proof * p) { + TRACE("pp_ast_dot_step", tout << " :kind " << p->get_kind() << " :num-args " << p->get_num_args() << "\n";); + if (m().has_fact(p)) { + // print result + expr* p_res = m().get_fact(p); // result of proof step + unsigned id = get_id(p); + unsigned num_parents = m().get_num_parents(p); + const char* color = + m_first ? (m_first=false,"color=\"red\"") : num_parents==0 ? "color=\"yellow\"": ""; + m_out << "node_" << id << + " [shape=box,style=\"filled\",label=\"" << label_of_expr(p_res) << "\"" + << color << "]" << std::endl; + // now print edges to parents (except last one, which is the result) + std::string label = p->get_decl()->get_name().str(); + for (unsigned i = 0 ; i < num_parents; ++i) { + expr* parent = m().get_parent(p, i); + // explore parent, also print a link to it + push_term(to_app(parent)); + m_out << "node_" << id << " -> " << "node_" << get_id((expr*)parent) + << "[label=\"" << label << "\"];" << std::endl;; + } + } else { + pp_atomic_step(p); + } + } + + // find a unique ID for this proof + unsigned get_id(const expr * e) { + unsigned id = 0; + if (!m_id_map.find(e, id)) { + id = m_next_id++; + m_id_map.insert(e, id); + } + return id; + } + +}; + +// main printer +std::ostream & ast_pp_dot::pp(std::ostream & out) const { + out << "digraph proof { " << std::endl; + ast_pp_dot_st pp_st(this, out); + pp_st.push_term(m_pr); + pp_st.pp_loop(); + out << std::endl << " } " << std::endl << std::flush; + return out; +} + +std::ostream &operator<<(std::ostream &out, const ast_pp_dot & p) { return p.pp(out); } + diff --git a/src/ast/ast_pp_dot.h b/src/ast/ast_pp_dot.h new file mode 100644 index 000000000..537754e83 --- /dev/null +++ b/src/ast/ast_pp_dot.h @@ -0,0 +1,24 @@ +/*++ + +Abstract: Pretty-printer for proofs in Graphviz format + +--*/ + +#pragma once + +#include +#include "ast_pp.h" + +class ast_pp_dot { + ast_manager & m_manager; + proof * const m_pr; + + public: + ast_pp_dot(proof *pr, ast_manager &m) : m_manager(m), m_pr(pr) {} + ast_pp_dot(proof_ref &e) : m_manager(e.m()), m_pr(e.get()) {} + + std::ostream & pp(std::ostream & out) const; + ast_manager & get_manager() const { return m_manager; } +}; + +std::ostream &operator<<(std::ostream &out, const ast_pp_dot & p); \ No newline at end of file diff --git a/src/ast/ast_pp_util.cpp b/src/ast/ast_pp_util.cpp index 3021b702b..677422b8a 100644 --- a/src/ast/ast_pp_util.cpp +++ b/src/ast/ast_pp_util.cpp @@ -17,9 +17,9 @@ Revision History: --*/ -#include "ast_pp_util.h" -#include "ast_smt2_pp.h" -#include "ast_smt_pp.h" +#include "ast/ast_pp_util.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_smt_pp.h" void ast_pp_util::collect(expr* e) { coll.visit(e); diff --git a/src/ast/ast_pp_util.h b/src/ast/ast_pp_util.h index a5aac2136..964a862a2 100644 --- a/src/ast/ast_pp_util.h +++ b/src/ast/ast_pp_util.h @@ -19,7 +19,7 @@ Revision History: #ifndef AST_PP_UTIL_H_ #define AST_PP_UTIL_H_ -#include "decl_collector.h" +#include "ast/decl_collector.h" class ast_pp_util { ast_manager& m; diff --git a/src/ast/ast_printer.cpp b/src/ast/ast_printer.cpp index 8d6ed91f7..b5cf60ee9 100644 --- a/src/ast/ast_printer.cpp +++ b/src/ast/ast_printer.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"ast_printer.h" -#include"pp.h" +#include "ast/ast_printer.h" +#include "ast/pp.h" class simple_ast_printer_context : public ast_printer_context { ast_manager & m_manager; diff --git a/src/ast/ast_printer.h b/src/ast/ast_printer.h index 78fe822f6..87fa8ef3d 100644 --- a/src/ast/ast_printer.h +++ b/src/ast/ast_printer.h @@ -19,8 +19,8 @@ Revision History: #ifndef AST_PRINTER_H_ #define AST_PRINTER_H_ -#include"ast.h" -#include"ast_smt2_pp.h" +#include "ast/ast.h" +#include "ast/ast_smt2_pp.h" class ast_printer { public: diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index f97397108..0139cb0f0 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -18,13 +18,13 @@ Author: Revision History: --*/ -#include"ast_smt2_pp.h" -#include"shared_occs.h" -#include"pp.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" -#include"algebraic_numbers.h" -#include"pp_params.hpp" +#include "ast/ast_smt2_pp.h" +#include "ast/shared_occs.h" +#include "ast/pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "math/polynomial/algebraic_numbers.h" +#include "ast/pp_params.hpp" using namespace format_ns; #define ALIAS_PREFIX "a" @@ -43,6 +43,10 @@ format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len) co len = static_cast(str.length()); return mk_string(m, str.c_str()); } + else if (!s.bare_str()) { + len = 4; + return mk_string(m, "null"); + } else { len = static_cast(strlen(s.bare_str())); return mk_string(m, s.bare_str()); @@ -431,16 +435,16 @@ format_ns::format * smt2_pp_environment::pp_sort(sort * s) { fs.push_back(pp_sort(to_sort(s->get_parameter(0).get_ast()))); return mk_seq1(m, fs.begin(), fs.end(), f2f(), get_sutil().is_seq(s)?"Seq":"RegEx"); } -#if 0 if (get_dtutil().is_datatype(s)) { - ptr_buffer fs; unsigned sz = get_dtutil().get_datatype_num_parameter_sorts(s); - for (unsigned i = 0; i < sz; i++) { - fs.push_back(pp_sort(get_dtutil().get_datatype_parameter_sort(s, i))); + if (sz > 0) { + ptr_buffer fs; + for (unsigned i = 0; i < sz; i++) { + fs.push_back(pp_sort(get_dtutil().get_datatype_parameter_sort(s, i))); + } + return mk_seq1(m, fs.begin(), fs.end(), f2f(), s->get_name().str().c_str()); } - return mk_seq1(m, fs.begin(), fs.end(), f2f(), s->get_name().str().c_str()); } -#endif return format_ns::mk_string(get_manager(), s->get_name().str().c_str()); } @@ -581,6 +585,8 @@ class smt2_printer { string_buffer<> buf; buf.append("(:var "); buf.append(v->get_idx()); + //buf.append(" "); + //buf.append(v->get_sort()->get_name().str().c_str()); buf.append(")"); f = mk_string(m(), buf.c_str()); } @@ -1222,15 +1228,15 @@ mk_ismt2_pp::mk_ismt2_pp(ast * t, ast_manager & m, unsigned indent, unsigned num std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p) { smt2_pp_environment_dbg env(p.m_manager); - if (is_expr(p.m_ast)) { + if (p.m_ast == 0) { + out << "null"; + } + else if (is_expr(p.m_ast)) { ast_smt2_pp(out, to_expr(p.m_ast), env, p.m_params, p.m_indent, p.m_num_vars, p.m_var_prefix); } else if (is_sort(p.m_ast)) { ast_smt2_pp(out, to_sort(p.m_ast), env, p.m_params, p.m_indent); } - else if (p.m_ast == 0) { - out << "null"; - } else { SASSERT(is_func_decl(p.m_ast)); ast_smt2_pp(out, to_func_decl(p.m_ast), env, p.m_params, p.m_indent); diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index c3e72f7bc..3e8b1aa39 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -22,16 +22,16 @@ Revision History: #ifndef AST_SMT2_PP_H_ #define AST_SMT2_PP_H_ -#include"format.h" -#include"params.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"array_decl_plugin.h" -#include"fpa_decl_plugin.h" -#include"dl_decl_plugin.h" -#include"seq_decl_plugin.h" -#include"datatype_decl_plugin.h" -#include"smt2_util.h" +#include "ast/format.h" +#include "util/params.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/fpa_decl_plugin.h" +#include "ast/dl_decl_plugin.h" +#include "ast/seq_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "util/smt2_util.h" class smt2_pp_environment { protected: diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index fe02f24a0..906fd054b 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -21,17 +21,17 @@ Revision History: #include #include -#include"ast_smt_pp.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"array_decl_plugin.h" -#include"datatype_decl_plugin.h" -#include"fpa_decl_plugin.h" -#include"vector.h" -#include"for_each_ast.h" -#include"decl_collector.h" -#include"smt2_util.h" -#include"seq_decl_plugin.h" +#include "util/vector.h" +#include "util/smt2_util.h" +#include "ast/ast_smt_pp.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/seq_decl_plugin.h" +#include "ast/fpa_decl_plugin.h" +#include "ast/for_each_ast.h" +#include "ast/decl_collector.h" // --------------------------------------- // smt_renaming @@ -174,7 +174,6 @@ class smt_printer { symbol m_logic; symbol m_AUFLIRA; bool m_no_lets; - bool m_is_smt2; bool m_simplify_implies; expr* m_top; @@ -199,37 +198,30 @@ class smt_printer { } void pp_id(expr* n) { - if (m_is_smt2) { - m_out << (is_bool(n)?"$x":(is_proof(n)?"@x":"?x")) << n->get_id(); - } - else { - m_out << (is_bool(n)?"$x":"?x") << n->get_id(); - } + m_out << (is_bool(n)?"$x":(is_proof(n)?"@x":"?x")) << n->get_id(); } void pp_decl(func_decl* d) { symbol sym = m_renaming.get_symbol(d->get_name()); if (d->get_family_id() == m_dt_fid) { - m_out << sym; - } - else if (m_manager.is_ite(d)) { - if (!m_is_smt2 && is_bool(d->get_range())) { - m_out << "if_then_else"; + datatype_util util(m_manager); + if (util.is_recognizer(d)) { + visit_params(false, sym, d->get_num_parameters(), d->get_parameters()); } else { - m_out << "ite"; + m_out << sym; } } - else if (!m_is_smt2 && m_manager.is_implies(d)) { - m_out << "implies"; + else if (m_manager.is_ite(d)) { + m_out << "ite"; } - else if (m_is_smt2 && m_manager.is_iff(d)) { + else if (m_manager.is_iff(d)) { m_out << "="; } - else if (m_is_smt2 && m_manager.is_implies(d)) { + else if (m_manager.is_implies(d)) { m_out << "=>"; } - else if (m_is_smt2 && is_decl_of(d, m_arith_fid, OP_UMINUS)) { + else if (is_decl_of(d, m_arith_fid, OP_UMINUS)) { m_out << "-"; } else { @@ -251,28 +243,23 @@ class smt_printer { return; } - if (m_is_smt2) { - if (is_sort_symbol && sym == symbol("String")) { - m_out << "String"; - return; - } - if (is_sort_symbol && - sym != symbol("BitVec") && - sym != symbol("FloatingPoint") && - sym != symbol("RoundingMode")) { - m_out << "(" << sym << " "; - } - else if (!is_sort_symbol && is_sort_param(num_params, params)) { - m_out << "(as " << sym << " "; - } - else { - m_out << "(_ " << sym << " "; - } + if (is_sort_symbol && sym == symbol("String")) { + m_out << "String"; + return; + } + if (is_sort_symbol && + sym != symbol("BitVec") && + sym != symbol("FloatingPoint") && + sym != symbol("RoundingMode")) { + m_out << "(" << sym << " "; + } + else if (!is_sort_symbol && is_sort_param(num_params, params)) { + m_out << "(as " << sym << " "; } else { - m_out << sym << "["; + m_out << "(_ " << sym << " "; } - + for (unsigned i = 0; i < num_params; ++i) { parameter const& p = params[i]; if (p.is_ast()) { @@ -293,20 +280,10 @@ class smt_printer { m_out << p; } if (i + 1 < num_params) { - if (m_is_smt2) { - m_out << " "; - } - else { - m_out << ": "; - } + m_out << " "; } } - if (m_is_smt2) { - m_out << ")"; - } - else { - m_out << "]"; - } + m_out << ")"; } bool is_auflira() const { @@ -315,9 +292,7 @@ class smt_printer { void visit_sort(sort* s, bool bool2int = false) { symbol sym; - if (bool2int && is_bool(s) && !m_is_smt2) { - sym = symbol("Int"); - } else if (s->is_sort_of(m_bv_fid, BV_SORT)) { + if (s->is_sort_of(m_bv_fid, BV_SORT)) { sym = symbol("BitVec"); } else if (s->is_sort_of(m_arith_fid, REAL_SORT)) { @@ -329,51 +304,16 @@ class smt_printer { else if (s->is_sort_of(m_arith_fid, INT_SORT)) { sym = s->get_name(); } - else if (s->is_sort_of(m_array_fid, ARRAY_SORT) && m_is_smt2) { + else if (s->is_sort_of(m_array_fid, ARRAY_SORT)) { sym = "Array"; } - else if (s->is_sort_of(m_array_fid, ARRAY_SORT) && !m_is_smt2) { - unsigned num_params = s->get_num_parameters(); - SASSERT(num_params >= 2); - if (is_auflira()) { - sort* rng = to_sort(s->get_parameter(1).get_ast()); - if (rng->get_family_id() == m_array_fid) { - m_out << "Array2"; - } - else { - m_out << "Array1"; - } - return; - } - sort* s1 = to_sort(s->get_parameter(0).get_ast()); - sort* s2 = to_sort(s->get_parameter(1).get_ast()); - if (num_params == 2 && - s1->is_sort_of(m_bv_fid, BV_SORT) && - s2->is_sort_of(m_bv_fid, BV_SORT)) { - m_out << "Array"; - m_out << "[" << s1->get_parameter(0).get_int(); - m_out << ":" << s2->get_parameter(0).get_int() << "]"; - return; - } - m_out << "(Array "; - for (unsigned i = 0; i < num_params; ++i) { - visit_sort(to_sort(s->get_parameter(i).get_ast())); - if (i + 1 < num_params) { - m_out << " "; - } - } - m_out << ")"; - return; - } else if (s->is_sort_of(m_dt_fid, DATATYPE_SORT)) { - m_out << m_renaming.get_symbol(s->get_name()); -#if 0 datatype_util util(m_manager); unsigned num_sorts = util.get_datatype_num_parameter_sorts(s); if (num_sorts > 0) { m_out << "("; } - + m_out << m_renaming.get_symbol(s->get_name()); if (num_sorts > 0) { for (unsigned i = 0; i < num_sorts; ++i) { m_out << " "; @@ -381,7 +321,6 @@ class smt_printer { } m_out << ")"; } -#endif return; } else { @@ -403,20 +342,7 @@ class smt_printer { void pp_arg(expr *arg, app *parent) { - if (!m_is_smt2 && is_bool(arg) && is_var(arg) && parent->get_family_id() == m_basic_fid) { - m_out << "(not (= "; - pp_marked_expr(arg); - m_out << " 0))"; - } else if (!m_is_smt2 && is_bool(arg) && !is_var(arg) && - parent->get_family_id() != m_basic_fid && - parent->get_family_id() != m_dt_fid) { - - m_out << "(ite "; - pp_marked_expr(arg); - m_out << " 1 0)"; - } else { - pp_marked_expr(arg); - } + pp_marked_expr(arg); } void visit_app(app* n) { @@ -431,12 +357,7 @@ class smt_printer { if (m_autil.is_numeral(n, val, is_int)) { if (val.is_neg()) { val.neg(); - if (m_is_smt2) { - m_out << "(- "; - } - else { - m_out << "(~ "; - } + m_out << "(- "; display_rational(val, is_int); m_out << ")"; } @@ -458,12 +379,7 @@ class smt_printer { m_out << "\""; } else if (m_bvutil.is_numeral(n, val, bv_size)) { - if (m_is_smt2) { - m_out << "(_ bv" << val << " " << bv_size << ")"; - } - else { - m_out << "bv" << val << "[" << bv_size << "]"; - } + m_out << "(_ bv" << val << " " << bv_size << ")"; } else if (m_futil.is_numeral(n, float_val)) { m_out << "((_ to_fp " << @@ -473,37 +389,17 @@ class smt_printer { } else if (m_bvutil.is_bit2bool(n)) { unsigned bit = n->get_decl()->get_parameter(0).get_int(); - if (m_is_smt2) { - m_out << "(= ((_ extract " << bit << " " << bit << ") "; - pp_marked_expr(n->get_arg(0)); - m_out << ") (_ bv1 1))"; - } - else { - m_out << "(= (extract[" << bit << ":" << bit << "] "; - pp_marked_expr(n->get_arg(0)); - m_out << ") bv1[1])"; - } + m_out << "(= ((_ extract " << bit << " " << bit << ") "; + pp_marked_expr(n->get_arg(0)); + m_out << ") (_ bv1 1))"; } else if (m_manager.is_label(n, pos, names) && names.size() >= 1) { - if (m_is_smt2) { - m_out << "(! "; - pp_marked_expr(n->get_arg(0)); - m_out << (pos?":lblpos":":lblneg") << " " << m_renaming.get_symbol(names[0]) << ")"; - } - else { - m_out << "(" << (pos?"lblpos":"lblneg") << " " << m_renaming.get_symbol(names[0]) << " "; - expr* ch = n->get_arg(0); - pp_marked_expr(ch); - m_out << ")"; - } + m_out << "(! "; + pp_marked_expr(n->get_arg(0)); + m_out << (pos?":lblpos":":lblneg") << " " << m_renaming.get_symbol(names[0]) << ")"; } else if (m_manager.is_label_lit(n, names) && names.size() >= 1) { - if (m_is_smt2) { - m_out << "(! true :lblpos " << m_renaming.get_symbol(names[0]) << ")"; - } - else { - m_out << "(lblpos " << m_renaming.get_symbol(names[0]) << " true )"; - } + m_out << "(! true :lblpos " << m_renaming.get_symbol(names[0]) << ")"; } else if (num_args == 0) { if (decl->private_parameters()) { @@ -533,7 +429,8 @@ class smt_printer { pp_arg(curr, n); m_out << ")"; - } else if (m_manager.is_distinct(decl)) { + } + else if (m_manager.is_distinct(decl)) { ptr_vector args(num_args, n->get_args()); unsigned idx = 0; m_out << "(and"; @@ -581,14 +478,11 @@ class smt_printer { void print_no_lets(expr *e) { - smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, m_is_smt2, m_indent, m_num_var_names, m_var_names); + smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, true, m_indent, m_num_var_names, m_var_names); p(e); } void print_bound(symbol const& name) { - if (!m_is_smt2 && (name.is_numerical() || '?' != name.bare_str()[0])) { - m_out << "?"; - } m_out << name; } @@ -602,9 +496,7 @@ class smt_printer { else { m_out << "exists "; } - if (m_is_smt2) { - m_out << "("; - } + m_out << "("; for (unsigned i = 0; i < q->get_num_decls(); ++i) { sort* s = q->get_decl_sort(i); m_out << "("; @@ -613,15 +505,13 @@ class smt_printer { visit_sort(s, true); m_out << ") "; } - if (m_is_smt2) { - m_out << ")"; - } + m_out << ")"; - if (m_is_smt2 && (q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) { + if ((q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) { m_out << "(! "; } { - smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, m_is_smt2, m_simplify_implies, m_indent, m_num_var_names, m_var_names); + smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, true, m_simplify_implies, m_indent, m_num_var_names, m_var_names); p(q->get_expr()); } @@ -640,28 +530,18 @@ class smt_printer { } } - if (m_is_smt2) { - m_out << " :pattern ( "; - } - else { - m_out << " :pat { "; - } + m_out << " :pattern ( "; for (unsigned j = 0; j < pat->get_num_args(); ++j) { print_no_lets(pat->get_arg(j)); m_out << " "; } - if (m_is_smt2) { - m_out << ")"; - } - else { - m_out << "}"; - } + m_out << ")"; } if (q->get_qid() != symbol::null) m_out << " :qid " << q->get_qid(); - if (m_is_smt2 && (q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) { + if ((q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) { m_out << ")"; } m_out << ")"; @@ -725,21 +605,11 @@ class smt_printer { } void visit_expr(expr* n) { - if (m_is_smt2) { - m_out << "(let (("; - } - else if (is_bool(n)) { - m_out << "(flet ("; - } - else { - m_out << "(let ("; - } + m_out << "(let (("; pp_id(n); m_out << " "; pp_expr(n); - if (m_is_smt2) { - m_out << ")"; - } + m_out << ")"; m_out << ")"; newline(); } @@ -851,7 +721,6 @@ public: m_AUFLIRA("AUFLIRA"), // It's much easier to read those testcases with that. m_no_lets(no_lets), - m_is_smt2(is_smt2), m_simplify_implies(simplify_implies) { m_basic_fid = m.get_basic_family_id(); @@ -905,91 +774,59 @@ public: } void pp_dt(ast_mark& mark, sort* s) { - SASSERT(s->is_sort_of(m_dt_fid, DATATYPE_SORT)); datatype_util util(m_manager); - ptr_vector const* decls; - ptr_vector rec_sorts; + SASSERT(util.is_datatype(s)); - rec_sorts.push_back(s); - mark.mark(s, true); + sort_ref_vector ps(m_manager); + ptr_vector defs; + util.get_defs(s, defs); - // collect siblings and sorts that have not already been printed. - for (unsigned h = 0; h < rec_sorts.size(); ++h) { - s = rec_sorts[h]; - decls = util.get_datatype_constructors(s); - - for (unsigned i = 0; i < decls->size(); ++i) { - func_decl* f = (*decls)[i]; - for (unsigned j = 0; j < f->get_arity(); ++j) { - sort* s2 = f->get_domain(j); - if (!mark.is_marked(s2)) { - if (m_manager.is_uninterp(s2)) { - pp_sort_decl(mark, s2); - } - else if (!util.is_datatype(s2)) { - // skip - } - else if (util.are_siblings(s, s2)) { - rec_sorts.push_back(s2); - mark.mark(s2, true); - } - else { - pp_sort_decl(mark, s2); - } - } + for (datatype::def* d : defs) { + sort_ref sr = d->instantiate(ps); + if (mark.is_marked(sr)) return; // already processed + mark.mark(sr, true); + } + + m_out << "(declare-datatypes ("; + bool first_def = true; + for (datatype::def* d : defs) { + if (!first_def) m_out << "\n "; else first_def = false; + m_out << "(" << d->name() << " " << d->params().size() << ")"; + } + m_out << ") ("; + bool first_sort = true; + for (datatype::def* d : defs) { + if (!first_sort) m_out << "\n "; else first_sort = false; + if (!d->params().empty()) { + m_out << "(par ("; + bool first_param = true; + for (sort* s : d->params()) { + if (!first_param) m_out << " "; else first_param = false; + visit_sort(s); } + m_out << ")"; } - } - - if (m_is_smt2) { - // TBD: datatypes may be declared parametrically. - // get access to parametric generalization, or print - // monomorphic specialization with a tag that gets reused at use-point. - m_out << "(declare-datatypes () ("; - } - else { - m_out << ":datatypes ("; - } - for (unsigned si = 0; si < rec_sorts.size(); ++si) { - s = rec_sorts[si]; m_out << "("; - m_out << m_renaming.get_symbol(s->get_name()); + m_out << m_renaming.get_symbol(d->name()); m_out << " "; - decls = util.get_datatype_constructors(s); - - for (unsigned i = 0; i < decls->size(); ++i) { - func_decl* f = (*decls)[i]; - ptr_vector const& accs = *util.get_constructor_accessors(f); - if (m_is_smt2 || accs.size() > 0) { - m_out << "("; - } - m_out << m_renaming.get_symbol(f->get_name()); - if (!accs.empty() || !m_is_smt2) { - m_out << " "; - } - for (unsigned j = 0; j < accs.size(); ++j) { - func_decl* a = accs[j]; - m_out << "(" << m_renaming.get_symbol(a->get_name()) << " "; - visit_sort(a->get_range()); + bool first_constr = true; + for (datatype::constructor* f : *d) { + if (!first_constr) m_out << " "; else first_constr = false; + m_out << "("; + m_out << m_renaming.get_symbol(f->name()); + for (datatype::accessor* a : *f) { + m_out << " (" << m_renaming.get_symbol(a->name()) << " "; + visit_sort(a->range()); m_out << ")"; - if (j + 1 < accs.size()) m_out << " "; - } - if (m_is_smt2 || accs.size() > 0) { - m_out << ")"; - if (i + 1 < decls->size()) { - m_out << " "; - } } + m_out << ")"; + } + if (!d->params().empty()) { + m_out << ")"; } m_out << ")"; - if (si + 1 < rec_sorts.size()) { - m_out << " "; - } } - if (m_is_smt2) { - m_out << ")"; - } - m_out << ")"; + m_out << "))"; newline(); } @@ -1002,12 +839,7 @@ public: pp_dt(mark, s); } else { - if (m_is_smt2) { - m_out << "(declare-sort "; - } - else { - m_out << ":extrasorts ("; - } + m_out << "(declare-sort "; visit_sort(s); m_out << ")"; newline(); @@ -1021,29 +853,16 @@ public: } void operator()(func_decl* d) { - if (m_is_smt2) { - m_out << "(declare-fun "; - pp_decl(d); - m_out << "("; - for (unsigned i = 0; i < d->get_arity(); ++i) { - if (i > 0) m_out << " "; - visit_sort(d->get_domain(i), true); - } - m_out << ") "; - visit_sort(d->get_range()); - m_out << ")"; - } - else { - m_out << "("; - pp_decl(d); - for (unsigned i = 0; i < d->get_arity(); ++i) { - m_out << " "; - visit_sort(d->get_domain(i), true); - } - m_out << " "; - visit_sort(d->get_range()); - m_out << ")"; + m_out << "(declare-fun "; + pp_decl(d); + m_out << "("; + for (unsigned i = 0; i < d->get_arity(); ++i) { + if (i > 0) m_out << " "; + visit_sort(d->get_domain(i), true); } + m_out << ") "; + visit_sort(d->get_range()); + m_out << ")"; } void visit_pred(func_decl* d) { diff --git a/src/ast/ast_smt_pp.h b/src/ast/ast_smt_pp.h index e88465828..dd2a6d753 100644 --- a/src/ast/ast_smt_pp.h +++ b/src/ast/ast_smt_pp.h @@ -19,9 +19,9 @@ Revision History: #ifndef AST_SMT_PP_H_ #define AST_SMT_PP_H_ -#include"ast.h" +#include "ast/ast.h" #include -#include"map.h" +#include "util/map.h" class smt_renaming { typedef map symbol2symbol; diff --git a/src/ast/ast_trail.h b/src/ast/ast_trail.h index 4e2c542fd..d5245bd77 100644 --- a/src/ast/ast_trail.h +++ b/src/ast/ast_trail.h @@ -22,8 +22,8 @@ Revision History: #ifndef AST_TRAIL_H_ #define AST_TRAIL_H_ -#include"ast.h" -#include"trail.h" +#include "ast/ast.h" +#include "util/trail.h" template diff --git a/src/ast/ast_translation.cpp b/src/ast/ast_translation.cpp index 4b1a80908..1bce4bcbe 100644 --- a/src/ast/ast_translation.cpp +++ b/src/ast/ast_translation.cpp @@ -16,13 +16,13 @@ Author: Revision History: --*/ -#include "arith_decl_plugin.h" -#include "bv_decl_plugin.h" -#include "datatype_decl_plugin.h" -#include "array_decl_plugin.h" -#include "format.h" -#include "ast_translation.h" -#include "ast_ll_pp.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/format.h" +#include "ast/ast_translation.h" +#include "ast/ast_ll_pp.h" ast_translation::~ast_translation() { reset_cache(); @@ -37,11 +37,9 @@ void ast_translation::cleanup() { } void ast_translation::reset_cache() { - obj_map::iterator it = m_cache.begin(); - obj_map::iterator end = m_cache.end(); - for (; it != end; ++it) { - m_from_manager.dec_ref(it->m_key); - m_to_manager.dec_ref(it->m_value); + for (auto & kv : m_cache) { + m_from_manager.dec_ref(kv.m_key); + m_to_manager.dec_ref(kv.m_value); } m_cache.reset(); } diff --git a/src/ast/ast_translation.h b/src/ast/ast_translation.h index ec187110b..b278791d7 100644 --- a/src/ast/ast_translation.h +++ b/src/ast/ast_translation.h @@ -21,7 +21,7 @@ Revision History: #ifndef AST_TRANSLATION_H_ #define AST_TRANSLATION_H_ -#include"ast.h" +#include "ast/ast.h" class ast_translation { struct frame { diff --git a/src/ast/ast_util.cpp b/src/ast/ast_util.cpp index 0129a88d5..68f5b2486 100644 --- a/src/ast/ast_util.cpp +++ b/src/ast/ast_util.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include "ast_util.h" +#include "ast/ast_util.h" app * mk_list_assoc_app(ast_manager & m, func_decl * f, unsigned num_args, expr * const * args) { SASSERT(f->is_associative()); diff --git a/src/ast/ast_util.h b/src/ast/ast_util.h index 6244e16b9..446854f5e 100644 --- a/src/ast/ast_util.h +++ b/src/ast/ast_util.h @@ -19,8 +19,8 @@ Revision History: #ifndef AST_UTIL_H_ #define AST_UTIL_H_ -#include"ast.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" template void remove_duplicates(C & v) { diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 321943c72..093d0f548 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -17,11 +17,11 @@ Revision History: --*/ #include -#include"bv_decl_plugin.h" -#include"arith_decl_plugin.h" -#include"warning.h" -#include"ast_pp.h" -#include"ast_smt2_pp.h" +#include "ast/bv_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "util/warning.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt2_pp.h" bv_decl_plugin::bv_decl_plugin(): m_bv_sym("bv"), @@ -738,6 +738,7 @@ void bv_decl_plugin::get_op_names(svector & op_names, symbol const op_names.push_back(builtin_name("ext_rotate_right",OP_EXT_ROTATE_RIGHT)); op_names.push_back(builtin_name("int2bv",OP_INT2BV)); op_names.push_back(builtin_name("bv2int",OP_BV2INT)); + op_names.push_back(builtin_name("bv2nat",OP_BV2INT)); op_names.push_back(builtin_name("mkbv",OP_MKBV)); } } @@ -784,6 +785,12 @@ bool bv_recognizers::is_numeral(expr const * n, rational & val, unsigned & bv_si return true; } +bool bv_recognizers::is_numeral(expr const * n, rational & val) const { + unsigned bv_size = 0; + return is_numeral(n, val, bv_size); +} + + bool bv_recognizers::is_allone(expr const * e) const { rational r; unsigned bv_size; @@ -847,7 +854,7 @@ bv_util::bv_util(ast_manager & m): m_plugin = static_cast(m.get_plugin(m.mk_family_id("bv"))); } -app * bv_util::mk_numeral(rational const & val, sort* s) { +app * bv_util::mk_numeral(rational const & val, sort* s) const { if (!is_bv_sort(s)) { return 0; } @@ -855,9 +862,8 @@ app * bv_util::mk_numeral(rational const & val, sort* s) { return mk_numeral(val, bv_size); } -app * bv_util::mk_numeral(rational const & val, unsigned bv_size) { - parameter p1(val); - parameter p[2] = { p1, parameter(static_cast(bv_size)) }; +app * bv_util::mk_numeral(rational const & val, unsigned bv_size) const { + parameter p[2] = { parameter(val), parameter(static_cast(bv_size)) }; return m_manager.mk_app(get_fid(), OP_BV_NUM, 2, p, 0, 0); } diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index 33cf094b9..a4ea7af80 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -19,7 +19,7 @@ Revision History: #ifndef BV_DECL_PLUGIN_H_ #define BV_DECL_PLUGIN_H_ -#include"ast.h" +#include "ast/ast.h" enum bv_sort_kind { BV_SORT @@ -293,6 +293,7 @@ public: family_id get_fid() const { return m_afid; } family_id get_family_id() const { return get_fid(); } + bool is_numeral(expr const * n, rational & val) const; bool is_numeral(expr const * n, rational & val, unsigned & bv_size) const; bool is_numeral(expr const * n) const { return is_app_of(n, get_fid(), OP_BV_NUM); } bool is_allone(expr const * e) const; @@ -381,9 +382,9 @@ public: ast_manager & get_manager() const { return m_manager; } - app * mk_numeral(rational const & val, sort* s); - app * mk_numeral(rational const & val, unsigned bv_size); - app * mk_numeral(uint64 u, unsigned bv_size) { return mk_numeral(rational(u, rational::ui64()), bv_size); } + app * mk_numeral(rational const & val, sort* s) const; + app * mk_numeral(rational const & val, unsigned bv_size) const; + app * mk_numeral(uint64 u, unsigned bv_size) const { return mk_numeral(rational(u, rational::ui64()), bv_size); } sort * mk_sort(unsigned bv_size); unsigned get_bv_size(sort const * s) const { diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 34b092ee9..566487e60 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2006 Microsoft Corporation +Copyright (c) 2017 Microsoft Corporation Module Name: @@ -11,320 +11,703 @@ Abstract: Author: - Leonardo de Moura (leonardo) 2008-01-10. + Nikolaj Bjorner (nbjorner) 2017-9-1 Revision History: --*/ -#include"datatype_decl_plugin.h" -#include"warning.h" -#include"ast_smt2_pp.h" + +#include "util/warning.h" +#include "ast/array_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_translation.h" -/** - \brief Auxiliary class used to declare inductive datatypes. -*/ -class accessor_decl { - symbol m_name; - type_ref m_type; -public: - accessor_decl(const symbol & n, type_ref r):m_name(n), m_type(r) {} - symbol const & get_name() const { return m_name; } - type_ref const & get_type() const { return m_type; } -}; +namespace datatype { -accessor_decl * mk_accessor_decl(symbol const & n, type_ref const & t) { - return alloc(accessor_decl, n, t); -} - -void del_accessor_decl(accessor_decl * d) { - dealloc(d); -} - -void del_accessor_decls(unsigned num, accessor_decl * const * as) { - for (unsigned i = 0; i < num; i++) - del_accessor_decl(as[i]); -} - -/** - \brief Auxiliary class used to declare inductive datatypes. -*/ -class constructor_decl { - symbol m_name; - symbol m_recogniser_name; - ptr_vector m_accessors; -public: - constructor_decl(const symbol & n, const symbol & r, unsigned num_accessors, accessor_decl * const * accessors): - m_name(n), m_recogniser_name(r), m_accessors(num_accessors, accessors) {} - ~constructor_decl() { - std::for_each(m_accessors.begin(), m_accessors.end(), delete_proc()); - } - symbol const & get_name() const { return m_name; } - symbol const & get_recognizer_name() const { return m_recogniser_name; } - ptr_vector const & get_accessors() const { return m_accessors; } -}; - -constructor_decl * mk_constructor_decl(symbol const & n, symbol const & r, unsigned num_accessors, accessor_decl * const * accessors) { - return alloc(constructor_decl, n, r, num_accessors, accessors); -} - -void del_constructor_decl(constructor_decl * d) { - dealloc(d); -} - -void del_constructor_decls(unsigned num, constructor_decl * const * cs) { - for (unsigned i = 0; i < num; i++) - del_constructor_decl(cs[i]); -} - -/** - \brief Auxiliary class used to declare inductive datatypes. -*/ -class datatype_decl { - symbol m_name; - ptr_vector m_constructors; -public: - datatype_decl(const symbol & n, unsigned num_constructors, constructor_decl * const * constructors): - m_name(n), m_constructors(num_constructors, constructors) { - } - ~datatype_decl() { - std::for_each(m_constructors.begin(), m_constructors.end(), delete_proc()); - } - symbol const & get_name() const { return m_name; } - ptr_vector const & get_constructors() const { return m_constructors; } -}; - -datatype_decl * mk_datatype_decl(symbol const & n, unsigned num_constructors, constructor_decl * const * cs) { - return alloc(datatype_decl, n, num_constructors, cs); -} - -void del_datatype_decl(datatype_decl * d) { - dealloc(d); -} - -void del_datatype_decls(unsigned num, datatype_decl * const * ds) { - for (unsigned i = 0; i < num; i++) - del_datatype_decl(ds[i]); -} - -typedef buffer bool_buffer; - -struct invalid_datatype {}; - -static parameter const & read(unsigned num_parameters, parameter const * parameters, unsigned idx, bool_buffer & read_pos) { - if (idx >= num_parameters) { - throw invalid_datatype(); - } - if (idx >= read_pos.size()) { - read_pos.resize(idx+1, false); - } - read_pos[idx] = true; - return parameters[idx]; -} - -static int read_int(unsigned num_parameters, parameter const * parameters, unsigned idx, bool_buffer & read_pos) { - const parameter & r = read(num_parameters, parameters, idx, read_pos); - if (!r.is_int()) { - TRACE("datatype", tout << "expected integer parameter at position " << idx << " got: " << r << "\n";); - throw invalid_datatype(); - } - return r.get_int(); -} - -static symbol read_symbol(unsigned num_parameters, parameter const * parameters, unsigned idx, bool_buffer & read_pos) { - parameter const & r = read(num_parameters, parameters, idx, read_pos); - if (!r.is_symbol()) { - TRACE("datatype", tout << "expected symol parameter at position " << idx << " got: " << r << "\n";); - throw invalid_datatype(); - } - return r.get_symbol(); -} - -static sort* read_sort(unsigned num_parameters, parameter const * parameters, unsigned idx, bool_buffer & read_pos) { - parameter const & r = read(num_parameters, parameters, idx, read_pos); - if (!r.is_ast()) { - TRACE("datatype", tout << "expected ast parameter at position " << idx << " got: " << r << "\n";); - throw invalid_datatype(); - } - ast* a = r.get_ast(); - if (!is_sort(a)) { - throw invalid_datatype(); - } - return to_sort(a); -} - -enum status { - WHITE, - GRAY, - BLACK -}; - -/** - \brief Return true if the inductive datatype is recursive. - Pre-condition: The given argument constains the parameters of an inductive datatype. -*/ -static bool is_recursive_datatype(parameter const * parameters) { - unsigned num_types = parameters[0].get_int(); - unsigned top_tid = parameters[1].get_int(); - buffer already_found(num_types, WHITE); - buffer todo; - todo.push_back(top_tid); - while (!todo.empty()) { - unsigned tid = todo.back(); - if (already_found[tid] == BLACK) { - todo.pop_back(); - continue; + void accessor::fix_range(sort_ref_vector const& dts) { + if (!m_range) { + m_range = dts[m_index]; } - already_found[tid] = GRAY; - unsigned o = datatype_decl_plugin::constructor_offset(parameters, tid); // constructor offset - unsigned num_constructors = parameters[o].get_int(); - bool can_process = true; - for (unsigned s = 1; s <= num_constructors; s++) { - unsigned k_i = parameters[o + s].get_int(); - unsigned num_accessors = parameters[k_i + 2].get_int(); - for (unsigned r = 0; r < num_accessors; r++) { - parameter const & a_type = parameters[k_i + 4 + 2*r]; - if (a_type.is_int()) { - unsigned tid_prime = a_type.get_int(); - switch (already_found[tid_prime]) { - case WHITE: - todo.push_back(tid_prime); - can_process = false; - break; - case GRAY: - // type is recursive - return true; - case BLACK: - break; + } + + func_decl_ref accessor::instantiate(sort_ref_vector const& ps) const { + ast_manager& m = ps.get_manager(); + unsigned n = ps.size(); + SASSERT(m_range); + SASSERT(n == get_def().params().size()); + sort_ref range(m.substitute(m_range, n, get_def().params().c_ptr(), ps.c_ptr()), m); + sort_ref src(get_def().instantiate(ps)); + sort* srcs[1] = { src.get() }; + parameter pas[2] = { parameter(name()), parameter(get_constructor().name()) }; + return func_decl_ref(m.mk_func_decl(u().get_family_id(), OP_DT_ACCESSOR, 2, pas, 1, srcs, range), m); + } + + func_decl_ref accessor::instantiate(sort* dt) const { + sort_ref_vector sorts = get_def().u().datatype_params(dt); + return instantiate(sorts); + } + + def const& accessor::get_def() const { return m_constructor->get_def(); } + util& accessor::u() const { return m_constructor->u(); } + accessor* accessor::translate(ast_translation& tr) { + return alloc(accessor, tr.to(), name(), to_sort(tr(m_range.get()))); + } + + constructor::~constructor() { + for (accessor* a : m_accessors) dealloc(a); + m_accessors.reset(); + } + util& constructor::u() const { return m_def->u(); } + + func_decl_ref constructor::instantiate(sort_ref_vector const& ps) const { + ast_manager& m = ps.get_manager(); + sort_ref_vector domain(m); + for (accessor const* a : accessors()) { + domain.push_back(a->instantiate(ps)->get_range()); + } + sort_ref range = get_def().instantiate(ps); + parameter pas[1] = { parameter(name()) }; + return func_decl_ref(m.mk_func_decl(u().get_family_id(), OP_DT_CONSTRUCTOR, 1, pas, domain.size(), domain.c_ptr(), range), m); + } + + func_decl_ref constructor::instantiate(sort* dt) const { + sort_ref_vector sorts = get_def().u().datatype_params(dt); + return instantiate(sorts); + } + + constructor* constructor::translate(ast_translation& tr) { + constructor* result = alloc(constructor, m_name, m_recognizer); + for (accessor* a : *this) { + result->add(a->translate(tr)); + } + return result; + } + + + sort_ref def::instantiate(sort_ref_vector const& sorts) const { + sort_ref s(m); + TRACE("datatype", tout << "instantiate " << m_name << "\n";); + if (!m_sort) { + vector ps; + ps.push_back(parameter(m_name)); + for (sort * s : m_params) ps.push_back(parameter(s)); + m_sort = m.mk_sort(u().get_family_id(), DATATYPE_SORT, ps.size(), ps.c_ptr()); + } + if (sorts.empty()) { + return m_sort; + } + return sort_ref(m.substitute(m_sort, sorts.size(), m_params.c_ptr(), sorts.c_ptr()), m); + } + + def* def::translate(ast_translation& tr, util& u) { + SASSERT(&u.get_manager() == &tr.to()); + sort_ref_vector ps(tr.to()); + for (sort* p : m_params) { + ps.push_back(to_sort(tr(p))); + } + def* result = alloc(def, tr.to(), u, m_name, m_class_id, ps.size(), ps.c_ptr()); + for (constructor* c : *this) { + result->add(c->translate(tr)); + } + if (m_sort) result->m_sort = to_sort(tr(m_sort.get())); + return result; + } + + enum status { + GRAY, + BLACK + }; + + namespace param_size { + size* size::mk_offset(sort_size const& s) { return alloc(offset, s); } + size* size::mk_param(sort_ref& p) { return alloc(sparam, p); } + size* size::mk_plus(size* a1, size* a2) { return alloc(plus, a1, a2); } + size* size::mk_times(size* a1, size* a2) { return alloc(times, a1, a2); } + size* size::mk_times(ptr_vector& szs) { + if (szs.empty()) return mk_offset(sort_size(1)); + if (szs.size() == 1) return szs[0]; + size* r = szs[0]; + for (unsigned i = 1; i < szs.size(); ++i) { + r = mk_times(r, szs[i]); + } + return r; + } + size* size::mk_plus(ptr_vector& szs) { + if (szs.empty()) return mk_offset(sort_size(0)); + if (szs.size() == 1) return szs[0]; + size* r = szs[0]; + for (unsigned i = 1; i < szs.size(); ++i) { + r = mk_plus(r, szs[i]); + } + return r; + } + size* size::mk_power(size* a1, size* a2) { return alloc(power, a1, a2); } + } + + namespace decl { + + plugin::~plugin() { + finalize(); + } + + void plugin::finalize() { + for (auto& kv : m_defs) { + dealloc(kv.m_value); + } + m_defs.reset(); + m_util = 0; // force deletion + } + + util & plugin::u() const { + SASSERT(m_manager); + SASSERT(m_family_id != null_family_id); + if (m_util.get() == 0) { + m_util = alloc(util, *m_manager); + } + return *(m_util.get()); + } + + void plugin::inherit(decl_plugin* other_p, ast_translation& tr) { + plugin* p = dynamic_cast(other_p); + svector names; + ptr_vector new_defs; + SASSERT(p); + for (auto& kv : p->m_defs) { + def* d = kv.m_value; + if (!m_defs.contains(kv.m_key)) { + names.push_back(kv.m_key); + new_defs.push_back(d->translate(tr, u())); + } + } + for (def* d : new_defs) + m_defs.insert(d->name(), d); + m_class_id = m_defs.size(); + u().compute_datatype_size_functions(names); + } + + + struct invalid_datatype {}; + + sort * plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { + try { + if (k != DATATYPE_SORT) { + TRACE("datatype", tout << "invalid kind parameter to datatype\n";); + throw invalid_datatype(); + } + if (num_parameters < 1) { + TRACE("datatype", tout << "at least one parameter expected to datatype declaration\n";); + throw invalid_datatype(); + } + parameter const & name = parameters[0]; + if (!name.is_symbol()) { + TRACE("datatype", tout << "expected symol parameter at position " << 0 << " got: " << name << "\n";); + throw invalid_datatype(); + } + for (unsigned i = 1; i < num_parameters; ++i) { + parameter const& s = parameters[i]; + if (!s.is_ast() || !is_sort(s.get_ast())) { + TRACE("datatype", tout << "expected sort parameter at position " << i << " got: " << s << "\n";); + throw invalid_datatype(); + } + } + + sort* s = m_manager->mk_sort(name.get_symbol(), + sort_info(m_family_id, k, num_parameters, parameters, true)); + def* d = 0; + if (m_defs.find(s->get_name(), d) && d->sort_size()) { + obj_map S; + for (unsigned i = 0; i + 1 < num_parameters; ++i) { + sort* r = to_sort(parameters[i + 1].get_ast()); + S.insert(d->params()[i], r->get_num_elements()); + } + sort_size ts = d->sort_size()->eval(S); + TRACE("datatype", tout << name << " has size " << ts << "\n";); + s->set_num_elements(ts); + } + else { + TRACE("datatype", tout << "not setting size for " << name << "\n";); + } + return s; + } + catch (invalid_datatype) { + m_manager->raise_exception("invalid datatype"); + return 0; + } + } + + func_decl * plugin::mk_update_field( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) { + decl_kind k = OP_DT_UPDATE_FIELD; + ast_manager& m = *m_manager; + + if (num_parameters != 1 || !parameters[0].is_ast()) { + m.raise_exception("invalid parameters for datatype field update"); + return 0; + } + if (arity != 2) { + m.raise_exception("invalid number of arguments for datatype field update"); + return 0; + } + func_decl* acc = 0; + if (is_func_decl(parameters[0].get_ast())) { + acc = to_func_decl(parameters[0].get_ast()); + } + if (acc && !u().is_accessor(acc)) { + acc = 0; + } + if (!acc) { + m.raise_exception("datatype field update requires a datatype accessor as the second argument"); + return 0; + } + sort* dom = acc->get_domain(0); + sort* rng = acc->get_range(); + if (dom != domain[0]) { + m.raise_exception("first argument to field update should be a data-type"); + return 0; + } + if (rng != domain[1]) { + std::ostringstream buffer; + buffer << "second argument to field update should be " << mk_ismt2_pp(rng, m) + << " instead of " << mk_ismt2_pp(domain[1], m); + m.raise_exception(buffer.str().c_str()); + return 0; + } + range = domain[0]; + func_decl_info info(m_family_id, k, num_parameters, parameters); + return m.mk_func_decl(symbol("update-field"), arity, domain, range, info); + } + +#define VALIDATE_PARAM(_pred_) if (!(_pred_)) m_manager->raise_exception("invalid parameter to datatype function " #_pred_); + + func_decl * decl::plugin::mk_constructor(unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) { + ast_manager& m = *m_manager; + VALIDATE_PARAM(num_parameters == 1 && parameters[0].is_symbol() && range && u().is_datatype(range)); + // we blindly trust other conditions are met, including domain types. + symbol name = parameters[0].get_symbol(); + func_decl_info info(m_family_id, OP_DT_CONSTRUCTOR, num_parameters, parameters); + info.m_private_parameters = true; + return m.mk_func_decl(name, arity, domain, range, info); + } + + func_decl * decl::plugin::mk_recognizer(unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort *) { + ast_manager& m = *m_manager; + VALIDATE_PARAM(arity == 1 && num_parameters == 2 && parameters[1].is_symbol() && parameters[0].is_ast() && is_func_decl(parameters[0].get_ast())); + VALIDATE_PARAM(u().is_datatype(domain[0])); + // blindly trust that parameter is a constructor + sort* range = m_manager->mk_bool_sort(); + func_decl_info info(m_family_id, OP_DT_RECOGNISER, num_parameters, parameters); + info.m_private_parameters = true; + return m.mk_func_decl(symbol(parameters[1].get_symbol()), arity, domain, range, info); + } + + func_decl * decl::plugin::mk_is(unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort *) { + ast_manager& m = *m_manager; + VALIDATE_PARAM(arity == 1 && num_parameters == 1 && parameters[0].is_ast() && is_func_decl(parameters[0].get_ast())); + VALIDATE_PARAM(u().is_datatype(domain[0])); + // blindly trust that parameter is a constructor + sort* range = m_manager->mk_bool_sort(); + func_decl_info info(m_family_id, OP_DT_IS, num_parameters, parameters); + info.m_private_parameters = true; + return m.mk_func_decl(symbol("is"), arity, domain, range, info); + } + + func_decl * decl::plugin::mk_accessor(unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) + { + ast_manager& m = *m_manager; + VALIDATE_PARAM(arity == 1 && num_parameters == 2 && parameters[0].is_symbol() && parameters[1].is_symbol()); + VALIDATE_PARAM(u().is_datatype(domain[0])); + SASSERT(range); + func_decl_info info(m_family_id, OP_DT_ACCESSOR, num_parameters, parameters); + info.m_private_parameters = true; + symbol name = parameters[0].get_symbol(); + return m.mk_func_decl(name, arity, domain, range, info); + } + + func_decl * decl::plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) { + switch (k) { + case OP_DT_CONSTRUCTOR: + return mk_constructor(num_parameters, parameters, arity, domain, range); + case OP_DT_RECOGNISER: + return mk_recognizer(num_parameters, parameters, arity, domain, range); + case OP_DT_IS: + return mk_is(num_parameters, parameters, arity, domain, range); + case OP_DT_ACCESSOR: + return mk_accessor(num_parameters, parameters, arity, domain, range); + case OP_DT_UPDATE_FIELD: + return mk_update_field(num_parameters, parameters, arity, domain, range); + default: + m_manager->raise_exception("invalid datatype operator kind"); + return 0; + } + } + + def* plugin::mk(symbol const& name, unsigned n, sort * const * params) { + ast_manager& m = *m_manager; + return alloc(def, m, u(), name, m_class_id, n, params); + } + + + void plugin::end_def_block() { + ast_manager& m = *m_manager; + + sort_ref_vector sorts(m); + for (symbol const& s : m_def_block) { + def const& d = *m_defs[s]; + sort_ref_vector ps(m); + sorts.push_back(d.instantiate(ps)); + } + for (symbol const& s : m_def_block) { + def& d = *m_defs[s]; + for (constructor* c : d) { + for (accessor* a : *c) { + a->fix_range(sorts); } } } - } - if (can_process) { - already_found[tid] = BLACK; - todo.pop_back(); - } - } - return false; -} + if (!u().is_well_founded(sorts.size(), sorts.c_ptr())) { + m_manager->raise_exception("datatype is not well-founded"); + } -/** - \brief Return the size of the inductive datatype. - Pre-condition: The given argument constains the parameters of an inductive datatype. -*/ -static sort_size get_datatype_size(parameter const * parameters) { - unsigned num_types = parameters[0].get_int(); - unsigned top_tid = parameters[1].get_int(); - buffer szs(num_types, sort_size()); - buffer already_found(num_types, WHITE); - buffer todo; - todo.push_back(top_tid); - while (!todo.empty()) { - unsigned tid = todo.back(); - if (already_found[tid] == BLACK) { - todo.pop_back(); - continue; - } - already_found[tid] = GRAY; - unsigned o = datatype_decl_plugin::constructor_offset(parameters, tid); - unsigned num_constructors = parameters[o].get_int(); - bool is_very_big = false; - bool can_process = true; - for (unsigned s = 1; s <= num_constructors; s++) { - unsigned k_i = parameters[o+s].get_int(); - unsigned num_accessors = parameters[k_i+2].get_int(); - for (unsigned r = 0; r < num_accessors; r++) { - parameter const & a_type = parameters[k_i+4 + 2*r]; - if (a_type.is_int()) { - int tid_prime = a_type.get_int(); - switch (already_found[tid_prime]) { - case WHITE: - todo.push_back(tid_prime); - can_process = false; - break; - case GRAY: - // type is recursive - return sort_size(); - case BLACK: - break; - } - } - else { - SASSERT(a_type.is_ast()); - sort * ty = to_sort(a_type.get_ast()); - if (ty->is_infinite()) { - // type is infinite - return sort_size(); - } - else if (ty->is_very_big()) { - is_very_big = true; - } - } + u().compute_datatype_size_functions(m_def_block); + for (symbol const& s : m_def_block) { + sort_ref_vector ps(m); + m_defs[s]->instantiate(ps); } } - if (can_process) { - todo.pop_back(); - already_found[tid] = BLACK; - if (is_very_big) { - szs[tid] = sort_size::mk_very_big(); + + bool plugin::mk_datatypes(unsigned num_datatypes, def * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts) { + begin_def_block(); + for (unsigned i = 0; i < num_datatypes; ++i) { + def* d = 0; + TRACE("datatype", tout << "declaring " << datatypes[i]->name() << "\n";); + if (m_defs.find(datatypes[i]->name(), d)) { + TRACE("datatype", tout << "delete previous version for " << datatypes[i]->name() << "\n";); + dealloc(d); + } + m_defs.insert(datatypes[i]->name(), datatypes[i]); + m_def_block.push_back(datatypes[i]->name()); + } + end_def_block(); + sort_ref_vector ps(*m_manager); + for (symbol const& s : m_def_block) { + new_sorts.push_back(m_defs[s]->instantiate(ps)); + } + return true; + } + + void plugin::remove(symbol const& s) { + def* d = 0; + if (m_defs.find(s, d)) dealloc(d); + m_defs.remove(s); + } + + bool plugin::is_value_visit(expr * arg, ptr_buffer & todo) const { + if (!is_app(arg)) + return false; + family_id fid = to_app(arg)->get_family_id(); + if (fid == m_family_id) { + if (!u().is_constructor(to_app(arg))) + return false; + if (to_app(arg)->get_num_args() == 0) + return true; + todo.push_back(to_app(arg)); + return true; } else { - // the type is not infinite nor the number of elements is infinite... - // computing the number of elements - rational num; - for (unsigned s = 1; s <= num_constructors; s++) { - unsigned k_i = parameters[o+s].get_int(); - unsigned num_accessors = parameters[k_i+2].get_int(); - rational c_num(1); - for (unsigned r = 0; r < num_accessors; r++) { - parameter const & a_type = parameters[k_i+4 + 2*r]; - if (a_type.is_int()) { - int tid_prime = a_type.get_int(); - SASSERT(!szs[tid_prime].is_infinite() && !szs[tid_prime].is_very_big()); - c_num *= rational(szs[tid_prime].size(),rational::ui64()); - } - else { - SASSERT(a_type.is_ast()); - sort * ty = to_sort(a_type.get_ast()); - SASSERT(!ty->is_infinite() && !ty->is_very_big()); - c_num *= rational(ty->get_num_elements().size(), rational::ui64()); - } - } - num += c_num; - } - szs[tid] = sort_size(num); + return m_manager->is_value(arg); + } + } + + bool plugin::is_value(app * e) const { + TRACE("dt_is_value", tout << "checking\n" << mk_ismt2_pp(e, *m_manager) << "\n";); + if (!u().is_constructor(e)) + return false; + if (e->get_num_args() == 0) + return true; + // REMARK: if the following check is too expensive, we should + // cache the values in the decl::plugin. + ptr_buffer todo; + // potentially expensive check for common sub-expressions. + for (expr* arg : *e) { + if (!is_value_visit(arg, todo)) { + TRACE("dt_is_value", tout << "not-value:\n" << mk_ismt2_pp(arg, *m_manager) << "\n";); + return false; + } + } + while (!todo.empty()) { + app * curr = todo.back(); + SASSERT(u().is_constructor(curr)); + todo.pop_back(); + for (expr* arg : *curr) { + if (!is_value_visit(arg, todo)) { + TRACE("dt_is_value", tout << "not-value:\n" << mk_ismt2_pp(arg, *m_manager) << "\n";); + return false; + } + } + } + return true; + } + + void plugin::get_op_names(svector & op_names, symbol const & logic) { + op_names.push_back(builtin_name("is", OP_DT_IS)); + if (logic == symbol::null) { + op_names.push_back(builtin_name("update-field", OP_DT_UPDATE_FIELD)); } } - } - return szs[top_tid]; -} -/** - \brief Return true if the inductive datatype is well-founded. - Pre-condition: The given argument constains the parameters of an inductive datatype. -*/ -static bool is_well_founded(parameter const * parameters) { - unsigned num_types = parameters[0].get_int(); - buffer well_founded(num_types, false); - unsigned num_well_founded = 0; - bool changed; - do { - changed = false; - for (unsigned tid = 0; tid < num_types; tid++) { - if (!well_founded[tid]) { - unsigned o = datatype_decl_plugin::constructor_offset(parameters, tid); // constructor offset - unsigned num_constructors = parameters[o].get_int(); - for (unsigned s = 1; s <= num_constructors; s++) { - unsigned k_i = parameters[o + s].get_int(); - unsigned num_accessors = parameters[k_i + 2].get_int(); - unsigned r = 0; - for (; r < num_accessors; r++) { - parameter const & a_type = parameters[k_i + 4 + 2*r]; - if (a_type.is_int() && !well_founded[a_type.get_int()]) { + expr * plugin::get_some_value(sort * s) { + SASSERT(u().is_datatype(s)); + func_decl * c = u().get_non_rec_constructor(s); + ptr_buffer args; + for (unsigned i = 0; i < c->get_arity(); i++) { + args.push_back(m_manager->get_some_value(c->get_domain(i))); + } + return m_manager->mk_app(c, args.size(), args.c_ptr()); + } + + bool plugin::is_fully_interp(sort * s) const { + return u().is_fully_interp(s); + } + } + + sort_ref_vector util::datatype_params(sort * s) const { + SASSERT(is_datatype(s)); + sort_ref_vector result(m); + for (unsigned i = 1; i < s->get_num_parameters(); ++i) { + result.push_back(to_sort(s->get_parameter(i).get_ast())); + } + return result; + } + + + bool util::is_fully_interp(sort * s) const { + SASSERT(is_datatype(s)); + bool fi = true; + return fi; + if (m_is_fully_interp.find(s, fi)) { + return fi; + } + unsigned sz = m_fully_interp_trail.size(); + m_is_fully_interp.insert(s, true); + def const& d = get_def(s); + bool is_interp = true; + m_fully_interp_trail.push_back(s); + for (constructor const* c : d) { + for (accessor const* a : *c) { + func_decl_ref ac = a->instantiate(s); + sort* r = ac->get_range(); + if (!m.is_fully_interp(r)) { + is_interp = false; + break; + } + } + if (!is_interp) break; + } + for (unsigned i = sz; i < m_fully_interp_trail.size(); ++i) { + m_is_fully_interp.remove(m_fully_interp_trail[i]); + } + m_fully_interp_trail.shrink(sz); + m_is_fully_interp.insert(s, is_interp); + m_asts.push_back(s); + return true; + } + + /** + \brief Return true if the inductive datatype is recursive. + */ + bool util::is_recursive_core(sort* s) const { + obj_map already_found; + ptr_vector todo, subsorts; + todo.push_back(s); + status st; + while (!todo.empty()) { + s = todo.back(); + if (already_found.find(s, st) && st == BLACK) { + todo.pop_back(); + continue; + } + already_found.insert(s, GRAY); + def const& d = get_def(s); + bool can_process = true; + for (constructor const* c : d) { + for (accessor const* a : *c) { + sort* d = a->range(); + // check if d is a datatype sort + subsorts.reset(); + get_subsorts(d, subsorts); + for (sort * s2 : subsorts) { + if (is_datatype(s2)) { + if (already_found.find(s2, st)) { + // type is recursive + if (st == GRAY) return true; + } + else { + todo.push_back(s2); + can_process = false; + } + } + } + } + } + if (can_process) { + already_found.insert(s, BLACK); + todo.pop_back(); + } + } + return false; + } + + unsigned util::get_datatype_num_parameter_sorts(sort * ty) { + SASSERT(ty->get_num_parameters() >= 1); + return ty->get_num_parameters() - 1; + } + + sort* util::get_datatype_parameter_sort(sort * ty, unsigned idx) { + SASSERT(idx < get_datatype_num_parameter_sorts(ty)); + return to_sort(ty->get_parameter(idx+1).get_ast()); + } + + param_size::size* util::get_sort_size(sort_ref_vector const& params, sort* s) { + if (params.empty()) { + return param_size::size::mk_offset(s->get_num_elements()); + } + if (is_datatype(s)) { + param_size::size* sz; + obj_map S; + unsigned n = get_datatype_num_parameter_sorts(s); + for (unsigned i = 0; i < n; ++i) { + sort* ps = get_datatype_parameter_sort(s, i); + sz = get_sort_size(params, ps); + sz->inc_ref(); + S.insert(ps, sz); + } + def & d = get_def(s->get_name()); + sz = d.sort_size()->subst(S); + for (auto & kv : S) { + kv.m_value->dec_ref(); + } + return sz; + } + array_util autil(m); + if (autil.is_array(s)) { + unsigned n = get_array_arity(s); + ptr_vector szs; + for (unsigned i = 0; i < n; ++i) { + szs.push_back(get_sort_size(params, get_array_domain(s, i))); + } + param_size::size* sz1 = param_size::size::mk_times(szs); + param_size::size* sz2 = get_sort_size(params, get_array_range(s)); + return param_size::size::mk_power(sz2, sz1); + } + for (sort* p : params) { + if (s == p) { + sort_ref sr(s, m); + return param_size::size::mk_param(sr); + } + } + return param_size::size::mk_offset(s->get_num_elements()); + } + + bool util::is_declared(sort* s) const { + return m_plugin->is_declared(s); + } + + void util::compute_datatype_size_functions(svector const& names) { + map already_found; + map szs; + + svector todo(names); + status st; + while (!todo.empty()) { + symbol s = todo.back(); + TRACE("datatype", tout << "Sort size for " << s << "\n";); + + if (already_found.find(s, st) && st == BLACK) { + todo.pop_back(); + continue; + } + already_found.insert(s, GRAY); + bool is_infinite = false; + bool can_process = true; + def& d = get_def(s); + for (constructor const* c : d) { + for (accessor const* a : *c) { + sort* r = a->range(); + if (is_datatype(r)) { + symbol s2 = r->get_name(); + if (already_found.find(s2, st)) { + // type is infinite + if (st == GRAY) { + is_infinite = true; + } + } + else if (names.contains(s2)) { + todo.push_back(s2); + can_process = false; + } + } + } + } + if (!can_process) { + continue; + } + todo.pop_back(); + already_found.insert(s, BLACK); + if (is_infinite) { + d.set_sort_size(param_size::size::mk_offset(sort_size::mk_infinite())); + continue; + } + + ptr_vector s_add; + for (constructor const* c : d) { + ptr_vector s_mul; + for (accessor const* a : *c) { + s_mul.push_back(get_sort_size(d.params(), a->range())); + } + s_add.push_back(param_size::size::mk_times(s_mul)); + } + d.set_sort_size(param_size::size::mk_plus(s_add)); + } + } + + + /** + \brief Return true if the inductive datatype is well-founded. + Pre-condition: The given argument constains the parameters of an inductive datatype. + */ + bool util::is_well_founded(unsigned num_types, sort* const* sorts) { + buffer well_founded(num_types, false); + obj_map sort2id; + for (unsigned i = 0; i < num_types; ++i) { + sort2id.insert(sorts[i], i); + } + unsigned num_well_founded = 0, id = 0; + bool changed; + do { + changed = false; + for (unsigned tid = 0; tid < num_types; tid++) { + if (well_founded[tid]) { + continue; + } + sort* s = sorts[tid]; + def const& d = get_def(s); + for (constructor const* c : d) { + bool found_nonwf = false; + for (accessor const* a : *c) { + if (sort2id.find(a->range(), id) && !well_founded[id]) { + found_nonwf = true; break; } } - if (r == num_accessors) { + if (!found_nonwf) { changed = true; well_founded[tid] = true; num_well_founded++; @@ -332,761 +715,358 @@ static bool is_well_founded(parameter const * parameters) { } } } - } - } while(changed && num_well_founded < num_types); - unsigned tid = parameters[1].get_int(); - return well_founded[tid]; -} - -datatype_decl_plugin::~datatype_decl_plugin() { - SASSERT(m_util.get() == 0); -} - -void datatype_decl_plugin::finalize() { - m_util = 0; // force deletion -} - -datatype_util & datatype_decl_plugin::get_util() const { - SASSERT(m_manager); - if (m_util.get() == 0) { - m_util = alloc(datatype_util, *m_manager); + } + while(changed && num_well_founded < num_types); + return num_well_founded == num_types; } - return *(m_util.get()); -} - -sort * datatype_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { - try { - if (k != DATATYPE_SORT) { - throw invalid_datatype(); - } - buffer found; - unsigned num_types = read_int(num_parameters, parameters, 0, found); - if (num_types == 0) { - throw invalid_datatype(); - } - unsigned tid = read_int(num_parameters, parameters, 1, found); - unsigned num_sort_params = read_int(num_parameters, parameters, 2, found); - for (unsigned j = 0; j < num_sort_params; ++j) { - read_sort(num_parameters, parameters, 3 + j, found); - } - unsigned c_offset = constructor_offset(parameters); - for (unsigned j = 0; j < num_types; j++) { - read_symbol(num_parameters, parameters, c_offset + 2*j, found); // type name - unsigned o = read_int(num_parameters, parameters, c_offset + 2*j + 1, found); - unsigned num_constructors = read_int(num_parameters, parameters, o, found); - if (num_constructors == 0) { - throw invalid_datatype(); + def const& util::get_def(sort* s) const { + return m_plugin->get_def(s); + } + + void util::get_subsorts(sort* s, ptr_vector& sorts) const { + sorts.push_back(s); + for (unsigned i = 0; i < s->get_num_parameters(); ++i) { + parameter const& p = s->get_parameter(i); + if (p.is_ast() && is_sort(p.get_ast())) { + get_subsorts(to_sort(p.get_ast()), sorts); } - for (unsigned s = 1; s <= num_constructors; s++) { - unsigned k_i = read_int(num_parameters, parameters, o + s, found); - read_symbol(num_parameters, parameters, k_i, found); // constructor name - read_symbol(num_parameters, parameters, k_i + 1, found); // recognizer name - unsigned num_accessors = read_int(num_parameters, parameters, k_i + 2, found); - unsigned first_accessor = k_i+3; - for (unsigned r = 0; r < num_accessors; r++) { - read_symbol(num_parameters, parameters, first_accessor + 2*r, found); // accessor name - parameter const & a_type = read(num_parameters, parameters, first_accessor + 2*r + 1, found); // accessort type - if (!a_type.is_int() && !a_type.is_ast()) { - throw invalid_datatype(); - } - if (a_type.is_ast() && !is_sort(a_type.get_ast())) { - throw invalid_datatype(); - } + } + } + + + util::util(ast_manager & m): + m(m), + m_family_id(m.mk_family_id("datatype")), + m_asts(m), + m_start(0) { + m_plugin = dynamic_cast(m.get_plugin(m_family_id)); + SASSERT(m_plugin); + } + + util::~util() { + std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc >()); + } + + ptr_vector const * util::get_datatype_constructors(sort * ty) { + SASSERT(is_datatype(ty)); + ptr_vector * r = 0; + if (m_datatype2constructors.find(ty, r)) + return r; + r = alloc(ptr_vector); + m_asts.push_back(ty); + m_vectors.push_back(r); + m_datatype2constructors.insert(ty, r); + def const& d = get_def(ty); + for (constructor const* c : d) { + func_decl_ref f = c->instantiate(ty); + m_asts.push_back(f); + r->push_back(f); + } + return r; + } + + ptr_vector const * util::get_constructor_accessors(func_decl * con) { + SASSERT(is_constructor(con)); + ptr_vector * res = 0; + if (m_constructor2accessors.find(con, res)) { + return res; + } + res = alloc(ptr_vector); + m_asts.push_back(con); + m_vectors.push_back(res); + m_constructor2accessors.insert(con, res); + sort * datatype = con->get_range(); + def const& d = get_def(datatype); + for (constructor const* c : d) { + if (c->name() == con->get_name()) { + for (accessor const* a : *c) { + func_decl_ref fn = a->instantiate(datatype); + res->push_back(fn); + m_asts.push_back(fn); } + break; } } - // check if there is no garbage - if (found.size() != num_parameters || std::find(found.begin(), found.end(), false) != found.end()) { - throw invalid_datatype(); - } + return res; + } - if (!is_well_founded(parameters)) { - m_manager->raise_exception("datatype is not well-founded"); - return 0; - } - - // compute datatype size - sort_size ts = get_datatype_size(parameters); - symbol const & tname = parameters[c_offset + 2*tid].get_symbol(); - return m_manager->mk_sort(tname, - sort_info(m_family_id, k, ts, num_parameters, parameters, true)); - } - catch (invalid_datatype) { - m_manager->raise_exception("invalid datatype"); - return 0; - } -} - -static sort * get_other_datatype(ast_manager & m, family_id datatype_fid, sort * source_datatype, unsigned tid) { - SASSERT(source_datatype->get_family_id() == datatype_fid); - SASSERT(source_datatype->get_decl_kind() == DATATYPE_SORT); - if (tid == static_cast(source_datatype->get_parameter(1).get_int())) { - return source_datatype; - } - buffer p; - unsigned n = source_datatype->get_num_parameters(); - for (unsigned i = 0; i < n; i++) { - p.push_back(source_datatype->get_parameter(i)); - } - p[1] = parameter(tid); - return m.mk_sort(datatype_fid, DATATYPE_SORT, n, p.c_ptr()); -} - -static sort * get_type(ast_manager & m, family_id datatype_fid, sort * source_datatype, parameter const & p) { - SASSERT(p.is_ast() || p.is_int()); - if (p.is_ast()) { - return to_sort(p.get_ast()); - } - else { - return get_other_datatype(m, datatype_fid, source_datatype, p.get_int()); - } -} - -func_decl * datatype_decl_plugin::mk_update_field( - unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - decl_kind k = OP_DT_UPDATE_FIELD; - ast_manager& m = *m_manager; - - if (num_parameters != 1 || !parameters[0].is_ast()) { - m.raise_exception("invalid parameters for datatype field update"); - return 0; - } - if (arity != 2) { - m.raise_exception("invalid number of arguments for datatype field update"); - return 0; - } - func_decl* acc = 0; - if (is_func_decl(parameters[0].get_ast())) { - acc = to_func_decl(parameters[0].get_ast()); - } - if (acc && !get_util().is_accessor(acc)) { - acc = 0; - } - if (!acc) { - m.raise_exception("datatype field update requires a datatype accessor as the second argument"); - return 0; - } - sort* dom = acc->get_domain(0); - sort* rng = acc->get_range(); - if (dom != domain[0]) { - m.raise_exception("first argument to field update should be a data-type"); - return 0; - } - if (rng != domain[1]) { - std::ostringstream buffer; - buffer << "second argument to field update should be " << mk_ismt2_pp(rng, m) - << " instead of " << mk_ismt2_pp(domain[1], m); - m.raise_exception(buffer.str().c_str()); - return 0; - } - range = domain[0]; - func_decl_info info(m_family_id, k, num_parameters, parameters); - return m.mk_func_decl(symbol("update-field"), arity, domain, range, info); -} - -func_decl * datatype_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - - if (k == OP_DT_UPDATE_FIELD) { - return mk_update_field(num_parameters, parameters, arity, domain, range); - } - if (num_parameters < 2 || !parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) { - m_manager->raise_exception("invalid parameters for datatype operator"); - return 0; - } - sort * datatype = to_sort(parameters[0].get_ast()); - if (datatype->get_family_id() != m_family_id || - datatype->get_decl_kind() != DATATYPE_SORT) { - m_manager->raise_exception("invalid parameters for datatype operator"); - return 0; - } - for (unsigned i = 1; i < num_parameters; i++) { - if (!parameters[i].is_int()) { - m_manager->raise_exception("invalid parameters for datatype operator"); - return 0; - } - } - unsigned c_idx = parameters[1].get_int(); - unsigned tid = datatype->get_parameter(1).get_int(); - unsigned o = datatype_decl_plugin::constructor_offset(datatype, tid); - unsigned num_constructors = datatype->get_parameter(o).get_int(); - if (c_idx >= num_constructors) { - m_manager->raise_exception("invalid parameters for datatype operator"); - return 0; - } - unsigned k_i = datatype->get_parameter(o + 1 + c_idx).get_int(); - - switch (k) { - case OP_DT_CONSTRUCTOR: - if (num_parameters != 2) { - m_manager->raise_exception("invalid parameters for datatype constructor"); - return 0; - } - else { - symbol c_name = datatype->get_parameter(k_i).get_symbol(); - unsigned num_accessors = datatype->get_parameter(k_i + 2).get_int(); - if (num_accessors != arity) { - m_manager->raise_exception("invalid domain size for datatype constructor"); - return 0; + func_decl * util::get_constructor_recognizer(func_decl * con) { + SASSERT(is_constructor(con)); + func_decl * d = 0; + if (m_constructor2recognizer.find(con, d)) + return d; + sort * datatype = con->get_range(); + def const& dd = get_def(datatype); + symbol r; + for (constructor const* c : dd) { + if (c->name() == con->get_name()) { + r = c->recognizer(); } + } + parameter ps[2] = { parameter(con), parameter(r) }; + d = m.mk_func_decl(m_family_id, OP_DT_RECOGNISER, 2, ps, 1, &datatype); + SASSERT(d); + m_asts.push_back(con); + m_asts.push_back(d); + m_constructor2recognizer.insert(con, d); + return d; + } - // - // the reference count to domain could be 0. - // we need to ensure that creating a temporary - // copy of the same type causes a free. - // - sort_ref_vector domain_check(*m_manager); + func_decl * util::get_recognizer_constructor(func_decl * recognizer) const { + SASSERT(is_recognizer(recognizer)); + return to_func_decl(recognizer->get_parameter(0).get_ast()); + } - for (unsigned r = 0; r < num_accessors; r++) { - sort_ref ty(*m_manager); - ty = get_type(*m_manager, m_family_id, datatype, datatype->get_parameter(k_i + 4 + 2*r)); - domain_check.push_back(ty); - if (ty != domain[r]) { - m_manager->raise_exception("invalid domain for datatype constructor"); - return 0; + bool util::is_recursive(sort * ty) { + SASSERT(is_datatype(ty)); + bool r = false; + if (!m_is_recursive.find(ty, r)) { + r = is_recursive_core(ty); + m_is_recursive.insert(ty, r); + m_asts.push_back(ty); + } + return r; + } + + bool util::is_enum_sort(sort* s) { + if (!is_datatype(s)) { + return false; + } + bool r = false; + if (m_is_enum.find(s, r)) + return r; + ptr_vector const& cnstrs = *get_datatype_constructors(s); + r = true; + for (unsigned i = 0; r && i < cnstrs.size(); ++i) { + r = cnstrs[i]->get_arity() == 0; + } + m_is_enum.insert(s, r); + m_asts.push_back(s); + return r; + } + + func_decl * util::get_accessor_constructor(func_decl * accessor) { + SASSERT(is_accessor(accessor)); + func_decl * r = 0; + if (m_accessor2constructor.find(accessor, r)) + return r; + sort * datatype = accessor->get_domain(0); + symbol c_id = accessor->get_parameter(1).get_symbol(); + def const& d = get_def(datatype); + func_decl_ref fn(m); + for (constructor const* c : d) { + if (c->name() == c_id) { + fn = c->instantiate(datatype); + break; + } + } + r = fn; + m_accessor2constructor.insert(accessor, r); + m_asts.push_back(accessor); + m_asts.push_back(r); + return r; + } + + + void util::reset() { + m_datatype2constructors.reset(); + m_datatype2nonrec_constructor.reset(); + m_constructor2accessors.reset(); + m_constructor2recognizer.reset(); + m_recognizer2constructor.reset(); + m_accessor2constructor.reset(); + m_is_recursive.reset(); + m_is_enum.reset(); + std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc >()); + m_vectors.reset(); + m_asts.reset(); + ++m_start; + } + + + /** + \brief Return a constructor mk(T_1, ... T_n) + where each T_i is not a datatype or it is a datatype that contains + a constructor that will not contain directly or indirectly an element of the given sort. + */ + func_decl * util::get_non_rec_constructor(sort * ty) { + SASSERT(is_datatype(ty)); + func_decl * r = 0; + if (m_datatype2nonrec_constructor.find(ty, r)) + return r; + r = 0; + ptr_vector forbidden_set; + forbidden_set.push_back(ty); + TRACE("util_bug", tout << "invoke get-non-rec: " << sort_ref(ty, m) << "\n";); + r = get_non_rec_constructor_core(ty, forbidden_set); + SASSERT(forbidden_set.back() == ty); + SASSERT(r); + m_asts.push_back(ty); + m_asts.push_back(r); + m_datatype2nonrec_constructor.insert(ty, r); + return r; + } + + /** + \brief Return a constructor mk(T_1, ..., T_n) where + each T_i is not a datatype or it is a datatype t not in forbidden_set, + and get_non_rec_constructor_core(T_i, forbidden_set union { T_i }) + */ + func_decl * util::get_non_rec_constructor_core(sort * ty, ptr_vector & forbidden_set) { + // We must select a constructor c(T_1, ..., T_n):T such that + // 1) T_i's are not recursive + // If there is no such constructor, then we select one that + // 2) each type T_i is not recursive or contains a constructor that does not depend on T + + ptr_vector const& constructors = *get_datatype_constructors(ty); + unsigned sz = constructors.size(); + TRACE("util_bug", tout << "get-non-rec constructor: " << sort_ref(ty, m) << "\n"; + tout << "forbidden: "; + for (sort* s : forbidden_set) tout << sort_ref(s, m) << " "; + tout << "\n"; + tout << "constructors: " << sz << "\n"; + for (func_decl* f : constructors) tout << func_decl_ref(f, m) << "\n"; + ); + // step 1) + unsigned start = ++m_start; + for (unsigned j = 0; j < sz; ++j) { + func_decl * c = constructors[(j + start) % sz]; + TRACE("util_bug", tout << "checking " << sort_ref(ty, m) << ": " << func_decl_ref(c, m) << "\n";); + unsigned num_args = c->get_arity(); + unsigned i = 0; + for (; i < num_args && !is_datatype(c->get_domain(i)); i++); + if (i == num_args) { + TRACE("util_bug", tout << "found non-rec " << func_decl_ref(c, m) << "\n";); + return c; + } + } + // step 2) + for (unsigned j = 0; j < sz; ++j) { + func_decl * c = constructors[(j + start) % sz]; + TRACE("util_bug", tout << "non_rec_constructor c: " << j << " " << func_decl_ref(c, m) << "\n";); + unsigned num_args = c->get_arity(); + unsigned i = 0; + for (; i < num_args; i++) { + sort * T_i = c->get_domain(i); + TRACE("util_bug", tout << "c: " << i << " " << sort_ref(T_i, m) << "\n";); + if (!is_datatype(T_i)) { + TRACE("util_bug", tout << sort_ref(T_i, m) << " is not a datatype\n";); + continue; } + if (std::find(forbidden_set.begin(), forbidden_set.end(), T_i) != forbidden_set.end()) { + TRACE("util_bug", tout << sort_ref(T_i, m) << " is in forbidden_set\n";); + break; + } + forbidden_set.push_back(T_i); + func_decl * nested_c = get_non_rec_constructor_core(T_i, forbidden_set); + SASSERT(forbidden_set.back() == T_i); + forbidden_set.pop_back(); + if (nested_c == 0) + break; + TRACE("util_bug", tout << "nested_c: " << nested_c->get_name() << "\n";); + } + if (i == num_args) + return c; + } + return 0; + } + unsigned util::get_constructor_idx(func_decl * f) const { + unsigned idx = 0; + def const& d = get_def(f->get_range()); + for (constructor* c : d) { + if (c->name() == f->get_name()) { + return idx; } - func_decl_info info(m_family_id, k, num_parameters, parameters); - info.m_private_parameters = true; - SASSERT(info.private_parameters()); - return m_manager->mk_func_decl(c_name, arity, domain, datatype, info); + ++idx; } - case OP_DT_RECOGNISER: - if (num_parameters != 2 || arity != 1 || domain[0] != datatype) { - m_manager->raise_exception("invalid parameters for datatype recogniser"); - return 0; - } - else { - symbol r_name = datatype->get_parameter(k_i + 1).get_symbol(); - sort * b = m_manager->mk_bool_sort(); - func_decl_info info(m_family_id, k, num_parameters, parameters); - info.m_private_parameters = true; - SASSERT(info.private_parameters()); - return m_manager->mk_func_decl(r_name, arity, domain, b, info); - } - case OP_DT_ACCESSOR: - if (num_parameters != 3 || arity != 1 || domain[0] != datatype) { - m_manager->raise_exception("invalid parameters for datatype accessor"); - return 0; - } - else { - unsigned a_idx = parameters[2].get_int(); - unsigned num_accessors = datatype->get_parameter(k_i + 2).get_int(); - if (a_idx >= num_accessors) { - m_manager->raise_exception("invalid datatype accessor"); - return 0; - } - symbol a_name = datatype->get_parameter(k_i + 3 + 2*a_idx).get_symbol(); - sort * a_type = get_type(*m_manager, m_family_id, datatype, datatype->get_parameter(k_i + 4 + 2*a_idx)); - func_decl_info info(m_family_id, k, num_parameters, parameters); - info.m_private_parameters = true; - SASSERT(info.private_parameters()); - return m_manager->mk_func_decl(a_name, arity, domain, a_type, info); - } - break; - case OP_DT_UPDATE_FIELD: UNREACHABLE(); return 0; - default: - m_manager->raise_exception("invalid datatype operator kind"); - return 0; } -} -bool datatype_decl_plugin::mk_datatypes(unsigned num_datatypes, datatype_decl * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_types) { - buffer p; - p.push_back(parameter(num_datatypes)); - p.push_back(parameter(-1)); - p.push_back(parameter(num_params)); - for (unsigned i = 0; i < num_params; ++i) { - p.push_back(parameter(sort_params[i])); + unsigned util::get_recognizer_constructor_idx(func_decl * f) const { + return get_constructor_idx(get_recognizer_constructor(f)); } - - unsigned c_offset = constructor_offset(p.c_ptr()); - for (unsigned i = 0; i < num_datatypes; i++) { - p.push_back(parameter(datatypes[i]->get_name())); - p.push_back(parameter(-1)); // offset is unknown at this point - } - for (unsigned i = 0; i < num_datatypes; i++) { - p[c_offset + 1 + 2*i] = parameter(p.size()); // save offset to constructor table - ptr_vector const & constructors = datatypes[i]->get_constructors(); - unsigned num_constructors = constructors.size(); - p.push_back(parameter(num_constructors)); - for (unsigned j = 0; j < num_constructors; j++) { - p.push_back(parameter(-1)); // offset is unknown at this point + + /** + \brief Two datatype sorts s1 and s2 are siblings if they were + defined together in the same mutually recursive definition. + */ + bool util::are_siblings(sort * s1, sort * s2) { + if (!is_datatype(s1) || !is_datatype(s2)) { + return s1 == s2; + } + else { + return get_def(s1).id() == get_def(s2).id(); } } - for (unsigned i = 0; i < num_datatypes; i++) { - unsigned o = constructor_offset(p.c_ptr(), i); - ptr_vector const & constructors = datatypes[i]->get_constructors(); - unsigned num_constructors = constructors.size(); - for (unsigned j = 0; j < num_constructors; j++) { - p[o+1+j] = parameter(p.size()); // save offset to constructor definition - constructor_decl * c = constructors[j]; - p.push_back(parameter(c->get_name())); - p.push_back(parameter(c->get_recognizer_name())); - ptr_vector const & accessors = c->get_accessors(); - unsigned num_accessors = accessors.size(); - p.push_back(parameter(num_accessors)); - for (unsigned k = 0; k < num_accessors; k++) { - accessor_decl * a = accessors[k]; - p.push_back(parameter(a->get_name())); - type_ref const & ty = a->get_type(); - if (ty.is_idx()) { - if (static_cast(ty.get_idx()) >= num_datatypes) { - TRACE("datatype", tout << "Index out of bounds: " << ty.get_idx() << "\n";); - return false; + + unsigned util::get_datatype_num_constructors(sort * ty) { + def const& d = get_def(ty->get_name()); + return d.constructors().size(); + } + + void util::get_defs(sort* s0, ptr_vector& defs) { + svector mark; + ptr_buffer todo; + todo.push_back(s0); + mark.push_back(s0->get_name()); + while (!todo.empty()) { + sort* s = todo.back(); + todo.pop_back(); + defs.push_back(&m_plugin->get_def(s->get_name())); + def const& d = get_def(s); + for (constructor* c : d) { + for (accessor* a : *c) { + sort* s = a->range(); + if (are_siblings(s0, s) && !mark.contains(s->get_name())) { + mark.push_back(s->get_name()); + todo.push_back(s); } - p.push_back(parameter(ty.get_idx())); - } - else { - p.push_back(parameter(ty.get_sort())); } } } } - for (unsigned i = 0; i < num_datatypes; i++) { - p[1] = parameter(i); - TRACE("datatype", tout << "new datatype parameters:\n"; - for (unsigned j = 0; j < p.size(); j++) { - tout << "p[" << j << "] -> " << p[j] << "\n"; - }); - sort * ty = mk_sort(DATATYPE_SORT, p.size(), p.c_ptr()); - if (ty == 0) { - TRACE("datatype", tout << "Failed to create datatype sort from parameters\n";); - return false; - } - new_types.push_back(ty); - } - return true; -} -expr * datatype_decl_plugin::get_some_value(sort * s) { - SASSERT(s->is_sort_of(m_family_id, DATATYPE_SORT)); - datatype_util & util = get_util(); - func_decl * c = util.get_non_rec_constructor(s); - ptr_buffer args; - for (unsigned i = 0; i < c->get_arity(); i++) { - args.push_back(m_manager->get_some_value(c->get_domain(i))); - } - return m_manager->mk_app(c, args.size(), args.c_ptr()); -} + void util::display_datatype(sort *s0, std::ostream& out) { + ast_mark mark; + ptr_buffer todo; + SASSERT(is_datatype(s0)); + out << s0->get_name() << " where\n"; + todo.push_back(s0); + mark.mark(s0, true); + while (!todo.empty()) { + sort* s = todo.back(); + todo.pop_back(); + out << s->get_name() << " =\n"; -bool datatype_decl_plugin::is_fully_interp(sort const * s) const { - SASSERT(s->is_sort_of(m_family_id, DATATYPE_SORT)); - parameter const * parameters = s->get_parameters(); - unsigned num_types = parameters[0].get_int(); - for (unsigned tid = 0; tid < num_types; tid++) { - unsigned o = datatype_decl_plugin::constructor_offset(s, tid); - unsigned num_constructors = parameters[o].get_int(); - for (unsigned si = 1; si <= num_constructors; si++) { - unsigned k_i = parameters[o + si].get_int(); - unsigned num_accessors = parameters[k_i + 2].get_int(); - unsigned r = 0; - for (; r < num_accessors; r++) { - parameter const & a_type = parameters[k_i + 4 + 2*r]; - if (a_type.is_int()) - continue; - SASSERT(a_type.is_ast()); - sort * arg_s = to_sort(a_type.get_ast()); - if (!m_manager->is_fully_interp(arg_s)) - return false; - } - } - } - return true; -} - -bool datatype_decl_plugin::is_value_visit(expr * arg, ptr_buffer & todo) const { - if (!is_app(arg)) - return false; - family_id fid = to_app(arg)->get_family_id(); - if (fid == m_family_id) { - if (!get_util().is_constructor(to_app(arg))) - return false; - if (to_app(arg)->get_num_args() == 0) - return true; - todo.push_back(to_app(arg)); - return true; - } - else { - return m_manager->is_value(arg); - } -} - -unsigned datatype_decl_plugin::constructor_offset(sort const* s) { - return constructor_offset(s->get_parameters()); -} - -unsigned datatype_decl_plugin::constructor_offset(parameter const& p) { - return 3 + p.get_int(); -} - -unsigned datatype_decl_plugin::constructor_offset(parameter const* ps) { - return constructor_offset(ps[2]); -} - -unsigned datatype_decl_plugin::constructor_offset(sort const* s, unsigned tid) { - unsigned c_offset = constructor_offset(s->get_parameters()); - return s->get_parameter(c_offset + 1 + 2*tid).get_int(); -} - -unsigned datatype_decl_plugin::constructor_offset(parameter const* ps, unsigned tid) { - unsigned c_offset = constructor_offset(ps[2]); - return ps[c_offset + 1 + 2*tid].get_int(); -} - -bool datatype_decl_plugin::is_value(app * e) const { - TRACE("dt_is_value", tout << "checking\n" << mk_ismt2_pp(e, *m_manager) << "\n";); - if (!get_util().is_constructor(e)) - return false; - if (e->get_num_args() == 0) - return true; - // REMARK: if the following check is too expensive, we should - // cache the values in the datatype_decl_plugin. - ptr_buffer todo; - // potentially expensive check for common sub-expressions. - for (unsigned i = 0; i < e->get_num_args(); i++) { - if (!is_value_visit(e->get_arg(i), todo)) { - TRACE("dt_is_value", tout << "not-value:\n" << mk_ismt2_pp(e->get_arg(i), *m_manager) << "\n";); - return false; - } - } - while (!todo.empty()) { - app * curr = todo.back(); - SASSERT(get_util().is_constructor(curr)); - todo.pop_back(); - for (unsigned i = 0; i < curr->get_num_args(); i++) { - if (!is_value_visit(curr->get_arg(i), todo)) { - TRACE("dt_is_value", tout << "not-value:\n" << mk_ismt2_pp(curr->get_arg(i), *m_manager) << "\n";); - return false; - } - } - } - return true; -} - -void datatype_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { - if (logic == symbol::null) { - op_names.push_back(builtin_name("update-field", OP_DT_UPDATE_FIELD)); - } -} - - -datatype_util::datatype_util(ast_manager & m): - m_manager(m), - m_family_id(m.mk_family_id("datatype")), - m_asts(m), - m_start(0) { -} - -datatype_util::~datatype_util() { - std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc >()); -} - -func_decl * datatype_util::get_constructor(sort * ty, unsigned c_id) { - unsigned tid = ty->get_parameter(1).get_int(); - unsigned o = datatype_decl_plugin::constructor_offset(ty, tid); - unsigned k_i = ty->get_parameter(o + c_id + 1).get_int(); - unsigned num_accessors = ty->get_parameter(k_i + 2).get_int(); - parameter p[2] = { parameter(ty), parameter(c_id) }; - ptr_buffer domain; - for (unsigned r = 0; r < num_accessors; r++) { - domain.push_back(get_type(m_manager, m_family_id, ty, ty->get_parameter(k_i + 4 + 2*r))); - } - func_decl * d = m_manager.mk_func_decl(m_family_id, OP_DT_CONSTRUCTOR, 2, p, domain.size(), domain.c_ptr()); - SASSERT(d); - return d; -} - -ptr_vector const * datatype_util::get_datatype_constructors(sort * ty) { - SASSERT(is_datatype(ty)); - ptr_vector * r = 0; - if (m_datatype2constructors.find(ty, r)) - return r; - r = alloc(ptr_vector); - m_asts.push_back(ty); - m_vectors.push_back(r); - m_datatype2constructors.insert(ty, r); - unsigned tid = ty->get_parameter(1).get_int(); - unsigned o = datatype_decl_plugin::constructor_offset(ty, tid); - unsigned num_constructors = ty->get_parameter(o).get_int(); - for (unsigned c_id = 0; c_id < num_constructors; c_id++) { - func_decl * c = get_constructor(ty, c_id); - m_asts.push_back(c); - r->push_back(c); - } - return r; -} - -/** - \brief Return a constructor mk(T_1, ... T_n) - where each T_i is not a datatype or it is a datatype that contains - a constructor that will not contain directly or indirectly an element of the given sort. -*/ -func_decl * datatype_util::get_non_rec_constructor(sort * ty) { - SASSERT(is_datatype(ty)); - func_decl * r = 0; - if (m_datatype2nonrec_constructor.find(ty, r)) - return r; - r = 0; - ptr_vector forbidden_set; - forbidden_set.push_back(ty); - r = get_non_rec_constructor_core(ty, forbidden_set); - SASSERT(forbidden_set.back() == ty); - SASSERT(r); - m_asts.push_back(ty); - m_asts.push_back(r); - m_datatype2nonrec_constructor.insert(ty, r); - return r; -} - -/** - \brief Return a constructor mk(T_1, ..., T_n) where - each T_i is not a datatype or it is a datatype t not in forbidden_set, - and get_non_rec_constructor_core(T_i, forbidden_set union { T_i }) -*/ -func_decl * datatype_util::get_non_rec_constructor_core(sort * ty, ptr_vector & forbidden_set) { - // We must select a constructor c(T_1, ..., T_n):T such that - // 1) T_i's are not recursive - // If there is no such constructor, then we select one that - // 2) each type T_i is not recursive or contains a constructor that does not depend on T - ptr_vector const * constructors = get_datatype_constructors(ty); - // step 1) - unsigned sz = constructors->size(); - ++m_start; - for (unsigned j = 0; j < sz; ++j) { - func_decl * c = (*constructors)[(j + m_start) % sz]; - unsigned num_args = c->get_arity(); - unsigned i = 0; - for (; i < num_args; i++) { - sort * T_i = c->get_domain(i); - if (is_datatype(T_i)) - break; - } - if (i == num_args) - return c; - } - // step 2) - for (unsigned j = 0; j < sz; ++j) { - func_decl * c = (*constructors)[(j + m_start) % sz]; - TRACE("datatype_util_bug", tout << "non_rec_constructor c: " << c->get_name() << "\n";); - unsigned num_args = c->get_arity(); - unsigned i = 0; - for (; i < num_args; i++) { - sort * T_i = c->get_domain(i); - TRACE("datatype_util_bug", tout << "c: " << c->get_name() << " i: " << i << " T_i: " << T_i->get_name() << "\n";); - if (!is_datatype(T_i)) { - TRACE("datatype_util_bug", tout << "T_i is not a datatype\n";); - continue; - } - if (std::find(forbidden_set.begin(), forbidden_set.end(), T_i) != forbidden_set.end()) { - TRACE("datatype_util_bug", tout << "T_i is in forbidden_set\n";); - break; - } - forbidden_set.push_back(T_i); - func_decl * nested_c = get_non_rec_constructor_core(T_i, forbidden_set); - SASSERT(forbidden_set.back() == T_i); - forbidden_set.pop_back(); - TRACE("datatype_util_bug", tout << "nested_c: " << nested_c->get_name() << "\n";); - if (nested_c == 0) - break; - } - if (i == num_args) - return c; - } - return 0; -} - -func_decl * datatype_util::get_constructor_recognizer(func_decl * constructor) { - SASSERT(is_constructor(constructor)); - func_decl * d = 0; - if (m_constructor2recognizer.find(constructor, d)) - return d; - sort * datatype = constructor->get_range(); - d = m_manager.mk_func_decl(m_family_id, OP_DT_RECOGNISER, 2, constructor->get_parameters(), 1, &datatype); - SASSERT(d); - m_asts.push_back(constructor); - m_asts.push_back(d); - m_constructor2recognizer.insert(constructor, d); - return d; -} - -ptr_vector const * datatype_util::get_constructor_accessors(func_decl * constructor) { - SASSERT(is_constructor(constructor)); - ptr_vector * res = 0; - if (m_constructor2accessors.find(constructor, res)) - return res; - res = alloc(ptr_vector); - m_asts.push_back(constructor); - m_vectors.push_back(res); - m_constructor2accessors.insert(constructor, res); - unsigned c_id = constructor->get_parameter(1).get_int(); - sort * datatype = constructor->get_range(); - unsigned tid = datatype->get_parameter(1).get_int(); - unsigned o = datatype_decl_plugin::constructor_offset(datatype, tid); - unsigned k_i = datatype->get_parameter(o + c_id + 1).get_int(); - unsigned num_accessors = datatype->get_parameter(k_i+2).get_int(); - parameter p[3] = { parameter(datatype), parameter(c_id), parameter(-1) }; - for (unsigned r = 0; r < num_accessors; r++) { - p[2] = parameter(r); - func_decl * d = m_manager.mk_func_decl(m_family_id, OP_DT_ACCESSOR, 3, p, 1, &datatype); - SASSERT(d); - m_asts.push_back(d); - res->push_back(d); - } - return res; -} - -func_decl * datatype_util::get_accessor_constructor(func_decl * accessor) { - SASSERT(is_accessor(accessor)); - func_decl * r = 0; - if (m_accessor2constructor.find(accessor, r)) - return r; - sort * datatype = to_sort(accessor->get_parameter(0).get_ast()); - unsigned c_id = accessor->get_parameter(1).get_int(); - r = get_constructor(datatype, c_id); - m_accessor2constructor.insert(accessor, r); - m_asts.push_back(accessor); - m_asts.push_back(r); - return r; -} - -func_decl * datatype_util::get_recognizer_constructor(func_decl * recognizer) { - SASSERT(is_recognizer(recognizer)); - func_decl * r = 0; - if (m_recognizer2constructor.find(recognizer, r)) - return r; - sort * datatype = to_sort(recognizer->get_parameter(0).get_ast()); - unsigned c_id = recognizer->get_parameter(1).get_int(); - r = get_constructor(datatype, c_id); - m_recognizer2constructor.insert(recognizer, r); - m_asts.push_back(recognizer); - m_asts.push_back(r); - return r; -} - -bool datatype_util::is_recursive(sort * ty) { - SASSERT(is_datatype(ty)); - bool r = false; - if (m_is_recursive.find(ty, r)) - return r; - r = is_recursive_datatype(ty->get_parameters()); - m_is_recursive.insert(ty, r); - m_asts.push_back(ty); - return r; -} - - -bool datatype_util::is_enum_sort(sort* s) { - if (!is_datatype(s)) { - return false; - } - bool r = false; - if (m_is_enum.find(s, r)) - return r; - ptr_vector const& cnstrs = *get_datatype_constructors(s); - r = true; - for (unsigned i = 0; r && i < cnstrs.size(); ++i) { - r = cnstrs[i]->get_arity() == 0; - } - m_is_enum.insert(s, r); - m_asts.push_back(s); - return r; -} - - -void datatype_util::reset() { - m_datatype2constructors.reset(); - m_datatype2nonrec_constructor.reset(); - m_constructor2accessors.reset(); - m_constructor2recognizer.reset(); - m_recognizer2constructor.reset(); - m_accessor2constructor.reset(); - m_is_recursive.reset(); - m_is_enum.reset(); - std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc >()); - m_vectors.reset(); - m_asts.reset(); - ++m_start; -} - -/** - \brief Two datatype sorts s1 and s2 are siblings if they were - defined together in the same mutually recursive definition. -*/ -bool datatype_util::are_siblings(sort * s1, sort * s2) { - SASSERT(is_datatype(s1)); - SASSERT(is_datatype(s2)); - if (s1 == s2) - return true; - if (s1->get_num_parameters() != s2->get_num_parameters()) - return false; - unsigned num_params = s1->get_num_parameters(); - if (s1->get_parameter(0) != s2->get_parameter(0)) - return false; - // position 1 contains the IDX of the datatype in a mutually recursive definition. - for (unsigned i = 2; i < num_params; i++) { - if (s1->get_parameter(i) != s2->get_parameter(i)) - return false; - } - return true; -} - -void datatype_util::display_datatype(sort *s0, std::ostream& strm) { - ast_mark mark; - ptr_buffer todo; - SASSERT(is_datatype(s0)); - strm << s0->get_name() << " where\n"; - todo.push_back(s0); - mark.mark(s0, true); - while (!todo.empty()) { - sort* s = todo.back(); - todo.pop_back(); - strm << s->get_name() << " =\n"; - - ptr_vector const * cnstrs = get_datatype_constructors(s); - for (unsigned i = 0; i < cnstrs->size(); ++i) { - func_decl* cns = (*cnstrs)[i]; - func_decl* rec = get_constructor_recognizer(cns); - strm << " " << cns->get_name() << " :: " << rec->get_name() << " :: "; - ptr_vector const * accs = get_constructor_accessors(cns); - for (unsigned j = 0; j < accs->size(); ++j) { - func_decl* acc = (*accs)[j]; - sort* s1 = acc->get_range(); - strm << "(" << acc->get_name() << ": " << s1->get_name() << ") "; - if (is_datatype(s1) && are_siblings(s1, s0) && !mark.is_marked(s1)) { + ptr_vector const& cnstrs = *get_datatype_constructors(s); + for (unsigned i = 0; i < cnstrs.size(); ++i) { + func_decl* cns = cnstrs[i]; + func_decl* rec = get_constructor_recognizer(cns); + out << " " << cns->get_name() << " :: " << rec->get_name() << " :: "; + ptr_vector const & accs = *get_constructor_accessors(cns); + for (unsigned j = 0; j < accs.size(); ++j) { + func_decl* acc = accs[j]; + sort* s1 = acc->get_range(); + out << "(" << acc->get_name() << ": " << s1->get_name() << ") "; + if (is_datatype(s1) && are_siblings(s1, s0) && !mark.is_marked(s1)) { mark.mark(s1, true); todo.push_back(s1); - } + } + } + out << "\n"; } - strm << "\n"; } } - } -bool datatype_util::is_func_decl(datatype_op_kind k, unsigned num_params, parameter const* params, func_decl* f) { - bool eq = - f->get_decl_kind() == k && - f->get_family_id() == m_family_id && - f->get_num_parameters() == num_params; - for (unsigned i = 0; eq && i < num_params; ++i) { - eq = params[i] == f->get_parameter(i); +datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort*const* params, unsigned num_constructors, constructor_decl * const * cs) { + datatype::decl::plugin* p = u.get_plugin(); + datatype::def* d = p->mk(n, num_params, params); + for (unsigned i = 0; i < num_constructors; ++i) { + d->add(cs[i]); } - return eq; + return d; } - -bool datatype_util::is_constructor_of(unsigned num_params, parameter const* params, func_decl* f) { - return - num_params == 2 && - m_family_id == f->get_family_id() && - OP_DT_CONSTRUCTOR == f->get_decl_kind() && - 2 == f->get_num_parameters() && - params[0] == f->get_parameter(0) && - params[1] == f->get_parameter(1); -} - diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index b2bcf3ab0..515ca6e20 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2006 Microsoft Corporation +Copyright (c) 2017 Microsoft Corporation Module Name: @@ -11,49 +11,390 @@ Abstract: Author: - Leonardo de Moura (leonardo) 2008-01-09. + Nikolaj Bjorner (nbjorner) 2017-9-1 Revision History: + rewritten to support SMTLIB-2.6 parameters from + Leonardo de Moura (leonardo) 2008-01-09. + --*/ #ifndef DATATYPE_DECL_PLUGIN_H_ #define DATATYPE_DECL_PLUGIN_H_ -#include"ast.h" -#include"tptr.h" -#include"buffer.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "util/buffer.h" +#include "util/symbol_table.h" +#include "util/obj_hashtable.h" -enum datatype_sort_kind { + +enum sort_kind { DATATYPE_SORT }; -enum datatype_op_kind { +enum op_kind { OP_DT_CONSTRUCTOR, OP_DT_RECOGNISER, - OP_DT_ACCESSOR, + OP_DT_IS, + OP_DT_ACCESSOR, OP_DT_UPDATE_FIELD, LAST_DT_OP }; -/** - \brief Auxiliary class used to declare inductive datatypes. - It may be a sort or an integer. If it is an integer, - then it represents a reference to a recursive type. +namespace datatype { - For example, consider the datatypes - Datatype - Tree = tree(value:Real, children:TreeList) - TreeList = cons_t(first_t:Tree, rest_t:Tree) - | nil_t - End - - The recursive occurrences of Tree and TreeList will have idx 0 and - 1 respectively. + class util; + class def; + class accessor; + class constructor; + + + class accessor { + symbol m_name; + sort_ref m_range; + unsigned m_index; // reference to recursive data-type may only get resolved after all mutually recursive data-types are procssed. + constructor* m_constructor; + public: + accessor(ast_manager& m, symbol const& n, sort* range): + m_name(n), + m_range(range, m), + m_index(UINT_MAX) + {} + accessor(ast_manager& m, symbol const& n, unsigned index): + m_name(n), + m_range(m), + m_index(index) + {} + sort* range() const { return m_range; } + void fix_range(sort_ref_vector const& dts); + symbol const& name() const { return m_name; } + func_decl_ref instantiate(sort_ref_vector const& ps) const; + func_decl_ref instantiate(sort* dt) const; + void attach(constructor* d) { m_constructor = d; } + constructor const& get_constructor() const { return *m_constructor; } + def const& get_def() const; + util& u() const; + accessor* translate(ast_translation& tr); + }; + + class constructor { + symbol m_name; + symbol m_recognizer; + ptr_vector m_accessors; + def* m_def; + public: + constructor(symbol n, symbol const& r): m_name(n), m_recognizer(r) {} + ~constructor(); + void add(accessor* a) { m_accessors.push_back(a); a->attach(this); } + symbol const& name() const { return m_name; } + symbol const& recognizer() const { return m_recognizer; } + ptr_vector const& accessors() const { return m_accessors; } + ptr_vector::const_iterator begin() const { return m_accessors.begin(); } + ptr_vector::const_iterator end() const { return m_accessors.end(); } + ptr_vector::iterator begin() { return m_accessors.begin(); } + ptr_vector::iterator end() { return m_accessors.end(); } + func_decl_ref instantiate(sort_ref_vector const& ps) const; + func_decl_ref instantiate(sort* dt) const; + void attach(def* d) { m_def = d; } + def const& get_def() const { return *m_def; } + util& u() const; + constructor* translate(ast_translation& tr); + }; + + namespace param_size { + class size { + unsigned m_ref; + public: + size(): m_ref(0) {} + virtual ~size() {} + void inc_ref() { ++m_ref; } + void dec_ref() { --m_ref; if (m_ref == 0) dealloc(this); } + static size* mk_offset(sort_size const& s); + static size* mk_param(sort_ref& p); + static size* mk_plus(size* a1, size* a2); + static size* mk_times(size* a1, size* a2); + static size* mk_plus(ptr_vector& szs); + static size* mk_times(ptr_vector& szs); + static size* mk_power(size* a1, size* a2); + + virtual size* subst(obj_map& S) = 0; + virtual sort_size eval(obj_map const& S) = 0; + + }; + struct offset : public size { + sort_size m_offset; + offset(sort_size const& s): m_offset(s) {} + virtual ~offset() {} + virtual size* subst(obj_map& S) { return this; } + virtual sort_size eval(obj_map const& S) { return m_offset; } + }; + struct plus : public size { + size* m_arg1, *m_arg2; + plus(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref();} + virtual ~plus() { m_arg1->dec_ref(); m_arg2->dec_ref(); } + virtual size* subst(obj_map& S) { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); } + virtual sort_size eval(obj_map const& S) { + sort_size s1 = m_arg1->eval(S); + sort_size s2 = m_arg2->eval(S); + if (s1.is_infinite()) return s1; + if (s2.is_infinite()) return s2; + if (s1.is_very_big()) return s1; + if (s2.is_very_big()) return s2; + rational r = rational(s1.size(), rational::ui64()) + rational(s2.size(), rational::ui64()); + return sort_size(r); + } + }; + struct times : public size { + size* m_arg1, *m_arg2; + times(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); } + virtual ~times() { m_arg1->dec_ref(); m_arg2->dec_ref(); } + virtual size* subst(obj_map& S) { return mk_times(m_arg1->subst(S), m_arg2->subst(S)); } + virtual sort_size eval(obj_map const& S) { + sort_size s1 = m_arg1->eval(S); + sort_size s2 = m_arg2->eval(S); + if (s1.is_infinite()) return s1; + if (s2.is_infinite()) return s2; + if (s1.is_very_big()) return s1; + if (s2.is_very_big()) return s2; + rational r = rational(s1.size(), rational::ui64()) * rational(s2.size(), rational::ui64()); + return sort_size(r); + } + }; + struct power : public size { + size* m_arg1, *m_arg2; + power(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); } + virtual ~power() { m_arg1->dec_ref(); m_arg2->dec_ref(); } + virtual size* subst(obj_map& S) { return mk_power(m_arg1->subst(S), m_arg2->subst(S)); } + virtual sort_size eval(obj_map const& S) { + sort_size s1 = m_arg1->eval(S); + sort_size s2 = m_arg2->eval(S); + // s1^s2 + if (s1.is_infinite()) return s1; + if (s2.is_infinite()) return s2; + if (s1.is_very_big()) return s1; + if (s2.is_very_big()) return s2; + if (s1.size() == 1) return s1; + if (s2.size() == 1) return s1; + if (s1.size() > (2 << 20) || s2.size() > 10) return sort_size::mk_very_big(); + rational r = ::power(rational(s1.size(), rational::ui64()), static_cast(s2.size())); + return sort_size(r); + } + }; + struct sparam : public size { + sort_ref m_param; + sparam(sort_ref& p): m_param(p) {} + virtual ~sparam() {} + virtual size* subst(obj_map& S) { return S[m_param]; } + virtual sort_size eval(obj_map const& S) { return S[m_param]; } + }; + }; + + class def { + ast_manager& m; + util& m_util; + symbol m_name; + unsigned m_class_id; + param_size::size* m_sort_size; + sort_ref_vector m_params; + mutable sort_ref m_sort; + ptr_vector m_constructors; + public: + def(ast_manager& m, util& u, symbol const& n, unsigned class_id, unsigned num_params, sort * const* params): + m(m), + m_util(u), + m_name(n), + m_class_id(class_id), + m_sort_size(0), + m_params(m, num_params, params), + m_sort(m) + {} + ~def() { + if (m_sort_size) m_sort_size->dec_ref(); + for (constructor* c : m_constructors) dealloc(c); + m_constructors.reset(); + } + void add(constructor* c) { + m_constructors.push_back(c); + c->attach(this); + } + symbol const& name() const { return m_name; } + unsigned id() const { return m_class_id; } + sort_ref instantiate(sort_ref_vector const& ps) const; + ptr_vector const& constructors() const { return m_constructors; } + ptr_vector::const_iterator begin() const { return m_constructors.begin(); } + ptr_vector::const_iterator end() const { return m_constructors.end(); } + ptr_vector::iterator begin() { return m_constructors.begin(); } + ptr_vector::iterator end() { return m_constructors.end(); } + sort_ref_vector const& params() const { return m_params; } + util& u() const { return m_util; } + param_size::size* sort_size() { return m_sort_size; } + void set_sort_size(param_size::size* p) { m_sort_size = p; p->inc_ref(); m_sort = 0; } + def* translate(ast_translation& tr, util& u); + }; + + namespace decl { + + class plugin : public decl_plugin { + mutable scoped_ptr m_util; + map m_defs; + svector m_def_block; + unsigned m_class_id; + util & u() const; + + virtual void inherit(decl_plugin* other_p, ast_translation& tr); + + public: + plugin(): m_class_id(0) {} + virtual ~plugin(); + + virtual void finalize(); + + virtual decl_plugin * mk_fresh() { return alloc(plugin); } + + virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + + virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + virtual expr * get_some_value(sort * s); + + virtual bool is_fully_interp(sort * s) const; + + virtual bool is_value(app* e) const; + + virtual bool is_unique_value(app * e) const { return is_value(e); } + + virtual void get_op_names(svector & op_names, symbol const & logic); + + void begin_def_block() { m_class_id++; m_def_block.reset(); } + + void end_def_block(); + + def* mk(symbol const& name, unsigned n, sort * const * params); + + void remove(symbol const& d); + + bool mk_datatypes(unsigned num_datatypes, def * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts); + + def const& get_def(sort* s) const { return *(m_defs[datatype_name(s)]); } + def& get_def(symbol const& s) { return *(m_defs[s]); } + bool is_declared(sort* s) const { return m_defs.contains(datatype_name(s)); } + private: + bool is_value_visit(expr * arg, ptr_buffer & todo) const; + + func_decl * mk_update_field( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + func_decl * mk_constructor( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + func_decl * mk_accessor( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + func_decl * mk_recognizer( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + func_decl * mk_is( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + symbol datatype_name(sort * s) const { + //SASSERT(u().is_datatype(s)); + return s->get_parameter(0).get_symbol(); + } + + }; + } + + class util { + ast_manager & m; + family_id m_family_id; + mutable decl::plugin* m_plugin; + + + obj_map *> m_datatype2constructors; + obj_map m_datatype2nonrec_constructor; + obj_map *> m_constructor2accessors; + obj_map m_constructor2recognizer; + obj_map m_recognizer2constructor; + obj_map m_accessor2constructor; + obj_map m_is_recursive; + obj_map m_is_enum; + mutable obj_map m_is_fully_interp; + mutable ast_ref_vector m_asts; + ptr_vector > m_vectors; + unsigned m_start; + mutable ptr_vector m_fully_interp_trail; + + func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector & forbidden_set); + + friend class decl::plugin; + + bool is_recursive_core(sort * s) const; + sort_size get_datatype_size(sort* s0); + void compute_datatype_size_functions(svector const& names); + param_size::size* get_sort_size(sort_ref_vector const& params, sort* s); + bool is_well_founded(unsigned num_types, sort* const* sorts); + def& get_def(symbol const& s) { return m_plugin->get_def(s); } + void get_subsorts(sort* s, ptr_vector& sorts) const; + + public: + util(ast_manager & m); + ~util(); + ast_manager & get_manager() const { return m; } + // sort * mk_datatype_sort(symbol const& name, unsigned n, sort* const* params); + bool is_datatype(sort const* s) const { return is_sort_of(s, m_family_id, DATATYPE_SORT); } + bool is_enum_sort(sort* s); + bool is_recursive(sort * ty); + bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); } + bool is_recognizer(func_decl * f) const { return is_recognizer0(f) || is_is(f); } + bool is_recognizer0(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); } + bool is_is(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_IS); } + bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); } + bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); } + bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); } + bool is_recognizer0(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER);} + bool is_is(app * f) const { return is_app_of(f, m_family_id, OP_DT_IS);} + bool is_recognizer(app * f) const { return is_recognizer0(f) || is_is(f); } + bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } + bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } + ptr_vector const * get_datatype_constructors(sort * ty); + unsigned get_datatype_num_constructors(sort * ty); + unsigned get_datatype_num_parameter_sorts(sort * ty); + sort* get_datatype_parameter_sort(sort * ty, unsigned idx); + func_decl * get_non_rec_constructor(sort * ty); + func_decl * get_constructor_recognizer(func_decl * constructor); + ptr_vector const * get_constructor_accessors(func_decl * constructor); + func_decl * get_accessor_constructor(func_decl * accessor); + func_decl * get_recognizer_constructor(func_decl * recognizer) const; + family_id get_family_id() const { return m_family_id; } + bool are_siblings(sort * s1, sort * s2); + bool is_func_decl(op_kind k, unsigned num_params, parameter const* params, func_decl* f); + bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f); + void reset(); + bool is_declared(sort* s) const; + void display_datatype(sort *s, std::ostream& strm); + bool is_fully_interp(sort * s) const; + sort_ref_vector datatype_params(sort * s) const; + unsigned get_constructor_idx(func_decl * f) const; + unsigned get_recognizer_constructor_idx(func_decl * f) const; + decl::plugin* get_plugin() { return m_plugin; } + void get_defs(sort* s, ptr_vector& defs); + def const& get_def(sort* s) const; + }; + +}; + +typedef datatype::accessor accessor_decl; +typedef datatype::constructor constructor_decl; +typedef datatype::def datatype_decl; +typedef datatype::decl::plugin datatype_decl_plugin; +typedef datatype::util datatype_util; - This is a transient value, it is only used to declare a set of - recursive datatypes. -*/ class type_ref { void * m_data; public: @@ -67,181 +408,29 @@ public: int get_idx() const { return UNBOXINT(m_data); } }; -class accessor_decl; -class constructor_decl; -class datatype_decl; -class datatype_util; +inline accessor_decl * mk_accessor_decl(ast_manager& m, symbol const & n, type_ref const & t) { + if (t.is_idx()) { + return alloc(accessor_decl, m, n, t.get_idx()); + } + else { + return alloc(accessor_decl, m, n, t.get_sort()); + } +} + +inline constructor_decl * mk_constructor_decl(symbol const & n, symbol const & r, unsigned num_accessors, accessor_decl * * acs) { + constructor_decl* c = alloc(constructor_decl, n, r); + for (unsigned i = 0; i < num_accessors; ++i) { + c->add(acs[i]); + } + return c; +} + + -accessor_decl * mk_accessor_decl(symbol const & n, type_ref const & t); -void del_accessor_decl(accessor_decl * d); -void del_accessor_decls(unsigned num, accessor_decl * const * as); -// Remark: the constructor becomes the owner of the accessor_decls -constructor_decl * mk_constructor_decl(symbol const & n, symbol const & r, unsigned num_accessors, accessor_decl * const * acs); -void del_constructor_decl(constructor_decl * d); -void del_constructor_decls(unsigned num, constructor_decl * const * cs); // Remark: the datatype becomes the owner of the constructor_decls -datatype_decl * mk_datatype_decl(symbol const & n, unsigned num_constructors, constructor_decl * const * cs); -void del_datatype_decl(datatype_decl * d); -void del_datatype_decls(unsigned num, datatype_decl * const * ds); +datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort*const* params, unsigned num_constructors, constructor_decl * const * cs); +inline void del_datatype_decl(datatype_decl * d) {} +inline void del_datatype_decls(unsigned num, datatype_decl * const * ds) {} -class datatype_decl_plugin : public decl_plugin { - mutable scoped_ptr m_util; - datatype_util & get_util() const; -public: - datatype_decl_plugin() {} - - virtual ~datatype_decl_plugin(); - virtual void finalize(); - - virtual decl_plugin * mk_fresh() { return alloc(datatype_decl_plugin); } - - - /** - Contract for sort: - parameters[0] - (int) n - number of recursive types. - parameters[1] - (int) i - index 0..n-1 of which type is defined. - - parameters[2] - (int) p - number of type parameters. - - for j = 0..p-1 - parameters[3 + j] - (sort) s - type parameter - - c_offset := 3 + p - for j in 0..n-1 - parameters[c_offset + 2*j] - (symbol) name of the type - parameters[c_offset + 2*j + 1] - (int) o - offset where the constructors are defined. - - for each offset o at parameters[2 + 2*j + 1] for some j in 0..n-1 - parameters[o] - (int) m - number of constructors - parameters[o+1] - (int) k_1 - offset for constructor definition - ... - parameters[o+m] - (int) k_m - offset for constructor definition - - for each offset k_i at parameters[o+s] for some s in 0..m-1 - parameters[k_i] - (symbol) name of the constructor - parameters[k_i+1] - (symbol) name of the recognizer - parameters[k_i+2] - (int) m' - number of accessors - parameters[k_i+3+2*r] - (symbol) name of the r accessor - parameters[k_i+3+2*r+1] - (int or type_ast) type of the accessor. If integer, then the value must be in [0..n-1], and it - represents an reference to the recursive type. - - The idea with the additional offsets is that - access to relevant constructors and types can be performed using - a few address calculations. - */ - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); - - /** - Contract for constructors - parameters[0] - (ast) datatype ast. - parmaeters[1] - (int) constructor idx. - Contract for accessors - parameters[0] - (ast) datatype ast. - parameters[1] - (int) constructor idx. - parameters[2] - (int) accessor idx. - Contract for tester - parameters[0] - (ast) datatype ast. - parameters[1] - (int) constructor idx. - */ - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - - bool mk_datatypes(unsigned num_datatypes, datatype_decl * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts); - - virtual expr * get_some_value(sort * s); - - virtual bool is_fully_interp(sort const * s) const; - - virtual bool is_value(app* e) const; - - virtual bool is_unique_value(app * e) const { return is_value(e); } - - virtual void get_op_names(svector & op_names, symbol const & logic); - - static unsigned constructor_offset(sort const* s); - static unsigned constructor_offset(parameter const& p); - static unsigned constructor_offset(parameter const* ps); - - static unsigned constructor_offset(sort const* s, unsigned tid); - static unsigned constructor_offset(parameter const* ps, unsigned tid); - -private: - bool is_value_visit(expr * arg, ptr_buffer & todo) const; - - func_decl * mk_update_field( - unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); -}; - -class datatype_util { - ast_manager & m_manager; - family_id m_family_id; - - func_decl * get_constructor(sort * ty, unsigned c_id) const; - - obj_map *> m_datatype2constructors; - obj_map m_datatype2nonrec_constructor; - obj_map *> m_constructor2accessors; - obj_map m_constructor2recognizer; - obj_map m_recognizer2constructor; - obj_map m_accessor2constructor; - obj_map m_is_recursive; - obj_map m_is_enum; - ast_ref_vector m_asts; - ptr_vector > m_vectors; - unsigned m_start; - - func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector & forbidden_set); - func_decl * get_constructor(sort * ty, unsigned c_id); - -public: - datatype_util(ast_manager & m); - ~datatype_util(); - ast_manager & get_manager() const { return m_manager; } - bool is_datatype(sort * s) const { return is_sort_of(s, m_family_id, DATATYPE_SORT); } - bool is_enum_sort(sort* s); - - bool is_recursive(sort * ty); - bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); } - bool is_recognizer(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); } - bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); } - bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); } - bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); } - bool is_recognizer(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER); } - bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } - bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } - ptr_vector const * get_datatype_constructors(sort * ty); - unsigned get_datatype_num_constructors(sort * ty) { - SASSERT(is_datatype(ty)); - unsigned tid = ty->get_parameter(1).get_int(); - unsigned o = datatype_decl_plugin::constructor_offset(ty, tid); - return ty->get_parameter(o).get_int(); - } - unsigned get_datatype_num_parameter_sorts(sort * ty) { - SASSERT(is_datatype(ty)); - return ty->get_parameter(2).get_int(); - } - sort* get_datatype_parameter_sort(sort * ty, unsigned idx) { - SASSERT(is_datatype(ty)); - SASSERT(idx < get_datatype_num_parameter_sorts(ty)); - return to_sort(ty->get_parameter(3 + idx).get_ast()); - } - unsigned get_constructor_idx(func_decl * f) const { SASSERT(is_constructor(f)); return f->get_parameter(1).get_int(); } - unsigned get_recognizer_constructor_idx(func_decl * f) const { SASSERT(is_recognizer(f)); return f->get_parameter(1).get_int(); } - func_decl * get_non_rec_constructor(sort * ty); - func_decl * get_constructor_recognizer(func_decl * constructor); - ptr_vector const * get_constructor_accessors(func_decl * constructor); - func_decl * get_accessor_constructor(func_decl * accessor); - func_decl * get_recognizer_constructor(func_decl * recognizer); - family_id get_family_id() const { return m_family_id; } - bool are_siblings(sort * s1, sort * s2); - bool is_func_decl(datatype_op_kind k, unsigned num_params, parameter const* params, func_decl* f); - bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f); - void reset(); - void display_datatype(sort *s, std::ostream& strm); - - -}; #endif /* DATATYPE_DECL_PLUGIN_H_ */ - diff --git a/src/ast/decl_collector.cpp b/src/ast/decl_collector.cpp index 773ebefc7..e000f43df 100644 --- a/src/ast/decl_collector.cpp +++ b/src/ast/decl_collector.cpp @@ -17,7 +17,7 @@ Author: Revision History: --*/ -#include"decl_collector.h" +#include "ast/decl_collector.h" void decl_collector::visit_sort(sort * n) { family_id fid = n->get_family_id(); diff --git a/src/ast/decl_collector.h b/src/ast/decl_collector.h index 0067d18eb..053d6df41 100644 --- a/src/ast/decl_collector.h +++ b/src/ast/decl_collector.h @@ -20,8 +20,8 @@ Revision History: #ifndef SMT_DECL_COLLECTOR_H_ #define SMT_DECL_COLLECTOR_H_ -#include"ast.h" -#include"datatype_decl_plugin.h" +#include "ast/ast.h" +#include "ast/datatype_decl_plugin.h" class decl_collector { ast_manager & m_manager; diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index f7d6d9d1c..1be3c4756 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -18,12 +18,12 @@ Revision History: --*/ #include -#include "ast_pp.h" -#include "array_decl_plugin.h" -#include "datatype_decl_plugin.h" -#include "dl_decl_plugin.h" -#include "warning.h" -#include "reg_decl_plugins.h" +#include "ast/ast_pp.h" +#include "ast/array_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/dl_decl_plugin.h" +#include "util/warning.h" +#include "ast/reg_decl_plugins.h" namespace datalog { diff --git a/src/ast/dl_decl_plugin.h b/src/ast/dl_decl_plugin.h index 66ce45c3c..75969d385 100644 --- a/src/ast/dl_decl_plugin.h +++ b/src/ast/dl_decl_plugin.h @@ -19,9 +19,9 @@ Revision History: #ifndef DL_DECL_PLUGIN_H_ #define DL_DECL_PLUGIN_H_ -#include"ast.h" -#include "arith_decl_plugin.h" -#include "bv_decl_plugin.h" +#include "ast/ast.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" namespace datalog { diff --git a/src/ast/expr2polynomial.cpp b/src/ast/expr2polynomial.cpp index a06ce7e2a..7413624cd 100644 --- a/src/ast/expr2polynomial.cpp +++ b/src/ast/expr2polynomial.cpp @@ -17,13 +17,13 @@ Author: Notes: --*/ -#include"expr2polynomial.h" -#include"expr2var.h" -#include"arith_decl_plugin.h" -#include"ast_smt2_pp.h" -#include"z3_exception.h" -#include"cooperate.h" -#include"common_msgs.h" +#include "ast/expr2polynomial.h" +#include "ast/expr2var.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_smt2_pp.h" +#include "util/z3_exception.h" +#include "util/cooperate.h" +#include "util/common_msgs.h" struct expr2polynomial::imp { struct frame { diff --git a/src/ast/expr2polynomial.h b/src/ast/expr2polynomial.h index 6b2fd6116..e7cbac6e5 100644 --- a/src/ast/expr2polynomial.h +++ b/src/ast/expr2polynomial.h @@ -20,8 +20,8 @@ Notes: #ifndef EXPR2POLYNOMIAL_H_ #define EXPR2POLYNOMIAL_H_ -#include"ast.h" -#include"polynomial.h" +#include "ast/ast.h" +#include "math/polynomial/polynomial.h" class expr2var; diff --git a/src/ast/expr2var.cpp b/src/ast/expr2var.cpp index a0d93a620..2f850d645 100644 --- a/src/ast/expr2var.cpp +++ b/src/ast/expr2var.cpp @@ -20,9 +20,9 @@ Author: Notes: --*/ -#include"expr2var.h" -#include"ast_smt2_pp.h" -#include"ref_util.h" +#include "ast/expr2var.h" +#include "ast/ast_smt2_pp.h" +#include "util/ref_util.h" void expr2var::insert(expr * n, var v) { if (!is_uninterp_const(n)) { diff --git a/src/ast/expr2var.h b/src/ast/expr2var.h index 43d9c31f4..2b4d8c3fe 100644 --- a/src/ast/expr2var.h +++ b/src/ast/expr2var.h @@ -23,8 +23,8 @@ Notes: #ifndef EXPR2VAR_H_ #define EXPR2VAR_H_ -#include"ast.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" /** \brief The mapping between Z3 expressions and (low level) variables. diff --git a/src/ast/expr_abstract.cpp b/src/ast/expr_abstract.cpp index 513162043..43035e203 100644 --- a/src/ast/expr_abstract.cpp +++ b/src/ast/expr_abstract.cpp @@ -17,8 +17,9 @@ Notes: --*/ -#include "expr_abstract.h" -#include "map.h" +#include "ast/expr_abstract.h" +#include "util/map.h" +#include "ast/ast_pp.h" void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) { @@ -109,6 +110,9 @@ void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) { expr_abstractor abs(m); abs(base, num_bound, bound, n, result); + TRACE("expr_abstract", + tout << expr_ref(n, m) << "\n"; + tout << result << "\n";); } expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) { @@ -123,6 +127,11 @@ expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* } result = m.mk_quantifier(is_forall, num_bound, sorts.c_ptr(), names.c_ptr(), result); } + TRACE("expr_abstract", + tout << expr_ref(n, m) << "\n"; + for (unsigned i = 0; i < num_bound; ++i) tout << expr_ref(bound[i], m) << " "; + tout << "\n"; + tout << result << "\n";); return result; } diff --git a/src/ast/expr_abstract.h b/src/ast/expr_abstract.h index 5c91a914e..84fb8c2b0 100644 --- a/src/ast/expr_abstract.h +++ b/src/ast/expr_abstract.h @@ -19,7 +19,7 @@ Notes: #ifndef EXPR_ABSTRACT_H_ #define EXPR_ABSTRACT_H_ -#include"ast.h" +#include "ast/ast.h" class expr_abstractor { ast_manager& m; diff --git a/src/ast/expr_functors.cpp b/src/ast/expr_functors.cpp index 592d96a68..4906ed3d7 100644 --- a/src/ast/expr_functors.cpp +++ b/src/ast/expr_functors.cpp @@ -19,7 +19,7 @@ Revision History: --*/ -#include "expr_functors.h" +#include "ast/expr_functors.h" // ---------- // check_pred diff --git a/src/ast/expr_functors.h b/src/ast/expr_functors.h index da2b43dea..322b9402a 100644 --- a/src/ast/expr_functors.h +++ b/src/ast/expr_functors.h @@ -22,8 +22,8 @@ Revision History: #ifndef EXPR_FUNCTORS_H_ #define EXPR_FUNCTORS_H_ -#include "ast.h" -#include "expr_map.h" +#include "ast/ast.h" +#include "ast/expr_map.h" class i_expr_pred { public: diff --git a/src/ast/expr_map.cpp b/src/ast/expr_map.cpp index 87db2186b..89fcccb00 100644 --- a/src/ast/expr_map.cpp +++ b/src/ast/expr_map.cpp @@ -18,8 +18,8 @@ Author: Notes: --*/ -#include"expr_map.h" -#include"dec_ref_util.h" +#include "ast/expr_map.h" +#include "util/dec_ref_util.h" expr_map::expr_map(ast_manager & m): m_manager(m), diff --git a/src/ast/expr_map.h b/src/ast/expr_map.h index 2b49a4a30..b32d52092 100644 --- a/src/ast/expr_map.h +++ b/src/ast/expr_map.h @@ -21,8 +21,8 @@ Notes: #ifndef EXPR_MAP_H_ #define EXPR_MAP_H_ -#include"ast.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" /** \brief Map from expressions to expressions+proofs. diff --git a/src/ast/expr_stat.cpp b/src/ast/expr_stat.cpp index 8ac259afa..689edc263 100644 --- a/src/ast/expr_stat.cpp +++ b/src/ast/expr_stat.cpp @@ -19,8 +19,8 @@ Author: Revision History: --*/ -#include"for_each_expr.h" -#include"expr_stat.h" +#include "ast/for_each_expr.h" +#include "ast/expr_stat.h" void get_expr_stat(expr * n, expr_stat & r) { typedef std::pair pair; diff --git a/src/ast/expr_substitution.cpp b/src/ast/expr_substitution.cpp index 8d6f0319c..f9333c443 100644 --- a/src/ast/expr_substitution.cpp +++ b/src/ast/expr_substitution.cpp @@ -16,8 +16,9 @@ Author: Notes: --*/ -#include"expr_substitution.h" -#include"ref_util.h" +#include "util/ref_util.h" +#include "ast/expr_substitution.h" +#include "ast/ast_pp.h" typedef obj_map expr2proof; typedef obj_map expr2expr_dependency; @@ -56,6 +57,13 @@ expr_substitution::~expr_substitution() { reset(); } +std::ostream& expr_substitution::display(std::ostream& out) { + for (auto & kv : m_subst) { + out << mk_pp(kv.m_key, m()) << " |-> " << mk_pp(kv.m_value, m()) << "\n"; + } + return out; +} + void expr_substitution::insert(expr * c, expr * def, proof * def_pr, expr_dependency * def_dep) { obj_map::obj_map_entry * entry = m_subst.insert_if_not_there2(c, 0); if (entry->get_data().m_value == 0) { diff --git a/src/ast/expr_substitution.h b/src/ast/expr_substitution.h index 073b56110..1590f888c 100644 --- a/src/ast/expr_substitution.h +++ b/src/ast/expr_substitution.h @@ -19,7 +19,7 @@ Notes: #ifndef EXPR_SUBSTITUTION_H_ #define EXPR_SUBSTITUTION_H_ -#include"ast.h" +#include "ast/ast.h" class expr_substitution { ast_manager & m_manager; @@ -50,6 +50,44 @@ public: bool contains(expr * s); void reset(); void cleanup(); + + std::ostream& display(std::ostream& out); +}; + +class scoped_expr_substitution { + expr_substitution& m_subst; + expr_ref_vector m_trail; + unsigned_vector m_trail_lim; +public: + + scoped_expr_substitution(expr_substitution& s): m_subst(s), m_trail(s.m()) {} + ~scoped_expr_substitution() {} + + void insert(expr * s, expr * def, proof * def_pr = 0, expr_dependency * def_dep = 0) { + if (!m_subst.contains(s)) { + m_subst.insert(s, def, def_pr, def_dep); + m_trail.push_back(s); + } + } + void reset() { m_subst.reset(); m_trail.reset(); m_trail_lim.reset(); } + void push() { m_trail_lim.push_back(m_trail.size()); } + void pop(unsigned n) { + if (n > 0) { + unsigned new_sz = m_trail_lim.size() - n; + unsigned old_sz = m_trail_lim[new_sz]; + for (unsigned i = old_sz; i < m_trail.size(); ++i) m_subst.erase(m_trail[i].get()); + m_trail.resize(old_sz); + m_trail_lim.resize(new_sz); + } + } + unsigned scope_level() const { return m_trail_lim.size(); } + bool empty() const { return m_subst.empty(); } + expr* find(expr * e) { proof* pr; expr* d = 0; if (find(e, d, pr)) return d; else return e; } + bool find(expr * s, expr * & def, proof * & def_pr) { return m_subst.find(s, def, def_pr); } + bool find(expr * s, expr * & def, proof * & def_pr, expr_dependency * & def_dep) { return m_subst.find(s, def, def_pr, def_dep); } + bool contains(expr * s) { return m_subst.contains(s); } + void cleanup() { m_subst.cleanup(); } + std::ostream& display(std::ostream& out) { return m_subst.display(out); } }; #endif diff --git a/src/ast/factor_equivs.cpp b/src/ast/factor_equivs.cpp new file mode 100644 index 000000000..bbb21c1b2 --- /dev/null +++ b/src/ast/factor_equivs.cpp @@ -0,0 +1,109 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + factor_equivs.cpp + +Abstract: + Factor equivalence classes out of an expression. + + "Equivalence class structure" for objs. Uses a union_find structure internally. + Operations are : + -Declare a new equivalence class with a single element + -Merge two equivalence classes + -Retrieve whether two elements are in the same equivalence class + -Iterate on all the elements of the equivalence class of a given element + -Iterate on all equivalence classes (and then within them) + +Author: + + Julien Braine + Arie Gurfinkel + +Revision History: + +*/ + +#include "ast/factor_equivs.h" +#include "ast/arith_decl_plugin.h" + +/** + Factors input vector v into equivalence classes and the rest + */ +void factor_eqs(expr_ref_vector &v, expr_equiv_class &equiv) { + ast_manager &m = v.get_manager(); + arith_util arith(m); + expr *e1 = 0, *e2 = 0; + + flatten_and(v); + unsigned j = 0; + for (unsigned i = 0; i < v.size(); ++i) { + if (m.is_eq(v.get(i), e1, e2)) { + if (arith.is_zero(e1)) { + std::swap(e1, e2); + } + + // y + -1*x == 0 + expr* a0 = 0, *a1 = 0, *x = 0; + if (arith.is_zero(e2) && arith.is_add(e1, a0, a1)) { + if (arith.is_times_minus_one(a1, x)) { + e1 = a0; + e2 = x; + } + else if (arith.is_times_minus_one(a0, x)) { + e1 = a1; + e2 = x; + } + } + equiv.merge(e1, e2); + } + else { + if (j < i) { + v[j] = v.get(i); + } + j++; + } + } + v.shrink(j); +} + +/** + * converts equivalence classes to equalities + */ +void equiv_to_expr(expr_equiv_class &equiv, expr_ref_vector &out) { + ast_manager &m = out.get_manager(); + for (auto eq_class : equiv) { + expr *rep = nullptr; + for (expr *elem : eq_class) { + if (!m.is_value(elem)) { + rep = elem; + break; + } + } + SASSERT(rep); + for (expr *elem : eq_class) { + if (rep != elem) { + out.push_back (m.mk_eq (rep, elem)); + } + } + } +} + +/** + * expands equivalence classes to all derivable equalities + */ +bool equiv_to_expr_full(expr_equiv_class &equiv, expr_ref_vector &out) { + ast_manager &m = out.get_manager(); + bool dirty = false; + for (auto eq_class : equiv) { + for (auto a = eq_class.begin(), end = eq_class.end(); a != end; ++a) { + expr_equiv_class::iterator b(a); + for (++b; b != end; ++b) { + out.push_back(m.mk_eq(*a, *b)); + dirty = true; + } + } + } + return dirty; +} diff --git a/src/ast/factor_equivs.h b/src/ast/factor_equivs.h new file mode 100644 index 000000000..f0ce1608d --- /dev/null +++ b/src/ast/factor_equivs.h @@ -0,0 +1,183 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + factor_equivs.h + +Abstract: + Factor equivalence classes out of an expression. + + "Equivalence class structure" for objs. Uses a union_find structure internally. + Operations are : + -Declare a new equivalence class with a single element + -Merge two equivalence classes + -Retrieve whether two elements are in the same equivalence class + -Iterate on all the elements of the equivalence class of a given element + -Iterate on all equivalence classes (and then within them) + +Author: + + Julien Braine + Arie Gurfinkel + +Revision History: + +*/ + +#ifndef FACTOR_EQUIVS_H_ +#define FACTOR_EQUIVS_H_ + +#include "util/union_find.h" +#include "ast/ast_util.h" + +///All functions naturally add their parameters to the union_find class +template +class obj_equiv_class { + basic_union_find m_uf; + obj_map m_to_int; + ref_vector m_to_obj; + + unsigned add_elem_impl(OBJ*o) { + unsigned id = m_to_obj.size(); + m_to_int.insert(o, id); + m_to_obj.push_back(o); + return id; + } + unsigned add_if_not_there(OBJ*o) { + unsigned id; + if(!m_to_int.find(o, id)) { + id = add_elem_impl(o); + } + return id; + } + +public: + class iterator; + class equiv_iterator; + friend class iterator; + friend class equiv_iterator; + + obj_equiv_class(Manager& m) : m_to_obj(m) {} + + void add_elem(OBJ*o) { + SASSERT(!m_to_int.find(o)); + add_elem_impl(o); + } + + //Invalidates all iterators + void merge(OBJ* a, OBJ* b) { + unsigned v1 = add_if_not_there(a); + unsigned v2 = add_if_not_there(b); + unsigned tmp1 = m_uf.find(v1); + unsigned tmp2 = m_uf.find(v2); + m_uf.merge(tmp1, tmp2); + } + + void reset() { + m_uf.reset(); + m_to_int.reset(); + m_to_obj.reset(); + } + + bool are_equiv(OBJ*a, OBJ*b) { + unsigned id1 = add_if_not_there(a); + unsigned id2 = add_if_not_there(b); + return m_uf.find(id1) == m_uf.find(id2); + } + + class iterator { + friend class obj_equiv_class; + private : + const obj_equiv_class& m_ouf; + unsigned m_curr_id; + bool m_first; + iterator(const obj_equiv_class& uf, unsigned id, bool f) : + m_ouf(uf), m_curr_id(id), m_first(f) {} + public : + OBJ*operator*() {return m_ouf.m_to_obj[m_curr_id];} + + iterator& operator++() { + m_curr_id = m_ouf.m_uf.next(m_curr_id); + m_first = false; + return *this; + } + bool operator==(const iterator& o) { + SASSERT(&m_ouf == &o.m_ouf); + return m_first == o.m_first && m_curr_id == o.m_curr_id; + } + bool operator!=(const iterator& o) {return !(*this == o);} + }; + + iterator begin(OBJ*o) { + unsigned id = add_if_not_there(o); + return iterator(*this, id, true); + } + iterator end(OBJ*o) { + unsigned id = add_if_not_there(o); + return iterator(*this, id, false); + } + + class eq_class { + private : + iterator m_begin; + iterator m_end; + public : + eq_class(const iterator& a, const iterator& b) : m_begin(a), m_end(b) {} + iterator begin() {return m_begin;} + iterator end() {return m_end;} + }; + + class equiv_iterator { + friend class obj_equiv_class; + private : + const obj_equiv_class& m_ouf; + unsigned m_rootnb; + equiv_iterator(const obj_equiv_class& uf, unsigned nb) : + m_ouf(uf), m_rootnb(nb) { + while(m_rootnb != m_ouf.m_to_obj.size() && + m_ouf.m_uf.is_root(m_rootnb) != true) + { m_rootnb++; } + } + public : + eq_class operator*() { + return eq_class(iterator(m_ouf, m_rootnb, true), + iterator(m_ouf, m_rootnb, false)); + } + equiv_iterator& operator++() { + do { + m_rootnb++; + } while(m_rootnb != m_ouf.m_to_obj.size() && + m_ouf.m_uf.is_root(m_rootnb) != true); + return *this; + } + bool operator==(const equiv_iterator& o) { + SASSERT(&m_ouf == &o.m_ouf); + return m_rootnb == o.m_rootnb; + } + bool operator!=(const equiv_iterator& o) {return !(*this == o);} + }; + + equiv_iterator begin() {return equiv_iterator(*this, 0);} + equiv_iterator end() {return equiv_iterator(*this, m_to_obj.size());} +}; + +typedef obj_equiv_class expr_equiv_class; + + +/** + * Factors input vector v into equivalence classes and the rest + */ +void factor_eqs(expr_ref_vector &v, expr_equiv_class &equiv); +/** + * converts equivalence classes to equalities + */ +void equiv_to_expr(expr_equiv_class &equiv, expr_ref_vector &out); + +/** + * expands equivalence classes to all derivable equalities + */ +bool equiv_to_expr_full(expr_equiv_class &equiv, expr_ref_vector &out); + + +#endif diff --git a/src/ast/for_each_ast.cpp b/src/ast/for_each_ast.cpp index f5b8218ae..77e975b98 100644 --- a/src/ast/for_each_ast.cpp +++ b/src/ast/for_each_ast.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"for_each_ast.h" +#include "ast/for_each_ast.h" struct ast_counter_proc { unsigned m_num; diff --git a/src/ast/for_each_ast.h b/src/ast/for_each_ast.h index a254ed058..0b70eb1a1 100644 --- a/src/ast/for_each_ast.h +++ b/src/ast/for_each_ast.h @@ -19,9 +19,9 @@ Revision History: #ifndef FOR_EACH_AST_H_ #define FOR_EACH_AST_H_ -#include"ast.h" -#include"trace.h" -#include"map.h" +#include "ast/ast.h" +#include "util/trace.h" +#include "util/map.h" template bool for_each_ast_args(ptr_vector & stack, ast_mark & visited, unsigned num_args, T * const * args) { diff --git a/src/ast/for_each_expr.cpp b/src/ast/for_each_expr.cpp index cca42b01c..d46388801 100644 --- a/src/ast/for_each_expr.cpp +++ b/src/ast/for_each_expr.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"for_each_expr.h" +#include "ast/for_each_expr.h" struct expr_counter_proc { unsigned m_num; diff --git a/src/ast/for_each_expr.h b/src/ast/for_each_expr.h index 3f5dbaac7..50a4089dc 100644 --- a/src/ast/for_each_expr.h +++ b/src/ast/for_each_expr.h @@ -19,8 +19,8 @@ Revision History: #ifndef FOR_EACH_EXPR_H_ #define FOR_EACH_EXPR_H_ -#include"ast.h" -#include"trace.h" +#include "ast/ast.h" +#include "util/trace.h" template void for_each_expr_core(ForEachProc & proc, ExprMark & visited, expr * n) { diff --git a/src/ast/format.cpp b/src/ast/format.cpp index 1a36ca8ae..835892121 100644 --- a/src/ast/format.cpp +++ b/src/ast/format.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"format.h" -#include"recurse_expr_def.h" +#include "ast/format.h" +#include "ast/recurse_expr_def.h" namespace format_ns { diff --git a/src/ast/format.h b/src/ast/format.h index a41ed9bd9..827f9bc1c 100644 --- a/src/ast/format.h +++ b/src/ast/format.h @@ -19,7 +19,7 @@ Revision History: #ifndef FORMAT_H_ #define FORMAT_H_ -#include"ast.h" +#include "ast/ast.h" namespace format_ns { typedef app format; diff --git a/src/ast/fpa/CMakeLists.txt b/src/ast/fpa/CMakeLists.txt index 4a9506d16..2a6d0763c 100644 --- a/src/ast/fpa/CMakeLists.txt +++ b/src/ast/fpa/CMakeLists.txt @@ -5,7 +5,7 @@ z3_add_component(fpa fpa2bv_rewriter.cpp COMPONENT_DEPENDENCIES ast - simplifier + rewriter model util PYG_FILES diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index c113627f9..2f5a7c3c1 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -18,12 +18,12 @@ Notes: --*/ #include -#include"ast_smt2_pp.h" -#include"well_sorted.h" -#include"th_rewriter.h" -#include"fpa_rewriter.h" +#include "ast/ast_smt2_pp.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/fpa_rewriter.h" -#include"bv2fpa_converter.h" +#include "ast/fpa/bv2fpa_converter.h" bv2fpa_converter::bv2fpa_converter(ast_manager & m) : @@ -62,8 +62,8 @@ bv2fpa_converter::bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv) : m.inc_ref(it->m_key); m.inc_ref(it->m_value); } - for (obj_map >::iterator it = conv.m_min_max_specials.begin(); - it != conv.m_min_max_specials.end(); + for (obj_map >::iterator it = conv.m_min_max_ufs.begin(); + it != conv.m_min_max_ufs.end(); it++) { m_specials.insert(it->m_key, it->m_value); m.inc_ref(it->m_key); @@ -120,9 +120,9 @@ expr_ref bv2fpa_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, expr res = m_fpa_util.mk_value(fp_val); TRACE("bv2fpa", tout << "[" << mk_ismt2_pp(sgn, m) << - " " << mk_ismt2_pp(exp, m) << - " " << mk_ismt2_pp(sig, m) << "] == " << - mk_ismt2_pp(res, m) << std::endl;); + " " << mk_ismt2_pp(exp, m) << + " " << mk_ismt2_pp(sig, m) << "] == " << + mk_ismt2_pp(res, m) << std::endl;); m_fpa_util.fm().del(fp_val); return res; @@ -250,7 +250,7 @@ bv2fpa_converter::array_model bv2fpa_converter::convert_array_func_interp(model_ am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng); am.new_float_fi = convert_func_interp(mc, am.new_float_fd, bv_f); am.bv_fd = bv_f; - am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd); + am.result = arr_util.mk_as_array(am.new_float_fd); return am; } @@ -263,7 +263,7 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * unsigned arity = bv_f->get_arity(); func_interp * bv_fi = mc->get_func_interp(bv_f); - if (bv_fi != 0) { + if (bv_fi) { fpa_rewriter rw(m); expr_ref ai(m); result = alloc(func_interp, m, arity); @@ -285,15 +285,31 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * bv_fres = bv_fe->get_result(); ft_fres = rebuild_floats(mc, rng, to_app(bv_fres)); m_th_rw(ft_fres); - result->insert_new_entry(new_args.c_ptr(), ft_fres); + TRACE("bv2fpa", + for (unsigned i = 0; i < new_args.size(); i++) + tout << mk_ismt2_pp(bv_args[i], m) << " == " << + mk_ismt2_pp(new_args[i], m) << std::endl; + tout << mk_ismt2_pp(bv_fres, m) << " == " << mk_ismt2_pp(ft_fres, m) << std::endl;); + func_entry * fe = result->get_entry(new_args.c_ptr()); + if (fe == 0) + result->insert_new_entry(new_args.c_ptr(), ft_fres); + else { + // The BV model may have multiple equivalent entries using different + // representations of NaN. We can only keep one and we check that + // the results for all those entries are the same. + if (ft_fres != fe->get_result()) + throw default_exception("BUG: UF function entries disagree with each other"); + } } app_ref bv_els(m); expr_ref ft_els(m); bv_els = (app*)bv_fi->get_else(); - ft_els = rebuild_floats(mc, rng, bv_els); - m_th_rw(ft_els); - result->set_else(ft_els); + if (bv_els != 0) { + ft_els = rebuild_floats(mc, rng, bv_els); + m_th_rw(ft_els); + result->set_else(ft_els); + } } return result; @@ -382,7 +398,7 @@ void bv2fpa_converter::convert_rm_consts(model_core * mc, model_core * target_mo expr * bvval = to_app(val)->get_arg(0); expr_ref fv(m); fv = convert_bv2rm(mc, to_app(bvval)); - TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << ")" << std::endl;); + TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << std::endl;); target_model->register_decl(var, fv); seen.insert(to_app(bvval)->get_decl()); } @@ -447,14 +463,34 @@ void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_mode } } else { - func_interp * fmv = convert_func_interp(mc, f, it->m_value); - if (fmv) target_model->register_decl(f, fmv); + if (it->get_key().get_family_id() == m_fpa_util.get_fid()) { + // it->m_value contains the model for the unspecified cases of it->m_key. + + func_interp * fmv = convert_func_interp(mc, f, it->m_value); + if (fmv) { +#if 0 + // Upon request, add this 'recursive' definition? + unsigned n = fmv->get_arity(); + expr_ref_vector args(m); + for (unsigned i = 0; i < n; i++) + args.push_back(m.mk_var(i, f->get_domain()[i])); + fmv->set_else(m.mk_app(it->m_key, n, args.c_ptr())); +#else + + fmv->set_else(0); +#endif + target_model->register_decl(f, fmv); + } + } + else { + func_interp * fmv = convert_func_interp(mc, f, it->m_value); + if (fmv) target_model->register_decl(f, fmv); + } } } } void bv2fpa_converter::display(std::ostream & out) { - out << "(fpa2bv-model-converter"; for (obj_map::iterator it = m_const2bv.begin(); it != m_const2bv.end(); it++) { @@ -488,7 +524,6 @@ void bv2fpa_converter::display(std::ostream & out) { out << mk_ismt2_pp(it->m_value.first, m, indent) << "; " << mk_ismt2_pp(it->m_value.second, m, indent) << ")"; } - out << ")"; } bv2fpa_converter * bv2fpa_converter::translate(ast_translation & translator) { @@ -536,23 +571,3 @@ bv2fpa_converter * bv2fpa_converter::translate(ast_translation & translator) { return res; } -void bv2fpa_converter::convert(model_core * mc, model_core * float_mdl) { - TRACE("bv2fpa", tout << "BV Model: " << std::endl; - for (unsigned i = 0; i < mc->get_num_constants(); i++) - tout << mc->get_constant(i)->get_name() << " --> " << - mk_ismt2_pp(mc->get_const_interp(mc->get_constant(i)), m) << std::endl; - for (unsigned i = 0; i < mc->get_num_functions(); i++) { - func_decl * f = mc->get_function(i); - tout << f->get_name() << "(...) := " << std::endl; - func_interp * fi = mc->get_func_interp(f); - for (unsigned j = 0; j < fi->num_entries(); j++) { - func_entry const * fe = fi->get_entry(j); - for (unsigned k = 0; k < f->get_arity(); k++) { - tout << mk_ismt2_pp(fe->get_arg(k), m) << " "; - } - tout << "--> " << mk_ismt2_pp(fe->get_result(), m) << std::endl; - } - tout << "else " << mk_ismt2_pp(fi->get_else(), m) << std::endl; - }); - -} diff --git a/src/ast/fpa/bv2fpa_converter.h b/src/ast/fpa/bv2fpa_converter.h index 5150056c4..caf36c1fc 100644 --- a/src/ast/fpa/bv2fpa_converter.h +++ b/src/ast/fpa/bv2fpa_converter.h @@ -19,11 +19,11 @@ Notes: #ifndef BV2FPA_CONVERTER_H_ #define BV2FPA_CONVERTER_H_ -#include"fpa_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"th_rewriter.h" -#include"model_core.h" -#include"fpa2bv_converter.h" +#include "ast/fpa_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/th_rewriter.h" +#include "model/model_core.h" +#include "ast/fpa/fpa2bv_converter.h" class bv2fpa_converter { @@ -50,7 +50,6 @@ public: expr_ref convert_bv2rm(expr * eval_v); expr_ref convert_bv2rm(model_core * mc, app * val); - void convert(model_core * mc, model_core * float_mdl); void convert_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); void convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); void convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable & seen); diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 99b8c5ac8..220295dad 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -18,12 +18,12 @@ Notes: --*/ #include -#include"ast_smt2_pp.h" -#include"well_sorted.h" -#include"th_rewriter.h" +#include "ast/ast_smt2_pp.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/th_rewriter.h" -#include"fpa2bv_converter.h" -#include"fpa_rewriter.h" +#include "ast/fpa/fpa2bv_converter.h" +#include "ast/rewriter/fpa_rewriter.h" #define BVULT(X,Y,R) { expr_ref bvult_eq(m), bvult_not(m); m_simp.mk_eq(X, Y, bvult_eq); m_simp.mk_not(bvult_eq, bvult_not); expr_ref t(m); t = m_bv_util.mk_ule(X,Y); m_simp.mk_and(t, bvult_not, R); } @@ -230,39 +230,7 @@ void fpa2bv_converter::mk_var(unsigned base_inx, sort * srt, expr_ref & result) result = m_util.mk_fp(sgn, e, s); } -void fpa2bv_converter::mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result) { - if (m_util.is_float(rng)) { - unsigned ebits = m_util.get_ebits(rng); - unsigned sbits = m_util.get_sbits(rng); - unsigned bv_sz = ebits + sbits; - - app_ref na(m); - na = m.mk_app(fbv, fbv->get_arity(), new_args); - result = m_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, na), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, na), - m_bv_util.mk_extract(sbits - 2, 0, na)); - } - else if (m_util.is_rm(rng)) { - app_ref na(m); - na = m.mk_app(fbv, fbv->get_arity(), new_args); - result = m_util.mk_bv2rm(na); - } - else - result = m.mk_app(fbv, fbv->get_arity(), new_args); -} - -func_decl * fpa2bv_converter::get_bv_uf(func_decl * f, sort * bv_rng, unsigned arity) { - func_decl * res; - if (!m_uf2bvuf.find(f, res)) { - res = m.mk_fresh_func_decl(f->get_name(), symbol("bv"), arity, f->get_domain(), bv_rng); - m_uf2bvuf.insert(f, res); - m.inc_ref(f); - m.inc_ref(res); - TRACE("fpa2bv", tout << "New UF func_decl: " << std::endl << mk_ismt2_pp(res, m) << std::endl;); - } - return res; -} -void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) +void fpa2bv_converter::mk_uf(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { TRACE("fpa2bv", tout << "UF: " << mk_ismt2_pp(f, m) << std::endl; ); @@ -278,7 +246,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a unsigned sbits = m_util.get_sbits(rng); unsigned bv_sz = ebits+sbits; bv_rng = m_bv_util.mk_sort(bv_sz); - func_decl * bv_f = get_bv_uf(f, bv_rng, num); + func_decl * bv_f = mk_bv_uf(f, f->get_domain(), bv_rng); bv_app = m.mk_app(bv_f, num, args); flt_app = m_util.mk_fp(m_bv_util.mk_extract(bv_sz-1, bv_sz-1, bv_app), m_bv_util.mk_extract(sbits+ebits-2, sbits-1, bv_app), @@ -291,7 +259,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a sort_ref bv_rng(m); expr_ref new_eq(m); bv_rng = m_bv_util.mk_sort(3); - func_decl * bv_f = get_bv_uf(f, bv_rng, num); + func_decl * bv_f = mk_bv_uf(f, f->get_domain(), bv_rng); bv_app = m.mk_app(bv_f, num, args); flt_app = m_util.mk_bv2rm(bv_app); new_eq = m.mk_eq(fapp, flt_app); @@ -1211,61 +1179,85 @@ void fpa2bv_converter::mk_abs(sort * s, expr_ref & x, expr_ref & result) { } void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - expr_ref x(m), y(m); - x = args[0]; - y = args[1]; - - expr_ref x_is_zero(m), y_is_zero(m), both_are_zero(m); - x_is_zero = m_util.mk_is_zero(x); - y_is_zero = m_util.mk_is_zero(y); - both_are_zero = m.mk_and(x_is_zero, y_is_zero); - - expr_ref x_is_positive(m), x_is_negative(m), y_is_positive(m), y_is_negative(m), pn(m), np(m), pn_or_np(m); - x_is_positive = m_util.mk_is_positive(x); - x_is_negative = m_util.mk_is_negative(x); - y_is_positive = m_util.mk_is_positive(y); - y_is_negative = m_util.mk_is_negative(y); - pn = m.mk_and(x_is_positive, y_is_negative); - np = m.mk_and(x_is_negative, y_is_positive); - pn_or_np = m.mk_or(pn, np); - - expr_ref c(m), v(m); - c = m.mk_and(both_are_zero, pn_or_np); - v = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_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_INTERNAL_MIN_I, x, y); - m_simp.mk_ite(c, v, min_i, result); -} - -void fpa2bv_converter::mk_min_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); expr * x = args[0], * y = args[1]; - expr * x_sgn, * x_sig, * x_exp; - expr * y_sgn, * y_sig, * y_exp; + expr * x_sgn, *x_sig, *x_exp; + expr * y_sgn, *y_sig, *y_exp; split_fp(x, x_sgn, x_exp, x_sig); split_fp(y, y_sgn, y_exp, y_sig); - expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), both_zero(m), pzero(m); - mk_is_zero(x, x_is_zero); - mk_is_zero(y, y_is_zero); - m_simp.mk_and(x_is_zero, y_is_zero, both_zero); + expr_ref bv0(m), bv1(m); + bv0 = m_bv_util.mk_numeral(0, 1); + bv1 = m_bv_util.mk_numeral(1, 1); + + expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), xy_are_zero(m); mk_is_nan(x, x_is_nan); mk_is_nan(y, y_is_nan); - mk_pzero(f, pzero); + mk_is_zero(x, x_is_zero); + mk_is_zero(y, y_is_zero); + xy_are_zero = m.mk_and(x_is_zero, y_is_zero); - expr_ref sgn_eq(m), sgn_diff(m); - sgn_eq = m.mk_eq(x_sgn, y_sgn); - sgn_diff = m.mk_not(sgn_eq); + expr_ref x_is_pos(m), x_is_neg(m); + expr_ref y_is_pos(m), y_is_neg(m); + expr_ref pn(m), np(m), pn_or_np_zeros(m); + mk_is_pos(x, x_is_pos); + mk_is_pos(y, y_is_pos); + mk_is_neg(x, x_is_neg); + mk_is_neg(y, y_is_neg); + pn_or_np_zeros = m.mk_and(xy_are_zero, m.mk_not(m.mk_eq(x_sgn, y_sgn))); - expr_ref lt(m); - mk_float_lt(f, num, args, lt); + expr_ref unspec(m); + unspec = mk_min_max_unspecified(f, x, y); - mk_ite(lt, x, y, result); - mk_ite(both_zero, y, result, result); + expr_ref x_lt_y(m); + mk_float_lt(f, num, args, x_lt_y); + + mk_ite(x_lt_y, x, y, result); + mk_ite(xy_are_zero, y, result, result); + mk_ite(pn_or_np_zeros, unspec, result, result); + mk_ite(y_is_nan, x, result, result); + mk_ite(x_is_nan, y, result, result); + + SASSERT(is_well_sorted(m, result)); +} + +void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 2); + + expr * x = args[0], *y = args[1]; + + expr * x_sgn, *x_sig, *x_exp; + expr * y_sgn, *y_sig, *y_exp; + split_fp(x, x_sgn, x_exp, x_sig); + split_fp(y, y_sgn, y_exp, y_sig); + + expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), xy_are_zero(m); + mk_is_nan(x, x_is_nan); + mk_is_nan(y, y_is_nan); + mk_is_zero(x, x_is_zero); + mk_is_zero(y, y_is_zero); + xy_are_zero = m.mk_and(x_is_zero, y_is_zero); + + expr_ref x_is_pos(m), x_is_neg(m); + expr_ref y_is_pos(m), y_is_neg(m); + expr_ref pn(m), np(m), pn_or_np_zeros(m); + mk_is_pos(x, x_is_pos); + mk_is_pos(y, y_is_pos); + mk_is_neg(x, x_is_neg); + mk_is_neg(y, y_is_neg); + pn_or_np_zeros = m.mk_and(xy_are_zero, m.mk_not(m.mk_eq(x_sgn, y_sgn))); + + expr_ref unspec(m); + unspec = mk_min_max_unspecified(f, x, y); + + expr_ref x_gt_y(m); + mk_float_gt(f, num, args, x_gt_y); + + mk_ite(x_gt_y, x, y, result); + mk_ite(xy_are_zero, y, result, result); + mk_ite(pn_or_np_zeros, unspec, result, result); mk_ite(y_is_nan, x, result, result); mk_ite(x_is_nan, y, result, result); @@ -1281,10 +1273,10 @@ expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr // There is no "hardware interpretation" for fp.min/fp.max. std::pair decls(0, 0); - if (!m_min_max_specials.find(f, decls)) { + if (!m_min_max_ufs.find(f, decls)) { decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); - m_min_max_specials.insert(f, decls); + m_min_max_ufs.insert(f, decls); m.inc_ref(f); m.inc_ref(decls.first); m.inc_ref(decls.second); @@ -1303,68 +1295,6 @@ expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr return res; } -void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - expr_ref x(m), y(m); - x = args[0]; - y = args[1]; - - expr_ref x_is_zero(m), y_is_zero(m), both_are_zero(m); - x_is_zero = m_util.mk_is_zero(x); - y_is_zero = m_util.mk_is_zero(y); - both_are_zero = m.mk_and(x_is_zero, y_is_zero); - - expr_ref x_is_positive(m), x_is_negative(m), y_is_positive(m), y_is_negative(m), pn(m), np(m), pn_or_np(m); - x_is_positive = m_util.mk_is_positive(x); - x_is_negative = m_util.mk_is_negative(x); - y_is_positive = m_util.mk_is_positive(y); - y_is_negative = m_util.mk_is_negative(y); - pn = m.mk_and(x_is_positive, y_is_negative); - np = m.mk_and(x_is_negative, y_is_positive); - pn_or_np = m.mk_or(pn, np); - - expr_ref c(m), v(m); - c = m.mk_and(both_are_zero, pn_or_np); - v = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_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_INTERNAL_MAX_I, x, y); - m_simp.mk_ite(c, v, max_i, result); -} - -void fpa2bv_converter::mk_max_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 2); - - expr * x = args[0], *y = args[1]; - - expr * x_sgn, *x_sig, *x_exp; - expr * y_sgn, *y_sig, *y_exp; - split_fp(x, x_sgn, x_exp, x_sig); - split_fp(y, y_sgn, y_exp, y_sig); - - expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), both_zero(m), pzero(m); - mk_is_zero(x, x_is_zero); - mk_is_zero(y, y_is_zero); - m_simp.mk_and(x_is_zero, y_is_zero, both_zero); - mk_is_nan(x, x_is_nan); - mk_is_nan(y, y_is_nan); - mk_pzero(f, pzero); - - expr_ref sgn_diff(m), sgn_eq(m); - sgn_eq = m.mk_eq(x_sgn, y_sgn); - sgn_diff = m.mk_not(sgn_eq); - - expr_ref gt(m); - mk_float_gt(f, num, args, gt); - - mk_ite(gt, x, y, result); - mk_ite(both_zero, y, result, result); - mk_ite(y_is_nan, x, result, result); - mk_ite(x_is_nan, y, result, result); - - SASSERT(is_well_sorted(m, result)); -} - void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 4); SASSERT(m_util.is_bv2rm(args[0])); @@ -1476,6 +1406,10 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, mk_ite(c71, zero_cond, z, v7); // else comes the fused multiplication. + expr_ref one_1(m), zero_1(m); + one_1 = m_bv_util.mk_numeral(1, 1); + zero_1 = m_bv_util.mk_numeral(0, 1); + unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); @@ -1516,7 +1450,8 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, mul_sgn = m_bv_util.mk_bv_xor(2, signs); dbg_decouple("fpa2bv_fma_mul_sgn", mul_sgn); - mul_exp = m_bv_util.mk_bv_add(m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext), + mul_exp = m_bv_util.mk_bv_add( + m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext), m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext)); dbg_decouple("fpa2bv_fma_mul_exp", mul_exp); @@ -1529,11 +1464,15 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, // The product has the form [-1][0].[2*sbits - 2]. // Extend c - c_sig = m_bv_util.mk_zero_extend(1, m_bv_util.mk_concat(c_sig, m_bv_util.mk_numeral(0, sbits-1))); + expr_ref c_sig_ext(m); + c_sig_ext = m_bv_util.mk_zero_extend(1, m_bv_util.mk_concat(c_sig, m_bv_util.mk_numeral(0, sbits+2))); c_exp_ext = m_bv_util.mk_bv_sub(c_exp_ext, c_lz_ext); + mul_sig = m_bv_util.mk_concat(mul_sig, m_bv_util.mk_numeral(0, 3)); - SASSERT(m_bv_util.get_bv_size(mul_sig) == 2 * sbits); - SASSERT(m_bv_util.get_bv_size(c_sig) == 2 * sbits); + SASSERT(m_bv_util.get_bv_size(mul_sig) == 2*sbits+3); + SASSERT(m_bv_util.get_bv_size(c_sig_ext) == 2*sbits+3); + dbg_decouple("fpa2bv_fma_c_sig_ext", c_sig_ext); + dbg_decouple("fpa2bv_fma_c_exp_ext", c_exp_ext); expr_ref swap_cond(m); swap_cond = m_bv_util.mk_sle(mul_exp, c_exp_ext); @@ -1542,10 +1481,10 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref e_sgn(m), e_sig(m), e_exp(m), f_sgn(m), f_sig(m), f_exp(m); m_simp.mk_ite(swap_cond, c_sgn, mul_sgn, e_sgn); - m_simp.mk_ite(swap_cond, c_sig, mul_sig, e_sig); // has 2 * sbits + m_simp.mk_ite(swap_cond, c_sig_ext, mul_sig, e_sig); // has 2 * sbits + 3 m_simp.mk_ite(swap_cond, c_exp_ext, mul_exp, e_exp); // has ebits + 2 m_simp.mk_ite(swap_cond, mul_sgn, c_sgn, f_sgn); - m_simp.mk_ite(swap_cond, mul_sig, c_sig, f_sig); // has 2 * sbits + m_simp.mk_ite(swap_cond, mul_sig, c_sig_ext, f_sig); // has 2 * sbits + 3 m_simp.mk_ite(swap_cond, mul_exp, c_exp_ext, f_exp); // has ebits + 2 SASSERT(is_well_sorted(m, e_sgn)); @@ -1555,11 +1494,16 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, SASSERT(is_well_sorted(m, f_sig)); SASSERT(is_well_sorted(m, f_exp)); - SASSERT(m_bv_util.get_bv_size(e_sig) == 2 * sbits); - SASSERT(m_bv_util.get_bv_size(f_sig) == 2 * sbits); + SASSERT(m_bv_util.get_bv_size(e_sig) == 2*sbits+3); + SASSERT(m_bv_util.get_bv_size(f_sig) == 2*sbits+3); SASSERT(m_bv_util.get_bv_size(e_exp) == ebits + 2); SASSERT(m_bv_util.get_bv_size(f_exp) == ebits + 2); + dbg_decouple("fpa2bv_fma_e_sig", e_sig); + dbg_decouple("fpa2bv_fma_e_exp", e_exp); + dbg_decouple("fpa2bv_fma_f_sig", f_sig); + dbg_decouple("fpa2bv_fma_f_exp", f_exp); + expr_ref res_sgn(m), res_sig(m), res_exp(m); expr_ref exp_delta(m); @@ -1568,7 +1512,7 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, // cap the delta expr_ref cap(m), cap_le_delta(m); - cap = m_bv_util.mk_numeral(2*sbits, ebits+2); + cap = m_bv_util.mk_numeral(2*sbits+3, ebits+2); cap_le_delta = m_bv_util.mk_ule(cap, exp_delta); m_simp.mk_ite(cap_le_delta, cap, exp_delta, exp_delta); SASSERT(m_bv_util.get_bv_size(exp_delta) == ebits+2); @@ -1576,61 +1520,63 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, dbg_decouple("fpa2bv_fma_add_exp_delta_capped", exp_delta); // Alignment shift with sticky bit computation. - expr_ref shifted_big(m), shifted_f_sig(m), sticky_raw(m); + expr_ref shifted_big(m), shifted_f_sig(m); + expr_ref alignment_sticky_raw(m), alignment_sticky(m); shifted_big = m_bv_util.mk_bv_lshr( m_bv_util.mk_concat(f_sig, m_bv_util.mk_numeral(0, sbits)), - m_bv_util.mk_zero_extend((3*sbits)-(ebits+2), exp_delta)); - shifted_f_sig = m_bv_util.mk_extract(3*sbits-1, sbits, shifted_big); - sticky_raw = m_bv_util.mk_extract(sbits-1, 0, shifted_big); - SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2 * sbits); - SASSERT(is_well_sorted(m, shifted_f_sig)); - - expr_ref sticky(m); - sticky = m_bv_util.mk_zero_extend(2*sbits-1, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_raw.get())); - SASSERT(is_well_sorted(m, sticky)); - dbg_decouple("fpa2bv_fma_f_sig_sticky_raw", sticky_raw); - dbg_decouple("fpa2bv_fma_f_sig_sticky", sticky); - - expr * or_args[2] = { shifted_f_sig, sticky }; - shifted_f_sig = m_bv_util.mk_bv_or(2, or_args); + m_bv_util.mk_zero_extend((3*sbits+3)-(ebits+2), exp_delta)); + shifted_f_sig = m_bv_util.mk_extract(3*sbits+2, sbits, shifted_big); + alignment_sticky_raw = m_bv_util.mk_extract(sbits-1, 0, shifted_big); + alignment_sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, alignment_sticky_raw.get()); + dbg_decouple("fpa2bv_fma_shifted_f_sig", shifted_f_sig); + dbg_decouple("fpa2bv_fma_f_sig_alignment_sticky", alignment_sticky); + SASSERT(is_well_sorted(m, alignment_sticky)); + SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2*sbits+3); SASSERT(is_well_sorted(m, shifted_f_sig)); // Significant addition. - // Two extra bits for catching the overflow. + // Two extra bits for the sign and for catching overflows. e_sig = m_bv_util.mk_zero_extend(2, e_sig); shifted_f_sig = m_bv_util.mk_zero_extend(2, shifted_f_sig); expr_ref eq_sgn(m); m_simp.mk_eq(e_sgn, f_sgn, eq_sgn); + dbg_decouple("fpa2bv_fma_eq_sgn", eq_sgn); - SASSERT(m_bv_util.get_bv_size(e_sig) == 2*sbits + 2); - SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2*sbits + 2); + SASSERT(m_bv_util.get_bv_size(e_sig) == 2*sbits+5); + SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2*sbits+5); dbg_decouple("fpa2bv_fma_add_e_sig", e_sig); dbg_decouple("fpa2bv_fma_add_shifted_f_sig", shifted_f_sig); - expr_ref sum(m), e_plus_f(m), e_minus_f(m); + expr_ref sum(m), e_plus_f(m), e_minus_f(m), sticky_wide(m); + sticky_wide = m_bv_util.mk_zero_extend(2*sbits+4, alignment_sticky); e_plus_f = m_bv_util.mk_bv_add(e_sig, shifted_f_sig); - e_minus_f = m_bv_util.mk_bv_sub(e_sig, shifted_f_sig), - m_simp.mk_ite(eq_sgn, e_plus_f, e_minus_f, sum); + e_plus_f = m.mk_ite(m.mk_eq(m_bv_util.mk_extract(0, 0, e_plus_f), zero_1), + m_bv_util.mk_bv_add(e_plus_f, sticky_wide), + e_plus_f); + e_minus_f = m_bv_util.mk_bv_sub(e_sig, shifted_f_sig); + e_minus_f = m.mk_ite(m.mk_eq(m_bv_util.mk_extract(0, 0, e_minus_f), zero_1), + m_bv_util.mk_bv_sub(e_minus_f, sticky_wide), + e_minus_f); + SASSERT(is_well_sorted(m, shifted_f_sig)); + dbg_decouple("fpa2bv_fma_f_sig_or_sticky", shifted_f_sig); + m_simp.mk_ite(eq_sgn, e_plus_f, e_minus_f, sum); + SASSERT(m_bv_util.get_bv_size(sum) == 2*sbits+5); SASSERT(is_well_sorted(m, sum)); - dbg_decouple("fpa2bv_fma_add_sum", sum); expr_ref sign_bv(m), n_sum(m); - sign_bv = m_bv_util.mk_extract(2*sbits+1, 2*sbits+1, sum); + sign_bv = m_bv_util.mk_extract(2*sbits+4, 2*sbits+4, sum); n_sum = m_bv_util.mk_bv_neg(sum); - - expr_ref res_sig_eq(m), sig_abs(m), one_1(m); - one_1 = m_bv_util.mk_numeral(1, 1); - m_simp.mk_eq(sign_bv, one_1, res_sig_eq); - m_simp.mk_ite(res_sig_eq, n_sum, sum, sig_abs); dbg_decouple("fpa2bv_fma_add_sign_bv", sign_bv); dbg_decouple("fpa2bv_fma_add_n_sum", n_sum); - dbg_decouple("fpa2bv_fma_add_sig_abs", sig_abs); - res_exp = e_exp; + expr_ref res_sig_eq(m), sig_abs(m); + m_simp.mk_eq(sign_bv, one_1, res_sig_eq); + m_simp.mk_ite(res_sig_eq, n_sum, sum, sig_abs); + dbg_decouple("fpa2bv_fma_add_sig_abs", sig_abs); family_id bvfid = m_bv_util.get_fid(); expr_ref res_sgn_c1(m), res_sgn_c2(m), res_sgn_c3(m); @@ -1643,44 +1589,76 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, res_sgn_c3 = m.mk_app(bvfid, OP_BAND, e_sgn, f_sgn); expr * res_sgn_or_args[3] = { res_sgn_c1, res_sgn_c2, res_sgn_c3 }; res_sgn = m_bv_util.mk_bv_or(3, res_sgn_or_args); + dbg_decouple("fpa2bv_fma_res_sgn", res_sgn); + + expr_ref is_sig_neg(m); + is_sig_neg = m.mk_eq(one_1, m_bv_util.mk_extract(2*sbits+4, 2*sbits+4, sig_abs)); + sig_abs = m.mk_ite(is_sig_neg, m_bv_util.mk_bv_neg(sig_abs), sig_abs); + dbg_decouple("fpa2bv_fma_is_sig_neg", is_sig_neg); // Result could have overflown into 4.xxx. - SASSERT(m_bv_util.get_bv_size(sig_abs) == 2 * sbits + 2); - expr_ref ovfl_into_4(m); - ovfl_into_4 = m.mk_eq(m_bv_util.mk_extract(2 * sbits + 1, 2 * sbits, sig_abs), - m_bv_util.mk_numeral(1, 2)); - dbg_decouple("fpa2bv_fma_ovfl_into_4", ovfl_into_4); - if (sbits > 5) { - expr_ref sticky_raw(m), sig_upper(m), sticky_redd(m), res_sig_norm(m); - sticky_raw = m_bv_util.mk_extract(sbits - 4, 0, sig_abs); - sig_upper = m_bv_util.mk_extract(2 * sbits, sbits - 3, sig_abs); - SASSERT(m_bv_util.get_bv_size(sig_upper) == sbits + 4); - sticky_redd = m.mk_app(bvfid, OP_BREDOR, sticky_raw.get()); - sticky = m_bv_util.mk_zero_extend(sbits + 3, sticky_redd); - expr * res_or_args[2] = { sig_upper, sticky }; - res_sig_norm = m_bv_util.mk_bv_or(2, res_or_args); + SASSERT(m_bv_util.get_bv_size(sig_abs) == 2*sbits+5); + expr_ref extra(m), extra_is_zero(m); + extra = m_bv_util.mk_extract(2*sbits+4, 2*sbits+3, sig_abs); + extra_is_zero = m.mk_eq(extra, m_bv_util.mk_numeral(0, 2)); + dbg_decouple("fpa2bv_fma_extra", extra); - expr_ref sticky_raw_ovfl(m), sig_upper_ovfl(m), sticky_redd_ovfl(m), sticky_ovfl(m), res_sig_ovfl(m); - sticky_raw_ovfl = m_bv_util.mk_extract(sbits - 4, 0, sig_abs); - sig_upper_ovfl = m_bv_util.mk_extract(2 * sbits, sbits - 3, sig_abs); - SASSERT(m_bv_util.get_bv_size(sig_upper_ovfl) == sbits + 4); - sticky_redd_ovfl = m.mk_app(bvfid, OP_BREDOR, sticky_raw_ovfl.get()); - sticky_ovfl = m_bv_util.mk_zero_extend(sbits + 3, sticky_redd_ovfl); - expr * res_or_args_ovfl[2] = { sig_upper_ovfl, sticky_ovfl }; - res_sig_ovfl = m_bv_util.mk_bv_or(2, res_or_args_ovfl); + res_exp = m.mk_ite(extra_is_zero, e_exp, m_bv_util.mk_bv_add(e_exp, m_bv_util.mk_numeral(1, ebits + 2))); - res_sig = m.mk_ite(ovfl_into_4, res_sig_ovfl, res_sig_norm); - res_exp = m.mk_ite(ovfl_into_4, m_bv_util.mk_bv_add(res_exp, m_bv_util.mk_numeral(1, ebits+2)), - res_exp); - } - else { - unsigned too_short = 6 - sbits; + // Renormalize + expr_ref zero_e2(m), min_exp(m), sig_lz(m), max_exp_delta(m), sig_lz_capped(m), renorm_delta(m); + zero_e2 = m_bv_util.mk_numeral(0, ebits + 2); + mk_min_exp(ebits, min_exp); + min_exp = m_bv_util.mk_sign_extend(2, min_exp); + mk_leading_zeros(sig_abs, ebits+2, sig_lz); + sig_lz = m_bv_util.mk_bv_sub(sig_lz, m_bv_util.mk_numeral(2, ebits+2)); + max_exp_delta = m_bv_util.mk_bv_sub(res_exp, min_exp); + sig_lz_capped = m.mk_ite(m_bv_util.mk_sle(sig_lz, max_exp_delta), sig_lz, max_exp_delta); + renorm_delta = m.mk_ite(m_bv_util.mk_sle(zero_e2, sig_lz_capped), sig_lz_capped, zero_e2); + res_exp = m_bv_util.mk_bv_sub(res_exp, renorm_delta); + sig_abs = m_bv_util.mk_bv_shl(sig_abs, m_bv_util.mk_zero_extend(2*sbits+3-ebits, renorm_delta)); + dbg_decouple("fpa2bv_fma_min_exp", min_exp); + dbg_decouple("fpa2bv_fma_max_exp_delta", max_exp_delta); + dbg_decouple("fpa2bv_fma_sig_lz", sig_lz); + dbg_decouple("fpa2bv_fma_sig_lz_capped", sig_lz_capped); + dbg_decouple("fpa2bv_fma_renorm_delta", renorm_delta); + + unsigned too_short = 0; + if (sbits < 5) { + too_short = 6 - sbits + 1; sig_abs = m_bv_util.mk_concat(sig_abs, m_bv_util.mk_numeral(0, too_short)); - res_sig = m_bv_util.mk_extract(sbits + 3, 0, sig_abs); } - dbg_decouple("fpa2bv_fma_add_sum_sticky", sticky); - dbg_decouple("fpa2bv_fma_sig_abs", sig_abs); + + expr_ref sig_abs_h1(m), sticky_h1(m), sticky_h1_red(m), sig_abs_h1_f(m), res_sig_1(m); + sticky_h1 = m_bv_util.mk_extract(sbits+too_short-2, 0, sig_abs); + sig_abs_h1 = m_bv_util.mk_extract(2*sbits+too_short+4, sbits-1+too_short, sig_abs); + sticky_h1_red = m_bv_util.mk_zero_extend(sbits+5, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_h1.get())); + expr * sticky_h1_red_args[2] = { sig_abs_h1, sticky_h1_red }; + sig_abs_h1_f = m_bv_util.mk_bv_or(2, sticky_h1_red_args); + res_sig_1 = m_bv_util.mk_extract(sbits+3, 0, sig_abs_h1_f); + SASSERT(m_bv_util.get_bv_size(sticky_h1) == sbits+too_short-1); + SASSERT(m_bv_util.get_bv_size(sig_abs_h1) == sbits+6); + SASSERT(m_bv_util.get_bv_size(sticky_h1_red) == sbits+6); + SASSERT(m_bv_util.get_bv_size(sig_abs_h1_f) == sbits+6); + SASSERT(m_bv_util.get_bv_size(res_sig_1) == sbits+4); + + expr_ref sig_abs_h2(m), sticky_h2(m), sticky_h2_red(m), sig_abs_h2_f(m), res_sig_2(m); + sticky_h2 = m_bv_util.mk_extract(sbits+too_short-1, 0, sig_abs); + sig_abs_h2 = m_bv_util.mk_extract(2*sbits+too_short+4, sbits+too_short, sig_abs); + sticky_h2_red = m_bv_util.mk_zero_extend(sbits+4, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_h1.get())); + expr * sticky_h2_red_args[2] = { sig_abs_h2, sticky_h2_red }; + sig_abs_h2_f = m_bv_util.mk_zero_extend(1, m_bv_util.mk_bv_or(2, sticky_h2_red_args)); + res_sig_2 = m_bv_util.mk_extract(sbits+3, 0, sig_abs_h2_f); + SASSERT(m_bv_util.get_bv_size(sticky_h2) == sbits+too_short); + SASSERT(m_bv_util.get_bv_size(sig_abs_h2) == sbits+5); + SASSERT(m_bv_util.get_bv_size(sticky_h2_red) == sbits+5); + SASSERT(m_bv_util.get_bv_size(sig_abs_h2_f) == sbits+6); + SASSERT(m_bv_util.get_bv_size(res_sig_2) == sbits+4); + + res_sig = m.mk_ite(extra_is_zero, res_sig_1, res_sig_2); + dbg_decouple("fpa2bv_fma_res_sig", res_sig); + dbg_decouple("fpa2bv_fma_res_exp", res_exp); SASSERT(m_bv_util.get_bv_size(res_sig) == sbits + 4); expr_ref is_zero_sig(m), nil_sbits4(m); @@ -2666,13 +2644,21 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con SASSERT(m_util.is_bv2rm(args[0])); expr * bv_rm = to_app(args[0])->get_arg(0); - rational e; - if (!m_arith_util.is_numeral(args[1], e)) - UNREACHABLE(); + SASSERT((m_arith_util.is_int(args[1]) && m_arith_util.is_real(args[2])) || + (m_arith_util.is_real(args[1]) && m_arith_util.is_int(args[2]))); - rational q; - if (!m_arith_util.is_numeral(args[2], q)) - UNREACHABLE(); + rational q, e; + + if (m_arith_util.is_int(args[1]) && m_arith_util.is_real(args[2])) { + if (!m_arith_util.is_numeral(args[1], e) || + !m_arith_util.is_numeral(args[2], q)) + UNREACHABLE(); + } + else { + if (!m_arith_util.is_numeral(args[2], e) || + !m_arith_util.is_numeral(args[1], q)) + UNREACHABLE(); + } SASSERT(e.is_int64()); SASSERT(m_mpz_manager.eq(e.to_mpq().denominator(), 1)); @@ -2799,8 +2785,7 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar tout << "exp2 = " << mk_ismt2_pp(exp2, m) << std::endl;); expr_ref unspec(m); - unspec = mk_to_real_unspecified(ebits, sbits); - + mk_to_real_unspecified(f, num, args, unspec); result = m.mk_ite(x_is_zero, zero, res); result = m.mk_ite(x_is_inf, unspec, result); result = m.mk_ite(x_is_nan, unspec, result); @@ -3091,63 +3076,43 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * split_fp(x, sgn, e, s); mk_is_nan(x, x_is_nan); - sort * fp_srt = m.get_sort(x); - unsigned ebits = m_util.get_ebits(fp_srt); - unsigned sbits = m_util.get_sbits(fp_srt); - - expr_ref nanv(m); - if (m_hi_fp_unspecified) - // The "hardware interpretation" is 01...10...01. - nanv = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1), - m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits), - m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2), - m_bv_util.mk_numeral(1, 1)))); - else { - app_ref unspec(m); - unspec = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits); - mk_to_ieee_bv_unspecified(unspec->get_decl(), 0, 0, nanv); - } + expr_ref unspec(m); + mk_to_ieee_bv_unspecified(f, num, args, unspec); expr_ref sgn_e_s(m); - sgn_e_s = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, e), s); - m_simp.mk_ite(x_is_nan, nanv, sgn_e_s, result); + join_fp(x, sgn_e_s); + m_simp.mk_ite(x_is_nan, unspec, sgn_e_s, result); TRACE("fpa2bv_to_ieee_bv", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); SASSERT(is_well_sorted(m, result)); } void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 0); - unsigned ebits = f->get_parameter(0).get_int(); - unsigned sbits = f->get_parameter(1).get_int(); + SASSERT(num == 1); + SASSERT(m_util.is_float(args[0])); + unsigned ebits = f->get_domain()[0]->get_parameter(0).get_int(); + unsigned sbits = f->get_domain()[0]->get_parameter(1).get_int(); - if (m_hi_fp_unspecified) { - result = m_bv_util.mk_concat(m_bv_util.mk_concat( - m_bv_util.mk_numeral(0, 1), - m_bv_util.mk_numeral(-1, ebits)), - m_bv_util.mk_numeral(1, sbits-1)); - } + if (m_hi_fp_unspecified) + mk_nan(f->get_range(), result); else { - func_decl * fd; - if (m_uf2bvuf.find(f, fd)) - result = m.mk_const(fd); - else { - fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); - m_uf2bvuf.insert(f, fd); - m.inc_ref(f); - m.inc_ref(fd); - result = m.mk_const(fd); + expr * n = args[0]; + expr_ref n_bv(m); + join_fp(n, n_bv); - expr_ref exp_bv(m), exp_all_ones(m); - exp_bv = m_bv_util.mk_extract(ebits+sbits-2, sbits-1, result); - exp_all_ones = m.mk_eq(exp_bv, m_bv_util.mk_numeral(-1, ebits)); - m_extra_assertions.push_back(exp_all_ones); + sort * domain[1] = { m.get_sort(n_bv) }; + func_decl * f_bv = mk_bv_uf(f, domain, f->get_range()); + result = m.mk_app(f_bv, n_bv); - expr_ref sig_bv(m), sig_is_non_zero(m); - sig_bv = m_bv_util.mk_extract(sbits-2, 0, result); - sig_is_non_zero = m.mk_not(m.mk_eq(sig_bv, m_bv_util.mk_numeral(0, sbits-1))); - m_extra_assertions.push_back(sig_is_non_zero); - } + expr_ref exp_bv(m), exp_all_ones(m); + exp_bv = m_bv_util.mk_extract(ebits+sbits-2, sbits-1, result); + exp_all_ones = m.mk_eq(exp_bv, m_bv_util.mk_numeral(-1, ebits)); + m_extra_assertions.push_back(exp_all_ones); + + expr_ref sig_bv(m), sig_is_non_zero(m); + sig_bv = m_bv_util.mk_extract(sbits-2, 0, result); + sig_is_non_zero = m.mk_not(m.mk_eq(sig_bv, m_bv_util.mk_numeral(0, sbits-1))); + m_extra_assertions.push_back(sig_is_non_zero); } TRACE("fpa2bv_to_ieee_bv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); @@ -3182,18 +3147,13 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args mk_is_nzero(x, x_is_nzero); // NaN, Inf, or negative (except -0) -> unspecified - expr_ref c1(m), v1(m); - if (!is_signed) { - c1 = m.mk_or(x_is_nan, x_is_inf, m.mk_and(x_is_neg, m.mk_not(x_is_nzero))); - v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz); - } - else { - c1 = m.mk_or(x_is_nan, x_is_inf); - v1 = mk_to_sbv_unspecified(ebits, sbits, bv_sz); - } + expr_ref c1(m), v1(m), unspec_v(m); + c1 = m.mk_or(x_is_nan, x_is_inf); + mk_to_bv_unspecified(f, num, args, unspec_v); + v1 = unspec_v; dbg_decouple("fpa2bv_to_bv_c1", c1); - // +-Zero -> 0 + // +-0 -> 0 expr_ref c2(m), v2(m); c2 = x_is_zero; v2 = m_bv_util.mk_numeral(rational(0), bv_srt); @@ -3214,60 +3174,57 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args SASSERT(m_bv_util.get_bv_size(exp) == ebits); SASSERT(m_bv_util.get_bv_size(lz) == ebits); - unsigned sig_sz = m_bv_util.get_bv_size(sig); - SASSERT(sig_sz == sbits); + unsigned sig_sz = sbits; if (sig_sz < (bv_sz + 3)) - sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, bv_sz - sig_sz + 3)); + sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, bv_sz-sig_sz+3)); sig_sz = m_bv_util.get_bv_size(sig); SASSERT(sig_sz >= (bv_sz + 3)); - expr_ref exp_m_lz(m), e_m_lz_m_bv_sz(m), shift(m), bv0_e2(m), shift_abs(m), shift_le_0(m); - exp_m_lz = m_bv_util.mk_bv_sub(m_bv_util.mk_sign_extend(2, exp), - m_bv_util.mk_zero_extend(2, lz)); - e_m_lz_m_bv_sz = m_bv_util.mk_bv_sub(exp_m_lz, - m_bv_util.mk_numeral(bv_sz - 1, ebits + 2)); - shift = m_bv_util.mk_bv_neg(e_m_lz_m_bv_sz); - bv0_e2 = m_bv_util.mk_numeral(0, ebits + 2); - shift_le_0 = m_bv_util.mk_sle(shift, bv0_e2); - shift_abs = m.mk_ite(shift_le_0, e_m_lz_m_bv_sz, shift); - SASSERT(m_bv_util.get_bv_size(shift) == ebits + 2); - SASSERT(m_bv_util.get_bv_size(shift_abs) == ebits + 2); - dbg_decouple("fpa2bv_to_bv_shift", shift); - dbg_decouple("fpa2bv_to_bv_shift_abs", shift_abs); - // x is of the form +- [1].[sig][r][g][s] ... and at least bv_sz + 3 long - // [1][ ... sig ... ][r][g][ ... s ...] - // [ ... ubv ... ][r][g][ ... s ... ] - shift_abs = m_bv_util.mk_zero_extend(sig_sz - ebits - 2, shift_abs); - SASSERT(m_bv_util.get_bv_size(shift_abs) == sig_sz); + expr_ref exp_m_lz(m), e_m_lz_m_bv_sz(m), shift(m), is_neg_shift(m), big_sig(m); + exp_m_lz = m_bv_util.mk_bv_sub(m_bv_util.mk_sign_extend(2, exp), + m_bv_util.mk_zero_extend(2, lz)); - expr_ref c_in_limits(m); - if (!is_signed) - c_in_limits = m_bv_util.mk_sle(bv0_e2, shift); - else { - expr_ref one_sle_shift(m), one_eq_shift(m), p2(m), sig_is_p2(m), shift1_and_sig_p2(m); - one_sle_shift = m_bv_util.mk_sle(m_bv_util.mk_numeral(1, ebits + 2), shift); - one_eq_shift = m.mk_eq(m_bv_util.mk_numeral(0, ebits + 2), shift); - p2 = m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, sig_sz-1)); - sig_is_p2 = m.mk_eq(sig, p2); - shift1_and_sig_p2 = m.mk_and(one_eq_shift, sig_is_p2); - c_in_limits = m.mk_or(one_sle_shift, shift1_and_sig_p2); + // big_sig is +- [... bv_sz+2 bits ...].[r][g][ ... sbits-1 ... ] + big_sig = m_bv_util.mk_zero_extend(bv_sz+2, sig); + unsigned big_sig_sz = sig_sz+bv_sz+2; + SASSERT(m_bv_util.get_bv_size(big_sig) == big_sig_sz); + + is_neg_shift = m_bv_util.mk_sle(exp_m_lz, m_bv_util.mk_numeral(0, ebits+2)); + shift = m.mk_ite(is_neg_shift, m_bv_util.mk_bv_neg(exp_m_lz), exp_m_lz); + if (ebits+2 < big_sig_sz) + shift = m_bv_util.mk_zero_extend(big_sig_sz-ebits-2, shift); + else if (ebits+2 > big_sig_sz) { + expr_ref upper(m); + upper = m_bv_util.mk_extract(big_sig_sz, ebits+2, shift); + shift = m_bv_util.mk_extract(ebits+1, 0, shift); + shift = m.mk_ite(m.mk_eq(upper, m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(upper))), + shift, + m_bv_util.mk_numeral(big_sig_sz-1, ebits+2)); } - dbg_decouple("fpa2bv_to_bv_in_limits", c_in_limits); + dbg_decouple("fpa2bv_to_bv_shift_uncapped", shift); + SASSERT(m_bv_util.get_bv_size(shift) == m_bv_util.get_bv_size(big_sig)); + dbg_decouple("fpa2bv_to_bv_big_sig", big_sig); - expr_ref r_shifted_sig(m), l_shifted_sig(m); - r_shifted_sig = m_bv_util.mk_bv_lshr(sig, shift_abs); - l_shifted_sig = m_bv_util.mk_bv_shl(sig, m_bv_util.mk_bv_sub( - m_bv_util.mk_numeral(m_bv_util.get_bv_size(sig), m_bv_util.get_bv_size(sig)), - shift_abs)); - dbg_decouple("fpa2bv_to_bv_r_shifted_sig", r_shifted_sig); - dbg_decouple("fpa2bv_to_bv_l_shifted_sig", l_shifted_sig); + expr_ref shift_limit(m); + shift_limit = m_bv_util.mk_numeral(bv_sz+2, m_bv_util.get_bv_size(shift)); + shift = m.mk_ite(m_bv_util.mk_ule(shift, shift_limit), shift, shift_limit); + dbg_decouple("fpa2bv_to_bv_shift_limit", shift_limit); + dbg_decouple("fpa2bv_to_bv_is_neg_shift", is_neg_shift); + dbg_decouple("fpa2bv_to_bv_shift", shift); - expr_ref last(m), round(m), sticky(m); - last = m_bv_util.mk_extract(sig_sz - bv_sz - 0, sig_sz - bv_sz - 0, r_shifted_sig); - round = m_bv_util.mk_extract(sig_sz - bv_sz - 1, sig_sz - bv_sz - 1, r_shifted_sig); - sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, l_shifted_sig.get()); + expr_ref big_sig_shifted(m), int_part(m), last(m), round(m), stickies(m), sticky(m); + big_sig_shifted = m.mk_ite(is_neg_shift, m_bv_util.mk_bv_lshr(big_sig, shift), + m_bv_util.mk_bv_shl(big_sig, shift)); + int_part = m_bv_util.mk_extract(big_sig_sz-1, big_sig_sz-(bv_sz+3), big_sig_shifted); + SASSERT(m_bv_util.get_bv_size(int_part) == bv_sz+3); + last = m_bv_util.mk_extract(big_sig_sz-(bv_sz+3), big_sig_sz-(bv_sz+3), big_sig_shifted); + round = m_bv_util.mk_extract(big_sig_sz-(bv_sz+4), big_sig_sz-(bv_sz+4), big_sig_shifted); + stickies = m_bv_util.mk_extract(big_sig_sz-(bv_sz+5), 0, big_sig_shifted); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, stickies.get()); + dbg_decouple("fpa2bv_to_bv_big_sig_shifted", big_sig_shifted); + dbg_decouple("fpa2bv_to_bv_int_part", int_part); dbg_decouple("fpa2bv_to_bv_last", last); dbg_decouple("fpa2bv_to_bv_round", round); dbg_decouple("fpa2bv_to_bv_sticky", sticky); @@ -3277,33 +3234,31 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args SASSERT(m_bv_util.get_bv_size(rounding_decision) == 1); dbg_decouple("fpa2bv_to_bv_rounding_decision", rounding_decision); - expr_ref unrounded_sig(m), pre_rounded(m), inc(m); - unrounded_sig = m_bv_util.mk_zero_extend(1, m_bv_util.mk_extract(sig_sz - 1, sig_sz - bv_sz, r_shifted_sig)); - inc = m_bv_util.mk_zero_extend(1, m_bv_util.mk_zero_extend(bv_sz - 1, rounding_decision)); - pre_rounded = m_bv_util.mk_bv_add(unrounded_sig, inc); + expr_ref inc(m), pre_rounded(m); + inc = m_bv_util.mk_zero_extend(bv_sz+2, rounding_decision); + pre_rounded = m_bv_util.mk_bv_add(int_part, inc); dbg_decouple("fpa2bv_to_bv_inc", inc); dbg_decouple("fpa2bv_to_bv_pre_rounded", pre_rounded); - expr_ref rnd_overflow(m), rnd(m), rnd_has_overflown(m); - rnd_overflow = m_bv_util.mk_extract(bv_sz, bv_sz, pre_rounded); - rnd = m_bv_util.mk_extract(bv_sz - 1, 0, pre_rounded); - rnd_has_overflown = m.mk_eq(rnd_overflow, bv1); - dbg_decouple("fpa2bv_to_bv_rnd_has_overflown", rnd_has_overflown); + pre_rounded = m.mk_ite(x_is_neg, m_bv_util.mk_bv_neg(pre_rounded), pre_rounded); - if (is_signed) { - expr_ref sgn_eq_1(m), neg_rnd(m); - sgn_eq_1 = m.mk_eq(sgn, bv1); - neg_rnd = m_bv_util.mk_bv_neg(rnd); - m_simp.mk_ite(sgn_eq_1, neg_rnd, rnd, rnd); + expr_ref ll(m), ul(m), in_range(m); + if (!is_signed) { + ll = m_bv_util.mk_numeral(0, bv_sz+3); + ul = m_bv_util.mk_zero_extend(3, m_bv_util.mk_numeral(-1, bv_sz)); } + else { + ll = m_bv_util.mk_sign_extend(3, m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, bv_sz-1))); + ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_numeral(-1, bv_sz-1)); + } + in_range = m.mk_and(m_bv_util.mk_sle(ll, pre_rounded), m_bv_util.mk_sle(pre_rounded, ul)); + dbg_decouple("fpa2bv_to_bv_in_range", in_range); - dbg_decouple("fpa2bv_to_bv_rnd", rnd); + expr_ref rounded(m); + rounded = m_bv_util.mk_extract(bv_sz-1, 0, pre_rounded); + dbg_decouple("fpa2bv_to_bv_rounded", rounded); - expr_ref unspec(m); - unspec = is_signed ? mk_to_sbv_unspecified(ebits, sbits, bv_sz) : - mk_to_ubv_unspecified(ebits, sbits, bv_sz); - result = m.mk_ite(rnd_has_overflown, unspec, rnd); - result = m.mk_ite(c_in_limits, result, unspec); + result = m.mk_ite(m.mk_not(in_range), unspec_v, rounded); result = m.mk_ite(c2, v2, result); result = m.mk_ite(c1, v1, result); @@ -3322,85 +3277,42 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg mk_to_bv(f, num, args, true, result); } -void fpa2bv_converter::mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 0); - unsigned width = m_bv_util.get_bv_size(f->get_range()); +void fpa2bv_converter::mk_to_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 2); + SASSERT(m_util.is_bv2rm(args[0])); + SASSERT(m_util.is_float(args[1])); if (m_hi_fp_unspecified) - result = m_bv_util.mk_numeral(0, width); + result = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(f->get_range())); else { - func_decl * fd; - if (!m_uf2bvuf.find(f, fd)) { - fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); - m_uf2bvuf.insert(f, fd); - m.inc_ref(f); - m.inc_ref(fd); - } - result = m.mk_const(fd); + expr * rm_bv = to_app(args[0])->get_arg(0); + expr * n = args[1]; + expr_ref n_bv(m); + join_fp(n, n_bv); + + sort * domain[2] = { m.get_sort(rm_bv), m.get_sort(n_bv) }; + func_decl * f_bv = mk_bv_uf(f, domain, f->get_range()); + result = m.mk_app(f_bv, rm_bv, n_bv); } - TRACE("fpa2bv_to_ubv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); + TRACE("fpa2bv_to_bv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); SASSERT(is_well_sorted(m, result)); } -expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) { - expr_ref res(m); - app_ref u(m); - u = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width); - mk_to_sbv_unspecified(u->get_decl(), 0, 0, res); - return res; -} - -void fpa2bv_converter::mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 0); - unsigned width = m_bv_util.get_bv_size(f->get_range()); - - if (m_hi_fp_unspecified) - result = m_bv_util.mk_numeral(0, width); - else { - func_decl * fd; - if (!m_uf2bvuf.find(f, fd)) { - fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); - m_uf2bvuf.insert(f, fd); - m.inc_ref(f); - m.inc_ref(fd); - } - result = m.mk_const(fd); - } - - TRACE("fpa2bv_to_sbv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); - SASSERT(is_well_sorted(m, result)); -} - -expr_ref fpa2bv_converter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) { - expr_ref res(m); - app_ref u(m); - u = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width); - mk_to_sbv_unspecified(u->get_decl(), 0, 0, res); - return res; -} - void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 1); + if (m_hi_fp_unspecified) result = m_arith_util.mk_numeral(rational(0), false); else { - func_decl * fd; - if (!m_uf2bvuf.find(f, fd)) { - fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); - m_uf2bvuf.insert(f, fd); - m.inc_ref(f); - m.inc_ref(fd); - } - result = m.mk_const(fd); - } -} + expr * n = args[0]; + expr_ref n_bv(m); + join_fp(n, n_bv); -expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits) { - expr_ref res(m); - app_ref u(m); - u = m_util.mk_internal_to_real_unspecified(ebits, sbits); - mk_to_real_unspecified(u->get_decl(), 0, 0, res); - return res; + sort * domain[1] = { m.get_sort(n_bv) }; + func_decl * f_bv = mk_bv_uf(f, domain, f->get_range()); + result = m.mk_app(f_bv, n_bv); + } } void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -3411,6 +3323,7 @@ void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, e result = m_util.mk_fp(args[0], args[1], args[2]); TRACE("fpa2bv_mk_fp", tout << "mk_fp result = " << mk_ismt2_pp(result, m) << std::endl;); } + void fpa2bv_converter::split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const { SASSERT(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); @@ -3429,6 +3342,14 @@ void fpa2bv_converter::split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_r sig = e_sig; } +void fpa2bv_converter::join_fp(expr * e, expr_ref & res) { + SASSERT(m_util.is_fp(e)); + SASSERT(to_app(e)->get_num_args() == 3); + expr *sgn, *exp, *sig; + split_fp(e, sgn, exp, sig); + res = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, exp), sig); +} + void fpa2bv_converter::mk_is_nan(expr * e, expr_ref & result) { expr * sgn, * sig, * exp; split_fp(e, sgn, exp, sig); @@ -3882,15 +3803,12 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & SASSERT(m_bv_util.get_bv_size(sig) == sbits+4); SASSERT(m_bv_util.get_bv_size(exp) == ebits+2); - // bool UNFen = false; - // bool OVFen = false; - expr_ref e_min(m), e_max(m); mk_min_exp(ebits, e_min); mk_max_exp(ebits, e_max); - TRACE("fpa2bv_dbg", tout << "e_min = " << mk_ismt2_pp(e_min, m) << std::endl << - "e_max = " << mk_ismt2_pp(e_max, m) << std::endl;); + TRACE("fpa2bv_dbg", tout << "e_min = " << mk_ismt2_pp(e_min, m) << std::endl; + tout << "e_max = " << mk_ismt2_pp(e_max, m) << std::endl;); expr_ref OVF1(m), e_top_three(m), sigm1(m), e_eq_emax_and_sigm1(m), e_eq_emax(m); expr_ref e3(m), ne3(m), e2(m), e1(m), e21(m), one_1(m), h_exp(m), sh_exp(m), th_exp(m); @@ -3998,12 +3916,11 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & // put the sticky bit into the significand. expr_ref ext_sticky(m); ext_sticky = m_bv_util.mk_zero_extend(sbits+1, sticky); - expr * tmp[] = { sig, ext_sticky }; + expr * tmp[2] = { sig, ext_sticky }; sig = m_bv_util.mk_bv_or(2, tmp); SASSERT(is_well_sorted(m, sig)); SASSERT(m_bv_util.get_bv_size(sig) == sbits+2); - // CMW: The (OVF1 && OVFen) and (TINY && UNFen) cases are never taken. expr_ref ext_emin(m); ext_emin = m_bv_util.mk_zero_extend(2, e_min); m_simp.mk_ite(TINY, ext_emin, beta, exp); @@ -4106,7 +4023,6 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & dbg_decouple("fpa2bv_rnd_rm_is_to_neg", rm_is_to_neg); dbg_decouple("fpa2bv_rnd_rm_is_to_pos", rm_is_to_pos); - expr_ref sgn_is_zero(m), zero1(m); zero1 = m_bv_util.mk_numeral(0, 1); m_simp.mk_eq(sgn, zero1, sgn_is_zero); @@ -4170,13 +4086,25 @@ void fpa2bv_converter::reset(void) { dec_ref_map_key_values(m, m_const2bv); dec_ref_map_key_values(m, m_rm_const2bv); dec_ref_map_key_values(m, m_uf2bvuf); - for (obj_map >::iterator it = m_min_max_specials.begin(); - it != m_min_max_specials.end(); + for (obj_map >::iterator it = m_min_max_ufs.begin(); + it != m_min_max_ufs.end(); it++) { m.dec_ref(it->m_key); m.dec_ref(it->m_value.first); m.dec_ref(it->m_value.second); } - m_min_max_specials.reset(); + m_min_max_ufs.reset(); m_extra_assertions.reset(); } + +func_decl * fpa2bv_converter::mk_bv_uf(func_decl * f, sort * const * domain, sort * range) { + func_decl * res; + if (!m_uf2bvuf.find(f, res)) { + res = m.mk_fresh_func_decl(0, f->get_arity(), domain, range); + m_uf2bvuf.insert(f, res); + m.inc_ref(f); + m.inc_ref(res); + TRACE("fpa2bv", tout << "New UF func_decl: " << std::endl << mk_ismt2_pp(res, m) << std::endl;); + } + return res; +} diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 34417b7fc..f0e50ba2d 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -19,17 +19,17 @@ Notes: #ifndef FPA2BV_CONVERTER_H_ #define FPA2BV_CONVERTER_H_ -#include"ast.h" -#include"obj_hashtable.h" -#include"ref_util.h" -#include"fpa_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"array_decl_plugin.h" -#include"datatype_decl_plugin.h" -#include"dl_decl_plugin.h" -#include"pb_decl_plugin.h" -#include"seq_decl_plugin.h" -#include"basic_simplifier_plugin.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "util/ref_util.h" +#include "ast/fpa_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/dl_decl_plugin.h" +#include "ast/pb_decl_plugin.h" +#include "ast/seq_decl_plugin.h" +#include "ast/rewriter/bool_rewriter.h" class fpa2bv_converter { public: @@ -39,7 +39,7 @@ public: protected: ast_manager & m; - basic_simplifier_plugin m_simp; + bool_rewriter m_simp; fpa_util m_util; bv_util m_bv_util; arith_util m_arith_util; @@ -53,7 +53,7 @@ protected: const2bv_t m_const2bv; const2bv_t m_rm_const2bv; uf2bvuf_t m_uf2bvuf; - special_t m_min_max_specials; + special_t m_min_max_ufs; friend class fpa2bv_model_converter; friend class bv2fpa_converter; @@ -76,6 +76,7 @@ public: void split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const; void split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_ref & sig) const; + void join_fp(expr * e, expr_ref & res); void mk_eq(expr * a, expr * b, expr_ref & result); void mk_ite(expr * c, expr * t, expr * f, expr_ref & result); @@ -86,7 +87,7 @@ public: void mk_numeral(sort * s, mpf const & v, expr_ref & result); virtual void mk_const(func_decl * f, expr_ref & result); virtual void mk_rm_const(func_decl * f, expr_ref & result); - virtual void mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + virtual void mk_uf(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_var(unsigned base_inx, sort * srt, expr_ref & result); void mk_pinf(func_decl * f, expr_ref & result); @@ -138,27 +139,23 @@ public: void mk_to_fp_real_int(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_ubv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_sbv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_to_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void set_unspecified_fp_hi(bool v) { m_hi_fp_unspecified = v; } void mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_min_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - virtual expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y); - void mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_max_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y); void reset(void); void dbg_decouple(const char * prefix, expr_ref & e); expr_ref_vector m_extra_assertions; - special_t const & get_min_max_specials() const { return m_min_max_specials; }; + special_t const & get_min_max_specials() const { return m_min_max_ufs; }; const2bv_t const & get_const2bv() const { return m_const2bv; }; const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; }; uf2bvuf_t const & get_uf2bvuf() const { return m_uf2bvuf; }; @@ -202,12 +199,6 @@ protected: void mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result); - sort_ref replace_float_sorts(sort * s); - func_decl_ref replace_function(func_decl * f); - expr_ref replace_float_arg(expr * a); - void mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result); - func_decl * get_bv_uf(func_decl * f, sort * bv_rng, unsigned arity); - private: void mk_nan(sort * s, expr_ref & result); void mk_nzero(sort * s, expr_ref & result); @@ -227,9 +218,7 @@ private: void mk_to_fp_float(sort * s, expr * rm, expr * x, expr_ref & result); - expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); - expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); - expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits); + func_decl * mk_bv_uf(func_decl * f, sort * const * domain, sort * range); }; #endif diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 32b62342b..6c96d92c1 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -18,10 +18,10 @@ Notes: --*/ -#include"rewriter_def.h" -#include"fpa2bv_rewriter.h" -#include"cooperate.h" -#include"fpa2bv_rewriter_params.hpp" +#include "ast/rewriter/rewriter_def.h" +#include "ast/fpa/fpa2bv_rewriter.h" +#include "util/cooperate.h" +#include "ast/fpa/fpa2bv_rewriter_params.hpp" fpa2bv_rewriter_cfg::fpa2bv_rewriter_cfg(ast_manager & m, fpa2bv_converter & c, params_ref const & p) : @@ -124,6 +124,8 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_DIV: m_conv.mk_div(f, num, args, result); return BR_DONE; case OP_FPA_REM: m_conv.mk_rem(f, num, args, result); return BR_DONE; case OP_FPA_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE; + case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_DONE; + case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_DONE; case OP_FPA_FMA: m_conv.mk_fma(f, num, args, result); return BR_DONE; case OP_FPA_SQRT: m_conv.mk_sqrt(f, num, args, result); return BR_DONE; case OP_FPA_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, num, args, result); return BR_DONE; @@ -143,24 +145,12 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_TO_FP_UNSIGNED: m_conv.mk_to_fp_unsigned(f, num, args, result); return BR_DONE; case OP_FPA_FP: m_conv.mk_fp(f, num, args, result); return BR_DONE; case OP_FPA_TO_UBV: m_conv.mk_to_ubv(f, num, args, result); return BR_DONE; - case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: m_conv.mk_to_ubv_unspecified(f, num, args, result); return BR_DONE; case OP_FPA_TO_SBV: m_conv.mk_to_sbv(f, num, args, result); return BR_DONE; - case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: m_conv.mk_to_sbv_unspecified(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_INTERNAL_TO_REAL_UNSPECIFIED: m_conv.mk_to_real_unspecified(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_INTERNAL_TO_IEEE_BV_UNSPECIFIED: m_conv.mk_to_ieee_bv_unspecified(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_INTERNAL_MIN_UNSPECIFIED: - case OP_FPA_INTERNAL_MAX_UNSPECIFIED: result = m_conv.mk_min_max_unspecified(f, args[0], args[1]); return BR_DONE; - case OP_FPA_INTERNAL_MIN_I: m_conv.mk_min_i(f, num, args, result); return BR_DONE; - case OP_FPA_INTERNAL_MAX_I: m_conv.mk_max_i(f, num, args, result); return BR_DONE; - - case OP_FPA_INTERNAL_BVWRAP: - case OP_FPA_INTERNAL_BV2RM: + case OP_FPA_BVWRAP: + case OP_FPA_BV2RM: return BR_FAILED; default: @@ -173,7 +163,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co { SASSERT(!m_conv.is_float_family(f)); if (m_conv.fu().contains_floats(f)) { - m_conv.mk_function(f, num, args, result); + m_conv.mk_uf(f, num, args, result); return BR_DONE; } } diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index a130c445b..ab87a3d68 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -20,9 +20,9 @@ Notes: #ifndef FPA2BV_REWRITER_H_ #define FPA2BV_REWRITER_H_ -#include"rewriter.h" -#include"bv_decl_plugin.h" -#include"fpa2bv_converter.h" +#include "ast/rewriter/rewriter.h" +#include "ast/bv_decl_plugin.h" +#include "ast/fpa/fpa2bv_converter.h" struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { ast_manager & m_manager; diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index e039bcbd9..9d298b413 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"fpa_decl_plugin.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" +#include "ast/fpa_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" fpa_decl_plugin::fpa_decl_plugin(): m_values(m_fm), @@ -361,10 +361,6 @@ func_decl * fpa_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_parameters case OP_FPA_REM: name = "fp.rem"; break; case OP_FPA_MIN: name = "fp.min"; break; case OP_FPA_MAX: name = "fp.max"; break; - case OP_FPA_INTERNAL_MIN_I: name = "fp.min_i"; break; - case OP_FPA_INTERNAL_MAX_I: name = "fp.max_i"; break; - case OP_FPA_INTERNAL_MIN_UNSPECIFIED: name = "fp.min_unspecified"; break; - case OP_FPA_INTERNAL_MAX_UNSPECIFIED: name = "fp.max_unspecified"; break; default: UNREACHABLE(); break; @@ -676,10 +672,10 @@ func_decl * fpa_decl_plugin::mk_to_ieee_bv(decl_kind k, unsigned num_parameters, return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k)); } -func_decl * fpa_decl_plugin::mk_internal_bv2rm(decl_kind k, unsigned num_parameters, parameter const * parameters, +func_decl * fpa_decl_plugin::mk_bv2rm(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { if (arity != 1) - m_manager->raise_exception("invalid number of arguments to internal_rm"); + m_manager->raise_exception("invalid number of arguments to bv2rm"); if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) || domain[0]->get_parameter(0).get_int() != 3) m_manager->raise_exception("sort mismatch, expected argument of sort bitvector, size 3"); if (!is_rm_sort(range)) @@ -690,7 +686,7 @@ func_decl * fpa_decl_plugin::mk_internal_bv2rm(decl_kind k, unsigned num_paramet return m_manager->mk_func_decl(symbol("rm"), 1, &bv_srt, range, func_decl_info(m_family_id, k, num_parameters, parameters)); } -func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters, +func_decl * fpa_decl_plugin::mk_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { if (arity != 1) m_manager->raise_exception("invalid number of arguments to bv_wrap"); @@ -711,65 +707,6 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param } } -func_decl * fpa_decl_plugin::mk_internal_to_ubv_unspecified( - decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - if (arity != 0) - m_manager->raise_exception("invalid number of arguments to fp.to_ubv_unspecified"); - if (num_parameters != 3) - m_manager->raise_exception("invalid number of parameters to fp.to_ubv_unspecified; expecting 3"); - if (!parameters[0].is_int() || !parameters[1].is_int() || !parameters[2].is_int()) - m_manager->raise_exception("invalid parameters type provided to fp.to_ubv_unspecified; expecting 3 integers"); - - sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ¶meters[2]); - return m_manager->mk_func_decl(symbol("fp.to_ubv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); -} - -func_decl * fpa_decl_plugin::mk_internal_to_sbv_unspecified( - decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - if (arity != 0) - m_manager->raise_exception("invalid number of arguments to fp.to_sbv_unspecified"); - if (num_parameters != 3) - m_manager->raise_exception("invalid number of parameters to fp.to_sbv_unspecified; expecting 3"); - if (!parameters[0].is_int() || !parameters[1].is_int() || !parameters[2].is_int()) - m_manager->raise_exception("invalid parameters type provided to fp.to_sbv_unspecified; expecting 3 integers"); - - sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ¶meters[2]); - return m_manager->mk_func_decl(symbol("fp.to_sbv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); -} - -func_decl * fpa_decl_plugin::mk_internal_to_real_unspecified( - decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - if (arity != 0) - m_manager->raise_exception("invalid number of arguments to fp.to_real_unspecified"); - if (num_parameters != 2) - m_manager->raise_exception("invalid number of parameters to fp.to_real_unspecified; expecting 2"); - if (!parameters[0].is_int() || !parameters[1].is_int()) - m_manager->raise_exception("invalid parameters type provided to fp.to_real_unspecified; expecting 2 integers"); - if (!is_sort_of(range, m_arith_fid, REAL_SORT)) - m_manager->raise_exception("sort mismatch, expected range of Real sort"); - - return m_manager->mk_func_decl(symbol("fp.to_real_unspecified"), 0, domain, m_real_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); -} - -func_decl * fpa_decl_plugin::mk_internal_to_ieee_bv_unspecified( - decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - if (arity != 0) - m_manager->raise_exception("invalid number of arguments to fp.to_ieee_bv_unspecified; expecting none"); - if (num_parameters != 2) - m_manager->raise_exception("invalid number of parameters to fp.to_ieee_bv_unspecified; expecting 2"); - if (!parameters[0].is_int() || !parameters[1].is_int()) - m_manager->raise_exception("invalid parameters type provided to fp.to_ieee_bv_unspecified; expecting 2 integers"); - - parameter width_p[1] = { parameter(parameters[0].get_int() + parameters[1].get_int()) }; - sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, width_p); - return m_manager->mk_func_decl(symbol("fp.to_ieee_bv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); -} - - func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { switch (k) { @@ -835,25 +772,11 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_FPA_TO_IEEE_BV: return mk_to_ieee_bv(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_BVWRAP: - return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_BV2RM: - return mk_internal_bv2rm(k, num_parameters, parameters, arity, domain, range); + case OP_FPA_BVWRAP: + return mk_bv_wrap(k, num_parameters, parameters, arity, domain, range); + case OP_FPA_BV2RM: + return mk_bv2rm(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_MIN_I: - case OP_FPA_INTERNAL_MAX_I: - case OP_FPA_INTERNAL_MIN_UNSPECIFIED: - case OP_FPA_INTERNAL_MAX_UNSPECIFIED: - return mk_binary_decl(k, num_parameters, parameters, arity, domain, range); - - case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: - return mk_internal_to_ubv_unspecified(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: - return mk_internal_to_sbv_unspecified(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: - return mk_internal_to_real_unspecified(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: - return mk_internal_to_ieee_bv_unspecified(k, num_parameters, parameters, arity, domain, range); default: m_manager->raise_exception("unsupported floating point operator"); return 0; @@ -1054,30 +977,6 @@ app * fpa_util::mk_nzero(unsigned ebits, unsigned sbits) { return mk_value(v); } -app * fpa_util::mk_internal_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) { - parameter ps[] = { parameter(ebits), parameter(sbits), parameter(width) }; - sort * range = m_bv_util.mk_sort(width); - return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, 3, ps, 0, 0, range); -} - -app * fpa_util::mk_internal_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) { - parameter ps[] = { parameter(ebits), parameter(sbits), parameter(width) }; - sort * range = m_bv_util.mk_sort(width); - return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, 3, ps, 0, 0, range); -} - -app * fpa_util::mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits) { - parameter ps[] = { parameter(ebits), parameter(sbits) }; - sort * range = m_bv_util.mk_sort(ebits+sbits); - return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED, 2, ps, 0, 0, range); -} - -app * fpa_util::mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits) { - parameter ps[] = { parameter(ebits), parameter(sbits) }; - sort * range = m_a_util.mk_real(); - return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, 2, ps, 0, 0, range); -} - bool fpa_util::contains_floats(ast * a) { switch (a->get_kind()) { case AST_APP: { diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index cf341a07b..4e86c9d3f 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -19,11 +19,11 @@ Revision History: #ifndef fpa_decl_plugin_H_ #define fpa_decl_plugin_H_ -#include"ast.h" -#include"id_gen.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"mpf.h" +#include "ast/ast.h" +#include "util/id_gen.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "util/mpf.h" enum fpa_sort_kind { FLOATING_POINT_SORT, @@ -86,18 +86,8 @@ enum fpa_op_kind { /* Extensions */ OP_FPA_TO_IEEE_BV, - /* Internal use only */ - OP_FPA_INTERNAL_BVWRAP, - OP_FPA_INTERNAL_BV2RM, - - OP_FPA_INTERNAL_MIN_I, - OP_FPA_INTERNAL_MAX_I, - OP_FPA_INTERNAL_MIN_UNSPECIFIED, - OP_FPA_INTERNAL_MAX_UNSPECIFIED, - OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, - OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, - OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED, - OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, + OP_FPA_BVWRAP, + OP_FPA_BV2RM, LAST_FLOAT_OP }; @@ -164,40 +154,16 @@ class fpa_decl_plugin : public decl_plugin { func_decl * mk_to_ieee_bv(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_bv2rm(decl_kind k, unsigned num_parameters, parameter const * parameters, + func_decl * mk_bv2rm(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters, + func_decl * mk_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_bv_unwrap(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_to_ubv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_to_sbv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_to_real_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_to_ieee_bv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); virtual void set_manager(ast_manager * m, family_id id); unsigned mk_id(mpf const & v); void recycled_id(unsigned id); - virtual bool is_considered_uninterpreted(func_decl * f) { - if (f->get_family_id() != get_family_id()) - return false; - switch (f->get_decl_kind()) - { - case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: - return true; - default: - return false; - } - return false; - } + virtual bool is_considered_uninterpreted(func_decl * f) { return false; } public: fpa_decl_plugin(); @@ -251,6 +217,7 @@ public: family_id get_fid() const { return m_fid; } family_id get_family_id() const { return m_fid; } arith_util & au() { return m_a_util; } + bv_util & bu() { return m_bv_util; } fpa_decl_plugin & plugin() { return *m_plugin; } sort * mk_float_sort(unsigned ebits, unsigned sbits); @@ -375,35 +342,18 @@ public: app * mk_bv2rm(expr * bv3) { SASSERT(m_bv_util.is_bv(bv3) && m_bv_util.get_bv_size(bv3) == 3); - return m().mk_app(m_fid, OP_FPA_INTERNAL_BV2RM, 0, 0, 1, &bv3, mk_rm_sort()); + return m().mk_app(m_fid, OP_FPA_BV2RM, 0, 0, 1, &bv3, mk_rm_sort()); } - app * mk_internal_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); - app * mk_internal_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); - app * mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits); - app * mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits); - bool is_bvwrap(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); } - bool is_bvwrap(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BVWRAP; } - bool is_bv2rm(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BV2RM); } - bool is_bv2rm(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BV2RM; } + bool is_bvwrap(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_BVWRAP); } + bool is_bv2rm(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_BV2RM); } + bool is_to_ubv(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_TO_UBV); } + bool is_to_sbv(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_TO_SBV); } - bool is_min_interpreted(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_I); } - bool is_min_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED); } - bool is_max_interpreted(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_I); } - bool is_max_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED); } - bool is_to_ubv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED); } - bool is_to_sbv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED); } - bool is_to_ieee_bv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED); } - bool is_to_real_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED); } - - bool is_min_interpreted(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_I; } - bool is_min_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_UNSPECIFIED; } - bool is_max_interpreted(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_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_INTERNAL_MAX_UNSPECIFIED; } - bool is_to_ubv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED; } - bool is_to_sbv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED; } - bool is_to_ieee_bv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED; } - bool is_to_real_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED; } + bool is_bvwrap(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BVWRAP; } + bool is_bv2rm(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BV2RM; } + bool is_to_ubv(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_TO_UBV; } + bool is_to_sbv(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_TO_SBV; } bool contains_floats(ast * a); }; diff --git a/src/ast/func_decl_dependencies.cpp b/src/ast/func_decl_dependencies.cpp index d53c2d9b1..a5412f206 100644 --- a/src/ast/func_decl_dependencies.cpp +++ b/src/ast/func_decl_dependencies.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"func_decl_dependencies.h" -#include"for_each_expr.h" -#include"ast_util.h" +#include "ast/func_decl_dependencies.h" +#include "ast/for_each_expr.h" +#include "ast/ast_util.h" struct collect_dependencies_proc { ast_manager & m_manager; diff --git a/src/ast/func_decl_dependencies.h b/src/ast/func_decl_dependencies.h index e354540c2..0a3c1892f 100644 --- a/src/ast/func_decl_dependencies.h +++ b/src/ast/func_decl_dependencies.h @@ -19,8 +19,8 @@ Revision History: #ifndef FUNC_DECL_DEPENDENCIES_H_ #define FUNC_DECL_DEPENDENCIES_H_ -#include"ast.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" // Set of dependencies typedef obj_hashtable func_decl_set; diff --git a/src/ast/has_free_vars.cpp b/src/ast/has_free_vars.cpp index ba2c9eeb8..09d6d7740 100644 --- a/src/ast/has_free_vars.cpp +++ b/src/ast/has_free_vars.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"ast.h" -#include"expr_delta_pair.h" -#include"hashtable.h" +#include "ast/ast.h" +#include "ast/expr_delta_pair.h" +#include "util/hashtable.h" class contains_vars { typedef hashtable, default_eq > cache; diff --git a/src/ast/justified_expr.h b/src/ast/justified_expr.h new file mode 100644 index 000000000..8aa961686 --- /dev/null +++ b/src/ast/justified_expr.h @@ -0,0 +1,52 @@ + +#ifndef JUSTIFIED_EXPR_H_ +#define JUSTIFIED_EXPR_H_ + +#include "ast/ast.h" + +class justified_expr { + ast_manager& m; + expr* m_fml; + proof* m_proof; +public: + justified_expr(ast_manager& m, expr* fml, proof* p): + m(m), + m_fml(fml), + m_proof(p) { + SASSERT(fml); + m.inc_ref(fml); + m.inc_ref(p); + } + + justified_expr& operator=(justified_expr const& other) { + SASSERT(&m == &other.m); + if (this != &other) { + m.inc_ref(other.get_fml()); + m.inc_ref(other.get_proof()); + m.dec_ref(m_fml); + m.dec_ref(m_proof); + m_fml = other.get_fml(); + m_proof = other.get_proof(); + } + return *this; + } + + justified_expr(justified_expr const& other): + m(other.m), + m_fml(other.m_fml), + m_proof(other.m_proof) + { + m.inc_ref(m_fml); + m.inc_ref(m_proof); + } + + ~justified_expr() { + m.dec_ref(m_fml); + m.dec_ref(m_proof); + } + + expr* get_fml() const { return m_fml; } + proof* get_proof() const { return m_proof; } +}; + +#endif diff --git a/src/ast/macro_substitution.cpp b/src/ast/macro_substitution.cpp index 9cf337d21..7b4cd6244 100644 --- a/src/ast/macro_substitution.cpp +++ b/src/ast/macro_substitution.cpp @@ -18,8 +18,8 @@ Author: Notes: --*/ -#include"macro_substitution.h" -#include"ref_util.h" +#include "ast/macro_substitution.h" +#include "util/ref_util.h" typedef obj_map func_decl2proof; typedef obj_map func_decl2expr_dependency; diff --git a/src/ast/macro_substitution.h b/src/ast/macro_substitution.h index 356449590..7c65421fd 100644 --- a/src/ast/macro_substitution.h +++ b/src/ast/macro_substitution.h @@ -21,7 +21,7 @@ Notes: #ifndef MACRO_SUBSTITUTION_H_ #define MACRO_SUBSTITUTION_H_ -#include"ast.h" +#include "ast/ast.h" class macro_substitution { ast_manager & m_manager; diff --git a/src/ast/macros/CMakeLists.txt b/src/ast/macros/CMakeLists.txt index ca38b4759..ec6d7e26c 100644 --- a/src/ast/macros/CMakeLists.txt +++ b/src/ast/macros/CMakeLists.txt @@ -5,5 +5,5 @@ z3_add_component(macros macro_util.cpp quasi_macros.cpp COMPONENT_DEPENDENCIES - simplifier + rewriter ) diff --git a/src/ast/macros/macro_finder.cpp b/src/ast/macros/macro_finder.cpp index ee211c44f..ed067f331 100644 --- a/src/ast/macros/macro_finder.cpp +++ b/src/ast/macros/macro_finder.cpp @@ -17,100 +17,167 @@ Revision History: --*/ -#include"macro_finder.h" -#include"occurs.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" +#include "ast/macros/macro_finder.h" +#include "ast/occurs.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) { if (!is_quantifier(n) || !to_quantifier(n)->is_forall()) return false; - TRACE("macro_finder", tout << "processing: " << mk_pp(n, m_manager) << "\n";); + TRACE("macro_finder", tout << "processing: " << mk_pp(n, m) << "\n";); expr * body = to_quantifier(n)->get_expr(); unsigned num_decls = to_quantifier(n)->get_num_decls(); return m_util.is_simple_macro(body, num_decls, head, def); } /** - \brief Detect macros of the form + \brief Detect macros of the form 1- (forall (X) (= (+ (f X) (R X)) c)) 2- (forall (X) (<= (+ (f X) (R X)) c)) 3- (forall (X) (>= (+ (f X) (R X)) c)) The second and third cases are first converted into (forall (X) (= (f X) (+ c (* -1 (R x)) (k X)))) - and + and (forall (X) (<= (k X) 0)) when case 2 (forall (X) (>= (k X) 0)) when case 3 For case 2 & 3, the new quantifiers are stored in new_exprs and new_prs. */ -bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) { +bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_dependency * dep, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) { if (!is_quantifier(n) || !to_quantifier(n)->is_forall()) return false; - arith_simplifier_plugin * as = get_arith_simp(); - arith_util & autil = as->get_arith_util(); expr * body = to_quantifier(n)->get_expr(); unsigned num_decls = to_quantifier(n)->get_num_decls(); - if (!autil.is_le(body) && !autil.is_ge(body) && !m_manager.is_eq(body)) + if (!m_autil.is_le(body) && !m_autil.is_ge(body) && !m.is_eq(body)) return false; - if (!as->is_add(to_app(body)->get_arg(0))) + if (!m_autil.is_add(to_app(body)->get_arg(0))) return false; - app_ref head(m_manager); - expr_ref def(m_manager); + app_ref head(m); + expr_ref def(m); bool inv = false; if (!m_util.is_arith_macro(body, num_decls, head, def, inv)) return false; - app_ref new_body(m_manager); - - if (!inv || m_manager.is_eq(body)) - new_body = m_manager.mk_app(to_app(body)->get_decl(), head, def); - else if (as->is_le(body)) - new_body = autil.mk_ge(head, def); - else - new_body = autil.mk_le(head, def); + app_ref new_body(m); - quantifier_ref new_q(m_manager); - new_q = m_manager.update_quantifier(to_quantifier(n), new_body); + if (!inv || m.is_eq(body)) + new_body = m.mk_app(to_app(body)->get_decl(), head, def); + else if (m_autil.is_le(body)) + new_body = m_autil.mk_ge(head, def); + else + new_body = m_autil.mk_le(head, def); + + quantifier_ref new_q(m); + new_q = m.update_quantifier(to_quantifier(n), new_body); proof * new_pr = 0; - if (m_manager.proofs_enabled()) { - proof * rw = m_manager.mk_rewrite(n, new_q); - new_pr = m_manager.mk_modus_ponens(pr, rw); + if (m.proofs_enabled()) { + proof * rw = m.mk_rewrite(n, new_q); + new_pr = m.mk_modus_ponens(pr, rw); } - if (m_manager.is_eq(body)) { + expr_dependency * new_dep = dep; + if (m.is_eq(body)) { + return m_macro_manager.insert(head->get_decl(), new_q, new_pr, new_dep); + } + // is ge or le + // + TRACE("macro_finder", tout << "is_arith_macro: is_ge or is_le\n";); + func_decl * f = head->get_decl(); + func_decl * k = m.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range()); + app * k_app = m.mk_app(k, head->get_num_args(), head->get_args()); + expr_ref_buffer new_rhs_args(m); + expr_ref new_rhs2(m_autil.mk_add(def, k_app), m); + expr * body1 = m.mk_eq(head, new_rhs2); + expr * body2 = m.mk_app(new_body->get_decl(), k_app, m_autil.mk_int(0)); + quantifier * q1 = m.update_quantifier(new_q, body1); + expr * patterns[1] = { m.mk_pattern(k_app) }; + quantifier * q2 = m.update_quantifier(new_q, 1, patterns, body2); + new_exprs.push_back(q1); + new_exprs.push_back(q2); + if (m.proofs_enabled()) { + // new_pr : new_q + // rw : [rewrite] new_q ~ q1 & q2 + // mp : [modus_pones new_pr rw] q1 & q2 + // pr1 : [and-elim mp] q1 + // pr2 : [and-elim mp] q2 + app * q1q2 = m.mk_and(q1,q2); + proof * rw = m.mk_oeq_rewrite(new_q, q1q2); + proof * mp = m.mk_modus_ponens(new_pr, rw); + proof * pr1 = m.mk_and_elim(mp, 0); + proof * pr2 = m.mk_and_elim(mp, 1); + new_prs.push_back(pr1); + new_prs.push_back(pr2); + } + if (dep) { + new_deps.push_back(new_dep); + new_deps.push_back(new_dep); + } + return true; +} + +bool macro_finder::is_arith_macro(expr * n, proof * pr, vector& new_fmls) { + if (!is_quantifier(n) || !to_quantifier(n)->is_forall()) + return false; + expr * body = to_quantifier(n)->get_expr(); + unsigned num_decls = to_quantifier(n)->get_num_decls(); + + if (!m_autil.is_le(body) && !m_autil.is_ge(body) && !m.is_eq(body)) + return false; + if (!m_autil.is_add(to_app(body)->get_arg(0))) + return false; + app_ref head(m); + expr_ref def(m); + bool inv = false; + if (!m_util.is_arith_macro(body, num_decls, head, def, inv)) + return false; + app_ref new_body(m); + + if (!inv || m.is_eq(body)) + new_body = m.mk_app(to_app(body)->get_decl(), head, def); + else if (m_autil.is_le(body)) + new_body = m_autil.mk_ge(head, def); + else + new_body = m_autil.mk_le(head, def); + + quantifier_ref new_q(m); + new_q = m.update_quantifier(to_quantifier(n), new_body); + proof * new_pr = 0; + if (m.proofs_enabled()) { + proof * rw = m.mk_rewrite(n, new_q); + new_pr = m.mk_modus_ponens(pr, rw); + } + if (m.is_eq(body)) { return m_macro_manager.insert(head->get_decl(), new_q, new_pr); } // is ge or le // TRACE("macro_finder", tout << "is_arith_macro: is_ge or is_le\n";); func_decl * f = head->get_decl(); - func_decl * k = m_manager.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range()); - app * k_app = m_manager.mk_app(k, head->get_num_args(), head->get_args()); - expr_ref_buffer new_rhs_args(m_manager); - expr_ref new_rhs2(m_manager); - as->mk_add(def, k_app, new_rhs2); - expr * body1 = m_manager.mk_eq(head, new_rhs2); - expr * body2 = m_manager.mk_app(new_body->get_decl(), k_app, as->mk_numeral(rational(0))); - quantifier * q1 = m_manager.update_quantifier(new_q, body1); - expr * patterns[1] = { m_manager.mk_pattern(k_app) }; - quantifier * q2 = m_manager.update_quantifier(new_q, 1, patterns, body2); - new_exprs.push_back(q1); - new_exprs.push_back(q2); - if (m_manager.proofs_enabled()) { + func_decl * k = m.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range()); + app * k_app = m.mk_app(k, head->get_num_args(), head->get_args()); + expr_ref_buffer new_rhs_args(m); + expr_ref new_rhs2(m_autil.mk_add(def, k_app), m); + expr * body1 = m.mk_eq(head, new_rhs2); + expr * body2 = m.mk_app(new_body->get_decl(), k_app, m_autil.mk_int(0)); + quantifier * q1 = m.update_quantifier(new_q, body1); + expr * patterns[1] = { m.mk_pattern(k_app) }; + quantifier * q2 = m.update_quantifier(new_q, 1, patterns, body2); + proof* pr1 = 0, *pr2 = 0; + if (m.proofs_enabled()) { // new_pr : new_q // rw : [rewrite] new_q ~ q1 & q2 // mp : [modus_pones new_pr rw] q1 & q2 // pr1 : [and-elim mp] q1 // pr2 : [and-elim mp] q2 - app * q1q2 = m_manager.mk_and(q1,q2); - proof * rw = m_manager.mk_oeq_rewrite(new_q, q1q2); - proof * mp = m_manager.mk_modus_ponens(new_pr, rw); - proof * pr1 = m_manager.mk_and_elim(mp, 0); - proof * pr2 = m_manager.mk_and_elim(mp, 1); - new_prs.push_back(pr1); - new_prs.push_back(pr2); + app * q1q2 = m.mk_and(q1,q2); + proof * rw = m.mk_oeq_rewrite(new_q, q1q2); + proof * mp = m.mk_modus_ponens(new_pr, rw); + pr1 = m.mk_and_elim(mp, 0); + pr2 = m.mk_and_elim(mp, 1); } + new_fmls.push_back(justified_expr(m, q1, pr1)); + new_fmls.push_back(justified_expr(m, q2, pr2)); return true; } @@ -118,7 +185,7 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_ex n is of the form: (forall (X) (iff (= (f X) t) def[X])) Convert it into: - + (forall (X) (= (f X) (ite def[X] t (k X)))) (forall (X) (not (= (k X) t))) @@ -126,13 +193,13 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_ex The new quantifiers and proofs are stored in new_exprs and new_prs */ -static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, expr * def, quantifier * q, proof * pr, - expr_ref_vector & new_exprs, proof_ref_vector & new_prs) { +static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, expr * def, quantifier * q, proof * pr, expr_dependency * dep, + expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps ) { func_decl * f = head->get_decl(); func_decl * k = m.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range()); app * k_app = m.mk_app(k, head->get_num_args(), head->get_args()); app * ite = m.mk_ite(def, t, k_app); - app * body_1 = m.mk_eq(head, ite); + app * body_1 = m.mk_eq(head, ite); app * body_2 = m.mk_not(m.mk_eq(k_app, t)); quantifier * q1 = m.update_quantifier(q, body_1); expr * pats[1] = { m.mk_pattern(k_app) }; @@ -153,68 +220,158 @@ static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, e new_prs.push_back(pr1); new_prs.push_back(pr2); } + new_deps.push_back(dep); + new_deps.push_back(dep); +} + +static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, expr * def, quantifier * q, proof * pr, + vector& new_fmls) { + func_decl * f = head->get_decl(); + func_decl * k = m.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range()); + app * k_app = m.mk_app(k, head->get_num_args(), head->get_args()); + app * ite = m.mk_ite(def, t, k_app); + app * body_1 = m.mk_eq(head, ite); + app * body_2 = m.mk_not(m.mk_eq(k_app, t)); + quantifier * q1 = m.update_quantifier(q, body_1); + proof * pr1 = 0, *pr2 = 0; + expr * pats[1] = { m.mk_pattern(k_app) }; + quantifier * q2 = m.update_quantifier(q, 1, pats, body_2); // erase patterns + if (m.proofs_enabled()) { + // r : [rewrite] q ~ q1 & q2 + // pr : q + // mp : [modus_pones pr pr1] q1 & q2 + // pr1 : [and-elim mp] q1 + // pr2 : [and-elim mp] q2 + app * q1q2 = m.mk_and(q1,q2); + proof * r = m.mk_oeq_rewrite(q, q1q2); + proof * mp = m.mk_modus_ponens(pr, r); + pr1 = m.mk_and_elim(mp, 0); + pr2 = m.mk_and_elim(mp, 1); + } + new_fmls.push_back(justified_expr(m, q1, pr1)); + new_fmls.push_back(justified_expr(m, q2, pr2)); } macro_finder::macro_finder(ast_manager & m, macro_manager & mm): - m_manager(m), + m(m), m_macro_manager(mm), - m_util(mm.get_util()) { + m_util(mm.get_util()), + m_autil(m) { } macro_finder::~macro_finder() { } -bool macro_finder::expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) { +bool macro_finder::expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) { TRACE("macro_finder", tout << "starting expand_macros:\n"; m_macro_manager.display(tout);); bool found_new_macro = false; for (unsigned i = 0; i < num; i++) { expr * n = exprs[i]; - proof * pr = m_manager.proofs_enabled() ? prs[i] : 0; - expr_ref new_n(m_manager), def(m_manager); - proof_ref new_pr(m_manager); - m_macro_manager.expand_macros(n, pr, new_n, new_pr); - app_ref head(m_manager), t(m_manager); - if (is_macro(new_n, head, def) && m_macro_manager.insert(head->get_decl(), to_quantifier(new_n.get()), new_pr)) { + proof * pr = m.proofs_enabled() ? prs[i] : 0; + expr_dependency * depi = deps != 0 ? deps[i] : 0; + expr_ref new_n(m), def(m); + proof_ref new_pr(m); + expr_dependency_ref new_dep(m); + m_macro_manager.expand_macros(n, pr, depi, new_n, new_pr, new_dep); + app_ref head(m), t(m); + if (is_macro(new_n, head, def) && m_macro_manager.insert(head->get_decl(), to_quantifier(new_n.get()), new_pr, new_dep)) { TRACE("macro_finder_found", tout << "found new macro: " << head->get_decl()->get_name() << "\n" << new_n << "\n";); found_new_macro = true; } - else if (is_arith_macro(new_n, new_pr, new_exprs, new_prs)) { + else if (is_arith_macro(new_n, new_pr, new_dep, new_exprs, new_prs, new_deps)) { TRACE("macro_finder_found", tout << "found new arith macro:\n" << new_n << "\n";); found_new_macro = true; } - else if (m_util.is_pseudo_predicate_macro(new_n, head, t, def)) { + else if (m_util.is_pseudo_predicate_macro(new_n, head, t, def)) { TRACE("macro_finder_found", tout << "found new pseudo macro:\n" << head << "\n" << t << "\n" << def << "\n";); - pseudo_predicate_macro2macro(m_manager, head, t, def, to_quantifier(new_n), new_pr, new_exprs, new_prs); + pseudo_predicate_macro2macro(m, head, t, def, to_quantifier(new_n), new_pr, new_dep, new_exprs, new_prs, new_deps); found_new_macro = true; } else { new_exprs.push_back(new_n); - if (m_manager.proofs_enabled()) + if (m.proofs_enabled()) new_prs.push_back(new_pr); + if (deps != 0) + new_deps.push_back(new_dep); } } return found_new_macro; } -void macro_finder::operator()(unsigned num, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) { +void macro_finder::operator()(unsigned num, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) { TRACE("macro_finder", tout << "processing macros...\n";); - expr_ref_vector _new_exprs(m_manager); - proof_ref_vector _new_prs(m_manager); - if (expand_macros(num, exprs, prs, _new_exprs, _new_prs)) { + expr_ref_vector _new_exprs(m); + proof_ref_vector _new_prs(m); + expr_dependency_ref_vector _new_deps(m); + if (expand_macros(num, exprs, prs, deps, _new_exprs, _new_prs, _new_deps)) { while (true) { - expr_ref_vector old_exprs(m_manager); - proof_ref_vector old_prs(m_manager); + expr_ref_vector old_exprs(m); + proof_ref_vector old_prs(m); + expr_dependency_ref_vector old_deps(m); _new_exprs.swap(old_exprs); _new_prs.swap(old_prs); + _new_deps.swap(old_deps); SASSERT(_new_exprs.empty()); SASSERT(_new_prs.empty()); - if (!expand_macros(old_exprs.size(), old_exprs.c_ptr(), old_prs.c_ptr(), _new_exprs, _new_prs)) + SASSERT(_new_deps.empty()); + if (!expand_macros(old_exprs.size(), old_exprs.c_ptr(), old_prs.c_ptr(), old_deps.c_ptr(), + _new_exprs, _new_prs, _new_deps)) break; } } new_exprs.append(_new_exprs); new_prs.append(_new_prs); + new_deps.append(_new_deps); +} + + + +bool macro_finder::expand_macros(unsigned num, justified_expr const * fmls, vector& new_fmls) { + TRACE("macro_finder", tout << "starting expand_macros:\n"; + m_macro_manager.display(tout);); + bool found_new_macro = false; + for (unsigned i = 0; i < num; i++) { + expr * n = fmls[i].get_fml(); + proof * pr = m.proofs_enabled() ? fmls[i].get_proof() : 0; + expr_ref new_n(m), def(m); + proof_ref new_pr(m); + expr_dependency_ref new_dep(m); + m_macro_manager.expand_macros(n, pr, 0, new_n, new_pr, new_dep); + app_ref head(m), t(m); + if (is_macro(new_n, head, def) && m_macro_manager.insert(head->get_decl(), to_quantifier(new_n.get()), new_pr)) { + TRACE("macro_finder_found", tout << "found new macro: " << head->get_decl()->get_name() << "\n" << new_n << "\n";); + found_new_macro = true; + } + else if (is_arith_macro(new_n, new_pr, new_fmls)) { + TRACE("macro_finder_found", tout << "found new arith macro:\n" << new_n << "\n";); + found_new_macro = true; + } + else if (m_util.is_pseudo_predicate_macro(new_n, head, t, def)) { + TRACE("macro_finder_found", tout << "found new pseudo macro:\n" << head << "\n" << t << "\n" << def << "\n";); + pseudo_predicate_macro2macro(m, head, t, def, to_quantifier(new_n), new_pr, new_fmls); + found_new_macro = true; + } + else { + new_fmls.push_back(justified_expr(m, new_n, new_pr)); + } + } + return found_new_macro; +} + +void macro_finder::operator()(unsigned n, justified_expr const* fmls, vector& new_fmls) { + TRACE("macro_finder", tout << "processing macros...\n";); + vector _new_fmls; + if (expand_macros(n, fmls, _new_fmls)) { + while (true) { + vector old_fmls; + _new_fmls.swap(old_fmls); + SASSERT(_new_fmls.empty()); + if (!expand_macros(old_fmls.size(), old_fmls.c_ptr(), _new_fmls)) + break; + } + } + new_fmls.append(_new_fmls); } diff --git a/src/ast/macros/macro_finder.h b/src/ast/macros/macro_finder.h index 04ec11939..2dd72a27f 100644 --- a/src/ast/macros/macro_finder.h +++ b/src/ast/macros/macro_finder.h @@ -19,36 +19,32 @@ Revision History: #ifndef MACRO_FINDER_H_ #define MACRO_FINDER_H_ -#include"macro_manager.h" -#include"arith_simplifier_plugin.h" +#include "ast/macros/macro_manager.h" -bool is_macro_head(expr * n, unsigned num_decls); -bool is_simple_macro(ast_manager & m, expr * n, unsigned num_decls, obj_hashtable const * forbidden_set, app * & head, expr * & def); -inline bool is_simple_macro(ast_manager & m, expr * n, unsigned num_decls, app * & head, expr * & def) { - return is_simple_macro(m, n, num_decls, 0, head, def); -} - /** \brief Macro finder is responsible for finding universally quantified sub-formulas that can be used as macros. */ class macro_finder { - ast_manager & m_manager; + ast_manager & m; macro_manager & m_macro_manager; macro_util & m_util; - arith_simplifier_plugin * get_arith_simp() { return m_util.get_arith_simp(); } - bool expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); + arith_util m_autil; + bool expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_dependency * const* deps, + expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector& new_deps); + bool expand_macros(unsigned n, justified_expr const * fmls, vector& new_fmls); bool is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); + bool is_arith_macro(expr * n, proof * pr, vector& new_fmls); + bool is_arith_macro(expr * n, proof * pr, expr_dependency * dep, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps); bool is_macro(expr * n, app_ref & head, expr_ref & def); - bool is_pseudo_head(expr * n, unsigned num_decls, app * & head, app * & t); - bool is_pseudo_predicate_macro(expr * n, app * & head, app * & t, expr * & def); public: macro_finder(ast_manager & m, macro_manager & mm); ~macro_finder(); - void operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); + void operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const* deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps); + void operator()(unsigned n, justified_expr const* fmls, vector& new_fmls); }; #endif /* MACRO_FINDER_H_ */ diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index b17e1ce28..855cae107 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -19,19 +19,22 @@ Revision History: Leonardo de Moura (leonardo) 2010-12-15: Moved dependency management to func_decl_dependencies.h --*/ -#include"macro_manager.h" -#include"for_each_expr.h" -#include"var_subst.h" -#include"ast_pp.h" -#include"recurse_expr_def.h" +#include "ast/macros/macro_manager.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_pp.h" +#include "ast/recurse_expr_def.h" -macro_manager::macro_manager(ast_manager & m, simplifier & s): - m_manager(m), - m_simplifier(s), - m_util(m, s), + +macro_manager::macro_manager(ast_manager & m): + m(m), + m_util(m), m_decls(m), m_macros(m), m_macro_prs(m), + m_macro_deps(m), m_forbidden(m), m_deps(m) { m_util.set_forbidden_set(&m_forbidden_set); @@ -60,13 +63,15 @@ void macro_manager::restore_decls(unsigned old_sz) { for (unsigned i = old_sz; i < sz; i++) { m_decl2macro.erase(m_decls.get(i)); m_deps.erase(m_decls.get(i)); - if (m_manager.proofs_enabled()) + if (m.proofs_enabled()) m_decl2macro_pr.erase(m_decls.get(i)); + m_decl2macro_dep.erase(m_decls.get(i)); } m_decls.shrink(old_sz); m_macros.shrink(old_sz); - if (m_manager.proofs_enabled()) + if (m.proofs_enabled()) m_macro_prs.shrink(old_sz); + m_macro_deps.shrink(old_sz); } void macro_manager::restore_forbidden(unsigned old_sz) { @@ -79,17 +84,19 @@ void macro_manager::restore_forbidden(unsigned old_sz) { void macro_manager::reset() { m_decl2macro.reset(); m_decl2macro_pr.reset(); + m_decl2macro_dep.reset(); m_decls.reset(); m_macros.reset(); m_macro_prs.reset(); + m_macro_deps.reset(); m_scopes.reset(); m_forbidden_set.reset(); m_forbidden.reset(); m_deps.reset(); } -bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) { - TRACE("macro_insert", tout << "trying to create macro: " << f->get_name() << "\n" << mk_pp(m, m_manager) << "\n";); +bool macro_manager::insert(func_decl * f, quantifier * q, proof * pr, expr_dependency* dep) { + TRACE("macro_insert", tout << "trying to create macro: " << f->get_name() << "\n" << mk_pp(q, m) << "\n";); // if we already have a macro for f then return false; if (m_decls.contains(f)) { @@ -99,7 +106,7 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) { app * head; expr * definition; - get_head_def(m, f, head, definition); + get_head_def(q, f, head, definition); func_decl_set * s = m_deps.mk_func_decl_set(); m_deps.collect_func_decls(definition, s); @@ -108,13 +115,15 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) { } // add macro - m_decl2macro.insert(f, m); + m_decl2macro.insert(f, q); m_decls.push_back(f); - m_macros.push_back(m); - if (m_manager.proofs_enabled()) { + m_macros.push_back(q); + if (m.proofs_enabled()) { m_macro_prs.push_back(pr); m_decl2macro_pr.insert(f, pr); } + m_macro_deps.push_back(dep); + m_decl2macro_dep.insert(f, dep); TRACE("macro_insert", tout << "A macro was successfully created for: " << f->get_name() << "\n";); @@ -150,9 +159,17 @@ void macro_manager::mark_forbidden(unsigned n, expr * const * exprs) { for_each_expr(p, visited, exprs[i]); } +void macro_manager::mark_forbidden(unsigned n, justified_expr const * exprs) { + expr_mark visited; + macro_manager_ns::proc p(m_forbidden_set, m_forbidden); + for (unsigned i = 0; i < n; i++) + for_each_expr(p, visited, exprs[i].get_fml()); +} + + void macro_manager::get_head_def(quantifier * q, func_decl * d, app * & head, expr * & def) const { app * body = to_app(q->get_expr()); - SASSERT(m_manager.is_eq(body) || m_manager.is_iff(body)); + SASSERT(m.is_eq(body) || m.is_iff(body)); expr * lhs = to_app(body)->get_arg(0); expr * rhs = to_app(body)->get_arg(1); SASSERT(is_app_of(lhs, d) || is_app_of(rhs, d)); @@ -177,7 +194,7 @@ void macro_manager::display(std::ostream & out) { expr * def; get_head_def(q, f, head, def); SASSERT(q); - out << mk_pp(head, m_manager) << " ->\n" << mk_pp(def, m_manager) << "\n"; + out << mk_pp(head, m) << " ->\n" << mk_pp(def, m) << "\n"; } } @@ -188,132 +205,157 @@ func_decl * macro_manager::get_macro_interpretation(unsigned i, expr_ref & inter expr * def; get_head_def(q, f, head, def); TRACE("macro_bug", - tout << f->get_name() << "\n" << mk_pp(head, m_manager) << "\n" << mk_pp(q, m_manager) << "\n";); + tout << f->get_name() << "\n" << mk_pp(head, m) << "\n" << mk_pp(q, m) << "\n";); m_util.mk_macro_interpretation(head, q->get_num_decls(), def, interp); return f; } -macro_manager::macro_expander::macro_expander(ast_manager & m, macro_manager & mm, simplifier & s): - simplifier(m), - m_macro_manager(mm) { - // REMARK: theory simplifier should not be used by macro_expander... - // is_arith_macro rewrites a quantifer such as: - // forall (x Int) (= (+ x (+ (f x) 1)) 2) - // into - // forall (x Int) (= (f x) (+ 1 (* -1 x))) - // The goal is to make simple macro detection detect the arith macro. - // The arith simplifier will undo this transformation. - // borrow_plugins(s); - enable_ac_support(false); -} +struct macro_manager::macro_expander_cfg : public default_rewriter_cfg { + ast_manager& m; + macro_manager& mm; + expr_dependency_ref m_used_macro_dependencies; + expr_ref_vector m_trail; -macro_manager::macro_expander::~macro_expander() { - // release_plugins(); -} + macro_expander_cfg(ast_manager& m, macro_manager& mm): + m(m), + mm(mm), + m_used_macro_dependencies(m), + m_trail(m) + {} -void macro_manager::macro_expander::reduce1_quantifier(quantifier * q) { - simplifier::reduce1_quantifier(q); - // If a macro was expanded in a pattern, we must erase it since it may not be a valid pattern anymore. - // The MAM assumes valid patterns, and it crashes if invalid patterns are provided. - // For example, it will crash if the pattern does not contain all variables. - // - // Alternative solution: use pattern_validation to check if the pattern is still valid. - // I'm not sure if this is a good solution, since the pattern may be meaningless after the macro expansion. - // So, I'm just erasing them. - expr * new_q_expr = 0; - proof * new_q_pr = 0; - get_cached(q, new_q_expr, new_q_pr); - if (!is_quantifier(new_q_expr)) - return; - quantifier * new_q = to_quantifier(new_q_expr); - bool erase_patterns = false; - if (q->get_num_patterns() != new_q->get_num_patterns() || - q->get_num_no_patterns() != new_q->get_num_no_patterns()) { - erase_patterns = true; + bool rewrite_patterns() const { return false; } + bool flat_assoc(func_decl * f) const { return false; } + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + result_pr = 0; + return BR_FAILED; } - else { - for (unsigned i = 0; !erase_patterns && i < q->get_num_patterns(); i++) { - if (q->get_pattern(i) != new_q->get_pattern(i)) + + bool reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + + // If a macro was expanded in a pattern, we must erase it since it may not be a valid pattern anymore. + // The MAM assumes valid patterns, and it crashes if invalid patterns are provided. + // For example, it will crash if the pattern does not contain all variables. + // + // Alternative solution: use pattern_validation to check if the pattern is still valid. + // I'm not sure if this is a good solution, since the pattern may be meaningless after the macro expansion. + // So, I'm just erasing them. + + bool erase_patterns = false; + for (unsigned i = 0; !erase_patterns && i < old_q->get_num_patterns(); i++) { + if (old_q->get_pattern(i) != new_patterns[i]) erase_patterns = true; } - for (unsigned i = 0; !erase_patterns && i < q->get_num_no_patterns(); i++) { - if (q->get_no_pattern(i) != new_q->get_no_pattern(i)) + for (unsigned i = 0; !erase_patterns && i < old_q->get_num_no_patterns(); i++) { + if (old_q->get_no_pattern(i) != new_no_patterns[i]) erase_patterns = true; } + if (erase_patterns) { + result = m.update_quantifier(old_q, 0, 0, 0, 0, new_body); + } + return erase_patterns; } - if (erase_patterns) { - ast_manager & m = get_manager(); - expr * new_new_q = m.update_quantifier(new_q, 0, 0, 0, 0, new_q->get_expr()); - // we can use the same proof since new_new_q and new_q are identical modulo patterns/annotations - cache_result(q, new_new_q, new_q_pr); - } -} -bool macro_manager::macro_expander::get_subst(expr * _n, expr_ref & r, proof_ref & p) { - if (!is_app(_n)) + bool get_subst(expr * _n, expr* & r, proof* & p) { + if (!is_app(_n)) + return false; + app * n = to_app(_n); + quantifier * q = 0; + func_decl * d = n->get_decl(); + TRACE("macro_manager", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";); + if (mm.m_decl2macro.find(d, q)) { + TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";); + app * head = 0; + expr * def = 0; + mm.get_head_def(q, d, head, def); + unsigned num = n->get_num_args(); + SASSERT(head && def); + ptr_buffer subst_args; + subst_args.resize(num, 0); + for (unsigned i = 0; i < num; i++) { + var * v = to_var(head->get_arg(i)); + SASSERT(v->get_idx() < num); + unsigned nidx = num - v->get_idx() - 1; + SASSERT(subst_args[nidx] == 0); + subst_args[nidx] = n->get_arg(i); + } + var_subst s(m); + expr_ref rr(m); + s(def, num, subst_args.c_ptr(), rr); + m_trail.push_back(rr); + r = rr; + if (m.proofs_enabled()) { + expr_ref instance(m); + s(q->get_expr(), num, subst_args.c_ptr(), instance); + proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr()); + proof * q_pr = 0; + mm.m_decl2macro_pr.find(d, q_pr); + SASSERT(q_pr != 0); + proof * prs[2] = { qi_pr, q_pr }; + p = m.mk_unit_resolution(2, prs); + } + else { + p = 0; + } + expr_dependency * ed = mm.m_decl2macro_dep.find(d); + m_used_macro_dependencies = m.mk_join(m_used_macro_dependencies, ed); + return true; + } return false; - app * n = to_app(_n); - quantifier * q = 0; - func_decl * d = n->get_decl(); - TRACE("macro_manager_bug", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";); - if (m_macro_manager.m_decl2macro.find(d, q)) { - TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";); - app * head = 0; - expr * def = 0; - m_macro_manager.get_head_def(q, d, head, def); - unsigned num = n->get_num_args(); - SASSERT(head && def); - ptr_buffer subst_args; - subst_args.resize(num, 0); - for (unsigned i = 0; i < num; i++) { - var * v = to_var(head->get_arg(i)); - SASSERT(v->get_idx() < num); - unsigned nidx = num - v->get_idx() - 1; - SASSERT(subst_args[nidx] == 0); - subst_args[nidx] = n->get_arg(i); - } - var_subst s(m); - s(def, num, subst_args.c_ptr(), r); - if (m.proofs_enabled()) { - expr_ref instance(m); - s(q->get_expr(), num, subst_args.c_ptr(), instance); - proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr()); - proof * q_pr = 0; - m_macro_manager.m_decl2macro_pr.find(d, q_pr); - SASSERT(q_pr != 0); - proof * prs[2] = { qi_pr, q_pr }; - p = m.mk_unit_resolution(2, prs); - } - else { - p = 0; - } - return true; } - return false; -} +}; -void macro_manager::expand_macros(expr * n, proof * pr, expr_ref & r, proof_ref & new_pr) { +struct macro_manager::macro_expander_rw : public rewriter_tpl { + macro_expander_cfg m_cfg; + + macro_expander_rw(ast_manager& m, macro_manager& mm): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, mm) + {} +}; + + +void macro_manager::expand_macros(expr * n, proof * pr, expr_dependency * dep, expr_ref & r, proof_ref & new_pr, expr_dependency_ref & new_dep) { if (has_macros()) { // Expand macros with "real" proof production support (NO rewrite*) - expr_ref old_n(m_manager); - proof_ref old_pr(m_manager); + expr_ref old_n(m); + proof_ref old_pr(m); + expr_dependency_ref old_dep(m); old_n = n; old_pr = pr; + old_dep = dep; + bool change = false; for (;;) { - macro_expander proc(m_manager, *this, m_simplifier); - proof_ref n_eq_r_pr(m_manager); - TRACE("macro_manager_bug", tout << "expand_macros:\n" << mk_pp(n, m_manager) << "\n";); + macro_expander_rw proc(m, *this); + proof_ref n_eq_r_pr(m); + TRACE("macro_manager_bug", tout << "expand_macros:\n" << mk_pp(n, m) << "\n";); proc(old_n, r, n_eq_r_pr); - new_pr = m_manager.mk_modus_ponens(old_pr, n_eq_r_pr); + new_pr = m.mk_modus_ponens(old_pr, n_eq_r_pr); + new_dep = m.mk_join(old_dep, proc.m_cfg.m_used_macro_dependencies); if (r.get() == old_n.get()) - return; + break; old_n = r; old_pr = new_pr; + old_dep = new_dep; + change = true; + } + // apply th_rewrite to the result. + if (change) { + th_rewriter rw(m); + proof_ref rw_pr(m); + expr_ref r1(r, m); + rw(r1, r, rw_pr); + new_pr = m.mk_modus_ponens(new_pr, rw_pr); } } else { r = n; new_pr = pr; + new_dep = dep; } } diff --git a/src/ast/macros/macro_manager.h b/src/ast/macros/macro_manager.h index bc015de41..0205fb891 100644 --- a/src/ast/macros/macro_manager.h +++ b/src/ast/macros/macro_manager.h @@ -19,12 +19,12 @@ Revision History: #ifndef MACRO_MANAGER_H_ #define MACRO_MANAGER_H_ -#include"ast_util.h" -#include"obj_hashtable.h" -#include"simplifier.h" -#include"recurse_expr.h" -#include"func_decl_dependencies.h" -#include"macro_util.h" +#include "util/obj_hashtable.h" +#include "ast/ast_util.h" +#include "ast/justified_expr.h" +#include "ast/recurse_expr.h" +#include "ast/func_decl_dependencies.h" +#include "ast/macros/macro_util.h" /** \brief Macros are universally quantified formulas of the form: @@ -36,15 +36,16 @@ Revision History: It has support for backtracking and tagging declarations in an expression as forbidded for being macros. */ class macro_manager { - ast_manager & m_manager; - simplifier & m_simplifier; + ast_manager & m; macro_util m_util; obj_map m_decl2macro; // func-decl -> quantifier obj_map m_decl2macro_pr; // func-decl -> quantifier_proof + obj_map m_decl2macro_dep; // func-decl -> unsat core dependency func_decl_ref_vector m_decls; quantifier_ref_vector m_macros; proof_ref_vector m_macro_prs; + expr_dependency_ref_vector m_macro_deps; obj_hashtable m_forbidden_set; func_decl_ref_vector m_forbidden; struct scope { @@ -52,34 +53,27 @@ class macro_manager { unsigned m_forbidden_lim; }; svector m_scopes; - + func_decl_dependencies m_deps; void restore_decls(unsigned old_sz); void restore_forbidden(unsigned old_sz); - class macro_expander : public simplifier { - protected: - macro_manager & m_macro_manager; - virtual bool get_subst(expr * n, expr_ref & r, proof_ref & p); - virtual void reduce1_quantifier(quantifier * q); - public: - macro_expander(ast_manager & m, macro_manager & mm, simplifier & s); - ~macro_expander(); - }; - friend class macro_expander; + struct macro_expander_cfg; + struct macro_expander_rw; public: - macro_manager(ast_manager & m, simplifier & s); + macro_manager(ast_manager & m); ~macro_manager(); - ast_manager & get_manager() const { return m_manager; } + ast_manager & get_manager() const { return m; } macro_util & get_util() { return m_util; } - bool insert(func_decl * f, quantifier * m, proof * pr); + bool insert(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep = 0); bool has_macros() const { return !m_macros.empty(); } void push_scope(); void pop_scope(unsigned num_scopes); void reset(); void mark_forbidden(unsigned n, expr * const * exprs); + void mark_forbidden(unsigned n, justified_expr const * exprs); void mark_forbidden(expr * e) { mark_forbidden(1, &e); } bool is_forbidden(func_decl * d) const { return m_forbidden_set.contains(d); } obj_hashtable const & get_forbidden_set() const { return m_forbidden_set; } @@ -90,9 +84,9 @@ public: func_decl * get_macro_interpretation(unsigned i, expr_ref & interp) const; quantifier * get_macro_quantifier(func_decl * f) const { quantifier * q = 0; m_decl2macro.find(f, q); return q; } void get_head_def(quantifier * q, func_decl * d, app * & head, expr * & def) const; - void expand_macros(expr * n, proof * pr, expr_ref & r, proof_ref & new_pr); - - + void expand_macros(expr * n, proof * pr, expr_dependency * dep, expr_ref & r, proof_ref & new_pr, expr_dependency_ref & new_dep); + + }; #endif /* MACRO_MANAGER_H_ */ diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index fce6f1b28..1ab54d0b5 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -17,44 +17,26 @@ Author: Revision History: --*/ -#include"macro_util.h" -#include"occurs.h" -#include"ast_util.h" -#include"arith_simplifier_plugin.h" -#include"bv_simplifier_plugin.h" -#include"var_subst.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"for_each_expr.h" -#include"well_sorted.h" -#include"bool_rewriter.h" +#include "ast/macros/macro_util.h" +#include "ast/occurs.h" +#include "ast/ast_util.h" +#include "ast/rewriter/var_subst.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/for_each_expr.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/bool_rewriter.h" -macro_util::macro_util(ast_manager & m, simplifier & s): +macro_util::macro_util(ast_manager & m): m_manager(m), m_bv(m), - m_simplifier(s), - m_arith_simp(0), - m_bv_simp(0), + m_arith(m), + m_arith_rw(m), + m_bv_rw(m), m_forbidden_set(0), m_curr_clause(0) { } -arith_simplifier_plugin * macro_util::get_arith_simp() const { - if (m_arith_simp == 0) { - const_cast(this)->m_arith_simp = static_cast(m_simplifier.get_plugin(m_manager.mk_family_id("arith"))); - } - SASSERT(m_arith_simp != 0); - return m_arith_simp; -} - -bv_simplifier_plugin * macro_util::get_bv_simp() const { - if (m_bv_simp == 0) { - const_cast(this)->m_bv_simp = static_cast(m_simplifier.get_plugin(m_manager.mk_family_id("bv"))); - } - SASSERT(m_bv_simp != 0); - return m_bv_simp; -} - bool macro_util::is_bv(expr * n) const { return m_bv.is_bv(n); @@ -65,60 +47,83 @@ bool macro_util::is_bv_sort(sort * s) const { } bool macro_util::is_add(expr * n) const { - return get_arith_simp()->is_add(n) || m_bv.is_bv_add(n); + return m_arith.is_add(n) || m_bv.is_bv_add(n); } bool macro_util::is_times_minus_one(expr * n, expr * & arg) const { - return get_arith_simp()->is_times_minus_one(n, arg) || get_bv_simp()->is_times_minus_one(n, arg); + return m_arith_rw.is_times_minus_one(n, arg) || m_bv_rw.is_times_minus_one(n, arg); } bool macro_util::is_le(expr * n) const { - return get_arith_simp()->is_le(n) || m_bv.is_bv_ule(n) || m_bv.is_bv_sle(n); + return m_arith.is_le(n) || m_bv.is_bv_ule(n) || m_bv.is_bv_sle(n); } bool macro_util::is_le_ge(expr * n) const { - return get_arith_simp()->is_le_ge(n) || m_bv.is_bv_ule(n) || m_bv.is_bv_sle(n); + return m_arith.is_ge(n) || m_arith.is_le(n) || m_bv.is_bv_ule(n) || m_bv.is_bv_sle(n); } -poly_simplifier_plugin * macro_util::get_poly_simp_for(sort * s) const { - if (is_bv_sort(s)) - return get_bv_simp(); - else - return get_arith_simp(); +bool macro_util::is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) { + return m_arith_rw.is_var_plus_ground(n, inv, v, t) || m_bv_rw.is_var_plus_ground(n, inv, v, t); +} + +bool macro_util::is_zero_safe(expr * n) const { + if (m_bv_rw.is_bv(n)) { + return m_bv.is_zero(n); + } + else { + return m_arith_rw.is_zero(n); + } } app * macro_util::mk_zero(sort * s) const { - poly_simplifier_plugin * ps = get_poly_simp_for(s); - ps->set_curr_sort(s); - return ps->mk_zero(); + if (m_bv.is_bv_sort(s)) { + return m_bv.mk_numeral(rational(0), s); + } + else { + return m_arith.mk_numeral(rational(0), s); + } } void macro_util::mk_sub(expr * t1, expr * t2, expr_ref & r) const { if (is_bv(t1)) { - r = m_bv.mk_bv_sub(t1, t2); + m_bv_rw.mk_sub(t1, t2, r); } else { - get_arith_simp()->mk_sub(t1, t2, r); + m_arith_rw.mk_sub(t1, t2, r); } } void macro_util::mk_add(expr * t1, expr * t2, expr_ref & r) const { if (is_bv(t1)) { - r = m_bv.mk_bv_add(t1, t2); + m_bv_rw.mk_add(t1, t2, r); } else { - get_arith_simp()->mk_add(t1, t2, r); + m_arith_rw.mk_add(t1, t2, r); } } void macro_util::mk_add(unsigned num_args, expr * const * args, sort * s, expr_ref & r) const { - if (num_args == 0) { + switch (num_args) { + case 0: r = mk_zero(s); - return; + break; + case 1: + r = args[0]; + break; + default: + if (m_bv.is_bv_sort(s)) { + r = args[0]; + while (num_args >= 2) { + --num_args; + ++args; + r = m_bv.mk_bv_add(r, args[0]); + } + } + else { + r = m_arith.mk_add(num_args, args); + } + break; } - poly_simplifier_plugin * ps = get_poly_simp_for(s); - ps->set_curr_sort(s); - ps->mk_add(num_args, args, r); } /** @@ -241,13 +246,12 @@ bool macro_util::poly_contains_head(expr * n, func_decl * f, expr * exception) c bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def, bool & inv) const { // TODO: obsolete... we should move to collect_arith_macro_candidates - arith_simplifier_plugin * as = get_arith_simp(); - if (!m_manager.is_eq(n) && !as->is_le(n) && !as->is_ge(n)) + if (!m_manager.is_eq(n) && !m_arith.is_le(n) && !m_arith.is_ge(n)) return false; expr * lhs = to_app(n)->get_arg(0); expr * rhs = to_app(n)->get_arg(1); - if (!as->is_numeral(rhs)) + if (!m_arith.is_numeral(rhs)) return false; inv = false; @@ -272,7 +276,7 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex !poly_contains_head(lhs, to_app(arg)->get_decl(), arg)) { h = arg; } - else if (h == 0 && as->is_times_minus_one(arg, neg_arg) && + else if (h == 0 && m_arith_rw.is_times_minus_one(arg, neg_arg) && is_macro_head(neg_arg, num_decls) && !is_forbidden(to_app(neg_arg)->get_decl()) && !poly_contains_head(lhs, to_app(neg_arg)->get_decl(), arg)) { @@ -287,11 +291,12 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex return false; head = to_app(h); expr_ref tmp(m_manager); - as->mk_add(args.size(), args.c_ptr(), tmp); + tmp = m_arith.mk_add(args.size(), args.c_ptr()); if (inv) - as->mk_sub(tmp, rhs, def); + mk_sub(tmp, rhs, def); else - as->mk_sub(rhs, tmp, def); + mk_sub(rhs, tmp, def); + TRACE("macro_util", tout << def << "\n";); return true; } diff --git a/src/ast/macros/macro_util.h b/src/ast/macros/macro_util.h index 8aa8e550e..3ab00df2a 100644 --- a/src/ast/macros/macro_util.h +++ b/src/ast/macros/macro_util.h @@ -20,14 +20,10 @@ Revision History: #ifndef MACRO_UTIL_H_ #define MACRO_UTIL_H_ -#include"ast.h" -#include"obj_hashtable.h" -#include"simplifier.h" - -class poly_simplifier_plugin; -class arith_simplifier_plugin; -class bv_simplifier_plugin; -class basic_simplifier_plugin; +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "ast/rewriter/arith_rewriter.h" +#include "ast/rewriter/bv_rewriter.h" class macro_util { public: @@ -63,9 +59,9 @@ public: private: ast_manager & m_manager; bv_util m_bv; - simplifier & m_simplifier; - arith_simplifier_plugin * m_arith_simp; - bv_simplifier_plugin * m_bv_simp; + arith_util m_arith; + mutable arith_rewriter m_arith_rw; + mutable bv_rewriter m_bv_rw; obj_hashtable * m_forbidden_set; bool is_forbidden(func_decl * f) const { return m_forbidden_set != 0 && m_forbidden_set->contains(f); } @@ -94,11 +90,9 @@ private: public: - macro_util(ast_manager & m, simplifier & s); + macro_util(ast_manager & m); void set_forbidden_set(obj_hashtable * s) { m_forbidden_set = s; } - arith_simplifier_plugin * get_arith_simp() const; - bv_simplifier_plugin * get_bv_simp() const; bool is_macro_head(expr * n, unsigned num_decls) const; bool is_left_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const; @@ -113,6 +107,8 @@ public: return is_arith_macro(n, num_decls, head, def, inv); } + bool is_zero_safe(expr * n) const; + bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t); bool is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t); bool is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def); @@ -137,7 +133,6 @@ public: void mk_sub(expr * t1, expr * t2, expr_ref & r) const; void mk_add(expr * t1, expr * t2, expr_ref & r) const; void mk_add(unsigned num_args, expr * const * args, sort * s, expr_ref & r) const; - poly_simplifier_plugin * get_poly_simp_for(sort * s) const; }; #endif diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index b26b7faba..7d5e7c3db 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -16,22 +16,22 @@ Author: Revision History: --*/ -#include"quasi_macros.h" -#include"for_each_expr.h" -#include"ast_pp.h" -#include"uint_set.h" -#include"var_subst.h" +#include "ast/macros/quasi_macros.h" +#include "ast/for_each_expr.h" +#include "ast/ast_pp.h" +#include "util/uint_set.h" +#include "ast/rewriter/var_subst.h" -quasi_macros::quasi_macros(ast_manager & m, macro_manager & mm, simplifier & s) : - m_manager(m), +quasi_macros::quasi_macros(ast_manager & m, macro_manager & mm) : + m_manager(m), m_macro_manager(mm), - m_simplifier(s), + m_rewriter(m), m_new_vars(m), m_new_eqs(m), m_new_qsorts(m) { } -quasi_macros::~quasi_macros() { +quasi_macros::~quasi_macros() { } void quasi_macros::find_occurrences(expr * e) { @@ -41,7 +41,7 @@ void quasi_macros::find_occurrences(expr * e) { // we remember whether we have seen an expr once, or more than once; // when we see it the second time, we don't have to visit it another time, - // as we are only interested in finding unique function applications. + // as we are only interested in finding unique function applications. m_visited_once.reset(); m_visited_more.reset(); @@ -64,8 +64,8 @@ void quasi_macros::find_occurrences(expr * e) { if (is_non_ground_uninterp(cur)) { func_decl * f = to_app(cur)->get_decl(); m_occurrences.insert_if_not_there(f, 0); - occurrences_map::iterator it = m_occurrences.find_iterator(f); - it->m_value++; + occurrences_map::iterator it = m_occurrences.find_iterator(f); + it->m_value++; } j = to_app(cur)->get_num_args(); while (j) @@ -84,16 +84,16 @@ bool quasi_macros::is_unique(func_decl * f) const { return m_occurrences.find(f) == 1; } -struct var_dep_proc { +struct var_dep_proc { bit_vector m_bitset; public: var_dep_proc(quantifier * q) { m_bitset.resize(q->get_num_decls(), false); } void operator()(var * n) { m_bitset.set(n->get_idx(), true); } void operator()(quantifier * n) {} void operator()(app * n) {} - bool all_used(void) { + bool all_used(void) { for (unsigned i = 0; i < m_bitset.size() ; i++) - if (!m_bitset.get(i)) + if (!m_bitset.get(i)) return false; return true; } @@ -101,7 +101,7 @@ public: bool quasi_macros::fully_depends_on(app * a, quantifier * q) const { // CMW: This checks whether all variables in q are used _somewhere_ deep down in the children of a - + /* var_dep_proc proc(q); for_each_expr(proc, a); return proc.all_used(); */ @@ -116,14 +116,14 @@ bool quasi_macros::fully_depends_on(app * a, quantifier * q) const { } for (unsigned i = 0; i < bitset.size() ; i++) { - if (!bitset.get(i)) + if (!bitset.get(i)) return false; } return true; } -bool quasi_macros::depends_on(expr * e, func_decl * f) const { +bool quasi_macros::depends_on(expr * e, func_decl * f) const { ptr_vector todo; expr_mark visited; todo.push_back(e); @@ -133,12 +133,12 @@ bool quasi_macros::depends_on(expr * e, func_decl * f) const { if (visited.is_marked(cur)) continue; - + if (is_app(cur)) { app * a = to_app(cur); - if (a->get_decl() == f) + if (a->get_decl() == f) return true; - + unsigned j = a->get_num_args(); while (j>0) todo.push_back(a->get_arg(--j)); @@ -151,7 +151,7 @@ bool quasi_macros::depends_on(expr * e, func_decl * f) const { bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const { // Our definition of a quasi-macro: - // Forall X. f[X] = T[X], where f[X] is a term starting with symbol f, f is uninterpreted, + // Forall X. f[X] = T[X], where f[X] is a term starting with symbol f, f is uninterpreted, // f[X] contains all universally quantified variables, and f does not occur in T[X]. TRACE("quasi_macros", tout << "Checking for quasi macro: " << mk_pp(e, m_manager) << std::endl;); @@ -165,14 +165,14 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const { if (is_non_ground_uninterp(lhs) && is_unique(to_app(lhs)->get_decl()) && !depends_on(rhs, to_app(lhs)->get_decl()) && fully_depends_on(to_app(lhs), q)) { a = to_app(lhs); - t = rhs; + t = rhs; return true; } else if (is_non_ground_uninterp(rhs) && is_unique(to_app(rhs)->get_decl()) && - !depends_on(lhs, to_app(rhs)->get_decl()) && fully_depends_on(to_app(rhs), q)) { + !depends_on(lhs, to_app(rhs)->get_decl()) && fully_depends_on(to_app(rhs), q)) { a = to_app(rhs); - t = lhs; + t = lhs; return true; - } + } } else if (m_manager.is_not(qe) && is_non_ground_uninterp(to_app(qe)->get_arg(0)) && is_unique(to_app(to_app(qe)->get_arg(0))->get_decl())) { // this is like f(...) = false a = to_app(to_app(qe)->get_arg(0)); @@ -189,7 +189,7 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const { } void quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quantifier_ref & macro) { - m_new_var_names.reset(); + m_new_var_names.reset(); m_new_vars.reset(); m_new_qsorts.reset(); m_new_eqs.reset(); @@ -197,19 +197,19 @@ void quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quant func_decl * f = a->get_decl(); // CMW: we rely on the fact that all variables in q appear at least once as - // a direct argument of `a'. + // a direct argument of `a'. bit_vector v_seen; - v_seen.resize(q->get_num_decls(), false); + v_seen.resize(q->get_num_decls(), false); for (unsigned i = 0 ; i < a->get_num_args() ; i++) { - if (!is_var(a->get_arg(i)) || + if (!is_var(a->get_arg(i)) || v_seen.get(to_var(a->get_arg(i))->get_idx())) { unsigned inx = m_new_var_names.size(); m_new_name.str(""); m_new_name << "X" << inx; - m_new_var_names.push_back(symbol(m_new_name.str().c_str())); + m_new_var_names.push_back(symbol(m_new_name.str().c_str())); m_new_qsorts.push_back(f->get_domain()[i]); - + m_new_vars.push_back(m_manager.mk_var(inx + q->get_num_decls(), f->get_domain()[i])); m_new_eqs.push_back(m_manager.mk_eq(m_new_vars.back(), a->get_arg(i))); } else { @@ -228,13 +228,13 @@ void quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quant new_var_names_rev.push_back(m_new_var_names.get(i)); new_qsorts_rev.push_back(m_new_qsorts.get(i)); } - + // We want to keep all the old variables [already reversed] for (unsigned i = 0 ; i < q->get_num_decls() ; i++) { new_var_names_rev.push_back(q->get_decl_name(i)); new_qsorts_rev.push_back(q->get_decl_sort(i)); } - + // Macro := Forall m_new_vars . appl = ITE( m_new_eqs, t, f_else) app_ref appl(m_manager); @@ -251,21 +251,59 @@ void quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quant eq = m_manager.mk_eq(appl, ite); - macro = m_manager.mk_quantifier(true, new_var_names_rev.size(), + macro = m_manager.mk_quantifier(true, new_var_names_rev.size(), new_qsorts_rev.c_ptr(), new_var_names_rev.c_ptr(), eq); } bool quasi_macros::find_macros(unsigned n, expr * const * exprs) { TRACE("quasi_macros", tout << "Finding quasi-macros in: " << std::endl; - for (unsigned i = 0 ; i < n ; i++) + for (unsigned i = 0 ; i < n ; i++) tout << i << ": " << mk_pp(exprs[i], m_manager) << std::endl; ); bool res = false; m_occurrences.reset(); + + + // Find out how many non-ground appearences for each uninterpreted function there are + for (unsigned i = 0 ; i < n ; i++) + find_occurrences(exprs[i]); + + TRACE("quasi_macros", + tout << "Occurrences: " << std::endl; + for (auto & kd : m_occurrences) + tout << kd.m_key->get_name() << ": " << kd.m_value << std::endl; ); + + // Find all macros + for (unsigned i = 0 ; i < n ; i++) { + app_ref a(m_manager); + expr_ref t(m_manager); + if (is_quasi_macro(exprs[i], a, t)) { + quantifier_ref macro(m_manager); + quasi_macro_to_macro(to_quantifier(exprs[i]), a, t, macro); + TRACE("quasi_macros", tout << "Found quasi macro: " << mk_pp(exprs[i], m_manager) << std::endl; + tout << "Macro: " << mk_pp(macro, m_manager) << std::endl; ); + proof * pr = 0; + if (m_manager.proofs_enabled()) + pr = m_manager.mk_def_axiom(macro); + expr_dependency * dep = 0; + if (m_macro_manager.insert(a->get_decl(), macro, pr, dep)) + res = true; + } + } + + return res; +} + +bool quasi_macros::find_macros(unsigned n, justified_expr const * exprs) { + TRACE("quasi_macros", tout << "Finding quasi-macros in: " << std::endl; + for (unsigned i = 0 ; i < n ; i++) + tout << i << ": " << mk_pp(exprs[i].get_fml(), m_manager) << std::endl; ); + bool res = false; + m_occurrences.reset(); // Find out how many non-ground appearences for each uninterpreted function there are for ( unsigned i = 0 ; i < n ; i++ ) - find_occurrences(exprs[i]); + find_occurrences(exprs[i].get_fml()); TRACE("quasi_macros", tout << "Occurrences: " << std::endl; for (occurrences_map::iterator it = m_occurrences.begin(); @@ -277,10 +315,10 @@ bool quasi_macros::find_macros(unsigned n, expr * const * exprs) { for ( unsigned i = 0 ; i < n ; i++ ) { app_ref a(m_manager); expr_ref t(m_manager); - if (is_quasi_macro(exprs[i], a, t)) { + if (is_quasi_macro(exprs[i].get_fml(), a, t)) { quantifier_ref macro(m_manager); - quasi_macro_to_macro(to_quantifier(exprs[i]), a, t, macro); - TRACE("quasi_macros", tout << "Found quasi macro: " << mk_pp(exprs[i], m_manager) << std::endl; + quasi_macro_to_macro(to_quantifier(exprs[i].get_fml()), a, t, macro); + TRACE("quasi_macros", tout << "Found quasi macro: " << mk_pp(exprs[i].get_fml(), m_manager) << std::endl; tout << "Macro: " << mk_pp(macro, m_manager) << std::endl; ); proof * pr = 0; if (m_manager.proofs_enabled()) @@ -293,28 +331,57 @@ bool quasi_macros::find_macros(unsigned n, expr * const * exprs) { return res; } -void quasi_macros::apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) { +void quasi_macros::apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const* deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector& new_deps) { for ( unsigned i = 0 ; i < n ; i++ ) { expr_ref r(m_manager), rs(m_manager); proof_ref pr(m_manager), ps(m_manager); + expr_dependency_ref dep(m_manager); proof * p = m_manager.proofs_enabled() ? prs[i] : 0; - m_macro_manager.expand_macros(exprs[i], p, r, pr); - m_simplifier(r, rs, ps); - new_exprs.push_back(rs); + + m_macro_manager.expand_macros(exprs[i], p, deps[i], r, pr, dep); + m_rewriter(r); + new_exprs.push_back(r); new_prs.push_back(ps); + new_deps.push_back(dep); } } -bool quasi_macros::operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) { +bool quasi_macros::operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) { if (find_macros(n, exprs)) { - apply_macros(n, exprs, prs, new_exprs, new_prs); + apply_macros(n, exprs, prs, deps, new_exprs, new_prs, new_deps); + return true; + } + else { + // just copy them over + for ( unsigned i = 0 ; i < n ; i++ ) { + new_exprs.push_back(exprs[i]); + if (m_manager.proofs_enabled()) + new_prs.push_back(prs[i]); + } + return false; + } +} + +void quasi_macros::apply_macros(unsigned n, justified_expr const* fmls, vector& new_fmls) { + for ( unsigned i = 0 ; i < n ; i++ ) { + expr_ref r(m_manager), rs(m_manager); + proof_ref pr(m_manager), ps(m_manager); + proof * p = m_manager.proofs_enabled() ? fmls[i].get_proof() : 0; + expr_dependency_ref dep(m_manager); + m_macro_manager.expand_macros(fmls[i].get_fml(), p, 0, r, pr, dep); + m_rewriter(r); + new_fmls.push_back(justified_expr(m_manager, r, pr)); + } +} + +bool quasi_macros::operator()(unsigned n, justified_expr const* fmls, vector& new_fmls) { + if (find_macros(n, fmls)) { + apply_macros(n, fmls, new_fmls); return true; } else { // just copy them over for ( unsigned i = 0 ; i < n ; i++ ) { - new_exprs.push_back(exprs[i]); - if (m_manager.proofs_enabled()) - new_prs.push_back(prs[i]); + new_fmls.push_back(fmls[i]); } return false; } diff --git a/src/ast/macros/quasi_macros.h b/src/ast/macros/quasi_macros.h index 5640fad30..1b1483a90 100644 --- a/src/ast/macros/quasi_macros.h +++ b/src/ast/macros/quasi_macros.h @@ -20,9 +20,9 @@ Revision History: #define QUASI_MACROS_H_ #include -#include"macro_manager.h" -#include"basic_simplifier_plugin.h" -#include"simplifier.h" +#include "ast/justified_expr.h" +#include "ast/macros/macro_manager.h" +#include "ast/rewriter/th_rewriter.h" /** \brief Finds quasi macros and applies them. @@ -32,38 +32,44 @@ class quasi_macros { ast_manager & m_manager; macro_manager & m_macro_manager; - simplifier & m_simplifier; + th_rewriter m_rewriter; occurrences_map m_occurrences; - ptr_vector m_todo; + ptr_vector m_todo; vector m_new_var_names; expr_ref_vector m_new_vars; expr_ref_vector m_new_eqs; sort_ref_vector m_new_qsorts; - std::stringstream m_new_name; + std::stringstream m_new_name; expr_mark m_visited_once; expr_mark m_visited_more; - + bool is_unique(func_decl * f) const; bool is_non_ground_uninterp(expr const * e) const; - bool fully_depends_on(app * a, quantifier * q) const; + bool fully_depends_on(app * a, quantifier * q) const; bool depends_on(expr * e, func_decl * f) const; - bool is_quasi_macro(expr * e, app_ref & a, expr_ref &v) const; + bool is_quasi_macro(expr * e, app_ref & a, expr_ref &v) const; void quasi_macro_to_macro(quantifier * q, app * a, expr * t, quantifier_ref & macro); void find_occurrences(expr * e); bool find_macros(unsigned n, expr * const * exprs); - void apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); + bool find_macros(unsigned n, justified_expr const* expr); + void apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const* deps, + expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector& new_deps); + void apply_macros(unsigned n, justified_expr const* fmls, vector& new_fmls); public: - quasi_macros(ast_manager & m, macro_manager & mm, simplifier & s); + quasi_macros(ast_manager & m, macro_manager & mm); ~quasi_macros(); - + /** \brief Find pure function macros and apply them. */ - bool operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); + // bool operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); + bool operator()(unsigned n, justified_expr const* fmls, vector& new_fmls); + bool operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps); + }; #endif diff --git a/src/ast/normal_forms/defined_names.cpp b/src/ast/normal_forms/defined_names.cpp index 1ac2049ac..12085b992 100644 --- a/src/ast/normal_forms/defined_names.cpp +++ b/src/ast/normal_forms/defined_names.cpp @@ -16,12 +16,12 @@ Author: Revision History: --*/ -#include"defined_names.h" -#include"obj_hashtable.h" -#include"used_vars.h" -#include"var_subst.h" -#include"ast_smt2_pp.h" -#include"ast_pp.h" +#include "ast/normal_forms/defined_names.h" +#include "util/obj_hashtable.h" +#include "ast/used_vars.h" +#include "ast/rewriter/var_subst.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_pp.h" struct defined_names::impl { typedef obj_map expr2name; diff --git a/src/ast/normal_forms/defined_names.h b/src/ast/normal_forms/defined_names.h index 69e365f3d..764822f66 100644 --- a/src/ast/normal_forms/defined_names.h +++ b/src/ast/normal_forms/defined_names.h @@ -20,7 +20,7 @@ Revision History: #ifndef DEFINED_NAMES_H_ #define DEFINED_NAMES_H_ -#include"ast.h" +#include "ast/ast.h" /** \brief Mapping from expressions to skolem functions that are used to name them. diff --git a/src/ast/normal_forms/name_exprs.cpp b/src/ast/normal_forms/name_exprs.cpp index 5a2e1659d..7cc2719c9 100644 --- a/src/ast/normal_forms/name_exprs.cpp +++ b/src/ast/normal_forms/name_exprs.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"name_exprs.h" -#include"rewriter_def.h" -#include"ast_smt2_pp.h" +#include "ast/normal_forms/name_exprs.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_smt2_pp.h" class name_exprs_core : public name_exprs { struct cfg : public default_rewriter_cfg { diff --git a/src/ast/normal_forms/name_exprs.h b/src/ast/normal_forms/name_exprs.h index 9403f3d12..9f896190f 100644 --- a/src/ast/normal_forms/name_exprs.h +++ b/src/ast/normal_forms/name_exprs.h @@ -19,8 +19,8 @@ Notes: #ifndef NAME_EXPRS_H_ #define NAME_EXPRS_H_ -#include"ast.h" -#include"defined_names.h" +#include "ast/ast.h" +#include "ast/normal_forms/defined_names.h" class expr_predicate { public: diff --git a/src/ast/normal_forms/nnf.cpp b/src/ast/normal_forms/nnf.cpp index e15e26bf2..6fc65543d 100644 --- a/src/ast/normal_forms/nnf.cpp +++ b/src/ast/normal_forms/nnf.cpp @@ -17,18 +17,18 @@ Notes: Major revision on 2011-10-06 --*/ -#include"nnf.h" -#include"nnf_params.hpp" -#include"warning.h" -#include"used_vars.h" -#include"well_sorted.h" -#include"var_subst.h" +#include "ast/normal_forms/nnf.h" +#include "ast/normal_forms/nnf_params.hpp" +#include "util/warning.h" +#include "ast/used_vars.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/var_subst.h" -#include"name_exprs.h" -#include"act_cache.h" -#include"cooperate.h" +#include "ast/normal_forms/name_exprs.h" +#include "ast/act_cache.h" +#include "util/cooperate.h" -#include"ast_smt2_pp.h" +#include "ast/ast_smt2_pp.h" /** \brief NNF translation mode. The cheapest mode is NNF_SKOLEM, and @@ -40,7 +40,7 @@ enum nnf_mode { transformation will be in skolem normal form. If a formula is too expensive to be put into NNF, then nested quantifiers and labels are renamed. - + This mode is sufficient when using E-matching. */ NNF_QUANT, /* A subformula is put into NNF if it contains @@ -48,7 +48,7 @@ enum nnf_mode { quantifier. The result of the transformation will be in skolem normal form, and the body of quantifiers will be in NNF. If a ground formula is too expensive to - be put into NNF, then nested quantifiers and labels + be put into NNF, then nested quantifiers and labels are renamed. This mode is sufficient when using Superposition @@ -89,7 +89,7 @@ class skolemizer { } TRACE("skolemizer", tout << "skid: " << q->get_skid() << "\n";); - + expr_ref_vector substitution(m()); unsigned num_decls = q->get_num_decls(); for (unsigned i = num_decls; i > 0; ) { @@ -111,7 +111,7 @@ class skolemizer { substitution.push_back(0); } // - // (VAR num_decls) ... (VAR num_decls+sz-1) + // (VAR num_decls) ... (VAR num_decls+sz-1) // are in positions num_decls .. num_decls+sz-1 // std::reverse(substitution.c_ptr(), substitution.c_ptr() + substitution.size()); @@ -139,7 +139,7 @@ class skolemizer { s(body, substitution.size(), substitution.c_ptr(), r); p = 0; if (m().proofs_enabled()) { - if (q->is_forall()) + if (q->is_forall()) p = m().mk_skolemization(m().mk_not(q), m().mk_not(r)); else p = m().mk_skolemization(q, r); @@ -175,7 +175,7 @@ public: m_cache_pr.insert(q, p); } } - + bool is_sk_hack(expr * p) const { SASSERT(m().is_pattern(p)); if (to_app(p)->get_num_args() != 1) @@ -204,11 +204,11 @@ struct nnf::imp { unsigned m_i:28; unsigned m_pol:1; // pos/neg polarity unsigned m_in_q:1; // true if m_curr is nested in a quantifier - unsigned m_new_child:1; + unsigned m_new_child:1; unsigned m_cache_result:1; unsigned m_spos; // top of the result stack, when the frame was created. - frame(expr_ref& n, bool pol, bool in_q, bool cache_res, unsigned spos): - m_curr(n), + frame(expr_ref && n, bool pol, bool in_q, bool cache_res, unsigned spos): + m_curr(std::move(n)), m_i(0), m_pol(pol), m_in_q(in_q), @@ -216,6 +216,16 @@ struct nnf::imp { m_cache_result(cache_res), m_spos(spos) { } + frame(frame && other): + m_curr(std::move(other.m_curr)), + m_i(other.m_i), + m_pol(other.m_pol), + m_in_q(other.m_in_q), + m_new_child(other.m_new_child), + m_cache_result(other.m_cache_result), + m_spos(other.m_spos) { + } + }; // There are four caches: @@ -223,22 +233,22 @@ struct nnf::imp { #define POS_NQ_CIDX 1 // positive polarity and not nested in a quantifier #define NEG_Q_CIDX 2 // negative polarity and nested in a quantifier #define POS_Q_CIDX 3 // positive polarity and nested in a quantifier - + ast_manager & m_manager; vector m_frame_stack; expr_ref_vector m_result_stack; - + typedef act_cache cache; cache * m_cache[4]; expr_ref_vector m_todo_defs; proof_ref_vector m_todo_proofs; - + // proof generation goodness ---- proof_ref_vector m_result_pr_stack; cache * m_cache_pr[4]; // ------------------------------ - + skolemizer m_skolemizer; // configuration ---------------- @@ -249,7 +259,7 @@ struct nnf::imp { name_exprs * m_name_nested_formulas; name_exprs * m_name_quant; - + unsigned long long m_max_memory; // in bytes imp(ast_manager & m, defined_names & n, params_ref const & p): @@ -292,9 +302,9 @@ struct nnf::imp { m_mode = NNF_FULL; else if (mode_sym == "quantifiers") m_mode = NNF_QUANT; - else + else throw nnf_params_exception("invalid NNF mode"); - + TRACE("nnf", tout << "nnf-mode: " << m_mode << " " << mode_sym << "\n" << _p << "\n";); m_ignore_labels = p.ignore_labels(); @@ -324,12 +334,11 @@ struct nnf::imp { } void push_frame(expr * t, bool pol, bool in_q, bool cache_res) { - expr_ref tr(t, m()); - m_frame_stack.push_back(frame(tr, pol, in_q, cache_res, m_result_stack.size())); + m_frame_stack.push_back(frame(expr_ref(t, m()), pol, in_q, cache_res, m_result_stack.size())); } - static unsigned get_cache_idx(bool pol, bool in_q) { - return static_cast(in_q) * 2 + static_cast(pol); + static unsigned get_cache_idx(bool pol, bool in_q) { + return static_cast(in_q) * 2 + static_cast(pol); } void cache_result(expr * t, bool pol, bool in_q, expr * v, proof * pr) { @@ -339,8 +348,8 @@ struct nnf::imp { m_cache_pr[idx]->insert(t, pr); } - expr * get_cached(expr * t, bool pol, bool in_q) const { - return m_cache[get_cache_idx(pol, in_q)]->find(t); + expr * get_cached(expr * t, bool pol, bool in_q) const { + return m_cache[get_cache_idx(pol, in_q)]->find(t); } proof * get_cached_pr(expr * t, bool pol, bool in_q) const { @@ -368,12 +377,12 @@ struct nnf::imp { return false; } - + void checkpoint() { cooperate("nnf"); if (memory::get_allocation_size() > m_max_memory) throw nnf_exception(Z3_MAX_MEMORY_MSG); - if (m().canceled()) + if (m().canceled()) throw nnf_exception(m().limit().get_cancel_msg()); } @@ -382,11 +391,11 @@ struct nnf::imp { m_frame_stack.back().m_new_child = true; } - void set_new_child_flag(expr * old_t, expr * new_t) { - if (old_t != new_t) - set_new_child_flag(); + void set_new_child_flag(expr * old_t, expr * new_t) { + if (old_t != new_t) + set_new_child_flag(); } - + void skip(expr * t, bool pol) { expr * r = pol ? t : m().mk_not(t); m_result_stack.push_back(r); @@ -448,10 +457,10 @@ struct nnf::imp { if (pol) { if (old_e->get_decl() == new_e->get_decl()) return m().mk_oeq_congruence(old_e, new_e, num_parents, parents); - else + else return m().mk_nnf_pos(old_e, new_e, num_parents, parents); } - else + else return m().mk_nnf_neg(old_e, new_e, num_parents, parents); } @@ -468,7 +477,7 @@ struct nnf::imp { r = m().mk_and(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos); else r = m().mk_or(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos); - + m_result_stack.shrink(fr.m_spos); m_result_stack.push_back(r); if (proofs_enabled()) { @@ -520,7 +529,7 @@ struct nnf::imp { r = m().mk_or(2, m_result_stack.c_ptr() + fr.m_spos); else r = m().mk_and(2, m_result_stack.c_ptr() + fr.m_spos); - + m_result_stack.shrink(fr.m_spos); m_result_stack.push_back(r); if (proofs_enabled()) { @@ -554,7 +563,7 @@ struct nnf::imp { default: break; } - + expr * const * rs = m_result_stack.c_ptr() + fr.m_spos; expr * _cond = rs[0]; expr * _not_cond = rs[1]; @@ -574,7 +583,7 @@ struct nnf::imp { } bool is_eq(app * t) const { return m().is_eq(t) || m().is_iff(t); } - + bool process_iff_xor(app * t, frame & fr) { SASSERT(t->get_num_args() == 2); switch (fr.m_i) { @@ -605,7 +614,7 @@ struct nnf::imp { expr * not_rhs = rs[3]; app * r; - if (is_eq(t) == fr.m_pol) + if (is_eq(t) == fr.m_pol) r = m().mk_and(m().mk_or(not_lhs, rhs), m().mk_or(lhs, not_rhs)); else r = m().mk_and(m().mk_or(lhs, rhs), m().mk_or(not_lhs, not_rhs)); @@ -626,7 +635,7 @@ struct nnf::imp { else return process_default(t, fr); } - + bool process_default(app * t, frame & fr) { SASSERT(fr.m_i == 0); if (m_mode == NNF_FULL || t->has_quantifiers() || t->has_labels()) { @@ -636,10 +645,10 @@ struct nnf::imp { m_name_nested_formulas->operator()(t, m_todo_defs, m_todo_proofs, n2, pr2); else m_name_quant->operator()(t, m_todo_defs, m_todo_proofs, n2, pr2); - + if (!fr.m_pol) n2 = m().mk_not(n2); - + m_result_stack.push_back(n2); if (proofs_enabled()) { if (!fr.m_pol) { @@ -666,10 +675,10 @@ struct nnf::imp { expr * arg = m_result_stack.back(); proof * arg_pr = proofs_enabled() ? m_result_pr_stack.back() : 0; - if (m_ignore_labels && !proofs_enabled()) + if (m_ignore_labels && !proofs_enabled()) return true; // the result is already on the stack - + buffer names; bool pos; m().is_label(t, pos, names); @@ -684,7 +693,7 @@ struct nnf::imp { pr = m().mk_transitivity(mk_proof(fr.m_pol, 1, &arg_pr, t, to_app(aux)), m().mk_iff_oeq(m().mk_rewrite(aux, r))); } - } + } else { r = arg; if (proofs_enabled()) { @@ -692,7 +701,7 @@ struct nnf::imp { pr = m().mk_transitivity(p1, arg_pr); } } - + m_result_stack.pop_back(); m_result_stack.push_back(r); if (proofs_enabled()) { @@ -729,7 +738,7 @@ struct nnf::imp { if (m().is_label(t)) { return process_label(t, fr); } - + return process_default(t, fr); } @@ -737,7 +746,7 @@ struct nnf::imp { skip(v, fr.m_pol); return true; } - + bool process_quantifier(quantifier * q, frame & fr) { expr_ref r(m()); proof_ref pr(m()); @@ -757,7 +766,7 @@ struct nnf::imp { if (q->is_forall() == fr.m_pol || !m_skolemize) { expr * new_expr = m_result_stack.back(); proof * new_expr_pr = proofs_enabled() ? m_result_pr_stack.back() : 0; - + ptr_buffer new_patterns; if (q->is_forall() == fr.m_pol) { @@ -773,7 +782,7 @@ struct nnf::imp { // New quantifier has existential force. // So, ignore patterns } - + quantifier * new_q = 0; proof * new_q_pr = 0; if (fr.m_pol) { @@ -786,7 +795,7 @@ struct nnf::imp { if (proofs_enabled()) new_q_pr = m().mk_nnf_neg(q, new_q, 1, &new_expr_pr); } - + m_result_stack.pop_back(); m_result_stack.push_back(new_q); if (proofs_enabled()) { @@ -809,7 +818,7 @@ struct nnf::imp { } return true; } - + void recover_result(expr * t, expr_ref & result, proof_ref & result_pr) { // recover result from the top of the stack. result = m_result_stack.back(); @@ -873,7 +882,7 @@ struct nnf::imp { process(n, r, pr); unsigned old_sz1 = new_defs.size(); unsigned old_sz2 = new_def_proofs.size(); - + for (unsigned i = 0; i < m_todo_defs.size(); i++) { expr_ref dr(m()); proof_ref dpr(m()); @@ -881,7 +890,7 @@ struct nnf::imp { new_defs.push_back(dr); if (proofs_enabled()) { proof * new_pr = m().mk_modus_ponens(m_todo_proofs.get(i), dpr); - new_def_proofs.push_back(new_pr); + new_def_proofs.push_back(new_pr); } } std::reverse(new_defs.c_ptr() + old_sz1, new_defs.c_ptr() + new_defs.size()); @@ -898,7 +907,7 @@ nnf::nnf(ast_manager & m, defined_names & n, params_ref const & p) { nnf::~nnf() { dealloc(m_imp); } - + void nnf::operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & p) { m_imp->operator()(n, new_defs, new_def_proofs, r, p); TRACE("nnf_result", tout << mk_ismt2_pp(n, m_imp->m()) << "\nNNF result:\n" << mk_ismt2_pp(r, m_imp->m()) << "\n";); diff --git a/src/ast/normal_forms/nnf.h b/src/ast/normal_forms/nnf.h index 60d50e3b6..073cc91e4 100644 --- a/src/ast/normal_forms/nnf.h +++ b/src/ast/normal_forms/nnf.h @@ -20,9 +20,9 @@ Notes: #ifndef NNF_H_ #define NNF_H_ -#include"ast.h" -#include"params.h" -#include"defined_names.h" +#include "ast/ast.h" +#include "util/params.h" +#include "ast/normal_forms/defined_names.h" class nnf { struct imp; diff --git a/src/ast/normal_forms/pull_quant.cpp b/src/ast/normal_forms/pull_quant.cpp index 74c7cafde..ee618c747 100644 --- a/src/ast/normal_forms/pull_quant.cpp +++ b/src/ast/normal_forms/pull_quant.cpp @@ -16,10 +16,10 @@ Author: Notes: --*/ -#include"pull_quant.h" -#include"var_subst.h" -#include"rewriter_def.h" -#include"ast_pp.h" +#include "ast/normal_forms/pull_quant.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_pp.h" struct pull_quant::imp { @@ -229,7 +229,7 @@ struct pull_quant::imp { proofs.push_back(m_manager.mk_pull_quant(arg, to_quantifier(new_arg))); } pull_quant1(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr(), r); - if (m_manager.fine_grain_proofs()) { + if (m_manager.proofs_enabled()) { app * r1 = m_manager.mk_app(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr()); proof * p1 = proofs.empty() ? 0 : m_manager.mk_congruence(to_app(n), r1, proofs.size(), proofs.c_ptr()); proof * p2 = r1 == r ? 0 : m_manager.mk_pull_quant(r1, to_quantifier(r)); @@ -240,11 +240,11 @@ struct pull_quant::imp { expr_ref new_expr(m_manager); pull_quant1(to_quantifier(n)->get_expr(), new_expr); pull_quant1(to_quantifier(n), new_expr, r); - if (m_manager.fine_grain_proofs()) { + if (m_manager.proofs_enabled()) { quantifier * q1 = m_manager.update_quantifier(to_quantifier(n), new_expr); proof * p1 = 0; if (n != q1) { - proof * p0 = m_manager.mk_pull_quant(to_quantifier(n)->get_expr(), to_quantifier(new_expr)); + proof * p0 = m_manager.mk_pull_quant(n, to_quantifier(new_expr)); p1 = m_manager.mk_quant_intro(to_quantifier(n), q1, p0); } proof * p2 = q1 == r ? 0 : m_manager.mk_pull_quant(q1, to_quantifier(r)); diff --git a/src/ast/normal_forms/pull_quant.h b/src/ast/normal_forms/pull_quant.h index dcdae056b..aadbad651 100644 --- a/src/ast/normal_forms/pull_quant.h +++ b/src/ast/normal_forms/pull_quant.h @@ -19,7 +19,7 @@ Notes: #ifndef PULL_QUANT_H_ #define PULL_QUANT_H_ -#include"ast.h" +#include "ast/ast.h" /** \brief Pull nested quantifiers in a formula. diff --git a/src/ast/num_occurs.cpp b/src/ast/num_occurs.cpp index c5d50475e..2448dd081 100644 --- a/src/ast/num_occurs.cpp +++ b/src/ast/num_occurs.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"num_occurs.h" +#include "ast/num_occurs.h" void num_occurs::process(expr * t, expr_fast_mark1 & visited) { ptr_buffer stack; diff --git a/src/ast/num_occurs.h b/src/ast/num_occurs.h index 3c51dbe5c..92215f440 100644 --- a/src/ast/num_occurs.h +++ b/src/ast/num_occurs.h @@ -19,8 +19,8 @@ Revision History: #ifndef NUM_OCCURS_H_ #define NUM_OCCURS_H_ -#include"ast.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" /** \brief Functor for computing the number of occurrences of each sub-expression in a expression F. diff --git a/src/ast/occurs.cpp b/src/ast/occurs.cpp index 9d2360351..c76e73748 100644 --- a/src/ast/occurs.cpp +++ b/src/ast/occurs.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"occurs.h" +#include "ast/occurs.h" -#include"for_each_expr.h" +#include "ast/for_each_expr.h" // ----------------------------------- // diff --git a/src/ast/pattern/CMakeLists.txt b/src/ast/pattern/CMakeLists.txt index 6e8301afc..5531bb29b 100644 --- a/src/ast/pattern/CMakeLists.txt +++ b/src/ast/pattern/CMakeLists.txt @@ -29,7 +29,7 @@ z3_add_component(pattern ${CMAKE_CURRENT_BINARY_DIR}/database.h COMPONENT_DEPENDENCIES normal_forms - simplifier + rewriter smt2parser PYG_FILES pattern_inference_params_helper.pyg diff --git a/src/ast/pattern/expr_pattern_match.cpp b/src/ast/pattern/expr_pattern_match.cpp index e18831650..628c777d3 100644 --- a/src/ast/pattern/expr_pattern_match.cpp +++ b/src/ast/pattern/expr_pattern_match.cpp @@ -29,13 +29,13 @@ Notes: --*/ -#include"ast.h" -#include"expr_pattern_match.h" -#include"for_each_ast.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" -#include"cmd_context.h" -#include"smt2parser.h" +#include "ast/ast.h" +#include "ast/pattern/expr_pattern_match.h" +#include "ast/for_each_ast.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "cmd_context/cmd_context.h" +#include "parsers/smt2/smt2parser.h" expr_pattern_match::expr_pattern_match(ast_manager & manager): m_manager(manager), m_precompiled(manager) { @@ -179,11 +179,11 @@ expr_pattern_match::compile(expr* q) } if (m_regs.size() <= max_reg) { - m_regs.resize(max_reg+1, 0); + m_regs.resize(max_reg+1); } if (m_bound_dom.size() <= num_bound) { - m_bound_dom.resize(num_bound+1, 0); - m_bound_rng.resize(num_bound+1, 0); + m_bound_dom.resize(num_bound+1); + m_bound_rng.resize(num_bound+1); } instr.m_kind = YIELD; diff --git a/src/ast/pattern/expr_pattern_match.h b/src/ast/pattern/expr_pattern_match.h index 245edd877..6d9d47e1e 100644 --- a/src/ast/pattern/expr_pattern_match.h +++ b/src/ast/pattern/expr_pattern_match.h @@ -20,8 +20,8 @@ Notes: #ifndef EXPR_PATTERN_MATCH_H_ #define EXPR_PATTERN_MATCH_H_ -#include"ast.h" -#include"map.h" +#include "ast/ast.h" +#include "util/map.h" class expr_pattern_match { diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index 64ec064a8..17d8747f2 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -16,15 +16,17 @@ Author: Revision History: --*/ -#include"pattern_inference.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" -#include"ast_util.h" -#include"warning.h" -#include"arith_decl_plugin.h" -#include"pull_quant.h" -#include"well_sorted.h" -#include"for_each_expr.h" + +#include "util/warning.h" +#include "ast/pattern/pattern_inference.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "ast/arith_decl_plugin.h" +#include "ast/normal_forms/pull_quant.h" +#include "ast/well_sorted.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/rewriter_def.h" void smaller_pattern::save(expr * p1, expr * p2) { expr_pair e(p1, p2); @@ -54,7 +56,7 @@ bool smaller_pattern::process(expr * p1, expr * p2) { unsigned num1 = app1->get_num_args(); if (num1 != app2->get_num_args() || app1->get_decl() != app2->get_decl()) return false; - for (unsigned i = 0; i < num1; i++) + for (unsigned i = 0; i < num1; i++) save(app1->get_arg(i), app2->get_arg(i)); break; } @@ -67,7 +69,7 @@ bool smaller_pattern::process(expr * p1, expr * p2) { return false; } // it is a variable bound by an external quantifier - else if (p1 != p2) + else if (p1 != p2) return false; break; } @@ -87,8 +89,20 @@ bool smaller_pattern::operator()(unsigned num_bindings, expr * p1, expr * p2) { return process(p1, p2); } -pattern_inference::pattern_inference(ast_manager & m, pattern_inference_params & params): - simplifier(m), + +#ifdef _TRACE +static void dump_app_vector(std::ostream & out, ptr_vector const & v, ast_manager & m) { + for (app * e : v) + out << mk_pp(e, m) << "\n"; +} +#endif + + +#include "ast/pattern/database.h" + + +pattern_inference_cfg::pattern_inference_cfg(ast_manager & m, pattern_inference_params & params): + m(m), m_params(params), m_bfid(m.get_basic_family_id()), m_afid(m.mk_family_id("arith")), @@ -102,10 +116,9 @@ pattern_inference::pattern_inference(ast_manager & m, pattern_inference_params & m_database(m) { if (params.m_pi_arith == AP_NO) register_forbidden_family(m_afid); - enable_ac_support(false); } -void pattern_inference::collect::operator()(expr * n, unsigned num_bindings) { +void pattern_inference_cfg::collect::operator()(expr * n, unsigned num_bindings) { SASSERT(m_info.empty()); SASSERT(m_todo.empty()); SASSERT(m_cache.empty()); @@ -125,7 +138,7 @@ void pattern_inference::collect::operator()(expr * n, unsigned num_bindings) { reset(); } -inline void pattern_inference::collect::visit(expr * n, unsigned delta, bool & visited) { +inline void pattern_inference_cfg::collect::visit(expr * n, unsigned delta, bool & visited) { entry e(n, delta); if (!m_cache.contains(e)) { m_todo.push_back(e); @@ -133,11 +146,11 @@ inline void pattern_inference::collect::visit(expr * n, unsigned delta, bool & v } } -bool pattern_inference::collect::visit_children(expr * n, unsigned delta) { +bool pattern_inference_cfg::collect::visit_children(expr * n, unsigned delta) { bool visited = true; unsigned i; switch (n->get_kind()) { - case AST_APP: + case AST_APP: i = to_app(n)->get_num_args(); while (i > 0) { --i; @@ -153,13 +166,13 @@ bool pattern_inference::collect::visit_children(expr * n, unsigned delta) { return visited; } -inline void pattern_inference::collect::save(expr * n, unsigned delta, info * i) { +inline void pattern_inference_cfg::collect::save(expr * n, unsigned delta, info * i) { m_cache.insert(entry(n, delta), i); if (i != 0) m_info.push_back(i); } -void pattern_inference::collect::save_candidate(expr * n, unsigned delta) { +void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { switch (n->get_kind()) { case AST_VAR: { unsigned idx = to_var(n)->get_idx(); @@ -187,14 +200,14 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) { save(n, delta, 0); return; } - + if (c->get_num_args() == 0) { save(n, delta, alloc(info, m, n, uint_set(), 1)); return; } ptr_buffer buffer; - bool changed = false; // false if none of the children is mapped to a node different from itself. + bool changed = false; // false if none of the children is mapped to a node different from itself. uint_set free_vars; unsigned size = 1; unsigned num = c->get_num_args(); @@ -216,7 +229,7 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) { if (child != child_info->m_node.get()) changed = true; } - + app * new_node = 0; if (changed) new_node = m.mk_app(decl, buffer.size(), buffer.c_ptr()); @@ -229,11 +242,11 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) { // // Remark: The rule above has an exception. The operators (div, idiv, mod) are allowed to be // used as patterns even when they are not nested in other terms. The motivation is that - // Z3 currently doesn't implement them (i.e., they are uninterpreted). So, some users add axioms + // Z3 currently doesn't implement them (i.e., they are uninterpreted). So, some users add axioms // stating properties about these operators. family_id fid = c->get_family_id(); decl_kind k = c->get_decl_kind(); - if (!free_vars.empty() && + if (!free_vars.empty() && (fid != m_afid || (fid == m_afid && !m_owner.m_nested_arith_only && (k == OP_DIV || k == OP_IDIV || k == OP_MOD || k == OP_REM || k == OP_MUL)))) { TRACE("pattern_inference", tout << "potential candidate: \n" << mk_pp(new_node, m) << "\n";); m_owner.add_candidate(new_node, free_vars, size); @@ -247,14 +260,14 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) { } -void pattern_inference::collect::reset() { +void pattern_inference_cfg::collect::reset() { m_cache.reset(); std::for_each(m_info.begin(), m_info.end(), delete_proc()); m_info.reset(); SASSERT(m_todo.empty()); } -void pattern_inference::add_candidate(app * n, uint_set const & free_vars, unsigned size) { +void pattern_inference_cfg::add_candidate(app * n, uint_set const & free_vars, unsigned size) { for (unsigned i = 0; i < m_num_no_patterns; i++) { if (n == m_no_patterns[i]) return; @@ -271,7 +284,7 @@ void pattern_inference::add_candidate(app * n, uint_set const & free_vars, unsig \brief Copy the non-looping patterns in m_candidates to result when m_params.m_pi_block_loop_patterns = true. Otherwise, copy m_candidates to result. */ -void pattern_inference::filter_looping_patterns(ptr_vector & result) { +void pattern_inference_cfg::filter_looping_patterns(ptr_vector & result) { unsigned num = m_candidates.size(); for (unsigned i1 = 0; i1 < num; i1++) { app * n1 = m_candidates.get(i1); @@ -288,7 +301,7 @@ void pattern_inference::filter_looping_patterns(ptr_vector & result) { uint_set const & s2 = e2->get_data().m_value.m_free_vars; // Remark: the comparison operator only makes sense if both AST nodes // contain the same number of variables. - // Example: + // Example: // (f X Y) <: (f (g X Z W) Y) if (s1 == s2 && m_le(m_num_bindings, n1, n2) && !m_le(m_num_bindings, n2, n1)) { smaller = true; @@ -310,7 +323,7 @@ void pattern_inference::filter_looping_patterns(ptr_vector & result) { -inline void pattern_inference::contains_subpattern::save(expr * n) { +inline void pattern_inference_cfg::contains_subpattern::save(expr * n) { unsigned id = n->get_id(); m_already_processed.assure_domain(id); if (!m_already_processed.contains(id)) { @@ -319,7 +332,7 @@ inline void pattern_inference::contains_subpattern::save(expr * n) { } } -bool pattern_inference::contains_subpattern::operator()(expr * n) { +bool pattern_inference_cfg::contains_subpattern::operator()(expr * n) { m_already_processed.reset(); m_todo.reset(); expr2info::obj_map_entry * _e = m_owner.m_candidates_info.find_core(n); @@ -360,7 +373,7 @@ bool pattern_inference::contains_subpattern::operator()(expr * n) { Return true if n contains a direct/indirect child that is also a pattern, and contains the same number of free variables. */ -inline bool pattern_inference::contains_subpattern(expr * n) { +inline bool pattern_inference_cfg::contains_subpattern(expr * n) { return m_contains_subpattern(n); } @@ -372,18 +385,15 @@ inline bool pattern_inference::contains_subpattern(expr * n) { Remark: Every pattern p in patterns is also a member of m_pattern_map. */ -void pattern_inference::filter_bigger_patterns(ptr_vector const & patterns, ptr_vector & result) { - ptr_vector::const_iterator it = patterns.begin(); - ptr_vector::const_iterator end = patterns.end(); - for (; it != end; ++it) { - app * curr = *it; +void pattern_inference_cfg::filter_bigger_patterns(ptr_vector const & patterns, ptr_vector & result) { + for (app * curr : patterns) { if (!contains_subpattern(curr)) result.push_back(curr); } } -bool pattern_inference::pattern_weight_lt::operator()(expr * n1, expr * n2) const { +bool pattern_inference_cfg::pattern_weight_lt::operator()(expr * n1, expr * n2) const { expr2info::obj_map_entry * e1 = m_candidates_info.find_core(n1); expr2info::obj_map_entry * e2 = m_candidates_info.find_core(n2); SASSERT(e1 != 0); @@ -401,13 +411,10 @@ bool pattern_inference::pattern_weight_lt::operator()(expr * n1, expr * n2) cons variables, then it is copied to remaining_candidate_patterns. The new patterns are stored in result. */ -void pattern_inference::candidates2unary_patterns(ptr_vector const & candidate_patterns, +void pattern_inference_cfg::candidates2unary_patterns(ptr_vector const & candidate_patterns, ptr_vector & remaining_candidate_patterns, app_ref_buffer & result) { - ptr_vector::const_iterator it = candidate_patterns.begin(); - ptr_vector::const_iterator end = candidate_patterns.end(); - for (; it != end; ++it) { - app * candidate = *it; + for (app * candidate : candidate_patterns) { expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate); info const & i = e->get_data().m_value; if (i.m_free_vars.num_elems() == m_num_bindings) { @@ -421,12 +428,12 @@ void pattern_inference::candidates2unary_patterns(ptr_vector const & candid } // TODO: this code is too inefficient when the number of candidate -// patterns is too big. +// patterns is too big. // HACK: limit the number of case-splits: #define MAX_SPLITS 32 -void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns, - ptr_vector const & candidate_patterns, +void pattern_inference_cfg::candidates2multi_patterns(unsigned max_num_patterns, + ptr_vector const & candidate_patterns, app_ref_buffer & result) { SASSERT(!candidate_patterns.empty()); m_pre_patterns.push_back(alloc(pre_pattern)); @@ -464,31 +471,23 @@ void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns, m_pre_patterns.push_back(curr); } } - TRACE("pattern_inference", tout << "m_pre_patterns.size(): " << m_pre_patterns.size() << + TRACE("pattern_inference", tout << "m_pre_patterns.size(): " << m_pre_patterns.size() << "\nnum_splits: " << num_splits << "\n";); } } -void pattern_inference::reset_pre_patterns() { +void pattern_inference_cfg::reset_pre_patterns() { std::for_each(m_pre_patterns.begin(), m_pre_patterns.end(), delete_proc()); m_pre_patterns.reset(); } -#ifdef _TRACE -static void dump_app_vector(std::ostream & out, ptr_vector const & v, ast_manager & m) { - ptr_vector::const_iterator it = v.begin(); - ptr_vector::const_iterator end = v.end(); - for (; it != end; ++it) - out << mk_pp(*it, m) << "\n"; -} -#endif -bool pattern_inference::is_forbidden(app * n) const { +bool pattern_inference_cfg::is_forbidden(app * n) const { func_decl const * decl = n->get_decl(); if (is_ground(n)) return false; - // Remark: skolem constants should not be used in patterns, since they do not - // occur outside of the quantifier. That is, Z3 will never match this kind of + // Remark: skolem constants should not be used in patterns, since they do not + // occur outside of the quantifier. That is, Z3 will never match this kind of // pattern. if (m_params.m_pi_avoid_skolems && decl->is_skolem()) { CTRACE("pattern_inference_skolem", decl->is_skolem(), tout << "ignoring: " << mk_pp(n, m) << "\n";); @@ -499,14 +498,11 @@ bool pattern_inference::is_forbidden(app * n) const { return false; } -bool pattern_inference::has_preferred_patterns(ptr_vector & candidate_patterns, app_ref_buffer & result) { +bool pattern_inference_cfg::has_preferred_patterns(ptr_vector & candidate_patterns, app_ref_buffer & result) { if (m_preferred.empty()) return false; bool found = false; - ptr_vector::const_iterator it = candidate_patterns.begin(); - ptr_vector::const_iterator end = candidate_patterns.end(); - for (; it != end; ++it) { - app * candidate = *it; + for (app * candidate : candidate_patterns) { if (m_preferred.contains(to_app(candidate)->get_decl())) { expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate); info const & i = e->get_data().m_value; @@ -521,9 +517,9 @@ bool pattern_inference::has_preferred_patterns(ptr_vector & candidate_patte return found; } -void pattern_inference::mk_patterns(unsigned num_bindings, - expr * n, - unsigned num_no_patterns, +void pattern_inference_cfg::mk_patterns(unsigned num_bindings, + expr * n, + unsigned num_no_patterns, expr * const * no_patterns, app_ref_buffer & result) { m_num_bindings = num_bindings; @@ -532,7 +528,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings, m_collect(n, num_bindings); - TRACE("pattern_inference", + TRACE("pattern_inference", tout << mk_pp(n, m); tout << "\ncandidates:\n"; unsigned num = m_candidates.size(); @@ -558,7 +554,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings, m_tmp1.reset(); candidates2unary_patterns(m_tmp2, m_tmp1, result); unsigned num_extra_multi_patterns = m_params.m_pi_max_multi_patterns; - if (result.empty()) + if (result.empty()) num_extra_multi_patterns++; if (num_extra_multi_patterns > 0 && !m_tmp1.empty()) { // m_pattern_weight_lt is not a total order @@ -576,75 +572,63 @@ void pattern_inference::mk_patterns(unsigned num_bindings, m_candidates.reset(); } -#include"database.h" // defines g_pattern_database -void pattern_inference::reduce1_quantifier(quantifier * q) { +bool pattern_inference_cfg::reduce_quantifier( + quantifier * q, + expr * new_body, + expr * const *, // new_patterns + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";); if (!q->is_forall()) { - simplifier::reduce1_quantifier(q); - return; + return false; } int weight = q->get_weight(); if (m_params.m_pi_use_database) { - m_database.initialize(g_pattern_database); app_ref_vector new_patterns(m); + m_database.initialize(g_pattern_database); unsigned new_weight; if (m_database.match_quantifier(q, new_patterns, new_weight)) { -#ifdef Z3DEBUG - for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m, new_patterns.get(i))); } -#endif + DEBUG_CODE(for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m, new_patterns.get(i))); }); quantifier_ref new_q(m); if (q->get_num_patterns() > 0) { // just update the weight... TRACE("pattern_inference", tout << "updating weight to: " << new_weight << "\n" << mk_pp(q, m) << "\n";); - new_q = m.update_quantifier_weight(q, new_weight); + result = m.update_quantifier_weight(q, new_weight); } else { quantifier_ref tmp(m); - tmp = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr()); - new_q = m.update_quantifier_weight(tmp, new_weight); + tmp = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr()); + result = m.update_quantifier_weight(tmp, new_weight); TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m) << "\n";); } - proof * pr = 0; - if (m.fine_grain_proofs()) - pr = m.mk_rewrite(q, new_q); - cache_result(q, new_q, pr); - return; + if (m.proofs_enabled()) + result_pr = m.mk_rewrite(q, new_q); + return true; } } if (q->get_num_patterns() > 0) { - simplifier::reduce1_quantifier(q); - return; + return false; } if (m_params.m_pi_nopat_weight >= 0) weight = m_params.m_pi_nopat_weight; SASSERT(q->get_num_patterns() == 0); - expr * new_body; - proof * new_body_pr; - get_cached(q->get_expr(), new_body, new_body_pr); - ptr_buffer new_no_patterns; - unsigned num_no_patterns = q->get_num_no_patterns(); - for (unsigned i = 0; i < num_no_patterns; i++) { - expr * new_pattern; - proof * new_pattern_pr; - get_cached(q->get_no_pattern(i), new_pattern, new_pattern_pr); - new_no_patterns.push_back(new_pattern); - } - - app_ref_buffer new_patterns(m); - if (m_params.m_pi_arith == AP_CONSERVATIVE) m_forbidden.push_back(m_afid); - mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns); - - if (new_patterns.empty() && !new_no_patterns.empty()) { + app_ref_buffer new_patterns(m); + unsigned num_no_patterns = q->get_num_no_patterns(); + mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns); + + if (new_patterns.empty() && num_no_patterns > 0) { if (new_patterns.empty()) { mk_patterns(q->get_num_decls(), new_body, 0, 0, new_patterns); if (m_params.m_pi_warnings && !new_patterns.empty()) { @@ -652,65 +636,61 @@ void pattern_inference::reduce1_quantifier(quantifier * q) { } } } - + if (m_params.m_pi_arith == AP_CONSERVATIVE) { m_forbidden.pop_back(); if (new_patterns.empty()) { flet l1(m_block_loop_patterns, false); // allow looping patterns - mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns); + mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns); if (!new_patterns.empty()) { weight = std::max(weight, static_cast(m_params.m_pi_arith_weight)); if (m_params.m_pi_warnings) { - warning_msg("using arith. in pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_ARITH_WEIGHT=).", + warning_msg("using arith. in pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_ARITH_WEIGHT=).", q->get_qid().str().c_str(), weight); } } } } - + if (m_params.m_pi_arith != AP_NO && new_patterns.empty()) { if (new_patterns.empty()) { flet l1(m_nested_arith_only, false); // try to find a non-nested arith pattern flet l2(m_block_loop_patterns, false); // allow looping patterns - mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns); + mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns); if (!new_patterns.empty()) { weight = std::max(weight, static_cast(m_params.m_pi_non_nested_arith_weight)); if (m_params.m_pi_warnings) { - warning_msg("using non nested arith. pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_NON_NESTED_ARITH_WEIGHT=).", - q->get_qid().str().c_str(), weight); + warning_msg("using non nested arith. pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_NON_NESTED_ARITH_WEIGHT=).", + q->get_qid().str().c_str(), weight); } // verbose_stream() << mk_pp(q, m) << "\n"; } } } - quantifier_ref new_q(m); - new_q = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body); + quantifier_ref new_q(m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body), m); if (weight != q->get_weight()) new_q = m.update_quantifier_weight(new_q, weight); - proof_ref pr(m); - if (m.fine_grain_proofs()) { - if (new_body_pr == 0) - new_body_pr = m.mk_reflexivity(new_body); - pr = m.mk_quant_intro(q, new_q, new_body_pr); + if (m.proofs_enabled()) { + proof* new_body_pr = m.mk_reflexivity(new_body); + result_pr = m.mk_quant_intro(q, new_q, new_body_pr); } - + if (new_patterns.empty() && m_params.m_pi_pull_quantifiers) { pull_quant pull(m); expr_ref new_expr(m); proof_ref new_pr(m); pull(new_q, new_expr, new_pr); - quantifier * new_new_q = to_quantifier(new_expr); - if (new_new_q != new_q) { - mk_patterns(new_new_q->get_num_decls(), new_new_q->get_expr(), 0, 0, new_patterns); + quantifier * result2 = to_quantifier(new_expr); + if (result2 != new_q) { + mk_patterns(result2->get_num_decls(), result2->get_expr(), 0, 0, new_patterns); if (!new_patterns.empty()) { if (m_params.m_pi_warnings) { warning_msg("pulled nested quantifier to be able to find an useable pattern (quantifier id: %s)", q->get_qid().str().c_str()); } - new_q = m.update_quantifier(new_new_q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_new_q->get_expr()); - if (m.fine_grain_proofs()) { - pr = m.mk_transitivity(pr, new_pr); - pr = m.mk_transitivity(pr, m.mk_quant_intro(new_new_q, new_q, m.mk_reflexivity(new_q->get_expr()))); + new_q = m.update_quantifier(result2, new_patterns.size(), (expr**) new_patterns.c_ptr(), result2->get_expr()); + if (m.proofs_enabled()) { + result_pr = m.mk_transitivity(new_pr, m.mk_quant_intro(result2, new_q, m.mk_reflexivity(new_q->get_expr()))); } TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";); } @@ -725,22 +705,21 @@ void pattern_inference::reduce1_quantifier(quantifier * q) { } if (new_patterns.empty() && new_body == q->get_expr()) { - cache_result(q, q, 0); - return; + return false; } - - cache_result(q, new_q, pr); + result = new_q; + + IF_IVERBOSE(10, + verbose_stream() << "(smt.inferred-patterns :qid " << q->get_qid() << "\n"; + for (unsigned i = 0; i < new_patterns.size(); i++) + verbose_stream() << " " << mk_ismt2_pp(new_patterns[i], m, 2) << "\n"; + verbose_stream() << ")\n"; ); + + return true; } - -#if 0 -// unused -static void dump_expr_vector(std::ostream & out, ptr_vector const & v, ast_manager & m) { - ptr_vector::const_iterator it = v.begin(); - ptr_vector::const_iterator end = v.end(); - for (; it != end; ++it) - out << mk_pp(*it, m) << "\n"; -} -#endif - +pattern_inference_rw::pattern_inference_rw(ast_manager& m, pattern_inference_params & params): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, params) +{} diff --git a/src/ast/pattern/pattern_inference.h b/src/ast/pattern/pattern_inference.h index d4ab708e9..905662477 100644 --- a/src/ast/pattern/pattern_inference.h +++ b/src/ast/pattern/pattern_inference.h @@ -19,16 +19,16 @@ Revision History: #ifndef PATTERN_INFERENCE_H_ #define PATTERN_INFERENCE_H_ -#include"ast.h" -#include"simplifier.h" -#include"pattern_inference_params.h" -#include"vector.h" -#include"uint_set.h" -#include"nat_set.h" -#include"obj_hashtable.h" -#include"obj_pair_hashtable.h" -#include"map.h" -#include"expr_pattern_match.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter.h" +#include "ast/pattern/pattern_inference_params.h" +#include "util/vector.h" +#include "util/uint_set.h" +#include "util/nat_set.h" +#include "util/obj_hashtable.h" +#include "util/obj_pair_hashtable.h" +#include "util/map.h" +#include "ast/pattern/expr_pattern_match.h" /** \brief A pattern p_1 is smaller than a pattern p_2 iff @@ -60,7 +60,8 @@ public: bool operator()(unsigned num_bindings, expr * p1, expr * p2); }; -class pattern_inference : public simplifier { +class pattern_inference_cfg : public default_rewriter_cfg { + ast_manager& m; pattern_inference_params & m_params; family_id m_bfid; family_id m_afid; @@ -88,7 +89,7 @@ class pattern_inference : public simplifier { typedef obj_map expr2info; - expr2info m_candidates_info; // candidate -> set of free vars + size + expr2info m_candidates_info; // candidate -> set of free vars + size app_ref_vector m_candidates; ptr_vector m_tmp1; @@ -136,7 +137,7 @@ class pattern_inference : public simplifier { }; ast_manager & m; - pattern_inference & m_owner; + pattern_inference_cfg & m_owner; family_id m_afid; unsigned m_num_bindings; typedef map, default_eq > cache; @@ -150,7 +151,7 @@ class pattern_inference : public simplifier { void save_candidate(expr * n, unsigned delta); void reset(); public: - collect(ast_manager & m, pattern_inference & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {} + collect(ast_manager & m, pattern_inference_cfg & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {} void operator()(expr * n, unsigned num_bindings); }; @@ -165,12 +166,12 @@ class pattern_inference : public simplifier { void filter_bigger_patterns(ptr_vector const & patterns, ptr_vector & result); class contains_subpattern { - pattern_inference & m_owner; + pattern_inference_cfg & m_owner; nat_set m_already_processed; ptr_vector m_todo; void save(expr * n); public: - contains_subpattern(pattern_inference & owner): + contains_subpattern(pattern_inference_cfg & owner): m_owner(owner) {} bool operator()(expr * n); }; @@ -214,10 +215,8 @@ class pattern_inference : public simplifier { expr * const * no_patterns, // IN patterns that should not be used. app_ref_buffer & result); // OUT result - virtual void reduce1_quantifier(quantifier * q); - public: - pattern_inference(ast_manager & m, pattern_inference_params & params); + pattern_inference_cfg(ast_manager & m, pattern_inference_params & params); void register_forbidden_family(family_id fid) { SASSERT(fid != m_bfid); @@ -232,6 +231,13 @@ public: m_preferred.insert(f); } + bool reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr); + void register_preferred(unsigned num, func_decl * const * fs) { for (unsigned i = 0; i < num; i++) register_preferred(fs[i]); } bool is_forbidden(func_decl const * decl) const { @@ -244,5 +250,11 @@ public: bool is_forbidden(app * n) const; }; +class pattern_inference_rw : public rewriter_tpl { + pattern_inference_cfg m_cfg; +public: + pattern_inference_rw(ast_manager& m, pattern_inference_params & params); +}; + #endif /* PATTERN_INFERENCE_H_ */ diff --git a/src/ast/pattern/pattern_inference_params.cpp b/src/ast/pattern/pattern_inference_params.cpp index b36d372f5..1f1118a02 100644 --- a/src/ast/pattern/pattern_inference_params.cpp +++ b/src/ast/pattern/pattern_inference_params.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"pattern_inference_params.h" -#include"pattern_inference_params_helper.hpp" +#include "ast/pattern/pattern_inference_params.h" +#include "ast/pattern/pattern_inference_params_helper.hpp" void pattern_inference_params::updt_params(params_ref const & _p) { pattern_inference_params_helper p(_p); diff --git a/src/ast/pattern/pattern_inference_params.h b/src/ast/pattern/pattern_inference_params.h index 0dc413399..fde64a8eb 100644 --- a/src/ast/pattern/pattern_inference_params.h +++ b/src/ast/pattern/pattern_inference_params.h @@ -19,7 +19,7 @@ Revision History: #ifndef PATTERN_INFERENCE_PARAMS_H_ #define PATTERN_INFERENCE_PARAMS_H_ -#include"params.h" +#include "util/params.h" enum arith_pattern_inference_kind { AP_NO, // do not infer patterns with arithmetic terms diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 28f889739..06c6aac48 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -17,8 +17,8 @@ Revision History: --*/ -#include "pb_decl_plugin.h" -#include "ast_util.h" +#include "ast/pb_decl_plugin.h" +#include "ast/ast_util.h" pb_decl_plugin::pb_decl_plugin(): m_at_most_sym("at-most"), diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index 36b1a9512..7fdb592aa 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -27,7 +27,7 @@ hence: #ifndef PB_DECL_PLUGIN_H_ #define PB_DECL_PLUGIN_H_ -#include"ast.h" +#include "ast/ast.h" enum pb_op_kind { OP_AT_MOST_K, // at most K Booleans are true. diff --git a/src/ast/pp.cpp b/src/ast/pp.cpp index 13247127d..39f1986ee 100644 --- a/src/ast/pp.cpp +++ b/src/ast/pp.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"pp.h" -#include"pp_params.hpp" +#include "ast/pp.h" +#include "ast/pp_params.hpp" using namespace format_ns; static std::pair space_upto_line_break(ast_manager & m, format * f) { diff --git a/src/ast/pp.h b/src/ast/pp.h index bfb907552..e702d298a 100644 --- a/src/ast/pp.h +++ b/src/ast/pp.h @@ -19,8 +19,8 @@ Revision History: #ifndef PP_H_ #define PP_H_ -#include"format.h" -#include"params.h" +#include "ast/format.h" +#include "util/params.h" void pp(std::ostream & out, format_ns::format * f, ast_manager & m, params_ref const & p = params_ref()); diff --git a/src/ast/proof_checker/CMakeLists.txt b/src/ast/proofs/CMakeLists.txt similarity index 60% rename from src/ast/proof_checker/CMakeLists.txt rename to src/ast/proofs/CMakeLists.txt index 5c947adec..6eedb0fac 100644 --- a/src/ast/proof_checker/CMakeLists.txt +++ b/src/ast/proofs/CMakeLists.txt @@ -1,6 +1,7 @@ -z3_add_component(proof_checker +z3_add_component(proofs SOURCES proof_checker.cpp + proof_utils.cpp COMPONENT_DEPENDENCIES rewriter -) +) \ No newline at end of file diff --git a/src/ast/proof_checker/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp similarity index 99% rename from src/ast/proof_checker/proof_checker.cpp rename to src/ast/proofs/proof_checker.cpp index 45223cdb7..3f9438229 100644 --- a/src/ast/proof_checker/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -4,14 +4,13 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "proof_checker.h" -#include "ast_ll_pp.h" -#include "ast_pp.h" -// include "spc_decl_plugin.h" -#include "ast_smt_pp.h" -#include "arith_decl_plugin.h" -#include "th_rewriter.h" -#include "var_subst.h" +#include "ast/proofs/proof_checker.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt_pp.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/var_subst.h" #define IS_EQUIV(_e_) (m.is_eq(_e_) || m.is_iff(_e_)) @@ -1299,7 +1298,7 @@ bool proof_checker::check_arith_literal(bool is_pos, app* lit0, rational const& is_pos = !is_pos; } if (!a.is_le(lit) && !a.is_lt(lit) && !a.is_ge(lit) && !a.is_gt(lit) && !m.is_eq(lit)) { - IF_VERBOSE(0, verbose_stream() << mk_pp(lit, m) << "\n";); + IF_VERBOSE(2, verbose_stream() << "Not arith literal: " << mk_pp(lit, m) << "\n";); return false; } SASSERT(lit->get_num_args() == 2); @@ -1363,7 +1362,7 @@ bool proof_checker::check_arith_literal(bool is_pos, app* lit0, rational const& rw(sum); } - IF_VERBOSE(0, verbose_stream() << coeff << "\n" << mk_pp(lit0, m) << "\n" << mk_pp(sum, m) << "\n";); + IF_VERBOSE(2, verbose_stream() << "coeff,lit,sum " << coeff << "\n" << mk_pp(lit0, m) << "\n" << mk_pp(sum, m) << "\n";); #endif return true; diff --git a/src/ast/proof_checker/proof_checker.h b/src/ast/proofs/proof_checker.h similarity index 99% rename from src/ast/proof_checker/proof_checker.h rename to src/ast/proofs/proof_checker.h index 5e1a170ee..ce2684c51 100644 --- a/src/ast/proof_checker/proof_checker.h +++ b/src/ast/proofs/proof_checker.h @@ -19,8 +19,8 @@ Revision History: #ifndef PROOF_CHECKER_H_ #define PROOF_CHECKER_H_ -#include "ast.h" -#include "map.h" +#include "ast/ast.h" +#include "util/map.h" class proof_checker { ast_manager& m; diff --git a/src/muz/base/proof_utils.cpp b/src/ast/proofs/proof_utils.cpp similarity index 60% rename from src/muz/base/proof_utils.cpp rename to src/ast/proofs/proof_utils.cpp index 59856c160..58500cb79 100644 --- a/src/muz/base/proof_utils.cpp +++ b/src/ast/proofs/proof_utils.cpp @@ -1,23 +1,358 @@ - /*++ -Copyright (c) 2015 Microsoft Corporation +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + proof_utils.cpp + +Abstract: + Utilities to traverse and manipulate proofs + +Author: + Bernhard Gleiss + Arie Gurfinkel + +Revision History: --*/ -#include "dl_util.h" -#include "proof_utils.h" -#include "ast_smt2_pp.h" -#include "var_subst.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" +#include "ast/proofs/proof_utils.h" +#include "ast/proofs/proof_checker.h" +#include "ast/rewriter/var_subst.h" +#include "util/container_util.h" + + +proof_post_order::proof_post_order(proof* root, ast_manager& manager) : m(manager) +{m_todo.push_back(root);} + +bool proof_post_order::hasNext() +{return !m_todo.empty();} + +/* + * iterative post-order depth-first search (DFS) through the proof DAG + */ +proof* proof_post_order::next() +{ + while (!m_todo.empty()) { + proof* currentNode = m_todo.back(); + + // if we haven't already visited the current unit + if (!m_visited.is_marked(currentNode)) { + bool existsUnvisitedParent = false; + + // add unprocessed premises to stack for DFS. + // If there is at least one unprocessed premise, don't compute the result + // for currentProof now, but wait until those unprocessed premises are processed. + for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) { + SASSERT(m.is_proof(currentNode->get_arg(i))); + proof* premise = to_app(currentNode->get_arg(i)); + + // if we haven't visited the current premise yet + if (!m_visited.is_marked(premise)) { + // add it to the stack + m_todo.push_back(premise); + existsUnvisitedParent = true; + } + } + + // if we already visited all parent-inferences, we can visit the inference too + if (!existsUnvisitedParent) { + m_visited.mark(currentNode, true); + m_todo.pop_back(); + return currentNode; + } + } else { + m_todo.pop_back(); + } + } + // we have already iterated through all inferences + return nullptr; +} + class reduce_hypotheses { + ast_manager &m; + // tracking all created expressions + expr_ref_vector m_pinned; + + // cache for the transformation + obj_map m_cache; + + // map from unit literals to their hypotheses-free derivations + obj_map m_units; + + // -- all hypotheses in the the proof + obj_hashtable m_hyps; + + // marks hypothetical proofs + ast_mark m_hypmark; + + + // stack + ptr_vector m_todo; + + void reset() + { + m_cache.reset(); + m_units.reset(); + m_hyps.reset(); + m_hypmark.reset(); + m_pinned.reset(); + } + + bool compute_mark1(proof *pr) + { + bool hyp_mark = false; + // lemmas clear all hypotheses + if (!m.is_lemma(pr)) { + for (unsigned i = 0, sz = m.get_num_parents(pr); i < sz; ++i) { + if (m_hypmark.is_marked(m.get_parent(pr, i))) { + hyp_mark = true; + break; + } + } + } + m_hypmark.mark(pr, hyp_mark); + return hyp_mark; + } + + void compute_marks(proof* pr) { + proof *p; + proof_post_order pit(pr, m); + while (pit.hasNext()) { + p = pit.next(); + if (m.is_hypothesis(p)) { + m_hypmark.mark(p, true); + m_hyps.insert(m.get_fact(p)); + } + else { + bool hyp_mark = compute_mark1(p); + // collect units that are hyp-free and are used as hypotheses somewhere + if (!hyp_mark && m.has_fact(p) && m_hyps.contains(m.get_fact(p))) { + m_units.insert(m.get_fact(p), p); + } + } + } + } + void find_units(proof *pr) + { + // optional. not implemented yet. + } + + void reduce(proof* pf, proof_ref &out) + { + proof *res = NULL; + + m_todo.reset(); + m_todo.push_back(pf); + ptr_buffer args; + bool dirty = false; + + while (!m_todo.empty()) { + proof *p, *tmp, *pp; + unsigned todo_sz; + + p = m_todo.back(); + if (m_cache.find(p, tmp)) { + res = tmp; + m_todo.pop_back(); + continue; + } + + dirty = false; + args.reset(); + todo_sz = m_todo.size(); + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { + pp = m.get_parent(p, i); + if (m_cache.find(pp, tmp)) { + args.push_back(tmp); + dirty = dirty || pp != tmp; + } else { + m_todo.push_back(pp); + } + } + + if (todo_sz < m_todo.size()) { continue; } + else { m_todo.pop_back(); } + + if (m.is_hypothesis(p)) { + // hyp: replace by a corresponding unit + if (m_units.find(m.get_fact(p), tmp)) { + res = tmp; + } else { res = p; } + } + + else if (!dirty) { res = p; } + + else if (m.is_lemma(p)) { + //lemma: reduce the premise; remove reduced consequences from conclusion + SASSERT(args.size() == 1); + res = mk_lemma_core(args.get(0), m.get_fact(p)); + compute_mark1(res); + } else if (m.is_unit_resolution(p)) { + // unit: reduce untis; reduce the first premise; rebuild unit resolution + res = mk_unit_resolution_core(args.size(), args.c_ptr()); + compute_mark1(res); + } else { + // other: reduce all premises; reapply + if (m.has_fact(p)) { args.push_back(to_app(m.get_fact(p))); } + SASSERT(p->get_decl()->get_arity() == args.size()); + res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr()); + m_pinned.push_back(res); + compute_mark1(res); + } + + SASSERT(res); + m_cache.insert(p, res); + + if (m.has_fact(res) && m.is_false(m.get_fact(res))) { break; } + } + + out = res; + } + + // returns true if (hypothesis (not a)) would be reduced + bool is_reduced(expr *a) + { + expr_ref e(m); + if (m.is_not(a)) { e = to_app(a)->get_arg(0); } + else { e = m.mk_not(a); } + + return m_units.contains(e); + } + + proof *mk_lemma_core(proof *pf, expr *fact) + { + ptr_buffer args; + expr_ref lemma(m); + + if (m.is_or(fact)) { + for (unsigned i = 0, sz = to_app(fact)->get_num_args(); i < sz; ++i) { + expr *a = to_app(fact)->get_arg(i); + if (!is_reduced(a)) + { args.push_back(a); } + } + } else if (!is_reduced(fact)) + { args.push_back(fact); } + + + if (args.size() == 0) { return pf; } + else if (args.size() == 1) { + lemma = args.get(0); + } else { + lemma = m.mk_or(args.size(), args.c_ptr()); + } + proof* res = m.mk_lemma(pf, lemma); + m_pinned.push_back(res); + + if (m_hyps.contains(lemma)) + { m_units.insert(lemma, res); } + return res; + } + + proof *mk_unit_resolution_core(unsigned num_args, proof* const *args) + { + + ptr_buffer pf_args; + pf_args.push_back(args [0]); + + app *cls_fact = to_app(m.get_fact(args[0])); + ptr_buffer cls; + if (m.is_or(cls_fact)) { + for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i) + { cls.push_back(cls_fact->get_arg(i)); } + } else { cls.push_back(cls_fact); } + + // construct new resovent + ptr_buffer new_fact_cls; + bool found; + // XXX quadratic + for (unsigned i = 0, sz = cls.size(); i < sz; ++i) { + found = false; + for (unsigned j = 1; j < num_args; ++j) { + if (m.is_complement(cls.get(i), m.get_fact(args [j]))) { + found = true; + pf_args.push_back(args [j]); + break; + } + } + if (!found) { + new_fact_cls.push_back(cls.get(i)); + } + } + + SASSERT(new_fact_cls.size() + pf_args.size() - 1 == cls.size()); + expr_ref new_fact(m); + new_fact = mk_or(m, new_fact_cls.size(), new_fact_cls.c_ptr()); + + // create new proof step + proof *res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), new_fact); + m_pinned.push_back(res); + return res; + } + + // reduce all units, if any unit reduces to false return true and put its proof into out + bool reduce_units(proof_ref &out) + { + proof_ref res(m); + for (auto entry : m_units) { + reduce(entry.get_value(), res); + if (m.is_false(m.get_fact(res))) { + out = res; + return true; + } + res.reset(); + } + return false; + } + + +public: + reduce_hypotheses(ast_manager &m) : m(m), m_pinned(m) {} + + + void operator()(proof_ref &pr) + { + compute_marks(pr); + if (!reduce_units(pr)) { + reduce(pr.get(), pr); + } + reset(); + } +}; + +void reduce_hypotheses(proof_ref &pr) { + ast_manager &m = pr.get_manager(); + class reduce_hypotheses hypred(m); + hypred(pr); + DEBUG_CODE(proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(pr, side)); + ); +} + + + +#include "ast/ast_smt2_pp.h" + +class reduce_hypotheses0 { typedef obj_hashtable expr_set; ast_manager& m; + // reference for any expression created by the tranformation expr_ref_vector m_refs; + // currently computed result obj_map m_cache; + // map conclusions to closed proofs that derive them obj_map m_units; + // currently active units ptr_vector m_units_trail; + // size of m_units_trail at the last push unsigned_vector m_limits; + // map from proofs to active hypotheses obj_map m_hypmap; + // refernce train for hypotheses sets ptr_vector m_hyprefs; ptr_vector m_literals; @@ -78,7 +413,7 @@ class reduce_hypotheses { m_hyprefs.push_back(hyps); inherited = false; } - datalog::set_union(*hyps, *hyps1); + set_union(*hyps, *hyps1); } } } @@ -130,7 +465,7 @@ class reduce_hypotheses { } public: - reduce_hypotheses(ast_manager& m): m(m), m_refs(m) {} + reduce_hypotheses0(ast_manager& m): m(m), m_refs(m) {} void operator()(proof_ref& pr) { proof_ref tmp(m); @@ -151,19 +486,33 @@ public: p = result; return; } + //SASSERT (p.get () == result); switch(p->get_decl_kind()) { case PR_HYPOTHESIS: + // replace result by m_units[m.get_fact (p)] if defined + // AG: This is the main step. Replace a hypothesis by a derivation of its consequence if (!m_units.find(m.get_fact(p), result)) { + // restore ther result back to p result = p.get(); } + // compute hypothesis of the result + // not clear what 'result' is at this point. + // probably the proof at the top of the call + // XXX not clear why this is re-computed each time + // XXX moreover, m_units are guaranteed to be closed! + // XXX so no hypotheses are needed for them add_hypotheses(result); break; case PR_LEMMA: { SASSERT(m.get_num_parents(p) == 1); tmp = m.get_parent(p, 0); + // eliminate hypothesis recursively in the proof of the lemma elim(tmp); expr_set* hyps = m_hypmap.find(tmp); expr_set* new_hyps = 0; + // XXX if the proof is correct, the hypotheses of the tmp + // XXX should be exactly those of the consequence of the lemma + // XXX but if this code actually eliminates hypotheses, the set might be a subset if (hyps) { new_hyps = alloc(expr_set, *hyps); } @@ -178,13 +527,19 @@ public: get_literals(fact); } + // go over all the literals in the consequence of the lemma for (unsigned i = 0; i < m_literals.size(); ++i) { expr* e = m_literals[i]; + // if the literal is not in hypothesis, skip it if (!in_hypotheses(e, hyps)) { m_literals[i] = m_literals.back(); m_literals.pop_back(); --i; } + // if the literal is in hypothesis remove it because + // it is not in hypothesis set of the lemma + // XXX but we assume that lemmas have empty hypothesis set. + // XXX eventually every element of new_hyps must be removed! else { SASSERT(new_hyps); expr_ref not_e = complement_lit(e); @@ -192,10 +547,13 @@ public: new_hyps->remove(not_e); } } + // killed all hypotheses, so can stop at the lemma since + // we have a closed pf of false if (m_literals.empty()) { result = tmp; } else { + // create a new lemma, but might be re-creating existing one expr_ref clause(m); if (m_literals.size() == 1) { clause = m_literals[0]; @@ -212,6 +570,7 @@ public: new_hyps = 0; } m_hypmap.insert(result, new_hyps); + // might push 0 into m_hyprefs. No reason for that m_hyprefs.push_back(new_hyps); TRACE("proof_utils", tout << "New lemma: " << mk_pp(m.get_fact(p), m) @@ -229,19 +588,27 @@ public: } case PR_UNIT_RESOLUTION: { proof_ref_vector parents(m); + // get the clause being resolved with parents.push_back(m.get_parent(p, 0)); + // save state push(); bool found_false = false; + // for every derivation of a unit literal for (unsigned i = 1; i < m.get_num_parents(p); ++i) { + // see if it derives false tmp = m.get_parent(p, i); elim(tmp); if (m.is_false(m.get_fact(tmp))) { + // if derived false, the whole pf is false and we can bail out result = tmp; found_false = true; break; } + // -- otherwise, the fact has not changed. nothing to simplify SASSERT(m.get_fact(tmp) == m.get_fact(m.get_parent(p, i))); parents.push_back(tmp); + // remember that we have this derivation while we have not poped the trail + // but only if the proof is closed (i.e., a real unit) if (is_closed(tmp) && !m_units.contains(m.get_fact(tmp))) { m_units.insert(m.get_fact(tmp), tmp); m_units_trail.push_back(m.get_fact(tmp)); @@ -251,10 +618,15 @@ public: pop(); break; } + // look at the clause being resolved with tmp = m.get_parent(p, 0); + // remember its fact expr* old_clause = m.get_fact(tmp); + // attempt to reduce its fact elim(tmp); + // update parents parents[0] = tmp; + // if the new fact is false, bail out expr* clause = m.get_fact(tmp); if (m.is_false(clause)) { m_refs.push_back(tmp); @@ -264,8 +636,10 @@ public: } // // case where clause is a literal in the old clause. + // i.e., reduce multi-literal clause to a unit // if (is_literal_in_clause(clause, old_clause)) { + // if the resulting literal was resolved, get a pf of false and bail out bool found = false; for (unsigned i = 1; !found && i < parents.size(); ++i) { if (m.is_complement(clause, m.get_fact(parents[i].get()))) { @@ -277,6 +651,7 @@ public: found = true; } } + // else if the resulting literal is not resolved, it is the new consequence if (!found) { result = parents[0].get(); } @@ -369,7 +744,7 @@ public: void proof_utils::reduce_hypotheses(proof_ref& pr) { ast_manager& m = pr.get_manager(); - class reduce_hypotheses reduce(m); + class reduce_hypotheses0 reduce(m); reduce(pr); CTRACE("proof_utils", !is_closed(m, pr), tout << mk_pp(pr, m) << "\n";); } @@ -508,6 +883,11 @@ static void permute_unit_resolution(expr_ref_vector& refs, obj_map SASSERT(params[0].is_symbol()); family_id tid = m.mk_family_id(params[0].get_symbol()); SASSERT(tid != null_family_id); + // AG: This can break a theory lemma. In particular, for Farkas lemmas the coefficients + // AG: for the literals propagated from the unit resolution are missing. + // AG: Why is this a good thing to do? + // AG: This can lead to merging of the units with other terms in interpolation, + // AG: but without farkas coefficients this does not make sense prNew = m.mk_th_lemma(tid, m.get_fact(pr), premises.size(), premises.c_ptr(), num_params-1, params+1); } diff --git a/src/ast/proofs/proof_utils.h b/src/ast/proofs/proof_utils.h new file mode 100644 index 000000000..b953c834d --- /dev/null +++ b/src/ast/proofs/proof_utils.h @@ -0,0 +1,238 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + proof_utils.h + +Abstract: + Utilities to traverse and manipulate proofs + +Author: + Bernhard Gleiss + Arie Gurfinkel + Nikolaj Bjorner + +Revision History: + +--*/ + +#ifndef PROOF_UTILS_H_ +#define PROOF_UTILS_H_ +#include "ast/ast.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/proofs/proof_checker.h" + +/* + * iterator, which traverses the proof in depth-first post-order. + */ + +class proof_post_order { +public: + proof_post_order(proof* refutation, ast_manager& manager); + bool hasNext(); + proof* next(); + +private: + ptr_vector m_todo; + ast_mark m_visited; // the proof nodes we have already visited + ast_manager& m; +}; + +void reduce_hypotheses(proof_ref &pr); + + +class proof_utils { +public: + /** + \brief reduce the set of hypotheses used in the proof. + */ + static void reduce_hypotheses(proof_ref& pr); + + /** + \brief Check that a proof does not contain open hypotheses. + */ + static bool is_closed(ast_manager& m, proof* p); + + /** + \brief Permute unit resolution rule with th-lemma + */ + static void permute_unit_resolution(proof_ref& pr); + + /** + \brief Push instantiations created in hyper-resolutions up to leaves. + This produces a "ground" proof where leaves are annotated by instantiations. + */ + static void push_instantiations_up(proof_ref& pr); + + +}; + +class elim_aux_assertions { + + static bool matches_fact(expr_ref_vector &args, expr* &match) { + ast_manager &m = args.get_manager(); + expr *fact = args.back(); + for (unsigned i = 0, sz = args.size() - 1; i < sz; ++i) { + expr *arg = args.get(i); + if (m.is_proof(arg) && + m.has_fact(to_app(arg)) && + m.get_fact(to_app(arg)) == fact) { + match = arg; + return true; + } + } + return false; + } + + app_ref m_aux; +public: + elim_aux_assertions(app_ref aux) : m_aux(aux) {} + + void mk_or_core(expr_ref_vector &args, expr_ref &res) + { + ast_manager &m = args.get_manager(); + unsigned j = 0; + for (unsigned i = 0, sz = args.size(); i < sz; ++i) { + if (m.is_false(args.get(i))) { continue; } + if (i != j) { args [j] = args.get(i); } + ++j; + } + SASSERT(j >= 1); + res = j > 1 ? m.mk_or(j, args.c_ptr()) : args.get(0); + } + + void mk_app(func_decl *decl, expr_ref_vector &args, expr_ref &res) + { + ast_manager &m = args.get_manager(); + bool_rewriter brwr(m); + + if (m.is_or(decl)) + { mk_or_core(args, res); } + else if (m.is_iff(decl) && args.size() == 2) + // avoiding simplifying equalities. In particular, + // we don't want (= (not a) (not b)) to be reduced to (= a b) + { res = m.mk_iff(args.get(0), args.get(1)); } + else + { brwr.mk_app(decl, args.size(), args.c_ptr(), res); } + } + + void operator()(ast_manager &m, proof *pr, proof_ref &res) + { + DEBUG_CODE(proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(pr, side)); + ); + obj_map cache; + bool_rewriter brwr(m); + + // for reference counting of new proofs + app_ref_vector pinned(m); + + ptr_vector todo; + todo.push_back(pr); + + expr_ref not_aux(m); + not_aux = m.mk_not(m_aux); + + expr_ref_vector args(m); + + while (!todo.empty()) { + app *p, *r; + expr *a; + + p = todo.back(); + if (cache.find(pr, r)) { + todo.pop_back(); + continue; + } + + SASSERT(!todo.empty() || pr == p); + bool dirty = false; + unsigned todo_sz = todo.size(); + args.reset(); + for (unsigned i = 0, sz = p->get_num_args(); i < sz; ++i) { + expr* arg = p->get_arg(i); + if (arg == m_aux.get()) { + dirty = true; + args.push_back(m.mk_true()); + } else if (arg == not_aux.get()) { + dirty = true; + args.push_back(m.mk_false()); + } + // skip (asserted m_aux) + else if (m.is_asserted(arg, a) && a == m_aux.get()) { + dirty = true; + } + // skip (hypothesis m_aux) + else if (m.is_hypothesis(arg, a) && a == m_aux.get()) { + dirty = true; + } else if (is_app(arg) && cache.find(to_app(arg), r)) { + dirty |= (arg != r); + args.push_back(r); + } else if (is_app(arg)) + { todo.push_back(to_app(arg)); } + else + // -- not an app + { args.push_back(arg); } + + } + if (todo_sz < todo.size()) { + // -- process parents + args.reset(); + continue; + } + + // ready to re-create + app_ref newp(m); + if (!dirty) { newp = p; } + else if (m.is_unit_resolution(p)) { + if (args.size() == 2) + // unit resolution with m_aux that got collapsed to nothing + { newp = to_app(args.get(0)); } + else { + ptr_vector parents; + for (unsigned i = 0, sz = args.size() - 1; i < sz; ++i) + { parents.push_back(to_app(args.get(i))); } + SASSERT(parents.size() == args.size() - 1); + newp = m.mk_unit_resolution(parents.size(), parents.c_ptr()); + // XXX the old and new facts should be + // equivalent. The test here is much + // stronger. It might need to be relaxed. + SASSERT(m.get_fact(newp) == args.back()); + pinned.push_back(newp); + } + } else if (matches_fact(args, a)) { + newp = to_app(a); + } else { + expr_ref papp(m); + mk_app(p->get_decl(), args, papp); + newp = to_app(papp.get()); + pinned.push_back(newp); + } + cache.insert(p, newp); + todo.pop_back(); + CTRACE("virtual", + p->get_decl_kind() == PR_TH_LEMMA && + p->get_decl()->get_parameter(0).get_symbol() == "arith" && + p->get_decl()->get_num_parameters() > 1 && + p->get_decl()->get_parameter(1).get_symbol() == "farkas", + tout << "Old pf: " << mk_pp(p, m) << "\n" + << "New pf: " << mk_pp(newp, m) << "\n";); + } + + proof *r; + VERIFY(cache.find(pr, r)); + + DEBUG_CODE( + proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(r, side)); + ); + + res = r ; + } +}; + +#endif diff --git a/src/ast/recurse_expr.h b/src/ast/recurse_expr.h index 46375d955..866e39d3f 100644 --- a/src/ast/recurse_expr.h +++ b/src/ast/recurse_expr.h @@ -19,8 +19,8 @@ Revision History: #ifndef RECURSE_EXPR_H_ #define RECURSE_EXPR_H_ -#include"ast.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" template class recurse_expr : public Visitor { diff --git a/src/ast/recurse_expr_def.h b/src/ast/recurse_expr_def.h index 5149baa93..d4f608c5a 100644 --- a/src/ast/recurse_expr_def.h +++ b/src/ast/recurse_expr_def.h @@ -19,7 +19,7 @@ Revision History: #ifndef RECURSE_EXPR_DEF_H_ #define RECURSE_EXPR_DEF_H_ -#include"recurse_expr.h" +#include "ast/recurse_expr.h" template inline void recurse_expr::visit(expr * n, bool & visited) { diff --git a/src/ast/reg_decl_plugins.cpp b/src/ast/reg_decl_plugins.cpp index b4ff63ede..985ecee9e 100644 --- a/src/ast/reg_decl_plugins.cpp +++ b/src/ast/reg_decl_plugins.cpp @@ -17,15 +17,15 @@ Author: Revision History: --*/ -#include"ast.h" -#include"arith_decl_plugin.h" -#include"array_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"datatype_decl_plugin.h" -#include"dl_decl_plugin.h" -#include"seq_decl_plugin.h" -#include"pb_decl_plugin.h" -#include"fpa_decl_plugin.h" +#include "ast/ast.h" +#include "ast/arith_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/dl_decl_plugin.h" +#include "ast/seq_decl_plugin.h" +#include "ast/pb_decl_plugin.h" +#include "ast/fpa_decl_plugin.h" void reg_decl_plugins(ast_manager & m) { if (!m.get_plugin(m.mk_family_id(symbol("arith")))) { diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index abf09ff0c..57924b48a 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -3,22 +3,29 @@ z3_add_component(rewriter arith_rewriter.cpp array_rewriter.cpp ast_counter.cpp + bit2int.cpp bool_rewriter.cpp bv_bounds.cpp + bv_elim.cpp bv_rewriter.cpp datatype_rewriter.cpp der.cpp distribute_forall.cpp dl_rewriter.cpp + elim_bounds.cpp enum2bv_rewriter.cpp expr_replacer.cpp expr_safe_replace.cpp factor_rewriter.cpp fpa_rewriter.cpp + inj_axiom.cpp label_rewriter.cpp + maximize_ac_sharing.cpp mk_simplified_app.cpp pb_rewriter.cpp pb2bv_rewriter.cpp + push_app_ite.cpp + pull_ite_tree.cpp quant_hoist.cpp rewriter.cpp seq_rewriter.cpp diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 258c28369..631e1d8f3 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -16,17 +16,17 @@ Author: Notes: --*/ -#include"arith_rewriter.h" -#include"arith_rewriter_params.hpp" -#include"poly_rewriter_def.h" -#include"algebraic_numbers.h" -#include"ast_pp.h" +#include "ast/rewriter/arith_rewriter.h" +#include "ast/rewriter/arith_rewriter_params.hpp" +#include "ast/rewriter/poly_rewriter_def.h" +#include "math/polynomial/algebraic_numbers.h" +#include "ast/ast_pp.h" void arith_rewriter::updt_local_params(params_ref const & _p) { arith_rewriter_params p(_p); m_arith_lhs = p.arith_lhs(); + m_arith_ineq_lhs = p.arith_ineq_lhs(); m_gcd_rounding = p.gcd_rounding(); - m_eq2ineq = p.eq2ineq(); m_elim_to_real = p.elim_to_real(); m_push_to_real = p.push_to_real(); m_anum_simp = p.algebraic_number_evaluator(); @@ -35,6 +35,7 @@ void arith_rewriter::updt_local_params(params_ref const & _p) { m_mul2power = p.mul_to_power(); m_elim_rem = p.elim_rem(); m_expand_tan = p.expand_tan(); + m_eq2ineq = p.eq2ineq(); set_sort_sums(p.sort_sums()); } @@ -370,8 +371,8 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin if ((is_zero(arg1) && is_reduce_power_target(arg2, kind == EQ)) || (is_zero(arg2) && is_reduce_power_target(arg1, kind == EQ))) return reduce_power(arg1, arg2, kind, result); - br_status st = cancel_monomials(arg1, arg2, m_arith_lhs, new_arg1, new_arg2); - TRACE("mk_le_bug", tout << "st: " << st << "\n";); + br_status st = cancel_monomials(arg1, arg2, m_arith_ineq_lhs || m_arith_lhs, new_arg1, new_arg2); + TRACE("mk_le_bug", tout << "st: " << st << " " << new_arg1 << " " << new_arg2 << "\n";); if (st != BR_FAILED) { arg1 = new_arg1; arg2 = new_arg2; @@ -454,7 +455,16 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin st = BR_DONE; } } - if (st == BR_DONE && arg1 == orig_arg1 && arg2 == orig_arg2) { + if ((m_arith_lhs || m_arith_ineq_lhs) && is_numeral(arg2, a2) && is_neg_poly(arg1, new_arg1)) { + a2.neg(); + new_arg2 = m_util.mk_numeral(a2, m_util.is_int(new_arg1)); + switch (kind) { + case LE: result = m_util.mk_ge(new_arg1, new_arg2); return BR_DONE; + case GE: result = m_util.mk_le(new_arg1, new_arg2); return BR_DONE; + case EQ: result = m_util.mk_eq(new_arg1, new_arg2); return BR_DONE; + } + } + else if (st == BR_DONE && arg1 == orig_arg1 && arg2 == orig_arg2) { // Nothing new; return BR_FAILED to avoid rewriting loops. return BR_FAILED; } @@ -486,12 +496,69 @@ br_status arith_rewriter::mk_gt_core(expr * arg1, expr * arg2, expr_ref & result return BR_REWRITE2; } +bool arith_rewriter::is_arith_term(expr * n) const { + return n->get_kind() == AST_APP && to_app(n)->get_family_id() == get_fid(); +} + br_status arith_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) { if (m_eq2ineq) { result = m().mk_and(m_util.mk_le(arg1, arg2), m_util.mk_ge(arg1, arg2)); return BR_REWRITE2; } - return mk_le_ge_eq_core(arg1, arg2, EQ, result); + if (m_arith_lhs || is_arith_term(arg1) || is_arith_term(arg2)) { + return mk_le_ge_eq_core(arg1, arg2, EQ, result); + } + return BR_FAILED; +} + +expr_ref arith_rewriter::neg_monomial(expr* e) const { + expr_ref_vector args(m()); + rational a1; + if (is_app(e) & m_util.is_mul(e)) { + if (is_numeral(to_app(e)->get_arg(0), a1)) { + if (!a1.is_minus_one()) { + args.push_back(m_util.mk_numeral(-a1, m_util.is_int(e))); + } + args.append(to_app(e)->get_num_args() - 1, to_app(e)->get_args() + 1); + } + else { + args.push_back(m_util.mk_numeral(rational(-1), m_util.is_int(e))); + args.push_back(e); + } + } + else { + args.push_back(m_util.mk_numeral(rational(-1), m_util.is_int(e))); + args.push_back(e); + } + if (args.size() == 1) { + return expr_ref(args.back(), m()); + } + else { + return expr_ref(m_util.mk_mul(args.size(), args.c_ptr()), m()); + } +} + +bool arith_rewriter::is_neg_poly(expr* t, expr_ref& neg) const { + rational r; + if (m_util.is_mul(t) && is_numeral(to_app(t)->get_arg(0), r) && r.is_neg()) { + neg = neg_monomial(t); + return true; + } + + if (!m_util.is_add(t)) { + return false; + } + expr * t2 = to_app(t)->get_arg(0); + + if (m_util.is_mul(t2) && is_numeral(to_app(t2)->get_arg(0), r) && r.is_neg()) { + expr_ref_vector args1(m()); + for (expr* e1 : *to_app(t)) { + args1.push_back(neg_monomial(e1)); + } + neg = m_util.mk_add(args1.size(), args1.c_ptr()); + return true; + } + return false; } bool arith_rewriter::is_anum_simp_target(unsigned num_args, expr * const * args) { @@ -680,8 +747,7 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul if (m_util.is_numeral(arg2, v2, is_int)) { SASSERT(!is_int); if (v2.is_zero()) { - result = m_util.mk_div0(arg1); - return BR_REWRITE1; + return BR_FAILED; } else if (m_util.is_numeral(arg1, v1, is_int)) { result = m_util.mk_numeral(v1/v2, false); @@ -734,10 +800,6 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu result = m_util.mk_numeral(div(v1, v2), is_int); return BR_DONE; } - if (m_util.is_numeral(arg2, v2, is_int) && v2.is_zero()) { - result = m_util.mk_idiv0(arg1); - return BR_REWRITE1; - } return BR_FAILED; } @@ -755,6 +817,13 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul return BR_DONE; } + if (arg1 == arg2 && !m_util.is_numeral(arg2)) { + expr_ref zero(m_util.mk_int(0), m()), abs(m()); + mk_abs_core(arg2, abs); + result = m().mk_ite(m().mk_eq(arg2, zero), m_util.mk_mod(zero, zero), abs); + return BR_DONE; + } + // mod is idempotent on non-zero modulus. expr* t1, *t2; if (m_util.is_mod(arg1, t1, t2) && t2 == arg2 && m_util.is_numeral(arg2, v2, is_int) && is_int && !v2.is_zero()) { diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index 68a60e1f0..95668ea44 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -19,8 +19,8 @@ Notes: #ifndef ARITH_REWRITER_H_ #define ARITH_REWRITER_H_ -#include"poly_rewriter.h" -#include"arith_decl_plugin.h" +#include "ast/rewriter/poly_rewriter.h" +#include "ast/arith_decl_plugin.h" class arith_rewriter_core { protected: @@ -35,7 +35,6 @@ protected: bool is_numeral(expr * n) const { return m_util.is_numeral(n); } bool is_numeral(expr * n, numeral & r) const { return m_util.is_numeral(n, r); } - bool is_zero(expr * n) const { return m_util.is_zero(n); } bool is_minus_one(expr * n) const { return m_util.is_minus_one(n); } void normalize(numeral & c, sort * s) {} app * mk_numeral(numeral const & r, sort * s) { return m_util.mk_numeral(r, s); } @@ -45,16 +44,18 @@ protected: decl_kind power_decl_kind() const { return OP_POWER; } public: arith_rewriter_core(ast_manager & m):m_util(m) {} + bool is_zero(expr * n) const { return m_util.is_zero(n); } }; class arith_rewriter : public poly_rewriter { bool m_arith_lhs; + bool m_arith_ineq_lhs; bool m_gcd_rounding; - bool m_eq2ineq; bool m_elim_to_real; bool m_push_to_real; bool m_anum_simp; bool m_elim_rem; + bool m_eq2ineq; unsigned m_max_degree; void get_coeffs_gcd(expr * t, numeral & g, bool & first, unsigned & num_consts); @@ -82,12 +83,16 @@ class arith_rewriter : public poly_rewriter { expr * reduce_power(expr * arg, bool is_eq); br_status reduce_power(expr * arg1, expr * arg2, op_kind kind, expr_ref & result); + bool is_arith_term(expr * n) const; + bool is_pi_multiple(expr * t, rational & k); bool is_pi_offset(expr * t, rational & k, expr * & m); bool is_2_pi_integer(expr * t); bool is_2_pi_integer_offset(expr * t, expr * & m); bool is_pi_integer(expr * t); bool is_pi_integer_offset(expr * t, expr * & m); + bool is_neg_poly(expr* e, expr_ref& neg) const; + expr_ref neg_monomial(expr * e) const; expr * mk_sin_value(rational const & k); app * mk_sqrt(rational const & k); diff --git a/src/ast/rewriter/arith_rewriter_params.pyg b/src/ast/rewriter/arith_rewriter_params.pyg index 8a41d838d..c7374105a 100644 --- a/src/ast/rewriter/arith_rewriter_params.pyg +++ b/src/ast/rewriter/arith_rewriter_params.pyg @@ -6,10 +6,11 @@ def_module_params(module_name='rewriter', ("expand_power", BOOL, False, "expand (^ t k) into (* t ... t) if 1 < k <= max_degree."), ("expand_tan", BOOL, False, "replace (tan x) with (/ (sin x) (cos x))."), ("max_degree", UINT, 64, "max degree of algebraic numbers (and power operators) processed by simplifier."), - ("eq2ineq", BOOL, False, "split arithmetic equalities into two inequalities."), ("sort_sums", BOOL, False, "sort the arguments of + application."), ("gcd_rounding", BOOL, False, "use gcd rounding on integer arithmetic atoms."), ("arith_lhs", BOOL, False, "all monomials are moved to the left-hand-side, and the right-hand-side is just a constant."), + ("arith_ineq_lhs", BOOL, False, "rewrite inequalities so that right-hand-side is a constant."), ("elim_to_real", BOOL, False, "eliminate to_real from arithmetic predicates that contain only integers."), ("push_to_real", BOOL, True, "distribute to_real over * and +."), + ("eq2ineq", BOOL, False, "expand equalities into two inequalities"), ("elim_rem", BOOL, False, "replace (rem x y) with (ite (>= y 0) (mod x y) (- (mod x y)))."))) diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 6f6b5b62e..fb7783fe9 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -16,10 +16,10 @@ Author: Notes: --*/ -#include"array_rewriter.h" -#include"array_rewriter_params.hpp" -#include"ast_lt.h" -#include"ast_pp.h" +#include "ast/rewriter/array_rewriter.h" +#include "ast/rewriter/array_rewriter_params.hpp" +#include "ast/ast_lt.h" +#include "ast/ast_pp.h" void array_rewriter::updt_params(params_ref const & _p) { array_rewriter_params p(_p); diff --git a/src/ast/rewriter/array_rewriter.h b/src/ast/rewriter/array_rewriter.h index 4ff48d496..90b3b6f34 100644 --- a/src/ast/rewriter/array_rewriter.h +++ b/src/ast/rewriter/array_rewriter.h @@ -19,10 +19,10 @@ Notes: #ifndef ARRAY_REWRITER_H_ #define ARRAY_REWRITER_H_ -#include"array_decl_plugin.h" -#include"rewriter_types.h" -#include"lbool.h" -#include"params.h" +#include "ast/array_decl_plugin.h" +#include "ast/rewriter/rewriter_types.h" +#include "util/lbool.h" +#include "util/params.h" /** \brief Cheap rewrite rules for Arrays diff --git a/src/ast/rewriter/array_rewriter_params.pyg b/src/ast/rewriter/array_rewriter_params.pyg index a43fadecf..3b4af7fb7 100644 --- a/src/ast/rewriter/array_rewriter_params.pyg +++ b/src/ast/rewriter/array_rewriter_params.pyg @@ -2,5 +2,5 @@ def_module_params(module_name='rewriter', class_name='array_rewriter_params', export=True, params=(("expand_select_store", BOOL, False, "replace a (select (store ...) ...) term by an if-then-else term"), - ("expand_store_eq", BOOL, False, "reduce (store ...) = (store ...) with a common base into selects"), + ("expand_store_eq", BOOL, False, "reduce (store ...) = (store ...) with a common base into selects"), ("sort_store", BOOL, False, "sort nested stores when the indices are known to be different"))) diff --git a/src/ast/rewriter/ast_counter.cpp b/src/ast/rewriter/ast_counter.cpp index f2c8cabf7..bc11e4fb0 100644 --- a/src/ast/rewriter/ast_counter.cpp +++ b/src/ast/rewriter/ast_counter.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include "ast_counter.h" +#include "ast/rewriter/ast_counter.h" void counter::update(unsigned el, int delta) { int & counter = get(el); diff --git a/src/ast/rewriter/ast_counter.h b/src/ast/rewriter/ast_counter.h index 4509d2549..a2d1c239b 100644 --- a/src/ast/rewriter/ast_counter.h +++ b/src/ast/rewriter/ast_counter.h @@ -24,10 +24,10 @@ Revision History: #ifndef AST_COUNTER_H_ #define AST_COUNTER_H_ -#include "ast.h" -#include "map.h" -#include "uint_set.h" -#include "var_subst.h" +#include "ast/ast.h" +#include "util/map.h" +#include "util/uint_set.h" +#include "ast/rewriter/var_subst.h" class counter { protected: diff --git a/src/ast/simplifier/bit2int.cpp b/src/ast/rewriter/bit2int.cpp similarity index 87% rename from src/ast/simplifier/bit2int.cpp rename to src/ast/rewriter/bit2int.cpp index 08c3da774..257740412 100644 --- a/src/ast/simplifier/bit2int.cpp +++ b/src/ast/rewriter/bit2int.cpp @@ -19,15 +19,16 @@ Revision History: --*/ -#include "bit2int.h" -#include "ast_pp.h" -#include "ast_ll_pp.h" -#include "for_each_ast.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/for_each_ast.h" +#include "ast/rewriter/bit2int.h" + #define CHECK(_x_) if (!(_x_)) { UNREACHABLE(); } bit2int::bit2int(ast_manager & m) : - m_manager(m), m_bv_util(m), m_arith_util(m), m_cache(m), m_bit0(m) { + m_manager(m), m_bv_util(m), m_rewriter(m), m_arith_util(m), m_cache(m), m_bit0(m) { m_bit0 = m_bv_util.mk_numeral(0,1); } @@ -67,7 +68,7 @@ unsigned bit2int::get_numeral_bits(numeral const& k) { void bit2int::align_size(expr* e, unsigned sz, expr_ref& result) { unsigned sz1 = m_bv_util.get_bv_size(e); SASSERT(sz1 <= sz); - m_bv_simplifier->mk_zeroext(sz-sz1, e, result); + result = m_rewriter.mk_zero_extend(sz-sz1, e); } void bit2int::align_sizes(expr_ref& a, expr_ref& b) { @@ -75,11 +76,11 @@ void bit2int::align_sizes(expr_ref& a, expr_ref& b) { unsigned sz2 = m_bv_util.get_bv_size(b); expr_ref tmp(m_manager); if (sz1 > sz2) { - m_bv_simplifier->mk_zeroext(sz1-sz2, b, tmp); + tmp = m_rewriter.mk_zero_extend(sz1-sz2, b); b = tmp; } else if (sz2 > sz1) { - m_bv_simplifier->mk_zeroext(sz2-sz1, a, tmp); + tmp = m_rewriter.mk_zero_extend(sz2-sz1, a); a = tmp; } } @@ -123,11 +124,11 @@ bool bit2int::mk_add(expr* e1, expr* e2, expr_ref& result) { return true; } align_sizes(tmp1, tmp2); - m_bv_simplifier->mk_zeroext(1, tmp1, tmp1); - m_bv_simplifier->mk_zeroext(1, tmp2, tmp2); + tmp1 = m_rewriter.mk_zero_extend(1, tmp1); + tmp2 = m_rewriter.mk_zero_extend(1, tmp2); SASSERT(m_bv_util.get_bv_size(tmp1) == m_bv_util.get_bv_size(tmp2)); - m_bv_simplifier->mk_add(tmp1, tmp2, tmp3); - m_bv_simplifier->mk_bv2int(tmp3, m_arith_util.mk_int(), result); + tmp3 = m_rewriter.mk_bv_add(tmp1, tmp2); + result = m_rewriter.mk_bv2int(tmp3); return true; } return false; @@ -143,14 +144,14 @@ bool bit2int::mk_comp(eq_type ty, expr* e1, expr* e2, expr_ref& result) { SASSERT(m_bv_util.get_bv_size(tmp1) == m_bv_util.get_bv_size(tmp2)); switch(ty) { case lt: - m_bv_simplifier->mk_leq_core(false, tmp2, tmp1, tmp3); + tmp3 = m_rewriter.mk_ule(tmp2, tmp1); result = m_manager.mk_not(tmp3); break; case le: - m_bv_simplifier->mk_leq_core(false,tmp1, tmp2, result); + result = m_rewriter.mk_ule(tmp1, tmp2); break; case eq: - result = m_manager.mk_eq(tmp1,tmp2); + result = m_manager.mk_eq(tmp1, tmp2); break; } return true; @@ -167,12 +168,12 @@ bool bit2int::mk_mul(expr* e1, expr* e2, expr_ref& result) { if (extract_bv(e1, sz1, sign1, tmp1) && extract_bv(e2, sz2, sign2, tmp2)) { align_sizes(tmp1, tmp2); - m_bv_simplifier->mk_zeroext(m_bv_util.get_bv_size(tmp1), tmp1, tmp1); - m_bv_simplifier->mk_zeroext(m_bv_util.get_bv_size(tmp2), tmp2, tmp2); + tmp1 = m_rewriter.mk_zero_extend(m_bv_util.get_bv_size(tmp1), tmp1); + tmp2 = m_rewriter.mk_zero_extend(m_bv_util.get_bv_size(tmp2), tmp2); SASSERT(m_bv_util.get_bv_size(tmp1) == m_bv_util.get_bv_size(tmp2)); - m_bv_simplifier->mk_mul(tmp1, tmp2, tmp3); - m_bv_simplifier->mk_bv2int(tmp3, m_arith_util.mk_int(), result); + tmp3 = m_rewriter.mk_bv_mul(tmp1, tmp2); + result = m_rewriter.mk_bv2int(tmp3); if (sign1 != sign2) { result = m_arith_util.mk_uminus(result); } @@ -187,8 +188,7 @@ bool bit2int::is_bv_poly(expr* n, expr_ref& pos, expr_ref& neg) { numeral k; bool is_int; todo.push_back(n); - m_bv_simplifier->mk_bv2int(m_bit0, m_arith_util.mk_int(), pos); - m_bv_simplifier->mk_bv2int(m_bit0, m_arith_util.mk_int(), neg); + neg = pos = m_rewriter.mk_bv2int(m_bit0); while (!todo.empty()) { n = todo.back(); @@ -372,8 +372,8 @@ void bit2int::visit(app* n) { tmp1 = tmp_p; tmp2 = e2bv; align_sizes(tmp1, tmp2); - m_bv_simplifier->mk_bv_urem(tmp1, tmp2, tmp3); - m_bv_simplifier->mk_bv2int(tmp3, m_arith_util.mk_int(), result); + tmp3 = m_rewriter.mk_bv_urem(tmp1, tmp2); + result = m_rewriter.mk_bv2int(tmp3); cache_result(n, result); return; } @@ -382,25 +382,24 @@ void bit2int::visit(app* n) { tmp1 = tmp_n; tmp2 = e2bv; align_sizes(tmp1, tmp2); - m_bv_simplifier->mk_bv_urem(tmp1, tmp2, tmp3); + tmp3 = m_rewriter.mk_bv_urem(tmp1, tmp2); // e2 - (neg1 mod e2) tmp1 = e2bv; tmp2 = tmp3; align_sizes(tmp1, tmp2); - m_bv_simplifier->mk_sub(tmp1, tmp2, tmp3); + tmp3 = m_rewriter.mk_bv_sub(tmp1, tmp2); // pos1 + (e2 - (neg1 mod e2)) tmp1 = tmp_p; tmp2 = tmp3; align_sizes(tmp1, tmp2); - m_bv_simplifier->mk_zeroext(1, tmp1, tmp_p); - m_bv_simplifier->mk_zeroext(1, tmp2, tmp_n); - m_bv_simplifier->mk_add(tmp_p, tmp_n, tmp1); + tmp_p = m_rewriter.mk_zero_extend(1, tmp1); + tmp_n = m_rewriter.mk_zero_extend(1, tmp2); + tmp1 = m_rewriter.mk_bv_add(tmp_p, tmp_n); // (pos1 + (e2 - (neg1 mod e2))) mod e2 tmp2 = e2bv; align_sizes(tmp1, tmp2); - m_bv_simplifier->mk_bv_urem(tmp1, tmp2, tmp3); - - m_bv_simplifier->mk_bv2int(tmp3, m_arith_util.mk_int(), result); + tmp3 = m_rewriter.mk_bv_urem(tmp1, tmp2); + result = m_rewriter.mk_bv2int(tmp3); cache_result(n, result); } diff --git a/src/ast/simplifier/bit2int.h b/src/ast/rewriter/bit2int.h similarity index 88% rename from src/ast/simplifier/bit2int.h rename to src/ast/rewriter/bit2int.h index 6277a83ae..fbbf2e6d1 100644 --- a/src/ast/simplifier/bit2int.h +++ b/src/ast/rewriter/bit2int.h @@ -19,12 +19,10 @@ Revision History: #ifndef BIT2INT_H_ #define BIT2INT_H_ -#include"bv_decl_plugin.h" -#include"arith_decl_plugin.h" -#include"act_cache.h" -#include"basic_simplifier_plugin.h" -#include"bv_simplifier_plugin.h" - +#include "ast/bv_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "ast/act_cache.h" +#include "ast/rewriter/bv_rewriter.h" class bit2int { protected: @@ -60,8 +58,8 @@ protected: typedef act_cache expr_map; ast_manager & m_manager; bv_util m_bv_util; + bv_rewriter m_rewriter; arith_util m_arith_util; - bv_simplifier_plugin * m_bv_simplifier; expr_map m_cache; // map: ast -> ast ref. counters are incremented when inserted here. expr_ref m_bit0; @@ -77,7 +75,7 @@ protected: bool mk_mul(expr* a, expr* b, expr_ref& result); bool mk_comp(eq_type ty, expr* e1, expr* e2, expr_ref& result); bool mk_add(expr* e1, expr* e2, expr_ref& result); - + expr * get_cached(expr * n) const; bool is_cached(expr * n) const { return get_cached(n) != 0; } void cache_result(expr * n, expr * r); @@ -88,7 +86,6 @@ protected: public: bit2int(ast_manager & m); - void set_bv_simplifier(bv_simplifier_plugin * p) { m_bv_simplifier = p; } void operator()(expr * m, expr_ref & result, proof_ref& p); }; diff --git a/src/ast/rewriter/bit_blaster/CMakeLists.txt b/src/ast/rewriter/bit_blaster/CMakeLists.txt index 9eea1558e..c8985a051 100644 --- a/src/ast/rewriter/bit_blaster/CMakeLists.txt +++ b/src/ast/rewriter/bit_blaster/CMakeLists.txt @@ -4,5 +4,4 @@ z3_add_component(bit_blaster bit_blaster_rewriter.cpp COMPONENT_DEPENDENCIES rewriter - simplifier ) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster.cpp b/src/ast/rewriter/bit_blaster/bit_blaster.cpp index 1055ceb58..6632fe811 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"bit_blaster.h" -#include"bit_blaster_tpl_def.h" -#include"ast_pp.h" -#include"bv_decl_plugin.h" +#include "ast/rewriter/bit_blaster/bit_blaster.h" +#include "ast/rewriter/bit_blaster/bit_blaster_tpl_def.h" +#include "ast/ast_pp.h" +#include "ast/bv_decl_plugin.h" bit_blaster_cfg::bit_blaster_cfg(bv_util & u, bit_blaster_params const & p, bool_rewriter& rw): m_util(u), diff --git a/src/ast/rewriter/bit_blaster/bit_blaster.h b/src/ast/rewriter/bit_blaster/bit_blaster.h index 6221eeaf9..ffaa69e12 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster.h @@ -19,11 +19,11 @@ Revision History: #ifndef BIT_BLASTER_H_ #define BIT_BLASTER_H_ -#include"bool_rewriter.h" -#include"bit_blaster_params.h" -#include"bit_blaster_tpl.h" -#include"bv_decl_plugin.h" -#include"rational.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/bit_blaster/bit_blaster_params.h" +#include "ast/rewriter/bit_blaster/bit_blaster_tpl.h" +#include "ast/bv_decl_plugin.h" +#include "util/rational.h" class bit_blaster_cfg { public: diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index 68f2a2b8e..c47dacc96 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -16,13 +16,13 @@ Author: Notes: --*/ -#include"bit_blaster_rewriter.h" -#include"bv_decl_plugin.h" -#include"bit_blaster_tpl_def.h" -#include"rewriter_def.h" -#include"bool_rewriter.h" -#include"ref_util.h" -#include"ast_smt2_pp.h" +#include "ast/rewriter/bit_blaster/bit_blaster_rewriter.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/bit_blaster/bit_blaster_tpl_def.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/bool_rewriter.h" +#include "util/ref_util.h" +#include "ast/ast_smt2_pp.h" struct blaster_cfg { typedef rational numeral; diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h index 8db328ec8..6ffed00ae 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h @@ -19,9 +19,9 @@ Notes: #ifndef BIT_BLASTER_REWRITER_H_ #define BIT_BLASTER_REWRITER_H_ -#include"ast.h" -#include"obj_hashtable.h" -#include"params.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "util/params.h" class bit_blaster_rewriter { struct imp; diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl.h index b812de941..8407b0791 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl.h @@ -19,7 +19,7 @@ Revision History: #ifndef BIT_BLASTER_TPL_H_ #define BIT_BLASTER_TPL_H_ -#include"rational.h" +#include "util/rational.h" template class bit_blaster_tpl : public Cfg { diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index 15b87697f..a80994f6c 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -16,12 +16,12 @@ Author: Revision History: --*/ -#include"bit_blaster_tpl.h" -#include"rational.h" -#include"ast_pp.h" -#include"cooperate.h" -#include"common_msgs.h" -#include"rewriter_types.h" +#include "ast/rewriter/bit_blaster/bit_blaster_tpl.h" +#include "util/rational.h" +#include "ast/ast_pp.h" +#include "util/cooperate.h" +#include "util/common_msgs.h" +#include "ast/rewriter/rewriter_types.h" template @@ -272,7 +272,7 @@ void bit_blaster_tpl::mk_multiplier(unsigned sz, expr * const * a_bits, exp zero = m().mk_false(); vector< expr_ref_vector > pps; - pps.resize(sz, m()); + pps.resize(sz, expr_ref_vector(m())); for (unsigned i = 0; i < sz; i++) { checkpoint(); diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index f6597fbc5..6e99cb23e 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"bool_rewriter.h" -#include"bool_rewriter_params.hpp" -#include"rewriter_def.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/bool_rewriter_params.hpp" +#include "ast/rewriter/rewriter_def.h" void bool_rewriter::updt_params(params_ref const & _p) { bool_rewriter_params p(_p); @@ -629,61 +629,23 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) return BR_REWRITE2; } } - expr* cond2, *t2, *e2; - if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) { - try_ite_value(to_app(t), val, result); - result = m().mk_ite(cond, result, m().mk_eq(e, val)); - return BR_REWRITE2; - } - if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) { - try_ite_value(to_app(e), val, result); - result = m().mk_ite(cond, m().mk_eq(t, val), result); - return BR_REWRITE2; + { + expr* cond2, *t2, *e2; + if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) { + try_ite_value(to_app(t), val, result); + result = m().mk_ite(cond, result, m().mk_eq(e, val)); + return BR_REWRITE2; + } + if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) { + try_ite_value(to_app(e), val, result); + result = m().mk_ite(cond, m().mk_eq(t, val), result); + return BR_REWRITE2; + } } return BR_FAILED; } -#if 0 -// Return true if ite is an if-then-else tree where the leaves are values, -// and they are all different from val -static bool is_ite_value_tree_neq_value(ast_manager & m, app * ite, app * val) { - SASSERT(m.is_ite(ite)); - SASSERT(m.is_value(val)); - - expr_fast_mark1 visited; - ptr_buffer todo; - todo.push_back(ite); - -#define VISIT(ARG) { \ - if (m.is_value(ARG)) { \ - if (ARG == val) \ - return false; \ - } \ - else if (m.is_ite(ARG)) { \ - if (!visited.is_marked(ARG)) { \ - visited.mark(ARG); \ - todo.push_back(to_app(ARG)); \ - } \ - } \ - else { \ - return false; \ - } \ - } - - while (!todo.empty()) { - app * ite = todo.back(); - todo.pop_back(); - SASSERT(m.is_ite(ite)); - expr * t = ite->get_arg(1); - expr * e = ite->get_arg(2); - VISIT(t); - VISIT(e); - } - - return true; -} -#endif br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { if (m().are_equal(lhs, rhs)) { @@ -697,26 +659,20 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { } br_status r = BR_FAILED; + if (m().is_ite(lhs) && m().is_value(rhs)) { - // if (is_ite_value_tree_neq_value(m(), to_app(lhs), to_app(rhs))) { - // result = m().mk_false(); - // return BR_DONE; - // } r = try_ite_value(to_app(lhs), to_app(rhs), result); CTRACE("try_ite_value", r != BR_FAILED, - tout << mk_ismt2_pp(lhs, m()) << "\n" << mk_ismt2_pp(rhs, m()) << "\n--->\n" << mk_ismt2_pp(result, m()) << "\n";); + tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";); } else if (m().is_ite(rhs) && m().is_value(lhs)) { - // if (is_ite_value_tree_neq_value(m(), to_app(rhs), to_app(lhs))) { - // result = m().mk_false(); - // return BR_DONE; - // } r = try_ite_value(to_app(rhs), to_app(lhs), result); CTRACE("try_ite_value", r != BR_FAILED, - tout << mk_ismt2_pp(lhs, m()) << "\n" << mk_ismt2_pp(rhs, m()) << "\n--->\n" << mk_ismt2_pp(result, m()) << "\n";); + tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";); } if (r != BR_FAILED) return r; + if (m().is_bool(lhs)) { bool unfolded = false; diff --git a/src/ast/rewriter/bool_rewriter.h b/src/ast/rewriter/bool_rewriter.h index b1d2dec53..be9799c13 100644 --- a/src/ast/rewriter/bool_rewriter.h +++ b/src/ast/rewriter/bool_rewriter.h @@ -19,9 +19,9 @@ Notes: #ifndef BOOL_REWRITER_H_ #define BOOL_REWRITER_H_ -#include"ast.h" -#include"rewriter.h" -#include"params.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter.h" +#include "util/params.h" /** \brief Apply basic Boolean rewriting operations. diff --git a/src/ast/rewriter/bv_bounds.cpp b/src/ast/rewriter/bv_bounds.cpp index 76cdfbdbe..fd263efb2 100644 --- a/src/ast/rewriter/bv_bounds.cpp +++ b/src/ast/rewriter/bv_bounds.cpp @@ -14,8 +14,8 @@ Revision History: --*/ -#include"bv_bounds.h" -#include"ast_smt2_pp.h" +#include "ast/rewriter/bv_bounds.h" +#include "ast/ast_smt2_pp.h" bv_bounds::~bv_bounds() { reset(); diff --git a/src/ast/rewriter/bv_bounds.h b/src/ast/rewriter/bv_bounds.h index eeefc2c11..4a7226fa7 100644 --- a/src/ast/rewriter/bv_bounds.h +++ b/src/ast/rewriter/bv_bounds.h @@ -19,9 +19,9 @@ --*/ #ifndef BV_BOUNDS_H_23754 #define BV_BOUNDS_H_23754 -#include"ast.h" -#include"bv_decl_plugin.h" -#include"rewriter_types.h" +#include "ast/ast.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/rewriter_types.h" /* \brief A class to analyze constraints on bit vectors. @@ -38,7 +38,7 @@ public: bv_bounds(ast_manager& m) : m_m(m), m_bv_util(m), m_okay(true) {}; ~bv_bounds(); public: // bounds addition methods - br_status rewrite(unsigned limit, func_decl * f, unsigned num, expr * const * args, expr_ref& result); + br_status rewrite(unsigned limit, func_decl * f, unsigned num, expr * const * args, expr_ref& result); /** \brief Add a constraint to the system. @@ -82,7 +82,7 @@ protected: bv_util m_bv_util; bool m_okay; bool is_sat(app * v); - bool is_sat_core(app * v); +bool is_sat_core(app * v); inline bool in_range(app *v, numeral l); inline bool is_constant_add(unsigned bv_sz, expr * e, app*& v, numeral& val); void record_singleton(app * v, numeral& singleton_value); @@ -94,7 +94,7 @@ protected: inline bool bv_bounds::is_okay() { return m_okay; } inline bool bv_bounds::to_bound(const expr * e) const { - return is_app(e) && m_bv_util.is_bv(e) + return is_app(e) && m_bv_util.is_bv(e) && !m_bv_util.is_bv_add(e) && !m_bv_util.is_numeral(e); } diff --git a/src/ast/rewriter/bv_elim.cpp b/src/ast/rewriter/bv_elim.cpp new file mode 100644 index 000000000..270d7deb8 --- /dev/null +++ b/src/ast/rewriter/bv_elim.cpp @@ -0,0 +1,115 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + +#include "ast/rewriter/bv_elim.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/rewriter_def.h" +#include + +bool bv_elim_cfg::reduce_quantifier(quantifier * q, + expr * body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + + + svector names, _names; + sort_ref_buffer sorts(m), _sorts(m); + expr_ref_buffer pats(m); + expr_ref_buffer no_pats(m); + expr_ref_buffer subst_map(m), _subst_map(m); + var_subst subst(m); + bv_util bv(m); + expr_ref new_body(m); + expr* old_body = body; + unsigned num_decls = q->get_num_decls(); + family_id bfid = m.mk_family_id("bv"); + + // + // Traverse sequence of bound variables to eliminate + // bit-vecctor variables and replace them by + // Booleans. + // + unsigned var_idx = 0; + bool found = false; + for (unsigned i = num_decls; i > 0; ) { + --i; + sort* s = q->get_decl_sort(i); + symbol nm = q->get_decl_name(i); + + if (bv.is_bv_sort(s)) { + // convert n-bit bit-vector variable into sequence of n-Booleans. + unsigned num_bits = bv.get_bv_size(s); + expr_ref_buffer args(m); + expr_ref bv(m); + found = true; + for (unsigned j = 0; j < num_bits; ++j) { + std::ostringstream new_name; + new_name << nm.str(); + new_name << "_"; + new_name << j; + var* v = m.mk_var(var_idx++, m.mk_bool_sort()); + args.push_back(v); + _sorts.push_back(m.mk_bool_sort()); + _names.push_back(symbol(new_name.str().c_str())); + } + bv = m.mk_app(bfid, OP_MKBV, 0, 0, args.size(), args.c_ptr()); + _subst_map.push_back(bv.get()); + } + else { + _subst_map.push_back(m.mk_var(var_idx++, s)); + _sorts.push_back(s); + _names.push_back(nm); + } + } + if (!found) { + return false; + } + // + // reverse the vectors. + // + SASSERT(_names.size() == _sorts.size()); + for (unsigned i = _names.size(); i > 0; ) { + --i; + names.push_back(_names[i]); + sorts.push_back(_sorts[i]); + } + for (unsigned i = _subst_map.size(); i > 0; ) { + --i; + subst_map.push_back(_subst_map[i]); + } + + expr* const* sub = subst_map.c_ptr(); + unsigned sub_size = subst_map.size(); + + subst(old_body, sub_size, sub, new_body); + + for (unsigned j = 0; j < q->get_num_patterns(); j++) { + expr_ref pat(m); + subst(new_patterns[j], sub_size, sub, pat); + pats.push_back(pat); + } + for (unsigned j = 0; j < q->get_num_no_patterns(); j++) { + expr_ref nopat(m); + subst(new_no_patterns[j], sub_size, sub, nopat); + no_pats.push_back(nopat); + } + + result = m.mk_quantifier(true, + names.size(), + sorts.c_ptr(), + names.c_ptr(), + new_body.get(), + q->get_weight(), + q->get_qid(), + q->get_skid(), + pats.size(), pats.c_ptr(), + no_pats.size(), no_pats.c_ptr()); + result_pr = m.mk_rewrite(q, result); + return true; +} diff --git a/src/ast/rewriter/bv_elim.h b/src/ast/rewriter/bv_elim.h new file mode 100644 index 000000000..6468cb8b9 --- /dev/null +++ b/src/ast/rewriter/bv_elim.h @@ -0,0 +1,50 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + bv_elim.h + +Abstract: + + Eliminate bit-vectors variables from clauses, by + replacing them by bound Boolean variables. + +Author: + + Nikolaj Bjorner (nbjorner) 2008-12-16. + +Revision History: + +--*/ +#ifndef BV_ELIM_H_ +#define BV_ELIM_H_ + +#include "ast/ast.h" +#include "ast/rewriter/rewriter.h" + +class bv_elim_cfg : public default_rewriter_cfg { + ast_manager& m; +public: + bv_elim_cfg(ast_manager& m) : m(m) {} + + bool reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr); +}; + +class bv_elim_rw : public rewriter_tpl { +protected: + bv_elim_cfg m_cfg; +public: + bv_elim_rw(ast_manager & m): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m) + {} +}; + +#endif /* BV_ELIM_H_ */ + diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 0246f2b16..ce35300ca 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -16,10 +16,11 @@ Author: Notes: --*/ -#include"bv_rewriter.h" -#include"bv_rewriter_params.hpp" -#include"poly_rewriter_def.h" -#include"ast_smt2_pp.h" +#include "ast/rewriter/bv_rewriter.h" +#include "ast/rewriter/bv_rewriter_params.hpp" +#include "ast/rewriter/poly_rewriter_def.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_lt.h" void bv_rewriter::updt_local_params(params_ref const & _p) { @@ -1365,13 +1366,88 @@ br_status bv_rewriter::mk_bv2int(expr * arg, expr_ref & result) { result = m_autil.mk_numeral(v, true); return BR_DONE; } - - // TODO: add other simplifications + if (m_util.is_concat(arg)) { + if (to_app(arg)->get_num_args() == 0) { + result = m_autil.mk_int(0); + return BR_DONE; + } + expr_ref_vector args(m()); + + unsigned num_args = to_app(arg)->get_num_args(); + for (expr* x : *to_app(arg)) { + args.push_back(m_util.mk_bv2int(x)); + } + unsigned sz = get_bv_size(to_app(arg)->get_arg(num_args-1)); + for (unsigned i = num_args - 1; i > 0; ) { + expr_ref tmp(m()); + --i; + tmp = args[i].get(); + tmp = m_autil.mk_mul(m_autil.mk_numeral(power(numeral(2), sz), true), tmp); + args[i] = tmp; + sz += get_bv_size(to_app(arg)->get_arg(i)); + } + result = m_autil.mk_add(args.size(), args.c_ptr()); + return BR_REWRITE2; + } + if (is_mul_no_overflow(arg)) { + expr_ref_vector args(m()); + for (expr* x : *to_app(arg)) args.push_back(m_util.mk_bv2int(x)); + result = m_autil.mk_mul(args.size(), args.c_ptr()); + return BR_REWRITE2; + } + if (is_add_no_overflow(arg)) { + expr_ref_vector args(m()); + for (expr* x : *to_app(arg)) args.push_back(m_util.mk_bv2int(x)); + result = m_autil.mk_add(args.size(), args.c_ptr()); + return BR_REWRITE2; + } return BR_FAILED; } +bool bv_rewriter::is_mul_no_overflow(expr* e) { + if (!m_util.is_bv_mul(e)) return false; + unsigned sz = get_bv_size(e); + unsigned sum = 0; + for (expr* x : *to_app(e)) sum += sz-num_leading_zero_bits(x); + return sum < sz; +} + +bool bv_rewriter::is_add_no_overflow(expr* e) { + if (!is_add(e)) return false; + for (expr* x : *to_app(e)) { + if (0 == num_leading_zero_bits(x)) return false; + } + return true; +} + +unsigned bv_rewriter::num_leading_zero_bits(expr* e) { + numeral v; + unsigned sz = get_bv_size(e); + if (m_util.is_numeral(e, v)) { + while (v.is_pos()) { + SASSERT(sz > 0); + --sz; + v = div(v, numeral(2)); + } + return sz; + } + else if (m_util.is_concat(e)) { + app* a = to_app(e); + unsigned sz1 = get_bv_size(a->get_arg(0)); + unsigned nb1 = num_leading_zero_bits(a->get_arg(0)); + if (sz1 == nb1) { + nb1 += num_leading_zero_bits(a->get_arg(1)); + } + return nb1; + } + return 0; +} + + + + br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_ref & result) { expr_ref_buffer new_args(m()); numeral v1; @@ -2314,7 +2390,7 @@ void bv_rewriter::mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & r result = m().mk_eq(t1, m_util.mk_bv_sub(c, t2)); } -#include "ast_pp.h" +#include "ast/ast_pp.h" bool bv_rewriter::isolate_term(expr* lhs, expr* rhs, expr_ref& result) { if (!m_util.is_numeral(lhs) || !is_add(rhs)) { diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index b5482e5fa..205ebbf8e 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -19,11 +19,11 @@ Notes: #ifndef BV_REWRITER_H_ #define BV_REWRITER_H_ -#include"poly_rewriter.h" -#include"bv_decl_plugin.h" -#include"arith_decl_plugin.h" -#include"mk_extract_proc.h" -#include"bv_trailing.h" +#include "ast/rewriter/poly_rewriter.h" +#include "ast/bv_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/mk_extract_proc.h" +#include "ast/rewriter/bv_trailing.h" class bv_rewriter_core { protected: @@ -42,6 +42,7 @@ protected: decl_kind mul_decl_kind() const { return OP_BMUL; } bool use_power() const { return false; } decl_kind power_decl_kind() const { UNREACHABLE(); return static_cast(UINT_MAX); } + public: bv_rewriter_core(ast_manager & m):m_util(m) {} }; @@ -98,17 +99,20 @@ class bv_rewriter : public poly_rewriter { br_status mk_bv_rotate_right(unsigned n, expr * arg, expr_ref & result); br_status mk_bv_ext_rotate_left(expr * arg1, expr * arg2, expr_ref & result); br_status mk_bv_ext_rotate_right(expr * arg1, expr * arg2, expr_ref & result); + br_status mk_bv_add(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_bv_add(2, args, result); } + br_status mk_bv_sub(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_sub(2, args, result); } + br_status mk_bv_mul(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_bv_mul(2, args, result); } br_status mk_bv_add(unsigned num_args, expr * const * args, expr_ref & result); - br_status mk_bv_add(expr * arg1, expr * arg2, expr_ref & result) { - expr * args[2] = { arg1, arg2 }; - return mk_bv_add(2, args, result); - } br_status mk_bv_mul(unsigned num_args, expr * const * args, expr_ref & result); br_status mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result); br_status mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result); br_status mk_bv_ashr(expr * arg1, expr * arg2, expr_ref & result); bool is_minus_one_core(expr * arg) const; bool is_x_minus_one(expr * arg, expr * & x); + bool is_add_no_overflow(expr* e); + bool is_mul_no_overflow(expr* e); + unsigned num_leading_zero_bits(expr* e); + br_status mk_bv_sdiv_core(expr * arg1, expr * arg2, bool hi_div0, expr_ref & result); br_status mk_bv_udiv_core(expr * arg1, expr * arg2, bool hi_div0, expr_ref & result); br_status mk_bv_srem_core(expr * arg1, expr * arg2, bool hi_div0, expr_ref & result); @@ -185,6 +189,38 @@ public: bool hi_div0() const { return m_hi_div0; } bv_util & get_util() { return m_util; } + +#define MK_BV_BINARY(OP) \ + expr_ref OP(expr* a, expr* b) { \ + expr_ref result(m()); \ + if (BR_FAILED == OP(a, b, result)) \ + result = m_util.OP(a, b); \ + return result; \ + } \ + + expr_ref mk_zero_extend(unsigned n, expr * arg) { + expr_ref result(m()); + if (BR_FAILED == mk_zero_extend(n, arg, result)) + result = m_util.mk_zero_extend(n, arg); + return result; + } + + MK_BV_BINARY(mk_bv_urem); + MK_BV_BINARY(mk_ule); + MK_BV_BINARY(mk_bv_add); + MK_BV_BINARY(mk_bv_mul); + MK_BV_BINARY(mk_bv_sub); + + + expr_ref mk_bv2int(expr* a) { + expr_ref result(m()); + if (BR_FAILED == mk_bv2int(a, result)) + result = m_util.mk_bv2int(a); + return result; + } + + + }; #endif diff --git a/src/ast/rewriter/bv_trailing.cpp b/src/ast/rewriter/bv_trailing.cpp index f0b96a91f..5cdf27574 100644 --- a/src/ast/rewriter/bv_trailing.cpp +++ b/src/ast/rewriter/bv_trailing.cpp @@ -14,9 +14,9 @@ Revision History: --*/ -#include"bv_trailing.h" -#include"bv_decl_plugin.h" -#include"ast_smt2_pp.h" +#include "ast/rewriter/bv_trailing.h" +#include "ast/bv_decl_plugin.h" +#include "ast/ast_smt2_pp.h" // The analyzer gives up analysis after going TRAILING_DEPTH deep. // This number shouldn't be too big. diff --git a/src/ast/rewriter/bv_trailing.h b/src/ast/rewriter/bv_trailing.h index 862a1bea6..3ad46cb5d 100644 --- a/src/ast/rewriter/bv_trailing.h +++ b/src/ast/rewriter/bv_trailing.h @@ -18,9 +18,9 @@ --*/ #ifndef BV_TRAILING_H_ #define BV_TRAILING_H_ -#include"ast.h" -#include"rewriter_types.h" -#include"mk_extract_proc.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter_types.h" +#include "ast/rewriter/mk_extract_proc.h" class bv_trailing { public: bv_trailing(mk_extract_proc& ep); diff --git a/src/ast/rewriter/datatype_rewriter.cpp b/src/ast/rewriter/datatype_rewriter.cpp index be198c3d9..f0a95929b 100644 --- a/src/ast/rewriter/datatype_rewriter.cpp +++ b/src/ast/rewriter/datatype_rewriter.cpp @@ -16,13 +16,14 @@ Author: Notes: --*/ -#include"datatype_rewriter.h" +#include "ast/rewriter/datatype_rewriter.h" br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { SASSERT(f->get_family_id() == get_fid()); switch(f->get_decl_kind()) { case OP_DT_CONSTRUCTOR: return BR_FAILED; case OP_DT_RECOGNISER: + case OP_DT_IS: // // simplify is_cons(cons(x,y)) -> true // simplify is_cons(nil) -> false @@ -47,11 +48,11 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr func_decl * c_decl = a->get_decl(); if (c_decl != m_util.get_accessor_constructor(f)) return BR_FAILED; - ptr_vector const * acc = m_util.get_constructor_accessors(c_decl); - SASSERT(acc && acc->size() == a->get_num_args()); - unsigned num = acc->size(); + ptr_vector const & acc = *m_util.get_constructor_accessors(c_decl); + SASSERT(acc.size() == a->get_num_args()); + unsigned num = acc.size(); for (unsigned i = 0; i < num; ++i) { - if (f == (*acc)[i]) { + if (f == acc[i]) { // found it. result = a->get_arg(i); return BR_DONE; @@ -70,13 +71,13 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr result = a; return BR_DONE; } - ptr_vector const * acc = m_util.get_constructor_accessors(c_decl); - SASSERT(acc && acc->size() == a->get_num_args()); - unsigned num = acc->size(); + ptr_vector const & acc = *m_util.get_constructor_accessors(c_decl); + SASSERT(acc.size() == a->get_num_args()); + unsigned num = acc.size(); ptr_buffer new_args; for (unsigned i = 0; i < num; ++i) { - if (f == (*acc)[i]) { + if (f == acc[i]) { new_args.push_back(args[1]); } else { diff --git a/src/ast/rewriter/datatype_rewriter.h b/src/ast/rewriter/datatype_rewriter.h index 43fbc46d9..8aae29b3a 100644 --- a/src/ast/rewriter/datatype_rewriter.h +++ b/src/ast/rewriter/datatype_rewriter.h @@ -19,8 +19,8 @@ Notes: #ifndef DATATYPE_REWRITER_H_ #define DATATYPE_REWRITER_H_ -#include"datatype_decl_plugin.h" -#include"rewriter_types.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/rewriter/rewriter_types.h" class datatype_rewriter { datatype_util m_util; diff --git a/src/ast/rewriter/der.cpp b/src/ast/rewriter/der.cpp index aef5d8ddd..56f895b8a 100644 --- a/src/ast/rewriter/der.cpp +++ b/src/ast/rewriter/der.cpp @@ -18,13 +18,13 @@ Revision History: Christoph Wintersteiger, 2010-03-30: Added Destr. Multi-Equality Resolution --*/ -#include"der.h" -#include"occurs.h" -#include"for_each_expr.h" -#include"rewriter_def.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"ast_smt2_pp.h" +#include "ast/rewriter/der.h" +#include "ast/occurs.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt2_pp.h" static bool is_var(expr * e, unsigned num_decls) { return is_var(e) && to_var(e)->get_idx() < num_decls; diff --git a/src/ast/rewriter/der.h b/src/ast/rewriter/der.h index 9de028be8..47e57c4fb 100644 --- a/src/ast/rewriter/der.h +++ b/src/ast/rewriter/der.h @@ -21,8 +21,8 @@ Revision History: #ifndef DER_H_ #define DER_H_ -#include"ast.h" -#include"var_subst.h" +#include "ast/ast.h" +#include "ast/rewriter/var_subst.h" /* New DER: the class DER (above) eliminates variables one by one. diff --git a/src/ast/rewriter/distribute_forall.cpp b/src/ast/rewriter/distribute_forall.cpp index c64c0f089..77db3bc28 100644 --- a/src/ast/rewriter/distribute_forall.cpp +++ b/src/ast/rewriter/distribute_forall.cpp @@ -18,11 +18,11 @@ Revision History: Christoph Wintersteiger 2010-04-06: Added implementation. --*/ -#include"var_subst.h" -#include"ast_ll_pp.h" -#include"ast_util.h" -#include"distribute_forall.h" -#include"bool_rewriter.h" +#include "ast/rewriter/var_subst.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_util.h" +#include "ast/rewriter/distribute_forall.h" +#include "ast/rewriter/bool_rewriter.h" distribute_forall::distribute_forall(ast_manager & m) : m_manager(m), diff --git a/src/ast/rewriter/distribute_forall.h b/src/ast/rewriter/distribute_forall.h index b2c239239..ab0976945 100644 --- a/src/ast/rewriter/distribute_forall.h +++ b/src/ast/rewriter/distribute_forall.h @@ -21,8 +21,8 @@ Revision History: #ifndef DISTRIBUTE_FORALL_H_ #define DISTRIBUTE_FORALL_H_ -#include"ast.h" -#include"act_cache.h" +#include "ast/ast.h" +#include "ast/act_cache.h" /** \brief Apply the following transformation diff --git a/src/ast/rewriter/dl_rewriter.cpp b/src/ast/rewriter/dl_rewriter.cpp index ddae6c9eb..74ea7814e 100644 --- a/src/ast/rewriter/dl_rewriter.cpp +++ b/src/ast/rewriter/dl_rewriter.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"dl_rewriter.h" +#include "ast/rewriter/dl_rewriter.h" br_status dl_rewriter::mk_app_core( func_decl * f, unsigned num_args, expr* const* args, expr_ref& result) { diff --git a/src/ast/rewriter/dl_rewriter.h b/src/ast/rewriter/dl_rewriter.h index ecb3f0944..dca2f26dd 100644 --- a/src/ast/rewriter/dl_rewriter.h +++ b/src/ast/rewriter/dl_rewriter.h @@ -19,8 +19,8 @@ Notes: #ifndef DL_REWRITER_H_ #define DL_REWRITER_H_ -#include"dl_decl_plugin.h" -#include"rewriter_types.h" +#include "ast/dl_decl_plugin.h" +#include "ast/rewriter/rewriter_types.h" class dl_rewriter { datalog::dl_decl_util m_util; diff --git a/src/ast/rewriter/elim_bounds.cpp b/src/ast/rewriter/elim_bounds.cpp new file mode 100644 index 000000000..d3240e511 --- /dev/null +++ b/src/ast/rewriter/elim_bounds.cpp @@ -0,0 +1,203 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + elim_bounds.cpp + +Abstract: + + + +Author: + + Leonardo de Moura (leonardo) 2008-06-28. + +Revision History: + +--*/ + +#ifndef ELIM_BOUNDS_H_ +#define ELIM_BOUNDS_H_ + +#include "ast/used_vars.h" +#include "util/obj_hashtable.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/elim_bounds.h" +#include "ast/ast_pp.h" + +elim_bounds_cfg::elim_bounds_cfg(ast_manager & m): + m(m), + m_util(m) { +} + +/** + \brief Find bounds of the form + + (<= x k) + (<= (+ x (* -1 y)) k) + (<= (+ x (* -1 t)) k) + (<= (+ t (* -1 x)) k) + + x and y are a bound variables, t is a ground term and k is a numeral + + It also detects >=, and the atom can be negated. +*/ +bool elim_bounds_cfg::is_bound(expr * n, var * & lower, var * & upper) { + upper = 0; + lower = 0; + bool neg = false; + if (m.is_not(n)) { + n = to_app(n)->get_arg(0); + neg = true; + } + + expr* l = 0, *r = 0; + bool le = false; + if (m_util.is_le(n, l, r) && m_util.is_numeral(r)) { + n = l; + le = true; + } + else if (m_util.is_ge(n, l, r) && m_util.is_numeral(r)) { + n = l; + le = false; + } + else { + return false; + } + + if (neg) + le = !le; + + if (is_var(n)) { + upper = to_var(n); + } + else if (m_util.is_add(n, l, r)) { + expr * arg1 = l; + expr * arg2 = r; + if (is_var(arg1)) + upper = to_var(arg1); + else if (!is_ground(arg1)) + return false; + rational k; + bool is_int; + if (m_util.is_mul(arg2) && m_util.is_numeral(to_app(arg2)->get_arg(0), k, is_int) && k.is_minus_one()) { + arg2 = to_app(arg2)->get_arg(1); + if (is_var(arg2)) + lower = to_var(arg2); + else if (!is_ground(arg2)) + return false; // not supported + } + else { + return false; // not supported + } + } + else { + return false; + } + + if (!le) + std::swap(upper, lower); + + return true; +} + +bool elim_bounds_cfg::is_bound(expr * n) { + var * lower, * upper; + return is_bound(n, lower, upper); +} + + +bool elim_bounds_cfg::reduce_quantifier(quantifier * q, + expr * n, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + if (!q->is_forall()) { + return false; + } + unsigned num_vars = q->get_num_decls(); + ptr_buffer atoms; + if (m.is_or(n)) + atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args()); + else + atoms.push_back(n); + used_vars used_vars; + // collect non-candidates + for (expr * a : atoms) { + if (!is_bound(a)) + used_vars.process(a); + } + if (used_vars.uses_all_vars(q->get_num_decls())) { + return false; + } + // collect candidates + obj_hashtable lowers; + obj_hashtable uppers; + obj_hashtable candidate_set; + ptr_buffer candidates; +#define ADD_CANDIDATE(V) if (!lowers.contains(V) && !uppers.contains(V)) { candidate_set.insert(V); candidates.push_back(V); } + for (expr * a : atoms) { + var * lower = 0; + var * upper = 0; + if (is_bound(a, lower, upper)) { + if (lower != 0 && !used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) { + ADD_CANDIDATE(lower); + lowers.insert(lower); + } + if (upper != 0 && !used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) { + ADD_CANDIDATE(upper); + uppers.insert(upper); + } + } + } + TRACE("elim_bounds", tout << "candidates:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";); + // remove candidates that have lower and upper bounds + + for (var * v : candidates) { + if (lowers.contains(v) && uppers.contains(v)) + candidate_set.erase(v); + } + TRACE("elim_bounds", tout << "candidates after filter:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";); + if (candidate_set.empty()) { + return false; + } + // remove bounds that contain variables in candidate_set + unsigned j = 0; + for (unsigned i = 0; i < atoms.size(); ++i) { + expr * a = atoms[i]; + var * lower = 0; + var * upper = 0; + if (is_bound(a, lower, upper) && ((lower != 0 && candidate_set.contains(lower)) || (upper != 0 && candidate_set.contains(upper)))) + continue; + atoms[j] = a; + j++; + } + if (j == atoms.size()) { + return false; + } + atoms.resize(j); + expr * new_body = 0; + switch (atoms.size()) { + case 0: + result = m.mk_false(); + result_pr = m.mk_rewrite(q, result); + TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";); + return true; + case 1: + new_body = atoms[0]; + break; + default: + new_body = m.mk_or(atoms.size(), atoms.c_ptr()); + break; + } + quantifier_ref new_q(m); + new_q = m.update_quantifier(q, new_body); + elim_unused_vars(m, new_q, params_ref(), result); + result_pr = m.mk_rewrite(q, result); + TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";); + return true; +} + +#endif /* ELIM_BOUNDS_H_ */ diff --git a/src/ast/simplifier/elim_bounds.h b/src/ast/rewriter/elim_bounds.h similarity index 50% rename from src/ast/simplifier/elim_bounds.h rename to src/ast/rewriter/elim_bounds.h index f8276c150..e0bba4e60 100644 --- a/src/ast/simplifier/elim_bounds.h +++ b/src/ast/rewriter/elim_bounds.h @@ -3,7 +3,7 @@ Copyright (c) 2006 Microsoft Corporation Module Name: - elim_bounds.h + elim_bounds2.h Abstract: @@ -16,12 +16,12 @@ Author: Revision History: --*/ -#ifndef ELIM_BOUNDS_H_ -#define ELIM_BOUNDS_H_ +#ifndef ELIM_BOUNDS2_H_ +#define ELIM_BOUNDS2_H_ -#include"ast.h" -#include"arith_decl_plugin.h" -#include"simplifier.h" +#include "ast/ast.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/rewriter.h" /** \brief Functor for eliminating irrelevant bounds in quantified formulas. @@ -39,31 +39,39 @@ Revision History: \remark This operation is subsumed by Fourier-Motzkin elimination. */ -class elim_bounds { - ast_manager & m_manager; +class elim_bounds_cfg : public default_rewriter_cfg { + ast_manager & m; arith_util m_util; bool is_bound(expr * n, var * & lower, var * & upper); bool is_bound(expr * n); public: - elim_bounds(ast_manager & m); - void operator()(quantifier * q, expr_ref & r); + elim_bounds_cfg(ast_manager & m); + + bool reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr); }; /** - \brief Functor for applying elim_bounds in all + \brief Functor for applying elim_bounds2 in all universal quantifiers in an expression. Assumption: the formula was already skolemized. */ -class elim_bounds_star : public simplifier { +class elim_bounds_rw : public rewriter_tpl { protected: - elim_bounds m_elim; - virtual bool visit_quantifier(quantifier * q); - virtual void reduce1_quantifier(quantifier * q); + elim_bounds_cfg m_cfg; public: - elim_bounds_star(ast_manager & m):simplifier(m), m_elim(m) { enable_ac_support(false); } - virtual ~elim_bounds_star() {} + elim_bounds_rw(ast_manager & m): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m) + {} + + virtual ~elim_bounds_rw() {} }; -#endif /* ELIM_BOUNDS_H_ */ +#endif /* ELIM_BOUNDS2_H_ */ diff --git a/src/ast/rewriter/enum2bv_rewriter.cpp b/src/ast/rewriter/enum2bv_rewriter.cpp index 08e7b0f69..eb6b195f0 100644 --- a/src/ast/rewriter/enum2bv_rewriter.cpp +++ b/src/ast/rewriter/enum2bv_rewriter.cpp @@ -17,11 +17,11 @@ Notes: --*/ -#include"rewriter.h" -#include"rewriter_def.h" -#include"enum2bv_rewriter.h" -#include"ast_util.h" -#include"ast_pp.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/enum2bv_rewriter.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" struct enum2bv_rewriter::imp { ast_manager& m; diff --git a/src/ast/rewriter/enum2bv_rewriter.h b/src/ast/rewriter/enum2bv_rewriter.h index 1b2c6160f..934271071 100644 --- a/src/ast/rewriter/enum2bv_rewriter.h +++ b/src/ast/rewriter/enum2bv_rewriter.h @@ -19,9 +19,9 @@ Notes: #ifndef ENUM_REWRITER_H_ #define ENUM_REWRITER_H_ -#include"datatype_decl_plugin.h" -#include"rewriter_types.h" -#include"expr_functors.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/rewriter/rewriter_types.h" +#include "ast/expr_functors.h" class enum2bv_rewriter { struct imp; diff --git a/src/ast/rewriter/expr_replacer.cpp b/src/ast/rewriter/expr_replacer.cpp index 3552c7d49..70e12dced 100644 --- a/src/ast/rewriter/expr_replacer.cpp +++ b/src/ast/rewriter/expr_replacer.cpp @@ -16,10 +16,10 @@ Author: Notes: --*/ -#include"expr_replacer.h" -#include"rewriter_def.h" -#include"th_rewriter.h" -#include"cooperate.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/th_rewriter.h" +#include "util/cooperate.h" void expr_replacer::operator()(expr * t, expr_ref & result, proof_ref & result_pr) { expr_dependency_ref result_dep(m()); diff --git a/src/ast/rewriter/expr_replacer.h b/src/ast/rewriter/expr_replacer.h index 2e445eadc..811cd1f23 100644 --- a/src/ast/rewriter/expr_replacer.h +++ b/src/ast/rewriter/expr_replacer.h @@ -19,9 +19,9 @@ Notes: #ifndef EXPR_REPLACER_H_ #define EXPR_REPLACER_H_ -#include"ast.h" -#include"expr_substitution.h" -#include"params.h" +#include "ast/ast.h" +#include "ast/expr_substitution.h" +#include "util/params.h" /** \brief Abstract interface for functors that replace constants with expressions. diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index 2655ac00d..31453691e 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -18,9 +18,9 @@ Revision History: --*/ -#include "expr_safe_replace.h" -#include "rewriter.h" -#include "ast_pp.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/rewriter/rewriter.h" +#include "ast/ast_pp.h" void expr_safe_replace::insert(expr* src, expr* dst) { diff --git a/src/ast/rewriter/expr_safe_replace.h b/src/ast/rewriter/expr_safe_replace.h index 84a74ccaa..fb66661af 100644 --- a/src/ast/rewriter/expr_safe_replace.h +++ b/src/ast/rewriter/expr_safe_replace.h @@ -22,7 +22,7 @@ Revision History: #ifndef EXPR_SAFE_REPLACE_H_ #define EXPR_SAFE_REPLACE_H_ -#include "ast.h" +#include "ast/ast.h" class expr_safe_replace { ast_manager& m; diff --git a/src/ast/rewriter/factor_rewriter.cpp b/src/ast/rewriter/factor_rewriter.cpp index 9e988caf7..abcdabc9c 100644 --- a/src/ast/rewriter/factor_rewriter.cpp +++ b/src/ast/rewriter/factor_rewriter.cpp @@ -18,9 +18,9 @@ Notes: --*/ -#include"factor_rewriter.h" -#include"ast_pp.h" -#include"rewriter_def.h" +#include "ast/rewriter/factor_rewriter.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/rewriter_def.h" factor_rewriter::factor_rewriter(ast_manager & m): m_manager(m), m_arith(m), m_factors(m) { } diff --git a/src/ast/rewriter/factor_rewriter.h b/src/ast/rewriter/factor_rewriter.h index 389eacd87..aae9b05b3 100644 --- a/src/ast/rewriter/factor_rewriter.h +++ b/src/ast/rewriter/factor_rewriter.h @@ -20,9 +20,9 @@ Notes: #ifndef FACTOR_REWRITER_H_ #define FACTOR_REWRITER_H_ -#include"ast.h" -#include"rewriter.h" -#include"arith_decl_plugin.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter.h" +#include "ast/arith_decl_plugin.h" class factor_rewriter { typedef obj_map powers_t; diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 26487c5a4..e62c9346f 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"fpa_rewriter.h" -#include"fpa_rewriter_params.hpp" -#include"ast_smt2_pp.h" +#include "ast/rewriter/fpa_rewriter.h" +#include "ast/rewriter/fpa_rewriter_params.hpp" +#include "ast/ast_smt2_pp.h" fpa_rewriter::fpa_rewriter(ast_manager & m, params_ref const & p) : m_util(m), @@ -94,21 +94,8 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con case OP_FPA_TO_IEEE_BV: SASSERT(num_args == 1); st = mk_to_ieee_bv(f, args[0], result); break; case OP_FPA_TO_REAL: SASSERT(num_args == 1); st = mk_to_real(args[0], result); break; - case OP_FPA_INTERNAL_MIN_I: - case OP_FPA_INTERNAL_MAX_I: - case OP_FPA_INTERNAL_MIN_UNSPECIFIED: - case OP_FPA_INTERNAL_MAX_UNSPECIFIED: - SASSERT(num_args == 2); st = BR_FAILED; break; - - case OP_FPA_INTERNAL_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break; - case OP_FPA_INTERNAL_BV2RM: SASSERT(num_args == 1); st = mk_bv2rm(args[0], result); break; - - case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: - st = BR_FAILED; - break; + case OP_FPA_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break; + case OP_FPA_BV2RM: SASSERT(num_args == 1); st = mk_bv2rm(args[0], result); break; default: NOT_IMPLEMENTED_YET(); @@ -116,49 +103,10 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con return st; } -br_status fpa_rewriter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) { - bv_util bu(m()); - if (m_hi_fp_unspecified) { - // The "hardware interpretation" is 0. - result = bu.mk_numeral(0, width); - return BR_DONE; - } - else { - result = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width); - return BR_REWRITE1; - } -} - -br_status fpa_rewriter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) { - bv_util bu(m()); - if (m_hi_fp_unspecified) { - // The "hardware interpretation" is 0. - result = bu.mk_numeral(0, width); - return BR_DONE; - } - else { - result = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width); - return BR_REWRITE1; - } -} - -br_status fpa_rewriter::mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result) { - if (m_hi_fp_unspecified) { - // The "hardware interpretation" is 0. - result = m_util.au().mk_numeral(rational(0), false); - return BR_DONE; - } - else { - result = m_util.mk_internal_to_real_unspecified(ebits, sbits); - return BR_REWRITE1; - } -} - br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { SASSERT(f->get_num_parameters() == 2); SASSERT(f->get_parameter(0).is_int()); SASSERT(f->get_parameter(1).is_int()); - bv_util bu(m()); scoped_mpf v(m_fm); mpf_rounding_mode rmv; rational r1, r2, r3; @@ -167,21 +115,19 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const unsigned sbits = f->get_parameter(1).get_int(); if (num_args == 1) { - if (bu.is_numeral(args[0], r1, bvs1)) { + if (m_util.bu().is_numeral(args[0], r1, bvs1)) { // BV -> float SASSERT(bvs1 == sbits + ebits); unsynch_mpz_manager & mpzm = m_fm.mpz_manager(); - unsynch_mpq_manager & mpqm = m_fm.mpq_manager(); scoped_mpz sig(mpzm), exp(mpzm); const mpz & sm1 = m_fm.m_powers2(sbits - 1); const mpz & em1 = m_fm.m_powers2(ebits); - scoped_mpq q(mpqm); - mpqm.set(q, r1.to_mpq()); - SASSERT(mpzm.is_one(q.get().denominator())); + const mpq & q = r1.to_mpq(); + SASSERT(mpzm.is_one(q.denominator())); scoped_mpz z(mpzm); - z = q.get().numerator(); + z = q.numerator(); mpzm.rem(z, sm1, sig); mpzm.div(z, sm1, z); @@ -226,10 +172,10 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const // TRACE("fp_rewriter", tout << "result: " << result << std::endl; ); return BR_DONE; } - else if (bu.is_numeral(args[1], r1, bvs1)) { + else if (m_util.bu().is_numeral(args[1], r1, bvs1)) { // rm + signed bv -> float TRACE("fp_rewriter", tout << "r1: " << r1 << std::endl;); - r1 = bu.norm(r1, bvs1, true); + r1 = m_util.bu().norm(r1, bvs1, true); TRACE("fp_rewriter", tout << "r1 norm: " << r1 << std::endl;); m_fm.set(v, ebits, sbits, rmv, r1.to_mpq()); result = m_util.mk_value(v); @@ -265,9 +211,9 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const result = m_util.mk_value(v); return BR_DONE; } - else if (bu.is_numeral(args[0], r1, bvs1) && - bu.is_numeral(args[1], r2, bvs2) && - bu.is_numeral(args[2], r3, bvs3)) { + else if (m_util.bu().is_numeral(args[0], r1, bvs1) && + m_util.bu().is_numeral(args[1], r2, bvs2) && + m_util.bu().is_numeral(args[2], r3, bvs3)) { // 3 BV -> float SASSERT(m_fm.mpz_manager().is_one(r2.to_mpq().denominator())); SASSERT(m_fm.mpz_manager().is_one(r3.to_mpq().denominator())); @@ -290,7 +236,6 @@ br_status fpa_rewriter::mk_to_fp_unsigned(func_decl * f, expr * arg1, expr * arg SASSERT(f->get_num_parameters() == 2); SASSERT(f->get_parameter(0).is_int()); SASSERT(f->get_parameter(1).is_int()); - bv_util bu(m()); unsigned ebits = f->get_parameter(0).get_int(); unsigned sbits = f->get_parameter(1).get_int(); mpf_rounding_mode rmv; @@ -298,7 +243,7 @@ br_status fpa_rewriter::mk_to_fp_unsigned(func_decl * f, expr * arg1, expr * arg unsigned bvs; if (m_util.is_rm_numeral(arg1, rmv) && - bu.is_numeral(arg2, r, bvs)) { + m_util.bu().is_numeral(arg2, r, bvs)) { scoped_mpf v(m_fm); m_fm.set(v, ebits, sbits, rmv, r.to_mpq()); result = m_util.mk_value(v); @@ -331,6 +276,7 @@ br_status fpa_rewriter::mk_sub(expr * arg1, expr * arg2, expr * arg3, expr_ref & br_status fpa_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { mpf_rounding_mode rm; + if (m_util.is_rm_numeral(arg1, rm)) { scoped_mpf v2(m_fm), v3(m_fm); if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3)) { @@ -346,6 +292,7 @@ br_status fpa_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & br_status fpa_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { mpf_rounding_mode rm; + if (m_util.is_rm_numeral(arg1, rm)) { scoped_mpf v2(m_fm), v3(m_fm); if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3)) { @@ -355,7 +302,6 @@ br_status fpa_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref & return BR_DONE; } } - return BR_FAILED; } @@ -393,6 +339,7 @@ br_status fpa_rewriter::mk_neg(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_rem(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)) { scoped_mpf t(m_fm); m_fm.rem(v1, v2, t); @@ -431,27 +378,16 @@ br_status fpa_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) { scoped_mpf v1(m_fm), v2(m_fm); if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) { - if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2)) { - result = m().mk_app(get_fid(), OP_FPA_INTERNAL_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_INTERNAL_MIN_UNSPECIFIED, arg1, arg2); + if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2)) + return BR_FAILED; - result = m().mk_ite(c, v, m().mk_app(get_fid(), OP_FPA_INTERNAL_MIN_I, arg1, arg2)); - return BR_REWRITE_FULL; + scoped_mpf r(m_fm); + m_fm.minimum(v1, v2, r); + result = m_util.mk_value(r); + return BR_DONE; } + + return BR_FAILED; } br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { @@ -466,31 +402,21 @@ br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { scoped_mpf v1(m_fm), v2(m_fm); if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) { - if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2)) { - result = m().mk_app(get_fid(), OP_FPA_INTERNAL_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_INTERNAL_MAX_UNSPECIFIED, arg1, arg2); + if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2)) + return BR_FAILED; - result = m().mk_ite(c, v, m().mk_app(get_fid(), OP_FPA_INTERNAL_MAX_I, arg1, arg2)); - return BR_REWRITE_FULL; + scoped_mpf r(m_fm); + m_fm.maximum(v1, v2, r); + result = m_util.mk_value(r); + return BR_DONE; } + + return BR_FAILED; } br_status fpa_rewriter::mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg4, expr_ref & result) { mpf_rounding_mode rm; + if (m_util.is_rm_numeral(arg1, rm)) { scoped_mpf v2(m_fm), v3(m_fm), v4(m_fm); if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3) && m_util.is_numeral(arg4, v4)) { @@ -506,6 +432,7 @@ br_status fpa_rewriter::mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg br_status fpa_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) { mpf_rounding_mode rm; + if (m_util.is_rm_numeral(arg1, rm)) { scoped_mpf v2(m_fm); if (m_util.is_numeral(arg2, v2)) { @@ -521,6 +448,7 @@ br_status fpa_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) { br_status fpa_rewriter::mk_round_to_integral(expr * arg1, expr * arg2, expr_ref & result) { mpf_rounding_mode rm; + if (m_util.is_rm_numeral(arg1, rm)) { scoped_mpf v2(m_fm); if (m_util.is_numeral(arg2, v2)) { @@ -588,7 +516,6 @@ br_status fpa_rewriter::mk_lt(expr * arg1, expr * arg2, expr_ref & result) { return BR_DONE; } - // TODO: more simplifications return BR_FAILED; } @@ -652,6 +579,7 @@ br_status fpa_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_nan(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_nan(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -662,6 +590,7 @@ br_status fpa_rewriter::mk_is_nan(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_inf(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_inf(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -672,6 +601,7 @@ br_status fpa_rewriter::mk_is_inf(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_normal(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_normal(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -682,6 +612,7 @@ br_status fpa_rewriter::mk_is_normal(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_denormal(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -692,6 +623,7 @@ br_status fpa_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_negative(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_neg(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -702,6 +634,7 @@ br_status fpa_rewriter::mk_is_negative(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_positive(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_neg(v) || m_fm.is_nan(v)) ? m().mk_false() : m().mk_true(); return BR_DONE; @@ -714,6 +647,7 @@ br_status fpa_rewriter::mk_is_positive(expr * arg1, expr_ref & result) { // This the SMT = br_status fpa_rewriter::mk_eq_core(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)) { // Note: == is the floats-equality, here we need normal equality. result = (m_fm.is_nan(v1) && m_fm.is_nan(v2)) ? m().mk_true() : @@ -727,10 +661,10 @@ br_status fpa_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) } br_status fpa_rewriter::mk_bv2rm(expr * arg, expr_ref & result) { - bv_util bu(m()); rational bv_val; unsigned sz = 0; - if (bu.is_numeral(arg, bv_val, sz)) { + + if (m_util.bu().is_numeral(arg, bv_val, sz)) { SASSERT(bv_val.is_uint64()); switch (bv_val.get_uint64()) { case BV_RM_TIES_TO_AWAY: result = m_util.mk_round_nearest_ties_to_away(); break; @@ -749,13 +683,12 @@ br_status fpa_rewriter::mk_bv2rm(expr * arg, expr_ref & result) { br_status fpa_rewriter::mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & result) { unsynch_mpz_manager & mpzm = m_fm.mpz_manager(); - bv_util bu(m()); rational rsgn, rexp, rsig; unsigned bvsz_sgn, bvsz_exp, bvsz_sig; - if (bu.is_numeral(sgn, rsgn, bvsz_sgn) && - bu.is_numeral(sig, rsig, bvsz_sig) && - bu.is_numeral(exp, rexp, bvsz_exp)) { + if (m_util.bu().is_numeral(sgn, rsgn, bvsz_sgn) && + m_util.bu().is_numeral(sig, rsig, bvsz_sig) && + m_util.bu().is_numeral(exp, rexp, bvsz_exp)) { SASSERT(mpzm.is_one(rexp.to_mpq().denominator())); SASSERT(mpzm.is_one(rsig.to_mpq().denominator())); scoped_mpf v(m_fm); @@ -772,7 +705,7 @@ br_status fpa_rewriter::mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & res return BR_FAILED; } -br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) { +br_status fpa_rewriter::mk_to_bv(func_decl * f, expr * arg1, expr * arg2, bool is_signed, expr_ref & result) { SASSERT(f->get_num_parameters() == 1); SASSERT(f->get_parameter(0).is_int()); int bv_sz = f->get_parameter(0).get_int(); @@ -781,10 +714,9 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ if (m_util.is_rm_numeral(arg1, rmv) && m_util.is_numeral(arg2, v)) { - const mpf & x = v.get(); - if (m_fm.is_nan(v) || m_fm.is_inf(v) || m_fm.is_neg(v)) - return mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); + if (m_fm.is_nan(v) || m_fm.is_inf(v)) + return mk_to_bv_unspecified(f, result); bv_util bu(m()); scoped_mpq q(m_fm.mpq_manager()); @@ -792,51 +724,41 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ rational r(q); rational ul, ll; - ul = m_fm.m_powers2.m1(bv_sz); - ll = rational(0); + if (!is_signed) { + ul = m_fm.m_powers2.m1(bv_sz); + ll = rational(0); + } + else { + ul = m_fm.m_powers2.m1(bv_sz - 1); + ll = -m_fm.m_powers2(bv_sz - 1); + } if (r >= ll && r <= ul) { result = bu.mk_numeral(r, bv_sz); return BR_DONE; } else - return mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); - + return mk_to_bv_unspecified(f, result); } return BR_FAILED; } -br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) { - SASSERT(f->get_num_parameters() == 1); - SASSERT(f->get_parameter(0).is_int()); - int bv_sz = f->get_parameter(0).get_int(); - mpf_rounding_mode rmv; - scoped_mpf v(m_fm); - - if (m_util.is_rm_numeral(arg1, rmv) && - m_util.is_numeral(arg2, v)) { - const mpf & x = v.get(); - - if (m_fm.is_nan(v) || m_fm.is_inf(v)) - return mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); - - bv_util bu(m()); - scoped_mpq q(m_fm.mpq_manager()); - m_fm.to_sbv_mpq(rmv, v, q); - - rational r(q); - rational ul, ll; - ul = m_fm.m_powers2.m1(bv_sz - 1); - ll = - m_fm.m_powers2(bv_sz - 1); - if (r >= ll && r <= ul) { - result = bu.mk_numeral(r, bv_sz); - return BR_DONE; - } - else - return mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); +br_status fpa_rewriter::mk_to_bv_unspecified(func_decl * f, expr_ref & result) { + if (m_hi_fp_unspecified) { + unsigned bv_sz = m_util.bu().get_bv_size(f->get_range()); + result = m_util.bu().mk_numeral(0, bv_sz); + return BR_DONE; } + else + return BR_FAILED; +} - return BR_FAILED; +br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) { + return mk_to_bv(f, arg1, arg2, false, result); +} + +br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) { + return mk_to_bv(f, arg1, arg2, true, result); } br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & result) { @@ -855,11 +777,8 @@ br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & resu bu.mk_numeral(0, x.get_sbits() - 2), bu.mk_numeral(1, 1) }; result = bu.mk_concat(4, args); + return BR_REWRITE1; } - else - result = m_util.mk_internal_to_ieee_bv_unspecified(x.get_ebits(), x.get_sbits()); - - return BR_REWRITE1; } else { scoped_mpz rz(m_fm.mpq_manager()); @@ -877,15 +796,17 @@ br_status fpa_rewriter::mk_to_real(expr * arg, expr_ref & result) { if (m_util.is_numeral(arg, v)) { if (m_fm.is_nan(v) || m_fm.is_inf(v)) { - const mpf & x = v.get(); - result = m_util.mk_internal_to_real_unspecified(x.get_ebits(), x.get_sbits()); + if (m_hi_fp_unspecified) { + result = m_util.au().mk_numeral(rational(0), false); + return BR_DONE; + } } else { scoped_mpq r(m_fm.mpq_manager()); m_fm.to_rational(v, r); result = m_util.au().mk_numeral(r.get(), false); + return BR_DONE; } - return BR_DONE; } return BR_FAILED; diff --git a/src/ast/rewriter/fpa_rewriter.h b/src/ast/rewriter/fpa_rewriter.h index 0d9c6a380..cfa1bea52 100644 --- a/src/ast/rewriter/fpa_rewriter.h +++ b/src/ast/rewriter/fpa_rewriter.h @@ -19,11 +19,12 @@ Notes: #ifndef FLOAT_REWRITER_H_ #define FLOAT_REWRITER_H_ -#include"ast.h" -#include"rewriter.h" -#include"params.h" -#include"fpa_decl_plugin.h" -#include"mpf.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter.h" +#include "ast/fpa_decl_plugin.h" +#include "ast/expr_map.h" +#include "util/params.h" +#include "util/mpf.h" class fpa_rewriter { fpa_util m_util; @@ -33,6 +34,9 @@ class fpa_rewriter { app * mk_eq_nan(expr * arg); app * mk_neq_nan(expr * arg); + br_status mk_to_bv(func_decl * f, expr * arg1, expr * arg2, bool is_signed, expr_ref & result); + br_status mk_to_bv_unspecified(func_decl * f, expr_ref & result); + public: fpa_rewriter(ast_manager & m, params_ref const & p = params_ref()); ~fpa_rewriter(); @@ -73,22 +77,17 @@ public: br_status mk_is_negative(expr * arg1, expr_ref & result); br_status mk_is_positive(expr * arg1, expr_ref & result); - br_status mk_to_ieee_bv(expr * arg1, expr_ref & result); - br_status mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); br_status mk_to_fp_unsigned(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); br_status mk_bv2rm(expr * arg, expr_ref & result); br_status mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & result); - br_status mk_to_fp_unsigned(expr * arg1, expr * arg2, expr_ref & result); br_status mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); br_status mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); br_status mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & result); br_status mk_to_real(expr * arg, expr_ref & result); - - br_status mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result); - br_status mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result); - br_status mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result); + br_status mk_min_i(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); + br_status mk_max_i(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); br_status mk_bvwrap(expr * arg, expr_ref & result); }; diff --git a/src/ast/rewriter/fpa_rewriter_params.pyg b/src/ast/rewriter/fpa_rewriter_params.pyg index f0cfbdf55..487c50a85 100644 --- a/src/ast/rewriter/fpa_rewriter_params.pyg +++ b/src/ast/rewriter/fpa_rewriter_params.pyg @@ -1,5 +1,5 @@ def_module_params(module_name='rewriter', class_name='fpa_rewriter_params', export=True, - params=(("hi_fp_unspecified", BOOL, False, "use the 'hardware interpretation' for unspecified values in fp.to_ubv, fp.to_sbv, fp.to_real, and fp.to_ieee_bv"), + params=(("hi_fp_unspecified", BOOL, False, "use the 'hardware interpretation' for unspecified values in fp.to_ubv, fp.to_sbv, fp.to_real, and fp.to_ieee_bv"), )) diff --git a/src/ast/simplifier/inj_axiom.cpp b/src/ast/rewriter/inj_axiom.cpp similarity index 88% rename from src/ast/simplifier/inj_axiom.cpp rename to src/ast/rewriter/inj_axiom.cpp index 5925e23ac..d322f3228 100644 --- a/src/ast/simplifier/inj_axiom.cpp +++ b/src/ast/rewriter/inj_axiom.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include"inj_axiom.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"has_free_vars.h" -#include"well_sorted.h" +#include "ast/rewriter/inj_axiom.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/has_free_vars.h" +#include "ast/well_sorted.h" /** \brief Little HACK for simplifying injectivity axioms @@ -29,18 +29,15 @@ Revision History: */ bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result) { expr * n = q->get_expr(); - if (q->is_forall() && m.is_or(n) && to_app(n)->get_num_args() == 2) { - expr * arg1 = to_app(n)->get_arg(0); - expr * arg2 = to_app(n)->get_arg(1); + expr* arg1 = 0, * arg2 = 0, *narg = 0; + expr* app1 = 0, * app2 = 0; + expr* var1 = 0, * var2 = 0; + if (q->is_forall() && m.is_or(n, arg1, arg2)) { if (m.is_not(arg2)) std::swap(arg1, arg2); - if (m.is_not(arg1) && - m.is_eq(to_app(arg1)->get_arg(0)) && - m.is_eq(arg2)) { - expr * app1 = to_app(to_app(arg1)->get_arg(0))->get_arg(0); - expr * app2 = to_app(to_app(arg1)->get_arg(0))->get_arg(1); - expr * var1 = to_app(arg2)->get_arg(0); - expr * var2 = to_app(arg2)->get_arg(1); + if (m.is_not(arg1, narg) && + m.is_eq(narg, app1, app2) && + m.is_eq(arg2, var1, var2)) { if (is_app(app1) && is_app(app2) && to_app(app1)->get_decl() == to_app(app2)->get_decl() && diff --git a/src/ast/simplifier/inj_axiom.h b/src/ast/rewriter/inj_axiom.h similarity index 94% rename from src/ast/simplifier/inj_axiom.h rename to src/ast/rewriter/inj_axiom.h index da441c15b..a6df16515 100644 --- a/src/ast/simplifier/inj_axiom.h +++ b/src/ast/rewriter/inj_axiom.h @@ -19,7 +19,7 @@ Revision History: #ifndef INJ_AXIOM_H_ #define INJ_AXIOM_H_ -#include"ast.h" +#include "ast/ast.h" bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result); diff --git a/src/ast/rewriter/label_rewriter.cpp b/src/ast/rewriter/label_rewriter.cpp index 3017f413c..8adefb896 100644 --- a/src/ast/rewriter/label_rewriter.cpp +++ b/src/ast/rewriter/label_rewriter.cpp @@ -17,9 +17,9 @@ Notes: --*/ -#include"rewriter.h" -#include"rewriter_def.h" -#include"label_rewriter.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/label_rewriter.h" label_rewriter::label_rewriter(ast_manager & m) : diff --git a/src/ast/rewriter/label_rewriter.h b/src/ast/rewriter/label_rewriter.h index 6400aa442..f2f578fbb 100644 --- a/src/ast/rewriter/label_rewriter.h +++ b/src/ast/rewriter/label_rewriter.h @@ -19,8 +19,8 @@ Notes: #ifndef LABEL_REWRITER_H_ #define LABEL_REWRITER_H_ -#include"ast.h" -#include"rewriter_types.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter_types.h" class label_rewriter : public default_rewriter_cfg { diff --git a/src/ast/simplifier/maximise_ac_sharing.cpp b/src/ast/rewriter/maximize_ac_sharing.cpp similarity index 51% rename from src/ast/simplifier/maximise_ac_sharing.cpp rename to src/ast/rewriter/maximize_ac_sharing.cpp index d5cf69a72..a838f59fa 100644 --- a/src/ast/simplifier/maximise_ac_sharing.cpp +++ b/src/ast/rewriter/maximize_ac_sharing.cpp @@ -3,7 +3,7 @@ Copyright (c) 2006 Microsoft Corporation Module Name: - maximise_ac_sharing.cpp + maximize_ac_sharing.cpp Abstract: @@ -17,33 +17,26 @@ Revision History: --*/ -#include"maximise_ac_sharing.h" -#include"ast_pp.h" -#include"basic_simplifier_plugin.h" +#include "ast/rewriter/maximize_ac_sharing.h" +#include "ast/ast_pp.h" -maximise_ac_sharing::ac_plugin::ac_plugin(symbol const & fname, ast_manager & m, maximise_ac_sharing & owner): - simplifier_plugin(fname, m), - m_owner(owner) { -} -void maximise_ac_sharing::ac_plugin::register_kind(decl_kind k) { +void maximize_ac_sharing::register_kind(decl_kind k) { m_kinds.push_back(k); } -maximise_ac_sharing::ac_plugin::~ac_plugin() { -} -bool maximise_ac_sharing::ac_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { +br_status maximize_ac_sharing::reduce_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result, proof_ref& result_pr) { decl_kind k = f->get_kind(); if (!f->is_associative()) - return false; + return BR_FAILED; if (num_args <= 2) - return false; + return BR_FAILED; if (std::find(m_kinds.begin(), m_kinds.end(), k) == m_kinds.end()) - return false; + return BR_FAILED; ptr_buffer _args; expr * numeral = 0; - if (m_owner.is_numeral(args[0])) { + if (is_numeral(args[0])) { numeral = args[0]; for (unsigned i = 1; i < num_args; i++) _args.push_back(args[i]); @@ -58,16 +51,16 @@ bool maximise_ac_sharing::ac_plugin::reduce(func_decl * f, unsigned num_args, ex #define MAX_NUM_ARGS_FOR_OPT 128 // Try to reuse already created circuits. - TRACE("ac_sharing_detail", tout << "args: "; for (unsigned i = 0; i < num_args; i++) tout << mk_pp(_args[i], m_manager) << "\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: if (num_args > 1 && num_args < MAX_NUM_ARGS_FOR_OPT) { - for (unsigned i = 0; i < num_args - 1; i++) { + for (unsigned i = 0; i + 1 < num_args; i++) { for (unsigned j = i + 1; j < num_args; j++) { - if (m_owner.contains(f, _args[i], _args[j])) { + if (contains(f, _args[i], _args[j])) { TRACE("ac_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";); - _args[i] = m_manager.mk_app(f, _args[i], _args[j]); + _args[i] = m.mk_app(f, _args[i], _args[j]); SASSERT(num_args > 1); - for (unsigned w = j; w < num_args - 1; w++) { + for (unsigned w = j; w + 1 < num_args; w++) { _args[w] = _args[w+1]; } num_args--; @@ -87,8 +80,8 @@ bool maximise_ac_sharing::ac_plugin::reduce(func_decl * f, unsigned num_args, ex _args[j] = _args[i]; } else { - m_owner.insert(f, _args[i], _args[i+1]); - _args[j] = m_manager.mk_app(f, _args[i], _args[i+1]); + insert(f, _args[i], _args[i+1]); + _args[j] = m.mk_app(f, _args[i], _args[i+1]); } } num_args = j; @@ -97,54 +90,47 @@ bool maximise_ac_sharing::ac_plugin::reduce(func_decl * f, unsigned num_args, ex result = _args[0]; } else { - result = m_manager.mk_app(f, numeral, _args[0]); + result = m.mk_app(f, numeral, _args[0]); } - TRACE("ac_sharing_detail", tout << "result: " << mk_pp(result, m_manager) << "\n";); - return true; + TRACE("ac_sharing_detail", tout << "result: " << mk_pp(result, m) << "\n";); + return BR_DONE; } } UNREACHABLE(); - return false; + return BR_FAILED; } -bool maximise_ac_sharing::contains(func_decl * f, expr * arg1, expr * arg2) { +bool maximize_ac_sharing::contains(func_decl * f, expr * arg1, expr * arg2) { entry e(f, arg1, arg2); return m_cache.contains(&e); } -void maximise_ac_sharing::insert(func_decl * f, expr * arg1, expr * arg2) { +void maximize_ac_sharing::insert(func_decl * f, expr * arg1, expr * arg2) { entry * e = new (m_region) entry(f, arg1, arg2); m_entries.push_back(e); m_cache.insert(e); - m_manager.inc_ref(arg1); - m_manager.inc_ref(arg2); + m.inc_ref(arg1); + m.inc_ref(arg2); } -maximise_ac_sharing::maximise_ac_sharing(ast_manager & m): - m_manager(m), - m_simplifier(m), +maximize_ac_sharing::maximize_ac_sharing(ast_manager & m): + m(m), m_init(false) { - basic_simplifier_plugin* basic_simp = alloc(basic_simplifier_plugin,m); - m_simplifier.register_plugin(basic_simp); } -maximise_ac_sharing::~maximise_ac_sharing() { +maximize_ac_sharing::~maximize_ac_sharing() { restore_entries(0); } -void maximise_ac_sharing::operator()(expr * s, expr_ref & r, proof_ref & p) { - init(); - m_simplifier.operator()(s, r, p); -} -void maximise_ac_sharing::push_scope() { +void maximize_ac_sharing::push_scope() { init(); m_scopes.push_back(m_entries.size()); m_region.push_scope(); } -void maximise_ac_sharing::pop_scope(unsigned num_scopes) { +void maximize_ac_sharing::pop_scope(unsigned num_scopes) { SASSERT(num_scopes <= m_scopes.size()); unsigned new_lvl = m_scopes.size() - num_scopes; unsigned old_lim = m_scopes[new_lvl]; @@ -153,40 +139,34 @@ void maximise_ac_sharing::pop_scope(unsigned num_scopes) { m_scopes.shrink(new_lvl); } -void maximise_ac_sharing::restore_entries(unsigned old_lim) { +void maximize_ac_sharing::restore_entries(unsigned old_lim) { unsigned i = m_entries.size(); while (i != old_lim) { --i; entry * e = m_entries[i]; - m_manager.dec_ref(e->m_arg1); - m_manager.dec_ref(e->m_arg2); + m_cache.remove(e); + m.dec_ref(e->m_arg1); + m.dec_ref(e->m_arg2); } m_entries.shrink(old_lim); } -void maximise_ac_sharing::reset() { - restore_entries(0); - m_entries.reset(); +void maximize_ac_sharing::reset() { m_cache.reset(); - m_simplifier.reset(); - m_region.reset(); - m_scopes.reset(); } -void maximise_bv_sharing::init_core() { - maximise_ac_sharing::ac_plugin * p = alloc(maximise_ac_sharing::ac_plugin, symbol("bv"), get_manager(), *this); - p->register_kind(OP_BADD); - p->register_kind(OP_BMUL); - p->register_kind(OP_BOR); - p->register_kind(OP_BAND); - register_plugin(p); +void maximize_bv_sharing::init_core() { + register_kind(OP_BADD); + register_kind(OP_BMUL); + register_kind(OP_BOR); + register_kind(OP_BAND); } -bool maximise_bv_sharing::is_numeral(expr * n) const { +bool maximize_bv_sharing::is_numeral(expr * n) const { return m_util.is_numeral(n); } -maximise_bv_sharing::maximise_bv_sharing(ast_manager & m): - maximise_ac_sharing(m), +maximize_bv_sharing::maximize_bv_sharing(ast_manager & m): + maximize_ac_sharing(m), m_util(m) { } diff --git a/src/ast/simplifier/maximise_ac_sharing.h b/src/ast/rewriter/maximize_ac_sharing.h similarity index 62% rename from src/ast/simplifier/maximise_ac_sharing.h rename to src/ast/rewriter/maximize_ac_sharing.h index bd369387c..c0ee0d09f 100644 --- a/src/ast/simplifier/maximise_ac_sharing.h +++ b/src/ast/rewriter/maximize_ac_sharing.h @@ -3,7 +3,7 @@ Copyright (c) 2006 Microsoft Corporation Module Name: - maximise_ac_sharing.h + maximize_ac_sharing.h Abstract: @@ -16,17 +16,17 @@ Author: Revision History: --*/ -#ifndef MAXIMISE_AC_SHARING_H_ -#define MAXIMISE_AC_SHARING_H_ +#ifndef MAXIMIZE_AC_SHARING_H_ +#define MAXIMIZE_AC_SHARING_H_ -#include"simplifier.h" -#include"hashtable.h" -#include"bv_decl_plugin.h" -#include"region.h" +#include "util/hashtable.h" +#include "util/region.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/rewriter.h" /** - \brief Functor used to maximise the amount of shared terms in an expression. - The idea is to rewrite AC terms to maximise sharing. + \brief Functor used to maximize the amount of shared terms in an expression. + The idea is to rewrite AC terms to maximize sharing. Example: (f (bvadd a (bvadd b c)) (bvadd a (bvadd b d))) @@ -35,10 +35,10 @@ Revision History: (f (bvadd (bvadd a b) c) (bvadd (bvadd a b) d)) - \warning This class uses an opportunistic heuristic to maximise sharing. + \warning This class uses an opportunistic heuristic to maximize sharing. There is no guarantee that the optimal expression will be produced. */ -class maximise_ac_sharing { +class maximize_ac_sharing : public default_rewriter_cfg { struct entry { func_decl * m_decl; @@ -67,26 +67,16 @@ class maximise_ac_sharing { typedef ptr_hashtable, deref_eq > cache; protected: - class ac_plugin : public simplifier_plugin { - maximise_ac_sharing & m_owner; - svector m_kinds; //!< kinds to be processed - public: - ac_plugin(symbol const & fname, ast_manager & m, maximise_ac_sharing & owner); - void register_kind(decl_kind k); - virtual ~ac_plugin(); - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - }; - - friend class ac_plugin; + void register_kind(decl_kind k); private: - ast_manager & m_manager; - simplifier m_simplifier; + ast_manager & m; bool m_init; region m_region; cache m_cache; ptr_vector m_entries; unsigned_vector m_scopes; + svector m_kinds; //!< kinds to be processed bool contains(func_decl * f, expr * arg1, expr * arg2); void insert(func_decl * f, expr * arg1, expr * arg2); @@ -100,25 +90,36 @@ private: protected: virtual void init_core() = 0; virtual bool is_numeral(expr * n) const = 0; - void register_plugin(ac_plugin * p) { m_simplifier.register_plugin(p); } public: - maximise_ac_sharing(ast_manager & m); - virtual ~maximise_ac_sharing(); - void operator()(expr * s, expr_ref & r, proof_ref & p); + maximize_ac_sharing(ast_manager & m); + virtual ~maximize_ac_sharing(); void push_scope(); void pop_scope(unsigned num_scopes); void reset(); - ast_manager & get_manager() { return m_manager; } + br_status reduce_app(func_decl* f, unsigned n, expr * const* args, expr_ref& result, proof_ref& result_pr); + }; -class maximise_bv_sharing : public maximise_ac_sharing { +class maximize_bv_sharing : public maximize_ac_sharing { bv_util m_util; protected: virtual void init_core(); virtual bool is_numeral(expr * n) const; public: - maximise_bv_sharing(ast_manager & m); + maximize_bv_sharing(ast_manager & m); }; -#endif /* MAXIMISE_AC_SHARING_H_ */ +class maximize_bv_sharing_rw : public rewriter_tpl { + maximize_bv_sharing m_cfg; +public: + maximize_bv_sharing_rw(ast_manager& m): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m) + {} + void push_scope() { m_cfg.push_scope(); } + void pop_scope(unsigned n) { m_cfg.pop_scope(n); } + void reset() { m_cfg.reset(); } +}; + +#endif /* MAXIMIZE_AC_SHARING_H_ */ diff --git a/src/ast/rewriter/mk_extract_proc.cpp b/src/ast/rewriter/mk_extract_proc.cpp index 5f470acd3..da22c3b80 100644 --- a/src/ast/rewriter/mk_extract_proc.cpp +++ b/src/ast/rewriter/mk_extract_proc.cpp @@ -14,7 +14,7 @@ Revision History: --*/ -#include"mk_extract_proc.h" +#include "ast/rewriter/mk_extract_proc.h" mk_extract_proc::mk_extract_proc(bv_util & u): m_util(u), m_high(0), diff --git a/src/ast/rewriter/mk_extract_proc.h b/src/ast/rewriter/mk_extract_proc.h index 2b242d0f5..4e7b1d1b7 100644 --- a/src/ast/rewriter/mk_extract_proc.h +++ b/src/ast/rewriter/mk_extract_proc.h @@ -16,8 +16,8 @@ --*/ #ifndef MK_EXTRACT_PROC_H_ #define MK_EXTRACT_PROC_H_ -#include"ast.h" -#include"bv_decl_plugin.h" +#include "ast/ast.h" +#include "ast/bv_decl_plugin.h" class mk_extract_proc { bv_util & m_util; unsigned m_high; diff --git a/src/ast/rewriter/mk_simplified_app.cpp b/src/ast/rewriter/mk_simplified_app.cpp index 45245ce1b..eac26ddc3 100644 --- a/src/ast/rewriter/mk_simplified_app.cpp +++ b/src/ast/rewriter/mk_simplified_app.cpp @@ -16,13 +16,13 @@ Author: Notes: --*/ -#include"mk_simplified_app.h" -#include"bool_rewriter.h" -#include"arith_rewriter.h" -#include"bv_rewriter.h" -#include"datatype_rewriter.h" -#include"array_rewriter.h" -#include"fpa_rewriter.h" +#include "ast/rewriter/mk_simplified_app.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/arith_rewriter.h" +#include "ast/rewriter/bv_rewriter.h" +#include "ast/rewriter/datatype_rewriter.h" +#include "ast/rewriter/array_rewriter.h" +#include "ast/rewriter/fpa_rewriter.h" struct mk_simplified_app::imp { ast_manager & m; diff --git a/src/ast/rewriter/mk_simplified_app.h b/src/ast/rewriter/mk_simplified_app.h index 40e6f993d..d979637d2 100644 --- a/src/ast/rewriter/mk_simplified_app.h +++ b/src/ast/rewriter/mk_simplified_app.h @@ -19,9 +19,9 @@ Notes: #ifndef MK_SIMPLIFIED_APP_H_ #define MK_SIMPLIFIED_APP_H_ -#include"ast.h" -#include"params.h" -#include"rewriter_types.h" +#include "ast/ast.h" +#include "util/params.h" +#include "ast/rewriter/rewriter_types.h" class mk_simplified_app { struct imp; diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 37c87cd5b..39d6e2143 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -17,14 +17,14 @@ Notes: --*/ -#include"rewriter.h" -#include"rewriter_def.h" -#include"statistics.h" -#include"pb2bv_rewriter.h" -#include"sorting_network.h" -#include"ast_util.h" -#include"ast_pp.h" -#include"lbool.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "util/statistics.h" +#include "ast/rewriter/pb2bv_rewriter.h" +#include "util/sorting_network.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" +#include "util/lbool.h" struct pb2bv_rewriter::imp { diff --git a/src/ast/rewriter/pb2bv_rewriter.h b/src/ast/rewriter/pb2bv_rewriter.h index 47d8361cb..a4176922a 100644 --- a/src/ast/rewriter/pb2bv_rewriter.h +++ b/src/ast/rewriter/pb2bv_rewriter.h @@ -19,9 +19,9 @@ Notes: #ifndef PB2BV_REWRITER_H_ #define PB2BV_REWRITER_H_ -#include"pb_decl_plugin.h" -#include"rewriter_types.h" -#include"expr_functors.h" +#include "ast/pb_decl_plugin.h" +#include "ast/rewriter/rewriter_types.h" +#include "ast/expr_functors.h" class pb2bv_rewriter { struct imp; diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index b14d350b1..5660f9d65 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -17,11 +17,11 @@ Notes: --*/ -#include "pb_rewriter.h" -#include "pb_rewriter_def.h" -#include "ast_pp.h" -#include "ast_util.h" -#include "ast_smt_pp.h" +#include "ast/rewriter/pb_rewriter.h" +#include "ast/rewriter/pb_rewriter_def.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "ast/ast_smt_pp.h" class pb_ast_rewriter_util { diff --git a/src/ast/rewriter/pb_rewriter.h b/src/ast/rewriter/pb_rewriter.h index ba98d774e..f52aea12b 100644 --- a/src/ast/rewriter/pb_rewriter.h +++ b/src/ast/rewriter/pb_rewriter.h @@ -19,10 +19,10 @@ Notes: #ifndef PB_REWRITER_H_ #define PB_REWRITER_H_ -#include"pb_decl_plugin.h" -#include"rewriter_types.h" -#include"params.h" -#include"lbool.h" +#include "ast/pb_decl_plugin.h" +#include "ast/rewriter/rewriter_types.h" +#include "util/params.h" +#include "util/lbool.h" template diff --git a/src/ast/rewriter/pb_rewriter_def.h b/src/ast/rewriter/pb_rewriter_def.h index a713a05a7..aa2c2a61f 100644 --- a/src/ast/rewriter/pb_rewriter_def.h +++ b/src/ast/rewriter/pb_rewriter_def.h @@ -19,7 +19,7 @@ Notes: #ifndef PB_REWRITER_DEF_H_ #define PB_REWRITER_DEF_H_ -#include"pb_rewriter.h" +#include "ast/rewriter/pb_rewriter.h" template diff --git a/src/ast/rewriter/poly_rewriter.h b/src/ast/rewriter/poly_rewriter.h index ea0b9e85a..23743399e 100644 --- a/src/ast/rewriter/poly_rewriter.h +++ b/src/ast/rewriter/poly_rewriter.h @@ -19,10 +19,10 @@ Notes: #ifndef POLY_REWRITER_H_ #define POLY_REWRITER_H_ -#include"ast.h" -#include"obj_hashtable.h" -#include"rewriter_types.h" -#include"params.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "ast/rewriter/rewriter_types.h" +#include "util/params.h" template class poly_rewriter : public Config { @@ -36,10 +36,10 @@ protected: bool m_sort_sums; bool m_hoist_mul; bool m_hoist_cmul; + bool m_ast_order; bool is_numeral(expr * n) const { return Config::is_numeral(n); } bool is_numeral(expr * n, numeral & r) const { return Config::is_numeral(n, r); } - bool is_zero(expr * n) const { return Config::is_zero(n); } bool is_minus_one(expr * n) const { return Config::is_minus_one(n); } void normalize(numeral & c) { Config::normalize(c, m_curr_sort); } app * mk_numeral(numeral const & r) { return Config::mk_numeral(r, m_curr_sort); } @@ -49,7 +49,6 @@ protected: decl_kind power_decl_kind() const { return Config::power_decl_kind(); } bool is_power(expr * t) const { return is_app_of(t, get_fid(), power_decl_kind()); } expr * get_power_body(expr * t, rational & k); - struct mon_pw_lt; // functor used to sort monomial elements when use_power() == true expr * mk_mul_app(unsigned num_args, expr * const * args); expr * mk_mul_app(numeral const & c, expr * arg); @@ -86,6 +85,14 @@ protected: bool is_mul(expr * t, numeral & c, expr * & pp); void hoist_cmul(expr_ref_buffer & args); + class mon_lt { + poly_rewriter& rw; + int ordinal(expr* e) const; + public: + mon_lt(poly_rewriter& rw): rw(rw) {} + bool operator()(expr* e1, expr * e2) const; + }; + public: poly_rewriter(ast_manager & m, params_ref const & p = params_ref()): Config(m), @@ -111,6 +118,10 @@ public: bool is_mul(expr * n) const { return is_app_of(n, get_fid(), mul_decl_kind()); } bool is_add(func_decl * f) const { return is_decl_of(f, get_fid(), add_decl_kind()); } bool is_mul(func_decl * f) const { return is_decl_of(f, get_fid(), mul_decl_kind()); } + bool is_times_minus_one(expr * n, expr*& r) const; + bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t); + bool is_zero(expr* e) const; + br_status mk_mul_core(unsigned num_args, expr * const * args, expr_ref & result) { SASSERT(num_args > 0); diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 962c9660e..3bb963a7f 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -16,11 +16,12 @@ Author: Notes: --*/ -#include"poly_rewriter.h" -#include"poly_rewriter_params.hpp" -#include"ast_lt.h" -#include"ast_ll_pp.h" -#include"ast_smt2_pp.h" +#include "ast/rewriter/poly_rewriter.h" +#include "ast/rewriter/poly_rewriter_params.hpp" +#include "ast/rewriter/arith_rewriter_params.hpp" +#include "ast/ast_lt.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt2_pp.h" template @@ -33,6 +34,8 @@ void poly_rewriter::updt_params(params_ref const & _p) { m_som_blowup = p.som_blowup(); if (!m_flat) m_som = false; if (m_som) m_hoist_mul = false; + arith_rewriter_params ap(_p); + m_ast_order = !ap.arith_ineq_lhs(); } template @@ -64,6 +67,13 @@ expr * poly_rewriter::get_power_body(expr * t, rational & k) { return t; } +template +bool poly_rewriter::is_zero(expr* e) const { + rational v; + return is_numeral(e, v) && v.is_zero(); +} + + template expr * poly_rewriter::mk_mul_app(unsigned num_args, expr * const * args) { switch (num_args) { @@ -118,6 +128,9 @@ expr * poly_rewriter::mk_mul_app(numeral const & c, expr * arg) { if (c.is_one()) { return arg; } + else if (is_zero(arg)) { + return arg; + } else { expr * new_args[2] = { mk_numeral(c), arg }; return mk_mul_app(2, new_args); @@ -181,21 +194,9 @@ br_status poly_rewriter::mk_flat_mul_core(unsigned num_args, expr * cons } -template -struct poly_rewriter::mon_pw_lt { - poly_rewriter & m_owner; - mon_pw_lt(poly_rewriter & o):m_owner(o) {} - - bool operator()(expr * n1, expr * n2) const { - rational k; - return lt(m_owner.get_power_body(n1, k), - m_owner.get_power_body(n2, k)); - } -}; - - template br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * const * args, expr_ref & result) { + mon_lt lt(*this); SASSERT(num_args >= 2); // cheap case numeral a; @@ -310,11 +311,8 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con if (ordered && num_coeffs == 0 && !use_power()) return BR_FAILED; if (!ordered) { - if (use_power()) - std::sort(new_args.begin(), new_args.end(), mon_pw_lt(*this)); - else - std::sort(new_args.begin(), new_args.end(), ast_to_lt()); - TRACE("poly_rewriter", + std::sort(new_args.begin(), new_args.end(), lt); + TRACE("poly_rewriter", tout << "after sorting:\n"; for (unsigned i = 0; i < new_args.size(); i++) { if (i > 0) @@ -488,8 +486,45 @@ void poly_rewriter::hoist_cmul(expr_ref_buffer & args) { args.resize(j); } +template +bool poly_rewriter::mon_lt::operator()(expr* e1, expr * e2) const { + if (rw.m_ast_order) + return lt(e1,e2); + return ordinal(e1) < ordinal(e2); +} + +inline bool is_essentially_var(expr * n, family_id fid) { + SASSERT(is_var(n) || is_app(n)); + return is_var(n) || to_app(n)->get_family_id() != fid; +} + +template +int poly_rewriter::mon_lt::ordinal(expr* e) const { + rational k; + if (is_essentially_var(e, rw.get_fid())) { + return e->get_id(); + } + else if (rw.is_mul(e)) { + if (rw.is_numeral(to_app(e)->get_arg(0))) + return to_app(e)->get_arg(1)->get_id(); + else + return e->get_id(); + } + else if (rw.is_numeral(e)) { + return -1; + } + else if (rw.use_power() && rw.is_power(e) && rw.is_numeral(to_app(e)->get_arg(1), k) && k > rational(1)) { + return to_app(e)->get_arg(0)->get_id(); + } + else { + return e->get_id(); + } +} + + template br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * const * args, expr_ref & result) { + mon_lt lt(*this); SASSERT(num_args >= 2); numeral c; unsigned num_coeffs = 0; @@ -498,22 +533,22 @@ br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * con expr_fast_mark2 multiple; // multiple.is_marked(power_product) if power_product occurs more than once bool has_multiple = false; expr * prev = 0; - bool ordered = true; + bool ordered = true; for (unsigned i = 0; i < num_args; i++) { expr * arg = args[i]; + if (is_numeral(arg, a)) { num_coeffs++; c += a; + ordered = !m_sort_sums || i == 0; } - else { - // arg is not a numeral - if (m_sort_sums && ordered) { - if (prev != 0 && lt(arg, prev)) - ordered = false; - prev = arg; - } + else if (m_sort_sums && ordered) { + if (prev != 0 && lt(arg, prev)) + ordered = false; + prev = arg; } + arg = get_power_product(arg); if (visited.is_marked(arg)) { multiple.mark(arg); @@ -525,8 +560,8 @@ br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * con } normalize(c); SASSERT(m_sort_sums || ordered); - TRACE("sort_sums", - tout << "ordered: " << ordered << "\n"; + TRACE("rewriter", + tout << "ordered: " << ordered << " sort sums: " << m_sort_sums << "\n"; for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";); if (has_multiple) { @@ -579,13 +614,14 @@ br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * con hoist_cmul(new_args); } else if (m_sort_sums) { - TRACE("sort_sums_bug", tout << "new_args.size(): " << new_args.size() << "\n";); + TRACE("rewriter_bug", tout << "new_args.size(): " << new_args.size() << "\n";); if (c.is_zero()) - std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt()); + std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), mon_lt(*this)); else - std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt()); + std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), mon_lt(*this)); } result = mk_add_app(new_args.size(), new_args.c_ptr()); + TRACE("rewriter", tout << result << "\n";); if (hoist_multiplication(result)) { return BR_REWRITE_FULL; } @@ -613,10 +649,10 @@ br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * con } else if (!ordered) { if (c.is_zero()) - std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt()); + std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), lt); else - std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt()); - } + std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), lt); + } result = mk_add_app(new_args.size(), new_args.c_ptr()); if (hoist_multiplication(result)) { return BR_REWRITE_FULL; @@ -650,10 +686,11 @@ br_status poly_rewriter::mk_sub(unsigned num_args, expr * const * args, return BR_DONE; } set_curr_sort(m().get_sort(args[0])); - expr * minus_one = mk_numeral(numeral(-1)); + expr_ref minus_one(mk_numeral(numeral(-1)), m()); ptr_buffer new_args; new_args.push_back(args[0]); for (unsigned i = 1; i < num_args; i++) { + if (is_zero(args[i])) continue; expr * aux_args[2] = { minus_one, args[i] }; new_args.push_back(mk_mul_app(2, aux_args)); } @@ -669,6 +706,7 @@ br_status poly_rewriter::mk_sub(unsigned num_args, expr * const * args, template br_status poly_rewriter::cancel_monomials(expr * lhs, expr * rhs, bool move, expr_ref & lhs_result, expr_ref & rhs_result) { set_curr_sort(m().get_sort(lhs)); + mon_lt lt(*this); unsigned lhs_sz; expr * const * lhs_monomials = get_monomials(lhs, lhs_sz); unsigned rhs_sz; @@ -693,8 +731,10 @@ br_status poly_rewriter::cancel_monomials(expr * lhs, expr * rhs, bool m } } - if (move && num_coeffs == 0 && is_numeral(rhs)) + if (move && num_coeffs == 0 && is_numeral(rhs)) { + TRACE("mk_le_bug", tout << "no coeffs\n";); return BR_FAILED; + } for (unsigned i = 0; i < rhs_sz; i++) { expr * arg = rhs_monomials[i]; @@ -712,15 +752,17 @@ br_status poly_rewriter::cancel_monomials(expr * lhs, expr * rhs, bool m } normalize(c); - + if (!has_multiple && num_coeffs <= 1) { if (move) { - if (is_numeral(rhs)) + if (is_numeral(rhs)) { return BR_FAILED; + } } else { - if (num_coeffs == 0 || is_numeral(rhs)) + if (num_coeffs == 0 || is_numeral(rhs)) { return BR_FAILED; + } } } @@ -811,7 +853,7 @@ br_status poly_rewriter::cancel_monomials(expr * lhs, expr * rhs, bool m if (move) { if (m_sort_sums) { // + 1 to skip coefficient - std::sort(new_lhs_monomials.begin() + 1, new_lhs_monomials.end(), ast_to_lt()); + std::sort(new_lhs_monomials.begin() + 1, new_lhs_monomials.end(), lt); } c_at_rhs = true; } @@ -836,6 +878,7 @@ br_status poly_rewriter::cancel_monomials(expr * lhs, expr * rhs, bool m new_lhs_monomials[0] = insert_c_lhs ? mk_numeral(c) : NULL; lhs_result = mk_add_app(new_lhs_monomials.size() - lhs_offset, new_lhs_monomials.c_ptr() + lhs_offset); rhs_result = mk_add_app(new_rhs_monomials.size() - rhs_offset, new_rhs_monomials.c_ptr() + rhs_offset); + TRACE("mk_le_bug", tout << lhs_result << " " << rhs_result << "\n";); return BR_DONE; } @@ -931,3 +974,62 @@ expr* poly_rewriter::merge_muls(expr* x, expr* y) { m1[k] = mk_add_app(2, args); return mk_mul_app(k+1, m1.c_ptr()); } + +template +bool poly_rewriter::is_times_minus_one(expr * n, expr* & r) const { + if (is_mul(n) && to_app(n)->get_num_args() == 2 && is_minus_one(to_app(n)->get_arg(0))) { + r = to_app(n)->get_arg(1); + return true; + } + return false; +} + +/** + \brief Return true if n is can be put into the form (+ v t) or (+ (- v) t) + \c inv = true will contain true if (- v) is found, and false otherwise. +*/ +template +bool poly_rewriter::is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) { + if (!is_add(n) || is_ground(n)) + return false; + + ptr_buffer args; + v = 0; + expr * curr = to_app(n); + bool stop = false; + inv = false; + while (!stop) { + expr * arg; + expr * neg_arg; + if (is_add(curr)) { + arg = to_app(curr)->get_arg(0); + curr = to_app(curr)->get_arg(1); + } + else { + arg = curr; + stop = true; + } + if (is_ground(arg)) { + args.push_back(arg); + } + else if (is_var(arg)) { + if (v != 0) + return false; // already found variable + v = to_var(arg); + } + else if (is_times_minus_one(arg, neg_arg) && is_var(neg_arg)) { + if (v != 0) + return false; // already found variable + v = to_var(neg_arg); + inv = true; + } + else { + return false; // non ground term. + } + } + if (v == 0) + return false; // did not find variable + SASSERT(!args.empty()); + mk_add(args.size(), args.c_ptr(), t); + return true; +} diff --git a/src/ast/simplifier/pull_ite_tree.cpp b/src/ast/rewriter/pull_ite_tree.cpp similarity index 87% rename from src/ast/simplifier/pull_ite_tree.cpp rename to src/ast/rewriter/pull_ite_tree.cpp index 05bb3d885..651744bf9 100644 --- a/src/ast/simplifier/pull_ite_tree.cpp +++ b/src/ast/rewriter/pull_ite_tree.cpp @@ -16,14 +16,14 @@ Author: Revision History: --*/ -#include"pull_ite_tree.h" -#include"recurse_expr_def.h" -#include"for_each_expr.h" -#include"ast_pp.h" +#include "ast/rewriter/pull_ite_tree.h" +#include "ast/recurse_expr_def.h" +#include "ast/for_each_expr.h" +#include "ast/ast_pp.h" -pull_ite_tree::pull_ite_tree(ast_manager & m, simplifier & s): +pull_ite_tree::pull_ite_tree(ast_manager & m): m_manager(m), - m_simplifier(s), + m_rewriter(m), m_cache(m) { } @@ -64,7 +64,7 @@ void pull_ite_tree::reduce(expr * n) { get_cached(e_old, e, e_pr); expr_ref r(m_manager); expr * args[3] = {c, t, e}; - m_simplifier.mk_app(to_app(n)->get_decl(), 3, args, r); + r = m_rewriter.mk_app(to_app(n)->get_decl(), 3, args); if (!m_manager.proofs_enabled()) { // expr * r = m_manager.mk_ite(c, t, e); cache_result(n, r, 0); @@ -117,7 +117,7 @@ void pull_ite_tree::reduce(expr * n) { else { expr_ref r(m_manager); m_args[m_arg_idx] = n; - m_simplifier.mk_app(m_p, m_args.size(), m_args.c_ptr(), r); + r = m_rewriter.mk_app(m_p, m_args.size(), m_args.c_ptr()); if (!m_manager.proofs_enabled()) { // expr * r = m_manager.mk_app(m_p, m_args.size(), m_args.c_ptr()); cache_result(n, r, 0); @@ -179,23 +179,31 @@ void pull_ite_tree::operator()(app * n, app_ref & r, proof_ref & pr) { m_todo.reset(); } -pull_ite_tree_star::pull_ite_tree_star(ast_manager & m, simplifier & s): - simplifier(m), - m_proc(m, s) { - borrow_plugins(s); + + +pull_ite_tree_cfg::pull_ite_tree_cfg(ast_manager & m): + m(m), + m_trail(m), + m_proc(m) { } -bool pull_ite_tree_star::get_subst(expr * n, expr_ref & r, proof_ref & p) { +bool pull_ite_tree_cfg::get_subst(expr * n, expr* & r, proof* & p) { if (is_app(n) && is_target(to_app(n))) { app_ref tmp(m); - m_proc(to_app(n), tmp, p); - r = tmp; - return true; + proof_ref pr(m); + m_proc(to_app(n), tmp, pr); + if (tmp != n) { + r = tmp; + p = pr; + m_trail.push_back(r); + m_trail.push_back(p); + return true; + } } return false; } -bool pull_cheap_ite_tree_star::is_target(app * n) const { +bool pull_cheap_ite_tree_cfg::is_target(app * n) const { bool r = n->get_num_args() == 2 && n->get_family_id() != null_family_id && diff --git a/src/ast/simplifier/pull_ite_tree.h b/src/ast/rewriter/pull_ite_tree.h similarity index 69% rename from src/ast/simplifier/pull_ite_tree.h rename to src/ast/rewriter/pull_ite_tree.h index 14c447697..3ff0a716d 100644 --- a/src/ast/simplifier/pull_ite_tree.h +++ b/src/ast/rewriter/pull_ite_tree.h @@ -19,11 +19,12 @@ Revision History: #ifndef PULL_ITE_TREE_H_ #define PULL_ITE_TREE_H_ -#include"ast.h" -#include"simplifier.h" -#include"recurse_expr.h" -#include"obj_hashtable.h" -#include"expr_map.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/expr_map.h" +#include "ast/recurse_expr.h" +#include "util/obj_hashtable.h" /** \brief Functor for applying the following transformation @@ -34,7 +35,7 @@ Revision History: */ class pull_ite_tree { ast_manager & m_manager; - simplifier & m_simplifier; + th_rewriter m_rewriter; func_decl * m_p; ptr_vector m_args; unsigned m_arg_idx; //!< position of the ite argument @@ -56,7 +57,7 @@ class pull_ite_tree { return m_manager.mk_app(m_p, m_args.size(), m_args.c_ptr()); } public: - pull_ite_tree(ast_manager & m, simplifier & s); + pull_ite_tree(ast_manager & m); /** \brief Apply the transformation above if n contains an ite-expression. Store the result in r. If n does not contain an ite-expression, then @@ -71,14 +72,16 @@ public: \brief Functor for applying the pull_ite_tree on subexpressions n that satisfy the is_target virtual predicate. */ -class pull_ite_tree_star : public simplifier { +class pull_ite_tree_cfg : public default_rewriter_cfg { protected: + ast_manager& m; + expr_ref_vector m_trail; pull_ite_tree m_proc; - virtual bool get_subst(expr * n, expr_ref & r, proof_ref & p); public: - pull_ite_tree_star(ast_manager & m, simplifier & s); - virtual ~pull_ite_tree_star() { release_plugins(); } + pull_ite_tree_cfg(ast_manager & m); + virtual ~pull_ite_tree_cfg() {} virtual bool is_target(app * n) const = 0; + bool get_subst(expr * n, expr* & r, proof* & p); }; /** @@ -90,12 +93,21 @@ public: - ite is an ite-term expression - v is a value */ -class pull_cheap_ite_tree_star : public pull_ite_tree_star { +class pull_cheap_ite_tree_cfg : public pull_ite_tree_cfg { public: - pull_cheap_ite_tree_star(ast_manager & m, simplifier & s):pull_ite_tree_star(m, s) {} - virtual ~pull_cheap_ite_tree_star() {} + pull_cheap_ite_tree_cfg(ast_manager & m):pull_ite_tree_cfg(m) {} + virtual ~pull_cheap_ite_tree_cfg() {} virtual bool is_target(app * n) const; }; +class pull_cheap_ite_tree_rw : public rewriter_tpl { + pull_cheap_ite_tree_cfg m_cfg; +public: + pull_cheap_ite_tree_rw(ast_manager& m): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m) + {} +}; + #endif /* PULL_ITE_TREE_H_ */ diff --git a/src/ast/rewriter/push_app_ite.cpp b/src/ast/rewriter/push_app_ite.cpp new file mode 100644 index 000000000..f3df4d711 --- /dev/null +++ b/src/ast/rewriter/push_app_ite.cpp @@ -0,0 +1,91 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + push_app_ite.cpp + +Abstract: + + TODO: Write a better ite lifter + + +Author: + + Leonardo de Moura (leonardo) 2008-05-14. + +Revision History: + +--*/ +#include "ast/rewriter/push_app_ite.h" +#include "ast/ast_pp.h" + + +static int has_ite_arg(ast_manager& m, unsigned num_args, expr * const * args) { + for (unsigned i = 0; i < num_args; i++) + if (m.is_ite(args[i])) + return i; + return -1; +} + + +/** + \brief Default (conservative) implementation. Return true if there one and only one ite-term argument. +*/ +bool push_app_ite_cfg::is_target(func_decl * decl, unsigned num_args, expr * const * args) { + if (m.is_ite(decl)) + return false; + bool found_ite = false; + for (unsigned i = 0; i < num_args; i++) { + if (m.is_ite(args[i]) && !m.is_bool(args[i])) { + if (found_ite) { + if (m_conservative) + return false; + } + else { + found_ite = true; + } + } + } + CTRACE("push_app_ite", found_ite, tout << "found target for push app ite:\n"; + tout << decl->get_name(); + for (unsigned i = 0; i < num_args; i++) tout << " " << mk_pp(args[i], m); + tout << "\n";); + return found_ite; +} + +br_status push_app_ite_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + if (!is_target(f, num, args)) { + return BR_FAILED; + } + int ite_arg_idx = has_ite_arg(m, num, args); + if (ite_arg_idx < 0) { + return BR_FAILED; + } + app * ite = to_app(args[ite_arg_idx]); + expr * c = 0, * t = 0, * e = 0; + VERIFY(m.is_ite(ite, c, t, e)); + expr ** args_prime = const_cast(args); + expr * old = args_prime[ite_arg_idx]; + args_prime[ite_arg_idx] = t; + expr_ref t_new(m.mk_app(f, num, args_prime), m); + args_prime[ite_arg_idx] = e; + expr_ref e_new(m.mk_app(f, num, args_prime), m); + args_prime[ite_arg_idx] = old; + result = m.mk_ite(c, t_new, e_new); + TRACE("push_app_ite", tout << result << "\n";); + if (m.proofs_enabled()) { + result_pr = m.mk_rewrite(m.mk_app(f, num, args), result); + } + return BR_REWRITE2; +} + +bool ng_push_app_ite_cfg::is_target(func_decl * decl, unsigned num_args, expr * const * args) { + bool r = push_app_ite_cfg::is_target(decl, num_args, args); + if (!r) + return false; + for (unsigned i = 0; i < num_args; i++) + if (!is_ground(args[i])) + return true; + return false; +} diff --git a/src/ast/rewriter/push_app_ite.h b/src/ast/rewriter/push_app_ite.h new file mode 100644 index 000000000..ae06aad30 --- /dev/null +++ b/src/ast/rewriter/push_app_ite.h @@ -0,0 +1,74 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + push_app_ite.h + +Abstract: + + + +Author: + + Leonardo de Moura (leonardo) 2008-05-14. + +Revision History: + +--*/ +#ifndef PUSH_APP_ITE_H_ +#define PUSH_APP_ITE_H_ + +#include "ast/ast.h" +#include "ast/rewriter/rewriter.h" + +/** + \brief Functor for applying the following transformation: + + (f s (ite c t1 t2)) ==> (ite c (f s t1) (f s t2)) +*/ + +struct push_app_ite_cfg : public default_rewriter_cfg { + ast_manager& m; + bool m_conservative; + virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args); + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr); + push_app_ite_cfg(ast_manager& m, bool conservative = true): m(m), m_conservative(conservative) {} + bool rewrite_patterns() const { return false; } +}; + +/** + \brief Variation of push_app_ite that applies the transformation on nonground terms only. + + \remark This functor uses the app::is_ground method. This method is not + completly precise, for instance, any term containing a quantifier is marked as non ground. +*/ +class ng_push_app_ite_cfg : public push_app_ite_cfg { +protected: + virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args); +public: + ng_push_app_ite_cfg(ast_manager& m, bool conservative = true): push_app_ite_cfg(m, conservative) {} + virtual ~ng_push_app_ite_cfg() {} +}; + +struct push_app_ite_rw : public rewriter_tpl { + push_app_ite_cfg m_cfg; +public: + push_app_ite_rw(ast_manager& m, bool conservative = true): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, conservative) + {} +}; + +struct ng_push_app_ite_rw : public rewriter_tpl { + ng_push_app_ite_cfg m_cfg; +public: + ng_push_app_ite_rw(ast_manager& m, bool conservative = true): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, conservative) + {} +}; + + +#endif /* PUSH_APP_ITE_H_ */ + diff --git a/src/ast/rewriter/quant_hoist.cpp b/src/ast/rewriter/quant_hoist.cpp index e59a079e7..3592f84cd 100644 --- a/src/ast/rewriter/quant_hoist.cpp +++ b/src/ast/rewriter/quant_hoist.cpp @@ -19,14 +19,14 @@ Revision History: --*/ -#include "quant_hoist.h" -#include "expr_functors.h" -#include "ast_smt_pp.h" -#include "bool_rewriter.h" -#include "var_subst.h" -#include "ast_pp.h" -#include "ast_counter.h" -#include "expr_safe_replace.h" +#include "ast/rewriter/quant_hoist.h" +#include "ast/expr_functors.h" +#include "ast/ast_smt_pp.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/var_subst.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/ast_counter.h" +#include "ast/rewriter/expr_safe_replace.h" // // Bring quantifiers of common type into prenex form. @@ -41,9 +41,9 @@ public: m_rewriter(m) {} - void operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result) { + void operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result, bool use_fresh, bool rewrite_ok) { quantifier_type qt = Q_none_pos; - pull_quantifier(fml, qt, vars, result); + pull_quantifier(fml, qt, vars, result, use_fresh, rewrite_ok); TRACE("qe_verbose", tout << mk_pp(fml, m) << "\n"; tout << mk_pp(result, m) << "\n";); @@ -51,36 +51,38 @@ public: is_fa = (Q_forall_pos == qt); } - void pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result) { + void pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result, bool use_fresh, bool rewrite_ok) { quantifier_type qt = Q_exists_pos; - pull_quantifier(fml, qt, vars, result); + pull_quantifier(fml, qt, vars, result, use_fresh, rewrite_ok); TRACE("qe_verbose", tout << mk_pp(fml, m) << "\n"; tout << mk_pp(result, m) << "\n";); } - void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars) { + void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars, bool use_fresh, bool rewrite_ok) { quantifier_type qt = is_forall?Q_forall_pos:Q_exists_pos; expr_ref result(m); - pull_quantifier(fml, qt, vars, result); + pull_quantifier(fml, qt, vars, result, use_fresh, rewrite_ok); TRACE("qe_verbose", tout << mk_pp(fml, m) << "\n"; tout << mk_pp(result, m) << "\n";); fml = result; } - void extract_quantifier(quantifier* q, app_ref_vector& vars, expr_ref& result) { + void extract_quantifier(quantifier* q, app_ref_vector& vars, expr_ref& result, bool use_fresh) { unsigned nd = q->get_num_decls(); for (unsigned i = 0; i < nd; ++i) { sort* s = q->get_decl_sort(i); - app* a = m.mk_fresh_const(q->get_decl_name(i).str().c_str(), s); + symbol const& sym = q->get_decl_name (i); + app* a = use_fresh ? m.mk_fresh_const(sym.str ().c_str (), s) + : m.mk_const (sym, s); vars.push_back(a); } expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd); instantiate(m, q, exprs, result); } - unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names) { + unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names, bool use_fresh, bool rewrite_ok) { unsigned index = var_counter().get_next_var(fml); while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) { quantifier* q = to_quantifier(fml); @@ -97,7 +99,7 @@ public: return index; } app_ref_vector vars(m); - pull_quantifier(is_forall, fml, vars); + pull_quantifier(is_forall, fml, vars, use_fresh, rewrite_ok); if (vars.empty()) { return index; } @@ -192,7 +194,7 @@ private: } - void pull_quantifier(expr* fml, quantifier_type& qt, app_ref_vector& vars, expr_ref& result) { + void pull_quantifier(expr* fml, quantifier_type& qt, app_ref_vector& vars, expr_ref& result, bool use_fresh, bool rewrite_ok) { if (!has_quantifiers(fml)) { result = fml; @@ -209,38 +211,48 @@ private: if (m.is_and(fml)) { num_args = a->get_num_args(); for (unsigned i = 0; i < num_args; ++i) { - pull_quantifier(a->get_arg(i), qt, vars, tmp); + pull_quantifier(a->get_arg(i), qt, vars, tmp, use_fresh, rewrite_ok); args.push_back(tmp); } + if (rewrite_ok) { m_rewriter.mk_and(args.size(), args.c_ptr(), result); + } + else { + result = m.mk_and (args.size (), args.c_ptr ()); + } } else if (m.is_or(fml)) { num_args = to_app(fml)->get_num_args(); for (unsigned i = 0; i < num_args; ++i) { - pull_quantifier(to_app(fml)->get_arg(i), qt, vars, tmp); + pull_quantifier(to_app(fml)->get_arg(i), qt, vars, tmp, use_fresh, rewrite_ok); args.push_back(tmp); } + if (rewrite_ok) { m_rewriter.mk_or(args.size(), args.c_ptr(), result); + } + else { + result = m.mk_or (args.size (), args.c_ptr ()); + } } else if (m.is_not(fml)) { - pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp); + pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp, use_fresh, rewrite_ok); negate(qt); result = m.mk_not(tmp); } else if (m.is_implies(fml, t1, t2)) { - pull_quantifier(t1, negate(qt), vars, tmp); + pull_quantifier(t1, negate(qt), vars, tmp, use_fresh, rewrite_ok); negate(qt); - pull_quantifier(t2, qt, vars, result); + pull_quantifier(t2, qt, vars, result, use_fresh, rewrite_ok); result = m.mk_implies(tmp, result); } else if (m.is_ite(fml, t1, t2, t3)) { expr_ref tt1(m), tt2(m), tt3(m), ntt1(m), nt1(m); - pull_quantifier(t2, qt, vars, tt2); - pull_quantifier(t3, qt, vars, tt3); + pull_quantifier(t2, qt, vars, tt2, use_fresh, rewrite_ok); + pull_quantifier(t3, qt, vars, tt3, use_fresh, rewrite_ok); if (has_quantifiers(t1)) { - pull_quantifier(t1, qt, vars, tt1); + pull_quantifier(t1, qt, vars, tt1, use_fresh, rewrite_ok); nt1 = m.mk_not(t1); - pull_quantifier(nt1, qt, vars, ntt1); + pull_quantifier(nt1, qt, vars, ntt1, use_fresh, rewrite_ok); result = m.mk_and(m.mk_or(ntt1, tt2), m.mk_or(tt1, tt3)); } else { @@ -249,12 +261,12 @@ private: } else if ((m.is_eq(fml, t1, t2) && m.is_bool(t1)) || m.is_iff(fml, t1, t2)) { expr_ref tt1(m), tt2(m), ntt1(m), ntt2(m), nt1(m), nt2(m); - pull_quantifier(t1, qt, vars, tt1); - pull_quantifier(t2, qt, vars, tt2); + pull_quantifier(t1, qt, vars, tt1, use_fresh, rewrite_ok); + pull_quantifier(t2, qt, vars, tt2, use_fresh, rewrite_ok); nt1 = m.mk_not(t1); nt2 = m.mk_not(t2); - pull_quantifier(nt1, qt, vars, ntt1); - pull_quantifier(nt2, qt, vars, ntt2); + pull_quantifier(nt1, qt, vars, ntt1, use_fresh, rewrite_ok); + pull_quantifier(nt2, qt, vars, ntt2, use_fresh, rewrite_ok); result = m.mk_and(m.mk_or(ntt1, tt2), m.mk_or(ntt2, tt1)); } else { @@ -271,8 +283,8 @@ private: break; } set_quantifier_type(qt, q->is_forall()); - extract_quantifier(q, vars, tmp); - pull_quantifier(tmp, qt, vars, result); + extract_quantifier(q, vars, tmp, use_fresh); + pull_quantifier(tmp, qt, vars, result, use_fresh, rewrite_ok); break; } case AST_VAR: @@ -295,18 +307,18 @@ quantifier_hoister::~quantifier_hoister() { dealloc(m_impl); } -void quantifier_hoister::operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result) { - (*m_impl)(fml, vars, is_fa, result); +void quantifier_hoister::operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result, bool use_fresh, bool rewrite_ok) { + (*m_impl)(fml, vars, is_fa, result, use_fresh, rewrite_ok); } -void quantifier_hoister::pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result) { - m_impl->pull_exists(fml, vars, result); +void quantifier_hoister::pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result, bool use_fresh, bool rewrite_ok) { + m_impl->pull_exists(fml, vars, result, use_fresh, rewrite_ok); } -void quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars) { - m_impl->pull_quantifier(is_forall, fml, vars); +void quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars, bool use_fresh, bool rewrite_ok) { + m_impl->pull_quantifier(is_forall, fml, vars, use_fresh, rewrite_ok); } -unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names) { - return m_impl->pull_quantifier(is_forall, fml, sorts, names); +unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names, bool use_fresh, bool rewrite_ok) { + return m_impl->pull_quantifier(is_forall, fml, sorts, names, use_fresh, rewrite_ok); } diff --git a/src/ast/rewriter/quant_hoist.h b/src/ast/rewriter/quant_hoist.h index 90e6ec7ad..e7ae38186 100644 --- a/src/ast/rewriter/quant_hoist.h +++ b/src/ast/rewriter/quant_hoist.h @@ -22,7 +22,7 @@ Revision History: #ifndef QUANTIFIER_HOISTER_H_ #define QUANTIFIER_HOISTER_H_ -#include "ast.h" +#include "ast/ast.h" class quantifier_hoister { class impl; @@ -43,14 +43,14 @@ public: or, and, implies, ite (then and else branch only). */ - void operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result); + void operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result, bool use_fresh = true, bool rewrite_ok = true); /** \brief Pull top-most existential quantifier up. The list of variables is empty if there are no top-level existential quantifier. */ - void pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result); + void pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result, bool use_fresh = true, bool rewrite_ok = true); /** @@ -58,7 +58,7 @@ public: The list of variables is empty if there are no top-level universal/existential quantifier. */ - void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars); + void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars, bool use_fresh = true, bool rewrite_ok = true); /** \brief Pull top-most universal (is_forall true) or existential (is_forall=false) quantifier up. @@ -66,7 +66,7 @@ public: Return index of maximal variable. */ - unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names); + unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names, bool use_fresh = true, bool rewrite_ok = true); }; diff --git a/src/ast/rewriter/rewriter.cpp b/src/ast/rewriter/rewriter.cpp index c7b110dff..36ad2dec4 100644 --- a/src/ast/rewriter/rewriter.cpp +++ b/src/ast/rewriter/rewriter.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"rewriter_def.h" -#include"ast_ll_pp.h" -#include"ast_smt2_pp.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt2_pp.h" void rewriter_core::init_cache_stack() { SASSERT(m_cache_stack.empty()); diff --git a/src/ast/rewriter/rewriter.h b/src/ast/rewriter/rewriter.h index 2b4f4b14e..17742f670 100644 --- a/src/ast/rewriter/rewriter.h +++ b/src/ast/rewriter/rewriter.h @@ -19,9 +19,9 @@ Notes: #ifndef REWRITER_H_ #define REWRITER_H_ -#include"ast.h" -#include"rewriter_types.h" -#include"act_cache.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter_types.h" +#include "ast/act_cache.h" /** \brief Common infrastructure for AST rewriters. diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 76f149df7..f5f72674d 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -16,8 +16,9 @@ Author: Notes: --*/ -#include"rewriter.h" -#include"ast_smt2_pp.h" +#include "ast/rewriter/rewriter.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_ll_pp.h" template template @@ -41,6 +42,10 @@ void rewriter_tpl::process_var(var * v) { unsigned index = m_bindings.size() - idx - 1; var * r = (var*)(m_bindings[index]); if (r != 0) { + CTRACE("rewriter", v->get_sort() != m().get_sort(r), + tout << expr_ref(v, m()) << ":" << sort_ref(v->get_sort(), m()) << " != " << expr_ref(r, m()) << ":" << sort_ref(m().get_sort(r), m()); + tout << "index " << index << " bindings " << m_bindings.size() << "\n"; + display_bindings(tout);); SASSERT(v->get_sort() == m().get_sort(r)); if (!is_ground(r) && m_shifts[index] != m_bindings.size()) { @@ -259,10 +264,10 @@ void rewriter_tpl::process_app(app * t, frame & fr) { } br_status st = m_cfg.reduce_app(f, new_num_args, new_args, m_r, m_pr2); SASSERT(st != BR_DONE || m().get_sort(m_r) == m().get_sort(t)); - TRACE("reduce_app", - tout << mk_ismt2_pp(t, m()) << "\n"; + CTRACE("reduce_app", st != BR_FAILED, + tout << mk_bounded_pp(t, m()) << "\n"; tout << "st: " << st; - if (m_r) tout << " --->\n" << mk_ismt2_pp(m_r, m()); + if (m_r) tout << " --->\n" << mk_bounded_pp(m_r, m()); tout << "\n";); if (st != BR_FAILED) { result_stack().shrink(fr.m_spos); @@ -496,6 +501,7 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) { expr * const * new_pats; expr * const * new_no_pats; if (rewrite_patterns()) { + TRACE("reduce_quantifier_bug", tout << "rewrite patterns\n";); new_pats = it + 1; new_no_pats = new_pats + q->get_num_patterns(); } @@ -518,7 +524,7 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) { } else { expr_ref tmp(m()); - + TRACE("reduce_quantifier_bug", tout << mk_ismt2_pp(q, m()) << " " << mk_ismt2_pp(new_body, m()) << "\n";); if (!m_cfg.reduce_quantifier(q, new_body, new_pats, new_no_pats, m_r, m_pr)) { if (fr.m_new_child) { m_r = m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body); diff --git a/src/ast/rewriter/rewriter_params.pyg b/src/ast/rewriter/rewriter_params.pyg index 06500086a..18bb29e56 100644 --- a/src/ast/rewriter/rewriter_params.pyg +++ b/src/ast/rewriter/rewriter_params.pyg @@ -9,5 +9,6 @@ def_module_params('rewriter', ("pull_cheap_ite", BOOL, False, "pull if-then-else terms when cheap."), ("bv_ineq_consistency_test_max", UINT, 0, "max size of conjunctions on which to perform consistency test based on inequalities on bitvectors."), ("cache_all", BOOL, False, "cache all intermediate results."), + ("rewrite_patterns", BOOL, False, "rewrite patterns."), ("ignore_patterns_on_ground_qbody", BOOL, True, "ignores patterns on quantifiers that don't mention their bound variables."))) diff --git a/src/ast/rewriter/rewriter_types.h b/src/ast/rewriter/rewriter_types.h index f5947eb92..094357fed 100644 --- a/src/ast/rewriter/rewriter_types.h +++ b/src/ast/rewriter/rewriter_types.h @@ -19,8 +19,8 @@ Notes: #ifndef REWRITER_TYPES_H_ #define REWRITER_TYPES_H_ -#include"z3_exception.h" -#include"common_msgs.h" +#include "util/z3_exception.h" +#include "util/common_msgs.h" /** \brief Builtin rewrite result status diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index ce707b108..13cb52df1 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -18,15 +18,16 @@ Notes: --*/ -#include"seq_rewriter.h" -#include"arith_decl_plugin.h" -#include"ast_pp.h" -#include"ast_util.h" -#include"uint_set.h" -#include"automaton.h" -#include"well_sorted.h" -#include"var_subst.h" -#include"symbolic_automata_def.h" +#include "ast/rewriter/seq_rewriter.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "util/uint_set.h" +#include "math/automata/automaton.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/bool_rewriter.h" +#include "math/automata/symbolic_automata_def.h" expr_ref sym_expr::accept(expr* e) { @@ -102,7 +103,6 @@ public: return sym_expr::mk_pred(fml, x->get_sort()); } } - sort* s = x->get_sort(); if (m.is_bool(s)) s = y->get_sort(); var_ref v(m.mk_var(0, s), m); @@ -112,7 +112,10 @@ public: return y; } if (m.is_true(fml2)) return x; - expr_ref fml(m.mk_and(fml1, fml2), m); + if (fml1 == fml2) return x; + bool_rewriter br(m); + expr_ref fml(m); + br.mk_and(fml1, fml2, fml); return sym_expr::mk_pred(fml, x->get_sort()); } virtual T mk_or(T x, T y) { @@ -120,12 +123,15 @@ public: x->get_char() == y->get_char()) { return x; } + if (x == y) return x; var_ref v(m.mk_var(0, x->get_sort()), m); expr_ref fml1 = x->accept(v); expr_ref fml2 = y->accept(v); if (m.is_false(fml1)) return y; if (m.is_false(fml2)) return x; - expr_ref fml(m.mk_or(fml1, fml2), m); + bool_rewriter br(m); + expr_ref fml(m); + br.mk_or(fml1, fml2, fml); return sym_expr::mk_pred(fml, x->get_sort()); } @@ -197,10 +203,10 @@ void re2automaton::set_solver(expr_solver* solver) { eautomaton* re2automaton::operator()(expr* e) { eautomaton* r = re2aut(e); - if (r) { - display_expr1 disp(m); + if (r) { r->compress(); - TRACE("seq", r->display(tout, disp);); + bool_rewriter br(m); + TRACE("seq", display_expr1 disp(m); r->display(tout, disp);); } return r; } @@ -597,6 +603,45 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu return BR_FAILED; } +bool seq_rewriter::cannot_contain_suffix(expr* a, expr* b) { + + if (m_util.str.is_unit(a) && m_util.str.is_unit(b) && m().are_distinct(a, b)) { + return true; + } + zstring A, B; + if (m_util.str.is_string(a, A) && m_util.str.is_string(b, B)) { + // some prefix of a is a suffix of b + bool found = false; + for (unsigned i = 1; !found && i <= A.length(); ++i) { + found = A.extract(0, i).suffixof(B); + } + return !found; + } + + return false; +} + + +bool seq_rewriter::cannot_contain_prefix(expr* a, expr* b) { + + if (m_util.str.is_unit(a) && m_util.str.is_unit(b) && m().are_distinct(a, b)) { + return true; + } + zstring A, B; + if (m_util.str.is_string(a, A) && m_util.str.is_string(b, B)) { + // some suffix of a is a prefix of b + bool found = false; + for (unsigned i = 0; !found && i < A.length(); ++i) { + found = A.extract(i, A.length()-i).suffixof(B); + } + return !found; + } + + return false; +} + + + br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { zstring c, d; if (m_util.str.is_string(a, c) && m_util.str.is_string(b, d)) { @@ -608,6 +653,7 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { m_util.str.get_concat(a, as); m_util.str.get_concat(b, bs); bool all_values = true; + TRACE("seq", tout << mk_pp(a, m()) << " contains " << mk_pp(b, m()) << "\n";); if (bs.empty()) { result = m().mk_true(); @@ -652,12 +698,21 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { return BR_REWRITE2; } + if (bs.size() == 1 && m_util.str.is_string(bs[0].get(), c)) { + for (auto a_i : as) { + if (m_util.str.is_string(a_i, d) && d.contains(c)) { + result = m().mk_true(); + return BR_DONE; + } + } + } + unsigned offs = 0; unsigned sz = as.size(); expr* b0 = bs[0].get(); expr* bL = bs[bs.size()-1].get(); - for (; offs < as.size() && m().are_distinct(b0, as[offs].get()); ++offs) {}; - for (; sz > offs && m().are_distinct(bL, as[sz-1].get()); --sz) {} + for (; offs < as.size() && cannot_contain_prefix(as[offs].get(), b0); ++offs) {} + for (; sz > offs && cannot_contain_suffix(as[sz-1].get(), bL); --sz) {} if (offs == sz) { result = m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b))); return BR_REWRITE2; @@ -815,11 +870,11 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { expr_ref_vector as(m()), bs(m()); if (a1 != b1 && isc1 && isc2) { - TRACE("seq", tout << s1 << " " << s2 << "\n";); if (s1.length() <= s2.length()) { if (s1.prefixof(s2)) { if (a == a1) { result = m().mk_true(); + TRACE("seq", tout << s1 << " " << s2 << " " << result << "\n";); return BR_DONE; } m_util.str.get_concat(a, as); @@ -829,10 +884,12 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { bs[0] = m_util.str.mk_string(s2); result = m_util.str.mk_prefix(m_util.str.mk_concat(as.size()-1, as.c_ptr()+1), m_util.str.mk_concat(bs.size(), bs.c_ptr())); + TRACE("seq", tout << s1 << " " << s2 << " " << result << "\n";); return BR_REWRITE_FULL; } else { result = m().mk_false(); + TRACE("seq", tout << s1 << " " << s2 << " " << result << "\n";); return BR_DONE; } } @@ -840,6 +897,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { if (s2.prefixof(s1)) { if (b == b1) { result = m().mk_false(); + TRACE("seq", tout << s1 << " " << s2 << " " << result << "\n";); return BR_DONE; } m_util.str.get_concat(a, as); @@ -849,10 +907,12 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { as[0] = m_util.str.mk_string(s1); result = m_util.str.mk_prefix(m_util.str.mk_concat(as.size(), as.c_ptr()), m_util.str.mk_concat(bs.size()-1, bs.c_ptr()+1)); + TRACE("seq", tout << s1 << " " << s2 << " " << result << "\n";); return BR_REWRITE_FULL; } else { result = m().mk_false(); + TRACE("seq", tout << s1 << " " << s2 << " " << result << "\n";); return BR_DONE; } } @@ -881,9 +941,6 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { if (i == as.size()) { result = mk_and(eqs); TRACE("seq", tout << result << "\n";); - if (m().is_true(result)) { - return BR_DONE; - } return BR_REWRITE3; } SASSERT(i < as.size()); @@ -1023,19 +1080,40 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { br_status seq_rewriter::mk_str_itos(expr* a, expr_ref& result) { rational r; if (m_autil.is_numeral(a, r)) { - result = m_util.str.mk_string(symbol(r.to_string().c_str())); + if (r.is_int() && !r.is_neg()) { + result = m_util.str.mk_string(symbol(r.to_string().c_str())); + } + else { + result = m_util.str.mk_string(symbol("")); + } return BR_DONE; } return BR_FAILED; } + +/** + \brief rewrite str.to.int according to the rules: + - if the expression is a string which is a non-empty + sequence of digits 0-9 extract the corresponding numeral. + - if the expression is a string that contains any other character + or is empty, produce -1 + - if the expression is int.to.str(x) produce + ite(x >= 0, x, -1) + +*/ br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) { zstring str; if (m_util.str.is_string(a, str)) { std::string s = str.encode(); + if (s.length() == 0) { + result = m_autil.mk_int(-1); + return BR_DONE; + } for (unsigned i = 0; i < s.length(); ++i) { - if (s[i] == '-') { if (i != 0) return BR_FAILED; } - else if ('0' <= s[i] && s[i] <= '9') continue; - return BR_FAILED; + if (!('0' <= s[i] && s[i] <= '9')) { + result = m_autil.mk_int(-1); + return BR_DONE; + } } rational r(s.c_str()); result = m_autil.mk_numeral(r, true); @@ -1043,7 +1121,7 @@ br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) { } expr* b; if (m_util.str.is_itos(a, b)) { - result = b; + result = m().mk_ite(m_autil.mk_ge(b, m_autil.mk_int(0)), b, m_autil.mk_int(-1)); return BR_DONE; } return BR_FAILED; @@ -1874,7 +1952,7 @@ bool seq_rewriter::solve_itos(unsigned szl, expr* const* ls, unsigned szr, expr* } } - if (szr == 1 && m_util.str.is_itos(rs[0], r) && !m_util.str.is_itos(ls[0])) { + if (szr == 1 && szl >= 1 && m_util.str.is_itos(rs[0], r) && !m_util.str.is_itos(ls[0])) { return solve_itos(szr, rs, szl, ls, rhs, lhs, is_sat); } @@ -1942,6 +2020,7 @@ void seq_rewriter::split_units(expr_ref_vector& lhs, expr_ref_vector& rhs) { } + bool seq_rewriter::is_epsilon(expr* e) const { expr* e1; return m_util.re.is_to_re(e, e1) && m_util.str.is_empty(e1); diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 210b2d72c..69f319168 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -19,13 +19,13 @@ Notes: #ifndef SEQ_REWRITER_H_ #define SEQ_REWRITER_H_ -#include"seq_decl_plugin.h" -#include"arith_decl_plugin.h" -#include"rewriter_types.h" -#include"params.h" -#include"lbool.h" -#include"automaton.h" -#include"symbolic_automata.h" +#include "ast/seq_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/rewriter_types.h" +#include "util/params.h" +#include "util/lbool.h" +#include "math/automata/automaton.h" +#include "math/automata/symbolic_automata.h" class sym_expr { enum ty { @@ -122,6 +122,9 @@ class seq_rewriter { br_status mk_re_loop(unsigned num_args, expr* const* args, expr_ref& result); br_status mk_re_range(expr* lo, expr* hi, expr_ref& result); + bool cannot_contain_prefix(expr* a, expr* b); + bool cannot_contain_suffix(expr* a, expr* b); + bool set_empty(unsigned sz, expr* const* es, bool all, expr_ref_vector& lhs, expr_ref_vector& rhs); bool is_subsequence(unsigned n, expr* const* l, unsigned m, expr* const* r, expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat); diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index b561e02fc..a2ca12b24 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -16,24 +16,24 @@ Author: Notes: --*/ -#include"th_rewriter.h" -#include"rewriter_params.hpp" -#include"bool_rewriter.h" -#include"arith_rewriter.h" -#include"bv_rewriter.h" -#include"datatype_rewriter.h" -#include"array_rewriter.h" -#include"fpa_rewriter.h" -#include"dl_rewriter.h" -#include"pb_rewriter.h" -#include"seq_rewriter.h" -#include"rewriter_def.h" -#include"expr_substitution.h" -#include"ast_smt2_pp.h" -#include"cooperate.h" -#include"var_subst.h" -#include"ast_util.h" -#include"well_sorted.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/rewriter_params.hpp" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/arith_rewriter.h" +#include "ast/rewriter/bv_rewriter.h" +#include "ast/rewriter/datatype_rewriter.h" +#include "ast/rewriter/array_rewriter.h" +#include "ast/rewriter/fpa_rewriter.h" +#include "ast/rewriter/dl_rewriter.h" +#include "ast/rewriter/pb_rewriter.h" +#include "ast/rewriter/seq_rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/expr_substitution.h" +#include "ast/ast_smt2_pp.h" +#include "util/cooperate.h" +#include "ast/rewriter/var_subst.h" +#include "ast/ast_util.h" +#include "ast/well_sorted.h" struct th_rewriter_cfg : public default_rewriter_cfg { bool_rewriter m_b_rw; @@ -55,6 +55,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { bool m_push_ite_arith; bool m_push_ite_bv; bool m_ignore_patterns_on_ground_qbody; + bool m_rewrite_patterns; // substitution support expr_dependency_ref m_used_dependencies; // set of dependencies of used substitutions @@ -72,6 +73,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { m_push_ite_arith = p.push_ite_arith(); m_push_ite_bv = p.push_ite_bv(); m_ignore_patterns_on_ground_qbody = p.ignore_patterns_on_ground_qbody(); + m_rewrite_patterns = p.rewrite_patterns(); } void updt_params(params_ref const & p) { @@ -99,7 +101,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { return false; } - bool rewrite_patterns() const { return false; } + bool rewrite_patterns() const { return m_rewrite_patterns; } bool cache_all_results() const { return m_cache_all; } diff --git a/src/ast/rewriter/th_rewriter.h b/src/ast/rewriter/th_rewriter.h index 6aa4bb3da..db495e8da 100644 --- a/src/ast/rewriter/th_rewriter.h +++ b/src/ast/rewriter/th_rewriter.h @@ -19,9 +19,9 @@ Notes: #ifndef TH_REWRITER_H_ #define TH_REWRITER_H_ -#include"ast.h" -#include"rewriter_types.h" -#include"params.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter_types.h" +#include "util/params.h" class expr_substitution; diff --git a/src/ast/rewriter/var_subst.cpp b/src/ast/rewriter/var_subst.cpp index fd290c8fe..756e62a5f 100644 --- a/src/ast/rewriter/var_subst.cpp +++ b/src/ast/rewriter/var_subst.cpp @@ -16,12 +16,12 @@ Author: Notes: --*/ -#include"var_subst.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" -#include"ast_smt2_pp.h" -#include"well_sorted.h" -#include"for_each_expr.h" +#include "ast/rewriter/var_subst.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/well_sorted.h" +#include "ast/for_each_expr.h" void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, expr_ref & result) { SASSERT(is_well_sorted(result.m(), n)); diff --git a/src/ast/rewriter/var_subst.h b/src/ast/rewriter/var_subst.h index 21aa58399..b6a25cfdb 100644 --- a/src/ast/rewriter/var_subst.h +++ b/src/ast/rewriter/var_subst.h @@ -19,9 +19,9 @@ Notes: #ifndef VAR_SUBST_H_ #define VAR_SUBST_H_ -#include"rewriter.h" -#include"used_vars.h" -#include"params.h" +#include "ast/rewriter/rewriter.h" +#include "ast/used_vars.h" +#include "util/params.h" /** \brief Alias for var_shifter class. diff --git a/src/ast/scoped_proof.h b/src/ast/scoped_proof.h index 2bbba5122..b2b3d7173 100644 --- a/src/ast/scoped_proof.h +++ b/src/ast/scoped_proof.h @@ -19,7 +19,7 @@ Revision History: #ifndef SCOPED_PROOF_H_ #define SCOPED_PROOF_H_ -#include "ast.h" +#include "ast/ast.h" class scoped_proof_mode { ast_manager& m; @@ -37,7 +37,7 @@ public: class scoped_proof : public scoped_proof_mode { public: - scoped_proof(ast_manager& m): scoped_proof_mode(m, PGM_FINE) {} + scoped_proof(ast_manager& m): scoped_proof_mode(m, PGM_ENABLED) {} }; class scoped_no_proof : public scoped_proof_mode { diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 750fe0f9d..7cc0ccb12 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include "seq_decl_plugin.h" -#include "arith_decl_plugin.h" -#include "array_decl_plugin.h" -#include "ast_pp.h" +#include "ast/seq_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/ast_pp.h" #include static bool is_hex_digit(char ch, unsigned& d) { diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index e2722aa9a..17fa50423 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -21,8 +21,8 @@ Revision History: #ifndef SEQ_DECL_PLUGIN_H_ #define SEQ_DECL_PLUGIN_H_ -#include "ast.h" -#include "bv_decl_plugin.h" +#include "ast/ast.h" +#include "ast/bv_decl_plugin.h" enum seq_sort_kind { diff --git a/src/ast/shared_occs.cpp b/src/ast/shared_occs.cpp index 5f624e1ac..89867e8c1 100644 --- a/src/ast/shared_occs.cpp +++ b/src/ast/shared_occs.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"shared_occs.h" -#include"ast_smt2_pp.h" -#include"ref_util.h" +#include "ast/shared_occs.h" +#include "ast/ast_smt2_pp.h" +#include "util/ref_util.h" inline void shared_occs::insert(expr * t) { obj_hashtable::entry * dummy; diff --git a/src/ast/shared_occs.h b/src/ast/shared_occs.h index 1566098aa..40921922a 100644 --- a/src/ast/shared_occs.h +++ b/src/ast/shared_occs.h @@ -19,8 +19,8 @@ Revision History: #ifndef SHARED_OCCS_H_ #define SHARED_OCCS_H_ -#include"ast.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" class shared_occs_mark { ptr_buffer m_to_unmark; diff --git a/src/ast/simplifier/CMakeLists.txt b/src/ast/simplifier/CMakeLists.txt deleted file mode 100644 index 9575c5c89..000000000 --- a/src/ast/simplifier/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -z3_add_component(simplifier - SOURCES - arith_simplifier_params.cpp - arith_simplifier_plugin.cpp - array_simplifier_params.cpp - array_simplifier_plugin.cpp - basic_simplifier_plugin.cpp - bit2int.cpp - bv_elim.cpp - bv_simplifier_params.cpp - bv_simplifier_plugin.cpp - datatype_simplifier_plugin.cpp - elim_bounds.cpp - fpa_simplifier_plugin.cpp - inj_axiom.cpp - maximise_ac_sharing.cpp - poly_simplifier_plugin.cpp - pull_ite_tree.cpp - push_app_ite.cpp - seq_simplifier_plugin.cpp - simplifier.cpp - simplifier_plugin.cpp - COMPONENT_DEPENDENCIES - rewriter - PYG_FILES - arith_simplifier_params_helper.pyg - array_simplifier_params_helper.pyg - bv_simplifier_params_helper.pyg -) diff --git a/src/ast/simplifier/README b/src/ast/simplifier/README deleted file mode 100644 index 4725d9de9..000000000 --- a/src/ast/simplifier/README +++ /dev/null @@ -1,2 +0,0 @@ -Simplifier module is now obsolete. -It is still being used in many places, but we will eventually replace all occurrences with the new rewriter module. diff --git a/src/ast/simplifier/arith_simplifier_params.cpp b/src/ast/simplifier/arith_simplifier_params.cpp deleted file mode 100644 index 8584cdae0..000000000 --- a/src/ast/simplifier/arith_simplifier_params.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - arith_simplifier_params.cpp - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2012-12-02. - -Revision History: - ---*/ -#include"arith_simplifier_params.h" -#include"arith_simplifier_params_helper.hpp" - -void arith_simplifier_params::updt_params(params_ref const & _p) { - arith_simplifier_params_helper p(_p); - m_arith_expand_eqs = p.arith_expand_eqs(); - m_arith_process_all_eqs = p.arith_process_all_eqs(); -} - -#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; - -void arith_simplifier_params::display(std::ostream & out) const { - DISPLAY_PARAM(m_arith_expand_eqs); - DISPLAY_PARAM(m_arith_process_all_eqs); -} \ No newline at end of file diff --git a/src/ast/simplifier/arith_simplifier_params.h b/src/ast/simplifier/arith_simplifier_params.h deleted file mode 100644 index 6186ee4a2..000000000 --- a/src/ast/simplifier/arith_simplifier_params.h +++ /dev/null @@ -1,38 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - arith_simplifier_params.h - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2008-05-09. - -Revision History: - ---*/ -#ifndef ARITH_SIMPLIFIER_PARAMS_H_ -#define ARITH_SIMPLIFIER_PARAMS_H_ - -#include"params.h" - -struct arith_simplifier_params { - bool m_arith_expand_eqs; - bool m_arith_process_all_eqs; - - arith_simplifier_params(params_ref const & p = params_ref()) { - updt_params(p); - } - - void updt_params(params_ref const & _p); - - void display(std::ostream & out) const; -}; - -#endif /* ARITH_SIMPLIFIER_PARAMS_H_ */ - diff --git a/src/ast/simplifier/arith_simplifier_params_helper.pyg b/src/ast/simplifier/arith_simplifier_params_helper.pyg deleted file mode 100644 index 49a7cf3d2..000000000 --- a/src/ast/simplifier/arith_simplifier_params_helper.pyg +++ /dev/null @@ -1,7 +0,0 @@ -def_module_params(class_name='arith_simplifier_params_helper', - module_name="old_simplify", # Parameters will be in the old_simplify module - description="old simplification (stack) still used in the smt module", - export=True, - params=( - ('arith.expand_eqs', BOOL, False, 'expand equalities into two inequalities'), - ('arith.process_all_eqs', BOOL, False, 'put all equations in the form (= t c), where c is a numeral'))) diff --git a/src/ast/simplifier/arith_simplifier_plugin.cpp b/src/ast/simplifier/arith_simplifier_plugin.cpp deleted file mode 100644 index ef320578a..000000000 --- a/src/ast/simplifier/arith_simplifier_plugin.cpp +++ /dev/null @@ -1,451 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - arith_simplifier_plugin.cpp - -Abstract: - - Simplifier for the arithmetic family. - -Author: - - Leonardo (leonardo) 2008-01-08 - ---*/ -#include"arith_simplifier_plugin.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"ast_smt2_pp.h" - -arith_simplifier_plugin::~arith_simplifier_plugin() { -} - -arith_simplifier_plugin::arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p): - poly_simplifier_plugin(symbol("arith"), m, OP_ADD, OP_MUL, OP_UMINUS, OP_SUB, OP_NUM), - m_params(p), - m_util(m), - m_bsimp(b), - m_int_zero(m), - m_real_zero(m) { - m_int_zero = m_util.mk_numeral(rational(0), true); - m_real_zero = m_util.mk_numeral(rational(0), false); -} - -/** - \brief Return true if the first monomial of t is negative. -*/ -bool arith_simplifier_plugin::is_neg_poly(expr * t) const { - if (m_util.is_add(t)) { - t = to_app(t)->get_arg(0); - } - if (m_util.is_mul(t)) { - t = to_app(t)->get_arg(0); - rational r; - if (is_numeral(t, r)) - return r.is_neg(); - } - return false; -} - -void arith_simplifier_plugin::get_monomial_gcd(expr_ref_vector& monomials, numeral& g) { - g = numeral::zero(); - numeral n; - for (unsigned i = 0; !g.is_one() && i < monomials.size(); ++i) { - expr* e = monomials[i].get(); - if (is_numeral(e, n)) { - g = gcd(abs(n), g); - } - else if (is_mul(e) && is_numeral(to_app(e)->get_arg(0), n)) { - g = gcd(abs(n), g); - } - else { - g = numeral::one(); - return; - } - } - if (g.is_zero()) { - g = numeral::one(); - } -} - -void arith_simplifier_plugin::div_monomial(expr_ref_vector& monomials, numeral const& g) { - numeral n; - for (unsigned i = 0; i < monomials.size(); ++i) { - expr* e = monomials[i].get(); - if (is_numeral(e, n)) { - SASSERT((n/g).is_int()); - monomials[i] = mk_numeral(n/g); - } - else if (is_mul(e) && is_numeral(to_app(e)->get_arg(0), n)) { - SASSERT((n/g).is_int()); - monomials[i] = mk_mul(n/g, to_app(e)->get_arg(1)); - } - else { - UNREACHABLE(); - } - } -} - -void arith_simplifier_plugin::gcd_reduce_monomial(expr_ref_vector& monomials, numeral& k) { - numeral g, n; - - get_monomial_gcd(monomials, g); - g = gcd(abs(k), g); - - if (g.is_one()) { - return; - } - SASSERT(g.is_pos()); - - k = k / g; - div_monomial(monomials, g); - -} - -template -void arith_simplifier_plugin::mk_le_ge_eq_core(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - bool is_int = m_curr_sort->get_decl_kind() == INT_SORT; - expr_ref_vector monomials(m_manager); - rational k; - TRACE("arith_eq_bug", tout << mk_ismt2_pp(arg1, m_manager) << "\n" << mk_ismt2_pp(arg2, m_manager) << "\n";); - process_sum_of_monomials(false, arg1, monomials, k); - process_sum_of_monomials(true, arg2, monomials, k); - k.neg(); - if (is_int) { - numeral g; - get_monomial_gcd(monomials, g); - if (!g.is_one()) { - div_monomial(monomials, g); - switch(Kind) { - case LE: - // - // g*monmials' <= k - // <=> - // monomials' <= floor(k/g) - // - k = floor(k/g); - break; - case GE: - // - // g*monmials' >= k - // <=> - // monomials' >= ceil(k/g) - // - k = ceil(k/g); - break; - case EQ: - k = k/g; - if (!k.is_int()) { - result = m_manager.mk_false(); - return; - } - break; - } - } - } - expr_ref lhs(m_manager); - mk_sum_of_monomials(monomials, lhs); - if (m_util.is_numeral(lhs)) { - SASSERT(lhs == mk_zero()); - if (( Kind == LE && numeral::zero() <= k) || - ( Kind == GE && numeral::zero() >= k) || - ( Kind == EQ && numeral::zero() == k)) - result = m_manager.mk_true(); - else - result = m_manager.mk_false(); - } - else { - - if (is_neg_poly(lhs)) { - expr_ref neg_lhs(m_manager); - mk_uminus(lhs, neg_lhs); - lhs = neg_lhs; - k.neg(); - expr * rhs = m_util.mk_numeral(k, is_int); - switch (Kind) { - case LE: - result = m_util.mk_ge(lhs, rhs); - break; - case GE: - result = m_util.mk_le(lhs, rhs); - break; - case EQ: - result = m_manager.mk_eq(lhs, rhs); - break; - } - } - else { - expr * rhs = m_util.mk_numeral(k, is_int); - switch (Kind) { - case LE: - result = m_util.mk_le(lhs, rhs); - break; - case GE: - result = m_util.mk_ge(lhs, rhs); - break; - case EQ: - result = m_manager.mk_eq(lhs, rhs); - break; - } - } - } -} - -void arith_simplifier_plugin::mk_arith_eq(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_le(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_ge(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_lt(expr * arg1, expr * arg2, expr_ref & result) { - expr_ref tmp(m_manager); - mk_le(arg2, arg1, tmp); - m_bsimp.mk_not(tmp, result); -} - -void arith_simplifier_plugin::mk_gt(expr * arg1, expr * arg2, expr_ref & result) { - expr_ref tmp(m_manager); - mk_le(arg1, arg2, tmp); - m_bsimp.mk_not(tmp, result); -} - -void arith_simplifier_plugin::gcd_normalize(numeral & coeff, expr_ref& term) { - if (!abs(coeff).is_one()) { - set_curr_sort(term); - SASSERT(m_curr_sort->get_decl_kind() == INT_SORT); - expr_ref_vector monomials(m_manager); - rational k; - monomials.push_back(mk_numeral(numeral(coeff), true)); - process_sum_of_monomials(false, term, monomials, k); - gcd_reduce_monomial(monomials, k); - numeral coeff1; - if (!is_numeral(monomials[0].get(), coeff1)) { - UNREACHABLE(); - } - if (coeff1 == coeff) { - return; - } - monomials[0] = mk_numeral(k, true); - coeff = coeff1; - mk_sum_of_monomials(monomials, term); - } -} - - -void arith_simplifier_plugin::mk_div(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - SASSERT(!is_int); - if (m_util.is_numeral(arg1, v1, is_int)) - result = m_util.mk_numeral(v1/v2, false); - else { - numeral k(1); - k /= v2; - - expr_ref inv_arg2(m_util.mk_numeral(k, false), m_manager); - mk_mul(inv_arg2, arg1, result); - } - } - else - result = m_util.mk_div(arg1, arg2); -} - -void arith_simplifier_plugin::mk_idiv(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) - result = m_util.mk_numeral(div(v1, v2), is_int); - else - result = m_util.mk_idiv(arg1, arg2); -} - -void arith_simplifier_plugin::prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result) { - SASSERT(m_util.is_int(e)); - SASSERT(k.is_int() && k.is_pos()); - numeral n; - bool is_int; - - if (depth == 0) { - result = e; - } - else if (is_add(e) || is_mul(e)) { - expr_ref_vector args(m_manager); - expr_ref tmp(m_manager); - app* a = to_app(e); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - prop_mod_const(a->get_arg(i), depth - 1, k, tmp); - args.push_back(tmp); - } - reduce(a->get_decl(), args.size(), args.c_ptr(), result); - } - else if (m_util.is_numeral(e, n, is_int) && is_int) { - result = mk_numeral(mod(n, k), true); - } - else { - result = e; - } -} - -void arith_simplifier_plugin::mk_mod(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - result = m_util.mk_numeral(mod(v1, v2), is_int); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_one()) { - result = m_util.mk_numeral(numeral(0), true); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_pos()) { - expr_ref tmp(m_manager); - prop_mod_const(arg1, 5, v2, tmp); - result = m_util.mk_mod(tmp, arg2); - } - else { - result = m_util.mk_mod(arg1, arg2); - } -} - -void arith_simplifier_plugin::mk_rem(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - numeral m = mod(v1, v2); - // - // rem(v1,v2) = if v2 >= 0 then mod(v1,v2) else -mod(v1,v2) - // - if (v2.is_neg()) { - m.neg(); - } - result = m_util.mk_numeral(m, is_int); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_one()) { - result = m_util.mk_numeral(numeral(0), true); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && !v2.is_zero()) { - expr_ref tmp(m_manager); - prop_mod_const(arg1, 5, v2, tmp); - result = m_util.mk_mod(tmp, arg2); - if (v2.is_neg()) { - result = m_util.mk_uminus(result); - } - } - else { - result = m_util.mk_rem(arg1, arg2); - } -} - -void arith_simplifier_plugin::mk_to_real(expr * arg, expr_ref & result) { - numeral v; - if (m_util.is_numeral(arg, v)) - result = m_util.mk_numeral(v, false); - else - result = m_util.mk_to_real(arg); -} - -void arith_simplifier_plugin::mk_to_int(expr * arg, expr_ref & result) { - numeral v; - if (m_util.is_numeral(arg, v)) - result = m_util.mk_numeral(floor(v), true); - else if (m_util.is_to_real(arg)) - result = to_app(arg)->get_arg(0); - else - result = m_util.mk_to_int(arg); -} - -void arith_simplifier_plugin::mk_is_int(expr * arg, expr_ref & result) { - numeral v; - if (m_util.is_numeral(arg, v)) - result = v.is_int()?m_manager.mk_true():m_manager.mk_false(); - else if (m_util.is_to_real(arg)) - result = m_manager.mk_true(); - else - result = m_util.mk_is_int(arg); -} - -bool arith_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - SASSERT(f->get_family_id() == m_fid); - TRACE("arith_simplifier_plugin", tout << mk_pp(f, m_manager) << "\n"; - for (unsigned i = 0; i < num_args; i++) tout << mk_pp(args[i], m_manager) << "\n";); - arith_op_kind k = static_cast(f->get_decl_kind()); - switch (k) { - case OP_NUM: return false; - case OP_LE: if (m_presimp) return false; SASSERT(num_args == 2); mk_le(args[0], args[1], result); break; - case OP_GE: if (m_presimp) return false; SASSERT(num_args == 2); mk_ge(args[0], args[1], result); break; - case OP_LT: if (m_presimp) return false; SASSERT(num_args == 2); mk_lt(args[0], args[1], result); break; - case OP_GT: if (m_presimp) return false; SASSERT(num_args == 2); mk_gt(args[0], args[1], result); break; - case OP_ADD: mk_add(num_args, args, result); break; - case OP_SUB: mk_sub(num_args, args, result); break; - case OP_UMINUS: SASSERT(num_args == 1); mk_uminus(args[0], result); break; - case OP_MUL: - mk_mul(num_args, args, result); - TRACE("arith_simplifier_plugin", tout << mk_pp(result, m_manager) << "\n";); - break; - case OP_DIV: SASSERT(num_args == 2); mk_div(args[0], args[1], result); break; - case OP_IDIV: SASSERT(num_args == 2); mk_idiv(args[0], args[1], result); break; - case OP_REM: SASSERT(num_args == 2); mk_rem(args[0], args[1], result); break; - case OP_MOD: SASSERT(num_args == 2); mk_mod(args[0], args[1], result); break; - case OP_TO_REAL: SASSERT(num_args == 1); mk_to_real(args[0], result); break; - case OP_TO_INT: SASSERT(num_args == 1); mk_to_int(args[0], result); break; - case OP_IS_INT: SASSERT(num_args == 1); mk_is_int(args[0], result); break; - case OP_POWER: return false; - case OP_ABS: SASSERT(num_args == 1); mk_abs(args[0], result); break; - case OP_IRRATIONAL_ALGEBRAIC_NUM: return false; - case OP_DIV_0: return false; - case OP_IDIV_0: return false; - default: - return false; - } - TRACE("arith_simplifier_plugin", tout << mk_pp(result.get(), m_manager) << "\n";); - return true; -} - -void arith_simplifier_plugin::mk_abs(expr * arg, expr_ref & result) { - expr_ref c(m_manager); - expr_ref m_arg(m_manager); - mk_uminus(arg, m_arg); - mk_ge(arg, m_util.mk_numeral(rational(0), m_util.is_int(arg)), c); - m_bsimp.mk_ite(c, arg, m_arg, result); -} - -bool arith_simplifier_plugin::is_arith_term(expr * n) const { - return n->get_kind() == AST_APP && to_app(n)->get_family_id() == m_fid; -} - -bool arith_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { - TRACE("reduce_eq_bug", tout << mk_ismt2_pp(lhs, m_manager) << "\n" << mk_ismt2_pp(rhs, m_manager) << "\n";); - set_reduce_invoked(); - if (m_presimp) { - return false; - } - if (m_params.m_arith_expand_eqs) { - expr_ref le(m_manager), ge(m_manager); - mk_le_ge_eq_core(lhs, rhs, le); - mk_le_ge_eq_core(lhs, rhs, ge); - m_bsimp.mk_and(le, ge, result); - return true; - } - - if (m_params.m_arith_process_all_eqs || is_arith_term(lhs) || is_arith_term(rhs)) { - mk_arith_eq(lhs, rhs, result); - return true; - } - return false; -} - - - diff --git a/src/ast/simplifier/arith_simplifier_plugin.h b/src/ast/simplifier/arith_simplifier_plugin.h deleted file mode 100644 index e6181e211..000000000 --- a/src/ast/simplifier/arith_simplifier_plugin.h +++ /dev/null @@ -1,96 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - arith_simplifier_plugin.h - -Abstract: - - Simplifier for the arithmetic family. - -Author: - - Leonardo (leonardo) 2008-01-08 - ---*/ -#ifndef ARITH_SIMPLIFIER_PLUGIN_H_ -#define ARITH_SIMPLIFIER_PLUGIN_H_ - -#include"basic_simplifier_plugin.h" -#include"poly_simplifier_plugin.h" -#include"arith_decl_plugin.h" -#include"arith_simplifier_params.h" - -/** - \brief Simplifier for the arith family. -*/ -class arith_simplifier_plugin : public poly_simplifier_plugin { -public: - enum op_kind { - LE, GE, EQ - }; -protected: - arith_simplifier_params & m_params; - arith_util m_util; - basic_simplifier_plugin & m_bsimp; - expr_ref m_int_zero; - expr_ref m_real_zero; - - bool is_neg_poly(expr * t) const; - - template - void mk_le_ge_eq_core(expr * arg1, expr * arg2, expr_ref & result); - - void prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result); - - void gcd_reduce_monomial(expr_ref_vector& monomials, numeral& k); - - void div_monomial(expr_ref_vector& monomials, numeral const& g); - void get_monomial_gcd(expr_ref_vector& monomials, numeral& g); - -public: - arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p); - ~arith_simplifier_plugin(); - arith_util & get_arith_util() { return m_util; } - virtual numeral norm(const numeral & n) { return n; } - virtual bool is_numeral(expr * n, rational & val) const { bool f; return m_util.is_numeral(n, val, f); } - bool is_numeral(expr * n) const { return m_util.is_numeral(n); } - virtual bool is_minus_one(expr * n) const { numeral tmp; return is_numeral(n, tmp) && tmp.is_minus_one(); } - virtual expr * get_zero(sort * s) const { return m_util.is_int(s) ? m_int_zero.get() : m_real_zero.get(); } - - virtual app * mk_numeral(numeral const & n) { return m_util.mk_numeral(n, m_curr_sort->get_decl_kind() == INT_SORT); } - app * mk_numeral(numeral const & n, bool is_int) { return m_util.mk_numeral(n, is_int); } - bool is_int_sort(sort const * s) const { return m_util.is_int(s); } - bool is_real_sort(sort const * s) const { return m_util.is_real(s); } - bool is_arith_sort(sort const * s) const { return is_int_sort(s) || is_real_sort(s); } - bool is_int(expr const * n) const { return m_util.is_int(n); } - bool is_le(expr const * n) const { return m_util.is_le(n); } - bool is_ge(expr const * n) const { return m_util.is_ge(n); } - - virtual bool is_le_ge(expr * n) const { return is_le(n) || is_ge(n); } - - void mk_le(expr * arg1, expr * arg2, expr_ref & result); - void mk_ge(expr * arg1, expr * arg2, expr_ref & result); - void mk_lt(expr * arg1, expr * arg2, expr_ref & result); - void mk_gt(expr * arg1, expr * arg2, expr_ref & result); - void mk_arith_eq(expr * arg1, expr * arg2, expr_ref & result); - void mk_div(expr * arg1, expr * arg2, expr_ref & result); - void mk_idiv(expr * arg1, expr * arg2, expr_ref & result); - void mk_mod(expr * arg1, expr * arg2, expr_ref & result); - void mk_rem(expr * arg1, expr * arg2, expr_ref & result); - void mk_to_real(expr * arg, expr_ref & result); - void mk_to_int(expr * arg, expr_ref & result); - void mk_is_int(expr * arg, expr_ref & result); - void mk_abs(expr * arg, expr_ref & result); - - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result); - - bool is_arith_term(expr * n) const; - - void gcd_normalize(numeral & coeff, expr_ref& term); - -}; - -#endif /* ARITH_SIMPLIFIER_PLUGIN_H_ */ diff --git a/src/ast/simplifier/array_simplifier_params.cpp b/src/ast/simplifier/array_simplifier_params.cpp deleted file mode 100644 index bffff44d9..000000000 --- a/src/ast/simplifier/array_simplifier_params.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - array_simplifier_params.cpp - -Abstract: - - This file was created during code reorg. - -Author: - - Leonardo de Moura (leonardo) 2012-12-02. - -Revision History: - ---*/ -#include"array_simplifier_params.h" -#include"array_simplifier_params_helper.hpp" - -void array_simplifier_params::updt_params(params_ref const & _p) { - array_simplifier_params_helper p(_p); - m_array_canonize_simplify = p.array_canonize(); - m_array_simplify = p.array_simplify(); -} diff --git a/src/ast/simplifier/array_simplifier_params.h b/src/ast/simplifier/array_simplifier_params.h deleted file mode 100644 index c62b990b9..000000000 --- a/src/ast/simplifier/array_simplifier_params.h +++ /dev/null @@ -1,36 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - array_simplifier_params.h - -Abstract: - - This file was created during code reorg. - -Author: - - Leonardo de Moura (leonardo) 2012-12-02. - -Revision History: - ---*/ -#ifndef ARRAY_SIMPLIFIER_PARAMS_H_ -#define ARRAY_SIMPLIFIER_PARAMS_H_ - -#include"params.h" - -struct array_simplifier_params { - bool m_array_canonize_simplify; - bool m_array_simplify; // temporary hack for disabling array simplifier plugin. - - array_simplifier_params(params_ref const & p = params_ref()) { - updt_params(p); - } - - void updt_params(params_ref const & _p); -}; - -#endif /* ARITH_SIMPLIFIER_PARAMS_H_ */ - diff --git a/src/ast/simplifier/array_simplifier_params_helper.pyg b/src/ast/simplifier/array_simplifier_params_helper.pyg deleted file mode 100644 index 93c184c23..000000000 --- a/src/ast/simplifier/array_simplifier_params_helper.pyg +++ /dev/null @@ -1,6 +0,0 @@ -def_module_params(class_name='array_simplifier_params_helper', - module_name="old_simplify", # Parameters will be in the old_simplify module - export=True, - params=( - ('array.canonize', BOOL, False, 'normalize array terms into normal form during simplification'), - ('array.simplify', BOOL, True, 'enable/disable array simplifications'))) diff --git a/src/ast/simplifier/array_simplifier_plugin.cpp b/src/ast/simplifier/array_simplifier_plugin.cpp deleted file mode 100644 index 85ef2e92f..000000000 --- a/src/ast/simplifier/array_simplifier_plugin.cpp +++ /dev/null @@ -1,877 +0,0 @@ -/*++ -Copyright (c) 2008 Microsoft Corporation - -Module Name: - - array_simplifier_plugin.cpp - -Abstract: - - - -Author: - - Nikolaj Bjorner (nbjorner) 2008-05-05 - -Revision History: - -Notes TODO: - - Examine quadratic cost of simplification vs. model-based procedure. - - Parameterize cache replacement strategy. - Some parameters are hard-wired. - ---*/ - -#include "array_simplifier_plugin.h" -#include "ast_ll_pp.h" -#include "ast_pp.h" - - -array_simplifier_plugin::array_simplifier_plugin( - ast_manager & m, - basic_simplifier_plugin& s, - simplifier& simp, - array_simplifier_params const& p) : - simplifier_plugin(symbol("array"),m), - m_util(m), - m_simp(s), - m_simplifier(simp), - m_params(p), - m_store_cache_size(0) -{} - - -array_simplifier_plugin::~array_simplifier_plugin() { - - select_cache::iterator it = m_select_cache.begin(); - select_cache::iterator end = m_select_cache.end(); - for ( ; it != end; ++it) { - m_manager.dec_array_ref(it->m_key->size(), it->m_key->c_ptr()); - m_manager.dec_ref(it->m_value); - dealloc(it->m_key); - } - - store_cache::iterator it2 = m_store_cache.begin(); - store_cache::iterator end2 = m_store_cache.end(); - for (; it2 != end2; ++it2) { - m_manager.dec_ref(it->m_value); - dealloc(it->m_key); - } -} - - -bool array_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - if (!m_params.m_array_simplify) - return false; - set_reduce_invoked(); - if (m_presimp) - return false; -#if Z3DEBUG - for (unsigned i = 0; i < num_args && i < f->get_arity(); ++i) { - SASSERT(m_manager.get_sort(args[i]) == f->get_domain(i)); - } -#endif - TRACE("array_simplifier", { - tout << mk_pp(f, m_manager) << " "; - for (unsigned i = 0; i < num_args; ++i) { - tout << mk_pp(args[i], m_manager) << " "; - } - tout << "\n"; - } - ); - SASSERT(f->get_family_id() == m_fid); - switch(f->get_decl_kind()) { - case OP_SELECT: - mk_select(num_args, args, result); - break; - case OP_STORE: - mk_store(f, num_args, args, result); - break; - case OP_SET_UNION: { - sort* s = f->get_range(); - expr_ref empty(m_manager); - mk_empty_set(s, empty); - switch(num_args) { - case 0: - result = empty; - break; - case 1: - result = args[0]; - break; - default: { - result = args[0]; - func_decl* f_or = m_manager.mk_or_decl(); - for (unsigned i = 1; i < num_args; ++i) { - mk_map(f_or, result, args[i], result); - } - break; - } - } - break; - } - case OP_SET_INTERSECT: { - expr_ref full(m_manager); - mk_full_set(f->get_range(), full); - switch(num_args) { - case 0: - result = full; - break; - case 1: - result = args[0]; - break; - default: { - result = args[0]; - func_decl* f_and = m_manager.mk_and_decl(); - for (unsigned i = 1; i < num_args; ++i) { - mk_map(f_and, result, args[i], result); - } - break; - } - } - TRACE("array_simplifier", tout << "sort " << mk_pp(result.get(), m_manager) << "\n";); - break; - } - case OP_SET_SUBSET: { - SASSERT(num_args == 2); - expr_ref diff(m_manager), emp(m_manager); - mk_set_difference(num_args, args, diff); - mk_empty_set(m_manager.get_sort(args[0]), emp); - m_simp.mk_eq(diff.get(), emp.get(), result); - break; - } - case OP_SET_COMPLEMENT: { - SASSERT(num_args == 1); - func_decl* f_not = m_manager.mk_not_decl(); - mk_map(f_not, args[0], result); - break; - } - case OP_SET_DIFFERENCE: { - SASSERT(num_args == 2); - expr_ref r1(m_manager); - mk_map(m_manager.mk_not_decl(), args[1], r1); - mk_map(m_manager.mk_and_decl(), args[0], r1, result); - break; - } - case OP_ARRAY_MAP: { - SASSERT(f->get_num_parameters() == 1); - SASSERT(f->get_parameter(0).is_ast()); - SASSERT(is_func_decl(f->get_parameter(0).get_ast())); - // - // map_d (store a j v) = (store (map_f a) v (d v)) - // - if (num_args == 1 && is_store(args[0])) { - app* store_expr = to_app(args[0]); - unsigned num_args = store_expr->get_num_args(); - SASSERT(num_args >= 3); - parameter p = f->get_parameter(0); - func_decl* d = to_func_decl(p.get_ast()); - expr* a = store_expr->get_arg(0); - expr* v = store_expr->get_arg(num_args-1); - // expr*const* args = store_expr->get_args()+1; - expr_ref r1(m_manager), r2(m_manager); - ptr_vector new_args; - - reduce(f, 1, &a, r1); - m_simplifier.mk_app(d, 1, &v, r2); - new_args.push_back(r1); - for (unsigned i = 1; i + 1 < num_args; ++i) { - new_args.push_back(store_expr->get_arg(i)); - } - new_args.push_back(r2); - mk_store(store_expr->get_decl(), num_args, new_args.c_ptr(), result); - break; - } - - // - // map_d (store a j v) (store b j w) = (store (map_f a b) j (d v w)) - // - if (num_args > 1 && same_store(num_args, args)) { - app* store_expr1 = to_app(args[0]); - unsigned num_indices = store_expr1->get_num_args(); - SASSERT(num_indices >= 3); - parameter p = f->get_parameter(0); - func_decl* d = to_func_decl(p.get_ast()); - ptr_vector arrays; - ptr_vector values; - for (unsigned i = 0; i < num_args; ++i) { - arrays.push_back(to_app(args[i])->get_arg(0)); - values.push_back(to_app(args[i])->get_arg(num_indices-1)); - } - - expr_ref r1(m_manager), r2(m_manager); - reduce(f, arrays.size(), arrays.c_ptr(), r1); - m_simplifier.mk_app(d, values.size(), values.c_ptr(), r2); - ptr_vector new_args; - new_args.push_back(r1); - for (unsigned i = 1; i + 1 < num_indices; ++i) { - new_args.push_back(store_expr1->get_arg(i)); - } - new_args.push_back(r2); - mk_store(store_expr1->get_decl(), new_args.size(), new_args.c_ptr(), result); - break; - } - // - // map_d (const v) = (const (d v)) - // - if (num_args == 1 && is_const_array(args[0])) { - app* const_expr = to_app(args[0]); - SASSERT(const_expr->get_num_args() == 1); - parameter p = f->get_parameter(0); - func_decl* d = to_func_decl(p.get_ast()); - expr* v = const_expr->get_arg(0); - expr_ref r1(m_manager); - - m_simplifier.mk_app(d, 1, &v, r1); - expr* arg = r1.get(); - parameter param(f->get_range()); - result = m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, ¶m, 1, &arg); - break; - } - // - // map_d (const v) (const w) = (const (d v w)) - // - if (num_args > 1 && all_const_array(num_args, args)) { - parameter p = f->get_parameter(0); - func_decl* d = to_func_decl(p.get_ast()); - ptr_vector values; - for (unsigned i = 0; i < num_args; ++i) { - values.push_back(to_app(args[i])->get_arg(0)); - } - expr_ref r1(m_manager); - - m_simplifier.mk_app(d, values.size(), values.c_ptr(), r1); - expr* arg = r1.get(); - parameter param(f->get_range()); - result = m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, ¶m, 1, &arg); - break; - } - result = m_manager.mk_app(f, num_args, args); - - break; - } - default: - result = m_manager.mk_app(f, num_args, args); - break; - } - TRACE("array_simplifier", - tout << mk_pp(result.get(), m_manager) << "\n";); - - return true; -} - -bool array_simplifier_plugin::same_store(unsigned num_args, expr* const* args) const { - if (num_args == 0) { - return true; - } - if (!is_store(args[0])) { - return false; - } - SASSERT(to_app(args[0])->get_num_args() >= 3); - unsigned num_indices = to_app(args[0])->get_num_args() - 2; - for (unsigned i = 1; i < num_args; ++i) { - if (!is_store(args[i])) { - return false; - } - for (unsigned j = 1; j < num_indices + 1; ++j) { - if (to_app(args[0])->get_arg(j) != to_app(args[i])->get_arg(j)) { - return false; - } - } - } - return true; -} - -bool array_simplifier_plugin::all_const_array(unsigned num_args, expr* const* args) const { - bool is_const = true; - for (unsigned i = 0; is_const && i < num_args; ++i) { - is_const = is_const_array(args[i]); - } - return is_const; -} - -bool array_simplifier_plugin::all_values(unsigned num_args, expr* const* args) const { - for (unsigned i = 0; i < num_args; ++i) { - if (!m_manager.is_unique_value(args[i])) { - return false; - } - } - return true; -} - -bool array_simplifier_plugin::lex_lt(unsigned num_args, expr* const* args1, expr* const* args2) { - for (unsigned i = 0; i < num_args; ++i) { - TRACE("array_simplifier", - tout << mk_pp(args1[i], m_manager) << "\n"; - tout << mk_pp(args2[i], m_manager) << "\n"; - tout << args1[i]->get_id() << " " << args2[i]->get_id() << "\n"; - ); - - if (args1[i]->get_id() < args2[i]->get_id()) return true; - if (args1[i]->get_id() > args2[i]->get_id()) return false; - } - return false; -} - - -void array_simplifier_plugin::get_stores(expr* n, unsigned& arity, expr*& m, ptr_vector& stores) { - while (is_store(n)) { - app* a = to_app(n); - SASSERT(a->get_num_args() > 2); - arity = a->get_num_args()-2; - n = a->get_arg(0); - stores.push_back(a->get_args()+1); - } - m = n; -} - -lbool array_simplifier_plugin::eq_default(expr* def, unsigned arity, unsigned num_st, expr*const* const* st) { - bool all_diseq = m_manager.is_unique_value(def) && num_st > 0; - bool all_eq = true; - for (unsigned i = 0; i < num_st; ++i) { - all_eq &= (st[i][arity] == def); - all_diseq &= m_manager.is_unique_value(st[i][arity]) && (st[i][arity] != def); - TRACE("array_simplifier", tout << m_manager.is_unique_value(st[i][arity]) << " " << mk_pp(st[i][arity], m_manager) << "\n";); - } - if (all_eq) { - return l_true; - } - if (all_diseq) { - return l_false; - } - return l_undef; -} - - -bool array_simplifier_plugin::insert_table(expr* def, unsigned arity, unsigned num_st, expr*const* const* st, arg_table& table) { - for (unsigned i = 0; i < num_st; ++i ) { - for (unsigned j = 0; j < arity; ++j) { - if (!m_manager.is_unique_value(st[i][j])) { - return false; - } - } - TRACE("array_simplifier", tout << "inserting: "; - for (unsigned j = 0; j < arity; ++j) { - tout << mk_pp(st[i][j], m_manager) << " "; - } - tout << " |-> " << mk_pp(def, m_manager) << "\n"; - ); - args_entry e(arity, st[i]); - table.insert_if_not_there(e); - } - return true; -} - - -lbool array_simplifier_plugin::eq_stores(expr* def, unsigned arity, unsigned num_st1, expr*const* const* st1, unsigned num_st2, expr*const* const* st2) { - if (num_st1 == 0) { - return eq_default(def, arity, num_st2, st2); - } - if (num_st2 == 0) { - return eq_default(def, arity, num_st1, st1); - } - arg_table table1, table2; - if (!insert_table(def, arity, num_st1, st1, table1)) { - return l_undef; - } - if (!insert_table(def, arity, num_st2, st2, table2)) { - return l_undef; - } - - arg_table::iterator it = table1.begin(); - arg_table::iterator end = table1.end(); - for (; it != end; ++it) { - args_entry const & e1 = *it; - args_entry e2; - expr* v1 = e1.m_args[arity]; - if (table2.find(e1, e2)) { - expr* v2 = e2.m_args[arity]; - if (v1 == v2) { - table2.erase(e1); - continue; - } - if (m_manager.is_unique_value(v1) && m_manager.is_unique_value(v2)) { - return l_false; - } - return l_undef; - } - else if (m_manager.is_unique_value(v1) && m_manager.is_unique_value(def) && v1 != def) { - return l_false; - } - } - it = table2.begin(); - end = table2.end(); - for (; it != end; ++it) { - args_entry const & e = *it; - expr* v = e.m_args[arity]; - if (m_manager.is_unique_value(v) && m_manager.is_unique_value(def) && v != def) { - return l_false; - } - } - if (!table2.empty() || !table1.empty()) { - return l_undef; - } - return l_true; -} - - -bool array_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { - set_reduce_invoked(); - expr* c1, *c2; - ptr_vector st1, st2; - unsigned arity1 = 0; - unsigned arity2 = 0; - get_stores(lhs, arity1, c1, st1); - get_stores(rhs, arity2, c2, st2); - if (arity1 == arity2 && is_const_array(c1) && is_const_array(c2)) { - c1 = to_app(c1)->get_arg(0); - c2 = to_app(c2)->get_arg(0); - if (c1 == c2) { - lbool eq = eq_stores(c1, arity2, st1.size(), st1.c_ptr(), st2.size(), st2.c_ptr()); - TRACE("array_simplifier", - tout << mk_pp(lhs, m_manager) << " = " - << mk_pp(rhs, m_manager) << " := " << eq << "\n"; - tout << "arity: " << arity1 << "\n";); - switch(eq) { - case l_false: - result = m_manager.mk_false(); - return true; - case l_true: - result = m_manager.mk_true(); - return true; - default: - return false; - } - } - else if (m_manager.is_unique_value(c1) && m_manager.is_unique_value(c2)) { - result = m_manager.mk_false(); - return true; - } - } - return false; -} - -bool array_simplifier_plugin::reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - return false; -} - - -array_simplifier_plugin::const_select_result -array_simplifier_plugin::mk_select_const(expr* m, app* index, expr_ref& result) { - store_info* info = 0; - expr* r = 0, *a = 0; - if (!is_store(m)) { - return NOT_CACHED; - } - if (!m_store_cache.find(m, info)) { - return NOT_CACHED; - } - if (info->m_map.find(index, r)) { - result = r; - return FOUND_VALUE; - } - a = info->m_default.get(); - - // - // Unfold and cache the store while searching for value of index. - // - while (is_store(a) && m_manager.is_unique_value(to_app(a)->get_arg(1))) { - app* b = to_app(a); - app* c = to_app(b->get_arg(1)); - - if (!info->m_map.contains(c)) { - info->m_map.insert(c, b->get_arg(2)); - m_manager.inc_ref(b->get_arg(2)); - ++m_store_cache_size; - } - a = b->get_arg(0); - info->m_default = a; - - if (c == index) { - result = b->get_arg(2); - return FOUND_VALUE; - } - } - result = info->m_default.get(); - return FOUND_DEFAULT; -} - -void array_simplifier_plugin::cache_store(unsigned num_stores, expr* store_term) -{ - if (num_stores <= m_const_store_threshold) { - return; - } - prune_store_cache(); - if (!m_store_cache.contains(store_term)) { - store_info * info = alloc(store_info, m_manager, store_term); - m_manager.inc_ref(store_term); - m_store_cache.insert(store_term, info); - TRACE("cache_store", tout << m_store_cache.size() << "\n";); - ++m_store_cache_size; - } -} - -void array_simplifier_plugin::cache_select(unsigned num_args, expr * const * args, expr * result) { - ptr_vector * entry = alloc(ptr_vector); - entry->append(num_args, const_cast(args)); - const select_cache::key_data & kd = m_select_cache.insert_if_not_there(entry, result); - if (kd.m_key != entry) { - dealloc(entry); - return; - } - m_manager.inc_array_ref(num_args, args); - m_manager.inc_ref(result); - TRACE("cache_select", tout << m_select_cache.size() << "\n";); -} - - - -void array_simplifier_plugin::prune_select_cache() { - if (m_select_cache.size() > m_select_cache_max_size) { - flush_select_cache(); - } -} - -void array_simplifier_plugin::prune_store_cache() { - if (m_store_cache_size > m_store_cache_max_size) { - flush_store_cache(); - } -} - -void array_simplifier_plugin::flush_select_cache() { - select_cache::iterator it = m_select_cache.begin(); - select_cache::iterator end = m_select_cache.end(); - for (; it != end; ++it) { - ptr_vector * e = (*it).m_key; - m_manager.dec_array_ref(e->size(), e->begin()); - m_manager.dec_ref((*it).m_value); - dealloc(e); - } - m_select_cache.reset(); -} - -void array_simplifier_plugin::flush_store_cache() { - store_cache::iterator it = m_store_cache.begin(); - store_cache::iterator end = m_store_cache.end(); - for (; it != end; ++it) { - m_manager.dec_ref((*it).m_key); - const_map::iterator mit = (*it).m_value->m_map.begin(); - const_map::iterator mend = (*it).m_value->m_map.end(); - for (; mit != mend; ++mit) { - m_manager.dec_ref((*mit).m_value); - } - dealloc((*it).m_value); - } - m_store_cache.reset(); - m_store_cache_size = 0; -} - - -void array_simplifier_plugin::flush_caches() { - flush_select_cache(); - flush_store_cache(); -} - -void array_simplifier_plugin::mk_set_difference(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args == 2); - result = m_manager.mk_app(m_fid, OP_SET_DIFFERENCE, 0, 0, num_args, args); -} - -void array_simplifier_plugin::mk_empty_set(sort* ty, expr_ref & result) { - parameter param(ty); - expr* args[1] = { m_manager.mk_false() }; - result = m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, ¶m, 1, args); -} - -void array_simplifier_plugin::mk_full_set(sort* ty, expr_ref & result) { - parameter param(ty); - expr* args[1] = { m_manager.mk_true() }; - result = m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, ¶m, 1, args); -} - - -bool array_simplifier_plugin::same_args(unsigned num_args, expr * const * args1, expr * const * args2) { - for (unsigned i = 0; i < num_args; ++i) { - if (args1[i] != args2[i]) { - return false; - } - } - return true; -} - -void array_simplifier_plugin::mk_store(func_decl* f, unsigned num_args, expr * const * args, expr_ref & result) { - - SASSERT(num_args >= 3); - - expr* arg0 = args[0]; - expr* argn = args[num_args-1]; - - // - // store(store(a,i,v),i,w) = store(a,i,w) - // - if (is_store(arg0) && - same_args(num_args-2, args+1, to_app(arg0)->get_args()+1)) { - expr_ref_buffer new_args(m_manager); - new_args.push_back(to_app(arg0)->get_arg(0)); - for (unsigned i = 1; i < num_args; ++i) { - new_args.push_back(args[i]); - } - reduce(f, num_args, new_args.c_ptr(), result); - TRACE("array_simplifier", tout << mk_pp(result.get(), m_manager) << "\n";); - return; - } - - // - // store(const(v),i,v) = const(v) - // - if (is_const_array(arg0) && - to_app(arg0)->get_arg(0) == args[num_args-1]) { - result = arg0; - TRACE("array_simplifier", tout << mk_pp(result.get(), m_manager) << "\n";); - return; - } - - // - // store(a, i, select(a, i)) = a - // - if (is_select(argn) && - (to_app(argn)->get_num_args() == num_args - 1) && - same_args(num_args-1, args, to_app(argn)->get_args())) { - TRACE("dummy_store", tout << "dummy store simplified mk_store(\n"; - for (unsigned i = 0; i < num_args; i++) ast_ll_pp(tout, m_manager, args[i]); - tout << ") =====>\n"; - ast_ll_pp(tout, m_manager, arg0);); - result = arg0; - TRACE("array_simplifier", tout << mk_pp(result.get(), m_manager) << "\n";); - return; - } - - // - // store(store(a,i,v),j,w) -> store(store(a,j,w),i,v) - // if i, j are values, i->get_id() < j->get_id() - // - if (m_params.m_array_canonize_simplify && - is_store(arg0) && - all_values(num_args-2, args+1) && - all_values(num_args-2, to_app(arg0)->get_args()+1) && - lex_lt(num_args-2, args+1, to_app(arg0)->get_args()+1)) { - expr* const* args2 = to_app(arg0)->get_args(); - expr_ref_buffer new_args(m_manager); - new_args.push_back(args2[0]); - for (unsigned i = 1; i < num_args; ++i) { - new_args.push_back(args[i]); - } - reduce(f, num_args, new_args.c_ptr(), result); - new_args.reset(); - new_args.push_back(result); - for (unsigned i = 1; i < num_args; ++i) { - new_args.push_back(args2[i]); - } - result = m_manager.mk_app(m_fid, OP_STORE, num_args, new_args.c_ptr()); - TRACE("array_simplifier", tout << mk_pp(result.get(), m_manager) << "\n";); - return; - } - - - result = m_manager.mk_app(m_fid, OP_STORE, num_args, args); - TRACE("array_simplifier", tout << "default: " << mk_pp(result.get(), m_manager) << "\n";); - -} - -void array_simplifier_plugin::mk_select_as_array(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(is_as_array(args[0])); - func_decl * f = get_as_array_func_decl(to_app(args[0])); - result = m_manager.mk_app(f, num_args - 1, args+1); -} - -void array_simplifier_plugin::mk_select_as_array_tree(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(is_as_array_tree(args[0])); - SASSERT(m_manager.is_ite(args[0])); - ptr_buffer todo; - obj_map cache; - app_ref_buffer trail(m_manager); - todo.push_back(to_app(args[0])); - while (!todo.empty()) { - app * curr = todo.back(); - SASSERT(m_manager.is_ite(curr)); - expr * branches[2] = {0, 0}; - bool visited = true; - for (unsigned i = 0; i < 2; i++) { - expr * arg = curr->get_arg(i+1); - if (is_as_array(arg)) { - branches[i] = m_manager.mk_app(get_as_array_func_decl(to_app(arg)), num_args - 1, args+1); - } - else { - SASSERT(m_manager.is_ite(arg)); - app * new_arg = 0; - if (!cache.find(to_app(arg), new_arg)) { - todo.push_back(to_app(arg)); - visited = false; - } - else { - branches[i] = new_arg; - } - } - } - if (visited) { - todo.pop_back(); - app * new_curr = m_manager.mk_ite(curr->get_arg(0), branches[0], branches[1]); - trail.push_back(new_curr); - cache.insert(curr, new_curr); - } - } - SASSERT(cache.contains(to_app(args[0]))); - app * r = 0; - cache.find(to_app(args[0]), r); - result = r; -} - -void array_simplifier_plugin::mk_select(unsigned num_args, expr * const * args, expr_ref & result) { - expr * r = 0; - - if (is_as_array(args[0])) { - mk_select_as_array(num_args, args, result); - return; - } - - if (is_as_array_tree(args[0])) { - mk_select_as_array_tree(num_args, args, result); - return; - } - - bool is_const_select = num_args == 2 && m_manager.is_unique_value(args[1]); - app* const_index = is_const_select?to_app(args[1]):0; - unsigned num_const_stores = 0; - expr_ref tmp(m_manager); - expr* args2[2]; - if (is_const_select) { - switch(mk_select_const(args[0], const_index, tmp)) { - case NOT_CACHED: - break; - case FOUND_VALUE: - TRACE("mk_select", tout << "found value\n"; ast_ll_pp(tout, m_manager, tmp.get()); ); - result = tmp.get(); - // value of select is stored under result. - return; - case FOUND_DEFAULT: - args2[0] = tmp.get(); - args2[1] = args[1]; - args = args2; - is_const_select = false; - break; - } - } - - SASSERT(num_args > 0); - ptr_vector & entry = m_tmp2; - entry.reset(); - entry.append(num_args, args); - expr * entry0 = entry[0]; - SASSERT(m_todo.empty()); - m_todo.push_back(entry0); - while (!m_todo.empty()) { - expr * m = m_todo.back(); - TRACE("array_simplifier", tout << mk_bounded_pp(m, m_manager) << "\n";); - if (is_store(m)) { - expr * nested_array = to_app(m)->get_arg(0); - expr * else_branch = 0; - entry[0] = nested_array; - if (is_const_select) { - if (m_manager.is_unique_value(to_app(m)->get_arg(1))) { - app* const_index2 = to_app(to_app(m)->get_arg(1)); - // - // we found the value, all other stores are different. - // there is no need to recurse. - // - if (const_index == const_index2) { - result = to_app(m)->get_arg(2); - cache_store(num_const_stores, args[0]); - m_todo.reset(); - return; - } - ++num_const_stores; - } - else { - is_const_select = false; - } - } - if (m_select_cache.find(&entry, else_branch)) { - expr_ref_buffer eqs(m_manager); - for (unsigned i = 1; i < num_args ; ++i) { - expr * a = args[i]; - expr * b = to_app(m)->get_arg(i); - expr_ref eq(m_manager); - m_simp.mk_eq(a, b, eq); - eqs.push_back(eq.get()); - } - expr_ref cond(m_manager); - m_simp.mk_and(eqs.size(), eqs.c_ptr(), cond); - expr * then_branch = to_app(m)->get_arg(num_args); - if (m_manager.is_true(cond.get())) { - result = then_branch; - } - else if (m_manager.is_false(cond.get())) { - result = else_branch; - } - else { - m_simp.mk_ite(cond.get(), then_branch, else_branch, result); - } - entry[0] = m; - cache_select(entry.size(), entry.c_ptr(), result.get()); - m_todo.pop_back(); - } - else { - m_todo.push_back(nested_array); - } - } - else if (is_const_array(m)) { - entry[0] = m; - cache_select(entry.size(), entry.c_ptr(), to_app(m)->get_arg(0)); - m_todo.pop_back(); - } - else { - entry[0] = m; - TRACE("array_simplifier", { - for (unsigned i = 0; i < entry.size(); ++i) { - tout << mk_bounded_pp(entry[i], m_manager) << ": " - << mk_bounded_pp(m_manager.get_sort(entry[i]), m_manager) << "\n"; - }} - ); - r = m_manager.mk_app(m_fid, OP_SELECT, 0, 0, entry.size(), entry.c_ptr()); - cache_select(entry.size(), entry.c_ptr(), r); - m_todo.pop_back(); - } - } - cache_store(num_const_stores, args[0]); - entry[0] = entry0; -#ifdef Z3DEBUG - bool f = -#endif - m_select_cache.find(&entry, r); - SASSERT(f); - result = r; - prune_select_cache(); - prune_store_cache(); - TRACE("mk_select", - for (unsigned i = 0; i < num_args; i++) { - ast_ll_pp(tout, m_manager, args[i]); tout << "\n"; - }; - tout << "is_store: " << is_store(args[0]) << "\n"; - ast_ll_pp(tout, m_manager, r);); -} - - -void array_simplifier_plugin::mk_map(func_decl* f, expr* a, expr* b, expr_ref& result) { - expr* exprs[2] = { a, b }; - parameter param(f); - result = m_manager.mk_app(m_fid, OP_ARRAY_MAP, 1, ¶m, 2, exprs ); -} - -void array_simplifier_plugin::mk_map(func_decl* f, expr* a, expr_ref& result) { - parameter param(f); - result = m_manager.mk_app(m_fid, OP_ARRAY_MAP, 1, ¶m, 1, &a ); -} - - diff --git a/src/ast/simplifier/array_simplifier_plugin.h b/src/ast/simplifier/array_simplifier_plugin.h deleted file mode 100644 index 34db04b67..000000000 --- a/src/ast/simplifier/array_simplifier_plugin.h +++ /dev/null @@ -1,154 +0,0 @@ -/*++ -Copyright (c) 2008 Microsoft Corporation - -Module Name: - - array_simplifier_plugin.h - -Abstract: - - - -Author: - - Nikolaj Bjorner (nbjorner) 2008-05-05 - -Revision History: - ---*/ -#ifndef ARRAY_SIMPLIFIER_PLUGIN_H_ -#define ARRAY_SIMPLIFIER_PLUGIN_H_ - -#include"ast.h" -#include"map.h" -#include"array_decl_plugin.h" -#include"simplifier_plugin.h" -#include"basic_simplifier_plugin.h" -#include"array_simplifier_params.h" -#include"simplifier.h" -#include"obj_hashtable.h" -#include"lbool.h" - -class array_simplifier_plugin : public simplifier_plugin { - - typedef ptr_vector entry; - - struct entry_hash_proc { - unsigned operator()(ptr_vector * entry) const { - return get_exprs_hash(entry->size(), entry->begin(), 0xbeef1010); - } - }; - - struct entry_eq_proc { - bool operator()(ptr_vector * entry1, ptr_vector * entry2) const { - if (entry1->size() != entry2->size()) return false; - return compare_arrays(entry1->begin(), entry2->begin(), entry1->size()); - } - }; - - typedef map select_cache; - - struct args_entry { - unsigned m_arity; - expr* const* m_args; - args_entry(unsigned a, expr* const* args) : m_arity(a), m_args(args) {} - args_entry() : m_arity(0), m_args(0) {} - }; - - struct args_entry_hash_proc { - unsigned operator()(args_entry const& e) const { - return get_exprs_hash(e.m_arity, e.m_args, 0xbeef1010); - } - }; - struct args_entry_eq_proc { - bool operator()(args_entry const& e1, args_entry const& e2) const { - if (e1.m_arity != e2.m_arity) return false; - return compare_arrays(e1.m_args, e2.m_args, e1.m_arity); - } - }; - typedef hashtable arg_table; - - array_util m_util; - basic_simplifier_plugin& m_simp; - simplifier& m_simplifier; - array_simplifier_params const& m_params; - select_cache m_select_cache; - ptr_vector m_tmp; - ptr_vector m_tmp2; - ptr_vector m_todo; - static const unsigned m_select_cache_max_size = 100000; - typedef obj_map const_map; - class store_info { - store_info(); - store_info(store_info const&); - public: - const_map m_map; - expr_ref m_default; - store_info(ast_manager& m, expr* d): m_default(d, m) {} - }; - - typedef obj_map store_cache; - store_cache m_store_cache; - unsigned m_store_cache_size; - static const unsigned m_store_cache_max_size = 10000; - static const unsigned m_const_store_threshold = 5; - enum const_select_result { - NOT_CACHED, - FOUND_DEFAULT, - FOUND_VALUE - }; - - -public: - array_simplifier_plugin(ast_manager & m, basic_simplifier_plugin& s, simplifier& simp, array_simplifier_params const& p); - virtual ~array_simplifier_plugin(); - - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - - virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result); - - virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result); - - virtual void flush_caches(); - -private: - bool is_select(expr* n) const { return m_util.is_select(n); } - bool is_store(expr * n) const { return m_util.is_store(n); } - bool is_const_array(expr * n) const { return m_util.is_const(n); } - bool is_as_array(expr * n) const { return m_util.is_as_array(n); } - bool is_as_array_tree(expr * n) { return m_util.is_as_array_tree(n); } - func_decl * get_as_array_func_decl(app * n) const { return m_util.get_as_array_func_decl(n); } - void mk_select_as_array(unsigned num_args, expr * const * args, expr_ref & result); - void mk_select_as_array_tree(unsigned num_args, expr * const * args, expr_ref & result); - bool is_enumerated(expr* n, expr_ref& c, ptr_vector& keys, ptr_vector& vals); - const_select_result mk_select_const(expr* m, app* index, expr_ref& result); - void cache_store(unsigned num_stores, expr* nested_store); - void cache_select(unsigned num_args, expr * const * args, expr * result); - void prune_select_cache(); - void prune_store_cache(); - void flush_select_cache(); - void flush_store_cache(); - void mk_set_difference(unsigned num_args, expr * const * args, expr_ref & result); - void mk_empty_set(sort* ty, expr_ref & result); - void mk_full_set(sort* ty, expr_ref & result); - void mk_select(unsigned num_args, expr * const * args, expr_ref & result); - void mk_store(func_decl* f, unsigned num_args, expr * const * args, expr_ref & result); - void mk_map(func_decl* f, expr* a, expr* b, expr_ref & result); - void mk_map(func_decl* f, expr* a, expr_ref & result); - bool same_args(unsigned num_args, expr * const * args1, expr * const * args2); - - void get_stores(expr* n, unsigned& arity, expr*& m, ptr_vector& stores); - lbool eq_default(expr* def, unsigned arity, unsigned num_st, expr*const* const* st); - bool insert_table(expr* def, unsigned arity, unsigned num_st, expr*const* const* st, arg_table& table); - lbool eq_stores(expr* def, unsigned arity, unsigned num_st1, expr*const* const* st1, unsigned num_st2, expr*const* const* st2); - - bool same_store(unsigned num_args, expr* const* args) const; - bool all_const_array(unsigned num_args, expr* const* args) const; - bool all_values(unsigned num_args, expr* const* args) const; - bool lex_lt(unsigned num_args, expr* const* args1, expr* const* args2); - -}; - - -#endif /* ARRAY_SIMPLIFIER_PLUGIN_H_ */ - diff --git a/src/ast/simplifier/base_simplifier.h b/src/ast/simplifier/base_simplifier.h deleted file mode 100644 index cb630cb7f..000000000 --- a/src/ast/simplifier/base_simplifier.h +++ /dev/null @@ -1,76 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - base_simplifier.h - -Abstract: - - Base class for expression simplifier functors. - -Author: - - Leonardo (leonardo) 2008-01-11 - -Notes: - ---*/ -#ifndef BASE_SIMPLIFIER_H_ -#define BASE_SIMPLIFIER_H_ - -#include"expr_map.h" -#include"ast_pp.h" - -/** - \brief Implements basic functionality used by expression simplifiers. -*/ -class base_simplifier { -protected: - ast_manager & m; - expr_map m_cache; - ptr_vector m_todo; - - void cache_result(expr * n, expr * r, proof * p) { - m_cache.insert(n, r, p); - CTRACE("simplifier", !is_rewrite_proof(n, r, p), - tout << mk_pp(n, m) << "\n"; - tout << mk_pp(r, m) << "\n"; - tout << mk_pp(p, m) << "\n";); - SASSERT(is_rewrite_proof(n, r, p)); - } - void reset_cache() { m_cache.reset(); } - void flush_cache() { m_cache.flush(); } - void get_cached(expr * n, expr * & r, proof * & p) const { m_cache.get(n, r, p); } - - void reinitialize() { m_cache.set_store_proofs(m.fine_grain_proofs()); } - - - void visit(expr * n, bool & visited) { - if (!is_cached(n)) { - m_todo.push_back(n); - visited = false; - } - } - -public: - base_simplifier(ast_manager & m): - m(m), - m_cache(m, m.fine_grain_proofs()) { - } - bool is_cached(expr * n) const { return m_cache.contains(n); } - ast_manager & get_manager() { return m; } - - bool is_rewrite_proof(expr* n, expr* r, proof* p) { - if (p && - !m.is_undef_proof(p) && - !(m.has_fact(p) && - (m.is_eq(m.get_fact(p)) || m.is_oeq(m.get_fact(p)) || m.is_iff(m.get_fact(p))) && - to_app(m.get_fact(p))->get_arg(0) == n && - to_app(m.get_fact(p))->get_arg(1) == r)) return false; - - return (!m.fine_grain_proofs() || p || (n == r)); - } -}; - -#endif /* BASE_SIMPLIFIER_H_ */ diff --git a/src/ast/simplifier/basic_simplifier_plugin.cpp b/src/ast/simplifier/basic_simplifier_plugin.cpp deleted file mode 100644 index 6c713bb10..000000000 --- a/src/ast/simplifier/basic_simplifier_plugin.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - basic_simplifier_plugin.cpp - -Abstract: - - Simplifier for the basic family. - -Author: - - Leonardo (leonardo) 2008-01-07 - ---*/ -#include"basic_simplifier_plugin.h" -#include"ast_ll_pp.h" -#include"bool_rewriter.h" - -basic_simplifier_plugin::basic_simplifier_plugin(ast_manager & m): - simplifier_plugin(symbol("basic"), m), - m_rewriter(alloc(bool_rewriter, m)) { -} - -basic_simplifier_plugin::~basic_simplifier_plugin() { - dealloc(m_rewriter); -} - -bool basic_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - SASSERT(f->get_family_id() == m_manager.get_basic_family_id()); - basic_op_kind k = static_cast(f->get_decl_kind()); - switch (k) { - case OP_FALSE: - case OP_TRUE: - return false; - case OP_EQ: - SASSERT(num_args == 2); - mk_eq(args[0], args[1], result); - return true; - case OP_DISTINCT: - mk_distinct(num_args, args, result); - return true; - case OP_ITE: - SASSERT(num_args == 3); - mk_ite(args[0], args[1], args[2], result); - return true; - case OP_AND: - mk_and(num_args, args, result); - return true; - case OP_OR: - mk_or(num_args, args, result); - return true; - case OP_IMPLIES: - mk_implies(args[0], args[1], result); - return true; - case OP_IFF: - mk_iff(args[0], args[1], result); - return true; - case OP_XOR: - mk_xor(args[0], args[1], result); - return true; - case OP_NOT: - SASSERT(num_args == 1); - mk_not(args[0], result); - return true; - default: - UNREACHABLE(); - return false; - } -} - -/** - \brief Return true if \c rhs is of the form (ite c t1 t2) and are_distinct(lhs, t1) and are_distinct(lhs, t2). -*/ -static bool is_lhs_diseq_rhs_ite_branches(ast_manager & m, expr * lhs, expr * rhs) { - return m.is_ite(rhs) && m.are_distinct(lhs, to_app(rhs)->get_arg(1)) && m.are_distinct(lhs, to_app(rhs)->get_arg(2)); -} - -/** - \brief Return true if \c rhs is of the form (ite c t1 t2) and lhs = t1 && are_distinct(lhs, t2) -*/ -static bool is_lhs_eq_rhs_ite_then(ast_manager & m, expr * lhs, expr * rhs) { - return m.is_ite(rhs) && lhs == to_app(rhs)->get_arg(1) && m.are_distinct(lhs, to_app(rhs)->get_arg(2)); -} - -/** - \brief Return true if \c rhs is of the form (ite c t1 t2) and are_distinct(lhs,t1) && lhs = t2 -*/ -static bool is_lhs_eq_rhs_ite_else(ast_manager & m, expr * lhs, expr * rhs) { - return m.is_ite(rhs) && lhs == to_app(rhs)->get_arg(2) && m.are_distinct(lhs, to_app(rhs)->get_arg(1)); -} - -void basic_simplifier_plugin::mk_eq(expr * lhs, expr * rhs, expr_ref & result) { - // (= t1 (ite C t2 t3)) --> false if are_distinct(t1, t2) && are_distinct(t1, t3) - if (is_lhs_diseq_rhs_ite_branches(m_manager, lhs, rhs) || is_lhs_diseq_rhs_ite_branches(m_manager, rhs, lhs)) { - result = m_manager.mk_false(); - } - // (= t1 (ite C t2 t3)) --> C if t1 = t2 && are_distinct(t1, t3) - else if (is_lhs_eq_rhs_ite_then(m_manager, lhs, rhs)) { - result = to_app(rhs)->get_arg(0); - } - // (= t1 (ite C t2 t3)) --> C if t1 = t2 && are_distinct(t1, t3) - else if (is_lhs_eq_rhs_ite_then(m_manager, rhs, lhs)) { - result = to_app(lhs)->get_arg(0); - } - // (= t1 (ite C t2 t3)) --> (not C) if t1 = t3 && are_distinct(t1, t2) - else if (is_lhs_eq_rhs_ite_else(m_manager, lhs, rhs)) { - mk_not(to_app(rhs)->get_arg(0), result); - } - // (= t1 (ite C t2 t3)) --> (not C) if t1 = t3 && are_distinct(t1, t2) - else if (is_lhs_eq_rhs_ite_else(m_manager, rhs, lhs)) { - mk_not(to_app(lhs)->get_arg(0), result); - } - else { - m_rewriter->mk_eq(lhs, rhs, result); - } -} - -bool basic_simplifier_plugin::eliminate_and() const { return m_rewriter->elim_and(); } -void basic_simplifier_plugin::set_eliminate_and(bool f) { m_rewriter->set_elim_and(f); } -void basic_simplifier_plugin::mk_iff(expr * lhs, expr * rhs, expr_ref & result) { mk_eq(lhs, rhs, result); } -void basic_simplifier_plugin::mk_xor(expr * lhs, expr * rhs, expr_ref & result) { m_rewriter->mk_xor(lhs, rhs, result); } -void basic_simplifier_plugin::mk_implies(expr * lhs, expr * rhs, expr_ref & result) { m_rewriter->mk_implies(lhs, rhs, result); } -void basic_simplifier_plugin::mk_ite(expr * c, expr * t, expr * e, expr_ref & result) { m_rewriter->mk_ite(c, t, e, result); } -void basic_simplifier_plugin::mk_and(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_and(num_args, args, result); } -void basic_simplifier_plugin::mk_or(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_or(num_args, args, result); } -void basic_simplifier_plugin::mk_and(expr * arg1, expr * arg2, expr_ref & result) { m_rewriter->mk_and(arg1, arg2, result); } -void basic_simplifier_plugin::mk_or(expr * arg1, expr * arg2, expr_ref & result) { m_rewriter->mk_or(arg1, arg2, result); } -void basic_simplifier_plugin::mk_and(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { m_rewriter->mk_and(arg1, arg2, arg3, result); } -void basic_simplifier_plugin::mk_or(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { m_rewriter->mk_or(arg1, arg2, arg3, result); } -void basic_simplifier_plugin::mk_nand(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_nand(num_args, args, result); } -void basic_simplifier_plugin::mk_nor(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_nor(num_args, args, result); } -void basic_simplifier_plugin::mk_nand(expr * arg1, expr * arg2, expr_ref & result) { m_rewriter->mk_nand(arg1, arg2, result); } -void basic_simplifier_plugin::mk_nor(expr * arg1, expr * arg2, expr_ref & result) { m_rewriter->mk_nor(arg1, arg2, result); } -void basic_simplifier_plugin::mk_distinct(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_distinct(num_args, args, result); } -void basic_simplifier_plugin::mk_not(expr * n, expr_ref & result) { m_rewriter->mk_not(n, result); } - -void basic_simplifier_plugin::enable_ac_support(bool flag) { - m_rewriter->set_flat(flag); -} diff --git a/src/ast/simplifier/basic_simplifier_plugin.h b/src/ast/simplifier/basic_simplifier_plugin.h deleted file mode 100644 index d39d6badb..000000000 --- a/src/ast/simplifier/basic_simplifier_plugin.h +++ /dev/null @@ -1,78 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - basic_simplifier_plugin.h - -Abstract: - - Simplifier for the basic family. - -Author: - - Leonardo (leonardo) 2008-01-07 - ---*/ -#ifndef BASIC_SIMPLIFIER_PLUGIN_H_ -#define BASIC_SIMPLIFIER_PLUGIN_H_ - -#include"simplifier_plugin.h" - -class bool_rewriter; - -/** - \brief Simplifier for the basic family. -*/ -class basic_simplifier_plugin : public simplifier_plugin { - bool_rewriter * m_rewriter; -public: - basic_simplifier_plugin(ast_manager & m); - virtual ~basic_simplifier_plugin(); - bool_rewriter & get_rewriter() { return *m_rewriter; } - bool eliminate_and() const; - void set_eliminate_and(bool f); - void mk_eq(expr * lhs, expr * rhs, expr_ref & result); - void mk_iff(expr * lhs, expr * rhs, expr_ref & result); - void mk_xor(expr * lhs, expr * rhs, expr_ref & result); - void mk_implies(expr * lhs, expr * rhs, expr_ref & result); - void mk_ite(expr * c, expr * t, expr * e, expr_ref & result); - void mk_and(unsigned num_args, expr * const * args, expr_ref & result); - void mk_or(unsigned num_args, expr * const * args, expr_ref & result); - void mk_and(expr * arg1, expr * arg2, expr_ref & result); - void mk_or(expr * arg1, expr * arg2, expr_ref & result); - void mk_and(expr * arg1, expr * arg2, expr * arg3, expr_ref & result); - void mk_or(expr * arg1, expr * arg2, expr * arg3, expr_ref & result); - void mk_nand(unsigned num_args, expr * const * args, expr_ref & result); - void mk_nor(unsigned num_args, expr * const * args, expr_ref & result); - void mk_nand(expr * arg1, expr * arg2, expr_ref & result); - void mk_nor(expr * arg1, expr * arg2, expr_ref & result); - void mk_distinct(unsigned num_args, expr * const * args, expr_ref & result); - void mk_not(expr * n, expr_ref & result); - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - virtual void enable_ac_support(bool flag); -}; - -/** - \brief Functor that compares expressions, but puts the expressions e and f(e) close to each other, where - f is in family m_fid, and has kind m_dkind; -*/ -struct expr_lt_proc { - family_id m_fid; - decl_kind m_dkind; - - expr_lt_proc(family_id fid = null_family_id, decl_kind k = null_decl_kind):m_fid(fid), m_dkind(k) {} - - unsigned get_id(expr * n) const { - if (m_fid != null_family_id && is_app_of(n, m_fid, m_dkind)) - return (to_app(n)->get_arg(0)->get_id() << 1) + 1; - else - return n->get_id() << 1; - } - - bool operator()(expr * n1, expr * n2) const { - return get_id(n1) < get_id(n2); - } -}; - -#endif /* BASIC_SIMPLIFIER_PLUGIN_H_ */ diff --git a/src/ast/simplifier/bv_elim.cpp b/src/ast/simplifier/bv_elim.cpp deleted file mode 100644 index 8dc2671ca..000000000 --- a/src/ast/simplifier/bv_elim.cpp +++ /dev/null @@ -1,119 +0,0 @@ - -/*++ -Copyright (c) 2015 Microsoft Corporation - ---*/ - -#include "bv_elim.h" -#include "bv_decl_plugin.h" -#include "var_subst.h" -#include - -void bv_elim::elim(quantifier* q, quantifier_ref& r) { - - svector names, _names; - sort_ref_buffer sorts(m_manager), _sorts(m_manager); - expr_ref_buffer pats(m_manager); - expr_ref_buffer no_pats(m_manager); - expr_ref_buffer subst_map(m_manager), _subst_map(m_manager); - var_subst subst(m_manager); - bv_util bv(m_manager); - expr_ref new_body(m_manager); - expr* old_body = q->get_expr(); - unsigned num_decls = q->get_num_decls(); - family_id bfid = m_manager.mk_family_id("bv"); - - // - // Traverse sequence of bound variables to eliminate - // bit-vecctor variables and replace them by - // Booleans. - // - unsigned var_idx = 0; - for (unsigned i = num_decls; i > 0; ) { - --i; - sort* s = q->get_decl_sort(i); - symbol nm = q->get_decl_name(i); - - if (bv.is_bv_sort(s)) { - // convert n-bit bit-vector variable into sequence of n-Booleans. - unsigned num_bits = bv.get_bv_size(s); - expr_ref_buffer args(m_manager); - expr_ref bv(m_manager); - for (unsigned j = 0; j < num_bits; ++j) { - std::ostringstream new_name; - new_name << nm.str(); - new_name << "_"; - new_name << j; - var* v = m_manager.mk_var(var_idx++, m_manager.mk_bool_sort()); - args.push_back(v); - _sorts.push_back(m_manager.mk_bool_sort()); - _names.push_back(symbol(new_name.str().c_str())); - } - bv = m_manager.mk_app(bfid, OP_MKBV, 0, 0, args.size(), args.c_ptr()); - _subst_map.push_back(bv.get()); - } - else { - _subst_map.push_back(m_manager.mk_var(var_idx++, s)); - _sorts.push_back(s); - _names.push_back(nm); - } - } - // - // reverse the vectors. - // - SASSERT(_names.size() == _sorts.size()); - for (unsigned i = _names.size(); i > 0; ) { - --i; - names.push_back(_names[i]); - sorts.push_back(_sorts[i]); - } - for (unsigned i = _subst_map.size(); i > 0; ) { - --i; - subst_map.push_back(_subst_map[i]); - } - - expr* const* sub = subst_map.c_ptr(); - unsigned sub_size = subst_map.size(); - - subst(old_body, sub_size, sub, new_body); - - for (unsigned j = 0; j < q->get_num_patterns(); j++) { - expr_ref pat(m_manager); - subst(q->get_pattern(j), sub_size, sub, pat); - pats.push_back(pat); - } - for (unsigned j = 0; j < q->get_num_no_patterns(); j++) { - expr_ref nopat(m_manager); - subst(q->get_no_pattern(j), sub_size, sub, nopat); - no_pats.push_back(nopat); - } - - r = m_manager.mk_quantifier(true, - names.size(), - sorts.c_ptr(), - names.c_ptr(), - new_body.get(), - q->get_weight(), - q->get_qid(), - q->get_skid(), - pats.size(), pats.c_ptr(), - no_pats.size(), no_pats.c_ptr()); -} - -bool bv_elim_star::visit_quantifier(quantifier* q) { - // behave like destructive resolution, do not recurse. - return true; -} - -void bv_elim_star::reduce1_quantifier(quantifier* q) { - quantifier_ref r(m); - proof_ref pr(m); - m_bv_elim.elim(q, r); - if (m.fine_grain_proofs()) { - pr = m.mk_rewrite(q, r.get()); - } - else { - pr = 0; - } - cache_result(q, r, pr); -} diff --git a/src/ast/simplifier/bv_elim.h b/src/ast/simplifier/bv_elim.h deleted file mode 100644 index 3bebcfef1..000000000 --- a/src/ast/simplifier/bv_elim.h +++ /dev/null @@ -1,45 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - bv_elim.h - -Abstract: - - Eliminate bit-vectors variables from clauses, by - replacing them by bound Boolean variables. - -Author: - - Nikolaj Bjorner (nbjorner) 2008-12-16. - -Revision History: - ---*/ -#ifndef BV_ELIM_H_ -#define BV_ELIM_H_ - -#include "ast.h" -#include "simplifier.h" - -class bv_elim { - ast_manager& m_manager; -public: - bv_elim(ast_manager& m) : m_manager(m) {}; - - void elim(quantifier* q, quantifier_ref& r); -}; - -class bv_elim_star : public simplifier { -protected: - bv_elim m_bv_elim; - virtual bool visit_quantifier(quantifier* q); - virtual void reduce1_quantifier(quantifier* q); -public: - bv_elim_star(ast_manager& m) : simplifier(m), m_bv_elim(m) { enable_ac_support(false); } - virtual ~bv_elim_star() {} -}; - -#endif /* BV_ELIM_H_ */ - diff --git a/src/ast/simplifier/bv_simplifier_params.cpp b/src/ast/simplifier/bv_simplifier_params.cpp deleted file mode 100644 index 1ed263aa6..000000000 --- a/src/ast/simplifier/bv_simplifier_params.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - bv_simplifier_params.cpp - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2012-12-02. - -Revision History: - ---*/ -#include"bv_simplifier_params.h" -#include"bv_simplifier_params_helper.hpp" -#include"bv_rewriter_params.hpp" - -void bv_simplifier_params::updt_params(params_ref const & _p) { - bv_simplifier_params_helper p(_p); - bv_rewriter_params rp(_p); - m_hi_div0 = rp.hi_div0(); - m_bv2int_distribute = p.bv_bv2int_distribute(); - -} - -#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; - -void bv_simplifier_params::display(std::ostream & out) const { - DISPLAY_PARAM(m_hi_div0); - DISPLAY_PARAM(m_bv2int_distribute); -} \ No newline at end of file diff --git a/src/ast/simplifier/bv_simplifier_params.h b/src/ast/simplifier/bv_simplifier_params.h deleted file mode 100644 index dafa99065..000000000 --- a/src/ast/simplifier/bv_simplifier_params.h +++ /dev/null @@ -1,38 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - bv_simplifier_params.h - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2008-10-10. - -Revision History: - ---*/ -#ifndef BV_SIMPLIFIER_PARAMS_H_ -#define BV_SIMPLIFIER_PARAMS_H_ - -#include"params.h" - -struct bv_simplifier_params { - bool m_hi_div0; //!< if true, uses the hardware interpretation for div0, mod0, ... if false, div0, mod0, ... are considered uninterpreted. - bool m_bv2int_distribute; //!< if true allows downward propagation of bv2int. - - bv_simplifier_params(params_ref const & p = params_ref()) { - updt_params(p); - } - - void updt_params(params_ref const & _p); - - void display(std::ostream & out) const; -}; - -#endif /* BV_SIMPLIFIER_PARAMS_H_ */ - diff --git a/src/ast/simplifier/bv_simplifier_params_helper.pyg b/src/ast/simplifier/bv_simplifier_params_helper.pyg deleted file mode 100644 index 6bcf83207..000000000 --- a/src/ast/simplifier/bv_simplifier_params_helper.pyg +++ /dev/null @@ -1,4 +0,0 @@ -def_module_params(class_name='bv_simplifier_params_helper', - module_name="old_simplify", # Parameters will be in the old_simplify module - export=True, - params=(('bv.bv2int_distribute', BOOL, True, 'if true, then int2bv is distributed over arithmetical operators'),)) diff --git a/src/ast/simplifier/bv_simplifier_plugin.cpp b/src/ast/simplifier/bv_simplifier_plugin.cpp deleted file mode 100644 index a72e7e117..000000000 --- a/src/ast/simplifier/bv_simplifier_plugin.cpp +++ /dev/null @@ -1,2261 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - bv_simplifier_plugin.cpp - -Abstract: - - Simplifier for the bv family. - -Author: - - Leonardo (leonardo) 2008-01-08 - Nikolaj Bjorner (nbjorner) 2008-01-05 - ---*/ -#include"bv_simplifier_plugin.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" -#include"arith_decl_plugin.h" -#include"obj_hashtable.h" -#include"ast_util.h" - -bv_simplifier_plugin::~bv_simplifier_plugin() { - flush_caches(); -} - -bv_simplifier_plugin::bv_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, bv_simplifier_params & p): - poly_simplifier_plugin(symbol("bv"), m, OP_BADD, OP_BMUL, OP_BNEG, OP_BSUB, OP_BV_NUM), - m_manager(m), - m_util(m), - m_arith(m), - m_bsimp(b), - m_params(p), - m_zeros(m) { -} - -rational bv_simplifier_plugin::norm(const numeral & n) { - unsigned bv_size = get_bv_size(m_curr_sort); - return norm(n, bv_size, false); -} - - -bool bv_simplifier_plugin::is_numeral(expr * n, rational & val) const { - unsigned bv_size; - return m_util.is_numeral(n, val, bv_size); -} - -expr * bv_simplifier_plugin::get_zero(sort * s) const { - bv_simplifier_plugin * _this = const_cast(this); - unsigned bv_size = _this->get_bv_size(s); - if (bv_size >= m_zeros.size()) - _this->m_zeros.resize(bv_size+1); - if (m_zeros.get(bv_size) == 0) - _this->m_zeros.set(bv_size, _this->m_util.mk_numeral(rational(0), s)); - return m_zeros.get(bv_size); -} - -bool bv_simplifier_plugin::are_numerals(unsigned num_args, expr * const* args, unsigned& bv_size) { - numeral r; - if (num_args == 0) { - return false; - } - for (unsigned i = 0; i < num_args; ++i) { - if (!m_util.is_numeral(args[i], r, bv_size)) { - return false; - } - } - return true; -} - -app * bv_simplifier_plugin::mk_numeral(numeral const & n) { - unsigned bv_size = get_bv_size(m_curr_sort); - return mk_numeral(n, bv_size); -} - -app * bv_simplifier_plugin::mk_numeral(numeral const& n, unsigned bv_size) { - numeral r = mod(n, rational::power_of_two(bv_size)); - SASSERT(!r.is_neg()); - SASSERT(r < rational::power_of_two(bv_size)); - return m_util.mk_numeral(r, bv_size); -} - -bool bv_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - - SASSERT(f->get_family_id() == m_fid); - - bv_op_kind k = static_cast(f->get_decl_kind()); - switch (k) { - case OP_BV_NUM: SASSERT(num_args == 0); result = mk_numeral(f->get_parameter(0).get_rational(), f->get_parameter(1).get_int()); break; - case OP_BIT0: SASSERT(num_args == 0); result = mk_numeral(0, 1); break; - case OP_BIT1: SASSERT(num_args == 0); result = mk_numeral(1, 1); break; - case OP_BADD: SASSERT(num_args > 0); - mk_add(num_args, args, result); - TRACE("bv_add_bug", - for (unsigned i = 0; i < num_args; i++) tout << mk_bounded_pp(args[i], m_manager, 10) << "\n"; - tout << mk_bounded_pp(result, m_manager, 10) << "\n";); - mk_add_concat(result); - break; - case OP_BSUB: SASSERT(num_args > 0); mk_sub(num_args, args, result); break; - case OP_BNEG: SASSERT(num_args == 1); mk_uminus(args[0], result); break; - case OP_BMUL: SASSERT(num_args > 0); mk_mul(num_args, args, result); break; - case OP_ULEQ: if (m_presimp) return false; SASSERT(num_args == 2); mk_ule(args[0], args[1], result); break; - case OP_UGEQ: if (m_presimp) return false; SASSERT(num_args == 2); mk_ule(args[1], args[0], result); break; - case OP_ULT: if (m_presimp) return false; SASSERT(num_args == 2); mk_ult(args[0], args[1], result); break; - case OP_UGT: if (m_presimp) return false; SASSERT(num_args == 2); mk_ult(args[1], args[0], result); break; - case OP_SLEQ: if (m_presimp) return false; SASSERT(num_args == 2); mk_sle(args[0], args[1], result); break; - case OP_SGEQ: if (m_presimp) return false; SASSERT(num_args == 2); mk_sle(args[1], args[0], result); break; - case OP_SLT: if (m_presimp) return false; SASSERT(num_args == 2); mk_slt(args[0], args[1], result); break; - case OP_SGT: if (m_presimp) return false; SASSERT(num_args == 2); mk_slt(args[1], args[0], result); break; - case OP_BAND: SASSERT(num_args > 0); mk_bv_and(num_args, args, result); break; - case OP_BOR: SASSERT(num_args > 0); mk_bv_or(num_args, args, result); break; - case OP_BNOT: SASSERT(num_args == 1); mk_bv_not(args[0], result); break; - case OP_BXOR: SASSERT(num_args > 0); mk_bv_xor(num_args, args, result); break; - case OP_CONCAT: SASSERT(num_args > 0); mk_concat(num_args, args, result); break; - case OP_ZERO_EXT: - SASSERT(num_args == 1); SASSERT(f->get_num_parameters() == 1); - mk_zeroext(f->get_parameter(0).get_int(), args[0], result); - break; - case OP_EXTRACT: - SASSERT(num_args == 1); SASSERT(f->get_num_parameters() == 2); - mk_extract(f->get_parameter(0).get_int(), f->get_parameter(1).get_int(), args[0], result); - break; - case OP_REPEAT: - SASSERT(num_args == 1); SASSERT(f->get_num_parameters() == 1); - mk_repeat(f->get_parameter(0).get_int(), args[0], result); - break; - case OP_BUREM: - SASSERT(num_args == 2); - mk_bv_urem(args[0], args[1], result); - break; - case OP_SIGN_EXT: - SASSERT(num_args == 1); SASSERT(f->get_num_parameters() == 1); - mk_sign_extend(f->get_parameter(0).get_int(), args[0], result); - break; - case OP_BSHL: SASSERT(num_args == 2); mk_bv_shl(args[0], args[1], result); break; - case OP_BLSHR: SASSERT(num_args == 2); mk_bv_lshr(args[0], args[1], result); break; - case OP_INT2BV: SASSERT(num_args == 1); mk_int2bv(args[0], f->get_range(), result); break; - case OP_BV2INT: SASSERT(num_args == 1); mk_bv2int(args[0], f->get_range(), result); break; - case OP_BSDIV: SASSERT(num_args == 2); mk_bv_sdiv(args[0], args[1], result); break; - case OP_BUDIV: SASSERT(num_args == 2); mk_bv_udiv(args[0], args[1], result); break; - case OP_BSREM: SASSERT(num_args == 2); mk_bv_srem(args[0], args[1], result); break; - case OP_BSMOD: SASSERT(num_args == 2); mk_bv_smod(args[0], args[1], result); break; - case OP_BNAND: SASSERT(num_args > 0); mk_bv_nand(num_args, args, result); break; - case OP_BNOR: SASSERT(num_args > 0); mk_bv_nor(num_args, args, result); break; - case OP_BXNOR: SASSERT(num_args > 0); mk_bv_xnor(num_args, args, result); break; - case OP_ROTATE_LEFT: SASSERT(num_args == 1); mk_bv_rotate_left(f, args[0], result); break; - case OP_ROTATE_RIGHT: SASSERT(num_args == 1); mk_bv_rotate_right(f, args[0], result); break; - case OP_EXT_ROTATE_LEFT: SASSERT(num_args == 2); mk_bv_ext_rotate_left(args[0], args[1], result); break; - case OP_EXT_ROTATE_RIGHT: SASSERT(num_args == 2); mk_bv_ext_rotate_right(args[0], args[1], result); break; - case OP_BREDOR: SASSERT(num_args == 1); mk_bv_redor(args[0], result); break; - case OP_BREDAND: SASSERT(num_args == 1); mk_bv_redand(args[0], result); break; - case OP_BCOMP: SASSERT(num_args == 2); mk_bv_comp(args[0], args[1], result); break; - case OP_BASHR: SASSERT(num_args == 2); mk_bv_ashr(args[0], args[1], result); break; - case OP_BSDIV_I: SASSERT(num_args == 2); mk_bv_sdiv_i(args[0], args[1], result); break; - case OP_BUDIV_I: SASSERT(num_args == 2); mk_bv_udiv_i(args[0], args[1], result); break; - case OP_BSREM_I: SASSERT(num_args == 2); mk_bv_srem_i(args[0], args[1], result); break; - case OP_BUREM_I: SASSERT(num_args == 2); mk_bv_urem_i(args[0], args[1], result); break; - case OP_BSMOD_I: SASSERT(num_args == 2); mk_bv_smod_i(args[0], args[1], result); break; - case OP_BSDIV0: - case OP_BUDIV0: - case OP_BSREM0: - case OP_BUREM0: - case OP_BSMOD0: - case OP_BIT2BOOL: - case OP_CARRY: - case OP_XOR3: - case OP_MKBV: - case OP_BUMUL_NO_OVFL: - case OP_BSMUL_NO_OVFL: - case OP_BSMUL_NO_UDFL: - result = m_manager.mk_app(f, num_args, args); - break; - default: - UNREACHABLE(); - break; - } - SASSERT(result.get()); - - TRACE("bv_simplifier", - tout << mk_pp(f, m_manager) << "\n"; - for (unsigned i = 0; i < num_args; ++i) { - tout << mk_pp(args[i], m_manager) << " "; - } - tout << "\n"; - tout << mk_pp(result.get(), m_manager) << "\n"; - ); - - return true; -} - -bool bv_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { - set_reduce_invoked(); - - if (m_presimp) - return false; - expr_ref tmp(m_manager); - tmp = m_manager.mk_eq(lhs,rhs); - mk_bv_eq(lhs, rhs, result); - return result.get() != tmp.get(); -} - -bool bv_simplifier_plugin::reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - - return false; -} - -void bv_simplifier_plugin::flush_caches() { - TRACE("extract_cache", tout << "flushing extract cache...\n";); - extract_cache::iterator it = m_extract_cache.begin(); - extract_cache::iterator end = m_extract_cache.end(); - for (; it != end; ++it) { - extract_entry & e = (*it).m_key; - m_manager.dec_ref(e.m_arg); - m_manager.dec_ref((*it).m_value); - } - m_extract_cache.reset(); -} - - -inline uint64 bv_simplifier_plugin::to_uint64(const numeral & n, unsigned bv_size) { - SASSERT(bv_size <= 64); - numeral tmp = n; - if (tmp.is_neg()) { - tmp = mod(tmp, rational::power_of_two(bv_size)); - } - SASSERT(tmp.is_nonneg()); - SASSERT(tmp.is_uint64()); - return tmp.get_uint64(); -} - -#define MK_BV_OP(_oper_,_binop_) \ -rational bv_simplifier_plugin::mk_bv_ ## _oper_(numeral const& a0, numeral const& b0, unsigned sz) { \ - rational r(0), a(a0), b(b0); \ - numeral p64 = rational::power_of_two(64); \ - numeral mul(1); \ - while (sz > 0) { \ - numeral a1 = a % p64; \ - numeral b1 = b % p64; \ - uint64 u = a1.get_uint64() _binop_ b1.get_uint64(); \ - if (sz < 64) { \ - uint64 mask = shift_left(1ull,(uint64)sz) - 1ull; \ - u = mask & u; \ - } \ - r += mul*rational(u,rational::ui64()); \ - mul *= p64; \ - a = div(a, p64); \ - b = div(b, p64); \ - sz -= (sz<64)?sz:64; \ - } \ - return r; \ -} - -MK_BV_OP(and,&) -MK_BV_OP(or,|) -MK_BV_OP(xor,^) - -rational bv_simplifier_plugin::mk_bv_not(numeral const& a0, unsigned sz) { - rational r(0), a(a0), mul(1); - numeral p64 = rational::power_of_two(64); - while (sz > 0) { - numeral a1 = a % p64; - uint64 u = ~a1.get_uint64(); - if (sz < 64) { - uint64 mask = shift_left(1ull,(uint64)sz) - 1ull; - u = mask & u; - } - r += mul*rational(u,rational::ui64()); - mul *= p64; - a = div(a, p64); - sz -= (64get_num_args() == 2) { - // - // c <=_u (concat 0 a) <=> c[u:l] = 0 && c[l-1:0] <=_u a - // - app* app = to_app(arg2); - expr * arg2_1 = app->get_arg(0); - expr * arg2_2 = app->get_arg(1); - if (m_util.is_zero(arg2_1)) { - unsigned sz1 = get_bv_size(arg2_1); - unsigned sz2 = get_bv_size(arg2_2); - - expr_ref tmp1(m_manager); - expr_ref tmp2(m_manager); - mk_extract(sz2 + sz1 - 1, sz2, arg1, tmp1); - mk_extract(sz2 - 1, 0, arg1, tmp2); - - expr_ref eq(m_manager); - expr_ref zero(m_manager); - zero = mk_bv0(sz1); - mk_bv_eq(tmp1.get(), zero, eq); - - expr_ref ineq(m_manager); - ineq = m_util.mk_ule(tmp2.get(), arg2_2); - - m_bsimp.mk_and(eq.get(), ineq.get(), result); - return; - } - } - - // - // TODO: - // Others: - // - // k <=_s (concat 0 a) <=> (k[u:l] = 0 && k[l-1:0] <=_u a) || k[u:u] = bv1 - // - // (concat 0 a) <=_s k <=> k[u:u] = bv0 && (k[u:l] != 0 || a <=_u k[l-1:0]) - // - // (concat 0 a) <=_u k <=> k[u:l] != 0 || a <=_u k[l-1:0] - // - - result = m_manager.mk_app(m_fid, k, arg1, arg2); -} - -void bv_simplifier_plugin::mk_extract(unsigned high, unsigned low, expr* arg, expr_ref& result) { - - unsigned arg_sz = get_bv_size(arg); - unsigned sz = high - low + 1; - TRACE("bv_simplifier_plugin", tout << "mk_extract [" << high << ":" << low << "]\n"; - tout << "arg_sz: " << arg_sz << " sz: " << sz << "\n"; - tout << "arg:\n"; - ast_ll_pp(tout, m_manager, arg);); - - if (arg_sz == sz) { - result = arg; - } - else { - mk_extract_core(high, low, arg, result); - } - if (m_extract_cache.size() > (1 << 12)) { - flush_caches(); - } - - TRACE("bv_simplifier_plugin", tout << "mk_extract [" << high << ":" << low << "]\n"; - tout << "arg_sz: " << arg_sz << " sz: " << sz << "\n"; - tout << "arg:\n"; - ast_ll_pp(tout, m_manager, arg); - tout << "=====================>\n"; - ast_ll_pp(tout, m_manager, result.get());); -} - - -void bv_simplifier_plugin::cache_extract(unsigned h, unsigned l, expr * arg, expr * result) { - m_manager.inc_ref(arg); - m_manager.inc_ref(result); - m_extract_cache.insert(extract_entry(h, l, arg), result); -} - -expr* bv_simplifier_plugin::get_cached_extract(unsigned h, unsigned l, expr * arg) { - expr * result = 0; - if (m_extract_cache.find(extract_entry(h, l, arg), result)) { - return result; - } - return 0; -} - - -void bv_simplifier_plugin::mk_extract_core(unsigned high, unsigned low, expr * arg, expr_ref& result) { - - if (!lookup_mk_extract(high, low, arg, result)) { - while (!m_extract_args.empty()) { - unsigned low2 = m_lows.back(); - unsigned high2 = m_highs.back(); - expr* arg2 = m_extract_args.back(); - if (try_mk_extract(high2, low2, arg2, result)) { - if (!m_extract_cache.contains(extract_entry(high2, low2, arg2))) { - cache_extract(high2, low2, arg2, result.get()); - } - m_lows.pop_back(); - m_highs.pop_back(); - m_extract_args.pop_back(); - } - } - if (!lookup_mk_extract(high, low, arg, result)) { - UNREACHABLE(); - } - } -} - - -bool bv_simplifier_plugin::lookup_mk_extract(unsigned high, unsigned low, expr * arg, expr_ref& result) { - expr* cached_result = get_cached_extract(high, low, arg); - if (cached_result) { - result = cached_result; - return true; - } - - m_extract_args.push_back(arg); - m_lows.push_back(low); - m_highs.push_back(high); - return false; -} - - -bool bv_simplifier_plugin::try_mk_extract(unsigned high, unsigned low, expr * arg, expr_ref& result) { - - SASSERT(low <= high); - unsigned arg_sz = get_bv_size(arg); - unsigned sz = high - low + 1; - numeral r; - unsigned num_bits; - - if (arg_sz == sz) { - result = arg; - return true; - } - - expr* cached_result = get_cached_extract(high, low, arg); - if (cached_result) { - result = cached_result; - return true; - } - - if (!is_app(arg)) { - result = m_util.mk_extract(high, low, arg); - return true; - } - app* a = to_app(arg); - - if (m_util.is_numeral(a, r, num_bits)) { - if (r.is_neg()) { - r = mod(r, rational::power_of_two(sz)); - } - SASSERT(r.is_nonneg()); - if (r.is_uint64()) { - uint64 u = r.get_uint64(); - uint64 e = shift_right(u, low) & (shift_left(1ull, sz) - 1ull); - TRACE("mk_extract_bug", tout << u << "[" << high << ":" << low << "] " << e << " (u >> low): " << shift_right(u, low) << " (1ull << sz): " - << shift_left(1ull, sz) << " ((1ull << sz) - 1ull)" << (shift_left(1ull, sz) - 1ull) << "\n";); - result = mk_numeral(numeral(e, numeral::ui64()), sz); - return true; - } - result = mk_numeral(div(r, rational::power_of_two(low)), sz); - return true; - } - // (extract[high:low] (extract[high2:low2] x)) == (extract[high+low2 : low+low2] x) - else if (is_app_of(a, m_fid, OP_EXTRACT)) { - expr * x = a->get_arg(0); - unsigned low2 = a->get_decl()->get_parameter(1).get_int(); - return lookup_mk_extract(high + low2, low + low2, x, result); - } - // - // (extract[hi:lo] (bvXshr A c:bv[n])) -> (extract[hi+c:lo+c] A) - // if c < n, c <= lo <= hi < n - c - // - else if ((is_app_of(a, m_fid, OP_BASHR) || is_app_of(a, m_fid, OP_BLSHR)) && - is_numeral(a->get_arg(1), r) && r.is_unsigned()) { - unsigned c = r.get_unsigned(); - unsigned bv_size = get_bv_size(a); - if (c < bv_size && c <= low && high < bv_size - c) { - return lookup_mk_extract(high+c, low+c, a->get_arg(0), result); - } - } - // (concat a_0 ... a_{n-1}) - // Remark: the least significant bits are stored in a_{n-1} - else if (is_app_of(a, m_fid, OP_CONCAT)) { - expr_ref_buffer new_args(m_manager); - unsigned i = a->get_num_args(); - // look for first argument - while (i > 0) { - --i; - expr * a_i = a->get_arg(i); - unsigned a_sz = get_bv_size(a_i); - TRACE("extract_bug", tout << "FIRST a_sz: " << a_sz << " high: " << high << " low: " << low << "\n" << - mk_pp(a_i, m_manager) << "\n";); - if (a_sz <= low) { - low -= a_sz; - high -= a_sz; - } - else { - // found first argument - if (a_sz <= high) { - expr_ref new_arg(m_manager); - if (!lookup_mk_extract(a_sz - 1, low, a_i, new_arg)) { - return false; - } - new_args.push_back(new_arg.get()); - unsigned num_consumed_bytes = a_sz - low; - // I have to apply extract[sz - num_consumed_bytes - 1, 0] on the rest of concat - high = (sz - num_consumed_bytes - 1); - break; - } - else { - return lookup_mk_extract(high, low, a_i, result); - } - } - } - TRACE("extract_bug", tout << " high: " << high << " low: " << low << "\n";); - - // look for remaining arguments - while (i > 0) { - --i; - expr * a_i = a->get_arg(i); - unsigned a_sz = get_bv_size(a_i); - TRACE("extract_bug", tout << "SECOND a_sz: " << a_sz << " high: " << high << " " << - mk_pp( a_i, m_manager) << "\n";); - if (a_sz <= high) { - high -= a_sz; - new_args.push_back(a_i); - } - else { - // found last argument - expr_ref new_arg(m_manager); - if (!lookup_mk_extract(high, 0, a_i, new_arg)) { - return false; - } - new_args.push_back(new_arg.get()); - // The arguments in new_args are in reverse order. - ptr_buffer rev_new_args; - unsigned i = new_args.size(); - while (i > 0) { - --i; - rev_new_args.push_back(new_args[i]); - } - mk_concat(rev_new_args.size(), rev_new_args.c_ptr(), result); - return true; - } - } - UNREACHABLE(); - } - else if (is_app_of(a, m_fid, OP_SIGN_EXT)) { - SASSERT(a->get_num_args() == 1); - unsigned bv_size = get_bv_size(a->get_arg(0)); - if (high < bv_size) { - return lookup_mk_extract(high, low, a->get_arg(0), result); - } - } - else if (is_app_of(a, m_fid, OP_BAND) || - is_app_of(a, m_fid, OP_BOR) || - is_app_of(a, m_fid, OP_BXOR) || - is_app_of(a, m_fid, OP_BNOR) || - is_app_of(a, m_fid, OP_BNAND) || - is_app_of(a, m_fid, OP_BNOT) || - (low == 0 && is_app_of(a, m_fid, OP_BADD)) || - (low == 0 && is_app_of(a, m_fid, OP_BMUL)) || - (low == 0 && is_app_of(a, m_fid, OP_BSUB))) { - expr_ref_buffer new_args(m_manager); - bool all_found = true; - for (unsigned i = 0; i < a->get_num_args(); ++i) { - expr_ref new_arg(m_manager); - if (!lookup_mk_extract(high, low, a->get_arg(i), new_arg)) { - all_found = false; - } - new_args.push_back(new_arg.get()); - } - if (!all_found) { - return false; - } - // We should not use mk_app because it does not guarantee that the result would be in simplified form. - // result = m_manager.mk_app(m_fid, a->get_decl_kind(), new_args.size(), new_args.c_ptr()); - if (is_app_of(a, m_fid, OP_BAND)) - mk_bv_and(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BOR)) - mk_bv_or(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BXOR)) - mk_bv_xor(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BNOR)) - mk_bv_nor(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BNAND)) - mk_bv_nand(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BNOT)) { - SASSERT(new_args.size() == 1); - mk_bv_not(new_args[0], result); - } - else if (is_app_of(a, m_fid, OP_BADD)) - mk_add(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BMUL)) - mk_mul(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BSUB)) - mk_sub(new_args.size(), new_args.c_ptr(), result); - else { - UNREACHABLE(); - } - return true; - } - else if (m_manager.is_ite(a)) { - expr_ref then_b(m_manager), else_b(m_manager); - bool ok = lookup_mk_extract(high, low, a->get_arg(1), then_b); - ok = lookup_mk_extract(high, low, a->get_arg(2), else_b) && ok; - if (ok) { - m_bsimp.mk_ite(a->get_arg(0), then_b.get(), else_b.get(), result); - } - return ok; - } - result = m_util.mk_extract(high, low, arg); - return true; -} - -/** - \brief Let f be the operator fid:k. Then, this function - store in result the flat args of n. If n is not an f application, then store n in result. - - Example: if n is (f (f a b) (f c (f d e))), then a b c d e are stored in result. -*/ -template -void get_assoc_args(family_id fid, decl_kind k, expr * n, T & result) { - ptr_buffer todo; - todo.push_back(n); - while (!todo.empty()) { - expr * n = todo.back(); - todo.pop_back(); - if (is_app_of(n, fid, k)) { - app * app = to_app(n); - unsigned i = app->get_num_args(); - while (i > 0) { - --i; - todo.push_back(app->get_arg(i)); - } - } - else { - result.push_back(n); - } - } -} - -/** - \brief Similar to get_assoc_args, but the arguments are stored in reverse - other in result. -*/ -template -void get_inv_assoc_args(family_id fid, decl_kind k, expr * n, T & result) { - ptr_buffer todo; - todo.push_back(n); - while (!todo.empty()) { - expr * n = todo.back(); - todo.pop_back(); - if (is_app_of(n, fid, k)) { - app * app = to_app(n); - unsigned num = app->get_num_args(); - for (unsigned i = 0; i < num; i++) - todo.push_back(app->get_arg(i)); - } - else { - result.push_back(n); - } - } -} - -void bv_simplifier_plugin::mk_bv_eq(expr* a1, expr* a2, expr_ref& result) { - - rational val1; - rational val2; - bool is_num1 = is_numeral(a1, val1); - bool is_num2 = is_numeral(a2, val2); - if (is_num1 && is_num2 && val1 != val2) { - result = m_manager.mk_false(); - return; - } - - if (!m_util.is_concat(a1) && !is_num1) { - mk_eq_core(a1, a2, result); - return; - } - if (!m_util.is_concat(a2) && !is_num2) { - mk_eq_core(a1, a2, result); - return; - } - - ptr_buffer args1, args2; - get_inv_assoc_args(m_fid, OP_CONCAT, a1, args1); - get_inv_assoc_args(m_fid, OP_CONCAT, a2, args2); - TRACE("mk_bv_eq_concat", tout << mk_ll_pp(a1, m_manager) << "\n" << mk_ll_pp(a2, m_manager) << "\n"; - tout << "args1:\n"; - for (unsigned i = 0; i < args1.size(); i++) tout << mk_ll_pp(args1[i], m_manager) << "\n"; - tout << "args2:\n"; - for (unsigned i = 0; i < args2.size(); i++) tout << mk_ll_pp(args2[i], m_manager) << "\n";); - - - - expr_ref lhs(m_manager), rhs(m_manager), eq(m_manager); - expr_ref_buffer eqs(m_manager); - unsigned low1 = 0, low2 = 0; - ptr_buffer::iterator it1 = args1.begin(); - ptr_buffer::iterator end1 = args1.end(); - ptr_buffer::iterator it2 = args2.begin(); - ptr_buffer::iterator end2 = args2.end(); - - while (it1 != end1 && it2 != end2) { - SASSERT(it1 != end1); - SASSERT(it2 != end2); - expr * arg1 = *it1; - expr * arg2 = *it2; - TRACE("expr_bv_util", tout << "low1: " << low1 << " low2: " << low2 << "\n"; - tout << mk_pp(arg1, m_manager) << "\n"; - tout << mk_pp(arg2, m_manager) << "\n";); - unsigned sz1 = get_bv_size(arg1); - unsigned sz2 = get_bv_size(arg2); - SASSERT(low1 < sz1 && low2 < sz2); - unsigned rsz1 = sz1 - low1; - unsigned rsz2 = sz2 - low2; - TRACE("expr_bv_util", tout << "rsz1: " << rsz1 << " rsz2: " << rsz2 << "\n"; - tout << mk_pp(arg1, m_manager) << "\n"; - tout << mk_pp(arg2, m_manager) << "\n";); - - if (rsz1 == rsz2) { - mk_extract(sz1 - 1, low1, arg1, lhs); - mk_extract(sz2 - 1, low2, arg2, rhs); - low1 = 0; - low2 = 0; - ++it1; - ++it2; - } - else if (rsz1 < rsz2) { - mk_extract(sz1 - 1, low1, arg1, lhs); - mk_extract(rsz1 + low2 - 1, low2, arg2, rhs); - low1 = 0; - low2 += rsz1; - ++it1; - } - else { - mk_extract(rsz2 + low1 - 1, low1, arg1, lhs); - mk_extract(sz2 - 1, low2, arg2, rhs); - low1 += rsz2; - low2 = 0; - ++it2; - } - mk_eq_core(lhs.get(), rhs.get(), eq); - eqs.push_back(eq.get()); - } - m_bsimp.mk_and(eqs.size(), eqs.c_ptr(), result); -} - -void bv_simplifier_plugin::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) { - TRACE("mk_eq_core", ast_ll_pp(tout, m_manager, arg1 ); ast_ll_pp(tout, m_manager, arg2);); - if (arg1 == arg2) { - result = m_manager.mk_true(); - return; - } - if ((m_util.is_bv_and(arg1) && m_util.is_allone(arg2)) || (m_util.is_bv_or(arg1) && m_util.is_zero(arg2))) { - mk_args_eq_numeral(to_app(arg1), arg2, result); - return; - } - if ((m_util.is_bv_and(arg2) && m_util.is_allone(arg1)) || (m_util.is_bv_or(arg2) && m_util.is_zero(arg1))) { - mk_args_eq_numeral(to_app(arg2), arg1, result); - return; - } - -#if 1 - rational r; - unsigned num_bits = 0; - if (m_util.is_numeral(arg2, r, num_bits)) { - std::swap(arg1, arg2); - } - - if (m_util.is_numeral(arg1, r, num_bits) && - (m_util.is_bv_and(arg2) || m_util.is_bv_or(arg2) || m_util.is_bv_not(arg2))) { - rational two(2); - expr_ref tmp(m_manager); - expr_ref_vector tmps(m_manager); - for (unsigned i = 0; i < num_bits; ++i) { - bool is_neg = (r % two).is_zero(); - bit2bool_simplify(i, arg2, tmp); - if (is_neg) { - expr_ref tmp2(m_manager); - m_bsimp.mk_not(tmp, tmp2); - tmp = tmp2; - } - tmps.push_back(tmp); - r = div(r, two); - } - m_bsimp.mk_and(tmps.size(), tmps.c_ptr(), result); - TRACE("mk_eq_bb", - tout << mk_pp(arg1, m_manager) << "\n"; - tout << mk_pp(arg2, m_manager) << "\n"; - tout << mk_pp(result, m_manager) << "\n";); - return; - } -#endif - - if (!m_util.is_bv_add(arg1) && !m_util.is_bv_add(arg2) && - !m_util.is_bv_mul(arg1) && !m_util.is_bv_mul(arg2)) { - m_bsimp.mk_eq(arg1, arg2, result); - return; - } - - set_curr_sort(arg1); - expr_ref_vector args1(m_manager); - expr_ref_vector args2(m_manager); - get_assoc_args(m_fid, OP_BADD, arg1, args1); - get_assoc_args(m_fid, OP_BADD, arg2, args2); - TRACE("mk_eq_core", - tout << mk_pp(arg1, m_manager) << "\n" << mk_pp(arg2, m_manager) << "\n"; - tout << args1.size() << " " << args2.size() << "\n";); - - unsigned idx2 = 0; - while (idx2 < args2.size()) { - expr * m2 = args2.get(idx2); - unsigned sz1 = args1.size(); - unsigned idx1 = 0; - for (; idx1 < sz1; ++idx1) { - expr * m1 = args1.get(idx1); - if (eq_monomials_modulo_k(m1, m2)) { - expr_ref tmp(m_manager); - if (merge_monomials(true, m1, m2, tmp)) { - args1.set(idx1, tmp.get()); - } - else { - // the monomial cancelled each other. - args1.erase(idx1); - } - break; - } - } - if (idx1 == sz1) { - ++idx2; - } - else { - args2.erase(idx2); - } - } - - expr_ref lhs(m_manager); - expr_ref rhs(m_manager); - mk_sum_of_monomials(args1, lhs); - mk_sum_of_monomials(args2, rhs); - m_bsimp.mk_eq(lhs.get(), rhs.get(), result); -} - -void bv_simplifier_plugin::mk_args_eq_numeral(app * app, expr * n, expr_ref & result) { - expr_ref_buffer eqs(m_manager); - expr_ref eq(m_manager); - unsigned num = app->get_num_args(); - for (unsigned i = 0; i < num; i++) { - mk_bv_eq(app->get_arg(i), n, eq); - eqs.push_back(eq.get()); - } - m_bsimp.mk_and(eqs.size(), eqs.c_ptr(), result); -} - -void bv_simplifier_plugin::mk_concat(unsigned num_args, expr * const * args, expr_ref & result) { - TRACE("bv_simplifier_plugin", tout << "mk_concat:\n"; - for (unsigned i = 0; i < num_args; i++) ast_ll_pp(tout, m_manager, args[i]);); - unsigned shift = 0; - numeral val(0), arg_val; - for (unsigned i = num_args; i > 0; ) { - --i; - expr * arg = args[i]; - if (is_numeral(arg, arg_val)) { - arg_val *= rational::power_of_two(shift); - val += arg_val; - shift += get_bv_size(arg); - TRACE("bv_simplifier_plugin", - tout << "val: " << val << " arg_val: " << arg_val << " shift: " << shift << "\n";); - } - else { - // one of the arguments is not a number - result = m_manager.mk_app(m_fid, OP_CONCAT, num_args, args); - return; - } - } - - // all arguments are numerals - result = mk_numeral(val, shift); -} - -void bv_simplifier_plugin::mk_bv_and(unsigned num_args, expr * const* args, expr_ref & result) { - ptr_buffer flat_args; - for (unsigned i = 0; i < num_args; ++i) { - flat_args.push_back(args[i]); - } - // expr_lt_proc is a total order on expressions. - std::sort(flat_args.begin(), flat_args.end(), expr_lt_proc(m_fid, OP_BNOT)); - SASSERT(num_args > 0); - - unsigned bv_size = get_bv_size(args[0]); - - numeral allone = mk_allone(bv_size); - numeral val; - - uint64 unit = bv_size <= 64 ? to_uint64(numeral(-1), bv_size) : 0; - numeral n_unit(allone); - - expr * prev = 0; - ptr_buffer::iterator it = flat_args.begin(); - ptr_buffer::iterator it2 = it; - ptr_buffer::iterator end = flat_args.end(); - for (; it != end; ++it) { - expr* n = *it; - if (prev && - ((is_app_of(n, m_fid, OP_BNOT) && to_app(n)->get_arg(0) == prev) || - (is_app_of(prev, m_fid, OP_BNOT) && to_app(prev)->get_arg(0) == n))) { - result = mk_bv0(bv_size); - return; - } - else if (bv_size <= 64 && is_numeral(n, val)) { - unit &= to_uint64(val, bv_size); - if (unit == 0) { - result = mk_bv0(bv_size); - return; - } - } - else if (bv_size > 64 && is_numeral(n, val)) { - n_unit = mk_bv_and(val, n_unit, bv_size); - if (n_unit.is_zero()) { - result = mk_bv0(bv_size); - return; - } - } - else if (!prev || prev != n) { - *it2 = n; - prev = *it2; - ++it2; - } - } - - if (bv_size <= 64) { - n_unit = numeral(unit, numeral::ui64()); - } - - flat_args.set_end(it2); - if (n_unit != allone) { - flat_args.push_back(mk_numeral(n_unit, bv_size)); - } - - unsigned sz = flat_args.size(); - switch(sz) { - case 0: - result = mk_numeral(n_unit, bv_size); - break; - case 1: - result = flat_args.back(); - break; - default: - result = mk_list_assoc_app(m_manager, m_fid, OP_BAND, sz, flat_args.c_ptr()); - break; - } -} - -void bv_simplifier_plugin::mk_bv_or(unsigned num_args, expr * const* args, expr_ref & result) { -#if 0 - // Transformations for SAGE - // (bvor (concat 0 x) (concat y 0)) ==> (concat y x) - // (bvor (concat x 0) (concat 0 y)) ==> (concat x y) - if (num_args == 2 && - m_util.is_concat(args[0]) && - m_util.is_concat(args[1]) && - to_app(args[0])->get_num_args() == 2 && - to_app(args[1])->get_num_args() == 2) { - expr * x1 = to_app(args[0])->get_arg(0); - expr * x2 = to_app(args[0])->get_arg(1); - expr * y1 = to_app(args[1])->get_arg(0); - expr * y2 = to_app(args[1])->get_arg(1); - if (get_bv_size(x1) == get_bv_size(y1) && - get_bv_size(x2) == get_bv_size(y2)) { - if (m_util.is_zero(x1) && m_util.is_zero(y2)) { - // (bvor (concat 0 x) (concat y 0)) ==> (concat y x) - mk_concat(y1, x2, result); - return; - } - if (m_util.is_zero(x2) && m_util.is_zero(y1)) { - // (bvor (concat x 0) (concat 0 y)) ==> (concat x y) - mk_concat(x1, y2, result); - return; - } - } - } - // Investigate why it did not work. -#endif - - ptr_buffer flat_args; - for (unsigned i = 0; i < num_args; ++i) { - flat_args.push_back(args[i]); - } - std::sort(flat_args.begin(), flat_args.end(), expr_lt_proc(m_fid, OP_BNOT)); - SASSERT(num_args > 0); - - unsigned bv_size = get_bv_size(args[0]), sz; - numeral allone = mk_allone(bv_size); - numeral val; - - uint64 unit = 0; - numeral n_unit(0); - - expr * prev = 0; - ptr_buffer::iterator it = flat_args.begin(); - ptr_buffer::iterator it2 = it; - ptr_buffer::iterator end = flat_args.end(); - for (; it != end; ++it) { - expr* n = *it; - if (prev && - ((is_app_of(n, m_fid, OP_BNOT) && to_app(n)->get_arg(0) == prev) || - (is_app_of(prev, m_fid, OP_BNOT) && to_app(prev)->get_arg(0) == n))) { - result = mk_numeral(allone, bv_size); - return; - } - else if (bv_size <= 64 && is_numeral(n, val)) { - unit |= to_uint64(val, bv_size); - } - else if (bv_size > 64 && is_numeral(n, val)) { - n_unit = mk_bv_or(val, n_unit, bv_size); - } - else if (!prev || prev != n) { - *it2 = n; - prev = *it2; - ++it2; - } - } - - if (bv_size <= 64) { - n_unit = numeral(unit, numeral::ui64()); - } - - if (allone == n_unit) { - result = mk_numeral(allone, bv_size); - return; - } - - flat_args.set_end(it2); - if (!n_unit.is_zero()) { - flat_args.push_back(mk_numeral(n_unit, bv_size)); - } - - sz = flat_args.size(); - switch(sz) { - case 0: - result = mk_numeral(n_unit, bv_size); - break; - case 1: - result = flat_args.back(); - break; - default: - result = mk_list_assoc_app(m_manager, m_fid, OP_BOR, sz, flat_args.c_ptr()); - break; - } -} - -void bv_simplifier_plugin::mk_bv_xor(unsigned num_args, expr * const * args, expr_ref & result) { - ptr_buffer flat_args; - for (unsigned i = 0; i < num_args; ++i) { - flat_args.push_back(args[i]); - } - std::sort(flat_args.begin(), flat_args.end(), expr_lt_proc()); - SASSERT(num_args > 0); - - unsigned bv_size = get_bv_size(args[0]); - numeral val; - - uint64 unit = 0; - numeral n_unit(0); - - expr * prev = 0; - ptr_buffer::iterator it = flat_args.begin(); - ptr_buffer::iterator it2 = it; - ptr_buffer::iterator end = flat_args.end(); - for (; it != end; ++it) { - if (bv_size <= 64 && is_numeral(*it, val)) { - uint64 u = to_uint64(val, bv_size); - unit = u ^ unit; - } - else if (bv_size > 64 && is_numeral(*it, val)) { - n_unit = mk_bv_xor(n_unit, val, bv_size); - } - else if (prev != 0 && prev == *it) { - --it2; // remove prev - prev = 0; - } - else { - *it2 = *it; - prev = *it2; - ++it2; - } - } - flat_args.set_end(it2); - - if (bv_size <= 64) { - n_unit = numeral(numeral(unit,numeral::ui64())); - } - - if (!n_unit.is_zero()) { - flat_args.push_back(mk_numeral(n_unit, bv_size)); - } - - unsigned sz = flat_args.size(); - switch(sz) { - case 0: - result = mk_numeral(n_unit, bv_size); - break; - case 1: - result = flat_args.back(); - break; - default: - result = mk_list_assoc_app(m_manager, m_fid, OP_BXOR, flat_args.size(), flat_args.c_ptr()); - break; - } -} - -void bv_simplifier_plugin::mk_bv_not(expr * arg, expr_ref & result) { - numeral val; - unsigned bv_size; - if (m_util.is_numeral(arg, val, bv_size)) { - if (bv_size <= 64) { - uint64 l = bv_size; - uint64 mask = shift_left(1ull,l) - 1ull; - uint64 u = val.get_uint64(); - u = mask & (~u); - result = mk_numeral(numeral(u, numeral::ui64()), bv_size); - TRACE("bv_not_bug", - tout << l << " " << mask << " " << u << "\n"; - tout << mk_pp(arg, m_manager) << "\n" << mk_pp(result, m_manager) << "\n";); - } - else { - numeral r = mk_bv_not(val, bv_size); - result = mk_numeral(r, bv_size); - TRACE("bv_not_bug", - tout << mk_pp(arg, m_manager) << "\n" << mk_pp(result, m_manager) << "\n";); - } - } - else if (is_app_of(arg, m_fid, OP_BNOT)) { - result = to_app(arg)->get_arg(0); - } - else { - result = m_manager.mk_app(m_fid, OP_BNOT, arg); - } -} - -void bv_simplifier_plugin::mk_zeroext(unsigned n, expr * arg, expr_ref & result) { - if (n == 0) { - result = arg; - } - else { - expr_ref zero(m_manager); - zero = mk_bv0(n); - mk_concat(zero.get(), arg, result); - } -} - -void bv_simplifier_plugin::mk_repeat(unsigned n, expr * arg, expr_ref & result) { - ptr_buffer args; - for (unsigned i = 0; i < n; i++) { - args.push_back(arg); - } - mk_concat(args.size(), args.c_ptr(), result); -} - -bool bv_simplifier_plugin::is_minus_one_core(expr * arg) const { - numeral r; - unsigned bv_size; - if (m_util.is_numeral(arg, r, bv_size)) { - numeral minus_one(-1); - minus_one = mod(minus_one, rational::power_of_two(bv_size)); - return r == minus_one; - } - return false; -} - -bool bv_simplifier_plugin::is_x_minus_one(expr * arg, expr * & x) { - if (is_add(arg) && to_app(arg)->get_num_args() == 2) { - if (is_minus_one_core(to_app(arg)->get_arg(0))) { - x = to_app(arg)->get_arg(1); - return true; - } - if (is_minus_one_core(to_app(arg)->get_arg(1))) { - x = to_app(arg)->get_arg(0); - return true; - } - } - return false; -} - -void bv_simplifier_plugin::mk_bv_urem(expr * arg1, expr * arg2, expr_ref & result) { - numeral r1, r2; - unsigned bv_size; - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); - bv_size = get_bv_size(arg1); - - if (is_num2 && r2.is_zero() && !m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BUREM0, arg1); - return; - } - - if (is_num1 && is_num2 && !r2.is_zero()) { - SASSERT(r1.is_nonneg() && r2.is_pos()); - r1 %= r2; - result = mk_numeral(r1, bv_size); - return; - } - - if (!m_params.m_hi_div0) { - // TODO: implement the optimization in this branch for the case the hardware interpretation is used for (x urem 0) - // urem(0, x) ==> ite(x = 0, urem0(x), 0) - if (is_num1 && r1.is_zero()) { - expr * zero = arg1; - expr_ref urem0(m_manager), eq0(m_manager); - urem0 = m_manager.mk_app(m_fid, OP_BUREM0, 1, &zero); - m_bsimp.mk_eq(arg2, zero, eq0); - m_bsimp.mk_ite(eq0.get(), urem0.get(), zero, result); - TRACE("urem", - tout << "urem:\n"; - ast_ll_pp(tout, m_manager, arg1); ast_ll_pp(tout, m_manager, arg2); - tout << "result:\n"; ast_ll_pp(tout, m_manager, result.get());); - return; - } - - // urem(x - 1, x) ==> ite(x = 0, urem0(x-1), x - 1) ==> ite(x = 0, urem0(-1), x - 1) - expr * x; - if (is_x_minus_one(arg1, x) && x == arg2) { - expr * x_minus_1 = arg1; - expr_ref zero(m_manager); - zero = mk_bv0(bv_size); - expr_ref minus_one(m_manager), urem0(m_manager), eq0(m_manager); - minus_one = mk_numeral(numeral::minus_one(), bv_size); - expr * minus_1 = minus_one.get(); - urem0 = m_manager.mk_app(m_fid, OP_BUREM0, 1, &minus_1); - m_bsimp.mk_eq(arg2, zero.get(), eq0); - m_bsimp.mk_ite(eq0.get(), urem0.get(), x_minus_1, result); - TRACE("urem", - tout << "urem:\n"; - ast_ll_pp(tout, m_manager, arg1); ast_ll_pp(tout, m_manager, arg2); - tout << "result:\n"; ast_ll_pp(tout, m_manager, result.get());); - return; - } - } - - if (is_num2 || m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BUREM_I, arg1, arg2); - } - else { - bv_size = get_bv_size(arg2); - result = m_manager.mk_ite(m_manager.mk_eq(arg2, mk_numeral(0, bv_size)), - m_manager.mk_app(m_fid, OP_BUREM0, arg1), - m_manager.mk_app(m_fid, OP_BUREM_I, arg1, arg2)); - } -} - -void bv_simplifier_plugin::mk_sign_extend(unsigned n, expr * arg, expr_ref & result) { - numeral r; - unsigned bv_size; - if (m_util.is_numeral(arg, r, bv_size)) { - unsigned result_bv_size = bv_size + n; - r = norm(r, bv_size, true); - r = mod(r, rational::power_of_two(result_bv_size)); - result = mk_numeral(r, result_bv_size); - TRACE("mk_sign_extend", tout << "n: " << n << "\n"; - ast_ll_pp(tout, m_manager, arg); tout << "====>\n"; - ast_ll_pp(tout, m_manager, result.get());); - return; - } - parameter param(n); - result = m_manager.mk_app(m_fid, OP_SIGN_EXT, 1, ¶m, 1, &arg); -} - -/** - Implement the following reductions - - (bvashr (bvashr a n1) n2) ==> (bvashr a (+ n1 n2)) - (bvlshr (bvlshr a n1) n2) ==> (bvlshr a (+ n1 n2)) - (bvshl (bvshl a n1) n2) ==> (bvshl a (+ n1 n2)) - when n1 and n2 are numerals. - Remark if (+ n1 n2) is greater than bv_size, we set (+ n1 n2) to bv_size - - Return true if the transformation was applied and the result stored in 'result'. - Return false otherwise. -*/ -bool bv_simplifier_plugin::shift_shift(bv_op_kind k, expr* arg1, expr* arg2, expr_ref& result) { - SASSERT(k == OP_BASHR || k == OP_BSHL || k == OP_BLSHR); - if (!is_app_of(arg1, m_fid, k)) - return false; - expr * a = to_app(arg1)->get_arg(0); - expr * n1 = to_app(arg1)->get_arg(1); - expr * n2 = arg2; - numeral r1, r2; - unsigned bv_size = UINT_MAX; - bool is_num1 = m_util.is_numeral(n1, r1, bv_size); - bool is_num2 = m_util.is_numeral(n2, r2, bv_size); - if (!is_num1 || !is_num2) - return false; - SASSERT(bv_size != UINT_MAX); - numeral r = r1 + r2; - if (r > numeral(bv_size)) - r = numeral(bv_size); - switch (k) { - case OP_BASHR: - mk_bv_ashr(a, m_util.mk_numeral(r, bv_size), result); - break; - case OP_BLSHR: - mk_bv_lshr(a, m_util.mk_numeral(r, bv_size), result); - break; - default: - SASSERT(k == OP_BSHL); - mk_bv_shl(a, m_util.mk_numeral(r, bv_size), result); - break; - } - return true; -} - -void bv_simplifier_plugin::mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result) { - // x << 0 == x - numeral r1, r2; - unsigned bv_size = get_bv_size(arg1); - bool is_num1 = is_numeral(arg1, r1); - bool is_num2 = is_numeral(arg2, r2); - - if (is_num2 && r2.is_zero()) { - result = arg1; - } - else if (is_num2 && r2 >= rational(bv_size)) { - result = mk_numeral(0, bv_size); - } - else if (is_num2 && is_num1 && bv_size <= 64) { - SASSERT(r1.is_uint64() && r2.is_uint64()); - SASSERT(r2.get_uint64() < bv_size); - - uint64 r = shift_left(r1.get_uint64(), r2.get_uint64()); - result = mk_numeral(r, bv_size); - } - else if (is_num1 && is_num2) { - SASSERT(r2 < rational(bv_size)); - SASSERT(r2.is_unsigned()); - result = mk_numeral(r1 * rational::power_of_two(r2.get_unsigned()), bv_size); - } - - // - // (bvshl x k) -> (concat (extract [n-1-k:0] x) bv0:k) - // - else if (is_num2 && r2.is_pos() && r2 < numeral(bv_size)) { - SASSERT(r2.is_unsigned()); - unsigned r = r2.get_unsigned(); - expr_ref tmp1(m_manager); - mk_extract(bv_size - r - 1, 0, arg1, tmp1); - expr_ref zero(m_manager); - zero = mk_bv0(r); - expr* args[2] = { tmp1.get(), zero.get() }; - mk_concat(2, args, result); - } - else if (shift_shift(OP_BSHL, arg1, arg2, result)) { - // done - } - else { - result = m_manager.mk_app(m_fid, OP_BSHL, arg1, arg2); - } - TRACE("mk_bv_shl", - tout << mk_pp(arg1, m_manager) << " << " - << mk_pp(arg2, m_manager) << " = " - << mk_pp(result.get(), m_manager) << "\n";); -} - -void bv_simplifier_plugin::mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result) { - // x >> 0 == x - numeral r1, r2; - unsigned bv_size = get_bv_size(arg1); - bool is_num1 = is_numeral(arg1, r1); - bool is_num2 = is_numeral(arg2, r2); - - if (is_num2 && r2.is_zero()) { - result = arg1; - } - else if (is_num2 && r2 >= rational(bv_size)) { - result = mk_numeral(rational(0), bv_size); - } - else if (is_num1 && is_num2 && bv_size <= 64) { - SASSERT(r1.is_uint64()); - SASSERT(r2.is_uint64()); - uint64 r = shift_right(r1.get_uint64(), r2.get_uint64()); - result = mk_numeral(r, bv_size); - } - else if (is_num1 && is_num2) { - SASSERT(r2.is_unsigned()); - unsigned sh = r2.get_unsigned(); - r1 = div(r1, rational::power_of_two(sh)); - result = mk_numeral(r1, bv_size); - } - // - // (bvlshr x k) -> (concat bv0:k (extract [n-1:k] x)) - // - else if (is_num2 && r2.is_pos() && r2 < numeral(bv_size)) { - SASSERT(r2.is_unsigned()); - unsigned r = r2.get_unsigned(); - expr_ref tmp1(m_manager); - mk_extract(bv_size - 1, r, arg1, tmp1); - expr_ref zero(m_manager); - zero = mk_bv0(r); - expr* args[2] = { zero.get(), tmp1.get() }; - mk_concat(2, args, result); - } - else if (shift_shift(OP_BLSHR, arg1, arg2, result)) { - // done - } - else { - result = m_manager.mk_app(m_fid, OP_BLSHR, arg1, arg2); - } - TRACE("mk_bv_lshr", tout << mk_pp(arg1, m_manager) << " >> " << - mk_pp(arg2, m_manager) << " = " << mk_pp(result.get(), m_manager) << "\n";); - -} - - -void bv_simplifier_plugin::mk_int2bv(expr * arg, sort* range, expr_ref & result) { - numeral val; - bool is_int; - unsigned bv_size = get_bv_size(range); - - if (m_arith.is_numeral(arg, val, is_int)) { - result = mk_numeral(val, bv_size); - } - // (int2bv (bv2int x)) == x - else if (is_app_of(arg, m_fid, OP_BV2INT) && bv_size == get_bv_size(to_app(arg)->get_arg(0))) { - result = to_app(arg)->get_arg(0); - } - else { - parameter parameter(bv_size); - result = m_manager.mk_app(m_fid, OP_INT2BV, 1, ¶meter, 1, &arg); - SASSERT(result.get()); - } -} - -void bv_simplifier_plugin::mk_bv2int(expr * arg, sort* range, expr_ref & result) { - if (!m_params.m_bv2int_distribute) { - parameter parameter(range); - result = m_manager.mk_app(m_fid, OP_BV2INT, 1, ¶meter, 1, &arg); - return; - } - numeral v; - if (is_numeral(arg, v)) { - result = m_arith.mk_numeral(v, true); - } - else if (is_mul_no_overflow(arg)) { - expr_ref tmp1(m_manager), tmp2(m_manager); - mk_bv2int(to_app(arg)->get_arg(0), range, tmp1); - mk_bv2int(to_app(arg)->get_arg(1), range, tmp2); - result = m_arith.mk_mul(tmp1, tmp2); - } - else if (is_add_no_overflow(arg)) { - expr_ref tmp1(m_manager), tmp2(m_manager); - mk_bv2int(to_app(arg)->get_arg(0), range, tmp1); - mk_bv2int(to_app(arg)->get_arg(1), range, tmp2); - result = m_arith.mk_add(tmp1, tmp2); - } - // commented out to reproduce bug in reduction of int2bv/bv2int - else if (m_util.is_concat(arg) && to_app(arg)->get_num_args() > 0) { - expr_ref_vector args(m_manager); - unsigned num_args = to_app(arg)->get_num_args(); - for (unsigned i = 0; i < num_args; ++i) { - expr_ref tmp(m_manager); - mk_bv2int(to_app(arg)->get_arg(i), range, tmp); - args.push_back(tmp); - } - unsigned sz = get_bv_size(to_app(arg)->get_arg(num_args-1)); - for (unsigned i = num_args - 1; i > 0; ) { - expr_ref tmp(m_manager); - --i; - tmp = args[i].get(); - tmp = m_arith.mk_mul(m_arith.mk_numeral(power(numeral(2), sz), true), tmp); - args[i] = tmp; - sz += get_bv_size(to_app(arg)->get_arg(i)); - } - result = m_arith.mk_add(args.size(), args.c_ptr()); - } - else { - parameter parameter(range); - result = m_manager.mk_app(m_fid, OP_BV2INT, 1, ¶meter, 1, &arg); - } - SASSERT(m_arith.is_int(m_manager.get_sort(result.get()))); -} - -unsigned bv_simplifier_plugin::num_leading_zero_bits(expr* e) { - numeral v; - unsigned sz = get_bv_size(e); - if (is_numeral(e, v)) { - while (v.is_pos()) { - SASSERT(sz > 0); - --sz; - v = div(v, numeral(2)); - } - return sz; - } - else if (m_util.is_concat(e)) { - app* a = to_app(e); - unsigned sz1 = get_bv_size(a->get_arg(0)); - unsigned nb1 = num_leading_zero_bits(a->get_arg(0)); - if (sz1 == nb1) { - nb1 += num_leading_zero_bits(a->get_arg(1)); - } - return nb1; - } - return 0; -} - -bool bv_simplifier_plugin::is_mul_no_overflow(expr* e) { - if (!is_mul(e)) { - return false; - } - expr* e1 = to_app(e)->get_arg(0); - expr* e2 = to_app(e)->get_arg(1); - unsigned sz = get_bv_size(e1); - unsigned nb1 = num_leading_zero_bits(e1); - unsigned nb2 = num_leading_zero_bits(e2); - return nb1 + nb2 >= sz; -} - -bool bv_simplifier_plugin::is_add_no_overflow(expr* e) { - if (!is_add(e)) { - return false; - } - expr* e1 = to_app(e)->get_arg(0); - expr* e2 = to_app(e)->get_arg(1); - unsigned nb1 = num_leading_zero_bits(e1); - unsigned nb2 = num_leading_zero_bits(e2); - return nb1 > 0 && nb2 > 0; -} - - - -// Macro for generating mk_bv_sdiv_i, mk_bv_udiv_i, mk_bv_srem_i, mk_bv_urem_i and mk_bv_smod_i. -// These are essentially evaluators for the arg1 and arg2 are numerals. -// Q: Why do we need them? -// A: A constant may be eliminated using substitution. Its value is computed using the evaluator. -// Example: Suppose we have the top-level atom (= x (bvsrem_i a b)), and x is eliminated. -#define MK_FIXED_DIV_I(NAME, OP) \ -void bv_simplifier_plugin::NAME##_i(expr * arg1, expr * arg2, expr_ref & result) { \ - numeral r1, r2; \ - unsigned bv_size; \ - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); \ - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); \ - if (is_num1 && is_num2 && !r2.is_zero()) { \ - NAME(arg1, arg2, result); \ - } \ - else { \ - result = m_manager.mk_app(m_fid, OP, arg1, arg2); \ - } \ -} - -MK_FIXED_DIV_I(mk_bv_sdiv, OP_BSDIV_I) -MK_FIXED_DIV_I(mk_bv_udiv, OP_BUDIV_I) -MK_FIXED_DIV_I(mk_bv_srem, OP_BSREM_I) -MK_FIXED_DIV_I(mk_bv_urem, OP_BUREM_I) -MK_FIXED_DIV_I(mk_bv_smod, OP_BSMOD_I) - -void bv_simplifier_plugin::mk_bv_sdiv(expr* arg1, expr* arg2, expr_ref& result) { - numeral r1, r2; - unsigned bv_size; - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); - - if (is_num2 && r2.is_zero() && !m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BSDIV0, arg1); - } - else if (is_num1 && is_num2 && !r2.is_zero()) { - r1 = norm(r1, bv_size, true); - r2 = norm(r2, bv_size, true); - result = mk_numeral(machine_div(r1, r2), bv_size); - } - else if (is_num2 || m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BSDIV_I, arg1, arg2); - } - else { - bv_size = get_bv_size(arg2); - result = m_manager.mk_ite(m_manager.mk_eq(arg2, mk_numeral(0, bv_size)), - m_manager.mk_app(m_fid, OP_BSDIV0, arg1), - m_manager.mk_app(m_fid, OP_BSDIV_I, arg1, arg2)); - } -} - -void bv_simplifier_plugin::mk_bv_udiv(expr* arg1, expr* arg2, expr_ref& result) { - numeral r1, r2; - unsigned bv_size; - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); - - if (is_num2 && r2.is_zero() && !m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BUDIV0, arg1); - } - else if (is_num1 && is_num2 && !r2.is_zero()) { - SASSERT(r1.is_nonneg()); - SASSERT(r2.is_nonneg()); - result = mk_numeral(machine_div(r1, r2), bv_size); - } - else if (is_num2 || m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BUDIV_I, arg1, arg2); - } - else { - bv_size = get_bv_size(arg2); - result = m_manager.mk_ite(m_manager.mk_eq(arg2, mk_numeral(0, bv_size)), - m_manager.mk_app(m_fid, OP_BUDIV0, arg1), - m_manager.mk_app(m_fid, OP_BUDIV_I, arg1, arg2)); - } -} - -void bv_simplifier_plugin::mk_bv_srem(expr* arg1, expr* arg2, expr_ref& result) { - numeral r1, r2; - unsigned bv_size; - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); - - if (is_num2 && r2.is_zero() && !m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BSREM0, arg1); - } - else if (is_num1 && is_num2 && !r2.is_zero()) { - r1 = norm(r1, bv_size, true); - r2 = norm(r2, bv_size, true); - result = mk_numeral(r1 % r2, bv_size); - } - else if (is_num2 || m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BSREM_I, arg1, arg2); - } - else { - bv_size = get_bv_size(arg2); - result = m_manager.mk_ite(m_manager.mk_eq(arg2, mk_numeral(0, bv_size)), - m_manager.mk_app(m_fid, OP_BSREM0, arg1), - m_manager.mk_app(m_fid, OP_BSREM_I, arg1, arg2)); - } -} - -void bv_simplifier_plugin::mk_bv_smod(expr* arg1, expr* arg2, expr_ref& result) { - numeral r1, r2; - unsigned bv_size; - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); - - if (is_num1) - r1 = m_util.norm(r1, bv_size, true); - if (is_num2) - r2 = m_util.norm(r2, bv_size, true); - - TRACE("bv_simplifier", - tout << mk_pp(arg1, m_manager) << " smod " << mk_pp(arg2, m_manager) << "\n"; - ); - - - if (is_num2 && r2.is_zero()) { - if (!m_params.m_hi_div0) - result = m_manager.mk_app(m_fid, OP_BSMOD0, arg1); - else - result = arg1; - } - else if (is_num1 && is_num2) { - SASSERT(!r2.is_zero()); - numeral abs_r1 = m_util.norm(abs(r1), bv_size); - numeral abs_r2 = m_util.norm(abs(r2), bv_size); - numeral u = m_util.norm(abs_r1 % abs_r2, bv_size); - numeral r; - if (u.is_zero()) - r = u; - else if (r1.is_pos() && r2.is_pos()) - r = u; - else if (r1.is_neg() && r2.is_pos()) - r = m_util.norm(-u + r2, bv_size); - else if (r1.is_pos() && r2.is_neg()) - r = m_util.norm(u + r2, bv_size); - else - r = m_util.norm(-u, bv_size); - result = mk_numeral(r, bv_size); - } - else if (is_num2 || m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BSMOD_I, arg1, arg2); - } - else { - bv_size = get_bv_size(arg2); - result = m_manager.mk_ite(m_manager.mk_eq(arg2, mk_numeral(0, bv_size)), - m_manager.mk_app(m_fid, OP_BSMOD0, arg1), - m_manager.mk_app(m_fid, OP_BSMOD_I, arg1, arg2)); - } -} - -uint64 bv_simplifier_plugin::n64(expr* e) { - numeral r; - unsigned bv_size; - if (m_util.is_numeral(e, r, bv_size) && bv_size <= 64) { - return r.get_uint64(); - } - UNREACHABLE(); - return 0; -} - -rational bv_simplifier_plugin::num(expr* e) { - numeral r; - unsigned bv_size; - if (!m_util.is_numeral(e, r, bv_size)) { - UNREACHABLE(); - } - return r; - -} - -void bv_simplifier_plugin::mk_bv_nand(unsigned num_args, expr* const* args, expr_ref& result) { - unsigned bv_size; - if (are_numerals(num_args, args, bv_size)) { - if (bv_size <= 64) { - uint64 r = n64(args[0]); - for (unsigned i = 1; i < num_args; i++) { - r &= n64(args[i]); - } - result = mk_numeral(~r, bv_size); - } - else { - numeral r = num(args[0]); - for (unsigned i = 1; i < num_args; i++) { - r = mk_bv_and(r, num(args[i]), bv_size); - } - result = mk_numeral(mk_bv_not(r, bv_size), bv_size); - } - } - else { - result = m_manager.mk_app(m_fid, OP_BNAND, num_args, args); - } -} - -void bv_simplifier_plugin::mk_bv_nor(unsigned num_args, expr* const* args, expr_ref& result) { - unsigned bv_size; - if (are_numerals(num_args, args, bv_size)) { - if (bv_size <= 64) { - uint64 r = n64(args[0]); - for (unsigned i = 1; i < num_args; i++) { - r |= n64(args[i]); - } - result = mk_numeral(~r, bv_size); - } - else { - numeral r = num(args[0]); - for (unsigned i = 1; i < num_args; i++) { - r = mk_bv_or(r, num(args[i]), bv_size); - } - result = mk_numeral(mk_bv_not(r, bv_size), bv_size); - } - } - else { - result = m_manager.mk_app(m_fid, OP_BNOR, num_args, args); - } -} - -void bv_simplifier_plugin::mk_bv_xnor(unsigned num_args, expr* const* args, expr_ref& result) { - unsigned bv_size; - if (are_numerals(num_args, args, bv_size)) { - if (bv_size <= 64) { - uint64 r = n64(args[0]); - for (unsigned i = 1; i < num_args; i++) { - r ^= n64(args[i]); - } - result = mk_numeral(~r, bv_size); - } - else { - numeral r = num(args[0]); - for (unsigned i = 1; i < num_args; i++) { - r = mk_bv_xor(r, num(args[i]), bv_size); - } - result = mk_numeral(mk_bv_not(r, bv_size), bv_size); - } - } - else { - result = m_manager.mk_app(m_fid, OP_BXNOR, num_args, args); - } -} - -void bv_simplifier_plugin::mk_bv_rotate_left_core(unsigned shift, numeral r, unsigned bv_size, expr_ref& result) { - SASSERT(shift < bv_size); - if (bv_size <= 64) { - uint64 a = r.get_uint64(); - uint64 r = shift_left(a, shift) | shift_right(a, bv_size - shift); - result = mk_numeral(r, bv_size); - } - else { - rational r1 = div(r, rational::power_of_two(bv_size - shift)); // shift right - rational r2 = (r * rational::power_of_two(shift)) % rational::power_of_two(bv_size); // shift left - result = mk_numeral(r1 + r2, bv_size); - } -} - -void bv_simplifier_plugin::mk_bv_rotate_left(func_decl* f, expr* arg, expr_ref& result) { - numeral r; - unsigned bv_size; - SASSERT(f->get_decl_kind() == OP_ROTATE_LEFT); - if (m_util.is_numeral(arg, r, bv_size)) { - unsigned shift = f->get_parameter(0).get_int() % bv_size; - mk_bv_rotate_left_core(shift, r, bv_size, result); - } - else { - result = m_manager.mk_app(f, arg); - } -} - -void bv_simplifier_plugin::mk_bv_rotate_right_core(unsigned shift, numeral r, unsigned bv_size, expr_ref& result) { - SASSERT(shift < bv_size); - if (bv_size <= 64) { - uint64 a = r.get_uint64(); - uint64 r = shift_right(a, shift) | shift_left(a, bv_size - shift); - result = mk_numeral(r, bv_size); - } - else { - rational r1 = div(r, rational::power_of_two(shift)); // shift right - rational r2 = (r * rational::power_of_two(bv_size - shift)) % rational::power_of_two(bv_size); // shift left - result = mk_numeral(r1 + r2, bv_size); - } -} - -void bv_simplifier_plugin::mk_bv_rotate_right(func_decl* f, expr* arg, expr_ref& result) { - numeral r; - unsigned bv_size; - SASSERT(f->get_decl_kind() == OP_ROTATE_RIGHT); - if (m_util.is_numeral(arg, r, bv_size)) { - unsigned shift = f->get_parameter(0).get_int() % bv_size; - mk_bv_rotate_right_core(shift, r, bv_size, result); - } - else { - result = m_manager.mk_app(f, arg); - } -} - -void bv_simplifier_plugin::mk_bv_redor(expr* arg, expr_ref& result) { - if (is_numeral(arg)) { - result = m_util.is_zero(arg)?mk_numeral(0, 1):mk_numeral(1,1); - } - else { - result = m_manager.mk_app(m_fid, OP_BREDOR, arg); - } -} - -void bv_simplifier_plugin::mk_bv_redand(expr* arg, expr_ref& result) { - numeral r; - unsigned bv_size; - if (m_util.is_numeral(arg, r, bv_size)) { - numeral allone = mk_allone(bv_size); - result = mk_numeral((r == allone)?1:0, 1); - } - else { - result = m_manager.mk_app(m_fid, OP_BREDAND, arg); - } -} - -void bv_simplifier_plugin::mk_bv_comp(expr* arg1, expr* arg2, expr_ref& result) { - numeral r1, r2; - if (arg1 == arg2) { - result = mk_numeral(1,1); - } - else if (is_numeral(arg1, r1) && is_numeral(arg2, r2)) { - result = mk_numeral((r1 == r2)?1:0, 1); - } - else { - result = m_manager.mk_app(m_fid, OP_BCOMP, arg1, arg2); - } -} - -void bv_simplifier_plugin::mk_bv_ashr(expr* arg1, expr* arg2, expr_ref& result) { - numeral r1, r2; - unsigned bv_size = get_bv_size(arg1); - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); - - if (bv_size == 0) { - result = mk_numeral(rational(0), bv_size); - } - else if (is_num2 && r2.is_zero()) { - result = arg1; - } - else if (bv_size <= 64 && is_num1 && is_num2) { - uint64 n1 = n64(arg1); - uint64 n2_orig = n64(arg2); - uint64 n2 = n2_orig % bv_size; - SASSERT(n2 < bv_size); - uint64 r = shift_right(n1, n2); - bool sign = (n1 & shift_left(1ull, bv_size - 1ull)) != 0; - if (n2_orig > n2) { - if (sign) { - r = shift_left(1ull, bv_size) - 1ull; - } - else { - r = 0; - } - } - else if (sign) { - uint64 allone = shift_left(1ull, bv_size) - 1ull; - uint64 mask = ~(shift_left(1ull, bv_size - n2) - 1ull); - mask &= allone; - r |= mask; - } - result = mk_numeral(r, bv_size); - TRACE("bv", tout << mk_pp(arg1, m_manager) << " >> " - << mk_pp(arg2, m_manager) << " = " - << mk_pp(result.get(), m_manager) << "\n"; - tout << n1 << " >> " << n2 << " = " << r << "\n"; - ); - } - else if (is_num1 && is_num2 && rational(bv_size) <= r2) { - if (has_sign_bit(r1, bv_size)) { - result = mk_numeral(mk_allone(bv_size), bv_size); - } - else { - result = mk_bv0(bv_size); - } - } - else if (is_num1 && is_num2) { - SASSERT(r2 < rational(bv_size)); - bool sign = has_sign_bit(r1, bv_size); - r1 = div(r1, rational::power_of_two(r2.get_unsigned())); - if (sign) { - // pad ones. - rational p(1); - for (unsigned i = 0; i < bv_size; ++i) { - if (r1 < p) { - r1 += p; - } - p *= rational(2); - } - } - result = mk_numeral(r1, bv_size); - - } - else if (shift_shift(OP_BASHR, arg1, arg2, result)) { - // done - } - else { - result = m_manager.mk_app(m_fid, OP_BASHR, arg1, arg2); - } -} - -void bv_simplifier_plugin::mk_bv_ext_rotate_right(expr* arg1, expr* arg2, expr_ref& result) { - numeral r2; - unsigned bv_size; - if (m_util.is_numeral(arg2, r2, bv_size)) { - unsigned shift = static_cast((r2 % numeral(bv_size)).get_uint64() % static_cast(bv_size)); - numeral r1; - if (is_numeral(arg1, r1)) { - mk_bv_rotate_right_core(shift, r1, bv_size, result); - } - else { - parameter p(shift); - result = m_manager.mk_app(m_fid, OP_ROTATE_RIGHT, 1, &p, 1, &arg1); - } - } - else { - result = m_manager.mk_app(m_fid, OP_EXT_ROTATE_RIGHT, arg1, arg2); - } -} - - -void bv_simplifier_plugin::mk_bv_ext_rotate_left(expr* arg1, expr* arg2, expr_ref& result) { - numeral r2; - unsigned bv_size; - if (m_util.is_numeral(arg2, r2, bv_size)) { - unsigned shift = static_cast((r2 % numeral(bv_size)).get_uint64() % static_cast(bv_size)); - numeral r1; - if (is_numeral(arg1, r1)) { - mk_bv_rotate_left_core(shift, r1, bv_size, result); - } - else { - parameter p(shift); - result = m_manager.mk_app(m_fid, OP_ROTATE_LEFT, 1, &p, 1, &arg1); - } - } - else { - result = m_manager.mk_app(m_fid, OP_EXT_ROTATE_LEFT, arg1, arg2); - } -} - -void bv_simplifier_plugin::bit2bool_simplify(unsigned idx, expr* e, expr_ref& result) { - - parameter p(idx); - - ptr_vector todo; - expr_ref_vector pinned(m_manager); - ptr_vector cache; - todo.push_back(e); - expr* e0 = e; - ptr_vector argv; - expr_ref tmp(m_manager); - while (!todo.empty()) { - e = todo.back(); - unsigned e_id = e->get_id(); - if (e_id >= cache.size()) { - cache.resize(e_id+1,0); - } - if (cache[e_id]) { - todo.pop_back(); - continue; - } - if (!m_util.is_numeral(e) && - !m_util.is_bv_and(e) && - !m_util.is_bv_or(e) && - !(is_app_of(e, m_fid, OP_BXOR) && to_app(e)->get_num_args() == 2) && - !m_manager.is_ite(e) && - !m_util.is_concat(e) && - !m_util.is_bv_not(e)) { - expr_ref extr(m_manager); - extr = m_util.mk_extract(idx, idx, e); - cache[e_id] = m_manager.mk_eq(m_util.mk_numeral(1, 1), extr); - pinned.push_back(cache[e_id]); - todo.pop_back(); - continue; - } - app* a = to_app(e); - unsigned sz = a->get_num_args(); - if (m_util.is_concat(e)) { - // look for first argument - unsigned idx1 = idx; - while (sz > 0) { - --sz; - expr * a_i = a->get_arg(sz); - unsigned a_sz = get_bv_size(a_i); - if (a_sz <= idx1) { - idx1 -= a_sz; - } - else { - // idx < a_sz; - bit2bool_simplify(idx1, a_i, tmp); - pinned.push_back(tmp); - cache[e_id] = to_app(tmp); - break; - } - } - todo.pop_back(); - continue; - } - argv.reset(); - for (unsigned i = 0; i < sz; ++i) { - expr* arg_i = a->get_arg(i); - if (i == 0 && m_manager.is_ite(e)) { - argv.push_back(arg_i); - } - else if (cache.size() > arg_i->get_id() && cache[arg_i->get_id()]) { - argv.push_back(cache[arg_i->get_id()]); - } - else { - todo.push_back(arg_i); - } - } - if (sz != argv.size()) { - continue; - } - todo.pop_back(); - rational val; - unsigned num_bits; - if (m_util.is_numeral(e, val, num_bits)) { - rational two(2); - for (unsigned i = 0; i < idx; ++i) { - val = div(val, two); - } - bool is_pos = !(val % two).is_zero(); - tmp = is_pos?m_manager.mk_true():m_manager.mk_false(); - } - else if (m_util.is_bv_and(e)) { - //tmp = m_manager.mk_and(sz, argv.c_ptr()); - m_bsimp.mk_and(sz, argv.c_ptr(), tmp); - pinned.push_back(tmp); - } - else if (m_util.is_bv_or(e)) { - //tmp = m_manager.mk_or(sz, argv.c_ptr()); - m_bsimp.mk_or(sz, argv.c_ptr(), tmp); - pinned.push_back(tmp); - } - else if (m_util.is_bv_not(e)) { - //tmp = m_manager.mk_not(argv[0]); - m_bsimp.mk_not(argv[0], tmp); - pinned.push_back(tmp); - } - else if (is_app_of(e, m_fid, OP_BXOR)) { - SASSERT(argv.size() == 2); - m_bsimp.mk_xor(argv[0], argv[1], tmp); - pinned.push_back(tmp); - } - else if (m_manager.is_ite(e)) { - //tmp = m_manager.mk_ite(argv[0], argv[1], argv[2]); - m_bsimp.mk_ite(argv[0], argv[1], argv[2], tmp); - pinned.push_back(tmp); - } - else { - UNREACHABLE(); - } - cache[e_id] = to_app(tmp); - } - result = cache[e0->get_id()]; -} - - -// replace addition by concatenation. -void bv_simplifier_plugin::mk_add_concat(expr_ref& result) { - if (!m_util.is_bv_add(result)) { - return; - } - app* a = to_app(result); - if (a->get_num_args() != 2) { - return; - } - expr* x = a->get_arg(0); - expr* y = a->get_arg(1); - if (!m_util.is_concat(x)) { - std::swap(x, y); - } - if (!m_util.is_concat(x)) { - return; - } - unsigned sz = m_util.get_bv_size(x); - -#if 0 - // optimzied version. Seems not worth it.. -#define UPDATE_CURR(_curr1, _idx1,_x,_is_num, _i) \ - if (_idx1 >= m_util.get_bv_size(_curr1)) { \ - _curr1 = _x; \ - _idx1 = _i; \ - _is_num = false; \ - } \ - while (m_util.is_concat(_curr1)) { \ - _is_num = false; \ - unsigned num_args = to_app(_curr1)->get_num_args(); \ - while (true) { \ - --num_args; \ - expr* c1 = to_app(_curr1)->get_arg(num_args); \ - unsigned sz1 = m_util.get_bv_size(c1); \ - if (sz1 < _idx1) { \ - _idx1 -= sz1; \ - } \ - else { \ - _curr1 = c1; \ - break; \ - } \ - } \ - } - - unsigned idx1 = 0, idx2 = 0; - expr* curr1 = x, *curr2 = y; - bool is_num1 = false, is_num2 = false; - rational val1, val2; - rational two(2); - for (unsigned i = 0; i < sz; ++i, ++idx1, ++idx2) { - UPDATE_CURR(curr1, idx1, x, is_num1, i); - UPDATE_CURR(curr2, idx2, y, is_num2, i); - if (idx1 == 0 && m_util.is_numeral(curr1, val1, bv_size)) { - is_num1 = true; - } - if (idx2 == 0 && m_util.is_numeral(curr2, val2, bv_size)) { - is_num2 = true; - } - if ((is_num1 && (val1 % two).is_zero()) || - (is_num2 && (val2 % two).is_zero())) { - val1 = div(val1, two); - val2 = div(val2, two); - continue; - } - return; - } - mk_bv_or(2, a->get_args(), result); -#endif - - for (unsigned i = 0; i < sz; ++i) { - if (!is_zero_bit(x,i) && !is_zero_bit(y,i)) { - return; - } - } - mk_bv_or(2, a->get_args(), result); -} - -bool bv_simplifier_plugin::is_zero_bit(expr* x, unsigned idx) { - rational val; - unsigned bv_size; - if (m_util.is_numeral(x, val, bv_size)) { - if (val.is_zero()) { - return true; - } - rational two(2); - while (idx > 0) { - val = div(val, two); - idx--; - } - return (val % two).is_zero(); - } - if (m_util.is_concat(x)) { - unsigned num_args = to_app(x)->get_num_args(); - while (num_args > 0) { - --num_args; - expr* y = to_app(x)->get_arg(num_args); - bv_size = m_util.get_bv_size(y); - if (bv_size <= idx) { - idx -= bv_size; - } - else { - return is_zero_bit(y, idx); - } - } - UNREACHABLE(); - } - - return false; -} diff --git a/src/ast/simplifier/bv_simplifier_plugin.h b/src/ast/simplifier/bv_simplifier_plugin.h deleted file mode 100644 index 484edca95..000000000 --- a/src/ast/simplifier/bv_simplifier_plugin.h +++ /dev/null @@ -1,187 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - bv_simplifier_plugin.h - -Abstract: - - Simplifier for the bv family. - -Author: - - Leonardo (leonardo) 2008-01-08 - ---*/ -#ifndef BV_SIMPLIFIER_PLUGIN_H_ -#define BV_SIMPLIFIER_PLUGIN_H_ - -#include"basic_simplifier_plugin.h" -#include"poly_simplifier_plugin.h" -#include"bv_decl_plugin.h" -#include"map.h" -#include"bv_simplifier_params.h" -#include"arith_decl_plugin.h" - -/** - \brief Simplifier for the bv family. -*/ -class bv_simplifier_plugin : public poly_simplifier_plugin { - - typedef rational numeral; - struct extract_entry { - unsigned m_high; - unsigned m_low; - expr * m_arg; - extract_entry():m_high(0), m_low(0), m_arg(0) {} - extract_entry(unsigned h, unsigned l, expr * n):m_high(h), m_low(l), m_arg(n) {} - unsigned hash() const { - unsigned a = m_high; - unsigned b = m_low; - unsigned c = m_arg->get_id(); - mix(a,b,c); - return c; - } - bool operator==(const extract_entry & e) const { - return m_high == e.m_high && m_low == e.m_low && m_arg == e.m_arg; - } - struct hash_proc { - unsigned operator()(extract_entry const& e) const { return e.hash(); } - }; - struct eq_proc { - bool operator()(extract_entry const& a, extract_entry const& b) const { return a == b; } - }; - }; - typedef map extract_cache; - -protected: - ast_manager& m_manager; - bv_util m_util; - arith_util m_arith; - basic_simplifier_plugin & m_bsimp; - bv_simplifier_params & m_params; - expr_ref_vector m_zeros; - extract_cache m_extract_cache; - - unsigned_vector m_lows, m_highs; - ptr_vector m_extract_args; - - rational mk_bv_and(numeral const& a0, numeral const& b0, unsigned sz); - rational mk_bv_or(numeral const& a0, numeral const& b0, unsigned sz); - rational mk_bv_xor(numeral const& a0, numeral const& b0, unsigned sz); - rational mk_bv_not(numeral const& a0, unsigned sz); - rational num(expr* e); - bool has_sign_bit(numeral const& n, unsigned bv_size) { return m_util.has_sign_bit(n, bv_size); } - - bool shift_shift(bv_op_kind k, expr* arg1, expr* arg2, expr_ref& result); - - void bit2bool_simplify(unsigned idx, expr* e, expr_ref& result); - - void mk_add_concat(expr_ref& result); - bool is_zero_bit(expr* x, unsigned idx); - - void mk_bv_rotate_left_core(unsigned shift, numeral r, unsigned bv_size, expr_ref& result); - void mk_bv_rotate_right_core(unsigned shift, numeral r, unsigned bv_size, expr_ref& result); - -public: - bv_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, bv_simplifier_params & p); - virtual ~bv_simplifier_plugin(); - - - // simplifier_plugin: - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result); - virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result); - virtual void flush_caches(); - - // poly_simplifier_plugin - virtual rational norm(const rational & n); - virtual bool is_numeral(expr * n, rational & val) const; - bool is_numeral(expr * n) const { return m_util.is_numeral(n); } - virtual bool is_minus_one(expr * n) const { return is_minus_one_core(n); } - virtual expr * get_zero(sort * s) const; - virtual app * mk_numeral(rational const & n); - - bool is_bv(expr * n) const { return m_util.is_bv(n); } - bool is_bv_sort(sort * s) const { return m_util.is_bv_sort(s); } - - bool is_le(expr * n) const { return m_util.is_bv_ule(n) || m_util.is_bv_sle(n); } - // REMARK: simplified bv expressions are never of the form a >= b. - virtual bool is_le_ge(expr * n) const { return is_le(n); } - - uint64 to_uint64(const numeral & n, unsigned bv_size); - rational norm(rational const& n, unsigned bv_size, bool is_signed) { return m_util.norm(n, bv_size, is_signed); } - unsigned get_bv_size(expr const * n) { return get_bv_size(m_manager.get_sort(n)); } - unsigned get_bv_size(sort const * s) { return m_util.get_bv_size(s); } - void mk_leq_core(bool is_signed, expr * arg1, expr * arg2, expr_ref & result); - void mk_ule(expr* a, expr* b, expr_ref& result); - void mk_ult(expr* a, expr* b, expr_ref& result); - void mk_sle(expr* a, expr* b, expr_ref& result); - void mk_slt(expr* a, expr* b, expr_ref& result); - void mk_bv_and(unsigned num_args, expr * const* args, expr_ref & result); - void mk_bv_or(unsigned num_args, expr * const* args, expr_ref & result); - void mk_bv_xor(unsigned num_args, expr * const* args, expr_ref & result); - void mk_bv_not(expr * arg, expr_ref & result); - void mk_extract(unsigned hi,unsigned lo, expr* bv, expr_ref& result); - void mk_extract_core(unsigned high, unsigned low, expr * arg, expr_ref& result); - void cache_extract(unsigned h, unsigned l, expr * arg, expr * result); - expr* get_cached_extract(unsigned h, unsigned l, expr * arg); - - bool lookup_mk_extract(unsigned high, unsigned low, expr * arg, expr_ref& result); - bool try_mk_extract(unsigned high, unsigned low, expr * arg, expr_ref& result); - - void mk_bv_eq(expr* a1, expr* a2, expr_ref& result); - void mk_eq_core(expr * arg1, expr * arg2, expr_ref & result); - void mk_args_eq_numeral(app * app, expr * n, expr_ref & result); - - void mk_concat(unsigned num_args, expr * const * args, expr_ref & result); - void mk_concat(expr * arg1, expr * arg2, expr_ref & result) { - expr * args[2] = { arg1, arg2 }; - mk_concat(2, args, result); - } - void mk_zeroext(unsigned n, expr * arg, expr_ref & result); - void mk_repeat(unsigned n, expr * arg, expr_ref & result); - void mk_sign_extend(unsigned n, expr * arg, expr_ref & result); - void mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result); - void mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result); - void mk_bv_ashr(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_smod(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_urem(expr * arg1, expr * arg2, expr_ref & result); - void mk_bv_srem(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_udiv(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_sdiv(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_smod_i(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_urem_i(expr * arg1, expr * arg2, expr_ref & result); - void mk_bv_srem_i(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_udiv_i(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_sdiv_i(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_nand(unsigned num_args, expr* const* args, expr_ref& result); - void mk_bv_nor(unsigned num_args, expr* const* args, expr_ref& result); - void mk_bv_xnor(unsigned num_args, expr* const* args, expr_ref& result); - void mk_bv_rotate_right(func_decl* f, expr* arg, expr_ref& result); - void mk_bv_rotate_left(func_decl* f, expr* arg, expr_ref& result); - void mk_bv_ext_rotate_right(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_ext_rotate_left(expr* arg1, expr* arg2, expr_ref& result); - - void mk_bv_redor(expr* arg, expr_ref& result); - void mk_bv_redand(expr* arg, expr_ref& result); - void mk_bv_comp(expr* arg1, expr* arg2, expr_ref& result); - - bool are_numerals(unsigned num_args, expr * const* args, unsigned& bv_size); - app * mk_numeral(rational const & n, unsigned bv_size); - app * mk_numeral(uint64 n, unsigned bv_size) { return mk_numeral(numeral(n, numeral::ui64()), bv_size); } - app* mk_bv0(unsigned bv_size) { return m_util.mk_numeral(numeral(0), bv_size); } - rational mk_allone(unsigned bv_size) { return rational::power_of_two(bv_size) - numeral(1); } - bool is_minus_one_core(expr * arg) const; - bool is_x_minus_one(expr * arg, expr * & x); - void mk_int2bv(expr * arg, sort* range, expr_ref & result); - void mk_bv2int(expr * arg, sort* range, expr_ref & result); - uint64 n64(expr* e); - bool is_mul_no_overflow(expr* e); - bool is_add_no_overflow(expr* e); - unsigned num_leading_zero_bits(expr* e); - -}; - -#endif /* BV_SIMPLIFIER_PLUGIN_H_ */ diff --git a/src/ast/simplifier/datatype_simplifier_plugin.cpp b/src/ast/simplifier/datatype_simplifier_plugin.cpp deleted file mode 100644 index b434a8bd0..000000000 --- a/src/ast/simplifier/datatype_simplifier_plugin.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/*++ -Copyright (c) 2008 Microsoft Corporation - -Module Name: - - datatype_simplifier_plugin.cpp - -Abstract: - - Simplifier for algebraic datatypes. - -Author: - - nbjorner 2008-11-6 - ---*/ - -#include"datatype_simplifier_plugin.h" - -datatype_simplifier_plugin::datatype_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b): - simplifier_plugin(symbol("datatype"), m), - m_util(m), - m_bsimp(b) { -} - -datatype_simplifier_plugin::~datatype_simplifier_plugin() { -} - -bool datatype_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - - SASSERT(f->get_family_id() == get_family_id()); - switch(f->get_decl_kind()) { - case OP_DT_CONSTRUCTOR: { - return false; - } - case OP_DT_RECOGNISER: { - // - // simplify is_cons(cons(x,y)) -> true - // simplify is_cons(nil) -> false - // - SASSERT(num_args == 1); - - if (!is_app_of(args[0], get_family_id(), OP_DT_CONSTRUCTOR)) { - return false; - } - app* a = to_app(args[0]); - func_decl* f1 = a->get_decl(); - func_decl* f2 = m_util.get_recognizer_constructor(f); - if (f1 == f2) { - result = m_manager.mk_true(); - } - else { - result = m_manager.mk_false(); - } - return true; - } - case OP_DT_ACCESSOR: { - // - // simplify head(cons(x,y)) -> x - // - SASSERT(num_args == 1); - - if (!is_app_of(args[0], get_family_id(), OP_DT_CONSTRUCTOR)) { - return false; - } - app* a = to_app(args[0]); - func_decl* f1 = a->get_decl(); - func_decl* f2 = m_util.get_accessor_constructor(f); - if (f1 != f2) { - return false; - } - ptr_vector const* acc = m_util.get_constructor_accessors(f1); - SASSERT(acc && acc->size() == a->get_num_args()); - for (unsigned i = 0; i < acc->size(); ++i) { - if (f == (*acc)[i]) { - // found it. - result = a->get_arg(i); - return true; - } - } - UNREACHABLE(); - } - case OP_DT_UPDATE_FIELD: - return false; - default: - UNREACHABLE(); - } - - return false; -} - -bool datatype_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { - set_reduce_invoked(); - if (is_app_of(lhs, get_family_id(), OP_DT_CONSTRUCTOR) && - is_app_of(rhs, get_family_id(), OP_DT_CONSTRUCTOR)) { - app* a = to_app(lhs); - app* b = to_app(rhs); - if (a->get_decl() != b->get_decl()) { - result = m_manager.mk_false(); - return true; - } - expr_ref_vector eqs(m_manager); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - m_bsimp.mk_eq(a->get_arg(i),b->get_arg(i), result); - eqs.push_back(result); - } - m_bsimp.mk_and(eqs.size(), eqs.c_ptr(), result); - return true; - } - // TBD: occurs check, constructor check. - - return false; -} - diff --git a/src/ast/simplifier/datatype_simplifier_plugin.h b/src/ast/simplifier/datatype_simplifier_plugin.h deleted file mode 100644 index b675bf92e..000000000 --- a/src/ast/simplifier/datatype_simplifier_plugin.h +++ /dev/null @@ -1,42 +0,0 @@ -/*++ -Copyright (c) 2008 Microsoft Corporation - -Module Name: - - datatype_simplifier_plugin.h - -Abstract: - - Simplifier for algebraic datatypes. - -Author: - - nbjorner 2008-11-6 - ---*/ -#ifndef DATATYPE_SIMPLIFIER_PLUGIN_H_ -#define DATATYPE_SIMPLIFIER_PLUGIN_H_ - -#include"basic_simplifier_plugin.h" -#include"datatype_decl_plugin.h" - -/** - \brief Simplifier for the arith family. -*/ -class datatype_simplifier_plugin : public simplifier_plugin { - datatype_util m_util; - basic_simplifier_plugin & m_bsimp; - - -public: - datatype_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b); - ~datatype_simplifier_plugin(); - - - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - - virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result); - -}; - -#endif /* DATATYPE_SIMPLIFIER_PLUGIN_H_ */ diff --git a/src/ast/simplifier/elim_bounds.cpp b/src/ast/simplifier/elim_bounds.cpp deleted file mode 100644 index 7a40b8602..000000000 --- a/src/ast/simplifier/elim_bounds.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - elim_bounds.cpp - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2008-06-28. - -Revision History: - ---*/ -#include"elim_bounds.h" -#include"used_vars.h" -#include"obj_hashtable.h" -#include"var_subst.h" -#include"ast_pp.h" - -elim_bounds::elim_bounds(ast_manager & m): - m_manager(m), - m_util(m) { -} - -/** - \brief Find bounds of the form - - (<= x k) - (<= (+ x (* -1 y)) k) - (<= (+ x (* -1 t)) k) - (<= (+ t (* -1 x)) k) - - x and y are a bound variables, t is a ground term and k is a numeral - - It also detects >=, and the atom can be negated. -*/ -bool elim_bounds::is_bound(expr * n, var * & lower, var * & upper) { - upper = 0; - lower = 0; - bool neg = false; - if (m_manager.is_not(n)) { - n = to_app(n)->get_arg(0); - neg = true; - } - - bool le = false; - if (m_util.is_le(n)) { - SASSERT(m_util.is_numeral(to_app(n)->get_arg(1))); - n = to_app(n)->get_arg(0); - le = true; - } - else if (m_util.is_ge(n)) { - SASSERT(m_util.is_numeral(to_app(n)->get_arg(1))); - n = to_app(n)->get_arg(0); - le = false; - } - else { - return false; - } - - if (neg) - le = !le; - - if (is_var(n)) { - upper = to_var(n); - } - else if (m_util.is_add(n) && to_app(n)->get_num_args() == 2) { - expr * arg1 = to_app(n)->get_arg(0); - expr * arg2 = to_app(n)->get_arg(1); - if (is_var(arg1)) - upper = to_var(arg1); - else if (!is_ground(arg1)) - return false; - rational k; - bool is_int; - if (m_util.is_mul(arg2) && m_util.is_numeral(to_app(arg2)->get_arg(0), k, is_int) && k.is_minus_one()) { - arg2 = to_app(arg2)->get_arg(1); - if (is_var(arg2)) - lower = to_var(arg2); - else if (!is_ground(arg2)) - return false; // not supported - } - else { - return false; // not supported - } - } - else { - return false; - } - - if (!le) - std::swap(upper, lower); - - return true; -} - -bool elim_bounds::is_bound(expr * n) { - var * lower, * upper; - return is_bound(n, lower, upper); -} - -void elim_bounds::operator()(quantifier * q, expr_ref & r) { - if (!q->is_forall()) { - r = q; - return; - } - expr * n = q->get_expr(); - unsigned num_vars = q->get_num_decls(); - ptr_buffer atoms; - if (m_manager.is_or(n)) - atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args()); - else - atoms.push_back(n); - used_vars m_used_vars; - // collect non-candidates - unsigned sz = atoms.size(); - for (unsigned i = 0; i < sz; i++) { - expr * a = atoms[i]; - if (!is_bound(a)) - m_used_vars.process(a); - } - if (m_used_vars.uses_all_vars(q->get_num_decls())) { - r = q; - return; - } - // collect candidates - obj_hashtable m_lowers; - obj_hashtable m_uppers; - obj_hashtable m_candidate_set; - ptr_buffer m_candidates; -#define ADD_CANDIDATE(V) if (!m_lowers.contains(V) && !m_uppers.contains(V)) { m_candidate_set.insert(V); m_candidates.push_back(V); } - for (unsigned i = 0; i < sz; i++) { - expr * a = atoms[i]; - var * lower = 0; - var * upper = 0; - if (is_bound(a, lower, upper)) { - if (lower != 0 && !m_used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) { - ADD_CANDIDATE(lower); - m_lowers.insert(lower); - } - if (upper != 0 && !m_used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) { - ADD_CANDIDATE(upper); - m_uppers.insert(upper); - } - } - } - TRACE("elim_bounds", tout << "candidates:\n"; for (unsigned i = 0; i < m_candidates.size(); i++) tout << mk_pp(m_candidates[i], m_manager) << "\n";); - // remove candidates that have lower and upper bounds - for (unsigned i = 0; i < m_candidates.size(); i++) { - var * v = m_candidates[i]; - if (m_lowers.contains(v) && m_uppers.contains(v)) - m_candidate_set.erase(v); - } - TRACE("elim_bounds", tout << "candidates after filter:\n"; for (unsigned i = 0; i < m_candidates.size(); i++) tout << mk_pp(m_candidates[i], m_manager) << "\n";); - if (m_candidate_set.empty()) { - r = q; - return; - } - // remove bounds that contain variables in m_candidate_set - unsigned j = 0; - for (unsigned i = 0; i < sz; i++) { - expr * a = atoms[i]; - var * lower = 0; - var * upper = 0; - if (is_bound(a, lower, upper) && ((lower != 0 && m_candidate_set.contains(lower)) || (upper != 0 && m_candidate_set.contains(upper)))) - continue; - atoms[j] = a; - j++; - } - atoms.resize(j); - expr * new_body = 0; - switch (atoms.size()) { - case 0: - r = m_manager.mk_false(); - TRACE("elim_bounds", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";); - return; - case 1: - new_body = atoms[0]; - break; - default: - new_body = m_manager.mk_or(atoms.size(), atoms.c_ptr()); - break; - } - quantifier_ref new_q(m_manager); - new_q = m_manager.update_quantifier(q, new_body); - elim_unused_vars(m_manager, new_q, params_ref(), r); - TRACE("elim_bounds", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";); -} - -bool elim_bounds_star::visit_quantifier(quantifier * q) { - if (!q->is_forall() || q->get_num_patterns() != 0) - return true; - bool visited = true; - visit(q->get_expr(), visited); - return visited; -} - -void elim_bounds_star::reduce1_quantifier(quantifier * q) { - if (!q->is_forall() || q->get_num_patterns() != 0) { - cache_result(q, q, 0); - return; - } - quantifier_ref new_q(m); - expr * new_body = 0; - proof * new_pr; - get_cached(q->get_expr(), new_body, new_pr); - new_q = m.update_quantifier(q, new_body); - expr_ref r(m); - m_elim(new_q, r); - if (q == r.get()) { - cache_result(q, q, 0); - return; - } - proof_ref pr(m); - if (m.fine_grain_proofs()) - pr = m.mk_rewrite(q, r); // TODO: improve justification - cache_result(q, r, pr); -} - diff --git a/src/ast/simplifier/fpa_simplifier_plugin.cpp b/src/ast/simplifier/fpa_simplifier_plugin.cpp deleted file mode 100644 index 5775f1af0..000000000 --- a/src/ast/simplifier/fpa_simplifier_plugin.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/*++ -Copyright (c) 2015 Microsoft Corporation - -Module Name: - - fpa_simplifier_plugin.cpp - -Abstract: - - Simplifier for the floating-point theory - -Author: - - Christoph (cwinter) 2015-01-14 - ---*/ -#include"fpa_simplifier_plugin.h" - -fpa_simplifier_plugin::fpa_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b) : -simplifier_plugin(symbol("fpa"), m), -m_util(m), -m_rw(m) {} - -fpa_simplifier_plugin::~fpa_simplifier_plugin() {} - -bool fpa_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - - SASSERT(f->get_family_id() == get_family_id()); - - return m_rw.mk_app_core(f, num_args, args, result) != BR_FAILED; -} - -bool fpa_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { - set_reduce_invoked(); - - return m_rw.mk_eq_core(lhs, rhs, result) != BR_FAILED; -} - diff --git a/src/ast/simplifier/fpa_simplifier_plugin.h b/src/ast/simplifier/fpa_simplifier_plugin.h deleted file mode 100644 index 0ee8debf2..000000000 --- a/src/ast/simplifier/fpa_simplifier_plugin.h +++ /dev/null @@ -1,39 +0,0 @@ -/*++ -Copyright (c) 2015 Microsoft Corporation - -Module Name: - - fpa_simplifier_plugin.h - -Abstract: - - Simplifier for the floating-point theory - -Author: - - Christoph (cwinter) 2015-01-14 - ---*/ -#ifndef FPA_SIMPLIFIER_PLUGIN_H_ -#define FPA_SIMPLIFIER_PLUGIN_H_ - -#include"basic_simplifier_plugin.h" -#include"fpa_decl_plugin.h" -#include"fpa_rewriter.h" - -class fpa_simplifier_plugin : public simplifier_plugin { - fpa_util m_util; - fpa_rewriter m_rw; - -public: - fpa_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b); - ~fpa_simplifier_plugin(); - - - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - - virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result); - -}; - -#endif /* FPA_SIMPLIFIER_PLUGIN_H_ */ diff --git a/src/ast/simplifier/poly_simplifier_plugin.cpp b/src/ast/simplifier/poly_simplifier_plugin.cpp deleted file mode 100644 index e5e74ca56..000000000 --- a/src/ast/simplifier/poly_simplifier_plugin.cpp +++ /dev/null @@ -1,835 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - poly_simplifier_plugin.cpp - -Abstract: - - Abstract class for families that have polynomials. - -Author: - - Leonardo (leonardo) 2008-01-08 - ---*/ -#include"poly_simplifier_plugin.h" -#include"ast_pp.h" -#include"ast_util.h" -#include"ast_smt2_pp.h" -#include"ast_ll_pp.h" - -poly_simplifier_plugin::poly_simplifier_plugin(symbol const & fname, ast_manager & m, decl_kind add, decl_kind mul, decl_kind uminus, decl_kind sub, - decl_kind num): - simplifier_plugin(fname, m), - m_ADD(add), - m_MUL(mul), - m_SUB(sub), - m_UMINUS(uminus), - m_NUM(num), - m_curr_sort(0), - m_curr_sort_zero(0) { -} - -expr * poly_simplifier_plugin::mk_add(unsigned num_args, expr * const * args) { - SASSERT(num_args > 0); -#ifdef Z3DEBUG - // check for incorrect use of mk_add - for (unsigned i = 0; i < num_args; i++) { - SASSERT(!is_zero(args[i])); - } -#endif - if (num_args == 1) - return args[0]; - else - return m_manager.mk_app(m_fid, m_ADD, num_args, args); -} - -expr * poly_simplifier_plugin::mk_mul(unsigned num_args, expr * const * args) { - SASSERT(num_args > 0); -#ifdef Z3DEBUG - // check for incorrect use of mk_mul - set_curr_sort(args[0]); - SASSERT(!is_zero(args[0])); - numeral k; - for (unsigned i = 0; i < num_args; i++) { - SASSERT(!is_numeral(args[i], k) || !k.is_one()); - SASSERT(i == 0 || !is_numeral(args[i])); - } -#endif - if (num_args == 1) - return args[0]; - else if (num_args == 2) - return m_manager.mk_app(m_fid, m_MUL, args[0], args[1]); - else if (is_numeral(args[0])) - return m_manager.mk_app(m_fid, m_MUL, args[0], m_manager.mk_app(m_fid, m_MUL, num_args - 1, args+1)); - else - return m_manager.mk_app(m_fid, m_MUL, num_args, args); -} - -expr * poly_simplifier_plugin::mk_mul(numeral const & c, expr * body) { - numeral c_prime, d; - c_prime = norm(c); - if (c_prime.is_zero()) - return 0; - if (body == 0) - return mk_numeral(c_prime); - if (c_prime.is_one()) - return body; - if (is_numeral(body, d)) { - c_prime = norm(c_prime*d); - if (c_prime.is_zero()) - return 0; - return mk_numeral(c_prime); - } - set_curr_sort(body); - expr * args[2] = { mk_numeral(c_prime), body }; - return mk_mul(2, args); -} - -/** - \brief Traverse args, and copy the non-numeral exprs to result, and accumulate the - value of the numerals in k. -*/ -void poly_simplifier_plugin::process_monomial(unsigned num_args, expr * const * args, numeral & k, ptr_buffer & result) { - rational v; - for (unsigned i = 0; i < num_args; i++) { - expr * arg = args[i]; - if (is_numeral(arg, v)) - k *= v; - else - result.push_back(arg); - } -} - -#ifdef Z3DEBUG -/** - \brief Return true if m is a wellformed monomial. -*/ -bool poly_simplifier_plugin::wf_monomial(expr * m) const { - SASSERT(!is_add(m)); - if (is_mul(m)) { - app * curr = to_app(m); - expr * pp = 0; - if (is_numeral(curr->get_arg(0))) - pp = curr->get_arg(1); - else - pp = curr; - if (is_mul(pp)) { - for (unsigned i = 0; i < to_app(pp)->get_num_args(); i++) { - expr * arg = to_app(pp)->get_arg(i); - CTRACE("wf_monomial_bug", is_mul(arg), - tout << "m: " << mk_ismt2_pp(m, m_manager) << "\n"; - tout << "pp: " << mk_ismt2_pp(pp, m_manager) << "\n"; - tout << "arg: " << mk_ismt2_pp(arg, m_manager) << "\n"; - tout << "i: " << i << "\n"; - ); - SASSERT(!is_mul(arg)); - SASSERT(!is_numeral(arg)); - } - } - } - return true; -} - -/** - \brief Return true if m is a wellformed polynomial. -*/ -bool poly_simplifier_plugin::wf_polynomial(expr * m) const { - if (is_add(m)) { - for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { - expr * arg = to_app(m)->get_arg(i); - SASSERT(!is_add(arg)); - SASSERT(wf_monomial(arg)); - } - } - else if (is_mul(m)) { - SASSERT(wf_monomial(m)); - } - return true; -} -#endif - -/** - \brief Functor used to sort the elements of a monomial. - Force numeric constants to be in the beginning. -*/ -struct monomial_element_lt_proc { - poly_simplifier_plugin & m_plugin; - monomial_element_lt_proc(poly_simplifier_plugin & p):m_plugin(p) {} - bool operator()(expr * m1, expr * m2) const { - SASSERT(!m_plugin.is_numeral(m1) || !m_plugin.is_numeral(m2)); - if (m_plugin.is_numeral(m1)) - return true; - if (m_plugin.is_numeral(m2)) - return false; - return m1->get_id() < m2->get_id(); - } -}; - -/** - \brief Create a monomial (* args). -*/ -void poly_simplifier_plugin::mk_monomial(unsigned num_args, expr * * args, expr_ref & result) { - switch(num_args) { - case 0: - result = mk_one(); - break; - case 1: - result = args[0]; - break; - default: - std::stable_sort(args, args + num_args, monomial_element_lt_proc(*this)); - result = mk_mul(num_args, args); - SASSERT(wf_monomial(result)); - break; - } -} - -/** - \brief Return the body of the monomial. That is, the monomial without a coefficient. - Examples: (* 2 (* x y)) ==> (* x y) - (* x x) ==> (* x x) - x ==> x - 10 ==> 10 -*/ -expr * poly_simplifier_plugin::get_monomial_body(expr * m) { - TRACE("get_monomial_body_bug", tout << mk_pp(m, m_manager) << "\n";); - SASSERT(wf_monomial(m)); - if (!is_mul(m)) - return m; - if (is_numeral(to_app(m)->get_arg(0))) - return to_app(m)->get_arg(1); - return m; -} - -inline bool is_essentially_var(expr * n, family_id fid) { - SASSERT(is_var(n) || is_app(n)); - return is_var(n) || to_app(n)->get_family_id() != fid; -} - -/** - \brief Hack for ordering monomials. - We want an order << where - - (* c1 m1) << (* c2 m2) when m1->get_id() < m2->get_id(), and c1 and c2 are numerals. - - c << m when c is a numeral, and m is not. - - So, this method returns -1 for numerals, and the id of the body of the monomial -*/ -int poly_simplifier_plugin::get_monomial_body_order(expr * m) { - if (is_essentially_var(m, m_fid)) { - return m->get_id(); - } - else if (is_mul(m)) { - if (is_numeral(to_app(m)->get_arg(0))) - return to_app(m)->get_arg(1)->get_id(); - else - return m->get_id(); - } - else if (is_numeral(m)) { - return -1; - } - else { - return m->get_id(); - } -} - -void poly_simplifier_plugin::get_monomial_coeff(expr * m, numeral & result) { - SASSERT(!is_numeral(m)); - SASSERT(wf_monomial(m)); - if (!is_mul(m)) - result = numeral::one(); - else if (is_numeral(to_app(m)->get_arg(0), result)) - return; - else - result = numeral::one(); -} - -/** - \brief Return true if n1 and n2 can be written as k1 * t and k2 * t, where k1 and - k2 are numerals, or n1 and n2 are both numerals. -*/ -bool poly_simplifier_plugin::eq_monomials_modulo_k(expr * n1, expr * n2) { - bool is_num1 = is_numeral(n1); - bool is_num2 = is_numeral(n2); - if (is_num1 != is_num2) - return false; - if (is_num1 && is_num2) - return true; - return get_monomial_body(n1) == get_monomial_body(n2); -} - -/** - \brief Return (k1 + k2) * t (or (k1 - k2) * t when inv = true), where n1 = k1 * t, and n2 = k2 * t - Return false if the monomials cancel each other. -*/ -bool poly_simplifier_plugin::merge_monomials(bool inv, expr * n1, expr * n2, expr_ref & result) { - numeral k1; - numeral k2; - bool is_num1 = is_numeral(n1, k1); - bool is_num2 = is_numeral(n2, k2); - SASSERT(is_num1 == is_num2); - if (!is_num1 && !is_num2) { - get_monomial_coeff(n1, k1); - get_monomial_coeff(n2, k2); - SASSERT(eq_monomials_modulo_k(n1, n2)); - } - if (inv) - k1 -= k2; - else - k1 += k2; - if (k1.is_zero()) - return false; - if (is_num1 && is_num2) { - result = mk_numeral(k1); - } - else { - expr * b = get_monomial_body(n1); - if (k1.is_one()) - result = b; - else - result = m_manager.mk_app(m_fid, m_MUL, mk_numeral(k1), b); - } - TRACE("merge_monomials", tout << mk_pp(n1, m_manager) << "\n" << mk_pp(n2, m_manager) << "\n" << mk_pp(result, m_manager) << "\n";); - return true; -} - -/** - \brief Return a monomial equivalent to -n. -*/ -void poly_simplifier_plugin::inv_monomial(expr * n, expr_ref & result) { - set_curr_sort(n); - SASSERT(wf_monomial(n)); - rational v; - SASSERT(n != 0); - TRACE("inv_monomial_bug", tout << "n:\n" << mk_ismt2_pp(n, m_manager) << "\n";); - if (is_numeral(n, v)) { - TRACE("inv_monomial_bug", tout << "is numeral\n";); - v.neg(); - result = mk_numeral(v); - } - else { - TRACE("inv_monomial_bug", tout << "is not numeral\n";); - numeral k; - get_monomial_coeff(n, k); - expr * b = get_monomial_body(n); - k.neg(); - if (k.is_one()) - result = b; - else - result = m_manager.mk_app(m_fid, m_MUL, mk_numeral(k), b); - } -} - -/** - \brief Add a monomial n to result. -*/ -template -void poly_simplifier_plugin::add_monomial_core(expr * n, expr_ref_vector & result) { - if (is_zero(n)) - return; - if (Inv) { - expr_ref n_prime(m_manager); - inv_monomial(n, n_prime); - result.push_back(n_prime); - } - else { - result.push_back(n); - } -} - -void poly_simplifier_plugin::add_monomial(bool inv, expr * n, expr_ref_vector & result) { - if (inv) - add_monomial_core(n, result); - else - add_monomial_core(n, result); -} - -/** - \brief Copy the monomials in n to result. The monomials are inverted if inv is true. - Equivalent monomials are merged. -*/ -template -void poly_simplifier_plugin::process_sum_of_monomials_core(expr * n, expr_ref_vector & result) { - SASSERT(wf_polynomial(n)); - if (is_add(n)) { - for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) - add_monomial_core(to_app(n)->get_arg(i), result); - } - else { - add_monomial_core(n, result); - } -} - -void poly_simplifier_plugin::process_sum_of_monomials(bool inv, expr * n, expr_ref_vector & result) { - if (inv) - process_sum_of_monomials_core(n, result); - else - process_sum_of_monomials_core(n, result); -} - -/** - \brief Copy the (non-numeral) monomials in n to result. The monomials are inverted if inv is true. - Equivalent monomials are merged. The constant (numeral) monomials are accumulated in k. -*/ -void poly_simplifier_plugin::process_sum_of_monomials(bool inv, expr * n, expr_ref_vector & result, numeral & k) { - SASSERT(wf_polynomial(n)); - numeral val; - if (is_add(n)) { - for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) { - expr * arg = to_app(n)->get_arg(i); - if (is_numeral(arg, val)) { - k += inv ? -val : val; - } - else { - add_monomial(inv, arg, result); - } - } - } - else if (is_numeral(n, val)) { - k += inv ? -val : val; - } - else { - add_monomial(inv, n, result); - } -} - -/** - \brief Functor used to sort monomials. - Force numeric constants to be in the beginning of a polynomial. -*/ -struct monomial_lt_proc { - poly_simplifier_plugin & m_plugin; - monomial_lt_proc(poly_simplifier_plugin & p):m_plugin(p) {} - bool operator()(expr * m1, expr * m2) const { - return m_plugin.get_monomial_body_order(m1) < m_plugin.get_monomial_body_order(m2); - } -}; - -void poly_simplifier_plugin::mk_sum_of_monomials_core(unsigned sz, expr ** ms, expr_ref & result) { - switch (sz) { - case 0: - result = mk_zero(); - break; - case 1: - result = ms[0]; - break; - default: - result = mk_add(sz, ms); - break; - } -} - -/** - \brief Return true if m is essentially a variable, or is of the form (* c x), - where c is a numeral and x is essentially a variable. - Store the "variable" in x. -*/ -bool poly_simplifier_plugin::is_simple_monomial(expr * m, expr * & x) { - if (is_essentially_var(m, m_fid)) { - x = m; - return true; - } - if (is_app(m) && to_app(m)->get_num_args() == 2) { - expr * arg1 = to_app(m)->get_arg(0); - expr * arg2 = to_app(m)->get_arg(1); - if (is_numeral(arg1) && is_essentially_var(arg2, m_fid)) { - x = arg2; - return true; - } - } - return false; -} - -/** - \brief Return true if all monomials are simple, and each "variable" occurs only once. - The method assumes the monomials were sorted using monomial_lt_proc. -*/ -bool poly_simplifier_plugin::is_simple_sum_of_monomials(expr_ref_vector & monomials) { - expr * last_var = 0; - expr * curr_var = 0; - unsigned size = monomials.size(); - for (unsigned i = 0; i < size; i++) { - expr * m = monomials.get(i); - if (!is_simple_monomial(m, curr_var)) - return false; - if (curr_var == last_var) - return false; - last_var = curr_var; - } - return true; -} - -/** - \brief Store in result the sum of the given monomials. -*/ -void poly_simplifier_plugin::mk_sum_of_monomials(expr_ref_vector & monomials, expr_ref & result) { - switch (monomials.size()) { - case 0: - result = mk_zero(); - break; - case 1: - result = monomials.get(0); - break; - default: { - TRACE("mk_sum_sort", tout << "before\n"; for (unsigned i = 0; i < monomials.size(); i++) tout << mk_ll_pp(monomials.get(i), m_manager) << "\n";); - std::stable_sort(monomials.c_ptr(), monomials.c_ptr() + monomials.size(), monomial_lt_proc(*this)); - TRACE("mk_sum_sort", tout << "after\n"; for (unsigned i = 0; i < monomials.size(); i++) tout << mk_ll_pp(monomials.get(i), m_manager) << "\n";); - if (is_simple_sum_of_monomials(monomials)) { - mk_sum_of_monomials_core(monomials.size(), monomials.c_ptr(), result); - return; - } - ptr_buffer new_monomials; - expr * last_body = 0; - numeral last_coeff; - numeral coeff; - unsigned sz = monomials.size(); - for (unsigned i = 0; i < sz; i++) { - expr * m = monomials.get(i); - expr * body = 0; - if (!is_numeral(m, coeff)) { - body = get_monomial_body(m); - get_monomial_coeff(m, coeff); - } - if (last_body == body) { - last_coeff += coeff; - continue; - } - expr * new_m = mk_mul(last_coeff, last_body); - if (new_m) - new_monomials.push_back(new_m); - last_body = body; - last_coeff = coeff; - } - expr * new_m = mk_mul(last_coeff, last_body); - if (new_m) - new_monomials.push_back(new_m); - TRACE("mk_sum", for (unsigned i = 0; i < monomials.size(); i++) tout << mk_pp(monomials.get(i), m_manager) << "\n"; - tout << "======>\n"; - for (unsigned i = 0; i < new_monomials.size(); i++) tout << mk_pp(new_monomials.get(i), m_manager) << "\n";); - mk_sum_of_monomials_core(new_monomials.size(), new_monomials.c_ptr(), result); - break; - } } -} - -/** - \brief Auxiliary template for mk_add_core -*/ -template -void poly_simplifier_plugin::mk_add_core_core(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args >= 2); - expr_ref_vector monomials(m_manager); - process_sum_of_monomials_core(args[0], monomials); - for (unsigned i = 1; i < num_args; i++) { - process_sum_of_monomials_core(args[i], monomials); - } - TRACE("mk_add_core_bug", - for (unsigned i = 0; i < monomials.size(); i++) { - SASSERT(monomials.get(i) != 0); - tout << mk_ismt2_pp(monomials.get(i), m_manager) << "\n"; - }); - mk_sum_of_monomials(monomials, result); -} - -/** - \brief Return a sum of monomials. The method assume that each arg in args is a sum of monomials. - If inv is true, then all but the first argument in args are inverted. -*/ -void poly_simplifier_plugin::mk_add_core(bool inv, unsigned num_args, expr * const * args, expr_ref & result) { - TRACE("mk_add_core_bug", - for (unsigned i = 0; i < num_args; i++) { - SASSERT(args[i] != 0); - tout << mk_ismt2_pp(args[i], m_manager) << "\n"; - }); - switch (num_args) { - case 0: - result = mk_zero(); - break; - case 1: - result = args[0]; - break; - default: - if (inv) - mk_add_core_core(num_args, args, result); - else - mk_add_core_core(num_args, args, result); - break; - } -} - -void poly_simplifier_plugin::mk_add(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args > 0); - set_curr_sort(args[0]); - mk_add_core(false, num_args, args, result); -} - -void poly_simplifier_plugin::mk_add(expr * arg1, expr * arg2, expr_ref & result) { - expr * args[2] = { arg1, arg2 }; - mk_add(2, args, result); -} - -void poly_simplifier_plugin::mk_sub(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args > 0); - set_curr_sort(args[0]); - mk_add_core(true, num_args, args, result); -} - -void poly_simplifier_plugin::mk_sub(expr * arg1, expr * arg2, expr_ref & result) { - expr * args[2] = { arg1, arg2 }; - mk_sub(2, args, result); -} - -void poly_simplifier_plugin::mk_uminus(expr * arg, expr_ref & result) { - set_curr_sort(arg); - rational v; - if (is_numeral(arg, v)) { - v.neg(); - result = mk_numeral(v); - } - else { - expr_ref zero(mk_zero(), m_manager); - mk_sub(zero.get(), arg, result); - } -} - -/** - \brief Add monomial n to result, the coeff of n is stored in k. -*/ -void poly_simplifier_plugin::append_to_monomial(expr * n, numeral & k, ptr_buffer & result) { - SASSERT(wf_monomial(n)); - rational val; - if (is_numeral(n, val)) { - k *= val; - return; - } - get_monomial_coeff(n, val); - k *= val; - n = get_monomial_body(n); - - unsigned hd = result.size(); - result.push_back(n); - while (hd < result.size()) { - n = result[hd]; - if (is_mul(n)) { - result[hd] = result.back(); - result.pop_back(); - for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) { - result.push_back(to_app(n)->get_arg(i)); - } - } - else if (is_numeral(n, val)) { - k *= val; - result[hd] = result.back(); - result.pop_back(); - } - else { - ++hd; - } - } -} - -/** - \brief Return a sum of monomials that is equivalent to (* args[0] ... args[num_args-1]). - This method assumes that each arg[i] is a sum of monomials. -*/ -void poly_simplifier_plugin::mk_mul(unsigned num_args, expr * const * args, expr_ref & result) { - if (num_args == 1) { - result = args[0]; - return; - } - rational val; - if (num_args == 2 && is_numeral(args[0], val) && is_essentially_var(args[1], m_fid)) { - if (val.is_one()) - result = args[1]; - else if (val.is_zero()) - result = args[0]; - else - result = mk_mul(num_args, args); - return; - } - if (num_args == 2 && is_essentially_var(args[0], m_fid) && is_numeral(args[1], val)) { - if (val.is_one()) - result = args[0]; - else if (val.is_zero()) - result = args[1]; - else { - expr * inv_args[2] = { args[1], args[0] }; - result = mk_mul(2, inv_args); - } - return; - } - - TRACE("mk_mul_bug", - for (unsigned i = 0; i < num_args; i++) { - tout << mk_pp(args[i], m_manager) << "\n"; - }); - set_curr_sort(args[0]); - buffer szs; - buffer it; - vector > sums; - for (unsigned i = 0; i < num_args; i ++) { - it.push_back(0); - expr * arg = args[i]; - SASSERT(wf_polynomial(arg)); - sums.push_back(ptr_vector()); - ptr_vector & v = sums.back(); - if (is_add(arg)) { - v.append(to_app(arg)->get_num_args(), to_app(arg)->get_args()); - } - else { - v.push_back(arg); - } - szs.push_back(v.size()); - } - expr_ref_vector monomials(m_manager); - do { - rational k(1); - ptr_buffer m; - for (unsigned i = 0; i < num_args; i++) { - ptr_vector & v = sums[i]; - expr * arg = v[it[i]]; - TRACE("mk_mul_bug", tout << "k: " << k << " arg: " << mk_pp(arg, m_manager) << "\n";); - append_to_monomial(arg, k, m); - TRACE("mk_mul_bug", tout << "after k: " << k << "\n";); - } - expr_ref num(m_manager); - if (!k.is_zero() && !k.is_one()) { - num = mk_numeral(k); - m.push_back(num); - // bit-vectors can normalize - // to 1 during - // internalization. - if (is_numeral(num, k) && k.is_one()) { - m.pop_back(); - } - } - if (!k.is_zero()) { - expr_ref new_monomial(m_manager); - TRACE("mk_mul_bug", - for (unsigned i = 0; i < m.size(); i++) { - tout << mk_pp(m[i], m_manager) << "\n"; - }); - mk_monomial(m.size(), m.c_ptr(), new_monomial); - TRACE("mk_mul_bug", tout << "new_monomial:\n" << mk_pp(new_monomial, m_manager) << "\n";); - add_monomial_core(new_monomial, monomials); - } - } - while (product_iterator_next(szs.size(), szs.c_ptr(), it.c_ptr())); - mk_sum_of_monomials(monomials, result); -} - -void poly_simplifier_plugin::mk_mul(expr * arg1, expr * arg2, expr_ref & result) { - expr * args[2] = { arg1, arg2 }; - mk_mul(2, args, result); -} - -bool poly_simplifier_plugin::reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - unsigned i = 0; - for (; i < num_args; i++) - if (!is_numeral(args[i])) - break; - if (i == num_args) { - // all arguments are numerals - // check if arguments are different... - ptr_buffer buffer; - buffer.append(num_args, args); - std::sort(buffer.begin(), buffer.end(), ast_lt_proc()); - for (unsigned i = 0; i < num_args; i++) { - if (i > 0 && buffer[i] == buffer[i-1]) { - result = m_manager.mk_false(); - return true; - } - } - result = m_manager.mk_true(); - return true; - } - return false; -} - -bool poly_simplifier_plugin::reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - if (is_decl_of(f, m_fid, m_ADD)) { - SASSERT(num_args > 0); - set_curr_sort(args[0]); - expr_ref_buffer args1(m_manager); - for (unsigned i = 0; i < num_args; ++i) { - expr * arg = args[i]; - rational m = norm(mults[i]); - if (m.is_zero()) { - // skip - } - else if (m.is_one()) { - args1.push_back(arg); - } - else { - expr_ref k(m_manager); - k = mk_numeral(m); - expr_ref new_arg(m_manager); - mk_mul(k, args[i], new_arg); - args1.push_back(new_arg); - } - } - if (args1.empty()) { - result = mk_zero(); - } - else { - mk_add(args1.size(), args1.c_ptr(), result); - } - return true; - } - else { - return simplifier_plugin::reduce(f, num_args, mults, args, result); - } -} - -/** - \brief Return true if n is can be put into the form (+ v t) or (+ (- v) t) - \c inv = true will contain true if (- v) is found, and false otherwise. -*/ -bool poly_simplifier_plugin::is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) { - if (!is_add(n) || is_ground(n)) - return false; - - ptr_buffer args; - v = 0; - expr * curr = to_app(n); - bool stop = false; - inv = false; - while (!stop) { - expr * arg; - expr * neg_arg; - if (is_add(curr)) { - arg = to_app(curr)->get_arg(0); - curr = to_app(curr)->get_arg(1); - } - else { - arg = curr; - stop = true; - } - if (is_ground(arg)) { - TRACE("model_checker_bug", tout << "pushing:\n" << mk_pp(arg, m_manager) << "\n";); - args.push_back(arg); - } - else if (is_var(arg)) { - if (v != 0) - return false; // already found variable - v = to_var(arg); - } - else if (is_times_minus_one(arg, neg_arg) && is_var(neg_arg)) { - if (v != 0) - return false; // already found variable - v = to_var(neg_arg); - inv = true; - } - else { - return false; // non ground term. - } - } - if (v == 0) - return false; // did not find variable - SASSERT(!args.empty()); - mk_add(args.size(), args.c_ptr(), t); - return true; -} diff --git a/src/ast/simplifier/poly_simplifier_plugin.h b/src/ast/simplifier/poly_simplifier_plugin.h deleted file mode 100644 index ed6d506c5..000000000 --- a/src/ast/simplifier/poly_simplifier_plugin.h +++ /dev/null @@ -1,155 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - poly_simplifier_plugin.h - -Abstract: - - Abstract class for families that have polynomials. - -Author: - - Leonardo (leonardo) 2008-01-08 - ---*/ -#ifndef POLY_SIMPLIFIER_PLUGIN_H_ -#define POLY_SIMPLIFIER_PLUGIN_H_ - -#include "simplifier_plugin.h" - -/** - \brief Abstract class that provides simplification functions for polynomials. -*/ -class poly_simplifier_plugin : public simplifier_plugin { -protected: - typedef rational numeral; - decl_kind m_ADD; - decl_kind m_MUL; - decl_kind m_SUB; - decl_kind m_UMINUS; - decl_kind m_NUM; - sort * m_curr_sort; - expr * m_curr_sort_zero; - - expr * mk_add(unsigned num_args, expr * const * args); - expr * mk_add(expr * arg1, expr * arg2) { expr * args[2] = { arg1, arg2 }; return mk_add(2, args); } - expr * mk_mul(unsigned num_args, expr * const * args); - expr * mk_mul(expr * arg1, expr * arg2) { expr * args[2] = { arg1, arg2 }; return mk_mul(2, args); } - // expr * mk_sub(unsigned num_args, expr * const * args) { return m_manager.mk_app(m_fid, m_SUB, num_args, args); } - expr * mk_uminus(expr * arg) { return m_manager.mk_app(m_fid, m_UMINUS, arg); } - - void process_monomial(unsigned num_args, expr * const * args, numeral & k, ptr_buffer & result); - void mk_monomial(unsigned num_args, expr * * args, expr_ref & result); - bool eq_monomials_modulo_k(expr * n1, expr * n2); - bool merge_monomials(bool inv, expr * n1, expr * n2, expr_ref & result); - template - void add_monomial_core(expr * n, expr_ref_vector & result); - void add_monomial(bool inv, expr * n, expr_ref_vector & result); - template - void process_sum_of_monomials_core(expr * n, expr_ref_vector & result); - void process_sum_of_monomials(bool inv, expr * n, expr_ref_vector & result); - void process_sum_of_monomials(bool inv, expr * n, expr_ref_vector & result, numeral & k); - void mk_sum_of_monomials(expr_ref_vector & monomials, expr_ref & result); - template - void mk_add_core_core(unsigned num_args, expr * const * args, expr_ref & result); - void mk_add_core(bool inv, unsigned num_args, expr * const * args, expr_ref & result); - void append_to_monomial(expr * n, numeral & k, ptr_buffer & result); - expr * mk_mul(numeral const & c, expr * body); - void mk_sum_of_monomials_core(unsigned sz, expr ** ms, expr_ref & result); - bool is_simple_sum_of_monomials(expr_ref_vector & monomials); - bool is_simple_monomial(expr * m, expr * & x); - -public: - poly_simplifier_plugin(symbol const & fname, ast_manager & m, decl_kind add, decl_kind mul, decl_kind uminus, decl_kind sub, decl_kind num); - virtual ~poly_simplifier_plugin() {} - - /** - \brief Return true if the given expression is a numeral, and store its value in \c val. - */ - virtual bool is_numeral(expr * n, numeral & val) const = 0; - bool is_numeral(expr * n) const { return is_app_of(n, m_fid, m_NUM); } - bool is_zero(expr * n) const { - SASSERT(m_curr_sort_zero != 0); - SASSERT(m_manager.get_sort(n) == m_manager.get_sort(m_curr_sort_zero)); - return n == m_curr_sort_zero; - } - bool is_zero_safe(expr * n) { - set_curr_sort(m_manager.get_sort(n)); - return is_zero(n); - } - virtual bool is_minus_one(expr * n) const = 0; - virtual expr * get_zero(sort * s) const = 0; - - - /** - \brief Return true if n is of the form (* -1 r) - */ - bool is_times_minus_one(expr * n, expr * & r) const { - if (is_mul(n) && to_app(n)->get_num_args() == 2 && is_minus_one(to_app(n)->get_arg(0))) { - r = to_app(n)->get_arg(1); - return true; - } - return false; - } - - /** - \brief Return true if n is of the form: a <= b or a >= b. - */ - virtual bool is_le_ge(expr * n) const = 0; - - /** - \brief Return a constant representing the giving numeral and sort m_curr_sort. - */ - virtual app * mk_numeral(numeral const & n) = 0; - app * mk_zero() { return mk_numeral(numeral::zero()); } - app * mk_one() { return mk_numeral(numeral::one()); } - app * mk_minus_one() { return mk_numeral(numeral::minus_one()); } - - /** - \brief Normalize the given numeral with respect to m_curr_sort - */ - virtual numeral norm(numeral const & n) = 0; - - void set_curr_sort(sort * s) { - if (s != m_curr_sort) { - // avoid virtual function call - m_curr_sort = s; - m_curr_sort_zero = get_zero(m_curr_sort); - } - } - void set_curr_sort(expr * n) { set_curr_sort(m_manager.get_sort(n)); } - - bool is_add(expr const * n) const { return is_app_of(n, m_fid, m_ADD); } - bool is_mul(expr const * n) const { return is_app_of(n, m_fid, m_MUL); } - void mk_add(unsigned num_args, expr * const * args, expr_ref & result); - void mk_add(expr * arg1, expr * arg2, expr_ref & result); - void mk_sub(unsigned num_args, expr * const * args, expr_ref & result); - void mk_sub(expr * arg1, expr * arg2, expr_ref & result); - void mk_uminus(expr * arg, expr_ref & result); - void mk_mul(unsigned num_args, expr * const * args, expr_ref & result); - void mk_mul(expr * arg1, expr * arg2, expr_ref & result); - - virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result); - - virtual bool reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result); - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - return simplifier_plugin::reduce(f, num_args, args, result); - } - - - expr * get_monomial_body(expr * m); - int get_monomial_body_order(expr * m); - void get_monomial_coeff(expr * m, numeral & result); - void inv_monomial(expr * n, expr_ref & result); - - bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t); - -#ifdef Z3DEBUG - bool wf_monomial(expr * m) const; - bool wf_polynomial(expr * m) const; -#endif -}; - -#endif /* POLY_SIMPLIFIER_PLUGIN_H_ */ diff --git a/src/ast/simplifier/push_app_ite.cpp b/src/ast/simplifier/push_app_ite.cpp deleted file mode 100644 index e33f0d094..000000000 --- a/src/ast/simplifier/push_app_ite.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - push_app_ite.cpp - -Abstract: - - TODO: Write a better ite lifter - - -Author: - - Leonardo de Moura (leonardo) 2008-05-14. - -Revision History: - ---*/ -#include"push_app_ite.h" -#include"ast_pp.h" - -push_app_ite::push_app_ite(simplifier & s, bool conservative): - simplifier(s.get_manager()), - m_conservative(conservative) { - - borrow_plugins(s); -} - -push_app_ite::~push_app_ite() { - // the plugins were borrowed. So, release ownership. - m_plugins.release(); -} - -int push_app_ite::has_ite_arg(unsigned num_args, expr * const * args) { - for (unsigned i = 0; i < num_args; i++) - if (m.is_ite(args[i])) - return i; - return -1; -} - -void push_app_ite::apply(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & r) { - TRACE("push_app_ite", tout << "pushing app...\n";); - int ite_arg_idx = has_ite_arg(num_args, args); - if (ite_arg_idx < 0) { - mk_app(decl, num_args, args, r); - return; - } - app * ite = to_app(args[ite_arg_idx]); - expr * c = ite->get_arg(0); - expr * t = ite->get_arg(1); - expr * e = ite->get_arg(2); - expr ** args_prime = const_cast(args); - expr * old = args_prime[ite_arg_idx]; - args_prime[ite_arg_idx] = t; - expr_ref t_new(m); - apply(decl, num_args, args_prime, t_new); - args_prime[ite_arg_idx] = e; - expr_ref e_new(m); - apply(decl, num_args, args_prime, e_new); - args_prime[ite_arg_idx] = old; - expr * new_args[3] = { c, t_new, e_new }; - mk_app(ite->get_decl(), 3, new_args, r); -} - -/** - \brief Default (conservative) implementation. Return true if there one and only one ite-term argument. -*/ -bool push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * const * args) { - if (m.is_ite(decl)) - return false; - bool found_ite = false; - for (unsigned i = 0; i < num_args; i++) { - if (m.is_ite(args[i]) && !m.is_bool(args[i])) { - if (found_ite) { - if (m_conservative) - return false; - } - else { - found_ite = true; - } - } - } - CTRACE("push_app_ite", found_ite, tout << "found target for push app ite:\n"; - tout << decl->get_name(); - for (unsigned i = 0; i < num_args; i++) tout << " " << mk_pp(args[i], m); - tout << "\n";); - return found_ite; -} - -void push_app_ite::operator()(expr * s, expr_ref & r, proof_ref & p) { - expr * result; - proof * result_proof; - reduce_core(s); - get_cached(s, result, result_proof); - r = result; - switch (m.proof_mode()) { - case PGM_DISABLED: - p = m.mk_undef_proof(); - break; - case PGM_COARSE: - if (result == s) - p = m.mk_reflexivity(s); - else - p = m.mk_rewrite_star(s, result, 0, 0); - break; - case PGM_FINE: - if (result == s) - p = m.mk_reflexivity(s); - else - p = result_proof; - break; - } -} - -void push_app_ite::reduce_core(expr * n) { - if (!is_cached(n)) { - unsigned sz = m_todo.size(); - m_todo.push_back(n); - while (m_todo.size() != sz) { - expr * n = m_todo.back(); - if (is_cached(n)) - m_todo.pop_back(); - else if (visit_children(n)) { - m_todo.pop_back(); - reduce1(n); - } - } - } -} - -bool push_app_ite::visit_children(expr * n) { - bool visited = true; - unsigned j; - switch(n->get_kind()) { - case AST_VAR: - return true; - case AST_APP: - j = to_app(n)->get_num_args(); - while (j > 0) { - --j; - visit(to_app(n)->get_arg(j), visited); - } - return visited; - case AST_QUANTIFIER: - visit(to_quantifier(n)->get_expr(), visited); - return visited; - default: - UNREACHABLE(); - return true; - } -} - -void push_app_ite::reduce1(expr * n) { - switch (n->get_kind()) { - case AST_VAR: - cache_result(n, n, 0); - break; - case AST_APP: - reduce1_app(to_app(n)); - break; - case AST_QUANTIFIER: - reduce1_quantifier(to_quantifier(n)); - break; - default: - UNREACHABLE(); - } -} - -void push_app_ite::reduce1_app(app * n) { - m_args.reset(); - - func_decl * decl = n->get_decl(); - proof_ref p1(m); - get_args(n, m_args, p1); - - expr_ref r(m); - if (is_target(decl, m_args.size(), m_args.c_ptr())) - apply(decl, m_args.size(), m_args.c_ptr(), r); - else - mk_app(decl, m_args.size(), m_args.c_ptr(), r); - - if (!m.fine_grain_proofs()) - cache_result(n, r, 0); - else { - expr * s = m.mk_app(decl, m_args.size(), m_args.c_ptr()); - proof * p; - if (n == r) - p = 0; - else if (r != s) - p = m.mk_transitivity(p1, m.mk_rewrite(s, r)); - else - p = p1; - cache_result(n, r, p); - } -} - -void push_app_ite::reduce1_quantifier(quantifier * q) { - expr * new_body; - proof * new_body_pr; - get_cached(q->get_expr(), new_body, new_body_pr); - - quantifier * new_q = m.update_quantifier(q, new_body); - proof * p = q == new_q ? 0 : m.mk_quant_intro(q, new_q, new_body_pr); - cache_result(q, new_q, p); -} - -bool ng_push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * const * args) { - bool r = push_app_ite::is_target(decl, num_args, args); - if (!r) - return false; - for (unsigned i = 0; i < num_args; i++) - if (!is_ground(args[i])) - return true; - return false; -} - -ng_push_app_ite::ng_push_app_ite(simplifier & s, bool conservative): - push_app_ite(s, conservative) { -} diff --git a/src/ast/simplifier/push_app_ite.h b/src/ast/simplifier/push_app_ite.h deleted file mode 100644 index 104a7ea74..000000000 --- a/src/ast/simplifier/push_app_ite.h +++ /dev/null @@ -1,63 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - push_app_ite.h - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2008-05-14. - -Revision History: - ---*/ -#ifndef PUSH_APP_ITE_H_ -#define PUSH_APP_ITE_H_ - -#include"ast.h" -#include"simplifier.h" - -/** - \brief Functor for applying the following transformation: - - (f s (ite c t1 t2)) ==> (ite c (f s t1) (f s t2)) -*/ -class push_app_ite : public simplifier { -protected: - bool m_conservative; - int has_ite_arg(unsigned num_args, expr * const * args); - void apply(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & result); - virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args); - void reduce_core(expr * n); - bool visit_children(expr * n); - void reduce1(expr * n); - void reduce1_app(app * n); - void reduce1_quantifier(quantifier * q); - -public: - push_app_ite(simplifier & s, bool conservative = true); - virtual ~push_app_ite(); - void operator()(expr * s, expr_ref & r, proof_ref & p); -}; - -/** - \brief Variation of push_app_ite that applies the transformation on nonground terms only. - - \remark This functor uses the app::is_ground method. This method is not - completly precise, for instance, any term containing a quantifier is marked as non ground. -*/ -class ng_push_app_ite : public push_app_ite { -protected: - virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args); -public: - ng_push_app_ite(simplifier & s, bool conservative = true); - virtual ~ng_push_app_ite() {} -}; - -#endif /* PUSH_APP_ITE_H_ */ - diff --git a/src/ast/simplifier/seq_simplifier_plugin.cpp b/src/ast/simplifier/seq_simplifier_plugin.cpp deleted file mode 100644 index 0b7bddf0a..000000000 --- a/src/ast/simplifier/seq_simplifier_plugin.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/*++ -Copyright (c) 2016 Microsoft Corporation - -Module Name: - - seq_simplifier_plugin.cpp - -Abstract: - - Simplifier for the theory of sequences - -Author: - - Nikolaj Bjorner (nbjorner) 2016-02-05 - ---*/ -#include"seq_simplifier_plugin.h" - -seq_simplifier_plugin::seq_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b) : -simplifier_plugin(symbol("seq"), m), -m_util(m), -m_rw(m) {} - -seq_simplifier_plugin::~seq_simplifier_plugin() {} - -bool seq_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - - SASSERT(f->get_family_id() == get_family_id()); - - return m_rw.mk_app_core(f, num_args, args, result) != BR_FAILED; -} - -bool seq_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { - set_reduce_invoked(); - - return m_rw.mk_eq_core(lhs, rhs, result) != BR_FAILED; -} - diff --git a/src/ast/simplifier/seq_simplifier_plugin.h b/src/ast/simplifier/seq_simplifier_plugin.h deleted file mode 100644 index 45668678c..000000000 --- a/src/ast/simplifier/seq_simplifier_plugin.h +++ /dev/null @@ -1,39 +0,0 @@ -/*++ -Copyright (c) 2016 Microsoft Corporation - -Module Name: - - seq_simplifier_plugin.h - -Abstract: - - Simplifier for the sequence theory - -Author: - - Nikolaj Bjorner (nbjorner) 2016-02-05 - ---*/ -#ifndef SEQ_SIMPLIFIER_PLUGIN_H_ -#define SEQ_SIMPLIFIER_PLUGIN_H_ - -#include"basic_simplifier_plugin.h" -#include"seq_decl_plugin.h" -#include"seq_rewriter.h" - -class seq_simplifier_plugin : public simplifier_plugin { - seq_util m_util; - seq_rewriter m_rw; - -public: - seq_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b); - ~seq_simplifier_plugin(); - - - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - - virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result); - -}; - -#endif /* SEQ_SIMPLIFIER_PLUGIN_H_ */ diff --git a/src/ast/simplifier/simplifier.cpp b/src/ast/simplifier/simplifier.cpp deleted file mode 100644 index 498244919..000000000 --- a/src/ast/simplifier/simplifier.cpp +++ /dev/null @@ -1,962 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - simplifier.cpp - -Abstract: - - Expression simplifier. - -Author: - - Leonardo (leonardo) 2008-01-03 - -Notes: - ---*/ -#include"simplifier.h" -#include"var_subst.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" -#include"well_sorted.h" -#include"ast_smt_pp.h" - -simplifier::simplifier(ast_manager & m): - base_simplifier(m), - m_proofs(m), - m_subst_proofs(m), - m_need_reset(false), - m_use_oeq(false), - m_visited_quantifier(false), - m_ac_support(true) { -} - -void simplifier::register_plugin(plugin * p) { - m_plugins.register_plugin(p); -} - -simplifier::~simplifier() { - flush_cache(); -} - -void simplifier::enable_ac_support(bool flag) { - m_ac_support = flag; - ptr_vector::const_iterator it = m_plugins.begin(); - ptr_vector::const_iterator end = m_plugins.end(); - for (; it != end; ++it) { - if (*it != 0) - (*it)->enable_ac_support(flag); - } -} - -/** - \brief External interface for the simplifier. - A client will invoke operator()(s, r, p) to simplify s. - The result is stored in r. - When proof generation is enabled, a proof for the equivalence (or equisatisfiability) - of s and r is stored in p. - When proof generation is disabled, this method stores the "undefined proof" object in p. -*/ -void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) { - m_need_reset = true; - reinitialize(); - expr * s_orig = s; - (void)s_orig; - expr * old_s; - expr * result; - proof * result_proof; - switch (m.proof_mode()) { - case PGM_DISABLED: // proof generation is disabled. - reduce_core(s); - // after executing reduce_core, the result of the simplification is in the cache - get_cached(s, result, result_proof); - r = result; - p = m.mk_undef_proof(); - break; - case PGM_COARSE: // coarse proofs... in this case, we do not produce a step by step (fine grain) proof to show the equivalence (or equisatisfiability) of s an r. - m_subst_proofs.reset(); // m_subst_proofs is an auxiliary vector that is used to justify substitutions. See comment on method get_subst. - reduce_core(s); - get_cached(s, result, result_proof); - r = result; - if (result == s) - p = m.mk_reflexivity(s); - else { - remove_duplicates(m_subst_proofs); - p = m.mk_rewrite_star(s, result, m_subst_proofs.size(), m_subst_proofs.c_ptr()); - } - break; - case PGM_FINE: // fine grain proofs... in this mode, every proof step (or most of them) is described. - m_proofs.reset(); - old_s = 0; - // keep simplyfing until no further simplifications are possible. - while (s != old_s) { - TRACE("simplifier", tout << "simplification pass... " << s->get_id() << "\n";); - TRACE("simplifier_loop", tout << mk_ll_pp(s, m) << "\n";); - reduce_core(s); - get_cached(s, result, result_proof); - SASSERT(is_rewrite_proof(s, result, result_proof)); - if (result_proof != 0) { - m_proofs.push_back(result_proof); - } - old_s = s; - s = result; - } - SASSERT(s != 0); - r = s; - p = m_proofs.empty() ? m.mk_reflexivity(s) : m.mk_transitivity(m_proofs.size(), m_proofs.c_ptr()); - SASSERT(is_rewrite_proof(s_orig, r, p)); - break; - default: - UNREACHABLE(); - } -} - -void simplifier::flush_cache() { - m_cache.flush(); - ptr_vector::const_iterator it = m_plugins.begin(); - ptr_vector::const_iterator end = m_plugins.end(); - for (; it != end; ++it) { - if (*it != 0) { - (*it)->flush_caches(); - } - } -} - -bool simplifier::get_subst(expr * n, expr_ref & r, proof_ref & p) { - return false; -} - -void simplifier::reduce_core(expr * n1) { - if (!is_cached(n1)) { - // We do not assume m_todo is empty... So, we store the current size of the todo-stack. - unsigned sz = m_todo.size(); - m_todo.push_back(n1); - while (m_todo.size() != sz) { - expr * n = m_todo.back(); - if (is_cached(n)) - m_todo.pop_back(); - else if (visit_children(n)) { - // if all children were already simplified, then remove n from the todo stack and apply a - // simplification step to it. - m_todo.pop_back(); - reduce1(n); - } - if (m.canceled()) { - cache_result(n1, n1, 0); - break; - } - } - } -} - -/** - \brief Return true if all children of n have been already simplified. -*/ -bool simplifier::visit_children(expr * n) { - switch(n->get_kind()) { - case AST_VAR: - return true; - case AST_APP: - // The simplifier has support for flattening AC (associative-commutative) operators. - // The method ast_manager::mk_app is used to create the flat version of an AC operator. - // In Z3 1.x, we used multi-ary operators. This creates problems for the superposition engine. - // So, starting at Z3 2.x, only boolean operators can be multi-ary. - // Example: - // (and (and a b) (and c d)) --> (and a b c d) - // (+ (+ a b) (+ c d)) --> (+ a (+ b (+ c d))) - // Remark: The flattening is only applied if m_ac_support is true. - if (m_ac_support && to_app(n)->get_decl()->is_associative() && to_app(n)->get_decl()->is_commutative()) - return visit_ac(to_app(n)); - else { - bool visited = true; - unsigned j = to_app(n)->get_num_args(); - while (j > 0) { - --j; - visit(to_app(n)->get_arg(j), visited); - } - return visited; - } - case AST_QUANTIFIER: - return visit_quantifier(to_quantifier(n)); - default: - UNREACHABLE(); - return true; - } -} - -/** - \brief Visit the children of n assuming it is an AC (associative-commutative) operator. - - For example, if n is of the form (+ (+ a b) (+ c d)), this method - will return true if the nodes a, b, c and d have been already simplified. - The nodes (+ a b) and (+ c d) are not really checked. -*/ -bool simplifier::visit_ac(app * n) { - bool visited = true; - func_decl * decl = n->get_decl(); - SASSERT(m_ac_support); - SASSERT(decl->is_associative()); - SASSERT(decl->is_commutative()); - m_ac_marked.reset(); - ptr_buffer todo; - todo.push_back(n); - while (!todo.empty()) { - app * n = todo.back(); - todo.pop_back(); - if (m_ac_mark.is_marked(n)) - continue; - m_ac_mark.mark(n, true); - m_ac_marked.push_back(n); - SASSERT(n->get_decl() == decl); - unsigned i = n->get_num_args(); - while (i > 0) { - --i; - expr * arg = n->get_arg(i); - if (is_app_of(arg, decl)) - todo.push_back(to_app(arg)); - else - visit(arg, visited); - } - } - ptr_vector::const_iterator it = m_ac_marked.begin(); - ptr_vector::const_iterator end = m_ac_marked.end(); - for (; it != end; ++it) - m_ac_mark.mark(*it, false); - return visited; -} - -bool simplifier::visit_quantifier(quantifier * n) { - m_visited_quantifier = true; - bool visited = true; - unsigned j = to_quantifier(n)->get_num_patterns(); - while (j > 0) { - --j; - visit(to_quantifier(n)->get_pattern(j), visited); - } - j = to_quantifier(n)->get_num_no_patterns(); - while (j > 0) { - --j; - visit(to_quantifier(n)->get_no_pattern(j), visited); - } - visit(to_quantifier(n)->get_expr(), visited); - return visited; -} - -/** - \brief Simplify n and store the result in the cache. -*/ -void simplifier::reduce1(expr * n) { - switch (n->get_kind()) { - case AST_VAR: - cache_result(n, n, 0); - break; - case AST_APP: - reduce1_app(to_app(n)); - break; - case AST_QUANTIFIER: - reduce1_quantifier(to_quantifier(n)); - break; - default: - UNREACHABLE(); - } -} - -/** - \brief Simplify the given application using the cached values, - associativity flattening, the given substitution, and family/theory - specific simplifications via plugins. -*/ -void simplifier::reduce1_app(app * n) { - expr_ref r(m); - proof_ref p(m); - TRACE("reduce", tout << "reducing...\n" << mk_pp(n, m) << "\n";); - if (get_subst(n, r, p)) { - TRACE("reduce", tout << "applying substitution...\n";); - cache_result(n, r, p); - return; - } - - func_decl * decl = n->get_decl(); - if (m_ac_support && decl->is_associative() && decl->is_commutative()) - reduce1_ac_app_core(n); - else - reduce1_app_core(n); -} - - -void simplifier::reduce1_app_core(app * n) { - m_args.reset(); - func_decl * decl = n->get_decl(); - proof_ref p1(m); - // Stores the new arguments of n in m_args. - // Let n be of the form - // (decl arg_0 ... arg_{n-1}) - // then - // m_args contains [arg_0', ..., arg_{n-1}'], - // where arg_i' is the simplification of arg_i - // and - // p1 is a proof for - // (decl arg_0 ... arg_{n-1}) is equivalente/equisatisfiable to (decl arg_0' ... arg_{n-1}') - // p1 is built using the congruence proof step and the proofs for arg_0' ... arg_{n-1}'. - // Of course, p1 is 0 if proofs are not enabled or coarse grain proofs are used. - bool has_new_args = get_args(n, m_args, p1); - // The following if implements a simple trick. - // If none of the arguments have been simplified, and n is not a theory symbol, - // Then no simplification is possible, and we can cache the result of the simplification of n as n. - if (has_new_args || decl->get_family_id() != null_family_id) { - expr_ref r(m); - TRACE("reduce", tout << "reduce1_app\n"; for(unsigned i = 0; i < m_args.size(); i++) tout << mk_ll_pp(m_args[i], m);); - // the method mk_app invokes get_subst and plugins to simplify - // (decl arg_0' ... arg_{n-1}') - mk_app(decl, m_args.size(), m_args.c_ptr(), r); - if (!m.fine_grain_proofs()) { - cache_result(n, r, 0); - } - else { - expr * s = m.mk_app(decl, m_args.size(), m_args.c_ptr()); - proof * p; - if (n == r) - p = 0; - else if (r != s) - // we use a "theory rewrite generic proof" to justify the step - // s = (decl arg_0' ... arg_{n-1}') --> r - p = m.mk_transitivity(p1, m.mk_rewrite(s, r)); - else - p = p1; - cache_result(n, r, p); - } - } - else { - cache_result(n, n, 0); - } -} - -bool is_ac_list(app * n, ptr_vector & args) { - args.reset(); - func_decl * f = n->get_decl(); - app * curr = n; - while (true) { - if (curr->get_num_args() != 2) - return false; - expr * arg1 = curr->get_arg(0); - if (is_app_of(arg1, f)) - return false; - args.push_back(arg1); - expr * arg2 = curr->get_arg(1); - if (!is_app_of(arg2, f)) { - args.push_back(arg2); - return true; - } - curr = to_app(arg2); - } -} - -bool is_ac_vector(app * n) { - func_decl * f = n->get_decl(); - unsigned num_args = n->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - if (is_app_of(n->get_arg(i), f)) - return false; - } - return true; -} - -void simplifier::reduce1_ac_app_core(app * n) { - app_ref n_c(m); - proof_ref p1(m); - mk_ac_congruent_term(n, n_c, p1); - TRACE("ac", tout << "expr:\n" << mk_pp(n, m) << "\ncongruent term:\n" << mk_pp(n_c, m) << "\n";); - expr_ref r(m); - func_decl * decl = n->get_decl(); - family_id fid = decl->get_family_id(); - plugin * p = get_plugin(fid); - if (is_ac_vector(n_c)) { - if (p != 0 && p->reduce(decl, n_c->get_num_args(), n_c->get_args(), r)) { - // done... - } - else { - r = n_c; - } - } - else if (is_ac_list(n_c, m_args)) { - // m_args contains the arguments... - if (p != 0 && p->reduce(decl, m_args.size(), m_args.c_ptr(), r)) { - // done... - } - else { - r = m.mk_app(decl, m_args.size(), m_args.c_ptr()); - } - } - else { - m_args.reset(); - m_mults.reset(); - get_ac_args(n_c, m_args, m_mults); - TRACE("ac", tout << "AC args:\n"; - for (unsigned i = 0; i < m_args.size(); i++) { - tout << mk_pp(m_args[i], m) << " * " << m_mults[i] << "\n"; - }); - if (p != 0 && p->reduce(decl, m_args.size(), m_mults.c_ptr(), m_args.c_ptr(), r)) { - // done... - } - else { - ptr_buffer new_args; - expand_args(m_args.size(), m_mults.c_ptr(), m_args.c_ptr(), new_args); - r = m.mk_app(decl, new_args.size(), new_args.c_ptr()); - } - } - TRACE("ac", tout << "AC result:\n" << mk_pp(r, m) << "\n";); - - if (!m.fine_grain_proofs()) { - cache_result(n, r, 0); - } - else { - proof * p; - if (n == r.get()) - p = 0; - else if (r.get() != n_c.get()) - p = m.mk_transitivity(p1, m.mk_rewrite(n_c, r)); - else - p = p1; - cache_result(n, r, p); - } -} - -static unsigned g_rewrite_lemma_id = 0; - -void simplifier::dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr * const * args, expr* result) { - expr_ref arg(m); - arg = m.mk_app(decl, num_args, args); - if (arg.get() != result) { - char buffer[128]; -#ifdef _WINDOWS - sprintf_s(buffer, ARRAYSIZE(buffer), "lemma_%d.smt", g_rewrite_lemma_id); -#else - sprintf(buffer, "rewrite_lemma_%d.smt", g_rewrite_lemma_id); -#endif - ast_smt_pp pp(m); - pp.set_benchmark_name("rewrite_lemma"); - pp.set_status("unsat"); - expr_ref n(m); - n = m.mk_not(m.mk_eq(arg.get(), result)); - std::ofstream out(buffer); - pp.display(out, n); - out.close(); - ++g_rewrite_lemma_id; - } -} - -/** - \brief Return in \c result an expression \c e equivalent to (f args[0] ... args[num_args - 1]), and - store in \c pr a proof for (= (f args[0] ... args[num_args - 1]) e) - - If e is identical to (f args[0] ... args[num_args - 1]), then pr is set to 0. -*/ -void simplifier::mk_app(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & result) { - m_need_reset = true; - if (m.is_eq(decl)) { - sort * s = m.get_sort(args[0]); - plugin * p = get_plugin(s->get_family_id()); - if (p != 0 && p->reduce_eq(args[0], args[1], result)) - return; - } - else if (m.is_distinct(decl)) { - sort * s = m.get_sort(args[0]); - plugin * p = get_plugin(s->get_family_id()); - if (p != 0 && p->reduce_distinct(num_args, args, result)) - return; - } - family_id fid = decl->get_family_id(); - plugin * p = get_plugin(fid); - if (p != 0 && p->reduce(decl, num_args, args, result)) { - //uncomment this line if you want to trace rewrites as lemmas: - //dump_rewrite_lemma(decl, num_args, args, result.get()); - return; - } - - result = m.mk_app(decl, num_args, args); -} - -/** - \brief Create a term congruence to n (f a[0] ... a[num_args-1]) using the - cached values for the a[i]'s. Store the result in r, and the proof for (= n r) in p. - If n and r are identical, then set p to 0. -*/ -void simplifier::mk_congruent_term(app * n, app_ref & r, proof_ref & p) { - bool has_new_args = false; - ptr_vector args; - ptr_vector proofs; - unsigned num = n->get_num_args(); - for (unsigned j = 0; j < num; j++) { - expr * arg = n->get_arg(j); - expr * new_arg; - proof * arg_proof; - get_cached(arg, new_arg, arg_proof); - - CTRACE("simplifier_bug", (arg != new_arg) != (arg_proof != 0), - tout << mk_ll_pp(arg, m) << "\n---->\n" << mk_ll_pp(new_arg, m) << "\n"; - tout << "#" << arg->get_id() << " #" << new_arg->get_id() << "\n"; - tout << arg << " " << new_arg << "\n";); - - - if (arg != new_arg) { - has_new_args = true; - proofs.push_back(arg_proof); - SASSERT(arg_proof); - } - else { - SASSERT(arg_proof == 0); - } - args.push_back(new_arg); - } - if (has_new_args) { - r = m.mk_app(n->get_decl(), args.size(), args.c_ptr()); - if (m_use_oeq) - p = m.mk_oeq_congruence(n, r, proofs.size(), proofs.c_ptr()); - else - p = m.mk_congruence(n, r, proofs.size(), proofs.c_ptr()); - } - else { - r = n; - p = 0; - } -} - -/** - \brief Store the new arguments of \c n in result. Store in p a proof for - (= n (f result[0] ... result[num_args - 1])), where f is the function symbol of n. - - If there are no new arguments or fine grain proofs are disabled, then p is set to 0. - - Return true there are new arguments. -*/ -bool simplifier::get_args(app * n, ptr_vector & result, proof_ref & p) { - bool has_new_args = false; - unsigned num = n->get_num_args(); - if (m.fine_grain_proofs()) { - app_ref r(m); - mk_congruent_term(n, r, p); - result.append(r->get_num_args(), r->get_args()); - SASSERT(n->get_num_args() == result.size()); - has_new_args = r != n; - } - else { - p = 0; - for (unsigned j = 0; j < num; j++) { - expr * arg = n->get_arg(j); - expr * new_arg; - proof * arg_proof; - get_cached(arg, new_arg, arg_proof); - if (arg != new_arg) { - has_new_args = true; - } - result.push_back(new_arg); - } - } - return has_new_args; -} - -/** - \brief Create a term congruence to n (where n is an expression such as: (f (f a_1 a_2) (f a_3 (f a_4 a_5))) using the - cached values for the a_i's. Store the result in r, and the proof for (= n r) in p. - If n and r are identical, then set p to 0. -*/ -void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) { - SASSERT(m_ac_support); - func_decl * f = n->get_decl(); - - m_ac_cache.reset(); - m_ac_pr_cache.reset(); - - ptr_buffer todo; - ptr_buffer new_args; - ptr_buffer new_arg_prs; - todo.push_back(n); - while (!todo.empty()) { - app * curr = todo.back(); - if (m_ac_cache.contains(curr)) { - todo.pop_back(); - continue; - } - bool visited = true; - bool has_new_arg = false; - new_args.reset(); - new_arg_prs.reset(); - unsigned num_args = curr->get_num_args(); - for (unsigned j = 0; j < num_args; j ++) { - expr * arg = curr->get_arg(j); - if (is_app_of(arg, f)) { - app * new_arg = 0; - if (m_ac_cache.find(to_app(arg), new_arg)) { - SASSERT(new_arg != 0); - new_args.push_back(new_arg); - if (arg != new_arg) - has_new_arg = true; - if (m.fine_grain_proofs()) { - proof * pr = 0; - m_ac_pr_cache.find(to_app(arg), pr); - if (pr != 0) - new_arg_prs.push_back(pr); - } - } - else { - visited = false; - todo.push_back(to_app(arg)); - } - } - else { - expr * new_arg = 0; - proof * pr; - get_cached(arg, new_arg, pr); - new_args.push_back(new_arg); - if (arg != new_arg) - has_new_arg = true; - if (m.fine_grain_proofs() && pr != 0) - new_arg_prs.push_back(pr); - } - } - if (visited) { - SASSERT(new_args.size() == curr->get_num_args()); - todo.pop_back(); - if (!has_new_arg) { - m_ac_cache.insert(curr, curr); - if (m.fine_grain_proofs()) - m_ac_pr_cache.insert(curr, 0); - } - else { - app * new_curr = m.mk_app(f, new_args.size(), new_args.c_ptr()); - m_ac_cache.insert(curr, new_curr); - if (m.fine_grain_proofs()) { - proof * p = m.mk_congruence(curr, new_curr, new_arg_prs.size(), new_arg_prs.c_ptr()); - m_ac_pr_cache.insert(curr, p); - } - } - } - } - - SASSERT(m_ac_cache.contains(n)); - app * new_n = 0; - m_ac_cache.find(n, new_n); - r = new_n; - if (m.fine_grain_proofs()) { - proof * new_pr = 0; - m_ac_pr_cache.find(n, new_pr); - p = new_pr; - } -} - -#define White 0 -#define Grey 1 -#define Black 2 - -#ifdef Z3DEBUG -static int get_color(obj_map & colors, expr * n) { - obj_map::obj_map_entry * entry = colors.insert_if_not_there2(n, White); - return entry->get_data().m_value; -} -#endif - -static bool visit_ac_children(func_decl * f, expr * n, obj_map & colors, ptr_buffer & todo, ptr_buffer & result) { - if (is_app_of(n, f)) { - unsigned num_args = to_app(n)->get_num_args(); - bool visited = true; - // Put the arguments in 'result' in reverse order. - // Reason: preserve the original order of the arguments in the final result. - // Remark: get_ac_args will traverse 'result' backwards. - for (unsigned i = 0; i < num_args; i++) { - expr * arg = to_app(n)->get_arg(i); - obj_map::obj_map_entry * entry = colors.insert_if_not_there2(arg, White); - if (entry->get_data().m_value == White) { - todo.push_back(arg); - visited = false; - } - } - return visited; - } - else { - return true; - } -} - -void simplifier::ac_top_sort(app * n, ptr_buffer & result) { - ptr_buffer todo; - func_decl * f = n->get_decl(); - obj_map & colors = m_colors; - colors.reset(); - todo.push_back(n); - while (!todo.empty()) { - expr * curr = todo.back(); - int color; - obj_map::obj_map_entry * entry = colors.insert_if_not_there2(curr, White); - SASSERT(entry); - color = entry->get_data().m_value; - switch (color) { - case White: - // Remark: entry becomes invalid if an element is inserted into the hashtable. - // So, I must set Grey before executing visit_ac_children. - entry->get_data().m_value = Grey; - SASSERT(get_color(colors, curr) == Grey); - if (visit_ac_children(f, curr, colors, todo, result)) { - // If visit_ac_children succeeded, then the hashtable was not modified, - // and entry is still valid. - SASSERT(todo.back() == curr); - entry->get_data().m_value = Black; - SASSERT(get_color(colors, curr) == Black); - result.push_back(curr); - todo.pop_back(); - } - break; - case Grey: - SASSERT(visit_ac_children(f, curr, colors, todo, result)); - SASSERT(entry); - entry->get_data().m_value = Black; - SASSERT(get_color(colors, curr) == Black); - result.push_back(curr); - SASSERT(todo.back() == curr); - todo.pop_back(); - break; - case Black: - todo.pop_back(); - break; - default: - UNREACHABLE(); - } - } -} - -void simplifier::get_ac_args(app * n, ptr_vector & args, vector & mults) { - SASSERT(m_ac_support); - ptr_buffer sorted_exprs; - ac_top_sort(n, sorted_exprs); - SASSERT(!sorted_exprs.empty()); - SASSERT(sorted_exprs[sorted_exprs.size()-1] == n); - - TRACE("ac", tout << mk_ll_pp(n, m, true, false) << "#" << n->get_id() << "\nsorted expressions...\n"; - for (unsigned i = 0; i < sorted_exprs.size(); i++) { - tout << "#" << sorted_exprs[i]->get_id() << " "; - } - tout << "\n";); - - m_ac_mults.reset(); - m_ac_mults.insert(n, rational(1)); - func_decl * decl = n->get_decl(); - unsigned j = sorted_exprs.size(); - while (j > 0) { - --j; - expr * curr = sorted_exprs[j]; - rational mult; - m_ac_mults.find(curr, mult); - SASSERT(!mult.is_zero()); - if (is_app_of(curr, decl)) { - unsigned num_args = to_app(curr)->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = to_app(curr)->get_arg(i); - rational zero; - obj_map::obj_map_entry * entry = m_ac_mults.insert_if_not_there2(arg, zero); - entry->get_data().m_value += mult; - } - } - else { - args.push_back(curr); - mults.push_back(mult); - } - } -} - -void simplifier::reduce1_quantifier(quantifier * q) { - expr * new_body; - proof * new_body_pr; - SASSERT(is_well_sorted(m, q)); - get_cached(q->get_expr(), new_body, new_body_pr); - - quantifier_ref q1(m); - proof * p1 = 0; - - if (is_quantifier(new_body) && - to_quantifier(new_body)->is_forall() == q->is_forall() && - !to_quantifier(q)->has_patterns() && - !to_quantifier(new_body)->has_patterns()) { - - quantifier * nested_q = to_quantifier(new_body); - - ptr_buffer sorts; - buffer names; - sorts.append(q->get_num_decls(), q->get_decl_sorts()); - names.append(q->get_num_decls(), q->get_decl_names()); - sorts.append(nested_q->get_num_decls(), nested_q->get_decl_sorts()); - names.append(nested_q->get_num_decls(), nested_q->get_decl_names()); - - q1 = m.mk_quantifier(q->is_forall(), - sorts.size(), - sorts.c_ptr(), - names.c_ptr(), - nested_q->get_expr(), - std::min(q->get_weight(), nested_q->get_weight()), - q->get_qid(), - q->get_skid(), - 0, 0, 0, 0); - SASSERT(is_well_sorted(m, q1)); - - if (m.fine_grain_proofs()) { - quantifier * q0 = m.update_quantifier(q, new_body); - proof * p0 = q == q0 ? 0 : m.mk_quant_intro(q, q0, new_body_pr); - p1 = m.mk_pull_quant(q0, q1); - p1 = m.mk_transitivity(p0, p1); - } - } - else { - ptr_buffer new_patterns; - ptr_buffer new_no_patterns; - expr * new_pattern; - proof * new_pattern_pr; - - // Remark: we can ignore the proofs for the patterns. - unsigned num = q->get_num_patterns(); - for (unsigned i = 0; i < num; i++) { - get_cached(q->get_pattern(i), new_pattern, new_pattern_pr); - if (m.is_pattern(new_pattern)) { - new_patterns.push_back(new_pattern); - } - } - num = q->get_num_no_patterns(); - for (unsigned i = 0; i < num; i++) { - get_cached(q->get_no_pattern(i), new_pattern, new_pattern_pr); - new_no_patterns.push_back(new_pattern); - } - - remove_duplicates(new_patterns); - remove_duplicates(new_no_patterns); - - q1 = m.mk_quantifier(q->is_forall(), - q->get_num_decls(), - q->get_decl_sorts(), - q->get_decl_names(), - new_body, - q->get_weight(), - q->get_qid(), - q->get_skid(), - new_patterns.size(), - new_patterns.c_ptr(), - new_no_patterns.size(), - new_no_patterns.c_ptr()); - SASSERT(is_well_sorted(m, q1)); - - TRACE("simplifier", tout << mk_pp(q, m) << "\n" << mk_pp(q1, m) << "\n";); - if (m.fine_grain_proofs()) { - if (q != q1 && !new_body_pr) { - new_body_pr = m.mk_rewrite(q->get_expr(), new_body); - } - p1 = q == q1 ? 0 : m.mk_quant_intro(q, q1, new_body_pr); - } - } - - expr_ref r(m); - elim_unused_vars(m, q1, params_ref(), r); - - proof * pr = 0; - if (m.fine_grain_proofs()) { - proof * p2 = 0; - if (q1.get() != r.get()) - p2 = m.mk_elim_unused_vars(q1, r); - pr = m.mk_transitivity(p1, p2); - } - - cache_result(q, r, pr); -} - -/** - \see release_plugins -*/ -void simplifier::borrow_plugins(simplifier const & s) { - ptr_vector::const_iterator it = s.begin_plugins(); - ptr_vector::const_iterator end = s.end_plugins(); - for (; it != end; ++it) - register_plugin(*it); -} - -/** - \brief Make the simplifier behave as a pre-simplifier: No AC, and plugins are marked in pre-simplification mode. -*/ -void simplifier::enable_presimp() { - enable_ac_support(false); - ptr_vector::const_iterator it = begin_plugins(); - ptr_vector::const_iterator end = end_plugins(); - for (; it != end; ++it) - (*it)->enable_presimp(true); -} - -/** - \brief This method should be invoked if the plugins of this simplifier were borrowed from a different simplifier. -*/ -void simplifier::release_plugins() { - m_plugins.release(); -} - -void subst_simplifier::set_subst_map(expr_map * s) { - flush_cache(); - m_subst_map = s; -} - -bool subst_simplifier::get_subst(expr * n, expr_ref & r, proof_ref & p) { - if (m_subst_map && m_subst_map->contains(n)) { - expr * _r; - proof * _p = 0; - m_subst_map->get(n, _r, _p); - r = _r; - p = _p; - if (m.coarse_grain_proofs()) - m_subst_proofs.push_back(p); - return true; - } - return false; -} - -static void push_core(ast_manager & m, expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) { - SASSERT(pr == 0 || m.is_undef_proof(pr) || e == m.get_fact(pr)); - TRACE("preprocessor", - tout << mk_pp(e, m) << "\n"; - if (pr) tout << mk_ll_pp(pr, m) << "\n\n";); - if (m.is_true(e)) - return; - result.push_back(e); - if (m.proofs_enabled()) - result_prs.push_back(pr); -} - -static void push_and(ast_manager & m, app * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) { - unsigned num = e->get_num_args(); - TRACE("push_and", tout << mk_pp(e, m) << "\n";); - for (unsigned i = 0; i < num; i++) - push_assertion(m, e->get_arg(i), m.mk_and_elim(pr, i), result, result_prs); -} - -static void push_not_or(ast_manager & m, app * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) { - unsigned num = e->get_num_args(); - TRACE("push_not_or", tout << mk_pp(e, m) << "\n";); - for (unsigned i = 0; i < num; i++) { - expr * child = e->get_arg(i); - if (m.is_not(child)) { - expr * not_child = to_app(child)->get_arg(0); - push_assertion(m, not_child, m.mk_not_or_elim(pr, i), result, result_prs); - } - else { - expr_ref not_child(m); - not_child = m.mk_not(child); - push_assertion(m, not_child, m.mk_not_or_elim(pr, i), result, result_prs); - } - } -} - -void push_assertion(ast_manager & m, expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) { - CTRACE("push_assertion", !(pr == 0 || m.is_undef_proof(pr) || m.get_fact(pr) == e), - tout << mk_pp(e, m) << "\n" << mk_pp(m.get_fact(pr), m) << "\n";); - SASSERT(pr == 0 || m.is_undef_proof(pr) || m.get_fact(pr) == e); - if (m.is_and(e)) - push_and(m, to_app(e), pr, result, result_prs); - else if (m.is_not(e) && m.is_or(to_app(e)->get_arg(0))) - push_not_or(m, to_app(to_app(e)->get_arg(0)), pr, result, result_prs); - else - push_core(m, e, pr, result, result_prs); -} - diff --git a/src/ast/simplifier/simplifier.h b/src/ast/simplifier/simplifier.h deleted file mode 100644 index 899b25810..000000000 --- a/src/ast/simplifier/simplifier.h +++ /dev/null @@ -1,232 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - simplifier.h - -Abstract: - - Generic expression simplifier with support for theory specific "plugins". - -Author: - - Leonardo (leonardo) 2008-01-03 - -Notes: - ---*/ -#ifndef SIMPLIFIER_H_ -#define SIMPLIFIER_H_ - -#include"base_simplifier.h" -#include"simplifier_plugin.h" -#include"plugin_manager.h" -#include"ast_util.h" -#include"obj_hashtable.h" - -/** - \brief Local simplifier. - Proof production can be enabled/disabled. - - The simplifier can also apply substitutions during the - simplification. A substitution is a mapping from expression - to expression+proof, where for each entry e_1->(e_2,p) p is - a proof for (= e_1 e_2). - - The simplifier can also generate coarse grain proofs. In a coarse - proof, local rewrite steps are omitted, and only the substitutions - used are tracked. - - Example: - - Consider the expression (+ a b), and the substitution b->(0, p) - When fine grain proofs are enabled, the simplifier will produce the - following proof - - Assume the id of the proof object p is $0. Note that p is a proof for (= b 0). - - $1: [reflexivity] |- (= a a) - $2: [congruence] $1 $0 |- (= (+ a b) (+ a 0)) - $3: [plus-0] |- (= (+ a 0) a) - $4: [transitivity] $2 $3 |- (= (+ a b) a) - - When coarse grain proofs are enabled, the simplifier produces the following - proof: - - $1: [simplifier] $0 |- (= (+ a b) a) -*/ -class simplifier : public base_simplifier { -protected: - typedef simplifier_plugin plugin; - plugin_manager m_plugins; - ptr_vector m_args; - vector m_mults; - ptr_vector m_args2; - - proof_ref_vector m_proofs; // auxiliary vector for implementing exhaustive simplification. - proof_ref_vector m_subst_proofs; // in coarse grain proof generation mode, this vector tracks the justification for substitutions (see method get_subst). - - bool m_need_reset; - bool m_use_oeq; - - bool m_visited_quantifier; //!< true, if the simplifier found a quantifier - - bool m_ac_support; - - expr_mark m_ac_mark; - ptr_vector m_ac_marked; - obj_map m_ac_cache; // temporary cache for ac - obj_map m_ac_pr_cache; // temporary cache for ac - obj_map m_colors; // temporary cache for topological sort. - obj_map m_ac_mults; - - /* - Simplifier uses an idiom for rewriting ASTs without using recursive calls. - - - It uses a cache (field m_cache in base_simplifier) and a todo-stack (field m_todo in base_simplifier). - - - The cache is a mapping from AST to (AST + Proof). An entry [n -> (n',pr)] is used to store the fact - that n and n' are equivalent and pr is a proof for that. If proofs are disabled, then pr is 0. - We say n' is the result of the simplification of n. - Note: Some simplifications do not preserve equivalence, but equisatisfiability. - For saving space, we use pr = 0 also to represent the reflexivity proof [n -> (n, 0)]. - - - - The simplifier can be extended using plugin (subclasses of the class simplifier_plugin). - Each theory has a family ID. All operators (func_decls) and sorts from a given theory have - the same family_id. Given an application (object of the class app), we use the method - get_family_id() to obtain the family id of the operator in this application. - The simplifier uses plugin to apply theory specific simplifications. The basic idea is: - whenever an AST with family_id X is found, invoke the plugin for this family_id. - A simplifier_plugin implements the following API: - 1) bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) - This method is invoked when the simplifier is trying to reduce/simplify an application - of the form (f args[0] ... args[num_args - 1]), and f has a family_id associated with - the plugin. The plugin may return false to indicate it could not simplify this application. - If it returns true (success), the result should be stored in the argument result. - - 2) bool reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result); - This method is a similar to the previous one, and it is used to handle associative operators. - A plugin does not need to implement this method, the default implementation will use the previous one. - The arguments mults indicates the multiplicity of every argument in args. - For example, suppose this reduce is invoked with the arguments (f, 2, [3, 2], [a, b], result). - This represents the application (f a a a b b). - Some theory simplifiers may have efficient ways to encode this multiplicity. For example, - the arithmetic solver, if f is "+", the multiplicity can be encoded using "*". - This optimization is used because some benchmarks can create term that are very huge when - flattened. One "real" example (that motivated this optimization) is: - let a1 = x1 + x1 - let a2 = a1 + a1 - ... - let an = a{n-1} + a{n-1} - an - In this example, n was 32, so after AC flattening, we had an application - (+ x1 ... x1) with 2^32 arguments. Using the simple reduce would produce a stack overflow. - - This class uses a topological sort for computing the multiplicities efficiently. - So, the field m_colors is used to implement the topological sort. - - - 3) bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result) - This method is invoked when the sort of lhs and rhs has a family_id associated with the plugin. - This method allows theory specific simplifications such as: - (= (+ a b) b) --> (= a 0) - Assuming n1 is a reference to (+ a b) and n2 to b, the simplifier would invoke - reduce_eq(n1, n2, result) - Like reduce, false can be returned if a simplification could not be applied. - And if true is returned, then the result is stored in the argument result. - - 4) bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) - It is similar to reduce_eq, but it used for theory specific simplifications for - (distinct args[0] ... args[num_args-1]) - Example: - (distinct 0 1 ... n) --> true - - - The idiom used in this class is implemented in the methdo reduce_core. - See reduce_core for more details. The basic idea is: - - 1) Get the next ast to be simplified from the todo-stack. - 2) If it is already cached, then do nothing. That is, this expression was already simplified. - 3) Otherwise, check whether all arguments already have been simplified (method visit_children). - 3a) The arguments that have not been simplified are added to the todo-stack by visit_children. - In this case visit_children will return false. - 3b) If all arguments have already been simplified, then invoke reduce1 to perform a reduction/simplification - step. The cache is updated with the result. - - - After invoking reduce_core(n), the cache contains an entry [n -> (n', pr)]. - - */ - - void flush_cache(); - - /** - \brief This method can be redefined in subclasses of simplifier to implement substitutions. - It returns true if n should be substituted by r, where the substitution is justified by the - proof p. The field m_subst_proofs is used to store these justifications when coarse proofs are used (PGM_COARSE). - This method is redefined in the class subst_simplifier. It is used in asserted_formulas - for implementing constant elimination. For example, if asserted_formulas contains the atoms - (= a (+ b 1)) (p a c), then the constant "a" can be eliminated. This is achieved by set (+ b 1) as - a substitution for "a". - */ - virtual bool get_subst(expr * n, expr_ref & r, proof_ref & p); - - void reduce_core(expr * n); - bool visit_children(expr * n); - bool visit_ac(app * n); - virtual bool visit_quantifier(quantifier * q); - void reduce1(expr * n); - void reduce1_app(app * n); - void reduce1_app_core(app * n); - void reduce1_ac_app_core(app * n); - void mk_congruent_term(app * n, app_ref & r, proof_ref & p); - void mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p); - bool get_args(app * n, ptr_vector & result, proof_ref & p); - void get_ac_args(app * n, ptr_vector & args, vector & mults); - virtual void reduce1_quantifier(quantifier * q); - void dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr * const * args, expr* result); - void ac_top_sort(app * n, ptr_buffer & result); - -public: - simplifier(ast_manager & manager); - virtual ~simplifier(); - - void enable_ac_support(bool flag); - - /** - \brief Simplify the expression \c s. Store the result in \c r, and a proof that (= s r) in \c p. - */ - void operator()(expr * s, expr_ref & r, proof_ref & p); - void reset() { if (m_need_reset) { flush_cache(); m_need_reset = false; } } - - bool visited_quantifier() const { return m_visited_quantifier; } - - void mk_app(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & r); - void cache_result(expr * n, expr * r, proof * p) { m_need_reset = true; base_simplifier::cache_result(n, r, p); } - - void register_plugin(plugin * p); - ptr_vector::const_iterator begin_plugins() const { return m_plugins.begin(); } - ptr_vector::const_iterator end_plugins() const { return m_plugins.end(); } - - plugin * get_plugin(family_id fid) const { return m_plugins.get_plugin(fid); } - - ast_manager & get_manager() { return m; } - - void borrow_plugins(simplifier const & s); - void release_plugins(); - - void enable_presimp(); -}; - -class subst_simplifier : public simplifier { -protected: - expr_map * m_subst_map; - virtual bool get_subst(expr * n, expr_ref & r, proof_ref & p); -public: - subst_simplifier(ast_manager & manager):simplifier(manager), m_subst_map(0) {} - void set_subst_map(expr_map * s); -}; - -void push_assertion(ast_manager & m, expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs); - -#endif diff --git a/src/ast/simplifier/simplifier_plugin.cpp b/src/ast/simplifier/simplifier_plugin.cpp deleted file mode 100644 index 1cdaadf8a..000000000 --- a/src/ast/simplifier/simplifier_plugin.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - simplifier_plugin.cpp - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2008-12-29. - -Revision History: - ---*/ -#include"simplifier_plugin.h" - -/** - \brief Copy every args[i] mult[i] times to new_args. -*/ -void expand_args(unsigned num_args, rational const * mults, expr * const * args, ptr_buffer & new_args) { - for (unsigned i = 0; i < num_args; i++) { - rational const & c = mults[i]; - SASSERT(c.is_int()); - rational j(0); - while (j < c) { - new_args.push_back(args[i]); - j++; - } - } -} - -bool simplifier_plugin::reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - if (f->is_idempotent()) { - return reduce(f, num_args, args, result); - } - else { - ptr_buffer new_args; - expand_args(num_args, mults, args, new_args); - return reduce(f, new_args.size(), new_args.c_ptr(), result); - } -} diff --git a/src/ast/simplifier/simplifier_plugin.h b/src/ast/simplifier/simplifier_plugin.h deleted file mode 100644 index b018dc731..000000000 --- a/src/ast/simplifier/simplifier_plugin.h +++ /dev/null @@ -1,94 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - simplifier_plugin.h - -Abstract: - - Expression simplifier plugin interface. - -Author: - - Leonardo (leonardo) 2008-01-03 - ---*/ - -#ifndef SIMPLIFIER_PLUGIN_H_ -#define SIMPLIFIER_PLUGIN_H_ - -#include"ast.h" - -class simplifier; - -void expand_args(unsigned num_args, rational const * mults, expr * const * args, ptr_buffer & new_args); - -/** - \brief Abstract simplifier for the operators in a given family. -*/ -class simplifier_plugin { -protected: - ast_manager & m_manager; - family_id m_fid; - bool m_presimp; // true if simplifier is performing pre-simplification... - bool m_reduce_invoked; // true if one of the reduce methods were invoked. - - void set_reduce_invoked() { m_reduce_invoked = true; } - -public: - simplifier_plugin(symbol const & fname, ast_manager & m):m_manager(m), m_fid(m.mk_family_id(fname)), m_presimp(false), m_reduce_invoked(false) {} - - bool reduce_invoked() const { return m_reduce_invoked; } - - virtual ~simplifier_plugin() {} - - virtual simplifier_plugin * mk_fresh() { - UNREACHABLE(); - return 0; - } - - /** - \brief Return in \c result an expression \c e equivalent to (f args[0] ... args[num_args - 1]). - - Return true if succeeded. - */ - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { set_reduce_invoked(); return false; } - - /** - \brief Return in \c result an expression \c e equivalent to (f args[0] ... args[0] ... args[num_args - 1]). - Where each args[i] occurs mults[i] times. - - Return true if succeeded. - */ - virtual bool reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result); - - /** - \brief Return in \c result an expression \c e equivalent to (= lhs rhs). - - Return true if succeeded. - */ - virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { set_reduce_invoked(); return false; } - - /** - \brief Return in \c result an expression \c e equivalent to (distinct args[0] ... args[num_args-1]). - - Return true if succeeded. - */ - virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) { set_reduce_invoked(); return false; } - - family_id get_family_id() const { return m_fid; } - - /** - \brief Simplifiers may maintain local caches. These caches must be flushed when this method is invoked. - */ - virtual void flush_caches() { /* do nothing */ } - - ast_manager & get_manager() { return m_manager; } - - void enable_presimp(bool flag) { m_presimp = flag; } - - virtual void enable_ac_support(bool flag) {} -}; - -#endif diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp index a3ad7fd07..3db4d02a2 100644 --- a/src/ast/static_features.cpp +++ b/src/ast/static_features.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"static_features.h" -#include"ast_pp.h" +#include "ast/static_features.h" +#include "ast/ast_pp.h" static_features::static_features(ast_manager & m): m_manager(m), @@ -145,18 +145,19 @@ bool static_features::is_diff_atom(expr const * e) const { return true; if (!is_numeral(rhs)) return false; - // lhs can be 'x' or '(+ x (* -1 y))' + // lhs can be 'x' or '(+ x (* -1 y))' or '(+ (* -1 x) y)' if (!is_arith_expr(lhs)) return true; expr* arg1, *arg2; if (!m_autil.is_add(lhs, arg1, arg2)) return false; - // x - if (is_arith_expr(arg1)) - return false; - // arg2: (* -1 y) expr* m1, *m2; - return m_autil.is_mul(arg2, m1, m2) && is_minus_one(m1) && !is_arith_expr(m2); + if (!is_arith_expr(arg1) && m_autil.is_mul(arg2, m1, m2) && is_minus_one(m1) && !is_arith_expr(m2)) + return true; + if (!is_arith_expr(arg2) && m_autil.is_mul(arg1, m1, m2) && is_minus_one(m1) && !is_arith_expr(m2)) + return true; + return false; + } bool static_features::is_gate(expr const * e) const { diff --git a/src/ast/static_features.h b/src/ast/static_features.h index e7f69e041..5473ba0ff 100644 --- a/src/ast/static_features.h +++ b/src/ast/static_features.h @@ -19,13 +19,13 @@ Revision History: #ifndef STATIC_FEATURES_H_ #define STATIC_FEATURES_H_ -#include"ast.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"array_decl_plugin.h" -#include"fpa_decl_plugin.h" -#include"seq_decl_plugin.h" -#include"map.h" +#include "ast/ast.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/fpa_decl_plugin.h" +#include "ast/seq_decl_plugin.h" +#include "util/map.h" struct static_features { ast_manager & m_manager; diff --git a/src/ast/substitution/expr_offset.h b/src/ast/substitution/expr_offset.h index ea4f36206..1f27f222a 100644 --- a/src/ast/substitution/expr_offset.h +++ b/src/ast/substitution/expr_offset.h @@ -24,7 +24,7 @@ Revision History: #ifndef EXPR_OFFSET_H_ #define EXPR_OFFSET_H_ -#include"ast.h" +#include "ast/ast.h" class expr_offset { expr * m_expr; diff --git a/src/ast/substitution/expr_offset_map.h b/src/ast/substitution/expr_offset_map.h index 83e22493b..371c7500e 100644 --- a/src/ast/substitution/expr_offset_map.h +++ b/src/ast/substitution/expr_offset_map.h @@ -19,8 +19,8 @@ Revision History: #ifndef EXPR_OFFSET_MAP_H_ #define EXPR_OFFSET_MAP_H_ -#include"expr_offset.h" -#include"vector.h" +#include "ast/substitution/expr_offset.h" +#include "util/vector.h" /** \brief A mapping from expr_offset to some value of type T. diff --git a/src/ast/substitution/matcher.cpp b/src/ast/substitution/matcher.cpp index ce9bdcb3e..a0786e5b4 100644 --- a/src/ast/substitution/matcher.cpp +++ b/src/ast/substitution/matcher.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"matcher.h" +#include "ast/substitution/matcher.h" bool matcher::operator()(expr * e1, expr * e2, substitution & s) { reset(); diff --git a/src/ast/substitution/matcher.h b/src/ast/substitution/matcher.h index c4936579e..1e8c3005a 100644 --- a/src/ast/substitution/matcher.h +++ b/src/ast/substitution/matcher.h @@ -19,8 +19,8 @@ Revision History: #ifndef MATCHER_H_ #define MATCHER_H_ -#include"substitution.h" -#include"hashtable.h" +#include "ast/substitution/substitution.h" +#include "util/hashtable.h" /** \brief Functor for matching expressions. diff --git a/src/ast/substitution/substitution.cpp b/src/ast/substitution/substitution.cpp index f741d3fd4..d54a8e057 100644 --- a/src/ast/substitution/substitution.cpp +++ b/src/ast/substitution/substitution.cpp @@ -17,10 +17,10 @@ Author: Revision History: --*/ -#include"substitution.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"rewriter.h" +#include "ast/substitution/substitution.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/rewriter/rewriter.h" substitution::substitution(ast_manager & m): m_manager(m), diff --git a/src/ast/substitution/substitution.h b/src/ast/substitution/substitution.h index ebd12ef3a..0d318e4fb 100644 --- a/src/ast/substitution/substitution.h +++ b/src/ast/substitution/substitution.h @@ -33,9 +33,9 @@ Revision History: #ifndef SUBSTITUTION_H_ #define SUBSTITUTION_H_ -#include"expr_offset_map.h" -#include"var_offset_map.h" -#include"ast_pp.h" +#include "ast/substitution/expr_offset_map.h" +#include "ast/substitution/var_offset_map.h" +#include "ast/ast_pp.h" /** \brief A mapping from (variable,offset) to expr_offset. diff --git a/src/ast/substitution/substitution_tree.cpp b/src/ast/substitution/substitution_tree.cpp index 6aaa2da66..20d5f1590 100644 --- a/src/ast/substitution/substitution_tree.cpp +++ b/src/ast/substitution/substitution_tree.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"substitution_tree.h" -#include"ast_pp.h" -#include"ast_smt2_pp.h" +#include "ast/substitution/substitution_tree.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt2_pp.h" /** \brief Return the next available register. @@ -256,7 +256,7 @@ void substitution_tree::insert(expr * new_expr) { sort * s = to_var(new_expr)->get_sort(); unsigned id = s->get_decl_id(); if (id >= m_vars.size()) - m_vars.resize(id+1, 0); + m_vars.resize(id+1); if (m_vars[id] == 0) m_vars[id] = alloc(var_ref_vector, m_manager); var_ref_vector * v = m_vars[id]; @@ -277,7 +277,7 @@ void substitution_tree::insert(app * new_expr) { unsigned id = d->get_decl_id(); if (id >= m_roots.size()) - m_roots.resize(id+1, 0); + m_roots.resize(id+1); if (!m_roots[id]) { // there is no tree for the function symbol heading new_expr diff --git a/src/ast/substitution/substitution_tree.h b/src/ast/substitution/substitution_tree.h index 167d08183..7a8c30a63 100644 --- a/src/ast/substitution/substitution_tree.h +++ b/src/ast/substitution/substitution_tree.h @@ -19,8 +19,8 @@ Revision History: #ifndef SUBSTITUTION_TREE_H_ #define SUBSTITUTION_TREE_H_ -#include"ast.h" -#include"substitution.h" +#include "ast/ast.h" +#include "ast/substitution/substitution.h" /** \brief Substitution tree visitor. diff --git a/src/ast/substitution/unifier.cpp b/src/ast/substitution/unifier.cpp index a5bd4d155..4942b5498 100644 --- a/src/ast/substitution/unifier.cpp +++ b/src/ast/substitution/unifier.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"unifier.h" -#include"ast_pp.h" +#include "ast/substitution/unifier.h" +#include "ast/ast_pp.h" void unifier::reset(unsigned num_offsets) { m_todo.reset(); diff --git a/src/ast/substitution/unifier.h b/src/ast/substitution/unifier.h index 24735117c..171b880e2 100644 --- a/src/ast/substitution/unifier.h +++ b/src/ast/substitution/unifier.h @@ -19,8 +19,8 @@ Revision History: #ifndef UNIFIER_H_ #define UNIFIER_H_ -#include"ast.h" -#include"substitution.h" +#include "ast/ast.h" +#include "ast/substitution/substitution.h" /** \brief Functor for unifying expressions. diff --git a/src/ast/substitution/var_offset_map.h b/src/ast/substitution/var_offset_map.h index f03b80aed..f5488483a 100644 --- a/src/ast/substitution/var_offset_map.h +++ b/src/ast/substitution/var_offset_map.h @@ -19,8 +19,8 @@ Revision History: #ifndef VAR_OFFSET_MAP_H_ #define VAR_OFFSET_MAP_H_ -#include"ast.h" -#include"vector.h" +#include "ast/ast.h" +#include "util/vector.h" /** \brief A mapping from variable-id + offset to some value of type T. diff --git a/src/ast/used_symbols.h b/src/ast/used_symbols.h index 994e3321a..2fd4830fe 100644 --- a/src/ast/used_symbols.h +++ b/src/ast/used_symbols.h @@ -19,9 +19,9 @@ Revision History: #ifndef USED_SYMBOLS_H_ #define USED_SYMBOLS_H_ -#include"ast.h" -#include"hashtable.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "util/hashtable.h" +#include "util/obj_hashtable.h" struct do_nothing_rename_proc { symbol operator()(symbol const & s) const { return s; } diff --git a/src/ast/used_vars.cpp b/src/ast/used_vars.cpp index f33c5cb50..a3030f087 100644 --- a/src/ast/used_vars.cpp +++ b/src/ast/used_vars.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"used_vars.h" +#include "ast/used_vars.h" void used_vars::process(expr * n, unsigned delta) { unsigned j, idx; @@ -58,7 +58,7 @@ void used_vars::process(expr * n, unsigned delta) { if (idx >= delta) { idx = idx - delta; if (idx >= m_found_vars.size()) - m_found_vars.resize(idx + 1, 0); + m_found_vars.resize(idx + 1); m_found_vars[idx] = to_var(n)->get_sort(); } break; diff --git a/src/ast/used_vars.h b/src/ast/used_vars.h index b14798e7d..56d633997 100644 --- a/src/ast/used_vars.h +++ b/src/ast/used_vars.h @@ -19,8 +19,8 @@ Revision History: #ifndef USED_VARS_H_ #define USED_VARS_H_ -#include"ast.h" -#include"expr_delta_pair.h" +#include "ast/ast.h" +#include "ast/expr_delta_pair.h" class used_vars { ptr_vector m_found_vars; diff --git a/src/ast/well_sorted.cpp b/src/ast/well_sorted.cpp index b0afe566b..f78cd9121 100644 --- a/src/ast/well_sorted.cpp +++ b/src/ast/well_sorted.cpp @@ -18,12 +18,12 @@ Revision History: --*/ #include -#include"for_each_expr.h" -#include"well_sorted.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" -#include"warning.h" -#include"ast_smt2_pp.h" +#include "ast/for_each_expr.h" +#include "ast/well_sorted.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "util/warning.h" +#include "ast/ast_smt2_pp.h" struct well_sorted_proc { ast_manager & m_manager; diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index ea6d1c232..65c8860b1 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -15,21 +15,22 @@ Author: Notes: --*/ -#include"cmd_context.h" -#include"version.h" -#include"ast_smt_pp.h" -#include"ast_smt2_pp.h" -#include"ast_pp.h" -#include"model_smt2_pp.h" -#include"array_decl_plugin.h" -#include"pp.h" -#include"cmd_util.h" -#include"simplify_cmd.h" -#include"eval_cmd.h" -#include"gparams.h" -#include"env_params.h" -#include"well_sorted.h" -#include"pp_params.hpp" +#include "util/gparams.h" +#include "util/env_params.h" +#include "util/version.h" +#include "ast/ast_smt_pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_pp_dot.h" +#include "ast/ast_pp.h" +#include "ast/array_decl_plugin.h" +#include "ast/pp.h" +#include "ast/well_sorted.h" +#include "ast/pp_params.hpp" +#include "model/model_smt2_pp.h" +#include "cmd_context/cmd_context.h" +#include "cmd_context/cmd_util.h" +#include "cmd_context/simplify_cmd.h" +#include "cmd_context/eval_cmd.h" class help_cmd : public cmd { svector m_cmds; @@ -79,19 +80,15 @@ public: } // named_cmd_lt is not a total order for commands, but this is irrelevant for Linux x Windows behavior std::sort(cmds.begin(), cmds.end(), named_cmd_lt()); - vector::const_iterator it2 = cmds.begin(); - vector::const_iterator end2 = cmds.end(); - for (; it2 != end2; ++it2) { - display_cmd(ctx, it2->first, it2->second); + for (named_cmd const& nc : cmds) { + display_cmd(ctx, nc.first, nc.second); } } else { - svector::const_iterator it = m_cmds.begin(); - svector::const_iterator end = m_cmds.end(); - for (; it != end; ++it) { - cmd * c = ctx.find_cmd(*it); + for (symbol const& s : m_cmds) { + cmd * c = ctx.find_cmd(s); SASSERT(c); - display_cmd(ctx, *it, c); + display_cmd(ctx, s, c); } } ctx.regular_stream() << "\"\n"; @@ -135,28 +132,29 @@ ATOMIC_CMD(get_assignment_cmd, "get-assignment", "retrieve assignment", { model_ref m; ctx.get_check_sat_result()->get_model(m); ctx.regular_stream() << "("; - dictionary const & macros = ctx.get_macros(); - dictionary::iterator it = macros.begin(); - dictionary::iterator end = macros.end(); - for (bool first = true; it != end; ++it) { - symbol const & name = (*it).m_key; - cmd_context::macro const & _m = (*it).m_value; - if (_m.first == 0 && ctx.m().is_bool(_m.second)) { - expr_ref val(ctx.m()); - m->eval(_m.second, val, true); - if (ctx.m().is_true(val) || ctx.m().is_false(val)) { - if (first) - first = false; - else - ctx.regular_stream() << " "; - ctx.regular_stream() << "("; - if (is_smt2_quoted_symbol(name)) { - ctx.regular_stream() << mk_smt2_quoted_symbol(name); + dictionary const & macros = ctx.get_macros(); + bool first = true; + for (auto const& kv : macros) { + symbol const & name = kv.m_key; + macro_decls const & _m = kv.m_value; + for (auto md : _m) { + if (md.m_domain.size() == 0 && ctx.m().is_bool(md.m_body)) { + expr_ref val(ctx.m()); + m->eval(md.m_body, val, true); + if (ctx.m().is_true(val) || ctx.m().is_false(val)) { + if (first) + first = false; + else + ctx.regular_stream() << " "; + ctx.regular_stream() << "("; + if (is_smt2_quoted_symbol(name)) { + ctx.regular_stream() << mk_smt2_quoted_symbol(name); + } + else { + ctx.regular_stream() << name; + } + ctx.regular_stream() << " " << (ctx.m().is_true(val) ? "true" : "false") << ")"; } - else { - ctx.regular_stream() << name; - } - ctx.regular_stream() << " " << (ctx.m().is_true(val) ? "true" : "false") << ")"; } } } @@ -205,18 +203,37 @@ ATOMIC_CMD(get_proof_cmd, "get-proof", "retrieve proof", { } }); +ATOMIC_CMD(get_proof_graph_cmd, "get-proof-graph", "retrieve proof and print it in graphviz", { + if (!ctx.produce_proofs()) + throw cmd_exception("proof construction is not enabled, use command (set-option :produce-proofs true)"); + if (!ctx.has_manager() || + ctx.cs_state() != cmd_context::css_unsat) + throw cmd_exception("proof is not available"); + proof_ref pr(ctx.m()); + pr = ctx.get_check_sat_result()->get_proof(); + if (pr == 0) + throw cmd_exception("proof is not available"); + if (ctx.well_sorted_check_enabled() && !is_well_sorted(ctx.m(), pr)) { + throw cmd_exception("proof is not well sorted"); + } + + context_params& params = ctx.params(); + const std::string& file = params.m_dot_proof_file; + std::ofstream out(file); + out << ast_pp_dot(pr) << std::endl; +}); + static void print_core(cmd_context& ctx) { ptr_vector core; ctx.get_check_sat_result()->get_unsat_core(core); ctx.regular_stream() << "("; - ptr_vector::const_iterator it = core.begin(); - ptr_vector::const_iterator end = core.end(); - for (bool first = true; it != end; ++it) { + bool first = true; + for (expr* e : core) { if (first) first = false; else ctx.regular_stream() << " "; - ctx.regular_stream() << mk_ismt2_pp(*it, ctx.m()); + ctx.regular_stream() << mk_ismt2_pp(e, ctx.m()); } ctx.regular_stream() << ")" << std::endl; } @@ -844,6 +861,7 @@ void install_basic_cmds(cmd_context & ctx) { ctx.insert(alloc(get_assignment_cmd)); ctx.insert(alloc(get_assertions_cmd)); ctx.insert(alloc(get_proof_cmd)); + ctx.insert(alloc(get_proof_graph_cmd)); ctx.insert(alloc(get_unsat_core_cmd)); ctx.insert(alloc(set_option_cmd)); ctx.insert(alloc(get_option_cmd)); diff --git a/src/cmd_context/check_logic.cpp b/src/cmd_context/check_logic.cpp index 0faddce73..dd08ac9db 100644 --- a/src/cmd_context/check_logic.cpp +++ b/src/cmd_context/check_logic.cpp @@ -16,15 +16,15 @@ Author: Revision History: --*/ -#include"check_logic.h" -#include"arith_decl_plugin.h" -#include"array_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"seq_decl_plugin.h" -#include"pb_decl_plugin.h" -#include"datatype_decl_plugin.h" -#include"ast_pp.h" -#include"for_each_expr.h" +#include "cmd_context/check_logic.h" +#include "ast/arith_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/seq_decl_plugin.h" +#include "ast/pb_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/for_each_expr.h" #include struct check_logic::imp { @@ -37,6 +37,7 @@ struct check_logic::imp { datatype_util m_dt_util; pb_util m_pb_util; bool m_uf; // true if the logic supports uninterpreted functions + bool m_dt; // true if the lgoic supports dattypes bool m_arrays; // true if the logic supports arbitrary arrays bool m_bv_arrays; // true if the logic supports only bv arrays bool m_reals; // true if the logic supports reals @@ -53,6 +54,7 @@ struct check_logic::imp { void reset() { m_uf = false; + m_dt = false; m_arrays = false; m_bv_arrays = false; m_reals = false; @@ -105,6 +107,10 @@ struct check_logic::imp { m_uf = true; m_bvs = true; } + else if (logic == "QF_DT") { + m_uf = true; + m_dt = true; + } else if (logic == "QF_AUFLIA") { m_uf = true; m_arrays = true; @@ -187,6 +193,7 @@ struct check_logic::imp { m_bvs = true; m_uf = true; m_ints = true; + m_dt = true; m_nonlinear = true; // non-linear 0-1 variables may get eliminated } else { @@ -443,7 +450,7 @@ struct check_logic::imp { else if (fid == m_seq_util.get_family_id()) { // nothing to check } - else if (fid == m_dt_util.get_family_id() && m_logic == "QF_FD") { + else if (fid == m_dt_util.get_family_id() && m_dt) { // nothing to check } else if (fid == m_pb_util.get_family_id() && m_logic == "QF_FD") { diff --git a/src/cmd_context/check_logic.h b/src/cmd_context/check_logic.h index 888c6ed9f..b9050fc14 100644 --- a/src/cmd_context/check_logic.h +++ b/src/cmd_context/check_logic.h @@ -19,7 +19,7 @@ Revision History: #ifndef CHECK_LOGIC_H_ #define CHECK_LOGIC_H_ -#include"ast.h" +#include "ast/ast.h" class check_logic { struct imp; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 45ad08a78..a1e7a4745 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -17,36 +17,36 @@ Notes: --*/ #include -#include"tptr.h" -#include"cmd_context.h" -#include"func_decl_dependencies.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"array_decl_plugin.h" -#include"datatype_decl_plugin.h" -#include"seq_decl_plugin.h" -#include"pb_decl_plugin.h" -#include"fpa_decl_plugin.h" -#include"ast_pp.h" -#include"var_subst.h" -#include"pp.h" -#include"ast_smt2_pp.h" -#include"basic_cmds.h" -#include"cancel_eh.h" -#include"scoped_ctrl_c.h" -#include"dec_ref_util.h" -#include"decl_collector.h" -#include"well_sorted.h" -#include"model_evaluator.h" -#include"for_each_expr.h" -#include"scoped_timer.h" -#include"interpolant_cmds.h" -#include"model_smt2_pp.h" -#include"model_v2_pp.h" -#include"model_params.hpp" -#include"th_rewriter.h" -#include"tactic_exception.h" -#include"smt_logics.h" +#include "util/tptr.h" +#include "util/cancel_eh.h" +#include "util/scoped_ctrl_c.h" +#include "util/dec_ref_util.h" +#include "util/scoped_timer.h" +#include "ast/func_decl_dependencies.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/seq_decl_plugin.h" +#include "ast/pb_decl_plugin.h" +#include "ast/fpa_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/var_subst.h" +#include "ast/pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/decl_collector.h" +#include "ast/well_sorted.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/th_rewriter.h" +#include "model/model_evaluator.h" +#include "model/model_smt2_pp.h" +#include "model/model_v2_pp.h" +#include "model/model_params.hpp" +#include "tactic/tactic_exception.h" +#include "solver/smt_logics.h" +#include "cmd_context/basic_cmds.h" +#include "cmd_context/interpolant_cmds.h" +#include "cmd_context/cmd_context.h" func_decls::func_decls(ast_manager & m, func_decl * f): m_decls(TAG(func_decl*, f, 0)) { @@ -61,11 +61,9 @@ void func_decls::finalize(ast_manager & m) { else { TRACE("func_decls", tout << "finalize...\n";); func_decl_set * fs = UNTAG(func_decl_set *, m_decls); - func_decl_set::iterator it = fs->begin(); - func_decl_set::iterator end = fs->end(); - for (; it != end; ++it) { - TRACE("func_decls", tout << "dec_ref of " << (*it)->get_name() << " ref_count: " << (*it)->get_ref_count() << "\n";); - m.dec_ref(*it); + for (func_decl * f : *fs) { + TRACE("func_decls", tout << "dec_ref of " << f->get_name() << " ref_count: " << f->get_ref_count() << "\n";); + m.dec_ref(f); } dealloc(fs); } @@ -76,6 +74,15 @@ bool func_decls::signatures_collide(func_decl* f, func_decl* g) const { return f == g; } +bool func_decls::signatures_collide(unsigned n, sort* const* domain, sort* range, func_decl* g) const { + if (g->get_range() != range) return false; + if (n != g->get_arity()) return false; + for (unsigned i = 0; i < n; ++i) { + if (domain[i] != g->get_domain(i)) return false; + } + return true; +} + bool func_decls::contains(func_decl * f) const { if (GET_TAG(m_decls) == 0) { func_decl* g = UNTAG(func_decl*, m_decls); @@ -90,6 +97,21 @@ bool func_decls::contains(func_decl * f) const { return false; } + +bool func_decls::contains(unsigned n, sort* const* domain, sort* range) const { + if (GET_TAG(m_decls) == 0) { + func_decl* g = UNTAG(func_decl*, m_decls); + return g && signatures_collide(n, domain, range, g); + } + else { + func_decl_set * fs = UNTAG(func_decl_set *, m_decls); + for (func_decl* g : *fs) { + if (signatures_collide(n, domain, range, g)) return true; + } + } + return false; +} + bool func_decls::insert(ast_manager & m, func_decl * f) { if (contains(f)) return false; @@ -137,10 +159,7 @@ bool func_decls::clash(func_decl * f) const { if (GET_TAG(m_decls) == 0) return false; func_decl_set * fs = UNTAG(func_decl_set *, m_decls); - func_decl_set::iterator it = fs->begin(); - func_decl_set::iterator end = fs->end(); - for (; it != end; ++it) { - func_decl * g = *it; + for (func_decl * g : *fs) { if (g == f) continue; if (g->get_arity() != f->get_arity()) @@ -177,16 +196,13 @@ func_decl * func_decls::find(unsigned arity, sort * const * domain, sort * range if (!more_than_one()) return first(); func_decl_set * fs = UNTAG(func_decl_set *, m_decls); - func_decl_set::iterator it = fs->begin(); - func_decl_set::iterator end = fs->end(); - for (; it != end; it++) { - func_decl * f = *it; + for (func_decl * f : *fs) { if (range != 0 && f->get_range() != range) continue; if (f->get_arity() != arity) continue; unsigned i = 0; - for (i = 0; i < arity; i++) { + for (i = 0; domain && i < arity; i++) { if (f->get_domain(i) != domain[i]) break; } @@ -205,6 +221,116 @@ func_decl * func_decls::find(ast_manager & m, unsigned num_args, expr * const * return find(num_args, sorts.c_ptr(), range); } +unsigned func_decls::get_num_entries() const { + if (!more_than_one()) + return 1; + + func_decl_set * fs = UNTAG(func_decl_set *, m_decls); + return fs->size(); +} + +func_decl * func_decls::get_entry(unsigned inx) { + if (!more_than_one()) { + SASSERT(inx == 0); + return first(); + } + else { + func_decl_set * fs = UNTAG(func_decl_set *, m_decls); + auto b = fs->begin(); + for (unsigned i = 0; i < inx; i++) + b++; + return *b; + } +} + +void macro_decls::finalize(ast_manager& m) { + for (auto v : *m_decls) m.dec_ref(v.m_body); + dealloc(m_decls); +} + +bool macro_decls::insert(ast_manager& m, unsigned arity, sort *const* domain, expr* body) { + if (find(arity, domain)) return false; + m.inc_ref(body); + if (!m_decls) m_decls = alloc(vector); + m_decls->push_back(macro_decl(arity, domain, body)); + return true; +} + +expr* macro_decls::find(unsigned arity, sort *const* domain) const { + if (!m_decls) return 0; + for (auto v : *m_decls) { + if (v.m_domain.size() != arity) continue; + bool eq = true; + for (unsigned i = 0; eq && i < arity; ++i) { + eq = domain[i] == v.m_domain[i]; + } + if (eq) return v.m_body; + } + return 0; +} + +void macro_decls::erase_last(ast_manager& m) { + SASSERT(m_decls); + SASSERT(!m_decls->empty()); + m.dec_ref(m_decls->back().m_body); + m_decls->pop_back(); +} + +bool cmd_context::contains_func_decl(symbol const& s, unsigned n, sort* const* domain, sort* range) const { + func_decls fs; + return m_func_decls.find(s, fs) && fs.contains(n, domain, range); +} + +bool cmd_context::contains_macro(symbol const& s) const { + return m_macros.contains(s); +} + +bool cmd_context::contains_macro(symbol const& s, func_decl* f) const { + return contains_macro(s, f->get_arity(), f->get_domain()); +} + +bool cmd_context::contains_macro(symbol const& s, unsigned arity, sort *const* domain) const { + macro_decls decls; + return m_macros.find(s, decls) && 0 != decls.find(arity, domain); +} + +void cmd_context::insert_macro(symbol const& s, unsigned arity, sort*const* domain, expr* t) { + macro_decls decls; + if (!m_macros.find(s, decls)) { + VERIFY(decls.insert(m(), arity, domain, t)); + m_macros.insert(s, decls); + } + else { + VERIFY(decls.insert(m(), arity, domain, t)); + } +} + +void cmd_context::erase_macro(symbol const& s) { + macro_decls decls; + VERIFY(m_macros.find(s, decls)); + decls.erase_last(m()); +} + +bool cmd_context::macros_find(symbol const& s, unsigned n, expr*const* args, expr*& t) const { + macro_decls decls; + if (!m_macros.find(s, decls)) { + return false; + } + for (macro_decl const& d : decls) { + if (d.m_domain.size() != n) continue; + bool eq = true; + for (unsigned i = 0; eq && i < n; ++i) { + eq = d.m_domain[i] == m().get_sort(args[i]); + } + if (eq) { + t = d.m_body; + return true; + } + } + return false; +} + + ast_object_ref::ast_object_ref(cmd_context & ctx, ast * a):m_ast(a) { ctx.m().inc_ref(a); } @@ -473,10 +599,8 @@ void cmd_context::register_builtin_sorts(decl_plugin * p) { svector names; p->get_sort_names(names, m_logic); family_id fid = p->get_family_id(); - svector::const_iterator it = names.begin(); - svector::const_iterator end = names.end(); - for (; it != end; ++it) { - psort_decl * d = pm().mk_psort_builtin_decl((*it).m_name, fid, (*it).m_kind); + for (builtin_name const& n : names) { + psort_decl * d = pm().mk_psort_builtin_decl(n.m_name, fid, n.m_kind); insert(d); } } @@ -485,17 +609,15 @@ void cmd_context::register_builtin_ops(decl_plugin * p) { svector names; p->get_op_names(names, m_logic); family_id fid = p->get_family_id(); - svector::const_iterator it = names.begin(); - svector::const_iterator end = names.end(); - for (; it != end; ++it) { - if (m_builtin_decls.contains((*it).m_name)) { - builtin_decl & d = m_builtin_decls.find((*it).m_name); - builtin_decl * new_d = alloc(builtin_decl, fid, (*it).m_kind, d.m_next); + for (builtin_name const& n : names) { + if (m_builtin_decls.contains(n.m_name)) { + builtin_decl & d = m_builtin_decls.find(n.m_name); + builtin_decl * new_d = alloc(builtin_decl, fid, n.m_kind, d.m_next); d.m_next = new_d; m_extra_builtin_decls.push_back(new_d); } else { - m_builtin_decls.insert((*it).m_name, builtin_decl(fid, (*it).m_kind)); + m_builtin_decls.insert(n.m_name, builtin_decl(fid, n.m_kind)); } } } @@ -552,8 +674,6 @@ bool cmd_context::logic_has_datatype() const { void cmd_context::init_manager_core(bool new_manager) { SASSERT(m_manager != 0); SASSERT(m_pmanager != 0); - m_dt_eh = alloc(dt_eh, *this); - m_pmanager->set_new_datatype_eh(m_dt_eh.get()); if (new_manager) { decl_plugin * basic = m_manager->get_plugin(m_manager->get_basic_family_id()); register_builtin_sorts(basic); @@ -581,16 +701,16 @@ void cmd_context::init_manager_core(bool new_manager) { load_plugin(symbol("seq"), logic_has_seq(), fids); load_plugin(symbol("fpa"), logic_has_fpa(), fids); load_plugin(symbol("pb"), logic_has_pb(), fids); - svector::iterator it = fids.begin(); - svector::iterator end = fids.end(); - for (; it != end; ++it) { - decl_plugin * p = m_manager->get_plugin(*it); + for (family_id fid : fids) { + decl_plugin * p = m_manager->get_plugin(fid); if (p) { register_builtin_sorts(p); register_builtin_ops(p); } } } + m_dt_eh = alloc(dt_eh, *this); + m_pmanager->set_new_datatype_eh(m_dt_eh.get()); if (!has_logic()) { // add list type only if the logic is not specified. // it prevents clashes with builtin types. @@ -654,11 +774,10 @@ bool cmd_context::is_func_decl(symbol const & s) const { } void cmd_context::insert(symbol const & s, func_decl * f) { - m_check_sat_result = 0; if (!m_check_logic(f)) { throw cmd_exception(m_check_logic.get_last_error()); } - if (m_macros.contains(s)) { + if (contains_macro(s, f)) { throw cmd_exception("invalid declaration, named expression already defined with this name ", s); } if (m_builtin_decls.contains(s)) { @@ -685,7 +804,6 @@ void cmd_context::insert(symbol const & s, func_decl * f) { } void cmd_context::insert(symbol const & s, psort_decl * p) { - m_check_sat_result = 0; if (m_psort_decls.contains(s)) { throw cmd_exception("sort already defined ", s); } @@ -697,20 +815,19 @@ void cmd_context::insert(symbol const & s, psort_decl * p) { TRACE("cmd_context", tout << "new sort decl\n"; p->display(tout); tout << "\n";); } -void cmd_context::insert(symbol const & s, unsigned arity, expr * t) { - m_check_sat_result = 0; +void cmd_context::insert(symbol const & s, unsigned arity, sort *const* domain, expr * t) { + expr_ref _t(t, m()); if (m_builtin_decls.contains(s)) { throw cmd_exception("invalid macro/named expression, builtin symbol ", s); } - if (m_macros.contains(s)) { + if (contains_macro(s, arity, domain)) { throw cmd_exception("named expression already defined"); } - if (m_func_decls.contains(s)) { + if (contains_func_decl(s, arity, domain, m().get_sort(t))) { throw cmd_exception("invalid named expression, declaration already defined with this name ", s); } - m().inc_ref(t); TRACE("insert_macro", tout << "new macro " << arity << "\n" << mk_pp(t, m()) << "\n";); - m_macros.insert(s, macro(arity, t)); + insert_macro(s, arity, domain, t); if (!m_global_decls) { m_macros_stack.push_back(s); } @@ -750,6 +867,12 @@ void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, s lhs = m().mk_app(f, binding.size(), binding.c_ptr()); eq = m().mk_eq(lhs, e); if (!ids.empty()) { + if (is_var(e)) { + ptr_vector domain; + for (expr* b : binding) domain.push_back(m().get_sort(b)); + insert_macro(f->get_name(), domain.size(), domain.c_ptr(), e); + return; + } if (!is_app(e)) { throw cmd_exception("Z3 only supports recursive definitions that are proper terms (not binders or variables)"); } @@ -758,11 +881,11 @@ void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, s } // - // disable warning given the current way they are used - // (Z3 will here silently assume and not check the definitions to be well founded, + // disable warning given the current way they are used + // (Z3 will here silently assume and not check the definitions to be well founded, // and please use HSF for everything else). // - if (false && !ids.empty() && !m_rec_fun_declared) { + if (false && !ids.empty() && !m_rec_fun_declared) { warning_msg("recursive function definitions are assumed well-founded"); m_rec_fun_declared = true; } @@ -783,8 +906,9 @@ func_decl * cmd_context::find_func_decl(symbol const & s) const { } throw cmd_exception("invalid function declaration reference, must provide signature for builtin symbol ", s); } - if (m_macros.contains(s)) + if (contains_macro(s)) { throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s); + } func_decls fs; if (m_func_decls.find(s, fs)) { if (fs.more_than_one()) @@ -816,7 +940,7 @@ static builtin_decl const & peek_builtin_decl(builtin_decl const & first, family func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices, unsigned arity, sort * const * domain, sort * range) const { builtin_decl d; - if (m_builtin_decls.find(s, d)) { + if (domain && m_builtin_decls.find(s, d)) { family_id fid = d.m_fid; decl_kind k = d.m_decl; // Hack: if d.m_next != 0, we use domain[0] (if available) to decide which plugin we use. @@ -840,7 +964,7 @@ func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, return f; } - if (m_macros.contains(s)) + if (domain && contains_macro(s, arity, domain)) throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s); if (num_indices > 0) @@ -862,11 +986,6 @@ psort_decl * cmd_context::find_psort_decl(symbol const & s) const { return p; } -cmd_context::macro cmd_context::find_macro(symbol const & s) const { - macro m; - m_macros.find(s, m); - return m; -} cmd * cmd_context::find_cmd(symbol const & s) const { cmd * c = 0; @@ -918,21 +1037,14 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg } if (num_indices > 0) throw cmd_exception("invalid use of indexed indentifier, unknown builtin function ", s); - macro _m; - if (m_macros.find(s, _m)) { - if (num_args != _m.first) - throw cmd_exception("invalid defined function application, incorrect number of arguments ", s); - if (num_args == 0) { - result = _m.second; - return; - } - SASSERT(num_args > 0); + expr* _t; + if (macros_find(s, num_args, args, _t)) { TRACE("macro_bug", tout << "well_sorted_check_enabled(): " << well_sorted_check_enabled() << "\n"; tout << "s: " << s << "\n"; - tout << "body:\n" << mk_ismt2_pp(_m.second, m()) << "\n"; + tout << "body:\n" << mk_ismt2_pp(_t, m()) << "\n"; tout << "args:\n"; for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n" << mk_pp(m().get_sort(args[i]), m()) << "\n";); var_subst subst(m()); - subst(_m.second, num_args, args, result); + subst(_t, num_args, args, result); if (well_sorted_check_enabled() && !is_well_sorted(m(), result)) throw cmd_exception("invalid macro application, sort mismatch ", s); return; @@ -951,21 +1063,34 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg if (fs.more_than_one()) throw cmd_exception("ambiguous constant reference, more than one constant with the same sort, use a qualified expression (as ) to disumbiguate ", s); func_decl * f = fs.first(); - if (f == 0) + if (f == 0) { throw cmd_exception("unknown constant ", s); + } if (f->get_arity() != 0) throw cmd_exception("invalid function application, missing arguments ", s); result = m().mk_const(f); - return; } else { func_decl * f = fs.find(m(), num_args, args, range); - if (f == 0) - throw cmd_exception("unknown constant ", s); + if (f == 0) { + std::ostringstream buffer; + buffer << "unknown constant " << s << " "; + buffer << " ("; + bool first = true; + for (unsigned i = 0; i < num_args; ++i, first = false) { + if (!first) buffer << " "; + buffer << mk_pp(m().get_sort(args[i]), m()); + } + buffer << ") "; + if (range) buffer << mk_pp(range, m()) << " "; + for (unsigned i = 0; i < fs.get_num_entries(); ++i) { + buffer << "\ndeclared: " << mk_pp(fs.get_entry(i), m()) << " "; + } + throw cmd_exception(buffer.str().c_str()); + } if (well_sorted_check_enabled()) m().check_sort(f, num_args, args); result = m().mk_app(f, num_args, args); - return; } } @@ -1023,21 +1148,6 @@ void cmd_context::erase_psort_decl(symbol const & s) { erase_psort_decl_core(s); } -void cmd_context::erase_macro_core(symbol const & s) { - macro _m; - if (m_macros.find(s, _m)) { - m().dec_ref(_m.second); - m_macros.erase(s); - } -} - -void cmd_context::erase_macro(symbol const & s) { - if (!global_decls()) { - throw cmd_exception("macros (aka named expressions) can only be erased when global (instead of scoped) declarations are used"); - } - erase_macro_core(s); -} - void cmd_context::erase_cmd(symbol const & s) { cmd * c; if (m_cmds.find(s, c)) { @@ -1064,11 +1174,8 @@ void cmd_context::erase_object_ref(symbol const & s) { } void cmd_context::reset_func_decls() { - dictionary::iterator it = m_func_decls.begin(); - dictionary::iterator end = m_func_decls.end(); - for (; it != end; ++it) { - func_decls fs = (*it).m_value; - fs.finalize(m()); + for (auto & kv : m_func_decls) { + kv.m_value.finalize(m()); } m_func_decls.reset(); m_func_decls_stack.reset(); @@ -1076,10 +1183,8 @@ void cmd_context::reset_func_decls() { } void cmd_context::reset_psort_decls() { - dictionary::iterator it = m_psort_decls.begin(); - dictionary::iterator end = m_psort_decls.end(); - for (; it != end; ++it) { - psort_decl * p = (*it).m_value; + for (auto & kv : m_psort_decls) { + psort_decl * p = kv.m_value; pm().dec_ref(p); } m_psort_decls.reset(); @@ -1087,30 +1192,22 @@ void cmd_context::reset_psort_decls() { } void cmd_context::reset_macros() { - dictionary::iterator it = m_macros.begin(); - dictionary::iterator end = m_macros.end(); - for (; it != end; ++it) { - expr * t = (*it).m_value.second; - m().dec_ref(t); + for (auto & kv : m_macros) { + kv.m_value.finalize(m()); } m_macros.reset(); m_macros_stack.reset(); } void cmd_context::reset_cmds() { - dictionary::iterator it = m_cmds.begin(); - dictionary::iterator end = m_cmds.end(); - for (; it != end; ++it) { - cmd * c = (*it).m_value; - c->reset(*this); + for (auto& kv : m_cmds) { + kv.m_value->reset(*this); } } void cmd_context::finalize_cmds() { - dictionary::iterator it = m_cmds.begin(); - dictionary::iterator end = m_cmds.end(); - for (; it != end; ++it) { - cmd * c = (*it).m_value; + for (auto& kv : m_cmds) { + cmd * c = kv.m_value; c->finalize(*this); dealloc(c); } @@ -1123,10 +1220,8 @@ void cmd_context::reset_user_tactics() { } void cmd_context::reset_object_refs() { - dictionary::iterator it = m_object_refs.begin(); - dictionary::iterator end = m_object_refs.end(); - for (; it != end; ++it) { - object_ref * r = (*it).m_value; + for (auto& kv : m_object_refs) { + object_ref * r = kv.m_value; r->dec_ref(*this); } m_object_refs.reset(); @@ -1235,7 +1330,7 @@ void cmd_context::push(unsigned n) { push(); } -void cmd_context::restore_func_decls(unsigned old_sz) { +void cmd_context::restore_func_decls(unsigned old_sz) { SASSERT(old_sz <= m_func_decls_stack.size()); svector::iterator it = m_func_decls_stack.begin() + old_sz; svector::iterator end = m_func_decls_stack.end(); @@ -1274,10 +1369,7 @@ void cmd_context::restore_macros(unsigned old_sz) { svector::iterator end = m_macros_stack.end(); for (; it != end; ++it) { symbol const & s = *it; - macro _m; - VERIFY (m_macros.find(s, _m)); - m().dec_ref(_m.second); - m_macros.erase(s); + erase_macro(s); } m_macros_stack.shrink(old_sz); } @@ -1340,7 +1432,7 @@ void cmd_context::pop(unsigned n) { restore_assertions(s.m_assertions_lim); restore_psort_inst(s.m_psort_inst_stack_lim); m_scopes.shrink(new_lvl); - + } void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions) { @@ -1410,6 +1502,7 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions } display_sat_result(r); if (r == l_true) { + complete_model(); validate_model(); } validate_check_sat_result(r); @@ -1463,14 +1556,32 @@ void cmd_context::reset_assertions() { mk_solver(); } restore_assertions(0); - svector::iterator it = m_scopes.begin(); - svector::iterator end = m_scopes.end(); - for (; it != end; ++it) { - it->m_assertions_lim = 0; + for (scope& s : m_scopes) { + s.m_assertions_lim = 0; if (m_solver) m_solver->push(); } } - + + +void cmd_context::display_dimacs() { + if (m_solver) { + try { + gparams::set("sat.dimacs.display", "true"); + params_ref p; + m_solver->updt_params(p); + m_solver->check_sat(0, nullptr); + } + catch (...) { + gparams::set("sat.dimacs.display", "false"); + params_ref p; + m_solver->updt_params(p); + throw; + } + gparams::set("sat.dimacs.display", "false"); + params_ref p; + m_solver->updt_params(p); + } +} void cmd_context::display_model(model_ref& mdl) { if (mdl) { @@ -1509,7 +1620,9 @@ void cmd_context::validate_check_sat_result(lbool r) { throw cmd_exception("check annotation that says unsat"); #else diagnostic_stream() << "BUG: incompleteness" << std::endl; - exit(ERR_INCOMPLETENESS); + // WORKAROUND: `exit()` causes LSan to be invoked and produce + // many false positives. + _Exit(ERR_INCOMPLETENESS); #endif } break; @@ -1519,7 +1632,9 @@ void cmd_context::validate_check_sat_result(lbool r) { throw cmd_exception("check annotation that says sat"); #else diagnostic_stream() << "BUG: unsoundness" << std::endl; - exit(ERR_UNSOUNDNESS); + // WORKAROUND: `exit()` causes LSan to be invoked and produce + // many false positives. + _Exit(ERR_UNSOUNDNESS); #endif } break; @@ -1536,12 +1651,16 @@ void cmd_context::set_diagnostic_stream(char const * name) { } } -struct contains_array_op_proc { +struct contains_underspecified_op_proc { struct found {}; family_id m_array_fid; - contains_array_op_proc(ast_manager & m):m_array_fid(m.mk_family_id("array")) {} + datatype_util m_dt; + + contains_underspecified_op_proc(ast_manager & m):m_array_fid(m.mk_family_id("array")), m_dt(m) {} void operator()(var * n) {} void operator()(app * n) { + if (m_dt.is_accessor(n->get_decl())) + throw found(); if (n->get_family_id() != m_array_fid) return; decl_kind k = n->get_decl_kind(); @@ -1554,6 +1673,75 @@ struct contains_array_op_proc { void operator()(quantifier * n) {} }; +/** + \brief Complete the model if necessary. +*/ +void cmd_context::complete_model() { + if (!is_model_available() || + gparams::get_value("model.completion") != "true") + return; + + model_ref md; + get_check_sat_result()->get_model(md); + SASSERT(md.get() != 0); + params_ref p; + p.set_uint("max_degree", UINT_MAX); // evaluate algebraic numbers of any degree. + p.set_uint("sort_store", true); + p.set_bool("completion", true); + model_evaluator evaluator(*(md.get()), p); + evaluator.set_expand_array_equalities(false); + + scoped_rlimit _rlimit(m().limit(), 0); + cancel_eh eh(m().limit()); + expr_ref r(m()); + scoped_ctrl_c ctrlc(eh); + + for (auto kd : m_psort_decls) { + symbol const & k = kd.m_key; + psort_decl * v = kd.m_value; + if (v->is_user_decl()) { + SASSERT(!v->has_var_params()); + IF_VERBOSE(12, verbose_stream() << "(model.completion " << k << ")\n"; ); + ptr_vector param_sorts(v->get_num_params(), m().mk_bool_sort()); + sort * srt = v->instantiate(*m_pmanager, param_sorts.size(), param_sorts.c_ptr()); + if (!md->has_uninterpreted_sort(srt)) { + expr * singleton = m().get_some_value(srt); + md->register_usort(srt, 1, &singleton); + } + } + } + + for (unsigned i = 0; i < md->get_num_functions(); i++) { + func_decl * f = md->get_function(i); + func_interp * fi = md->get_func_interp(f); + IF_VERBOSE(12, verbose_stream() << "(model.completion " << f->get_name() << ")\n"; ); + if (fi->is_partial()) { + sort * range = f->get_range(); + fi->set_else(m().get_some_value(range)); + } + } + + for (auto kd : m_func_decls) { + symbol const & k = kd.m_key; + func_decls & v = kd.m_value; + IF_VERBOSE(12, verbose_stream() << "(model.completion " << k << ")\n"; ); + for (unsigned i = 0; i < v.get_num_entries(); i++) { + func_decl * f = v.get_entry(i); + if (!md->has_interpretation(f)) { + sort * range = f->get_range(); + expr * some_val = m().get_some_value(range); + if (f->get_arity() > 0) { + func_interp * fi = alloc(func_interp, m(), f->get_arity()); + fi->set_else(some_val); + md->register_decl(f, fi); + } + else + md->register_decl(f, some_val); + } + } + } +} + /** \brief Check if the current model satisfies the quantifier free formulas. */ @@ -1571,7 +1759,7 @@ void cmd_context::validate_model() { p.set_bool("completion", true); model_evaluator evaluator(*(md.get()), p); evaluator.set_expand_array_equalities(false); - contains_array_op_proc contains_array(m()); + contains_underspecified_op_proc contains_underspecified(m()); { scoped_rlimit _rlimit(m().limit(), 0); cancel_eh eh(m().limit()); @@ -1597,9 +1785,10 @@ void cmd_context::validate_model() { continue; } try { - for_each_expr(contains_array, r); + for_each_expr(contains_underspecified, a); + for_each_expr(contains_underspecified, r); } - catch (contains_array_op_proc::found) { + catch (contains_underspecified_op_proc::found) { continue; } TRACE("model_validate", model_smt2_pp(tout, *this, *(md.get()), 0);); @@ -1639,10 +1828,7 @@ void cmd_context::set_solver_factory(solver_factory * f) { mk_solver(); // assert formulas and create scopes in the new solver. unsigned lim = 0; - svector::iterator it = m_scopes.begin(); - svector::iterator end = m_scopes.end(); - for (; it != end; ++it) { - scope & s = *it; + for (scope& s : m_scopes) { for (unsigned i = lim; i < s.m_assertions_lim; i++) { m_solver->assert_expr(m_assertions[i]); } @@ -1679,11 +1865,9 @@ void cmd_context::display_statistics(bool show_total_time, double total_time) { void cmd_context::display_assertions() { if (!m_interactive_mode) throw cmd_exception("command is only available in interactive mode, use command (set-option :interactive-mode true)"); - std::vector::const_iterator it = m_assertion_strings.begin(); - std::vector::const_iterator end = m_assertion_strings.end(); regular_stream() << "("; - for (bool first = true; it != end; ++it) { - std::string const & s = *it; + bool first = true; + for (std::string const& s : m_assertion_strings) { if (first) first = false; else @@ -1759,10 +1943,8 @@ void cmd_context::display(std::ostream & out, func_decl * d, unsigned indent) co } void cmd_context::dump_assertions(std::ostream & out) const { - ptr_vector::const_iterator it = m_assertions.begin(); - ptr_vector::const_iterator end = m_assertions.end(); - for (; it != end; ++it) { - display(out, *it); + for (expr * e : m_assertions) { + display(out, e); out << std::endl; } } @@ -1821,26 +2003,20 @@ cmd_context::dt_eh::~dt_eh() { void cmd_context::dt_eh::operator()(sort * dt, pdecl* pd) { TRACE("new_dt_eh", tout << "new datatype: "; m_owner.pm().display(tout, dt); tout << "\n";); - ptr_vector const * constructors = m_dt_util.get_datatype_constructors(dt); - unsigned num_constructors = constructors->size(); - for (unsigned j = 0; j < num_constructors; j++) { - func_decl * c = constructors->get(j); - m_owner.insert(c); + for (func_decl * c : *m_dt_util.get_datatype_constructors(dt)) { TRACE("new_dt_eh", tout << "new constructor: " << c->get_name() << "\n";); + m_owner.insert(c); func_decl * r = m_dt_util.get_constructor_recognizer(c); m_owner.insert(r); TRACE("new_dt_eh", tout << "new recognizer: " << r->get_name() << "\n";); - ptr_vector const * accessors = m_dt_util.get_constructor_accessors(c); - unsigned num_accessors = accessors->size(); - for (unsigned k = 0; k < num_accessors; k++) { - func_decl * a = accessors->get(k); - m_owner.insert(a); + for (func_decl * a : *m_dt_util.get_constructor_accessors(c)) { TRACE("new_dt_eh", tout << "new accessor: " << a->get_name() << "\n";); + m_owner.insert(a); } } if (m_owner.m_scopes.size() > 0) { m_owner.m_psort_inst_stack.push_back(pd); - + } } diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 171d59a21..b60f590a9 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -8,7 +8,7 @@ Module Name: Abstract: Ultra-light command context. It provides a generic command pluging infrastructure. - A command context also provides names (aka symbols) to Z3 objects. + A command context also provides names (aka symbols) to Z3 objects. These names are used to reference Z3 objects in commands. Author: @@ -23,31 +23,33 @@ Notes: #include #include -#include"ast.h" -#include"ast_printer.h" -#include"pdecl.h" -#include"dictionary.h" -#include"solver.h" -#include"datatype_decl_plugin.h" -#include"stopwatch.h" -#include"cmd_context_types.h" -#include"event_handler.h" -#include"sexpr.h" -#include"tactic_manager.h" -#include"check_logic.h" -#include"progress_callback.h" -#include"scoped_ptr_vector.h" -#include"context_params.h" +#include "ast/ast.h" +#include "ast/ast_printer.h" +#include "cmd_context/pdecl.h" +#include "util/dictionary.h" +#include "solver/solver.h" +#include "ast/datatype_decl_plugin.h" +#include "util/stopwatch.h" +#include "util/cmd_context_types.h" +#include "util/event_handler.h" +#include "util/sexpr.h" +#include "cmd_context/tactic_manager.h" +#include "cmd_context/check_logic.h" +#include "solver/progress_callback.h" +#include "util/scoped_ptr_vector.h" +#include "cmd_context/context_params.h" class func_decls { func_decl * m_decls; bool signatures_collide(func_decl* f, func_decl* g) const; + bool signatures_collide(unsigned n, sort*const* domain, sort* range, func_decl* g) const; public: func_decls():m_decls(0) {} func_decls(ast_manager & m, func_decl * f); void finalize(ast_manager & m); bool contains(func_decl * f) const; + bool contains(unsigned n, sort* const* domain, sort* range) const; bool insert(ast_manager & m, func_decl * f); void erase(ast_manager & m, func_decl * f); bool more_than_one() const; @@ -56,6 +58,31 @@ public: func_decl * first() const; func_decl * find(unsigned arity, sort * const * domain, sort * range) const; func_decl * find(ast_manager & m, unsigned num_args, expr * const * args, sort * range) const; + unsigned get_num_entries() const; + func_decl * get_entry(unsigned inx); +}; + +struct macro_decl { + ptr_vector m_domain; + expr* m_body; + + macro_decl(unsigned arity, sort *const* domain, expr* body): + m_domain(arity, domain), m_body(body) {} + + void dec_ref(ast_manager& m) { m.dec_ref(m_body); } + +}; + +class macro_decls { + vector* m_decls; +public: + macro_decls() { m_decls = 0; } + void finalize(ast_manager& m); + bool insert(ast_manager& m, unsigned arity, sort *const* domain, expr* body); + expr* find(unsigned arity, sort *const* domain) const; + void erase_last(ast_manager& m); + vector::iterator begin() const { return m_decls->begin(); } + vector::iterator end() const { return m_decls->end(); } }; /** @@ -133,11 +160,11 @@ public: enum status { UNSAT, SAT, UNKNOWN }; - + enum check_sat_state { css_unsat, css_sat, css_unknown, css_clear }; - + typedef std::pair macro; struct scoped_watch { @@ -163,7 +190,7 @@ protected: bool m_ignore_check; // used by the API to disable check-sat() commands when parsing SMT 2.0 files. bool m_processing_pareto; // used when re-entering check-sat for pareto front. bool m_exit_on_error; - + static std::ostringstream g_error_stream; ast_manager * m_manager; @@ -175,7 +202,7 @@ protected: check_logic m_check_logic; stream_ref m_regular; stream_ref m_diagnostic; - dictionary m_cmds; + dictionary m_cmds; dictionary m_builtin_decls; scoped_ptr_vector m_extra_builtin_decls; // make sure that dynamically allocated builtin_decls are deleted dictionary m_object_refs; // anything that can be named. @@ -184,7 +211,7 @@ protected: dictionary m_func_decls; obj_map m_func_decl2alias; dictionary m_psort_decls; - dictionary m_macros; + dictionary m_macros; // the following fields m_func_decls_stack, m_psort_decls_stack and m_exprs_stack are used when m_global_decls == false typedef std::pair sf_pair; svector m_func_decls_stack; @@ -192,7 +219,7 @@ protected: svector m_macros_stack; ptr_vector m_psort_inst_stack; - // + // ptr_vector m_aux_pdecls; ptr_vector m_assertions; std::vector m_assertion_strings; @@ -211,7 +238,7 @@ protected: svector m_scopes; scoped_ptr m_solver_factory; scoped_ptr m_interpolating_solver_factory; - ref m_solver; + ref m_solver; ref m_check_sat_result; ref m_opt; @@ -253,7 +280,6 @@ protected: void erase_func_decl_core(symbol const & s, func_decl * f); void erase_psort_decl_core(symbol const & s); - void erase_macro_core(symbol const & s); bool logic_has_arith() const; bool logic_has_bv() const; @@ -268,9 +294,19 @@ protected: void mk_solver(); + bool contains_func_decl(symbol const& s, unsigned n, sort* const* domain, sort* range) const; + + bool contains_macro(symbol const& s) const; + bool contains_macro(symbol const& s, func_decl* f) const; + bool contains_macro(symbol const& s, unsigned arity, sort *const* domain) const; + void insert_macro(symbol const& s, unsigned arity, sort*const* domain, expr* t); + void erase_macro(symbol const& s); + bool macros_find(symbol const& s, unsigned n, expr*const* args, expr*& t) const; + + public: cmd_context(bool main_ctx = true, ast_manager * m = 0, symbol const & l = symbol::null); - ~cmd_context(); + ~cmd_context(); void set_cancel(bool f); context_params & params() { return m_params; } solver_factory &get_solver_factory() { return *m_solver_factory; } @@ -320,47 +356,46 @@ public: virtual ast_manager & get_ast_manager() { return m(); } pdecl_manager & pm() const { if (!m_pmanager) const_cast(this)->init_manager(); return *m_pmanager; } sexpr_manager & sm() const { if (!m_sexpr_manager) const_cast(this)->m_sexpr_manager = alloc(sexpr_manager); return *m_sexpr_manager; } - + void set_solver_factory(solver_factory * s); void set_interpolating_solver_factory(solver_factory * s); void set_check_sat_result(check_sat_result * r) { m_check_sat_result = r; } check_sat_result * get_check_sat_result() const { return m_check_sat_result.get(); } check_sat_state cs_state() const; + void complete_model(); void validate_model(); void display_model(model_ref& mdl); - void register_plugin(symbol const & name, decl_plugin * p, bool install_names); + void register_plugin(symbol const & name, decl_plugin * p, bool install_names); bool is_func_decl(symbol const & s) const; bool is_sort_decl(symbol const& s) const { return m_psort_decls.contains(s); } void insert(cmd * c); - void insert(symbol const & s, func_decl * f); + void insert(symbol const & s, func_decl * f); void insert(func_decl * f) { insert(f->get_name(), f); } void insert(symbol const & s, psort_decl * p); void insert(psort_decl * p) { insert(p->get_name(), p); } - void insert(symbol const & s, unsigned arity, expr * t); + void insert(symbol const & s, unsigned arity, sort *const* domain, expr * t); void insert(symbol const & s, object_ref *); void insert(tactic_cmd * c) { tactic_manager::insert(c); } - void insert(probe_info * p) { tactic_manager::insert(p); } - void insert_user_tactic(symbol const & s, sexpr * d); + void insert(probe_info * p) { tactic_manager::insert(p); } + void insert_user_tactic(symbol const & s, sexpr * d); void insert_aux_pdecl(pdecl * p); void insert_rec_fun(func_decl* f, expr_ref_vector const& binding, svector const& ids, expr* e); func_decl * find_func_decl(symbol const & s) const; - func_decl * find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices, + func_decl * find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices, unsigned arity, sort * const * domain, sort * range) const; psort_decl * find_psort_decl(symbol const & s) const; - macro find_macro(symbol const & s) const; cmd * find_cmd(symbol const & s) const; sexpr * find_user_tactic(symbol const & s) const; object_ref * find_object_ref(symbol const & s) const; void mk_const(symbol const & s, expr_ref & result) const; - void mk_app(symbol const & s, unsigned num_args, expr * const * args, unsigned num_indices, parameter const * indices, sort * range, + void mk_app(symbol const & s, unsigned num_args, expr * const * args, unsigned num_indices, parameter const * indices, sort * range, expr_ref & r) const; void erase_cmd(symbol const & s); void erase_func_decl(symbol const & s); void erase_func_decl(symbol const & s, func_decl * f); void erase_func_decl(func_decl * f) { erase_func_decl(f->get_name(), f); } void erase_psort_decl(symbol const & s); - void erase_macro(symbol const & s); void erase_object_ref(symbol const & s); void erase_user_tactic(symbol const & s); void reset_func_decls(); @@ -369,7 +404,7 @@ public: void reset_object_refs(); void reset_user_tactics(); void set_regular_stream(char const * name) { m_regular.set(name); } - void set_diagnostic_stream(char const * name); + void set_diagnostic_stream(char const * name); virtual std::ostream & regular_stream() { return *m_regular; } virtual std::ostream & diagnostic_stream() { return *m_diagnostic; } char const * get_regular_stream_name() const { return m_regular.name(); } @@ -384,6 +419,7 @@ public: void display_assertions(); void display_statistics(bool show_total_time = false, double total_time = 0.0); + void display_dimacs(); void reset(bool finalize = false); void assert_expr(expr * t); void assert_expr(symbol const & name, expr * t); @@ -397,10 +433,10 @@ public: // display the result produced by a check-sat or check-sat-using commands in the regular stream void display_sat_result(lbool r); // check if result produced by check-sat or check-sat-using matches the known status - void validate_check_sat_result(lbool r); + void validate_check_sat_result(lbool r); unsigned num_scopes() const { return m_scopes.size(); } - dictionary const & get_macros() const { return m_macros; } + dictionary const & get_macros() const { return m_macros; } bool is_model_available() const; diff --git a/src/cmd_context/cmd_context_to_goal.cpp b/src/cmd_context/cmd_context_to_goal.cpp index c0b4379aa..beff9a7bd 100644 --- a/src/cmd_context/cmd_context_to_goal.cpp +++ b/src/cmd_context/cmd_context_to_goal.cpp @@ -16,8 +16,8 @@ Author: Notes: --*/ -#include"cmd_context.h" -#include"goal.h" +#include "cmd_context/cmd_context.h" +#include "tactic/goal.h" /** \brief Assert expressions from ctx into t. diff --git a/src/cmd_context/cmd_util.cpp b/src/cmd_context/cmd_util.cpp index 9774c75ff..ae626118c 100644 --- a/src/cmd_context/cmd_util.cpp +++ b/src/cmd_context/cmd_util.cpp @@ -15,7 +15,7 @@ Author: Notes: --*/ -#include"cmd_context.h" +#include "cmd_context/cmd_context.h" ast * get_ast_ref(cmd_context & ctx, symbol const & v) { object_ref * r = ctx.find_object_ref(v); diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp index ff8b50c60..78f4223fc 100644 --- a/src/cmd_context/context_params.cpp +++ b/src/cmd_context/context_params.cpp @@ -17,11 +17,11 @@ Author: Notes: --*/ -#include"context_params.h" -#include"gparams.h" -#include"params.h" -#include"ast.h" -#include"solver.h" +#include "cmd_context/context_params.h" +#include "util/gparams.h" +#include "util/params.h" +#include "ast/ast.h" +#include "solver/solver.h" context_params::context_params() { m_unsat_core = false; @@ -111,6 +111,9 @@ void context_params::set(char const * param, char const * value) { else if (p == "trace_file_name") { m_trace_file_name = value; } + else if (p == "dot_proof_file") { + m_dot_proof_file = value; + } else if (p == "unsat_core") { set_bool(m_unsat_core, param, value); } @@ -146,6 +149,7 @@ void context_params::updt_params(params_ref const & p) { m_dump_models = p.get_bool("dump_models", m_dump_models); m_trace = p.get_bool("trace", m_trace); m_trace_file_name = p.get_str("trace_file_name", "z3.log"); + m_dot_proof_file = p.get_str("dot_proof_file", "proof.dot"); m_unsat_core = p.get_bool("unsat_core", m_unsat_core); m_debug_ref_count = p.get_bool("debug_ref_count", m_debug_ref_count); m_smtlib2_compliant = p.get_bool("smtlib2_compliant", m_smtlib2_compliant); @@ -161,6 +165,7 @@ void context_params::collect_param_descrs(param_descrs & d) { d.insert("dump_models", CPK_BOOL, "dump models whenever check-sat returns sat", "false"); d.insert("trace", CPK_BOOL, "trace generation for VCC", "false"); d.insert("trace_file_name", CPK_STRING, "trace out file name (see option 'trace')", "z3.log"); + d.insert("dot_proof_file", CPK_STRING, "file in which to output graphical proofs", "proof.dot"); d.insert("debug_ref_count", CPK_BOOL, "debug support for AST reference counting", "false"); d.insert("smtlib2_compliant", CPK_BOOL, "enable/disable SMT-LIB 2.0 compliance", "false"); collect_solver_param_descrs(d); @@ -192,7 +197,7 @@ void context_params::get_solver_params(ast_manager const & m, params_ref & p, bo ast_manager * context_params::mk_ast_manager() { ast_manager * r = alloc(ast_manager, - m_proof ? PGM_FINE : PGM_DISABLED, + m_proof ? PGM_ENABLED : PGM_DISABLED, m_trace ? m_trace_file_name.c_str() : 0); if (m_smtlib2_compliant) r->enable_int_real_coercions(false); diff --git a/src/cmd_context/context_params.h b/src/cmd_context/context_params.h index 40b6c9482..df62057fe 100644 --- a/src/cmd_context/context_params.h +++ b/src/cmd_context/context_params.h @@ -20,7 +20,7 @@ Notes: #ifndef CONTEXT_PARAMS_H_ #define CONTEXT_PARAMS_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class context_params { @@ -30,6 +30,7 @@ class context_params { public: bool m_auto_config; bool m_proof; + std::string m_dot_proof_file; bool m_interpolants; bool m_debug_ref_count; bool m_trace; diff --git a/src/cmd_context/echo_tactic.cpp b/src/cmd_context/echo_tactic.cpp index 218d9c196..848ae5429 100644 --- a/src/cmd_context/echo_tactic.cpp +++ b/src/cmd_context/echo_tactic.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"tactic.h" -#include"probe.h" -#include"cmd_context.h" +#include "tactic/tactic.h" +#include "tactic/probe.h" +#include "cmd_context/cmd_context.h" class echo_tactic : public skip_tactic { cmd_context & m_ctx; diff --git a/src/cmd_context/eval_cmd.cpp b/src/cmd_context/eval_cmd.cpp index 86078a13c..9d3c1ced3 100644 --- a/src/cmd_context/eval_cmd.cpp +++ b/src/cmd_context/eval_cmd.cpp @@ -16,12 +16,12 @@ Author: Notes: --*/ -#include"cmd_context.h" -#include"model_evaluator.h" -#include"parametric_cmd.h" -#include"scoped_timer.h" -#include"scoped_ctrl_c.h" -#include"cancel_eh.h" +#include "cmd_context/cmd_context.h" +#include "model/model_evaluator.h" +#include "cmd_context/parametric_cmd.h" +#include "util/scoped_timer.h" +#include "util/scoped_ctrl_c.h" +#include "util/cancel_eh.h" class eval_cmd : public parametric_cmd { expr * m_target; @@ -58,6 +58,8 @@ public: virtual void execute(cmd_context & ctx) { if (!ctx.is_model_available()) throw cmd_exception("model is not available"); + if (!m_target) + throw cmd_exception("no arguments passed to eval"); model_ref md; unsigned index = m_params.get_uint("model_index", 0); check_sat_result * last_result = ctx.get_check_sat_result(); diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 7ee1c0aeb..dfdfa6175 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -16,22 +16,21 @@ Notes: --*/ #include -#include"cmd_context.h" -#include"cmd_util.h" -#include"rewriter.h" -#include"shared_occs.h" -#include"for_each_expr.h" -#include"rewriter.h" -#include"bool_rewriter.h" -#include"ast_lt.h" -#include"simplify_cmd.h" -#include"ast_smt2_pp.h" -#include"bound_manager.h" -#include"used_vars.h" -#include"var_subst.h" -#include"gparams.h" +#include "cmd_context/cmd_context.h" +#include "cmd_context/cmd_util.h" +#include "ast/rewriter/rewriter.h" +#include "ast/shared_occs.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/ast_lt.h" +#include "cmd_context/simplify_cmd.h" +#include "ast/ast_smt2_pp.h" +#include "tactic/arith/bound_manager.h" +#include "ast/used_vars.h" +#include "ast/rewriter/var_subst.h" +#include "util/gparams.h" -#ifndef _EXTERNAL_RELEASE BINARY_SYM_CMD(get_quantifier_body_cmd, "dbg-get-qbody", @@ -106,7 +105,7 @@ class subst_cmd : public cmd { public: subst_cmd():cmd("dbg-subst") {} virtual char const * get_usage() const { return " (*) "; } - virtual char const * get_descr() const { return "substitute the free variables in the AST referenced by using the ASTs referenced by *"; } + virtual char const * get_descr(cmd_context & ctx) const { return "substitute the free variables in the AST referenced by using the ASTs referenced by *"; } virtual unsigned get_arity() const { return 3; } virtual void prepare(cmd_context & ctx) { m_idx = 0; m_source = 0; } virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { @@ -285,7 +284,7 @@ protected: public: instantiate_cmd_core(char const * name):cmd(name) {} virtual char const * get_usage() const { return " (*)"; } - virtual char const * get_descr() const { return "instantiate the quantifier using the given expressions."; } + virtual char const * get_descr(cmd_context & ctx) const { return "instantiate the quantifier using the given expressions."; } virtual unsigned get_arity() const { return 2; } virtual void prepare(cmd_context & ctx) { m_q = 0; m_args.reset(); } @@ -333,7 +332,7 @@ class instantiate_nested_cmd : public instantiate_cmd_core { public: instantiate_nested_cmd():instantiate_cmd_core("dbg-instantiate-nested") {} - virtual char const * get_descr() const { return "instantiate the quantifier nested in the outermost quantifier, this command is used to test the instantiation procedure with quantifiers that contain free variables."; } + virtual char const * get_descr(cmd_context & ctx) const { return "instantiate the quantifier nested in the outermost quantifier, this command is used to test the instantiation procedure with quantifiers that contain free variables."; } virtual void set_next_arg(cmd_context & ctx, expr * s) { instantiate_cmd_core::set_next_arg(ctx, s); @@ -343,10 +342,19 @@ public: } }; -#endif +class print_dimacs_cmd : public cmd { +public: + print_dimacs_cmd():cmd("display-dimacs") {} + virtual char const * get_usage() const { return ""; } + virtual char const * get_descr(cmd_context & ctx) const { return "print benchmark in DIMACS format"; } + virtual unsigned get_arity() const { return 0; } + virtual void prepare(cmd_context & ctx) {} + virtual void execute(cmd_context & ctx) { ctx.display_dimacs(); } +}; + void install_dbg_cmds(cmd_context & ctx) { -#ifndef _EXTERNAL_RELEASE + ctx.insert(alloc(print_dimacs_cmd)); ctx.insert(alloc(get_quantifier_body_cmd)); ctx.insert(alloc(set_cmd)); ctx.insert(alloc(pp_var_cmd)); @@ -369,5 +377,4 @@ void install_dbg_cmds(cmd_context & ctx) { ctx.insert(alloc(instantiate_cmd)); ctx.insert(alloc(instantiate_nested_cmd)); ctx.insert(alloc(set_next_id)); -#endif } diff --git a/src/cmd_context/extra_cmds/polynomial_cmds.cpp b/src/cmd_context/extra_cmds/polynomial_cmds.cpp index afd4713bd..7a748ac66 100644 --- a/src/cmd_context/extra_cmds/polynomial_cmds.cpp +++ b/src/cmd_context/extra_cmds/polynomial_cmds.cpp @@ -16,20 +16,20 @@ Notes: --*/ #include -#include"cmd_context.h" -#include"cmd_util.h" -#include"scoped_timer.h" -#include"scoped_ctrl_c.h" -#include"cancel_eh.h" -#include"ast_smt2_pp.h" -#include"expr2polynomial.h" -#include"parametric_cmd.h" -#include"mpq.h" -#include"algebraic_numbers.h" -#include"polynomial_var2value.h" -#include"expr2var.h" -#include"pp.h" -#include"pp_params.hpp" +#include "cmd_context/cmd_context.h" +#include "cmd_context/cmd_util.h" +#include "util/scoped_timer.h" +#include "util/scoped_ctrl_c.h" +#include "util/cancel_eh.h" +#include "ast/ast_smt2_pp.h" +#include "ast/expr2polynomial.h" +#include "cmd_context/parametric_cmd.h" +#include "util/mpq.h" +#include "math/polynomial/algebraic_numbers.h" +#include "math/polynomial/polynomial_var2value.h" +#include "ast/expr2var.h" +#include "ast/pp.h" +#include "ast/pp_params.hpp" static void to_poly(cmd_context & ctx, expr * t) { polynomial::numeral_manager nm; diff --git a/src/cmd_context/extra_cmds/subpaving_cmds.cpp b/src/cmd_context/extra_cmds/subpaving_cmds.cpp index d6496bccc..3c8a657ac 100644 --- a/src/cmd_context/extra_cmds/subpaving_cmds.cpp +++ b/src/cmd_context/extra_cmds/subpaving_cmds.cpp @@ -16,12 +16,12 @@ Notes: --*/ #include -#include"cmd_context.h" -#include"cmd_util.h" -#include"expr2subpaving.h" -#include"th_rewriter.h" -#include"ast_smt2_pp.h" -#include"expr2var.h" +#include "cmd_context/cmd_context.h" +#include "cmd_context/cmd_util.h" +#include "math/subpaving/tactic/expr2subpaving.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/ast_smt2_pp.h" +#include "ast/expr2var.h" static void to_subpaving(cmd_context & ctx, expr * t) { ast_manager & m = ctx.m(); diff --git a/src/cmd_context/interpolant_cmds.cpp b/src/cmd_context/interpolant_cmds.cpp index 53da91d1e..8b9f0ebd8 100644 --- a/src/cmd_context/interpolant_cmds.cpp +++ b/src/cmd_context/interpolant_cmds.cpp @@ -16,23 +16,23 @@ --*/ #include -#include"cmd_context.h" -#include"cmd_util.h" -#include"scoped_timer.h" -#include"scoped_ctrl_c.h" -#include"cancel_eh.h" -#include"ast_pp.h" -#include"ast_smt_pp.h" -#include"ast_smt2_pp.h" -#include"parametric_cmd.h" -#include"mpq.h" -#include"expr2var.h" -#include"pp.h" -#include"iz3interp.h" -#include"iz3checker.h" -#include"iz3profiling.h" -#include"interp_params.hpp" -#include"scoped_proof.h" +#include "cmd_context/cmd_context.h" +#include "cmd_context/cmd_util.h" +#include "util/scoped_timer.h" +#include "util/scoped_ctrl_c.h" +#include "util/cancel_eh.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt_pp.h" +#include "ast/ast_smt2_pp.h" +#include "cmd_context/parametric_cmd.h" +#include "util/mpq.h" +#include "ast/expr2var.h" +#include "ast/pp.h" +#include "interp/iz3interp.h" +#include "interp/iz3checker.h" +#include "interp/iz3profiling.h" +#include "interp/interp_params.hpp" +#include "ast/scoped_proof.h" static void show_interpolant_and_maybe_check(cmd_context & ctx, ptr_vector &cnsts, @@ -46,20 +46,14 @@ static void show_interpolant_and_maybe_check(cmd_context & ctx, m_params.set_bool("flat", true); th_rewriter s(ctx.m(), m_params); + ctx.regular_stream() << "(interpolants"; for(unsigned i = 0; i < interps.size(); i++){ - expr_ref r(ctx.m()); proof_ref pr(ctx.m()); s(to_expr(interps[i]),r,pr); - - ctx.regular_stream() << mk_pp(r.get(), ctx.m()) << std::endl; -#if 0 - ast_smt_pp pp(ctx.m()); - pp.set_logic(ctx.get_logic().str().c_str()); - pp.display_smt2(ctx.regular_stream(), to_expr(interps[i])); - ctx.regular_stream() << std::endl; -#endif + ctx.regular_stream() << "\n " << r; } + ctx.regular_stream() << ")\n"; s.cleanup(); @@ -153,7 +147,7 @@ static void compute_interpolant_and_maybe_check(cmd_context & ctx, expr * t, par ast_manager &_m = ctx.m(); // TODO: the following is a HACK to enable proofs in the old smt solver // When we stop using that solver, this hack can be removed - scoped_proof_mode spm(_m,PGM_FINE); + scoped_proof_mode spm(_m,PGM_ENABLED); ctx.params().get_solver_params(_m, p, proofs_enabled, models_enabled, unsat_core_enabled); p.set_bool("proof", true); scoped_ptr sp = (ctx.get_interpolating_solver_factory())(_m, p, true, models_enabled, false, ctx.get_logic()); diff --git a/src/cmd_context/parametric_cmd.cpp b/src/cmd_context/parametric_cmd.cpp index c229bc29c..4a85821b2 100644 --- a/src/cmd_context/parametric_cmd.cpp +++ b/src/cmd_context/parametric_cmd.cpp @@ -16,8 +16,8 @@ Notes: --*/ #include -#include"cmd_context.h" -#include"parametric_cmd.h" +#include "cmd_context/cmd_context.h" +#include "cmd_context/parametric_cmd.h" char const * parametric_cmd::get_descr(cmd_context & ctx) const { if (m_descr == 0) { diff --git a/src/cmd_context/parametric_cmd.h b/src/cmd_context/parametric_cmd.h index cac5fe38e..6d676d6f9 100644 --- a/src/cmd_context/parametric_cmd.h +++ b/src/cmd_context/parametric_cmd.h @@ -18,10 +18,10 @@ Notes: #ifndef PARAMETRIC_CMD_H_ #define PARAMETRIC_CMD_H_ -#include"params.h" -#include"symbol.h" -#include"string_buffer.h" -#include"cmd_context_types.h" +#include "util/params.h" +#include "util/symbol.h" +#include "util/string_buffer.h" +#include "util/cmd_context_types.h" class parametric_cmd : public cmd { public: diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index bd2ef849a..7eac1f347 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"pdecl.h" -#include"datatype_decl_plugin.h" +#include "cmd_context/pdecl.h" +#include "ast/datatype_decl_plugin.h" using namespace format_ns; class psort_inst_cache { @@ -25,11 +25,11 @@ class psort_inst_cache { sort * m_const; obj_map m_map; // if m_num_params == 1 value is a sort, otherwise it is a reference to another inst_cache public: - psort_inst_cache(unsigned num_params):m_num_params(num_params), m_const(0) { + psort_inst_cache(unsigned num_params):m_num_params(num_params), m_const(0) { } ~psort_inst_cache() { SASSERT(m_map.empty()); SASSERT(m_const == 0); } - + void finalize(pdecl_manager & m) { if (m_num_params == 0) { SASSERT(m_map.empty()); @@ -39,15 +39,13 @@ public: } else { SASSERT(m_const == 0); - obj_map::iterator it = m_map.begin(); - obj_map::iterator end = m_map.end(); - for (; it != end; ++it) { - m.m().dec_ref((*it).m_key); + for (auto kv : m_map) { + m.m().dec_ref(kv.m_key); if (m_num_params == 1) { - m.m().dec_ref(static_cast((*it).m_value)); + m.m().dec_ref(static_cast(kv.m_value)); } else { - psort_inst_cache * child = static_cast((*it).m_value); + psort_inst_cache * child = static_cast(kv.m_value); child->finalize(m); child->~psort_inst_cache(); m.a().deallocate(sizeof(psort_inst_cache), child); @@ -85,7 +83,7 @@ public: curr = static_cast(next); } } - + sort * find(sort * const * s) const { if (m_num_params == 0) return m_const; @@ -138,8 +136,8 @@ class psort_sort : public psort { friend class pdecl_manager; sort * m_sort; psort_sort(unsigned id, pdecl_manager & m, sort * s):psort(id, 0), m_sort(s) { m.m().inc_ref(m_sort); } - virtual void finalize(pdecl_manager & m) { - m.m().dec_ref(m_sort); + virtual void finalize(pdecl_manager & m) { + m.m().dec_ref(m_sort); psort::finalize(m); } virtual bool check_num_params(pdecl * other) const { return true; } @@ -152,7 +150,7 @@ public: virtual char const * hcons_kind() const { return "psort_sort"; } virtual unsigned hcons_hash() const { return m_sort->get_id(); } virtual bool hcons_eq(psort const * other) const { - if (other->hcons_kind() != hcons_kind()) + if (other->hcons_kind() != hcons_kind()) return false; return m_sort == static_cast(other)->m_sort; } @@ -172,10 +170,11 @@ public: virtual char const * hcons_kind() const { return "psort_var"; } virtual unsigned hcons_hash() const { return hash_u_u(m_num_params, m_idx); } virtual bool hcons_eq(psort const * other) const { - if (other->hcons_kind() != hcons_kind()) - return false; - return get_num_params() == other->get_num_params() && m_idx == static_cast(other)->m_idx; - } + return + other->hcons_kind() == hcons_kind() && + get_num_params() == other->get_num_params() && + m_idx == static_cast(other)->m_idx; + } virtual void display(std::ostream & out) const { out << "s_" << m_idx; } @@ -197,7 +196,7 @@ class psort_app : public psort { DEBUG_CODE(if (num_args == num_params) { for (unsigned i = 0; i < num_params; i++) args[i]->check_num_params(this); }); } - virtual void finalize(pdecl_manager & m) { + virtual void finalize(pdecl_manager & m) { m.lazy_dec_ref(m_decl); m.lazy_dec_ref(m_args.size(), m_args.c_ptr()); psort::finalize(m); @@ -208,14 +207,14 @@ class psort_app : public psort { struct khasher { unsigned operator()(psort_app const * d) const { return d->m_decl->hash(); } }; - + struct chasher { unsigned operator()(psort_app const * d, unsigned idx) const { return d->m_args[idx]->hash(); } }; - virtual sort * instantiate(pdecl_manager & m, sort * const * s) { + virtual sort * instantiate(pdecl_manager & m, sort * const * s) { sort * r = find(s); - if (r) + if (r) return r; sort_ref_buffer args_i(m.m()); unsigned sz = m_args.size(); @@ -231,11 +230,11 @@ class psort_app : public psort { public: virtual ~psort_app() {} virtual char const * hcons_kind() const { return "psort_app"; } - virtual unsigned hcons_hash() const { + virtual unsigned hcons_hash() const { return get_composite_hash(const_cast(this), m_args.size()); } virtual bool hcons_eq(psort const * other) const { - if (other->hcons_kind() != hcons_kind()) + if (other->hcons_kind() != hcons_kind()) return false; if (get_num_params() != other->get_num_params()) return false; @@ -269,6 +268,7 @@ public: psort_decl::psort_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n): pdecl(id, num_params), m_name(n), + m_psort_kind(PSORT_BASE), m_inst_cache(0) { } @@ -293,30 +293,10 @@ sort * psort_decl::find(sort * const * s) { return m_inst_cache->find(s); } -#if 0 -psort_dt_decl::psort_dt_decl(unsigned id, unsigned num_params, pdecl_manager& m, symbol const& n): - psort_decl(id, num_params, m, n) { -} - -void psort_dt_decl::finalize(pdecl_manager& m) { - psort_decl::finalize(m); -} - - -sort * psort_dt_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { - UNREACHABLE(); - return 0; -} - -void psort_dt_decl::display(std::ostream & out) const { - out << get_name() << " " << get_num_params(); -} -#endif - - -psort_user_decl::psort_user_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, psort * p): +psort_user_decl::psort_user_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, psort * p) : psort_decl(id, num_params, m, n), m_def(p) { + m_psort_kind = PSORT_USER; m.inc_ref(p); SASSERT(p == 0 || num_params == p->get_num_params()); } @@ -365,10 +345,32 @@ void psort_user_decl::display(std::ostream & out) const { out << ")"; } +// ------------------- +// psort_dt_decl + +psort_dt_decl::psort_dt_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n) : + psort_decl(id, num_params, m, n) { + m_psort_kind = PSORT_DT; +} + + +sort * psort_dt_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { + SASSERT(n == m_num_params); + return m.instantiate_datatype(this, m_name, n, s); +} + +void psort_dt_decl::display(std::ostream & out) const { + out << "(datatype-sort " << m_name << ")"; +} + +// ------------------- +// psort_builtin_decl + psort_builtin_decl::psort_builtin_decl(unsigned id, pdecl_manager & m, symbol const & n, family_id fid, decl_kind k): psort_decl(id, PSORT_DECL_VAR_PARAMS, m, n), m_fid(fid), m_kind(k) { + m_psort_kind = PSORT_BUILTIN; } sort * psort_builtin_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { @@ -417,16 +419,16 @@ void ptype::display(std::ostream & out, pdatatype_decl const * const * dts) cons paccessor_decl::paccessor_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, ptype const & r): pdecl(id, num_params), - m_name(n), + m_name(n), m_type(r) { if (m_type.kind() == PTR_PSORT) { m.inc_ref(r.get_psort()); } } -void paccessor_decl::finalize(pdecl_manager & m) { +void paccessor_decl::finalize(pdecl_manager & m) { if (m_type.kind() == PTR_PSORT) { - m.lazy_dec_ref(m_type.get_psort()); + m.lazy_dec_ref(m_type.get_psort()); } } @@ -439,7 +441,7 @@ bool paccessor_decl::has_missing_refs(symbol & missing) const { } bool paccessor_decl::fix_missing_refs(dictionary const & symbol2idx, symbol & missing) { - TRACE("fix_missing_refs", tout << "m_type.kind(): " << m_type.kind() << "\n"; + TRACE("fix_missing_refs", tout << "m_type.kind(): " << m_type.kind() << "\n"; if (m_type.kind() == PTR_MISSING_REF) tout << m_type.get_missing_ref() << "\n";); if (m_type.kind() != PTR_MISSING_REF) return true; @@ -455,8 +457,8 @@ bool paccessor_decl::fix_missing_refs(dictionary const & symbol2idx, symbol accessor_decl * paccessor_decl::instantiate_decl(pdecl_manager & m, sort * const * s) { switch (m_type.kind()) { - case PTR_REC_REF: return mk_accessor_decl(m_name, type_ref(m_type.get_idx())); - case PTR_PSORT: return mk_accessor_decl(m_name, type_ref(m_type.get_psort()->instantiate(m, s))); + case PTR_REC_REF: return mk_accessor_decl(m.m(), m_name, type_ref(m_type.get_idx())); + case PTR_PSORT: return mk_accessor_decl(m.m(), m_name, type_ref(m_type.get_psort()->instantiate(m, s))); default: // missing refs must have been eliminated. UNREACHABLE(); @@ -470,7 +472,7 @@ void paccessor_decl::display(std::ostream & out, pdatatype_decl const * const * out << ")"; } -pconstructor_decl::pconstructor_decl(unsigned id, unsigned num_params, pdecl_manager & m, +pconstructor_decl::pconstructor_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, symbol const & r, unsigned num_accessors, paccessor_decl * const * accessors): pdecl(id, num_params), m_name(n), @@ -485,20 +487,16 @@ void pconstructor_decl::finalize(pdecl_manager & m) { } bool pconstructor_decl::has_missing_refs(symbol & missing) const { - ptr_vector::const_iterator it = m_accessors.begin(); - ptr_vector::const_iterator end = m_accessors.end(); - for (; it != end; ++it) { - if ((*it)->has_missing_refs(missing)) + for (paccessor_decl* a : m_accessors) { + if (a->has_missing_refs(missing)) return true; } return false; } bool pconstructor_decl::fix_missing_refs(dictionary const & symbol2idx, symbol & missing) { - ptr_vector::iterator it = m_accessors.begin(); - ptr_vector::iterator end = m_accessors.end(); - for (; it != end; ++it) { - if (!(*it)->fix_missing_refs(symbol2idx, missing)) + for (paccessor_decl* a : m_accessors) { + if (!a->fix_missing_refs(symbol2idx, missing)) return false; } return true; @@ -506,25 +504,21 @@ bool pconstructor_decl::fix_missing_refs(dictionary const & symbol2idx, sym constructor_decl * pconstructor_decl::instantiate_decl(pdecl_manager & m, sort * const * s) { ptr_buffer as; - ptr_vector::iterator it = m_accessors.begin(); - ptr_vector::iterator end = m_accessors.end(); - for (; it != end; ++it) - as.push_back((*it)->instantiate_decl(m, s)); + for (paccessor_decl* a : m_accessors) + as.push_back(a->instantiate_decl(m, s)); return mk_constructor_decl(m_name, m_recogniser_name, as.size(), as.c_ptr()); } void pconstructor_decl::display(std::ostream & out, pdatatype_decl const * const * dts) const { out << "(" << m_name; - ptr_vector::const_iterator it = m_accessors.begin(); - ptr_vector::const_iterator end = m_accessors.end(); - for (; it != end; ++it) { + for (paccessor_decl* a : m_accessors) { out << " "; - (*it)->display(out, dts); + a->display(out, dts); } out << ")"; } -pdatatype_decl::pdatatype_decl(unsigned id, unsigned num_params, pdecl_manager & m, +pdatatype_decl::pdatatype_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, unsigned num_constructors, pconstructor_decl * const * constructors): psort_decl(id, num_params, m, n), m_constructors(num_constructors, constructors), @@ -538,23 +532,17 @@ void pdatatype_decl::finalize(pdecl_manager & m) { } bool pdatatype_decl::has_missing_refs(symbol & missing) const { - ptr_vector::const_iterator it = m_constructors.begin(); - ptr_vector::const_iterator end = m_constructors.end(); - for (; it != end; ++it) { - if ((*it)->has_missing_refs(missing)) + for (auto c : m_constructors) + if (c->has_missing_refs(missing)) return true; - } return false; } bool pdatatype_decl::has_duplicate_accessors(symbol & duplicated) const { hashtable names; - ptr_vector::const_iterator it = m_constructors.begin(); - ptr_vector::const_iterator end = m_constructors.end(); - for (; it != end; ++it) { - ptr_vector const& acc = (*it)->m_accessors; - for (unsigned i = 0; i < acc.size(); ++i) { - symbol const& name = acc[i]->get_name(); + for (auto c : m_constructors) { + for (auto a : c->m_accessors) { + symbol const& name = a->get_name(); if (names.contains(name)) { duplicated = name; return true; @@ -567,10 +555,8 @@ bool pdatatype_decl::has_duplicate_accessors(symbol & duplicated) const { bool pdatatype_decl::fix_missing_refs(dictionary const & symbol2idx, symbol & missing) { - ptr_vector::iterator it = m_constructors.begin(); - ptr_vector::iterator end = m_constructors.end(); - for (; it != end; ++it) { - if (!(*it)->fix_missing_refs(symbol2idx, missing)) + for (auto c : m_constructors) { + if (!c->fix_missing_refs(symbol2idx, missing)) return false; } return true; @@ -578,12 +564,11 @@ bool pdatatype_decl::fix_missing_refs(dictionary const & symbol2idx, symbol datatype_decl * pdatatype_decl::instantiate_decl(pdecl_manager & m, sort * const * s) { ptr_buffer cs; - ptr_vector::iterator it = m_constructors.begin(); - ptr_vector::iterator end = m_constructors.end(); - for (; it != end; ++it) { - cs.push_back((*it)->instantiate_decl(m, s)); + for (auto c : m_constructors) { + cs.push_back(c->instantiate_decl(m, s)); } - return mk_datatype_decl(m_name, cs.size(), cs.c_ptr()); + datatype_util util(m.m()); + return mk_datatype_decl(util, m_name, m_num_params, s, cs.size(), cs.c_ptr()); } struct datatype_decl_buffer { @@ -591,67 +576,86 @@ struct datatype_decl_buffer { ~datatype_decl_buffer() { del_datatype_decls(m_buffer.size(), m_buffer.c_ptr()); } }; + sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { - SASSERT(m_num_params == n); - sort * r = find(s); - if (r) - return r; - if (m_parent != 0) { - if (m_parent->instantiate(m, s)) { - r = find(s); - SASSERT(r); - return r; + sort * r = m.instantiate_datatype(this, m_name, n, s); + datatype_util util(m.m()); + if (r && n > 0 && util.is_declared(r)) { + ast_mark mark; + datatype::def const& d = util.get_def(r); + mark.mark(r, true); + sort_ref_vector params(m.m(), n, s); + for (datatype::constructor* c : d) { + for (datatype::accessor* a : *c) { + sort* rng = a->range(); + if (util.is_datatype(rng) && !mark.is_marked(rng) && m_parent) { + mark.mark(rng, true); + // TBD: search over more than just parents + for (pdatatype_decl* p : *m_parent) { + if (p->get_name() == rng->get_name()) { + ptr_vector ps; + func_decl_ref acc = a->instantiate(params); + for (unsigned j = 0; j < util.get_datatype_num_parameter_sorts(rng); ++j) { + ps.push_back(util.get_datatype_parameter_sort(acc->get_range(), j)); + } + m.instantiate_datatype(p, p->get_name(), ps.size(), ps.c_ptr()); + break; + } + } + } + } } } - else { - datatype_decl_buffer dts; - dts.m_buffer.push_back(instantiate_decl(m, s)); - datatype_decl * d_ptr = dts.m_buffer[0]; - sort_ref_vector sorts(m.m()); - bool is_ok = m.get_dt_plugin()->mk_datatypes(1, &d_ptr, m_num_params, s, sorts); - TRACE("pdatatype_decl", tout << "instantiating " << m_name << " is_ok: " << is_ok << "\n";); - if (is_ok) { - r = sorts.get(0); - cache(m, s, r); - m.save_info(r, this, n, s); - m.notify_new_dt(r, this); - return r; - } - } - return 0; + return r; } + void pdatatype_decl::display(std::ostream & out) const { out << "(declare-datatype " << m_name; display_sort_args(out, m_num_params); - ptr_vector::const_iterator it = m_constructors.begin(); - ptr_vector::const_iterator end = m_constructors.end(); - for (bool first = true; it != end; ++it) { + bool first = true; + for (auto c : m_constructors) { if (!first) out << " "; if (m_parent) { - (*it)->display(out, m_parent->children()); + c->display(out, m_parent->children()); } else { pdatatype_decl const * dts[1] = { this }; - (*it)->display(out, dts); + c->display(out, dts); } first = false; } out << ")"; } -pdatatypes_decl::pdatatypes_decl(unsigned id, unsigned num_params, pdecl_manager & m, +bool pdatatype_decl::commit(pdecl_manager& m) { + TRACE("datatype", tout << m_name << "\n";); + sort_ref_vector ps(m.m()); + for (unsigned i = 0; i < m_num_params; ++i) { + ps.push_back(m.m().mk_uninterpreted_sort(symbol(i), 0, 0)); + } + datatype_decl_buffer dts; + dts.m_buffer.push_back(instantiate_decl(m, ps.c_ptr())); + datatype_decl * d_ptr = dts.m_buffer[0]; + sort_ref_vector sorts(m.m()); + bool is_ok = m.get_dt_plugin()->mk_datatypes(1, &d_ptr, m_num_params, ps.c_ptr(), sorts); + if (is_ok && m_num_params == 0) { + m.notify_new_dt(sorts.get(0), this); + } + return is_ok; +} + + +pdatatypes_decl::pdatatypes_decl(unsigned id, unsigned num_params, pdecl_manager & m, unsigned num_datatypes, pdatatype_decl * const * dts): pdecl(id, num_params), m_datatypes(num_datatypes, dts) { m.inc_ref(num_datatypes, dts); - ptr_vector::iterator it = m_datatypes.begin(); - ptr_vector::iterator end = m_datatypes.end(); - for (; it != end; ++it) { - SASSERT((*it)->m_parent == 0); - (*it)->m_parent = this; + for (auto d : m_datatypes) { + SASSERT(d->m_parent == 0); + d->m_parent = this; } } @@ -662,38 +666,67 @@ void pdatatypes_decl::finalize(pdecl_manager & m) { bool pdatatypes_decl::fix_missing_refs(symbol & missing) { TRACE("fix_missing_refs", tout << "pdatatypes_decl::fix_missing_refs\n";); dictionary symbol2idx; - ptr_vector::iterator it = m_datatypes.begin(); - ptr_vector::iterator end = m_datatypes.end(); - for (unsigned idx = 0; it != end; ++it, ++idx) - symbol2idx.insert((*it)->get_name(), idx); - - it = m_datatypes.begin(); - for (unsigned idx = 0; it != end; ++it, ++idx) { - if (!(*it)->fix_missing_refs(symbol2idx, missing)) + int idx = 0; + for (pdatatype_decl* d : m_datatypes) + symbol2idx.insert(d->get_name(), idx++); + for (pdatatype_decl* d : m_datatypes) + if (!d->fix_missing_refs(symbol2idx, missing)) return false; - } return true; } +sort* pdecl_manager::instantiate_datatype(psort_decl* p, symbol const& name, unsigned n, sort * const* s) { + TRACE("datatype", tout << name << " "; for (unsigned i = 0; i < n; ++i) tout << s[i]->get_name() << " "; tout << "\n";); + pdecl_manager& m = *this; + sort * r = p->find(s); + if (r) + return r; + buffer ps; + ps.push_back(parameter(name)); + for (unsigned i = 0; i < n; i++) + ps.push_back(parameter(s[i])); + datatype_util util(m.m()); + r = m.m().mk_sort(util.get_family_id(), DATATYPE_SORT, ps.size(), ps.c_ptr()); + p->cache(m, s, r); + m.save_info(r, p, n, s); + if (n > 0 && util.is_declared(r)) { + bool has_typevar = false; + // crude check .. + for (unsigned i = 0; !has_typevar && i < n; ++i) { + has_typevar = s[i]->get_name().is_numerical(); + } + if (!has_typevar) { + m.notify_new_dt(r, p); + } + } + return r; +} + bool pdatatypes_decl::instantiate(pdecl_manager & m, sort * const * s) { + UNREACHABLE(); + return false; +} + +bool pdatatypes_decl::commit(pdecl_manager& m) { datatype_decl_buffer dts; - ptr_vector::iterator it = m_datatypes.begin(); - ptr_vector::iterator end = m_datatypes.end(); - for (; it != end; ++it) { - dts.m_buffer.push_back((*it)->instantiate_decl(m, s)); + for (pdatatype_decl* d : m_datatypes) { + sort_ref_vector ps(m.m()); + for (unsigned i = 0; i < d->get_num_params(); ++i) { + ps.push_back(m.m().mk_uninterpreted_sort(symbol(i), 0, 0)); + } + dts.m_buffer.push_back(d->instantiate_decl(m, ps.c_ptr())); } sort_ref_vector sorts(m.m()); - bool is_ok = m.get_dt_plugin()->mk_datatypes(dts.m_buffer.size(), dts.m_buffer.c_ptr(), m_num_params, s, sorts); - if (!is_ok) - return false; - it = m_datatypes.begin(); - for (unsigned i = 0; it != end; ++it, ++i) { - sort * new_dt = sorts.get(i); - (*it)->cache(m, s, new_dt); - m.save_info(new_dt, *it, m_num_params, s); - m.notify_new_dt(new_dt, *it); + bool is_ok = m.get_dt_plugin()->mk_datatypes(m_datatypes.size(), dts.m_buffer.c_ptr(), 0, nullptr, sorts); + if (is_ok) { + for (unsigned i = 0; i < m_datatypes.size(); ++i) { + pdatatype_decl* d = m_datatypes[i]; + if (d->get_num_params() == 0) { + m.notify_new_dt(sorts.get(i), this); + } + } } - return true; + return is_ok; } struct pdecl_manager::sort_info { @@ -705,31 +738,29 @@ struct pdecl_manager::sort_info { } virtual ~sort_info() {} virtual unsigned obj_size() const { return sizeof(sort_info); } - virtual void finalize(pdecl_manager & m) { - m.dec_ref(m_decl); - } + virtual void finalize(pdecl_manager & m) { m.dec_ref(m_decl); } virtual void display(std::ostream & out, pdecl_manager const & m) const = 0; virtual format * pp(pdecl_manager const & m) const = 0; }; struct pdecl_manager::app_sort_info : public pdecl_manager::sort_info { ptr_vector m_args; - + app_sort_info(pdecl_manager & m, psort_decl * d, unsigned n, sort * const * s): sort_info(m, d), m_args(n, s) { m.m().inc_array_ref(n, s); } - + virtual ~app_sort_info() {} - + virtual unsigned obj_size() const { return sizeof(app_sort_info); } - + virtual void finalize(pdecl_manager & m) { sort_info::finalize(m); m.m().dec_array_ref(m_args.size(), m_args.c_ptr()); } - + virtual void display(std::ostream & out, pdecl_manager const & m) const { if (m_args.empty()) { out << m_decl->get_name(); @@ -743,7 +774,7 @@ struct pdecl_manager::app_sort_info : public pdecl_manager::sort_info { out << ")"; } } - + virtual format * pp(pdecl_manager const & m) const { if (m_args.empty()) { return mk_string(m.m(), m_decl->get_name().str().c_str()); @@ -755,7 +786,7 @@ struct pdecl_manager::app_sort_info : public pdecl_manager::sort_info { return mk_seq1(m.m(), b.begin(), b.end(), f2f(), m_decl->get_name().str().c_str()); } } -}; +}; struct pdecl_manager::indexed_sort_info : public pdecl_manager::sort_info { svector m_indices; @@ -781,7 +812,7 @@ struct pdecl_manager::indexed_sort_info : public pdecl_manager::sort_info { out << ")"; } } - + virtual format * pp(pdecl_manager const & m) const { if (m_indices.empty()) { return mk_string(m.m(), m_decl->get_name().str().c_str()); @@ -801,12 +832,13 @@ void pdecl_manager::init_list() { psort * v = mk_psort_var(1, 0); ptype T(v); ptype ListT(0); - paccessor_decl * as[2] = { mk_paccessor_decl(1, symbol("head"), T), + paccessor_decl * as[2] = { mk_paccessor_decl(1, symbol("head"), T), mk_paccessor_decl(1, symbol("tail"), ListT) }; pconstructor_decl * cs[2] = { mk_pconstructor_decl(1, symbol("nil"), symbol("is-nil"), 0, 0), mk_pconstructor_decl(1, symbol("insert"), symbol("is-insert"), 2, as) }; m_list = mk_pdatatype_decl(1, symbol("List"), 2, cs); inc_ref(m_list); + m_list->commit(*this); } pdecl_manager::pdecl_manager(ast_manager & m): @@ -838,9 +870,8 @@ psort * pdecl_manager::register_psort(psort * n) { psort * r = m_table.insert_if_not_there(n); if (r != n) { del_decl_core(n); - return r; } - return n; + return r; } psort * pdecl_manager::mk_psort_var(unsigned num_params, unsigned vidx) { @@ -851,14 +882,15 @@ psort * pdecl_manager::mk_psort_var(unsigned num_params, unsigned vidx) { paccessor_decl * pdecl_manager::mk_paccessor_decl(unsigned num_params, symbol const & s, ptype const & p) { return new (a().allocate(sizeof(paccessor_decl))) paccessor_decl(m_id_gen.mk(), num_params, *this, s, p); } - -pconstructor_decl * pdecl_manager::mk_pconstructor_decl(unsigned num_params, + +pconstructor_decl * pdecl_manager::mk_pconstructor_decl(unsigned num_params, symbol const & s, symbol const & r, unsigned num, paccessor_decl * const * as) { return new (a().allocate(sizeof(pconstructor_decl))) pconstructor_decl(m_id_gen.mk(), num_params, *this, s, r, num, as); } pdatatype_decl * pdecl_manager::mk_pdatatype_decl(unsigned num_params, symbol const & s, unsigned num, pconstructor_decl * const * cs) { + TRACE("datatype", tout << s << " has " << num_params << " parameters\n";); return new (a().allocate(sizeof(pdatatype_decl))) pdatatype_decl(m_id_gen.mk(), num_params, *this, s, num, cs); } @@ -885,10 +917,10 @@ psort_decl * pdecl_manager::mk_psort_user_decl(unsigned num_params, symbol const return new (a().allocate(sizeof(psort_user_decl))) psort_user_decl(m_id_gen.mk(), num_params, *this, n, def); } +psort_decl * pdecl_manager::mk_psort_dt_decl(unsigned num_params, symbol const & n) { + return new (a().allocate(sizeof(psort_dt_decl))) psort_dt_decl(m_id_gen.mk(), num_params, *this, n); +} -//psort_decl * pdecl_manager::mk_psort_dt_decl(unsigned num_params, symbol const & n) { -// return new (a().allocate(sizeof(psort_dt_decl))) psort_dt_decl(m_id_gen.mk(), num_params, *this, n); -//} psort_decl * pdecl_manager::mk_psort_builtin_decl(symbol const & n, family_id fid, decl_kind k) { return new (a().allocate(sizeof(psort_builtin_decl))) psort_builtin_decl(m_id_gen.mk(), *this, n, fid, k); @@ -901,9 +933,9 @@ sort * pdecl_manager::instantiate(psort * p, unsigned num, sort * const * args) void pdecl_manager::del_decl_core(pdecl * p) { - TRACE("pdecl_manager", + TRACE("pdecl_manager", tout << "del_decl_core:\n"; - if (p->is_psort()) static_cast(p)->display(tout); + if (p->is_psort()) static_cast(p)->display(tout); else static_cast(p)->display(tout); tout << "\n";); size_t sz = p->obj_size(); @@ -921,7 +953,7 @@ void pdecl_manager::del_decl(pdecl * p) { else m_table.erase(_p); } - del_decl_core(p); + del_decl_core(p); } void pdecl_manager::del_decls() { @@ -965,11 +997,9 @@ void pdecl_manager::save_info(sort * s, psort_decl * d, unsigned num_indices, un } void pdecl_manager::reset_sort_info() { - obj_map::iterator it = m_sort2info.begin(); - obj_map::iterator end = m_sort2info.end(); - for (; it != end; ++it) { - sort * s = (*it).m_key; - sort_info * info = (*it).m_value; + for (auto kv : m_sort2info) { + sort * s = kv.m_key; + sort_info * info = kv.m_value; m().dec_ref(s); unsigned sz = info->obj_size(); info->finalize(*this); diff --git a/src/cmd_context/pdecl.h b/src/cmd_context/pdecl.h index 31005fe0d..c72020827 100644 --- a/src/cmd_context/pdecl.h +++ b/src/cmd_context/pdecl.h @@ -19,10 +19,11 @@ Revision History: #ifndef PDECL_H_ #define PDECL_H_ -#include"ast.h" -#include"obj_hashtable.h" -#include"dictionary.h" -#include"format.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "util/dictionary.h" +#include "ast/format.h" +#include "ast/datatype_decl_plugin.h" class pdecl_manager; @@ -86,10 +87,13 @@ typedef ptr_hashtable psort_table; #define PSORT_DECL_VAR_PARAMS UINT_MAX +typedef enum { PSORT_BASE = 0, PSORT_USER, PSORT_BUILTIN, PSORT_DT } psort_decl_kind; + class psort_decl : public pdecl { protected: friend class pdecl_manager; symbol m_name; + psort_decl_kind m_psort_kind; psort_inst_cache * m_inst_cache; void cache(pdecl_manager & m, sort * const * s, sort * r); sort * find(sort * const * s); @@ -105,6 +109,9 @@ public: bool has_var_params() const { return m_num_params == PSORT_DECL_VAR_PARAMS; } symbol const & get_name() const { return m_name; } virtual void reset_cache(pdecl_manager& m); + bool is_user_decl() const { return m_psort_kind == PSORT_USER; } + bool is_builtin_decl() const { return m_psort_kind == PSORT_BUILTIN; } + bool is_dt_decl() const { return m_psort_kind == PSORT_DT; } }; class psort_user_decl : public psort_decl { @@ -119,7 +126,7 @@ public: virtual sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s); virtual void display(std::ostream & out) const; }; - + class psort_builtin_decl : public psort_decl { protected: friend class pdecl_manager; @@ -134,24 +141,17 @@ public: virtual void display(std::ostream & out) const; }; -#if 0 class psort_dt_decl : public psort_decl { protected: friend class pdecl_manager; psort_dt_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n); virtual size_t obj_size() const { return sizeof(psort_dt_decl); } - virtual void finalize(pdecl_manager & m); virtual ~psort_dt_decl() {} public: virtual sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s); virtual void display(std::ostream & out) const; }; -#endif -class datatype_decl_plugin; -class datatype_decl; -class constructor_decl; -class accessor_decl; class pdatatypes_decl; class pdatatype_decl; @@ -209,7 +209,7 @@ class pconstructor_decl : public pdecl { symbol m_name; symbol m_recogniser_name; ptr_vector m_accessors; - pconstructor_decl(unsigned id, unsigned num_params, pdecl_manager & m, + pconstructor_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, symbol const & r, unsigned num_accessors, paccessor_decl * const * accessors); virtual void finalize(pdecl_manager & m); virtual size_t obj_size() const { return sizeof(pconstructor_decl); } @@ -229,7 +229,7 @@ class pdatatype_decl : public psort_decl { friend class pdatatypes_decl; ptr_vector m_constructors; pdatatypes_decl * m_parent; - pdatatype_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, + pdatatype_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, unsigned num_constructors, pconstructor_decl * const * constructors); virtual void finalize(pdecl_manager & m); virtual size_t obj_size() const { return sizeof(pdatatype_decl); } @@ -241,6 +241,7 @@ public: virtual void display(std::ostream & out) const; bool has_missing_refs(symbol & missing) const; bool has_duplicate_accessors(symbol & repeated) const; + bool commit(pdecl_manager& m); }; /** @@ -258,6 +259,10 @@ class pdatatypes_decl : public pdecl { virtual ~pdatatypes_decl() {} public: pdatatype_decl const * const * children() const { return m_datatypes.c_ptr(); } + pdatatype_decl * const * begin() const { return m_datatypes.begin(); } + pdatatype_decl * const * end() const { return m_datatypes.end(); } + // commit declaration + bool commit(pdecl_manager& m); }; class new_datatype_eh { @@ -282,7 +287,7 @@ class pdecl_manager { struct indexed_sort_info; obj_map m_sort2info; // for pretty printing sorts - + void init_list(); void del_decl_core(pdecl * p); void del_decl(pdecl * p); @@ -296,11 +301,11 @@ public: small_object_allocator & a() const { return m_allocator; } family_id get_datatype_fid() const { return m_datatype_fid; } void set_new_datatype_eh(new_datatype_eh * eh) { m_new_dt_eh = eh; } - psort * mk_psort_cnst(sort * s); + psort * mk_psort_cnst(sort * s); psort * mk_psort_var(unsigned num_params, unsigned vidx); psort * mk_psort_app(unsigned num_params, psort_decl * d, unsigned num_args, psort * const * args); psort * mk_psort_app(psort_decl * d); - // psort_decl * mk_psort_dt_decl(unsigned num_params, symbol const & n); + psort_decl * mk_psort_dt_decl(unsigned num_params, symbol const & n); psort_decl * mk_psort_user_decl(unsigned num_params, symbol const & n, psort * def); psort_decl * mk_psort_builtin_decl(symbol const & n, family_id fid, decl_kind k); paccessor_decl * mk_paccessor_decl(unsigned num_params, symbol const & s, ptype const & p); @@ -309,6 +314,7 @@ public: pdatatypes_decl * mk_pdatatypes_decl(unsigned num_params, unsigned num, pdatatype_decl * const * dts); pdatatype_decl * mk_plist_decl() { if (!m_list) init_list(); return m_list; } bool fix_missing_refs(pdatatypes_decl * s, symbol & missing) { return s->fix_missing_refs(missing); } + sort * instantiate_datatype(psort_decl* p, symbol const& name, unsigned n, sort * const* s); sort * instantiate(psort * s, unsigned num, sort * const * args); void lazy_dec_ref(pdecl * p) { p->dec_ref(); if (p->get_ref_count() == 0) m_to_delete.push_back(p); } diff --git a/src/cmd_context/simplify_cmd.cpp b/src/cmd_context/simplify_cmd.cpp index 8b354c8b7..5112a6ea2 100644 --- a/src/cmd_context/simplify_cmd.cpp +++ b/src/cmd_context/simplify_cmd.cpp @@ -15,16 +15,16 @@ Author: Notes: --*/ -#include"cmd_context.h" -#include"th_rewriter.h" -#include"shared_occs.h" -#include"ast_smt_pp.h" -#include"for_each_expr.h" -#include"parametric_cmd.h" -#include"scoped_timer.h" -#include"scoped_ctrl_c.h" -#include"cancel_eh.h" -#include"seq_rewriter.h" +#include "cmd_context/cmd_context.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/shared_occs.h" +#include "ast/ast_smt_pp.h" +#include "ast/for_each_expr.h" +#include "cmd_context/parametric_cmd.h" +#include "util/scoped_timer.h" +#include "util/scoped_ctrl_c.h" +#include "util/cancel_eh.h" +#include "ast/rewriter/seq_rewriter.h" #include class simplify_cmd : public parametric_cmd { diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index 2b60486f7..cbc90c62c 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -16,21 +16,21 @@ Notes: --*/ #include -#include"tactic_cmds.h" -#include"cmd_context.h" -#include"cmd_util.h" -#include"parametric_cmd.h" -#include"scoped_timer.h" -#include"scoped_ctrl_c.h" -#include"cancel_eh.h" -#include"model_smt2_pp.h" -#include"ast_smt2_pp.h" -#include"tactic.h" -#include"tactical.h" -#include"probe.h" -#include"check_sat_result.h" -#include"cmd_context_to_goal.h" -#include"echo_tactic.h" +#include "cmd_context/tactic_cmds.h" +#include "cmd_context/cmd_context.h" +#include "cmd_context/cmd_util.h" +#include "cmd_context/parametric_cmd.h" +#include "util/scoped_timer.h" +#include "util/scoped_ctrl_c.h" +#include "util/cancel_eh.h" +#include "model/model_smt2_pp.h" +#include "ast/ast_smt2_pp.h" +#include "tactic/tactic.h" +#include "tactic/tactical.h" +#include "tactic/probe.h" +#include "solver/check_sat_result.h" +#include "cmd_context/cmd_context_to_goal.h" +#include "cmd_context/echo_tactic.h" tactic_cmd::~tactic_cmd() { dealloc(m_factory); @@ -197,6 +197,9 @@ public: } virtual void execute(cmd_context & ctx) { + if (!m_tactic) { + throw cmd_exception("check-sat-using needs a tactic argument"); + } params_ref p = ctx.params().merge_default_params(ps()); tactic_ref tref = using_params(sexpr2tactic(ctx, m_tactic), p); tref->set_logic(ctx.get_logic()); @@ -255,11 +258,9 @@ public: result->m_core.append(core_elems.size(), core_elems.c_ptr()); if (p.get_bool("print_unsat_core", false)) { ctx.regular_stream() << "(unsat-core"; - ptr_vector::const_iterator it = core_elems.begin(); - ptr_vector::const_iterator end = core_elems.end(); - for (; it != end; ++it) { + for (expr * e : core_elems) { ctx.regular_stream() << " "; - ctx.display(ctx.regular_stream(), *it); + ctx.display(ctx.regular_stream(), e); } ctx.regular_stream() << ")" << std::endl; } @@ -308,6 +309,9 @@ public: } virtual void execute(cmd_context & ctx) { + if (!m_tactic) { + throw cmd_exception("apply needs a tactic argument"); + } params_ref p = ctx.params().merge_default_params(ps()); tactic_ref tref = using_params(sexpr2tactic(ctx, m_tactic), p); { diff --git a/src/cmd_context/tactic_cmds.h b/src/cmd_context/tactic_cmds.h index e21d818bb..fc15c795b 100644 --- a/src/cmd_context/tactic_cmds.h +++ b/src/cmd_context/tactic_cmds.h @@ -18,9 +18,9 @@ Notes: #ifndef TACTIC_CMDS_H_ #define TACTIC_CMDS_H_ -#include"ast.h" -#include"cmd_context_types.h" -#include"ref.h" +#include "ast/ast.h" +#include "util/cmd_context_types.h" +#include "util/ref.h" class tactic; class probe; diff --git a/src/cmd_context/tactic_manager.cpp b/src/cmd_context/tactic_manager.cpp index 3442dd9b9..94b5e35ab 100644 --- a/src/cmd_context/tactic_manager.cpp +++ b/src/cmd_context/tactic_manager.cpp @@ -16,7 +16,7 @@ Author: Notes: --*/ -#include"tactic_manager.h" +#include "cmd_context/tactic_manager.h" tactic_manager::~tactic_manager() { finalize_tactic_cmds(); diff --git a/src/cmd_context/tactic_manager.h b/src/cmd_context/tactic_manager.h index 44a25f01e..276c756ba 100644 --- a/src/cmd_context/tactic_manager.h +++ b/src/cmd_context/tactic_manager.h @@ -18,8 +18,8 @@ Notes: #ifndef TACTIC_MANAGER_H_ #define TACTIC_MANAGER_H_ -#include"tactic_cmds.h" -#include"dictionary.h" +#include "cmd_context/tactic_cmds.h" +#include "util/dictionary.h" class tactic_manager { protected: diff --git a/src/duality/duality.h b/src/duality/duality.h index 72d72ac6b..657fa18b4 100644 --- a/src/duality/duality.h +++ b/src/duality/duality.h @@ -20,7 +20,8 @@ #pragma once -#include "duality_wrapper.h" +#include "duality/duality_wrapper.h" +#include #include #include @@ -41,9 +42,9 @@ namespace Duality { typedef expr Term; Z3User(context &_ctx) : ctx(_ctx){} - + const char *string_of_int(int n); - + Term conjoin(const std::vector &args); Term sum(const std::vector &args); @@ -130,58 +131,58 @@ namespace Duality { /** This class represents a relation post-fixed point (RPFP) problem as * a "problem graph". The graph consists of Nodes and hyper-edges. - * + * * A node consists of * - Annotation, a symbolic relation * - Bound, a symbolic relation giving an upper bound on Annotation - * + * * * A hyper-edge consists of: * - Children, a sequence of children Nodes, * - F, a symbolic relational transformer, * - Parent, a single parent Node. - * + * * The graph is "solved" when: * - For every Node n, n.Annotation subseteq n.Bound * - For every hyperedge e, e.F(e.Children.Annotation) subseteq e.Parent.Annotation - * + * * where, if x is a sequence of Nodes, x.Annotation is the sequences * of Annotations of the nodes in the sequence. - * + * * A symbolic Transformer consists of * - RelParams, a sequence of relational symbols * - IndParams, a sequence of individual symbols * - Formula, a formula over RelParams and IndParams - * + * * A Transformer t represents a function that takes sequence R of relations * and yields the relation lambda (t.Indparams). Formula(R/RelParams). - * + * * As a special case, a nullary Transformer (where RelParams is the empty sequence) * represents a fixed relation. - * + * * An RPFP consists of * - Nodes, a set of Nodes * - Edges, a set of hyper-edges * - Context, a prover context that contains formula AST's - * + * * Multiple RPFP's can use the same Context, but you should be careful - * that only one RPFP asserts constraints in the context at any time. - * + * that only one RPFP asserts constraints in the context at any time. + * * */ class RPFP : public Z3User { public: - + class Edge; class Node; bool HornClauses; - + /** Interface class for interpolating solver. */ class LogicSolver { public: - + context *ctx; /** Z3 context for formulas */ solver *slvr; /** Z3 solver */ bool need_goals; /** Can the solver use the goal tree to optimize interpolants? */ @@ -191,7 +192,7 @@ namespace Duality { "assumptions" are currently asserted in the solver. The return value indicates whether the assertions are satisfiable. In the UNSAT case, a tree interpolant is returned in "interpolants". - In the SAT case, a model is returned. + In the SAT case, a model is returned. */ virtual @@ -201,7 +202,7 @@ namespace Duality { TermTree *goals = 0, bool weak = false ) = 0; - + /** Declare a constant in the background theory. */ virtual void declare_constant(const func_decl &f) = 0; @@ -319,7 +320,7 @@ namespace Duality { virtual void declare_constant(const func_decl &f){ bckg.insert(f); } - + /** Is this a background constant? */ virtual bool is_constant(const func_decl &f){ return bckg.find(f) != bckg.end(); @@ -344,9 +345,9 @@ namespace Duality { static iZ3LogicSolver *CreateLogicSolver(config &_config){ return new iZ3LogicSolver(_config); } -#endif +#endif - /** Create a logic solver from a low-level Z3 context. + /** Create a logic solver from a low-level Z3 context. Only use this if you know what you're doing. */ static iZ3LogicSolver *CreateLogicSolver(context c){ return new iZ3LogicSolver(c); @@ -357,7 +358,7 @@ namespace Duality { protected: int nodeCount; int edgeCount; - + class stack_entry { public: @@ -365,8 +366,8 @@ namespace Duality { std::list nodes; std::list > constraints; }; - - + + public: model dualModel; protected: @@ -375,14 +376,14 @@ namespace Duality { std::vector axioms; // only saved here for printing purposes solver &aux_solver; hash_set *proof_core; - + public: /** Construct an RPFP graph with a given interpolating prover context. It is allowed to have multiple RPFP's use the same context, but you should never have teo RPFP's with the same conext asserting nodes or edges at the same time. Note, if you create axioms in one RPFP, them create a second RPFP with the same context, the second will - inherit the axioms. + inherit the axioms. */ RPFP(LogicSolver *_ls) : Z3User(*(_ls->ctx)), dualModel(*(_ls->ctx)), aux_solver(_ls->aux_solver) @@ -396,7 +397,7 @@ namespace Duality { } virtual ~RPFP(); - + /** Symbolic representation of a relational transformer */ class Transformer { @@ -406,12 +407,12 @@ namespace Duality { Term Formula; RPFP *owner; hash_map labels; - + Transformer *Clone() { return new Transformer(*this); } - + void SetEmpty(){ Formula = owner->ctx.bool_val(false); } @@ -451,7 +452,7 @@ namespace Duality { void Complement(){ Formula = !Formula; } - + void Simplify(){ Formula = Formula.simplify(); } @@ -459,7 +460,7 @@ namespace Duality { Transformer(const std::vector &_RelParams, const std::vector &_IndParams, const Term &_Formula, RPFP *_owner) : RelParams(_RelParams), IndParams(_IndParams), Formula(_Formula) {owner = _owner;} }; - + /** Create a symbolic transformer. */ Transformer CreateTransformer(const std::vector &_RelParams, const std::vector &_IndParams, const Term &_Formula) { @@ -469,13 +470,13 @@ namespace Duality { // t.labels = foo.Item2; return Transformer(_RelParams,_IndParams,_Formula,this); } - + /** Create a relation (nullary relational transformer) */ Transformer CreateRelation(const std::vector &_IndParams, const Term &_Formula) { return CreateTransformer(std::vector(), _IndParams, _Formula); } - + /** A node in the RPFP graph */ class Node { @@ -491,17 +492,17 @@ namespace Duality { Term dual; Node *map; unsigned recursion_bound; - + Node(const FuncDecl &_Name, const Transformer &_Annotation, const Transformer &_Bound, const Transformer &_Underapprox, const Term &_dual, RPFP *_owner, int _number) : Name(_Name), Annotation(_Annotation), Bound(_Bound), Underapprox(_Underapprox), dual(_dual) {owner = _owner; number = _number; Outgoing = 0; recursion_bound = UINT_MAX;} }; - + /** Create a node in the graph. The input is a term R(v_1...v_n) * where R is an arbitrary relational symbol and v_1...v_n are * arbitary distinct variables. The names are only of mnemonic value, * however, the number and type of arguments determine the type * of the relation at this node. */ - + Node *CreateNode(const Term &t) { std::vector _IndParams; @@ -517,9 +518,9 @@ namespace Duality { nodes.push_back(n); return n; } - + /** Clone a node (can be from another graph). */ - + Node *CloneNode(Node *old) { Node *n = new Node(old->Name, @@ -534,7 +535,7 @@ namespace Duality { n->map = old; return n; } - + /** Delete a node. You can only do this if not connected to any edges.*/ void DeleteNode(Node *node){ if(node->Outgoing || !node->Incoming.empty()) @@ -549,7 +550,7 @@ namespace Duality { } /** This class represents a hyper-edge in the RPFP graph */ - + class Edge { public: @@ -565,15 +566,15 @@ namespace Duality { Edge *map; Term labeled; std::vector constraints; - + Edge(Node *_Parent, const Transformer &_F, const std::vector &_Children, RPFP *_owner, int _number) : F(_F), Parent(_Parent), Children(_Children), dual(expr(_owner->ctx)) { owner = _owner; number = _number; } }; - - + + /** Create a hyper-edge. */ Edge *CreateEdge(Node *_Parent, const Transformer &_F, const std::vector &_Children) { @@ -584,8 +585,8 @@ namespace Duality { edges.push_back(e); return e; } - - + + /** Delete a hyper-edge and unlink it from any nodes. */ void DeleteEdge(Edge *edge){ if(edge->Parent) @@ -607,19 +608,19 @@ namespace Duality { } delete edge; } - + /** Create an edge that lower-bounds its parent. */ Edge *CreateLowerBoundEdge(Node *_Parent) { return CreateEdge(_Parent, _Parent->Annotation, std::vector()); } - + /** For incremental solving, asserts the constraint associated * with this edge in the SMT context. If this edge is removed, * you must pop the context accordingly. The second argument is * the number of pushes we are inside. */ - + virtual void AssertEdge(Edge *e, int persist = 0, bool with_children = false, bool underapprox = false); /* Constrain an edge by the annotation of one of its children. */ @@ -629,19 +630,19 @@ namespace Duality { /** For incremental solving, asserts the negation of the upper bound associated * with a node. * */ - + void AssertNode(Node *n); - /** Assert a constraint on an edge in the SMT context. + /** Assert a constraint on an edge in the SMT context. */ void ConstrainEdge(Edge *e, const Term &t); - + /** Fix the truth values of atomic propositions in the given edge to their values in the current assignment. */ void FixCurrentState(Edge *root); - + void FixCurrentStateFull(Edge *edge, const expr &extra); - + void FixCurrentStateFull(Edge *edge, const std::vector &assumps, const hash_map &renaming); /** Declare a constant in the background theory. */ @@ -660,78 +661,78 @@ namespace Duality { #if 0 /** Do not call this. */ - + void RemoveAxiom(const Term &t); #endif /** Solve an RPFP graph. This means either strengthen the annotation * so that the bound at the given root node is satisfied, or - * show that this cannot be done by giving a dual solution - * (i.e., a counterexample). - * + * show that this cannot be done by giving a dual solution + * (i.e., a counterexample). + * * In the current implementation, this only works for graphs that * are: * - tree-like - * + * * - closed. - * + * * In a tree-like graph, every nod has out most one incoming and one out-going edge, * and there are no cycles. In a closed graph, every node has exactly one out-going * edge. This means that the leaves of the tree are all hyper-edges with no * children. Such an edge represents a relation (nullary transformer) and thus * a lower bound on its parent. The parameter root must be the root of this tree. - * + * * If Solve returns LBool.False, this indicates success. The annotation of the tree - * has been updated to satisfy the upper bound at the root. - * + * has been updated to satisfy the upper bound at the root. + * * If Solve returns LBool.True, this indicates a counterexample. For each edge, * you can then call Eval to determine the values of symbols in the transformer formula. * You can also call Empty on a node to determine if its value in the counterexample * is the empty relation. - * + * * \param root The root of the tree - * \param persist Number of context pops through which result should persist - * - * + * \param persist Number of context pops through which result should persist + * + * */ lbool Solve(Node *root, int persist); - + /** Same as Solve, but annotates only a single node. */ lbool SolveSingleNode(Node *root, Node *node); /** Get the constraint tree (but don't solve it) */ - + TermTree *GetConstraintTree(Node *root, Node *skip_descendant = 0); - + /** Dispose of the dual model (counterexample) if there is one. */ - + void DisposeDualModel(); /** Check satisfiability of asserted edges and nodes. Same functionality as - * Solve, except no primal solution (interpolant) is generated in the unsat case. */ - - check_result Check(Node *root, std::vector underapproxes = std::vector(), + * Solve, except no primal solution (interpolant) is generated in the unsat case. */ + + check_result Check(Node *root, std::vector underapproxes = std::vector(), std::vector *underapprox_core = 0); /** Update the model, attempting to make the propositional literals in assumps true. If possible, return sat, else return unsat and keep the old model. */ - + check_result CheckUpdateModel(Node *root, std::vector assumps); /** Determines the value in the counterexample of a symbol occuring in the transformer formula of * a given edge. */ - + Term Eval(Edge *e, Term t); - + /** Return the fact derived at node p in a counterexample. */ Term EvalNode(Node *p); - + /** Returns true if the given node is empty in the primal solution. For proecudure summaries, this means that the procedure is not called in the current counter-model. */ - + bool Empty(Node *p); /** Compute an underapproximation of every node in a tree rooted at "root", @@ -747,11 +748,11 @@ namespace Duality { void InterpolateByCases(Node *root, Node *node); /** Push a scope. Assertions made after Push can be undone by Pop. */ - + void Push(); /** Exception thrown when bad clause is encountered */ - + struct bad_clause { std::string msg; int i; @@ -777,7 +778,7 @@ namespace Duality { // thrown on internal error struct Bad { }; - + // thrown on more serious internal error struct ReallyBad { }; @@ -786,56 +787,56 @@ namespace Duality { struct greedy_reduce_failed {}; /** Pop a scope (see Push). Note, you cannot pop axioms. */ - + void Pop(int num_scopes); - + /** Erase the proof by performing a Pop, Push and re-assertion of all the popped constraints */ void PopPush(); /** Return true if the given edge is used in the proof of unsat. Can be called only after Solve or Check returns an unsat result. */ - + bool EdgeUsedInProof(Edge *edge); /** Convert a collection of clauses to Nodes and Edges in the RPFP. - + Predicate unknowns are uninterpreted predicates not occurring in the background theory. - - Clauses are of the form - + + Clauses are of the form + B => P(t_1,...,t_k) - + where P is a predicate unknown and predicate unknowns occur only positivey in H and only under existential quantifiers in prenex form. - + Each predicate unknown maps to a node. Each clause maps to an edge. Let C be a clause B => P(t_1,...,t_k) where the sequence of predicate unknowns occurring in B (in order of occurrence) is P_1..P_n. The clause maps to a transformer T where: - + T.Relparams = P_1..P_n T.Indparams = x_1...x+k T.Formula = B /\ t_1 = x_1 /\ ... /\ t_k = x_k - + Throws exception bad_clause(msg,i) if a clause i is in the wrong form. - + */ - + struct label_struct { symbol name; expr value; bool pos; - label_struct(const symbol &s, const expr &e, bool b) - : name(s), value(e), pos(b) {} + label_struct(const symbol &s, const expr &e, bool b) + : name(s), value(e), pos(b) {} }; - + #ifdef _WINDOWS __declspec(dllexport) #endif @@ -847,7 +848,7 @@ namespace Duality { void WriteCounterexample(std::ostream &s, Node *node); - enum FileFormat {DualityFormat, SMT2Format, HornFormat}; + enum FileFormat {DualityFormat, SMT2Format, HornFormat}; /** Write the RPFP to a file (currently in SMTLIB 1.2 format) */ void WriteProblemToFile(std::string filename, FileFormat format = DualityFormat); @@ -870,9 +871,9 @@ namespace Duality { /** Fuse a vector of transformers. If the total number of inputs of the transformers is N, then the result is an N-ary transfomer whose output is the union of the outputs of the given transformers. The is, suppose we have a vetor of transfoermers - {T_i(r_i1,...,r_iN(i) : i=1..M}. The the result is a transformer - - F(r_11,...,r_iN(1),...,r_M1,...,r_MN(M)) = + {T_i(r_i1,...,r_iN(i) : i=1..M}. The the result is a transformer + + F(r_11,...,r_iN(1),...,r_M1,...,r_MN(M)) = T_1(r_11,...,r_iN(1)) U ... U T_M(r_M1,...,r_MN(M)) */ @@ -921,7 +922,7 @@ namespace Duality { } protected: - + void ClearProofCore(){ if(proof_core) delete proof_core; @@ -929,7 +930,7 @@ namespace Duality { } Term SuffixVariable(const Term &t, int n); - + Term HideVariable(const Term &t, int n); void RedVars(Node *node, Term &b, std::vector &v); @@ -958,16 +959,16 @@ namespace Duality { #if 0 void WriteInterps(System.IO.StreamWriter f, TermTree t); -#endif +#endif void WriteEdgeVars(Edge *e, hash_map &memo, const Term &t, std::ostream &s); void WriteEdgeAssignment(std::ostream &s, Edge *e); - + // Scan the clause body for occurrences of the predicate unknowns - - Term ScanBody(hash_map &memo, + + Term ScanBody(hash_map &memo, const Term &t, hash_map &pmap, std::vector &res, @@ -1035,7 +1036,7 @@ namespace Duality { void ConstrainEdgeLocalized(Edge *e, const Term &t); void GreedyReduce(solver &s, std::vector &conjuncts); - + void NegateLits(std::vector &lits); expr SimplifyOr(std::vector &lits); @@ -1053,7 +1054,7 @@ namespace Duality { void GetGroundLitsUnderQuants(hash_set *memo, const Term &f, std::vector &res, int under); Term StrengthenFormulaByCaseSplitting(const Term &f, std::vector &case_lits); - + expr NegateLit(const expr &f); expr GetEdgeFormula(Edge *e, int persist, bool with_children, bool underapprox); @@ -1065,7 +1066,7 @@ namespace Duality { expr UnhoistPullRec(hash_map & memo, const expr &w, hash_map & init_defs, hash_map & const_params, hash_map &const_params_inv, std::vector &new_params); void AddParamsToTransformer(Transformer &trans, const std::vector ¶ms); - + expr AddParamsToApp(const expr &app, const func_decl &new_decl, const std::vector ¶ms); expr GetRelRec(hash_set &memo, const expr &t, const func_decl &rel); @@ -1081,7 +1082,7 @@ namespace Duality { void UnhoistLoop(Edge *loop_edge, Edge *init_edge); void Unhoist(); - + Term ElimIteRec(hash_map &memo, const Term &t, std::vector &cnsts); Term ElimIte(const Term &t); @@ -1089,11 +1090,11 @@ namespace Duality { void MarkLiveNodes(hash_map > &outgoing, hash_set &live_nodes, Node *node); virtual void slvr_add(const expr &e); - + virtual void slvr_pop(int i); virtual void slvr_push(); - + virtual check_result slvr_check(unsigned n = 0, expr * const assumptions = 0, unsigned *core_size = 0, expr *core = 0); virtual lbool ls_interpolate_tree(TermTree *assumptions, @@ -1105,14 +1106,14 @@ namespace Duality { virtual bool proof_core_contains(const expr &e); }; - + /** RPFP solver base class. */ class Solver { - + public: - + class Counterexample { private: RPFP *tree; @@ -1148,18 +1149,18 @@ namespace Duality { Counterexample &operator=(const Counterexample &); Counterexample(const Counterexample &); }; - + /** Solve the problem. You can optionally give an old counterexample to use as a guide. This is chiefly useful for abstraction refinement metholdologies, and is only used as a heuristic. */ - + virtual bool Solve() = 0; - + virtual Counterexample &GetCounterexample() = 0; - + virtual bool SetOption(const std::string &option, const std::string &value) = 0; - + /** Learn heuristic information from another solver. This is chiefly useful for abstraction refinement, when we want to solve a series of similar problems. */ @@ -1184,7 +1185,7 @@ namespace Duality { /** Object thrown on cancellation */ struct Canceled {}; - + /** Object thrown on incompleteness */ struct Incompleteness {}; }; @@ -1235,16 +1236,16 @@ namespace Duality { public: /** appends assumption literals for edge to lits. if with_children is true, - includes that annotation of the edge's children. - */ + includes that annotation of the edge's children. + */ void AssertEdgeCache(Edge *e, std::vector &lits, bool with_children = false); - + /** appends assumption literals for node to lits */ void AssertNodeCache(Node *, std::vector lits); /** check assumption lits, and return core */ check_result CheckCore(const std::vector &assumps, std::vector &core); - + /** Clone another RPFP into this one, keeping a map */ void Clone(RPFP *other); @@ -1287,7 +1288,7 @@ namespace Duality { uptr slvr; }; hash_map edge_solvers; - + #ifdef LIMIT_STACK_WEIGHT struct weight_counter { int val; @@ -1296,7 +1297,7 @@ namespace Duality { std::swap(val,other.val); } }; - + struct big_stack_entry { weight_counter weight_added; std::vector new_alits; @@ -1319,11 +1320,11 @@ namespace Duality { void ConstrainEdgeLocalizedCache(Edge *e, const Term &tl, std::vector &lits); virtual void slvr_add(const expr &e); - + virtual void slvr_pop(int i); virtual void slvr_push(); - + virtual check_result slvr_check(unsigned n = 0, expr * const assumptions = 0, unsigned *core_size = 0, expr *core = 0); virtual lbool ls_interpolate_tree(TermTree *assumptions, @@ -1348,7 +1349,7 @@ namespace Duality { scoped_solver_for_edge(RPFP_caching *_rpfp, Edge *edge, bool models = false, bool axioms = false){ rpfp = _rpfp; orig_slvr = rpfp->ls->slvr; - es = &(rpfp->SolverForEdge(edge,models,axioms)); + es = &(rpfp->SolverForEdge(edge,models,axioms)); rpfp->ls->slvr = es->slvr.get(); rpfp->AssumptionLits.swap(es->AssumptionLits); } diff --git a/src/duality/duality_profiling.cpp b/src/duality/duality_profiling.cpp index e841f674b..2e659f0a1 100755 --- a/src/duality/duality_profiling.cpp +++ b/src/duality/duality_profiling.cpp @@ -31,8 +31,8 @@ #pragma warning(disable:4267) #endif -#include "duality_wrapper.h" -#include "iz3profiling.h" +#include "duality/duality_wrapper.h" +#include "interp/iz3profiling.h" namespace Duality { diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp index c86ff9f62..c9ad8fd56 100755 --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -33,8 +33,8 @@ #include -#include "duality.h" -#include "duality_profiling.h" +#include "duality/duality.h" +#include "duality/duality_profiling.h" // TODO: do we need these? #ifdef Z3OPS diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp index 1869b74ce..1711b65ad 100644 --- a/src/duality/duality_solver.cpp +++ b/src/duality/duality_solver.cpp @@ -25,8 +25,8 @@ #pragma warning(disable:4267) #endif -#include "duality.h" -#include "duality_profiling.h" +#include "duality/duality.h" +#include "duality/duality_profiling.h" #include #include diff --git a/src/duality/duality_wrapper.cpp b/src/duality/duality_wrapper.cpp index 35033f739..4493beddf 100755 --- a/src/duality/duality_wrapper.cpp +++ b/src/duality/duality_wrapper.cpp @@ -25,15 +25,15 @@ #pragma warning(disable:4101) #endif -#include "duality_wrapper.h" +#include "duality/duality_wrapper.h" #include -#include "smt_solver.h" -#include "iz3interp.h" -#include "statistics.h" -#include "expr_abstract.h" -#include "stopwatch.h" -#include "model_smt2_pp.h" -#include "qe_lite.h" +#include "smt/smt_solver.h" +#include "interp/iz3interp.h" +#include "util/statistics.h" +#include "ast/expr_abstract.h" +#include "util/stopwatch.h" +#include "model/model_smt2_pp.h" +#include "qe/qe_lite.h" namespace Duality { diff --git a/src/duality/duality_wrapper.h b/src/duality/duality_wrapper.h index e5e55efed..96c49b36b 100644 --- a/src/duality/duality_wrapper.h +++ b/src/duality/duality_wrapper.h @@ -27,31 +27,31 @@ #include #include #include -#include"version.h" +#include "util/version.h" #include -#include "iz3hash.h" -#include "model.h" -#include "solver.h" +#include "interp/iz3hash.h" +#include "model/model.h" +#include "solver/solver.h" -#include"well_sorted.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"datatype_decl_plugin.h" -#include"array_decl_plugin.h" -#include"ast_translation.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"ast_smt_pp.h" -#include"ast_smt2_pp.h" -#include"th_rewriter.h" -#include"var_subst.h" -#include"expr_substitution.h" -#include"pp.h" -#include"scoped_ctrl_c.h" -#include"cancel_eh.h" -#include"scoped_timer.h" -#include"scoped_proof.h" +#include "ast/well_sorted.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/ast_translation.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt_pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/var_subst.h" +#include "ast/expr_substitution.h" +#include "ast/pp.h" +#include "util/scoped_ctrl_c.h" +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" +#include "ast/scoped_proof.h" namespace Duality { @@ -176,7 +176,7 @@ namespace Duality { m_datalog_fid = m().mk_family_id("datalog_relation"); } ~context() { } - + ast_manager &m() const {return *(ast_manager *)&mgr;} void set(char const * param, char const * value) { m_config.set(param,value); } @@ -186,13 +186,13 @@ namespace Duality { symbol str_symbol(char const * s); symbol int_symbol(int n); - + sort bool_sort(); sort int_sort(); sort real_sort(); sort bv_sort(unsigned sz); sort array_sort(sort d, sort r); - + func_decl function(symbol const & name, unsigned arity, sort const * domain, sort const & range); func_decl function(char const * name, unsigned arity, sort const * domain, sort const & range); func_decl function(char const * name, sort const & domain, sort const & range); @@ -210,22 +210,22 @@ namespace Duality { expr int_const(char const * name); expr real_const(char const * name); expr bv_const(char const * name, unsigned sz); - + expr bool_val(bool b); - + expr int_val(int n); expr int_val(unsigned n); expr int_val(char const * n); - + expr real_val(int n, int d); expr real_val(int n); expr real_val(unsigned n); expr real_val(char const * n); - + expr bv_val(int n, unsigned sz); expr bv_val(unsigned n, unsigned sz); expr bv_val(char const * n, unsigned sz); - + expr num_val(int n, sort const & s); expr mki(family_id fid, ::decl_kind dk, int n, ::expr **args); @@ -281,17 +281,17 @@ namespace Duality { object(object const & s):m_ctx(s.m_ctx) {} context & ctx() const { return *m_ctx; } friend void check_context(object const & a, object const & b) { assert(a.m_ctx == b.m_ctx); } - ast_manager &m() const {return m_ctx->m();} + ast_manager &m() const {return m_ctx->m();} }; class symbol : public object { ::symbol m_sym; public: - symbol(context & c, ::symbol s):object(c), m_sym(s) {} - symbol(symbol const & s):object(s), m_sym(s.m_sym) {} + symbol(context & c, ::symbol s):object(c), m_sym(s) {} + symbol(symbol const & s):object(s), m_sym(s.m_sym) {} symbol & operator=(symbol const & s) { m_ctx = s.m_ctx; m_sym = s.m_sym; return *this; } - operator ::symbol() const {return m_sym;} - std::string str() const { + operator ::symbol() const {return m_sym;} + std::string str() const { if (m_sym.is_numerical()) { std::ostringstream buffer; buffer << m_sym.get_num(); @@ -300,13 +300,13 @@ namespace Duality { else { return m_sym.bare_str(); } - } - friend std::ostream & operator<<(std::ostream & out, symbol const & s){ + } + friend std::ostream & operator<<(std::ostream & out, symbol const & s) { return out << s.str(); - } - friend bool operator==(const symbol &x, const symbol &y){ + } + friend bool operator==(const symbol &x, const symbol &y) { return x.m_sym == y.m_sym; - } + } }; class params : public config {}; @@ -318,7 +318,7 @@ namespace Duality { public: ::ast * const &raw() const {return _ast;} ast_i(context & c, ::ast *a = 0) : object(c) {_ast = a;} - + ast_i(){_ast = 0;} bool eq(const ast_i &other) const { return _ast == other._ast; @@ -345,19 +345,19 @@ namespace Duality { operator ::ast*() const { return raw(); } friend bool eq(ast const & a, ast const & b) { return a.raw() == b.raw(); } - + ast(context &c, ::ast *a = 0) : ast_i(c,a) { if(_ast) m().inc_ref(a); } - + ast() {} - + ast(const ast &other) : ast_i(other) { if(_ast) m().inc_ref(_ast); } - + ast &operator=(const ast &other) { if(_ast) m().dec_ref(_ast); @@ -367,7 +367,7 @@ namespace Duality { m().inc_ref(_ast); return *this; } - + ~ast(){ if(_ast) m().dec_ref(_ast); @@ -386,15 +386,15 @@ namespace Duality { sort & operator=(sort const & s) { return static_cast(ast::operator=(s)); } bool is_bool() const { return m().is_bool(*this); } - bool is_int() const { return ctx().get_sort_kind(*this) == IntSort; } - bool is_real() const { return ctx().get_sort_kind(*this) == RealSort; } + bool is_int() const { return ctx().get_sort_kind(*this) == IntSort; } + bool is_real() const { return ctx().get_sort_kind(*this) == RealSort; } bool is_arith() const; - bool is_array() const { return ctx().get_sort_kind(*this) == ArraySort; } - bool is_datatype() const; - bool is_relation() const; - bool is_finite_domain() const; + bool is_array() const { return ctx().get_sort_kind(*this) == ArraySort; } + bool is_datatype() const; + bool is_relation() const; + bool is_finite_domain() const; + - sort array_domain() const; sort array_range() const; @@ -404,7 +404,7 @@ namespace Duality { } }; - + class func_decl : public ast { public: func_decl() : ast() {} @@ -413,7 +413,7 @@ namespace Duality { func_decl(func_decl const & s):ast(s) {} operator ::func_decl*() const { return to_func_decl(*this); } func_decl & operator=(func_decl const & s) { return static_cast(ast::operator=(s)); } - + unsigned arity() const; sort domain(unsigned i) const; sort range() const; @@ -434,9 +434,9 @@ namespace Duality { expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4) const; expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4, expr const & a5) const; - func_decl get_func_decl_parameter(unsigned idx){ + func_decl get_func_decl_parameter(unsigned idx){ return func_decl(ctx(),to_func_decl(to_func_decl(raw())->get_parameters()[idx].get_ast())); - } + } }; @@ -447,8 +447,8 @@ namespace Duality { expr(context & c, ::ast *n):ast(c, n) {} expr(expr const & n):ast(n) {} expr & operator=(expr const & n) { return static_cast(ast::operator=(n)); } - operator ::expr*() const { return to_expr(raw()); } - unsigned get_id() const {return to_expr(raw())->get_id();} + operator ::expr*() const { return to_expr(raw()); } + unsigned get_id() const {return to_expr(raw())->get_id();} sort get_sort() const { return sort(ctx(),m().get_sort(to_expr(raw()))); } @@ -460,27 +460,27 @@ namespace Duality { bool is_datatype() const { return get_sort().is_datatype(); } bool is_relation() const { return get_sort().is_relation(); } bool is_finite_domain() const { return get_sort().is_finite_domain(); } - bool is_true() const {return is_app() && decl().get_decl_kind() == True; } + bool is_true() const {return is_app() && decl().get_decl_kind() == True; } bool is_numeral() const { return is_app() && decl().get_decl_kind() == OtherArith && m().is_unique_value(to_expr(raw())); - } - bool is_app() const {return raw()->get_kind() == AST_APP;} + } + bool is_app() const {return raw()->get_kind() == AST_APP;} bool is_quantifier() const {return raw()->get_kind() == AST_QUANTIFIER;} bool is_var() const {return raw()->get_kind() == AST_VAR;} - bool is_label (bool &pos,std::vector &names) const ; - bool is_ground() const {return to_app(raw())->is_ground();} - bool has_quantifiers() const {return to_app(raw())->has_quantifiers();} - bool has_free(int idx) const { + bool is_label (bool &pos,std::vector &names) const ; + bool is_ground() const {return to_app(raw())->is_ground();} + bool has_quantifiers() const {return to_app(raw())->has_quantifiers();} + bool has_free(int idx) const { used_vars proc; proc.process(to_expr(raw())); return proc.contains(idx); - } - unsigned get_max_var_idx_plus_1() const { + } + unsigned get_max_var_idx_plus_1() const { used_vars proc; proc.process(to_expr(raw())); return proc.get_max_found_var_idx_plus_1(); - } + } // operator Z3_app() const { assert(is_app()); return reinterpret_cast(m_ast); } func_decl decl() const {return func_decl(ctx(),to_app(raw())->get_decl());} @@ -493,11 +493,11 @@ namespace Duality { return 1; case AST_VAR: return 0; - default:; + default:; } SASSERT(0); return 0; - } + } expr arg(unsigned i) const { ast_kind dk = raw()->get_kind(); switch(dk){ @@ -509,25 +509,25 @@ namespace Duality { } assert(0); return expr(); - } + } expr body() const { return ctx().cook(to_quantifier(raw())->get_expr()); - } + } friend expr operator!(expr const & a) { // ::expr *e = a; return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_NOT,a)); - } + } friend expr operator&&(expr const & a, expr const & b) { return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_AND,a,b)); - } + } friend expr operator||(expr const & a, expr const & b) { return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_OR,a,b)); } - + friend expr implies(expr const & a, expr const & b) { return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_IMPLIES,a,b)); } @@ -546,12 +546,12 @@ namespace Duality { friend expr operator*(expr const & a, expr const & b) { return a.ctx().make(Times,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_MUL,a,b)); - } + } friend expr operator/(expr const & a, expr const & b) { return a.ctx().make(Div,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_DIV,a,b)); } - + friend expr operator-(expr const & a) { return a.ctx().make(Uminus,a); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_UMINUS,a)); } @@ -562,71 +562,71 @@ namespace Duality { friend expr operator<=(expr const & a, expr const & b) { return a.ctx().make(Leq,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_LE,a,b)); - } + } friend expr operator>=(expr const & a, expr const & b) { return a.ctx().make(Geq,a,b); //expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_GE,a,b)); } - + friend expr operator<(expr const & a, expr const & b) { return a.ctx().make(Lt,a,b); expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_LT,a,b)); } - + friend expr operator>(expr const & a, expr const & b) { return a.ctx().make(Gt,a,b); expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_GT,a,b)); - } + } expr simplify() const; expr simplify(params const & p) const; - + expr qe_lite() const; - expr qe_lite(const std::set &idxs, bool index_of_bound) const; + expr qe_lite(const std::set &idxs, bool index_of_bound) const; - friend expr clone_quantifier(const expr &, const expr &); + friend expr clone_quantifier(const expr &, const expr &); friend expr clone_quantifier(const expr &q, const expr &b, const std::vector &patterns); - friend expr clone_quantifier(decl_kind, const expr &, const expr &); + friend expr clone_quantifier(decl_kind, const expr &, const expr &); friend std::ostream & operator<<(std::ostream & out, expr const & m){ m.ctx().print_expr(out,m); return out; - } + } - void get_patterns(std::vector &pats) const ; + void get_patterns(std::vector &pats) const ; - unsigned get_quantifier_num_bound() const { + unsigned get_quantifier_num_bound() const { return to_quantifier(raw())->get_num_decls(); - } + } - unsigned get_index_value() const { + unsigned get_index_value() const { var* va = to_var(raw()); return va->get_idx(); - } + } bool is_quantifier_forall() const { return to_quantifier(raw())->is_forall(); - } + } - sort get_quantifier_bound_sort(unsigned n) const { + sort get_quantifier_bound_sort(unsigned n) const { return sort(ctx(),to_quantifier(raw())->get_decl_sort(n)); - } + } - symbol get_quantifier_bound_name(unsigned n) const { + symbol get_quantifier_bound_name(unsigned n) const { return symbol(ctx(),to_quantifier(raw())->get_decl_names()[n]); - } + } - friend expr forall(const std::vector &quants, const expr &body); + friend expr forall(const std::vector &quants, const expr &body); - friend expr exists(const std::vector &quants, const expr &body); + friend expr exists(const std::vector &quants, const expr &body); }; - + typedef ::decl_kind pfrule; - + class proof : public ast { public: proof(context & c):ast(c) {} @@ -643,15 +643,15 @@ namespace Duality { unsigned num_prems() const { return to_app(raw())->get_num_args() - 1; } - + expr conc() const { return ctx().cook(to_app(raw())->get_arg(num_prems())); } - + proof prem(unsigned i) const { return proof(ctx(),to_app(to_app(raw())->get_arg(i))); } - + void get_assumptions(std::vector &assumps); }; @@ -675,12 +675,12 @@ namespace Duality { T back() const { return operator[](size() - 1); } void pop_back() { assert(size() > 0); resize(size() - 1); } bool empty() const { return size() == 0; } - ast_vector_tpl & operator=(ast_vector_tpl const & s) { - Z3_ast_vector_inc_ref(s.ctx(), s.m_vector); + ast_vector_tpl & operator=(ast_vector_tpl const & s) { + Z3_ast_vector_inc_ref(s.ctx(), s.m_vector); // Z3_ast_vector_dec_ref(ctx(), m_vector); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_vector = s.m_vector; - return *this; + return *this; } friend std::ostream & operator<<(std::ostream & out, ast_vector_tpl const & v) { out << Z3_ast_vector_to_string(v.ctx(), v); return out; } }; @@ -705,9 +705,9 @@ namespace Duality { ~func_interp() { } operator ::func_interp *() const { return m_interp; } func_interp & operator=(func_interp const & s) { - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_interp = s.m_interp; - return *this; + return *this; } unsigned num_entries() const { return m_interp->num_entries(); } expr get_arg(unsigned ent, unsigned arg) const { @@ -729,32 +729,32 @@ namespace Duality { m_model = m; } public: - model(context & c, ::model * m = 0):object(c), m_model(m) { } - model(model const & s):object(s), m_model(s.m_model) { } - ~model() { } + model(context & c, ::model * m = 0):object(c), m_model(m) { } + model(model const & s):object(s), m_model(s.m_model) { } + ~model() { } operator ::model *() const { return m_model.get(); } model & operator=(model const & s) { // ::model *_inc_ref(s.ctx(), s.m_model); // ::model *_dec_ref(ctx(), m_model); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_model = s.m_model.get(); - return *this; + return *this; } model & operator=(::model *s) { - m_model = s; - return *this; + m_model = s; + return *this; } - bool null() const {return !m_model;} - + bool null() const {return !m_model;} + expr eval(expr const & n, bool model_completion=true) const { ::model * _m = m_model.get(); expr_ref result(ctx().m()); _m->eval(n, result, model_completion); return expr(ctx(), result); } - + void show() const; - void show_hash() const; + void show_hash() const; unsigned num_consts() const {return m_model.get()->get_num_constants();} unsigned num_funcs() const {return m_model.get()->get_num_functions();} @@ -765,11 +765,11 @@ namespace Duality { expr get_const_interp(func_decl f) const { return ctx().cook(m_model->get_const_interp(to_func_decl(f.raw()))); - } + } func_interp get_func_interp(func_decl f) const { return func_interp(ctx(),m_model->get_func_interp(to_func_decl(f.raw()))); - } + } #if 0 friend std::ostream & operator<<(std::ostream & out, model const & m) { out << Z3_model_to_string(m.ctx(), m); return out; } @@ -792,9 +792,9 @@ namespace Duality { stats & operator=(stats const & s) { Z3_stats_inc_ref(s.ctx(), s.m_stats); if (m_stats) Z3_stats_dec_ref(ctx(), m_stats); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_stats = s.m_stats; - return *this; + return *this; } unsigned size() const { return Z3_stats_size(ctx(), m_stats); } std::string key(unsigned i) const { Z3_string s = Z3_stats_get_key(ctx(), m_stats, i); check_error(); return s; } @@ -820,7 +820,7 @@ namespace Duality { void assert_cnst(const expr &cnst); }; - inline std::ostream & operator<<(std::ostream & out, check_result r) { + inline std::ostream & operator<<(std::ostream & out, check_result r) { if (r == unsat) out << "unsat"; else if (r == sat) out << "sat"; else out << "unknown"; @@ -837,54 +837,54 @@ namespace Duality { protected: ::solver *m_solver; model the_model; - bool canceled; - proof_gen_mode m_mode; - bool extensional; + bool canceled; + proof_gen_mode m_mode; + bool extensional; public: solver(context & c, bool extensional = false, bool models = true); - solver(context & c, ::solver *s):object(c),the_model(c) { m_solver = s; canceled = false;} - solver(solver const & s):object(s), the_model(s.the_model) { m_solver = s.m_solver; canceled = false;} + solver(context & c, ::solver *s):object(c),the_model(c) { m_solver = s; canceled = false;} + solver(solver const & s):object(s), the_model(s.the_model) { m_solver = s.m_solver; canceled = false;} ~solver() { if(m_solver) dealloc(m_solver); - } - operator ::solver*() const { return m_solver; } - solver & operator=(solver const & s) { - m_ctx = s.m_ctx; - m_solver = s.m_solver; - the_model = s.the_model; - m_mode = s.m_mode; - return *this; } - struct cancel_exception {}; - void checkpoint(){ + operator ::solver*() const { return m_solver; } + solver & operator=(solver const & s) { + m_ctx = s.m_ctx; + m_solver = s.m_solver; + the_model = s.the_model; + m_mode = s.m_mode; + return *this; + } + struct cancel_exception {}; + void checkpoint(){ if(canceled) throw(cancel_exception()); - } + } // void set(params const & p) { Z3_solver_set_params(ctx(), m_solver, p); check_error(); } void push() { scoped_proof_mode spm(m(),m_mode); m_solver->push(); } void pop(unsigned n = 1) { scoped_proof_mode spm(m(),m_mode); m_solver->pop(n); } // void reset() { Z3_solver_reset(ctx(), m_solver); check_error(); } void add(expr const & e) { scoped_proof_mode spm(m(),m_mode); m_solver->assert_expr(e); } - check_result check() { - scoped_proof_mode spm(m(),m_mode); + check_result check() { + scoped_proof_mode spm(m(),m_mode); checkpoint(); lbool r = m_solver->check_sat(0,0); model_ref m; m_solver->get_model(m); the_model = m.get(); return to_check_result(r); - } - check_result check_keep_model(unsigned n, expr * const assumptions, unsigned *core_size = 0, expr *core = 0) { - scoped_proof_mode spm(m(),m_mode); + } + check_result check_keep_model(unsigned n, expr * const assumptions, unsigned *core_size = 0, expr *core = 0) { + scoped_proof_mode spm(m(),m_mode); model old_model(the_model); check_result res = check(n,assumptions,core_size,core); if(the_model == 0) the_model = old_model; return res; - } + } check_result check(unsigned n, expr * const assumptions, unsigned *core_size = 0, expr *core = 0) { - scoped_proof_mode spm(m(),m_mode); + scoped_proof_mode spm(m(),m_mode); checkpoint(); std::vector< ::expr *> _assumptions(n); for (unsigned i = 0; i < n; i++) { @@ -892,7 +892,7 @@ namespace Duality { } the_model = 0; lbool r = m_solver->check_sat(n, VEC2PTR(_assumptions)); - + if(core_size && core){ ptr_vector< ::expr> _core; m_solver->get_unsat_core(_core); @@ -905,20 +905,20 @@ namespace Duality { m_solver->get_model(m); the_model = m.get(); - return to_check_result(r); + return to_check_result(r); } #if 0 - check_result check(expr_vector assumptions) { - scoped_proof_mode spm(m(),m_mode); + check_result check(expr_vector assumptions) { + scoped_proof_mode spm(m(),m_mode); unsigned n = assumptions.size(); z3array _assumptions(n); for (unsigned i = 0; i < n; i++) { check_context(*this, assumptions[i]); _assumptions[i] = assumptions[i]; } - Z3_lbool r = Z3_check_assumptions(ctx(), m_solver, n, _assumptions.ptr()); - check_error(); - return to_check_result(r); + Z3_lbool r = Z3_check_assumptions(ctx(), m_solver, n, _assumptions.ptr()); + check_error(); + return to_check_result(r); } #endif model get_model() const { return model(ctx(), the_model); } @@ -930,27 +930,26 @@ namespace Duality { #endif // expr proof() const { Z3_ast r = Z3_solver_proof(ctx(), m_solver); check_error(); return expr(ctx(), r); } // friend std::ostream & operator<<(std::ostream & out, solver const & s) { out << Z3_solver_to_string(s.ctx(), s); return out; } - - int get_num_decisions(); + int get_num_decisions(); - void cancel(){ - scoped_proof_mode spm(m(),m_mode); + void cancel(){ + scoped_proof_mode spm(m(),m_mode); canceled = true; m().limit().cancel(); - } + } - unsigned get_scope_level(){ scoped_proof_mode spm(m(),m_mode); return m_solver->get_scope_level();} + unsigned get_scope_level(){ scoped_proof_mode spm(m(),m_mode); return m_solver->get_scope_level();} - void show(); - void print(const char *filename); - void show_assertion_ids(); + void show(); + void print(const char *filename); + void show_assertion_ids(); - proof get_proof(){ - scoped_proof_mode spm(m(),m_mode); + proof get_proof(){ + scoped_proof_mode spm(m(),m_mode); return proof(ctx(),m_solver->get_proof()); - } + } - bool extensional_array_theory() {return extensional;} + bool extensional_array_theory() {return extensional;} }; #if 0 @@ -969,20 +968,20 @@ namespace Duality { goal & operator=(goal const & s) { Z3_goal_inc_ref(s.ctx(), s.m_goal); Z3_goal_dec_ref(ctx(), m_goal); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_goal = s.m_goal; - return *this; + return *this; } void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } unsigned size() const { return Z3_goal_size(ctx(), m_goal); } expr operator[](unsigned i) const { Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); } bool inconsistent() const { return Z3_goal_inconsistent(ctx(), m_goal) != 0; } - unsigned depth() const { return Z3_goal_depth(ctx(), m_goal); } + unsigned depth() const { return Z3_goal_depth(ctx(), m_goal); } void reset() { Z3_goal_reset(ctx(), m_goal); } unsigned num_exprs() const { Z3_goal_num_exprs(ctx(), m_goal); } - bool is_decided_sat() const { return Z3_goal_is_decided_sat(ctx(), m_goal) != 0; } - bool is_decided_unsat() const { return Z3_goal_is_decided_unsat(ctx(), m_goal) != 0; } + bool is_decided_sat() const { return Z3_goal_is_decided_sat(ctx(), m_goal) != 0; } + bool is_decided_unsat() const { return Z3_goal_is_decided_unsat(ctx(), m_goal) != 0; } friend std::ostream & operator<<(std::ostream & out, goal const & g) { out << Z3_goal_to_string(g.ctx(), g); return out; } }; @@ -1000,15 +999,15 @@ namespace Duality { apply_result & operator=(apply_result const & s) { Z3_apply_result_inc_ref(s.ctx(), s.m_apply_result); Z3_apply_result_dec_ref(ctx(), m_apply_result); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_apply_result = s.m_apply_result; - return *this; + return *this; } unsigned size() const { return Z3_apply_result_get_num_subgoals(ctx(), m_apply_result); } goal operator[](unsigned i) const { Z3_goal r = Z3_apply_result_get_subgoal(ctx(), m_apply_result, i); check_error(); return goal(ctx(), r); } goal operator[](int i) const { assert(i >= 0); return this->operator[](static_cast(i)); } - model convert_model(model const & m, unsigned i = 0) const { - check_context(*this, m); + model convert_model(model const & m, unsigned i = 0) const { + check_context(*this, m); Z3_model new_m = Z3_apply_result_convert_model(ctx(), m_apply_result, i, m); check_error(); return model(ctx(), new_m); @@ -1031,16 +1030,16 @@ namespace Duality { tactic & operator=(tactic const & s) { Z3_tactic_inc_ref(s.ctx(), s.m_tactic); Z3_tactic_dec_ref(ctx(), m_tactic); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_tactic = s.m_tactic; - return *this; + return *this; } solver mk_solver() const { Z3_solver r = Z3_mk_solver_from_tactic(ctx(), m_tactic); check_error(); return solver(ctx(), r); } - apply_result apply(goal const & g) const { + apply_result apply(goal const & g) const { check_context(*this, g); - Z3_apply_result r = Z3_tactic_apply(ctx(), m_tactic, g); - check_error(); - return apply_result(ctx(), r); + Z3_apply_result r = Z3_tactic_apply(ctx(), m_tactic, g); + check_error(); + return apply_result(ctx(), r); } apply_result operator()(goal const & g) const { return apply(g); @@ -1091,45 +1090,45 @@ namespace Duality { probe & operator=(probe const & s) { Z3_probe_inc_ref(s.ctx(), s.m_probe); Z3_probe_dec_ref(ctx(), m_probe); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_probe = s.m_probe; - return *this; + return *this; } double apply(goal const & g) const { double r = Z3_probe_apply(ctx(), m_probe, g); check_error(); return r; } double operator()(goal const & g) const { return apply(g); } - friend probe operator<=(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_le(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator<=(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_le(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } friend probe operator<=(probe const & p1, double p2) { return p1 <= probe(p1.ctx(), p2); } friend probe operator<=(double p1, probe const & p2) { return probe(p2.ctx(), p1) <= p2; } - friend probe operator>=(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_ge(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator>=(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_ge(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } friend probe operator>=(probe const & p1, double p2) { return p1 >= probe(p1.ctx(), p2); } friend probe operator>=(double p1, probe const & p2) { return probe(p2.ctx(), p1) >= p2; } - friend probe operator<(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_lt(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator<(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_lt(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } friend probe operator<(probe const & p1, double p2) { return p1 < probe(p1.ctx(), p2); } friend probe operator<(double p1, probe const & p2) { return probe(p2.ctx(), p1) < p2; } - friend probe operator>(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_gt(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator>(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_gt(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } friend probe operator>(probe const & p1, double p2) { return p1 > probe(p1.ctx(), p2); } friend probe operator>(double p1, probe const & p2) { return probe(p2.ctx(), p1) > p2; } - friend probe operator==(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_eq(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator==(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_eq(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } friend probe operator==(probe const & p1, double p2) { return p1 == probe(p1.ctx(), p2); } friend probe operator==(double p1, probe const & p2) { return probe(p2.ctx(), p1) == p2; } - friend probe operator&&(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_and(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator&&(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_and(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } - friend probe operator||(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_or(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator||(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_or(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } friend probe operator!(probe const & p) { - Z3_probe r = Z3_probe_not(p.ctx(), p); p.check_error(); return probe(p.ctx(), r); + Z3_probe r = Z3_probe_not(p.ctx(), p); p.check_error(); return probe(p.ctx(), r); } }; @@ -1159,15 +1158,15 @@ namespace Duality { inline symbol context::int_symbol(int n) { ::symbol r = ::symbol(n); return symbol(*this, r); } inline sort context::bool_sort() { - ::sort *s = m().mk_sort(m_basic_fid, BOOL_SORT); + ::sort *s = m().mk_sort(m_basic_fid, BOOL_SORT); return sort(*this, s); } inline sort context::int_sort() { - ::sort *s = m().mk_sort(m_arith_fid, INT_SORT); + ::sort *s = m().mk_sort(m_arith_fid, INT_SORT); return sort(*this, s); } inline sort context::real_sort() { - ::sort *s = m().mk_sort(m_arith_fid, REAL_SORT); + ::sort *s = m().mk_sort(m_arith_fid, REAL_SORT); return sort(*this, s); } inline sort context::array_sort(sort d, sort r) { @@ -1188,7 +1187,7 @@ namespace Duality { inline func_decl context::function(char const * name, unsigned arity, sort const * domain, sort const & range) { return function(str_symbol(name), arity, domain, range); } - + inline func_decl context::function(char const * name, sort const & domain, sort const & range) { sort args[1] = { domain }; return function(name, 1, args, range); @@ -1196,7 +1195,7 @@ namespace Duality { inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & range) { sort args[2] = { d1, d2 }; - return function(name, 2, args, range); + return function(name, 2, args, range); } inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & range) { @@ -1208,7 +1207,7 @@ namespace Duality { sort args[4] = { d1, d2, d3, d4 }; return function(name, 4, args, range); } - + inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & d5, sort const & range) { sort args[5] = { d1, d2, d3, d4, d5 }; return function(name, 5, args, range); @@ -1217,7 +1216,7 @@ namespace Duality { inline expr context::constant(symbol const & name, sort const & s) { ::expr *r = m().mk_const(m().mk_const_decl(name, s)); - return expr(*this, r); + return expr(*this, r); } inline expr context::constant(char const * name, sort const & s) { return constant(str_symbol(name), s); } inline expr context::bool_const(char const * name) { return constant(name, bool_sort()); } @@ -1250,11 +1249,11 @@ namespace Duality { expr args[5] = {a1,a2,a3,a4,a5}; return operator()(5,args); } - - + + inline expr select(expr const & a, expr const & i) { return a.ctx().make(Select,a,i); } inline expr store(expr const & a, expr const & i, expr const & v) { return a.ctx().make(Store,a,i,v); } - + inline expr forall(const std::vector &quants, const expr &body){ return body.ctx().make_quant(Forall,quants,body); } @@ -1304,7 +1303,7 @@ namespace Duality { } inline void setTerm(expr t){term = t;} - + inline void addTerm(expr t){terms.push_back(t);} inline void setChildren(const std::vector & _children){ @@ -1326,7 +1325,7 @@ namespace Duality { std::vector children; int num; }; - + typedef context interpolating_context; class interpolating_solver : public solver { @@ -1336,7 +1335,7 @@ namespace Duality { { weak_mode = false; } - + public: lbool interpolate(const std::vector &assumptions, std::vector &interpolants, @@ -1344,41 +1343,41 @@ namespace Duality { literals &lits, bool incremental ); - + lbool interpolate_tree(TermTree *assumptions, TermTree *&interpolants, model &_model, literals &lits, bool incremental ); - + bool read_interpolation_problem(const std::string &file_name, std::vector &assumptions, std::vector &theory, std::string &error_message ); - + void write_interpolation_problem(const std::string &file_name, const std::vector &assumptions, const std::vector &theory ); - + void AssertInterpolationAxiom(const expr &expr); void RemoveInterpolationAxiom(const expr &expr); - + void SetWeakInterpolants(bool weak); void SetPrintToFile(const std::string &file_name); - + const std::vector &GetInterpolationAxioms() {return theory;} const char *profile(); - + private: bool weak_mode; std::string print_filename; std::vector theory; }; - - + + inline expr context::cook(::expr *a) {return expr(*this,a);} inline std::vector context::cook(ptr_vector< ::expr> v) { diff --git a/src/interp/iz3base.cpp b/src/interp/iz3base.cpp index d0f8c3a75..b9284b869 100755 --- a/src/interp/iz3base.cpp +++ b/src/interp/iz3base.cpp @@ -25,12 +25,12 @@ #pragma warning(disable:4101) #endif -#include "iz3base.h" +#include "interp/iz3base.h" #include #include #include #include -#include "solver.h" +#include "solver/solver.h" #include "../smt/smt_solver.h" diff --git a/src/interp/iz3base.h b/src/interp/iz3base.h index 59cbf3a61..15f613730 100755 --- a/src/interp/iz3base.h +++ b/src/interp/iz3base.h @@ -21,8 +21,8 @@ #ifndef IZ3BASE_H #define IZ3BASE_H -#include "iz3mgr.h" -#include "iz3scopes.h" +#include "interp/iz3mgr.h" +#include "interp/iz3scopes.h" namespace hash_space { template <> @@ -66,35 +66,35 @@ class iz3base : public iz3mgr, public scopes { /** Constructor */ - iz3base(ast_manager &_m_manager, - const std::vector &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3mgr(_m_manager), scopes(_parents) { + iz3base(ast_manager &_m_manager, + const std::vector &_cnsts, + const std::vector &_parents, + const std::vector &_theory) + : iz3mgr(_m_manager), scopes(_parents) { initialize(_cnsts,_parents,_theory); weak = false; } - iz3base(const iz3mgr& other, - const std::vector &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3mgr(other), scopes(_parents) { + iz3base(const iz3mgr& other, + const std::vector &_cnsts, + const std::vector &_parents, + const std::vector &_theory) + : iz3mgr(other), scopes(_parents) { initialize(_cnsts,_parents,_theory); weak = false; } - iz3base(const iz3mgr& other, - const std::vector > &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3mgr(other), scopes(_parents) { + iz3base(const iz3mgr& other, + const std::vector > &_cnsts, + const std::vector &_parents, + const std::vector &_theory) + : iz3mgr(other), scopes(_parents) { initialize(_cnsts,_parents,_theory); weak = false; } - iz3base(const iz3mgr& other) - : iz3mgr(other), scopes() { + iz3base(const iz3mgr& other) + : iz3mgr(other), scopes() { weak = false; } diff --git a/src/interp/iz3checker.cpp b/src/interp/iz3checker.cpp index 69cfea8b8..8fa99fe10 100755 --- a/src/interp/iz3checker.cpp +++ b/src/interp/iz3checker.cpp @@ -24,8 +24,8 @@ #pragma warning(disable:4101) #endif -#include "iz3base.h" -#include "iz3checker.h" +#include "interp/iz3base.h" +#include "interp/iz3checker.h" #include #include diff --git a/src/interp/iz3checker.h b/src/interp/iz3checker.h index 6028e60db..d89db3011 100644 --- a/src/interp/iz3checker.h +++ b/src/interp/iz3checker.h @@ -20,30 +20,30 @@ #ifndef IZ3_CHECKER_H #define IZ3_CHECKER_H -#include "iz3mgr.h" -#include "solver.h" +#include "interp/iz3mgr.h" +#include "solver/solver.h" bool iz3check(ast_manager &_m_manager, - solver *s, - std::ostream &err, - const ptr_vector &cnsts, - const ::vector &parents, - const ptr_vector &interps, - const ptr_vector &theory); + solver *s, + std::ostream &err, + const ptr_vector &cnsts, + const ::vector &parents, + const ptr_vector &interps, + const ptr_vector &theory); bool iz3check(ast_manager &_m_manager, - solver *s, - std::ostream &err, - const ptr_vector &cnsts, - ast *tree, - const ptr_vector &interps); + solver *s, + std::ostream &err, + const ptr_vector &cnsts, + ast *tree, + const ptr_vector &interps); bool iz3check(iz3mgr &mgr, - solver *s, - std::ostream &err, - const std::vector &cnsts, - const std::vector &parents, - const std::vector &interps, - const ptr_vector &theory); + solver *s, + std::ostream &err, + const std::vector &cnsts, + const std::vector &parents, + const std::vector &interps, + const ptr_vector &theory); #endif diff --git a/src/interp/iz3exception.h b/src/interp/iz3exception.h index 134c049cf..b3f841565 100644 --- a/src/interp/iz3exception.h +++ b/src/interp/iz3exception.h @@ -17,8 +17,8 @@ Notes: #ifndef _IZ3EXCEPTION_H_ #define _IZ3EXCEPTION_H_ -#include "z3_exception.h" -#include "error_codes.h" +#include "util/z3_exception.h" +#include "util/error_codes.h" class iz3_exception: public default_exception { public: diff --git a/src/interp/iz3hash.h b/src/interp/iz3hash.h index 9cf03b53d..c796a247b 100644 --- a/src/interp/iz3hash.h +++ b/src/interp/iz3hash.h @@ -36,7 +36,7 @@ #include #include #include -#include "hash.h" +#include "util/hash.h" #define stl_ext hash_space @@ -468,10 +468,10 @@ namespace hash_space { : hashtable,Key,HashFun,proj1,EqFun>(7) {} Value &operator[](const Key& key) { - std::pair kvp(key,Value()); - return - hashtable,Key,HashFun,proj1,EqFun>:: - lookup(kvp,true)->val.second; + std::pair kvp(key,Value()); + return + hashtable,Key,HashFun,proj1,EqFun>:: + lookup(kvp,true)->val.second; } }; diff --git a/src/interp/iz3interp.cpp b/src/interp/iz3interp.cpp index bb83349da..f9bf03951 100755 --- a/src/interp/iz3interp.cpp +++ b/src/interp/iz3interp.cpp @@ -33,13 +33,13 @@ #include #include -#include "iz3profiling.h" -#include "iz3translate.h" -#include "iz3proof.h" -#include "iz3hash.h" -#include "iz3interp.h" +#include "interp/iz3profiling.h" +#include "interp/iz3translate.h" +#include "interp/iz3proof.h" +#include "interp/iz3hash.h" +#include "interp/iz3interp.h" -#include"scoped_proof.h" +#include "ast/scoped_proof.h" using namespace stl_ext; diff --git a/src/interp/iz3interp.h b/src/interp/iz3interp.h index 601c8c3f5..a4e1024a9 100644 --- a/src/interp/iz3interp.h +++ b/src/interp/iz3interp.h @@ -20,9 +20,9 @@ #ifndef IZ3_INTERP_H #define IZ3_INTERP_H -#include "iz3hash.h" -#include "iz3exception.h" -#include "solver.h" +#include "interp/iz3hash.h" +#include "interp/iz3exception.h" +#include "solver/solver.h" class iz3base; @@ -73,22 +73,22 @@ typedef interpolation_options_struct *interpolation_options; representation, for compatibility with the old API. */ void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ptr_vector &cnsts, - const ::vector &parents, - ptr_vector &interps, - const ptr_vector &theory, - interpolation_options_struct * options = 0); + ast *proof, + const ptr_vector &cnsts, + const ::vector &parents, + ptr_vector &interps, + const ptr_vector &theory, + interpolation_options_struct * options = 0); /* Same as above, but each constraint is a vector of formulas. */ void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const vector > &cnsts, - const ::vector &parents, - ptr_vector &interps, - const ptr_vector &theory, - interpolation_options_struct * options = 0); + ast *proof, + const vector > &cnsts, + const ::vector &parents, + ptr_vector &interps, + const ptr_vector &theory, + interpolation_options_struct * options = 0); /* Compute an interpolant from a proof. This version uses the ast representation, for compatibility with the new API. Here, cnsts is @@ -98,11 +98,11 @@ void iz3interpolate(ast_manager &_m_manager, proof, so it can be considered a hint. */ void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ptr_vector &cnsts, - ast *tree, - ptr_vector &interps, - interpolation_options_struct * options); + ast *proof, + const ptr_vector &cnsts, + ast *tree, + ptr_vector &interps, + interpolation_options_struct * options); /* Compute an interpolant from an ast representing an interpolation @@ -112,12 +112,12 @@ void iz3interpolate(ast_manager &_m_manager, */ lbool iz3interpolate(ast_manager &_m_manager, - solver &s, - ast *tree, - ptr_vector &cnsts, - ptr_vector &interps, - model_ref &m, - interpolation_options_struct * options); + solver &s, + ast *tree, + ptr_vector &cnsts, + ptr_vector &interps, + model_ref &m, + interpolation_options_struct * options); #endif diff --git a/src/interp/iz3mgr.cpp b/src/interp/iz3mgr.cpp index 2e55d7040..7314403b0 100755 --- a/src/interp/iz3mgr.cpp +++ b/src/interp/iz3mgr.cpp @@ -27,15 +27,17 @@ #pragma warning(disable:4800) #endif -#include "iz3mgr.h" +#include "interp/iz3mgr.h" #include #include #include #include +#include -#include "expr_abstract.h" -#include "params.h" +#include "ast/expr_abstract.h" +#include "util/params.h" +#include "ast/used_vars.h" using namespace stl_ext; @@ -938,3 +940,30 @@ void iz3mgr::get_bound_substitutes(stl_ext::hash_map &memo, const ast } #endif + +unsigned iz3mgr::num_free_variables(const ast &e){ + used_vars uv; + uv(to_expr(e.raw())); + return uv.get_num_vars(); +} + +iz3mgr::ast iz3mgr::close_universally (ast e){ + used_vars uv; + uv(to_expr(e.raw())); + std::vector bvs; + stl_ext::hash_map 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; +} diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h index 424b95359..0ad751326 100755 --- a/src/interp/iz3mgr.h +++ b/src/interp/iz3mgr.h @@ -25,26 +25,26 @@ #include #include -#include "iz3hash.h" -#include "iz3exception.h" +#include "interp/iz3hash.h" +#include "interp/iz3exception.h" -#include"well_sorted.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"datatype_decl_plugin.h" -#include"array_decl_plugin.h" -#include"ast_translation.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"ast_smt_pp.h" -#include"ast_smt2_pp.h" -#include"th_rewriter.h" -#include"var_subst.h" -#include"expr_substitution.h" -#include"pp.h" -#include"scoped_ctrl_c.h" -#include"cancel_eh.h" -#include"scoped_timer.h" +#include "ast/well_sorted.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/ast_translation.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt_pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/var_subst.h" +#include "ast/expr_substitution.h" +#include "ast/pp.h" +#include "util/scoped_ctrl_c.h" +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" /* A wrapper around an ast manager, providing convenience methods. */ @@ -57,12 +57,12 @@ typedef ast raw_ast; /** Wrapper around an ast pointer */ class ast_i { - protected: +protected: raw_ast *_ast; - public: +public: raw_ast * const &raw() const {return _ast;} ast_i(raw_ast *a){_ast = a;} - + ast_i(){_ast = 0;} bool eq(const ast_i &other) const { return _ast == other._ast; @@ -86,33 +86,33 @@ class ast_i { /** Reference counting verison of above */ class ast_r : public ast_i { ast_manager *_m; - public: - ast_r(ast_manager *m, raw_ast *a) : ast_i(a) { +public: + ast_r(ast_manager *m, raw_ast *a) : ast_i(a) { _m = m; m->inc_ref(a); } - + ast_r() {_m = 0;} - - ast_r(const ast_r &other) : ast_i(other) { + + ast_r(const ast_r &other) : ast_i(other) { _m = other._m; - _m->inc_ref(_ast); + if (_m) _m->inc_ref(_ast); } - + ast_r &operator=(const ast_r &other) { if(_ast) _m->dec_ref(_ast); _ast = other._ast; _m = other._m; - _m->inc_ref(_ast); + if (_m) _m->inc_ref(_ast); return *this; } - - ~ast_r(){ + + ~ast_r() { if(_ast) _m->dec_ref(_ast); } - + ast_manager *mgr() const {return _m;} }; @@ -661,6 +661,12 @@ class iz3mgr { ast apply_quant(opr quantifier, ast var, ast e); + // Universally quantify all the free variables in a formula. + // Makes up names for the quntifiers. + + ast close_universally (ast e); + + unsigned num_free_variables(const ast &e); /** For debugging */ void show(ast); diff --git a/src/interp/iz3pp.cpp b/src/interp/iz3pp.cpp index 066e04e83..787fa4ec7 100644 --- a/src/interp/iz3pp.cpp +++ b/src/interp/iz3pp.cpp @@ -26,14 +26,14 @@ #include #include -#include "iz3mgr.h" -#include "iz3pp.h" -#include "func_decl_dependencies.h" -#include"for_each_expr.h" -#include"ast_smt_pp.h" -#include"ast_smt2_pp.h" -#include"expr_functors.h" -#include"expr_abstract.h" +#include "interp/iz3mgr.h" +#include "interp/iz3pp.h" +#include "ast/func_decl_dependencies.h" +#include "ast/for_each_expr.h" +#include "ast/ast_smt_pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/expr_functors.h" +#include "ast/expr_abstract.h" using namespace stl_ext; diff --git a/src/interp/iz3pp.h b/src/interp/iz3pp.h index c66b4a4fa..7b3405f9b 100644 --- a/src/interp/iz3pp.h +++ b/src/interp/iz3pp.h @@ -20,7 +20,7 @@ #ifndef IZ3_PP_H #define IZ3_PP_H -#include "iz3mgr.h" +#include "interp/iz3mgr.h" /** Exception thrown in case of mal-formed tree interpoloation specification */ @@ -30,7 +30,7 @@ struct iz3pp_bad_tree: public iz3_exception { }; void iz3pp(ast_manager &m, - const ptr_vector &cnsts_vec, - expr *tree, - std::ostream& out); + const ptr_vector &cnsts_vec, + expr *tree, + std::ostream& out); #endif diff --git a/src/interp/iz3profiling.cpp b/src/interp/iz3profiling.cpp index f3b3d0efc..df3126e4f 100755 --- a/src/interp/iz3profiling.cpp +++ b/src/interp/iz3profiling.cpp @@ -24,14 +24,14 @@ #pragma warning(disable:4101) #endif -#include "iz3profiling.h" +#include "interp/iz3profiling.h" #include #include #include #include #include -#include "stopwatch.h" +#include "util/stopwatch.h" // FIXME fill in these stubs diff --git a/src/interp/iz3proof.cpp b/src/interp/iz3proof.cpp index 9adcce3c3..bc046ceff 100755 --- a/src/interp/iz3proof.cpp +++ b/src/interp/iz3proof.cpp @@ -25,8 +25,8 @@ #pragma warning(disable:4101) #endif -#include "iz3proof.h" -#include "iz3profiling.h" +#include "interp/iz3proof.h" +#include "interp/iz3profiling.h" #include #include diff --git a/src/interp/iz3proof.h b/src/interp/iz3proof.h index 213afce5e..ba4507ba2 100755 --- a/src/interp/iz3proof.h +++ b/src/interp/iz3proof.h @@ -22,8 +22,8 @@ #include -#include "iz3base.h" -#include "iz3secondary.h" +#include "interp/iz3base.h" +#include "interp/iz3secondary.h" // #define CHECK_PROOFS diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp index 26ef7386c..fc9d0fac6 100755 --- a/src/interp/iz3proof_itp.cpp +++ b/src/interp/iz3proof_itp.cpp @@ -24,7 +24,7 @@ #pragma warning(disable:4101) #endif -#include "iz3proof_itp.h" +#include "interp/iz3proof_itp.h" using namespace stl_ext; @@ -2968,9 +2968,9 @@ class iz3proof_itp_impl : public iz3proof_itp { ast interpolate(const node &pf){ // proof of false must be a formula, with quantified symbols #ifndef BOGUS_QUANTS - return add_quants(z3_simplify(pf)); + return close_universally(add_quants(z3_simplify(pf))); #else - return z3_simplify(pf); + return close_universally(z3_simplify(pf)); #endif } diff --git a/src/interp/iz3proof_itp.h b/src/interp/iz3proof_itp.h index bd9eca441..c9a36e9b1 100644 --- a/src/interp/iz3proof_itp.h +++ b/src/interp/iz3proof_itp.h @@ -22,8 +22,8 @@ #include -#include "iz3base.h" -#include "iz3secondary.h" +#include "interp/iz3base.h" +#include "interp/iz3secondary.h" // #define CHECK_PROOFS diff --git a/src/interp/iz3scopes.cpp b/src/interp/iz3scopes.cpp index b70f37a06..e3a28abdd 100755 --- a/src/interp/iz3scopes.cpp +++ b/src/interp/iz3scopes.cpp @@ -21,7 +21,7 @@ #include -#include "iz3scopes.h" +#include "interp/iz3scopes.h" /** computes the least common ancestor of two nodes in the tree, or SHRT_MAX if none */ diff --git a/src/interp/iz3scopes.h b/src/interp/iz3scopes.h index 38f9e2292..ece30dc25 100755 --- a/src/interp/iz3scopes.h +++ b/src/interp/iz3scopes.h @@ -23,7 +23,7 @@ #include #include -#include "iz3hash.h" +#include "interp/iz3hash.h" class scopes { @@ -105,7 +105,7 @@ class scopes { void range_add(int i, range &n){ #if 0 - if(i < n.lo) n.lo = i; + if(i < n.lo) n.lo = i; if(i > n.hi) n.hi = i; #else range rng; rng.lo = i; rng.hi = i; @@ -119,7 +119,7 @@ class scopes { int thing = tree_lca(rng1.lo,rng2.hi); if(thing == rng1.lo) frame = rng1.lo; else frame = tree_gcd(thing,rng1.hi); - return frame; + return frame; } #else diff --git a/src/interp/iz3secondary.h b/src/interp/iz3secondary.h index 46d080595..a5a949b54 100755 --- a/src/interp/iz3secondary.h +++ b/src/interp/iz3secondary.h @@ -23,7 +23,7 @@ /** Interface class for secondary provers. */ -#include "iz3base.h" +#include "interp/iz3base.h" #include class iz3secondary : public iz3mgr { diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index 4f6741989..e4730ea63 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -24,11 +24,12 @@ #pragma warning(disable:4101) #endif -#include "iz3translate.h" -#include "iz3proof.h" -#include "iz3profiling.h" -#include "iz3interp.h" -#include "iz3proof_itp.h" +#include "interp/iz3translate.h" +#include "interp/iz3proof.h" +#include "interp/iz3profiling.h" +#include "interp/iz3interp.h" +#include "interp/iz3proof_itp.h" +#include "ast/ast_pp.h" #include #include @@ -234,6 +235,11 @@ public: } } + // if(!range_is_empty(rng)){ + // if (num_free_variables(con) > 0) + // rng = range_empty(); + // } + if(res == INT_MAX){ if(range_is_empty(rng)) res = -1; @@ -1846,6 +1852,21 @@ public: } break; } + case PR_TRANSITIVITY_STAR: { + // assume the premises are x = y, y = z, z = u, u = v, .. + + ast x = arg(conc(prem(proof,0)),0); + ast y = arg(conc(prem(proof,0)),1); + ast z = arg(conc(prem(proof,1)),1); + res = iproof->make_transitivity(x,y,z,args[0],args[1]); + + for (unsigned i = 2; i < nprems; ++i) { + y = z; + z = arg(conc(prem(proof,i)),1); + res = iproof->make_transitivity(x,y,z,res,args[i]); + } + break; + } case PR_QUANT_INTRO: case PR_MONOTONICITY: { @@ -2024,6 +2045,7 @@ public: break; } default: + IF_VERBOSE(0, verbose_stream() << "Unsupported proof rule: " << expr_ref((expr*)proof.raw(), *proof.mgr()) << "\n";); // pfgoto(proof); // SASSERT(0 && "translate_main: unsupported proof rule"); throw unsupported(); diff --git a/src/interp/iz3translate.h b/src/interp/iz3translate.h index 15e836cd8..8ecafbd3a 100755 --- a/src/interp/iz3translate.h +++ b/src/interp/iz3translate.h @@ -22,8 +22,8 @@ #ifndef IZ3TRANSLATION_H #define IZ3TRANSLATION_H -#include "iz3proof.h" -#include "iz3secondary.h" +#include "interp/iz3proof.h" +#include "interp/iz3secondary.h" // This is a interface class for translation from Z3 proof terms to // an interpolatable proof @@ -36,7 +36,7 @@ class iz3translation : public iz3base { /** This is thrown when the proof cannot be translated. */ struct unsupported: public iz3_exception { - unsupported(): iz3_exception("unsupported") {} + unsupported(): iz3_exception("unsupported") { } }; static iz3translation *create(iz3mgr &mgr, @@ -47,9 +47,9 @@ class iz3translation : public iz3base { protected: iz3translation(iz3mgr &mgr, - const std::vector > &_cnsts, - const std::vector &_parents, - const std::vector &_theory) + const std::vector > &_cnsts, + const std::vector &_parents, + const std::vector &_theory) : iz3base(mgr,_cnsts,_parents,_theory) {} }; diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp index de1da6ce6..b88e488b4 100755 --- a/src/interp/iz3translate_direct.cpp +++ b/src/interp/iz3translate_direct.cpp @@ -28,10 +28,10 @@ #pragma warning(disable:4390) #endif -#include "iz3translate.h" -#include "iz3proof.h" -#include "iz3profiling.h" -#include "iz3interp.h" +#include "interp/iz3translate.h" +#include "interp/iz3proof.h" +#include "interp/iz3profiling.h" +#include "interp/iz3interp.h" #include #include diff --git a/src/math/automata/automaton.cpp b/src/math/automata/automaton.cpp index ab908525e..20cfc3a84 100644 --- a/src/math/automata/automaton.cpp +++ b/src/math/automata/automaton.cpp @@ -18,6 +18,6 @@ Revision History: --*/ -#include "automaton.h" +#include "math/automata/automaton.h" template class automaton; diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index 2a68cba08..41fc19907 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -22,9 +22,10 @@ Revision History: #define AUTOMATON_H_ -#include "util.h" -#include "vector.h" -#include "uint_set.h" +#include "util/util.h" +#include "util/vector.h" +#include "util/uint_set.h" +#include "util/trace.h" template class default_value_manager { @@ -107,11 +108,10 @@ public: m_init = init; m_delta.push_back(moves()); m_delta_inv.push_back(moves()); - for (unsigned i = 0; i < final.size(); ++i) { - add_to_final_states(final[i]); + for (unsigned f : final) { + add_to_final_states(f); } - for (unsigned i = 0; i < mvs.size(); ++i) { - move const& mv = mvs[i]; + for (move const& mv : mvs) { unsigned n = std::max(mv.src(), mv.dst()); if (n >= m_delta.size()) { m_delta.resize(n+1, moves()); @@ -280,8 +280,8 @@ public: } else { init = a.num_states(); - for (unsigned i = 0; i < a.m_final_states.size(); ++i) { - mvs.push_back(move(m, init, a.m_final_states[i])); + for (unsigned st : a.m_final_states) { + mvs.push_back(move(m, init, st)); } } return alloc(automaton, m, init, final, mvs); @@ -301,6 +301,16 @@ public: } } + bool is_sink_state(unsigned s) const { + if (is_final_state(s)) return false; + moves mvs; + get_moves_from(s, mvs); + for (move const& m : mvs) { + if (s != m.dst()) return false; + } + return true; + } + void add_init_to_final_states() { add_to_final_states(init()); } @@ -374,12 +384,12 @@ public: else if (1 == in_degree(dst) && (!is_final_state(dst) || is_final_state(src)) && init() != dst) { moves const& mvs = m_delta[dst]; moves mvs1; - for (unsigned k = 0; k < mvs.size(); ++k) { - mvs1.push_back(move(m, src, mvs[k].dst(), mvs[k].t())); + for (move const& mv : mvs) { + mvs1.push_back(move(m, src, mv.dst(), mv.t())); } - for (unsigned k = 0; k < mvs1.size(); ++k) { - remove(dst, mvs1[k].dst(), mvs1[k].t()); - add(mvs1[k]); + for (move const& mv : mvs1) { + remove(dst, mv.dst(), mv.t()); + add(mv); } } // @@ -392,13 +402,13 @@ public: unsigned_vector src0s; moves const& mvs = m_delta_inv[dst]; moves mvs1; - for (unsigned k = 0; k < mvs.size(); ++k) { - SASSERT(mvs[k].is_epsilon()); - mvs1.push_back(move(m, mvs[k].src(), dst1, t)); + for (move const& mv1 : mvs) { + SASSERT(mv1.is_epsilon()); + mvs1.push_back(move(m, mv1.src(), dst1, t)); } - for (unsigned k = 0; k < mvs1.size(); ++k) { - remove(mvs1[k].src(), dst, 0); - add(mvs1[k]); + for (move const& mv1 : mvs1) { + remove(mv1.src(), dst, 0); + add(mv1); } remove(dst, dst1, t); --j; @@ -410,12 +420,12 @@ public: else if (1 == out_degree(src) && init() != src && (!is_final_state(src) || is_final_state(dst))) { moves const& mvs = m_delta_inv[src]; moves mvs1; - for (unsigned k = 0; k < mvs.size(); ++k) { - mvs1.push_back(move(m, mvs[k].src(), dst, mvs[k].t())); + for (move const& mv : mvs) { + mvs1.push_back(move(m, mv.src(), dst, mv.t())); } - for (unsigned k = 0; k < mvs1.size(); ++k) { - remove(mvs1[k].src(), src, mvs1[k].t()); - add(mvs1[k]); + for (move const& mv : mvs1) { + remove(mv.src(), src, mv.t()); + add(mv); } } else { @@ -438,6 +448,7 @@ public: break; } } + sinkify_dead_states(); } bool is_sequence(unsigned& length) const { @@ -467,22 +478,21 @@ public: unsigned out_degree(unsigned state) const { return m_delta[state].size(); } move const& get_move_from(unsigned state) const { SASSERT(m_delta[state].size() == 1); return m_delta[state][0]; } move const& get_move_to(unsigned state) const { SASSERT(m_delta_inv[state].size() == 1); return m_delta_inv[state][0]; } - moves const& get_moves_from(unsigned state) const { return m_delta[state]; } + moves const& get_moves_from(unsigned state) const { return m_delta[state]; } moves const& get_moves_to(unsigned state) const { return m_delta_inv[state]; } bool initial_state_is_source() const { return m_delta_inv[m_init].empty(); } bool is_final_state(unsigned s) const { return m_final_set.contains(s); } - bool is_final_configuration(uint_set s) const { - for (uint_set::iterator it = s.begin(), end = s.end(); it != end; ++it) { - if (is_final_state(*it)) - return true; - } - return false; - } + bool is_final_configuration(uint_set s) const { + for (unsigned i : s) { + if (is_final_state(i)) + return true; + } + return false; + } bool is_epsilon_free() const { - for (unsigned i = 0; i < m_delta.size(); ++i) { - moves const& mvs = m_delta[i]; - for (unsigned j = 0; j < mvs.size(); ++j) { - if (!mvs[j].t()) return false; + for (moves const& mvs : m_delta) { + for (move const & m : mvs) { + if (!m.t()) return false; } } return true; @@ -490,8 +500,8 @@ public: bool all_epsilon_in(unsigned s) { moves const& mvs = m_delta_inv[s]; - for (unsigned j = 0; j < mvs.size(); ++j) { - if (mvs[j].t()) return false; + for (move const& m : mvs) { + if (m.t()) return false; } return true; } @@ -504,15 +514,15 @@ public: bool is_loop_state(unsigned s) const { moves mvs; get_moves_from(s, mvs); - for (unsigned i = 0; i < mvs.size(); ++i) { - if (s == mvs[i].dst()) return true; + for (move const& m : mvs) { + if (s == m.dst()) return true; } return false; } unsigned move_count() const { unsigned result = 0; - for (unsigned i = 0; i < m_delta.size(); result += m_delta[i].size(), ++i) {} + for (moves const& mvs : m_delta) result += mvs.size(); return result; } void get_epsilon_closure(unsigned state, unsigned_vector& states) { @@ -524,13 +534,13 @@ public: void get_moves_from(unsigned state, moves& mvs, bool epsilon_closure = true) const { get_moves(state, m_delta, mvs, epsilon_closure); } - void get_moves_from_states(uint_set states, moves& mvs, bool epsilon_closure = true) const { - for (uint_set::iterator it = states.begin(), end = states.end(); it != end; ++it) { - moves curr; - get_moves(*it, m_delta, curr, epsilon_closure); - mvs.append(curr); - } - } + void get_moves_from_states(uint_set states, moves& mvs, bool epsilon_closure = true) const { + for (unsigned i : states) { + moves curr; + get_moves(i, m_delta, curr, epsilon_closure); + mvs.append(curr); + } + } void get_moves_to(unsigned state, moves& mvs, bool epsilon_closure = true) { get_moves(state, m_delta_inv, mvs, epsilon_closure); } @@ -543,8 +553,7 @@ public: out << "\n"; for (unsigned i = 0; i < m_delta.size(); ++i) { moves const& mvs = m_delta[i]; - for (unsigned j = 0; j < mvs.size(); ++j) { - move const& mv = mvs[j]; + for (move const& mv : mvs) { out << i << " -> " << mv.dst() << " "; if (mv.t()) { out << "if "; @@ -557,6 +566,40 @@ public: } private: + void sinkify_dead_states() { + uint_set dead_states; + for (unsigned i = 0; i < m_delta.size(); ++i) { + if (!m_final_states.contains(i)) { + dead_states.insert(i); + } + } + bool change = true; + unsigned_vector to_remove; + while (change) { + change = false; + to_remove.reset(); + for (unsigned s : dead_states) { + moves const& mvs = m_delta[s]; + for (move const& mv : mvs) { + if (!dead_states.contains(mv.dst())) { + to_remove.push_back(s); + break; + } + } + } + change = !to_remove.empty(); + for (unsigned s : to_remove) { + dead_states.remove(s); + } + to_remove.reset(); + } + TRACE("seq", tout << "remove: " << dead_states << "\n";); + for (unsigned s : dead_states) { + CTRACE("seq", !m_delta[s].empty(), tout << "live state " << s << "\n";); + m_delta[s].reset(); + } + } + void remove_dead_states() { unsigned_vector remap; for (unsigned i = 0; i < m_delta.size(); ++i) { @@ -662,8 +705,8 @@ private: } static void append_final(unsigned offset, automaton const& a, unsigned_vector& final) { - for (unsigned i = 0; i < a.m_final_states.size(); ++i) { - final.push_back(a.m_final_states[i]+offset); + for (unsigned s : a.m_final_states) { + final.push_back(s+offset); } } diff --git a/src/math/automata/boolean_algebra.h b/src/math/automata/boolean_algebra.h index 4f5527f5e..d54ff5d1a 100644 --- a/src/math/automata/boolean_algebra.h +++ b/src/math/automata/boolean_algebra.h @@ -21,7 +21,7 @@ Revision History: #ifndef BOOLEAN_ALGEBRA_H_ #define BOOLEAN_ALGEBRA_H_ -#include "util.h" +#include "util/util.h" template class positive_boolean_algebra { @@ -40,9 +40,7 @@ template class boolean_algebra : public positive_boolean_algebra { public: virtual ~boolean_algebra() {} - virtual T mk_not(T x) = 0; - //virtual lbool are_equivalent(T x, T y) = 0; - //virtual T simplify(T x) = 0; + virtual T mk_not(T x) = 0; }; #endif diff --git a/src/math/automata/symbolic_automata.h b/src/math/automata/symbolic_automata.h index 5c2b4a2a4..4831280af 100644 --- a/src/math/automata/symbolic_automata.h +++ b/src/math/automata/symbolic_automata.h @@ -22,8 +22,8 @@ Revision History: #define SYMBOLIC_AUTOMATA_H_ -#include "automaton.h" -#include "boolean_algebra.h" +#include "math/automata/automaton.h" +#include "math/automata/boolean_algebra.h" template > @@ -130,13 +130,14 @@ private: else { //true case curr_bv.push_back(true); - ref_t new_pred_pos(m_ba.mk_and(curr_pred, constraints[i]), m); + ref_t new_pred_pos(m_ba.mk_and(curr_pred, constraints[i]), m); generate_min_terms_rec(constraints, min_terms, i + 1, curr_bv, new_pred_pos); curr_bv.pop_back(); //false case curr_bv.push_back(false); - ref_t new_pred_neg(m_ba.mk_and(curr_pred, m_ba.mk_not(constraints[i])), m); + ref_t neg(m_ba.mk_not(constraints[i]), m); + ref_t new_pred_neg(m_ba.mk_and(curr_pred, neg), m); generate_min_terms_rec(constraints, min_terms, i + 1, curr_bv, new_pred_neg); curr_bv.pop_back(); } diff --git a/src/math/automata/symbolic_automata_def.h b/src/math/automata/symbolic_automata_def.h index 01476eb53..be38a60bc 100644 --- a/src/math/automata/symbolic_automata_def.h +++ b/src/math/automata/symbolic_automata_def.h @@ -22,8 +22,9 @@ Revision History: #define SYMBOLIC_AUTOMATA_DEF_H_ -#include "symbolic_automata.h" -#include "hashtable.h" +#include "math/automata/symbolic_automata.h" +#include "util/hashtable.h" +#include "util/vector.h" @@ -288,7 +289,7 @@ typename symbolic_automata::automaton_t* symbolic_automata::mk_determinstic_param(automaton_t& a, bool flip_acceptance) { vector, ref_t> > min_terms; vector predicates; - + map s2id; // set of states to unique id vector id2s; // unique id to set of b-states uint_set set; @@ -296,17 +297,22 @@ symbolic_automata::mk_determinstic_param(automaton_t& a, bool flip_accepta moves_t new_mvs; // moves in the resulting automaton unsigned_vector new_final_states; // new final states unsigned p_state_id = 0; // next state identifier - - // adds non-final states of a to final if flipping and and final otherwise + + TRACE("seq", tout << "mk-deterministic " << flip_acceptance << " " << set << " " << a.is_final_configuration(set) << "\n";); + // adds non-final states of a to final if flipping and final otherwise + unsigned_vector init_states; + a.get_epsilon_closure(a.init(), init_states); + for (unsigned s : init_states) { + set.insert(s); + } if (a.is_final_configuration(set) != flip_acceptance) { new_final_states.push_back(p_state_id); } - set.insert(a.init()); // Initial state as aset s2id.insert(set, p_state_id++); // the index to the initial state is 0 id2s.push_back(set); - svector todo; //States to visit + ::vector todo; //States to visit todo.push_back(set); uint_set state; @@ -342,6 +348,7 @@ symbolic_automata::mk_determinstic_param(automaton_t& a, bool flip_accepta bool is_new = !s2id.contains(set); if (is_new) { + TRACE("seq", tout << "mk-deterministic " << flip_acceptance << " " << set << " " << a.is_final_configuration(set) << "\n";); if (a.is_final_configuration(set) != flip_acceptance) { new_final_states.push_back(p_state_id); } @@ -445,7 +452,15 @@ typename symbolic_automata::automaton_t* symbolic_automata::mk_produ } } if (mvs1.empty()) { - return alloc(automaton_t, m); + if (a.is_final_state(a.init()) && b.is_final_state(b.init())) { + // special case: automaton has no moves, but the initial state is final on both sides + // this results in the automaton which accepts the empty sequence and nothing else + final.clear(); + final.push_back(0); + return alloc(automaton_t, m, 0, final, mvs1); + } else { + return alloc(automaton_t, m); + } } else { return alloc(automaton_t, m, 0, final, mvs1); diff --git a/src/math/euclid/euclidean_solver.cpp b/src/math/euclid/euclidean_solver.cpp index b33dbf3aa..1be239c36 100644 --- a/src/math/euclid/euclidean_solver.cpp +++ b/src/math/euclid/euclidean_solver.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"euclidean_solver.h" -#include"numeral_buffer.h" -#include"heap.h" +#include "math/euclid/euclidean_solver.h" +#include "util/numeral_buffer.h" +#include "util/heap.h" struct euclidean_solver::imp { typedef unsigned var; diff --git a/src/math/euclid/euclidean_solver.h b/src/math/euclid/euclidean_solver.h index 98a202e5e..74d0d7fa4 100644 --- a/src/math/euclid/euclidean_solver.h +++ b/src/math/euclid/euclidean_solver.h @@ -19,8 +19,8 @@ Revision History: #ifndef EUCLIDEAN_SOLVER_H_ #define EUCLIDEAN_SOLVER_H_ -#include"mpq.h" -#include"vector.h" +#include "util/mpq.h" +#include "util/vector.h" class euclidean_solver { struct imp; diff --git a/src/math/grobner/grobner.cpp b/src/math/grobner/grobner.cpp index baa16b405..3295c4eae 100644 --- a/src/math/grobner/grobner.cpp +++ b/src/math/grobner/grobner.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"grobner.h" -#include"ast_pp.h" -#include"ref_util.h" +#include "math/grobner/grobner.h" +#include "ast/ast_pp.h" +#include "util/ref_util.h" // #define PROFILE_GB diff --git a/src/math/grobner/grobner.h b/src/math/grobner/grobner.h index 770f0a538..f024a33e4 100644 --- a/src/math/grobner/grobner.h +++ b/src/math/grobner/grobner.h @@ -19,12 +19,12 @@ Revision History: #ifndef GROBNER_H_ #define GROBNER_H_ -#include"ast.h" -#include"arith_decl_plugin.h" -#include"heap.h" -#include"obj_hashtable.h" -#include"region.h" -#include"dependency.h" +#include "ast/ast.h" +#include "ast/arith_decl_plugin.h" +#include "util/heap.h" +#include "util/obj_hashtable.h" +#include "util/region.h" +#include "util/dependency.h" struct grobner_stats { diff --git a/src/math/hilbert/heap_trie.h b/src/math/hilbert/heap_trie.h index e288bb076..ace5381b8 100644 --- a/src/math/hilbert/heap_trie.h +++ b/src/math/hilbert/heap_trie.h @@ -37,11 +37,11 @@ Notes: #ifndef HEAP_TRIE_H_ #define HEAP_TRIE_H_ -#include "map.h" -#include "vector.h" -#include "buffer.h" -#include "statistics.h" -#include "small_object_allocator.h" +#include "util/map.h" +#include "util/vector.h" +#include "util/buffer.h" +#include "util/statistics.h" +#include "util/small_object_allocator.h" template diff --git a/src/math/hilbert/hilbert_basis.cpp b/src/math/hilbert/hilbert_basis.cpp index adac63e5c..9baa0beac 100644 --- a/src/math/hilbert/hilbert_basis.cpp +++ b/src/math/hilbert/hilbert_basis.cpp @@ -17,11 +17,11 @@ Revision History: --*/ -#include "hilbert_basis.h" -#include "heap.h" -#include "map.h" -#include "heap_trie.h" -#include "stopwatch.h" +#include "math/hilbert/hilbert_basis.h" +#include "util/heap.h" +#include "util/map.h" +#include "math/hilbert/heap_trie.h" +#include "util/stopwatch.h" typedef int_hashtable > int_table; diff --git a/src/math/hilbert/hilbert_basis.h b/src/math/hilbert/hilbert_basis.h index 2cfb4e36f..a0350492a 100644 --- a/src/math/hilbert/hilbert_basis.h +++ b/src/math/hilbert/hilbert_basis.h @@ -28,11 +28,11 @@ Revision History: #ifndef HILBERT_BASIS_H_ #define HILBERT_BASIS_H_ -#include "rational.h" -#include "lbool.h" -#include "statistics.h" -#include "checked_int64.h" -#include "rlimit.h" +#include "util/rational.h" +#include "util/lbool.h" +#include "util/statistics.h" +#include "util/checked_int64.h" +#include "util/rlimit.h" typedef vector rational_vector; diff --git a/src/math/interval/interval.h b/src/math/interval/interval.h index 4c0204604..db3c5a850 100644 --- a/src/math/interval/interval.h +++ b/src/math/interval/interval.h @@ -19,9 +19,9 @@ Revision History: #ifndef INTERVAL_H_ #define INTERVAL_H_ -#include"mpq.h" -#include"ext_numeral.h" -#include"rlimit.h" +#include "util/mpq.h" +#include "util/ext_numeral.h" +#include "util/rlimit.h" /** \brief Default configuration for interval manager. @@ -162,7 +162,7 @@ private: void checkpoint(); public: - interval_manager(reslimit& lim, C const & c); + interval_manager(reslimit& lim, C && c); ~interval_manager(); numeral_manager & m() const { return m_c.m(); } diff --git a/src/math/interval/interval_def.h b/src/math/interval/interval_def.h index 43bf9f91a..de3a5fa19 100644 --- a/src/math/interval/interval_def.h +++ b/src/math/interval/interval_def.h @@ -19,19 +19,19 @@ Revision History: #ifndef INTERVAL_DEF_H_ #define INTERVAL_DEF_H_ -#include"interval.h" -#include"debug.h" -#include"trace.h" -#include"scoped_numeral.h" -#include"cooperate.h" -#include"common_msgs.h" +#include "math/interval/interval.h" +#include "util/debug.h" +#include "util/trace.h" +#include "util/scoped_numeral.h" +#include "util/cooperate.h" +#include "util/common_msgs.h" #define DEFAULT_PI_PRECISION 2 // #define TRACE_NTH_ROOT template -interval_manager::interval_manager(reslimit& lim, C const & c): m_limit(lim), m_c(c) { +interval_manager::interval_manager(reslimit& lim, C && c): m_limit(lim), m_c(std::move(c)) { m().set(m_minus_one, -1); m().set(m_one, 1); m_pi_n = 0; diff --git a/src/math/interval/interval_mpq.cpp b/src/math/interval/interval_mpq.cpp index fa7cec853..7d3de6379 100644 --- a/src/math/interval/interval_mpq.cpp +++ b/src/math/interval/interval_mpq.cpp @@ -16,6 +16,6 @@ Author: Revision History: --*/ -#include"interval_def.h" +#include "math/interval/interval_def.h" template class interval_manager; diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index 986c17664..9484c3c83 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -16,17 +16,17 @@ Author: Notes: --*/ -#include"algebraic_numbers.h" -#include"upolynomial.h" -#include"mpbq.h" -#include"basic_interval.h" -#include"cooperate.h" -#include"sexpr2upolynomial.h" -#include"scoped_ptr_vector.h" -#include"mpbqi.h" -#include"timeit.h" -#include"algebraic_params.hpp" -#include"common_msgs.h" +#include "math/polynomial/algebraic_numbers.h" +#include "math/polynomial/upolynomial.h" +#include "util/mpbq.h" +#include "util/basic_interval.h" +#include "util/cooperate.h" +#include "math/polynomial/sexpr2upolynomial.h" +#include "util/scoped_ptr_vector.h" +#include "util/mpbqi.h" +#include "util/timeit.h" +#include "math/polynomial/algebraic_params.hpp" +#include "util/common_msgs.h" namespace algebraic_numbers { @@ -2632,10 +2632,14 @@ namespace algebraic_numbers { scoped_mpz neg_n(qm()); qm().set(neg_n, v.numerator()); qm().neg(neg_n); - mpz const coeffs[2] = { neg_n.get(), v.denominator() }; + unsynch_mpz_manager zmgr; + // FIXME: remove these copies + mpz coeffs[2] = { zmgr.dup(neg_n.get()), zmgr.dup(v.denominator()) }; out << "("; upm().display(out, 2, coeffs, "#"); out << ", 1)"; // first root of the polynomial d*# - n + zmgr.del(coeffs[0]); + zmgr.del(coeffs[1]); } else { algebraic_cell * c = a.to_algebraic(); @@ -2678,10 +2682,14 @@ namespace algebraic_numbers { scoped_mpz neg_n(qm()); qm().set(neg_n, v.numerator()); qm().neg(neg_n); - mpz const coeffs[2] = { neg_n.get(), v.denominator() }; + unsynch_mpz_manager zmgr; + // FIXME: remove these copies + mpz coeffs[2] = { zmgr.dup(neg_n.get()), zmgr.dup(v.denominator()) }; out << "(root-obj "; upm().display_smt2(out, 2, coeffs, "x"); out << " 1)"; // first root of the polynomial d*# - n + zmgr.del(coeffs[0]); + zmgr.del(coeffs[1]); } else { algebraic_cell * c = a.to_algebraic(); diff --git a/src/math/polynomial/algebraic_numbers.h b/src/math/polynomial/algebraic_numbers.h index e86be7752..3a8ee766b 100644 --- a/src/math/polynomial/algebraic_numbers.h +++ b/src/math/polynomial/algebraic_numbers.h @@ -19,16 +19,16 @@ Notes: #ifndef ALGEBRAIC_NUMBERS_H_ #define ALGEBRAIC_NUMBERS_H_ -#include"rational.h" -#include"mpq.h" -#include"polynomial.h" -#include"z3_exception.h" -#include"scoped_numeral.h" -#include"scoped_numeral_vector.h" -#include"tptr.h" -#include"statistics.h" -#include"params.h" -#include"rlimit.h" +#include "util/rational.h" +#include "util/mpq.h" +#include "math/polynomial/polynomial.h" +#include "util/z3_exception.h" +#include "util/scoped_numeral.h" +#include "util/scoped_numeral_vector.h" +#include "util/tptr.h" +#include "util/statistics.h" +#include "util/params.h" +#include "util/rlimit.h" class small_object_allocator; class mpbq_manager; diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index 1a4aa8304..d6d392148 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -16,24 +16,24 @@ Author: Notes: --*/ -#include"polynomial.h" -#include"vector.h" -#include"chashtable.h" -#include"small_object_allocator.h" -#include"id_gen.h" -#include"buffer.h" -#include"scoped_ptr_vector.h" -#include"cooperate.h" -#include"upolynomial_factorization.h" -#include"polynomial_primes.h" -#include"permutation.h" -#include"algebraic_numbers.h" -#include"mpzzp.h" -#include"timeit.h" -#include"linear_eq_solver.h" -#include"scoped_numeral_buffer.h" -#include"ref_buffer.h" -#include"common_msgs.h" +#include "math/polynomial/polynomial.h" +#include "util/vector.h" +#include "util/chashtable.h" +#include "util/small_object_allocator.h" +#include "util/id_gen.h" +#include "util/buffer.h" +#include "util/scoped_ptr_vector.h" +#include "util/cooperate.h" +#include "math/polynomial/upolynomial_factorization.h" +#include "math/polynomial/polynomial_primes.h" +#include "util/permutation.h" +#include "math/polynomial/algebraic_numbers.h" +#include "util/mpzzp.h" +#include "util/timeit.h" +#include "math/polynomial/linear_eq_solver.h" +#include "util/scoped_numeral_buffer.h" +#include "util/ref_buffer.h" +#include "util/common_msgs.h" namespace polynomial { @@ -3536,10 +3536,11 @@ namespace polynomial { iccp(p, max_var(p), i, c, pp); } - void pp(polynomial const * p, var x, polynomial_ref & pp) { + polynomial_ref pp(polynomial const * p, var x) { scoped_numeral i(m_manager); - polynomial_ref c(pm()); - iccp(p, x, i, c, pp); + polynomial_ref c(pm()), result(pm()); + iccp(p, x, i, c, result); + return result; } bool is_primitive(polynomial const * p, var x) { @@ -3598,7 +3599,7 @@ namespace polynomial { if (is_zero(rem)) { TRACE("polynomial", tout << "rem is zero...\npp_v: " << pp_v << "\n";); flip_sign_if_lm_neg(pp_v); - pp(pp_v, x, r); + r = pp(pp_v, x); r = mul(d_a, d_r, r); return; } @@ -3849,7 +3850,7 @@ namespace polynomial { TRACE("mgcd", tout << "new combined:\n" << C_star << "\n";); } } - pp(C_star, x, candidate); + candidate = pp(C_star, x); TRACE("mgcd", tout << "candidate:\n" << candidate << "\n";); scoped_numeral lc_candidate(m()); lc_candidate = univ_coeff(candidate, degree(candidate, x)); @@ -4821,10 +4822,9 @@ namespace polynomial { polynomial * mk_x_minus_y(var x, var y) { numeral zero(0); - numeral one(1); numeral minus_one; // It is not safe to initialize with -1 when numeral_manager is GF_2 m_manager.set(minus_one, -1); - numeral as[2] = { one, minus_one }; + numeral as[2] = { numeral(1), std::move(minus_one) }; var xs[2] = { x, y }; return mk_linear(2, as, xs, zero); } @@ -4844,8 +4844,7 @@ namespace polynomial { polynomial * mk_x_plus_y(var x, var y) { numeral zero(0); - numeral one(1); - numeral as[2] = { one, one }; + numeral as[2] = { numeral(1), numeral(1) }; var xs[2] = { x, y }; return mk_linear(2, as, xs, zero); } @@ -6619,8 +6618,8 @@ namespace polynomial { polynomial_ref cf1(pm()); m_wrapper.content(f1, x, cf1); polynomial_ref cf2(pm()); m_wrapper.content(f2, x, cf2); tout << "content(f1): " << cf1 << "\ncontent(f2): " << cf2 << "\n";); - pp(f1, x, f1); - pp(f2, x, f2); + f1 = pp(f1, x); + f2 = pp(f2, x); TRACE("factor", tout << "f1: " << f1 << "\nf2: " << f2 << "\n";); DEBUG_CODE({ polynomial_ref f1f2(pm()); @@ -7150,7 +7149,7 @@ namespace polynomial { } void manager::primitive(polynomial const * p, var x, polynomial_ref & pp) { - m_imp->pp(p, x, pp); + pp = m_imp->pp(p, x); } void manager::icpp(polynomial const * p, var x, numeral & i, polynomial_ref & c, polynomial_ref & pp) { diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index cb1880495..43b3c1138 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -19,16 +19,16 @@ Notes: #ifndef POLYNOMIAL_H_ #define POLYNOMIAL_H_ -#include"mpz.h" -#include"rational.h" -#include"obj_ref.h" -#include"ref_vector.h" -#include"z3_exception.h" -#include"scoped_numeral.h" -#include"scoped_numeral_vector.h" -#include"params.h" -#include"mpbqi.h" -#include"rlimit.h" +#include "util/mpz.h" +#include "util/rational.h" +#include "util/obj_ref.h" +#include "util/ref_vector.h" +#include "util/z3_exception.h" +#include "util/scoped_numeral.h" +#include "util/scoped_numeral_vector.h" +#include "util/params.h" +#include "util/mpbqi.h" +#include "util/rlimit.h" class small_object_allocator; @@ -63,8 +63,8 @@ namespace polynomial { public: void set_degree(var x, unsigned d) { m_var2degree.setx(x, d, 0); } unsigned degree(var x) const { return m_var2degree.get(x, 0); } - void display(std::ostream & out) const; - friend std::ostream & operator<<(std::ostream & out, var2degree const & ideal) { ideal.display(out); return out; } + void display(std::ostream & out) const; + friend std::ostream & operator<<(std::ostream & out, var2degree const & ideal) { ideal.display(out); return out; } }; template diff --git a/src/math/polynomial/polynomial_cache.cpp b/src/math/polynomial/polynomial_cache.cpp index dee0e722d..9a021ce36 100644 --- a/src/math/polynomial/polynomial_cache.cpp +++ b/src/math/polynomial/polynomial_cache.cpp @@ -16,8 +16,8 @@ Author: Notes: --*/ -#include"polynomial_cache.h" -#include"chashtable.h" +#include "math/polynomial/polynomial_cache.h" +#include "util/chashtable.h" namespace polynomial { diff --git a/src/math/polynomial/polynomial_cache.h b/src/math/polynomial/polynomial_cache.h index 538a08b5c..4ebb05b04 100644 --- a/src/math/polynomial/polynomial_cache.h +++ b/src/math/polynomial/polynomial_cache.h @@ -19,7 +19,7 @@ Notes: #ifndef POLYNOMIAL_CACHE_H_ #define POLYNOMIAL_CACHE_H_ -#include"polynomial.h" +#include "math/polynomial/polynomial.h" namespace polynomial { diff --git a/src/math/polynomial/polynomial_var2value.h b/src/math/polynomial/polynomial_var2value.h index 7da2e5980..c4aa16dfa 100644 --- a/src/math/polynomial/polynomial_var2value.h +++ b/src/math/polynomial/polynomial_var2value.h @@ -19,8 +19,8 @@ Notes: #ifndef POLYNOMIAL_VAR2VALUE_H_ #define POLYNOMIAL_VAR2VALUE_H_ -#include"polynomial.h" -#include"scoped_numeral_vector.h" +#include "math/polynomial/polynomial.h" +#include "util/scoped_numeral_vector.h" namespace polynomial { diff --git a/src/math/polynomial/rpolynomial.cpp b/src/math/polynomial/rpolynomial.cpp index 03cfac8c8..5e7a829f6 100644 --- a/src/math/polynomial/rpolynomial.cpp +++ b/src/math/polynomial/rpolynomial.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"rpolynomial.h" -#include"tptr.h" -#include"buffer.h" +#include "math/polynomial/rpolynomial.h" +#include "util/tptr.h" +#include "util/buffer.h" namespace rpolynomial { diff --git a/src/math/polynomial/rpolynomial.h b/src/math/polynomial/rpolynomial.h index b84dcca95..f2ba78894 100644 --- a/src/math/polynomial/rpolynomial.h +++ b/src/math/polynomial/rpolynomial.h @@ -19,12 +19,12 @@ Notes: #ifndef RPOLYNOMIAL_H_ #define RPOLYNOMIAL_H_ -#include"mpz.h" -#include"rational.h" -#include"obj_ref.h" -#include"ref_vector.h" -#include"z3_exception.h" -#include"polynomial.h" +#include "util/mpz.h" +#include "util/rational.h" +#include "util/obj_ref.h" +#include "util/ref_vector.h" +#include "util/z3_exception.h" +#include "math/polynomial/polynomial.h" namespace rpolynomial { diff --git a/src/math/polynomial/sexpr2upolynomial.cpp b/src/math/polynomial/sexpr2upolynomial.cpp index ea3de77da..790fefeb8 100644 --- a/src/math/polynomial/sexpr2upolynomial.cpp +++ b/src/math/polynomial/sexpr2upolynomial.cpp @@ -16,8 +16,8 @@ Author: Notes: --*/ -#include"sexpr2upolynomial.h" -#include"sexpr.h" +#include "math/polynomial/sexpr2upolynomial.h" +#include "util/sexpr.h" sexpr2upolynomial_exception::sexpr2upolynomial_exception(char const * msg, sexpr const * s): cmd_exception(msg, s->get_line(), s->get_pos()) { diff --git a/src/math/polynomial/sexpr2upolynomial.h b/src/math/polynomial/sexpr2upolynomial.h index 64488b0f4..0b849ad36 100644 --- a/src/math/polynomial/sexpr2upolynomial.h +++ b/src/math/polynomial/sexpr2upolynomial.h @@ -19,8 +19,8 @@ Notes: #ifndef SEXPR2UPOLYNOMIAL_H_ #define SEXPR2UPOLYNOMIAL_H_ -#include"upolynomial.h" -#include"cmd_context_types.h" +#include "math/polynomial/upolynomial.h" +#include "util/cmd_context_types.h" class sexpr; class sexpr2upolynomial_exception : public cmd_exception { diff --git a/src/math/polynomial/upolynomial.cpp b/src/math/polynomial/upolynomial.cpp index aa26ccf4c..fe890b040 100644 --- a/src/math/polynomial/upolynomial.cpp +++ b/src/math/polynomial/upolynomial.cpp @@ -21,12 +21,12 @@ Author: Notes: --*/ -#include"upolynomial.h" -#include"upolynomial_factorization.h" -#include"polynomial_primes.h" -#include"buffer.h" -#include"cooperate.h" -#include"common_msgs.h" +#include "math/polynomial/upolynomial.h" +#include "math/polynomial/upolynomial_factorization.h" +#include "math/polynomial/polynomial_primes.h" +#include "util/buffer.h" +#include "util/cooperate.h" +#include "util/common_msgs.h" namespace upolynomial { diff --git a/src/math/polynomial/upolynomial.h b/src/math/polynomial/upolynomial.h index 789759dc6..f8efae465 100644 --- a/src/math/polynomial/upolynomial.h +++ b/src/math/polynomial/upolynomial.h @@ -24,12 +24,12 @@ Notes: #ifndef UPOLYNOMIAL_H_ #define UPOLYNOMIAL_H_ -#include"mpzzp.h" -#include"rational.h" -#include"polynomial.h" -#include"z3_exception.h" -#include"mpbq.h" -#include"rlimit.h" +#include "util/mpzzp.h" +#include "util/rational.h" +#include "math/polynomial/polynomial.h" +#include "util/z3_exception.h" +#include "util/mpbq.h" +#include "util/rlimit.h" #define FACTOR_VERBOSE_LVL 1000 namespace upolynomial { @@ -434,11 +434,11 @@ namespace upolynomial { m().reset(r[i]); } for (unsigned i = 0; i < sz; i++) { - typename polynomial::monomial * mon = pm.get_monomial(p, i); - if (pm.size(mon) == 0) { + typename polynomial::monomial * mon = pm.get_monomial(p, i); + if (pm.size(mon) == 0) { m().set(r[0], pm.coeff(p, i)); - } else if (pm.size(mon) == 1 && pm.get_var(mon, 0) == x) { - unsigned m_deg_x = pm.degree(mon, 0); + } else if (pm.size(mon) == 1 && pm.get_var(mon, 0) == x) { + unsigned m_deg_x = pm.degree(mon, 0); m().set(r[m_deg_x], pm.coeff(p, i)); } } diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp index 5a7aefa18..11a37648a 100644 --- a/src/math/polynomial/upolynomial_factorization.cpp +++ b/src/math/polynomial/upolynomial_factorization.cpp @@ -22,10 +22,10 @@ Notes: [3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993. --*/ -#include"trace.h" -#include"util.h" -#include"upolynomial_factorization_int.h" -#include"prime_generator.h" +#include "util/trace.h" +#include "util/util.h" +#include "math/polynomial/upolynomial_factorization_int.h" +#include "util/prime_generator.h" using namespace std; diff --git a/src/math/polynomial/upolynomial_factorization.h b/src/math/polynomial/upolynomial_factorization.h index ba184d613..6fe0f2be6 100644 --- a/src/math/polynomial/upolynomial_factorization.h +++ b/src/math/polynomial/upolynomial_factorization.h @@ -25,10 +25,10 @@ Notes: #ifndef UPOLYNOMIAL_FACTORIZATION_H_ #define UPOLYNOMIAL_FACTORIZATION_H_ -#include"upolynomial.h" -#include"polynomial.h" -#include"bit_vector.h" -#include"z3_exception.h" +#include "math/polynomial/upolynomial.h" +#include "math/polynomial/polynomial.h" +#include "util/bit_vector.h" +#include "util/z3_exception.h" namespace upolynomial { typedef manager::scoped_numeral scoped_numeral; diff --git a/src/math/polynomial/upolynomial_factorization_int.h b/src/math/polynomial/upolynomial_factorization_int.h index 86fe52b03..ea2b51d8f 100644 --- a/src/math/polynomial/upolynomial_factorization_int.h +++ b/src/math/polynomial/upolynomial_factorization_int.h @@ -26,7 +26,7 @@ Notes: #ifndef UPOLYNOMIAL_FACTORIZATION_INT_H_ #define UPOLYNOMIAL_FACTORIZATION_INT_H_ -#include"upolynomial_factorization.h" +#include "math/polynomial/upolynomial_factorization.h" namespace upolynomial { // copy p from some manager to zp_p in Z_p[x] @@ -45,7 +45,7 @@ namespace upolynomial { for (unsigned i = 0; i < p.size(); ++ i) { numeral p_i; // no need to delete, we keep it pushed in zp_p zp_nm.set(p_i, p[i]); - zp_p.push_back(p_i); + zp_p.push_back(std::move(p_i)); } zp_upm.trim(zp_p); } diff --git a/src/math/realclosure/mpz_matrix.cpp b/src/math/realclosure/mpz_matrix.cpp index 799a5817e..62a328b8d 100644 --- a/src/math/realclosure/mpz_matrix.cpp +++ b/src/math/realclosure/mpz_matrix.cpp @@ -28,8 +28,8 @@ Author: Notes: --*/ -#include"mpz_matrix.h" -#include"buffer.h" +#include "math/realclosure/mpz_matrix.h" +#include "util/buffer.h" mpz_matrix_manager::mpz_matrix_manager(unsynch_mpz_manager & nm, small_object_allocator & a): m_nm(nm), diff --git a/src/math/realclosure/mpz_matrix.h b/src/math/realclosure/mpz_matrix.h index bd9c1bd45..f5d7358da 100644 --- a/src/math/realclosure/mpz_matrix.h +++ b/src/math/realclosure/mpz_matrix.h @@ -31,7 +31,7 @@ Notes: #ifndef MPZ_MATRIX_H_ #define MPZ_MATRIX_H_ -#include"mpz.h" +#include "util/mpz.h" /** \brief A mxn matrix. diff --git a/src/math/realclosure/realclosure.cpp b/src/math/realclosure/realclosure.cpp index 0268470f7..8f2d933e2 100644 --- a/src/math/realclosure/realclosure.cpp +++ b/src/math/realclosure/realclosure.cpp @@ -19,17 +19,17 @@ Author: Notes: --*/ -#include"realclosure.h" -#include"rcf_params.hpp" -#include"array.h" -#include"mpbq.h" -#include"mpz_matrix.h" -#include"interval_def.h" -#include"obj_ref.h" -#include"ref_vector.h" -#include"ref_buffer.h" -#include"cooperate.h" -#include"common_msgs.h" +#include "math/realclosure/realclosure.h" +#include "math/realclosure/rcf_params.hpp" +#include "util/array.h" +#include "util/mpbq.h" +#include "math/realclosure/mpz_matrix.h" +#include "math/interval/interval_def.h" +#include "util/obj_ref.h" +#include "util/ref_vector.h" +#include "util/ref_buffer.h" +#include "util/cooperate.h" +#include "util/common_msgs.h" #ifndef REALCLOSURE_INI_BUFFER_SIZE #define REALCLOSURE_INI_BUFFER_SIZE 32 diff --git a/src/math/realclosure/realclosure.h b/src/math/realclosure/realclosure.h index 10d35f58d..c18f626a3 100644 --- a/src/math/realclosure/realclosure.h +++ b/src/math/realclosure/realclosure.h @@ -22,13 +22,13 @@ Notes: #ifndef REALCLOSURE_H_ #define REALCLOSURE_H_ -#include"mpq.h" -#include"params.h" -#include"scoped_numeral.h" -#include"scoped_numeral_vector.h" -#include"interval.h" -#include"z3_exception.h" -#include"rlimit.h" +#include "util/mpq.h" +#include "util/params.h" +#include "util/scoped_numeral.h" +#include "util/scoped_numeral_vector.h" +#include "math/interval/interval.h" +#include "util/z3_exception.h" +#include "util/rlimit.h" namespace realclosure { class num; diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index c31eabb62..f12918bfe 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -18,8 +18,9 @@ Revision History: --*/ -#include "model_based_opt.h" -#include "uint_set.h" +#include "math/simplex/model_based_opt.h" +#include "util/uint_set.h" +#include "util/z3_exception.h" std::ostream& operator<<(std::ostream& out, opt::ineq_type ie) { switch (ie) { @@ -868,6 +869,9 @@ namespace opt { for (unsigned i = 0; i < mod_rows.size(); ++i) { D = lcm(D, m_rows[mod_rows[i]].m_mod); } + if (D.is_zero()) { + throw default_exception("modulo 0 is not defined"); + } TRACE("opt", display(tout << "lcm: " << D << " tableau\n");); rational val_x = m_var2value[x]; rational u = mod(val_x, D); @@ -954,7 +958,8 @@ namespace opt { row& r1 = m_rows[row_id1]; vector coeffs; mk_coeffs_without(coeffs, r1.m_vars, x); - add_divides(coeffs, r1.m_coeff, abs(a)); + rational c = r1.m_coeff; + add_divides(coeffs, c, abs(a)); } unsigned_vector const& row_ids = m_var2row_ids[x]; uint_set visited; diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index eb0bc2570..54360d0ac 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -21,9 +21,9 @@ Revision History: #ifndef __MODEL_BASED_OPT_H__ #define __MODEL_BASED_OPT_H__ -#include "util.h" -#include "rational.h" -#include"inf_eps_rational.h" +#include "util/util.h" +#include "util/rational.h" +#include "util/inf_eps_rational.h" namespace opt { diff --git a/src/math/simplex/network_flow.h b/src/math/simplex/network_flow.h index 13aff5089..d4c7df77f 100644 --- a/src/math/simplex/network_flow.h +++ b/src/math/simplex/network_flow.h @@ -28,9 +28,9 @@ Notes: #ifndef NETWORK_FLOW_H_ #define NETWORK_FLOW_H_ -#include"inf_rational.h" -#include"diff_logic.h" -#include"spanning_tree.h" +#include "util/inf_rational.h" +#include "smt/diff_logic.h" +#include "smt/spanning_tree.h" namespace smt { diff --git a/src/math/simplex/network_flow_def.h b/src/math/simplex/network_flow_def.h index a4a6246ce..4a7d00a23 100644 --- a/src/math/simplex/network_flow_def.h +++ b/src/math/simplex/network_flow_def.h @@ -20,9 +20,9 @@ Notes: #ifndef NETWORK_FLOW_DEF_H_ #define NETWORK_FLOW_DEF_H_ -#include"network_flow.h" -#include"uint_set.h" -#include"spanning_tree_def.h" +#include "math/simplex/network_flow.h" +#include "util/uint_set.h" +#include "smt/spanning_tree_def.h" namespace smt { diff --git a/src/math/simplex/simplex.cpp b/src/math/simplex/simplex.cpp index 494c0b6bb..42bb46eef 100644 --- a/src/math/simplex/simplex.cpp +++ b/src/math/simplex/simplex.cpp @@ -17,9 +17,9 @@ Notes: --*/ -#include"simplex.h" -#include"sparse_matrix_def.h" -#include"simplex_def.h" +#include "math/simplex/simplex.h" +#include "math/simplex/sparse_matrix_def.h" +#include "math/simplex/simplex_def.h" namespace simplex { template class simplex; template class simplex; diff --git a/src/math/simplex/simplex.h b/src/math/simplex/simplex.h index 277179507..5c412e356 100644 --- a/src/math/simplex/simplex.h +++ b/src/math/simplex/simplex.h @@ -32,11 +32,11 @@ Notes: #ifndef SIMPLEX_H_ #define SIMPLEX_H_ -#include "sparse_matrix.h" -#include "mpq_inf.h" -#include "heap.h" -#include "lbool.h" -#include "uint_set.h" +#include "math/simplex/sparse_matrix.h" +#include "util/mpq_inf.h" +#include "util/heap.h" +#include "util/lbool.h" +#include "util/uint_set.h" namespace simplex { diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index 803d27fde..4edbb2b9d 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -19,8 +19,8 @@ Notes: #ifndef SPARSE_MATRIX_H_ #define SPARSE_MATRIX_H_ -#include "mpq_inf.h" -#include "statistics.h" +#include "util/mpq_inf.h" +#include "util/statistics.h" namespace simplex { @@ -35,7 +35,7 @@ namespace simplex { struct row_entry { numeral m_coeff; var_t m_var; - row_entry(numeral const& c, var_t v): m_coeff(c), m_var(v) {} + row_entry(numeral && c, var_t v) : m_coeff(std::move(c)), m_var(v) {} }; private: @@ -61,7 +61,7 @@ namespace simplex { int m_col_idx; int m_next_free_row_entry_idx; }; - _row_entry(numeral const & c, var_t v): row_entry(c, v), m_col_idx(0) {} + _row_entry(numeral && c, var_t v) : row_entry(std::move(c), v), m_col_idx(0) {} _row_entry() : row_entry(numeral(), dead_id), m_col_idx(0) {} bool is_dead() const { return row_entry::m_var == dead_id; } }; diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index b050e45e1..be18a8702 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -21,8 +21,8 @@ Notes: #ifndef SPARSE_MATRIX_DEF_H_ #define SPARSE_MATRIX_DEF_H_ -#include "sparse_matrix.h" -#include "uint_set.h" +#include "math/simplex/sparse_matrix.h" +#include "util/uint_set.h" namespace simplex { diff --git a/src/math/subpaving/subpaving.cpp b/src/math/subpaving/subpaving.cpp index 8aa394abe..96fc5b6d7 100644 --- a/src/math/subpaving/subpaving.cpp +++ b/src/math/subpaving/subpaving.cpp @@ -22,13 +22,13 @@ Author: Revision History: --*/ -#include"subpaving.h" -#include"subpaving_types.h" -#include"subpaving_mpq.h" -#include"subpaving_mpf.h" -#include"subpaving_hwf.h" -#include"subpaving_mpff.h" -#include"subpaving_mpfx.h" +#include "math/subpaving/subpaving.h" +#include "math/subpaving/subpaving_types.h" +#include "math/subpaving/subpaving_mpq.h" +#include "math/subpaving/subpaving_mpf.h" +#include "math/subpaving/subpaving_hwf.h" +#include "math/subpaving/subpaving_mpff.h" +#include "math/subpaving/subpaving_mpfx.h" namespace subpaving { diff --git a/src/math/subpaving/subpaving.h b/src/math/subpaving/subpaving.h index c6daca5cc..2c2c9978f 100644 --- a/src/math/subpaving/subpaving.h +++ b/src/math/subpaving/subpaving.h @@ -25,10 +25,10 @@ Revision History: #ifndef SUBPAVING_H_ #define SUBPAVING_H_ -#include"mpq.h" -#include"subpaving_types.h" -#include"params.h" -#include"statistics.h" +#include "util/mpq.h" +#include "math/subpaving/subpaving_types.h" +#include "util/params.h" +#include "util/statistics.h" template class f2n; class mpf_manager; diff --git a/src/math/subpaving/subpaving_hwf.cpp b/src/math/subpaving/subpaving_hwf.cpp index 142db72f6..7279a6273 100644 --- a/src/math/subpaving/subpaving_hwf.cpp +++ b/src/math/subpaving/subpaving_hwf.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"subpaving_hwf.h" -#include"subpaving_t_def.h" +#include "math/subpaving/subpaving_hwf.h" +#include "math/subpaving/subpaving_t_def.h" // force template instantiation template class subpaving::context_t; diff --git a/src/math/subpaving/subpaving_hwf.h b/src/math/subpaving/subpaving_hwf.h index f57035b01..52594e050 100644 --- a/src/math/subpaving/subpaving_hwf.h +++ b/src/math/subpaving/subpaving_hwf.h @@ -19,9 +19,9 @@ Revision History: #ifndef SUBPAVING_HWF_H_ #define SUBPAVING_HWF_H_ -#include"subpaving_t.h" -#include"f2n.h" -#include"hwf.h" +#include "math/subpaving/subpaving_t.h" +#include "util/f2n.h" +#include "util/hwf.h" namespace subpaving { diff --git a/src/math/subpaving/subpaving_mpf.cpp b/src/math/subpaving/subpaving_mpf.cpp index 96ada040b..ef8b5903c 100644 --- a/src/math/subpaving/subpaving_mpf.cpp +++ b/src/math/subpaving/subpaving_mpf.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"subpaving_mpf.h" -#include"subpaving_t_def.h" +#include "math/subpaving/subpaving_mpf.h" +#include "math/subpaving/subpaving_t_def.h" // force template instantiation template class subpaving::context_t; diff --git a/src/math/subpaving/subpaving_mpf.h b/src/math/subpaving/subpaving_mpf.h index 16e4b38cc..8e0d4cfc7 100644 --- a/src/math/subpaving/subpaving_mpf.h +++ b/src/math/subpaving/subpaving_mpf.h @@ -19,9 +19,9 @@ Revision History: #ifndef SUBPAVING_MPF_H_ #define SUBPAVING_MPF_H_ -#include"subpaving_t.h" -#include"mpf.h" -#include"f2n.h" +#include "math/subpaving/subpaving_t.h" +#include "util/mpf.h" +#include "util/f2n.h" namespace subpaving { diff --git a/src/math/subpaving/subpaving_mpff.cpp b/src/math/subpaving/subpaving_mpff.cpp index f5be655ba..18dcd4e6e 100644 --- a/src/math/subpaving/subpaving_mpff.cpp +++ b/src/math/subpaving/subpaving_mpff.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"subpaving_mpff.h" -#include"subpaving_t_def.h" +#include "math/subpaving/subpaving_mpff.h" +#include "math/subpaving/subpaving_t_def.h" // force template instantiation template class subpaving::context_t; diff --git a/src/math/subpaving/subpaving_mpff.h b/src/math/subpaving/subpaving_mpff.h index c0ddb019d..8e5c7f3ea 100644 --- a/src/math/subpaving/subpaving_mpff.h +++ b/src/math/subpaving/subpaving_mpff.h @@ -19,8 +19,8 @@ Revision History: #ifndef SUBPAVING_MPFF_H_ #define SUBPAVING_MPFF_H_ -#include"subpaving_t.h" -#include"mpff.h" +#include "math/subpaving/subpaving_t.h" +#include "util/mpff.h" namespace subpaving { diff --git a/src/math/subpaving/subpaving_mpfx.cpp b/src/math/subpaving/subpaving_mpfx.cpp index b8a1e048f..23902dce3 100644 --- a/src/math/subpaving/subpaving_mpfx.cpp +++ b/src/math/subpaving/subpaving_mpfx.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"subpaving_mpfx.h" -#include"subpaving_t_def.h" +#include "math/subpaving/subpaving_mpfx.h" +#include "math/subpaving/subpaving_t_def.h" // force template instantiation template class subpaving::context_t; diff --git a/src/math/subpaving/subpaving_mpfx.h b/src/math/subpaving/subpaving_mpfx.h index 6213df1e5..5802b1abf 100644 --- a/src/math/subpaving/subpaving_mpfx.h +++ b/src/math/subpaving/subpaving_mpfx.h @@ -19,8 +19,8 @@ Revision History: #ifndef SUBPAVING_MPFX_H_ #define SUBPAVING_MPFX_H_ -#include"subpaving_t.h" -#include"mpfx.h" +#include "math/subpaving/subpaving_t.h" +#include "util/mpfx.h" namespace subpaving { diff --git a/src/math/subpaving/subpaving_mpq.cpp b/src/math/subpaving/subpaving_mpq.cpp index b7b76a5e3..77b1405a7 100644 --- a/src/math/subpaving/subpaving_mpq.cpp +++ b/src/math/subpaving/subpaving_mpq.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"subpaving_mpq.h" -#include"subpaving_t_def.h" +#include "math/subpaving/subpaving_mpq.h" +#include "math/subpaving/subpaving_t_def.h" // force template instantiation template class subpaving::context_t; diff --git a/src/math/subpaving/subpaving_mpq.h b/src/math/subpaving/subpaving_mpq.h index 04bcd6059..b08eb9ccd 100644 --- a/src/math/subpaving/subpaving_mpq.h +++ b/src/math/subpaving/subpaving_mpq.h @@ -19,8 +19,8 @@ Revision History: #ifndef SUBPAVING_MPQ_H_ #define SUBPAVING_MPQ_H_ -#include"subpaving_t.h" -#include"mpq.h" +#include "math/subpaving/subpaving_t.h" +#include "util/mpq.h" namespace subpaving { diff --git a/src/math/subpaving/subpaving_t.h b/src/math/subpaving/subpaving_t.h index ccef1a318..a4bc02ff6 100644 --- a/src/math/subpaving/subpaving_t.h +++ b/src/math/subpaving/subpaving_t.h @@ -20,18 +20,18 @@ Revision History: #define SUBPAVING_T_H_ #include -#include"tptr.h" -#include"small_object_allocator.h" -#include"chashtable.h" -#include"parray.h" -#include"interval.h" -#include"scoped_numeral_vector.h" -#include"subpaving_types.h" -#include"params.h" -#include"statistics.h" -#include"lbool.h" -#include"id_gen.h" -#include"rlimit.h" +#include "util/tptr.h" +#include "util/small_object_allocator.h" +#include "util/chashtable.h" +#include "util/parray.h" +#include "math/interval/interval.h" +#include "util/scoped_numeral_vector.h" +#include "math/subpaving/subpaving_types.h" +#include "util/params.h" +#include "util/statistics.h" +#include "util/lbool.h" +#include "util/id_gen.h" +#include "util/rlimit.h" #ifdef _MSC_VER #pragma warning(disable : 4200) #pragma warning(disable : 4355) diff --git a/src/math/subpaving/subpaving_t_def.h b/src/math/subpaving/subpaving_t_def.h index 6ae7d97b1..3574787d8 100644 --- a/src/math/subpaving/subpaving_t_def.h +++ b/src/math/subpaving/subpaving_t_def.h @@ -16,12 +16,12 @@ Author: Revision History: --*/ -#include"subpaving_t.h" -#include"interval_def.h" -#include"buffer.h" -#include"cooperate.h" -#include"z3_exception.h" -#include"common_msgs.h" +#include "math/subpaving/subpaving_t.h" +#include "math/interval/interval_def.h" +#include "util/buffer.h" +#include "util/cooperate.h" +#include "util/z3_exception.h" +#include "util/common_msgs.h" namespace subpaving { @@ -739,7 +739,7 @@ void context_t::del_sum(polynomial * p) { template var context_t::mk_sum(numeral const & c, unsigned sz, numeral const * as, var const * xs) { - m_num_buffer.reserve(num_vars(), numeral()); + m_num_buffer.reserve(num_vars()); for (unsigned i = 0; i < sz; i++) { SASSERT(xs[i] < num_vars()); nm().set(m_num_buffer[xs[i]], as[i]); diff --git a/src/math/subpaving/tactic/expr2subpaving.cpp b/src/math/subpaving/tactic/expr2subpaving.cpp index 267a04b9a..b00c0007f 100644 --- a/src/math/subpaving/tactic/expr2subpaving.cpp +++ b/src/math/subpaving/tactic/expr2subpaving.cpp @@ -17,14 +17,14 @@ Author: Notes: --*/ -#include"expr2subpaving.h" -#include"expr2var.h" -#include"ref_util.h" -#include"z3_exception.h" -#include"cooperate.h" -#include"arith_decl_plugin.h" -#include"scoped_numeral_buffer.h" -#include"common_msgs.h" +#include "math/subpaving/tactic/expr2subpaving.h" +#include "ast/expr2var.h" +#include "util/ref_util.h" +#include "util/z3_exception.h" +#include "util/cooperate.h" +#include "ast/arith_decl_plugin.h" +#include "util/scoped_numeral_buffer.h" +#include "util/common_msgs.h" struct expr2subpaving::imp { struct frame { diff --git a/src/math/subpaving/tactic/expr2subpaving.h b/src/math/subpaving/tactic/expr2subpaving.h index 8e6e69332..d95699759 100644 --- a/src/math/subpaving/tactic/expr2subpaving.h +++ b/src/math/subpaving/tactic/expr2subpaving.h @@ -20,8 +20,8 @@ Notes: #ifndef EXPR2SUBPAVING_H_ #define EXPR2SUBPAVING_H_ -#include"ast.h" -#include"subpaving.h" +#include "ast/ast.h" +#include "math/subpaving/subpaving.h" class expr2var; diff --git a/src/math/subpaving/tactic/subpaving_tactic.cpp b/src/math/subpaving/tactic/subpaving_tactic.cpp index 2d0199223..6a7bc11e8 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.cpp +++ b/src/math/subpaving/tactic/subpaving_tactic.cpp @@ -16,16 +16,16 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"expr2subpaving.h" -#include"expr2var.h" -#include"arith_decl_plugin.h" -#include"ast_smt2_pp.h" -#include"hwf.h" -#include"mpff.h" -#include"mpfx.h" -#include"f2n.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "math/subpaving/tactic/expr2subpaving.h" +#include "ast/expr2var.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_smt2_pp.h" +#include "util/hwf.h" +#include "util/mpff.h" +#include "util/mpfx.h" +#include "util/f2n.h" class subpaving_tactic : public tactic { diff --git a/src/math/subpaving/tactic/subpaving_tactic.h b/src/math/subpaving/tactic/subpaving_tactic.h index 30a72b888..208f762de 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.h +++ b/src/math/subpaving/tactic/subpaving_tactic.h @@ -19,7 +19,7 @@ Revision History: #ifndef SUBPAVING_TACTIC_H_ #define SUBPAVING_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/model/func_interp.cpp b/src/model/func_interp.cpp index 01e160eb0..e458cc4b0 100644 --- a/src/model/func_interp.cpp +++ b/src/model/func_interp.cpp @@ -15,11 +15,11 @@ Author: Revision History: --*/ -#include"func_interp.h" -#include"var_subst.h" -#include"obj_hashtable.h" -#include"ast_pp.h" -#include"ast_smt2_pp.h" +#include "model/func_interp.h" +#include "ast/rewriter/var_subst.h" +#include "util/obj_hashtable.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt2_pp.h" func_entry::func_entry(ast_manager & m, unsigned arity, expr * const * args, expr * result): m_args_are_values(true), @@ -117,7 +117,7 @@ bool func_interp::is_fi_entry_expr(expr * e, ptr_vector & args) { (m_arity > 1 && (!m().is_and(c) || to_app(c)->get_num_args() != m_arity))) return false; - args.resize(m_arity, 0); + args.resize(m_arity); for (unsigned i = 0; i < m_arity; i++) { expr * ci = (m_arity == 1 && i == 0) ? c : to_app(c)->get_arg(i); @@ -140,7 +140,6 @@ void func_interp::set_else(expr * e) { return; reset_interp_cache(); - ptr_vector args; while (e && is_fi_entry_expr(e, args)) { TRACE("func_interp", tout << "fi entry expr: " << mk_ismt2_pp(e, m()) << std::endl;); diff --git a/src/model/func_interp.h b/src/model/func_interp.h index d0d61546e..47eb0e82c 100644 --- a/src/model/func_interp.h +++ b/src/model/func_interp.h @@ -30,8 +30,8 @@ Revision History: #ifndef FUNC_INTERP_H_ #define FUNC_INTERP_H_ -#include"ast.h" -#include"ast_translation.h" +#include "ast/ast.h" +#include "ast/ast_translation.h" class func_interp; diff --git a/src/model/model.cpp b/src/model/model.cpp index 951c7f744..7ac1300de 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -16,14 +16,14 @@ Author: Revision History: --*/ -#include"model.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"var_subst.h" -#include"array_decl_plugin.h" -#include"well_sorted.h" -#include"used_symbols.h" -#include"model_evaluator.h" +#include "model/model.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/rewriter/var_subst.h" +#include "ast/array_decl_plugin.h" +#include "ast/well_sorted.h" +#include "ast/used_symbols.h" +#include "model/model_evaluator.h" model::model(ast_manager & m): model_core(m) { diff --git a/src/model/model.h b/src/model/model.h index 338b6ad74..f6de8ce0e 100644 --- a/src/model/model.h +++ b/src/model/model.h @@ -19,9 +19,9 @@ Revision History: #ifndef MODEL_H_ #define MODEL_H_ -#include"model_core.h" -#include"ref.h" -#include"ast_translation.h" +#include "model/model_core.h" +#include "util/ref.h" +#include "ast/ast_translation.h" class model : public model_core { protected: diff --git a/src/model/model2expr.cpp b/src/model/model2expr.cpp index 05aea6ee7..990f9df0f 100644 --- a/src/model/model2expr.cpp +++ b/src/model/model2expr.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include "model2expr.h" -#include "for_each_ast.h" -#include "bool_rewriter.h" -#include "var_subst.h" +#include "model/model2expr.h" +#include "ast/for_each_ast.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/var_subst.h" struct for_each_symbol_proc { symbol_set& m_symbols; diff --git a/src/model/model2expr.h b/src/model/model2expr.h index 272ba20b6..d55e31bba 100644 --- a/src/model/model2expr.h +++ b/src/model/model2expr.h @@ -19,7 +19,7 @@ Revision History: #ifndef MODEL2EXPR_H_ #define MODEL2EXPR_H_ -#include"model.h" +#include "model/model.h" void model2expr(model& m, expr_ref& result); diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index 503abac2f..833c254c3 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -16,21 +16,17 @@ Author: Revision History: --*/ -#include"model_core.h" +#include "model/model_core.h" model_core::~model_core() { - decl2expr::iterator it1 = m_interp.begin(); - decl2expr::iterator end1 = m_interp.end(); - for (; it1 != end1; ++it1) { - m_manager.dec_ref(it1->m_key); - m_manager.dec_ref(it1->m_value); + for (auto & kv : m_interp) { + m_manager.dec_ref(kv.m_key); + m_manager.dec_ref(kv.m_value); } - decl2finterp::iterator it2 = m_finterp.begin(); - decl2finterp::iterator end2 = m_finterp.end(); - for (; it2 != end2; ++it2) { - m_manager.dec_ref(it2->m_key); - dealloc(it2->m_value); + for (auto & kv : m_finterp) { + m_manager.dec_ref(kv.m_key); + dealloc(kv.m_value); } } @@ -90,18 +86,22 @@ void model_core::register_decl(func_decl * d, func_interp * fi) { void model_core::unregister_decl(func_decl * d) { decl2expr::obj_map_entry * ec = m_interp.find_core(d); if (ec && ec->get_data().m_value != 0) { - m_manager.dec_ref(ec->get_data().m_key); - m_manager.dec_ref(ec->get_data().m_value); + auto k = ec->get_data().m_key; + auto v = ec->get_data().m_value; m_interp.remove(d); m_const_decls.erase(d); - return; + m_manager.dec_ref(k); + m_manager.dec_ref(v); + return; } - + decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); if (ef && ef->get_data().m_value != 0) { - m_manager.dec_ref(ef->get_data().m_key); - dealloc(ef->get_data().m_value); + auto k = ef->get_data().m_key; + auto v = ef->get_data().m_value; m_finterp.remove(d); m_func_decls.erase(d); + m_manager.dec_ref(k); + dealloc(v); } } diff --git a/src/model/model_core.h b/src/model/model_core.h index c42451c5a..ec128c796 100644 --- a/src/model/model_core.h +++ b/src/model/model_core.h @@ -19,9 +19,9 @@ Revision History: #ifndef MODEL_CORE_H_ #define MODEL_CORE_H_ -#include"ast.h" -#include"obj_hashtable.h" -#include"func_interp.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "model/func_interp.h" class model_core { protected: diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 805ed8e5d..32ed1e236 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -16,26 +16,28 @@ Author: Revision History: --*/ -#include"model.h" -#include"model_evaluator_params.hpp" -#include"rewriter_types.h" -#include"model_evaluator.h" -#include"bool_rewriter.h" -#include"arith_rewriter.h" -#include"bv_rewriter.h" -#include"pb_rewriter.h" -#include"seq_rewriter.h" -#include"datatype_rewriter.h" -#include"array_rewriter.h" -#include"fpa_rewriter.h" -#include"rewriter_def.h" -#include"cooperate.h" -#include"ast_pp.h" -#include"ast_util.h" -#include"model_smt2_pp.h" +#include "model/model.h" +#include "model/model_evaluator_params.hpp" +#include "ast/rewriter/rewriter_types.h" +#include "model/model_evaluator.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/arith_rewriter.h" +#include "ast/rewriter/bv_rewriter.h" +#include "ast/rewriter/pb_rewriter.h" +#include "ast/rewriter/seq_rewriter.h" +#include "ast/rewriter/datatype_rewriter.h" +#include "ast/rewriter/array_rewriter.h" +#include "ast/rewriter/fpa_rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "util/cooperate.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "model/model_smt2_pp.h" +#include "ast/rewriter/var_subst.h" struct evaluator_cfg : public default_rewriter_cfg { + ast_manager & m; model_core & m_model; bool_rewriter m_b_rw; arith_rewriter m_a_rw; @@ -53,6 +55,7 @@ struct evaluator_cfg : public default_rewriter_cfg { bool m_array_equalities; evaluator_cfg(ast_manager & m, model_core & md, params_ref const & p): + m(m), m_model(md), m_b_rw(m), // We must allow customers to set parameters for arithmetic rewriter/evaluator. @@ -74,6 +77,7 @@ struct evaluator_cfg : public default_rewriter_cfg { m_ar_rw.set_expand_select_store(true); m_ar_rw.set_expand_select_ite(true); updt_params(p); + //add_unspecified_function_models(md); } void updt_params(params_ref const & _p) { @@ -85,10 +89,8 @@ struct evaluator_cfg : public default_rewriter_cfg { m_array_equalities = p.array_equalities(); } - ast_manager & m() const { return m_model.get_manager(); } - - bool evaluate(func_decl* f, unsigned num, expr * const * args, expr_ref & result) { - func_interp* fi = m_model.get_func_interp(f); + bool evaluate(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + func_interp * fi = m_model.get_func_interp(f); return (fi != 0) && eval_fi(fi, num, args, result); } @@ -101,9 +103,8 @@ struct evaluator_cfg : public default_rewriter_cfg { bool actuals_are_values = true; - for (unsigned i = 0; actuals_are_values && i < num; i++) { - actuals_are_values = m().is_value(args[i]); - } + for (unsigned i = 0; actuals_are_values && i < num; i++) + actuals_are_values = m.is_value(args[i]); if (!actuals_are_values) return false; // let get_macro handle it @@ -120,7 +121,7 @@ struct evaluator_cfg : public default_rewriter_cfg { br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { result_pr = 0; family_id fid = f->get_family_id(); - bool is_uninterp = fid != null_family_id && m().get_plugin(fid)->is_considered_uninterpreted(f); + bool is_uninterp = fid != null_family_id && m.get_plugin(fid)->is_considered_uninterpreted(f); if (num == 0 && (fid == null_family_id || is_uninterp)) { expr * val = m_model.get_const_interp(f); if (val != 0) { @@ -145,7 +146,7 @@ struct evaluator_cfg : public default_rewriter_cfg { if (k == OP_EQ) { // theory dispatch for = SASSERT(num == 2); - family_id s_fid = m().get_sort(args[0])->get_family_id(); + family_id s_fid = m.get_sort(args[0])->get_family_id(); if (s_fid == m_a_rw.get_fid()) st = m_a_rw.mk_eq_core(args[0], args[1], result); else if (s_fid == m_bv_rw.get_fid()) @@ -178,16 +179,18 @@ struct evaluator_cfg : public default_rewriter_cfg { st = m_f_rw.mk_app_core(f, num, args, result); else if (fid == m_seq_rw.get_fid()) st = m_seq_rw.mk_app_core(f, num, args, result); - else if (fid == m().get_label_family_id() && num == 1) { + else if (fid == m.get_label_family_id() && num == 1) { result = args[0]; st = BR_DONE; } else if (evaluate(f, num, args, result)) { TRACE("model_evaluator", tout << "reduce_app " << f->get_name() << "\n"; - for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << "\n"; - tout << "---->\n" << mk_ismt2_pp(result, m()) << "\n";); + for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m) << "\n"; + tout << "---->\n" << mk_ismt2_pp(result, m) << "\n";); return BR_DONE; } + if (st == BR_FAILED && !m.is_builtin_family_id(fid)) + st = evaluate_partial_theory_func(f, num, args, result, result_pr); if (st == BR_DONE && is_app(result)) { app* a = to_app(result); if (evaluate(a->get_decl(), a->get_num_args(), a->get_args(), result)) { @@ -200,14 +203,14 @@ struct evaluator_cfg : public default_rewriter_cfg { void expand_value(expr_ref& val) { vector stores; - expr_ref else_case(m()); + expr_ref else_case(m); bool _unused; if (m_ar.is_array(val) && extract_array_func_interp(val, stores, else_case, _unused)) { - sort* srt = m().get_sort(val); + sort* srt = m.get_sort(val); val = m_ar.mk_const_array(srt, else_case); for (unsigned i = stores.size(); i > 0; ) { --i; - expr_ref_vector args(m()); + expr_ref_vector args(m); args.push_back(val); args.append(stores[i].size(), stores[i].c_ptr()); val = m_ar.mk_store(args.size(), args.c_ptr()); @@ -220,6 +223,7 @@ struct evaluator_cfg : public default_rewriter_cfg { #define TRACE_MACRO TRACE("model_evaluator", tout << "get_macro for " << f->get_name() << " (model completion: " << m_model_completion << ")\n";); func_interp * fi = m_model.get_func_interp(f); + if (fi != 0) { TRACE_MACRO; if (fi->is_partial()) { @@ -228,31 +232,52 @@ struct evaluator_cfg : public default_rewriter_cfg { expr * val = m_model.get_some_value(s); fi->set_else(val); } - else { + else return false; - } } - def = fi->get_interp(); + def = fi->get_interp(); SASSERT(def != 0); return true; } if (m_model_completion && (f->get_family_id() == null_family_id || - m().get_plugin(f->get_family_id())->is_considered_uninterpreted(f))) + m.get_plugin(f->get_family_id())->is_considered_uninterpreted(f))) { TRACE_MACRO; sort * s = f->get_range(); expr * val = m_model.get_some_value(s); - func_interp * new_fi = alloc(func_interp, m(), f->get_arity()); + func_interp * new_fi = alloc(func_interp, m, f->get_arity()); new_fi->set_else(val); m_model.register_decl(f, new_fi); def = val; return true; } + return false; } + br_status evaluate_partial_theory_func(func_decl * f, + unsigned num, expr * const * args, + expr_ref & result, proof_ref & result_pr) { + SASSERT(f != 0); + SASSERT(!m.is_builtin_family_id(f->get_family_id())); + result = 0; + result_pr = 0; + + func_interp * fi = m_model.get_func_interp(f); + if (fi) { + if (fi->is_partial()) + fi->set_else(m.get_some_value(f->get_range())); + + var_subst vs(m, false); + vs(fi->get_interp(), num, args, result); + return BR_REWRITE_FULL; + } + + return BR_FAILED; + } + bool max_steps_exceeded(unsigned num_steps) const { cooperate("model evaluator"); @@ -266,7 +291,7 @@ struct evaluator_cfg : public default_rewriter_cfg { br_status mk_array_eq(expr* a, expr* b, expr_ref& result) { if (a == b) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } if (!m_array_equalities) { @@ -275,19 +300,19 @@ struct evaluator_cfg : public default_rewriter_cfg { vector stores1, stores2; bool args_are_unique1, args_are_unique2; - expr_ref else1(m()), else2(m()); + expr_ref else1(m), else2(m); if (extract_array_func_interp(a, stores1, else1, args_are_unique1) && extract_array_func_interp(b, stores2, else2, args_are_unique2)) { - expr_ref_vector conj(m()), args1(m()), args2(m()); - if (m().are_equal(else1, else2)) { + expr_ref_vector conj(m), args1(m), args2(m); + if (m.are_equal(else1, else2)) { // no op } - else if (m().are_distinct(else1, else2) && !(m().get_sort(else1)->get_info()->get_num_elements().is_finite())) { - result = m().mk_false(); + else if (m.are_distinct(else1, else2) && !(m.get_sort(else1)->get_info()->get_num_elements().is_finite())) { + result = m.mk_false(); return BR_DONE; } else { - conj.push_back(m().mk_eq(else1, else2)); + conj.push_back(m.mk_eq(else1, else2)); } if (args_are_unique1 && args_are_unique2 && !stores1.empty()) { return mk_array_eq_core(stores1, else1, stores2, else2, conj, result); @@ -300,11 +325,11 @@ struct evaluator_cfg : public default_rewriter_cfg { for (unsigned i = 0; i < stores1.size(); ++i) { args1.resize(1); args1.append(stores1[i].size() - 1, stores1[i].c_ptr()); args2.resize(1); args2.append(stores1[i].size() - 1, stores1[i].c_ptr()); - expr_ref s1(m_ar.mk_select(args1.size(), args1.c_ptr()), m()); - expr_ref s2(m_ar.mk_select(args2.size(), args2.c_ptr()), m()); - conj.push_back(m().mk_eq(s1, s2)); + expr_ref s1(m_ar.mk_select(args1.size(), args1.c_ptr()), m); + expr_ref s2(m_ar.mk_select(args2.size(), args2.c_ptr()), m); + conj.push_back(m.mk_eq(s1, s2)); } - result = m().mk_and(conj.size(), conj.c_ptr()); + result = m.mk_and(conj.size(), conj.c_ptr()); return BR_REWRITE_FULL; } return BR_FAILED; @@ -362,15 +387,15 @@ struct evaluator_cfg : public default_rewriter_cfg { if (table1.find(stores2[i].c_ptr(), args)) { switch (compare(args[arity], val)) { case l_true: table1.remove(args); break; - case l_false: result = m().mk_false(); return BR_DONE; - default: conj.push_back(m().mk_eq(val, args[arity])); break; + case l_false: result = m.mk_false(); return BR_DONE; + default: conj.push_back(m.mk_eq(val, args[arity])); break; } } else { switch (compare(else1, val)) { case l_true: break; - case l_false: result = m().mk_false(); return BR_DONE; - default: conj.push_back(m().mk_eq(else1, val)); break; + case l_false: result = m.mk_false(); return BR_DONE; + default: conj.push_back(m.mk_eq(else1, val)); break; } } } @@ -378,8 +403,8 @@ struct evaluator_cfg : public default_rewriter_cfg { for (; it != end; ++it) { switch (compare((*it)[arity], else2)) { case l_true: break; - case l_false: result = m().mk_false(); return BR_DONE; - default: conj.push_back(m().mk_eq((*it)[arity], else2)); break; + case l_false: result = m.mk_false(); return BR_DONE; + default: conj.push_back(m.mk_eq((*it)[arity], else2)); break; } } result = mk_and(conj); @@ -387,8 +412,8 @@ struct evaluator_cfg : public default_rewriter_cfg { } lbool compare(expr* a, expr* b) { - if (m().are_equal(a, b)) return l_true; - if (m().are_distinct(a, b)) return l_false; + if (m.are_equal(a, b)) return l_true; + if (m.are_distinct(a, b)) return l_false; return l_undef; } @@ -396,8 +421,8 @@ struct evaluator_cfg : public default_rewriter_cfg { bool args_are_values(expr_ref_vector const& store, bool& are_unique) { bool are_values = true; for (unsigned j = 0; are_values && j + 1 < store.size(); ++j) { - are_values = m().is_value(store[j]); - are_unique &= m().is_unique_value(store[j]); + are_values = m.is_value(store[j]); + are_unique &= m.is_unique_value(store[j]); } SASSERT(!are_unique || are_values); return are_values; @@ -408,10 +433,10 @@ struct evaluator_cfg : public default_rewriter_cfg { SASSERT(m_ar.is_array(a)); bool are_values = true; are_unique = true; - TRACE("model_evaluator", tout << mk_pp(a, m()) << "\n";); + TRACE("model_evaluator", tout << mk_pp(a, m) << "\n";); while (m_ar.is_store(a)) { - expr_ref_vector store(m()); + expr_ref_vector store(m); store.append(to_app(a)->get_num_args()-1, to_app(a)->get_args()+1); are_values &= args_are_values(store, are_unique); stores.push_back(store); @@ -424,7 +449,7 @@ struct evaluator_cfg : public default_rewriter_cfg { } if (!m_ar.is_as_array(a)) { - TRACE("model_evaluator", tout << "no translation: " << mk_pp(a, m()) << "\n";); + TRACE("model_evaluator", tout << "no translation: " << mk_pp(a, m) << "\n";); return false; } @@ -434,13 +459,13 @@ struct evaluator_cfg : public default_rewriter_cfg { unsigned arity = f->get_arity(); unsigned base_sz = stores.size(); for (unsigned i = 0; i < sz; ++i) { - expr_ref_vector store(m()); + expr_ref_vector store(m); func_entry const* fe = g->get_entry(i); store.append(arity, fe->get_args()); store.push_back(fe->get_result()); for (unsigned j = 0; j < store.size(); ++j) { if (!is_ground(store[j].get())) { - TRACE("model_evaluator", tout << "could not extract array interpretation: " << mk_pp(a, m()) << "\n" << mk_pp(store[j].get(), m()) << "\n";); + TRACE("model_evaluator", tout << "could not extract array interpretation: " << mk_pp(a, m) << "\n" << mk_pp(store[j].get(), m) << "\n";); return false; } } @@ -448,18 +473,18 @@ struct evaluator_cfg : public default_rewriter_cfg { } else_case = g->get_else(); if (!else_case) { - TRACE("model_evaluator", tout << "no else case " << mk_pp(a, m()) << "\n"; - /*model_smt2_pp(tout, m(), m_model, 0);*/ + TRACE("model_evaluator", tout << "no else case " << mk_pp(a, m) << "\n"; + /*model_smt2_pp(tout, m, m_model, 0);*/ ); return false; } if (!is_ground(else_case)) { - TRACE("model_evaluator", tout << "non-ground else case " << mk_pp(a, m()) << "\n" << else_case << "\n";); + TRACE("model_evaluator", tout << "non-ground else case " << mk_pp(a, m) << "\n" << else_case << "\n";); return false; } for (unsigned i = stores.size(); are_values && i > base_sz; ) { --i; - if (m().are_equal(else_case, stores[i].back())) { + if (m.are_equal(else_case, stores[i].back())) { for (unsigned j = i + 1; j < stores.size(); ++j) { stores[j-1].reset(); stores[j-1].append(stores[j]); @@ -469,7 +494,7 @@ struct evaluator_cfg : public default_rewriter_cfg { } are_values &= args_are_values(stores[i], are_unique); } - TRACE("model_evaluator", tout << "else case: " << mk_pp(else_case, m()) << "\n";); + TRACE("model_evaluator", tout << "else case: " << mk_pp(else_case, m) << "\n";); return true; } diff --git a/src/model/model_evaluator.h b/src/model/model_evaluator.h index ba55e96ba..bd2b2d664 100644 --- a/src/model/model_evaluator.h +++ b/src/model/model_evaluator.h @@ -19,10 +19,12 @@ Revision History: #ifndef MODEL_EVALUATOR_H_ #define MODEL_EVALUATOR_H_ -#include"ast.h" -#include"rewriter_types.h" -#include"params.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter_types.h" +#include "util/params.h" + class model; +class model_core; typedef rewriter_exception model_evaluator_exception; @@ -46,7 +48,7 @@ public: void cleanup(params_ref const & p = params_ref()); void reset(params_ref const & p = params_ref()); - + unsigned get_num_steps() const; }; diff --git a/src/model/model_implicant.cpp b/src/model/model_implicant.cpp index 0d37a04df..6abdacfba 100644 --- a/src/model/model_implicant.cpp +++ b/src/model/model_implicant.cpp @@ -22,23 +22,23 @@ Notes: --*/ #include -#include "array_decl_plugin.h" -#include "ast_pp.h" -#include "bool_rewriter.h" -#include "for_each_expr.h" -#include "model.h" -#include "ref_vector.h" -#include "rewriter.h" -#include "rewriter_def.h" -#include "util.h" -#include "model_implicant.h" -#include "arith_decl_plugin.h" -#include "expr_replacer.h" -#include "model_smt2_pp.h" -#include "poly_rewriter.h" -#include "poly_rewriter_def.h" -#include "arith_rewriter.h" -#include "scoped_proof.h" +#include "ast/array_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/for_each_expr.h" +#include "model/model.h" +#include "util/ref_vector.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "util/util.h" +#include "model/model_implicant.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/expr_replacer.h" +#include "model/model_smt2_pp.h" +#include "ast/rewriter/poly_rewriter.h" +#include "ast/rewriter/poly_rewriter_def.h" +#include "ast/rewriter/arith_rewriter.h" +#include "ast/scoped_proof.h" diff --git a/src/model/model_implicant.h b/src/model/model_implicant.h index 91bfe9894..c34a4b810 100644 --- a/src/model/model_implicant.h +++ b/src/model/model_implicant.h @@ -20,14 +20,14 @@ Revision History: #ifndef MODEL_IMPLICANT_H_ #define MODEL_IMPLICANT_H_ -#include "ast.h" -#include "ast_pp.h" -#include "obj_hashtable.h" -#include "ref_vector.h" -#include "trace.h" -#include "vector.h" -#include "arith_decl_plugin.h" -#include "array_decl_plugin.h" +#include "ast/ast.h" +#include "ast/ast_pp.h" +#include "util/obj_hashtable.h" +#include "util/ref_vector.h" +#include "util/trace.h" +#include "util/vector.h" +#include "ast/arith_decl_plugin.h" +#include "ast/array_decl_plugin.h" class model; class model_core; diff --git a/src/model/model_params.pyg b/src/model/model_params.pyg index 14e83952c..58337e863 100644 --- a/src/model/model_params.pyg +++ b/src/model/model_params.pyg @@ -1,8 +1,9 @@ -def_module_params('model', +def_module_params('model', export=True, params=(('partial', BOOL, False, 'enable/disable partial function interpretations'), ('v1', BOOL, False, 'use Z3 version 1.x pretty printer'), ('v2', BOOL, False, 'use Z3 version 2.x (x <= 16) pretty printer'), ('compact', BOOL, False, 'try to compact function graph (i.e., function interpretations that are lookup tables)'), + ('completion', BOOL, False, 'enable/disable model completion'), )) diff --git a/src/model/model_pp.cpp b/src/model/model_pp.cpp index b968c7184..2f9b114bb 100644 --- a/src/model/model_pp.cpp +++ b/src/model/model_pp.cpp @@ -17,12 +17,12 @@ Revision History: --*/ -#include"model_pp.h" -#include"model_core.h" -#include"ast_pp.h" -#include"ast_smt2_pp.h" -#include"used_symbols.h" -#include"pp.h" +#include "model/model_pp.h" +#include "model/model_core.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/used_symbols.h" +#include "ast/pp.h" static void display_uninterp_sorts(std::ostream & out, model_core const & md) { ast_manager & m = md.get_manager(); diff --git a/src/model/model_smt2_pp.cpp b/src/model/model_smt2_pp.cpp index 929668638..152cbc8d3 100644 --- a/src/model/model_smt2_pp.cpp +++ b/src/model/model_smt2_pp.cpp @@ -18,10 +18,10 @@ Revision History: --*/ #include -#include"model_smt2_pp.h" -#include"ast_smt2_pp.h" -#include"func_decl_dependencies.h" -#include"pp.h" +#include "model/model_smt2_pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/func_decl_dependencies.h" +#include "ast/pp.h" using namespace format_ns; static void pp_indent(std::ostream & out, unsigned indent) { diff --git a/src/model/model_smt2_pp.h b/src/model/model_smt2_pp.h index c123bfb24..c43e26ca6 100644 --- a/src/model/model_smt2_pp.h +++ b/src/model/model_smt2_pp.h @@ -20,8 +20,8 @@ Revision History: #ifndef MODEL_SMT2_PP_H_ #define MODEL_SMT2_PP_H_ -#include"ast_printer.h" -#include"model_core.h" +#include "ast/ast_printer.h" +#include "model/model_core.h" void model_smt2_pp(std::ostream & out, ast_printer_context & ctx, model_core const & m, unsigned indent); void model_smt2_pp(std::ostream & out, ast_manager & m, model_core const & md, unsigned indent); diff --git a/src/model/model_v2_pp.cpp b/src/model/model_v2_pp.cpp index 4600ccc9e..dae9b2104 100644 --- a/src/model/model_v2_pp.cpp +++ b/src/model/model_v2_pp.cpp @@ -15,9 +15,9 @@ Author: Revision History: --*/ -#include"model_v2_pp.h" -#include"model_core.h" -#include"ast_pp.h" +#include "model/model_v2_pp.h" +#include "model/model_core.h" +#include "ast/ast_pp.h" static void display_function(std::ostream & out, model_core const & md, func_decl * f, bool partial) { ast_manager & m = md.get_manager(); diff --git a/src/muz/base/CMakeLists.txt b/src/muz/base/CMakeLists.txt index ec1ce47c3..6b0334664 100644 --- a/src/muz/base/CMakeLists.txt +++ b/src/muz/base/CMakeLists.txt @@ -10,7 +10,6 @@ z3_add_component(muz dl_rule_transformer.cpp dl_util.cpp hnf.cpp - proof_utils.cpp rule_properties.cpp COMPONENT_DEPENDENCIES aig_tactic diff --git a/src/muz/base/bind_variables.cpp b/src/muz/base/bind_variables.cpp index 0cc50625e..2ba7d1473 100644 --- a/src/muz/base/bind_variables.cpp +++ b/src/muz/base/bind_variables.cpp @@ -18,7 +18,7 @@ Notes: --*/ -#include "bind_variables.h" +#include "muz/base/bind_variables.h" bind_variables::bind_variables(ast_manager & m): m(m), diff --git a/src/muz/base/bind_variables.h b/src/muz/base/bind_variables.h index 18af319f8..693010132 100644 --- a/src/muz/base/bind_variables.h +++ b/src/muz/base/bind_variables.h @@ -21,7 +21,7 @@ Notes: #ifndef BIND_VARIABLES_H_ #define BIND_VARIABLES_H_ -#include"ast.h" +#include "ast/ast.h" class bind_variables { typedef obj_map var2bound; diff --git a/src/muz/base/dl_boogie_proof.cpp b/src/muz/base/dl_boogie_proof.cpp index 75579323c..8f4f9c02d 100644 --- a/src/muz/base/dl_boogie_proof.cpp +++ b/src/muz/base/dl_boogie_proof.cpp @@ -51,11 +51,11 @@ Example from Boogie: ") */ -#include "dl_boogie_proof.h" -#include "model_pp.h" -#include "proof_utils.h" -#include "ast_pp.h" -#include "ast_util.h" +#include "muz/base/dl_boogie_proof.h" +#include "model/model_pp.h" +#include "ast/proofs/proof_utils.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" namespace datalog { diff --git a/src/muz/base/dl_boogie_proof.h b/src/muz/base/dl_boogie_proof.h index 0f829dbdf..f335159b6 100644 --- a/src/muz/base/dl_boogie_proof.h +++ b/src/muz/base/dl_boogie_proof.h @@ -48,8 +48,8 @@ define-fun) when Boogie supports this. */ -#include "ast.h" -#include "model.h" +#include "ast/ast.h" +#include "model/model.h" namespace datalog { class boogie_proof { diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 2ca74a73b..39e044ec3 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -19,16 +19,16 @@ Revision History: #include #include -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"dl_context.h" -#include"for_each_expr.h" -#include"ast_smt_pp.h" -#include"ast_smt2_pp.h" -#include"datatype_decl_plugin.h" -#include"scoped_proof.h" -#include"fixedpoint_params.hpp" -#include"ast_pp_util.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "muz/base/dl_context.h" +#include "ast/for_each_expr.h" +#include "ast/ast_smt_pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/scoped_proof.h" +#include "muz/base/fixedpoint_params.hpp" +#include "ast/ast_pp_util.h" namespace datalog { @@ -229,6 +229,7 @@ namespace datalog { m_enable_bind_variables(true), m_last_status(OK), m_last_answer(m), + m_last_ground_answer(m), m_engine_type(LAST_ENGINE) { re.set_context(this); updt_params(pa); @@ -306,6 +307,8 @@ namespace datalog { bool context::compress_unbound() const { return m_params->xform_compress_unbound(); } bool context::quantify_arrays() const { return m_params->xform_quantify_arrays(); } bool context::instantiate_quantifiers() const { return m_params->xform_instantiate_quantifiers(); } + bool context::array_blast() const { return m_params->xform_array_blast(); } + bool context::array_blast_full() const { return m_params->xform_array_blast_full(); } void context::register_finite_sort(sort * s, sort_kind k) { @@ -450,7 +453,8 @@ namespace datalog { return new_pred; } - void context::add_rule(expr* rl, symbol const& name, unsigned bound) { + void context::add_rule(expr* rl, symbol const& name, unsigned bound) { + SASSERT(rl); m_rule_fmls.push_back(rl); m_rule_names.push_back(name); m_rule_bounds.push_back(bound); @@ -458,7 +462,7 @@ namespace datalog { void context::flush_add_rules() { datalog::rule_manager& rm = get_rule_manager(); - scoped_proof_mode _scp(m, generate_proof_trace()?PGM_FINE:PGM_DISABLED); + scoped_proof_mode _scp(m, generate_proof_trace()?PGM_ENABLED:PGM_DISABLED); while (m_rule_fmls_head < m_rule_fmls.size()) { expr* fml = m_rule_fmls[m_rule_fmls_head].get(); proof* p = generate_proof_trace()?m.mk_asserted(fml):0; @@ -546,10 +550,20 @@ namespace datalog { return m_engine->get_cover_delta(level, pred); } + expr_ref context::get_reachable(func_decl *pred) { + ensure_engine(); + return m_engine->get_reachable(pred); + } void context::add_cover(int level, func_decl* pred, expr* property) { ensure_engine(); m_engine->add_cover(level, pred, property); } + + void context::add_invariant(func_decl* pred, expr *property) + { + ensure_engine(); + m_engine->add_invariant(pred, property); + } void context::check_rules(rule_set& r) { m_rule_properties.set_generate_proof(generate_proof_trace()); @@ -561,6 +575,7 @@ namespace datalog { m_rule_properties.check_nested_free(); m_rule_properties.check_infinite_sorts(); break; + case SPACER_ENGINE: case PDR_ENGINE: m_rule_properties.collect(r); m_rule_properties.check_existential_tail(); @@ -792,6 +807,9 @@ namespace datalog { if (e == symbol("datalog")) { m_engine_type = DATALOG_ENGINE; } + else if (e == symbol("spacer")) { + m_engine_type = SPACER_ENGINE; + } else if (e == symbol("pdr")) { m_engine_type = PDR_ENGINE; } @@ -844,8 +862,10 @@ namespace datalog { m_mc = mk_skip_model_converter(); m_last_status = OK; m_last_answer = 0; + m_last_ground_answer = 0; switch (get_engine()) { case DATALOG_ENGINE: + case SPACER_ENGINE: case PDR_ENGINE: case QPDR_ENGINE: case BMC_ENGINE: @@ -867,6 +887,28 @@ namespace datalog { return m_engine->query(query); } + lbool context::query_from_lvl (expr* query, unsigned lvl) { + m_mc = mk_skip_model_converter(); + m_last_status = OK; + m_last_answer = 0; + m_last_ground_answer = 0; + switch (get_engine()) { + case DATALOG_ENGINE: + case SPACER_ENGINE: + case PDR_ENGINE: + case QPDR_ENGINE: + case BMC_ENGINE: + case QBMC_ENGINE: + case TAB_ENGINE: + case CLP_ENGINE: + flush_add_rules(); + break; + default: + UNREACHABLE(); + } + ensure_engine(); + return m_engine->query_from_lvl (query, lvl); + } model_ref context::get_model() { ensure_engine(); return m_engine->get_model(); @@ -905,6 +947,42 @@ namespace datalog { return m_last_answer.get(); } + expr* context::get_ground_sat_answer () { + if (m_last_ground_answer) { + return m_last_ground_answer; + } + ensure_engine (); + m_last_ground_answer = m_engine->get_ground_sat_answer (); + return m_last_ground_answer; + } + + void context::get_rules_along_trace (rule_ref_vector& rules) { + ensure_engine (); + m_engine->get_rules_along_trace (rules); + } + + void context::get_rules_along_trace_as_formulas (expr_ref_vector& rules, svector& names) { + rule_manager& rm = get_rule_manager (); + rule_ref_vector rv (rm); + get_rules_along_trace (rv); + expr_ref fml (m); + rule_ref_vector::iterator it = rv.begin (), end = rv.end (); + for (; it != end; it++) { + m_rule_manager.to_formula (**it, fml); + rules.push_back (fml); + // The concatenated names are already stored last-first, so do not need to be reversed here + const symbol& rule_name = (*it)->name(); + names.push_back (rule_name); + + TRACE ("dl", + if (rule_name == symbol::null) { + tout << "Encountered unnamed rule: "; + (*it)->display(*this, tout); + tout << "\n"; + }); + } + } + void context::display_certificate(std::ostream& out) { ensure_engine(); m_engine->display_certificate(out); diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index ba841c84f..129277514 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -23,26 +23,26 @@ Revision History: #undef min #undef max #endif -#include"arith_decl_plugin.h" -#include"map.h" -#include"th_rewriter.h" -#include"str_hashtable.h" -#include"var_subst.h" -#include"dl_costs.h" -#include"dl_decl_plugin.h" -#include"dl_rule_set.h" -#include"lbool.h" -#include"statistics.h" -#include"params.h" -#include"trail.h" -#include"model_converter.h" -#include"model2expr.h" -#include"smt_params.h" -#include"dl_rule_transformer.h" -#include"expr_functors.h" -#include"dl_engine_base.h" -#include"bind_variables.h" -#include"rule_properties.h" +#include "ast/arith_decl_plugin.h" +#include "util/map.h" +#include "ast/rewriter/th_rewriter.h" +#include "util/str_hashtable.h" +#include "ast/rewriter/var_subst.h" +#include "muz/base/dl_costs.h" +#include "ast/dl_decl_plugin.h" +#include "muz/base/dl_rule_set.h" +#include "util/lbool.h" +#include "util/statistics.h" +#include "util/params.h" +#include "util/trail.h" +#include "tactic/model_converter.h" +#include "model/model2expr.h" +#include "smt/params/smt_params.h" +#include "muz/base/dl_rule_transformer.h" +#include "ast/expr_functors.h" +#include "muz/base/dl_engine_base.h" +#include "muz/base/bind_variables.h" +#include "muz/base/rule_properties.h" struct fixedpoint_params; @@ -54,7 +54,7 @@ namespace datalog { MEMOUT, INPUT_ERROR, APPROX, - BOUNDED, + BOUNDED, CANCELED }; @@ -207,6 +207,7 @@ namespace datalog { bool m_enable_bind_variables; execution_result m_last_status; expr_ref m_last_answer; + expr_ref m_last_ground_answer; DL_ENGINE m_engine_type; @@ -277,6 +278,8 @@ namespace datalog { bool xform_bit_blast() const; bool xform_slice() const; bool xform_coi() const; + bool array_blast() const; + bool array_blast_full() const; void register_finite_sort(sort * s, sort_kind k); @@ -315,7 +318,7 @@ namespace datalog { \brief Retrieve predicates */ func_decl_set const& get_predicates() const { return m_preds; } - ast_ref_vector const &get_pinned() const {return m_pinned; } + ast_ref_vector const &get_pinned() const {return m_pinned; } bool is_predicate(func_decl* pred) const { return m_preds.contains(pred); } bool is_predicate(expr * e) const { return is_app(e) && is_predicate(to_app(e)->get_decl()); } @@ -407,6 +410,10 @@ namespace datalog { */ unsigned get_num_levels(func_decl* pred); + /** + Retrieve reachable facts of 'pred'. + */ + expr_ref get_reachable(func_decl *pred); /** Retrieve the current cover of 'pred' up to 'level' unfoldings. Return just the delta that is known at 'level'. To @@ -421,6 +428,11 @@ namespace datalog { */ void add_cover(int level, func_decl* pred, expr* property); + /** + Add an invariant of predicate 'pred'. + */ + void add_invariant (func_decl *pred, expr *property); + /** \brief Check rule subsumption. */ @@ -509,6 +521,7 @@ namespace datalog { lbool query(expr* q); + lbool query_from_lvl (expr* q, unsigned lvl); /** \brief retrieve model from inductive invariant that shows query is unsat. @@ -521,7 +534,7 @@ namespace datalog { \brief retrieve proof from derivation of the query. \pre engine == 'pdr' || engine == 'duality'- this option is only supported - for PDR mode and Duality mode. + for PDR mode and Duality mode. */ proof_ref get_proof(); @@ -545,6 +558,18 @@ namespace datalog { in the query that are derivable. */ expr* get_answer_as_formula(); + /** + * get bottom-up (from query) sequence of ground predicate instances + * (for e.g. P(0,1,0,0,3)) that together form a ground derivation to query + */ + expr* get_ground_sat_answer (); + + /** + * \brief obtain the sequence of rules along the counterexample trace + */ + void get_rules_along_trace (rule_ref_vector& rules); + + void get_rules_along_trace_as_formulas (expr_ref_vector& rules, svector& names); void collect_statistics(statistics& st) const; diff --git a/src/muz/base/dl_costs.cpp b/src/muz/base/dl_costs.cpp index fe085d7f7..f97a4d451 100644 --- a/src/muz/base/dl_costs.cpp +++ b/src/muz/base/dl_costs.cpp @@ -17,11 +17,11 @@ Revision History: --*/ -#include "debug.h" -#include "stopwatch.h" -#include "dl_context.h" -#include "dl_rule.h" -#include "dl_costs.h" +#include "util/debug.h" +#include "util/stopwatch.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule.h" +#include "muz/base/dl_costs.h" namespace datalog { diff --git a/src/muz/base/dl_costs.h b/src/muz/base/dl_costs.h index f3f97f6fd..fd5a99f15 100644 --- a/src/muz/base/dl_costs.h +++ b/src/muz/base/dl_costs.h @@ -22,7 +22,7 @@ Revision History: #include -#include "ast.h" +#include "ast/ast.h" class stopwatch; diff --git a/src/muz/base/dl_engine_base.h b/src/muz/base/dl_engine_base.h index 9878f3a9e..576ed7f6b 100644 --- a/src/muz/base/dl_engine_base.h +++ b/src/muz/base/dl_engine_base.h @@ -19,18 +19,20 @@ Revision History: #ifndef DL_ENGINE_BASE_H_ #define DL_ENGINE_BASE_H_ -#include "model.h" +#include "model/model.h" +#include "muz/base/dl_util.h" namespace datalog { enum DL_ENGINE { DATALOG_ENGINE, PDR_ENGINE, + SPACER_ENGINE, QPDR_ENGINE, BMC_ENGINE, QBMC_ENGINE, TAB_ENGINE, CLP_ENGINE, - DUALITY_ENGINE, + DUALITY_ENGINE, DDNF_ENGINE, LAST_ENGINE }; @@ -43,6 +45,9 @@ namespace datalog { virtual ~engine_base() {} virtual expr_ref get_answer() = 0; + virtual expr_ref get_ground_sat_answer () { + throw default_exception(std::string("operation is not supported for ") + m_name); + } virtual lbool query(expr* q) = 0; virtual lbool query(unsigned num_rels, func_decl*const* rels) { if (num_rels != 1) return l_undef; @@ -64,6 +69,9 @@ namespace datalog { } return query(q); } + virtual lbool query_from_lvl (expr* q, unsigned lvl) { + throw default_exception(std::string("operation is not supported for ") + m_name); + } virtual void reset_statistics() {} virtual void display_profile(std::ostream& out) {} @@ -71,18 +79,27 @@ namespace datalog { virtual unsigned get_num_levels(func_decl* pred) { throw default_exception(std::string("get_num_levels is not supported for ") + m_name); } + virtual expr_ref get_reachable(func_decl* pred) { + throw default_exception(std::string("operation is not supported for ") + m_name); + } virtual expr_ref get_cover_delta(int level, func_decl* pred) { throw default_exception(std::string("operation is not supported for ") + m_name); } virtual void add_cover(int level, func_decl* pred, expr* property) { throw default_exception(std::string("operation is not supported for ") + m_name); } + virtual void add_invariant (func_decl *pred, expr *property) { + throw default_exception(std::string("operation is not supported for ") + m_name); + } virtual void display_certificate(std::ostream& out) const { throw default_exception(std::string("certificates are not supported for ") + m_name); } virtual model_ref get_model() { return model_ref(alloc(model, m)); } + virtual void get_rules_along_trace (rule_ref_vector& rules) { + throw default_exception(std::string("get_rules_along_trace is not supported for ") + m_name); + } virtual proof_ref get_proof() { return proof_ref(m.mk_asserted(m.mk_true()), m); } diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index 27d62538e..4f832c4c9 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -24,26 +24,27 @@ Revision History: #include #include -#include"ast_pp.h" -#include"dl_context.h" -#include"map.h" -#include"recurse_expr_def.h" -#include"dl_rule.h" -#include"qe.h" -#include"for_each_expr.h" -#include"used_vars.h" -#include"var_subst.h" -#include"rewriter_def.h" -#include"th_rewriter.h" -#include"ast_smt2_pp.h" -#include"used_symbols.h" -#include"quant_hoist.h" -#include"expr_replacer.h" -#include"bool_rewriter.h" -#include"expr_safe_replace.h" -#include"filter_model_converter.h" -#include"scoped_proof.h" -#include"datatype_decl_plugin.h" +#include "ast/ast_pp.h" +#include "muz/base/dl_context.h" +#include "util/map.h" +#include "ast/recurse_expr_def.h" +#include "muz/base/dl_rule.h" +#include "qe/qe.h" +#include "ast/for_each_expr.h" +#include "ast/used_vars.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/ast_smt2_pp.h" +#include "ast/used_symbols.h" +#include "ast/rewriter/quant_hoist.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "tactic/filter_model_converter.h" +#include "ast/scoped_proof.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/ast_util.h" namespace datalog { @@ -54,7 +55,7 @@ namespace datalog { m_head(m), m_args(m), m_hnf(m), - m_qe(m, params_ref()), + m_qe(m, params_ref(), false), m_rwr(m), m_ufproc(m) {} @@ -140,7 +141,7 @@ namespace datalog { void rule_manager::mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) { - scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); + scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_ENABLED:PGM_DISABLED); proof_ref pr(p, m); expr_ref fml1(m); bind_variables(fml, true, fml1); @@ -342,7 +343,7 @@ namespace datalog { } TRACE("dl", tout << rule_expr << "\n";); - scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); + scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_ENABLED:PGM_DISABLED); proof_ref pr(m); if (m_ctx.generate_proof_trace()) { pr = m.mk_asserted(rule_expr); @@ -639,7 +640,7 @@ namespace datalog { tail.push_back(ensure_app(conjs[i].get())); } tail_neg.resize(tail.size(), false); - r = mk(r->get_head(), tail.size(), tail.c_ptr(), tail_neg.c_ptr()); + r = mk(r->get_head(), tail.size(), tail.c_ptr(), tail_neg.c_ptr(), r->name()); TRACE("dl", r->display(m_ctx, tout << "reduced rule\n");); } } @@ -757,7 +758,7 @@ namespace datalog { ); proof_ref pr(m); - qe::expr_quant_elim_star1 simpl(m, m_ctx.get_fparams()); + qe::simplify_rewriter_star simpl(m); simpl(quant_tail, fixed_tail, pr); } else { diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index 856814531..ea0e64e4f 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -20,19 +20,19 @@ Revision History: #ifndef DL_RULE_H_ #define DL_RULE_H_ -#include"ast.h" -#include"dl_costs.h" -#include"dl_util.h" -#include"used_vars.h" -#include"proof_converter.h" -#include"model_converter.h" -#include"ast_counter.h" -#include"rewriter.h" -#include"hnf.h" -#include"qe_lite.h" -#include"var_subst.h" -#include"datatype_decl_plugin.h" -#include"label_rewriter.h" +#include "ast/ast.h" +#include "muz/base/dl_costs.h" +#include "muz/base/dl_util.h" +#include "ast/used_vars.h" +#include "tactic/proof_converter.h" +#include "tactic/model_converter.h" +#include "ast/rewriter/ast_counter.h" +#include "ast/rewriter/rewriter.h" +#include "muz/base/hnf.h" +#include "qe/qe_lite.h" +#include "ast/rewriter/var_subst.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/rewriter/label_rewriter.h" namespace datalog { diff --git a/src/muz/base/dl_rule_set.cpp b/src/muz/base/dl_rule_set.cpp index 229db4d27..65c940091 100644 --- a/src/muz/base/dl_rule_set.cpp +++ b/src/muz/base/dl_rule_set.cpp @@ -19,9 +19,9 @@ Revision History: #include #include -#include"dl_context.h" -#include"dl_rule_set.h" -#include"ast_pp.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_set.h" +#include "ast/ast_pp.h" namespace datalog { diff --git a/src/muz/base/dl_rule_set.h b/src/muz/base/dl_rule_set.h index 2e7401fea..748574d96 100644 --- a/src/muz/base/dl_rule_set.h +++ b/src/muz/base/dl_rule_set.h @@ -19,8 +19,8 @@ Revision History: #ifndef DL_RULE_SET_H_ #define DL_RULE_SET_H_ -#include"obj_hashtable.h" -#include"dl_rule.h" +#include "util/obj_hashtable.h" +#include "muz/base/dl_rule.h" namespace datalog { diff --git a/src/muz/base/dl_rule_subsumption_index.cpp b/src/muz/base/dl_rule_subsumption_index.cpp index 43f801bbf..f3fb545b6 100644 --- a/src/muz/base/dl_rule_subsumption_index.cpp +++ b/src/muz/base/dl_rule_subsumption_index.cpp @@ -20,9 +20,9 @@ Revision History: #include -#include "ast_pp.h" +#include "ast/ast_pp.h" -#include "dl_rule_subsumption_index.h" +#include "muz/base/dl_rule_subsumption_index.h" namespace datalog { diff --git a/src/muz/base/dl_rule_subsumption_index.h b/src/muz/base/dl_rule_subsumption_index.h index 89f7d44b7..2d09200f1 100644 --- a/src/muz/base/dl_rule_subsumption_index.h +++ b/src/muz/base/dl_rule_subsumption_index.h @@ -21,7 +21,7 @@ Revision History: #ifndef DL_RULE_SUBSUMPTION_INDEX_H_ #define DL_RULE_SUBSUMPTION_INDEX_H_ -#include "dl_context.h" +#include "muz/base/dl_context.h" namespace datalog { diff --git a/src/muz/base/dl_rule_transformer.cpp b/src/muz/base/dl_rule_transformer.cpp index 2df8b9453..9206efef6 100644 --- a/src/muz/base/dl_rule_transformer.cpp +++ b/src/muz/base/dl_rule_transformer.cpp @@ -20,9 +20,9 @@ Revision History: #include #include -#include"dl_context.h" -#include"dl_rule_transformer.h" -#include"stopwatch.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_transformer.h" +#include "util/stopwatch.h" namespace datalog { diff --git a/src/muz/base/dl_rule_transformer.h b/src/muz/base/dl_rule_transformer.h index d166acdd0..dc930ae2b 100644 --- a/src/muz/base/dl_rule_transformer.h +++ b/src/muz/base/dl_rule_transformer.h @@ -19,10 +19,10 @@ Revision History: #ifndef DL_RULE_TRANSFORMER_H_ #define DL_RULE_TRANSFORMER_H_ -#include"map.h" -#include"vector.h" -#include"dl_rule.h" -#include"dl_rule_set.h" +#include "util/map.h" +#include "util/vector.h" +#include "muz/base/dl_rule.h" +#include "muz/base/dl_rule_set.h" namespace datalog { diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index 0f254ee0a..f0439a55c 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -23,14 +23,14 @@ Revision History: #ifdef _WINDOWS #include #endif -#include"ast_pp.h" -#include"bool_rewriter.h" -#include"for_each_expr.h" -#include"scoped_proof.h" -#include"dl_context.h" -#include"dl_rule.h" -#include"dl_util.h" -#include"stopwatch.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/for_each_expr.h" +#include "ast/scoped_proof.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule.h" +#include "muz/base/dl_util.h" +#include "util/stopwatch.h" namespace datalog { diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index a4e9f192e..c560ee28e 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -11,7 +11,7 @@ Abstract: Author: - Leonardo de Moura (leonardo) 2010-05-20. + Krystof Hoder 2010 Revision History: @@ -20,17 +20,18 @@ Revision History: #define DL_UTIL_H_ #include -#include"ast.h" -#include"hashtable.h" -#include"obj_hashtable.h" -#include"uint_set.h" -#include"horn_subsume_model_converter.h" -#include"replace_proof_converter.h" -#include"substitution.h" -#include"ast_counter.h" -#include"statistics.h" -#include"stopwatch.h" -#include"lbool.h" +#include "ast/ast.h" +#include "util/hashtable.h" +#include "util/obj_hashtable.h" +#include "util/uint_set.h" +#include "tactic/horn_subsume_model_converter.h" +#include "tactic/replace_proof_converter.h" +#include "ast/substitution/substitution.h" +#include "ast/rewriter/ast_counter.h" +#include "util/statistics.h" +#include "util/stopwatch.h" +#include "util/lbool.h" +#include "util/container_util.h" namespace datalog { @@ -52,6 +53,7 @@ namespace datalog { ~verbose_action(); }; + typedef ref_vector rule_ref_vector; enum PDR_CACHE_MODE { NO_CACHE, HASH_CACHE, @@ -380,129 +382,6 @@ namespace datalog { */ void apply_subst(expr_ref_vector& tgt, expr_ref_vector const& sub); - // ----------------------------------- - // - // container functions - // - // ----------------------------------- - - template - void set_intersection(Set1 & tgt, const Set2 & src) { - svector to_remove; - typename Set1::iterator vit = tgt.begin(); - typename Set1::iterator vend = tgt.end(); - for(;vit!=vend;++vit) { - typename Set1::data itm=*vit; - if(!src.contains(itm)) { - to_remove.push_back(itm); - } - } - while(!to_remove.empty()) { - tgt.remove(to_remove.back()); - to_remove.pop_back(); - } - } - - template - void set_difference(Set & tgt, const Set & to_remove) { - typename Set::iterator vit = to_remove.begin(); - typename Set::iterator vend = to_remove.end(); - for(;vit!=vend;++vit) { - typename Set::data itm=*vit; - tgt.remove(itm); - } - } - - template - void set_union(Set1 & tgt, const Set2 & to_add) { - typename Set2::iterator vit = to_add.begin(); - typename Set2::iterator vend = to_add.end(); - for(;vit!=vend;++vit) { - typename Set1::data itm=*vit; - tgt.insert(itm); - } - } - - void idx_set_union(idx_set & tgt, const idx_set & src); - - template - void unite_disjoint_maps(T & tgt, const T & src) { - typename T::iterator it = src.begin(); - typename T::iterator end = src.end(); - for(; it!=end; ++it) { - SASSERT(!tgt.contains(it->m_key)); - tgt.insert(it->m_key, it->m_value); - } - } - - template - void collect_map_range(T & acc, const U & map) { - typename U::iterator it = map.begin(); - typename U::iterator end = map.end(); - for(; it!=end; ++it) { - acc.push_back(it->m_value); - } - } - - - template - void print_container(const T & begin, const T & end, std::ostream & out) { - T it = begin; - out << "("; - bool first = true; - for(; it!=end; ++it) { - if(first) { first = false; } else { out << ","; } - out << (*it); - } - out << ")"; - } - - template - void print_container(const T & cont, std::ostream & out) { - print_container(cont.begin(), cont.end(), out); - } - - template - void print_container(const ref_vector & cont, std::ostream & out) { - print_container(cont.c_ptr(), cont.c_ptr() + cont.size(), out); - } - - template - void print_map(const T & cont, std::ostream & out) { - typename T::iterator it = cont.begin(); - typename T::iterator end = cont.end(); - out << "("; - bool first = true; - for(; it!=end; ++it) { - if(first) { first = false; } else { out << ","; } - out << it->m_key << "->" << it->m_value; - } - out << ")"; - } - - template - unsigned find_index(const It & begin, const It & end, const V & val) { - unsigned idx = 0; - It it = begin; - for(; it!=end; it++, idx++) { - if(*it==val) { - return idx; - } - } - return UINT_MAX; - } - - template - bool containers_equal(const T & begin1, const T & end1, const U & begin2, const U & end2) { - T it1 = begin1; - U it2 = begin2; - for(; it1!=end1 && it2!=end2; ++it1, ++it2) { - if(*it1!=*it2) { - return false; - } - } - return it1==end1 && it2==end2; - } template bool vectors_equal(const T & c1, const U & c2) { @@ -520,6 +399,8 @@ namespace datalog { return true; } + void idx_set_union(idx_set & tgt, const idx_set & src); + template struct default_obj_chash { unsigned operator()(T const& cont, unsigned i) const { diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 8e7d6a7cb..0c2f03460 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -3,8 +3,8 @@ def_module_params('fixedpoint', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('engine', SYMBOL, 'auto-config', - 'Select: auto-config, datalog, duality, pdr, bmc'), - ('datalog.default_table', SYMBOL, 'sparse', + 'Select: auto-config, datalog, duality, pdr, bmc, spacer'), + ('datalog.default_table', SYMBOL, 'sparse', 'default table implementation: sparse, hashtable, bitvector, interval'), ('datalog.default_relation', SYMBOL, 'pentagon', 'default relation implementation: external_relation, pentagon'), @@ -54,18 +54,20 @@ def_module_params('fixedpoint', "if true, finite_product_relation will attempt to avoid creating " + "inner relation with empty signature by putting in half of the " + "table columns, if it would have been empty otherwise"), - ('duality.full_expand', BOOL, False, 'Fully expand derivation trees'), - ('duality.no_conj', BOOL, False, 'No forced covering (conjectures)'), - ('duality.feasible_edges', BOOL, True, + ('datalog.subsumption', BOOL, True, + "if true, removes/filters predicates with total transitions"), + ('duality.full_expand', BOOL, False, 'Fully expand derivation trees'), + ('duality.no_conj', BOOL, False, 'No forced covering (conjectures)'), + ('duality.feasible_edges', BOOL, True, 'Don\'t expand definitley infeasible edges'), - ('duality.use_underapprox', BOOL, False, 'Use underapproximations'), - ('duality.stratified_inlining', BOOL, False, 'Use stratified inlining'), - ('duality.recursion_bound', UINT, UINT_MAX, + ('duality.use_underapprox', BOOL, False, 'Use underapproximations'), + ('duality.stratified_inlining', BOOL, False, 'Use stratified inlining'), + ('duality.recursion_bound', UINT, UINT_MAX, 'Recursion bound for stratified inlining'), - ('duality.profile', BOOL, False, 'profile run time'), - ('duality.mbqi', BOOL, True, 'use model-based quantifier instantiation'), - ('duality.batch_expand', BOOL, False, 'use batch expansion'), - ('duality.conjecture_file', STRING, '', 'save conjectures to file'), + ('duality.profile', BOOL, False, 'profile run time'), + ('duality.mbqi', BOOL, True, 'use model-based quantifier instantiation'), + ('duality.batch_expand', BOOL, False, 'use batch expansion'), + ('duality.conjecture_file', STRING, '', 'save conjectures to file'), ('pdr.bfs_model_search', BOOL, True, "use BFS strategy for expanding model search"), ('pdr.farkas', BOOL, True, @@ -74,6 +76,8 @@ def_module_params('fixedpoint', ('pdr.flexible_trace', BOOL, False, "allow PDR generate long counter-examples " + "by extending candidate trace within search area"), + ('pdr.flexible_trace_depth', UINT, UINT_MAX, + 'Controls the depth (below the current level) at which flexible trace can be applied'), ('pdr.use_model_generalizer', BOOL, False, "use model for backwards propagation (instead of symbolic simulation)"), ('pdr.validate_result', BOOL, False, @@ -88,9 +92,9 @@ def_module_params('fixedpoint', "generalize lemmas using induction strengthening"), ('pdr.use_arith_inductive_generalizer', BOOL, False, "generalize lemmas using arithmetic heuristics for induction strengthening"), - ('pdr.use_convex_closure_generalizer', BOOL, False, + ('pdr.use_convex_closure_generalizer', BOOL, False, "generalize using convex closures of lemmas"), - ('pdr.use_convex_interior_generalizer', BOOL, False, + ('pdr.use_convex_interior_generalizer', BOOL, False, "generalize using convex interiors of lemmas"), ('pdr.cache_mode', UINT, 0, "use no (0), symbolic (1) or explicit " + "cache (2) for model search"), @@ -100,7 +104,7 @@ def_module_params('fixedpoint', ('pdr.max_num_contexts', UINT, 500, "maximal number of contexts to create"), ('pdr.try_minimize_core', BOOL, False, "try to reduce core size (before inductive minimization)"), - ('pdr.utvpi', BOOL, True, 'Enable UTVPI strategy'), + ('pdr.utvpi', BOOL, True, 'Enable UTVPI strategy'), ('print_fixedpoint_extensions', BOOL, True, "use SMT-LIB2 fixedpoint extensions, instead of pure SMT2, " + "when printing rules"), @@ -119,7 +123,7 @@ def_module_params('fixedpoint', ('print_statistics', BOOL, False, 'print statistics'), ('print_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'), - ('tab.selection', SYMBOL, 'weight', + ('tab.selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'), ('xform.bit_blast', BOOL, False, 'bit-blast bit-vectors'), @@ -136,15 +140,67 @@ def_module_params('fixedpoint', ('xform.unfold_rules', UINT, 0, "unfold rules statically using iterative squarring"), ('xform.slice', BOOL, True, "simplify clause set using slicing"), - ('xform.karr', BOOL, False, + ('xform.karr', BOOL, False, "Add linear invariants to clauses using Karr's method"), - ('xform.quantify_arrays', BOOL, False, + ('spacer.use_eqclass', BOOL, False, "Generalizes equalities to equivalence classes"), + ('xform.transform_arrays', BOOL, False, + "Rewrites arrays equalities and applies select over store"), + ('xform.instantiate_arrays', BOOL, False, + "Transforms P(a) into P(i, a[i] a)"), + ('xform.instantiate_arrays.enforce', BOOL, False, + "Transforms P(a) into P(i, a[i]), discards a from predicate"), + ('xform.instantiate_arrays.nb_quantifier', UINT, 1, + "Gives the number of quantifiers per array"), + ('xform.instantiate_arrays.slice_technique', SYMBOL, "no-slicing", + "=> GetId(i) = i, => GetId(i) = true"), + ('xform.quantify_arrays', BOOL, False, "create quantified Horn clauses from clauses with arrays"), - ('xform.instantiate_quantifiers', BOOL, False, + ('xform.instantiate_quantifiers', BOOL, False, "instantiate quantified Horn clauses using E-matching heuristic"), ('xform.coalesce_rules', BOOL, False, "coalesce rules"), - ('xform.coi', BOOL, True, "use cone of influence simplificaiton"), - ('duality.enable_restarts', BOOL, False, 'DUALITY: enable restarts'), + ('xform.tail_simplifier_pve', BOOL, True, "propagate_variable_equivalences"), + ('xform.subsumption_checker', BOOL, True, "Enable subsumption checker (no support for model conversion)"), + ('xform.coi', BOOL, True, "use cone of influence simplification"), + ('duality.enable_restarts', BOOL, False, 'DUALITY: enable restarts'), + ('spacer.order_children', UINT, 0, 'SPACER: order of enqueuing children in non-linear rules : 0 (original), 1 (reverse)'), + ('spacer.eager_reach_check', BOOL, True, 'SPACER: eagerly check if a query is reachable using reachability facts of predecessors'), + ('spacer.use_lemma_as_cti', BOOL, False, 'SPACER: use a lemma instead of a CTI in flexible_trace'), + ('spacer.reset_obligation_queue', BOOL, True, 'SPACER: reset obligation queue when entering a new level'), + ('spacer.init_reach_facts', BOOL, True, 'SPACER: initialize reachability facts with false'), + ('spacer.use_array_eq_generalizer', BOOL, True, 'SPACER: attempt to generalize lemmas with array equalities'), + ('spacer.use_derivations', BOOL, True, 'SPACER: using derivation mechanism to cache intermediate results for non-linear rules'), + ('xform.array_blast', BOOL, False, "try to eliminate local array terms using Ackermannization -- some array terms may remain"), + ('xform.array_blast_full', BOOL, False, "eliminate all local array variables by QE"), + ('spacer.skip_propagate', BOOL, False, "Skip propagate/pushing phase. Turns PDR into a BMC that returns either reachable or unknown"), + ('spacer.max_level', UINT, UINT_MAX, "Maximum level to explore"), + ('spacer.elim_aux', BOOL, True, "Eliminate auxiliary variables in reachability facts"), + ('spacer.reach_as_init', BOOL, True, "Extend initial rules with computed reachability facts"), + ('spacer.blast_term_ite', BOOL, True, "Expand non-Boolean ite-terms"), + ('spacer.nondet_tie_break', BOOL, False, "Break ties in obligation queue non-deterministicly"), + ('spacer.reach_dnf', BOOL, True, "Restrict reachability facts to DNF"), + ('bmc.linear_unrolling_depth', UINT, UINT_MAX, "Maximal level to explore"), + ('spacer.split_farkas_literals', BOOL, False, "Split Farkas literals"), + ('spacer.native_mbp', BOOL, False, "Use native mbp of Z3"), + ('spacer.eq_prop', BOOL, True, "Enable equality and bound propagation in arithmetic"), + ('spacer.weak_abs', BOOL, True, "Weak abstraction"), + ('spacer.restarts', BOOL, False, "Enable reseting obligation queue"), + ('spacer.restart_initial_threshold', UINT, 10, "Intial threshold for restarts"), + ('spacer.random_seed', UINT, 0, "Random seed to be used by SMT solver"), + ('spacer.ground_cti', BOOL, True, "Require CTI to be ground"), + ('spacer.vs.dump_benchmarks', BOOL, False, 'dump benchmarks in virtual solver'), + ('spacer.vs.dump_min_time', DOUBLE, 5.0, 'min time to dump benchmark'), + ('spacer.vs.recheck', BOOL, False, 're-check locally during benchmark dumping'), + ('spacer.mbqi', BOOL, True, 'use model-based quantifier instantiation'), + ('spacer.keep_proxy', BOOL, True, 'keep proxy variables (internal parameter)'), + ('spacer.instantiate', BOOL, True, 'instantiate quantified lemmas'), + ('spacer.qlemmas', BOOL, True, 'allow quantified lemmas in frames'), + ('spacer.new_unsat_core', BOOL, True, 'use the new implementation of unsat-core-generation'), + ('spacer.minimize_unsat_core', BOOL, False, 'compute unsat-core by min-cut'), + ('spacer.farkas_optimized', BOOL, True, 'use the optimized farkas plugin, which performs gaussian elimination'), + ('spacer.farkas_a_const', BOOL, True, 'if the unoptimized farkas plugin is used, use the constants from A while constructing unsat_cores'), + ('spacer.lemma_sanity_check', BOOL, False, 'check during generalization whether lemma is actually correct'), + ('spacer.reuse_pobs', BOOL, True, 'reuse POBs'), + ('spacer.simplify_pob', BOOL, False, 'simplify POBs by removing redundant constraints') )) diff --git a/src/muz/base/hnf.cpp b/src/muz/base/hnf.cpp index 6d1c19a13..7db30a9f0 100644 --- a/src/muz/base/hnf.cpp +++ b/src/muz/base/hnf.cpp @@ -43,20 +43,20 @@ Notes: --*/ -#include"hnf.h" -#include"warning.h" -#include"used_vars.h" -#include"well_sorted.h" -#include"var_subst.h" -#include"name_exprs.h" -#include"act_cache.h" -#include"cooperate.h" -#include"ast_pp.h" -#include"quant_hoist.h" -#include"ast_util.h" -#include"dl_util.h" -#include"for_each_ast.h" -#include"for_each_expr.h" +#include "muz/base/hnf.h" +#include "util/warning.h" +#include "ast/used_vars.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/var_subst.h" +#include "ast/normal_forms/name_exprs.h" +#include "ast/act_cache.h" +#include "util/cooperate.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/quant_hoist.h" +#include "ast/ast_util.h" +#include "muz/base/dl_util.h" +#include "ast/for_each_ast.h" +#include "ast/for_each_expr.h" class hnf::imp { diff --git a/src/muz/base/hnf.h b/src/muz/base/hnf.h index 23b379d4d..330dfab70 100644 --- a/src/muz/base/hnf.h +++ b/src/muz/base/hnf.h @@ -25,10 +25,10 @@ Copyright (c) 2015 Microsoft Corporation #ifndef HNF_H_ #define HNF_H_ -#include"ast.h" -#include"params.h" -#include"defined_names.h" -#include"proof_converter.h" +#include "ast/ast.h" +#include "util/params.h" +#include "ast/normal_forms/defined_names.h" +#include "tactic/proof_converter.h" class hnf { class imp; diff --git a/src/muz/base/proof_utils.h b/src/muz/base/proof_utils.h deleted file mode 100644 index 0db831c4f..000000000 --- a/src/muz/base/proof_utils.h +++ /dev/null @@ -1,48 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - proof_utils.h - -Abstract: - - Utilities for transforming proofs. - -Author: - - Nikolaj Bjorner (nbjorner) 2012-10-12. - -Revision History: - ---*/ -#ifndef PROOF_UTILS_H_ -#define PROOF_UTILS_H_ - -class proof_utils { -public: - /** - \brief reduce the set of hypotheses used in the proof. - */ - static void reduce_hypotheses(proof_ref& pr); - - /** - \brief Check that a proof does not contain open hypotheses. - */ - static bool is_closed(ast_manager& m, proof* p); - - /** - \brief Permute unit resolution rule with th-lemma - */ - static void permute_unit_resolution(proof_ref& pr); - - /** - \brief Push instantiations created in hyper-resolutions up to leaves. - This produces a "ground" proof where leaves are annotated by instantiations. - */ - static void push_instantiations_up(proof_ref& pr); - - -}; - -#endif diff --git a/src/muz/base/rule_properties.cpp b/src/muz/base/rule_properties.cpp index 247519d63..21317a07c 100644 --- a/src/muz/base/rule_properties.cpp +++ b/src/muz/base/rule_properties.cpp @@ -18,11 +18,11 @@ Notes: --*/ -#include"expr_functors.h" -#include"rule_properties.h" -#include"dl_rule_set.h" -#include"for_each_expr.h" -#include"dl_context.h" +#include "ast/expr_functors.h" +#include "muz/base/rule_properties.h" +#include "muz/base/dl_rule_set.h" +#include "ast/for_each_expr.h" +#include "muz/base/dl_context.h" using namespace datalog; rule_properties::rule_properties(ast_manager & m, rule_manager& rm, context& ctx, i_expr_pred& p): diff --git a/src/muz/base/rule_properties.h b/src/muz/base/rule_properties.h index f53ad3841..197633aff 100644 --- a/src/muz/base/rule_properties.h +++ b/src/muz/base/rule_properties.h @@ -21,10 +21,10 @@ Notes: #ifndef RULE_PROPERTIES_H_ #define RULE_PROPERTIES_H_ -#include"ast.h" -#include"datatype_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"dl_rule.h" +#include "ast/ast.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "muz/base/dl_rule.h" namespace datalog { class rule_properties { diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 8cc5c4f60..3368c7640 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -17,21 +17,23 @@ Revision History: --*/ -#include "dl_context.h" -#include "dl_rule_transformer.h" -#include "dl_bmc_engine.h" -#include "dl_mk_slice.h" -#include "smt_kernel.h" -#include "datatype_decl_plugin.h" -#include "dl_decl_plugin.h" -#include "bool_rewriter.h" -#include "model_smt2_pp.h" -#include "ast_smt_pp.h" -#include "well_sorted.h" -#include "rewriter_def.h" -#include "dl_transforms.h" -#include "dl_mk_rule_inliner.h" -#include "scoped_proof.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_transformer.h" +#include "muz/bmc/dl_bmc_engine.h" +#include "muz/transforms/dl_mk_slice.h" +#include "smt/smt_kernel.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/dl_decl_plugin.h" +#include "ast/rewriter/bool_rewriter.h" +#include "model/model_smt2_pp.h" +#include "ast/ast_smt_pp.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/rewriter_def.h" +#include "muz/transforms/dl_transforms.h" +#include "muz/transforms/dl_mk_rule_inliner.h" +#include "ast/scoped_proof.h" + +#include "muz/base/fixedpoint_params.hpp" namespace datalog { @@ -143,6 +145,7 @@ namespace datalog { b.m_fparams.m_model = true; b.m_fparams.m_model_compact = true; b.m_fparams.m_mbqi = true; + b.m_rule_trace.reset(); } void mk_qrule_vars(datalog::rule const& r, unsigned rule_id, expr_ref_vector& sub) { @@ -279,6 +282,7 @@ namespace datalog { } SASSERT(r); mk_qrule_vars(*r, i, sub); + b.m_rule_trace.push_back(r); // we have rule, we have variable names of rule. // extract values for the variables in the rule. @@ -470,6 +474,7 @@ namespace datalog { b.m_fparams.m_model_compact = true; // b.m_fparams.m_mbqi = true; b.m_fparams.m_relevancy_lvl = 2; + b.m_rule_trace.reset(); } lbool check(unsigned level) { @@ -507,6 +512,7 @@ namespace datalog { } } SASSERT(r); + b.m_rule_trace.push_back(r); rm.to_formula(*r, fml); IF_VERBOSE(1, verbose_stream() << mk_pp(fml, m) << "\n";); prs.push_back(r->get_proof()); @@ -760,6 +766,7 @@ namespace datalog { b.m_fparams.m_model_compact = true; b.m_fparams.m_mbqi = false; b.m_fparams.m_relevancy_lvl = 2; + b.m_rule_trace.reset(); } func_decl_ref mk_predicate(func_decl* pred) { @@ -963,7 +970,7 @@ namespace datalog { _name << pred->get_name() << "_" << q->get_name() << j; symbol name(_name.str().c_str()); type_ref tr(idx); - accs.push_back(mk_accessor_decl(name, tr)); + accs.push_back(mk_accessor_decl(m, name, tr)); } std::stringstream _name; _name << pred->get_name() << "_" << i; @@ -972,7 +979,7 @@ namespace datalog { symbol is_name(_name.str().c_str()); cnstrs.push_back(mk_constructor_decl(name, is_name, accs.size(), accs.c_ptr())); } - dts.push_back(mk_datatype_decl(pred->get_name(), cnstrs.size(), cnstrs.c_ptr())); + dts.push_back(mk_datatype_decl(dtu, pred->get_name(), 0, nullptr, cnstrs.size(), cnstrs.c_ptr())); } @@ -1017,10 +1024,10 @@ namespace datalog { _name2 << "get_succ#" << i; ptr_vector accs; type_ref tr(0); - accs.push_back(mk_accessor_decl(name, tr)); + accs.push_back(mk_accessor_decl(m, name, tr)); cnstrs.push_back(mk_constructor_decl(name, is_name, accs.size(), accs.c_ptr())); } - dts.push_back(mk_datatype_decl(symbol("Path"), cnstrs.size(), cnstrs.c_ptr())); + dts.push_back(mk_datatype_decl(dtu, symbol("Path"), 0, nullptr, cnstrs.size(), cnstrs.c_ptr())); VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), 0, 0, new_sorts)); m_path_sort = new_sorts[0].get(); } @@ -1078,6 +1085,7 @@ namespace datalog { } head = rl->get_head(); pr = m.mk_hyper_resolve(sz+1, prs.c_ptr(), head, positions, substs); + b.m_rule_trace.push_back(rl.get()); return pr; } } @@ -1131,7 +1139,7 @@ namespace datalog { md->eval(path, path); IF_VERBOSE(2, verbose_stream() << mk_pp(trace, m) << "\n"; for (unsigned i = 0; i < b.m_solver.size(); ++i) { - verbose_stream() << mk_pp(b.m_solver.get_formulas()[i], m) << "\n"; + verbose_stream() << mk_pp(b.m_solver.get_formula(i), m) << "\n"; }); scoped_proof _sp(m); proof_ref pr(m); @@ -1154,7 +1162,8 @@ namespace datalog { lbool check() { setup(); - for (unsigned i = 0; ; ++i) { + unsigned max_depth = b.m_ctx.get_params().bmc_linear_unrolling_depth(); + for (unsigned i = 0; i < max_depth; ++i) { IF_VERBOSE(1, verbose_stream() << "level: " << i << "\n";); b.checkpoint(); compile(i); @@ -1167,6 +1176,7 @@ namespace datalog { return res; } } + return l_undef; } private: @@ -1202,6 +1212,7 @@ namespace datalog { } } SASSERT(r); + b.m_rule_trace.push_back(r); mk_rule_vars(*r, level, i, sub); // we have rule, we have variable names of rule. @@ -1284,6 +1295,7 @@ namespace datalog { b.m_fparams.m_model_compact = true; b.m_fparams.m_mbqi = false; // m_fparams.m_auto_config = false; + b.m_rule_trace.reset(); } @@ -1426,7 +1438,8 @@ namespace datalog { m_solver(m, m_fparams), m_rules(ctx), m_query_pred(m), - m_answer(m) { + m_answer(m), + m_rule_trace(ctx.get_rule_manager()) { } bmc::~bmc() {} @@ -1530,6 +1543,10 @@ namespace datalog { return m_answer; } + void bmc::get_rules_along_trace(datalog::rule_ref_vector& rules) { + rules.append(m_rule_trace); + } + void bmc::compile(rule_set const& rules, expr_ref_vector& fmls, unsigned level) { nonlinear nl(*this); nl.compile(rules, fmls, level); diff --git a/src/muz/bmc/dl_bmc_engine.h b/src/muz/bmc/dl_bmc_engine.h index a9ef44066..fd5ce92e6 100644 --- a/src/muz/bmc/dl_bmc_engine.h +++ b/src/muz/bmc/dl_bmc_engine.h @@ -20,11 +20,11 @@ Revision History: #ifndef DL_BMC_ENGINE_H_ #define DL_BMC_ENGINE_H_ -#include "params.h" -#include "statistics.h" -#include "smt_kernel.h" -#include "bv_decl_plugin.h" -#include "smt_params.h" +#include "util/params.h" +#include "util/statistics.h" +#include "smt/smt_kernel.h" +#include "ast/bv_decl_plugin.h" +#include "smt/params/smt_params.h" namespace datalog { @@ -38,6 +38,7 @@ namespace datalog { rule_set m_rules; func_decl_ref m_query_pred; expr_ref m_answer; + rule_ref_vector m_rule_trace; void checkpoint(); @@ -63,6 +64,7 @@ namespace datalog { void collect_statistics(statistics& st) const; void reset_statistics(); + void get_rules_along_trace(datalog::rule_ref_vector& rules); expr_ref get_answer(); diff --git a/src/muz/clp/clp_context.cpp b/src/muz/clp/clp_context.cpp index 7dec835a9..d1ce80e12 100644 --- a/src/muz/clp/clp_context.cpp +++ b/src/muz/clp/clp_context.cpp @@ -17,13 +17,13 @@ Revision History: --*/ -#include "clp_context.h" -#include "dl_context.h" -#include "unifier.h" -#include "var_subst.h" -#include "substitution.h" -#include "smt_kernel.h" -#include "dl_transforms.h" +#include "muz/clp/clp_context.h" +#include "muz/base/dl_context.h" +#include "ast/substitution/unifier.h" +#include "ast/rewriter/var_subst.h" +#include "ast/substitution/substitution.h" +#include "smt/smt_kernel.h" +#include "muz/transforms/dl_transforms.h" namespace datalog { diff --git a/src/muz/clp/clp_context.h b/src/muz/clp/clp_context.h index 214dd891a..44f99d564 100644 --- a/src/muz/clp/clp_context.h +++ b/src/muz/clp/clp_context.h @@ -19,10 +19,10 @@ Revision History: #ifndef CLP_CONTEXT_H_ #define CLP_CONTEXT_H_ -#include "ast.h" -#include "lbool.h" -#include "statistics.h" -#include "dl_engine_base.h" +#include "ast/ast.h" +#include "util/lbool.h" +#include "util/statistics.h" +#include "muz/base/dl_engine_base.h" namespace datalog { class context; diff --git a/src/muz/dataflow/dataflow.cpp b/src/muz/dataflow/dataflow.cpp index 73e152ad7..7908231c5 100644 --- a/src/muz/dataflow/dataflow.cpp +++ b/src/muz/dataflow/dataflow.cpp @@ -15,8 +15,8 @@ Author: --*/ -#include "dataflow.h" -#include "reachability.h" +#include "muz/dataflow/dataflow.h" +#include "muz/dataflow/reachability.h" namespace datalog { diff --git a/src/muz/dataflow/dataflow.h b/src/muz/dataflow/dataflow.h index d2be194eb..5e91a0149 100644 --- a/src/muz/dataflow/dataflow.h +++ b/src/muz/dataflow/dataflow.h @@ -18,10 +18,10 @@ Author: #ifndef DATAFLOW_H_ #define DATAFLOW_H_ -#include "dl_rule.h" -#include "dl_rule_set.h" -#include "hashtable.h" -#include "vector.h" +#include "muz/base/dl_rule.h" +#include "muz/base/dl_rule_set.h" +#include "util/hashtable.h" +#include "util/vector.h" namespace datalog { template class fact_reader; diff --git a/src/muz/dataflow/reachability.h b/src/muz/dataflow/reachability.h index 54da04967..da593a794 100644 --- a/src/muz/dataflow/reachability.h +++ b/src/muz/dataflow/reachability.h @@ -17,7 +17,7 @@ Author: #ifndef REACHABILITY_H_ #define REACHABILITY_H_ -#include "dataflow.h" +#include "muz/dataflow/dataflow.h" namespace datalog { class reachability_info { diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 6863a908f..da1f5392b 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -20,12 +20,12 @@ Revision History: --*/ -#include "ddnf.h" -#include "dl_rule_set.h" -#include "dl_context.h" -#include "scoped_proof.h" -#include "bv_decl_plugin.h" -#include "tbv.h" +#include "muz/ddnf/ddnf.h" +#include "muz/base/dl_rule_set.h" +#include "muz/base/dl_context.h" +#include "ast/scoped_proof.h" +#include "ast/bv_decl_plugin.h" +#include "muz/rel/tbv.h" namespace datalog { @@ -192,10 +192,15 @@ namespace datalog { for (unsigned i = 0; i < new_tbvs.size(); ++i) { tbv const& nt = *new_tbvs[i]; IF_VERBOSE(10, m_tbv.display(verbose_stream() << "insert: ", nt); verbose_stream() << "\n";); - if (contains(nt)) continue; - ddnf_node* n = alloc(ddnf_node, *this, m_tbv, nt, m_noderefs.size()); - m_noderefs.push_back(n); - m_nodes.insert(n); + ddnf_node* n; + if (contains(nt)) { + n = find(nt); + } + else { + n = alloc(ddnf_node, *this, m_tbv, nt, m_noderefs.size()); + m_noderefs.push_back(n); + m_nodes.insert(n); + } insert(*m_root, n, new_tbvs); } return find(t); @@ -275,13 +280,17 @@ namespace datalog { void insert(ddnf_node& root, ddnf_node* new_n, ptr_vector& new_intersections) { tbv const& new_tbv = new_n->get_tbv(); + IF_VERBOSE(10, m_tbv.display(verbose_stream() << "root: ", root.get_tbv()); + m_tbv.display(verbose_stream() << " new node ", new_tbv); verbose_stream() << "\n";); SASSERT(m_tbv.contains(root.get_tbv(), new_tbv)); - if (&root == new_n) return; + if (m_eq(&root, new_n)) return; ++m_stats.m_num_inserts; bool inserted = false; for (unsigned i = 0; i < root.num_children(); ++i) { ddnf_node& child = *(root[i]); ++m_stats.m_num_comparisons; + IF_VERBOSE(10, m_tbv.display(verbose_stream() << "child ", child.get_tbv()); + verbose_stream() << " contains: " << m_tbv.contains(child.get_tbv(), new_tbv) << "\n";); if (m_tbv.contains(child.get_tbv(), new_tbv)) { inserted = true; insert(child, new_n, new_intersections); @@ -299,11 +308,13 @@ namespace datalog { // checking for subset if (m_tbv.contains(new_tbv, child.get_tbv())) { subset_children.push_back(&child); + IF_VERBOSE(10, m_tbv.display(verbose_stream() << "contains child", child.get_tbv()); verbose_stream() << "\n";); ++m_stats.m_num_comparisons; } else if (m_tbv.intersect(child.get_tbv(), new_tbv, *intr)) { // this means there is a non-full intersection new_intersections.push_back(intr); + IF_VERBOSE(10, m_tbv.display(verbose_stream() << "intersect child ", child.get_tbv()); verbose_stream() << "\n";); intr = m_tbv.allocate(); m_stats.m_num_comparisons += 2; } diff --git a/src/muz/ddnf/ddnf.h b/src/muz/ddnf/ddnf.h index 997009026..29e9b1555 100644 --- a/src/muz/ddnf/ddnf.h +++ b/src/muz/ddnf/ddnf.h @@ -19,10 +19,10 @@ Revision History: #ifndef DDNF_H_ #define DDNF_H_ -#include "ast.h" -#include "lbool.h" -#include "statistics.h" -#include "dl_engine_base.h" +#include "ast/ast.h" +#include "util/lbool.h" +#include "util/statistics.h" +#include "muz/base/dl_engine_base.h" class tbv; class tbv_manager; diff --git a/src/muz/duality/duality_dl_interface.cpp b/src/muz/duality/duality_dl_interface.cpp index 978391ad2..5ce4ef957 100755 --- a/src/muz/duality/duality_dl_interface.cpp +++ b/src/muz/duality/duality_dl_interface.cpp @@ -18,26 +18,26 @@ --*/ -#include "dl_context.h" -#include "dl_mk_coi_filter.h" -#include "dl_mk_interp_tail_simplifier.h" -#include "dl_mk_subsumption_checker.h" -#include "dl_mk_rule_inliner.h" -#include "dl_rule.h" -#include "dl_rule_transformer.h" -#include "smt2parser.h" -#include "duality_dl_interface.h" -#include "dl_rule_set.h" -#include "dl_mk_slice.h" -#include "dl_mk_unfold.h" -#include "dl_mk_coalesce.h" -#include "expr_abstract.h" -#include "model_smt2_pp.h" -#include "model_v2_pp.h" -#include "fixedpoint_params.hpp" -#include "used_vars.h" -#include "func_decl_dependencies.h" -#include "dl_transforms.h" +#include "muz/base/dl_context.h" +#include "muz/transforms/dl_mk_coi_filter.h" +#include "muz/transforms/dl_mk_interp_tail_simplifier.h" +#include "muz/transforms/dl_mk_subsumption_checker.h" +#include "muz/transforms/dl_mk_rule_inliner.h" +#include "muz/base/dl_rule.h" +#include "muz/base/dl_rule_transformer.h" +#include "parsers/smt2/smt2parser.h" +#include "muz/duality/duality_dl_interface.h" +#include "muz/base/dl_rule_set.h" +#include "muz/transforms/dl_mk_slice.h" +#include "muz/transforms/dl_mk_unfold.h" +#include "muz/transforms/dl_mk_coalesce.h" +#include "ast/expr_abstract.h" +#include "model/model_smt2_pp.h" +#include "model/model_v2_pp.h" +#include "muz/base/fixedpoint_params.hpp" +#include "ast/used_vars.h" +#include "ast/func_decl_dependencies.h" +#include "muz/transforms/dl_transforms.h" // template class symbol_table; @@ -48,8 +48,8 @@ #pragma warning(disable:4101) #endif -#include "duality.h" -#include "duality_profiling.h" +#include "duality/duality.h" +#include "duality/duality_profiling.h" // using namespace Duality; diff --git a/src/muz/duality/duality_dl_interface.h b/src/muz/duality/duality_dl_interface.h index a7c186074..506642217 100644 --- a/src/muz/duality/duality_dl_interface.h +++ b/src/muz/duality/duality_dl_interface.h @@ -21,11 +21,11 @@ #ifndef DUALITY_DL_INTERFACE_H_ #define DUALITY_DL_INTERFACE_H_ -#include "lbool.h" -#include "dl_rule.h" -#include "dl_rule_set.h" -#include "dl_engine_base.h" -#include "statistics.h" +#include "util/lbool.h" +#include "muz/base/dl_rule.h" +#include "muz/base/dl_rule_set.h" +#include "muz/base/dl_engine_base.h" +#include "util/statistics.h" namespace datalog { class context; @@ -37,7 +37,7 @@ namespace Duality { class dl_interface : public datalog::engine_base { duality_data *_d; - datalog::context &m_ctx; + datalog::context &m_ctx; public: dl_interface(datalog::context& ctx); @@ -69,7 +69,7 @@ namespace Duality { proof_ref get_proof(); - duality_data *dd(){return _d;} + duality_data *dd(){return _d;} private: void display_certificate_non_const(std::ostream& out); diff --git a/src/muz/fp/CMakeLists.txt b/src/muz/fp/CMakeLists.txt index 4a7c4d018..0c5f5e915 100644 --- a/src/muz/fp/CMakeLists.txt +++ b/src/muz/fp/CMakeLists.txt @@ -12,6 +12,7 @@ z3_add_component(fp muz pdr rel + spacer tab TACTIC_HEADERS horn_tactic.h diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index b51af7d53..7191f1931 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -5,13 +5,13 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include"datalog_parser.h" -#include"string_buffer.h" -#include"str_hashtable.h" -#include"ast_pp.h" -#include"arith_decl_plugin.h" -#include"region.h" -#include"warning.h" +#include "muz/fp/datalog_parser.h" +#include "util/string_buffer.h" +#include "util/str_hashtable.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" +#include "util/region.h" +#include "util/warning.h" #include #include #include diff --git a/src/muz/fp/datalog_parser.h b/src/muz/fp/datalog_parser.h index 70b251585..c52fc6589 100644 --- a/src/muz/fp/datalog_parser.h +++ b/src/muz/fp/datalog_parser.h @@ -19,8 +19,8 @@ Revision History: #ifndef DATALOG_PARSER_H_ #define DATALOG_PARSER_H_ -#include "ast.h" -#include "dl_context.h" +#include "ast/ast.h" +#include "muz/base/dl_context.h" namespace datalog { diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 49632b39c..2610f821c 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -15,22 +15,22 @@ Author: Notes: --*/ -#include"cmd_context.h" -#include"dl_cmds.h" -#include"dl_external_relation.h" -#include"dl_context.h" -#include"dl_register_engine.h" -#include"dl_decl_plugin.h" -#include"dl_instruction.h" -#include"dl_compiler.h" -#include"dl_rule.h" -#include"ast_pp.h" -#include"parametric_cmd.h" -#include"cancel_eh.h" -#include"scoped_ctrl_c.h" -#include"scoped_timer.h" -#include"trail.h" -#include"fixedpoint_params.hpp" +#include "cmd_context/cmd_context.h" +#include "muz/fp/dl_cmds.h" +#include "muz/rel/dl_external_relation.h" +#include "muz/base/dl_context.h" +#include "muz/fp/dl_register_engine.h" +#include "ast/dl_decl_plugin.h" +#include "muz/rel/dl_instruction.h" +#include "muz/rel/dl_compiler.h" +#include "muz/base/dl_rule.h" +#include "ast/ast_pp.h" +#include "cmd_context/parametric_cmd.h" +#include "util/cancel_eh.h" +#include "util/scoped_ctrl_c.h" +#include "util/scoped_timer.h" +#include "util/trail.h" +#include "muz/base/fixedpoint_params.hpp" #include @@ -189,11 +189,12 @@ public: m_bound = bound; m_arg_idx++; } - virtual void reset(cmd_context & ctx) { m_dl_ctx->reset(); prepare(ctx); } + virtual void reset(cmd_context & ctx) { m_dl_ctx->reset(); prepare(ctx); m_t = nullptr; } virtual void prepare(cmd_context& ctx) { m_arg_idx = 0; m_name = symbol::null; m_bound = UINT_MAX; } virtual void finalize(cmd_context & ctx) { } virtual void execute(cmd_context & ctx) { + if (!m_t) throw cmd_exception("invalid rule, expected formula"); m_dl_ctx->add_rule(m_t, m_name, m_bound); } }; @@ -374,12 +375,9 @@ class dl_declare_rel_cmd : public cmd { unsigned m_arg_idx; mutable unsigned m_query_arg_idx; symbol m_rel_name; - scoped_ptr m_domain; + ptr_vector m_domain; svector m_kinds; - void ensure_domain(cmd_context& ctx) { - if (!m_domain) m_domain = alloc(sort_ref_vector, ctx.m()); - } public: dl_declare_rel_cmd(dl_context * dl_ctx): @@ -395,7 +393,7 @@ public: ctx.m(); // ensure manager is initialized. m_arg_idx = 0; m_query_arg_idx = 0; - m_domain = 0; + m_domain.reset(); m_kinds.reset(); } virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { @@ -406,8 +404,8 @@ public: } } virtual void set_next_arg(cmd_context & ctx, unsigned num, sort * const * slist) { - ensure_domain(ctx); - m_domain->append(num, slist); + m_domain.reset(); + m_domain.append(num, slist); m_arg_idx++; } virtual void set_next_arg(cmd_context & ctx, symbol const & s) { @@ -424,14 +422,12 @@ public: if(m_arg_idx<2) { throw cmd_exception("at least 2 arguments expected"); } - ensure_domain(ctx); ast_manager& m = ctx.m(); func_decl_ref pred( - m.mk_func_decl(m_rel_name, m_domain->size(), m_domain->c_ptr(), m.mk_bool_sort()), m); + m.mk_func_decl(m_rel_name, m_domain.size(), m_domain.c_ptr(), m.mk_bool_sort()), m); ctx.insert(pred); m_dl_ctx->register_predicate(pred, m_kinds.size(), m_kinds.c_ptr()); - m_domain = 0; } }; diff --git a/src/muz/fp/dl_cmds.h b/src/muz/fp/dl_cmds.h index a06e6140e..326ff2413 100644 --- a/src/muz/fp/dl_cmds.h +++ b/src/muz/fp/dl_cmds.h @@ -18,7 +18,7 @@ Notes: #ifndef DL_CMDS_H_ #define DL_CMDS_H_ -#include "ast.h" +#include "ast/ast.h" class cmd_context; diff --git a/src/muz/fp/dl_register_engine.cpp b/src/muz/fp/dl_register_engine.cpp index 6e1ba40ce..b56a07a7c 100644 --- a/src/muz/fp/dl_register_engine.cpp +++ b/src/muz/fp/dl_register_engine.cpp @@ -16,14 +16,15 @@ Author: Revision History: --*/ -#include "dl_register_engine.h" -#include "dl_bmc_engine.h" -#include "clp_context.h" -#include "tab_context.h" -#include "rel_context.h" -#include "pdr_dl_interface.h" -#include "ddnf.h" -#include "duality_dl_interface.h" +#include "muz/fp/dl_register_engine.h" +#include "muz/bmc/dl_bmc_engine.h" +#include "muz/clp/clp_context.h" +#include "muz/tab/tab_context.h" +#include "muz/rel/rel_context.h" +#include "muz/pdr/pdr_dl_interface.h" +#include "muz/ddnf/ddnf.h" +#include "muz/duality/duality_dl_interface.h" +#include "muz/spacer/spacer_dl_interface.h" namespace datalog { register_engine::register_engine(): m_ctx(0) {} @@ -33,6 +34,8 @@ namespace datalog { case PDR_ENGINE: case QPDR_ENGINE: return alloc(pdr::dl_interface, *m_ctx); + case SPACER_ENGINE: + return alloc(spacer::dl_interface, *m_ctx); case DATALOG_ENGINE: return alloc(rel_context, *m_ctx); case BMC_ENGINE: diff --git a/src/muz/fp/dl_register_engine.h b/src/muz/fp/dl_register_engine.h index 4d5076b75..11f778346 100644 --- a/src/muz/fp/dl_register_engine.h +++ b/src/muz/fp/dl_register_engine.h @@ -19,7 +19,7 @@ Revision History: #ifndef DL_REGISTER_ENGINE_H_ #define DL_REGISTER_ENGINE_H_ -#include "dl_context.h" +#include "muz/base/dl_context.h" namespace datalog { diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index b3e7eeb67..5db57a12c 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -16,20 +16,20 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"model_converter.h" -#include"proof_converter.h" -#include"horn_tactic.h" -#include"dl_context.h" -#include"dl_register_engine.h" -#include"expr_replacer.h" -#include"dl_rule_transformer.h" -#include"dl_mk_slice.h" -#include"filter_model_converter.h" -#include"dl_transforms.h" -#include"fixedpoint_params.hpp" -#include"ast_util.h" -#include"var_subst.h" +#include "tactic/tactical.h" +#include "tactic/model_converter.h" +#include "tactic/proof_converter.h" +#include "muz/fp/horn_tactic.h" +#include "muz/base/dl_context.h" +#include "muz/fp/dl_register_engine.h" +#include "ast/rewriter/expr_replacer.h" +#include "muz/base/dl_rule_transformer.h" +#include "muz/transforms/dl_mk_slice.h" +#include "tactic/filter_model_converter.h" +#include "muz/transforms/dl_transforms.h" +#include "muz/base/fixedpoint_params.hpp" +#include "ast/ast_util.h" +#include "ast/rewriter/var_subst.h" class horn_tactic : public tactic { struct imp { diff --git a/src/muz/fp/horn_tactic.h b/src/muz/fp/horn_tactic.h index 72432b4e2..b48585ee2 100644 --- a/src/muz/fp/horn_tactic.h +++ b/src/muz/fp/horn_tactic.h @@ -19,7 +19,7 @@ Revision History: #ifndef HORN_TACTIC_H_ #define HORN_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/muz/pdr/pdr_closure.cpp b/src/muz/pdr/pdr_closure.cpp index 746b12416..82caf285b 100644 --- a/src/muz/pdr/pdr_closure.cpp +++ b/src/muz/pdr/pdr_closure.cpp @@ -17,10 +17,10 @@ Revision History: --*/ -#include "pdr_closure.h" -#include "pdr_context.h" -#include "expr_safe_replace.h" -#include "ast_util.h" +#include "muz/pdr/pdr_closure.h" +#include "muz/pdr/pdr_context.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/ast_util.h" namespace pdr { diff --git a/src/muz/pdr/pdr_closure.h b/src/muz/pdr/pdr_closure.h index ab417e90e..8af53376b 100644 --- a/src/muz/pdr/pdr_closure.h +++ b/src/muz/pdr/pdr_closure.h @@ -20,7 +20,7 @@ Revision History: #ifndef PDR_CLOSURE_H_ #define PDR_CLOSURE_H_ -#include "arith_decl_plugin.h" +#include "ast/arith_decl_plugin.h" namespace pdr { diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 05bb5489a..37d80e2d6 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -25,31 +25,30 @@ Notes: #include -#include "dl_util.h" -#include "rewriter.h" -#include "rewriter_def.h" -#include "var_subst.h" -#include "util.h" -#include "pdr_prop_solver.h" -#include "pdr_context.h" -#include "pdr_generalizers.h" -#include "for_each_expr.h" -#include "dl_rule_set.h" -#include "unit_subsumption_tactic.h" -#include "model_smt2_pp.h" -#include "dl_mk_rule_inliner.h" -#include "ast_smt2_pp.h" -#include "qe_lite.h" -#include "ast_ll_pp.h" -#include "proof_checker.h" -#include "smt_value_sort.h" -#include "proof_utils.h" -#include "dl_boogie_proof.h" -#include "scoped_proof.h" -#include "blast_term_ite_tactic.h" -#include "model_implicant.h" -#include "expr_safe_replace.h" -#include "ast_util.h" +#include "muz/base/dl_util.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/var_subst.h" +#include "util/util.h" +#include "muz/pdr/pdr_prop_solver.h" +#include "muz/pdr/pdr_context.h" +#include "muz/pdr/pdr_generalizers.h" +#include "ast/for_each_expr.h" +#include "muz/base/dl_rule_set.h" +#include "smt/tactic/unit_subsumption_tactic.h" +#include "model/model_smt2_pp.h" +#include "muz/transforms/dl_mk_rule_inliner.h" +#include "ast/ast_smt2_pp.h" +#include "qe/qe_lite.h" +#include "ast/ast_ll_pp.h" +#include "ast/proofs/proof_checker.h" +#include "smt/smt_value_sort.h" +#include "muz/base/dl_boogie_proof.h" +#include "ast/scoped_proof.h" +#include "tactic/core/blast_term_ite_tactic.h" +#include "model/model_implicant.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/ast_util.h" namespace pdr { @@ -1825,7 +1824,7 @@ namespace pdr { m_core_generalizers.push_back(alloc(core_multi_generalizer, *this, 0)); } if (!classify.is_bool()) { - m.toggle_proof_mode(PGM_FINE); + m.toggle_proof_mode(PGM_ENABLED); m_fparams.m_arith_bound_prop = BP_NONE; m_fparams.m_arith_auto_config_simplex = true; m_fparams.m_arith_propagate_eqs = false; @@ -1835,16 +1834,16 @@ namespace pdr { !m_params.pdr_use_convex_interior_generalizer()) { if (classify.is_dl()) { m_fparams.m_arith_mode = AS_DIFF_LOGIC; - m_fparams.m_arith_expand_eqs = true; + m_fparams.m_arith_eq2ineq = true; } else if (classify.is_utvpi()) { IF_VERBOSE(1, verbose_stream() << "UTVPI\n";); m_fparams.m_arith_mode = AS_UTVPI; - m_fparams.m_arith_expand_eqs = true; + m_fparams.m_arith_eq2ineq = true; } else { m_fparams.m_arith_mode = AS_ARITH; - m_fparams.m_arith_expand_eqs = false; + m_fparams.m_arith_eq2ineq = false; } } } diff --git a/src/muz/pdr/pdr_context.h b/src/muz/pdr/pdr_context.h index a32a65c48..f160cff6a 100644 --- a/src/muz/pdr/pdr_context.h +++ b/src/muz/pdr/pdr_context.h @@ -25,10 +25,10 @@ Revision History: #undef max #endif #include -#include "pdr_manager.h" -#include "pdr_prop_solver.h" -#include "pdr_reachable_cache.h" -#include "fixedpoint_params.hpp" +#include "muz/pdr/pdr_manager.h" +#include "muz/pdr/pdr_prop_solver.h" +#include "muz/pdr/pdr_reachable_cache.h" +#include "muz/base/fixedpoint_params.hpp" namespace datalog { diff --git a/src/muz/pdr/pdr_dl_interface.cpp b/src/muz/pdr/pdr_dl_interface.cpp index 5f4a200fc..87bc68bd9 100644 --- a/src/muz/pdr/pdr_dl_interface.cpp +++ b/src/muz/pdr/pdr_dl_interface.cpp @@ -17,19 +17,19 @@ Revision History: --*/ -#include "dl_context.h" -#include "dl_mk_coi_filter.h" -#include "dl_rule.h" -#include "dl_rule_transformer.h" -#include "pdr_context.h" -#include "pdr_dl_interface.h" -#include "dl_rule_set.h" -#include "dl_mk_slice.h" -#include "dl_mk_unfold.h" -#include "dl_mk_coalesce.h" -#include "dl_transforms.h" -#include "scoped_proof.h" -#include "model_smt2_pp.h" +#include "muz/base/dl_context.h" +#include "muz/transforms/dl_mk_coi_filter.h" +#include "muz/base/dl_rule.h" +#include "muz/base/dl_rule_transformer.h" +#include "muz/pdr/pdr_context.h" +#include "muz/pdr/pdr_dl_interface.h" +#include "muz/base/dl_rule_set.h" +#include "muz/transforms/dl_mk_slice.h" +#include "muz/transforms/dl_mk_unfold.h" +#include "muz/transforms/dl_mk_coalesce.h" +#include "muz/transforms/dl_transforms.h" +#include "ast/scoped_proof.h" +#include "model/model_smt2_pp.h" using namespace pdr; diff --git a/src/muz/pdr/pdr_dl_interface.h b/src/muz/pdr/pdr_dl_interface.h index 008655a0b..884f89e4b 100644 --- a/src/muz/pdr/pdr_dl_interface.h +++ b/src/muz/pdr/pdr_dl_interface.h @@ -20,12 +20,12 @@ Revision History: #ifndef PDR_DL_INTERFACE_H_ #define PDR_DL_INTERFACE_H_ -#include "lbool.h" -#include "dl_rule.h" -#include "dl_rule_set.h" -#include "dl_util.h" -#include "dl_engine_base.h" -#include "statistics.h" +#include "util/lbool.h" +#include "muz/base/dl_rule.h" +#include "muz/base/dl_rule_set.h" +#include "muz/base/dl_util.h" +#include "muz/base/dl_engine_base.h" +#include "util/statistics.h" namespace datalog { class context; diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index 54d9ada89..4a77d2f5f 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -18,21 +18,21 @@ Revision History: --*/ -#include "ast_smt2_pp.h" -#include "array_decl_plugin.h" -#include "bool_rewriter.h" -#include "dl_decl_plugin.h" -#include "for_each_expr.h" -#include "dl_util.h" -#include "rewriter.h" -#include "rewriter_def.h" -#include "pdr_util.h" -#include "pdr_farkas_learner.h" -#include "th_rewriter.h" -#include "ast_ll_pp.h" -#include "arith_bounds_tactic.h" -#include "proof_utils.h" -#include "reg_decl_plugins.h" +#include "ast/ast_smt2_pp.h" +#include "ast/array_decl_plugin.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/dl_decl_plugin.h" +#include "ast/for_each_expr.h" +#include "muz/base/dl_util.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "muz/pdr/pdr_util.h" +#include "muz/pdr/pdr_farkas_learner.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/ast_ll_pp.h" +#include "tactic/arith/arith_bounds_tactic.h" +#include "ast/proofs/proof_utils.h" +#include "ast/reg_decl_plugins.h" namespace pdr { @@ -372,7 +372,7 @@ namespace pdr { farkas_learner::farkas_learner(smt_params& params, ast_manager& outer_mgr) : m_proof_params(get_proof_params(params)), - m_pr(PGM_FINE), + m_pr(PGM_ENABLED), m_constr(0), m_combine_farkas_coefficients(true), p2o(m_pr, outer_mgr), @@ -733,8 +733,8 @@ namespace pdr { } else { expr_set* hyps3 = alloc(expr_set); - datalog::set_union(*hyps3, *hyps); - datalog::set_union(*hyps3, *hyps2); + set_union(*hyps3, *hyps); + set_union(*hyps3, *hyps2); hyps = hyps3; hyprefs.push_back(hyps); } @@ -795,7 +795,7 @@ namespace pdr { case PR_LEMMA: { expr_set* hyps2 = alloc(expr_set); hyprefs.push_back(hyps2); - datalog::set_union(*hyps2, *hyps); + set_union(*hyps2, *hyps); hyps = hyps2; expr* fml = m.get_fact(p); hyps->remove(fml); diff --git a/src/muz/pdr/pdr_farkas_learner.h b/src/muz/pdr/pdr_farkas_learner.h index 3a4d81f96..a5f3482e6 100644 --- a/src/muz/pdr/pdr_farkas_learner.h +++ b/src/muz/pdr/pdr_farkas_learner.h @@ -20,14 +20,14 @@ Revision History: #ifndef PDR_FARKAS_LEARNER_H_ #define PDR_FARKAS_LEARNER_H_ -#include "arith_decl_plugin.h" -#include "ast_translation.h" -#include "bv_decl_plugin.h" -#include "smt_kernel.h" -#include "bool_rewriter.h" -#include "pdr_util.h" -#include "smt_params.h" -#include "tactic.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_translation.h" +#include "ast/bv_decl_plugin.h" +#include "smt/smt_kernel.h" +#include "ast/rewriter/bool_rewriter.h" +#include "muz/pdr/pdr_util.h" +#include "smt/params/smt_params.h" +#include "tactic/tactic.h" namespace pdr { diff --git a/src/muz/pdr/pdr_generalizers.cpp b/src/muz/pdr/pdr_generalizers.cpp index 5b7e11877..094379a0b 100644 --- a/src/muz/pdr/pdr_generalizers.cpp +++ b/src/muz/pdr/pdr_generalizers.cpp @@ -18,13 +18,13 @@ Revision History: --*/ -#include "pdr_context.h" -#include "pdr_farkas_learner.h" -#include "pdr_generalizers.h" -#include "expr_abstract.h" -#include "var_subst.h" -#include "expr_safe_replace.h" -#include "model_smt2_pp.h" +#include "muz/pdr/pdr_context.h" +#include "muz/pdr/pdr_farkas_learner.h" +#include "muz/pdr/pdr_generalizers.h" +#include "ast/expr_abstract.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "model/model_smt2_pp.h" namespace pdr { @@ -81,7 +81,7 @@ namespace pdr { m_gen(n, core0, uses_level1); new_cores.push_back(std::make_pair(core0, uses_level1)); obj_hashtable core_exprs, core1_exprs; - datalog::set_union(core_exprs, core0); + set_union(core_exprs, core0); for (unsigned i = 0; i < old_core.size(); ++i) { expr* lit = old_core[i].get(); if (core_exprs.contains(lit)) { @@ -94,8 +94,8 @@ namespace pdr { if (core1.size() < old_core.size()) { new_cores.push_back(std::make_pair(core1, uses_level1)); core1_exprs.reset(); - datalog::set_union(core1_exprs, core1); - datalog::set_intersection(core_exprs, core1_exprs); + set_union(core1_exprs, core1); + set_intersection(core_exprs, core1_exprs); } } } diff --git a/src/muz/pdr/pdr_generalizers.h b/src/muz/pdr/pdr_generalizers.h index 3e4576fa1..e0feda310 100644 --- a/src/muz/pdr/pdr_generalizers.h +++ b/src/muz/pdr/pdr_generalizers.h @@ -20,9 +20,9 @@ Revision History: #ifndef PDR_GENERALIZERS_H_ #define PDR_GENERALIZERS_H_ -#include "pdr_context.h" -#include "pdr_closure.h" -#include "arith_decl_plugin.h" +#include "muz/pdr/pdr_context.h" +#include "muz/pdr/pdr_closure.h" +#include "ast/arith_decl_plugin.h" namespace pdr { @@ -88,7 +88,7 @@ namespace pdr { virtual ~core_convex_hull_generalizer() {} virtual void operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); virtual void operator()(model_node& n, expr_ref_vector& core, bool& uses_level); - }; + }; class core_multi_generalizer : public core_generalizer { core_bool_inductive_generalizer m_gen; diff --git a/src/muz/pdr/pdr_manager.cpp b/src/muz/pdr/pdr_manager.cpp index 319f38255..077d27427 100644 --- a/src/muz/pdr/pdr_manager.cpp +++ b/src/muz/pdr/pdr_manager.cpp @@ -19,15 +19,15 @@ Revision History: --*/ #include -#include "pdr_manager.h" -#include "ast_smt2_pp.h" -#include "for_each_expr.h" -#include "has_free_vars.h" -#include "expr_replacer.h" -#include "expr_abstract.h" -#include "model2expr.h" -#include "model_smt2_pp.h" -#include "model_converter.h" +#include "muz/pdr/pdr_manager.h" +#include "ast/ast_smt2_pp.h" +#include "ast/for_each_expr.h" +#include "ast/has_free_vars.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/expr_abstract.h" +#include "model/model2expr.h" +#include "model/model_smt2_pp.h" +#include "tactic/model_converter.h" namespace pdr { diff --git a/src/muz/pdr/pdr_manager.h b/src/muz/pdr/pdr_manager.h index 790e2465d..9fc98940d 100644 --- a/src/muz/pdr/pdr_manager.h +++ b/src/muz/pdr/pdr_manager.h @@ -23,17 +23,17 @@ Revision History: #include #include -#include "bool_rewriter.h" -#include "expr_replacer.h" -#include "expr_substitution.h" -#include "map.h" -#include "ref_vector.h" -#include "smt_kernel.h" -#include "pdr_util.h" -#include "pdr_sym_mux.h" -#include "pdr_farkas_learner.h" -#include "pdr_smt_context_manager.h" -#include "dl_rule.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/expr_substitution.h" +#include "util/map.h" +#include "util/ref_vector.h" +#include "smt/smt_kernel.h" +#include "muz/pdr/pdr_util.h" +#include "muz/pdr/pdr_sym_mux.h" +#include "muz/pdr/pdr_farkas_learner.h" +#include "muz/pdr/pdr_smt_context_manager.h" +#include "muz/base/dl_rule.h" namespace smt { diff --git a/src/muz/pdr/pdr_prop_solver.cpp b/src/muz/pdr/pdr_prop_solver.cpp index 8c407161e..3055985f4 100644 --- a/src/muz/pdr/pdr_prop_solver.cpp +++ b/src/muz/pdr/pdr_prop_solver.cpp @@ -18,18 +18,18 @@ Revision History: --*/ #include -#include "model.h" -#include "pdr_util.h" -#include "pdr_prop_solver.h" -#include "ast_smt2_pp.h" -#include "dl_util.h" -#include "model_pp.h" -#include "smt_params.h" -#include "datatype_decl_plugin.h" -#include "bv_decl_plugin.h" -#include "pdr_farkas_learner.h" -#include "ast_smt2_pp.h" -#include "expr_replacer.h" +#include "model/model.h" +#include "muz/pdr/pdr_util.h" +#include "muz/pdr/pdr_prop_solver.h" +#include "ast/ast_smt2_pp.h" +#include "muz/base/dl_util.h" +#include "model/model_pp.h" +#include "smt/params/smt_params.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "muz/pdr/pdr_farkas_learner.h" +#include "ast/ast_smt2_pp.h" +#include "ast/rewriter/expr_replacer.h" // // Auxiliary structure to introduce propositional names for assumptions that are not diff --git a/src/muz/pdr/pdr_prop_solver.h b/src/muz/pdr/pdr_prop_solver.h index ad7e1fd9a..463163fbd 100644 --- a/src/muz/pdr/pdr_prop_solver.h +++ b/src/muz/pdr/pdr_prop_solver.h @@ -23,13 +23,13 @@ Revision History: #include #include #include -#include "ast.h" -#include "obj_hashtable.h" -#include "smt_kernel.h" -#include "util.h" -#include "vector.h" -#include "pdr_manager.h" -#include "pdr_smt_context_manager.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "smt/smt_kernel.h" +#include "util/util.h" +#include "util/vector.h" +#include "muz/pdr/pdr_manager.h" +#include "muz/pdr/pdr_smt_context_manager.h" namespace pdr { diff --git a/src/muz/pdr/pdr_reachable_cache.cpp b/src/muz/pdr/pdr_reachable_cache.cpp index 2bedc1393..d28c1415b 100644 --- a/src/muz/pdr/pdr_reachable_cache.cpp +++ b/src/muz/pdr/pdr_reachable_cache.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include "pdr_reachable_cache.h" +#include "muz/pdr/pdr_reachable_cache.h" namespace pdr { diff --git a/src/muz/pdr/pdr_reachable_cache.h b/src/muz/pdr/pdr_reachable_cache.h index 66832ba42..0833541ba 100644 --- a/src/muz/pdr/pdr_reachable_cache.h +++ b/src/muz/pdr/pdr_reachable_cache.h @@ -20,10 +20,10 @@ Revision History: #ifndef REACHABLE_CACHE_H_ #define REACHABLE_CACHE_H_ -#include "ast.h" -#include "ref_vector.h" -#include "pdr_manager.h" -#include "pdr_smt_context_manager.h" +#include "ast/ast.h" +#include "util/ref_vector.h" +#include "muz/pdr/pdr_manager.h" +#include "muz/pdr/pdr_smt_context_manager.h" namespace pdr { class reachable_cache { diff --git a/src/muz/pdr/pdr_smt_context_manager.cpp b/src/muz/pdr/pdr_smt_context_manager.cpp index b6aa8411d..b87d1e451 100644 --- a/src/muz/pdr/pdr_smt_context_manager.cpp +++ b/src/muz/pdr/pdr_smt_context_manager.cpp @@ -17,12 +17,12 @@ Revision History: --*/ -#include "pdr_smt_context_manager.h" -#include "has_free_vars.h" -#include "ast_pp.h" -#include "ast_smt_pp.h" +#include "muz/pdr/pdr_smt_context_manager.h" +#include "ast/has_free_vars.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt_pp.h" #include -#include "smt_params.h" +#include "smt/params/smt_params.h" namespace pdr { @@ -83,7 +83,7 @@ namespace pdr { { ast_smt_pp pp(m); for (unsigned i = 0; i < m_context.size(); ++i) { - pp.add_assumption(m_context.get_formulas()[i]); + pp.add_assumption(m_context.get_formula(i)); } for (unsigned i = 0; i < assumptions.size(); ++i) { pp.add_assumption(assumptions[i].get()); diff --git a/src/muz/pdr/pdr_smt_context_manager.h b/src/muz/pdr/pdr_smt_context_manager.h index 173367a41..735b2cd62 100644 --- a/src/muz/pdr/pdr_smt_context_manager.h +++ b/src/muz/pdr/pdr_smt_context_manager.h @@ -20,9 +20,9 @@ Revision History: #ifndef PDR_SMT_CONTEXT_MANAGER_H_ #define PDR_SMT_CONTEXT_MANAGER_H_ -#include "smt_kernel.h" -#include "func_decl_dependencies.h" -#include "dl_util.h" +#include "smt/smt_kernel.h" +#include "ast/func_decl_dependencies.h" +#include "muz/base/dl_util.h" namespace pdr { diff --git a/src/muz/pdr/pdr_sym_mux.cpp b/src/muz/pdr/pdr_sym_mux.cpp index 47edb35ac..72549f2d6 100644 --- a/src/muz/pdr/pdr_sym_mux.cpp +++ b/src/muz/pdr/pdr_sym_mux.cpp @@ -18,13 +18,13 @@ Revision History: --*/ #include -#include "ast_pp.h" -#include "for_each_expr.h" -#include "model.h" -#include "rewriter.h" -#include "rewriter_def.h" -#include "pdr_util.h" -#include "pdr_sym_mux.h" +#include "ast/ast_pp.h" +#include "ast/for_each_expr.h" +#include "model/model.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "muz/pdr/pdr_util.h" +#include "muz/pdr/pdr_sym_mux.h" using namespace pdr; diff --git a/src/muz/pdr/pdr_sym_mux.h b/src/muz/pdr/pdr_sym_mux.h index 13bdb71ec..981dc9615 100644 --- a/src/muz/pdr/pdr_sym_mux.h +++ b/src/muz/pdr/pdr_sym_mux.h @@ -20,9 +20,9 @@ Revision History: #ifndef SYM_MUX_H_ #define SYM_MUX_H_ -#include "ast.h" -#include "map.h" -#include "vector.h" +#include "ast/ast.h" +#include "util/map.h" +#include "util/vector.h" #include class model_core; diff --git a/src/muz/pdr/pdr_util.cpp b/src/muz/pdr/pdr_util.cpp index 934be5c63..19ffdeeec 100644 --- a/src/muz/pdr/pdr_util.cpp +++ b/src/muz/pdr/pdr_util.cpp @@ -22,29 +22,26 @@ Notes: --*/ #include -#include "arith_simplifier_plugin.h" -#include "array_decl_plugin.h" -#include "ast_pp.h" -#include "basic_simplifier_plugin.h" -#include "bv_simplifier_plugin.h" -#include "bool_rewriter.h" -#include "dl_util.h" -#include "for_each_expr.h" -#include "smt_params.h" -#include "model.h" -#include "ref_vector.h" -#include "rewriter.h" -#include "rewriter_def.h" -#include "util.h" -#include "pdr_manager.h" -#include "pdr_util.h" -#include "arith_decl_plugin.h" -#include "expr_replacer.h" -#include "model_smt2_pp.h" -#include "poly_rewriter.h" -#include "poly_rewriter_def.h" -#include "arith_rewriter.h" -#include "scoped_proof.h" +#include "util/util.h" +#include "util/ref_vector.h" +#include "ast/array_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/for_each_expr.h" +#include "ast/scoped_proof.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/poly_rewriter.h" +#include "ast/rewriter/poly_rewriter_def.h" +#include "ast/rewriter/arith_rewriter.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "smt/params/smt_params.h" +#include "model/model.h" +#include "muz/base/dl_util.h" +#include "muz/pdr/pdr_manager.h" +#include "muz/pdr/pdr_util.h" +#include "model/model_smt2_pp.h" diff --git a/src/muz/pdr/pdr_util.h b/src/muz/pdr/pdr_util.h index 09fad8a30..51f6978ec 100644 --- a/src/muz/pdr/pdr_util.h +++ b/src/muz/pdr/pdr_util.h @@ -20,16 +20,16 @@ Revision History: #ifndef PDR_UTIL_H_ #define PDR_UTIL_H_ -#include "ast.h" -#include "ast_pp.h" -#include "obj_hashtable.h" -#include "ref_vector.h" -#include "simplifier.h" -#include "trace.h" -#include "vector.h" -#include "arith_decl_plugin.h" -#include "array_decl_plugin.h" -#include "bv_decl_plugin.h" +#include "ast/ast.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "util/obj_hashtable.h" +#include "util/ref_vector.h" +#include "util/trace.h" +#include "util/vector.h" +#include "ast/arith_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/bv_decl_plugin.h" class model; diff --git a/src/muz/rel/aig_exporter.cpp b/src/muz/rel/aig_exporter.cpp index ca0030fc3..bc98ab1f8 100644 --- a/src/muz/rel/aig_exporter.cpp +++ b/src/muz/rel/aig_exporter.cpp @@ -11,8 +11,8 @@ Abstract: --*/ -#include "aig_exporter.h" -#include "dl_context.h" +#include "muz/rel/aig_exporter.h" +#include "muz/base/dl_context.h" #include namespace datalog { diff --git a/src/muz/rel/aig_exporter.h b/src/muz/rel/aig_exporter.h index 71af6fb35..ea241fe2b 100644 --- a/src/muz/rel/aig_exporter.h +++ b/src/muz/rel/aig_exporter.h @@ -14,11 +14,11 @@ Abstract: #ifndef AIG_EXPORTER_H_ #define AIG_EXPORTER_H_ -#include "aig.h" -#include "dl_rule_set.h" +#include "tactic/aig/aig.h" +#include "muz/base/dl_rule_set.h" #include #include -#include "rel_context.h" +#include "muz/rel/rel_context.h" namespace datalog { class aig_exporter { diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index e630d7083..ddda295cd 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -4,10 +4,10 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "check_relation.h" -#include "dl_relation_manager.h" -#include "ast_util.h" -#include "smt_kernel.h" +#include "muz/rel/check_relation.h" +#include "muz/rel/dl_relation_manager.h" +#include "ast/ast_util.h" +#include "smt/smt_kernel.h" #include diff --git a/src/muz/rel/check_relation.h b/src/muz/rel/check_relation.h index c91567553..0fbb2a269 100644 --- a/src/muz/rel/check_relation.h +++ b/src/muz/rel/check_relation.h @@ -22,8 +22,8 @@ Revision History: #ifndef CHECK_RELATION_H_ #define CHECK_RELATION_H_ -#include "doc.h" -#include "dl_base.h" +#include "muz/rel/doc.h" +#include "muz/rel/dl_base.h" namespace datalog { class check_relation_plugin; diff --git a/src/muz/rel/dl_base.cpp b/src/muz/rel/dl_base.cpp index f79f6c8eb..904faf71f 100644 --- a/src/muz/rel/dl_base.cpp +++ b/src/muz/rel/dl_base.cpp @@ -18,13 +18,13 @@ Revision History: --*/ -#include"ast_pp.h" -#include"union_find.h" -#include"vector.h" -#include"dl_context.h" -#include"dl_base.h" -#include"bool_rewriter.h" -#include"dl_relation_manager.h" +#include "ast/ast_pp.h" +#include "util/union_find.h" +#include "util/vector.h" +#include "muz/base/dl_context.h" +#include "muz/rel/dl_base.h" +#include "ast/rewriter/bool_rewriter.h" +#include "muz/rel/dl_relation_manager.h" #include diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index d3422f882..4e59e9258 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -23,12 +23,12 @@ Revision History: #include -#include"ast.h" -#include"map.h" -#include"vector.h" -#include"ref.h" -#include"dl_util.h" -#include"dl_context.h" +#include "ast/ast.h" +#include "util/map.h" +#include "util/vector.h" +#include "util/ref.h" +#include "muz/base/dl_util.h" +#include "muz/base/dl_context.h" namespace datalog { diff --git a/src/muz/rel/dl_bound_relation.cpp b/src/muz/rel/dl_bound_relation.cpp index 182046c1e..9dc0eb8d5 100644 --- a/src/muz/rel/dl_bound_relation.cpp +++ b/src/muz/rel/dl_bound_relation.cpp @@ -17,9 +17,9 @@ Revision History: --*/ -#include "dl_bound_relation.h" -#include "debug.h" -#include "ast_pp.h" +#include "muz/rel/dl_bound_relation.h" +#include "util/debug.h" +#include "ast/ast_pp.h" namespace datalog { @@ -653,7 +653,7 @@ namespace datalog { void bound_relation::to_formula(expr_ref& fml) const { ast_manager& m = get_plugin().get_ast_manager(); arith_util& arith = get_plugin().m_arith; - basic_simplifier_plugin& bsimp = get_plugin().m_bsimp; + bool_rewriter& bsimp = get_plugin().m_bsimp; expr_ref_vector conjs(m); relation_signature const& sig = get_signature(); for (unsigned i = 0; i < sig.size(); ++i) { diff --git a/src/muz/rel/dl_bound_relation.h b/src/muz/rel/dl_bound_relation.h index 485dfbafa..3dec9d313 100644 --- a/src/muz/rel/dl_bound_relation.h +++ b/src/muz/rel/dl_bound_relation.h @@ -19,14 +19,14 @@ Revision History: #ifndef DL_BOUND_RELATION_H_ #define DL_BOUND_RELATION_H_ -#include "dl_context.h" -#include "dl_relation_manager.h" -#include "dl_base.h" -#include "uint_set.h" -#include "dl_vector_relation.h" -#include "dl_interval_relation.h" -#include "arith_decl_plugin.h" -#include "basic_simplifier_plugin.h" +#include "muz/base/dl_context.h" +#include "muz/rel/dl_relation_manager.h" +#include "muz/rel/dl_base.h" +#include "util/uint_set.h" +#include "muz/rel/dl_vector_relation.h" +#include "muz/rel/dl_interval_relation.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/bool_rewriter.h" namespace datalog { @@ -44,7 +44,7 @@ namespace datalog { class filter_interpreted_fn; class filter_intersection_fn; arith_util m_arith; - basic_simplifier_plugin m_bsimp; + bool_rewriter m_bsimp; public: bound_relation_plugin(relation_manager& m); virtual bool can_handle_signature(const relation_signature & s); diff --git a/src/muz/rel/dl_check_table.cpp b/src/muz/rel/dl_check_table.cpp index ea4003e5f..0c4be18f1 100644 --- a/src/muz/rel/dl_check_table.cpp +++ b/src/muz/rel/dl_check_table.cpp @@ -19,8 +19,8 @@ Revision History: --*/ -#include "dl_check_table.h" -#include "dl_table.h" +#include "muz/rel/dl_check_table.h" +#include "muz/rel/dl_table.h" namespace datalog { diff --git a/src/muz/rel/dl_check_table.h b/src/muz/rel/dl_check_table.h index 35f399452..412dd2dbc 100644 --- a/src/muz/rel/dl_check_table.h +++ b/src/muz/rel/dl_check_table.h @@ -21,9 +21,9 @@ Revision History: #ifndef DL_CHECK_TABLE_H_ #define DL_CHECK_TABLE_H_ -#include "dl_base.h" -#include "dl_decl_plugin.h" -#include "dl_relation_manager.h" +#include "muz/rel/dl_base.h" +#include "ast/dl_decl_plugin.h" +#include "muz/rel/dl_relation_manager.h" namespace datalog { class check_table; diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 0d4507971..32bcfed50 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -19,15 +19,15 @@ Revision History: #include -#include"ref_vector.h" -#include"dl_context.h" -#include"rel_context.h" -#include"dl_rule.h" -#include"dl_util.h" -#include"dl_compiler.h" -#include"ast_pp.h" +#include "util/ref_vector.h" +#include "muz/base/dl_context.h" +#include "muz/rel/rel_context.h" +#include "muz/base/dl_rule.h" +#include "muz/base/dl_util.h" +#include "muz/rel/dl_compiler.h" +#include "ast/ast_pp.h" // include"ast_smt2_pp.h" -#include"ast_util.h" +#include "ast/ast_util.h" namespace datalog { diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 33d92d805..9aedf141a 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -23,16 +23,16 @@ Revision History: #include #include -#include "ast.h" -#include "hashtable.h" -#include "map.h" -#include "obj_pair_hashtable.h" -#include "ref_vector.h" -#include "vector.h" +#include "ast/ast.h" +#include "util/hashtable.h" +#include "util/map.h" +#include "util/obj_pair_hashtable.h" +#include "util/ref_vector.h" +#include "util/vector.h" -#include "dl_base.h" -#include "dl_context.h" -#include "dl_instruction.h" +#include "muz/rel/dl_base.h" +#include "muz/base/dl_context.h" +#include "muz/rel/dl_instruction.h" namespace datalog { diff --git a/src/muz/rel/dl_external_relation.cpp b/src/muz/rel/dl_external_relation.cpp index e9c24abd3..ff9bef40e 100644 --- a/src/muz/rel/dl_external_relation.cpp +++ b/src/muz/rel/dl_external_relation.cpp @@ -17,11 +17,11 @@ Revision History: --*/ -#include "debug.h" -#include "ast_pp.h" -#include "dl_context.h" -#include "dl_external_relation.h" -#include "dl_decl_plugin.h" +#include "util/debug.h" +#include "ast/ast_pp.h" +#include "muz/base/dl_context.h" +#include "muz/rel/dl_external_relation.h" +#include "ast/dl_decl_plugin.h" namespace datalog { diff --git a/src/muz/rel/dl_external_relation.h b/src/muz/rel/dl_external_relation.h index 0bd78b776..0dfb4a7f2 100644 --- a/src/muz/rel/dl_external_relation.h +++ b/src/muz/rel/dl_external_relation.h @@ -19,7 +19,7 @@ Revision History: #ifndef DL_EXTERNAL_RELATION_H_ #define DL_EXTERNAL_RELATION_H_ -#include "dl_base.h" +#include "muz/rel/dl_base.h" namespace datalog { diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index 879e29699..c036d3cfd 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -19,11 +19,11 @@ Revision History: #include -#include"dl_context.h" -#include"dl_relation_manager.h" -#include"dl_table_relation.h" -#include"dl_finite_product_relation.h" -#include"bool_rewriter.h" +#include "muz/base/dl_context.h" +#include "muz/rel/dl_relation_manager.h" +#include "muz/rel/dl_table_relation.h" +#include "muz/rel/dl_finite_product_relation.h" +#include "ast/rewriter/bool_rewriter.h" namespace datalog { diff --git a/src/muz/rel/dl_finite_product_relation.h b/src/muz/rel/dl_finite_product_relation.h index e91ab4a17..946296df1 100644 --- a/src/muz/rel/dl_finite_product_relation.h +++ b/src/muz/rel/dl_finite_product_relation.h @@ -20,9 +20,9 @@ Revision History: #define DL_FINITE_PRODUCT_RELATION_H_ -#include "dl_base.h" -#include "dl_relation_manager.h" -#include "dl_table_relation.h" +#include "muz/rel/dl_base.h" +#include "muz/rel/dl_relation_manager.h" +#include "muz/rel/dl_table_relation.h" namespace datalog { diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index f0b88cae1..fb718d8b8 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -17,14 +17,14 @@ Revision History: --*/ -#include"ast_pp.h" -#include"stopwatch.h" -#include"dl_context.h" -#include"dl_util.h" -#include"dl_instruction.h" -#include"rel_context.h" -#include"debug.h" -#include"warning.h" +#include "ast/ast_pp.h" +#include "util/stopwatch.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_util.h" +#include "muz/rel/dl_instruction.h" +#include "muz/rel/rel_context.h" +#include "util/debug.h" +#include "util/warning.h" namespace datalog { diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h index 196f5268c..56dd249a5 100644 --- a/src/muz/rel/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -22,11 +22,11 @@ Revision History: #include #include #include -#include "ast.h" -#include "vector.h" -#include "dl_base.h" -#include "dl_costs.h" -#include "dl_context.h" +#include "ast/ast.h" +#include "util/vector.h" +#include "muz/rel/dl_base.h" +#include "muz/base/dl_costs.h" +#include "muz/base/dl_context.h" namespace datalog { @@ -128,7 +128,7 @@ namespace datalog { void set_reg(reg_idx i, reg_type val) { if (i >= m_registers.size()) { check_overflow(i); - m_registers.resize(i+1,0); + m_registers.resize(i+1); } if (m_registers[i]) { m_registers[i]->deallocate(); diff --git a/src/muz/rel/dl_interval_relation.cpp b/src/muz/rel/dl_interval_relation.cpp index 88c262cbe..e14d242bb 100644 --- a/src/muz/rel/dl_interval_relation.cpp +++ b/src/muz/rel/dl_interval_relation.cpp @@ -17,12 +17,11 @@ Revision History: --*/ -#include "debug.h" -#include "optional.h" -#include "ast_pp.h" -#include "dl_interval_relation.h" -#include "dl_relation_manager.h" -#include "bool_rewriter.h" +#include "util/debug.h" +#include "ast/ast_pp.h" +#include "muz/rel/dl_interval_relation.h" +#include "muz/rel/dl_relation_manager.h" +#include "ast/rewriter/bool_rewriter.h" namespace datalog { diff --git a/src/muz/rel/dl_interval_relation.h b/src/muz/rel/dl_interval_relation.h index a8239ef24..a9cce9802 100644 --- a/src/muz/rel/dl_interval_relation.h +++ b/src/muz/rel/dl_interval_relation.h @@ -20,13 +20,12 @@ Revision History: #define DL_INTERVAL_RELATION_H_ -#include "dl_context.h" -#include "dl_relation_manager.h" -#include "dl_base.h" -#include "old_interval.h" -#include "dl_vector_relation.h" -#include "arith_decl_plugin.h" -#include "basic_simplifier_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "smt/old_interval.h" +#include "muz/base/dl_context.h" +#include "muz/rel/dl_relation_manager.h" +#include "muz/rel/dl_base.h" +#include "muz/rel/dl_vector_relation.h" namespace datalog { diff --git a/src/muz/rel/dl_lazy_table.cpp b/src/muz/rel/dl_lazy_table.cpp index ec97a4bf5..54105891a 100644 --- a/src/muz/rel/dl_lazy_table.cpp +++ b/src/muz/rel/dl_lazy_table.cpp @@ -17,8 +17,8 @@ Revision History: --*/ -#include "dl_lazy_table.h" -#include "dl_relation_manager.h" +#include "muz/rel/dl_lazy_table.h" +#include "muz/rel/dl_relation_manager.h" #include namespace datalog { diff --git a/src/muz/rel/dl_lazy_table.h b/src/muz/rel/dl_lazy_table.h index 28360c95f..6752e5a5a 100644 --- a/src/muz/rel/dl_lazy_table.h +++ b/src/muz/rel/dl_lazy_table.h @@ -21,8 +21,8 @@ Revision History: #ifndef DL_LAZY_TABLE_H_ #define DL_LAZY_TABLE_H_ -#include "dl_base.h" -#include "ref.h" +#include "muz/rel/dl_base.h" +#include "util/ref.h" namespace datalog { diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index 7fcbdaaff..c4fb57eeb 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -19,12 +19,12 @@ Revision History: #include -#include"ast_pp.h" -#include"ast_smt_pp.h" -#include"dl_finite_product_relation.h" -#include"dl_product_relation.h" -#include"dl_sieve_relation.h" -#include"dl_mk_explanations.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt_pp.h" +#include "muz/rel/dl_finite_product_relation.h" +#include "muz/rel/dl_product_relation.h" +#include "muz/rel/dl_sieve_relation.h" +#include "muz/rel/dl_mk_explanations.h" namespace datalog { @@ -465,7 +465,7 @@ namespace datalog { unsigned sz = r.get_signature().size(); ptr_vector subst_arg; - subst_arg.resize(sz, 0); + subst_arg.resize(sz); unsigned ofs = sz-1; for (unsigned i=0; i #include -#include"dl_mk_similarity_compressor.h" -#include"dl_relation_manager.h" +#include "muz/rel/dl_mk_similarity_compressor.h" +#include "muz/rel/dl_relation_manager.h" namespace datalog { diff --git a/src/muz/rel/dl_mk_similarity_compressor.h b/src/muz/rel/dl_mk_similarity_compressor.h index 9ecbf7bfb..096305c59 100644 --- a/src/muz/rel/dl_mk_similarity_compressor.h +++ b/src/muz/rel/dl_mk_similarity_compressor.h @@ -21,12 +21,12 @@ Revision History: #include -#include"map.h" -#include"obj_pair_hashtable.h" +#include "util/map.h" +#include "util/obj_pair_hashtable.h" -#include"dl_context.h" -#include"dl_rule_set.h" -#include"dl_rule_transformer.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_set.h" +#include "muz/base/dl_rule_transformer.h" namespace datalog { @@ -53,7 +53,7 @@ namespace datalog { */ class mk_similarity_compressor : public rule_transformer::plugin { - context & m_context; + context & m_context; ast_manager & m_manager; /** number of similar rules necessary for a group to be introduced */ unsigned m_threshold_count; diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index a8e54085d..60eea2e53 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -20,10 +20,10 @@ Revision History: #include #include #include -#include"dl_mk_simple_joins.h" -#include"dl_relation_manager.h" -#include"ast_pp.h" -#include"trace.h" +#include "muz/rel/dl_mk_simple_joins.h" +#include "muz/rel/dl_relation_manager.h" +#include "ast/ast_pp.h" +#include "util/trace.h" namespace datalog { diff --git a/src/muz/rel/dl_mk_simple_joins.h b/src/muz/rel/dl_mk_simple_joins.h index 1289e7831..cf4522c22 100644 --- a/src/muz/rel/dl_mk_simple_joins.h +++ b/src/muz/rel/dl_mk_simple_joins.h @@ -19,12 +19,12 @@ Revision History: #ifndef DL_MK_SIMPLE_JOINS_H_ #define DL_MK_SIMPLE_JOINS_H_ -#include"map.h" -#include"obj_pair_hashtable.h" +#include "util/map.h" +#include "util/obj_pair_hashtable.h" -#include"dl_context.h" -#include"dl_rule_set.h" -#include"dl_rule_transformer.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_set.h" +#include "muz/base/dl_rule_transformer.h" namespace datalog { @@ -49,7 +49,7 @@ namespace datalog { We say that a rule containing C_i's is a rule with a "big tail". */ class mk_simple_joins : public rule_transformer::plugin { - context & m_context; + context & m_context; rule_manager & rm; public: mk_simple_joins(context & ctx); diff --git a/src/muz/rel/dl_product_relation.cpp b/src/muz/rel/dl_product_relation.cpp index 817ff194c..8a2029748 100644 --- a/src/muz/rel/dl_product_relation.cpp +++ b/src/muz/rel/dl_product_relation.cpp @@ -42,11 +42,11 @@ Notes: --*/ -#include "dl_sieve_relation.h" -#include "dl_table_relation.h" -#include "dl_product_relation.h" -#include "bool_rewriter.h" -#include "ast_pp.h" +#include "muz/rel/dl_sieve_relation.h" +#include "muz/rel/dl_table_relation.h" +#include "muz/rel/dl_product_relation.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/ast_pp.h" namespace datalog { diff --git a/src/muz/rel/dl_product_relation.h b/src/muz/rel/dl_product_relation.h index 6381fcf37..002fe5289 100644 --- a/src/muz/rel/dl_product_relation.h +++ b/src/muz/rel/dl_product_relation.h @@ -20,8 +20,8 @@ Revision History: #define DL_PRODUCT_RELATION_H_ -#include "dl_context.h" -#include "dl_relation_manager.h" +#include "muz/base/dl_context.h" +#include "muz/rel/dl_relation_manager.h" namespace datalog { diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 5bb47c5c3..1eb973776 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -19,14 +19,14 @@ Revision History: #include -#include"ast_pp.h" -#include"dl_check_table.h" -#include"dl_context.h" -#include"dl_finite_product_relation.h" -#include"dl_product_relation.h" -#include"dl_sieve_relation.h" -#include"dl_table_relation.h" -#include"dl_relation_manager.h" +#include "ast/ast_pp.h" +#include "muz/rel/dl_check_table.h" +#include "muz/base/dl_context.h" +#include "muz/rel/dl_finite_product_relation.h" +#include "muz/rel/dl_product_relation.h" +#include "muz/rel/dl_sieve_relation.h" +#include "muz/rel/dl_table_relation.h" +#include "muz/rel/dl_relation_manager.h" namespace datalog { diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index a641a5fd2..c77127eb7 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -20,9 +20,9 @@ Revision History: #define DL_RELATION_MANAGER_H_ -#include"map.h" -#include"vector.h" -#include"dl_base.h" +#include "util/map.h" +#include "util/vector.h" +#include "muz/rel/dl_base.h" namespace datalog { diff --git a/src/muz/rel/dl_sieve_relation.cpp b/src/muz/rel/dl_sieve_relation.cpp index 7729ec2eb..0d70212e2 100644 --- a/src/muz/rel/dl_sieve_relation.cpp +++ b/src/muz/rel/dl_sieve_relation.cpp @@ -18,8 +18,8 @@ Revision History: --*/ #include -#include"ast_pp.h" -#include"dl_sieve_relation.h" +#include "ast/ast_pp.h" +#include "muz/rel/dl_sieve_relation.h" namespace datalog { diff --git a/src/muz/rel/dl_sieve_relation.h b/src/muz/rel/dl_sieve_relation.h index 4d89a66ae..021c9d8df 100644 --- a/src/muz/rel/dl_sieve_relation.h +++ b/src/muz/rel/dl_sieve_relation.h @@ -20,8 +20,8 @@ Revision History: #ifndef DL_SIEVE_RELATION_H_ #define DL_SIEVE_RELATION_H_ -#include "dl_context.h" -#include "dl_relation_manager.h" +#include "muz/base/dl_context.h" +#include "muz/rel/dl_relation_manager.h" namespace datalog { diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp index f045bee4b..6048f358b 100644 --- a/src/muz/rel/dl_sparse_table.cpp +++ b/src/muz/rel/dl_sparse_table.cpp @@ -18,9 +18,9 @@ Revision History: --*/ #include -#include"dl_context.h" -#include"dl_util.h" -#include"dl_sparse_table.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_util.h" +#include "muz/rel/dl_sparse_table.h" namespace datalog { diff --git a/src/muz/rel/dl_sparse_table.h b/src/muz/rel/dl_sparse_table.h index a45f4e6c6..a699cf165 100644 --- a/src/muz/rel/dl_sparse_table.h +++ b/src/muz/rel/dl_sparse_table.h @@ -24,15 +24,15 @@ Revision History: #include #include -#include "ast.h" -#include "bit_vector.h" -#include "buffer.h" -#include "hashtable.h" -#include "map.h" -#include "ref_vector.h" -#include "vector.h" +#include "ast/ast.h" +#include "util/bit_vector.h" +#include "util/buffer.h" +#include "util/hashtable.h" +#include "util/map.h" +#include "util/ref_vector.h" +#include "util/vector.h" -#include "dl_base.h" +#include "muz/rel/dl_base.h" namespace datalog { diff --git a/src/muz/rel/dl_table.cpp b/src/muz/rel/dl_table.cpp index 9df9dde5e..1c068a878 100644 --- a/src/muz/rel/dl_table.cpp +++ b/src/muz/rel/dl_table.cpp @@ -17,10 +17,10 @@ Revision History: --*/ -#include"dl_context.h" -#include"dl_util.h" -#include"dl_table.h" -#include"dl_relation_manager.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_util.h" +#include "muz/rel/dl_table.h" +#include "muz/rel/dl_relation_manager.h" namespace datalog { diff --git a/src/muz/rel/dl_table.h b/src/muz/rel/dl_table.h index d25aa31bc..c428191af 100644 --- a/src/muz/rel/dl_table.h +++ b/src/muz/rel/dl_table.h @@ -23,17 +23,17 @@ Revision History: #include #include -#include "ast.h" -#include "bit_vector.h" -#include "buffer.h" -#include "hashtable.h" -#include "map.h" -#include "ref_vector.h" -#include "vector.h" -#include "union_find.h" -#include "dl_base.h" -#include "dl_util.h" -#include "bit_vector.h" +#include "ast/ast.h" +#include "util/bit_vector.h" +#include "util/buffer.h" +#include "util/hashtable.h" +#include "util/map.h" +#include "util/ref_vector.h" +#include "util/vector.h" +#include "util/union_find.h" +#include "muz/rel/dl_base.h" +#include "muz/base/dl_util.h" +#include "util/bit_vector.h" namespace datalog { diff --git a/src/muz/rel/dl_table_plugin.h b/src/muz/rel/dl_table_plugin.h index 7765f54d3..9becc1773 100644 --- a/src/muz/rel/dl_table_plugin.h +++ b/src/muz/rel/dl_table_plugin.h @@ -19,9 +19,9 @@ Revision History: #ifndef DL_TABLE_PLUGIN_H_ #define DL_TABLE_PLUGIN_H_ -#include"ast.h" -#include"map.h" -#include"vector.h" +#include "ast/ast.h" +#include "util/map.h" +#include "util/vector.h" #include"dl_table_ops.h" diff --git a/src/muz/rel/dl_table_relation.cpp b/src/muz/rel/dl_table_relation.cpp index 00a25d169..d8f1c7314 100644 --- a/src/muz/rel/dl_table_relation.cpp +++ b/src/muz/rel/dl_table_relation.cpp @@ -19,9 +19,9 @@ Revision History: #include -#include"dl_context.h" -#include"dl_relation_manager.h" -#include"dl_table_relation.h" +#include "muz/base/dl_context.h" +#include "muz/rel/dl_relation_manager.h" +#include "muz/rel/dl_table_relation.h" namespace datalog { diff --git a/src/muz/rel/dl_table_relation.h b/src/muz/rel/dl_table_relation.h index 56ca509fa..16ff8c482 100644 --- a/src/muz/rel/dl_table_relation.h +++ b/src/muz/rel/dl_table_relation.h @@ -20,8 +20,8 @@ Revision History: #define DL_TABLE_RELATION_H_ -#include "dl_base.h" -#include "dl_util.h" +#include "muz/rel/dl_base.h" +#include "muz/base/dl_util.h" namespace datalog { diff --git a/src/muz/rel/dl_vector_relation.h b/src/muz/rel/dl_vector_relation.h index 040d23300..85e7a78d1 100644 --- a/src/muz/rel/dl_vector_relation.h +++ b/src/muz/rel/dl_vector_relation.h @@ -19,9 +19,9 @@ Revision History: #ifndef DL_VECTOR_RELATION_H_ #define DL_VECTOR_RELATION_H_ -#include "ast_pp.h" -#include "dl_context.h" -#include "union_find.h" +#include "ast/ast_pp.h" +#include "muz/base/dl_context.h" +#include "util/union_find.h" namespace datalog { diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index e73395bc9..23d24dfc3 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -20,12 +20,12 @@ Revision History: --*/ -#include "doc.h" -#include "smt_kernel.h" -#include "expr_safe_replace.h" -#include "smt_params.h" -#include "ast_util.h" -#include "ast_pp.h" +#include "muz/rel/doc.h" +#include "smt/smt_kernel.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "smt/params/smt_params.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" doc_manager::doc_manager(unsigned n): m(n), m_alloc("doc") { m_full = m.allocateX(); diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 23b636cf9..419081892 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -23,9 +23,9 @@ Revision History: #ifndef DOC_H_ #define DOC_H_ -#include "tbv.h" -#include "union_find.h" -#include "buffer.h" +#include "muz/rel/tbv.h" +#include "util/union_find.h" +#include "util/buffer.h" class doc; diff --git a/src/muz/rel/karr_relation.cpp b/src/muz/rel/karr_relation.cpp index 0baa297bc..c8a489d69 100644 --- a/src/muz/rel/karr_relation.cpp +++ b/src/muz/rel/karr_relation.cpp @@ -4,9 +4,9 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "karr_relation.h" -#include "bool_rewriter.h" -#include "ast_util.h" +#include "muz/rel/karr_relation.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/ast_util.h" namespace datalog { class karr_relation : public relation_base { @@ -111,8 +111,8 @@ namespace datalog { void filter_interpreted(app* cond) { rational one(1), mone(-1); - expr* e1, *e2, *en; - var* v, *w; + expr* e1 = 0, *e2 = 0, *en = 0; + var* v = 0, *w = 0; rational n1, n2; expr_ref_vector conjs(m); flatten_and(cond, conjs); diff --git a/src/muz/rel/karr_relation.h b/src/muz/rel/karr_relation.h index 8e5c09156..47e10f09e 100644 --- a/src/muz/rel/karr_relation.h +++ b/src/muz/rel/karr_relation.h @@ -19,8 +19,8 @@ Revision History: #ifndef KARR_RELATION_H_ #define KARR_RELATION_H_ -#include"dl_mk_karr_invariants.h" -#include"dl_relation_manager.h" +#include "muz/transforms/dl_mk_karr_invariants.h" +#include "muz/rel/dl_relation_manager.h" namespace datalog { diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index abaf88f32..9fb1e89e0 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -20,36 +20,36 @@ Revision History: --*/ -#include"rel_context.h" -#include"stopwatch.h" -#include"dl_context.h" -#include"dl_compiler.h" -#include"dl_instruction.h" -#include"dl_mk_explanations.h" -#include"dl_mk_magic_sets.h" -#include"dl_product_relation.h" -#include"dl_bound_relation.h" -#include"dl_interval_relation.h" -#include"karr_relation.h" -#include"dl_finite_product_relation.h" -#include"udoc_relation.h" -#include"check_relation.h" -#include"dl_lazy_table.h" -#include"dl_sparse_table.h" -#include"dl_table.h" -#include"dl_table_relation.h" -#include"aig_exporter.h" -#include"dl_mk_simple_joins.h" -#include"dl_mk_similarity_compressor.h" -#include"dl_mk_unbound_compressor.h" -#include"dl_mk_subsumption_checker.h" -#include"dl_mk_coi_filter.h" -#include"dl_mk_filter_rules.h" -#include"dl_mk_rule_inliner.h" -#include"dl_mk_interp_tail_simplifier.h" -#include"dl_mk_bit_blast.h" -#include"dl_mk_separate_negated_tails.h" -#include"ast_util.h" +#include "muz/rel/rel_context.h" +#include "util/stopwatch.h" +#include "muz/base/dl_context.h" +#include "muz/rel/dl_compiler.h" +#include "muz/rel/dl_instruction.h" +#include "muz/rel/dl_mk_explanations.h" +#include "muz/transforms/dl_mk_magic_sets.h" +#include "muz/rel/dl_product_relation.h" +#include "muz/rel/dl_bound_relation.h" +#include "muz/rel/dl_interval_relation.h" +#include "muz/rel/karr_relation.h" +#include "muz/rel/dl_finite_product_relation.h" +#include "muz/rel/udoc_relation.h" +#include "muz/rel/check_relation.h" +#include "muz/rel/dl_lazy_table.h" +#include "muz/rel/dl_sparse_table.h" +#include "muz/rel/dl_table.h" +#include "muz/rel/dl_table_relation.h" +#include "muz/rel/aig_exporter.h" +#include "muz/rel/dl_mk_simple_joins.h" +#include "muz/rel/dl_mk_similarity_compressor.h" +#include "muz/transforms/dl_mk_unbound_compressor.h" +#include "muz/transforms/dl_mk_subsumption_checker.h" +#include "muz/transforms/dl_mk_coi_filter.h" +#include "muz/transforms/dl_mk_filter_rules.h" +#include "muz/transforms/dl_mk_rule_inliner.h" +#include "muz/transforms/dl_mk_interp_tail_simplifier.h" +#include "muz/transforms/dl_mk_bit_blast.h" +#include "muz/transforms/dl_mk_separate_negated_tails.h" +#include "ast/ast_util.h" namespace datalog { diff --git a/src/muz/rel/rel_context.h b/src/muz/rel/rel_context.h index c263ddc03..f4a87d496 100644 --- a/src/muz/rel/rel_context.h +++ b/src/muz/rel/rel_context.h @@ -20,12 +20,12 @@ Revision History: --*/ #ifndef REL_CONTEXT_H_ #define REL_CONTEXT_H_ -#include "ast.h" -#include "dl_relation_manager.h" -#include "dl_instruction.h" -#include "dl_engine_base.h" -#include "dl_context.h" -#include "lbool.h" +#include "ast/ast.h" +#include "muz/rel/dl_relation_manager.h" +#include "muz/rel/dl_instruction.h" +#include "muz/base/dl_engine_base.h" +#include "muz/base/dl_context.h" +#include "util/lbool.h" namespace datalog { diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 568f63f51..69cc4819a 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -18,9 +18,9 @@ Revision History: --*/ -#include "tbv.h" -#include "hashtable.h" -#include "ast_util.h" +#include "muz/rel/tbv.h" +#include "util/hashtable.h" +#include "ast/ast_util.h" static bool s_debug_alloc = false; @@ -74,8 +74,7 @@ tbv* tbv_manager::allocate(tbv const& bv) { } tbv* tbv_manager::allocate(uint64 val) { tbv* v = allocate0(); - for (unsigned bit = num_tbits(); bit > 0;) { - --bit; + for (unsigned bit = std::min(64u, num_tbits()); bit-- > 0;) { if (val & (1ULL << bit)) { set(*v, bit, BIT_1); } else { diff --git a/src/muz/rel/tbv.h b/src/muz/rel/tbv.h index e2e09d691..1839700d6 100644 --- a/src/muz/rel/tbv.h +++ b/src/muz/rel/tbv.h @@ -21,9 +21,9 @@ Revision History: #ifndef TBV_H_ #define TBV_H_ -#include "fixed_bit_vector.h" -#include "rational.h" -#include "ast.h" +#include "util/fixed_bit_vector.h" +#include "util/rational.h" +#include "ast/ast.h" class tbv; diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 22e70a367..febabb36d 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -21,10 +21,10 @@ Revision History: Notes: --*/ -#include "udoc_relation.h" -#include "dl_relation_manager.h" -#include "ast_util.h" -#include "smt_kernel.h" +#include "muz/rel/udoc_relation.h" +#include "muz/rel/dl_relation_manager.h" +#include "ast/ast_util.h" +#include "smt/smt_kernel.h" namespace datalog { diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 026abfab0..15918d80d 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -22,8 +22,8 @@ Revision History: #ifndef UDOC_RELATION_H_ #define UDOC_RELATION_H_ -#include "doc.h" -#include "dl_base.h" +#include "muz/rel/doc.h" +#include "muz/rel/dl_base.h" namespace datalog { class udoc_plugin; diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt new file mode 100644 index 000000000..37bc7f352 --- /dev/null +++ b/src/muz/spacer/CMakeLists.txt @@ -0,0 +1,30 @@ +z3_add_component(spacer + SOURCES + spacer_legacy_mev.cpp + spacer_legacy_frames.cpp + spacer_context.cpp + spacer_dl_interface.cpp + spacer_farkas_learner.cpp + spacer_generalizers.cpp + spacer_manager.cpp + spacer_prop_solver.cpp + spacer_smt_context_manager.cpp + spacer_sym_mux.cpp + spacer_util.cpp + spacer_itp_solver.cpp + spacer_virtual_solver.cpp + spacer_legacy_mbp.cpp + spacer_unsat_core_learner.cpp + spacer_unsat_core_plugin.cpp + spacer_matrix.cpp + spacer_antiunify.cpp + spacer_mev_array.cpp + spacer_qe_project.cpp + COMPONENT_DEPENDENCIES + arith_tactics + core_tactics + muz + qe + smt_tactic + transforms + ) diff --git a/src/muz/spacer/spacer_antiunify.cpp b/src/muz/spacer/spacer_antiunify.cpp new file mode 100644 index 000000000..7dae59b6a --- /dev/null +++ b/src/muz/spacer/spacer_antiunify.cpp @@ -0,0 +1,459 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_antiunify.cpp + +Abstract: + + Antiunification utilities + +Author: + + Bernhard Gleiss + Arie Gurfinkel + +Revision History: + +--*/ + +#include"muz/spacer/spacer_antiunify.h" +#include"ast/ast.h" +#include"ast/rewriter/rewriter.h" +#include"ast/rewriter/rewriter_def.h" +#include"ast/arith_decl_plugin.h" +#include"ast/ast_util.h" +#include"ast/expr_abstract.h" + +namespace spacer { + +// Abstracts numeric values by variables +struct var_abs_rewriter : public default_rewriter_cfg { + ast_manager &m; + arith_util m_util; + ast_mark m_seen; + ast_mark m_has_num; + unsigned m_var_index; + expr_ref_vector m_pinned; + obj_map& m_substitution; + ptr_vector m_stack; + + var_abs_rewriter (ast_manager &manager, obj_map& substitution, + unsigned k = 0) : + m(manager), m_util(m), m_var_index(k), + m_pinned(m), m_substitution(substitution) {} + + void reset(unsigned k = 0) { + m_pinned.reset(); + m_var_index = k; + } + + bool pre_visit(expr * t) { + bool r = (!m_seen.is_marked(t) || m_has_num.is_marked(t)); + // only unify if convex closure will not contain non-linear multiplication + if (m_util.is_mul(t)) + { + bool contains_const_child = false; + app* a = to_app(t); + for (unsigned i=0, sz = a->get_num_args(); i < sz; ++i) { + if (m_util.is_numeral(a->get_arg(i))) { + contains_const_child = true; + } + } + if (!contains_const_child) {r = false;} + } + if (r) {m_stack.push_back (t);} + return r; + } + + + br_status reduce_app (func_decl * f, unsigned num, expr * const * args, + expr_ref & result, proof_ref & result_pr) { + expr *s; + s = m_stack.back(); + m_stack.pop_back(); + if (is_app(s)) { + app *a = to_app(s); + for (unsigned i=0, sz = a->get_num_args(); i < sz; ++i) { + if (m_has_num.is_marked(a->get_arg(i))) { + m_has_num.mark(a,true); + return BR_FAILED; + } + } + } + return BR_FAILED; + } + + bool cache_all_results() const { return false; } + bool cache_results() const { return false; } + + bool get_subst(expr * s, expr * & t, proof * & t_pr) { + if (m_util.is_numeral(s)) { + t = m.mk_var(m_var_index++, m.get_sort(s)); + m_substitution.insert(t, s); + m_pinned.push_back(t); + m_has_num.mark(s, true); + m_seen.mark(t, true); + return true; + } + return false; + } + +}; + +/* +* construct m_g, which is a generalization of t, where every constant +* is replaced by a variable for any variable in m_g, remember the +* substitution to get back t and save it in m_substitutions +*/ +anti_unifier::anti_unifier(expr* t, ast_manager& man) : m(man), m_pinned(m), m_g(m) +{ + m_pinned.push_back(t); + + obj_map substitution; + + var_abs_rewriter var_abs_cfg(m, substitution); + rewriter_tpl var_abs_rw (m, false, var_abs_cfg); + var_abs_rw (t, m_g); + + m_substitutions.push_back(substitution); //TODO: refactor into vector, remove k +} + +/* traverses m_g and t in parallel. if they only differ in constants + * (i.e. m_g contains a variable, where t contains a constant), then + * add the substitutions, which need to be applied to m_g to get t, to + * m_substitutions. +*/ +bool anti_unifier::add_term(expr* t) { + m_pinned.push_back(t); + + ptr_vector todo; + ptr_vector todo2; + todo.push_back(m_g); + todo2.push_back(t); + + ast_mark visited; + + arith_util util(m); + + obj_map substitution; + + while (!todo.empty()) { + expr* current = todo.back(); + todo.pop_back(); + expr* current2 = todo2.back(); + todo2.pop_back(); + + if (!visited.is_marked(current)) { + visited.mark(current, true); + + if (is_var(current)) { + // TODO: for now we don't allow variables in the terms we want to antiunify + SASSERT(m_substitutions[0].contains(current)); + if (util.is_numeral(current2)) { + substitution.insert(current, current2); + } + else {return false;} + } + else { + SASSERT(is_app(current)); + + if (is_app(current2) && + to_app(current)->get_decl() == to_app(current2)->get_decl() && + to_app(current)->get_num_args() == to_app(current2)->get_num_args()) { + // TODO: what to do for numerals here? E.g. if we + // have 1 and 2, do they have the same decl or are + // the decls already different? + SASSERT (!util.is_numeral(current) || current == current2); + for (unsigned i = 0, num_args = to_app(current)->get_num_args(); + i < num_args; ++i) { + todo.push_back(to_app(current)->get_arg(i)); + todo2.push_back(to_app(current2)->get_arg(i)); + } + } + else { + return false; + } + } + } + } + + // we now know that the terms can be anti-unified, so add the cached substitution + m_substitutions.push_back(substitution); + return true; +} + +/* +* returns m_g, where additionally any variable, which has only equal +* substitutions, is substituted with that substitution +*/ +void anti_unifier::finalize() { + ptr_vector todo; + todo.push_back(m_g); + + ast_mark visited; + + obj_map generalization; + + arith_util util(m); + + // post-order traversel which ignores constants and handles them + // directly when the enclosing term of the constant is handled + while (!todo.empty()) { + expr* current = todo.back(); + SASSERT(is_app(current)); + + // if we haven't already visited current + if (!visited.is_marked(current)) { + bool existsUnvisitedParent = false; + + for (unsigned i = 0, sz = to_app(current)->get_num_args(); i < sz; ++i) { + expr* argument = to_app(current)->get_arg(i); + + if (!is_var(argument)) { + SASSERT(is_app(argument)); + // if we haven't visited the current parent yet + if(!visited.is_marked(argument)) { + // add it to the stack + todo.push_back(argument); + existsUnvisitedParent = true; + } + } + } + + // if we already visited all parents, we can visit current too + if (!existsUnvisitedParent) { + visited.mark(current, true); + todo.pop_back(); + + ptr_buffer arg_list; + for (unsigned i = 0, num_args = to_app(current)->get_num_args(); + i < num_args; ++i) { + expr* argument = to_app(current)->get_arg(i); + + if (is_var(argument)) { + // compute whether there are different + // substitutions for argument + bool containsDifferentSubstitutions = false; + + for (unsigned i=0, sz = m_substitutions.size(); i+1 < sz; ++i) { + SASSERT(m_substitutions[i].contains(argument)); + SASSERT(m_substitutions[i+1].contains(argument)); + + // TODO: how to check equality? + if (m_substitutions[i][argument] != + m_substitutions[i+1][argument]) + { + containsDifferentSubstitutions = true; + break; + } + } + + // if yes, use the variable + if (containsDifferentSubstitutions) { + arg_list.push_back(argument); + } + // otherwise use the concrete value instead + // and remove the substitutions + else + { + arg_list.push_back(m_substitutions[0][argument]); + + for (unsigned i=0, sz = m_substitutions.size(); i < sz; ++i) { + SASSERT(m_substitutions[i].contains(argument)); + m_substitutions[i].remove(argument); + } + } + } + else { + SASSERT(generalization.contains(argument)); + arg_list.push_back(generalization[argument]); + } + } + + SASSERT(to_app(current)->get_num_args() == arg_list.size()); + expr_ref application(m.mk_app(to_app(current)->get_decl(), + to_app(current)->get_num_args(), + arg_list.c_ptr()), m); + m_pinned.push_back(application); + generalization.insert(current, application); + } + } + else { + todo.pop_back(); + } + } + + m_g = generalization[m_g]; +} + + +class ncc_less_than_key +{ +public: + ncc_less_than_key(arith_util& util) : m_util(util) {} + + bool operator() (const expr*& e1, const expr*& e2) { + rational val1; + rational val2; + + if (m_util.is_numeral(e1, val1) && m_util.is_numeral(e2, val2)) + { + return val1 < val2; + } + else + { + SASSERT(false); + return false; + } + } + arith_util m_util; +}; + +/* + * if there is a single interval which exactly captures each of the + * substitutions, return the corresponding closure, otherwise do + * nothing + */ +bool naive_convex_closure::compute_closure(anti_unifier& au, ast_manager& m, + expr_ref& result) { + arith_util util(m); + + SASSERT(au.get_num_substitutions() > 0); + if (au.get_substitution(0).size() == 0) { + result = au.get_generalization(); + return true; + } + + // check that all substitutions have the same size + for (unsigned i=0, sz = au.get_num_substitutions(); i+1 < sz; ++i) { + if (au.get_substitution(i).size() != au.get_substitution(i+1).size()) { + return false; + } + } + + // for each substitution entry + bool is_first_key = true; + unsigned lower_bound = 0; + unsigned upper_bound = 0; + for (const auto& pair : au.get_substitution(0)) { + // construct vector + expr* key = &pair.get_key(); + vector entries; + + rational val; + for (unsigned i=0, sz = au.get_num_substitutions(); i < sz; ++i) + { + if (util.is_numeral(au.get_substitution(i)[key], val) && + val.is_unsigned()) { + entries.push_back(val.get_unsigned()); + } + else { + return false; + } + } + + // check whether vector represents interval + unsigned current_lower_bound = 0; + unsigned current_upper_bound = 0; + + // if vector represents interval + if (get_range(entries, current_lower_bound, current_upper_bound)) { + // if interval is the same as previous interval + if (is_first_key) { + is_first_key = false; + lower_bound = current_lower_bound; + upper_bound = current_upper_bound; + } + else { + if (current_lower_bound != lower_bound || + current_upper_bound != upper_bound) { + return false; + } + } + } + // otherwise we don't do a convex closure + else { + return false; + } + } + + // we finally know that we can express the substitutions using a + // single interval, so build the expression 1. construct const + expr_ref const_ref(m.mk_const(symbol("scti!0"), util.mk_int()), m); + + // 2. construct body with const + expr_ref lit1(util.mk_le(util.mk_int(lower_bound), const_ref), m); + expr_ref lit2(util.mk_le(const_ref, util.mk_int(upper_bound)), m); + expr_ref lit3(m); + substitute_vars_by_const(m, au.get_generalization(), const_ref, lit3); + + expr_ref_vector args(m); + args.push_back(lit1); + args.push_back(lit2); + args.push_back(lit3); + expr_ref body_with_consts = mk_and(args); + + // 3. replace const by var + ptr_vector vars; + vars.push_back(const_ref); + + expr_ref body(m); + expr_abstract(m, 0, vars.size(), (expr*const*)vars.c_ptr(), body_with_consts, body); + + // 4. introduce quantifier + ptr_vector sorts; + sorts.push_back(util.mk_int()); + svector names; + names.push_back(symbol("scti!0")); + + result = expr_ref(m.mk_exists(vars.size(), sorts.c_ptr(), names.c_ptr(), body),m); + + return true; +} + +bool naive_convex_closure::get_range(vector& v, + unsigned int& lower_bound, unsigned int& upper_bound) +{ + // sort substitutions + std::sort(v.begin(), v.end()); + + // check that numbers are consecutive + for (unsigned i=0; i+1 < v.size(); ++i) { + if (v[i] + 1 != v[i+1]) { + return false; + } + } + + SASSERT(v.size() > 0); + lower_bound = v[0]; + upper_bound = v.back(); + + return true; +} + +struct subs_rewriter_cfg : public default_rewriter_cfg { + ast_manager &m; + expr_ref m_c; + + subs_rewriter_cfg (ast_manager &manager, expr* c) : m(manager), m_c(c, m) {} + + bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { + result = m_c; + result_pr = 0; + return true; + } +}; + +void naive_convex_closure::substitute_vars_by_const(ast_manager& m, expr* t, + expr* c, expr_ref& res) { + subs_rewriter_cfg subs_cfg(m, c); + rewriter_tpl subs_rw (m, false, subs_cfg); + subs_rw (t, res); +} + +} + +template class rewriter_tpl; +template class rewriter_tpl; diff --git a/src/muz/spacer/spacer_antiunify.h b/src/muz/spacer/spacer_antiunify.h new file mode 100644 index 000000000..2b86f67ec --- /dev/null +++ b/src/muz/spacer/spacer_antiunify.h @@ -0,0 +1,67 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_antiunify.h + +Abstract: + + Antiunification utilities + +Author: + + Bernhard Gleiss + Arie Gurfinkel + +Revision History: + +--*/ + +#ifndef _SPACER_ANTIUNIFY_H_ +#define _SPACER_ANTIUNIFY_H_ + +#include "ast/ast.h" + +namespace spacer { +class anti_unifier +{ +public: + anti_unifier(expr* t, ast_manager& m); + ~anti_unifier() {} + + bool add_term(expr* t); + void finalize(); + + expr* get_generalization() {return m_g;} + unsigned get_num_substitutions() {return m_substitutions.size();} + obj_map get_substitution(unsigned index){ + SASSERT(index < m_substitutions.size()); + return m_substitutions[index]; + } + +private: + ast_manager& m; + // tracking all created expressions + expr_ref_vector m_pinned; + + expr_ref m_g; + + vector> m_substitutions; +}; + +class naive_convex_closure +{ +public: + static bool compute_closure(anti_unifier& au, ast_manager& m, + expr_ref& result); + +private: + static bool get_range(vector& v, unsigned& lower_bound, + unsigned& upper_bound); + static void substitute_vars_by_const(ast_manager& m, expr* t, expr* c, + expr_ref& res); +}; + +} +#endif diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp new file mode 100644 index 000000000..b057730d8 --- /dev/null +++ b/src/muz/spacer/spacer_context.cpp @@ -0,0 +1,3508 @@ +/** +Copyright (c) 2017 Microsoft Corporation and Arie Gurfinkel + +Module Name: + + spacer_context.cpp + +Abstract: + + SPACER predicate transformers and search context. + +Author: + + Arie Gurfinkel + Anvesh Komuravelli + + Based on muz/pdr/pdr_context.cpp by Nikolaj Bjorner (nbjorner) + +Notes: + +--*/ + + +#include +#include + +#include "muz/base/dl_util.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/var_subst.h" +#include "util/util.h" +#include "muz/spacer/spacer_prop_solver.h" +#include "muz/spacer/spacer_context.h" +#include "muz/spacer/spacer_generalizers.h" +#include "ast/for_each_expr.h" +#include "muz/base/dl_rule_set.h" +#include "smt/tactic/unit_subsumption_tactic.h" +#include "model/model_smt2_pp.h" +#include "muz/transforms/dl_mk_rule_inliner.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_util.h" +#include "ast/proofs/proof_checker.h" +#include "smt/smt_value_sort.h" +#include "ast/scoped_proof.h" +#include "muz/spacer/spacer_qe_project.h" +#include "tactic/core/blast_term_ite_tactic.h" + +#include "util/timeit.h" +#include "util/luby.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/expr_abstract.h" + +namespace spacer { + +// ---------------- +// pred_tansformer + +pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): + pm(pm), m(pm.get_manager()), + ctx(ctx), m_head(head, m), + m_sig(m), m_solver(pm, ctx.get_params(), head->get_name()), + m_reach_ctx (pm.mk_fresh3 ()), + m_pobs(*this), + m_frames(*this), + m_reach_facts(), m_rf_init_sz(0), + m_transition(m), m_initial_state(m), m_extend_lit(m), + m_all_init(false), + m_reach_case_vars(m) +{ + init_sig (); + app_ref v(m); + std::stringstream name; + name << m_head->get_name () << "_ext0"; + v = m.mk_const (symbol(name.str().c_str()), m.mk_bool_sort()); + m_extend_lit = m.mk_not (m.mk_const (pm.get_n_pred (v->get_decl ()))); +} + +pred_transformer::~pred_transformer() +{ + rule2inst::iterator it2 = m_rule2inst.begin(), end2 = m_rule2inst.end(); + for (; it2 != end2; ++it2) { + dealloc(it2->m_value); + } + rule2expr::iterator it3 = m_rule2transition.begin(), end3 = m_rule2transition.end(); + for (; it3 != end3; ++it3) { + m.dec_ref(it3->m_value); + } +} + +std::ostream& pred_transformer::display(std::ostream& out) const +{ + if (!rules().empty()) { out << "rules\n"; } + datalog::rule_manager& rm = ctx.get_datalog_context().get_rule_manager(); + for (unsigned i = 0; i < rules().size(); ++i) { + rm.display_smt2(*rules()[i], out) << "\n"; + } + out << "transition\n" << mk_pp(transition(), m) << "\n"; + return out; +} + +void pred_transformer::collect_statistics(statistics& st) const +{ + m_solver.collect_statistics(st); + st.update("SPACER num propagations", m_stats.m_num_propagations); + st.update("SPACER num properties", m_frames.lemma_size ()); + st.update("SPACER num invariants", m_stats.m_num_invariants); + + st.update ("time.spacer.init_rules.pt.init", m_initialize_watch.get_seconds ()); + st.update ("time.spacer.solve.pt.must_reachable", + m_must_reachable_watch.get_seconds ()); +} + +void pred_transformer::reset_statistics() +{ + m_solver.reset_statistics(); + //m_reachable.reset_statistics(); + m_stats.reset(); + m_initialize_watch.reset (); + m_must_reachable_watch.reset (); +} + +void pred_transformer::init_sig() +{ + for (unsigned i = 0; i < m_head->get_arity(); ++i) { + sort * arg_sort = m_head->get_domain(i); + std::stringstream name_stm; + name_stm << m_head->get_name() << '_' << i; + func_decl_ref stm(m); + stm = m.mk_func_decl(symbol(name_stm.str().c_str()), 0, (sort*const*)0, arg_sort); + m_sig.push_back(pm.get_o_pred(stm, 0)); + } +} + +void pred_transformer::ensure_level(unsigned level) +{ + if (is_infty_level(level)) { return; } + + while (m_frames.size() <= level) { + m_frames.add_frame (); + m_solver.add_level (); + } +} + +bool pred_transformer::is_must_reachable(expr* state, model_ref* model) +{ + scoped_watch _t_(m_must_reachable_watch); + SASSERT (state); + // XXX This seems to mis-handle the case when state is + // reachable using the init rule of the current transformer + if (m_reach_facts.empty()) { return false; } + + m_reach_ctx->push (); + m_reach_ctx->assert_expr (state); + m_reach_ctx->assert_expr (m.mk_not (m_reach_case_vars.back ())); + lbool res = m_reach_ctx->check_sat (0, NULL); + if (model) { m_reach_ctx->get_model(*model); } + m_reach_ctx->pop (1); + return (res == l_true); +} + + + + +reach_fact* pred_transformer::get_used_reach_fact (model_evaluator_util& mev, + bool all) +{ + expr_ref v (m); + + for (unsigned i = all ? 0 : m_rf_init_sz, sz = m_reach_case_vars.size (); + i < sz; i++) { + VERIFY (mev.eval (m_reach_case_vars.get (i), v, false)); + if (m.is_false (v)) { + return m_reach_facts.get (i); + } + } + + UNREACHABLE (); + return NULL; +} + +reach_fact *pred_transformer::get_used_origin_reach_fact (model_evaluator_util& mev, + unsigned oidx) +{ + expr_ref b(m), v(m); + reach_fact *res = NULL; + + for (unsigned i = 0, sz = m_reach_case_vars.size (); i < sz; i++) { + pm.formula_n2o (m_reach_case_vars.get (i), v, oidx); + VERIFY(mev.eval (v, b, false)); + + if (m.is_false (b)) { + res = m_reach_facts.get (i); + break; + } + } + SASSERT (res); + return res; +} + +datalog::rule const* pred_transformer::find_rule(model &model, + bool& is_concrete, + vector& reach_pred_used, + unsigned& num_reuse_reach) +{ + typedef obj_map tag2rule; + TRACE ("spacer_verbose", + datalog::rule_manager& rm = ctx.get_datalog_context().get_rule_manager(); + tag2rule::iterator it = m_tag2rule.begin(); + tag2rule::iterator end = m_tag2rule.end(); + for (; it != end; ++it) { + expr* pred = it->m_key; + tout << mk_pp(pred, m) << ":\n"; + if (it->m_value) { rm.display_smt2(*(it->m_value), tout) << "\n"; } + } + ); + + // find a rule whose tag is true in the model; + // prefer a rule where the model intersects with reach facts of all predecessors; + // also find how many predecessors' reach facts are true in the model + expr_ref vl(m); + datalog::rule const* r = ((datalog::rule*)0); + tag2rule::iterator it = m_tag2rule.begin(), end = m_tag2rule.end(); + for (; it != end; ++it) { + expr* tag = it->m_key; + if (model.eval(to_app(tag)->get_decl(), vl) && m.is_true(vl)) { + r = it->m_value; + is_concrete = true; + num_reuse_reach = 0; + reach_pred_used.reset (); + unsigned tail_sz = r->get_uninterpreted_tail_size (); + for (unsigned i = 0; i < tail_sz; i++) { + bool used = false; + func_decl* d = r->get_tail(i)->get_decl(); + pred_transformer const& pt = ctx.get_pred_transformer (d); + if (!pt.has_reach_facts()) { is_concrete = false; } + else { + expr_ref v(m); + pm.formula_n2o (pt.get_last_reach_case_var (), v, i); + model.eval (to_app (v.get ())->get_decl (), vl); + used = m.is_false (vl); + is_concrete = is_concrete && used; + } + + reach_pred_used.push_back (used); + if (used) { num_reuse_reach++; } + } + if (is_concrete) { break; } + } + } + // SASSERT (r); + // reached by a reachability fact + if (!r) { is_concrete = true; } + return r; +} + +void pred_transformer::find_predecessors(datalog::rule const& r, ptr_vector& preds) const +{ + preds.reset(); + unsigned tail_sz = r.get_uninterpreted_tail_size(); + for (unsigned ti = 0; ti < tail_sz; ti++) { + preds.push_back(r.get_tail(ti)->get_decl()); + } +} + +void pred_transformer::find_predecessors(vector >& preds) const +{ + preds.reset(); + obj_map::iterator it = m_tag2rule.begin(), end = m_tag2rule.end(); + for (; it != end; it++) { + datalog::rule const& r = *it->m_value; + unsigned tail_sz = r.get_uninterpreted_tail_size(); + for (unsigned ti = 0; ti < tail_sz; ti++) { + preds.push_back(std::make_pair (r.get_tail(ti)->get_decl(), ti)); + } + } +} + + +void pred_transformer::remove_predecessors(expr_ref_vector& literals) +{ + // remove tags + for (unsigned i = 0; i < literals.size(); ) { + expr* l = literals[i].get(); + m.is_not(l, l); + if (m_tag2rule.contains(l)) { + literals[i] = literals.back(); + literals.pop_back(); + } else { + ++i; + } + } +} + +void pred_transformer::simplify_formulas() +{ + m_frames.simplify_formulas (); +} + + +expr_ref pred_transformer::get_formulas(unsigned level, bool add_axioms) +{ + expr_ref_vector res(m); + if (add_axioms) { + res.push_back(pm.get_background()); + res.push_back((level == 0)?initial_state():transition()); + } + m_frames.get_frame_geq_lemmas (level, res); + return pm.mk_and(res); +} + +bool pred_transformer::propagate_to_next_level (unsigned src_level) +{return m_frames.propagate_to_next_level (src_level);} + + +/// \brief adds a lema to the solver and to child solvers +void pred_transformer::add_lemma_core(lemma* lemma) +{ + unsigned lvl = lemma->level(); + expr* l = lemma->get_expr(); + SASSERT(!lemma->is_ground() || is_clause(m, l)); + SASSERT(!is_quantifier(l) || is_clause(m, to_quantifier(l)->get_expr())); + + TRACE("spacer", tout << "add-lemma-core: " << pp_level (lvl) + << " " << head ()->get_name () + << " " << mk_pp (l, m) << "\n";); + + TRACE("core_array_eq", tout << "add-lemma-core: " << pp_level (lvl) + << " " << head ()->get_name () + << " " << mk_pp (l, m) << "\n";); + + STRACE ("spacer.expand-add", + tout << "add-lemma: " << pp_level (lvl) << " " + << head ()->get_name () << " " + << mk_epp (l, m) << "\n\n";); + + + if (is_infty_level(lvl)) { m_stats.m_num_invariants++; } + + if (lemma->is_ground()) { + if (is_infty_level(lvl)) { m_solver.assert_expr(l); } + else { + ensure_level (lvl); + m_solver.assert_expr (l, lvl); + } + } + + for (unsigned i = 0, sz = m_use.size (); i < sz; ++i) + { m_use [i]->add_lemma_from_child(*this, lemma, next_level(lvl)); } +} + +bool pred_transformer::add_lemma (expr *e, unsigned lvl) { + lemma_ref lem = alloc(lemma, m, e, lvl); + return m_frames.add_lemma(lem.get()); +} + +void pred_transformer::add_lemma_from_child (pred_transformer& child, + lemma* lemma, unsigned lvl) +{ + ensure_level(lvl); + expr_ref_vector fmls(m); + mk_assumptions(child.head(), lemma->get_expr(), fmls); + + for (unsigned i = 0; i < fmls.size(); ++i) { + expr_ref_vector inst(m); + expr* a = to_app(fmls.get(i))->get_arg(0); + expr* l = to_app(fmls.get(i))->get_arg(1); + if (get_context().use_instantiate()) + { lemma->mk_insts(inst, l); } + for (unsigned j=0; j < inst.size(); j++) { + inst.set(j, m.mk_implies(a, inst.get(j))); + } + if (lemma->is_ground() || get_context().use_qlemmas()) + { inst.push_back(fmls.get(i)); } + SASSERT (!inst.empty ()); + for (unsigned j = 0; j < inst.size(); ++j) { + TRACE("spacer_detail", tout << "child property: " + << mk_pp(inst.get (j), m) << "\n";); + if (is_infty_level(lvl)) + { m_solver.assert_expr(inst.get(j)); } + else + { m_solver.assert_expr(inst.get(j), lvl); } + } + } + +} + +expr* pred_transformer::mk_fresh_reach_case_var () +{ + std::stringstream name; + func_decl_ref decl(m); + + name << head ()->get_name () << "#reach_case_" << m_reach_case_vars.size (); + decl = m.mk_func_decl (symbol (name.str ().c_str ()), 0, + (sort*const*)0, m.mk_bool_sort ()); + m_reach_case_vars.push_back (m.mk_const (pm.get_n_pred (decl))); + return m_reach_case_vars.back (); +} + +expr* pred_transformer::get_reach_case_var (unsigned idx) const +{return m_reach_case_vars.get (idx);} + + +void pred_transformer::add_reach_fact (reach_fact *fact) +{ + timeit _timer (is_trace_enabled("spacer_timeit"), + "spacer::pred_transformer::add_reach_fact", + verbose_stream ()); + + TRACE ("spacer", + tout << "add_reach_fact: " << head()->get_name() << " " + << (fact->is_init () ? "INIT " : "") + << mk_pp(fact->get (), m) << "\n";); + + // -- avoid duplicates + if (fact == nullptr || get_reach_fact(fact->get())) { return; } + + // all initial facts are grouped together + SASSERT (!fact->is_init () || m_reach_facts.empty () || + m_reach_facts.back ()->is_init ()); + + m_reach_facts.push_back (fact); + if (fact->is_init()) { m_rf_init_sz++; } + + + // update m_reach_ctx + expr_ref last_var (m); + expr_ref new_var (m); + expr_ref fml (m); + + if (!m_reach_case_vars.empty()) { last_var = m_reach_case_vars.back(); } + if (fact->is_init () || !ctx.get_params ().spacer_reach_as_init ()) + { new_var = mk_fresh_reach_case_var(); } + else { + new_var = extend_initial (fact->get ())->get_arg (0); + m_reach_case_vars.push_back (new_var); + } + + SASSERT (m_reach_facts.size () == m_reach_case_vars.size ()); + + if (last_var) + { fml = m.mk_or(m.mk_not(last_var), fact->get(), new_var); } + else + { fml = m.mk_or(fact->get(), new_var); } + + m_reach_ctx->assert_expr (fml); + TRACE ("spacer", + tout << "updating reach ctx: " << mk_pp(fml, m) << "\n";); + + lemma lem(m, fml, infty_level()); + // update users; reach facts are independent of levels + for (unsigned i = 0; i < m_use.size(); ++i) { + m_use[i]->add_lemma_from_child (*this, &lem, infty_level ()); + } +} + +expr_ref pred_transformer::get_reachable() +{ + expr_ref res(m); + res = m.mk_false(); + + if (!m_reach_facts.empty()) { + expr_substitution sub(m); + expr_ref c(m), v(m); + for (unsigned i = 0, sz = sig_size(); i < sz; ++i) { + c = m.mk_const(pm.o2n(sig(i), 0)); + v = m.mk_var(i, sig(i)->get_range()); + sub.insert(c, v); + } + scoped_ptr rep = mk_expr_simp_replacer(m); + rep->set_substitution(&sub); + + expr_ref_vector args(m); + for (unsigned i = 0, sz = m_reach_facts.size (); i < sz; ++i) { + reach_fact *f; + f = m_reach_facts.get(i); + expr_ref r(m); + r = f->get(); + const ptr_vector &aux = f->aux_vars(); + if (!aux.empty()) { + // -- existentially quantify auxiliary variables + r = mk_exists (m, aux.size(), aux.c_ptr(), r); + // XXX not sure how this interacts with variable renaming later on. + // XXX For now, simply dissallow existentially quantified auxiliaries + NOT_IMPLEMENTED_YET(); + } + (*rep)(r); + + args.push_back (r); + } + res = mk_or(args); + } + return res; +} + +expr* pred_transformer::get_last_reach_case_var () const +{ + return m_reach_case_vars.empty () ? NULL : m_reach_case_vars.back (); +} + +expr_ref pred_transformer::get_cover_delta(func_decl* p_orig, int level) +{ + expr_ref result(m.mk_true(), m), v(m), c(m); + + expr_ref_vector lemmas (m); + m_frames.get_frame_lemmas (level == -1 ? infty_level() : level, lemmas); + if (!lemmas.empty()) { result = pm.mk_and(lemmas); } + + // replace local constants by bound variables. + expr_substitution sub(m); + for (unsigned i = 0; i < sig_size(); ++i) { + c = m.mk_const(pm.o2n(sig(i), 0)); + v = m.mk_var(i, sig(i)->get_range()); + sub.insert(c, v); + } + scoped_ptr rep = mk_default_expr_replacer(m); + rep->set_substitution(&sub); + (*rep)(result); + + // adjust result according to model converter. + unsigned arity = m_head->get_arity(); + model_ref md = alloc(model, m); + if (arity == 0) { + md->register_decl(m_head, result); + } else { + func_interp* fi = alloc(func_interp, m, arity); + fi->set_else(result); + md->register_decl(m_head, fi); + } + model_converter_ref mc = ctx.get_model_converter(); + apply(mc, md, 0); + if (p_orig->get_arity() == 0) { + result = md->get_const_interp(p_orig); + } else { + result = md->get_func_interp(p_orig)->get_interp(); + } + return result; +} + +/** + * get an origin summary used by this transformer in the given model + * level is the level at which may summaries are obtained + * oidx is the origin index of this predicate in the model + * must indicates whether a must or a may summary is requested + * + * returns an implicant of the summary + */ +expr_ref pred_transformer::get_origin_summary (model_evaluator_util &mev, + unsigned level, + unsigned oidx, + bool must, + const ptr_vector **aux) +{ + expr_ref_vector summary (m); + expr_ref v(m); + + if (!must) { // use may summary + summary.push_back (get_formulas (level, false)); + // -- no auxiliary variables in lemmas + *aux = NULL; + } else { // find must summary to use + reach_fact *f = get_used_origin_reach_fact (mev, oidx); + summary.push_back (f->get ()); + *aux = &f->aux_vars (); + } + + SASSERT (!summary.empty ()); + + // -- convert to origin + for (unsigned i = 0; i < summary.size(); ++i) { + pm.formula_n2o (summary.get (i), v, oidx); + summary[i] = v; + } + + // -- pick an implicant + expr_ref_vector literals (m); + compute_implicant_literals (mev, summary, literals); + + return get_manager ().mk_and (literals); +} + + +void pred_transformer::add_cover(unsigned level, expr* property) +{ + // replace bound variables by local constants. + expr_ref result(property, m), v(m), c(m); + expr_substitution sub(m); + for (unsigned i = 0; i < sig_size(); ++i) { + c = m.mk_const(pm.o2n(sig(i), 0)); + v = m.mk_var(i, sig(i)->get_range()); + sub.insert(v, c); + } + scoped_ptr rep = mk_default_expr_replacer(m); + rep->set_substitution(&sub); + (*rep)(result); + TRACE("spacer", tout << "cover:\n" << mk_pp(result, m) << "\n";); + + // add the property. + expr_ref_vector lemmas(m); + flatten_and(result, lemmas); + for (unsigned i = 0, sz = lemmas.size(); i < sz; ++i) { + add_lemma(lemmas.get(i), level); + } +} + +void pred_transformer::propagate_to_infinity (unsigned level) +{m_frames.propagate_to_infinity (level);} + + + +/// \brief Returns true if the obligation is already blocked by current lemmas +bool pred_transformer::is_blocked (pob &n, unsigned &uses_level) +{ + ensure_level (n.level ()); + prop_solver::scoped_level _sl (m_solver, n.level ()); + m_solver.set_core (NULL); + m_solver.set_model (NULL); + + expr_ref_vector post(m), aux(m); + post.push_back (n.post ()); + lbool res = m_solver.check_assumptions (post, aux, 0, NULL, 0); + if (res == l_false) { uses_level = m_solver.uses_level(); } + return res == l_false; +} + +bool pred_transformer::is_qblocked (pob &n) +{ + // XXX Trivial implementation to get us started + smt::kernel solver (m, get_manager ().fparams2()); + expr_ref_vector frame_lemmas(m); + m_frames.get_frame_geq_lemmas (n.level (), frame_lemmas); + + // assert all lemmas + for (unsigned i = 0, sz = frame_lemmas.size (); i < sz; ++i) + { solver.assert_expr(frame_lemmas.get(i)); } + // assert cti + solver.assert_expr (n.post ()); + lbool res = solver.check (); + + return res == l_false; +} + +// +// check if predicate transformer has a satisfiable predecessor state. +// returns either a satisfiable predecessor state or +// return a property that blocks state and is implied by the +// predicate transformer (or some unfolding of it). +// +lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, + model_ref* model, unsigned& uses_level, + bool& is_concrete, datalog::rule const*& r, + vector& reach_pred_used, + unsigned& num_reuse_reach) +{ + TRACE("spacer", + tout << "is-reachable: " << head()->get_name() << " level: " + << n.level() << " depth: " << n.depth () << "\n"; + tout << mk_pp(n.post(), m) << "\n";); + timeit _timer (is_trace_enabled("spacer_timeit"), + "spacer::pred_transformer::is_reachable", + verbose_stream ()); + + ensure_level(n.level()); + + // prepare the solver + prop_solver::scoped_level _sl(m_solver, n.level()); + prop_solver::scoped_subset_core _sc (m_solver, !n.use_farkas_generalizer ()); + m_solver.set_core(core); + m_solver.set_model(model); + + expr_ref_vector post (m), reach_assumps (m); + post.push_back (n.post ()); + + // populate reach_assumps + + // XXX eager_reach_check must always be + // XXX enabled. Otherwise, we can get into an infinite loop in + // XXX which a model is consistent with a must-summary, but the + // XXX appropriate assumption is not set correctly by the model. + // XXX Original code handled reachability-events differently. + if (/* ctx.get_params ().eager_reach_check () && */ + n.level () > 0 && !m_all_init) { + obj_map::iterator it = m_tag2rule.begin (), + end = m_tag2rule.end (); + for (; it != end; ++it) { + datalog::rule const* r = it->m_value; + if (!r) { continue; } + find_predecessors(*r, m_predicates); + if (m_predicates.empty()) { continue; } + for (unsigned i = 0; i < m_predicates.size(); i++) { + const pred_transformer &pt = + ctx.get_pred_transformer (m_predicates [i]); + if (pt.has_reach_facts()) { + expr_ref a(m); + pm.formula_n2o (pt.get_last_reach_case_var (), a, i); + reach_assumps.push_back (m.mk_not (a)); + } else if (ctx.get_params().spacer_init_reach_facts()) { + reach_assumps.push_back (m.mk_not (it->m_key)); + break; + } + } + } + } + + TRACE ("spacer", + if (!reach_assumps.empty ()) { + tout << "reach assumptions\n"; + for (unsigned i = 0; i < reach_assumps.size (); i++) { + tout << mk_pp (reach_assumps.get (i), m) << "\n"; + } + } + ); + + // check local reachability; + // result is either sat (with some reach assumps) or + // unsat (even with no reach assumps) + expr *bg = m_extend_lit.get (); + lbool is_sat = m_solver.check_assumptions (post, reach_assumps, 1, &bg, 0); + + TRACE ("spacer", + if (!reach_assumps.empty ()) { + tout << "reach assumptions used\n"; + for (unsigned i = 0; i < reach_assumps.size (); i++) { + tout << mk_pp (reach_assumps.get (i), m) << "\n"; + } + } + ); + + if (is_sat == l_true || is_sat == l_undef) { + if (core) { core->reset(); } + if (model) { + r = find_rule (**model, is_concrete, reach_pred_used, num_reuse_reach); + TRACE ("spacer", tout << "reachable " + << "is_concrete " << is_concrete << " rused: "; + for (unsigned i = 0, sz = reach_pred_used.size (); i < sz; ++i) + tout << reach_pred_used [i]; + tout << "\n";); + } + + return is_sat; + } + if (is_sat == l_false) { + SASSERT (reach_assumps.empty ()); + TRACE ("spacer", tout << "unreachable with lemmas\n"; + if (core) { + tout << "Core:\n"; + for (unsigned i = 0; i < core->size (); i++) { + tout << mk_pp (core->get(i), m) << "\n"; + } + } + ); + uses_level = m_solver.uses_level(); + return l_false; + } + UNREACHABLE(); + return l_undef; +} + +bool pred_transformer::is_invariant(unsigned level, expr* lemma, + unsigned& solver_level, expr_ref_vector* core) +{ + expr_ref_vector conj(m), aux(m); + expr_ref glemma(m); + + if (false && is_quantifier(lemma)) { + SASSERT(is_forall(lemma)); + app_ref_vector tmp(m); + ground_expr(to_quantifier(lemma)->get_expr (), glemma, tmp); + lemma = glemma.get(); + } + + conj.push_back(mk_not(m, lemma)); + flatten_and (conj); + + prop_solver::scoped_level _sl(m_solver, level); + prop_solver::scoped_subset_core _sc (m_solver, true); + m_solver.set_core(core); + m_solver.set_model(0); + expr * bg = m_extend_lit.get (); + lbool r = m_solver.check_assumptions (conj, aux, 1, &bg, 1); + if (r == l_false) { + solver_level = m_solver.uses_level (); + CTRACE ("spacer", level < m_solver.uses_level (), + tout << "Checking at level " << level + << " but only using " << m_solver.uses_level () << "\n";); + SASSERT (level <= solver_level); + } + return r == l_false; +} + +bool pred_transformer::check_inductive(unsigned level, expr_ref_vector& state, + unsigned& uses_level) +{ + manager& pm = get_manager(); + expr_ref_vector conj(m), core(m); + expr_ref states(m); + states = m.mk_not(pm.mk_and(state)); + mk_assumptions(head(), states, conj); + prop_solver::scoped_level _sl(m_solver, level); + prop_solver::scoped_subset_core _sc (m_solver, true); + m_solver.set_core(&core); + m_solver.set_model (0); + expr_ref_vector aux (m); + conj.push_back (m_extend_lit); + lbool res = m_solver.check_assumptions (state, aux, conj.size (), conj.c_ptr (), 1); + if (res == l_false) { + state.reset(); + state.append(core); + uses_level = m_solver.uses_level(); + } + TRACE ("core_array_eq", + tout << "check_inductive: " + << "states: " << mk_pp (states, m) + << " is: " << res << "\n" + << "with transition: " << mk_pp (m_transition, m) << "\n";); + return res == l_false; +} + +void pred_transformer::mk_assumptions(func_decl* head, expr* fml, + expr_ref_vector& result) +{ + expr_ref tmp1(m), tmp2(m); + expr_substitution sub (m); + proof_ref pr (m.mk_asserted (m.mk_true ()), m); + obj_map::iterator it = m_tag2rule.begin(), + end = m_tag2rule.end(); + for (; it != end; ++it) { + expr* tag = it->m_key; + datalog::rule const* r = it->m_value; + if (!r) { continue; } + find_predecessors(*r, m_predicates); + for (unsigned i = 0; i < m_predicates.size(); i++) { + func_decl* d = m_predicates[i]; + if (d == head) { + tmp1 = m.mk_implies(tag, fml); + pm.formula_n2o(tmp1, tmp2, i); + result.push_back(tmp2); + } + } + } +} + +void pred_transformer::initialize(decl2rel const& pts) +{ + m_initial_state = m.mk_false(); + m_transition = m.mk_true(); + init_rules(pts, m_initial_state, m_transition); + th_rewriter rw(m); + rw(m_transition); + rw(m_initial_state); + + m_solver.assert_expr (m_transition); + m_solver.assert_expr (m_initial_state, 0); + TRACE("spacer", + tout << "Initial state: " << mk_pp(m_initial_state, m) << "\n"; + tout << "Transition: " << mk_pp(m_transition, m) << "\n";); + SASSERT(is_app(m_initial_state)); + //m_reachable.add_init(to_app(m_initial_state)); + + +} + +void pred_transformer::init_reach_facts () +{ + expr_ref_vector v(m); + reach_fact_ref fact; + + rule2expr::iterator it = m_rule2tag.begin (), end = m_rule2tag.end (); + for (; it != end; ++it) { + const datalog::rule* r = it->m_key; + if (r->get_uninterpreted_tail_size() == 0) { + fact = alloc (reach_fact, m, *r, m_rule2transition.find (r), + get_aux_vars (*r), true); + add_reach_fact (fact.get ()); + } + } +} + +void pred_transformer::init_rules(decl2rel const& pts, expr_ref& init, expr_ref& transition) +{ + expr_ref_vector transitions(m); + ptr_vector tr_rules; + datalog::rule const* rule; + expr_ref_vector disj(m), init_conds (m); + app_ref pred(m); + vector is_init; + for (unsigned i = 0; i < rules().size(); ++i) { + init_rule(pts, *rules()[i], is_init, tr_rules, transitions); + } + SASSERT (is_init.size () == transitions.size ()); + switch(transitions.size()) { + case 0: + transition = m.mk_false(); + break; + case 1: { + std::stringstream name; + // create a dummy tag. + name << head()->get_name() << "_dummy"; + pred = m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()); + rule = tr_rules[0]; + m_tag2rule.insert(pred, rule); + m_rule2tag.insert(rule, pred.get()); + transitions [0] = m.mk_implies (pred, transitions.get (0)); + transitions.push_back (m.mk_or (pred, m_extend_lit->get_arg (0))); + if (!is_init [0]) { init_conds.push_back(m.mk_not(pred)); } + + transition = pm.mk_and(transitions); + break; + } + default: + disj.push_back (m_extend_lit->get_arg (0)); + for (unsigned i = 0; i < transitions.size(); ++i) { + std::stringstream name; + name << head()->get_name() << "_tr" << i; + pred = m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()); + rule = tr_rules[i]; + m_tag2rule.insert(pred, rule); + m_rule2tag.insert(rule, pred); + disj.push_back(pred); + transitions[i] = m.mk_implies(pred, transitions[i].get()); + // update init conds + if (!is_init[i]) { + init_conds.push_back (m.mk_not (pred)); + } + } + transitions.push_back(m.mk_or(disj.size(), disj.c_ptr())); + transition = pm.mk_and(transitions); + break; + } + // mk init condition + init = pm.mk_and (init_conds); + if (init_conds.empty ()) { // no rule has uninterpreted tail + m_all_init = true; + } +} + +void pred_transformer::init_rule( + decl2rel const& pts, + datalog::rule const& rule, + vector& is_init, + ptr_vector& rules, + expr_ref_vector& transitions) +{ + scoped_watch _t_(m_initialize_watch); + + // Predicates that are variable representatives. Other predicates at + // positions the variables occur are made equivalent with these. + expr_ref_vector conj(m); + app_ref_vector& var_reprs = *(alloc(app_ref_vector, m)); + ptr_vector aux_vars; + + unsigned ut_size = rule.get_uninterpreted_tail_size(); + unsigned t_size = rule.get_tail_size(); + SASSERT(ut_size <= t_size); + init_atom(pts, rule.get_head(), var_reprs, conj, UINT_MAX); + for (unsigned i = 0; i < ut_size; ++i) { + if (rule.is_neg_tail(i)) { + throw default_exception("SPACER does not support negated predicates in rule tails"); + } + init_atom(pts, rule.get_tail(i), var_reprs, conj, i); + } + // -- substitute free variables + expr_ref fml(m); + { + expr_ref_vector tail(m); + for (unsigned i = ut_size; i < t_size; ++i) + { tail.push_back(rule.get_tail(i)); } + fml = mk_and (tail); + + ground_free_vars (fml, var_reprs, aux_vars, ut_size == 0); + SASSERT(check_filled(var_reprs)); + + expr_ref tmp(m); + var_subst (m, false)(fml, + var_reprs.size (), (expr*const*)var_reprs.c_ptr(), tmp); + flatten_and (tmp, conj); + fml = mk_and(conj); + conj.reset (); + } + + th_rewriter rw(m); + rw(fml); + if (ctx.get_params().spacer_blast_term_ite()) { + blast_term_ite (fml); + rw(fml); + } + TRACE("spacer", tout << mk_pp(fml, m) << "\n";); + + // allow quantifiers in init rule + SASSERT(ut_size == 0 || is_ground(fml)); + if (m.is_false(fml)) { + // no-op. + } else { + is_init.push_back (ut_size == 0); + transitions.push_back(fml); + m.inc_ref(fml); + m_rule2transition.insert(&rule, fml.get()); + rules.push_back(&rule); + } + m_rule2inst.insert(&rule,&var_reprs); + m_rule2vars.insert(&rule, aux_vars); + TRACE("spacer", + tout << rule.get_decl()->get_name() << "\n"; + for (unsigned i = 0; i < var_reprs.size(); ++i) { + tout << mk_pp(var_reprs[i].get(), m) << " "; + } + tout << "\n";); +} + +bool pred_transformer::check_filled(app_ref_vector const& v) const +{ + for (unsigned i = 0; i < v.size(); ++i) { + if (!v[i]) { return false; } + } + return true; +} + +// create constants for free variables in tail. +void pred_transformer::ground_free_vars(expr* e, app_ref_vector& vars, + ptr_vector& aux_vars, bool is_init) +{ + expr_free_vars fv; + fv(e); + + while (vars.size() < fv.size()) { + vars.push_back(0); + } + for (unsigned i = 0; i < fv.size(); ++i) { + if (fv[i] && !vars[i].get()) { + vars[i] = m.mk_fresh_const("aux", fv[i]); + vars[i] = m.mk_const (pm.get_n_pred (vars.get (i)->get_decl ())); + aux_vars.push_back(vars[i].get()); + } + } + +} + +// create names for variables used in relations. +void pred_transformer::init_atom( + decl2rel const& pts, + app * atom, + app_ref_vector& var_reprs, + expr_ref_vector& conj, + unsigned tail_idx + ) +{ + unsigned arity = atom->get_num_args(); + func_decl* head = atom->get_decl(); + pred_transformer& pt = *pts.find(head); + for (unsigned i = 0; i < arity; i++) { + app_ref rep(m); + + if (tail_idx == UINT_MAX) { + rep = m.mk_const(pm.o2n(pt.sig(i), 0)); + } else { + rep = m.mk_const(pm.o2o(pt.sig(i), 0, tail_idx)); + } + + expr * arg = atom->get_arg(i); + if (is_var(arg)) { + var * v = to_var(arg); + unsigned var_idx = v->get_idx(); + if (var_idx >= var_reprs.size()) { + var_reprs.resize(var_idx+1); + } + expr * repr = var_reprs[var_idx].get(); + if (repr) { + conj.push_back(m.mk_eq(rep, repr)); + } else { + var_reprs[var_idx] = rep; + } + } else { + SASSERT(is_app(arg)); + conj.push_back(m.mk_eq(rep, arg)); + } + } +} + +void pred_transformer::add_premises(decl2rel const& pts, unsigned lvl, expr_ref_vector& r) +{ + r.push_back(pm.get_background()); + r.push_back((lvl == 0)?initial_state():transition()); + for (unsigned i = 0; i < rules().size(); ++i) { + add_premises(pts, lvl, *rules()[i], r); + } +} + +void pred_transformer::add_premises(decl2rel const& pts, unsigned lvl, datalog::rule& rule, expr_ref_vector& r) +{ + find_predecessors(rule, m_predicates); + for (unsigned i = 0; i < m_predicates.size(); ++i) { + expr_ref tmp(m); + func_decl* head = m_predicates[i]; + pred_transformer& pt = *pts.find(head); + expr_ref inv = pt.get_formulas(lvl, false); + if (!m.is_true(inv)) { + pm.formula_n2o(inv, tmp, i, true); + r.push_back(tmp); + } + } +} + +void pred_transformer::inherit_properties(pred_transformer& other) +{ + m_frames.inherit_frames (other.m_frames); +} + + +lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : + m_ref_count(0), m(manager), + m_body(body, m), m_cube(m), + m_bindings(m), m_lvl(lvl), + m_pob(0), m_new_pob(false) { + SASSERT(m_body); + normalize(m_body, m_body); +} + +lemma::lemma(pob_ref const &p) : + m_ref_count(0), m(p->get_ast_manager()), + m_body(m), m_cube(m), + m_bindings(m), m_lvl(p->level()), + m_pob(p), m_new_pob(m_pob) {SASSERT(m_pob);} + +lemma::lemma(pob_ref const &p, expr_ref_vector &cube, unsigned lvl) : + m_ref_count(0), + m(p->get_ast_manager()), + m_body(m), m_cube(m), + m_bindings(m), m_lvl(p->level()), + m_pob(p), m_new_pob(m_pob) +{ + update_cube(p, cube); + set_level(lvl); +} + +void lemma::mk_expr_core() { + if (m_body) return; + + if (m_pob) { + mk_cube_core(); + + // make a clause by negating the cube + m_body = ::push_not(::mk_and(m_cube)); + normalize(m_body, m_body); + + if (!m_pob->is_ground() && has_zk_const(m_body)) { + app_ref_vector zks(m); + m_pob->get_skolems(zks); + zks.reverse(); + expr_abstract(m, 0, + zks.size(), (expr* const*)zks.c_ptr(), m_body, + m_body); + ptr_buffer sorts; + svector names; + for (unsigned i=0, sz=zks.size(); i < sz; ++i) { + sorts.push_back(get_sort(zks.get(i))); + names.push_back(zks.get(i)->get_decl()->get_name()); + } + m_body = m.mk_quantifier(true, zks.size(), + sorts.c_ptr(), + names.c_ptr(), + m_body, 0, symbol(m_body->get_id())); + if (m_new_pob) { + add_binding(m_pob->get_binding()); + } + } + m_new_pob = false; + return; + } + else if (!m_cube.empty()) { + m_body = ::push_not(::mk_and(m_cube)); + normalize(m_body, m_body); + return; + } + else { + UNREACHABLE(); + } + SASSERT(m_body); +} +void lemma::mk_cube_core() { + if (!m_cube.empty()) {return;} + expr_ref cube(m); + if (m_pob || m_body) { + if(m_pob) { + cube = m_pob->post(); + } + else if (m_body) { + // no quantifiers for now + SASSERT(!is_quantifier(m_body)); + cube = m_body; + cube = ::push_not(cube); + } + flatten_and(cube, m_cube); + if (m_cube.empty()) { + m_cube.push_back(m.mk_true()); + } + else { + std::sort(m_cube.c_ptr(), m_cube.c_ptr() + m_cube.size(), ast_lt_proc()); + } + } + else { + UNREACHABLE(); + } +} +bool lemma::is_false() { + // a lemma is false if + // 1. it is defined by a cube, and the cube contains a single literal 'true' + // 2. it is defined by a body, and the body is a single literal false + // 3. it is defined by a pob, and the pob post is false + if (m_cube.size() == 1) {return m.is_true(m_cube.get(0));} + else if (m_body) {return m.is_false(m_body);} + else if (m_pob) {return m.is_true(m_pob->post());} + + return false; +} +expr* lemma::get_expr() { + mk_expr_core(); + return m_body; +} +expr_ref_vector const &lemma::get_cube() { + mk_cube_core(); + return m_cube; +} + +void lemma::update_cube (pob_ref const &p, expr_ref_vector &cube) { + SASSERT(m_pob); + SASSERT(m_pob.get() == p.get()); + m_cube.reset(); + m_body.reset(); + m_cube.append(cube); + if (m_cube.empty()) {m_cube.push_back(m.mk_true());} +} + +void lemma::mk_insts(expr_ref_vector &out, expr* e) +{ + expr *lem = e == nullptr ? get_expr() : e; + if (!is_quantifier (lem) || m_bindings.empty()) {return;} + + expr *body = to_quantifier(lem)->get_expr(); + unsigned num_decls = to_quantifier(lem)->get_num_decls(); + expr_ref inst(m); + var_subst vs(m, false); + for (unsigned i = 0, + sz = m_bindings.size() / num_decls, + off = 0; + i < sz; + ++i, off += num_decls) { + inst.reset(); + vs.reset(); + vs(body, num_decls, (expr**) m_bindings.c_ptr() + off, inst); + out.push_back(inst); + } +} + +bool pred_transformer::frames::add_lemma(lemma *lem) +{ + TRACE("spacer", tout << "add-lemma: " << pp_level(lem->level()) << " " + << m_pt.head()->get_name() << " " + << mk_pp(lem->get_expr(), m_pt.get_ast_manager()) << "\n";); + + for (unsigned i = 0, sz = m_lemmas.size(); i < sz; ++i) { + if (m_lemmas [i]->get_expr() == lem->get_expr()) { + // extend bindings if needed + if (!lem->get_bindings().empty()) { + m_lemmas [i]->add_binding(lem->get_bindings()); + } + // if the lemma is at a higher level, skip it + // XXX if there are new bindings, we need to assert new instances + if (m_lemmas [i]->level() >= lem->level()) { + TRACE("spacer", tout << "Already at a higher level: " + << pp_level(m_lemmas [i]->level()) << "\n";); + return false; + } + + // update level of the existing lemma + m_lemmas [i]->set_level(lem->level()); + // assert lemma in the solver + m_pt.add_lemma_core(m_lemmas[i]); + // move the lemma to its new place to maintain sortedness + for (unsigned j = i; (j + 1) < sz && m_lt(m_lemmas [j + 1], m_lemmas[j]); ++j) { + m_lemmas.swap (j, j+1); + } + + return true; + } + } + + // did not find, create new lemma + m_lemmas.push_back(lem); + m_sorted = false; + m_pt.add_lemma_core(lem); + return true; +} + + +void pred_transformer::frames::propagate_to_infinity (unsigned level) +{ + for (unsigned i = 0, sz = m_lemmas.size (); i < sz; ++i) + if (m_lemmas[i]->level() >= level && !is_infty_level(m_lemmas [i]->level())) { + m_lemmas [i]->set_level (infty_level ()); + m_pt.add_lemma_core (m_lemmas [i]); + m_sorted = false; + } +} + +void pred_transformer::frames::sort () +{ + if (m_sorted) { return; } + + m_sorted = true; + std::sort(m_lemmas.c_ptr(), m_lemmas.c_ptr() + m_lemmas.size (), m_lt); +} + +bool pred_transformer::frames::propagate_to_next_level (unsigned level) +{ + sort (); + bool all = true; + + + if (m_lemmas.empty()) { return all; } + + unsigned tgt_level = next_level (level); + m_pt.ensure_level (tgt_level); + + for (unsigned i = 0, sz = m_lemmas.size(); i < sz && m_lemmas [i]->level() <= level;) { + if (m_lemmas [i]->level () < level) + {++i; continue;} + + + unsigned solver_level; + expr * curr = m_lemmas [i]->get_expr (); + if (m_pt.is_invariant(tgt_level, curr, solver_level)) { + m_lemmas [i]->set_level (solver_level); + m_pt.add_lemma_core (m_lemmas [i]); + + // percolate the lemma up to its new place + for (unsigned j = i; (j+1) < sz && m_lt (m_lemmas[j+1], m_lemmas[j]); ++j) { + m_lemmas.swap(j, j + 1); + } + } else { + all = false; + ++i; + } + } + + return all; +} + +void pred_transformer::frames::simplify_formulas () +{ + // number of subsumed lemmas + unsigned num_sumbsumed = 0; + + // ensure that the lemmas are sorted + sort(); + ast_manager &m = m_pt.get_ast_manager (); + + tactic_ref simplifier = mk_unit_subsumption_tactic (m); + lemma_ref_vector new_lemmas; + + unsigned lemmas_size = m_lemmas.size (); + goal_ref g (alloc (goal, m, false, false, false)); + + unsigned j = 0; + // for every frame + infinity frame + for (unsigned i = 0; i <= m_size; ++i) { + g->reset_all (); + // normalize level + unsigned level = i < m_size ? i : infty_level (); + + model_converter_ref mc; + proof_converter_ref pc; + expr_dependency_ref core(m); + goal_ref_buffer result; + + // simplify lemmas of the current level + // XXX lemmas of higher levels can be assumed in background + // XXX decide what to do with non-ground lemmas! + unsigned begin = j; + for (; j < lemmas_size && m_lemmas[j]->level() <= level; ++j) { + if (m_lemmas[j]->level() == level) { + g->assert_expr(m_lemmas[j]->get_expr()); + } + } + unsigned end = j; + + unsigned sz = end - begin; + // no lemmas at current level, move to next level + if (sz <= 0) {continue;} + + // exactly one lemma at current level, nothing to + // simplify. move to next level + if (sz == 1) { + new_lemmas.push_back(m_lemmas[begin]); + continue; + } + + // more than one lemma at current level. simplify. + (*simplifier)(g, result, mc, pc, core); + SASSERT(result.size () == 1); + goal *r = result[0]; + + // no simplification happened, copy all the lemmas + if (r->size () == sz) { + for (unsigned n = begin; n < end; ++n) { + new_lemmas.push_back (m_lemmas[n]); + } + } + // something got simplified, find out which lemmas remain + else { + num_sumbsumed += (sz - r->size()); + // For every expression in the result, copy corresponding + // lemma into new_lemmas + // XXX linear search. optimize if needed. + for (unsigned k = 0; k < r->size(); ++k) { + bool found = false; + for (unsigned n = begin; n < end; ++n) { + if (m_lemmas[n]->get_expr() == r->form(k)) { + new_lemmas.push_back(m_lemmas[n]); + found = true; + break; + } + } + if (!found) { + verbose_stream() << "Failed to find a lemma for: " + << mk_pp(r->form(k), m) << "\n"; + verbose_stream() << "Available lemmas are: "; + for (unsigned n = begin; n < end; ++n) { + verbose_stream() << n << ": " + << mk_pp(m_lemmas[n]->get_expr(), m) + << "\n"; + } + } + ENSURE(found); + SASSERT(found); + } + } + } + + SASSERT(new_lemmas.size() + num_sumbsumed == m_lemmas.size()); + ENSURE(new_lemmas.size() + num_sumbsumed == m_lemmas.size()); + if (new_lemmas.size() < m_lemmas.size()) { + m_lemmas.reset(); + m_lemmas.append(new_lemmas); + m_sorted = false; + sort(); + } +} + +pob* pred_transformer::pobs::mk_pob(pob *parent, + unsigned level, unsigned depth, + expr *post, app_ref_vector const &b) { + + if (!m_pt.ctx.get_params().spacer_reuse_pobs()) { + pob* n = alloc(pob, parent, m_pt, level, depth); + n->set_post(post, b); + return n; + } + + // create a new pob and set its post to normalize it + pob p(parent, m_pt, level, depth, false); + p.set_post(post, b); + + if (m_pobs.contains(p.post())) { + auto &buf = m_pobs[p.post()]; + for (unsigned i = 0, sz = buf.size(); i < sz; ++i) { + pob *f = buf.get(i); + if (f->parent() == parent) { + f->inherit(p); + return f; + } + } + } + + pob* n = alloc(pob, parent, m_pt, level, depth); + n->set_post(post, b); + m_pinned.push_back(n); + + if (m_pobs.contains(n->post())) { + m_pobs[n->post()].push_back(n); + } + else { + pob_buffer buf; + buf.push_back(n); + m_pobs.insert(n->post(), buf); + } + return n; +} + +app* pred_transformer::extend_initial (expr *e) +{ + // create fresh extend literal + app_ref v(m); + std::stringstream name; + name << m_head->get_name() << "_ext"; + v = m.mk_fresh_const (name.str ().c_str (), + m.mk_bool_sort ()); + v = m.mk_const (pm.get_n_pred (v->get_decl ())); + + expr_ref ic(m); + + // -- extend the initial condition + ic = m.mk_or (m_extend_lit, e, v); + m_solver.assert_expr (ic); + + // -- remember the new extend literal + m_extend_lit = m.mk_not (v); + + return m_extend_lit; +} + + +// ---------------- +// derivation + +derivation::derivation (pob& parent, datalog::rule const& rule, + expr *trans, app_ref_vector const &evars) : + m_parent (parent), + m_rule (rule), + m_premises (), + m_active (0), + m_trans (trans, m_parent.get_ast_manager ()), + m_evars (evars) {} + +derivation::premise::premise (pred_transformer &pt, unsigned oidx, + expr *summary, bool must, + const ptr_vector *aux_vars) : + m_pt (pt), m_oidx (oidx), + m_summary (summary, pt.get_ast_manager ()), m_must (must), + m_ovars (pt.get_ast_manager ()) +{ + + ast_manager &m = m_pt.get_ast_manager (); + manager &sm = m_pt.get_manager (); + + unsigned sig_sz = m_pt.head ()->get_arity (); + for (unsigned i = 0; i < sig_sz; ++i) + { m_ovars.push_back(m.mk_const(sm.o2o(pt.sig(i), 0, m_oidx))); } + + if (aux_vars) + for (unsigned i = 0, sz = aux_vars->size (); i < sz; ++i) + { m_ovars.push_back(m.mk_const(sm.n2o(aux_vars->get(i)->get_decl(), m_oidx))); } +} + +derivation::premise::premise (const derivation::premise &p) : + m_pt (p.m_pt), m_oidx (p.m_oidx), m_summary (p.m_summary), m_must (p.m_must), + m_ovars (p.m_ovars) {} + +/// \brief Updated the summary. +/// The new summary is over n-variables. +void derivation::premise::set_summary (expr * summary, bool must, + const ptr_vector *aux_vars) +{ + ast_manager &m = m_pt.get_ast_manager (); + manager &sm = m_pt.get_manager (); + unsigned sig_sz = m_pt.head ()->get_arity (); + + m_must = must; + sm.formula_n2o (summary, m_summary, m_oidx); + + m_ovars.reset (); + for (unsigned i = 0; i < sig_sz; ++i) + { m_ovars.push_back(m.mk_const(sm.o2o(m_pt.sig(i), 0, m_oidx))); } + + if (aux_vars) + for (unsigned i = 0, sz = aux_vars->size (); i < sz; ++i) + m_ovars.push_back (m.mk_const (sm.n2o (aux_vars->get (i)->get_decl (), + m_oidx))); +} + + +void derivation::add_premise (pred_transformer &pt, + unsigned oidx, + expr* summary, + bool must, + const ptr_vector *aux_vars) +{m_premises.push_back (premise (pt, oidx, summary, must, aux_vars));} + + + +pob *derivation::create_first_child (model_evaluator_util &mev) +{ + if (m_premises.empty()) { return NULL; } + m_active = 0; + return create_next_child(mev); +} + +pob *derivation::create_next_child (model_evaluator_util &mev) +{ + timeit _timer (is_trace_enabled("spacer_timeit"), + "spacer::derivation::create_next_child", + verbose_stream ()); + + ast_manager &m = get_ast_manager (); + expr_ref_vector summaries (m); + app_ref_vector vars (m); + + bool use_native_mbp = get_context ().use_native_mbp (); + bool ground = get_context ().use_ground_cti (); + // -- find first may premise + while (m_active < m_premises.size() && m_premises[m_active].is_must()) { + summaries.push_back (m_premises[m_active].get_summary ()); + vars.append (m_premises[m_active].get_ovars ()); + ++m_active; + } + if (m_active >= m_premises.size()) { return NULL; } + + // -- update m_trans with the pre-image of m_trans over the must summaries + summaries.push_back (m_trans); + m_trans = get_manager ().mk_and (summaries); + summaries.reset (); + + if (!vars.empty()) { + timeit _timer1 (is_trace_enabled("spacer_timeit"), + "create_next_child::qproject1", + verbose_stream ()); + qe_project (m, vars, m_trans, mev.get_model (), true, use_native_mbp, !ground); + //qe::reduce_array_selects (*mev.get_model (), m_trans); + // remember variables that need to be existentially quantified + m_evars.append (vars); + } + + if (!mev.is_true (m_premises[m_active].get_summary())) { + IF_VERBOSE(1, verbose_stream() << "Summary unexpectendly not true\n";); + return NULL; + } + + + // create the post condition by compute post-image over summaries + // that precede currently active premise + vars.reset (); + for (unsigned i = m_active + 1; i < m_premises.size(); ++i) { + summaries.push_back (m_premises [i].get_summary ()); + vars.append (m_premises [i].get_ovars ()); + } + summaries.push_back (m_trans); + + expr_ref post(m); + post = get_manager ().mk_and (summaries); + summaries.reset (); + if (!vars.empty()) { + timeit _timer2 (is_trace_enabled("spacer_timeit"), + "create_next_child::qproject2", + verbose_stream ()); + qe_project (m, vars, post, mev.get_model (), true, use_native_mbp, !ground); + //qe::reduce_array_selects (*mev.get_model (), post); + + // remember variables that need to be existentially quantified + m_evars.append (vars); + } + + get_manager ().formula_o2n (post.get (), post, + m_premises [m_active].get_oidx (), m_evars.empty()); + + + /* The level and depth are taken from the parent, not the sibling. + The reasoning is that the sibling has not been checked before, + and lower level is a better starting point. */ + pob *n = m_premises[m_active].pt().mk_pob(&m_parent, + prev_level (m_parent.level ()), + m_parent.depth (), post, m_evars); + + IF_VERBOSE (1, verbose_stream () + << "\n\tcreate_child: " << n->pt ().head ()->get_name () + << " (" << n->level () << ", " << n->depth () << ") " + << (n->use_farkas_generalizer () ? "FAR " : "SUB ") + << n->post ()->get_id (); + verbose_stream().flush ();); + return n; +} + +pob *derivation::create_next_child () +{ + if (m_active + 1 >= m_premises.size()) { return NULL; } + + bool use_native_mbp = get_context ().use_native_mbp (); + bool ground = get_context ().use_ground_cti (); + + // update the summary of the active node to some must summary + + // construct a new model consistent with the must summary of m_active premise + pred_transformer &pt = m_premises[m_active].pt (); + model_ref model; + + ast_manager &m = get_ast_manager (); + manager &pm = get_manager (); + + expr_ref_vector summaries (m); + + for (unsigned i = m_active + 1; i < m_premises.size (); ++i) + { summaries.push_back(m_premises [i].get_summary()); } + + // -- orient transition relation towards m_active premise + expr_ref active_trans (m); + pm.formula_o2n (m_trans, active_trans, + m_premises[m_active].get_oidx (), false); + summaries.push_back (active_trans); + + // if not true, bail out, the must summary of m_active is not strong enough + // this is possible if m_post was weakened for some reason + if (!pt.is_must_reachable(pm.mk_and(summaries), &model)) { return NULL; } + + model_evaluator_util mev (m); + mev.set_model (*model); + // find must summary used + + reach_fact *rf = pt.get_used_reach_fact (mev, true); + + // get an implicant of the summary + expr_ref_vector u(m), lits (m); + u.push_back (rf->get ()); + compute_implicant_literals (mev, u, lits); + expr_ref v(m); + v = pm.mk_and (lits); + + // XXX The summary is not used by anyone after this point + m_premises[m_active].set_summary (v, true, &(rf->aux_vars ())); + + + /** HACK: needs a rewrite + * compute post over the new must summary this must be done here + * because the must summary is currently described over new + * variables. However, we store it over old-variables, but we do + * not update the model. So we must get rid of all of the + * new-variables at this point. + */ + { + pred_transformer &pt = m_premises[m_active].pt (); + app_ref_vector vars (m); + + summaries.reset (); + summaries.push_back (v); + summaries.push_back (active_trans); + m_trans = pm.mk_and (summaries); + + // variables to eliminate + vars.append (rf->aux_vars ().size (), rf->aux_vars ().c_ptr ()); + for (unsigned i = 0, sz = pt.head ()->get_arity (); i < sz; ++i) + { vars.push_back(m.mk_const(pm.o2n(pt.sig(i), 0))); } + + if (!vars.empty ()) { + qe_project (m, vars, m_trans, mev.get_model (), true, use_native_mbp, + !ground); + // keep track of implicitly quantified variables + m_evars.append (vars); + } + } + + m_active++; + + return create_next_child (mev); +} + +pob::pob (pob* parent, pred_transformer& pt, + unsigned level, unsigned depth, bool add_to_parent): + m_ref_count (0), + m_parent (parent), m_pt (pt), + m_post (m_pt.get_ast_manager ()), + m_binding(m_pt.get_ast_manager()), + m_new_post (m_pt.get_ast_manager ()), + m_level (level), m_depth (depth), + m_open (true), m_use_farkas (true), m_weakness(0) { + if(add_to_parent && m_parent) { + m_parent->add_child(*this); + } +} + + +void pob::set_post(expr* post) { + app_ref_vector b(get_ast_manager()); + set_post(post, b); +} + +void pob::set_post(expr* post, app_ref_vector const &b) { + normalize(post, m_post, + m_pt.get_context().get_params().spacer_simplify_pob(), + m_pt.get_context().get_params().spacer_use_eqclass()); + + m_binding.reset(); + if (b.empty()) return; + + m_binding.append(b); + + std::sort (m_binding.c_ptr(), m_binding.c_ptr() + m_binding.size(), ast_lt_proc()); + + // skolemize implicit existential quantifier + ast_manager &m = get_ast_manager(); + app_ref_vector pinned(m); + + expr_safe_replace sub(m); + for (unsigned i = 0, sz = m_binding.size(); i < sz; ++i) { + expr* e; + + e = m_binding.get(i); + pinned.push_back (mk_zk_const (m, i, get_sort(e))); + sub.insert (e, pinned.back()); + } + sub(m_post); +} + +void pob::inherit(pob const &p) { + SASSERT(m_parent == p.m_parent); + SASSERT(&m_pt == &p.m_pt); + SASSERT(m_post == p.m_post); + SASSERT(!m_new_post); + + m_binding.reset(); + m_binding.append(p.m_binding); + + m_level = p.m_level; + m_depth = p.m_depth; + m_open = p.m_open; + m_use_farkas = p.m_use_farkas; + m_weakness = p.m_weakness; + + m_derivation = nullptr; +} + +void pob::clean () { + if(m_new_post) { + m_post = m_new_post; + m_new_post.reset(); + } +} + +void pob::close () { + if(!m_open) { return; } + + reset (); + m_open = false; + for (unsigned i = 0, sz = m_kids.size (); i < sz; ++i) + { m_kids [i]->close(); } +} + +void pob::get_skolems(app_ref_vector &v) { + for (unsigned i = 0, sz = m_binding.size(); i < sz; ++i) { + expr* e; + + e = m_binding.get(i); + v.push_back (mk_zk_const (get_ast_manager(), i, get_sort(e))); + } +} + + + +// ---------------- +// pob_queue + +pob* pob_queue::top () +{ + /// nothing in the queue + if (m_obligations.empty()) { return NULL; } + /// top queue element is above max level + if (m_obligations.top()->level() > m_max_level) { return NULL; } + /// top queue element is at the max level, but at a higher than base depth + if (m_obligations.top ()->level () == m_max_level && + m_obligations.top()->depth() > m_min_depth) { return NULL; } + + /// there is something good in the queue + return m_obligations.top ().get (); +} + +void pob_queue::set_root(pob& root) +{ + m_root = &root; + m_max_level = root.level (); + m_min_depth = root.depth (); + reset(); +} + +pob_queue::~pob_queue() {} + +void pob_queue::reset() +{ + while (!m_obligations.empty()) { m_obligations.pop(); } + if (m_root) { m_obligations.push(m_root); } +} + +// ---------------- +// context + +context::context(fixedpoint_params const& params, + ast_manager& m) : + m_params(params), + m(m), + m_context(0), + m_pm(params.pdr_max_num_contexts(), m), + m_query_pred(m), + m_query(0), + m_pob_queue(), + m_last_result(l_undef), + m_inductive_lvl(0), + m_expanded_lvl(0), + m_use_native_mbp(params.spacer_native_mbp ()), + m_ground_cti (params.spacer_ground_cti ()), + m_instantiate (params.spacer_instantiate ()), + m_use_qlemmas (params.spacer_qlemmas ()), + m_weak_abs(params.spacer_weak_abs()), + m_use_restarts(params.spacer_restarts()), + m_restart_initial_threshold(params.spacer_restart_initial_threshold()) +{} + +context::~context() +{ + reset_lemma_generalizers(); + reset(); +} + +void context::reset() +{ + TRACE("spacer", tout << "\n";); + m_pob_queue.reset(); + decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + m_rels.reset(); + m_query = 0; + m_last_result = l_undef; + m_inductive_lvl = 0; +} + +void context::init_rules(datalog::rule_set& rules, decl2rel& rels) +{ + scoped_watch _t_(m_init_rules_watch); + m_context = &rules.get_context(); + // Allocate collection of predicate transformers + datalog::rule_set::decl2rules::iterator dit = rules.begin_grouped_rules(), dend = rules.end_grouped_rules(); + decl2rel::obj_map_entry* e; + for (; dit != dend; ++dit) { + func_decl* pred = dit->m_key; + TRACE("spacer", tout << mk_pp(pred, m) << "\n";); + SASSERT(!rels.contains(pred)); + e = rels.insert_if_not_there2(pred, alloc(pred_transformer, *this, + get_manager(), pred)); + datalog::rule_vector const& pred_rules = *dit->m_value; + for (unsigned i = 0; i < pred_rules.size(); ++i) { + e->get_data().m_value->add_rule(pred_rules[i]); + } + } + datalog::rule_set::iterator rit = rules.begin(), rend = rules.end(); + for (; rit != rend; ++rit) { + datalog::rule* r = *rit; + pred_transformer* pt; + unsigned utz = r->get_uninterpreted_tail_size(); + for (unsigned i = 0; i < utz; ++i) { + func_decl* pred = r->get_decl(i); + if (!rels.find(pred, pt)) { + pt = alloc(pred_transformer, *this, get_manager(), pred); + rels.insert(pred, pt); + } + } + } + // Initialize use list dependencies + decl2rel::iterator it = rels.begin(), end = rels.end(); + for (; it != end; ++it) { + func_decl* pred = it->m_key; + pred_transformer* pt = it->m_value, *pt_user; + obj_hashtable const& deps = rules.get_dependencies().get_deps(pred); + obj_hashtable::iterator itf = deps.begin(), endf = deps.end(); + for (; itf != endf; ++itf) { + TRACE("spacer", tout << mk_pp(pred, m) << " " << mk_pp(*itf, m) << "\n";); + pt_user = rels.find(*itf); + pt_user->add_use(pt); + } + } + + // Initialize the predicate transformers. + it = rels.begin(), end = rels.end(); + for (; it != end; ++it) { + pred_transformer& rel = *it->m_value; + rel.initialize(rels); + TRACE("spacer", rel.display(tout); ); + } + + // initialize reach facts + it = rels.begin (), end = rels.end (); + for (; it != end; ++it) + { it->m_value->init_reach_facts(); } +} + +void context::update_rules(datalog::rule_set& rules) +{ + decl2rel rels; + init_lemma_generalizers(rules); + init_rules(rules, rels); + decl2rel::iterator it = rels.begin(), end = rels.end(); + for (; it != end; ++it) { + pred_transformer* pt = 0; + if (m_rels.find(it->m_key, pt)) { + it->m_value->inherit_properties(*pt); + } + } + reset(); + it = rels.begin(), end = rels.end(); + for (; it != end; ++it) { + m_rels.insert(it->m_key, it->m_value); + } +} + +unsigned context::get_num_levels(func_decl* p) +{ + pred_transformer* pt = 0; + if (m_rels.find(p, pt)) { + return pt->get_num_levels(); + } else { + IF_VERBOSE(10, verbose_stream() << "did not find predicate " << p->get_name() << "\n";); + return 0; + } +} + +expr_ref context::get_cover_delta(int level, func_decl* p_orig, func_decl* p) +{ + pred_transformer* pt = 0; + if (m_rels.find(p, pt)) { + return pt->get_cover_delta(p_orig, level); + } else { + IF_VERBOSE(10, verbose_stream() << "did not find predicate " << p->get_name() << "\n";); + return expr_ref(m.mk_true(), m); + } +} + +void context::add_cover(int level, func_decl* p, expr* property) +{ + pred_transformer* pt = 0; + if (!m_rels.find(p, pt)) { + pt = alloc(pred_transformer, *this, get_manager(), p); + m_rels.insert(p, pt); + IF_VERBOSE(10, verbose_stream() << "did not find predicate " << p->get_name() << "\n";); + } + unsigned lvl = (level == -1)?infty_level():((unsigned)level); + pt->add_cover(lvl, property); +} + +void context::add_invariant (func_decl *p, expr *property) +{add_cover (infty_level(), p, property);} + +expr_ref context::get_reachable(func_decl *p) +{ + pred_transformer* pt = 0; + if (!m_rels.find(p, pt)) + { return expr_ref(m.mk_false(), m); } + return pt->get_reachable(); +} + +bool context::validate() +{ + if (!m_params.pdr_validate_result()) { return true; } + + std::stringstream msg; + + switch(m_last_result) { + case l_true: { + expr_ref cex(m); + cex = get_ground_sat_answer(); + if (!cex.get()) { + IF_VERBOSE(0, verbose_stream() << "Cex validation failed\n";); + throw default_exception("Cex validation failed\n"); + return false; + } + break; + } + case l_false: { + expr_ref_vector refs(m); + expr_ref tmp(m); + model_ref model; + vector rs; + model_converter_ref mc; + get_level_property(m_inductive_lvl, refs, rs); + inductive_property ex(m, mc, rs); + ex.to_model(model); + decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); + var_subst vs(m, false); + for (; it != end; ++it) { + ptr_vector const& rules = it->m_value->rules(); + TRACE ("spacer", tout << "PT: " << it->m_value->head ()->get_name ().str () + << "\n";); + for (unsigned i = 0; i < rules.size(); ++i) { + datalog::rule& r = *rules[i]; + + TRACE ("spacer", + get_datalog_context (). + get_rule_manager (). + display_smt2(r, tout) << "\n";); + + model->eval(r.get_head(), tmp); + expr_ref_vector fmls(m); + fmls.push_back(m.mk_not(tmp)); + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + for (unsigned j = 0; j < utsz; ++j) { + model->eval(r.get_tail(j), tmp); + fmls.push_back(tmp); + } + for (unsigned j = utsz; j < tsz; ++j) { + fmls.push_back(r.get_tail(j)); + } + tmp = m.mk_and(fmls.size(), fmls.c_ptr()); + svector names; + expr_free_vars fv; + fv (tmp); + fv.set_default_sort (m.mk_bool_sort ()); + + for (unsigned i = 0; i < fv.size(); ++i) { + names.push_back(symbol(fv.size () - i - 1)); + } + if (!fv.empty()) { + fv.reverse (); + tmp = m.mk_exists(fv.size(), fv.c_ptr(), names.c_ptr(), tmp); + } + smt::kernel solver(m, m_pm.fparams2()); + solver.assert_expr(tmp); + lbool res = solver.check(); + if (res != l_false) { + msg << "rule validation failed when checking: " + << mk_pp(tmp, m); + IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); + throw default_exception(msg.str()); + return false; + } + } + } + TRACE ("spacer", tout << "Validation Succeeded\n";); + break; + } + default: + break; + } + return true; +} + + +void context::reset_lemma_generalizers() +{ + std::for_each(m_lemma_generalizers.begin(), m_lemma_generalizers.end(), + delete_proc()); + m_lemma_generalizers.reset(); +} + +void context::init_lemma_generalizers(datalog::rule_set& rules) +{ + reset_lemma_generalizers(); + m.toggle_proof_mode(PGM_ENABLED); + smt_params &fparams = m_pm.fparams (); + if (!m_params.spacer_eq_prop ()) { + fparams.m_arith_bound_prop = BP_NONE; + fparams.m_arith_auto_config_simplex = true; + fparams.m_arith_propagate_eqs = false; + fparams.m_arith_eager_eq_axioms = false; + } + fparams.m_random_seed = m_params.spacer_random_seed (); + + fparams.m_dump_benchmarks = m_params.spacer_vs_dump_benchmarks(); + fparams.m_dump_min_time = m_params.spacer_vs_dump_min_time(); + fparams.m_dump_recheck = m_params.spacer_vs_recheck(); + + fparams.m_mbqi = m_params.spacer_mbqi(); + + if (get_params().spacer_use_eqclass()) { + m_lemma_generalizers.push_back (alloc(lemma_eq_generalizer, *this)); + } + + // -- AG: commented out because it is causing performance issues at the moment + //m_lemma_generalizers.push_back (alloc (unsat_core_generalizer, *this)); + + if (m_params.pdr_use_inductive_generalizer()) { + m_lemma_generalizers.push_back(alloc(lemma_bool_inductive_generalizer, *this, 0)); + } + + if (m_params.spacer_use_array_eq_generalizer()) { + m_lemma_generalizers.push_back(alloc(lemma_array_eq_generalizer, *this)); + } + + if (get_params().spacer_lemma_sanity_check()) { + m_lemma_generalizers.push_back(alloc(lemma_sanity_checker, *this)); + } + +} + +void context::get_level_property(unsigned lvl, expr_ref_vector& res, + vector& rs) const +{ + decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); + for (; it != end; ++it) { + pred_transformer* r = it->m_value; + if (r->head() == m_query_pred) { + continue; + } + expr_ref conj = r->get_formulas(lvl, false); + m_pm.formula_n2o(0, false, conj); + res.push_back(conj); + ptr_vector sig(r->head()->get_arity(), r->sig()); + rs.push_back(relation_info(m, r->head(), sig, conj)); + } +} + +void context::simplify_formulas() +{ + decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); + for (; it != end; ++it) { + pred_transformer* r = it->m_value; + r->simplify_formulas(); + } +} + +lbool context::solve(unsigned from_lvl) +{ + m_last_result = l_undef; + try { + m_last_result = solve_core (from_lvl); + if (m_last_result == l_false) { + simplify_formulas(); + m_last_result = l_false; + IF_VERBOSE(1, { + expr_ref_vector refs(m); + vector rs; + get_level_property(m_inductive_lvl, refs, rs); + model_converter_ref mc; + inductive_property ex(m, mc, rs); + verbose_stream() << ex.to_string(); + }); + + // upgrade invariants that are known to be inductive. + // decl2rel::iterator it = m_rels.begin (), end = m_rels.end (); + // for (; m_inductive_lvl > 0 && it != end; ++it) { + // if (it->m_value->head() != m_query_pred) { + // it->m_value->propagate_to_infinity (m_inductive_lvl); + // } + // } + } + VERIFY (validate ()); + } catch (unknown_exception) + {} + + if (m_last_result == l_true) { + m_stats.m_cex_depth = get_cex_depth (); + } + + if (m_params.print_statistics ()) { + statistics st; + collect_statistics (st); + st.display_smt2 (verbose_stream ()); + } + + return m_last_result; +} + + +void context::checkpoint() +{ + if (m.canceled ()) { + throw default_exception("spacer canceled"); + } +} + +unsigned context::get_cex_depth() +{ + if (m_last_result != l_true) { + IF_VERBOSE(1, + verbose_stream () + << "Trace unavailable when result is false\n";); + return 0; + } + + // treat the following as queues: read from left to right and insert at right + ptr_vector preds; + ptr_vector pts; + reach_fact_ref_vector facts; + + // temporary + reach_fact* fact; + datalog::rule const* r; + pred_transformer* pt; + + // get and discard query rule + fact = m_query->get_last_reach_fact (); + r = &fact->get_rule (); + + unsigned cex_depth = 0; + + // initialize queues + // assume that the query is only on a single predicate + // (i.e. disallow fancy queries for now) + facts.append (fact->get_justifications ()); + if (facts.size() != 1) { + // XXX AG: Escape if an assertion is about to fail + IF_VERBOSE(1, + verbose_stream () << + "Warning: counterexample is trivial or non-existent\n";); + return cex_depth; + } + SASSERT (facts.size () == 1); + m_query->find_predecessors (*r, preds); + SASSERT (preds.size () == 1); + pts.push_back (&(get_pred_transformer (preds[0]))); + + pts.push_back (NULL); // cex depth marker + + // bfs traversal of the query derivation tree + for (unsigned curr = 0; curr < pts.size (); curr++) { + // get current pt and fact + pt = pts.get (curr); + // check for depth marker + if (pt == NULL) { + ++cex_depth; + // insert new marker if there are pts at higher depth + if (curr + 1 < pts.size()) { pts.push_back(NULL); } + continue; + } + fact = facts.get (curr - cex_depth); // discount the number of markers + // get rule justifying the derivation of fact at pt + r = &fact->get_rule (); + TRACE ("spacer", + tout << "next rule: " << r->name ().str () << "\n"; + ); + // add child facts and pts + facts.append (fact->get_justifications ()); + pt->find_predecessors (*r, preds); + for (unsigned j = 0; j < preds.size (); j++) { + pts.push_back (&(get_pred_transformer (preds[j]))); + } + } + + return cex_depth; +} + +/** + \brief retrieve answer. +*/ + +void context::get_rules_along_trace(datalog::rule_ref_vector& rules) +{ + if (m_last_result != l_true) { + IF_VERBOSE(1, + verbose_stream () + << "Trace unavailable when result is false\n";); + return; + } + + // treat the following as queues: read from left to right and insert at right + ptr_vector preds; + ptr_vector pts; + reach_fact_ref_vector facts; + + // temporary + reach_fact* fact; + datalog::rule const* r; + pred_transformer* pt; + + // get query rule + fact = m_query->get_last_reach_fact (); + r = &fact->get_rule (); + rules.push_back (const_cast (r)); + TRACE ("spacer", + tout << "Initial rule: " << r->name().str() << "\n"; + ); + + // initialize queues + // assume that the query is only on a single predicate + // (i.e. disallow fancy queries for now) + facts.append (fact->get_justifications ()); + if (facts.size() != 1) { + // XXX AG: Escape if an assertion is about to fail + IF_VERBOSE(1, + verbose_stream () << + "Warning: counterexample is trivial or non-existent\n";); + return; + } + SASSERT (facts.size () == 1); + m_query->find_predecessors (*r, preds); + SASSERT (preds.size () == 1); + pts.push_back (&(get_pred_transformer (preds[0]))); + + // populate rules according to a preorder traversal of the query derivation tree + for (unsigned curr = 0; curr < pts.size (); curr++) { + // get current pt and fact + pt = pts.get (curr); + fact = facts.get (curr); + // get rule justifying the derivation of fact at pt + r = &fact->get_rule (); + rules.push_back (const_cast (r)); + TRACE ("spacer", + tout << "next rule: " << r->name ().str () << "\n"; + ); + // add child facts and pts + facts.append (fact->get_justifications ()); + pt->find_predecessors (*r, preds); + for (unsigned j = 0; j < preds.size (); j++) { + pts.push_back (&(get_pred_transformer (preds[j]))); + } + } +} + +model_ref context::get_model() +{ + model_ref model; + expr_ref_vector refs(m); + vector rs; + get_level_property(m_inductive_lvl, refs, rs); + inductive_property ex(m, const_cast(m_mc), rs); + ex.to_model (model); + return model; +} + +proof_ref context::get_proof() const +{ + return proof_ref (m); +} + +expr_ref context::get_answer() +{ + switch(m_last_result) { + case l_true: + return mk_sat_answer(); + case l_false: + return mk_unsat_answer(); + default: + return expr_ref(m.mk_true(), m); + } +} + +/** + \brief Retrieve satisfying assignment with explanation. +*/ +expr_ref context::mk_sat_answer() {return get_ground_sat_answer();} + + +expr_ref context::mk_unsat_answer() const +{ + expr_ref_vector refs(m); + vector rs; + get_level_property(m_inductive_lvl, refs, rs); + inductive_property ex(m, const_cast(m_mc), rs); + return ex.to_expr(); +} + +expr_ref context::get_ground_sat_answer() +{ + if (m_last_result != l_true) { + verbose_stream () << "Sat answer unavailable when result is false\n"; + return expr_ref (m); + } + + // treat the following as queues: read from left to right and insert at the right + reach_fact_ref_vector reach_facts; + ptr_vector preds; + ptr_vector pts; + expr_ref_vector cex (m), // pre-order list of ground instances of predicates + cex_facts (m); // equalities for the ground cex using signature constants + + // temporary + reach_fact *reach_fact; + pred_transformer* pt; + expr_ref cex_fact (m); + datalog::rule const* r; + + // get and discard query rule + reach_fact = m_query->get_last_reach_fact (); + r = &reach_fact->get_rule (); + + // initialize queues + reach_facts.append (reach_fact->get_justifications ()); + if (reach_facts.size() != 1) { + // XXX Escape if an assertion is about to fail + IF_VERBOSE(1, + verbose_stream () << + "Warning: counterexample is trivial or non-existent\n";); + return expr_ref(m.mk_true(), m); + } + m_query->find_predecessors (*r, preds); + SASSERT (preds.size () == 1); + pts.push_back (&(get_pred_transformer (preds[0]))); + cex_facts.push_back (m.mk_true ()); + + // XXX a hack to avoid assertion when query predicate is not nullary + if (preds[0]->get_arity () == 0) + { cex.push_back(m.mk_const(preds[0])); } + + // smt context to obtain local cexes + scoped_ptr cex_ctx = alloc (smt::kernel, m, m_pm.fparams2 ()); + model_evaluator_util mev (m); + + // preorder traversal of the query derivation tree + for (unsigned curr = 0; curr < pts.size (); curr++) { + // pick next pt, fact, and cex_fact + pt = pts.get (curr); + reach_fact = reach_facts[curr]; + + cex_fact = cex_facts.get (curr); + + ptr_vector child_pts; + + // get justifying rule and child facts for the derivation of reach_fact at pt + r = &reach_fact->get_rule (); + const reach_fact_ref_vector &child_reach_facts = + reach_fact->get_justifications (); + // get child pts + preds.reset(); + pt->find_predecessors(*r, preds); + for (unsigned j = 0; j < preds.size (); j++) { + child_pts.push_back (&(get_pred_transformer (preds[j]))); + } + // update the queues + reach_facts.append (child_reach_facts); + pts.append (child_pts); + + // update cex and cex_facts by making a local sat check: + // check consistency of reach facts of children, rule body, and cex_fact + cex_ctx->push (); + cex_ctx->assert_expr (cex_fact); + unsigned u_tail_sz = r->get_uninterpreted_tail_size (); + SASSERT (child_reach_facts.size () == u_tail_sz); + for (unsigned i = 0; i < u_tail_sz; i++) { + expr_ref ofml (m); + child_pts.get (i)->get_manager ().formula_n2o + (child_reach_facts[i]->get (), ofml, i); + cex_ctx->assert_expr (ofml); + } + cex_ctx->assert_expr (pt->transition ()); + cex_ctx->assert_expr (pt->rule2tag (r)); + lbool res = cex_ctx->check (); + CTRACE("cex", res == l_false, + tout << "Cex fact: " << mk_pp(cex_fact, m) << "\n"; + for (unsigned i = 0; i < u_tail_sz; i++) + tout << "Pre" << i << " " + << mk_pp(child_reach_facts[i]->get(), m) << "\n"; + tout << "Rule: "; + get_datalog_context().get_rule_manager().display_smt2(*r, tout) << "\n"; + ); + VERIFY (res == l_true); + model_ref local_mdl; + cex_ctx->get_model (local_mdl); + cex_ctx->pop (1); + + model_evaluator_util mev (m); + mev.set_model (*local_mdl); + for (unsigned i = 0; i < child_pts.size (); i++) { + pred_transformer& ch_pt = *(child_pts.get (i)); + unsigned sig_size = ch_pt.sig_size (); + expr_ref_vector ground_fact_conjs (m); + expr_ref_vector ground_arg_vals (m); + for (unsigned j = 0; j < sig_size; j++) { + expr_ref sig_arg (m), sig_val (m); + sig_arg = m.mk_const (ch_pt.get_manager ().o2o (ch_pt.sig (j), 0, i)); + VERIFY(mev.eval (sig_arg, sig_val, true)); + ground_fact_conjs.push_back (m.mk_eq (sig_arg, sig_val)); + ground_arg_vals.push_back (sig_val); + } + if (ground_fact_conjs.size () > 0) { + expr_ref ground_fact (m); + ground_fact = m.mk_and (ground_fact_conjs.size (), ground_fact_conjs.c_ptr ()); + ch_pt.get_manager ().formula_o2n (ground_fact, ground_fact, i); + cex_facts.push_back (ground_fact); + } else { + cex_facts.push_back (m.mk_true ()); + } + cex.push_back (m.mk_app (ch_pt.head (), sig_size, ground_arg_vals.c_ptr ())); + } + } + + TRACE ("spacer", + tout << "ground cex\n"; + for (unsigned i = 0; i < cex.size (); i++) { + tout << mk_pp (cex.get (i), m) << "\n"; + } + ); + + return expr_ref (m.mk_and (cex.size (), cex.c_ptr ()), m); +} + +///this is where everything starts +lbool context::solve_core (unsigned from_lvl) +{ + scoped_watch _w_(m_solve_watch); + //if there is no query predicate, abort + if (!m_rels.find(m_query_pred, m_query)) { return l_false; } + + unsigned lvl = from_lvl; + + pob *root = m_query->mk_pob(nullptr,from_lvl,0,m.mk_true()); + m_pob_queue.set_root (*root); + + unsigned max_level = get_params ().spacer_max_level (); + + for (unsigned i = 0; i < max_level; ++i) { + checkpoint(); + m_expanded_lvl = infty_level (); + m_stats.m_max_query_lvl = lvl; + + if (check_reachability()) { return l_true; } + + if (lvl > 0 && !get_params ().spacer_skip_propagate ()) + if (propagate(m_expanded_lvl, lvl, UINT_MAX)) { return l_false; } + + m_pob_queue.inc_level (); + lvl = m_pob_queue.max_level (); + m_stats.m_max_depth = std::max(m_stats.m_max_depth, lvl); + IF_VERBOSE(1,verbose_stream() << "Entering level "<< lvl << "\n";); + + STRACE("spacer.expand-add", tout << "\n* LEVEL " << lvl << "\n";); + + IF_VERBOSE(1, + if (m_params.print_statistics ()) { + statistics st; + collect_statistics (st); + }; + ); + } + // communicate failure to datalog::context + if (m_context) { m_context->set_status(datalog::BOUNDED); } + return l_undef; +} + + +// +bool context::check_reachability () +{ + scoped_watch _w_(m_reach_watch); + + timeit _timer (get_verbosity_level () >= 1, + "spacer::context::check_reachability", + verbose_stream ()); + + pob_ref last_reachable; + + if (get_params().spacer_reset_obligation_queue()) { m_pob_queue.reset(); } + + unsigned initial_size = m_stats.m_num_lemmas; + unsigned threshold = m_restart_initial_threshold; + unsigned luby_idx = 1; + + while (m_pob_queue.top()) { + pob_ref node; + checkpoint (); + + while (last_reachable) { + checkpoint (); + node = last_reachable; + last_reachable = NULL; + if (m_pob_queue.is_root(*node)) { return true; } + if (is_reachable (*node->parent())) { + last_reachable = node->parent (); + SASSERT(last_reachable->is_closed()); + last_reachable->close (); + } else if (!node->parent()->is_closed()) { + /* bump node->parent */ + node->parent ()->bump_weakness(); + } + } + + SASSERT (m_pob_queue.top ()); + // -- remove all closed nodes and updated all dirty nodes + // -- this is necessary because there is no easy way to + // -- remove nodes from the priority queue. + while (m_pob_queue.top ()->is_closed () || + m_pob_queue.top()->is_dirty()) { + pob_ref n = m_pob_queue.top (); + m_pob_queue.pop (); + if (n->is_closed()) { + IF_VERBOSE (1, + verbose_stream () << "Deleting closed node: " + << n->pt ().head ()->get_name () + << "(" << n->level () << ", " << n->depth () << ")" + << " " << n->post ()->get_id () << "\n";); + if (m_pob_queue.is_root(*n)) { return true; } + SASSERT (m_pob_queue.top ()); + } else if (n->is_dirty()) { + n->clean (); + // -- the node n might not be at the top after it is cleaned + m_pob_queue.push (*n); + } else + { UNREACHABLE(); } + } + + SASSERT (m_pob_queue.top ()); + + if (m_use_restarts && m_stats.m_num_lemmas - initial_size > threshold) { + luby_idx++; + m_stats.m_num_restarts++; + threshold = + static_cast(get_luby(luby_idx)) * m_restart_initial_threshold; + IF_VERBOSE (1, verbose_stream () + << "(restarting :lemmas " << m_stats.m_num_lemmas + << " :restart_threshold " << threshold + << ")\n";); + // -- clear obligation queue up to the root + while (!m_pob_queue.is_root(*m_pob_queue.top())) { m_pob_queue.pop(); } + initial_size = m_stats.m_num_lemmas; + } + + node = m_pob_queue.top (); + SASSERT (node->level () <= m_pob_queue.max_level ()); + switch (expand_node(*node)) { + case l_true: + SASSERT (m_pob_queue.top () == node.get ()); + m_pob_queue.pop (); + last_reachable = node; + last_reachable->close (); + if (m_pob_queue.is_root(*node)) { return true; } + break; + case l_false: + SASSERT (m_pob_queue.top () == node.get ()); + m_pob_queue.pop (); + + if (node->is_dirty()) { node->clean(); } + + node->inc_level (); + if (get_params ().pdr_flexible_trace () && + (node->level () >= m_pob_queue.max_level () || + m_pob_queue.max_level () - node->level () + <= get_params ().pdr_flexible_trace_depth ())) + { m_pob_queue.push(*node); } + + if (m_pob_queue.is_root(*node)) { return false; } + break; + case l_undef: + // SASSERT (m_pob_queue.top () != node.get ()); + break; + } + } + + UNREACHABLE(); + return false; +} + +/// check whether node n is concretely reachable +bool context::is_reachable(pob &n) +{ + scoped_watch _w_(m_is_reach_watch); + // XXX hold a reference for n during this call. + // XXX Should convert is_reachable() to accept pob_ref as argument + pob_ref nref(&n); + + TRACE ("spacer", + tout << "is-reachable: " << n.pt().head()->get_name() + << " level: " << n.level() + << " depth: " << (n.depth () - m_pob_queue.min_depth ()) << "\n" + << mk_pp(n.post(), m) << "\n";); + + stopwatch watch; + IF_VERBOSE (1, verbose_stream () << "is-reachable: " << n.pt ().head ()->get_name () + << " (" << n.level () << ", " + << (n.depth () - m_pob_queue.min_depth ()) << ") " + << (n.use_farkas_generalizer () ? "FAR " : "SUB ") + << n.post ()->get_id (); + verbose_stream().flush (); + watch.start ();); + + // used in case n is unreachable + unsigned uses_level = infty_level (); + model_ref model; + + // used in case n is reachable + bool is_concrete; + const datalog::rule * r = NULL; + // denotes which predecessor's (along r) reach facts are used + vector reach_pred_used; + unsigned num_reuse_reach = 0; + + unsigned saved = n.level (); + n.m_level = infty_level (); + lbool res = n.pt().is_reachable(n, NULL, &model, + uses_level, is_concrete, r, + reach_pred_used, num_reuse_reach); + n.m_level = saved; + + if (res != l_true || !is_concrete) { + IF_VERBOSE(1, verbose_stream () << " F " + << std::fixed << std::setprecision(2) + << watch.get_seconds () << "\n";); + return false; + } + SASSERT(res == l_true); + SASSERT(is_concrete); + + model_evaluator_util mev (m); + mev.set_model(*model); + // -- update must summary + if (r && r->get_uninterpreted_tail_size () > 0) { + reach_fact_ref rf = mk_reach_fact (n, mev, *r); + n.pt ().add_reach_fact (rf.get ()); + } + + // if n has a derivation, create a new child and report l_undef + // otherwise if n has no derivation or no new children, report l_true + pob *next = NULL; + scoped_ptr deriv; + if (n.has_derivation()) {deriv = n.detach_derivation();} + + // -- close n, it is reachable + // -- don't worry about removing n from the obligation queue + n.close (); + + if (deriv) { + next = deriv->create_next_child (); + if (next) { + SASSERT(!next->is_closed()); + // move derivation over to the next obligation + next->set_derivation(deriv.detach()); + + // remove the current node from the queue if it is at the top + if (m_pob_queue.top() == &n) { m_pob_queue.pop(); } + + m_pob_queue.push(*next); + } + } + + // either deriv was a nullptr or it was moved into next + SASSERT(!next || !deriv); + + + IF_VERBOSE(1, verbose_stream () << (next ? " X " : " T ") + << std::fixed << std::setprecision(2) + << watch.get_seconds () << "\n";); + + // recurse on the new proof obligation + return next ? is_reachable(*next) : true; +} + +//this processes a goal and creates sub-goal +lbool context::expand_node(pob& n) +{ + TRACE ("spacer", + tout << "expand-node: " << n.pt().head()->get_name() + << " level: " << n.level() + << " depth: " << (n.depth () - m_pob_queue.min_depth ()) << "\n" + << mk_pp(n.post(), m) << "\n";); + + STRACE ("spacer.expand-add", + tout << "expand-node: " << n.pt().head()->get_name() + << " level: " << n.level() + << " depth: " << (n.depth () - m_pob_queue.min_depth ()) << "\n" + << mk_epp(n.post(), m) << "\n\n";); + + TRACE ("core_array_eq", + tout << "expand-node: " << n.pt().head()->get_name() + << " level: " << n.level() + << " depth: " << (n.depth () - m_pob_queue.min_depth ()) << "\n" + << mk_pp(n.post(), m) << "\n";); + + stopwatch watch; + IF_VERBOSE (1, verbose_stream () << "expand: " << n.pt ().head ()->get_name () + << " (" << n.level () << ", " + << (n.depth () - m_pob_queue.min_depth ()) << ") " + << (n.use_farkas_generalizer () ? "FAR " : "SUB ") + << " w(" << n.weakness() << ") " + << n.post ()->get_id (); + verbose_stream().flush (); + watch.start ();); + + // used in case n is unreachable + unsigned uses_level = infty_level (); + expr_ref_vector cube(m); + model_ref model; + + // used in case n is reachable + bool is_concrete; + const datalog::rule * r = NULL; + // denotes which predecessor's (along r) reach facts are used + vector reach_pred_used; + unsigned num_reuse_reach = 0; + + + if (get_params().pdr_flexible_trace() && n.pt().is_blocked(n, uses_level)) { + // if (!m_pob_queue.is_root (n)) n.close (); + IF_VERBOSE (1, verbose_stream () << " K " + << std::fixed << std::setprecision(2) + << watch.get_seconds () << "\n";); + + return l_false; + } + + smt_params &fparams = m_pm.fparams(); + flet _arith_ignore_int_(fparams.m_arith_ignore_int, + m_weak_abs && n.weakness() < 1); + flet _array_weak_(fparams.m_array_weak, + m_weak_abs && n.weakness() < 2); + + lbool res = n.pt ().is_reachable (n, &cube, &model, uses_level, is_concrete, r, + reach_pred_used, num_reuse_reach); + checkpoint (); + IF_VERBOSE (1, verbose_stream () << "." << std::flush;); + switch (res) { + //reachable but don't know if this is purely using UA + case l_true: { + // update stats + m_stats.m_num_reuse_reach += num_reuse_reach; + + model_evaluator_util mev (m); + mev.set_model (*model); + // must-reachable + if (is_concrete) { + // -- update must summary + if (r && r->get_uninterpreted_tail_size() > 0) { + reach_fact_ref rf = mk_reach_fact (n, mev, *r); + checkpoint (); + n.pt ().add_reach_fact (rf.get ()); + checkpoint (); + } + + // if n has a derivation, create a new child and report l_undef + // otherwise if n has no derivation or no new children, report l_true + pob *next = NULL; + scoped_ptr deriv; + if (n.has_derivation()) {deriv = n.detach_derivation();} + + // -- close n, it is reachable + // -- don't worry about removing n from the obligation queue + n.close (); + + if (deriv) { + next = deriv->create_next_child (); + checkpoint (); + if (next) { + // move derivation over to the next obligation + next->set_derivation (deriv.detach()); + + // remove the current node from the queue if it is at the top + if (m_pob_queue.top() == &n) { m_pob_queue.pop(); } + + m_pob_queue.push (*next); + } + } + + + IF_VERBOSE(1, verbose_stream () << (next ? " X " : " T ") + << std::fixed << std::setprecision(2) + << watch.get_seconds () << "\n";); + return next ? l_undef : l_true; + } + + // create a child of n + VERIFY(create_children (n, *r, mev, reach_pred_used)); + IF_VERBOSE(1, verbose_stream () << " U " + << std::fixed << std::setprecision(2) + << watch.get_seconds () << "\n";); + return l_undef; + + } + // n is unreachable, create new summary facts + case l_false: { + timeit _timer (is_trace_enabled("spacer_timeit"), + "spacer::expand_node::false", + verbose_stream ()); + + // -- only update expanded level when new lemmas are generated at it. + if (n.level() < m_expanded_lvl) { m_expanded_lvl = n.level(); } + + TRACE("spacer", tout << "cube:\n"; + for (unsigned j = 0; j < cube.size(); ++j) + tout << mk_pp(cube[j].get(), m) << "\n";); + + + pob_ref nref(&n); + // -- create lemma from a pob and last unsat core + lemma_ref lemma = alloc(class lemma, pob_ref(&n), cube, uses_level); + + // -- run all lemma generalizers + for (unsigned i = 0; + // -- only generalize if lemma was constructed using farkas + n.use_farkas_generalizer () && !lemma->is_false() && + i < m_lemma_generalizers.size(); ++i) { + checkpoint (); + (*m_lemma_generalizers[i])(lemma); + } + + TRACE("spacer", tout << "invariant state: " + << (is_infty_level(lemma->level())?"(inductive)":"") + << mk_pp(lemma->get_expr(), m) << "\n";); + + bool v = n.pt().add_lemma (lemma.get()); + if (v) { m_stats.m_num_lemmas++; } + + // Optionally update the node to be the negation of the lemma + if (v && get_params().spacer_use_lemma_as_cti()) { + n.new_post (mk_and(lemma->get_cube())); + n.set_farkas_generalizer (false); + } + CASSERT("spacer", n.level() == 0 || check_invariant(n.level()-1)); + + + IF_VERBOSE(1, verbose_stream () << " F " + << std::fixed << std::setprecision(2) + << watch.get_seconds () << "\n";); + + return l_false; + } + case l_undef: + // something went wrong + if (n.weakness() < 100 /* MAX_WEAKENSS */) { + bool has_new_child = false; + SASSERT(m_weak_abs); + m_stats.m_expand_node_undef++; + if (r && r->get_uninterpreted_tail_size() > 0) { + model_evaluator_util mev(m); + mev.set_model(*model); + // do not trust reach_pred_used + for (unsigned i = 0, sz = reach_pred_used.size(); i < sz; ++i) + { reach_pred_used[i] = false; } + has_new_child = create_children(n,*r,mev,reach_pred_used); + } + IF_VERBOSE(1, verbose_stream() << " UNDEF " + << std::fixed << std::setprecision(2) + << watch.get_seconds () << "\n";); + if (has_new_child) { return l_undef; } + + // -- failed to create a child, bump weakness and repeat + // -- the recursion is bounded by the levels of weakness supported + n.bump_weakness(); + return expand_node(n); + } + TRACE("spacer", tout << "unknown state: " + << mk_pp(m_pm.mk_and(cube), m) << "\n";); + throw unknown_exception(); + } + UNREACHABLE(); + throw unknown_exception(); +} + +// +// check if predicate transformer has a satisfiable predecessor state. +// returns either a satisfiable predecessor state or +// return a property that blocks state and is implied by the +// predicate transformer (or some unfolding of it). +// + +bool context::propagate(unsigned min_prop_lvl, + unsigned max_prop_lvl, unsigned full_prop_lvl) +{ + scoped_watch _w_(m_propagate_watch); + + if (min_prop_lvl == infty_level()) { return false; } + + timeit _timer (get_verbosity_level() >= 1, + "spacer::context::propagate", + verbose_stream ()); + + if (full_prop_lvl < max_prop_lvl) { full_prop_lvl = max_prop_lvl; } + + if (m_params.pdr_simplify_formulas_pre()) { + simplify_formulas(); + } + IF_VERBOSE (1, verbose_stream () << "Propagating: " << std::flush;); + + for (unsigned lvl = min_prop_lvl; lvl <= full_prop_lvl; lvl++) { + IF_VERBOSE (1, + if (lvl > max_prop_lvl && lvl == max_prop_lvl + 1) + verbose_stream () << " ! "; + verbose_stream () << lvl << " " << std::flush;); + + checkpoint(); + CTRACE ("spacer", lvl > max_prop_lvl && lvl == max_prop_lvl + 1, + tout << "In full propagation\n";); + + bool all_propagated = true; + decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); + for (; it != end; ++it) { + checkpoint(); + pred_transformer& r = *it->m_value; + all_propagated = r.propagate_to_next_level(lvl) && all_propagated; + } + //CASSERT("spacer", check_invariant(lvl)); + + if (all_propagated) { + for (it = m_rels.begin(); it != end; ++it) { + checkpoint (); + pred_transformer& r = *it->m_value; + r.propagate_to_infinity (lvl); + } + if (lvl <= max_prop_lvl) { + m_inductive_lvl = lvl; + IF_VERBOSE(1, verbose_stream () << "\n";); + return true; + } + break; + } + + if (all_propagated && lvl == max_prop_lvl) { + m_inductive_lvl = lvl; + return true; + } else if (all_propagated && lvl > max_prop_lvl) { break; } + } + if (m_params.pdr_simplify_formulas_post()) { + simplify_formulas(); + } + + IF_VERBOSE(1, verbose_stream () << "\n";); + return false; +} + +reach_fact *context::mk_reach_fact (pob& n, model_evaluator_util &mev, + const datalog::rule& r) +{ + timeit _timer1 (is_trace_enabled("spacer_timeit"), + "mk_reach_fact", + verbose_stream ()); + expr_ref res(m); + reach_fact_ref_vector child_reach_facts; + + pred_transformer& pt = n.pt (); + + ptr_vector preds; + pt.find_predecessors (r, preds); + + expr_ref_vector path_cons (m); + path_cons.push_back (pt.get_transition (r)); + app_ref_vector vars (m); + + for (unsigned i = 0; i < preds.size (); i++) { + func_decl* pred = preds[i]; + pred_transformer& ch_pt = get_pred_transformer (pred); + // get a reach fact of body preds used in the model + expr_ref o_ch_reach (m); + reach_fact *kid = ch_pt.get_used_origin_reach_fact (mev, i); + child_reach_facts.push_back (kid); + m_pm.formula_n2o (kid->get (), o_ch_reach, i); + path_cons.push_back (o_ch_reach); + // collect o-vars to eliminate + for (unsigned j = 0; j < pred->get_arity (); j++) + { vars.push_back(m.mk_const(m_pm.o2o(ch_pt.sig(j), 0, i))); } + + const ptr_vector &v = kid->aux_vars (); + for (unsigned j = 0, sz = v.size (); j < sz; ++j) + { vars.push_back(m.mk_const(m_pm.n2o(v [j]->get_decl(), i))); } + } + // collect aux vars to eliminate + ptr_vector& aux_vars = pt.get_aux_vars (r); + bool elim_aux = get_params ().spacer_elim_aux (); + if (elim_aux) { vars.append(aux_vars.size(), aux_vars.c_ptr()); } + + res = m_pm.mk_and (path_cons); + + // -- pick an implicant from the path condition + if (get_params().spacer_reach_dnf()) { + expr_ref_vector u(m), lits(m); + u.push_back (res); + compute_implicant_literals (mev, u, lits); + res = m_pm.mk_and (lits); + } + + + TRACE ("spacer", + tout << "Reach fact, before QE:\n"; + tout << mk_pp (res, m) << "\n"; + tout << "Vars:\n"; + for (unsigned i = 0; i < vars.size(); ++i) { + tout << mk_pp(vars.get (i), m) << "\n"; + } + ); + + { + timeit _timer1 (is_trace_enabled("spacer_timeit"), + "mk_reach_fact::qe_project", + verbose_stream ()); + qe_project (m, vars, res, mev.get_model (), false, m_use_native_mbp); + } + + + TRACE ("spacer", + tout << "Reach fact, after QE project:\n"; + tout << mk_pp (res, m) << "\n"; + tout << "Vars:\n"; + for (unsigned i = 0; i < vars.size(); ++i) { + tout << mk_pp(vars.get (i), m) << "\n"; + } + ); + + SASSERT (vars.empty ()); + + m_stats.m_num_reach_queries++; + ptr_vector empty; + reach_fact *f = alloc(reach_fact, m, r, res, elim_aux ? empty : aux_vars); + for (unsigned i = 0, sz = child_reach_facts.size (); i < sz; ++i) + { f->add_justification(child_reach_facts.get(i)); } + return f; +} + + +/** + \brief create children states from model cube. +*/ +bool context::create_children(pob& n, datalog::rule const& r, + model_evaluator_util &mev, + const vector &reach_pred_used) +{ + + scoped_watch _w_ (m_create_children_watch); + pred_transformer& pt = n.pt(); + expr* const T = pt.get_transition(r); + expr* const phi = n.post(); + + TRACE("spacer", + tout << "Model:\n"; + model_smt2_pp(tout, m, *mev.get_model (), 0); + tout << "\n"; + tout << "Transition:\n" << mk_pp(T, m) << "\n"; + tout << "Phi:\n" << mk_pp(phi, m) << "\n";); + + SASSERT (r.get_uninterpreted_tail_size () > 0); + + ptr_vector preds; + pt.find_predecessors(r, preds); + + ptr_vector pred_pts; + + for (ptr_vector::iterator it = preds.begin (); + it != preds.end (); it++) { + pred_pts.push_back (&get_pred_transformer (*it)); + } + + expr_ref_vector forms(m), Phi(m); + + // obtain all formulas to consider for model generalization + forms.push_back(T); + forms.push_back(phi); + + compute_implicant_literals (mev, forms, Phi); + + //pt.remove_predecessors (Phi); + + app_ref_vector vars(m); + unsigned sig_size = pt.head()->get_arity(); + for (unsigned i = 0; i < sig_size; ++i) { + vars.push_back(m.mk_const(m_pm.o2n(pt.sig(i), 0))); + } + ptr_vector& aux_vars = pt.get_aux_vars(r); + vars.append(aux_vars.size(), aux_vars.c_ptr()); + + n.get_skolems(vars); + + expr_ref phi1 = m_pm.mk_and (Phi); + qe_project (m, vars, phi1, mev.get_model (), true, + m_use_native_mbp, !m_ground_cti); + //qe::reduce_array_selects (*mev.get_model (), phi1); + SASSERT (!m_ground_cti || vars.empty ()); + + TRACE ("spacer", + tout << "Implicant\n"; + tout << mk_pp (m_pm.mk_and (Phi), m) << "\n"; + tout << "Projected Implicant\n" << mk_pp (phi1, m) << "\n"; + ); + + // expand literals. Ideally, we do not want to split aliasing + // equalities. Unfortunately, the interface does not allow for + // that yet. + // XXX This mixes up with derivation. Needs more thought. + // Phi.reset (); + // flatten_and (phi1, Phi); + // if (!Phi.empty ()) + // { + // expand_literals (m, Phi); + // phi1 = m_pm.mk_and (Phi); + // } + + + derivation *deriv = alloc (derivation, n, r, phi1, vars); + for (unsigned i = 0, sz = preds.size(); i < sz; ++i) { + unsigned j; + if (get_params ().spacer_order_children () == 1) + // -- reverse order + { j = sz - i - 1; } + else + // -- default order + { j = i; } + + pred_transformer &pt = get_pred_transformer (preds [j]); + + const ptr_vector *aux = NULL; + expr_ref sum(m); + // XXX This is a bit confusing. The summary is returned over + // XXX o-variables. But it is simpler if it is returned over n-variables instead. + sum = pt.get_origin_summary (mev, prev_level (n.level ()), + j, reach_pred_used [j], &aux); + deriv->add_premise (pt, j, sum, reach_pred_used [j], aux); + } + + // create post for the first child and add to queue + pob* kid = deriv->create_first_child (mev); + + // -- failed to create derivation, cleanup and bail out + if (!kid) { + dealloc(deriv); + return false; + } + SASSERT (kid); + kid->set_derivation (deriv); + + // Optionally disable derivation optimization + if (!get_params().spacer_use_derivations()) { kid->reset_derivation(); } + + // -- deriviation is abstract if the current weak model does + // -- not satisfy 'T && phi'. It is possible to recover from + // -- that more gracefully. For now, we just remove the + // -- derivation completely forcing it to be recomputed + if (m_weak_abs && (!mev.is_true(T) || !mev.is_true(phi))) + { kid->reset_derivation(); } + + m_pob_queue.push (*kid); + m_stats.m_num_queries++; + return true; +} + + + + +void context::collect_statistics(statistics& st) const +{ + decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); + for (it = m_rels.begin(); it != end; ++it) { + it->m_value->collect_statistics(st); + } + st.update("SPACER num queries", m_stats.m_num_queries); + st.update("SPACER num reach queries", m_stats.m_num_reach_queries); + st.update("SPACER num reuse reach facts", m_stats.m_num_reuse_reach); + st.update("SPACER max query lvl", m_stats.m_max_query_lvl); + st.update("SPACER max depth", m_stats.m_max_depth); + st.update("SPACER inductive level", m_inductive_lvl); + st.update("SPACER cex depth", m_stats.m_cex_depth); + st.update("SPACER expand node undef", m_stats.m_expand_node_undef); + st.update("SPACER num lemmas", m_stats.m_num_lemmas); + st.update("SPACER restarts", m_stats.m_num_restarts); + + st.update ("time.spacer.init_rules", m_init_rules_watch.get_seconds ()); + st.update ("time.spacer.solve", m_solve_watch.get_seconds ()); + st.update ("time.spacer.solve.propagate", m_propagate_watch.get_seconds ()); + st.update ("time.spacer.solve.reach", m_reach_watch.get_seconds ()); + st.update ("time.spacer.solve.reach.is-reach", m_is_reach_watch.get_seconds ()); + st.update ("time.spacer.solve.reach.children", + m_create_children_watch.get_seconds ()); + m_pm.collect_statistics(st); + + for (unsigned i = 0; i < m_lemma_generalizers.size(); ++i) { + m_lemma_generalizers[i]->collect_statistics(st); + } + + // brunch out + verbose_stream () << "BRUNCH_STAT max_query_lvl " << m_stats.m_max_query_lvl << "\n"; + verbose_stream () << "BRUNCH_STAT num_queries " << m_stats.m_num_queries << "\n"; + verbose_stream () << "BRUNCH_STAT num_reach_queries " << m_stats.m_num_reach_queries << "\n"; + verbose_stream () << "BRUNCH_STAT num_reach_reuse " << m_stats.m_num_reuse_reach << "\n"; + verbose_stream () << "BRUNCH_STAT inductive_lvl " << m_inductive_lvl << "\n"; + verbose_stream () << "BRUNCH_STAT max_depth " << m_stats.m_max_depth << "\n"; + verbose_stream () << "BRUNCH_STAT cex_depth " << m_stats.m_cex_depth << "\n"; +} + +void context::reset_statistics() +{ + decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); + for (it = m_rels.begin(); it != end; ++it) { + it->m_value->reset_statistics(); + } + m_stats.reset(); + m_pm.reset_statistics(); + + for (unsigned i = 0; i < m_lemma_generalizers.size(); ++i) { + m_lemma_generalizers[i]->reset_statistics(); + } + + m_init_rules_watch.reset (); + m_solve_watch.reset (); + m_propagate_watch.reset (); + m_reach_watch.reset (); + m_is_reach_watch.reset (); + m_create_children_watch.reset (); +} + +bool context::check_invariant(unsigned lvl) +{ + decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); + for (; it != end; ++it) { + checkpoint(); + if (!check_invariant(lvl, it->m_key)) { + return false; + } + } + return true; +} + +bool context::check_invariant(unsigned lvl, func_decl* fn) +{ + smt::kernel ctx(m, m_pm.fparams2()); + pred_transformer& pt = *m_rels.find(fn); + expr_ref_vector conj(m); + expr_ref inv = pt.get_formulas(next_level(lvl), false); + if (m.is_true(inv)) { return true; } + pt.add_premises(m_rels, lvl, conj); + conj.push_back(m.mk_not(inv)); + expr_ref fml(m.mk_and(conj.size(), conj.c_ptr()), m); + ctx.assert_expr(fml); + lbool result = ctx.check(); + TRACE("spacer", tout << "Check invariant level: " << lvl << " " << result << "\n" << mk_pp(fml, m) << "\n";); + return result == l_false; +} + +expr_ref context::get_constraints (unsigned level) +{ + expr_ref res(m); + expr_ref_vector constraints(m); + + decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); + for (; it != end; ++it) { + pred_transformer& r = *it->m_value; + expr_ref c = r.get_formulas(level, false); + + if (m.is_true(c)) { continue; } + + // replace local constants by bound variables. + expr_ref_vector args(m); + for (unsigned i = 0; i < r.sig_size(); ++i) + { args.push_back(m.mk_const(m_pm.o2n(r.sig(i), 0))); } + + expr_ref pred(m); + pred = m.mk_app(r.head (), r.sig_size(), args.c_ptr()); + + constraints.push_back(m.mk_implies(pred, c)); + } + + if (constraints.empty()) { return expr_ref(m.mk_true(), m); } + return m_pm.mk_and (constraints); +} + +void context::add_constraints (unsigned level, expr_ref c) +{ + if (!c.get()) { return; } + if (m.is_true(c)) { return; } + + expr_ref_vector constraints (m); + constraints.push_back (c); + flatten_and (constraints); + + for (unsigned i = 0, sz = constraints.size(); i < sz; ++i) { + expr *c = constraints.get (i); + expr *e1, *e2; + if (m.is_implies(c, e1, e2)) { + SASSERT (is_app (e1)); + pred_transformer *r = 0; + if (m_rels.find (to_app (e1)->get_decl (), r)) + { r->add_lemma(e2, level); } + } + } +} + +inline bool pob_lt::operator() (const pob *pn1, const pob *pn2) const +{ + SASSERT (pn1); + SASSERT (pn2); + const pob& n1 = *pn1; + const pob& n2 = *pn2; + + if (n1.level() != n2.level()) { return n1.level() < n2.level(); } + + if (n1.depth() != n2.depth()) { return n1.depth() < n2.depth(); } + + // -- a more deterministic order of proof obligations in a queue + // if (!n1.get_context ().get_params ().spacer_nondet_tie_break ()) + { + const expr* p1 = n1.post (); + const expr* p2 = n2.post (); + ast_manager &m = n1.get_ast_manager (); + + + // -- order by size. Less conjunctions is a proxy for + // -- generality. Currently, this takes precedence over + // -- predicates which might not be the best choice + unsigned sz1 = 1; + unsigned sz2 = 1; + + if (m.is_and(p1)) { sz1 = to_app(p1)->get_num_args(); } + if (m.is_and(p2)) { sz2 = to_app(p2)->get_num_args(); } + if (sz1 != sz2) { return sz1 < sz2; } + + // -- when all else fails, order by identifiers of the + // -- expressions. This roughly means that expressions created + // -- earlier are preferred. Note that variables in post are + // -- based on names of the predicates. Hence this guarantees an + // -- order over predicates as well. That is, two expressions + // -- are equal if and only if they correspond to the same proof + // -- obligation of the same predicate. + if (p1->get_id() != p2->get_id()) { return p1->get_id() < p2->get_id(); } + + if (n1.pt().head()->get_id() == n2.pt().head()->get_id()) { + IF_VERBOSE (1, + verbose_stream () + << "dup: " << n1.pt ().head ()->get_name () + << "(" << n1.level () << ", " << n1.depth () << ") " + << p1->get_id () << "\n"; + //<< " p1: " << mk_pp (const_cast(p1), m) << "\n" + ); + } + + // XXX see comment below on identical nodes + // SASSERT (n1.pt ().head ()->get_id () != n2.pt ().head ()->get_id ()); + // -- if expression comparison fails, compare by predicate id + if (n1.pt().head ()->get_id () != n2.pt ().head ()->get_id ()) + { return n1.pt().head()->get_id() < n2.pt().head()->get_id(); } + + /** XXX Identical nodes. This should not happen. However, + * currently, when propagating reachability, we might call + * expand_node() twice on the same node, causing it to generate + * the same proof obligation multiple times */ + return &n1 < &n2; + } + // else + // return &n1 < &n2; +} + + + +} diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h new file mode 100644 index 000000000..cb422d08f --- /dev/null +++ b/src/muz/spacer/spacer_context.h @@ -0,0 +1,842 @@ +/**++ +Copyright (c) 2017 Microsoft Corporation and Arie Gurfinkel + +Module Name: + + spacer_context.h + +Abstract: + + SPACER predicate transformers and search context. + +Author: + + Arie Gurfinkel + Anvesh Komuravelli + + Based on muz/pdr/pdr_context.h by Nikolaj Bjorner (nbjorner) + +Notes: + +--*/ + +#ifndef _SPACER_CONTEXT_H_ +#define _SPACER_CONTEXT_H_ + +#ifdef _CYGWIN +#undef min +#undef max +#endif +#include + +#include "muz/spacer/spacer_manager.h" +#include "muz/spacer/spacer_prop_solver.h" + +#include "muz/base/fixedpoint_params.hpp" + +namespace datalog { + class rule_set; + class context; +}; + +namespace spacer { + +class pred_transformer; +class derivation; +class pob_queue; +class context; + +typedef obj_map rule2inst; +typedef obj_map decl2rel; + +class pob; +typedef ref pob_ref; +typedef sref_vector pob_ref_vector; + +class reach_fact; +typedef ref reach_fact_ref; +typedef sref_vector reach_fact_ref_vector; + +class reach_fact { + unsigned m_ref_count; + + expr_ref m_fact; + ptr_vector m_aux_vars; + + const datalog::rule &m_rule; + reach_fact_ref_vector m_justification; + + bool m_init; + +public: + reach_fact (ast_manager &m, const datalog::rule &rule, + expr* fact, const ptr_vector &aux_vars, + bool init = false) : + m_ref_count (0), m_fact (fact, m), m_aux_vars (aux_vars), + m_rule(rule), m_init (init) {} + reach_fact (ast_manager &m, const datalog::rule &rule, + expr* fact, bool init = false) : + m_ref_count (0), m_fact (fact, m), m_rule(rule), m_init (init) {} + + bool is_init () {return m_init;} + const datalog::rule& get_rule () {return m_rule;} + + void add_justification (reach_fact *f) {m_justification.push_back (f);} + const reach_fact_ref_vector& get_justifications () {return m_justification;} + + expr *get () {return m_fact.get ();} + const ptr_vector &aux_vars () {return m_aux_vars;} + + void inc_ref () {++m_ref_count;} + void dec_ref () + { + SASSERT (m_ref_count > 0); + --m_ref_count; + if(m_ref_count == 0) { dealloc(this); } + } +}; + + +class lemma; +typedef ref lemma_ref; +typedef sref_vector lemma_ref_vector; + +typedef pob pob; + +// a lemma +class lemma { + unsigned m_ref_count; + + ast_manager &m; + expr_ref m_body; + expr_ref_vector m_cube; + app_ref_vector m_bindings; + unsigned m_lvl; + pob_ref m_pob; + bool m_new_pob; + + void mk_expr_core(); + void mk_cube_core(); +public: + lemma(ast_manager &manager, expr * fml, unsigned lvl); + lemma(pob_ref const &p); + lemma(pob_ref const &p, expr_ref_vector &cube, unsigned lvl); +// lemma(const lemma &other) = delete; + + ast_manager &get_ast_manager() {return m;} + expr *get_expr(); + bool is_false(); + expr_ref_vector const &get_cube(); + void update_cube(pob_ref const &p, expr_ref_vector &cube); + + bool has_pob() {return m_pob;} + pob_ref &get_pob() {return m_pob;} + + unsigned level () const {return m_lvl;} + void set_level (unsigned lvl) {m_lvl = lvl;} + app_ref_vector& get_bindings() {return m_bindings;} + void add_binding(app_ref_vector const &binding) {m_bindings.append(binding);} + void mk_insts(expr_ref_vector& inst, expr* e = nullptr); + bool is_ground () {return !is_quantifier (get_expr());} + + void inc_ref () {++m_ref_count;} + void dec_ref () + { + SASSERT (m_ref_count > 0); + --m_ref_count; + if(m_ref_count == 0) { dealloc(this); } + } +}; + +struct lemma_lt_proc : public std::binary_function { + bool operator() (lemma *a, lemma *b) { + return (a->level () < b->level ()) || + (a->level () == b->level () && + ast_lt_proc() (a->get_expr (), b->get_expr ())); + } +}; + + + +// +// Predicate transformer state. +// A predicate transformer corresponds to the +// set of rules that have the same head predicates. +// + +class pred_transformer { + + struct stats { + unsigned m_num_propagations; + unsigned m_num_invariants; + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + }; + + /// manager of the lemmas in all the frames +#include "muz/spacer/spacer_legacy_frames.h" + class frames { + private: + pred_transformer &m_pt; + lemma_ref_vector m_lemmas; + unsigned m_size; + + bool m_sorted; + lemma_lt_proc m_lt; + + void sort (); + + public: + frames (pred_transformer &pt) : m_pt (pt), m_size(0), m_sorted (true) {} + ~frames() {} + void simplify_formulas (); + + pred_transformer& pt () {return m_pt;} + + + void get_frame_lemmas (unsigned level, expr_ref_vector &out) { + for (unsigned i = 0, sz = m_lemmas.size (); i < sz; ++i) + if(m_lemmas[i]->level() == level) { + out.push_back(m_lemmas[i]->get_expr()); + } + } + void get_frame_geq_lemmas (unsigned level, expr_ref_vector &out) { + for (unsigned i = 0, sz = m_lemmas.size (); i < sz; ++i) + if(m_lemmas [i]->level() >= level) { + out.push_back(m_lemmas[i]->get_expr()); + } + } + + + unsigned size () const {return m_size;} + unsigned lemma_size () const {return m_lemmas.size ();} + void add_frame () {m_size++;} + void inherit_frames (frames &other) { + for (unsigned i = 0, sz = other.m_lemmas.size (); i < sz; ++i) { + lemma_ref lem = alloc(lemma, m_pt.get_ast_manager(), + other.m_lemmas[i]->get_expr (), + other.m_lemmas[i]->level()); + lem->add_binding(other.m_lemmas[i]->get_bindings()); + add_lemma(lem.get()); + } + m_sorted = false; + } + + bool add_lemma (lemma *lem); + void propagate_to_infinity (unsigned level); + bool propagate_to_next_level (unsigned level); + + + }; + + /** + manager of proof-obligations (pobs) + */ + class pobs { + typedef ptr_buffer pob_buffer; + typedef obj_map expr2pob_buffer; + + pred_transformer &m_pt; + + expr2pob_buffer m_pobs; + pob_ref_vector m_pinned; + public: + pobs(pred_transformer &pt) : m_pt(pt) {} + pob* mk_pob(pob *parent, unsigned level, unsigned depth, + expr *post, app_ref_vector const &b); + + pob* mk_pob(pob *parent, unsigned level, unsigned depth, + expr *post) { + app_ref_vector b(m_pt.get_ast_manager()); + return mk_pob (parent, level, depth, post, b); + } + + }; + + typedef obj_map rule2expr; + typedef obj_map > rule2apps; + + manager& pm; // spacer-manager + ast_manager& m; // manager + context& ctx; + + func_decl_ref m_head; // predicate + func_decl_ref_vector m_sig; // signature + ptr_vector m_use; // places where 'this' is referenced. + ptr_vector m_rules; // rules used to derive transformer + prop_solver m_solver; // solver context + solver* m_reach_ctx; // context for reachability facts + pobs m_pobs; + frames m_frames; + reach_fact_ref_vector m_reach_facts; // reach facts + /// Number of initial reachability facts + unsigned m_rf_init_sz; + obj_map m_tag2rule; // map tag predicate to rule. + rule2expr m_rule2tag; // map rule to predicate tag. + rule2inst m_rule2inst; // map rules to instantiations of indices + rule2expr m_rule2transition; // map rules to transition + rule2apps m_rule2vars; // map rule to auxiliary variables + expr_ref m_transition; // transition relation. + expr_ref m_initial_state; // initial state. + app_ref m_extend_lit; // literal to extend initial state + bool m_all_init; // true if the pt has no uninterpreted body in any rule + ptr_vector m_predicates; + stats m_stats; + stopwatch m_initialize_watch; + stopwatch m_must_reachable_watch; + + + + /// Auxiliary variables to represent different disjunctive + /// cases of must summaries. Stored over 'n' (a.k.a. new) + /// versions of the variables + expr_ref_vector m_reach_case_vars; + + void init_sig(); + void ensure_level(unsigned level); + void add_lemma_core (lemma *lemma); + void add_lemma_from_child (pred_transformer &child, lemma *lemma, unsigned lvl); + + void mk_assumptions(func_decl* head, expr* fml, expr_ref_vector& result); + + // Initialization + void init_rules(decl2rel const& pts, expr_ref& init, expr_ref& transition); + void init_rule(decl2rel const& pts, datalog::rule const& rule, vector& is_init, + ptr_vector& rules, expr_ref_vector& transition); + void init_atom(decl2rel const& pts, app * atom, app_ref_vector& var_reprs, expr_ref_vector& conj, unsigned tail_idx); + + void simplify_formulas(tactic& tac, expr_ref_vector& fmls); + + // Debugging + bool check_filled(app_ref_vector const& v) const; + + void add_premises(decl2rel const& pts, unsigned lvl, datalog::rule& rule, expr_ref_vector& r); + + expr* mk_fresh_reach_case_var (); + +public: + pred_transformer(context& ctx, manager& pm, func_decl* head); + ~pred_transformer(); + + inline bool use_native_mbp (); + reach_fact *get_reach_fact (expr *v) + { + for (unsigned i = 0, sz = m_reach_facts.size (); i < sz; ++i) + if(v == m_reach_facts [i]->get()) { return m_reach_facts[i]; } + return NULL; + } + + void add_rule(datalog::rule* r) { m_rules.push_back(r); } + void add_use(pred_transformer* pt) { if(!m_use.contains(pt)) { m_use.insert(pt); } } + void initialize(decl2rel const& pts); + + func_decl* head() const { return m_head; } + ptr_vector const& rules() const { return m_rules; } + func_decl* sig(unsigned i) const { return m_sig[i]; } // signature + func_decl* const* sig() { return m_sig.c_ptr(); } + unsigned sig_size() const { return m_sig.size(); } + expr* transition() const { return m_transition; } + expr* initial_state() const { return m_initial_state; } + expr* rule2tag(datalog::rule const* r) { return m_rule2tag.find(r); } + unsigned get_num_levels() { return m_frames.size (); } + expr_ref get_cover_delta(func_decl* p_orig, int level); + void add_cover(unsigned level, expr* property); + expr_ref get_reachable (); + + std::ostream& display(std::ostream& strm) const; + + void collect_statistics(statistics& st) const; + void reset_statistics(); + + bool is_must_reachable (expr* state, model_ref* model = 0); + /// \brief Returns reachability fact active in the given model + /// all determines whether initial reachability facts are included as well + reach_fact *get_used_reach_fact (model_evaluator_util& mev, bool all = true); + /// \brief Returns reachability fact active in the origin of the given model + reach_fact* get_used_origin_reach_fact (model_evaluator_util &mev, unsigned oidx); + expr_ref get_origin_summary (model_evaluator_util &mev, + unsigned level, unsigned oidx, bool must, + const ptr_vector **aux); + + void remove_predecessors(expr_ref_vector& literals); + void find_predecessors(datalog::rule const& r, ptr_vector& predicates) const; + void find_predecessors(vector >& predicates) const; + datalog::rule const* find_rule(model &mev, bool& is_concrete, + vector& reach_pred_used, + unsigned& num_reuse_reach); + expr* get_transition(datalog::rule const& r) { return m_rule2transition.find(&r); } + ptr_vector& get_aux_vars(datalog::rule const& r) { return m_rule2vars.find(&r); } + + bool propagate_to_next_level(unsigned level); + void propagate_to_infinity(unsigned level); + /// \brief Add a lemma to the current context and all users + bool add_lemma(expr * lemma, unsigned lvl); + bool add_lemma(lemma* lem) {return m_frames.add_lemma(lem);} + expr* get_reach_case_var (unsigned idx) const; + bool has_reach_facts () const { return !m_reach_facts.empty () ;} + + /// initialize reachability facts using initial rules + void init_reach_facts (); + void add_reach_fact (reach_fact *fact); // add reachability fact + reach_fact* get_last_reach_fact () const { return m_reach_facts.back (); } + expr* get_last_reach_case_var () const; + + pob* mk_pob(pob *parent, unsigned level, unsigned depth, + expr *post, app_ref_vector const &b){ + return m_pobs.mk_pob(parent, level, depth, post, b); + } + + pob* mk_pob(pob *parent, unsigned level, unsigned depth, + expr *post) { + return m_pobs.mk_pob(parent, level, depth, post); + } + + lbool is_reachable(pob& n, expr_ref_vector* core, model_ref *model, + unsigned& uses_level, bool& is_concrete, + datalog::rule const*& r, + vector& reach_pred_used, + unsigned& num_reuse_reach); + bool is_invariant(unsigned level, expr* lemma, + unsigned& solver_level, expr_ref_vector* core = 0); + bool check_inductive(unsigned level, expr_ref_vector& state, + unsigned& assumes_level); + + expr_ref get_formulas(unsigned level, bool add_axioms); + + void simplify_formulas(); + + context& get_context () const {return ctx;} + manager& get_manager() const { return pm; } + ast_manager& get_ast_manager() const { return m; } + + void add_premises(decl2rel const& pts, unsigned lvl, expr_ref_vector& r); + + void inherit_properties(pred_transformer& other); + + void ground_free_vars(expr* e, app_ref_vector& vars, ptr_vector& aux_vars, + bool is_init); + + /// \brief Adds a given expression to the set of initial rules + app* extend_initial (expr *e); + + /// \brief Returns true if the obligation is already blocked by current lemmas + bool is_blocked (pob &n, unsigned &uses_level); + /// \brief Returns true if the obligation is already blocked by current quantified lemmas + bool is_qblocked (pob &n); + +}; + + +/** + * A proof obligation. + */ +class pob { + friend class context; + unsigned m_ref_count; + /// parent node + pob_ref m_parent; + /// predicate transformer + pred_transformer& m_pt; + /// post-condition decided by this node + expr_ref m_post; + // if m_post is not ground, then m_binding is an instantiation for + // all quantified variables + app_ref_vector m_binding; + /// new post to be swapped in for m_post + expr_ref m_new_post; + /// level at which to decide the post + unsigned m_level; + + unsigned m_depth; + + /// whether a concrete answer to the post is found + bool m_open; + /// whether to use farkas generalizer to construct a lemma blocking this node + bool m_use_farkas; + + unsigned m_weakness; + /// derivation representing the position of this node in the parent's rule + scoped_ptr m_derivation; + + ptr_vector m_kids; +public: + pob (pob* parent, pred_transformer& pt, + unsigned level, unsigned depth=0, bool add_to_parent=true); + + ~pob() {if(m_parent) { m_parent->erase_child(*this); }} + + unsigned weakness() {return m_weakness;} + void bump_weakness() {m_weakness++;} + void reset_weakness() {m_weakness=0;} + + void inc_level () {m_level++; m_depth++;reset_weakness();} + + void inherit(pob const &p); + void set_derivation (derivation *d) {m_derivation = d;} + bool has_derivation () const {return (bool)m_derivation;} + derivation &get_derivation() const {return *m_derivation.get ();} + void reset_derivation () {set_derivation (NULL);} + /// detaches derivation from the node without deallocating + derivation* detach_derivation () {return m_derivation.detach ();} + + pob* parent () const { return m_parent.get (); } + + pred_transformer& pt () const { return m_pt; } + ast_manager& get_ast_manager () const { return m_pt.get_ast_manager (); } + manager& get_manager () const { return m_pt.get_manager (); } + context& get_context () const {return m_pt.get_context ();} + + unsigned level () const { return m_level; } + unsigned depth () const {return m_depth;} + + bool use_farkas_generalizer () const {return m_use_farkas;} + void set_farkas_generalizer (bool v) {m_use_farkas = v;} + + expr* post() const { return m_post.get (); } + void set_post(expr *post); + void set_post(expr *post, app_ref_vector const &b); + + /// indicate that a new post should be set for the node + void new_post(expr *post) {if(post != m_post) {m_new_post = post;}} + /// true if the node needs to be updated outside of the priority queue + bool is_dirty () {return m_new_post;} + /// clean a dirty node + void clean(); + + void reset () {clean (); m_derivation = NULL; m_open = true;} + + bool is_closed () const { return !m_open; } + void close(); + + void add_child (pob &v) {m_kids.push_back (&v);} + void erase_child (pob &v) {m_kids.erase (&v);} + + bool is_ground () { return m_binding.empty (); } + app_ref_vector const &get_binding() const {return m_binding;} + /* + * Return skolem variables that appear in post + */ + void get_skolems(app_ref_vector& v); + + void inc_ref () {++m_ref_count;} + void dec_ref () + { + --m_ref_count; + if(m_ref_count == 0) { dealloc(this); } + } + +}; + + +struct pob_lt : + public std::binary_function +{bool operator() (const pob *pn1, const pob *pn2) const;}; + +struct pob_gt : + public std::binary_function { + pob_lt lt; + bool operator() (const pob *n1, const pob *n2) const + {return lt(n2, n1);} +}; + +struct pob_ref_gt : + public std::binary_function { + pob_gt gt; + bool operator() (const pob_ref &n1, const pob_ref &n2) const + {return gt (n1.get (), n2.get ());} +}; + + +/** + */ +class derivation { + /// a single premise of a derivation + class premise { + pred_transformer &m_pt; + /// origin order in the rule + unsigned m_oidx; + /// summary fact corresponding to the premise + expr_ref m_summary; + /// whether this is a must or may premise + bool m_must; + app_ref_vector m_ovars; + + public: + premise (pred_transformer &pt, unsigned oidx, expr *summary, bool must, + const ptr_vector *aux_vars = NULL); + premise (const premise &p); + + bool is_must () {return m_must;} + expr * get_summary () {return m_summary.get ();} + app_ref_vector &get_ovars () {return m_ovars;} + unsigned get_oidx () {return m_oidx;} + pred_transformer &pt () {return m_pt;} + + /// \brief Updated the summary. + /// The new summary is over n-variables. + void set_summary (expr * summary, bool must, + const ptr_vector *aux_vars = NULL); + }; + + + /// parent model node + pob& m_parent; + + /// the rule corresponding to this derivation + const datalog::rule &m_rule; + + /// the premises + vector m_premises; + /// pointer to the active premise + unsigned m_active; + // transition relation over origin variables + expr_ref m_trans; + // implicitly existentially quantified variables in m_trans + app_ref_vector m_evars; + /// -- create next child using given model as the guide + /// -- returns NULL if there is no next child + pob* create_next_child (model_evaluator_util &mev); +public: + derivation (pob& parent, datalog::rule const& rule, + expr *trans, app_ref_vector const &evars); + void add_premise (pred_transformer &pt, unsigned oidx, + expr * summary, bool must, const ptr_vector *aux_vars = NULL); + + /// creates the first child. Must be called after all the premises + /// are added. The model must be valid for the premises + /// Returns NULL if no child exits + pob *create_first_child (model_evaluator_util &mev); + + /// Create the next child. Must summary of the currently active + /// premise must be consistent with the transition relation + pob *create_next_child (); + + datalog::rule const& get_rule () const { return m_rule; } + pob& get_parent () const { return m_parent; } + ast_manager &get_ast_manager () const {return m_parent.get_ast_manager ();} + manager &get_manager () const {return m_parent.get_manager ();} + context &get_context() const {return m_parent.get_context();} +}; + + +class pob_queue { + pob_ref m_root; + unsigned m_max_level; + unsigned m_min_depth; + + std::priority_queue, + pob_ref_gt> m_obligations; + +public: + pob_queue(): m_root(NULL), m_max_level(0), m_min_depth(0) {} + ~pob_queue(); + + void reset(); + pob * top (); + void pop () {m_obligations.pop ();} + void push (pob &n) {m_obligations.push (&n);} + + void inc_level () + { + SASSERT (!m_obligations.empty () || m_root); + m_max_level++; + m_min_depth++; + if(m_root && m_obligations.empty()) { m_obligations.push(m_root); } + } + + pob& get_root() const { return *m_root.get (); } + void set_root(pob& n); + bool is_root (pob& n) const {return m_root.get () == &n;} + + unsigned max_level () {return m_max_level;} + unsigned min_depth () {return m_min_depth;} + size_t size () {return m_obligations.size ();} + +}; + + +/** + * Generalizers (strengthens) a lemma + */ +class lemma_generalizer { +protected: + context& m_ctx; +public: + lemma_generalizer(context& ctx): m_ctx(ctx) {} + virtual ~lemma_generalizer() {} + virtual void operator()(lemma_ref &lemma) = 0; + virtual void collect_statistics(statistics& st) const {} + virtual void reset_statistics() {} +}; + + +class context { + + struct stats { + unsigned m_num_queries; + unsigned m_num_reach_queries; + unsigned m_num_reuse_reach; + unsigned m_max_query_lvl; + unsigned m_max_depth; + unsigned m_cex_depth; + unsigned m_expand_node_undef; + unsigned m_num_lemmas; + unsigned m_num_restarts; + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + }; + + // stat watches + stopwatch m_solve_watch; + stopwatch m_propagate_watch; + stopwatch m_reach_watch; + stopwatch m_is_reach_watch; + stopwatch m_create_children_watch; + stopwatch m_init_rules_watch; + + fixedpoint_params const& m_params; + ast_manager& m; + datalog::context* m_context; + manager m_pm; + decl2rel m_rels; // Map from relation predicate to fp-operator. + func_decl_ref m_query_pred; + pred_transformer* m_query; + mutable pob_queue m_pob_queue; + lbool m_last_result; + unsigned m_inductive_lvl; + unsigned m_expanded_lvl; + ptr_buffer m_lemma_generalizers; + stats m_stats; + model_converter_ref m_mc; + proof_converter_ref m_pc; + bool m_use_native_mbp; + bool m_ground_cti; + bool m_instantiate; + bool m_use_qlemmas; + bool m_weak_abs; + bool m_use_restarts; + unsigned m_restart_initial_threshold; + + // Functions used by search. + lbool solve_core (unsigned from_lvl = 0); + bool check_reachability (); + bool propagate(unsigned min_prop_lvl, unsigned max_prop_lvl, + unsigned full_prop_lvl); + bool is_reachable(pob &n); + lbool expand_node(pob& n); + reach_fact *mk_reach_fact (pob& n, model_evaluator_util &mev, + datalog::rule const& r); + bool create_children(pob& n, datalog::rule const& r, + model_evaluator_util &model, + const vector& reach_pred_used); + expr_ref mk_sat_answer(); + expr_ref mk_unsat_answer() const; + + // Generate inductive property + void get_level_property(unsigned lvl, expr_ref_vector& res, + vector & rs) const; + + + // Initialization + void init_lemma_generalizers(datalog::rule_set& rules); + + bool check_invariant(unsigned lvl); + bool check_invariant(unsigned lvl, func_decl* fn); + + void checkpoint(); + + void init_rules(datalog::rule_set& rules, decl2rel& transformers); + + void simplify_formulas(); + + void reset_lemma_generalizers(); + + bool validate(); + + unsigned get_cex_depth (); + +public: + /** + Initial values of predicates are stored in corresponding relations in dctx. + + We check whether there is some reachable state of the relation checked_relation. + */ + context( + fixedpoint_params const& params, + ast_manager& m); + + ~context(); + + fixedpoint_params const& get_params() const { return m_params; } + bool use_native_mbp () {return m_use_native_mbp;} + bool use_ground_cti () {return m_ground_cti;} + bool use_instantiate () { return m_instantiate; } + bool use_qlemmas () {return m_use_qlemmas; } + + ast_manager& get_ast_manager() const { return m; } + manager& get_manager() { return m_pm; } + decl2rel const& get_pred_transformers() const { return m_rels; } + pred_transformer& get_pred_transformer(func_decl* p) const + { return *m_rels.find(p); } + datalog::context& get_datalog_context() const + { SASSERT(m_context); return *m_context; } + expr_ref get_answer(); + /** + * get bottom-up (from query) sequence of ground predicate instances + * (for e.g. P(0,1,0,0,3)) that together form a ground derivation to query + */ + expr_ref get_ground_sat_answer (); + + void collect_statistics(statistics& st) const; + void reset_statistics(); + + std::ostream& display(std::ostream& strm) const; + + void display_certificate(std::ostream& strm) const {} + + lbool solve(unsigned from_lvl = 0); + + lbool solve_from_lvl (unsigned from_lvl); + + void reset(); + + void set_query(func_decl* q) { m_query_pred = q; } + + void set_unsat() { m_last_result = l_false; } + + void set_model_converter(model_converter_ref& mc) { m_mc = mc; } + + void get_rules_along_trace (datalog::rule_ref_vector& rules); + + model_converter_ref get_model_converter() { return m_mc; } + + void set_proof_converter(proof_converter_ref& pc) { m_pc = pc; } + + void update_rules(datalog::rule_set& rules); + + void set_axioms(expr* axioms) { m_pm.set_background(axioms); } + + unsigned get_num_levels(func_decl* p); + + expr_ref get_cover_delta(int level, func_decl* p_orig, func_decl* p); + + void add_cover(int level, func_decl* pred, expr* property); + + expr_ref get_reachable (func_decl* p); + + void add_invariant (func_decl *pred, expr* property); + + model_ref get_model(); + + proof_ref get_proof() const; + + pob& get_root() const { return m_pob_queue.get_root(); } + + expr_ref get_constraints (unsigned lvl); + void add_constraints (unsigned lvl, expr_ref c); +}; + +inline bool pred_transformer::use_native_mbp () {return ctx.use_native_mbp ();} +} + +#endif diff --git a/src/muz/spacer/spacer_dl_interface.cpp b/src/muz/spacer/spacer_dl_interface.cpp new file mode 100644 index 000000000..78776e074 --- /dev/null +++ b/src/muz/spacer/spacer_dl_interface.cpp @@ -0,0 +1,354 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation and Arie Gurfinkel + +Module Name: + + spacer_dl.cpp + +Abstract: + + SMT2 interface for the datalog SPACER + +Author: + + Arie Gurfinkel + +Revision History: + +--*/ + +#include "muz/base/dl_context.h" +#include "muz/transforms/dl_mk_coi_filter.h" +#include "muz/transforms/dl_mk_interp_tail_simplifier.h" +#include "muz/transforms/dl_mk_subsumption_checker.h" +#include "muz/transforms/dl_mk_rule_inliner.h" +#include "muz/base/dl_rule.h" +#include "muz/base/dl_rule_transformer.h" +#include "parsers/smt2/smt2parser.h" +#include "muz/spacer/spacer_context.h" +#include "muz/spacer/spacer_dl_interface.h" +#include "muz/base/dl_rule_set.h" +#include "muz/transforms/dl_mk_slice.h" +#include "muz/transforms/dl_mk_unfold.h" +#include "muz/transforms/dl_mk_coalesce.h" +#include "model/model_smt2_pp.h" +#include "ast/scoped_proof.h" +#include "muz/transforms/dl_transforms.h" + +using namespace spacer; + +dl_interface::dl_interface(datalog::context& ctx) : + engine_base(ctx.get_manager(), "spacer"), + m_ctx(ctx), + m_spacer_rules(ctx), + m_old_rules(ctx), + m_context(0), + m_refs(ctx.get_manager()) +{ + m_context = alloc(spacer::context, ctx.get_params(), ctx.get_manager()); +} + + +dl_interface::~dl_interface() +{ + dealloc(m_context); +} + + +// +// Check if the new rules are weaker so that we can +// re-use existing context. +// +void dl_interface::check_reset() +{ + datalog::rule_set const& new_rules = m_ctx.get_rules(); + datalog::rule_ref_vector const& old_rules = m_old_rules.get_rules(); + bool is_subsumed = !old_rules.empty(); + for (unsigned i = 0; is_subsumed && i < new_rules.get_num_rules(); ++i) { + is_subsumed = false; + for (unsigned j = 0; !is_subsumed && j < old_rules.size(); ++j) { + if (m_ctx.check_subsumes(*old_rules[j], *new_rules.get_rule(i))) { + is_subsumed = true; + } + } + if (!is_subsumed) { + TRACE("spacer", new_rules.get_rule(i)->display(m_ctx, tout << "Fresh rule ");); + m_context->reset(); + } + } + m_old_rules.replace_rules(new_rules); +} + + +lbool dl_interface::query(expr * query) +{ + //we restore the initial state in the datalog context + m_ctx.ensure_opened(); + m_refs.reset(); + m_pred2slice.reset(); + ast_manager& m = m_ctx.get_manager(); + datalog::rule_manager& rm = m_ctx.get_rule_manager(); + datalog::rule_set& rules0 = m_ctx.get_rules(); + datalog::rule_set old_rules(rules0); + func_decl_ref query_pred(m); + rm.mk_query(query, m_ctx.get_rules()); + expr_ref bg_assertion = m_ctx.get_background_assertion(); + + check_reset(); + + TRACE("spacer", + if (!m.is_true(bg_assertion)) { + tout << "axioms:\n"; + tout << mk_pp(bg_assertion, m) << "\n"; + } + tout << "query: " << mk_pp(query, m) << "\n"; + tout << "rules:\n"; + m_ctx.display_rules(tout); + ); + + + apply_default_transformation(m_ctx); + + if (m_ctx.get_params().xform_slice()) { + datalog::rule_transformer transformer(m_ctx); + datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); + transformer.register_plugin(slice); + m_ctx.transform_rules(transformer); + + // track sliced predicates. + obj_map const& preds = slice->get_predicates(); + obj_map::iterator it = preds.begin(); + obj_map::iterator end = preds.end(); + for (; it != end; ++it) { + m_pred2slice.insert(it->m_key, it->m_value); + m_refs.push_back(it->m_key); + m_refs.push_back(it->m_value); + } + } + + if (m_ctx.get_params().xform_unfold_rules() > 0) { + unsigned num_unfolds = m_ctx.get_params().xform_unfold_rules(); + datalog::rule_transformer transf1(m_ctx), transf2(m_ctx); + transf1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); + transf2.register_plugin(alloc(datalog::mk_unfold, m_ctx)); + if (m_ctx.get_params().xform_coalesce_rules()) { + m_ctx.transform_rules(transf1); + } + while (num_unfolds > 0) { + m_ctx.transform_rules(transf2); + --num_unfolds; + } + } + + const datalog::rule_set& rules = m_ctx.get_rules(); + if (rules.get_output_predicates().empty()) { + m_context->set_unsat(); + return l_false; + } + + query_pred = rules.get_output_predicate(); + + IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); + m_spacer_rules.replace_rules(rules); + m_spacer_rules.close(); + m_ctx.record_transformed_rules(); + m_ctx.reopen(); + m_ctx.replace_rules(old_rules); + + scoped_restore_proof _sc(m); // update_rules may overwrite the proof mode. + + m_context->set_proof_converter(m_ctx.get_proof_converter()); + m_context->set_model_converter(m_ctx.get_model_converter()); + m_context->set_query(query_pred); + m_context->set_axioms(bg_assertion); + m_context->update_rules(m_spacer_rules); + + if (m_spacer_rules.get_rules().empty()) { + m_context->set_unsat(); + IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *m_context->get_model(), 0);); + return l_false; + } + + return m_context->solve(); + +} + +lbool dl_interface::query_from_lvl(expr * query, unsigned lvl) +{ + //we restore the initial state in the datalog context + m_ctx.ensure_opened(); + m_refs.reset(); + m_pred2slice.reset(); + ast_manager& m = m_ctx.get_manager(); + datalog::rule_manager& rm = m_ctx.get_rule_manager(); + datalog::rule_set& rules0 = m_ctx.get_rules(); + datalog::rule_set old_rules(rules0); + func_decl_ref query_pred(m); + rm.mk_query(query, m_ctx.get_rules()); + expr_ref bg_assertion = m_ctx.get_background_assertion(); + + check_reset(); + + TRACE("spacer", + if (!m.is_true(bg_assertion)) { + tout << "axioms:\n"; + tout << mk_pp(bg_assertion, m) << "\n"; + } + tout << "query: " << mk_pp(query, m) << "\n"; + tout << "rules:\n"; + m_ctx.display_rules(tout); + ); + + + apply_default_transformation(m_ctx); + + if (m_ctx.get_params().xform_slice()) { + datalog::rule_transformer transformer(m_ctx); + datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); + transformer.register_plugin(slice); + m_ctx.transform_rules(transformer); + + // track sliced predicates. + obj_map const& preds = slice->get_predicates(); + obj_map::iterator it = preds.begin(); + obj_map::iterator end = preds.end(); + for (; it != end; ++it) { + m_pred2slice.insert(it->m_key, it->m_value); + m_refs.push_back(it->m_key); + m_refs.push_back(it->m_value); + } + } + + if (m_ctx.get_params().xform_unfold_rules() > 0) { + unsigned num_unfolds = m_ctx.get_params().xform_unfold_rules(); + datalog::rule_transformer transf1(m_ctx), transf2(m_ctx); + transf1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); + transf2.register_plugin(alloc(datalog::mk_unfold, m_ctx)); + if (m_ctx.get_params().xform_coalesce_rules()) { + m_ctx.transform_rules(transf1); + } + while (num_unfolds > 0) { + m_ctx.transform_rules(transf2); + --num_unfolds; + } + } + + const datalog::rule_set& rules = m_ctx.get_rules(); + if (rules.get_output_predicates().empty()) { + + m_context->set_unsat(); + return l_false; + } + + query_pred = rules.get_output_predicate(); + + IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); + m_spacer_rules.replace_rules(rules); + m_spacer_rules.close(); + m_ctx.record_transformed_rules(); + m_ctx.reopen(); + m_ctx.replace_rules(old_rules); + + scoped_restore_proof _sc(m); // update_rules may overwrite the proof mode. + + m_context->set_proof_converter(m_ctx.get_proof_converter()); + m_context->set_model_converter(m_ctx.get_model_converter()); + m_context->set_query(query_pred); + m_context->set_axioms(bg_assertion); + m_context->update_rules(m_spacer_rules); + + if (m_spacer_rules.get_rules().empty()) { + m_context->set_unsat(); + IF_VERBOSE(1, model_smt2_pp(verbose_stream(), m, *m_context->get_model(), 0);); + return l_false; + } + + return m_context->solve(lvl); + +} + +expr_ref dl_interface::get_cover_delta(int level, func_decl* pred_orig) +{ + func_decl* pred = pred_orig; + m_pred2slice.find(pred_orig, pred); + SASSERT(pred); + return m_context->get_cover_delta(level, pred_orig, pred); +} + +void dl_interface::add_cover(int level, func_decl* pred, expr* property) +{ + if (m_ctx.get_params().xform_slice()) { + throw default_exception("Covers are incompatible with slicing. Disable slicing before using covers"); + } + m_context->add_cover(level, pred, property); +} + +void dl_interface::add_invariant(func_decl* pred, expr* property) +{ + if (m_ctx.get_params().xform_slice()) { + throw default_exception("Invariants are incompatible with slicing. Disable slicing before using invariants"); + } + m_context->add_invariant(pred, property); +} + +expr_ref dl_interface::get_reachable(func_decl* pred) +{ + if (m_ctx.get_params().xform_slice()) { + throw default_exception("Invariants are incompatible with slicing. " + "Disable slicing before using invariants"); + } + return m_context->get_reachable(pred); +} + +unsigned dl_interface::get_num_levels(func_decl* pred) +{ + m_pred2slice.find(pred, pred); + SASSERT(pred); + return m_context->get_num_levels(pred); +} + +void dl_interface::collect_statistics(statistics& st) const +{ + m_context->collect_statistics(st); +} + +void dl_interface::reset_statistics() +{ + m_context->reset_statistics(); +} + +void dl_interface::display_certificate(std::ostream& out) const +{ + m_context->display_certificate(out); +} + +expr_ref dl_interface::get_answer() +{ + return m_context->get_answer(); +} + +expr_ref dl_interface::get_ground_sat_answer() +{ + return m_context->get_ground_sat_answer(); +} + +void dl_interface::get_rules_along_trace(datalog::rule_ref_vector& rules) +{ + m_context->get_rules_along_trace(rules); +} + +void dl_interface::updt_params() +{ + dealloc(m_context); + m_context = alloc(spacer::context, m_ctx.get_params(), m_ctx.get_manager()); +} + +model_ref dl_interface::get_model() +{ + return m_context->get_model(); +} + +proof_ref dl_interface::get_proof() +{ + return m_context->get_proof(); +} diff --git a/src/muz/spacer/spacer_dl_interface.h b/src/muz/spacer/spacer_dl_interface.h new file mode 100644 index 000000000..1581762d5 --- /dev/null +++ b/src/muz/spacer/spacer_dl_interface.h @@ -0,0 +1,86 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation and Arie Gurfinkel + +Module Name: + + spacer_dl_interface.h + +Abstract: + + SMT2 interface for the datalog SPACER + +Author: + + +Revision History: + +--*/ + +#ifndef _SPACER_DL_INTERFACE_H_ +#define _SPACER_DL_INTERFACE_H_ + +#include "util/lbool.h" +#include "muz/base/dl_rule.h" +#include "muz/base/dl_rule_set.h" +#include "muz/base/dl_engine_base.h" +#include "util/statistics.h" + +namespace datalog { +class context; +} + +namespace spacer { + +class context; + +class dl_interface : public datalog::engine_base { + datalog::context& m_ctx; + datalog::rule_set m_spacer_rules; + datalog::rule_set m_old_rules; + context* m_context; + obj_map m_pred2slice; + ast_ref_vector m_refs; + + void check_reset(); + +public: + dl_interface(datalog::context& ctx); + ~dl_interface(); + + lbool query(expr* query); + + lbool query_from_lvl(expr* query, unsigned lvl); + + void display_certificate(std::ostream& out) const; + + void collect_statistics(statistics& st) const; + + void reset_statistics(); + + expr_ref get_answer(); + + expr_ref get_ground_sat_answer(); + + void get_rules_along_trace(datalog::rule_ref_vector& rules); + + unsigned get_num_levels(func_decl* pred); + + expr_ref get_cover_delta(int level, func_decl* pred); + + void add_cover(int level, func_decl* pred, expr* property); + + void add_invariant(func_decl* pred, expr* property); + + expr_ref get_reachable(func_decl *pred); + + void updt_params(); + + model_ref get_model(); + + proof_ref get_proof(); + +}; +} + + +#endif diff --git a/src/muz/spacer/spacer_farkas_learner.cpp b/src/muz/spacer/spacer_farkas_learner.cpp new file mode 100644 index 000000000..d97bee49f --- /dev/null +++ b/src/muz/spacer/spacer_farkas_learner.cpp @@ -0,0 +1,439 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + spacer_farkas_learner.cpp + +Abstract: + + Proviced abstract interface and some inplementations of algorithms + for strenghtning lemmas + +Author: + + Krystof Hoder (t-khoder) 2011-11-1. + +Revision History: +// TODO: what to write here +--*/ + +//TODO: reorder, delete unnecessary includes +#include "ast/ast_smt2_pp.h" +#include "ast/array_decl_plugin.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/dl_decl_plugin.h" +#include "ast/for_each_expr.h" +#include "muz/base/dl_util.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "muz/spacer/spacer_util.h" +#include "muz/spacer/spacer_farkas_learner.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/ast_ll_pp.h" +#include "ast/proofs/proof_utils.h" +#include "ast/reg_decl_plugins.h" +#include "smt/smt_farkas_util.h" + +namespace spacer { + +class collect_pure_proc { + func_decl_set& m_symbs; +public: + collect_pure_proc(func_decl_set& s): m_symbs(s) {} + + void operator()(app* a) + { + if (a->get_family_id() == null_family_id) { + m_symbs.insert(a->get_decl()); + } + } + void operator()(var*) {} + void operator()(quantifier*) {} +}; + +void farkas_learner::combine_constraints(unsigned n, app * const * lits, rational const * coeffs, expr_ref& res) +{ + ast_manager& m = res.get_manager(); + smt::farkas_util res_c(m); + res_c.set_split_literals(m_split_literals); + for (unsigned i = 0; i < n; ++i) { + res_c.add(coeffs[i], lits[i]); + } + res = res_c.get(); +} + +// every uninterpreted symbol is in symbs +class is_pure_expr_proc { + func_decl_set const& m_symbs; + array_util m_au; +public: + struct non_pure {}; + + is_pure_expr_proc(func_decl_set const& s, ast_manager& m): + m_symbs(s), + m_au(m) + {} + + void operator()(app* a) + { + if (a->get_family_id() == null_family_id) { + if (!m_symbs.contains(a->get_decl())) { + throw non_pure(); + } + } else if (a->get_family_id() == m_au.get_family_id() && + a->is_app_of(a->get_family_id(), OP_ARRAY_EXT)) { + throw non_pure(); + } + } + void operator()(var*) {} + void operator()(quantifier*) {} +}; + +bool farkas_learner::is_pure_expr(func_decl_set const& symbs, expr* e, ast_manager& m) const +{ + is_pure_expr_proc proc(symbs, m); + try { + for_each_expr(proc, e); + } catch (is_pure_expr_proc::non_pure) { + return false; + } + return true; +}; + + +/** + Revised version of Farkas strengthener. + 1. Mark B-pure nodes as derivations that depend only on B. + 2. Collect B-influenced nodes + 3. (optional) Permute B-pure units over resolution steps to narrow dependencies on B. + 4. Weaken B-pure units for resolution with Farkas Clauses. + 5. Add B-pure units elsewhere. + + Rules: + - hypothesis h |- h + + H |- false + - lemma ---------- + |- not H + + Th |- L \/ C H |- not L + - th-lemma ------------------------- + H |- C + + Note: C is false for theory axioms, C is unit literal for propagation. + + - rewrite |- t = s + + H |- t = s + - monotonicity ---------------- + H |- f(t) = f(s) + + H |- t = s H' |- s = u + - trans ---------------------- + H, H' |- t = u + + H |- C \/ L H' |- not L + - unit_resolve ------------------------ + H, H' |- C + + H |- a ~ b H' |- a + - mp -------------------- + H, H' |- b + + - def-axiom |- C + + - asserted |- f + + Mark nodes by: + - Hypotheses + - Dependency on bs + - Dependency on A + + A node is unit derivable from bs if: + - It has no hypotheses. + - It depends on bs. + - It does not depend on A. + + NB: currently unit derivable is not symmetric: A clause can be + unit derivable, but a unit literal with hypotheses is not. + This is clearly wrong, because hypotheses are just additional literals + in a clausal version. + + NB: the routine is not interpolating, though an interpolating variant would + be preferrable because then we can also use it for model propagation. + + We collect the unit derivable nodes from bs. + These are the weakenings of bs, besides the + units under Farkas. + +*/ + +#define INSERT(_x_) if (!lemma_set.contains(_x_)) { lemma_set.insert(_x_); lemmas.push_back(_x_); } + +void farkas_learner::get_lemmas(proof* root, expr_set const& bs, expr_ref_vector& lemmas) +{ + ast_manager& m = lemmas.get_manager(); + bool_rewriter brwr(m); + func_decl_set Bsymbs; + collect_pure_proc collect_proc(Bsymbs); + expr_set::iterator it = bs.begin(), end = bs.end(); + for (; it != end; ++it) { + for_each_expr(collect_proc, *it); + } + + proof_ref pr(root, m); + proof_utils::reduce_hypotheses(pr); + proof_utils::permute_unit_resolution(pr); + IF_VERBOSE(3, verbose_stream() << "Reduced proof:\n" << mk_ismt2_pp(pr, m) << "\n";); + + ptr_vector hyprefs; + obj_map hypmap; + obj_hashtable lemma_set; + ast_mark b_depend, a_depend, visited, b_closed; + expr_set* empty_set = alloc(expr_set); + hyprefs.push_back(empty_set); + ptr_vector todo; + TRACE("spacer_verbose", tout << mk_pp(pr, m) << "\n";); + todo.push_back(pr); + while (!todo.empty()) { + proof* p = todo.back(); + SASSERT(m.is_proof(p)); + if (visited.is_marked(p)) { + todo.pop_back(); + continue; + } + bool all_visit = true; + for (unsigned i = 0; i < m.get_num_parents(p); ++i) { + expr* arg = p->get_arg(i); + SASSERT(m.is_proof(arg)); + if (!visited.is_marked(arg)) { + all_visit = false; + todo.push_back(to_app(arg)); + } + } + if (!all_visit) { + continue; + } + visited.mark(p, true); + todo.pop_back(); + + // retrieve hypotheses and dependencies on A, bs. + bool b_dep = false, a_dep = false; + expr_set* hyps = empty_set; + for (unsigned i = 0; i < m.get_num_parents(p); ++i) { + expr* arg = p->get_arg(i); + a_dep = a_dep || a_depend.is_marked(arg); + b_dep = b_dep || b_depend.is_marked(arg); + expr_set* hyps2 = hypmap.find(arg); + if (hyps != hyps2 && !hyps2->empty()) { + if (hyps->empty()) { + hyps = hyps2; + } else { + expr_set* hyps3 = alloc(expr_set); + set_union(*hyps3, *hyps); + set_union(*hyps3, *hyps2); + hyps = hyps3; + hyprefs.push_back(hyps); + } + } + } + hypmap.insert(p, hyps); + a_depend.mark(p, a_dep); + b_depend.mark(p, b_dep); + +#define IS_B_PURE(_p) (b_depend.is_marked(_p) && !a_depend.is_marked(_p) && hypmap.find(_p)->empty()) + + + // Add lemmas that depend on bs, have no hypotheses, don't depend on A. + if ((!hyps->empty() || a_depend.is_marked(p)) && + b_depend.is_marked(p) && !is_farkas_lemma(m, p)) { + for (unsigned i = 0; i < m.get_num_parents(p); ++i) { + app* arg = to_app(p->get_arg(i)); + if (IS_B_PURE(arg)) { + expr* fact = m.get_fact(arg); + if (is_pure_expr(Bsymbs, fact, m)) { + TRACE("farkas_learner2", + tout << "Add: " << mk_pp(m.get_fact(arg), m) << "\n"; + tout << mk_pp(arg, m) << "\n"; + ); + INSERT(fact); + } else { + get_asserted(p, bs, b_closed, lemma_set, lemmas); + b_closed.mark(p, true); + } + } + } + } + + switch (p->get_decl_kind()) { + case PR_ASSERTED: + if (bs.contains(m.get_fact(p))) { + b_depend.mark(p, true); + } else { + a_depend.mark(p, true); + } + break; + case PR_HYPOTHESIS: { + SASSERT(hyps == empty_set); + hyps = alloc(expr_set); + hyps->insert(m.get_fact(p)); + hyprefs.push_back(hyps); + hypmap.insert(p, hyps); + break; + } + case PR_DEF_AXIOM: { + if (!is_pure_expr(Bsymbs, m.get_fact(p), m)) { + a_depend.mark(p, true); + } + break; + } + case PR_LEMMA: { + expr_set* hyps2 = alloc(expr_set); + hyprefs.push_back(hyps2); + set_union(*hyps2, *hyps); + hyps = hyps2; + expr* fml = m.get_fact(p); + hyps->remove(fml); + if (m.is_or(fml)) { + for (unsigned i = 0; i < to_app(fml)->get_num_args(); ++i) { + expr* f = to_app(fml)->get_arg(i); + expr_ref hyp(m); + brwr.mk_not(f, hyp); + hyps->remove(hyp); + } + } + hypmap.insert(p, hyps); + break; + } + case PR_TH_LEMMA: { + if (!is_farkas_lemma(m, p)) { break; } + + SASSERT(m.has_fact(p)); + unsigned prem_cnt = m.get_num_parents(p); + func_decl * d = p->get_decl(); + SASSERT(d->get_num_parameters() >= prem_cnt + 2); + SASSERT(d->get_parameter(0).get_symbol() == "arith"); + SASSERT(d->get_parameter(1).get_symbol() == "farkas"); + parameter const* params = d->get_parameters() + 2; + + app_ref_vector lits(m); + expr_ref tmp(m); + unsigned num_b_pures = 0; + rational coef; + vector coeffs; + + TRACE("farkas_learner2", + for (unsigned i = 0; i < prem_cnt; ++i) { + VERIFY(params[i].is_rational(coef)); + proof* prem = to_app(p->get_arg(i)); + bool b_pure = IS_B_PURE(prem); + tout << (b_pure ? "B" : "A") << " " << coef << " " << mk_pp(m.get_fact(prem), m) << "\n"; + } + tout << mk_pp(m.get_fact(p), m) << "\n"; + ); + + // NB. Taking 'abs' of coefficients is a workaround. + // The Farkas coefficient extraction in arith_core must be wrong. + // The coefficients would be always positive relative to the theory lemma. + + for (unsigned i = 0; i < prem_cnt; ++i) { + expr * prem_e = p->get_arg(i); + SASSERT(is_app(prem_e)); + proof * prem = to_app(prem_e); + + if (IS_B_PURE(prem)) { + ++num_b_pures; + } else { + VERIFY(params[i].is_rational(coef)); + lits.push_back(to_app(m.get_fact(prem))); + coeffs.push_back(abs(coef)); + } + } + params += prem_cnt; + if (prem_cnt + 2 < d->get_num_parameters()) { + unsigned num_args = 1; + expr* fact = m.get_fact(p); + expr* const* args = &fact; + if (m.is_or(fact)) { + app* _or = to_app(fact); + num_args = _or->get_num_args(); + args = _or->get_args(); + } + SASSERT(prem_cnt + 2 + num_args == d->get_num_parameters()); + for (unsigned i = 0; i < num_args; ++i) { + expr* prem_e = args[i]; + brwr.mk_not(prem_e, tmp); + VERIFY(params[i].is_rational(coef)); + SASSERT(is_app(tmp)); + lits.push_back(to_app(tmp)); + coeffs.push_back(abs(coef)); + } + + } + SASSERT(coeffs.size() == lits.size()); + if (num_b_pures > 0) { + expr_ref res(m); + combine_constraints(coeffs.size(), lits.c_ptr(), coeffs.c_ptr(), res); + TRACE("farkas_learner2", tout << "Add: " << mk_pp(res, m) << "\n";); + INSERT(res); + b_closed.mark(p, true); + } + } + default: + break; + } + } + + std::for_each(hyprefs.begin(), hyprefs.end(), delete_proc()); + simplify_bounds(lemmas); +} + +void farkas_learner::get_asserted(proof* p0, expr_set const& bs, ast_mark& b_closed, obj_hashtable& lemma_set, expr_ref_vector& lemmas) +{ + ast_manager& m = lemmas.get_manager(); + ast_mark visited; + proof* p = p0; + ptr_vector todo; + todo.push_back(p); + + while (!todo.empty()) { + p = todo.back(); + todo.pop_back(); + if (visited.is_marked(p) || b_closed.is_marked(p)) { + continue; + } + visited.mark(p, true); + for (unsigned i = 0; i < m.get_num_parents(p); ++i) { + expr* arg = p->get_arg(i); + SASSERT(m.is_proof(arg)); + todo.push_back(to_app(arg)); + } + if (p->get_decl_kind() == PR_ASSERTED && + bs.contains(m.get_fact(p))) { + expr* fact = m.get_fact(p); + TRACE("farkas_learner2", + tout << mk_ll_pp(p0, m) << "\n"; + tout << "Add: " << mk_pp(p, m) << "\n";); + INSERT(fact); + b_closed.mark(p, true); + } + } +} + + +bool farkas_learner::is_farkas_lemma(ast_manager& m, expr* e) +{ + app * a; + func_decl* d; + symbol sym; + return + is_app(e) && + (a = to_app(e), d = a->get_decl(), true) && + PR_TH_LEMMA == a->get_decl_kind() && + d->get_num_parameters() >= 2 && + d->get_parameter(0).is_symbol(sym) && sym == "arith" && + d->get_parameter(1).is_symbol(sym) && sym == "farkas" && + d->get_num_parameters() >= m.get_num_parents(to_app(e)) + 2; +} +} diff --git a/src/muz/spacer/spacer_farkas_learner.h b/src/muz/spacer/spacer_farkas_learner.h new file mode 100644 index 000000000..724b18b73 --- /dev/null +++ b/src/muz/spacer/spacer_farkas_learner.h @@ -0,0 +1,66 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + spacer_farkas_learner.h + +Abstract: + + SMT2 interface for the datalog SPACER + +Author: + + Krystof Hoder (t-khoder) 2011-11-1. + +Revision History: + +--*/ + +#ifndef _SPACER_FARKAS_LEARNER_H_ +#define _SPACER_FARKAS_LEARNER_H_ + +#include "ast/ast.h" + +namespace spacer { + + + + + + + +class farkas_learner { + typedef obj_hashtable expr_set; + + bool m_split_literals; + + void combine_constraints(unsigned cnt, app * const * constrs, rational const * coeffs, expr_ref& res); + + bool is_farkas_lemma(ast_manager& m, expr* e); + + void get_asserted(proof* p, expr_set const& bs, ast_mark& b_closed, obj_hashtable& lemma_set, expr_ref_vector& lemmas); + + bool is_pure_expr(func_decl_set const& symbs, expr* e, ast_manager& m) const; + +public: + farkas_learner(): m_split_literals(false) {} + + /** + Traverse a proof and retrieve lemmas using the vocabulary from bs. + */ + void get_lemmas(proof* root, expr_set const& bs, expr_ref_vector& lemmas); + + void collect_statistics(statistics& st) const {} + void reset_statistics() {} + + + /** \brief see smt::farkas_util::set_split_literals */ + void set_split_literals(bool v) {m_split_literals = v;} + +}; + + +} + +#endif diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp new file mode 100644 index 000000000..94c419493 --- /dev/null +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -0,0 +1,293 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation and Arie Gurfinkel + +Module Name: + + spacer_generalizers.cpp + +Abstract: + + Lemma generalizers. + +Author: + + Nikolaj Bjorner (nbjorner) 2011-11-20. + Arie Gurfinkel + +Revision History: + +--*/ + + +#include "muz/spacer/spacer_context.h" +#include "muz/spacer/spacer_generalizers.h" +#include "ast/expr_abstract.h" +#include "ast/rewriter/var_subst.h" +#include "ast/for_each_expr.h" +#include "ast/factor_equivs.h" + + +namespace spacer { +void lemma_sanity_checker::operator()(lemma_ref &lemma) { + unsigned uses_level; + expr_ref_vector cube(lemma->get_ast_manager()); + cube.append(lemma->get_cube()); + ENSURE(lemma->get_pob()->pt().check_inductive(lemma->level(), + cube, uses_level)); +} + + +// ------------------------ +// lemma_bool_inductive_generalizer +/// Inductive generalization by dropping and expanding literals +void lemma_bool_inductive_generalizer::operator()(lemma_ref &lemma) { + if (lemma->get_cube().empty()) return; + + m_st.count++; + scoped_watch _w_(m_st.watch); + + unsigned uses_level; + pred_transformer &pt = lemma->get_pob()->pt(); + ast_manager &m = pt.get_ast_manager(); + + expr_ref_vector cube(m); + cube.append(lemma->get_cube()); + + bool dirty = false; + expr_ref true_expr(m.mk_true(), m); + ptr_vector processed; + expr_ref_vector extra_lits(m); + + unsigned i = 0, num_failures = 0; + while (i < cube.size() && + (!m_failure_limit || num_failures < m_failure_limit)) { + expr_ref lit(m); + lit = cube.get(i); + cube[i] = true_expr; + if (cube.size() > 1 && + pt.check_inductive(lemma->level(), cube, uses_level)) { + num_failures = 0; + dirty = true; + for (i = 0; i < cube.size() && + processed.contains(cube.get(i)); ++i); + } else { + // check if the literal can be expanded and any single + // literal in the expansion can replace it + extra_lits.reset(); + extra_lits.push_back(lit); + expand_literals(m, extra_lits); + SASSERT(extra_lits.size() > 0); + bool found = false; + if (extra_lits.get(0) != lit) { + SASSERT(extra_lits.size() > 1); + for (unsigned j = 0, sz = extra_lits.size(); !found && j < sz; ++j) { + cube[i] = extra_lits.get(j); + if (pt.check_inductive(lemma->level(), cube, uses_level)) { + num_failures = 0; + dirty = true; + found = true; + processed.push_back(extra_lits.get(j)); + for (i = 0; i < cube.size() && + processed.contains(cube.get(i)); ++i); + } + } + } + if (!found) { + cube[i] = lit; + processed.push_back(lit); + ++num_failures; + ++m_st.num_failures; + ++i; + } + } + } + + if (dirty) { + TRACE("spacer", + tout << "Generalized from:\n" << mk_and(lemma->get_cube()) + << "\ninto\n" << mk_and(cube) << "\n";); + + lemma->update_cube(lemma->get_pob(), cube); + SASSERT(uses_level >= lemma->level()); + lemma->set_level(uses_level); + } +} + +void lemma_bool_inductive_generalizer::collect_statistics(statistics &st) const +{ + st.update("time.spacer.solve.reach.gen.bool_ind", m_st.watch.get_seconds()); + st.update("bool inductive gen", m_st.count); + st.update("bool inductive gen failures", m_st.num_failures); +} + +void unsat_core_generalizer::operator()(lemma_ref &lemma) +{ + m_st.count++; + scoped_watch _w_(m_st.watch); + ast_manager &m = lemma->get_ast_manager(); + + pred_transformer &pt = lemma->get_pob()->pt(); + + unsigned old_sz = lemma->get_cube().size(); + unsigned old_level = lemma->level(); + + unsigned uses_level; + expr_ref_vector core(m); + VERIFY(pt.is_invariant(old_level, lemma->get_expr(), uses_level, &core)); + + CTRACE("spacer", old_sz > core.size(), + tout << "unsat core reduced lemma from: " + << old_sz << " to " << core.size() << "\n";); + CTRACE("spacer", old_level < uses_level, + tout << "unsat core moved lemma up from: " + << old_level << " to " << uses_level << "\n";); + if (old_sz > core.size()) { + lemma->update_cube(lemma->get_pob(), core); + lemma->set_level(uses_level); + } +} + +void unsat_core_generalizer::collect_statistics(statistics &st) const +{ + st.update("time.spacer.solve.reach.gen.unsat_core", m_st.watch.get_seconds()); + st.update("gen.unsat_core.cnt", m_st.count); + st.update("gen.unsat_core.fail", m_st.num_failures); +} + +namespace { +class collect_array_proc { + array_util m_au; + func_decl_set &m_symbs; + sort *m_sort; +public: + collect_array_proc(ast_manager &m, func_decl_set& s) : + m_au(m), m_symbs(s), m_sort(NULL) {} + + void operator()(app* a) + { + if (a->get_family_id() == null_family_id && m_au.is_array(a)) { + if (m_sort && m_sort != get_sort(a)) { return; } + if (!m_sort) { m_sort = get_sort(a); } + m_symbs.insert(a->get_decl()); + } + } + void operator()(var*) {} + void operator()(quantifier*) {} +}; +} + +void lemma_array_eq_generalizer::operator() (lemma_ref &lemma) +{ + TRACE("core_array_eq", tout << "Looking for equalities\n";); + + // -- find array constants + ast_manager &m = lemma->get_ast_manager(); + manager &pm = m_ctx.get_manager(); + (void)pm; + + expr_ref_vector core(m); + expr_ref v(m); + func_decl_set symb; + collect_array_proc cap(m, symb); + + core.append (lemma->get_cube()); + v = mk_and(core); + for_each_expr(cap, v); + + TRACE("core_array_eq", + tout << "found " << symb.size() << " array variables in: \n" + << mk_pp(v, m) << "\n";); + + // too few constants + if (symb.size() <= 1) { return; } + // too many constants, skip this + if (symb.size() >= 8) { return; } + + + // -- for every pair of variables, try an equality + typedef func_decl_set::iterator iterator; + ptr_vector vsymbs; + for (iterator it = symb.begin(), end = symb.end(); + it != end; ++it) + { vsymbs.push_back(*it); } + + expr_ref_vector eqs(m); + + for (unsigned i = 0, sz = vsymbs.size(); i < sz; ++i) + for (unsigned j = i + 1; j < sz; ++j) + { eqs.push_back(m.mk_eq(m.mk_const(vsymbs.get(i)), + m.mk_const(vsymbs.get(j)))); } + + smt::kernel solver(m, m_ctx.get_manager().fparams2()); + expr_ref_vector lits(m); + for (unsigned i = 0, core_sz = core.size(); i < core_sz; ++i) { + SASSERT(lits.size() == i); + solver.push(); + solver.assert_expr(core.get(i)); + for (unsigned j = 0, eqs_sz = eqs.size(); j < eqs_sz; ++j) { + solver.push(); + solver.assert_expr(eqs.get(j)); + lbool res = solver.check(); + solver.pop(1); + + if (res == l_false) { + TRACE("core_array_eq", + tout << "strengthened " << mk_pp(core.get(i), m) + << " with " << mk_pp(m.mk_not(eqs.get(j)), m) << "\n";); + lits.push_back(m.mk_not(eqs.get(j))); + break; + } + } + solver.pop(1); + if (lits.size() == i) { lits.push_back(core.get(i)); } + } + + /** + HACK: if the first 3 arguments of pt are boolean, assume + they correspond to SeaHorn encoding and condition the equality on them. + */ + // pred_transformer &pt = n.pt (); + // if (pt.sig_size () >= 3 && + // m.is_bool (pt.sig (0)->get_range ()) && + // m.is_bool (pt.sig (1)->get_range ()) && + // m.is_bool (pt.sig (2)->get_range ())) + // { + // lits.push_back (m.mk_const (pm.o2n(pt.sig (0), 0))); + // lits.push_back (m.mk_not (m.mk_const (pm.o2n(pt.sig (1), 0)))); + // lits.push_back (m.mk_not (m.mk_const (pm.o2n(pt.sig (2), 0)))); + // } + + TRACE("core_array_eq", tout << "new possible core " + << mk_pp(pm.mk_and(lits), m) << "\n";); + + + pred_transformer &pt = lemma->get_pob()->pt(); + // -- check if it is consistent with the transition relation + unsigned uses_level1; + if (pt.check_inductive(lemma->level(), lits, uses_level1)) { + TRACE("core_array_eq", tout << "Inductive!\n";); + lemma->update_cube(lemma->get_pob(),lits); + lemma->set_level(uses_level1); + return; + } else + { TRACE("core_array_eq", tout << "Not-Inductive!\n";);} +} + +void lemma_eq_generalizer::operator() (lemma_ref &lemma) +{ + TRACE("core_eq", tout << "Transforming equivalence classes\n";); + + ast_manager &m = m_ctx.get_ast_manager(); + expr_ref_vector core(m); + core.append (lemma->get_cube()); + + bool dirty; + expr_equiv_class eq_classes(m); + factor_eqs(core, eq_classes); + // create all possible equalities to allow for simple inductive generalization + dirty = equiv_to_expr_full(eq_classes, core); + if (dirty) { + lemma->update_cube(lemma->get_pob(), core); + } +} +}; diff --git a/src/muz/spacer/spacer_generalizers.h b/src/muz/spacer/spacer_generalizers.h new file mode 100644 index 000000000..aa542ec04 --- /dev/null +++ b/src/muz/spacer/spacer_generalizers.h @@ -0,0 +1,99 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation and Arie Gurfinkel + +Module Name: + + spacer_generalizers.h + +Abstract: + + Generalizer plugins. + +Author: + + Nikolaj Bjorner (nbjorner) 2011-11-22. + Arie Gurfinkel +Revision History: + +--*/ + +#ifndef _SPACER_GENERALIZERS_H_ +#define _SPACER_GENERALIZERS_H_ + +#include "muz/spacer/spacer_context.h" +#include "ast/arith_decl_plugin.h" + +namespace spacer { + +// can be used to check whether produced core is really implied by +// frame and therefore valid TODO: or negation? +class lemma_sanity_checker : public lemma_generalizer { +public: + lemma_sanity_checker(context& ctx) : lemma_generalizer(ctx) {} + virtual ~lemma_sanity_checker() {} + virtual void operator()(lemma_ref &lemma); +}; + +/** + * Boolean inductive generalization by dropping literals + */ +class lemma_bool_inductive_generalizer : public lemma_generalizer { + + struct stats { + unsigned count; + unsigned num_failures; + stopwatch watch; + stats() {reset();} + void reset() {count = 0; num_failures = 0; watch.reset();} + }; + + unsigned m_failure_limit; + stats m_st; + +public: + lemma_bool_inductive_generalizer(context& ctx, unsigned failure_limit) : + lemma_generalizer(ctx), m_failure_limit(failure_limit) {} + virtual ~lemma_bool_inductive_generalizer() {} + virtual void operator()(lemma_ref &lemma); + + virtual void collect_statistics(statistics& st) const; + virtual void reset_statistics() {m_st.reset();} +}; + +class unsat_core_generalizer : public lemma_generalizer { + struct stats { + unsigned count; + unsigned num_failures; + stopwatch watch; + stats() { reset(); } + void reset() {count = 0; num_failures = 0; watch.reset();} + }; + + stats m_st; +public: + unsat_core_generalizer(context &ctx) : lemma_generalizer(ctx) {} + virtual ~unsat_core_generalizer() {} + virtual void operator()(lemma_ref &lemma); + + virtual void collect_statistics(statistics &st) const; + virtual void reset_statistics() {m_st.reset();} +}; + +class lemma_array_eq_generalizer : public lemma_generalizer { +public: + lemma_array_eq_generalizer(context &ctx) : lemma_generalizer(ctx) {} + virtual ~lemma_array_eq_generalizer() {} + virtual void operator()(lemma_ref &lemma); + +}; + +class lemma_eq_generalizer : public lemma_generalizer { +public: + lemma_eq_generalizer(context &ctx) : lemma_generalizer(ctx) {} + virtual ~lemma_eq_generalizer() {} + virtual void operator()(lemma_ref &lemma); +}; + + +}; +#endif diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp new file mode 100644 index 000000000..bcf6b07ae --- /dev/null +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -0,0 +1,355 @@ +/** +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_itp_solver.cpp + +Abstract: + + A solver that produces interpolated unsat cores + +Author: + + Arie Gurfinkel + +Notes: + +--*/ +#include"muz/spacer/spacer_itp_solver.h" +#include"ast/ast.h" +#include"muz/spacer/spacer_util.h" +#include"muz/spacer/spacer_farkas_learner.h" +#include"ast/rewriter/expr_replacer.h" +#include"muz/spacer/spacer_unsat_core_learner.h" +#include"muz/spacer/spacer_unsat_core_plugin.h" + +namespace spacer { +void itp_solver::push () +{ + m_defs.push_back (def_manager (*this)); + m_solver.push (); +} + +void itp_solver::pop (unsigned n) +{ + m_solver.pop (n); + unsigned lvl = m_defs.size (); + SASSERT (n <= lvl); + unsigned new_lvl = lvl-n; + while (m_defs.size() > new_lvl) { + m_num_proxies -= m_defs.back ().m_defs.size (); + m_defs.pop_back (); + } +} + +app* itp_solver::fresh_proxy () +{ + if (m_num_proxies == m_proxies.size()) { + std::stringstream name; + name << "spacer_proxy!" << m_proxies.size (); + app_ref res(m); + res = m.mk_const (symbol (name.str ().c_str ()), + m.mk_bool_sort ()); + m_proxies.push_back (res); + + // -- add the new proxy to proxy eliminator + proof_ref pr(m); + pr = m.mk_asserted (m.mk_true ()); + m_elim_proxies_sub.insert (res, m.mk_true (), pr); + + } + return m_proxies.get (m_num_proxies++); +} + +app* itp_solver::mk_proxy (expr *v) +{ + { + expr *e = v; + m.is_not (v, e); + if (is_uninterp_const(e)) { return to_app(v); } + } + + def_manager &def = m_defs.size () > 0 ? m_defs.back () : m_base_defs; + return def.mk_proxy (v); +} + +bool itp_solver::mk_proxies (expr_ref_vector &v, unsigned from) +{ + bool dirty = false; + for (unsigned i = from, sz = v.size(); i < sz; ++i) { + app *p = mk_proxy (v.get (i)); + dirty |= (v.get (i) != p); + v[i] = p; + } + return dirty; +} + +void itp_solver::push_bg (expr *e) +{ + if (m_assumptions.size () > m_first_assumption) + { m_assumptions.shrink(m_first_assumption); } + m_assumptions.push_back (e); + m_first_assumption = m_assumptions.size (); +} + +void itp_solver::pop_bg (unsigned n) +{ + if (n == 0) { return; } + + if (m_assumptions.size () > m_first_assumption) + { m_assumptions.shrink(m_first_assumption); } + m_first_assumption = m_first_assumption > n ? m_first_assumption - n : 0; + m_assumptions.shrink (m_first_assumption); +} + +unsigned itp_solver::get_num_bg () {return m_first_assumption;} + +lbool itp_solver::check_sat (unsigned num_assumptions, expr * const *assumptions) +{ + // -- remove any old assumptions + if (m_assumptions.size () > m_first_assumption) + { m_assumptions.shrink(m_first_assumption); } + + // -- replace theory literals in background assumptions with proxies + mk_proxies (m_assumptions); + // -- in case mk_proxies added new literals, they are all background + m_first_assumption = m_assumptions.size (); + + m_assumptions.append (num_assumptions, assumptions); + m_is_proxied = mk_proxies (m_assumptions, m_first_assumption); + + lbool res; + res = m_solver.check_sat (m_assumptions.size (), m_assumptions.c_ptr ()); + set_status (res); + return res; +} + + +app* itp_solver::def_manager::mk_proxy (expr *v) +{ + app* r; + if (m_expr2proxy.find(v, r)) { return r; } + + ast_manager &m = m_parent.m; + app_ref proxy(m); + app_ref def(m); + proxy = m_parent.fresh_proxy (); + def = m.mk_or (m.mk_not (proxy), v); + m_defs.push_back (def); + m_expr2proxy.insert (v, proxy); + m_proxy2def.insert (proxy, def); + + m_parent.assert_expr (def.get ()); + return proxy; +} + +bool itp_solver::def_manager::is_proxy (app *k, app_ref &def) +{ + app *r = NULL; + bool found = m_proxy2def.find (k, r); + def = r; + return found; +} + +void itp_solver::def_manager::reset () +{ + m_expr2proxy.reset (); + m_proxy2def.reset (); + m_defs.reset (); +} + +bool itp_solver::def_manager::is_proxy_def (expr *v) +{ + // XXX This might not be the most robust way to check + return m_defs.contains (v); +} + +bool itp_solver::is_proxy(expr *e, app_ref &def) +{ + if (!is_uninterp_const(e)) { return false; } + + app *a = to_app (e); + + for (int i = m_defs.size (); i > 0; --i) + if (m_defs[i-1].is_proxy (a, def)) + { return true; } + + if (m_base_defs.is_proxy (a, def)) + { return true; } + + return false; +} + +void itp_solver::collect_statistics (statistics &st) const +{ + m_solver.collect_statistics (st); + st.update ("time.itp_solver.itp_core", m_itp_watch.get_seconds ()); +} + +void itp_solver::reset_statistics () +{ + m_itp_watch.reset (); +} + +void itp_solver::get_unsat_core (ptr_vector &core) +{ + m_solver.get_unsat_core (core); + undo_proxies_in_core (core); +} +void itp_solver::undo_proxies_in_core (ptr_vector &r) +{ + app_ref e(m); + expr_fast_mark1 bg; + for (unsigned i = 0; i < m_first_assumption; ++i) + { bg.mark(m_assumptions.get(i)); } + + // expand proxies + unsigned j = 0; + for (unsigned i = 0, sz = r.size(); i < sz; ++i) { + // skip background assumptions + if (bg.is_marked(r[i])) { continue; } + + // -- undo proxies, but only if they were introduced in check_sat + if (m_is_proxied && is_proxy(r[i], e)) { + SASSERT (m.is_or (e)); + r[j] = e->get_arg (1); + } else if (i != j) { r[j] = r[i]; } + j++; + } + r.shrink (j); +} + +void itp_solver::undo_proxies (expr_ref_vector &r) +{ + app_ref e(m); + // expand proxies + for (unsigned i = 0, sz = r.size (); i < sz; ++i) + if (is_proxy(r.get(i), e)) { + SASSERT (m.is_or (e)); + r[i] = e->get_arg (1); + } +} + +void itp_solver::get_unsat_core (expr_ref_vector &_core) +{ + ptr_vector core; + get_unsat_core (core); + _core.append (core.size (), core.c_ptr ()); +} + +void itp_solver::elim_proxies (expr_ref_vector &v) +{ + expr_ref f = mk_and (v); + scoped_ptr rep = mk_expr_simp_replacer (m); + rep->set_substitution (&m_elim_proxies_sub); + (*rep) (f); + v.reset (); + flatten_and (f, v); +} + +void itp_solver::get_itp_core (expr_ref_vector &core) +{ + scoped_watch _t_ (m_itp_watch); + + typedef obj_hashtable expr_set; + expr_set B; + for (unsigned i = m_first_assumption, sz = m_assumptions.size(); i < sz; ++i) { + expr *a = m_assumptions.get (i); + app_ref def(m); + if (is_proxy(a, def)) { B.insert(def.get()); } + B.insert (a); + } + + proof_ref pr(m); + pr = get_proof (); + + if (!m_new_unsat_core) { + // old code + farkas_learner learner_old; + learner_old.set_split_literals(m_split_literals); + + learner_old.get_lemmas (pr, B, core); + elim_proxies (core); + simplify_bounds (core); // XXX potentially redundant + } else { + // new code + unsat_core_learner learner(m); + + if (m_farkas_optimized) { + if (true) // TODO: proper options + { + unsat_core_plugin_farkas_lemma_optimized* plugin_farkas_lemma_optimized = alloc(unsat_core_plugin_farkas_lemma_optimized, learner,m); + learner.register_plugin(plugin_farkas_lemma_optimized); + } + else + { + unsat_core_plugin_farkas_lemma_bounded* plugin_farkas_lemma_bounded = alloc(unsat_core_plugin_farkas_lemma_bounded, learner,m); + learner.register_plugin(plugin_farkas_lemma_bounded); + } + + } else { + unsat_core_plugin_farkas_lemma* plugin_farkas_lemma = alloc(unsat_core_plugin_farkas_lemma, learner, m_split_literals, m_farkas_a_const); + learner.register_plugin(plugin_farkas_lemma); + } + + if (m_minimize_unsat_core) { + unsat_core_plugin_min_cut* plugin_min_cut = alloc(unsat_core_plugin_min_cut, learner, m); + learner.register_plugin(plugin_min_cut); + } else { + unsat_core_plugin_lemma* plugin_lemma = alloc(unsat_core_plugin_lemma, learner); + learner.register_plugin(plugin_lemma); + } + + learner.compute_unsat_core(pr, B, core); + + elim_proxies (core); + simplify_bounds (core); // XXX potentially redundant + +// // debug +// expr_ref_vector core2(m); +// unsat_core_learner learner2(m); +// +// unsat_core_plugin_farkas_lemma* plugin_farkas_lemma2 = alloc(unsat_core_plugin_farkas_lemma, learner2, m_split_literals); +// learner2.register_plugin(plugin_farkas_lemma2); +// unsat_core_plugin_lemma* plugin_lemma2 = alloc(unsat_core_plugin_lemma, learner2); +// learner2.register_plugin(plugin_lemma2); +// learner2.compute_unsat_core(pr, B, core2); +// +// elim_proxies (core2); +// simplify_bounds (core2); +// +// IF_VERBOSE(2, +// verbose_stream () << "Itp Core:\n" +// << mk_pp (mk_and (core), m) << "\n";); +// IF_VERBOSE(2, +// verbose_stream () << "Itp Core2:\n" +// << mk_pp (mk_and (core2), m) << "\n";); + //SASSERT(mk_and (core) == mk_and (core2)); + } + + IF_VERBOSE(2, + verbose_stream () << "Itp Core:\n" + << mk_pp (mk_and (core), m) << "\n";); + +} + +void itp_solver::refresh () +{ + // only refresh in non-pushed state + SASSERT (m_defs.size () == 0); + expr_ref_vector assertions (m); + for (unsigned i = 0, e = m_solver.get_num_assertions(); i < e; ++i) { + expr* a = m_solver.get_assertion (i); + if (!m_base_defs.is_proxy_def(a)) { assertions.push_back(a); } + + } + m_base_defs.reset (); + NOT_IMPLEMENTED_YET (); + // solver interface does not have a reset method. need to introduce it somewhere. + // m_solver.reset (); + for (unsigned i = 0, e = assertions.size (); i < e; ++i) + { m_solver.assert_expr(assertions.get(i)); } +} + +} diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h new file mode 100644 index 000000000..8194379b8 --- /dev/null +++ b/src/muz/spacer/spacer_itp_solver.h @@ -0,0 +1,177 @@ +/** +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_itp_solver.h + +Abstract: + + A solver that produces interpolated unsat cores + +Author: + + Arie Gurfinkel + +Notes: + +--*/ +#ifndef SPACER_ITP_SOLVER_H_ +#define SPACER_ITP_SOLVER_H_ + +#include"solver/solver.h" +#include"ast/expr_substitution.h" +#include"util/stopwatch.h" +namespace spacer { +class itp_solver : public solver { +private: + struct def_manager { + itp_solver &m_parent; + obj_map m_expr2proxy; + obj_map m_proxy2def; + + expr_ref_vector m_defs; + + def_manager(itp_solver &parent) : + m_parent(parent), m_defs(m_parent.m) + {} + + bool is_proxy(app *k, app_ref &v); + app* mk_proxy(expr *v); + void reset(); + bool is_proxy_def(expr *v); + + }; + + friend struct def_manager; + ast_manager &m; + solver &m_solver; + app_ref_vector m_proxies; + unsigned m_num_proxies; + vector m_defs; + def_manager m_base_defs; + expr_ref_vector m_assumptions; + unsigned m_first_assumption; + bool m_is_proxied; + + stopwatch m_itp_watch; + + expr_substitution m_elim_proxies_sub; + bool m_split_literals; + bool m_new_unsat_core; + bool m_minimize_unsat_core; + bool m_farkas_optimized; + bool m_farkas_a_const; + + bool is_proxy(expr *e, app_ref &def); + void undo_proxies_in_core(ptr_vector &v); + app* mk_proxy(expr *v); + app* fresh_proxy(); + void elim_proxies(expr_ref_vector &v); +public: + itp_solver(solver &solver, bool new_unsat_core, bool minimize_unsat_core, bool farkas_optimized, bool farkas_a_const, bool split_literals = false) : + m(solver.get_manager()), + m_solver(solver), + m_proxies(m), + m_num_proxies(0), + m_base_defs(*this), + m_assumptions(m), + m_first_assumption(0), + m_is_proxied(false), + m_elim_proxies_sub(m, false, true), + m_split_literals(split_literals), + m_new_unsat_core(new_unsat_core), + m_minimize_unsat_core(minimize_unsat_core), + m_farkas_optimized(farkas_optimized), + m_farkas_a_const(farkas_a_const) + {} + + virtual ~itp_solver() {} + + /* itp solver specific */ + virtual void get_unsat_core(expr_ref_vector &core); + virtual void get_itp_core(expr_ref_vector &core); + void set_split_literals(bool v) {m_split_literals = v;} + bool mk_proxies(expr_ref_vector &v, unsigned from = 0); + void undo_proxies(expr_ref_vector &v); + + void push_bg(expr *e); + void pop_bg(unsigned n); + unsigned get_num_bg(); + + void get_full_unsat_core(ptr_vector &core) + {m_solver.get_unsat_core(core);} + + /* solver interface */ + + virtual solver* translate(ast_manager &m, params_ref const &p) + {return m_solver.translate(m, p);} + virtual void updt_params(params_ref const &p) + {m_solver.updt_params(p);} + virtual void collect_param_descrs(param_descrs &r) + {m_solver.collect_param_descrs(r);} + virtual void set_produce_models(bool f) + {m_solver.set_produce_models(f);} + virtual void assert_expr(expr *t) + {m_solver.assert_expr(t);} + + virtual void assert_expr(expr *t, expr *a) + {NOT_IMPLEMENTED_YET();} + + virtual void push(); + virtual void pop(unsigned n); + virtual unsigned get_scope_level() const + {return m_solver.get_scope_level();} + + virtual lbool check_sat(unsigned num_assumptions, expr * const *assumptions); + virtual void set_progress_callback(progress_callback *callback) + {m_solver.set_progress_callback(callback);} + virtual unsigned get_num_assertions() const + {return m_solver.get_num_assertions();} + virtual expr * get_assertion(unsigned idx) const + {return m_solver.get_assertion(idx);} + virtual unsigned get_num_assumptions() const + {return m_solver.get_num_assumptions();} + virtual expr * get_assumption(unsigned idx) const + {return m_solver.get_assumption(idx);} + virtual std::ostream &display(std::ostream &out, unsigned n, expr* const* es) const + { return m_solver.display(out, n, es); } + + /* check_sat_result interface */ + + virtual void collect_statistics(statistics &st) const ; + virtual void reset_statistics(); + virtual void get_unsat_core(ptr_vector &r); + virtual void get_model(model_ref &m) {m_solver.get_model(m);} + virtual proof *get_proof() {return m_solver.get_proof();} + virtual std::string reason_unknown() const + {return m_solver.reason_unknown();} + virtual void set_reason_unknown(char const* msg) + {m_solver.set_reason_unknown(msg);} + virtual void get_labels(svector &r) + {m_solver.get_labels(r);} + virtual ast_manager &get_manager() const {return m;} + + virtual void refresh(); + + class scoped_mk_proxy { + itp_solver &m_s; + expr_ref_vector &m_v; + public: + scoped_mk_proxy(itp_solver &s, expr_ref_vector &v) : m_s(s), m_v(v) + {m_s.mk_proxies(m_v);} + ~scoped_mk_proxy() + {m_s.undo_proxies(m_v);} + }; + + class scoped_bg { + itp_solver &m_s; + unsigned m_bg_sz; + public: + scoped_bg(itp_solver &s) : m_s(s), m_bg_sz(m_s.get_num_bg()) {} + ~scoped_bg() + {if (m_s.get_num_bg() > m_bg_sz) { m_s.pop_bg(m_s.get_num_bg() - m_bg_sz); }} + }; +}; +} +#endif diff --git a/src/muz/spacer/spacer_legacy_frames.cpp b/src/muz/spacer/spacer_legacy_frames.cpp new file mode 100644 index 000000000..679736add --- /dev/null +++ b/src/muz/spacer/spacer_legacy_frames.cpp @@ -0,0 +1,171 @@ +/* + Copyright (c) 2017 Arie Gurfinkel + + Legacy implementations of frames. To be removed. + */ +#include +#include + +#include "muz/spacer/spacer_context.h" +#include "muz/base/dl_util.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/var_subst.h" +#include "util/util.h" +#include "muz/spacer/spacer_prop_solver.h" +#include "muz/spacer/spacer_context.h" +#include "muz/spacer/spacer_generalizers.h" +#include "ast/for_each_expr.h" +#include "muz/base/dl_rule_set.h" +#include "smt/tactic/unit_subsumption_tactic.h" +#include "model/model_smt2_pp.h" +#include "muz/transforms/dl_mk_rule_inliner.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_util.h" +#include "ast/proofs/proof_checker.h" +#include "smt/smt_value_sort.h" +#include "ast/proofs/proof_utils.h" +#include "ast/scoped_proof.h" +#include "muz/spacer/spacer_qe_project.h" +#include "tactic/core/blast_term_ite_tactic.h" + +#include "util/timeit.h" +#include "util/luby.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/expr_abstract.h" +#include "ast/factor_equivs.h" + + +namespace spacer { +// ------------------ +// legacy_frames +void pred_transformer::legacy_frames::simplify_formulas(tactic& tac, + expr_ref_vector& v) +{ + ast_manager &m = m_pt.get_ast_manager(); + goal_ref g(alloc(goal, m, false, false, false)); + for (unsigned j = 0; j < v.size(); ++j) { g->assert_expr(v[j].get()); } + model_converter_ref mc; + proof_converter_ref pc; + expr_dependency_ref core(m); + goal_ref_buffer result; + tac(g, result, mc, pc, core); + SASSERT(result.size() == 1); + goal* r = result[0]; + v.reset(); + for (unsigned j = 0; j < r->size(); ++j) { v.push_back(r->form(j)); } +} + +void pred_transformer::legacy_frames::simplify_formulas() +{ + ast_manager &m = m_pt.get_ast_manager(); + tactic_ref us = mk_unit_subsumption_tactic(m); + simplify_formulas(*us, m_invariants); + for (unsigned i = 0; i < m_levels.size(); ++i) { + simplify_formulas(*us, m_levels[i]); + } +} + +void pred_transformer::legacy_frames::get_frame_geq_lemmas(unsigned lvl, + expr_ref_vector &out) +{ + get_frame_lemmas(infty_level(), out); + for (unsigned i = lvl, sz = m_levels.size(); i < sz; ++i) + { get_frame_lemmas(i, out); } +} + +bool pred_transformer::legacy_frames::propagate_to_next_level(unsigned src_level) +{ + + ast_manager &m = m_pt.get_ast_manager(); + (void) m; + if (m_levels.size() <= src_level) { return true; } + if (m_levels [src_level].empty()) { return true; } + + unsigned tgt_level = next_level(src_level); + m_pt.ensure_level(next_level(tgt_level)); + + TRACE("spacer", + tout << "propagating " << src_level << " to " << tgt_level; + tout << " for relation " << m_pt.head()->get_name() << "\n";); + + for (unsigned i = 0; i < m_levels[src_level].size();) { + expr_ref_vector &src = m_levels[src_level]; + expr * curr = src[i].get(); + unsigned stored_lvl; + VERIFY(m_prop2level.find(curr, stored_lvl)); + SASSERT(stored_lvl >= src_level); + unsigned solver_level; + if (stored_lvl > src_level) { + TRACE("spacer", tout << "at level: " << stored_lvl << " " << mk_pp(curr, m) << "\n";); + src[i] = src.back(); + src.pop_back(); + } else if (m_pt.is_invariant(tgt_level, curr, solver_level)) { + // -- might invalidate src reference + add_lemma(curr, solver_level); + TRACE("spacer", tout << "is invariant: " << pp_level(solver_level) << " " << mk_pp(curr, m) << "\n";); + // shadow higher-level src + expr_ref_vector &src = m_levels[src_level]; + src[i] = src.back(); + src.pop_back(); + ++m_pt.m_stats.m_num_propagations; + } else { + TRACE("spacer", tout << "not propagated: " << mk_pp(curr, m) << "\n";); + ++i; + } + } + + CTRACE("spacer", m_levels[src_level].empty(), + tout << "Fully propagated level " + << src_level << " of " << m_pt.head()->get_name() << "\n";); + + return m_levels[src_level].empty(); +} + +bool pred_transformer::legacy_frames::add_lemma(expr * lemma, unsigned lvl) +{ + if (is_infty_level(lvl)) { + if (!m_invariants.contains(lemma)) { + m_invariants.push_back(lemma); + m_prop2level.insert(lemma, lvl); + //m_pt.add_lemma_core (lemma, lvl); + return true; + } + return false; + } + + unsigned old_level; + if (!m_prop2level.find(lemma, old_level) || old_level < lvl) { + m_levels[lvl].push_back(lemma); + m_prop2level.insert(lemma, lvl); + //m_pt.add_lemma_core (lemma, lvl); + return true; + } + return false; +} + +void pred_transformer::legacy_frames::propagate_to_infinity(unsigned level) +{ + TRACE("spacer", tout << "propagating to oo from lvl " << level + << " of " << m_pt.m_head->get_name() << "\n";); + + if (m_levels.empty()) { return; } + + for (unsigned i = m_levels.size(); i > level; --i) { + expr_ref_vector &lemmas = m_levels [i - 1]; + for (unsigned j = 0; j < lemmas.size(); ++j) + { add_lemma(lemmas.get(j), infty_level()); } + lemmas.reset(); + } +} + +void pred_transformer::legacy_frames::inherit_frames(legacy_frames& other) +{ + + SASSERT(m_pt.m_head == other.m_pt.m_head); + obj_map::iterator it = other.m_prop2level.begin(); + obj_map::iterator end = other.m_prop2level.end(); + for (; it != end; ++it) { add_lemma(it->m_key, it->m_value); } +} +} diff --git a/src/muz/spacer/spacer_legacy_frames.h b/src/muz/spacer/spacer_legacy_frames.h new file mode 100644 index 000000000..7ff4b6fad --- /dev/null +++ b/src/muz/spacer/spacer_legacy_frames.h @@ -0,0 +1,47 @@ +/**++ + Copyright (c) 2017 Arie Gurfinkel + + Legacy implementations of frames. To be removed. + + Notes: this file is included from the middle of spacer_context.h +*/ + +class legacy_frames +{ + pred_transformer &m_pt; + + /// level formulas + vector m_levels; + /// map property to level where it occurs. + obj_map m_prop2level; + /// properties that are invariant. + expr_ref_vector m_invariants; + + void simplify_formulas (tactic& tac, expr_ref_vector& v); + +public: + legacy_frames (pred_transformer &pt) : + m_pt(pt), m_invariants (m_pt.get_ast_manager ()) {} + pred_transformer& pt () const {return m_pt;} + bool add_lemma (expr * lemma, unsigned level); + void get_frame_lemmas (unsigned level, expr_ref_vector &out) + { + if(is_infty_level(level)) { out.append(m_invariants); } + else if(level < m_levels.size()) { out.append(m_levels [level]); } + } + + void get_frame_geq_lemmas (unsigned level, expr_ref_vector &out); + void add_frame () {m_levels.push_back (expr_ref_vector (m_pt.get_ast_manager ()));} + + unsigned size () const {return m_levels.size ();} + unsigned lemma_size () const {return m_prop2level.size ();} + + + void propagate_to_infinity (unsigned level); + bool propagate_to_next_level (unsigned level); + + void simplify_formulas (); + + void inherit_frames (legacy_frames& other); + +}; diff --git a/src/muz/spacer/spacer_legacy_mbp.cpp b/src/muz/spacer/spacer_legacy_mbp.cpp new file mode 100644 index 000000000..9f03e6d2f --- /dev/null +++ b/src/muz/spacer/spacer_legacy_mbp.cpp @@ -0,0 +1,114 @@ +/** +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_legacy_mbp.cpp + +Abstract: + + Legacy Model Based Projection. Used by Grigory Fedyukovich + +Author: + + Arie Gurfinkel + Anvesh Komuravelli +Notes: + +--*/ +#include + +#include "ast/array_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/bool_rewriter.h" +#include "muz/base/dl_util.h" +#include "ast/for_each_expr.h" +#include "smt/params/smt_params.h" +#include "model/model.h" +#include "util/ref_vector.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "util/util.h" +#include "muz/spacer/spacer_manager.h" +#include "muz/spacer/spacer_util.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/expr_replacer.h" +#include "model/model_smt2_pp.h" +#include "ast/scoped_proof.h" +#include "qe/qe_lite.h" +#include "muz/spacer/spacer_qe_project.h" +#include "model/model_pp.h" +#include "ast/rewriter/expr_safe_replace.h" + +#include "ast/datatype_decl_plugin.h" +#include "ast/bv_decl_plugin.h" + +#include "muz/spacer/spacer_legacy_mev.h" + +namespace spacer { +void qe_project(ast_manager& m, app_ref_vector& vars, expr_ref& fml, model_ref& M, expr_map& map) +{ + th_rewriter rw(m); + // qe-lite; TODO: use qe_lite aggressively + params_ref p; + qe_lite qe(m, p, true); + qe(vars, fml); + rw(fml); + + TRACE("spacer", + tout << "After qe_lite:\n"; + tout << mk_pp(fml, m) << "\n"; + tout << "Vars:\n"; + for (unsigned i = 0; i < vars.size(); ++i) { + tout << mk_pp(vars.get(i), m) << "\n"; + } + ); + + // substitute model values for booleans and + // use LW projection for arithmetic variables + if (!vars.empty()) { + app_ref_vector arith_vars(m); + expr_substitution sub(m); + proof_ref pr(m.mk_asserted(m.mk_true()), m); + expr_ref bval(m); + for (unsigned i = 0; i < vars.size(); i++) { + if (m.is_bool(vars.get(i))) { + // obtain the interpretation of the ith var using model completion + VERIFY(M->eval(vars.get(i), bval, true)); + sub.insert(vars.get(i), bval, pr); + } else { + arith_vars.push_back(vars.get(i)); + } + } + if (!sub.empty()) { + scoped_ptr rep = mk_expr_simp_replacer(m); + rep->set_substitution(&sub); + (*rep)(fml); + rw(fml); + TRACE("spacer", + tout << "Projected Boolean vars:\n" << mk_pp(fml, m) << "\n"; + ); + } + // model based projection + if (!arith_vars.empty()) { + TRACE("spacer", + tout << "Arith vars:\n"; + for (unsigned i = 0; i < arith_vars.size(); ++i) { + tout << mk_pp(arith_vars.get(i), m) << "\n"; + } + ); + { + scoped_no_proof _sp(m); + qe::arith_project(*M, arith_vars, fml, map); + } + SASSERT(arith_vars.empty()); + TRACE("spacer", + tout << "Projected arith vars:\n" << mk_pp(fml, m) << "\n"; + ); + } + SASSERT(M->eval(fml, bval, true) && m.is_true(bval)); // M |= fml + vars.reset(); + vars.append(arith_vars); + } +} +} diff --git a/src/muz/spacer/spacer_legacy_mev.cpp b/src/muz/spacer/spacer_legacy_mev.cpp new file mode 100644 index 000000000..16e2cc734 --- /dev/null +++ b/src/muz/spacer/spacer_legacy_mev.cpp @@ -0,0 +1,834 @@ +/** +Copyright (c) 2017 Arie Gurfinkel + + Deprecated implementation of model evaluator. To be removed. +*/ + +#include +#include "ast/array_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/bool_rewriter.h" +#include "muz/base/dl_util.h" +#include "ast/for_each_expr.h" +#include "smt/params/smt_params.h" +#include "model/model.h" +#include "util/ref_vector.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "util/util.h" +#include "muz/spacer/spacer_manager.h" +#include "muz/spacer/spacer_legacy_mev.h" +#include "muz/spacer/spacer_util.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/expr_replacer.h" +#include "model/model_smt2_pp.h" +#include "ast/scoped_proof.h" +#include "qe/qe_lite.h" +#include "muz/spacer/spacer_qe_project.h" +#include "model/model_pp.h" +#include "ast/rewriter/expr_safe_replace.h" + +#include "ast/datatype_decl_plugin.h" +#include "ast/bv_decl_plugin.h" + +namespace old { + +///////////////////////// +// model_evaluator +// + + +void model_evaluator::assign_value(expr* e, expr* val) +{ + rational r; + if (m.is_true(val)) { + set_true(e); + } else if (m.is_false(val)) { + set_false(e); + } else if (m_arith.is_numeral(val, r)) { + set_number(e, r); + } else if (m.is_value(val)) { + set_value(e, val); + } else { + IF_VERBOSE(3, verbose_stream() << "Not evaluated " << mk_pp(e, m) << "\n";); + TRACE("old_spacer", tout << "Variable is not tracked: " << mk_pp(e, m) << "\n";); + set_x(e); + } +} + +void model_evaluator::setup_model(const model_ref& model) +{ + m_numbers.reset(); + m_values.reset(); + m_model = model.get(); + rational r; + unsigned sz = model->get_num_constants(); + for (unsigned i = 0; i < sz; i++) { + func_decl * d = model->get_constant(i); + expr* val = model->get_const_interp(d); + expr* e = m.mk_const(d); + m_refs.push_back(e); + assign_value(e, val); + } +} + +void model_evaluator::reset() +{ + m1.reset(); + m2.reset(); + m_values.reset(); + m_visited.reset(); + m_numbers.reset(); + m_refs.reset(); + m_model = 0; +} + + +void model_evaluator::minimize_literals(ptr_vector const& formulas, + const model_ref& mdl, expr_ref_vector& result) +{ + + TRACE("old_spacer", + tout << "formulas:\n"; + for (unsigned i = 0; i < formulas.size(); ++i) tout << mk_pp(formulas[i], m) << "\n"; + ); + + expr_ref tmp(m); + ptr_vector tocollect; + + setup_model(mdl); + collect(formulas, tocollect); + for (unsigned i = 0; i < tocollect.size(); ++i) { + expr* e = tocollect[i]; + expr* e1, *e2; + SASSERT(m.is_bool(e)); + SASSERT(is_true(e) || is_false(e)); + if (is_true(e)) { + result.push_back(e); + } + // hack to break disequalities for arithmetic variables. + else if (m.is_eq(e, e1, e2) && m_arith.is_int_real(e1)) { + if (get_number(e1) < get_number(e2)) { + result.push_back(m_arith.mk_lt(e1, e2)); + } else { + result.push_back(m_arith.mk_lt(e2, e1)); + } + } else { + result.push_back(m.mk_not(e)); + } + } + reset(); + TRACE("old_spacer", + tout << "minimized model:\n"; + for (unsigned i = 0; i < result.size(); ++i) tout << mk_pp(result[i].get(), m) << "\n"; + ); +} + +void model_evaluator::process_formula(app* e, ptr_vector& todo, ptr_vector& tocollect) +{ + SASSERT(m.is_bool(e)); + SASSERT(is_true(e) || is_false(e)); + unsigned v = is_true(e); + unsigned sz = e->get_num_args(); + expr* const* args = e->get_args(); + if (e->get_family_id() == m.get_basic_family_id()) { + switch (e->get_decl_kind()) { + case OP_TRUE: + break; + case OP_FALSE: + break; + case OP_EQ: + case OP_IFF: + if (args[0] == args[1]) { + SASSERT(v); + // no-op + } else if (m.is_bool(args[0])) { + todo.append(sz, args); + } else { + tocollect.push_back(e); + } + break; + case OP_DISTINCT: + tocollect.push_back(e); + break; + case OP_ITE: + if (args[1] == args[2]) { + tocollect.push_back(args[1]); + } else if (is_true(args[1]) && is_true(args[2])) { + todo.append(2, args + 1); + } else if (is_false(args[1]) && is_false(args[2])) { + todo.append(2, args + 1); + } else if (is_true(args[0])) { + todo.append(2, args); + } else { + SASSERT(is_false(args[0])); + todo.push_back(args[0]); + todo.push_back(args[2]); + } + break; + case OP_AND: + if (v) { + todo.append(sz, args); + } else { + unsigned i = 0; + for (; !is_false(args[i]) && i < sz; ++i); + if (i == sz) { + fatal_error(1); + } + VERIFY(i < sz); + todo.push_back(args[i]); + } + break; + case OP_OR: + if (v) { + unsigned i = 0; + for (; !is_true(args[i]) && i < sz; ++i); + if (i == sz) { + fatal_error(1); + } + VERIFY(i < sz); + todo.push_back(args[i]); + } else { + todo.append(sz, args); + } + break; + case OP_XOR: + case OP_NOT: + todo.append(sz, args); + break; + case OP_IMPLIES: + if (v) { + if (is_true(args[1])) { + todo.push_back(args[1]); + } else if (is_false(args[0])) { + todo.push_back(args[0]); + } else { + IF_VERBOSE(0, verbose_stream() << "Term not handled " << mk_pp(e, m) << "\n";); + UNREACHABLE(); + } + } else { + todo.append(sz, args); + } + break; + default: + IF_VERBOSE(0, verbose_stream() << "Term not handled " << mk_pp(e, m) << "\n";); + UNREACHABLE(); + } + } else { + tocollect.push_back(e); + } +} + +void model_evaluator::collect(ptr_vector const& formulas, ptr_vector& tocollect) +{ + ptr_vector todo; + todo.append(formulas); + m_visited.reset(); + + VERIFY(check_model(formulas)); + + while (!todo.empty()) { + app* e = to_app(todo.back()); + todo.pop_back(); + if (!m_visited.is_marked(e)) { + process_formula(e, todo, tocollect); + m_visited.mark(e, true); + } + } + m_visited.reset(); +} + +void model_evaluator::eval_arith(app* e) +{ + rational r, r2; + +#define ARG1 e->get_arg(0) +#define ARG2 e->get_arg(1) + + unsigned arity = e->get_num_args(); + for (unsigned i = 0; i < arity; ++i) { + expr* arg = e->get_arg(i); + if (is_x(arg)) { + set_x(e); + return; + } + SASSERT(!is_unknown(arg)); + } + switch (e->get_decl_kind()) { + case OP_NUM: + VERIFY(m_arith.is_numeral(e, r)); + set_number(e, r); + break; + case OP_IRRATIONAL_ALGEBRAIC_NUM: + set_x(e); + break; + case OP_LE: + set_bool(e, get_number(ARG1) <= get_number(ARG2)); + break; + case OP_GE: + set_bool(e, get_number(ARG1) >= get_number(ARG2)); + break; + case OP_LT: + set_bool(e, get_number(ARG1) < get_number(ARG2)); + break; + case OP_GT: + set_bool(e, get_number(ARG1) > get_number(ARG2)); + break; + case OP_ADD: + r = rational::zero(); + for (unsigned i = 0; i < arity; ++i) { + r += get_number(e->get_arg(i)); + } + set_number(e, r); + break; + case OP_SUB: + r = get_number(e->get_arg(0)); + for (unsigned i = 1; i < arity; ++i) { + r -= get_number(e->get_arg(i)); + } + set_number(e, r); + break; + case OP_UMINUS: + SASSERT(arity == 1); + set_number(e, -get_number(e->get_arg(0))); + break; + case OP_MUL: + r = rational::one(); + for (unsigned i = 0; i < arity; ++i) { + r *= get_number(e->get_arg(i)); + } + set_number(e, r); + break; + case OP_DIV: + SASSERT(arity == 2); + r = get_number(ARG2); + if (r.is_zero()) { + set_x(e); + } else { + set_number(e, get_number(ARG1) / r); + } + break; + case OP_IDIV: + SASSERT(arity == 2); + r = get_number(ARG2); + if (r.is_zero()) { + set_x(e); + } else { + set_number(e, div(get_number(ARG1), r)); + } + break; + case OP_REM: + // rem(v1,v2) = if v2 >= 0 then mod(v1,v2) else -mod(v1,v2) + SASSERT(arity == 2); + r = get_number(ARG2); + if (r.is_zero()) { + set_x(e); + } else { + r2 = mod(get_number(ARG1), r); + if (r.is_neg()) { r2.neg(); } + set_number(e, r2); + } + break; + case OP_MOD: + SASSERT(arity == 2); + r = get_number(ARG2); + if (r.is_zero()) { + set_x(e); + } else { + set_number(e, mod(get_number(ARG1), r)); + } + break; + case OP_TO_REAL: + SASSERT(arity == 1); + set_number(e, get_number(ARG1)); + break; + case OP_TO_INT: + SASSERT(arity == 1); + set_number(e, floor(get_number(ARG1))); + break; + case OP_IS_INT: + SASSERT(arity == 1); + set_bool(e, get_number(ARG1).is_int()); + break; + case OP_POWER: + set_x(e); + break; + default: + IF_VERBOSE(0, verbose_stream() << "Term not handled " << mk_pp(e, m) << "\n";); + UNREACHABLE(); + break; + } +} + +void model_evaluator::inherit_value(expr* e, expr* v) +{ + expr* w; + SASSERT(!is_unknown(v)); + SASSERT(m.get_sort(e) == m.get_sort(v)); + if (is_x(v)) { + set_x(e); + } else if (m.is_bool(e)) { + SASSERT(m.is_bool(v)); + if (is_true(v)) { set_true(e); } + else if (is_false(v)) { set_false(e); } + else { + TRACE("old_spacer", tout << "not inherited:\n" << mk_pp(e, m) << "\n" << mk_pp(v, m) << "\n";); + set_x(e); + } + } else if (m_arith.is_int_real(e)) { + set_number(e, get_number(v)); + } else if (m.is_value(v)) { + set_value(e, v); + } else if (m_values.find(v, w)) { + set_value(e, w); + } else { + TRACE("old_spacer", tout << "not inherited:\n" << mk_pp(e, m) << "\n" << mk_pp(v, m) << "\n";); + set_x(e); + } +} + +void model_evaluator::eval_exprs(expr_ref_vector& es) +{ + model_ref mr(m_model); + for (unsigned j = 0; j < es.size(); ++j) { + if (m_array.is_as_array(es[j].get())) { + es[j] = eval(mr, es[j].get()); + } + } +} + +bool model_evaluator::extract_array_func_interp(expr* a, vector& stores, expr_ref& else_case) +{ + SASSERT(m_array.is_array(a)); + + TRACE("old_spacer", tout << mk_pp(a, m) << "\n";); + while (m_array.is_store(a)) { + expr_ref_vector store(m); + store.append(to_app(a)->get_num_args() - 1, to_app(a)->get_args() + 1); + eval_exprs(store); + stores.push_back(store); + a = to_app(a)->get_arg(0); + } + + if (m_array.is_const(a)) { + else_case = to_app(a)->get_arg(0); + return true; + } + + while (m_array.is_as_array(a)) { + func_decl* f = m_array.get_as_array_func_decl(to_app(a)); + func_interp* g = m_model->get_func_interp(f); + unsigned sz = g->num_entries(); + unsigned arity = f->get_arity(); + for (unsigned i = 0; i < sz; ++i) { + expr_ref_vector store(m); + func_entry const* fe = g->get_entry(i); + store.append(arity, fe->get_args()); + store.push_back(fe->get_result()); + for (unsigned j = 0; j < store.size(); ++j) { + if (!is_ground(store[j].get())) { + TRACE("old_spacer", tout << "could not extract array interpretation: " << mk_pp(a, m) << "\n" << mk_pp(store[j].get(), m) << "\n";); + return false; + } + } + eval_exprs(store); + stores.push_back(store); + } + else_case = g->get_else(); + if (!else_case) { + TRACE("old_spacer", tout << "no else case " << mk_pp(a, m) << "\n";); + return false; + } + if (!is_ground(else_case)) { + TRACE("old_spacer", tout << "non-ground else case " << mk_pp(a, m) << "\n" << mk_pp(else_case, m) << "\n";); + return false; + } + if (m_array.is_as_array(else_case)) { + model_ref mr(m_model); + else_case = eval(mr, else_case); + } + TRACE("old_spacer", tout << "else case: " << mk_pp(else_case, m) << "\n";); + return true; + } + TRACE("old_spacer", tout << "no translation: " << mk_pp(a, m) << "\n";); + + return false; +} + +/** + best effort evaluator of extensional array equality. +*/ +void model_evaluator::eval_array_eq(app* e, expr* arg1, expr* arg2) +{ + TRACE("old_spacer", tout << "array equality: " << mk_pp(e, m) << "\n";); + expr_ref v1(m), v2(m); + m_model->eval(arg1, v1); + m_model->eval(arg2, v2); + if (v1 == v2) { + set_true(e); + return; + } + sort* s = m.get_sort(arg1); + sort* r = get_array_range(s); + // give up evaluating finite domain/range arrays + if (!r->is_infinite() && !r->is_very_big() && !s->is_infinite() && !s->is_very_big()) { + TRACE("old_spacer", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); + set_x(e); + return; + } + vector store; + expr_ref else1(m), else2(m); + if (!extract_array_func_interp(v1, store, else1) || + !extract_array_func_interp(v2, store, else2)) { + TRACE("old_spacer", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); + set_x(e); + return; + } + + if (else1 != else2) { + if (m.is_value(else1) && m.is_value(else2)) { + TRACE("old_spacer", tout + << "defaults are different: " << mk_pp(e, m) << " " + << mk_pp(else1, m) << " " << mk_pp(else2, m) << "\n";); + set_false(e); + } else if (m_array.is_array(else1)) { + eval_array_eq(e, else1, else2); + } else { + TRACE("old_spacer", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); + set_x(e); + } + return; + } + + expr_ref s1(m), s2(m), w1(m), w2(m); + expr_ref_vector args1(m), args2(m); + args1.push_back(v1); + args2.push_back(v2); + for (unsigned i = 0; i < store.size(); ++i) { + args1.resize(1); + args2.resize(1); + args1.append(store[i].size() - 1, store[i].c_ptr()); + args2.append(store[i].size() - 1, store[i].c_ptr()); + s1 = m_array.mk_select(args1.size(), args1.c_ptr()); + s2 = m_array.mk_select(args2.size(), args2.c_ptr()); + m_model->eval(s1, w1); + m_model->eval(s2, w2); + if (w1 == w2) { + continue; + } + if (m.is_value(w1) && m.is_value(w2)) { + TRACE("old_spacer", tout << "Equality evaluation: " << mk_pp(e, m) << "\n"; + tout << mk_pp(s1, m) << " |-> " << mk_pp(w1, m) << "\n"; + tout << mk_pp(s2, m) << " |-> " << mk_pp(w2, m) << "\n";); + set_false(e); + } else if (m_array.is_array(w1)) { + eval_array_eq(e, w1, w2); + if (is_true(e)) { + continue; + } + } else { + TRACE("old_spacer", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); + set_x(e); + } + return; + } + set_true(e); +} + +void model_evaluator::eval_eq(app* e, expr* arg1, expr* arg2) +{ + if (arg1 == arg2) { + set_true(e); + } else if (m_array.is_array(arg1)) { + eval_array_eq(e, arg1, arg2); + } else if (is_x(arg1) || is_x(arg2)) { + set_x(e); + } else if (m.is_bool(arg1)) { + bool val = is_true(arg1) == is_true(arg2); + SASSERT(val == (is_false(arg1) == is_false(arg2))); + if (val) { + set_true(e); + } else { + set_false(e); + } + } else if (m_arith.is_int_real(arg1)) { + set_bool(e, get_number(arg1) == get_number(arg2)); + } else { + expr* e1 = get_value(arg1); + expr* e2 = get_value(arg2); + if (m.is_value(e1) && m.is_value(e2)) { + set_bool(e, e1 == e2); + } else if (e1 == e2) { + set_bool(e, true); + } else { + TRACE("old_spacer", tout << "not value equal:\n" << mk_pp(e1, m) << "\n" << mk_pp(e2, m) << "\n";); + set_x(e); + } + } +} + +void model_evaluator::eval_basic(app* e) +{ + expr* arg1, *arg2; + expr *argCond, *argThen, *argElse, *arg; + bool has_x = false; + unsigned arity = e->get_num_args(); + switch (e->get_decl_kind()) { + case OP_AND: + for (unsigned j = 0; j < arity; ++j) { + expr * arg = e->get_arg(j); + if (is_false(arg)) { + set_false(e); + return; + } else if (is_x(arg)) { + has_x = true; + } else { + SASSERT(is_true(arg)); + } + } + if (has_x) { + set_x(e); + } else { + set_true(e); + } + break; + case OP_OR: + for (unsigned j = 0; j < arity; ++j) { + expr * arg = e->get_arg(j); + if (is_true(arg)) { + set_true(e); + return; + } else if (is_x(arg)) { + has_x = true; + } else { + SASSERT(is_false(arg)); + } + } + if (has_x) { + set_x(e); + } else { + set_false(e); + } + break; + case OP_NOT: + VERIFY(m.is_not(e, arg)); + if (is_true(arg)) { + set_false(e); + } else if (is_false(arg)) { + set_true(e); + } else { + SASSERT(is_x(arg)); + set_x(e); + } + break; + case OP_IMPLIES: + VERIFY(m.is_implies(e, arg1, arg2)); + if (is_false(arg1) || is_true(arg2)) { + set_true(e); + } else if (arg1 == arg2) { + set_true(e); + } else if (is_true(arg1) && is_false(arg2)) { + set_false(e); + } else { + SASSERT(is_x(arg1) || is_x(arg2)); + set_x(e); + } + break; + case OP_IFF: + VERIFY(m.is_iff(e, arg1, arg2)); + eval_eq(e, arg1, arg2); + break; + case OP_XOR: + VERIFY(m.is_xor(e, arg1, arg2)); + eval_eq(e, arg1, arg2); + if (is_false(e)) { set_true(e); } + else if (is_true(e)) { set_false(e); } + break; + case OP_ITE: + VERIFY(m.is_ite(e, argCond, argThen, argElse)); + if (is_true(argCond)) { + inherit_value(e, argThen); + } else if (is_false(argCond)) { + inherit_value(e, argElse); + } else if (argThen == argElse) { + inherit_value(e, argThen); + } else if (m.is_bool(e)) { + SASSERT(is_x(argCond)); + if (is_x(argThen) || is_x(argElse)) { + set_x(e); + } else if (is_true(argThen) == is_true(argElse)) { + inherit_value(e, argThen); + } else { + set_x(e); + } + } else { + set_x(e); + } + break; + case OP_TRUE: + set_true(e); + break; + case OP_FALSE: + set_false(e); + break; + case OP_EQ: + VERIFY(m.is_eq(e, arg1, arg2)); + eval_eq(e, arg1, arg2); + break; + case OP_DISTINCT: { + vector values; + for (unsigned i = 0; i < arity; ++i) { + expr* arg = e->get_arg(i); + if (is_x(arg)) { + set_x(e); + return; + } + values.push_back(get_number(arg)); + } + std::sort(values.begin(), values.end()); + for (unsigned i = 0; i + 1 < values.size(); ++i) { + if (values[i] == values[i + 1]) { + set_false(e); + return; + } + } + set_true(e); + break; + } + default: + IF_VERBOSE(0, verbose_stream() << "Term not handled " << mk_pp(e, m) << "\n";); + UNREACHABLE(); + } +} + +void model_evaluator::eval_fmls(ptr_vector const& formulas) +{ + ptr_vector todo(formulas); + + while (!todo.empty()) { + expr * curr_e = todo.back(); + + if (!is_app(curr_e)) { + todo.pop_back(); + continue; + } + app * curr = to_app(curr_e); + + if (!is_unknown(curr)) { + todo.pop_back(); + continue; + } + unsigned arity = curr->get_num_args(); + for (unsigned i = 0; i < arity; ++i) { + if (is_unknown(curr->get_arg(i))) { + todo.push_back(curr->get_arg(i)); + } + } + if (todo.back() != curr) { + continue; + } + todo.pop_back(); + if (curr->get_family_id() == m_arith.get_family_id()) { + eval_arith(curr); + } else if (curr->get_family_id() == m.get_basic_family_id()) { + eval_basic(curr); + } else { + expr_ref vl(m); + m_model->eval(curr, vl); + assign_value(curr, vl); + } + + IF_VERBOSE(35, verbose_stream() << "assigned " << mk_pp(curr_e, m) + << (is_true(curr_e) ? "true" : is_false(curr_e) ? "false" : "unknown") << "\n";); + SASSERT(!is_unknown(curr)); + } +} + +bool model_evaluator::check_model(ptr_vector const& formulas) +{ + eval_fmls(formulas); + bool has_x = false; + for (unsigned i = 0; i < formulas.size(); ++i) { + expr * form = formulas[i]; + SASSERT(!is_unknown(form)); + TRACE("spacer_verbose", + tout << "formula is " << (is_true(form) ? "true" : is_false(form) ? "false" : "unknown") << "\n" << mk_pp(form, m) << "\n";); + + if (is_false(form)) { + IF_VERBOSE(0, verbose_stream() << "formula false in model: " << mk_pp(form, m) << "\n";); + UNREACHABLE(); + } + if (is_x(form)) { + IF_VERBOSE(0, verbose_stream() << "formula undetermined in model: " << mk_pp(form, m) << "\n";); + TRACE("old_spacer", model_smt2_pp(tout, m, *m_model, 0);); + has_x = true; + } + } + return !has_x; +} + +expr_ref model_evaluator::eval_heavy(const model_ref& model, expr* fml) +{ + expr_ref result(model->get_manager()); + + setup_model(model); + ptr_vector fmls; + fmls.push_back(fml); + eval_fmls(fmls); + if (is_false(fml)) { + result = m.mk_false(); + } else if (is_true(fml) || is_x(fml)) { + result = m.mk_true(); + } else if (m_arith.is_int_real(fml)) { + result = m_arith.mk_numeral(get_number(fml), m_arith.is_int(fml)); + } else { + result = get_value(fml); + } + reset(); + + return result; +} + +expr_ref model_evaluator::eval(const model_ref& model, func_decl* d) +{ + SASSERT(d->get_arity() == 0); + expr_ref result(m); + if (m_array.is_array(d->get_range())) { + expr_ref e(m); + e = m.mk_const(d); + result = eval(model, e); + } else { + result = model->get_const_interp(d); + } + return result; +} + +expr_ref model_evaluator::eval(const model_ref& model, expr* e) +{ + expr_ref result(m); + m_model = model.get(); + VERIFY(m_model->eval(e, result, true)); + if (m_array.is_array(e)) { + vector stores; + expr_ref_vector args(m); + expr_ref else_case(m); + if (extract_array_func_interp(result, stores, else_case)) { + result = m_array.mk_const_array(m.get_sort(e), else_case); + while (!stores.empty() && stores.back().back() == else_case) { + stores.pop_back(); + } + for (unsigned i = stores.size(); i > 0;) { + --i; + args.resize(1); + args[0] = result; + args.append(stores[i]); + result = m_array.mk_store(args.size(), args.c_ptr()); + } + return result; + } + } + return result; +} + + +} diff --git a/src/muz/spacer/spacer_legacy_mev.h b/src/muz/spacer/spacer_legacy_mev.h new file mode 100644 index 000000000..ff8f63d1f --- /dev/null +++ b/src/muz/spacer/spacer_legacy_mev.h @@ -0,0 +1,116 @@ +/** +Copyright (c) 2017 Arie Gurfinkel + + Deprecated implementation of model evaluator. To be removed. +*/ +#ifndef OLD_MEV_H +#define OLD_MEV_H + +#include "ast/ast.h" +#include "ast/ast_pp.h" +#include "util/obj_hashtable.h" +#include "util/ref_vector.h" +#include "util/trace.h" +#include "util/vector.h" +#include "ast/arith_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/bv_decl_plugin.h" + +namespace old { +class model_evaluator { + ast_manager& m; + arith_util m_arith; + array_util m_array; + obj_map m_numbers; + expr_ref_vector m_refs; + obj_map m_values; + model_ref m_model; + + //00 -- non-visited + //01 -- X + //10 -- false + //11 -- true + expr_mark m1; + expr_mark m2; + + /// used by collect() + expr_mark m_visited; + + + + void reset(); + + /// caches the values of all constants in the given model + void setup_model(const model_ref& model); + /// caches the value of an expression + void assign_value(expr* e, expr* v); + + /// extracts an implicant of the conjunction of formulas + void collect(ptr_vector const& formulas, ptr_vector& tocollect); + + /// one-round of extracting an implicant of e. The implicant + /// literals are stored in tocollect. The worklist is stored in todo + void process_formula(app* e, ptr_vector& todo, ptr_vector& tocollect); + void eval_arith(app* e); + void eval_basic(app* e); + void eval_eq(app* e, expr* arg1, expr* arg2); + void eval_array_eq(app* e, expr* arg1, expr* arg2); + void inherit_value(expr* e, expr* v); + + bool is_unknown(expr* x) { return !m1.is_marked(x) && !m2.is_marked(x); } + void set_unknown(expr* x) { m1.mark(x, false); m2.mark(x, false); } + bool is_x(expr* x) { return !m1.is_marked(x) && m2.is_marked(x); } + bool is_false(expr* x) { return m1.is_marked(x) && !m2.is_marked(x); } + bool is_true(expr* x) { return m1.is_marked(x) && m2.is_marked(x); } + void set_x(expr* x) { SASSERT(is_unknown(x)); m2.mark(x); } + void set_v(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); } + void set_false(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); } + void set_true(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); m2.mark(x); } + void set_bool(expr* x, bool v) { if(v) { set_true(x); } else { set_false(x); } } + rational const& get_number(expr* x) const { return m_numbers.find(x); } + void set_number(expr* x, rational const& v) + { + set_v(x); + m_numbers.insert(x, v); + TRACE("spacer_verbose", tout << mk_pp(x, m) << " " << v << "\n";); + } + expr* get_value(expr* x) { return m_values.find(x); } + void set_value(expr* x, expr* v) + { set_v(x); m_refs.push_back(v); m_values.insert(x, v); } + + + /// evaluates all sub-formulas and terms of the input in the current model. + /// Caches the result + void eval_fmls(ptr_vector const & formulas); + + /// calls eval_fmls(). Then checks whether all formulas are + /// TRUE. Returns false if at lest one formula is unknown (X) + bool check_model(ptr_vector const & formulas); + + bool extract_array_func_interp(expr* a, vector& stores, + expr_ref& else_case); + + void eval_exprs(expr_ref_vector& es); + +public: + model_evaluator(ast_manager& m) : m(m), m_arith(m), m_array(m), m_refs(m) {} + + + /** + \brief extract literals from formulas that satisfy formulas. + + \pre model satisfies formulas + */ + void minimize_literals(ptr_vector const & formulas, const model_ref& mdl, + expr_ref_vector& result); + + expr_ref eval_heavy(const model_ref& mdl, expr* fml); + + expr_ref eval(const model_ref& mdl, expr* e); + expr_ref eval(const model_ref& mdl, func_decl* d); +}; +} + + + +#endif /* OLD_MEV_H */ diff --git a/src/muz/spacer/spacer_manager.cpp b/src/muz/spacer/spacer_manager.cpp new file mode 100644 index 000000000..4ad3e0d7f --- /dev/null +++ b/src/muz/spacer/spacer_manager.cpp @@ -0,0 +1,387 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + spacer_manager.cpp + +Abstract: + + A manager class for SPACER, taking care of creating of AST + objects and conversions between them. + +Author: + + Krystof Hoder (t-khoder) 2011-8-25. + +Revision History: + +--*/ + +#include + +#include "muz/spacer/spacer_manager.h" +#include "ast/ast_smt2_pp.h" +#include "ast/for_each_expr.h" +#include "ast/has_free_vars.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/expr_abstract.h" +#include "model/model2expr.h" +#include "model/model_smt2_pp.h" +#include "tactic/model_converter.h" + +namespace spacer { + +class collect_decls_proc { + func_decl_set& m_bound_decls; + func_decl_set& m_aux_decls; +public: + collect_decls_proc(func_decl_set& bound_decls, func_decl_set& aux_decls): + m_bound_decls(bound_decls), + m_aux_decls(aux_decls) + { + } + + void operator()(app* a) + { + if (a->get_family_id() == null_family_id) { + func_decl* f = a->get_decl(); + if (!m_bound_decls.contains(f)) { + m_aux_decls.insert(f); + } + } + } + void operator()(var* v) {} + void operator()(quantifier* q) {} +}; + +typedef hashtable symbol_set; + +expr_ref inductive_property::fixup_clause(expr* fml) const +{ + expr_ref_vector disjs(m); + flatten_or(fml, disjs); + expr_ref result(m); + bool_rewriter(m).mk_or(disjs.size(), disjs.c_ptr(), result); + return result; +} + +expr_ref inductive_property::fixup_clauses(expr* fml) const +{ + expr_ref_vector conjs(m); + expr_ref result(m); + flatten_and(fml, conjs); + for (unsigned i = 0; i < conjs.size(); ++i) { + conjs[i] = fixup_clause(conjs[i].get()); + } + bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), result); + return result; +} + +std::string inductive_property::to_string() const +{ + std::stringstream stm; + model_ref md; + expr_ref result(m); + to_model(md); + model_smt2_pp(stm, m, *md.get(), 0); + return stm.str(); +} + +void inductive_property::to_model(model_ref& md) const +{ + md = alloc(model, m); + vector const& rs = m_relation_info; + expr_ref_vector conjs(m); + for (unsigned i = 0; i < rs.size(); ++i) { + relation_info ri(rs[i]); + func_decl * pred = ri.m_pred; + expr_ref prop = fixup_clauses(ri.m_body); + func_decl_ref_vector const& sig = ri.m_vars; + expr_ref q(m); + expr_ref_vector sig_vars(m); + for (unsigned j = 0; j < sig.size(); ++j) { + sig_vars.push_back(m.mk_const(sig[sig.size() - j - 1])); + } + expr_abstract(m, 0, sig_vars.size(), sig_vars.c_ptr(), prop, q); + if (sig.empty()) { + md->register_decl(pred, q); + } else { + func_interp* fi = alloc(func_interp, m, sig.size()); + fi->set_else(q); + md->register_decl(pred, fi); + } + } + TRACE("spacer", model_smt2_pp(tout, m, *md, 0);); + apply(const_cast(m_mc), md, 0); +} + +expr_ref inductive_property::to_expr() const +{ + model_ref md; + expr_ref result(m); + to_model(md); + model2expr(md, result); + return result; +} + + +void inductive_property::display(datalog::rule_manager& rm, ptr_vector const& rules, std::ostream& out) const +{ + func_decl_set bound_decls, aux_decls; + collect_decls_proc collect_decls(bound_decls, aux_decls); + + for (unsigned i = 0; i < m_relation_info.size(); ++i) { + bound_decls.insert(m_relation_info[i].m_pred); + func_decl_ref_vector const& sig = m_relation_info[i].m_vars; + for (unsigned j = 0; j < sig.size(); ++j) { + bound_decls.insert(sig[j]); + } + for_each_expr(collect_decls, m_relation_info[i].m_body); + } + for (unsigned i = 0; i < rules.size(); ++i) { + bound_decls.insert(rules[i]->get_decl()); + } + for (unsigned i = 0; i < rules.size(); ++i) { + unsigned u_sz = rules[i]->get_uninterpreted_tail_size(); + unsigned t_sz = rules[i]->get_tail_size(); + for (unsigned j = u_sz; j < t_sz; ++j) { + for_each_expr(collect_decls, rules[i]->get_tail(j)); + } + } + smt2_pp_environment_dbg env(m); + func_decl_set::iterator it = aux_decls.begin(), end = aux_decls.end(); + for (; it != end; ++it) { + func_decl* f = *it; + ast_smt2_pp(out, f, env); + out << "\n"; + } + + out << to_string() << "\n"; + for (unsigned i = 0; i < rules.size(); ++i) { + out << "(push)\n"; + out << "(assert (not\n"; + rm.display_smt2(*rules[i], out); + out << "))\n"; + out << "(check-sat)\n"; + out << "(pop)\n"; + } +} + +std::vector manager::get_state_suffixes() +{ + std::vector res; + res.push_back("_n"); + return res; +} + +manager::manager(unsigned max_num_contexts, ast_manager& manager) : + m(manager), + m_brwr(m), + m_mux(m, get_state_suffixes()), + m_background(m.mk_true(), m), + m_contexts(m, max_num_contexts), + m_contexts2(m, max_num_contexts), + m_contexts3(m, max_num_contexts), + m_next_unique_num(0) +{ +} + + +void manager::add_new_state(func_decl * s) +{ + SASSERT(s->get_arity() == 0); //we currently don't support non-constant states + decl_vector vect; + + SASSERT(o_index(0) == 1); //we assume this in the number of retrieved symbols + m_mux.create_tuple(s, s->get_arity(), s->get_domain(), s->get_range(), 2, vect); + m_o0_preds.push_back(vect[o_index(0)]); +} + +func_decl * manager::get_o_pred(func_decl* s, unsigned idx) +{ + func_decl * res = m_mux.try_get_by_prefix(s, o_index(idx)); + if (res) { return res; } + add_new_state(s); + res = m_mux.try_get_by_prefix(s, o_index(idx)); + SASSERT(res); + return res; +} + +func_decl * manager::get_n_pred(func_decl* s) +{ + func_decl * res = m_mux.try_get_by_prefix(s, n_index()); + if (res) { return res; } + add_new_state(s); + res = m_mux.try_get_by_prefix(s, n_index()); + SASSERT(res); + return res; +} + +void manager::mk_model_into_cube(const expr_ref_vector & mdl, expr_ref & res) +{ + m_brwr.mk_and(mdl.size(), mdl.c_ptr(), res); +} + +void manager::mk_core_into_cube(const expr_ref_vector & core, expr_ref & res) +{ + m_brwr.mk_and(core.size(), core.c_ptr(), res); +} + +void manager::mk_cube_into_lemma(expr * cube, expr_ref & res) +{ + m_brwr.mk_not(cube, res); +} + +void manager::mk_lemma_into_cube(expr * lemma, expr_ref & res) +{ + m_brwr.mk_not(lemma, res); +} + +expr_ref manager::mk_and(unsigned sz, expr* const* exprs) +{ + expr_ref result(m); + m_brwr.mk_and(sz, exprs, result); + return result; +} + +expr_ref manager::mk_or(unsigned sz, expr* const* exprs) +{ + expr_ref result(m); + m_brwr.mk_or(sz, exprs, result); + return result; +} + +expr_ref manager::mk_not_and(expr_ref_vector const& conjs) +{ + expr_ref result(m), e(m); + expr_ref_vector es(conjs); + flatten_and(es); + for (unsigned i = 0; i < es.size(); ++i) { + m_brwr.mk_not(es[i].get(), e); + es[i] = e; + } + m_brwr.mk_or(es.size(), es.c_ptr(), result); + return result; +} + +void manager::get_or(expr* e, expr_ref_vector& result) +{ + result.push_back(e); + for (unsigned i = 0; i < result.size();) { + e = result[i].get(); + if (m.is_or(e)) { + result.append(to_app(e)->get_num_args(), to_app(e)->get_args()); + result[i] = result.back(); + result.pop_back(); + } else { + ++i; + } + } +} + +bool manager::try_get_state_and_value_from_atom(expr * atom0, app *& state, app_ref& value) +{ + if (!is_app(atom0)) { + return false; + } + app * atom = to_app(atom0); + expr * arg1; + expr * arg2; + app * candidate_state; + app_ref candidate_value(m); + if (m.is_not(atom, arg1)) { + if (!is_app(arg1)) { + return false; + } + candidate_state = to_app(arg1); + candidate_value = m.mk_false(); + } else if (m.is_eq(atom, arg1, arg2)) { + if (!is_app(arg1) || !is_app(arg2)) { + return false; + } + if (!m_mux.is_muxed(to_app(arg1)->get_decl())) { + std::swap(arg1, arg2); + } + candidate_state = to_app(arg1); + candidate_value = to_app(arg2); + } else { + candidate_state = atom; + candidate_value = m.mk_true(); + } + if (!m_mux.is_muxed(candidate_state->get_decl())) { + return false; + } + state = candidate_state; + value = candidate_value; + return true; +} + +bool manager::try_get_state_decl_from_atom(expr * atom, func_decl *& state) +{ + app_ref dummy_value_holder(m); + app * s; + if (try_get_state_and_value_from_atom(atom, s, dummy_value_holder)) { + state = s->get_decl(); + return true; + } else { + return false; + } +} + +/** + * Create a new skolem constant + */ +app* mk_zk_const(ast_manager &m, unsigned idx, sort *s) { + std::stringstream name; + name << "sk!" << idx; + return m.mk_const(symbol(name.str().c_str()), s); +} + +namespace find_zk_const_ns { +struct proc { + app_ref_vector &m_out; + proc (app_ref_vector &out) : m_out(out) {} + void operator() (var const * n) const {} + void operator() (app *n) const { + if (is_uninterp_const(n) && + n->get_decl()->get_name().str().compare (0, 3, "sk!") == 0) { + m_out.push_back (n); + } + } + void operator() (quantifier const *n) const {} +}; +} + +void find_zk_const(expr *e, app_ref_vector &res) { + find_zk_const_ns::proc p(res); + for_each_expr (p, e); +} + +namespace has_zk_const_ns { +struct found {}; +struct proc { + void operator() (var const *n) const {} + void operator() (app const *n) const { + if (is_uninterp_const(n) && + n->get_decl()->get_name().str().compare(0, 3, "sk!") == 0) { + throw found(); + } + } + void operator() (quantifier const *n) const {} +}; +} + + +bool has_zk_const(expr *e){ + has_zk_const_ns::proc p; + try { + for_each_expr(p, e); + } + catch (has_zk_const_ns::found) { + return true; + } + return false; +} + +} diff --git a/src/muz/spacer/spacer_manager.h b/src/muz/spacer/spacer_manager.h new file mode 100644 index 000000000..f2382c15d --- /dev/null +++ b/src/muz/spacer/spacer_manager.h @@ -0,0 +1,346 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + spacer_manager.h + +Abstract: + + A manager class for SPACER, taking care of creating of AST + objects and conversions between them. + +Author: + + Krystof Hoder (t-khoder) 2011-8-25. + +Revision History: + +--*/ + +#ifndef _SPACER_MANAGER_H_ +#define _SPACER_MANAGER_H_ + +#include +#include +#include + +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/expr_substitution.h" +#include "util/map.h" +#include "util/ref_vector.h" +#include "smt/smt_kernel.h" +#include "muz/spacer/spacer_util.h" +#include "muz/spacer/spacer_sym_mux.h" +#include "muz/spacer/spacer_farkas_learner.h" +#include "muz/spacer/spacer_smt_context_manager.h" +#include "muz/base/dl_rule.h" + +namespace smt { +class context; +} + +namespace spacer { + +struct relation_info { + func_decl_ref m_pred; + func_decl_ref_vector m_vars; + expr_ref m_body; + relation_info(ast_manager& m, func_decl* pred, ptr_vector const& vars, expr* b): + m_pred(pred, m), m_vars(m, vars.size(), vars.c_ptr()), m_body(b, m) {} + relation_info(relation_info const& other): m_pred(other.m_pred), m_vars(other.m_vars), m_body(other.m_body) {} +}; + +class unknown_exception {}; + +class inductive_property { + ast_manager& m; + model_converter_ref m_mc; + vector m_relation_info; + expr_ref fixup_clauses(expr* property) const; + expr_ref fixup_clause(expr* clause) const; +public: + inductive_property(ast_manager& m, model_converter_ref& mc, vector const& relations): + m(m), + m_mc(mc), + m_relation_info(relations) {} + + std::string to_string() const; + + expr_ref to_expr() const; + + void to_model(model_ref& md) const; + + void display(datalog::rule_manager& rm, ptr_vector const& rules, std::ostream& out) const; +}; + +class manager { + ast_manager& m; + + mutable bool_rewriter m_brwr; + + sym_mux m_mux; + expr_ref m_background; + decl_vector m_o0_preds; + spacer::smt_context_manager m_contexts; + spacer::smt_context_manager m_contexts2; + spacer::smt_context_manager m_contexts3; + + /** whenever we need an unique number, we get this one and increase */ + unsigned m_next_unique_num; + + + static std::vector get_state_suffixes(); + + unsigned n_index() const { return 0; } + unsigned o_index(unsigned i) const { return i + 1; } + + void add_new_state(func_decl * s); + +public: + manager(unsigned max_num_contexts, ast_manager & manager); + + ast_manager& get_manager() const { return m; } + bool_rewriter& get_brwr() const { return m_brwr; } + + expr_ref mk_and(unsigned sz, expr* const* exprs); + expr_ref mk_and(expr_ref_vector const& exprs) + { + return mk_and(exprs.size(), exprs.c_ptr()); + } + expr_ref mk_and(expr* a, expr* b) + { + expr* args[2] = { a, b }; + return mk_and(2, args); + } + expr_ref mk_or(unsigned sz, expr* const* exprs); + expr_ref mk_or(expr_ref_vector const& exprs) + { + return mk_or(exprs.size(), exprs.c_ptr()); + } + + expr_ref mk_not_and(expr_ref_vector const& exprs); + + void get_or(expr* e, expr_ref_vector& result); + + //"o" predicates stand for the old states and "n" for the new states + func_decl * get_o_pred(func_decl * s, unsigned idx); + func_decl * get_n_pred(func_decl * s); + + /** + Marks symbol as non-model which means it will not appear in models collected by + get_state_cube_from_model function. + This is to take care of auxiliary symbols introduced by the disjunction relations + to relativize lemmas coming from disjuncts. + */ + void mark_as_non_model(func_decl * p) + { + m_mux.mark_as_non_model(p); + } + + + func_decl * const * begin_o0_preds() const { return m_o0_preds.begin(); } + func_decl * const * end_o0_preds() const { return m_o0_preds.end(); } + + bool is_state_pred(func_decl * p) const { return m_mux.is_muxed(p); } + func_decl * to_o0(func_decl * p) { return m_mux.conv(m_mux.get_primary(p), 0, o_index(0)); } + + bool is_o(func_decl * p, unsigned idx) const + { + return m_mux.has_index(p, o_index(idx)); + } + void get_o_index(func_decl* p, unsigned& idx) const + { + m_mux.try_get_index(p, idx); + SASSERT(idx != n_index()); + idx--; // m_mux has indices starting at 1 + } + bool is_o(expr* e, unsigned idx) const + { + return is_app(e) && is_o(to_app(e)->get_decl(), idx); + } + bool is_o(func_decl * p) const + { + unsigned idx; + return m_mux.try_get_index(p, idx) && idx != n_index(); + } + bool is_o(expr* e) const + { + return is_app(e) && is_o(to_app(e)->get_decl()); + } + bool is_n(func_decl * p) const + { + return m_mux.has_index(p, n_index()); + } + bool is_n(expr* e) const + { + return is_app(e) && is_n(to_app(e)->get_decl()); + } + + /** true if p should not appead in models propagates into child relations */ + bool is_non_model_sym(func_decl * p) const + { return m_mux.is_non_model_sym(p); } + + + /** true if f doesn't contain any n predicates */ + bool is_o_formula(expr * f) const + { + return !m_mux.contains(f, n_index()); + } + + /** true if f contains only o state preds of index o_idx */ + bool is_o_formula(expr * f, unsigned o_idx) const + { + return m_mux.is_homogenous_formula(f, o_index(o_idx)); + } + /** true if f doesn't contain any o predicates */ + bool is_n_formula(expr * f) const + { + return m_mux.is_homogenous_formula(f, n_index()); + } + + func_decl * o2n(func_decl * p, unsigned o_idx) const + { + return m_mux.conv(p, o_index(o_idx), n_index()); + } + func_decl * o2o(func_decl * p, unsigned src_idx, unsigned tgt_idx) const + { + return m_mux.conv(p, o_index(src_idx), o_index(tgt_idx)); + } + func_decl * n2o(func_decl * p, unsigned o_idx) const + { + return m_mux.conv(p, n_index(), o_index(o_idx)); + } + + void formula_o2n(expr * f, expr_ref & result, unsigned o_idx, bool homogenous = true) const + { m_mux.conv_formula(f, o_index(o_idx), n_index(), result, homogenous); } + + void formula_n2o(expr * f, expr_ref & result, unsigned o_idx, bool homogenous = true) const + { m_mux.conv_formula(f, n_index(), o_index(o_idx), result, homogenous); } + + void formula_n2o(unsigned o_idx, bool homogenous, expr_ref & result) const + { m_mux.conv_formula(result.get(), n_index(), o_index(o_idx), result, homogenous); } + + void formula_o2o(expr * src, expr_ref & tgt, unsigned src_idx, unsigned tgt_idx, bool homogenous = true) const + { m_mux.conv_formula(src, o_index(src_idx), o_index(tgt_idx), tgt, homogenous); } + + /** + Return true if all state symbols which e contains are of one kind (either "n" or one of "o"). + */ + bool is_homogenous_formula(expr * e) const + { + return m_mux.is_homogenous_formula(e); + } + + /** + Collect indices used in expression. + */ + void collect_indices(expr* e, unsigned_vector& indices) const + { + m_mux.collect_indices(e, indices); + } + + /** + Collect used variables of each index. + */ + void collect_variables(expr* e, vector >& vars) const + { + m_mux.collect_variables(e, vars); + } + + /** + Return true iff both s1 and s2 are either "n" or "o" of the same index. + If one (or both) of them are not state symbol, return false. + */ + bool have_different_state_kinds(func_decl * s1, func_decl * s2) const + { + unsigned i1, i2; + return m_mux.try_get_index(s1, i1) && m_mux.try_get_index(s2, i2) && i1 != i2; + } + + /** + Increase indexes of state symbols in formula by dist. + The 'N' index becomes 'O' index with number dist-1. + */ + void formula_shift(expr * src, expr_ref & tgt, unsigned dist) const + { + SASSERT(n_index() == 0); + SASSERT(o_index(0) == 1); + m_mux.shift_formula(src, dist, tgt); + } + + void mk_model_into_cube(const expr_ref_vector & mdl, expr_ref & res); + void mk_core_into_cube(const expr_ref_vector & core, expr_ref & res); + void mk_cube_into_lemma(expr * cube, expr_ref & res); + void mk_lemma_into_cube(expr * lemma, expr_ref & res); + + /** + Remove from vec all atoms that do not have an "o" state. + The order of elements in vec may change. + An assumption is that atoms having "o" state of given index + do not have "o" states of other indexes or "n" states. + */ + void filter_o_atoms(expr_ref_vector& vec, unsigned o_idx) const + { m_mux.filter_idx(vec, o_index(o_idx)); } + void filter_n_atoms(expr_ref_vector& vec) const + { m_mux.filter_idx(vec, n_index()); } + + /** + Partition literals into o_lits and others. + */ + void partition_o_atoms(expr_ref_vector const& lits, + expr_ref_vector& o_lits, + expr_ref_vector& other, + unsigned o_idx) const + { + m_mux.partition_o_idx(lits, o_lits, other, o_index(o_idx)); + } + + void filter_out_non_model_atoms(expr_ref_vector& vec) const + { m_mux.filter_non_model_lits(vec); } + + bool try_get_state_and_value_from_atom(expr * atom, app *& state, app_ref& value); + bool try_get_state_decl_from_atom(expr * atom, func_decl *& state); + + + std::string pp_model(const model_core & mdl) const + { return m_mux.pp_model(mdl); } + + + void set_background(expr* b) { m_background = b; } + + expr* get_background() const { return m_background; } + + unsigned get_unique_num() { return m_next_unique_num++; } + + solver* mk_fresh() {return m_contexts.mk_fresh();} + smt_params& fparams() { return m_contexts.fparams(); } + solver* mk_fresh2() {return m_contexts2.mk_fresh();} + smt_params &fparams2() { return m_contexts2.fparams(); } + solver* mk_fresh3() {return m_contexts3.mk_fresh();} + smt_params &fparams3() {return m_contexts3.fparams();} + + + + void collect_statistics(statistics& st) const + { + m_contexts.collect_statistics(st); + m_contexts2.collect_statistics(st); + m_contexts3.collect_statistics(st); + } + + void reset_statistics() + { + m_contexts.reset_statistics(); + m_contexts2.reset_statistics(); + m_contexts3.reset_statistics(); + } +}; + +app* mk_zk_const (ast_manager &m, unsigned idx, sort *s); +void find_zk_const(expr* e, app_ref_vector &out); +bool has_zk_const(expr* e); +} + +#endif diff --git a/src/muz/spacer/spacer_matrix.cpp b/src/muz/spacer/spacer_matrix.cpp new file mode 100644 index 000000000..3cc83996c --- /dev/null +++ b/src/muz/spacer/spacer_matrix.cpp @@ -0,0 +1,159 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_matrix.cpp + +Abstract: + a matrix + +Author: + Bernhard Gleiss + +Revision History: + + +--*/ +#include "muz/spacer/spacer_matrix.h" + +namespace spacer +{ + spacer_matrix::spacer_matrix(unsigned m, unsigned n) : m_num_rows(m), m_num_cols(n) + { + for (unsigned i=0; i < m; ++i) + { + vector v; + for (unsigned j=0; j < n; ++j) + { + v.push_back(rational(0)); + } + m_matrix.push_back(v); + } + } + + unsigned spacer_matrix::num_rows() + { + return m_num_rows; + } + + unsigned spacer_matrix::num_cols() + { + return m_num_cols; + } + + rational spacer_matrix::get(unsigned int i, unsigned int j) + { + SASSERT(i < m_num_rows); + SASSERT(j < m_num_cols); + + return m_matrix[i][j]; + } + + void spacer_matrix::set(unsigned int i, unsigned int j, rational v) + { + SASSERT(i < m_num_rows); + SASSERT(j < m_num_cols); + + m_matrix[i][j] = v; + } + + unsigned spacer_matrix::perform_gaussian_elimination() + { + unsigned i=0; + unsigned j=0; + while(i < m_matrix.size() && j < m_matrix[0].size()) + { + // find maximal element in column with row index bigger or equal i + rational max = m_matrix[i][j]; + unsigned max_index = i; + + for (unsigned k=i+1; k < m_matrix.size(); ++k) + { + if (max < m_matrix[k][j]) + { + max = m_matrix[k][j]; + max_index = k; + } + } + + if (max.is_zero()) // skip this column + { + ++j; + } + else + { + // reorder rows if necessary + vector tmp = m_matrix[i]; + m_matrix[i] = m_matrix[max_index]; + m_matrix[max_index] = m_matrix[i]; + + // normalize row + rational pivot = m_matrix[i][j]; + if (!pivot.is_one()) + { + for (unsigned k=0; k < m_matrix[i].size(); ++k) + { + m_matrix[i][k] = m_matrix[i][k] / pivot; + } + } + + // subtract row from all other rows + for (unsigned k=1; k < m_matrix.size(); ++k) + { + if (k != i) + { + rational factor = m_matrix[k][j]; + for (unsigned l=0; l < m_matrix[k].size(); ++l) + { + m_matrix[k][l] = m_matrix[k][l] - (factor * m_matrix[i][l]); + } + } + } + + ++i; + ++j; + } + } + + if (get_verbosity_level() >= 1) + { + SASSERT(m_matrix.size() > 0); + } + + return i; //i points to the row after the last row which is non-zero + } + + void spacer_matrix::print_matrix() + { + verbose_stream() << "\nMatrix\n"; + for (const auto& row : m_matrix) + { + for (const auto& element : row) + { + verbose_stream() << element << ", "; + } + verbose_stream() << "\n"; + } + verbose_stream() << "\n"; + } + void spacer_matrix::normalize() + { + rational den = rational::one(); + for (unsigned i=0; i < m_num_rows; ++i) + { + for (unsigned j=0; j < m_num_cols; ++j) + { + den = lcm(den, denominator(m_matrix[i][j])); + } + } + for (unsigned i=0; i < m_num_rows; ++i) + { + for (unsigned j=0; j < m_num_cols; ++j) + { + m_matrix[i][j] = den * m_matrix[i][j]; + SASSERT(m_matrix[i][j].is_int()); + } + } + } +} diff --git a/src/muz/spacer/spacer_matrix.h b/src/muz/spacer/spacer_matrix.h new file mode 100644 index 000000000..4fc418f2b --- /dev/null +++ b/src/muz/spacer/spacer_matrix.h @@ -0,0 +1,47 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_matrix.h + +Abstract: + a matrix + +Author: + Bernhard Gleiss + +Revision History: + + +--*/ +#ifndef _SPACER_MATRIX_H_ +#define _SPACER_MATRIX_H_ + +#include "util/rational.h" +#include "util/vector.h" + +namespace spacer { + + class spacer_matrix { + public: + spacer_matrix(unsigned m, unsigned n); // m rows, n colums + + unsigned num_rows(); + unsigned num_cols(); + + rational get(unsigned i, unsigned j); + void set(unsigned i, unsigned j, rational v); + + unsigned perform_gaussian_elimination(); + + void print_matrix(); + void normalize(); + private: + unsigned m_num_rows; + unsigned m_num_cols; + vector> m_matrix; + }; +} + +#endif diff --git a/src/muz/spacer/spacer_mev_array.cpp b/src/muz/spacer/spacer_mev_array.cpp new file mode 100644 index 000000000..7a4bc321b --- /dev/null +++ b/src/muz/spacer/spacer_mev_array.cpp @@ -0,0 +1,217 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + model_mev_array.cpp + +Abstract: + + Evaluate array expressions in a given model. + +Author: + +Revision History: + +--*/ +#include"model/model.h" +#include "model/model_evaluator_params.hpp" +#include"ast/rewriter/rewriter_types.h" +#include"model/model_evaluator.h" +#include"muz/spacer/spacer_mev_array.h" +#include"ast/rewriter/bool_rewriter.h" +#include"ast/rewriter/arith_rewriter.h" +#include"ast/rewriter/bv_rewriter.h" +#include"ast/rewriter/datatype_rewriter.h" +#include"ast/rewriter/array_rewriter.h" +#include"ast/rewriter/rewriter_def.h" +#include"util/cooperate.h" +#include"ast/ast_pp.h" +#include"model/func_interp.h" + + + +// model_evaluator_array_util + + +void model_evaluator_array_util::eval_exprs(model& mdl, expr_ref_vector& es) { + for (unsigned j = 0; j < es.size(); ++j) { + if (m_array.is_as_array(es.get (j))) { + expr_ref r (m); + eval(mdl, es.get (j), r); + es.set (j, r); + } + } +} + +bool model_evaluator_array_util::extract_array_func_interp(model& mdl, expr* a, vector& stores, expr_ref& else_case) { + SASSERT(m_array.is_array(a)); + + TRACE("model_evaluator", tout << mk_pp(a, m) << "\n";); + while (m_array.is_store(a)) { + expr_ref_vector store(m); + store.append(to_app(a)->get_num_args()-1, to_app(a)->get_args()+1); + eval_exprs(mdl, store); + stores.push_back(store); + a = to_app(a)->get_arg(0); + } + + if (m_array.is_const(a)) { + else_case = to_app(a)->get_arg(0); + return true; + } + + while (m_array.is_as_array(a)) { + func_decl* f = m_array.get_as_array_func_decl(to_app(a)); + func_interp* g = mdl.get_func_interp(f); + unsigned sz = g->num_entries(); + unsigned arity = f->get_arity(); + for (unsigned i = 0; i < sz; ++i) { + expr_ref_vector store(m); + func_entry const* fe = g->get_entry(i); + store.append(arity, fe->get_args()); + store.push_back(fe->get_result()); + for (unsigned j = 0; j < store.size(); ++j) { + if (!is_ground(store[j].get())) { + TRACE("model_evaluator", tout << "could not extract array interpretation: " << mk_pp(a, m) << "\n" << mk_pp(store[j].get(), m) << "\n";); + return false; + } + } + eval_exprs(mdl, store); + stores.push_back(store); + } + else_case = g->get_else(); + if (!else_case) { + TRACE("model_evaluator", tout << "no else case " << mk_pp(a, m) << "\n";); + return false; + } + if (!is_ground(else_case)) { + TRACE("model_evaluator", tout << "non-ground else case " << mk_pp(a, m) << "\n" << mk_pp(else_case, m) << "\n";); + return false; + } + if (m_array.is_as_array(else_case)) { + expr_ref r (m); + eval(mdl, else_case, r); + else_case = r; + } + TRACE("model_evaluator", tout << "else case: " << mk_pp(else_case, m) << "\n";); + return true; + } + TRACE("model_evaluator", tout << "no translation: " << mk_pp(a, m) << "\n";); + + return false; +} + +void model_evaluator_array_util::eval_array_eq(model& mdl, app* e, expr* arg1, expr* arg2, expr_ref& res) { + TRACE("model_evaluator", tout << "array equality: " << mk_pp(e, m) << "\n";); + expr_ref v1(m), v2(m); + eval (mdl, arg1, v1); + eval (mdl, arg2, v2); + if (v1 == v2) { + res = m.mk_true (); + return; + } + sort* s = m.get_sort(arg1); + sort* r = get_array_range(s); + // give up evaluating finite domain/range arrays + if (!r->is_infinite() && !r->is_very_big() && !s->is_infinite() && !s->is_very_big()) { + TRACE("model_evaluator", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); + res.reset (); + return; + } + vector store; + expr_ref else1(m), else2(m); + if (!extract_array_func_interp(mdl, v1, store, else1) || + !extract_array_func_interp(mdl, v2, store, else2)) { + TRACE("model_evaluator", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); + res.reset (); + return; + } + + if (else1 != else2) { + if (m.is_value(else1) && m.is_value(else2)) { + TRACE("model_evaluator", tout + << "defaults are different: " << mk_pp(e, m) << " " + << mk_pp(else1, m) << " " << mk_pp(else2, m) << "\n";); + res = m.mk_false (); + } + else if (m_array.is_array(else1)) { + eval_array_eq(mdl, e, else1, else2, res); + } + else { + TRACE("model_evaluator", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); + res.reset (); + } + return; + } + + expr_ref s1(m), s2(m), w1(m), w2(m); + expr_ref_vector args1(m), args2(m); + args1.push_back(v1); + args2.push_back(v2); + for (unsigned i = 0; i < store.size(); ++i) { + args1.resize(1); + args2.resize(1); + args1.append(store[i].size()-1, store[i].c_ptr()); + args2.append(store[i].size()-1, store[i].c_ptr()); + s1 = m_array.mk_select(args1.size(), args1.c_ptr()); + s2 = m_array.mk_select(args2.size(), args2.c_ptr()); + eval (mdl, s1, w1); + eval (mdl, s2, w2); + if (w1 == w2) { + continue; + } + if (m.is_value(w1) && m.is_value(w2)) { + TRACE("model_evaluator", tout << "Equality evaluation: " << mk_pp(e, m) << "\n"; + tout << mk_pp(s1, m) << " |-> " << mk_pp(w1, m) << "\n"; + tout << mk_pp(s2, m) << " |-> " << mk_pp(w2, m) << "\n";); + res = m.mk_false (); + } + else if (m_array.is_array(w1)) { + eval_array_eq(mdl, e, w1, w2, res); + if (m.is_true (res)) { + continue; + } + } + else { + TRACE("model_evaluator", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); + res.reset (); + } + return; + } + res = m.mk_true (); +} + +void model_evaluator_array_util::eval(model& mdl, expr* e, expr_ref& r, bool model_completion) { + model_evaluator mev (mdl); + mev.set_model_completion (model_completion); + bool eval_result = true; + try { + mev (e, r); + } + catch (model_evaluator_exception &) { + eval_result = false; + } + VERIFY(eval_result); + + if (m_array.is_array(e)) { + vector stores; + expr_ref_vector args(m); + expr_ref else_case(m); + if (extract_array_func_interp(mdl, r, stores, else_case)) { + r = m_array.mk_const_array(m.get_sort(e), else_case); + while (!stores.empty() && stores.back().back() == else_case) { + stores.pop_back(); + } + for (unsigned i = stores.size(); i > 0; ) { + --i; + args.resize(1); + args[0] = r; + args.append(stores[i]); + r = m_array.mk_store(args.size(), args.c_ptr()); + } + return; + } + } + return; +} diff --git a/src/muz/spacer/spacer_mev_array.h b/src/muz/spacer/spacer_mev_array.h new file mode 100644 index 000000000..078925865 --- /dev/null +++ b/src/muz/spacer/spacer_mev_array.h @@ -0,0 +1,52 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + spacer_mev_array.h + +Abstract: + + Utilities to evaluate arrays in the model. + +Author: + based on model_evaluator in muz/pdr/pdr_util.h + +Revision History: + +--*/ +#ifndef _SPACER_MEV_ARRAY_H_ +#define _SPACER_MEV_ARRAY_H_ + +#include"ast/ast.h" +#include"ast/rewriter/rewriter_types.h" +#include"util/params.h" +#include"ast/array_decl_plugin.h" + +/** + * based on model_evaluator in muz/pdr/pdr_util.h + */ +class model_evaluator_array_util { + ast_manager& m; + array_util m_array; + + void eval_exprs(model& mdl, expr_ref_vector& es); + + bool extract_array_func_interp(model& mdl, expr* a, vector& stores, expr_ref& else_case); + +public: + + model_evaluator_array_util (ast_manager& m): + m (m), + m_array (m) + {} + + /** + * best effort evaluator of extensional array equality. + */ + void eval_array_eq(model& mdl, app* e, expr* arg1, expr* arg2, expr_ref& res); + + void eval(model& mdl, expr* e, expr_ref& r, bool model_completion = true); +}; + +#endif diff --git a/src/muz/spacer/spacer_notes.txt b/src/muz/spacer/spacer_notes.txt new file mode 100644 index 000000000..4211bc1ce --- /dev/null +++ b/src/muz/spacer/spacer_notes.txt @@ -0,0 +1,231 @@ +a queue contains a model_node + +let n = leaves.pop_top () + +if (!n.has_derivation ()) + + if n.pt ().must_reach (n.post ()) + add parent of n to the leaves + return + + check abstract reachability of n + + if must reachable then + create new reachability fact for n.pt () + add parent of n to the leaves + else if may reachable then + create derivation d for n + create model_node kid for the top of d + add kid to the leaves + + else /* unreachable */ + create a lemma for n.pt () + p = parent of n + p.reset_derivation() + add p to the leaves + +else if (n.has_derivation ()) + + create next model_node kid for n.get_derivation () + + if (kid != NULL) + add kid to leaves + else /* done with the derivation, no more kids */ + // the derivation is reachable, otherwise it was reset in another branch + p = parent of n + p.reset_derivation () + add p to the leaves + + +================================================================================= +create derivation for the top of d +input: + model M, + transition relation formula trans with auxiliary variables quantified out + sequence of pedicates P_i, + may and must summaries of P_i +================================================================================= + +create first derivation child: + input: model + + +create next derivation child: + create new model + update trans by computing pre-image over new reachability facts + call create next derivation child + +private: +create next derivation child using a given model, and starting index + +========================================================= + +create a next model for a derivation + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +// an obligation +model_node + // NULL means root + model_node_ref parent + model_node_ref_vector kids + + pred_transformer &predicate + expr* condition + unsigned level + unsigned depth + // monotonically increasing + unsigned id + + bool open; + + +model_node::close () + open = false + for k : kids do k.close () + +model_search + + model_node_ref root; + + // proof obligations + priority_queue m_obligations; + model_node_ref m_last_reachable; + + +bool model_node::operator< (model_node& other) + lexicographic order based on + level<, depth<, id> + + + +assert (!m_last_reachable); +while (!m_obligations.empty ()) +{ + // propagate reachability as much as possible + while (m_last_reachable) + { + obl = m_last_reachable + m_last_reachable.reset (); + if (is_root (obl)) return true; + if (discharge_obligation (obl.get_parent ()) == l_true) + m_last_reachable = obl.get_parent (); + } + + // at least one obligation is not closed, ow root was reachable + while (m_obligations.top ().is_closed ()) m_obligations.pop (); + assert (!m_obligations.empty ()); + + // process an obligation + assert (!m_last_reachable) + obl = m_obligations.top (); + switch (discharge_obligation (obl)) + { + case l_true: + // if reachable, schedule a reachability round + m_last_reachable = m_obligations.top (); + m_obligations.pop (); + break; + case l_false: + // if unreachable removed from the queue + m_obligations.pop (); + /// bump level + obl.inc_level (); + /// optionally insert back into the queue + if (is_active (obl)) m_obligations.push (obl); + break; + default: + assert (m_obligations.top () != obl); + } +} +return false + +/// with priority queue +bool is_active (model_node obl) { return level <= m_search.max_level (); } +/// with out priority queue. Discharged obligations are dropped +bool is_active (model_node obl) { return false; } + +discharge_obligation (model_node obl) +{ + assert (!obl.is_closed ()); + switch (check_reachability (obl)) + { + case l_true: + obl.close () + update reachability facts + return l_true; + case l_false: + update lemmas + return l_false + case l_unknown: + create children + populate m_obligations queue + return l_unknown + } +} + + +============================================================= + +a node keeps a derivation object + +if a node is sat, a new node is constructed and inherits the derivation object +if a node is sat and the derivation is done, this is reported to the parent + +expand_node(n): + process node ignoring derivation + if sat: + if concrete: + if has derivation and has next child + close current node and push new node + return l_undef + else + return l_true + else + create_child (creates a new node and optionally sets derivation) + else if unsat + generate lemmas + derivation remains unchanged to be used at a higher level + return +====================================================================== +1. open disjunction for transition relation + - a fresh literal to open the disjunction of the transition relation + - expr* expand_init (expr *e) -- add e to initial state and return + new disj var + - close the disjunction by passing the negation of the literal + during various calls + - store the literal negated to have access to both positive and + negative versions + - with this, can do an optional check whether the lemmas alone are + strong enough to discharge the counterexample. Easiest is to + implement it as a separate pre-check. + +2. auxiliary variables in lemmas and reach-facts. + - store and expect auxiliary variables + - quantify them out when necessary + +3. initial rules as reach-facts + - add initial rules of a predicate to its reach-facts. Propagate them to uses. + - this way, the checks at level 0 will include initial rules of + immediate predecessors +====================================================================== + +reach_fact_ref_vector m_reach_facts +app_ref_vector m_reach_case_vars + +bool is_must_reachable (expr *state, model_ref *model) +reach_fact* get_used_reach_fact (model_evaluator &mev) +app* mk_fresh_reach_case_var () +expr* get_reach () +expr* get_last_reach_case_var () +app* get_reach_case_var (unsigned idx) + +get_used_origin_reach_fact(): + + +====================================================================== +4. track relationship between an obligation and lemmas. Attempt to + generalize an obligation into the exact lemma that worked + before. Perhaps pick one lemma with highest level? Implement as + core-generalizer. Will require reworking how legacy_frames is implemented. diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp new file mode 100644 index 000000000..19c5c3aa3 --- /dev/null +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -0,0 +1,302 @@ +/** +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_prop_solver.cpp + +Abstract: + + SAT solver abstraction for SPACER. + +Author: + + Arie Gurfinkel + Anvesh Komuravelli + +Revision History: + +--*/ + +#include "ast/ast_smt2_pp.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/bv_decl_plugin.h" + +#include "ast/rewriter/expr_replacer.h" + +#include "smt/params/smt_params.h" + +#include "model/model.h" +#include "model/model_pp.h" + +#include "muz/base/dl_util.h" + +#include "muz/spacer/spacer_util.h" +#include "muz/spacer/spacer_farkas_learner.h" +#include "muz/spacer/spacer_prop_solver.h" + +#include "muz/base/fixedpoint_params.hpp" + +namespace spacer { + +prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& name) : + m(pm.get_manager()), + m_pm(pm), + m_name(name), + m_ctx(NULL), + m_pos_level_atoms(m), + m_neg_level_atoms(m), + m_core(0), + m_subset_based_core(false), + m_uses_level(infty_level()), + m_delta_level(false), + m_in_level(false), + m_use_push_bg(p.spacer_keep_proxy()) +{ + + m_solvers[0] = pm.mk_fresh(); + m_fparams[0] = &pm.fparams(); + + m_solvers[1] = pm.mk_fresh2(); + m_fparams[1] = &pm.fparams2(); + + m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_new_unsat_core(), p.spacer_minimize_unsat_core(), p.spacer_farkas_optimized(), p.spacer_farkas_a_const(), p.spacer_split_farkas_literals()); + m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_new_unsat_core(), p.spacer_minimize_unsat_core(), p.spacer_farkas_optimized(), p.spacer_farkas_a_const(), p.spacer_split_farkas_literals()); + + for (unsigned i = 0; i < 2; ++i) + { m_contexts[i]->assert_expr(m_pm.get_background()); } +} + +void prop_solver::add_level() +{ + unsigned idx = level_cnt(); + std::stringstream name; + name << m_name << "#level_" << idx; + func_decl * lev_pred = m.mk_fresh_func_decl(name.str().c_str(), 0, 0, m.mk_bool_sort()); + m_level_preds.push_back(lev_pred); + + app_ref pos_la(m.mk_const(lev_pred), m); + app_ref neg_la(m.mk_not(pos_la.get()), m); + + m_pos_level_atoms.push_back(pos_la); + m_neg_level_atoms.push_back(neg_la); + + m_level_atoms_set.insert(pos_la.get()); + m_level_atoms_set.insert(neg_la.get()); +} + +void prop_solver::ensure_level(unsigned lvl) +{ + while (lvl >= level_cnt()) { + add_level(); + } +} + +unsigned prop_solver::level_cnt() const +{ + return m_level_preds.size(); +} + +void prop_solver::assert_level_atoms(unsigned level) +{ + unsigned lev_cnt = level_cnt(); + for (unsigned i = 0; i < lev_cnt; i++) { + bool active = m_delta_level ? i == level : i >= level; + app * lev_atom = + active ? m_neg_level_atoms.get(i) : m_pos_level_atoms.get(i); + m_ctx->push_bg(lev_atom); + } +} + +void prop_solver::assert_expr(expr * form) +{ + SASSERT(!m_in_level); + m_contexts[0]->assert_expr(form); + m_contexts[1]->assert_expr(form); + IF_VERBOSE(21, verbose_stream() << "$ asserted " << mk_pp(form, m) << "\n";); + TRACE("spacer", tout << "add_formula: " << mk_pp(form, m) << "\n";); +} + +void prop_solver::assert_expr(expr * form, unsigned level) +{ + ensure_level(level); + app * lev_atom = m_pos_level_atoms[level].get(); + app_ref lform(m.mk_or(form, lev_atom), m); + assert_expr(lform); +} + + +/// Poor man's maxsat. No guarantees of maximum solution +/// Runs maxsat loop on m_ctx Returns l_false if hard is unsat, +/// otherwise reduces soft such that hard & soft is sat. +lbool prop_solver::maxsmt(expr_ref_vector &hard, expr_ref_vector &soft) +{ + // replace expressions by assumption literals + itp_solver::scoped_mk_proxy _p_(*m_ctx, hard); + unsigned hard_sz = hard.size(); + // assume soft constraints are propositional literals (no need to proxy) + hard.append(soft); + + lbool res = m_ctx->check_sat(hard.size(), hard.c_ptr()); + // if hard constraints alone are unsat or there are no soft + // constraints, we are done + if (res != l_false || soft.empty()) { return res; } + + // clear soft constraints, we will recompute them later + soft.reset(); + + expr_ref saved(m); + ptr_vector core; + m_ctx->get_unsat_core(core); + + // while there are soft constraints + while (hard.size() > hard_sz) { + bool found = false; + // look for a soft constraint that is in the unsat core + for (unsigned i = hard_sz, sz = hard.size(); i < sz; ++i) + if (core.contains(hard.get(i))) { + found = true; + // AG: not sure why we are saving it + saved = hard.get(i); + hard[i] = hard.back(); + hard.pop_back(); + break; + } + // if no soft constraints in the core, return this should + // not happen because it implies that hard alone is unsat + // and that is taken care of earlier + if (!found) { + hard.resize(hard_sz); + return l_false; + } + + // check that the NEW constraints became sat + res = m_ctx->check_sat(hard.size(), hard.c_ptr()); + if (res != l_false) { break; } + // still unsat, update the core and repeat + core.reset(); + m_ctx->get_unsat_core(core); + } + + // update soft with found soft constraints + if (res == l_true) { + for (unsigned i = hard_sz, sz = hard.size(); i < sz; ++i) + { soft.push_back(hard.get(i)); } + } + // revert hard back to the right size + // proxies are undone on exit via scoped_mk_proxy + hard.resize(hard_sz); + return res; +} + +lbool prop_solver::internal_check_assumptions( + expr_ref_vector& hard_atoms, + expr_ref_vector& soft_atoms) +{ + // XXX Turn model generation if m_model != 0 + SASSERT(m_ctx); + SASSERT(m_ctx_fparams); + flet _model(m_ctx_fparams->m_model, m_model != 0); + + if (m_in_level) { assert_level_atoms(m_current_level); } + lbool result = maxsmt(hard_atoms, soft_atoms); + if (result != l_false && m_model) { m_ctx->get_model(*m_model); } + + SASSERT(result != l_false || soft_atoms.empty()); + + /// compute level used in the core + // XXX this is a poor approximation because the core will get minimized further + if (result == l_false) { + ptr_vector core; + m_ctx->get_full_unsat_core(core); + unsigned core_size = core.size(); + m_uses_level = infty_level(); + + for (unsigned i = 0; i < core_size; ++i) { + if (m_level_atoms_set.contains(core[i])) { + unsigned sz = std::min(m_uses_level, m_neg_level_atoms.size()); + for (unsigned j = 0; j < sz; ++j) + if (m_neg_level_atoms [j].get() == core[i]) { + m_uses_level = j; + break; + } + SASSERT(!is_infty_level(m_uses_level)); + } + } + } + + if (result == l_false && m_core && m.proofs_enabled() && !m_subset_based_core) { + TRACE("spacer", tout << "theory core\n";); + m_core->reset(); + m_ctx->get_itp_core(*m_core); + } else if (result == l_false && m_core) { + m_core->reset(); + m_ctx->get_unsat_core(*m_core); + // manually undo proxies because maxsmt() call above manually adds proxies + m_ctx->undo_proxies(*m_core); + } + return result; +} + + + +lbool prop_solver::check_assumptions(const expr_ref_vector & _hard, + expr_ref_vector& soft, + unsigned num_bg, expr * const * bg, + unsigned solver_id) +{ + // current clients expect that flattening of HARD is + // done implicitly during check_assumptions + expr_ref_vector hard(m); + hard.append(_hard.size(), _hard.c_ptr()); + flatten_and(hard); + + m_ctx = m_contexts [solver_id == 0 ? 0 : 0 /* 1 */].get(); + m_ctx_fparams = m_fparams [solver_id == 0 ? 0 : 0 /* 1 */]; + + // can be disabled if use_push_bg == true + // solver::scoped_push _s_(*m_ctx); + if (!m_use_push_bg) { m_ctx->push(); } + itp_solver::scoped_bg _b_(*m_ctx); + + for (unsigned i = 0; i < num_bg; ++i) + if (m_use_push_bg) { m_ctx->push_bg(bg [i]); } + else { m_ctx->assert_expr(bg[i]); } + + unsigned soft_sz = soft.size(); + (void) soft_sz; + lbool res = internal_check_assumptions(hard, soft); + if (!m_use_push_bg) { m_ctx->pop(1); } + + TRACE("psolve_verbose", + tout << "sat: " << mk_pp(mk_and(hard), m) << "\n" + << mk_pp(mk_and(soft), m) << "\n"; + for (unsigned i = 0; i < num_bg; ++i) + tout << "bg" << i << ": " << mk_pp(bg[i], m) << "\n"; + tout << "res: " << res << "\n";); + CTRACE("psolve", m_core, + tout << "core is: " << mk_pp(mk_and(*m_core), m) << "\n";); + + SASSERT(soft_sz >= soft.size()); + + // -- reset all parameters + m_core = 0; + m_model = 0; + m_subset_based_core = false; + return res; +} + +void prop_solver::collect_statistics(statistics& st) const +{ + m_contexts[0]->collect_statistics(st); + m_contexts[1]->collect_statistics(st); +} + +void prop_solver::reset_statistics() +{ +} + + + + +} diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h new file mode 100644 index 000000000..1ddec91c6 --- /dev/null +++ b/src/muz/spacer/spacer_prop_solver.h @@ -0,0 +1,144 @@ +/** +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_prop_solver.h + +Abstract: + + SAT solver abstraction for SPACER. + +Author: + + Arie Gurfinkel + +Revision History: + +--*/ + +#ifndef _PROP_SOLVER_H_ +#define _PROP_SOLVER_H_ + +#include +#include +#include + +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "smt/smt_kernel.h" +#include "util/util.h" +#include "util/vector.h" +#include "muz/spacer/spacer_manager.h" +#include "muz/spacer/spacer_smt_context_manager.h" +#include "muz/spacer/spacer_itp_solver.h" + +struct fixedpoint_params; + +namespace spacer { + +class prop_solver { + +private: + ast_manager& m; + manager& m_pm; + symbol m_name; + smt_params* m_fparams[2]; + solver* m_solvers[2]; + scoped_ptr m_contexts[2]; + itp_solver * m_ctx; + smt_params * m_ctx_fparams; + decl_vector m_level_preds; + app_ref_vector m_pos_level_atoms; // atoms used to identify level + app_ref_vector m_neg_level_atoms; // + obj_hashtable m_level_atoms_set; + expr_ref_vector* m_core; + model_ref* m_model; + bool m_subset_based_core; + unsigned m_uses_level; + /// if true sets the solver into a delta level, enabling only + /// atoms explicitly asserted in m_current_level + bool m_delta_level; + bool m_in_level; + bool m_use_push_bg; + unsigned m_current_level; // set when m_in_level + + void assert_level_atoms(unsigned level); + + void ensure_level(unsigned lvl); + + lbool internal_check_assumptions(expr_ref_vector &hard, + expr_ref_vector &soft); + + lbool maxsmt(expr_ref_vector &hard, expr_ref_vector &soft); + + +public: + prop_solver(spacer::manager& pm, fixedpoint_params const& p, symbol const& name); + + + void set_core(expr_ref_vector* core) { m_core = core; } + void set_model(model_ref* mdl) { m_model = mdl; } + void set_subset_based_core(bool f) { m_subset_based_core = f; } + bool assumes_level() const { return !is_infty_level(m_uses_level); } + unsigned uses_level() const {return m_uses_level;} + + + void add_level(); + unsigned level_cnt() const; + + + void assert_expr(expr * form); + void assert_expr(expr * form, unsigned level); + + /** + * check assumptions with a background formula + */ + lbool check_assumptions(const expr_ref_vector & hard, + expr_ref_vector & soft, + unsigned num_bg = 0, + expr * const *bg = NULL, + unsigned solver_id = 0); + + void collect_statistics(statistics& st) const; + void reset_statistics(); + + class scoped_level { + bool& m_lev; + public: + scoped_level(prop_solver& ps, unsigned lvl): m_lev(ps.m_in_level) + { + SASSERT(!m_lev); + m_lev = true; + ps.m_current_level = lvl; + } + ~scoped_level() { m_lev = false; } + }; + + class scoped_subset_core { + prop_solver &m_ps; + bool m_subset_based_core; + + public: + scoped_subset_core(prop_solver &ps, bool subset_core) : + m_ps(ps), m_subset_based_core(ps.m_subset_based_core) + {m_ps.set_subset_based_core(subset_core);} + + ~scoped_subset_core() + {m_ps.set_subset_based_core(m_subset_based_core);} + }; + + class scoped_delta_level : public scoped_level { + bool &m_delta; + public: + scoped_delta_level(prop_solver &ps, unsigned lvl) : + scoped_level(ps, lvl), m_delta(ps.m_delta_level) {m_delta = true;} + ~scoped_delta_level() {m_delta = false;} + }; + + +}; +} + + +#endif diff --git a/src/muz/spacer/spacer_qe_project.cpp b/src/muz/spacer/spacer_qe_project.cpp new file mode 100644 index 000000000..9f4f4e4fe --- /dev/null +++ b/src/muz/spacer/spacer_qe_project.cpp @@ -0,0 +1,2338 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation and Arie Gurfinkel + +Module Name: + + spacer_qe_project.cpp + +Abstract: + + Simple projection function for real arithmetic based on Loos-W. + Projection functions for arrays based on MBP + +Author: + + Nikolaj Bjorner (nbjorner) 2013-09-12 + Anvesh Komuravelli + Arie Gurfinkel + +Revision History: + + +--*/ + +#include "ast/arith_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/expr_functors.h" +#include "ast/expr_substitution.h" +#include "ast/ast_util.h" + +#include "ast/rewriter/expr_replacer.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/rewriter/th_rewriter.h" + +#include "model/model_evaluator.h" +#include "model/model_pp.h" + +#include "qe/qe.h" +#include "qe/qe_vartest.h" +#include "qe/qe_lite.h" + +#include "muz/spacer/spacer_mev_array.h" +#include "muz/spacer/spacer_qe_project.h" + +namespace +{ +bool is_partial_eq (app* a); + +/** + * \brief utility class for partial equalities + * + * A partial equality (a ==I b), for two arrays a,b and a finite set of indices I holds + * iff (Forall i. i \not\in I => a[i] == b[i]); in other words, it is a + * restricted form of the extensionality axiom + * + * using this class, we denote (a =I b) as f(a,b,i0,i1,...) + * where f is an uninterpreted predicate with name PARTIAL_EQ and + * I = {i0,i1,...} + */ +class peq { + ast_manager& m; + expr_ref m_lhs; + expr_ref m_rhs; + unsigned m_num_indices; + expr_ref_vector m_diff_indices; + func_decl_ref m_decl; // the partial equality declaration + app_ref m_peq; // partial equality application + app_ref m_eq; // equivalent std equality using def. of partial eq + array_util m_arr_u; + +public: + static const char* PARTIAL_EQ; + + peq (app* p, ast_manager& m); + + peq (expr* lhs, expr* rhs, unsigned num_indices, expr * const * diff_indices, ast_manager& m); + + void lhs (expr_ref& result); + + void rhs (expr_ref& result); + + void get_diff_indices (expr_ref_vector& result); + + void mk_peq (app_ref& result); + + void mk_eq (app_ref_vector& aux_consts, app_ref& result, bool stores_on_rhs = true); +}; + +const char* peq::PARTIAL_EQ = "partial_eq"; + +peq::peq (app* p, ast_manager& m): + m (m), + m_lhs (p->get_arg (0), m), + m_rhs (p->get_arg (1), m), + m_num_indices (p->get_num_args ()-2), + m_diff_indices (m), + m_decl (p->get_decl (), m), + m_peq (p, m), + m_eq (m), + m_arr_u (m) +{ + VERIFY (is_partial_eq (p)); + SASSERT (m_arr_u.is_array (m_lhs) && + m_arr_u.is_array (m_rhs) && + ast_eq_proc() (m.get_sort (m_lhs), m.get_sort (m_rhs))); + for (unsigned i = 2; i < p->get_num_args (); i++) { + m_diff_indices.push_back (p->get_arg (i)); + } +} + +peq::peq (expr* lhs, expr* rhs, unsigned num_indices, expr * const * diff_indices, ast_manager& m): + m (m), + m_lhs (lhs, m), + m_rhs (rhs, m), + m_num_indices (num_indices), + m_diff_indices (m), + m_decl (m), + m_peq (m), + m_eq (m), + m_arr_u (m) +{ + SASSERT (m_arr_u.is_array (lhs) && + m_arr_u.is_array (rhs) && + ast_eq_proc() (m.get_sort (lhs), m.get_sort (rhs))); + ptr_vector sorts; + sorts.push_back (m.get_sort (m_lhs)); + sorts.push_back (m.get_sort (m_rhs)); + for (unsigned i = 0; i < num_indices; i++) { + sorts.push_back (m.get_sort (diff_indices [i])); + m_diff_indices.push_back (diff_indices [i]); + } + m_decl = m.mk_func_decl (symbol (PARTIAL_EQ), sorts.size (), sorts.c_ptr (), m.mk_bool_sort ()); +} + +void peq::lhs (expr_ref& result) { result = m_lhs; } + +void peq::rhs (expr_ref& result) { result = m_rhs; } + +void peq::get_diff_indices (expr_ref_vector& result) { + for (unsigned i = 0; i < m_diff_indices.size (); i++) { + result.push_back (m_diff_indices.get (i)); + } +} + +void peq::mk_peq (app_ref& result) { + if (!m_peq) { + ptr_vector args; + args.push_back (m_lhs); + args.push_back (m_rhs); + for (unsigned i = 0; i < m_num_indices; i++) { + args.push_back (m_diff_indices.get (i)); + } + m_peq = m.mk_app (m_decl, args.size (), args.c_ptr ()); + } + result = m_peq; +} + +void peq::mk_eq (app_ref_vector& aux_consts, app_ref& result, bool stores_on_rhs) { + if (!m_eq) { + expr_ref lhs (m_lhs, m), rhs (m_rhs, m); + if (!stores_on_rhs) { + std::swap (lhs, rhs); + } + // lhs = (...(store (store rhs i0 v0) i1 v1)...) + sort* val_sort = get_array_range (m.get_sort (lhs)); + expr_ref_vector::iterator end = m_diff_indices.end (); + for (expr_ref_vector::iterator it = m_diff_indices.begin (); + it != end; it++) { + app* val = m.mk_fresh_const ("diff", val_sort); + ptr_vector store_args; + store_args.push_back (rhs); + store_args.push_back (*it); + store_args.push_back (val); + rhs = m_arr_u.mk_store (store_args.size (), store_args.c_ptr ()); + aux_consts.push_back (val); + } + m_eq = m.mk_eq (lhs, rhs); + } + result = m_eq; +} + + +bool is_partial_eq (app* a) { + return a->get_decl ()->get_name () == peq::PARTIAL_EQ; +} + +} + + +namespace qe { + + class is_relevant_default : public i_expr_pred { + public: + bool operator()(expr* e) { + return true; + } + }; + + class mk_atom_default : public i_nnf_atom { + public: + virtual void operator()(expr* e, bool pol, expr_ref& result) { + if (pol) result = e; + else result = result.get_manager().mk_not(e); + } + }; + + class arith_project_util { + ast_manager& m; + arith_util a; + th_rewriter m_rw; + expr_ref_vector m_lits; + expr_ref_vector m_terms; + vector m_coeffs; + vector m_divs; + svector m_strict; + svector m_eq; + scoped_ptr m_var; + + bool is_linear(rational const& mul, expr* t, rational& c, expr_ref_vector& ts) { + expr* t1, *t2; + rational mul1; + bool res = true; + if (t == m_var->x()) { + c += mul; + } + else if (a.is_mul(t, t1, t2) && a.is_numeral(t1, mul1)) { + res = is_linear(mul* mul1, t2, c, ts); + } + else if (a.is_mul(t, t1, t2) && a.is_numeral(t2, mul1)) { + res = is_linear(mul* mul1, t1, c, ts); + } + else if (a.is_add(t)) { + app* ap = to_app(t); + for (unsigned i = 0; res && i < ap->get_num_args(); ++i) { + res = is_linear(mul, ap->get_arg(i), c, ts); + } + } + else if (a.is_sub(t, t1, t2)) { + res = is_linear(mul, t1, c, ts) && is_linear(-mul, t2, c, ts); + } + else if (a.is_uminus(t, t1)) { + res = is_linear(-mul, t1, c, ts); + } + else if (a.is_numeral(t, mul1)) { + ts.push_back(a.mk_numeral(mul*mul1, m.get_sort(t))); + } + else if ((*m_var)(t)) { + IF_VERBOSE(2, verbose_stream() << "can't project:" << mk_pp(t, m) << "\n";); + TRACE ("qe", tout << "Failed to project: " << mk_pp (t, m) << "\n";); + res = false; + } + else if (mul.is_one()) { + ts.push_back(t); + } + else { + ts.push_back(a.mk_mul(a.mk_numeral(mul, m.get_sort(t)), t)); + } + return res; + } + + // either an equality (cx + t = 0) or an inequality (cx + t <= 0) or a divisibility literal (d | cx + t) + bool is_linear(expr* lit, rational& c, expr_ref& t, rational& d, bool& is_strict, bool& is_eq, bool& is_diseq) { + SASSERT ((*m_var)(lit)); + expr* e1, *e2; + c.reset(); + sort* s; + expr_ref_vector ts(m); + bool is_not = m.is_not(lit, lit); + rational mul(1); + if (is_not) { + mul.neg(); + } + SASSERT(!m.is_not(lit)); + if (a.is_le(lit, e1, e2) || a.is_ge(lit, e2, e1)) { + if (!is_linear( mul, e1, c, ts) || !is_linear(-mul, e2, c, ts)) + return false; + s = m.get_sort(e1); + is_strict = is_not; + } + else if (a.is_lt(lit, e1, e2) || a.is_gt(lit, e2, e1)) { + if (!is_linear( mul, e1, c, ts) || !is_linear(-mul, e2, c, ts)) + return false; + s = m.get_sort(e1); + is_strict = !is_not; + } + else if (m.is_eq(lit, e1, e2) && a.is_int_real (e1)) { + expr *t, *num; + rational num_val, d_val, z; + bool is_int; + if (a.is_mod (e1, t, num) && a.is_numeral (num, num_val, is_int) && is_int && + a.is_numeral (e2, z) && z.is_zero ()) { + // divsibility constraint: t % num == 0 <=> num | t + if (num_val.is_zero ()) { + IF_VERBOSE(1, verbose_stream() << "div by zero" << mk_pp(lit, m) << "\n";); + return false; + } + d = num_val; + if (!is_linear (mul, t, c, ts)) return false; + } else if (a.is_mod (e2, t, num) && a.is_numeral (num, num_val, is_int) && is_int && + a.is_numeral (e1, z) && z.is_zero ()) { + // divsibility constraint: 0 == t % num <=> num | t + if (num_val.is_zero ()) { + IF_VERBOSE(1, verbose_stream() << "div by zero" << mk_pp(lit, m) << "\n";); + return false; + } + d = num_val; + if (!is_linear (mul, t, c, ts)) return false; + } else { + // equality or disequality + if (!is_linear( mul, e1, c, ts) || !is_linear(-mul, e2, c, ts)) + return false; + if (is_not) is_diseq = true; + else is_eq = true; + } + s = m.get_sort(e1); + } + else { + IF_VERBOSE(2, verbose_stream() << "can't project:" << mk_pp(lit, m) << "\n";); + TRACE ("qe", tout << "Failed to project: " << mk_pp (lit, m) << "\n";); + return false; + } + + if (ts.empty()) { + t = a.mk_numeral(rational(0), s); + } + else if (ts.size () == 1) { + t = ts.get (0); + } + else { + t = a.mk_add(ts.size(), ts.c_ptr()); + } + + return true; + } + + bool project(model& mdl, expr_ref_vector& lits) { + unsigned num_pos = 0; + unsigned num_neg = 0; + bool use_eq = false; + expr_ref_vector new_lits(m); + expr_ref eq_term (m); + + m_lits.reset (); + m_terms.reset(); + m_coeffs.reset(); + m_strict.reset(); + m_eq.reset (); + + for (unsigned i = 0; i < lits.size(); ++i) { + rational c(0), d(0); + expr_ref t(m); + bool is_strict = false; + bool is_eq = false; + bool is_diseq = false; + if (!(*m_var)(lits.get (i))) { + new_lits.push_back(lits.get (i)); + continue; + } + if (is_linear(lits.get (i), c, t, d, is_strict, is_eq, is_diseq)) { + if (c.is_zero()) { + m_rw(lits.get (i), t); + new_lits.push_back(t); + } else if (is_eq) { + if (!use_eq) { + // c*x + t = 0 <=> x = -t/c + eq_term = mk_mul (-(rational::one ()/c), t); + use_eq = true; + } + m_lits.push_back (lits.get (i)); + m_coeffs.push_back(c); + m_terms.push_back(t); + m_strict.push_back(false); + m_eq.push_back (true); + } else { + if (is_diseq) { + // c*x + t != 0 + // find out whether c*x + t < 0, or c*x + t > 0 + expr_ref cx (m), cxt (m), val (m); + rational r; + cx = mk_mul (c, m_var->x()); + cxt = mk_add (cx, t); + VERIFY(mdl.eval(cxt, val, true)); + VERIFY(a.is_numeral(val, r)); + SASSERT (r > rational::zero () || r < rational::zero ()); + if (r > rational::zero ()) { + c = -c; + t = mk_mul (-(rational::one()), t); + } + is_strict = true; + } + m_lits.push_back (lits.get (i)); + m_coeffs.push_back(c); + m_terms.push_back(t); + m_strict.push_back(is_strict); + m_eq.push_back (false); + if (c.is_pos()) { + ++num_pos; + } + else { + ++num_neg; + } + } + } + else return false; + } + if (use_eq) { + TRACE ("qe", + tout << "Using equality term: " << mk_pp (eq_term, m) << "\n"; + ); + // substitute eq_term for x everywhere + for (unsigned i = 0; i < m_lits.size(); ++i) { + expr_ref cx (m), cxt (m), z (m), result (m); + cx = mk_mul (m_coeffs[i], eq_term); + cxt = mk_add (cx, m_terms.get(i)); + z = a.mk_numeral(rational(0), m.get_sort(eq_term)); + if (m_eq[i]) { + // c*x + t = 0 + result = a.mk_eq (cxt, z); + } else if (m_strict[i]) { + // c*x + t < 0 + result = a.mk_lt (cxt, z); + } else { + // c*x + t <= 0 + result = a.mk_le (cxt, z); + } + m_rw (result); + new_lits.push_back (result); + } + } + lits.reset(); + lits.append(new_lits); + if (use_eq || num_pos == 0 || num_neg == 0) { + return true; + } + bool use_pos = num_pos < num_neg; + unsigned max_t = find_max(mdl, use_pos); + + expr_ref new_lit (m); + for (unsigned i = 0; i < m_lits.size(); ++i) { + if (i != max_t) { + if (m_coeffs[i].is_pos() == use_pos) { + new_lit = mk_le(i, max_t); + } + else { + new_lit = mk_lt(i, max_t); + } + lits.push_back(new_lit); + TRACE ("qe", + tout << "Old literal: " << mk_pp (m_lits.get (i), m) << "\n"; + tout << "New literal: " << mk_pp (new_lit, m) << "\n"; + ); + } + } + return true; + } + + bool project(model& mdl, app_ref_vector const& lits, expr_map& map, app_ref& div_lit) { + unsigned num_pos = 0; // number of positive literals true in the model + unsigned num_neg = 0; // number of negative literals true in the model + + m_lits.reset (); + m_terms.reset(); + m_coeffs.reset(); + m_divs.reset (); + m_strict.reset(); + m_eq.reset (); + + expr_ref var_val (m); + VERIFY (mdl.eval (m_var->x(), var_val, true)); + + unsigned eq_idx = lits.size (); + for (unsigned i = 0; i < lits.size(); ++i) { + rational c(0), d(0); + expr_ref t(m); + bool is_strict = false; + bool is_eq = false; + bool is_diseq = false; + if (!(*m_var)(lits.get (i))) continue; + if (is_linear(lits.get (i), c, t, d, is_strict, is_eq, is_diseq)) { + TRACE ("qe", + tout << "Literal: " << mk_pp (lits.get (i), m) << "\n"; + ); + + if (c.is_zero()) { + TRACE ("qe", + tout << "independent of variable\n"; + ); + continue; + } + + // evaluate c*x + t in the model + expr_ref cx (m), cxt (m), val (m); + rational r; + cx = mk_mul (c, m_var->x()); + cxt = mk_add (cx, t); + VERIFY(mdl.eval(cxt, val, true)); + VERIFY(a.is_numeral(val, r)); + + if (is_eq) { + TRACE ("qe", + tout << "equality term\n"; + ); + // check if the equality is true in the mdl + if (eq_idx == lits.size () && r == rational::zero ()) { + eq_idx = m_lits.size (); + } + m_lits.push_back (lits.get (i)); + m_coeffs.push_back(c); + m_terms.push_back(t); + m_strict.push_back(false); + m_eq.push_back (true); + m_divs.push_back (d); + } else { + TRACE ("qe", + tout << "not an equality term\n"; + ); + if (is_diseq) { + // c*x + t != 0 + // find out whether c*x + t < 0, or c*x + t > 0 + if (r > rational::zero ()) { + c = -c; + t = mk_mul (-(rational::one()), t); + r = -r; + } + // note: if the disequality is false in the model, + // r==0 and we end up choosing c*x + t < 0 + is_strict = true; + } + m_lits.push_back (lits.get (i)); + m_coeffs.push_back(c); + m_terms.push_back(t); + m_strict.push_back(is_strict); + m_eq.push_back (false); + m_divs.push_back (d); + if (d.is_zero ()) { // not a div term + if ((is_strict && r < rational::zero ()) || + (!is_strict && r <= rational::zero ())) { // literal true in the model + if (c.is_pos()) { + ++num_pos; + } + else { + ++num_neg; + } + } + } + } + TRACE ("qe", + tout << "c: " << c << "\n"; + tout << "t: " << mk_pp (t, m) << "\n"; + tout << "d: " << d << "\n"; + ); + } + else return false; + } + + rational lcm_coeffs (1), lcm_divs (1); + if (a.is_int (m_var->x())) { + // lcm of (absolute values of) coeffs + for (unsigned i = 0; i < m_lits.size (); i++) { + lcm_coeffs = lcm (lcm_coeffs, abs (m_coeffs[i])); + } + // normalize coeffs of x to +/-lcm_coeffs and scale terms and divs appropriately; + // find lcm of scaled-up divs + for (unsigned i = 0; i < m_lits.size (); i++) { + rational factor (lcm_coeffs / abs(m_coeffs[i])); + if (!factor.is_one () && !a.is_zero (m_terms.get (i))) + m_terms[i] = a.mk_mul (a.mk_numeral (factor, a.mk_int ()), + m_terms.get (i)); + m_coeffs[i] = (m_coeffs[i].is_pos () ? lcm_coeffs : -lcm_coeffs); + if (!m_divs[i].is_zero ()) { + m_divs[i] *= factor; + lcm_divs = lcm (lcm_divs, m_divs[i]); + } + TRACE ("qe", + tout << "normalized coeff: " << m_coeffs[i] << "\n"; + tout << "normalized term: " << mk_pp (m_terms.get (i), m) << "\n"; + tout << "normalized div: " << m_divs[i] << "\n"; + ); + } + + // consider new divisibility literal (lcm_coeffs | (lcm_coeffs * x)) + lcm_divs = lcm (lcm_divs, lcm_coeffs); + + TRACE ("qe", + tout << "lcm of coeffs: " << lcm_coeffs << "\n"; + tout << "lcm of divs: " << lcm_divs << "\n"; + ); + } + + expr_ref z (a.mk_numeral (rational::zero (), a.mk_int ()), m); + expr_ref x_term_val (m); + + // use equality term + if (eq_idx < lits.size ()) { + if (a.is_real (m_var->x ())) { + // c*x + t = 0 <=> x = -t/c + expr_ref eq_term (mk_mul (-(rational::one ()/m_coeffs[eq_idx]), m_terms.get (eq_idx)), m); + m_rw (eq_term); + map.insert (m_var->x (), eq_term, 0); + TRACE ("qe", + tout << "Using equality term: " << mk_pp (eq_term, m) << "\n"; + ); + } + else { + // find substitution term for (lcm_coeffs * x) + if (m_coeffs[eq_idx].is_pos ()) { + x_term_val = a.mk_uminus (m_terms.get (eq_idx)); + } else { + x_term_val = m_terms.get (eq_idx); + } + m_rw (x_term_val); + TRACE ("qe", + tout << "Using equality literal: " << mk_pp (m_lits.get (eq_idx), m) << "\n"; + tout << "substitution for (lcm_coeffs * x): " << mk_pp (x_term_val, m) << "\n"; + ); + // can't simply substitute for x; need to explicitly substitute the lits + mk_lit_substitutes (x_term_val, map, eq_idx); + + if (!lcm_coeffs.is_one ()) { + // new div constraint: lcm_coeffs | x_term_val + div_lit = m.mk_eq (a.mk_mod (x_term_val, + a.mk_numeral (lcm_coeffs, a.mk_int ())), + z); + } + } + + return true; + } + + expr_ref new_lit (m); + + if (num_pos == 0 || num_neg == 0) { + TRACE ("qe", + if (num_pos == 0) { + tout << "virtual substitution with +infinity\n"; + } else { + tout << "virtual substitution with -infinity\n"; + } + ); + + /** + * make all equalities false; + * if num_pos = 0 (num_neg = 0), make all positive (negative) inequalities false; + * make the rest inequalities true; + * substitute value of x under given model for the rest (div terms) + */ + + if (a.is_int (m_var->x())) { + // to substitute for (lcm_coeffs * x), it suffices to pick + // some element in the congruence class of (lcm_coeffs * x) mod lcm_divs; + // simply substituting var_val for x in the literals does this job; + // but to keep constants small, we use (lcm_coeffs * var_val) % lcm_divs instead + rational var_val_num; + VERIFY (a.is_numeral (var_val, var_val_num)); + x_term_val = a.mk_numeral (mod (lcm_coeffs * var_val_num, lcm_divs), + a.mk_int ()); + TRACE ("qe", + tout << "Substitution for (lcm_coeffs * x): " + << mk_pp (x_term_val, m) << "\n"; + ); + } + for (unsigned i = 0; i < m_lits.size (); i++) { + if (!m_divs[i].is_zero ()) { + // m_divs[i] | (x_term_val + m_terms[i]) + + // -- x_term_val is the absolute value, negate it if needed + if (m_coeffs.get (i).is_pos ()) + new_lit = a.mk_add (m_terms.get (i), x_term_val); + else + new_lit = a.mk_add (m_terms.get (i), a.mk_uminus (x_term_val)); + + // XXX Our handling of divisibility constraints is very fragile. + // XXX Rewrite before applying divisibility to preserve syntactic structure + m_rw(new_lit); + new_lit = m.mk_eq (a.mk_mod (new_lit, + a.mk_numeral (m_divs[i], a.mk_int ())), z); + } else if (m_eq[i] || + (num_pos == 0 && m_coeffs[i].is_pos ()) || + (num_neg == 0 && m_coeffs[i].is_neg ())) { + new_lit = m.mk_false (); + } else { + new_lit = m.mk_true (); + } + map.insert (m_lits.get (i), new_lit, 0); + TRACE ("qe", + tout << "Old literal: " << mk_pp (m_lits.get (i), m) << "\n"; + tout << "New literal: " << mk_pp (new_lit, m) << "\n"; + ); + } + return true; + } + + bool use_pos = num_pos < num_neg; // pick a side; both are sound + + unsigned max_t = find_max(mdl, use_pos); + + TRACE ("qe", + if (use_pos) { + tout << "virtual substitution with upper bound:\n"; + } else { + tout << "virtual substitution with lower bound:\n"; + } + tout << "test point: " << mk_pp (m_lits.get (max_t), m) << "\n"; + tout << "coeff: " << m_coeffs[max_t] << "\n"; + tout << "term: " << mk_pp (m_terms.get (max_t), m) << "\n"; + tout << "is_strict: " << m_strict[max_t] << "\n"; + ); + + if (a.is_real (m_var->x ())) { + for (unsigned i = 0; i < m_lits.size(); ++i) { + if (i != max_t) { + if (m_eq[i]) { + if (!m_strict[max_t]) { + new_lit = mk_eq (i, max_t); + } else { + new_lit = m.mk_false (); + } + } else if (m_coeffs[i].is_pos() == use_pos) { + new_lit = mk_le (i, max_t); + } else { + new_lit = mk_lt (i, max_t); + } + } else { + new_lit = m.mk_true (); + } + map.insert (m_lits.get (i), new_lit, 0); + TRACE ("qe", + tout << "Old literal: " << mk_pp (m_lits.get (i), m) << "\n"; + tout << "New literal: " << mk_pp (new_lit, m) << "\n"; + ); + } + } else { + SASSERT (a.is_int (m_var->x ())); + + // mk substitution term for (lcm_coeffs * x) + + // evaluate c*x + t for the literal at max_t + expr_ref cx (m), cxt (m), val (m); + rational r; + cx = mk_mul (m_coeffs[max_t], m_var->x()); + cxt = mk_add (cx, m_terms.get (max_t)); + VERIFY(mdl.eval(cxt, val, true)); + VERIFY(a.is_numeral(val, r)); + + // get the offset from the smallest/largest possible value for x + // literal smallest/largest val of x + // ------- -------------------------- + // l < x l+1 + // l <= x l + // x < u u-1 + // x <= u u + rational offset; + if (m_strict[max_t]) { + offset = abs(r) - rational::one (); + } else { + offset = abs(r); + } + // obtain the offset modulo lcm_divs + offset %= lcm_divs; + + // for strict negative literal (i.e. strict lower bound), + // substitution term is (t+1+offset); for non-strict, it's (t+offset) + // + // for positive term, subtract from 0 + x_term_val = mk_add (m_terms.get (max_t), a.mk_numeral (offset, a.mk_int ())); + if (m_strict[max_t]) { + x_term_val = a.mk_add (x_term_val, a.mk_numeral (rational::one(), a.mk_int ())); + } + if (m_coeffs[max_t].is_pos ()) { + x_term_val = a.mk_uminus (x_term_val); + } + m_rw (x_term_val); + + TRACE ("qe", + tout << "substitution for (lcm_coeffs * x): " << mk_pp (x_term_val, m) << "\n"; + ); + + // obtain substitutions for all literals in map + mk_lit_substitutes (x_term_val, map, max_t); + + if (!lcm_coeffs.is_one ()) { + // new div constraint: lcm_coeffs | x_term_val + div_lit = m.mk_eq (a.mk_mod (x_term_val, + a.mk_numeral (lcm_coeffs, a.mk_int ())), + z); + } + } + return true; + } + + unsigned find_max(model& mdl, bool do_pos) { + unsigned result = UINT_MAX; + bool found = false; + bool found_strict = false; + rational found_val (0), r, r_plus_x, found_c; + expr_ref val(m); + + // evaluate x in mdl + rational r_x; + VERIFY(mdl.eval(m_var->x (), val, true)); + VERIFY(a.is_numeral (val, r_x)); + + for (unsigned i = 0; i < m_terms.size(); ++i) { + rational const& ac = m_coeffs[i]; + if (!m_eq[i] && ac.is_pos() == do_pos) { + VERIFY(mdl.eval(m_terms.get (i), val, true)); + VERIFY(a.is_numeral(val, r)); + r /= abs(ac); + // skip the literal if false in the model + if (do_pos) { r_plus_x = r + r_x; } + else { r_plus_x = r - r_x; } + if (!((m_strict[i] && r_plus_x < rational::zero ()) || + (!m_strict[i] && r_plus_x <= rational::zero ()))) { + continue; + } + IF_VERBOSE(2, verbose_stream() << "max: " << mk_pp(m_terms.get (i), m) << " " << r << " " << + (!found || r > found_val || (r == found_val && !found_strict && m_strict[i])) << "\n";); + if (!found || r > found_val || (r == found_val && !found_strict && m_strict[i])) { + result = i; + found_val = r; + found_c = ac; + found = true; + found_strict = m_strict[i]; + } + } + } + SASSERT(found); + return result; + } + + // ax + t <= 0 + // bx + s <= 0 + // a and b have different signs. + // Infer: a|b|x + |b|t + |a|bx + |a|s <= 0 + // e.g. |b|t + |a|s <= 0 + expr_ref mk_lt(unsigned i, unsigned j) { + rational const& ac = m_coeffs[i]; + rational const& bc = m_coeffs[j]; + SASSERT(ac.is_pos() != bc.is_pos()); + SASSERT(ac.is_neg() != bc.is_neg()); + expr_ref bt (m), as (m), ts (m), z (m); + expr* t = m_terms.get (i); + expr* s = m_terms.get (j); + bt = mk_mul(abs(bc), t); + as = mk_mul(abs(ac), s); + ts = mk_add(bt, as); + z = a.mk_numeral(rational(0), m.get_sort(t)); + expr_ref result1(m), result2(m); + if (m_strict[i] || m_strict[j]) { + result1 = a.mk_lt(ts, z); + } + else { + result1 = a.mk_le(ts, z); + } + m_rw(result1, result2); + return result2; + } + + // ax + t <= 0 + // bx + s <= 0 + // a and b have same signs. + // encode:// t/|a| <= s/|b| + // e.g. |b|t <= |a|s + expr_ref mk_le(unsigned i, unsigned j) { + rational const& ac = m_coeffs[i]; + rational const& bc = m_coeffs[j]; + SASSERT(ac.is_pos() == bc.is_pos()); + SASSERT(ac.is_neg() == bc.is_neg()); + expr_ref bt (m), as (m); + expr* t = m_terms.get (i); + expr* s = m_terms.get (j); + bt = mk_mul(abs(bc), t); + as = mk_mul(abs(ac), s); + expr_ref result1(m), result2(m); + if (!m_strict[j] && m_strict[i]) { + result1 = a.mk_lt(bt, as); + } + else { + result1 = a.mk_le(bt, as); + } + m_rw(result1, result2); + return result2; + } + + // ax + t = 0 + // bx + s <= 0 + // replace equality by (-t/a == -s/b), or, as = bt + expr_ref mk_eq (unsigned i, unsigned j) { + expr_ref as (m), bt (m); + as = mk_mul (m_coeffs[i], m_terms.get (j)); + bt = mk_mul (m_coeffs[j], m_terms.get (i)); + expr_ref result (m); + result = m.mk_eq (as, bt); + m_rw (result); + return result; + } + + + expr* mk_add(expr* t1, expr* t2) { + return a.mk_add(t1, t2); + } + expr* mk_mul(rational const& r, expr* t2) { + expr* t1 = a.mk_numeral(r, m.get_sort(t2)); + return a.mk_mul(t1, t2); + } + + /** + * walk the ast of fml and introduce a fresh variable for every mod term + * (updating the mdl accordingly) + */ + void factor_mod_terms (expr_ref& fml, app_ref_vector& vars, model& mdl) { + expr_ref_vector todo (m), eqs (m); + expr_map factored_terms (m); + ast_mark done; + + todo.push_back (fml); + while (!todo.empty ()) { + expr* e = todo.back (); + if (!is_app (e) || done.is_marked (e)) { + todo.pop_back (); + continue; + } + app* ap = to_app (e); + unsigned num_args = ap->get_num_args (); + bool all_done = true, changed = false; + expr_ref_vector args (m); + for (unsigned i = 0; i < num_args; i++) { + expr* old_arg = ap->get_arg (i); + if (!done.is_marked (old_arg)) { + todo.push_back (old_arg); + all_done = false; + } + if (!all_done) continue; + // all args so far have been processed + // get the correct arg to use + proof* pr = 0; expr* new_arg = 0; + factored_terms.get (old_arg, new_arg, pr); + if (new_arg) { + // changed + args.push_back (new_arg); + changed = true; + } + else { + // not changed + args.push_back (old_arg); + } + } + if (all_done) { + // all args processed; make new term + func_decl* d = ap->get_decl (); + expr_ref new_term (m); + new_term = m.mk_app (d, args.size (), args.c_ptr ()); + // check for mod and introduce new var + if (a.is_mod (ap)) { + app_ref new_var (m); + new_var = m.mk_fresh_const ("mod_var", d->get_range ()); + eqs.push_back (m.mk_eq (new_var, new_term)); + // obtain value of new_term in mdl + expr_ref val (m); + mdl.eval (new_term, val, true); + // use the variable from now on + new_term = new_var; + changed = true; + // update vars and mdl + vars.push_back (new_var); + mdl.register_decl (new_var->get_decl (), val); + } + if (changed) { + factored_terms.insert (e, new_term, 0); + } + done.mark (e, true); + todo.pop_back (); + } + } + + // mk new fml + proof* pr = 0; expr* new_fml = 0; + factored_terms.get (fml, new_fml, pr); + if (new_fml) { + fml = new_fml; + // add in eqs + fml = m.mk_and (fml, m.mk_and (eqs.size (), eqs.c_ptr ())); + } + else { + // unchanged + SASSERT (eqs.empty ()); + } + } + + /** + * factor out mod terms by using divisibility terms; + * + * for now, only handle mod equalities of the form (t1 % num == t2), + * replacing it by the equivalent (num | (t1-t2)) /\ (0 <= t2 < abs(num)); + * the divisibility atom is a special mod term ((t1-t2) % num == 0) + */ + void mod2div (expr_ref& fml, expr_map& map) { + expr* new_fml = 0; + + proof *pr = 0; + map.get (fml, new_fml, pr); + if (new_fml) { + fml = new_fml; + return; + } + + expr_ref z (a.mk_numeral (rational::zero (), a.mk_int ()), m); + bool is_mod_eq = false; + + expr *e1, *e2, *num; + expr_ref t1 (m), t2 (m); + rational num_val; + bool is_int; + // check if fml is a mod equality (t1 % num) == t2 + if (m.is_eq (fml, e1, e2)) { + expr* t; + if (a.is_mod (e1, t, num) && a.is_numeral (num, num_val, is_int) && is_int) { + t1 = t; + t2 = e2; + is_mod_eq = true; + } else if (a.is_mod (e2, t, num) && a.is_numeral (num, num_val, is_int) && is_int) { + t1 = t; + t2 = e1; + is_mod_eq = true; + } + } + + if (is_mod_eq) { + // recursively mod2div for t1 and t2 + mod2div (t1, map); + mod2div (t2, map); + + rational t2_num; + if (a.is_numeral (t2, t2_num) && t2_num.is_zero ()) { + // already in the desired form; + // new_fml is (num_val | t1) + new_fml = m.mk_eq (a.mk_mod (t1, a.mk_numeral (num_val, a.mk_int ())), + z); + } + else { + expr_ref_vector lits (m); + // num_val | (t1 - t2) + lits.push_back (m.mk_eq (a.mk_mod (a.mk_sub (t1, t2), + a.mk_numeral (num_val, a.mk_int ())), + z)); + // 0 <= t2 + lits.push_back (a.mk_le (z, t2)); + // t2 < abs (num_val) + lits.push_back (a.mk_lt (t2, a.mk_numeral (abs (num_val), a.mk_int ()))); + + new_fml = m.mk_and (lits.size (), lits.c_ptr ()); + } + } + else if (!is_app (fml)) { + new_fml = fml; + } + else { + app* a = to_app (fml); + expr_ref_vector children (m); + expr_ref ch (m); + for (unsigned i = 0; i < a->get_num_args (); i++) { + ch = a->get_arg (i); + mod2div (ch, map); + children.push_back (ch); + } + new_fml = m.mk_app (a->get_decl (), children.size (), children.c_ptr ()); + } + + map.insert (fml, new_fml, 0); + fml = new_fml; + } + + void collect_lits (expr* fml, app_ref_vector& lits) { + expr_ref_vector todo (m); + ast_mark visited; + todo.push_back(fml); + while (!todo.empty()) { + expr* e = todo.back(); + todo.pop_back(); + if (visited.is_marked(e)) { + continue; + } + visited.mark(e, true); + if (!is_app(e)) { + continue; + } + app* a = to_app(e); + if (m.is_and(a) || m.is_or(a)) { + for (unsigned i = 0; i < a->get_num_args(); ++i) { + todo.push_back(a->get_arg(i)); + } + } else { + lits.push_back (a); + } + } + SASSERT(todo.empty()); + visited.reset(); + } + + /** + * assume that all coeffs of x are the same, say c + * substitute x_term_val for (c*x) in all lits and update map + * make the literal at idx true + */ + void mk_lit_substitutes (expr_ref const& x_term_val, expr_map& map, unsigned idx) { + expr_ref z (a.mk_numeral (rational::zero (), a.mk_int ()), m); + expr_ref cxt (m), new_lit (m); + for (unsigned i = 0; i < m_lits.size(); ++i) { + if (i == idx) { + new_lit = m.mk_true (); + } else { + // cxt + if (m_coeffs[i].is_neg ()) { + cxt = a.mk_sub (m_terms.get (i), x_term_val); + } else { + cxt = a.mk_add (m_terms.get (i), x_term_val); + } + + if (m_divs[i].is_zero ()) { + if (m_eq[i]) { + new_lit = m.mk_eq (cxt, z); + } else if (m_strict[i]) { + new_lit = a.mk_lt (cxt, z); + } else { + new_lit = a.mk_le (cxt, z); + } + m_rw(new_lit); + } else { + // div term + // XXX rewrite before applying mod to ensure mod is the top-level operator + m_rw(cxt); + new_lit = m.mk_eq (a.mk_mod (cxt, + a.mk_numeral (m_divs[i], a.mk_int ())), + z); + } + } + map.insert (m_lits.get (i), new_lit, 0); + TRACE ("qe", + tout << "Old literal: " << mk_pp (m_lits.get (i), m) << "\n"; + tout << "New literal: " << mk_pp (new_lit, m) << "\n"; + ); + } + } + + void substitute (expr_ref& fml, app_ref_vector& lits, expr_map& map) { + expr_substitution sub (m); + // literals + for (unsigned i = 0; i < lits.size (); i++) { + expr* new_lit = 0; proof* pr = 0; + app* old_lit = lits.get (i); + map.get (old_lit, new_lit, pr); + if (new_lit) { + sub.insert (old_lit, new_lit); + TRACE ("qe", + tout << "old lit " << mk_pp (old_lit, m) << "\n"; + tout << "new lit " << mk_pp (new_lit, m) << "\n"; + ); + } + } + // substitute for x, if any + expr* x_term = 0; proof* pr = 0; + map.get (m_var->x (), x_term, pr); + if (x_term) { + sub.insert (m_var->x (), x_term); + TRACE ("qe", + tout << "substituting " << mk_pp (m_var->x (), m) << " by " << mk_pp (x_term, m) << "\n"; + ); + } + scoped_ptr rep = mk_default_expr_replacer (m); + rep->set_substitution (&sub); + (*rep)(fml); + } + + public: + arith_project_util(ast_manager& m): + m(m), a(m), m_rw(m), m_lits (m), m_terms (m) {} + + // OLD AND UNUSED INTERFACE + expr_ref operator()(model& mdl, app_ref_vector& vars, expr_ref_vector const& lits) { + app_ref_vector new_vars(m); + expr_ref_vector result(lits); + for (unsigned i = 0; i < vars.size(); ++i) { + app* v = vars.get (i); + m_var = alloc(contains_app, m, v); + bool fail = a.is_int (v) || !project (mdl, result); + if (fail) new_vars.push_back (v); + + IF_VERBOSE(2, + if (fail) { + verbose_stream() << "can't project:" << mk_pp(v, m) << "\n"; + } + ); + TRACE("qe", + if (!fail) { + tout << "projected: " << mk_pp(v, m) << "\n"; + for (unsigned i = 0; i < result.size(); ++i) { + tout << mk_pp(result.get (i), m) << "\n"; + } + } + else { + tout << "Failed to project: " << mk_pp (v, m) << "\n"; + } + ); + } + vars.reset(); + vars.append(new_vars); + return mk_and(result); + } + + void operator()(model& mdl, app_ref_vector& vars, expr_ref& fml) { + expr_map map (m); + operator()(mdl, vars, fml, map); + } + + void operator()(model& mdl, app_ref_vector& vars, expr_ref& fml, expr_map& map) { + app_ref_vector new_vars(m); + + // factor out mod terms by introducing new variables + TRACE ("qe", + tout << "before factoring out mod terms:" << "\n"; + tout << mk_pp (fml, m) << "\n"; + tout << "mdl:\n"; + model_pp (tout, mdl); + tout << "\n"; + ); + + factor_mod_terms (fml, vars, mdl); + + TRACE ("qe", + tout << "after factoring out mod terms:" << "\n"; + tout << mk_pp (fml, m) << "\n"; + tout << "updated mdl:\n"; + model_pp (tout, mdl); + tout << "\n"; + ); + + app_ref_vector lits (m); +// expr_map map (m); + for (unsigned i = 0; i < vars.size(); ++i) { + app* v = vars.get (i); + TRACE ("qe", + tout << "projecting variable: " << mk_pp (v, m) << "\n"; + ); + m_var = alloc(contains_app, m, v); + map.reset (); + lits.reset (); + if (a.is_int (v)) { + // factor out mod terms using div terms + expr_map mod_map (m); + mod2div (fml, mod_map); + TRACE ("qe", + tout << "after mod2div:" << "\n"; + tout << mk_pp (fml, m) << "\n"; + ); + } + collect_lits (fml, lits); + app_ref div_lit (m); + if (project (mdl, lits, map, div_lit)) { + substitute (fml, lits, map); + if (div_lit) { + fml = m.mk_and (fml, div_lit); + } + TRACE("qe", + tout << "projected: " << mk_pp(v, m) << " " + << mk_pp(fml, m) << "\n"; + ); + } + else { + IF_VERBOSE(2, verbose_stream() << "can't project:" << mk_pp(v, m) << "\n";); + TRACE ("qe", tout << "Failed to project: " << mk_pp (v, m) << "\n";); + new_vars.push_back(v); + } + } + vars.reset(); + vars.append(new_vars); + m_rw (fml); + } + }; + + + class array_project_eqs_util { + ast_manager& m; + array_util m_arr_u; + model_ref M; + app_ref m_v; // array var to eliminate + ast_mark m_has_stores_v; // has stores for m_v + expr_ref m_subst_term_v; // subst term for m_v + expr_safe_replace m_true_sub_v; // subst for true equalities + expr_safe_replace m_false_sub_v; // subst for false equalities + expr_ref_vector m_aux_lits_v; + expr_ref_vector m_idx_lits_v; + app_ref_vector m_aux_vars; + model_evaluator_array_util m_mev; + + void reset_v () { + m_v = 0; + m_has_stores_v.reset (); + m_subst_term_v = 0; + m_true_sub_v.reset (); + m_false_sub_v.reset (); + m_aux_lits_v.reset (); + m_idx_lits_v.reset (); + } + + void reset () { + M = 0; + reset_v (); + m_aux_vars.reset (); + } + + /** + * find all array equalities on m_v or containing stores on/of m_v + * + * also mark terms containing stores on/of m_v + */ + void find_arr_eqs (expr_ref const& fml, expr_ref_vector& eqs) { + if (!is_app (fml)) return; + ast_mark done; + ptr_vector todo; + todo.push_back (to_app (fml)); + while (!todo.empty ()) { + app* a = todo.back (); + if (done.is_marked (a)) { + todo.pop_back (); + continue; + } + bool all_done = true; + bool args_have_stores = false; + unsigned num_args = a->get_num_args (); + for (unsigned i = 0; i < num_args; i++) { + expr* arg = a->get_arg (i); + if (!is_app (arg)) continue; + if (!done.is_marked (arg)) { + all_done = false; + todo.push_back (to_app (arg)); + } + else if (!args_have_stores && m_has_stores_v.is_marked (arg)) { + args_have_stores = true; + } + } + if (!all_done) continue; + todo.pop_back (); + + // mark if a has stores + if ((!m_arr_u.is_select (a) && args_have_stores) || + (m_arr_u.is_store (a) && (a->get_arg (0) == m_v))) { + m_has_stores_v.mark (a, true); + + TRACE ("qe", + tout << "has stores:\n"; + tout << mk_pp (a, m) << "\n"; + ); + } + + // check if a is a relevant array equality + if (m.is_eq (a)) { + expr* a0 = to_app (a)->get_arg (0); + expr* a1 = to_app (a)->get_arg (1); + if (a0 == m_v || a1 == m_v || + (m_arr_u.is_array (a0) && m_has_stores_v.is_marked (a))) { + eqs.push_back (a); + } + } + // else, we can check for disequalities and handle them using extensionality, + // but it's not necessary + + done.mark (a, true); + } + } + + /** + * factor out select terms on m_v using fresh consts + */ + void factor_selects (app_ref& fml) { + expr_map sel_cache (m); + ast_mark done; + ptr_vector todo; + expr_ref_vector pinned (m); // to ensure a reference + + todo.push_back (fml); + while (!todo.empty ()) { + app* a = todo.back (); + if (done.is_marked (a)) { + todo.pop_back (); + continue; + } + expr_ref_vector args (m); + bool all_done = true; + for (unsigned i = 0; i < a->get_num_args (); i++) { + expr* arg = a->get_arg (i); + if (!is_app (arg)) continue; + if (!done.is_marked (arg)) { + all_done = false; + todo.push_back (to_app (arg)); + } + else if (all_done) { // all done so far.. + expr* arg_new = 0; proof* pr; + sel_cache.get (arg, arg_new, pr); + if (!arg_new) { + arg_new = arg; + } + args.push_back (arg_new); + } + } + if (!all_done) continue; + todo.pop_back (); + + expr_ref a_new (m.mk_app (a->get_decl (), args.size (), args.c_ptr ()), m); + + // if a_new is select on m_v, introduce new constant + if (m_arr_u.is_select (a) && + (args.get (0) == m_v || m_has_stores_v.is_marked (args.get (0)))) { + sort* val_sort = get_array_range (m.get_sort (m_v)); + app_ref val_const (m.mk_fresh_const ("sel", val_sort), m); + m_aux_vars.push_back (val_const); + // extend M to include val_const + expr_ref val (m); + m_mev.eval (*M, a_new, val); + M->register_decl (val_const->get_decl (), val); + // add equality + m_aux_lits_v.push_back (m.mk_eq (val_const, a_new)); + // replace select by const + a_new = val_const; + } + + if (a != a_new) { + sel_cache.insert (a, a_new, 0); + pinned.push_back (a_new); + } + done.mark (a, true); + } + expr* res = 0; proof* pr; + sel_cache.get (fml, res, pr); + if (res) { + fml = to_app (res); + } + } + + /** + * convert partial equality expression p_exp to an equality by + * recursively adding stores on diff indices + * + * add stores on lhs or rhs depending on whether stores_on_rhs is false/true + */ + void convert_peq_to_eq (expr* p_exp, app_ref& eq, bool stores_on_rhs = true) { + peq p (to_app (p_exp), m); + app_ref_vector diff_val_consts (m); + p.mk_eq (diff_val_consts, eq, stores_on_rhs); + m_aux_vars.append (diff_val_consts); + // extend M to include diff_val_consts + expr_ref arr (m); + expr_ref_vector I (m); + p.lhs (arr); + p.get_diff_indices (I); + expr_ref val (m); + unsigned num_diff = diff_val_consts.size (); + SASSERT (num_diff == I.size ()); + for (unsigned i = 0; i < num_diff; i++) { + // mk val term + ptr_vector sel_args; + sel_args.push_back (arr); + sel_args.push_back (I.get (i)); + expr_ref val_term (m_arr_u.mk_select (sel_args.size (), sel_args.c_ptr ()), m); + // evaluate and assign to ith diff_val_const + m_mev.eval (*M, val_term, val); + M->register_decl (diff_val_consts.get (i)->get_decl (), val); + } + } + + /** + * mk (e0 ==indices e1) + * + * result has stores if either e0 or e1 or an index term has stores + */ + void mk_peq (expr* e0, expr* e1, unsigned num_indices, expr* const* indices, app_ref& result) { + peq p (e0, e1, num_indices, indices, m); + p.mk_peq (result); + } + + void find_subst_term (app* eq) { + app_ref p_exp (m); + mk_peq (eq->get_arg (0), eq->get_arg (1), 0, 0, p_exp); + bool subst_eq_found = false; + while (true) { + TRACE ("qe", + tout << "processing peq:\n"; + tout << mk_pp (p_exp, m) << "\n"; + ); + + peq p (p_exp, m); + expr_ref lhs (m), rhs (m); + p.lhs (lhs); p.rhs (rhs); + if (!m_has_stores_v.is_marked (lhs)) { + std::swap (lhs, rhs); + } + if (m_has_stores_v.is_marked (lhs)) { + /** project using the equivalence: + * + * (store(arr0,idx,x) ==I arr1) <-> + * + * (idx \in I => (arr0 ==I arr1)) /\ + * (idx \not\in I => (arr0 ==I+idx arr1) /\ (arr1[idx] == x))) + */ + expr_ref_vector I (m); + p.get_diff_indices (I); + app* a_lhs = to_app (lhs); + expr* arr0 = a_lhs->get_arg (0); + expr* idx = a_lhs->get_arg (1); + expr* x = a_lhs->get_arg (2); + expr* arr1 = rhs; + // check if (idx \in I) in M + bool idx_in_I = false; + expr_ref_vector idx_diseq (m); + if (!I.empty ()) { + expr_ref val (m); + m_mev.eval (*M, idx, val); + for (unsigned i = 0; i < I.size () && !idx_in_I; i++) { + if (idx == I.get (i)) { + idx_in_I = true; + } + else { + expr_ref val1 (m); + expr* idx1 = I.get (i); + expr_ref idx_eq (m.mk_eq (idx, idx1), m); + m_mev.eval (*M, idx1, val1); + if (val == val1) { + idx_in_I = true; + m_idx_lits_v.push_back (idx_eq); + } + else { + idx_diseq.push_back (m.mk_not (idx_eq)); + } + } + } + } + if (idx_in_I) { + TRACE ("qe", + tout << "store index in diff indices:\n"; + tout << mk_pp (m_idx_lits_v.back (), m) << "\n"; + ); + + // arr0 ==I arr1 + mk_peq (arr0, arr1, I.size (), I.c_ptr (), p_exp); + + TRACE ("qe", + tout << "new peq:\n"; + tout << mk_pp (p_exp, m) << "\n"; + ); + } + else { + m_idx_lits_v.append (idx_diseq); + // arr0 ==I+idx arr1 + I.push_back (idx); + mk_peq (arr0, arr1, I.size (), I.c_ptr (), p_exp); + + TRACE ("qe", + tout << "new peq:\n"; + tout << mk_pp (p_exp, m) << "\n"; + ); + + // arr1[idx] == x + ptr_vector sel_args; + sel_args.push_back (arr1); + sel_args.push_back (idx); + expr_ref arr1_idx (m_arr_u.mk_select (sel_args.size (), sel_args.c_ptr ()), m); + expr_ref eq (m.mk_eq (arr1_idx, x), m); + m_aux_lits_v.push_back (eq); + + TRACE ("qe", + tout << "new eq:\n"; + tout << mk_pp (eq, m) << "\n"; + ); + } + } + else if (lhs == rhs) { // trivial peq (a ==I a) + break; + } + else if (lhs == m_v || rhs == m_v) { + subst_eq_found = true; + TRACE ("qe", + tout << "subst eq found!\n"; + ); + break; + } + else { + UNREACHABLE (); + } + } + + // factor out select terms on m_v from p_exp using fresh constants + if (subst_eq_found) { + factor_selects (p_exp); + + TRACE ("qe", + tout << "after factoring selects:\n"; + tout << mk_pp (p_exp, m) << "\n"; + for (unsigned i = m_aux_lits_v.size () - m_aux_vars.size (); i < m_aux_lits_v.size (); i++) { + tout << mk_pp (m_aux_lits_v.get (i), m) << "\n"; + } + ); + + // find subst_term + bool stores_on_rhs = true; + app* a = to_app (p_exp); + if (a->get_arg (1) == m_v) { + stores_on_rhs = false; + } + app_ref eq (m); + convert_peq_to_eq (p_exp, eq, stores_on_rhs); + m_subst_term_v = eq->get_arg (1); + + TRACE ("qe", + tout << "subst term found:\n"; + tout << mk_pp (m_subst_term_v, m) << "\n"; + ); + } + } + + /** + * try to substitute for m_v, using array equalities + * + * compute substitution term and aux lits + */ + bool project (expr_ref const& fml) { + expr_ref_vector eqs (m); + ptr_vector true_eqs; // subset of eqs; eqs ensures references + + find_arr_eqs (fml, eqs); + TRACE ("qe", + tout << "array equalities:\n"; + for (unsigned i = 0; i < eqs.size (); i++) { + tout << mk_pp (eqs.get (i), m) << "\n"; + } + ); + + // evaluate eqs in M + for (unsigned i = 0; i < eqs.size (); i++) { + TRACE ("qe", + tout << "array equality:\n"; + tout << mk_pp (eqs.get (i), m) << "\n"; + ); + + expr* eq = eqs.get (i); + + // evaluate eq in M + app* a = to_app (eq); + expr_ref val (m); + m_mev.eval_array_eq (*M, a, a->get_arg (0), a->get_arg (1), val); + if (!val) { + // XXX HACK: unable to evaluate. set to true? + val = m.mk_true (); + } + SASSERT (m.is_true (val) || m.is_false (val)); + + if (m.is_false (val)) { + m_false_sub_v.insert (eq, m.mk_false ()); + } + else { + true_eqs.push_back (to_app (eq)); + } + } + + // compute nesting depths of stores on m_v in true_eqs, as follows: + // 0 if m_v appears on both sides of equality + // 1 if equality is (m_v=t) + // 2 if equality is (store(m_v,i,v)=t) + // ... + unsigned num_true_eqs = true_eqs.size (); + vector nds (num_true_eqs); + for (unsigned i = 0; i < num_true_eqs; i++) { + app* eq = true_eqs.get (i); + expr* lhs = eq->get_arg (0); + expr* rhs = eq->get_arg (1); + bool lhs_has_v = (lhs == m_v || m_has_stores_v.is_marked (lhs)); + bool rhs_has_v = (rhs == m_v || m_has_stores_v.is_marked (rhs)); + app* store = 0; + + SASSERT (lhs_has_v || rhs_has_v); + + if (!lhs_has_v) { + store = to_app (rhs); + } + else if (!rhs_has_v) { + store = to_app (lhs); + } + // else v appears on both sides -- trivial equality + // put it in the beginning to simplify it away + + unsigned nd = 0; // nesting depth + if (store) { + for (nd = 1; m_arr_u.is_store (store); + nd++, store = to_app (store->get_arg (0))) + /* empty */ ; + SASSERT (store == m_v); + } + nds[i] = nd; + } + + SASSERT (true_eqs.size () == nds.size ()); + + // sort true_eqs according to nesting depth + // use insertion sort + for (unsigned i = 1; i < num_true_eqs; i++) { + app_ref eq(m); + eq = true_eqs.get (i); + unsigned nd = nds.get (i); + unsigned j = i; + for (; j >= 1 && nds.get (j-1) > nd; j--) { + true_eqs.set (j, true_eqs.get (j-1)); + nds.set (j, nds.get (j-1)); + } + if (j < i) { + true_eqs.set (j, eq); + nds.set (j, nd); + TRACE ("qe", + tout << "changing eq order!\n"; + ); + } + } + + // search for subst term + for (unsigned i = 0; !m_subst_term_v && i < num_true_eqs; i++) { + app* eq = true_eqs.get (i); + m_true_sub_v.insert (eq, m.mk_true ()); + // try to find subst term + find_subst_term (eq); + } + + return true; + } + + void mk_result (expr_ref& fml) { + th_rewriter rw(m); + rw (fml); + // add in aux_lits and idx_lits + expr_ref_vector lits (m); + // TODO: eliminate possible duplicates, especially in idx_lits + // theory rewriting is a possibility, but not sure if it + // introduces unwanted terms such as ite's + lits.append (m_idx_lits_v); + lits.append (m_aux_lits_v); + lits.push_back (fml); + fml = m.mk_and (lits.size (), lits.c_ptr ()); + + if (m_subst_term_v) { + m_true_sub_v.insert (m_v, m_subst_term_v); + m_true_sub_v (fml); + } + else { + m_true_sub_v (fml); + m_false_sub_v (fml); + } + rw(fml); + SASSERT (!m.is_false (fml)); + } + + public: + + array_project_eqs_util (ast_manager& m): + m (m), + m_arr_u (m), + m_v (m), + m_subst_term_v (m), + m_true_sub_v (m), + m_false_sub_v (m), + m_aux_lits_v (m), + m_idx_lits_v (m), + m_aux_vars (m), + m_mev (m) + {} + + void operator () (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars) { + reset (); + app_ref_vector rem_arr_vars (m); // remaining arr vars + M = &mdl; + + for (unsigned i = 0; i < arr_vars.size (); i++) { + reset_v (); + m_v = arr_vars.get (i); + if (!m_arr_u.is_array (m_v)) { + TRACE ("qe", + tout << "not an array variable: " << mk_pp (m_v, m) << "\n"; + ); + aux_vars.push_back (m_v); + continue; + } + TRACE ("qe", + tout << "projecting equalities on variable: " << mk_pp (m_v, m) << "\n"; + ); + + if (project (fml)) { + mk_result (fml); + + contains_app contains_v (m, m_v); + if (!m_subst_term_v || contains_v (m_subst_term_v)) { + rem_arr_vars.push_back (m_v); + } + TRACE ("qe", + tout << "after projection: \n"; + tout << mk_pp (fml, m) << "\n"; + ); + } + else { + IF_VERBOSE(2, verbose_stream() << "can't project:" << mk_pp(m_v, m) << "\n";); + TRACE ("qe", tout << "Failed to project: " << mk_pp (m_v, m) << "\n";); + rem_arr_vars.push_back(m_v); + } + } + arr_vars.reset (); + arr_vars.append (rem_arr_vars); + aux_vars.append (m_aux_vars); + } + }; + + + class array_select_reducer { + ast_manager& m; + array_util m_arr_u; + obj_map m_cache; + expr_ref_vector m_pinned; // to ensure a reference + expr_ref_vector m_idx_lits; + model_ref M; + model_evaluator_array_util m_mev; + th_rewriter m_rw; + ast_mark m_arr_test; + ast_mark m_has_stores; + bool m_reduce_all_selects; + + void reset () { + m_cache.reset (); + m_pinned.reset (); + m_idx_lits.reset (); + M = 0; + m_arr_test.reset (); + m_has_stores.reset (); + m_reduce_all_selects = false; + } + + bool is_equals (expr *e1, expr *e2) { + if (e1 == e2) return true; + expr_ref val1 (m), val2 (m); + m_mev.eval (*M, e1, val1); + m_mev.eval (*M, e2, val2); + return (val1 == val2); + } + + void add_idx_cond (expr_ref& cond) { + m_rw (cond); + if (!m.is_true (cond)) m_idx_lits.push_back (cond); + } + + bool has_stores (expr* e) { + if (m_reduce_all_selects) return true; + return m_has_stores.is_marked (e); + } + + void mark_stores (app* a, bool args_have_stores) { + if (m_reduce_all_selects) return; + if (args_have_stores || + (m_arr_u.is_store (a) && m_arr_test.is_marked (a->get_arg (0)))) { + m_has_stores.mark (a, true); + } + } + + bool reduce (expr_ref& e) { + if (!is_app (e)) return true; + + expr *r = 0; + if (m_cache.find (e, r)) { + e = r; + return true; + } + + ptr_vector todo; + todo.push_back (to_app (e)); + + while (!todo.empty ()) { + app *a = todo.back (); + unsigned sz = todo.size (); + expr_ref_vector args (m); + bool dirty = false; + bool args_have_stores = false; + + for (unsigned i = 0; i < a->get_num_args (); ++i) { + expr *arg = a->get_arg (i); + expr *narg = 0; + + if (!is_app (arg)) args.push_back (arg); + else if (m_cache.find (arg, narg)) { + args.push_back (narg); + dirty |= (arg != narg); + if (!args_have_stores && has_stores (narg)) { + args_have_stores = true; + } + } + else { + todo.push_back (to_app (arg)); + } + } + + if (todo.size () > sz) continue; + todo.pop_back (); + + if (dirty) { + r = m.mk_app (a->get_decl (), args.size (), args.c_ptr ()); + m_pinned.push_back (r); + } + else r = a; + + if (m_arr_u.is_select (r) && has_stores (to_app (r)->get_arg (0))) { + r = reduce_core (to_app(r)); + } + else { + mark_stores (to_app (r), args_have_stores); + } + + m_cache.insert (a, r); + } + + SASSERT (r); + e = r; + return true; + } + + expr* reduce_core (app *a) { + if (!m_arr_u.is_store (a->get_arg (0))) return a; + + SASSERT (a->get_num_args () == 2 && "Multi-dimensional arrays are not supported"); + expr* array = a->get_arg (0); + expr* j = a->get_arg (1); + + while (m_arr_u.is_store (array)) { + a = to_app (array); + expr* idx = a->get_arg (1); + expr_ref cond (m); + + if (is_equals (idx, j)) { + cond = m.mk_eq (idx, j); + add_idx_cond (cond); + return a->get_arg (2); + } + else { + cond = m.mk_not (m.mk_eq (idx, j)); + add_idx_cond (cond); + array = a->get_arg (0); + } + } + + expr* args[2] = {array, j}; + expr* r = m_arr_u.mk_select (2, args); + m_pinned.push_back (r); + return r; + } + + void mk_result (expr_ref& fml) { + // conjoin idx lits + expr_ref_vector lits (m); + lits.append (m_idx_lits); + lits.push_back (fml); + fml = m.mk_and (lits.size (), lits.c_ptr ()); + // simplify all trivial expressions introduced + m_rw (fml); + + TRACE ("qe", + tout << "after reducing selects:\n"; + tout << mk_pp (fml, m) << "\n"; + ); + } + + public: + + array_select_reducer (ast_manager& m): + m (m), + m_arr_u (m), + m_pinned (m), + m_idx_lits (m), + m_mev (m), + m_rw (m), + m_reduce_all_selects (false) + {} + + void operator () (model& mdl, app_ref_vector const& arr_vars, expr_ref& fml, bool reduce_all_selects = false) { + if (!reduce_all_selects && arr_vars.empty ()) return; + + reset (); + M = &mdl; + m_reduce_all_selects = reduce_all_selects; + + // mark vars to eliminate + for (unsigned i = 0; i < arr_vars.size (); i++) { + m_arr_test.mark (arr_vars.get (i), true); + } + + // assume all arr_vars are of array sort + // and assume no store equalities on arr_vars + if (reduce (fml)) { + mk_result (fml); + } + else { + IF_VERBOSE(2, verbose_stream() << "can't project arrays:" << "\n";); + TRACE ("qe", tout << "Failed to project arrays\n";); + } + } + }; + + class array_project_selects_util { + typedef obj_map*> sel_map; + + ast_manager& m; + array_util m_arr_u; + arith_util m_ari_u; + sel_map m_sel_terms; + // representative indices for eliminating selects + expr_ref_vector m_idx_reprs; + expr_ref_vector m_idx_vals; + app_ref_vector m_sel_consts; + expr_ref_vector m_idx_lits; + model_ref M; + model_evaluator_array_util m_mev; + expr_safe_replace m_sub; + ast_mark m_arr_test; + + void reset () { + m_sel_terms.reset (); + m_idx_reprs.reset (); + m_idx_vals.reset (); + m_sel_consts.reset (); + m_idx_lits.reset (); + M = 0; + m_sub.reset (); + m_arr_test.reset (); + } + + /** + * collect sel terms on array vars as given by m_arr_test + */ + void collect_selects (expr* fml) { + if (!is_app (fml)) return; + ast_mark done; + ptr_vector todo; + todo.push_back (to_app (fml)); + while (!todo.empty ()) { + app* a = todo.back (); + if (done.is_marked (a)) { + todo.pop_back (); + continue; + } + unsigned num_args = a->get_num_args (); + bool all_done = true; + for (unsigned i = 0; i < num_args; i++) { + expr* arg = a->get_arg (i); + if (!done.is_marked (arg) && is_app (arg)) { + todo.push_back (to_app (arg)); + all_done = false; + } + } + if (!all_done) continue; + todo.pop_back (); + if (m_arr_u.is_select (a)) { + expr* arr = a->get_arg (0); + if (m_arr_test.is_marked (arr)) { + ptr_vector* lst = m_sel_terms.find (to_app (arr));; + lst->push_back (a); + } + } + done.mark (a, true); + } + } + + /** + * model based ackermannization for sel terms of some array + * + * update sub with val consts for sel terms + */ + void ackermann (ptr_vector const& sel_terms) { + if (sel_terms.empty ()) return; + + expr* v = sel_terms.get (0)->get_arg (0); // array variable + sort* v_sort = m.get_sort (v); + sort* val_sort = get_array_range (v_sort); + sort* idx_sort = get_array_domain (v_sort, 0); + (void) idx_sort; + + unsigned start = m_idx_reprs.size (); // append at the end + + for (unsigned i = 0; i < sel_terms.size (); i++) { + app* a = sel_terms.get (i); + expr* idx = a->get_arg (1); + expr_ref val (m); + m_mev.eval (*M, idx, val); + + bool is_new = true; + for (unsigned j = start; j < m_idx_vals.size (); j++) { + if (m_idx_vals.get (j) == val) { + // idx belongs to the jth equivalence class; + // substitute sel term with ith sel const + expr* c = m_sel_consts.get (j); + m_sub.insert (a, c); + // add equality (idx == repr) + expr* repr = m_idx_reprs.get (j); + m_idx_lits.push_back (m.mk_eq (idx, repr)); + + is_new = false; + break; + } + } + if (is_new) { + // new repr, val, and sel const + m_idx_reprs.push_back (idx); + m_idx_vals.push_back (val); + app_ref c (m.mk_fresh_const ("sel", val_sort), m); + m_sel_consts.push_back (c); + // substitute sel term with new const + m_sub.insert (a, c); + // extend M to include c + m_mev.eval (*M, a, val); + M->register_decl (c->get_decl (), val); + } + } + + // sort reprs by their value and add a chain of strict inequalities + + unsigned num_reprs = m_idx_reprs.size () - start; + if (num_reprs == 0) return; + + SASSERT ((m_ari_u.is_real (idx_sort) || m_ari_u.is_int (idx_sort)) + && "Unsupported index sort: neither real nor int"); + + // using insertion sort + unsigned end = start + num_reprs; + for (unsigned i = start+1; i < end; i++) { + expr_ref repr(m), val(m); + repr = m_idx_reprs.get (i); + val = m_idx_vals.get (i); + unsigned j = i; + for (; j > start; j--) { + rational j_val, jm1_val; + VERIFY (m_ari_u.is_numeral (val, j_val)); + VERIFY (m_ari_u.is_numeral (m_idx_vals.get (j-1), jm1_val)); + if (j_val >= jm1_val) break; + m_idx_reprs[j] = m_idx_reprs.get (j-1); + m_idx_vals[j] = m_idx_vals.get (j-1); + } + m_idx_reprs[j] = repr; + m_idx_vals[j] = val; + } + + for (unsigned i = start; i < end-1; i++) { + m_idx_lits.push_back (m_ari_u.mk_lt (m_idx_reprs.get (i), + m_idx_reprs.get (i+1))); + } + } + + void mk_result (expr_ref& fml) { + // conjoin idx lits + expr_ref_vector lits (m); + lits.append (m_idx_lits); + lits.push_back (fml); + fml = m.mk_and (lits.size (), lits.c_ptr ()); + + // substitute for sel terms + m_sub (fml); + + TRACE ("qe", + tout << "after projection of selects:\n"; + tout << mk_pp (fml, m) << "\n"; + ); + } + + /** + * project selects + * populates idx lits and obtains substitution for sel terms + */ + bool project (expr_ref& fml) { + // collect sel terms -- populate the map m_sel_terms + collect_selects (fml); + + // model based ackermannization + sel_map::iterator begin = m_sel_terms.begin (), + end = m_sel_terms.end (); + for (sel_map::iterator it = begin; it != end; it++) { + TRACE ("qe", + tout << "ackermann for var: " << mk_pp (it->m_key, m) << "\n"; + ); + ackermann (*(it->m_value)); + } + + TRACE ("qe", + tout << "idx lits:\n"; + for (unsigned i = 0; i < m_idx_lits.size (); i++) { + tout << mk_pp (m_idx_lits.get (i), m) << "\n"; + } + ); + + return true; + } + + public: + + array_project_selects_util (ast_manager& m): + m (m), + m_arr_u (m), + m_ari_u (m), + m_idx_reprs (m), + m_idx_vals (m), + m_sel_consts (m), + m_idx_lits (m), + m_mev (m), + m_sub (m) + {} + + void operator () (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars) { + reset (); + M = &mdl; + + // mark vars to eliminate + for (unsigned i = 0; i < arr_vars.size (); i++) { + m_arr_test.mark (arr_vars.get (i), true); + } + + // alloc empty map from array var to sel terms over it + for (unsigned i = 0; i < arr_vars.size (); i++) { + ptr_vector* lst = alloc (ptr_vector); + m_sel_terms.insert (arr_vars.get (i), lst); + } + + // assume all arr_vars are of array sort + // and they only appear in select terms + if (project (fml)) { + mk_result (fml); + aux_vars.append (m_sel_consts); + arr_vars.reset (); + } + else { + IF_VERBOSE(2, verbose_stream() << "can't project arrays:" << "\n";); + TRACE ("qe", tout << "Failed to project arrays\n";); + } + + // dealloc + sel_map::iterator begin = m_sel_terms.begin (), + end = m_sel_terms.end (); + for (sel_map::iterator it = begin; it != end; it++) { + dealloc (it->m_value); + } + m_sel_terms.reset (); + } + }; + + expr_ref arith_project(model& mdl, app_ref_vector& vars, expr_ref_vector const& lits) { + ast_manager& m = vars.get_manager(); + arith_project_util ap(m); + return ap(mdl, vars, lits); + } + + void arith_project(model& mdl, app_ref_vector& vars, expr_ref& fml) { + ast_manager& m = vars.get_manager(); + arith_project_util ap(m); + atom_set pos_lits, neg_lits; + is_relevant_default is_relevant; + mk_atom_default mk_atom; + get_nnf (fml, is_relevant, mk_atom, pos_lits, neg_lits); + ap(mdl, vars, fml); + } + + void arith_project(model& mdl, app_ref_vector& vars, expr_ref& fml, expr_map& map) { + ast_manager& m = vars.get_manager(); + arith_project_util ap(m); + atom_set pos_lits, neg_lits; + is_relevant_default is_relevant; + mk_atom_default mk_atom; + get_nnf (fml, is_relevant, mk_atom, pos_lits, neg_lits); + ap(mdl, vars, fml, map); + } + + void array_project_eqs (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars) { + ast_manager& m = arr_vars.get_manager (); + array_project_eqs_util ap (m); + ap (mdl, arr_vars, fml, aux_vars); + } + + void reduce_array_selects (model& mdl, app_ref_vector const& arr_vars, expr_ref& fml, bool reduce_all_selects) { + ast_manager& m = arr_vars.get_manager (); + array_select_reducer ap (m); + ap (mdl, arr_vars, fml, reduce_all_selects); + } + + void reduce_array_selects (model& mdl, expr_ref& fml) { + ast_manager& m = fml.get_manager (); + app_ref_vector _tmp (m); + reduce_array_selects (mdl, _tmp, fml, true); + } + + void array_project_selects (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars) { + ast_manager& m = arr_vars.get_manager (); + array_project_selects_util ap (m); + ap (mdl, arr_vars, fml, aux_vars); + } + + void array_project (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars, bool reduce_all_selects) { + // 1. project array equalities + array_project_eqs (mdl, arr_vars, fml, aux_vars); + TRACE ("qe", + ast_manager& m = fml.get_manager (); + tout << "Projected array eqs:\n" << mk_pp (fml, m) << "\n"; + tout << "Remaining array vars:\n"; + for (unsigned i = 0; i < arr_vars.size (); i++) { + tout << mk_pp (arr_vars.get (i), m) << "\n"; + } + tout << "Aux vars:\n"; + for (unsigned i = 0; i < aux_vars.size (); i++) { + tout << mk_pp (aux_vars.get (i), m) << "\n"; + } + ); + + // 2. reduce selects + if (reduce_all_selects) { + reduce_array_selects (mdl, fml); + } + else { + reduce_array_selects (mdl, arr_vars, fml); + } + TRACE ("qe", + ast_manager& m = fml.get_manager (); + tout << "Reduced selects:\n" << mk_pp (fml, m) << "\n"; + ); + + // 3. project selects using model based ackermannization + array_project_selects (mdl, arr_vars, fml, aux_vars); + TRACE ("qe", + ast_manager& m = fml.get_manager (); + tout << "Projected array selects:\n" << mk_pp (fml, m) << "\n"; + tout << "All aux vars:\n"; + for (unsigned i = 0; i < aux_vars.size (); i++) { + tout << mk_pp (aux_vars.get (i), m) << "\n"; + } + ); + } + +} diff --git a/src/muz/spacer/spacer_qe_project.h b/src/muz/spacer/spacer_qe_project.h new file mode 100644 index 000000000..b923dc3c7 --- /dev/null +++ b/src/muz/spacer/spacer_qe_project.h @@ -0,0 +1,49 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_qe_project.h + +Abstract: + + Model-based projection + +Author: + + Anvesh Komuravelli + Arie Gurfinkel (arie) + +Notes: + +--*/ +#ifndef SPACER_QE_PROJECT_H_ +#define SPACER_QE_PROJECT_H_ + +#include "model/model.h" +#include "ast/expr_map.h" + +namespace qe { + /** + Loos-Weispfenning model-based projection for a basic conjunction. + Lits is a vector of literals. + return vector of variables that could not be projected. + */ + expr_ref arith_project(model& model, app_ref_vector& vars, expr_ref_vector const& lits); + + void arith_project(model& model, app_ref_vector& vars, expr_ref& fml); + + void arith_project(model& model, app_ref_vector& vars, expr_ref& fml, expr_map& map); + + void array_project_eqs (model& model, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars); + + void reduce_array_selects (model& mdl, app_ref_vector const& arr_vars, expr_ref& fml, bool reduce_all_selects = false); + + void reduce_array_selects (model& mdl, expr_ref& fml); + + void array_project_selects (model& model, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars); + + void array_project (model& model, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars, bool reduce_all_selects = false); +}; + +#endif diff --git a/src/muz/spacer/spacer_smt_context_manager.cpp b/src/muz/spacer/spacer_smt_context_manager.cpp new file mode 100644 index 000000000..e6ab2c883 --- /dev/null +++ b/src/muz/spacer/spacer_smt_context_manager.cpp @@ -0,0 +1,79 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + spacer_smt_context_manager.cpp + +Abstract: + + Manager of smt contexts + +Author: + + Nikolaj Bjorner (nbjorner) 2011-11-26. + Arie Gurfinkel +Revision History: + +--*/ + + +#include "ast/ast_pp.h" +#include "ast/ast_pp_util.h" +#include "ast/ast_smt_pp.h" + +#include "smt/smt_context.h" +#include "smt/params/smt_params.h" + +#include "muz/spacer/spacer_util.h" +#include "muz/spacer/spacer_smt_context_manager.h" +namespace spacer { + + + + +smt_context_manager::smt_context_manager(ast_manager &m, + unsigned max_num_contexts, + const params_ref &p) : + m_fparams(p), + m(m), + m_max_num_contexts(max_num_contexts), + m_num_contexts(0) { m_stats.reset();} + + +smt_context_manager::~smt_context_manager() +{ + std::for_each(m_solvers.begin(), m_solvers.end(), + delete_proc()); +} + +virtual_solver* smt_context_manager::mk_fresh() +{ + ++m_num_contexts; + virtual_solver_factory *solver_factory = 0; + + if (m_max_num_contexts == 0 || m_solvers.size() < m_max_num_contexts) { + m_solvers.push_back(alloc(spacer::virtual_solver_factory, m, m_fparams)); + solver_factory = m_solvers.back(); + } else + { solver_factory = m_solvers[(m_num_contexts - 1) % m_max_num_contexts]; } + + return solver_factory->mk_solver(); +} + +void smt_context_manager::collect_statistics(statistics& st) const +{ + for (unsigned i = 0; i < m_solvers.size(); ++i) { + m_solvers[i]->collect_statistics(st); + } +} + +void smt_context_manager::reset_statistics() +{ + for (unsigned i = 0; i < m_solvers.size(); ++i) { + m_solvers[i]->reset_statistics(); + } +} + + +}; diff --git a/src/muz/spacer/spacer_smt_context_manager.h b/src/muz/spacer/spacer_smt_context_manager.h new file mode 100644 index 000000000..0df9bc77b --- /dev/null +++ b/src/muz/spacer/spacer_smt_context_manager.h @@ -0,0 +1,68 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + spacer_smt_context_manager.h + +Abstract: + + Manager of smt contexts + +Author: + + Nikolaj Bjorner (nbjorner) 2011-11-26. + Arie Gurfinkel +Revision History: + +--*/ + +#ifndef _SPACER_SMT_CONTEXT_MANAGER_H_ +#define _SPACER_SMT_CONTEXT_MANAGER_H_ + +#include "util/stopwatch.h" + +#include "smt/smt_kernel.h" +#include "muz/base/dl_util.h" +#include "muz/spacer/spacer_virtual_solver.h" + +namespace spacer { + +class smt_context_manager { + + struct stats { + unsigned m_num_smt_checks; + unsigned m_num_sat_smt_checks; + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + }; + + smt_params m_fparams; + ast_manager& m; + unsigned m_max_num_contexts; + ptr_vector m_solvers; + unsigned m_num_contexts; + + + stats m_stats; + stopwatch m_check_watch; + stopwatch m_check_sat_watch; + +public: + smt_context_manager(ast_manager& m, unsigned max_num_contexts = 1, + const params_ref &p = params_ref::get_empty()); + + ~smt_context_manager(); + virtual_solver* mk_fresh(); + + void collect_statistics(statistics& st) const; + void reset_statistics(); + + void updt_params(params_ref const &p) { m_fparams.updt_params(p); } + smt_params& fparams() {return m_fparams;} + +}; + +}; + +#endif diff --git a/src/muz/spacer/spacer_sym_mux.cpp b/src/muz/spacer/spacer_sym_mux.cpp new file mode 100644 index 000000000..ee1d3726d --- /dev/null +++ b/src/muz/spacer/spacer_sym_mux.cpp @@ -0,0 +1,608 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + sym_mux.cpp + +Abstract: + + A symbol multiplexer that helps with having multiple versions of each of a set of symbols. + +Author: + + Krystof Hoder (t-khoder) 2011-9-8. + +Revision History: + +--*/ + +#include "ast/ast_pp.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" + +#include "model/model.h" + +#include "muz/spacer/spacer_util.h" +#include "muz/spacer/spacer_sym_mux.h" + +using namespace spacer; + +sym_mux::sym_mux(ast_manager & m, const std::vector & suffixes) + : m(m), m_ref_holder(m), m_next_sym_suffix_idx(0), m_suffixes(suffixes) +{ + for (std::string const& s : m_suffixes) { + m_used_suffixes.insert(symbol(s.c_str())); + } +} + +std::string sym_mux::get_suffix(unsigned i) const +{ + while (m_suffixes.size() <= i) { + std::string new_suffix; + symbol new_syffix_sym; + do { + std::stringstream stm; + stm << '_' << m_next_sym_suffix_idx; + m_next_sym_suffix_idx++; + new_suffix = stm.str(); + new_syffix_sym = symbol(new_suffix.c_str()); + } while (m_used_suffixes.contains(new_syffix_sym)); + m_used_suffixes.insert(new_syffix_sym); + m_suffixes.push_back(new_suffix); + } + return m_suffixes[i]; +} + +void sym_mux::create_tuple(func_decl* prefix, unsigned arity, sort * const * domain, sort * range, + unsigned tuple_length, decl_vector & tuple) +{ + SASSERT(tuple_length > 0); + while (tuple.size() < tuple_length) { + tuple.push_back(0); + } + SASSERT(tuple.size() == tuple_length); + std::string pre = prefix->get_name().str(); + for (unsigned i = 0; i < tuple_length; i++) { + + if (tuple[i] != 0) { + SASSERT(tuple[i]->get_arity() == arity); + SASSERT(tuple[i]->get_range() == range); + //domain should match as well, but we won't bother checking an array equality + } else { + std::string name = pre + get_suffix(i); + tuple[i] = m.mk_func_decl(symbol(name.c_str()), arity, domain, range); + } + m_ref_holder.push_back(tuple[i]); + m_sym2idx.insert(tuple[i], i); + m_sym2prim.insert(tuple[i], tuple[0]); + } + + m_prim2all.insert(tuple[0], tuple); + m_prefix2prim.insert(prefix, tuple[0]); + m_prim2prefix.insert(tuple[0], prefix); + m_prim_preds.push_back(tuple[0]); + m_ref_holder.push_back(prefix); +} + +void sym_mux::ensure_tuple_size(func_decl * prim, unsigned sz) const +{ + SASSERT(m_prim2all.contains(prim)); + decl_vector& tuple = m_prim2all.find_core(prim)->get_data().m_value; + SASSERT(tuple[0] == prim); + + if (sz <= tuple.size()) { return; } + + func_decl * prefix; + TRUSTME(m_prim2prefix.find(prim, prefix)); + std::string prefix_name = prefix->get_name().bare_str(); + for (unsigned i = tuple.size(); i < sz; ++i) { + std::string name = prefix_name + get_suffix(i); + func_decl * new_sym = m.mk_func_decl(symbol(name.c_str()), prefix->get_arity(), + prefix->get_domain(), prefix->get_range()); + + tuple.push_back(new_sym); + m_ref_holder.push_back(new_sym); + m_sym2idx.insert(new_sym, i); + m_sym2prim.insert(new_sym, prim); + } +} + +func_decl * sym_mux::conv(func_decl * sym, unsigned src_idx, unsigned tgt_idx) const +{ + if (src_idx == tgt_idx) { return sym; } + func_decl * prim = (src_idx == 0) ? sym : get_primary(sym); + if (tgt_idx > src_idx) { + ensure_tuple_size(prim, tgt_idx + 1); + } + decl_vector & sym_vect = m_prim2all.find_core(prim)->get_data().m_value; + SASSERT(sym_vect[src_idx] == sym); + return sym_vect[tgt_idx]; +} + + +func_decl * sym_mux::get_or_create_symbol_by_prefix(func_decl* prefix, unsigned idx, + unsigned arity, sort * const * domain, sort * range) +{ + func_decl * prim = try_get_primary_by_prefix(prefix); + if (prim) { + SASSERT(prim->get_arity() == arity); + SASSERT(prim->get_range() == range); + //domain should match as well, but we won't bother checking an array equality + + return conv(prim, 0, idx); + } + + decl_vector syms; + create_tuple(prefix, arity, domain, range, idx + 1, syms); + return syms[idx]; +} + +bool sym_mux::is_muxed_lit(expr * e, unsigned idx) const +{ + if (!is_app(e)) { return false; } + app * a = to_app(e); + if (m.is_not(a) && is_app(a->get_arg(0))) { + a = to_app(a->get_arg(0)); + } + return is_muxed(a->get_decl()); +} + + +struct sym_mux::formula_checker { + formula_checker(const sym_mux & parent, bool all, unsigned idx) : + m_parent(parent), m_all(all), m_idx(idx), + m_found_what_needed(false) + { + } + + void operator()(expr * e) + { + if (m_found_what_needed || !is_app(e)) { return; } + + func_decl * sym = to_app(e)->get_decl(); + unsigned sym_idx; + if (!m_parent.try_get_index(sym, sym_idx)) { return; } + + bool have_idx = sym_idx == m_idx; + + if (m_all ? (!have_idx) : have_idx) { + m_found_what_needed = true; + } + + } + + bool all_have_idx() const + { + SASSERT(m_all); //we were looking for the queried property + return !m_found_what_needed; + } + + bool some_with_idx() const + { + SASSERT(!m_all); //we were looking for the queried property + return m_found_what_needed; + } + +private: + const sym_mux & m_parent; + bool m_all; + unsigned m_idx; + + /** + If we check whether all muxed symbols are of given index, we look for + counter-examples, checking whether form contains a muxed symbol of an index, + we look for symbol of index m_idx. + */ + bool m_found_what_needed; +}; + +bool sym_mux::contains(expr * e, unsigned idx) const +{ + formula_checker chck(*this, false, idx); + for_each_expr(chck, m_visited, e); + m_visited.reset(); + return chck.some_with_idx(); +} + +bool sym_mux::is_homogenous_formula(expr * e, unsigned idx) const +{ + formula_checker chck(*this, true, idx); + for_each_expr(chck, m_visited, e); + m_visited.reset(); + return chck.all_have_idx(); +} + +bool sym_mux::is_homogenous(const expr_ref_vector & vect, unsigned idx) const +{ + expr * const * begin = vect.c_ptr(); + expr * const * end = begin + vect.size(); + for (expr * const * it = begin; it != end; it++) { + if (!is_homogenous_formula(*it, idx)) { + return false; + } + } + return true; +} + +class sym_mux::index_collector { + sym_mux const& m_parent; + svector m_indices; +public: + index_collector(sym_mux const& s): + m_parent(s) {} + + void operator()(expr * e) + { + if (is_app(e)) { + func_decl * sym = to_app(e)->get_decl(); + unsigned idx; + if (m_parent.try_get_index(sym, idx)) { + SASSERT(idx > 0); + --idx; + if (m_indices.size() <= idx) { + m_indices.resize(idx + 1, false); + } + m_indices[idx] = true; + } + } + } + + void extract(unsigned_vector& indices) + { + for (unsigned i = 0; i < m_indices.size(); ++i) { + if (m_indices[i]) { + indices.push_back(i); + } + } + } +}; + + + +void sym_mux::collect_indices(expr* e, unsigned_vector& indices) const +{ + indices.reset(); + index_collector collector(*this); + for_each_expr(collector, m_visited, e); + m_visited.reset(); + collector.extract(indices); +} + +class sym_mux::variable_collector { + sym_mux const& m_parent; + vector >& m_vars; +public: + variable_collector(sym_mux const& s, vector >& vars): + m_parent(s), m_vars(vars) {} + + void operator()(expr * e) + { + if (is_app(e)) { + func_decl * sym = to_app(e)->get_decl(); + unsigned idx; + if (m_parent.try_get_index(sym, idx)) { + SASSERT(idx > 0); + --idx; + if (m_vars.size() <= idx) { + m_vars.resize(idx + 1, ptr_vector()); + } + m_vars[idx].push_back(to_app(e)); + } + } + } +}; + +void sym_mux::collect_variables(expr* e, vector >& vars) const +{ + vars.reset(); + variable_collector collector(*this, vars); + for_each_expr(collector, m_visited, e); + m_visited.reset(); +} + +class sym_mux::hmg_checker { + const sym_mux & m_parent; + + bool m_found_idx; + unsigned m_idx; + bool m_multiple_indexes; + +public: + hmg_checker(const sym_mux & parent) : + m_parent(parent), m_found_idx(false), m_multiple_indexes(false) + { + } + + void operator()(expr * e) + { + if (m_multiple_indexes || !is_app(e)) { return; } + + func_decl * sym = to_app(e)->get_decl(); + unsigned sym_idx; + if (!m_parent.try_get_index(sym, sym_idx)) { return; } + + if (!m_found_idx) { + m_found_idx = true; + m_idx = sym_idx; + return; + } + if (m_idx == sym_idx) { return; } + m_multiple_indexes = true; + } + + bool has_multiple_indexes() const + { + return m_multiple_indexes; + } +}; + +bool sym_mux::is_homogenous_formula(expr * e) const +{ + hmg_checker chck(*this); + for_each_expr(chck, m_visited, e); + m_visited.reset(); + return !chck.has_multiple_indexes(); +} + + +struct sym_mux::conv_rewriter_cfg : public default_rewriter_cfg { +private: + ast_manager & m; + const sym_mux & m_parent; + unsigned m_from_idx; + unsigned m_to_idx; + bool m_homogenous; +public: + conv_rewriter_cfg(const sym_mux & parent, unsigned from_idx, unsigned to_idx, bool homogenous) + : m(parent.get_manager()), + m_parent(parent), + m_from_idx(from_idx), + m_to_idx(to_idx), + m_homogenous(homogenous) {} + + bool get_subst(expr * s, expr * & t, proof * & t_pr) + { + if (!is_app(s)) { return false; } + app * a = to_app(s); + func_decl * sym = a->get_decl(); + if (!m_parent.has_index(sym, m_from_idx)) { + (void) m_homogenous; + SASSERT(!m_homogenous || !m_parent.is_muxed(sym)); + return false; + } + func_decl * tgt = m_parent.conv(sym, m_from_idx, m_to_idx); + + t = m.mk_app(tgt, a->get_args()); + return true; + } +}; + +void sym_mux::conv_formula(expr * f, unsigned src_idx, unsigned tgt_idx, expr_ref & res, bool homogenous) const +{ + if (src_idx == tgt_idx) { + res = f; + return; + } + conv_rewriter_cfg r_cfg(*this, src_idx, tgt_idx, homogenous); + rewriter_tpl rwr(m, false, r_cfg); + rwr(f, res); +} + +struct sym_mux::shifting_rewriter_cfg : public default_rewriter_cfg { +private: + ast_manager & m; + const sym_mux & m_parent; + int m_shift; +public: + shifting_rewriter_cfg(const sym_mux & parent, int shift) + : m(parent.get_manager()), + m_parent(parent), + m_shift(shift) {} + + bool get_subst(expr * s, expr * & t, proof * & t_pr) + { + if (!is_app(s)) { return false; } + app * a = to_app(s); + func_decl * sym = a->get_decl(); + + unsigned idx; + if (!m_parent.try_get_index(sym, idx)) { + return false; + } + SASSERT(static_cast(idx) + m_shift >= 0); + func_decl * tgt = m_parent.conv(sym, idx, idx + m_shift); + t = m.mk_app(tgt, a->get_args()); + return true; + } +}; + +void sym_mux::shift_formula(expr * f, int dist, expr_ref & res) const +{ + if (dist == 0) { + res = f; + return; + } + shifting_rewriter_cfg r_cfg(*this, dist); + rewriter_tpl rwr(m, false, r_cfg); + rwr(f, res); +} + +void sym_mux::conv_formula_vector(const expr_ref_vector & vect, unsigned src_idx, unsigned tgt_idx, + expr_ref_vector & res) const +{ + res.reset(); + expr * const * begin = vect.c_ptr(); + expr * const * end = begin + vect.size(); + for (expr * const * it = begin; it != end; it++) { + expr_ref converted(m); + conv_formula(*it, src_idx, tgt_idx, converted); + res.push_back(converted); + } +} + +void sym_mux::filter_idx(expr_ref_vector & vect, unsigned idx) const +{ + unsigned i = 0; + while (i < vect.size()) { + expr* e = vect[i].get(); + if (contains(e, idx) && is_homogenous_formula(e, idx)) { + i++; + } else { + //we don't allow mixing states inside vector elements + SASSERT(!contains(e, idx)); + vect[i] = vect.back(); + vect.pop_back(); + } + } +} + +void sym_mux::partition_o_idx( + expr_ref_vector const& lits, + expr_ref_vector& o_lits, + expr_ref_vector& other, unsigned idx) const +{ + + for (unsigned i = 0; i < lits.size(); ++i) { + if (contains(lits[i], idx) && is_homogenous_formula(lits[i], idx)) { + o_lits.push_back(lits[i]); + } else { + other.push_back(lits[i]); + } + } +} + + + +class sym_mux::nonmodel_sym_checker { + const sym_mux & m_parent; + + bool m_found; +public: + nonmodel_sym_checker(const sym_mux & parent) : + m_parent(parent), m_found(false) + { + } + + void operator()(expr * e) + { + if (m_found || !is_app(e)) { return; } + + func_decl * sym = to_app(e)->get_decl(); + + if (m_parent.is_non_model_sym(sym)) { + m_found = true; + } + } + + bool found() const + { + return m_found; + } +}; + +bool sym_mux::has_nonmodel_symbol(expr * e) const +{ + nonmodel_sym_checker chck(*this); + for_each_expr(chck, e); + return chck.found(); +} + +void sym_mux::filter_non_model_lits(expr_ref_vector & vect) const +{ + unsigned i = 0; + while (i < vect.size()) { + if (!has_nonmodel_symbol(vect[i].get())) { + i++; + continue; + } + vect[i] = vect.back(); + vect.pop_back(); + } +} + +class sym_mux::decl_idx_comparator { + const sym_mux & m_parent; +public: + decl_idx_comparator(const sym_mux & parent) + : m_parent(parent) + { } + + bool operator()(func_decl * sym1, func_decl * sym2) + { + unsigned idx1, idx2; + if (!m_parent.try_get_index(sym1, idx1)) { idx1 = UINT_MAX; } + if (!m_parent.try_get_index(sym2, idx2)) { idx2 = UINT_MAX; } + + if (idx1 != idx2) { return idx1 < idx2; } + return lt(sym1->get_name(), sym2->get_name()); + } +}; + +std::string sym_mux::pp_model(const model_core & mdl) const +{ + decl_vector consts; + unsigned sz = mdl.get_num_constants(); + for (unsigned i = 0; i < sz; i++) { + func_decl * d = mdl.get_constant(i); + consts.push_back(d); + } + + std::sort(consts.begin(), consts.end(), decl_idx_comparator(*this)); + + std::stringstream res; + + decl_vector::iterator end = consts.end(); + for (decl_vector::iterator it = consts.begin(); it != end; it++) { + func_decl * d = *it; + std::string name = d->get_name().str(); + const char * arrow = " -> "; + res << name << arrow; + unsigned indent = static_cast(name.length() + strlen(arrow)); + res << mk_pp(mdl.get_const_interp(d), m, indent) << "\n"; + + if (it + 1 != end) { + unsigned idx1, idx2; + if (!try_get_index(*it, idx1)) { idx1 = UINT_MAX; } + if (!try_get_index(*(it + 1), idx2)) { idx2 = UINT_MAX; } + if (idx1 != idx2) { res << "\n"; } + } + } + return res.str(); +} + + +#if 0 + +class sym_mux::index_renamer_cfg : public default_rewriter_cfg { + const sym_mux & m_parent; + unsigned m_idx; + +public: + index_renamer_cfg(const sym_mux & p, unsigned idx) : m_parent(p), m_idx(idx) {} + + bool get_subst(expr * s, expr * & t, proof * & t_pr) + { + if (!is_app(s)) { return false; } + app * a = to_app(s); + if (a->get_family_id() != null_family_id) { + return false; + } + func_decl * sym = a->get_decl(); + unsigned idx; + if (!m_parent.try_get_index(sym, idx)) { + return false; + } + if (m_idx == idx) { + return false; + } + ast_manager& m = m_parent.get_manager(); + symbol name = symbol((sym->get_name().str() + "!").c_str()); + func_decl * tgt = m.mk_func_decl(name, sym->get_arity(), sym->get_domain(), sym->get_range()); + t = m.mk_app(tgt, a->get_num_args(), a->get_args()); + return true; + } +}; + +#endif diff --git a/src/muz/spacer/spacer_sym_mux.h b/src/muz/spacer/spacer_sym_mux.h new file mode 100644 index 000000000..892542557 --- /dev/null +++ b/src/muz/spacer/spacer_sym_mux.h @@ -0,0 +1,256 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + sym_mux.h + +Abstract: + + A symbol multiplexer that helps with having multiple versions of each of a set of symbols. + +Author: + + Krystof Hoder (t-khoder) 2011-9-8. + +Revision History: + +--*/ + +#ifndef _SYM_MUX_H_ +#define _SYM_MUX_H_ + +#include "ast/ast.h" +#include "util/map.h" +#include "util/vector.h" +#include + +class model_core; + +namespace spacer { +class sym_mux { +public: + typedef ptr_vector app_vector; + typedef ptr_vector decl_vector; +private: + typedef obj_map sym2u; + typedef obj_map sym2dv; + typedef obj_map sym2sym; + typedef obj_map sym2pred; + typedef hashtable symbols; + + ast_manager & m; + mutable ast_ref_vector m_ref_holder; + mutable expr_mark m_visited; + + mutable unsigned m_next_sym_suffix_idx; + mutable symbols m_used_suffixes; + /** Here we have default suffixes for each of the variants */ + mutable std::vector m_suffixes; + + + /** + Primary symbol is the 0-th variant. This member maps from primary symbol + to vector of all its variants (including the primary variant). + */ + sym2dv m_prim2all; + + /** + For each symbol contains its variant index + */ + mutable sym2u m_sym2idx; + /** + For each symbol contains its primary variant + */ + mutable sym2sym m_sym2prim; + + /** + Maps prefixes passed to the create_tuple to + the primary symbol created from it. + */ + sym2pred m_prefix2prim; + + /** + Maps pripary symbols to prefixes that were used to create them. + */ + sym2sym m_prim2prefix; + + decl_vector m_prim_preds; + + obj_hashtable m_non_model_syms; + + struct formula_checker; + struct conv_rewriter_cfg; + struct shifting_rewriter_cfg; + class decl_idx_comparator; + class hmg_checker; + class nonmodel_sym_checker; + class index_renamer_cfg; + class index_collector; + class variable_collector; + + std::string get_suffix(unsigned i) const; + void ensure_tuple_size(func_decl * prim, unsigned sz) const; + + expr_ref isolate_o_idx(expr* e, unsigned idx) const; +public: + sym_mux(ast_manager & m, const std::vector & suffixes); + + ast_manager & get_manager() const { return m; } + + bool is_muxed(func_decl * sym) const { return m_sym2idx.contains(sym); } + + bool try_get_index(func_decl * sym, unsigned & idx) const + { + return m_sym2idx.find(sym, idx); + } + + bool has_index(func_decl * sym, unsigned idx) const + { + unsigned actual_idx; + return try_get_index(sym, actual_idx) && idx == actual_idx; + } + + /** Return primary symbol. sym must be muxed. */ + func_decl * get_primary(func_decl * sym) const + { + func_decl * prim; + TRUSTME(m_sym2prim.find(sym, prim)); + return prim; + } + + /** + Return primary symbol created from prefix, or 0 if the prefix was never used. + */ + func_decl * try_get_primary_by_prefix(func_decl* prefix) const + { + func_decl * res; + if(!m_prefix2prim.find(prefix, res)) { + return 0; + } + return res; + } + + /** + Return symbol created from prefix, or 0 if the prefix was never used. + */ + func_decl * try_get_by_prefix(func_decl* prefix, unsigned idx) const + { + func_decl * prim = try_get_primary_by_prefix(prefix); + if(!prim) { + return 0; + } + return conv(prim, 0, idx); + } + + /** + Marks symbol as non-model which means it will not appear in models collected by + get_muxed_cube_from_model function. + This is to take care of auxiliary symbols introduced by the disjunction relations + to relativize lemmas coming from disjuncts. + */ + void mark_as_non_model(func_decl * sym) + { + SASSERT(is_muxed(sym)); + m_non_model_syms.insert(get_primary(sym)); + } + + func_decl * get_or_create_symbol_by_prefix(func_decl* prefix, unsigned idx, + unsigned arity, sort * const * domain, sort * range); + + + + bool is_muxed_lit(expr * e, unsigned idx) const; + + bool is_non_model_sym(func_decl * s) const + { + return is_muxed(s) && m_non_model_syms.contains(get_primary(s)); + } + + /** + Create a multiplexed tuple of propositional constants. + Symbols may be suplied in the tuple vector, + those beyond the size of the array and those with corresponding positions + assigned to zero will be created using prefix. + Tuple length must be at least one. + */ + void create_tuple(func_decl* prefix, unsigned arity, sort * const * domain, sort * range, + unsigned tuple_length, decl_vector & tuple); + + /** + Return true if the only multiplexed symbols which e contains are of index idx. + */ + bool is_homogenous_formula(expr * e, unsigned idx) const; + bool is_homogenous(const expr_ref_vector & vect, unsigned idx) const; + + /** + Return true if all multiplexed symbols which e contains are of one index. + */ + bool is_homogenous_formula(expr * e) const; + + /** + Return true if expression e contains a muxed symbol of index idx. + */ + bool contains(expr * e, unsigned idx) const; + + /** + Collect indices used in expression. + */ + void collect_indices(expr* e, unsigned_vector& indices) const; + + /** + Collect used variables of each index. + */ + void collect_variables(expr* e, vector >& vars) const; + + /** + Convert symbol sym which has to be of src_idx variant into variant tgt_idx. + */ + func_decl * conv(func_decl * sym, unsigned src_idx, unsigned tgt_idx) const; + + + /** + Convert src_idx symbols in formula f variant into tgt_idx. + If homogenous is true, formula cannot contain symbols of other variants. + */ + void conv_formula(expr * f, unsigned src_idx, unsigned tgt_idx, expr_ref & res, bool homogenous = true) const; + void conv_formula_vector(const expr_ref_vector & vect, unsigned src_idx, unsigned tgt_idx, + expr_ref_vector & res) const; + + /** + Shifts the muxed symbols in f by dist. Dist can be negative, but it should never shift + symbol index to a negative value. + */ + void shift_formula(expr * f, int dist, expr_ref & res) const; + + /** + Remove from vect literals (atoms or negations of atoms) of symbols + that contain multiplexed symbols with indexes other than idx. + + Each of the literals can contain only symbols multiplexed with one index + (this trivially holds if the literals are propositional). + + Order of elements in vect may be modified by this function + */ + void filter_idx(expr_ref_vector & vect, unsigned idx) const; + + /** + Partition literals into o_literals and others. + */ + void partition_o_idx(expr_ref_vector const& lits, + expr_ref_vector& o_lits, + expr_ref_vector& other, unsigned idx) const; + + bool has_nonmodel_symbol(expr * e) const; + void filter_non_model_lits(expr_ref_vector & vect) const; + + func_decl * const * begin_prim_preds() const { return m_prim_preds.begin(); } + func_decl * const * end_prim_preds() const { return m_prim_preds.end(); } + + void get_muxed_cube_from_model(const model_core & model, expr_ref_vector & res) const; + + std::string pp_model(const model_core & mdl) const; +}; +} + +#endif diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp new file mode 100644 index 000000000..d478b1e8f --- /dev/null +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -0,0 +1,355 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_unsat_core_learner.cpp + +Abstract: + itp cores + +Author: + Bernhard Gleiss + +Revision History: + + +--*/ +#include + +#include "muz/spacer/spacer_unsat_core_learner.h" +#include "muz/spacer/spacer_unsat_core_plugin.h" +#include "ast/for_each_expr.h" + +namespace spacer +{ + + +unsat_core_learner::~unsat_core_learner() +{ + std::for_each(m_plugins.begin(), m_plugins.end(), delete_proc()); + +} + +void unsat_core_learner::register_plugin(unsat_core_plugin* plugin) +{ + m_plugins.push_back(plugin); +} + +void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, expr_ref_vector& unsat_core) +{ + // transform proof in order to get a proof which is better suited for unsat-core-extraction + proof_ref pr(root, m); + + reduce_hypotheses(pr); + STRACE("spacer.unsat_core_learner", + verbose_stream() << "Reduced proof:\n" << mk_ismt2_pp(pr, m) << "\n"; + ); + + // compute symbols occuring in B + collect_symbols_b(asserted_b); + + // traverse proof + proof_post_order it(root, m); + while (it.hasNext()) + { + proof* currentNode = it.next(); + + if (m.get_num_parents(currentNode) == 0) + { + switch(currentNode->get_decl_kind()) + { + + case PR_ASSERTED: // currentNode is an axiom + { + if (asserted_b.contains(m.get_fact(currentNode))) + { + m_b_mark.mark(currentNode, true); + } + else + { + m_a_mark.mark(currentNode, true); + } + break; + } + // currentNode is a hypothesis: + case PR_HYPOTHESIS: + { + m_h_mark.mark(currentNode, true); + break; + } + default: + { + break; + } + } + } + else + { + // collect from parents whether derivation of current node contains A-axioms, B-axioms and hypothesis + bool need_to_mark_a = false; + bool need_to_mark_b = false; + bool need_to_mark_h = false; + bool need_to_mark_closed = true; + + for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) + { + SASSERT(m.is_proof(currentNode->get_arg(i))); + proof* premise = to_app(currentNode->get_arg(i)); + + need_to_mark_a = need_to_mark_a || m_a_mark.is_marked(premise); + need_to_mark_b = need_to_mark_b || m_b_mark.is_marked(premise); + need_to_mark_h = need_to_mark_h || m_h_mark.is_marked(premise); + need_to_mark_closed = need_to_mark_closed && (!m_b_mark.is_marked(premise) || m_closed.is_marked(premise)); + } + + // if current node is application of lemma, we know that all hypothesis are removed + if(currentNode->get_decl_kind() == PR_LEMMA) + { + need_to_mark_h = false; + } + + // save results + m_a_mark.mark(currentNode, need_to_mark_a); + m_b_mark.mark(currentNode, need_to_mark_b); + m_h_mark.mark(currentNode, need_to_mark_h); + m_closed.mark(currentNode, need_to_mark_closed); + } + + // we have now collected all necessary information, so we can visit the node + // if the node mixes A-reasoning and B-reasoning and contains non-closed premises + if (m_a_mark.is_marked(currentNode) && m_b_mark.is_marked(currentNode) && !m_closed.is_marked(currentNode)) + { + compute_partial_core(currentNode); // then we need to compute a partial core + // SASSERT(!(m_a_mark.is_marked(currentNode) && m_b_mark.is_marked(currentNode)) || m_closed.is_marked(currentNode)); TODO: doesn't hold anymore if we do the mincut-thing! + } + } + + // give plugins chance to finalize their unsat-core-computation + finalize(); + + // TODO: remove duplicates from unsat core? + + bool debug_proof = false; + if(debug_proof) + { + // print proof for debugging + verbose_stream() << "\n\nProof:\n"; + std::unordered_map id_to_small_id; + unsigned counter = 0; + + proof_post_order it2(root, m); + while (it2.hasNext()) + { + proof* currentNode = it2.next(); + + SASSERT(id_to_small_id.find(currentNode->get_id()) == id_to_small_id.end()); + id_to_small_id.insert(std::make_pair(currentNode->get_id(), counter)); + + verbose_stream() << counter << " "; + verbose_stream() << "["; + if (is_a_marked(currentNode)) + { + verbose_stream() << "a"; + } + if (is_b_marked(currentNode)) + { + verbose_stream() << "b"; + } + if (is_h_marked(currentNode)) + { + verbose_stream() << "h"; + } + if (is_closed(currentNode)) + { + verbose_stream() << "c"; + } + verbose_stream() << "] "; + + if (m.get_num_parents(currentNode) == 0) + { + switch (currentNode->get_decl_kind()) + { + case PR_ASSERTED: + verbose_stream() << "asserted"; + break; + case PR_HYPOTHESIS: + verbose_stream() << "hypothesis"; + break; + default: + verbose_stream() << "unknown axiom-type"; + break; + } + } + else + { + if (currentNode->get_decl_kind() == PR_LEMMA) + { + verbose_stream() << "lemma"; + } + else if (currentNode->get_decl_kind() == PR_TH_LEMMA) + { + verbose_stream() << "th_lemma"; + func_decl* d = currentNode->get_decl(); + symbol sym; + if (d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step + d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", + d->get_parameter(1).is_symbol(sym) && sym == "farkas") + { + verbose_stream() << "(farkas)"; + } + else + { + verbose_stream() << "(other)"; + } + } + else + { + verbose_stream() << "step"; + } + verbose_stream() << " from "; + for (int i = m.get_num_parents(currentNode) - 1; i >= 0 ; --i) + { + proof* premise = to_app(currentNode->get_arg(i)); + unsigned premise_small_id = id_to_small_id[premise->get_id()]; + if (i > 0) + { + verbose_stream() << premise_small_id << ", "; + } + else + { + verbose_stream() << premise_small_id; + } + + } + } + if (currentNode->get_decl_kind() == PR_TH_LEMMA || (is_a_marked(currentNode) && is_b_marked(currentNode)) || is_h_marked(currentNode) || (!is_a_marked(currentNode) && !is_b_marked(currentNode))) + { + verbose_stream() << std::endl; + } + else + { + verbose_stream() << ": " << mk_pp(m.get_fact(currentNode), m) << std::endl; + } + ++counter; + } + } + // move all lemmas into vector + for (expr* const* it = m_unsat_core.begin(); it != m_unsat_core.end(); ++it) + { + unsat_core.push_back(*it); + } +} + +void unsat_core_learner::compute_partial_core(proof* step) +{ + for (unsat_core_plugin** it=m_plugins.begin(), **end = m_plugins.end (); it != end && !m_closed.is_marked(step); ++it) + { + unsat_core_plugin* plugin = *it; + plugin->compute_partial_core(step); + } +} + +void unsat_core_learner::finalize() +{ + for (unsat_core_plugin** it=m_plugins.begin(); it != m_plugins.end(); ++it) + { + unsat_core_plugin* plugin = *it; + plugin->finalize(); + } +} + + +bool unsat_core_learner::is_a_marked(proof* p) +{ + return m_a_mark.is_marked(p); +} +bool unsat_core_learner::is_b_marked(proof* p) +{ + return m_b_mark.is_marked(p); +} +bool unsat_core_learner::is_h_marked(proof* p) +{ + return m_h_mark.is_marked(p); +} +bool unsat_core_learner::is_closed(proof*p) +{ + return m_closed.is_marked(p); +} +void unsat_core_learner::set_closed(proof* p, bool value) +{ + m_closed.mark(p, value); +} + + void unsat_core_learner::add_lemma_to_core(expr* lemma) + { + m_unsat_core.push_back(lemma); + } + + +class collect_pure_proc { + func_decl_set& m_symbs; +public: + collect_pure_proc(func_decl_set& s):m_symbs(s) {} + + void operator()(app* a) { + if (a->get_family_id() == null_family_id) { + m_symbs.insert(a->get_decl()); + } + } + void operator()(var*) {} + void operator()(quantifier*) {} +}; + +void unsat_core_learner::collect_symbols_b(expr_set axioms_b) +{ + expr_mark visited; + collect_pure_proc proc(m_symbols_b); + for (expr_set::iterator it = axioms_b.begin(); it != axioms_b.end(); ++it) + { + for_each_expr(proc, visited, *it); + } +} + +class is_pure_expr_proc { + func_decl_set const& m_symbs; + array_util m_au; +public: + struct non_pure {}; + + is_pure_expr_proc(func_decl_set const& s, ast_manager& m): + m_symbs(s), + m_au (m) + {} + + void operator()(app* a) { + if (a->get_family_id() == null_family_id) { + if (!m_symbs.contains(a->get_decl())) { + throw non_pure(); + } + } + else if (a->get_family_id () == m_au.get_family_id () && + a->is_app_of (a->get_family_id (), OP_ARRAY_EXT)) { + throw non_pure(); + } + } + void operator()(var*) {} + void operator()(quantifier*) {} +}; + +bool unsat_core_learner::only_contains_symbols_b(expr* expr) const +{ + is_pure_expr_proc proc(m_symbols_b, m); + try { + for_each_expr(proc, expr); + } + catch (is_pure_expr_proc::non_pure) + { + return false; + } + return true; +} + + + +} diff --git a/src/muz/spacer/spacer_unsat_core_learner.h b/src/muz/spacer/spacer_unsat_core_learner.h new file mode 100644 index 000000000..a7c9f6aa7 --- /dev/null +++ b/src/muz/spacer/spacer_unsat_core_learner.h @@ -0,0 +1,107 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_unsat_core_learner.h + +Abstract: + itp cores + +Author: + Bernhard Gleiss + +Revision History: + + +--*/ +#ifndef _SPACER_UNSAT_CORE_LEARNER_H_ +#define _SPACER_UNSAT_CORE_LEARNER_H_ + +#include "ast/ast.h" +#include "muz/spacer/spacer_util.h" +#include "ast/proofs/proof_utils.h" + +namespace spacer { + + + class unsat_core_plugin; + class unsat_core_learner + { + typedef obj_hashtable expr_set; + + public: + unsat_core_learner(ast_manager& m) : m(m), m_unsat_core(m) {}; + virtual ~unsat_core_learner(); + + ast_manager& m; + + /* + * register a plugin for computation of partial unsat cores + * currently plugins are called in the order they have been registered + */ + void register_plugin(unsat_core_plugin* plugin); + + /* + * compute unsat core using the registered unsat-core-plugins + */ + void compute_unsat_core(proof* root, expr_set& asserted_b, expr_ref_vector& unsat_core); + + /* + * getter/setter methods for data structures exposed to plugins + * the following invariants can be assumed and need to be maintained by the plugins: + * - a node is a-marked iff it is derived using at least one asserted proof step from A. + * - a node is b-marked iff its derivation contains no asserted proof steps from A and + * no hypothesis (with the additional complication that lemmas conceptually remove hypothesis) + * - a node is h-marked, iff it is derived using at least one hypothesis + * - a node is closed, iff it has already been interpolated, i.e. its contribution is + * already covered by the unsat-core. + */ + bool is_a_marked(proof* p); + bool is_b_marked(proof* p); + bool is_h_marked(proof* p); + bool is_closed(proof* p); + void set_closed(proof* p, bool value); + + /* + * adds a lemma to the unsat core + */ + void add_lemma_to_core(expr* lemma); + + /* + * helper method, which can be used by plugins + * returns true iff all symbols of expr occur in some b-asserted formula. + * must only be called after a call to collect_symbols_b. + */ + bool only_contains_symbols_b(expr* expr) const; + bool is_b_pure (proof *p) + {return !is_h_marked (p) && only_contains_symbols_b (m.get_fact (p));} + bool is_b_open (proof *p) + { return is_b_marked (p) && !is_closed (p); } + + private: + ptr_vector m_plugins; + func_decl_set m_symbols_b; // symbols, which occur in any b-asserted formula + void collect_symbols_b(expr_set axioms_b); + + ast_mark m_a_mark; + ast_mark m_b_mark; + ast_mark m_h_mark; + ast_mark m_closed; + + expr_ref_vector m_unsat_core; // collects the lemmas of the unsat-core, will at the end be inserted into unsat_core. + + /* + * computes partial core for step by delegating computation to plugins + */ + void compute_partial_core(proof* step); + + /* + * finalize computation of unsat-core + */ + void finalize(); + }; + +} + +#endif diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp new file mode 100644 index 000000000..af9230713 --- /dev/null +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -0,0 +1,790 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_unsat_core_plugin.cpp + +Abstract: + plugin for itp cores + +Author: + Bernhard Gleiss + +Revision History: + + +--*/ +#include +#include + +#include "ast/rewriter/bool_rewriter.h" +#include "ast/arith_decl_plugin.h" +#include "ast/proofs/proof_utils.h" + +#include "solver/solver.h" + +#include "smt/smt_farkas_util.h" +#include "smt/smt_solver.h" + +#include "muz/spacer/spacer_matrix.h" +#include "muz/spacer/spacer_unsat_core_plugin.h" +#include "muz/spacer/spacer_unsat_core_learner.h" + +namespace spacer +{ + + +void unsat_core_plugin_lemma::compute_partial_core(proof* step) +{ + SASSERT(m_learner.is_a_marked(step)); + SASSERT(m_learner.is_b_marked(step)); + + for (unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i) + { + SASSERT(m_learner.m.is_proof(step->get_arg(i))); + proof* premise = to_app(step->get_arg(i)); + + if (m_learner.is_b_open (premise)) + { + // by IH, premises that are AB marked are already closed + SASSERT(!m_learner.is_a_marked(premise)); + add_lowest_split_to_core(premise); + } + } + m_learner.set_closed(step, true); +} + +void unsat_core_plugin_lemma::add_lowest_split_to_core(proof* step) const +{ + SASSERT(m_learner.is_b_open(step)); + ast_manager &m = m_learner.m; + + ptr_vector todo; + todo.push_back(step); + + while (!todo.empty()) + { + proof* pf = todo.back(); + todo.pop_back(); + + // if current step hasn't been processed, + if (!m_learner.is_closed(pf)) + { + m_learner.set_closed(pf, true); + // the step is b-marked and not closed. + // by I.H. the step must be already visited + // so if it is also a-marked, it must be closed + SASSERT(m_learner.is_b_marked(pf)); + SASSERT(!m_learner.is_a_marked(pf)); + + // the current step needs to be interpolated: + expr* fact = m_learner.m.get_fact(pf); + // if we trust the current step and we are able to use it + if (m_learner.is_b_pure (pf) && + (m.is_asserted(pf) || is_literal(m, fact))) + { + // just add it to the core + m_learner.add_lemma_to_core(fact); + } + // otherwise recurse on premises + else + { + for (unsigned i = 0, sz = m_learner.m.get_num_parents(pf); + i < sz; ++i) + { + SASSERT(m_learner.m.is_proof(pf->get_arg(i))); + proof* premise = m.get_parent (pf, i); + if (m_learner.is_b_open(premise)) { + todo.push_back(premise); + } + } + } + + } + } +} + + +void unsat_core_plugin_farkas_lemma::compute_partial_core(proof* step) +{ + ast_manager &m = m_learner.m; + SASSERT(m_learner.is_a_marked(step)); + SASSERT(m_learner.is_b_marked(step)); + // XXX this assertion should be true so there is no need to check for it + SASSERT (!m_learner.is_closed (step)); + func_decl* d = step->get_decl(); + symbol sym; + if(!m_learner.is_closed(step) && // if step is not already interpolated + step->get_decl_kind() == PR_TH_LEMMA && // and step is a Farkas lemma + d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step + d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", + d->get_parameter(1).is_symbol(sym) && sym == "farkas" && + d->get_num_parameters() >= m_learner.m.get_num_parents(step) + 2) // the following parameters are the Farkas coefficients + { + SASSERT(m_learner.m.has_fact(step)); + + ptr_vector literals; + vector coefficients; + + /* The farkas lemma represents a subproof starting from premise(-set)s A, BNP and BP(ure) and + * ending in a disjunction D. We need to compute the contribution of BP, i.e. a formula, which + * is entailed by BP and together with A and BNP entails D. + * + * Let Fark(F) be the farkas coefficient for F. We can use the fact that + * (A*Fark(A) + BNP*Fark(BNP) + BP*Fark(BP) + (neg D)*Fark(D)) => false. (E1) + * We further have that A+B => C implies (A \land B) => C. (E2) + * + * Alternative 1: + * From (E1) immediately get that BP*Fark(BP) is a solution. + * + * Alternative 2: + * We can rewrite (E2) to rewrite (E1) to + * (BP*Fark(BP)) => (neg(A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D))) (E3) + * and since we can derive (A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D)) from + * A, BNP and D, we also know that it is inconsisent. Therefore + * neg(A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D)) is a solution. + * + * Finally we also need the following workaround: + * 1) Although we know from theory, that the Farkas coefficients are always nonnegative, + * the Farkas coefficients provided by arith_core are sometimes negative (must be a bug) + * as workaround we take the absolute value of the provided coefficients. + */ + parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient + + STRACE("spacer.farkas", + verbose_stream() << "Farkas input: "<< "\n"; + for (unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i) + { + SASSERT(m_learner.m.is_proof(step->get_arg(i))); + proof *prem = m.get_parent (step, i); + + rational coef; + VERIFY(params[i].is_rational(coef)); + + bool b_pure = m_learner.is_b_pure (prem); + verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m_learner.m.get_fact(prem), m_learner.m) << "\n"; + } + ); + + bool can_be_closed = true; + + for(unsigned i = 0; i < m.get_num_parents(step); ++i) + { + SASSERT(m_learner.m.is_proof(step->get_arg(i))); + proof * premise = m.get_parent (step, i); + + if (m_learner.is_b_open (premise)) + { + SASSERT(!m_learner.is_a_marked(premise)); + + if (m_learner.is_b_pure (step)) + { + if (!m_use_constant_from_a) + { + rational coefficient; + VERIFY(params[i].is_rational(coefficient)); + literals.push_back(to_app(m_learner.m.get_fact(premise))); + coefficients.push_back(abs(coefficient)); + } + } + else + { + can_be_closed = false; + + if (m_use_constant_from_a) + { + rational coefficient; + VERIFY(params[i].is_rational(coefficient)); + literals.push_back(to_app(m_learner.m.get_fact(premise))); + coefficients.push_back(abs(coefficient)); + } + } + } + else + { + if (m_use_constant_from_a) + { + rational coefficient; + VERIFY(params[i].is_rational(coefficient)); + literals.push_back(to_app(m_learner.m.get_fact(premise))); + coefficients.push_back(abs(coefficient)); + } + } + } + + if (m_use_constant_from_a) + { + params += m_learner.m.get_num_parents(step); // point to the first Farkas coefficient, which corresponds to a formula in the conclusion + + // the conclusion can either be a single formula or a disjunction of several formulas, we have to deal with both situations + if (m_learner.m.get_num_parents(step) + 2 < d->get_num_parameters()) + { + unsigned num_args = 1; + expr* conclusion = m_learner.m.get_fact(step); + expr* const* args = &conclusion; + if (m_learner.m.is_or(conclusion)) + { + app* _or = to_app(conclusion); + num_args = _or->get_num_args(); + args = _or->get_args(); + } + SASSERT(m_learner.m.get_num_parents(step) + 2 + num_args == d->get_num_parameters()); + + bool_rewriter brw(m_learner.m); + for (unsigned i = 0; i < num_args; ++i) + { + expr* premise = args[i]; + + expr_ref negatedPremise(m_learner.m); + brw.mk_not(premise, negatedPremise); + literals.push_back(to_app(negatedPremise)); + + rational coefficient; + VERIFY(params[i].is_rational(coefficient)); + coefficients.push_back(abs(coefficient)); + } + } + } + + // only if all b-premises can be used directly, add the farkas core and close the step + if (can_be_closed) + { + m_learner.set_closed(step, true); + + expr_ref res(m_learner.m); + compute_linear_combination(coefficients, literals, res); + + m_learner.add_lemma_to_core(res); + } + } +} + +void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector& coefficients, const ptr_vector& literals, expr_ref& res) +{ + SASSERT(literals.size() == coefficients.size()); + + ast_manager& m = res.get_manager(); + smt::farkas_util util(m); + if (m_use_constant_from_a) + { + util.set_split_literals (m_split_literals); // small optimization: if flag m_split_literals is set, then preserve diff constraints + } + for(unsigned i = 0; i < literals.size(); ++i) + { + util.add(coefficients[i], literals[i]); + } + if (m_use_constant_from_a) + { + res = util.get(); + } + else + { + expr_ref negated_linear_combination = util.get(); + res = mk_not(m, negated_linear_combination); + } +} + + void unsat_core_plugin_farkas_lemma_optimized::compute_partial_core(proof* step) + { + SASSERT(m_learner.is_a_marked(step)); + SASSERT(m_learner.is_b_marked(step)); + + func_decl* d = step->get_decl(); + symbol sym; + if(!m_learner.is_closed(step) && // if step is not already interpolated + step->get_decl_kind() == PR_TH_LEMMA && // and step is a Farkas lemma + d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step + d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", + d->get_parameter(1).is_symbol(sym) && sym == "farkas" && + d->get_num_parameters() >= m_learner.m.get_num_parents(step) + 2) // the following parameters are the Farkas coefficients + { + SASSERT(m_learner.m.has_fact(step)); + + vector > linear_combination; // collects all summands of the linear combination + + parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient + + STRACE("spacer.farkas", + verbose_stream() << "Farkas input: "<< "\n"; + for (unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i) + { + SASSERT(m_learner.m.is_proof(step->get_arg(i))); + proof *prem = m.get_parent (step, i); + + rational coef; + VERIFY(params[i].is_rational(coef)); + + bool b_pure = m_learner.is_b_pure (prem); + verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m_learner.m.get_fact(prem), m_learner.m) << "\n"; + } + ); + + bool can_be_closed = true; + for(unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i) + { + SASSERT(m_learner.m.is_proof(step->get_arg(i))); + proof * premise = m.get_parent (step, i); + + if (m_learner.is_b_marked(premise) && !m_learner.is_closed(premise)) + { + SASSERT(!m_learner.is_a_marked(premise)); + + if (m_learner.only_contains_symbols_b(m_learner.m.get_fact(premise)) && !m_learner.is_h_marked(premise)) + { + rational coefficient; + VERIFY(params[i].is_rational(coefficient)); + linear_combination.push_back(std::make_pair(to_app(m_learner.m.get_fact(premise)), abs(coefficient))); + } + else + { + can_be_closed = false; + } + } + } + + // only if all b-premises can be used directly, close the step and add linear combinations for later processing + if (can_be_closed) + { + m_learner.set_closed(step, true); + if (!linear_combination.empty()) + { + m_linear_combinations.push_back(linear_combination); + } + } + } + } + + struct farkas_optimized_less_than_pairs + { + inline bool operator() (const std::pair& pair1, const std::pair& pair2) const + { + return (pair1.first->get_id() < pair2.first->get_id()); + } + }; + + void unsat_core_plugin_farkas_lemma_optimized::finalize() + { + if(m_linear_combinations.empty()) + { + return; + } + DEBUG_CODE( + for (auto& linear_combination : m_linear_combinations) { + SASSERT(linear_combination.size() > 0); + }); + + // 1. construct ordered basis + ptr_vector ordered_basis; + obj_map map; + unsigned counter = 0; + for (const auto& linear_combination : m_linear_combinations) + { + for (const auto& pair : linear_combination) + { + if (!map.contains(pair.first)) + { + ordered_basis.push_back(pair.first); + map.insert(pair.first, counter++); + } + } + } + + // 2. populate matrix + spacer_matrix matrix(m_linear_combinations.size(), ordered_basis.size()); + + for (unsigned i=0; i < m_linear_combinations.size(); ++i) + { + auto linear_combination = m_linear_combinations[i]; + for (const auto& pair : linear_combination) + { + matrix.set(i, map[pair.first], pair.second); + } + } + + // 3. perform gaussian elimination + unsigned i = matrix.perform_gaussian_elimination(); + + // 4. extract linear combinations from matrix and add result to core + for (unsigned k=0; k < i; k++)// i points to the row after the last row which is non-zero + { + ptr_vector literals; + vector coefficients; + for (unsigned l=0; l < matrix.num_cols(); ++l) + { + if (!matrix.get(k,l).is_zero()) + { + literals.push_back(ordered_basis[l]); + coefficients.push_back(matrix.get(k,l)); + } + } + SASSERT(literals.size() > 0); + expr_ref linear_combination(m); + compute_linear_combination(coefficients, literals, linear_combination); + + m_learner.add_lemma_to_core(linear_combination); + } + + } + + void unsat_core_plugin_farkas_lemma_optimized::compute_linear_combination(const vector& coefficients, const ptr_vector& literals, expr_ref& res) + { + SASSERT(literals.size() == coefficients.size()); + + ast_manager& m = res.get_manager(); + smt::farkas_util util(m); + for(unsigned i = 0; i < literals.size(); ++i) + { + util.add(coefficients[i], literals[i]); + } + expr_ref negated_linear_combination = util.get(); + SASSERT(m.is_not(negated_linear_combination)); + res = mk_not(m, negated_linear_combination); //TODO: rewrite the get-method to return nonnegated stuff? + } + + + void unsat_core_plugin_farkas_lemma_bounded::finalize() { + if (m_linear_combinations.empty()) { + return; + } + DEBUG_CODE( + for (auto& linear_combination : m_linear_combinations) { + SASSERT(linear_combination.size() > 0); + }); + + // 1. construct ordered basis + ptr_vector ordered_basis; + obj_map map; + unsigned counter = 0; + for (const auto& linear_combination : m_linear_combinations) { + for (const auto& pair : linear_combination) { + if (!map.contains(pair.first)) { + ordered_basis.push_back(pair.first); + map.insert(pair.first, counter++); + } + } + } + + // 2. populate matrix + spacer_matrix matrix(m_linear_combinations.size(), ordered_basis.size()); + + for (unsigned i=0; i < m_linear_combinations.size(); ++i) { + auto linear_combination = m_linear_combinations[i]; + for (const auto& pair : linear_combination) { + matrix.set(i, map[pair.first], pair.second); + } + } + matrix.print_matrix(); + + // 3. normalize matrix to integer values + matrix.normalize(); + + + arith_util util(m); + + vector coeffs; + for (unsigned i=0; i < matrix.num_rows(); ++i) { + coeffs.push_back(expr_ref_vector(m)); + } + + vector bounded_vectors; + for (unsigned j=0; j < matrix.num_cols(); ++j) + { + bounded_vectors.push_back(expr_ref_vector(m)); + } + + // 4. find smallest n using guess and check algorithm + for(unsigned n = 1; true; ++n) + { + params_ref p; + p.set_bool("model", true); + scoped_ptr s = mk_smt_solver(m, p, symbol::null); // TODO: incremental version? + + // add new variables w_in, + for (unsigned i=0; i < matrix.num_rows(); ++i) + { + std::string name = "w_" + std::to_string(i) + std::to_string(n); + + func_decl_ref decl(m); + decl = m.mk_func_decl(symbol(name.c_str()), 0, (sort*const*)0, util.mk_int()); + coeffs[i].push_back(m.mk_const(decl)); + } + + // we need s_jn + for (unsigned j=0; j < matrix.num_cols(); ++j) + { + std::string name = "s_" + std::to_string(j) + std::to_string(n); + + func_decl_ref decl(m); + decl = m.mk_func_decl(symbol(name.c_str()), 0, (sort*const*)0, util.mk_int()); + + expr_ref s_jn(m); + s_jn = m.mk_const(decl); + + bounded_vectors[j].push_back(s_jn); + } + + // assert bounds for all s_jn + for (unsigned l=0; l < n; ++l) { + for (unsigned j=0; j < matrix.num_cols(); ++j) { + expr* s_jn = bounded_vectors[j][l].get(); + + expr_ref lb(util.mk_le(util.mk_int(0), s_jn), m); + expr_ref ub(util.mk_le(s_jn, util.mk_int(1)), m); + s->assert_expr(lb); + s->assert_expr(ub); + } + } + + // assert: forall i,j: a_ij = sum_k w_ik * s_jk + for (unsigned i=0; i < matrix.num_rows(); ++i) + { + for (unsigned j=0; j < matrix.num_cols(); ++j) + { + SASSERT(matrix.get(i, j).is_int()); + app_ref a_ij(util.mk_numeral(matrix.get(i,j), true),m); + + app_ref sum(m); + sum = util.mk_int(0); + for (unsigned k=0; k < n; ++k) + { + sum = util.mk_add(sum, util.mk_mul(coeffs[i][k].get(), bounded_vectors[j][k].get())); + } + expr_ref eq(m.mk_eq(a_ij, sum),m); + s->assert_expr(eq); + } + } + + // check result + lbool res = s->check_sat(0,0); + + // if sat extract model and add corresponding linear combinations to core + if (res == lbool::l_true) { + model_ref model; + s->get_model(model); + + for (unsigned k=0; k < n; ++k) { + ptr_vector literals; + vector coefficients; + for (unsigned j=0; j < matrix.num_cols(); ++j) { + expr_ref evaluation(m); + + model.get()->eval(bounded_vectors[j][k].get(), evaluation, false); + if (!util.is_zero(evaluation)) { + literals.push_back(ordered_basis[j]); + coefficients.push_back(rational(1)); + } + } + SASSERT(!literals.empty()); // since then previous outer loop would have found solution already + expr_ref linear_combination(m); + compute_linear_combination(coefficients, literals, linear_combination); + + m_learner.add_lemma_to_core(linear_combination); + } + return; + } + } + } + + unsat_core_plugin_min_cut::unsat_core_plugin_min_cut(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner), m(m){} + + /* + * traverses proof rooted in step and constructs graph, which corresponds to the proof-DAG, with the following differences: + * + * 1) we want to skip vertices, which have a conclusion, which we don't like (call those steps bad and the other ones good). In other words, we start at a good step r and compute the smallest subproof with root r, which has only good leaves. Then we add an edge from the root to each of the leaves and remember that we already dealt with s. Then we recurse on all leaves. + * 2) we want to introduce two vertices for all (unskipped) edges in order to run the min-cut algorithm + * 3) we want to introduce a single super-source vertex, which is connected to all source-vertices of the proof-DAG and a + * single super-sink vertex, to which all sink-vertices of the proof-DAG are connected + * + * 1) is dealt with using advance_to_lowest_partial_cut + * 2) and 3) are dealt with using add_edge + */ + void unsat_core_plugin_min_cut::compute_partial_core(proof* step) + { + ptr_vector todo; + + SASSERT(m_learner.is_a_marked(step)); + SASSERT(m_learner.is_b_marked(step)); + SASSERT(m.get_num_parents(step) > 0); + SASSERT(!m_learner.is_closed(step)); + todo.push_back(step); + + while (!todo.empty()) + { + proof* current = todo.back(); + todo.pop_back(); + + // if we need to deal with the node and if we haven't added the corresponding edges so far + if (!m_learner.is_closed(current) && !m_visited.is_marked(current)) + { + // compute smallest subproof rooted in current, which has only good edges + // add an edge from current to each leaf of that subproof + // add the leaves to todo + advance_to_lowest_partial_cut(current, todo); + + m_visited.mark(current, true); + + } + } + m_learner.set_closed(step, true); + } + + + void unsat_core_plugin_min_cut::advance_to_lowest_partial_cut(proof* step, ptr_vector& todo) + { + bool is_sink = true; + + ast_manager &m = m_learner.m; + ptr_vector todo_subproof; + + for (unsigned i = 0, sz = m.get_num_parents(step); i < sz; ++i) + { + proof* premise = m.get_parent (step, i); + { + if (m_learner.is_b_marked(premise)) + { + todo_subproof.push_back(premise); + } + } + } + while (!todo_subproof.empty()) + { + proof* current = todo_subproof.back(); + todo_subproof.pop_back(); + + // if we need to deal with the node + if (!m_learner.is_closed(current)) + { + SASSERT(!m_learner.is_a_marked(current)); // by I.H. the step must be already visited + + // and the current step needs to be interpolated: + if (m_learner.is_b_marked(current)) + { + // if we trust the current step and we are able to use it + if (m_learner.is_b_pure (current) && + (m.is_asserted(current) || + is_literal(m, m.get_fact(current)))) + { + // we found a leaf of the subproof, so + // 1) we add corresponding edges + if (m_learner.is_a_marked(step)) + { + add_edge(nullptr, current); // current is sink + } + else + { + add_edge(step, current); // standard edge + } + // 2) add the leaf to todo + todo.push_back(current); + is_sink = false; + } + // otherwise continue search for leaves of subproof + else + { + for (unsigned i = 0; i < m_learner.m.get_num_parents(current); ++i) + { + SASSERT(m_learner.m.is_proof(current->get_arg(i))); + proof* premise = m.get_parent (current, i); + todo_subproof.push_back(premise); + } + } + } + } + } + + if (is_sink) + { + add_edge(step, nullptr); + } + } + + /* + * adds an edge from the out-vertex of i to the in-vertex of j to the graph + * if i or j isn't already present, it adds the corresponding in- and out-vertices to the graph + * if i is a nullptr, it is treated as source vertex + * if j is a nullptr, it is treated as sink vertex + */ + void unsat_core_plugin_min_cut::add_edge(proof* i, proof* j) + { + unsigned node_i; + unsigned node_j; + if (i == nullptr) + { + node_i = 0; + } + else + { + unsigned tmp; + if (m_proof_to_node_plus.find(i, tmp)) + { + node_i = tmp; + } + else + { + unsigned node_other = m_min_cut.new_node(); + node_i = m_min_cut.new_node(); + + m_proof_to_node_minus.insert(i, node_other); + m_proof_to_node_plus.insert(i, node_i); + + if (node_i >= m_node_to_formula.size()) + { + m_node_to_formula.resize(node_i + 1); + } + m_node_to_formula[node_other] = m.get_fact(i); + m_node_to_formula[node_i] = m.get_fact(i); + + m_min_cut.add_edge(node_other, node_i); + } + } + + if (j == nullptr) + { + node_j = 1; + } + else + { + unsigned tmp; + if (m_proof_to_node_minus.find(j, tmp)) + { + node_j = tmp; + } + else + { + node_j = m_min_cut.new_node(); + unsigned node_other = m_min_cut.new_node(); + + m_proof_to_node_minus.insert(j, node_j); + m_proof_to_node_plus.insert(j, node_other); + + if (node_other >= m_node_to_formula.size()) + { + m_node_to_formula.resize(node_other + 1); + } + m_node_to_formula[node_j] = m.get_fact(j); + m_node_to_formula[node_other] = m.get_fact(j); + + m_min_cut.add_edge(node_j, node_other); + } + } + + // finally connect nodes + m_min_cut.add_edge(node_i, node_j); + } + + /* + * computes min-cut on the graph constructed by compute_partial_core-method + * and adds the corresponding lemmas to the core + */ + void unsat_core_plugin_min_cut::finalize() + { + unsigned_vector cut_nodes; + m_min_cut.compute_min_cut(cut_nodes); + + for (unsigned cut_node : cut_nodes) + { + m_learner.add_lemma_to_core(m_node_to_formula[cut_node]); + } + } +} diff --git a/src/muz/spacer/spacer_unsat_core_plugin.h b/src/muz/spacer/spacer_unsat_core_plugin.h new file mode 100644 index 000000000..96d03140c --- /dev/null +++ b/src/muz/spacer/spacer_unsat_core_plugin.h @@ -0,0 +1,115 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_unsat_core_plugin.h + +Abstract: + plugin for itp cores + +Author: + Bernhard Gleiss + +Revision History: + + +--*/ +#ifndef _SPACER_UNSAT_CORE_PLUGIN_H_ +#define _SPACER_UNSAT_CORE_PLUGIN_H_ + +#include "ast/ast.h" +#include "util/min_cut.h" + +namespace spacer { + +class unsat_core_learner; + + +class unsat_core_plugin { + +public: + unsat_core_plugin(unsat_core_learner& learner) : m_learner(learner){}; + virtual ~unsat_core_plugin(){}; + virtual void compute_partial_core(proof* step) = 0; + virtual void finalize(){}; + + unsat_core_learner& m_learner; +}; + + +class unsat_core_plugin_lemma : public unsat_core_plugin { + +public: + unsat_core_plugin_lemma(unsat_core_learner& learner) : unsat_core_plugin(learner){}; + + virtual void compute_partial_core(proof* step) override; + +private: + void add_lowest_split_to_core(proof* step) const; +}; + + +class unsat_core_plugin_farkas_lemma : public unsat_core_plugin { + +public: + unsat_core_plugin_farkas_lemma(unsat_core_learner& learner, bool split_literals, bool use_constant_from_a=true) : unsat_core_plugin(learner), m_split_literals(split_literals), m_use_constant_from_a(use_constant_from_a) {}; + + virtual void compute_partial_core(proof* step) override; + +private: + bool m_split_literals; + bool m_use_constant_from_a; + /* + * compute linear combination of literals 'literals' having coefficients 'coefficients' and save result in res + */ + void compute_linear_combination(const vector& coefficients, const ptr_vector& literals, expr_ref& res); +}; + + class unsat_core_plugin_farkas_lemma_optimized : public unsat_core_plugin { + + public: + unsat_core_plugin_farkas_lemma_optimized(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner), m(m) {}; + + virtual void compute_partial_core(proof* step) override; + virtual void finalize() override; + + protected: + vector > > m_linear_combinations; + ast_manager& m; + /* + * compute linear combination of literals 'literals' having coefficients 'coefficients' and save result in res + */ + void compute_linear_combination(const vector& coefficients, const ptr_vector& literals, expr_ref& res); + }; + + class unsat_core_plugin_farkas_lemma_bounded : public unsat_core_plugin_farkas_lemma_optimized { + + public: + unsat_core_plugin_farkas_lemma_bounded(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin_farkas_lemma_optimized(learner, m) {}; + + virtual void finalize() override; + }; + + class unsat_core_plugin_min_cut : public unsat_core_plugin { + + public: + unsat_core_plugin_min_cut(unsat_core_learner& learner, ast_manager& m); + + virtual void compute_partial_core(proof* step) override; + virtual void finalize() override; + private: + ast_manager& m; + + ast_mark m_visited; // saves for each node i whether the subproof with root i has already been added to the min-cut-problem + obj_map m_proof_to_node_minus; // maps proof-steps to the corresponding minus-nodes (the ones which are closer to source) + obj_map m_proof_to_node_plus; // maps proof-steps to the corresponding plus-nodes (the ones which are closer to sink) + void advance_to_lowest_partial_cut(proof* step, ptr_vector& todo); + void add_edge(proof* i, proof* j); + + vector m_node_to_formula; // maps each node to the corresponding formula in the original proof + + min_cut m_min_cut; + }; +} +#endif diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp new file mode 100644 index 000000000..83042cd6d --- /dev/null +++ b/src/muz/spacer/spacer_util.cpp @@ -0,0 +1,1378 @@ +/** +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + spacer_util.cpp + +Abstract: + + Utility functions for SPACER. + +Author: + + Krystof Hoder (t-khoder) 2011-8-19. + Arie Gurfinkel + Anvesh Komuravelli + +Revision History: + + Modified by Anvesh Komuravelli + +Notes: + + +--*/ + +#include +#include + +#include "ast/ast.h" +#include "ast/occurs.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/bool_rewriter.h" +#include "muz/base/dl_util.h" +#include "ast/for_each_expr.h" +#include "smt/params/smt_params.h" +#include "model/model.h" +#include "model/model_evaluator.h" +#include "util/ref_vector.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "util/util.h" +#include "muz/spacer/spacer_manager.h" +#include "muz/spacer/spacer_util.h" +#include "ast/rewriter/expr_replacer.h" +#include "model/model_smt2_pp.h" +#include "ast/scoped_proof.h" +#include "qe/qe_lite.h" +#include "muz/spacer/spacer_qe_project.h" +#include "model/model_pp.h" +#include "ast/rewriter/expr_safe_replace.h" + +#include "ast/array_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/bv_decl_plugin.h" + +#include "muz/spacer/spacer_legacy_mev.h" +#include "qe/qe_mbp.h" + +#include "tactic/tactical.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/arith/propagate_ineqs_tactic.h" +#include "tactic/arith/arith_bounds_tactic.h" + +#include "ast/factor_equivs.h" + +namespace spacer { + + ///////////////////////// + // model_evaluator_util + // + + model_evaluator_util::model_evaluator_util(ast_manager& m) : + m(m), m_mev(nullptr) { + reset (nullptr); + } + + model_evaluator_util::~model_evaluator_util() {reset (NULL);} + + + void model_evaluator_util::reset(model* model) { + if (m_mev) { + dealloc(m_mev); + m_mev = NULL; + } + m_model = model; + if (!m_model) { return; } + m_mev = alloc(model_evaluator, *m_model); + } + + bool model_evaluator_util::eval(expr *e, expr_ref &result, bool model_completion) { + m_mev->set_model_completion (model_completion); + try { + m_mev->operator() (e, result); + return true; + } + catch (model_evaluator_exception &ex) { + (void)ex; + TRACE("spacer_model_evaluator", tout << ex.msg () << "\n";); + return false; + } + } + + bool model_evaluator_util::eval(const expr_ref_vector &v, + expr_ref& res, bool model_completion) { + expr_ref e(m); + e = mk_and (v); + return eval(e, res, model_completion); + } + + + bool model_evaluator_util::is_true(const expr_ref_vector &v) { + expr_ref res(m); + return eval (v, res, false) && m.is_true (res); + } + + bool model_evaluator_util::is_false(expr *x) { + expr_ref res(m); + return eval(x, res, false) && m.is_false (res); + } + + bool model_evaluator_util::is_true(expr *x) { + expr_ref res(m); + return eval(x, res, false) && m.is_true (res); + } + + void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) { + ast_manager& m = fml.get_manager(); + expr_ref_vector conjs(m); + flatten_and(fml, conjs); + obj_map diseqs; + expr* n, *lhs, *rhs; + for (unsigned i = 0; i < conjs.size(); ++i) { + if (m.is_not(conjs[i].get(), n) && m.is_eq(n, lhs, rhs)) { + if (!m.is_value(rhs)) { + std::swap(lhs, rhs); + } + if (!m.is_value(rhs)) { + continue; + } + diseqs.insert_if_not_there2(lhs, 0)->get_data().m_value++; + } + } + expr_substitution sub(m); + + unsigned orig_size = conjs.size(); + unsigned num_deleted = 0; + expr_ref val(m), tmp(m); + proof_ref pr(m); + pr = m.mk_asserted(m.mk_true()); + for (auto const& kv : diseqs) { + if (kv.m_value >= threshold) { + model.eval(kv.m_key, val); + sub.insert(kv.m_key, val, pr); + conjs.push_back(m.mk_eq(kv.m_key, val)); + num_deleted += kv.m_value; + } + } + if (orig_size < conjs.size()) { + scoped_ptr rep = mk_expr_simp_replacer(m); + rep->set_substitution(&sub); + for (unsigned i = 0; i < orig_size; ++i) { + tmp = conjs[i].get(); + (*rep)(tmp); + if (m.is_true(tmp)) { + conjs[i] = conjs.back(); + SASSERT(orig_size <= conjs.size()); + conjs.pop_back(); + SASSERT(orig_size <= 1 + conjs.size()); + if (i + 1 == orig_size) { + // no-op. + } + else if (orig_size <= conjs.size()) { + // no-op + } + else { + SASSERT(orig_size == 1 + conjs.size()); + --orig_size; + --i; + } + } + else { + conjs[i] = tmp; + } + } + IF_VERBOSE(2, verbose_stream() << "Deleted " << num_deleted << " disequalities " << conjs.size() << " conjuncts\n";); + } + fml = m.mk_and(conjs.size(), conjs.c_ptr()); + } + + // + // (f (if c1 (if c2 e1 e2) e3) b c) -> + // (if c1 (if c2 (f e1 b c) + + class ite_hoister { + ast_manager& m; + public: + ite_hoister(ast_manager& m): m(m) {} + + br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { + if (m.is_ite(f)) { + return BR_FAILED; + } + for (unsigned i = 0; i < num_args; ++i) { + expr* c, *t, *e; + if (!m.is_bool(args[i]) && m.is_ite(args[i], c, t, e)) { + expr_ref e1(m), e2(m); + ptr_vector args1(num_args, args); + args1[i] = t; + e1 = m.mk_app(f, num_args, args1.c_ptr()); + if (t == e) { + result = e1; + return BR_REWRITE1; + } + args1[i] = e; + e2 = m.mk_app(f, num_args, args1.c_ptr()); + result = m.mk_app(f, num_args, args); + result = m.mk_ite(c, e1, e2); + return BR_REWRITE3; + } + } + return BR_FAILED; + } + }; + + struct ite_hoister_cfg: public default_rewriter_cfg { + ite_hoister m_r; + bool rewrite_patterns() const { return false; } + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + return m_r.mk_app_core(f, num, args, result); + } + ite_hoister_cfg(ast_manager & m, params_ref const & p):m_r(m) {} + }; + + class ite_hoister_star : public rewriter_tpl { + ite_hoister_cfg m_cfg; + public: + ite_hoister_star(ast_manager & m, params_ref const & p): + rewriter_tpl(m, false, m_cfg), + m_cfg(m, p) {} + }; + + void hoist_non_bool_if(expr_ref& fml) { + ast_manager& m = fml.get_manager(); + scoped_no_proof _sp(m); + params_ref p; + ite_hoister_star ite_rw(m, p); + expr_ref tmp(m); + ite_rw(fml, tmp); + fml = tmp; + } + + class test_diff_logic { + ast_manager& m; + arith_util a; + bv_util bv; + bool m_is_dl; + bool m_test_for_utvpi; + + bool is_numeric(expr* e) const { + if (a.is_numeral(e)) { + return true; + } + expr* cond, *th, *el; + if (m.is_ite(e, cond, th, el)) { + return is_numeric(th) && is_numeric(el); + } + return false; + } + + bool is_arith_expr(expr *e) const { + return is_app(e) && a.get_family_id() == to_app(e)->get_family_id(); + } + + bool is_offset(expr* e) const { + if (a.is_numeral(e)) { + return true; + } + expr* cond, *th, *el, *e1, *e2; + if (m.is_ite(e, cond, th, el)) { + return is_offset(th) && is_offset(el); + } + // recognize offsets. + if (a.is_add(e, e1, e2)) { + if (is_numeric(e1)) { + return is_offset(e2); + } + if (is_numeric(e2)) { + return is_offset(e1); + } + return false; + } + if (m_test_for_utvpi) { + if (a.is_mul(e, e1, e2)) { + if (is_minus_one(e1)) { + return is_offset(e2); + } + if (is_minus_one(e2)) { + return is_offset(e1); + } + } + } + return !is_arith_expr(e); + } + + bool is_minus_one(expr const * e) const { + rational r; + return a.is_numeral(e, r) && r.is_minus_one(); + } + + bool test_ineq(expr* e) const { + SASSERT(a.is_le(e) || a.is_ge(e) || m.is_eq(e)); + SASSERT(to_app(e)->get_num_args() == 2); + expr * lhs = to_app(e)->get_arg(0); + expr * rhs = to_app(e)->get_arg(1); + if (is_offset(lhs) && is_offset(rhs)) + { return true; } + if (!is_numeric(rhs)) + { std::swap(lhs, rhs); } + if (!is_numeric(rhs)) + { return false; } + // lhs can be 'x' or '(+ x (* -1 y))' + if (is_offset(lhs)) + { return true; } + expr* arg1, *arg2; + if (!a.is_add(lhs, arg1, arg2)) + { return false; } + // x + if (m_test_for_utvpi) { + return is_offset(arg1) && is_offset(arg2); + } + if (is_arith_expr(arg1)) + { std::swap(arg1, arg2); } + if (is_arith_expr(arg1)) + { return false; } + // arg2: (* -1 y) + expr* m1, *m2; + if (!a.is_mul(arg2, m1, m2)) + { return false; } + return is_minus_one(m1) && is_offset(m2); + } + + bool test_eq(expr* e) const { + expr* lhs, *rhs; + VERIFY(m.is_eq(e, lhs, rhs)); + if (!a.is_int_real(lhs)) { + return true; + } + if (a.is_numeral(lhs) || a.is_numeral(rhs)) { + return test_ineq(e); + } + return + test_term(lhs) && + test_term(rhs) && + !a.is_mul(lhs) && + !a.is_mul(rhs); + } + + bool test_term(expr* e) const { + if (m.is_bool(e)) { + return true; + } + if (a.is_numeral(e)) { + return true; + } + if (is_offset(e)) { + return true; + } + expr* lhs, *rhs; + if (a.is_add(e, lhs, rhs)) { + if (!a.is_numeral(lhs)) { + std::swap(lhs, rhs); + } + return a.is_numeral(lhs) && is_offset(rhs); + } + if (a.is_mul(e, lhs, rhs)) { + return is_minus_one(lhs) || is_minus_one(rhs); + } + return false; + } + + bool is_non_arith_or_basic(expr* e) + { + if (!is_app(e)) { + return false; + } + family_id fid = to_app(e)->get_family_id(); + + if (fid == null_family_id && + !m.is_bool(e) && + to_app(e)->get_num_args() > 0) { + return true; + } + return + fid != m.get_basic_family_id() && + fid != null_family_id && + fid != a.get_family_id() && + fid != bv.get_family_id(); + } + + public: + test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true), m_test_for_utvpi(false) {} + + void test_for_utvpi() { m_test_for_utvpi = true; } + + void operator()(expr* e) + { + if (!m_is_dl) { + return; + } + if (a.is_le(e) || a.is_ge(e)) { + m_is_dl = test_ineq(e); + } else if (m.is_eq(e)) { + m_is_dl = test_eq(e); + } else if (is_non_arith_or_basic(e)) { + m_is_dl = false; + } else if (is_app(e)) { + app* a = to_app(e); + for (unsigned i = 0; m_is_dl && i < a->get_num_args(); ++i) { + m_is_dl = test_term(a->get_arg(i)); + } + } + + if (!m_is_dl) { + char const* msg = "non-diff: "; + if (m_test_for_utvpi) { + msg = "non-utvpi: "; + } + IF_VERBOSE(1, verbose_stream() << msg << mk_pp(e, m) << "\n";); + } + } + + bool is_dl() const { return m_is_dl; } + }; + +bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) +{ + test_diff_logic test(m); + expr_fast_mark1 mark; + for (unsigned i = 0; i < num_fmls; ++i) { + quick_for_each_expr(test, mark, fmls[i]); + } + return test.is_dl(); + } + +bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) +{ + test_diff_logic test(m); + test.test_for_utvpi(); + expr_fast_mark1 mark; + for (unsigned i = 0; i < num_fmls; ++i) { + quick_for_each_expr(test, mark, fmls[i]); + } + return test.is_dl(); + } + + + void subst_vars (ast_manager& m, app_ref_vector const& vars, + model* M, expr_ref& fml) +{ + expr_safe_replace sub (m); + model_evaluator_util mev (m); + mev.set_model(*M); + for (unsigned i = 0; i < vars.size (); i++) { + app* v = vars.get (i); + expr_ref val (m); + VERIFY(mev.eval (v, val, true)); + sub.insert (v, val); + } + sub (fml); + } + + /* + * eliminate simple equalities using qe_lite + * then, MBP for Booleans (substitute), reals (based on LW), ints (based on Cooper), and arrays + */ +void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, + const model_ref& M, bool reduce_all_selects, bool use_native_mbp, + bool dont_sub) +{ + th_rewriter rw (m); + TRACE ("spacer_mbp", + tout << "Before projection:\n"; + tout << mk_pp (fml, m) << "\n"; + tout << "Vars:\n"; + for (unsigned i = 0; i < vars.size(); ++i) { + tout << mk_pp(vars.get (i), m) << "\n"; + } + ); + + { + // Ensure that top-level AND of fml is flat + expr_ref_vector flat(m); + flatten_and (fml, flat); + if (flat.size () == 1) + { fml = flat.get(0); } + else if (flat.size () > 1) + { fml = m.mk_and(flat.size(), flat.c_ptr()); } + } + + app_ref_vector arith_vars (m); + app_ref_vector array_vars (m); + array_util arr_u (m); + arith_util ari_u (m); + expr_safe_replace bool_sub (m); + expr_ref bval (m); + + while (true) { + params_ref p; + qe_lite qe(m, p, false); + qe (vars, fml); + rw (fml); + + TRACE ("spacer_mbp", + tout << "After qe_lite:\n"; + tout << mk_pp (fml, m) << "\n"; + tout << "Vars:\n"; + for (unsigned i = 0; i < vars.size(); ++i) { + tout << mk_pp(vars.get (i), m) << "\n"; + } + ); + SASSERT (!m.is_false (fml)); + + bool has_bool_vars = false; + + // sort out vars into bools, arith (int/real), and arrays + for (unsigned i = 0; i < vars.size (); i++) { + if (m.is_bool (vars.get (i))) { + // obtain the interpretation of the ith var using model completion + VERIFY (M->eval (vars.get (i), bval, true)); + bool_sub.insert (vars.get (i), bval); + has_bool_vars = true; + } else if (arr_u.is_array(vars.get(i))) { + array_vars.push_back (vars.get (i)); + } else { + SASSERT (ari_u.is_int (vars.get (i)) || ari_u.is_real (vars.get (i))); + arith_vars.push_back (vars.get (i)); + } + } + + // substitute Booleans + if (has_bool_vars) { + bool_sub (fml); + // -- bool_sub is not simplifying + rw (fml); + SASSERT (!m.is_false (fml)); + TRACE ("spacer_mbp", + tout << "Projected Booleans:\n" << mk_pp (fml, m) << "\n"; + ); + bool_sub.reset (); + } + + TRACE ("spacer_mbp", + tout << "Array vars:\n"; + for (unsigned i = 0; i < array_vars.size (); ++i) { + tout << mk_pp (array_vars.get (i), m) << "\n"; + } + ); + + vars.reset (); + + // project arrays + { + scoped_no_proof _sp (m); + // -- local rewriter that is aware of current proof mode + th_rewriter srw(m); + qe::array_project (*M.get (), array_vars, fml, vars, reduce_all_selects); + SASSERT (array_vars.empty ()); + srw (fml); + SASSERT (!m.is_false (fml)); + } + + TRACE ("spacer_mbp", + tout << "extended model:\n"; + model_pp (tout, *M); + tout << "Auxiliary variables of index and value sorts:\n"; + for (unsigned i = 0; i < vars.size (); i++) { + tout << mk_pp (vars.get (i), m) << "\n"; + } + ); + + if (vars.empty()) { break; } + } + + // project reals and ints + if (!arith_vars.empty ()) { + TRACE ("spacer_mbp", + tout << "Arith vars:\n"; + for (unsigned i = 0; i < arith_vars.size (); ++i) { + tout << mk_pp (arith_vars.get (i), m) << "\n"; + } + ); + + // XXX Does not seem to have an effect + // qe_lite qe(m); + // qe (arith_vars, fml); + // TRACE ("spacer_mbp", + // tout << "After second qelite: " << + // mk_pp (fml, m) << "\n";); + + if (use_native_mbp) { + qe::mbp mbp (m); + expr_ref_vector fmls(m); + flatten_and (fml, fmls); + + mbp (true, arith_vars, *M.get (), fmls); + fml = mk_and (fmls); + SASSERT (arith_vars.empty ()); + } else { + scoped_no_proof _sp (m); + qe::arith_project (*M.get (), arith_vars, fml); + } + + TRACE ("spacer_mbp", + tout << "Projected arith vars:\n" << mk_pp (fml, m) << "\n"; + tout << "Remaining arith vars:\n"; + for (unsigned i = 0; i < arith_vars.size (); i++) { + tout << mk_pp (arith_vars.get (i), m) << "\n"; + } + ); + SASSERT (!m.is_false (fml)); + } + + if (!arith_vars.empty ()) { + mbqi_project (*M.get(), arith_vars, fml); + } + + // substitute any remaining arith vars + if (!dont_sub && !arith_vars.empty ()) { + subst_vars (m, arith_vars, M.get(), fml); + TRACE ("spacer_mbp", + tout << "After substituting remaining arith vars:\n"; + tout << mk_pp (fml, m) << "\n"; + ); + // an extra round of simplification because subst_vars is not simplifying + rw(fml); + } + + DEBUG_CODE ( + model_evaluator_util mev (m); + expr_ref v(m); + mev.set_model(*M.get()); + SASSERT (mev.eval (fml, v, false)); + SASSERT (m.is_true (v)); + ); + + vars.reset (); + if (dont_sub && !arith_vars.empty ()) + { vars.append(arith_vars); } + } + + + static expr* apply_accessor(ast_manager &m, + ptr_vector const& acc, + unsigned j, + func_decl* f, + expr* c) +{ + if (is_app(c) && to_app(c)->get_decl() == f) { + return to_app(c)->get_arg(j); + } else { + return m.mk_app(acc[j], c); + } + } + +void expand_literals(ast_manager &m, expr_ref_vector& conjs) +{ + if (conjs.empty()) { return; } + arith_util arith(m); + datatype_util dt(m); + bv_util bv(m); + expr* e1, *e2, *c, *val; + rational r; + unsigned bv_size; + + TRACE("spacer_expand", + tout << "begin expand\n"; + for (unsigned i = 0; i < conjs.size(); ++i) { + tout << mk_pp(conjs[i].get(), m) << "\n"; + }); + + for (unsigned i = 0; i < conjs.size(); ++i) { + expr* e = conjs[i].get(); + if (m.is_eq(e, e1, e2) && arith.is_int_real(e1)) { + conjs[i] = arith.mk_le(e1,e2); + if (i+1 == conjs.size()) { + conjs.push_back(arith.mk_ge(e1, e2)); + } else { + conjs.push_back(conjs[i+1].get()); + conjs[i+1] = arith.mk_ge(e1, e2); + } + ++i; + } else if ((m.is_eq(e, c, val) && is_app(val) && dt.is_constructor(to_app(val))) || + (m.is_eq(e, val, c) && is_app(val) && dt.is_constructor(to_app(val)))){ + func_decl* f = to_app(val)->get_decl(); + func_decl* r = dt.get_constructor_recognizer(f); + conjs[i] = m.mk_app(r, c); + ptr_vector const& acc = *dt.get_constructor_accessors(f); + for (unsigned j = 0; j < acc.size(); ++j) { + conjs.push_back(m.mk_eq(apply_accessor(m, acc, j, f, c), to_app(val)->get_arg(j))); + } + } else if ((m.is_eq(e, c, val) && bv.is_numeral(val, r, bv_size)) || + (m.is_eq(e, val, c) && bv.is_numeral(val, r, bv_size))) { + rational two(2); + for (unsigned j = 0; j < bv_size; ++j) { + parameter p(j); + //expr* e = m.mk_app(bv.get_family_id(), OP_BIT2BOOL, 1, &p, 1, &c); + expr* e = m.mk_eq(m.mk_app(bv.get_family_id(), OP_BIT1), bv.mk_extract(j, j, c)); + if ((r % two).is_zero()) { + e = m.mk_not(e); + } + r = div(r, two); + if (j == 0) { + conjs[i] = e; + } else { + conjs.push_back(e); + } + } + } + } + TRACE("spacer_expand", + tout << "end expand\n"; + for (unsigned i = 0; i < conjs.size(); ++i) { + tout << mk_pp(conjs[i].get(), m) << "\n"; + }); + } + +namespace { +class implicant_picker { + model_evaluator_util &m_mev; + ast_manager &m; + arith_util m_arith; + + expr_ref_vector m_todo; + expr_mark m_visited; + + + void add_literal (expr *e, expr_ref_vector &out) + { + SASSERT (m.is_bool (e)); + + expr_ref res (m), v(m); + m_mev.eval (e, v, false); + SASSERT (m.is_true (v) || m.is_false (v)); + + res = m.is_false (v) ? m.mk_not (e) : e; + + if (m.is_distinct (res)) { + // -- (distinct a b) == (not (= a b)) + if (to_app(res)->get_num_args() == 2) { + res = m.mk_eq (to_app(res)->get_arg(0), to_app(res)->get_arg(1)); + res = m.mk_not (res); + } + } + + expr *nres, *f1, *f2; + if (m.is_not(res, nres)) { + // -- (not (xor a b)) == (= a b) + if (m.is_xor(nres, f1, f2)) + { res = m.mk_eq(f1, f2); } + + // -- split arithmetic inequality + else if (m.is_eq (nres, f1, f2) && m_arith.is_int_real (f1)) { + expr_ref u(m); + u = m_arith.mk_lt(f1, f2); + if (m_mev.eval (u, v, false) && m.is_true (v)) + { res = u; } + else + { res = m_arith.mk_lt(f2, f1); } + } + } + + if (!m_mev.is_true (res)) + { verbose_stream() << "Bad literal: " << mk_pp(res, m) << "\n"; } + SASSERT (m_mev.is_true (res)); + out.push_back (res); + } + + void process_app(app *a, expr_ref_vector &out) + { + if (m_visited.is_marked(a)) { return; } + SASSERT (m.is_bool (a)); + expr_ref v(m); + m_mev.eval (a, v, false); + + if (!m.is_true(v) && !m.is_false(v)) { return; } + + expr *na, *f1, *f2, *f3; + + if (a->get_family_id() != m.get_basic_family_id()) + { add_literal(a, out); } + else if (is_uninterp_const(a)) + { add_literal(a, out); } + else if (m.is_not(a, na) && m.is_not(na, na)) + { m_todo.push_back(na); } + else if (m.is_not(a, na)) + { m_todo.push_back(na); } + else if (m.is_distinct(a)) { + if (m.is_false(v)) + m_todo.push_back + (qe::project_plugin::pick_equality(m, *m_mev.get_model(), a)); + else if (a->get_num_args() == 2) + { add_literal(a, out); } + else + m_todo.push_back(m.mk_distinct_expanded(a->get_num_args(), + a->get_args())); + } else if (m.is_and(a)) { + if (m.is_true(v)) + { m_todo.append(a->get_num_args(), a->get_args()); } + else if (m.is_false(v)) { + for (unsigned i = 0, sz = a->get_num_args (); i < sz; ++i) { + if (m_mev.is_false(a->get_arg(i))) { + m_todo.push_back(a->get_arg(i)); + break; + } + } + } + } else if (m.is_or(a)) { + if (m.is_false(v)) + { m_todo.append(a->get_num_args(), a->get_args()); } + else if (m.is_true(v)) { + for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { + if (m_mev.is_true(a->get_arg(i))) { + m_todo.push_back(a->get_arg(i)); + break; + } + } + } + } else if (m.is_iff(a, f1, f2) || m.is_eq(a, f1, f2) || + (m.is_true(v) && m.is_not(a, na) && m.is_xor (na, f1, f2))) { + if (!m.are_equal(f1, f2) && !m.are_distinct(f1, f2)) { + if (m.is_bool(f1) && + (!is_uninterp_const(f1) || !is_uninterp_const(f2))) + { m_todo.append(a->get_num_args(), a->get_args()); } + else + { add_literal(a, out); } + } + } else if (m.is_ite(a, f1, f2, f3)) { + if (m.are_equal(f2, f3)) { m_todo.push_back(f2); } + else if (m_mev.is_true (f2) && m_mev.is_true (f3)) { + m_todo.push_back(f2); + m_todo.push_back(f3); + } else if (m_mev.is_false(f2) && m_mev.is_false(f3)) { + m_todo.push_back(f2); + m_todo.push_back(f3); + } else if (m_mev.is_true(f1)) { + m_todo.push_back(f1); + m_todo.push_back(f2); + } else if (m_mev.is_false(f1)) { + m_todo.push_back(f1); + m_todo.push_back(f3); + } + } else if (m.is_xor(a, f1, f2)) + { m_todo.append(a->get_num_args(), a->get_args()); } + else if (m.is_implies(a, f1, f2)) { + if (m.is_true (v)) { + if (m_mev.is_true(f2)) { m_todo.push_back(f2); } + else if (m_mev.is_false(f1)) { m_todo.push_back(f1); } + } else if (m.is_false(v)) + { m_todo.append(a->get_num_args(), a->get_args()); } + } else if (m.is_true(a) || m.is_false(a)) { /* nothing */ } + else { + verbose_stream () << "Unexpected expression: " + << mk_pp(a, m) << "\n"; + UNREACHABLE(); + } + } + + void pick_literals(expr *e, expr_ref_vector &out) + { + SASSERT(m_todo.empty()); + if (m_visited.is_marked(e)) { return; } + SASSERT(is_app(e)); + + m_todo.push_back(e); + do { + app *a = to_app(m_todo.back()); + m_todo.pop_back(); + process_app(a, out); + m_visited.mark(a, true); + } while (!m_todo.empty()); + } + + bool pick_implicant(const expr_ref_vector &in, expr_ref_vector &out) + { + m_visited.reset(); + expr_ref e(m); + e = mk_and (in); + bool is_true = m_mev.is_true (e); + + for (unsigned i = 0, sz = in.size (); i < sz; ++i) { + if (is_true || m_mev.is_true(in.get(i))) + { pick_literals(in.get(i), out); } + } + + m_visited.reset (); + return is_true; + } + + public: + implicant_picker (model_evaluator_util &mev) : + m_mev (mev), m (m_mev.get_ast_manager ()), m_arith(m), m_todo(m) {} + + void operator() (expr_ref_vector &in, expr_ref_vector& out) + {pick_implicant (in, out);} + }; + } + + void compute_implicant_literals (model_evaluator_util &mev, expr_ref_vector &formula, + expr_ref_vector &res) + { + // XXX what is the point of flattening? + flatten_and (formula); + if (formula.empty()) { return; } + + implicant_picker ipick (mev); + ipick (formula, res); + } + +void simplify_bounds_old(expr_ref_vector& cube) { + ast_manager& m = cube.m(); + + scoped_no_proof _no_pf_(m); + goal_ref g(alloc(goal, m, false, false, false)); + + for (unsigned i = 0; i < cube.size(); ++i) { + g->assert_expr(cube.get(i)); + } + + expr_ref tmp(m); + model_converter_ref mc; + proof_converter_ref pc; + expr_dependency_ref core(m); + goal_ref_buffer result; + tactic_ref simplifier = mk_arith_bounds_tactic(m); + (*simplifier)(g, result, mc, pc, core); + SASSERT(result.size() == 1); + goal* r = result[0]; + + cube.reset(); + for (unsigned i = 0; i < r->size(); ++i) { + cube.push_back(r->form(i)); + } +} + +void simplify_bounds_new (expr_ref_vector &cube) { + ast_manager &m = cube.m(); + + + scoped_no_proof _no_pf_(m); + + goal_ref g(alloc(goal, m, false, false, false)); + for (unsigned i = 0, sz = cube.size(); i < sz; ++i) { + g->assert_expr(cube.get(i)); + } + + model_converter_ref mc; + proof_converter_ref pc; + expr_dependency_ref dep(m); + goal_ref_buffer goals; + tactic_ref prop_values = mk_propagate_values_tactic(m); + tactic_ref prop_bounds = mk_propagate_ineqs_tactic(m); + tactic_ref t = and_then(prop_values.get(), prop_bounds.get()); + + (*t)(g, goals, mc, pc, dep); + SASSERT(goals.size() == 1); + + g = goals[0]; + cube.reset(); + for (unsigned i = 0; i < g->size(); ++i) { + cube.push_back(g->form(i)); + } +} + +void simplify_bounds(expr_ref_vector &cube) { + simplify_bounds_new(cube); +} + +/// Adhoc rewriting of arithmetic expressions +struct adhoc_rewriter_cfg : public default_rewriter_cfg { + ast_manager &m; + arith_util m_util; + + adhoc_rewriter_cfg (ast_manager &manager) : m(manager), m_util(m) {} + + bool is_le(func_decl const * n) const + { return is_decl_of(n, m_util.get_family_id (), OP_LE); } + bool is_ge(func_decl const * n) const + { return is_decl_of(n, m_util.get_family_id (), OP_GE); } + + br_status reduce_app (func_decl * f, unsigned num, expr * const * args, + expr_ref & result, proof_ref & result_pr) + { + expr * e; + br_status st = BR_FAILED; + if (is_le(f)) { + st = mk_le_core (args[0], args[1], result); + } else if (is_ge(f)) { + st = mk_ge_core (args[0], args[1], result); + } else if (m.is_not(f)) { + if (m.is_not (args[0], e)) { + result = e; + st = BR_DONE; + } + } + + return st; + } + + br_status mk_le_core (expr *arg1, expr * arg2, expr_ref & result) + { + // t <= -1 ==> t < 0 ==> ! (t >= 0) + if (m_util.is_int (arg1) && m_util.is_minus_one (arg2)) { + result = m.mk_not (m_util.mk_ge (arg1, mk_zero ())); + return BR_DONE; + } + return BR_FAILED; + } + br_status mk_ge_core (expr * arg1, expr * arg2, expr_ref & result) + { + // t >= 1 ==> t > 0 ==> ! (t <= 0) + if (m_util.is_int (arg1) && is_one (arg2)) { + + result = m.mk_not (m_util.mk_le (arg1, mk_zero ())); + return BR_DONE; + } + return BR_FAILED; + } + expr * mk_zero () {return m_util.mk_numeral (rational (0), true);} + bool is_one (expr const * n) const + {rational val; return m_util.is_numeral (n, val) && val.is_one ();} +}; + +void normalize (expr *e, expr_ref &out, + bool use_simplify_bounds, + bool use_factor_eqs) +{ + + params_ref params; + // arith_rewriter + params.set_bool ("sort_sums", true); + params.set_bool ("gcd_rounding", true); + params.set_bool ("arith_lhs", true); + // poly_rewriter + params.set_bool ("som", true); + params.set_bool ("flat", true); + + // apply rewriter + th_rewriter rw(out.m(), params); + rw (e, out); + + adhoc_rewriter_cfg adhoc_cfg(out.m ()); + rewriter_tpl adhoc_rw (out.m (), false, adhoc_cfg); + adhoc_rw (out.get (), out); + + if (out.m().is_and(out)) { + expr_ref_vector v(out.m()); + flatten_and (out, v); + + if (v.size() > 1) { + // sort arguments of the top-level and + std::stable_sort (v.c_ptr(), v.c_ptr () + v.size (), ast_lt_proc()); + + if (use_simplify_bounds) { + // remove redundant inequalities + simplify_bounds (v); + } + if (use_factor_eqs) { + // pick non-constant value representative for + // equivalence classes + expr_equiv_class eq_classes(out.m()); + factor_eqs(v, eq_classes); + equiv_to_expr(eq_classes, v); + } + + out = mk_and (v); + } + } +} + +// rewrite term such that the pretty printing is easier to read +struct adhoc_rewriter_rpp : public default_rewriter_cfg { + ast_manager &m; + arith_util m_arith; + + adhoc_rewriter_rpp (ast_manager &manager) : m(manager), m_arith(m) {} + + bool is_le(func_decl const * n) const + { return is_decl_of(n, m_arith.get_family_id (), OP_LE); } + bool is_ge(func_decl const * n) const + { return is_decl_of(n, m_arith.get_family_id (), OP_GE); } + bool is_lt(func_decl const * n) const + { return is_decl_of(n, m_arith.get_family_id (), OP_LT); } + bool is_gt(func_decl const * n) const + { return is_decl_of(n, m_arith.get_family_id (), OP_GT); } + bool is_zero (expr const * n) const + {rational val; return m_arith.is_numeral(n, val) && val.is_zero();} + + br_status reduce_app (func_decl * f, unsigned num, expr * const * args, + expr_ref & result, proof_ref & result_pr) + { + br_status st = BR_FAILED; + expr *e1, *e2, *e3, *e4; + + // rewrites (= (+ A (* -1 B)) 0) into (= A B) + if (m.is_eq (f) && is_zero (args [1]) && + m_arith.is_add (args[0], e1, e2) && + m_arith.is_mul (e2, e3, e4) && m_arith.is_minus_one (e3)) { + result = m.mk_eq (e1, e4); + return BR_DONE; + } + // simplify normalized leq, where right side is different from 0 + // rewrites (<= (+ A (* -1 B)) C) into (<= A B+C) + else if ((is_le(f) || is_lt(f) || is_ge(f) || is_gt(f)) && + m_arith.is_add (args[0], e1, e2) && + m_arith.is_mul (e2, e3, e4) && m_arith.is_minus_one (e3)) { + expr_ref rhs(m); + rhs = is_zero (args[1]) ? e4 : m_arith.mk_add(e4, args[1]); + + if (is_le(f)) { + result = m_arith.mk_le(e1, rhs); + st = BR_DONE; + } else if (is_lt(f)) { + result = m_arith.mk_lt(e1, rhs); + st = BR_DONE; + } else if (is_ge(f)) { + result = m_arith.mk_ge(e1, rhs); + st = BR_DONE; + } else if (is_gt(f)) { + result = m_arith.mk_gt(e1, rhs); + st = BR_DONE; + } else + { UNREACHABLE(); } + } + // simplify negation of ordering predicate + else if (m.is_not (f)) { + if (m_arith.is_lt(args[0], e1, e2)) { + result = m_arith.mk_ge(e1, e2); + st = BR_DONE; + } else if (m_arith.is_le(args[0], e1, e2)) { + result = m_arith.mk_gt(e1, e2); + st = BR_DONE; + } else if (m_arith.is_gt(args[0], e1, e2)) { + result = m_arith.mk_le(e1, e2); + st = BR_DONE; + } else if (m_arith.is_ge(args[0], e1, e2)) { + result = m_arith.mk_lt(e1, e2); + st = BR_DONE; + } + } + return st; + } + +}; +mk_epp::mk_epp(ast *t, ast_manager &m, unsigned indent, + unsigned num_vars, char const * var_prefix) : + mk_pp (t, m, m_epp_params, indent, num_vars, var_prefix), m_epp_expr(m) { + m_epp_params.set_uint("min_alias_size", UINT_MAX); + m_epp_params.set_uint("max_depth", UINT_MAX); + + if (is_expr (m_ast)) { + rw(to_expr(m_ast), m_epp_expr); + m_ast = m_epp_expr; + } +} + +void mk_epp::rw(expr *e, expr_ref &out) +{ + adhoc_rewriter_rpp cfg(out.m()); + rewriter_tpl arw(out.m(), false, cfg); + arw(e, out); +} + + void ground_expr (expr *e, expr_ref &out, app_ref_vector &vars) + { + expr_free_vars fv; + ast_manager &m = out.get_manager (); + fv (e); + if (vars.size () < fv.size ()) + { vars.resize(fv.size()); } + for (unsigned i = 0, sz = fv.size (); i < sz; ++i) { + SASSERT (fv[i]); + std::string str = "zk!" + datalog::to_string(sz - 1 - i); + vars [i] = m.mk_const (symbol(str.c_str()), fv [i]); + } + var_subst vs(m); + vs (e, vars.size (), (expr**) vars.c_ptr (), out); + } + + + struct index_term_finder { + ast_manager &m; + array_util m_array; + app_ref m_var; + expr_ref_vector &m_res; + + index_term_finder (ast_manager &mgr, app* v, expr_ref_vector &res) : m(mgr), m_array (m), m_var (v, m), m_res (res) {} + void operator() (var *n) {} + void operator() (quantifier *n) {} + void operator() (app *n) + { + expr *e1, *e2; + if (m_array.is_select (n) && n->get_arg (1) != m_var) { + m_res.push_back (n->get_arg (1)); + } else if (m.is_eq(n, e1, e2)) { + if (e1 == m_var) { m_res.push_back(e2); } + else if (e2 == m_var) { m_res.push_back(e1); } + } + } + }; + + bool mbqi_project_var (model_evaluator_util &mev, app* var, expr_ref &fml) + { + ast_manager &m = fml.get_manager (); + + expr_ref val(m); + mev.eval (var, val, false); + + TRACE ("mbqi_project_verbose", + tout << "MBQI: var: " << mk_pp (var, m) << "\n" + << "fml: " << mk_pp (fml, m) << "\n";); + expr_ref_vector terms (m); + index_term_finder finder (m, var, terms); + for_each_expr (finder, fml); + + + TRACE ("mbqi_project_verbose", + tout << "terms:\n"; + for (unsigned i = 0, e = terms.size (); i < e; ++i) + tout << i << ": " << mk_pp (terms.get (i), m) << "\n"; + ); + + for (unsigned i = 0, e = terms.size(); i < e; ++i) { + expr* term = terms.get (i); + expr_ref tval (m); + mev.eval (term, tval, false); + + TRACE ("mbqi_project_verbose", + tout << "term: " << mk_pp (term, m) + << " tval: " << mk_pp (tval, m) + << " val: " << mk_pp (val, m) << "\n";); + + // -- if the term does not contain an occurrence of var + // -- and is in the same equivalence class in the model + if (tval == val && !occurs (var, term)) { + TRACE ("mbqi_project", + tout << "MBQI: replacing " << mk_pp (var, m) << " with " << mk_pp (term, m) << "\n";); + expr_safe_replace sub(m); + sub.insert (var, term); + sub (fml); + return true; + } + } + + TRACE ("mbqi_project", + tout << "MBQI: failed to eliminate " << mk_pp (var, m) << " from " << mk_pp (fml, m) << "\n";); + + return false; + } + + void mbqi_project (model &M, app_ref_vector &vars, expr_ref &fml) + { + ast_manager &m = fml.get_manager (); + model_evaluator_util mev(m); + mev.set_model (M); + expr_ref tmp(m); + // -- evaluate to initialize mev cache + mev.eval (fml, tmp, false); + tmp.reset (); + + for (unsigned idx = 0; idx < vars.size (); ) { + if (mbqi_project_var (mev, vars.get (idx), fml)) { + vars[idx] = vars.back (); + vars.pop_back (); + } else { + idx++; + } + } + } + +bool contains_selects(expr* fml, ast_manager& m) +{ + array_util a_util(m); + if (!is_app(fml)) { return false; } + ast_mark done; + ptr_vector todo; + todo.push_back (to_app (fml)); + while (!todo.empty ()) { + app* a = todo.back (); + if (done.is_marked (a)) { + todo.pop_back (); + continue; + } + unsigned num_args = a->get_num_args (); + bool all_done = true; + for (unsigned i = 0; i < num_args; i++) { + expr* arg = a->get_arg (i); + if (!done.is_marked (arg) && is_app (arg)) { + todo.push_back (to_app (arg)); + all_done = false; + } + } + if (!all_done) { continue; } + todo.pop_back (); + if (a_util.is_select (a)) + { return true; } + done.mark (a, true); + } + return false; + } + +void get_select_indices(expr* fml, app_ref_vector& indices, ast_manager& m) +{ + array_util a_util(m); + if (!is_app(fml)) { return; } + ast_mark done; + ptr_vector todo; + todo.push_back (to_app (fml)); + while (!todo.empty ()) { + app* a = todo.back (); + if (done.is_marked (a)) { + todo.pop_back (); + continue; + } + unsigned num_args = a->get_num_args (); + bool all_done = true; + for (unsigned i = 0; i < num_args; i++) { + expr* arg = a->get_arg (i); + if (!done.is_marked (arg) && is_app (arg)) { + todo.push_back (to_app (arg)); + all_done = false; + } + } + if (!all_done) { continue; } + todo.pop_back (); + if (a_util.is_select (a)) { + SASSERT(a->get_num_args() == 2); + indices.push_back(to_app(a->get_arg(1))); + } + done.mark (a, true); + } + } + +void find_decls(expr* fml, app_ref_vector& decls, std::string& prefix) +{ + if (!is_app(fml)) { return; } + ast_mark done; + ptr_vector todo; + todo.push_back (to_app (fml)); + while (!todo.empty ()) { + app* a = todo.back (); + if (done.is_marked (a)) { + todo.pop_back (); + continue; + } + unsigned num_args = a->get_num_args (); + bool all_done = true; + for (unsigned i = 0; i < num_args; i++) { + expr* arg = a->get_arg (i); + if (!done.is_marked (arg) && is_app (arg)) { + todo.push_back (to_app (arg)); + all_done = false; + } + } + if (!all_done) { continue; } + todo.pop_back (); + if (a->get_decl()->get_name().str().find(prefix) != std::string::npos) + { decls.push_back(a); } + done.mark (a, true); + } + return; +} + +} +template class rewriter_tpl; +template class rewriter_tpl; +template class rewriter_tpl; diff --git a/src/muz/spacer/spacer_util.h b/src/muz/spacer/spacer_util.h new file mode 100644 index 000000000..7fb17329e --- /dev/null +++ b/src/muz/spacer/spacer_util.h @@ -0,0 +1,172 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + spacer_util.h + +Abstract: + + Utility functions for SPACER. + +Author: + + Krystof Hoder (t-khoder) 2011-8-19. + Arie Gurfinkel + Anvesh Komuravelli + +Revision History: + +--*/ + +#ifndef _SPACER_UTIL_H_ +#define _SPACER_UTIL_H_ + +#include "ast/ast.h" +#include "ast/ast_pp.h" +#include "util/obj_hashtable.h" +#include "util/ref_vector.h" +#include "util/trace.h" +#include "util/vector.h" +#include "ast/arith_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/ast_util.h" +#include "ast/expr_map.h" +#include "model/model.h" + +#include "util/stopwatch.h" +#include "muz/spacer/spacer_antiunify.h" + +class model; +class model_core; +class model_evaluator; + +namespace spacer { + +inline unsigned infty_level () {return UINT_MAX;} + +inline bool is_infty_level(unsigned lvl) +{ return lvl == infty_level (); } + +inline unsigned next_level(unsigned lvl) +{ return is_infty_level(lvl)?lvl:(lvl+1); } + +inline unsigned prev_level (unsigned lvl) +{ + if(is_infty_level(lvl)) { return infty_level(); } + if(lvl == 0) { return 0; } + return lvl -1; +} + +struct pp_level { + unsigned m_level; + pp_level(unsigned l): m_level(l) {} +}; + +inline std::ostream& operator<<(std::ostream& out, pp_level const& p) +{ + if (is_infty_level(p.m_level)) { + return out << "oo"; + } else { + return out << p.m_level; + } +} + + + + +typedef ptr_vector app_vector; +typedef ptr_vector decl_vector; +typedef obj_hashtable func_decl_set; + + +class model_evaluator_util { + ast_manager& m; + model_ref m_model; + model_evaluator* m_mev; + + /// initialize with a given model. All previous state is lost. model can be NULL + void reset (model *model); +public: + model_evaluator_util(ast_manager& m); + ~model_evaluator_util(); + + void set_model(model &model) {reset (&model);} + model_ref &get_model() {return m_model;} + ast_manager& get_ast_manager() const {return m;} + +public: + bool is_true (const expr_ref_vector &v); + bool is_false(expr* x); + bool is_true(expr* x); + + bool eval (const expr_ref_vector &v, expr_ref &result, bool model_completion); + /// evaluates an expression + bool eval (expr *e, expr_ref &result, bool model_completion); + // expr_ref eval(expr* e, bool complete=true); +}; + + +/** + \brief replace variables that are used in many disequalities by + an equality using the model. + + Assumption: the model satisfies the conjunctions. +*/ +void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml); + +/** + \brief hoist non-boolean if expressions. +*/ +void hoist_non_bool_if(expr_ref& fml); + +bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls); + +bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls); + +/** + * do the following in sequence + * 1. use qe_lite to cheaply eliminate vars + * 2. for remaining boolean vars, substitute using M + * 3. use MBP for remaining array and arith variables + * 4. for any remaining arith variables, substitute using M + */ +void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, + const model_ref& M, bool reduce_all_selects=false, bool native_mbp=false, + bool dont_sub=false); + +void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, model_ref& M, expr_map& map); + +void expand_literals(ast_manager &m, expr_ref_vector& conjs); +void compute_implicant_literals (model_evaluator_util &mev, + expr_ref_vector &formula, expr_ref_vector &res); +void simplify_bounds (expr_ref_vector &lemmas); +void normalize(expr *e, expr_ref &out, bool use_simplify_bounds = true, bool factor_eqs = false); + +/** ground expression by replacing all free variables by skolem constants */ +void ground_expr (expr *e, expr_ref &out, app_ref_vector &vars); + + +void mbqi_project (model &M, app_ref_vector &vars, expr_ref &fml); + +bool contains_selects (expr* fml, ast_manager& m); +void get_select_indices (expr* fml, app_ref_vector& indices, ast_manager& m); + +void find_decls (expr* fml, app_ref_vector& decls, std::string& prefix); + +/** extended pretty-printer + * used for debugging + * disables aliasing of common sub-expressions +*/ +struct mk_epp : public mk_pp { + params_ref m_epp_params; + expr_ref m_epp_expr; + mk_epp(ast *t, ast_manager &m, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = 0); + void rw(expr *e, expr_ref &out); + +}; + +} + +#endif diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp new file mode 100644 index 000000000..938e8cb94 --- /dev/null +++ b/src/muz/spacer/spacer_virtual_solver.cpp @@ -0,0 +1,360 @@ +/** +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_virtual_solver.cpp + +Abstract: + + multi-solver view of a single smt::kernel + +Author: + + Arie Gurfinkel + +Notes: + +--*/ + +#include "muz/spacer/spacer_virtual_solver.h" +#include "ast/ast_util.h" +#include "ast/ast_pp_util.h" +#include "muz/spacer/spacer_util.h" +#include "ast/rewriter/bool_rewriter.h" + +#include "ast/proofs/proof_checker.h" +#include "ast/proofs/proof_utils.h" + +#include "ast/scoped_proof.h" + +namespace spacer { +virtual_solver::virtual_solver(virtual_solver_factory &factory, + smt::kernel &context, app* pred) : + solver_na2as(context.m()), + m_factory(factory), + m(context.m()), + m_context(context), + m_pred(pred, m), + m_virtual(!m.is_true(pred)), + m_assertions(m), + m_head(0), + m_flat(m), + m_pushed(false), + m_in_delay_scope(false), + m_dump_benchmarks(factory.fparams().m_dump_benchmarks), + m_dump_counter(0), + m_proof(m) +{ + // -- insert m_pred->true background assumption this will not + // -- change m_context, but will add m_pred to + // -- the private field solver_na2as::m_assumptions + if (m_virtual) + { solver_na2as::assert_expr(m.mk_true(), m_pred); } +} + +virtual_solver::~virtual_solver() +{ + SASSERT(!m_pushed || get_scope_level() > 0); + if (m_pushed) { pop(get_scope_level()); } + + if (m_virtual) { + m_pred = m.mk_not(m_pred); + m_context.assert_expr(m_pred); + } +} + +namespace { + + +// TBD: move to ast/proofs/elim_aux_assertions + + +} + +proof *virtual_solver::get_proof() +{ + scoped_watch _t_(m_factory.m_proof_watch); + + if (!m_proof.get()) { + elim_aux_assertions pc(m_pred); + m_proof = m_context.get_proof(); + pc(m, m_proof.get(), m_proof); + } + return m_proof.get(); +} + +bool virtual_solver::is_aux_predicate(expr *p) +{return is_app(p) && to_app(p) == m_pred.get();} + +lbool virtual_solver::check_sat_core(unsigned num_assumptions, + expr *const * assumptions) +{ + SASSERT(!m_pushed || get_scope_level() > 0); + m_proof.reset(); + scoped_watch _t_(m_factory.m_check_watch); + m_factory.m_stats.m_num_smt_checks++; + + stopwatch sw; + sw.start(); + internalize_assertions(); + if (false) { + std::stringstream file_name; + file_name << "virt_solver"; + if (m_virtual) { file_name << "_" << m_pred->get_decl()->get_name(); } + file_name << "_" << (m_dump_counter++) << ".smt2"; + + verbose_stream() << "Dumping SMT2 benchmark: " << file_name.str() << "\n"; + + std::ofstream out(file_name.str().c_str()); + + to_smt2_benchmark(out, m_context, num_assumptions, assumptions, + "virt_solver"); + + out << "(exit)\n"; + out.close(); + } + lbool res = m_context.check(num_assumptions, assumptions); + sw.stop(); + if (res == l_true) { + m_factory.m_check_sat_watch.add(sw); + m_factory.m_stats.m_num_sat_smt_checks++; + } else if (res == l_undef) { + m_factory.m_check_undef_watch.add(sw); + m_factory.m_stats.m_num_undef_smt_checks++; + } + set_status(res); + + if (m_dump_benchmarks && + sw.get_seconds() >= m_factory.fparams().m_dump_min_time) { + std::stringstream file_name; + file_name << "virt_solver"; + if (m_virtual) { file_name << "_" << m_pred->get_decl()->get_name(); } + file_name << "_" << (m_dump_counter++) << ".smt2"; + + std::ofstream out(file_name.str().c_str()); + + + out << "(set-info :status "; + if (res == l_true) { out << "sat"; } + else if (res == l_false) { out << "unsat"; } + else { out << "unknown"; } + out << ")\n"; + + to_smt2_benchmark(out, m_context, num_assumptions, assumptions, + "virt_solver"); + + out << "(exit)\n"; + ::statistics st; + m_context.collect_statistics(st); + st.update("time", sw.get_seconds()); + st.display_smt2(out); + + out.close(); + + if (m_factory.fparams().m_dump_recheck) { + scoped_no_proof _no_proof_(m); + smt_params p; + stopwatch sw2; + smt::kernel kernel(m, p); + for (unsigned i = 0, sz = m_context.size(); i < sz; ++i) + { kernel.assert_expr(m_context.get_formula(i)); } + sw2.start(); + kernel.check(num_assumptions, assumptions); + sw2.stop(); + verbose_stream() << file_name.str() << " :orig " + << sw.get_seconds() << " :new " << sw2.get_seconds(); + } + } + + + return res; +} + +void virtual_solver::push_core() +{ + SASSERT(!m_pushed || get_scope_level() > 0); + if (m_in_delay_scope) { + // second push + internalize_assertions(); + m_context.push(); + m_pushed = true; + m_in_delay_scope = false; + } + + if (!m_pushed) { m_in_delay_scope = true; } + else { + SASSERT(m_pushed); + SASSERT(!m_in_delay_scope); + m_context.push(); + } +} +void virtual_solver::pop_core(unsigned n) { + SASSERT(!m_pushed || get_scope_level() > 0); + if (m_pushed) { + SASSERT(!m_in_delay_scope); + m_context.pop(n); + m_pushed = get_scope_level() - n > 0; + } + else { + m_in_delay_scope = get_scope_level() - n > 0; + } +} + +void virtual_solver::get_unsat_core(ptr_vector &r) +{ + for (unsigned i = 0, sz = m_context.get_unsat_core_size(); i < sz; ++i) { + expr *core = m_context.get_unsat_core_expr(i); + if (is_aux_predicate(core)) { continue; } + r.push_back(core); + } +} + +void virtual_solver::assert_expr(expr *e) +{ + SASSERT(!m_pushed || get_scope_level() > 0); + if (m.is_true(e)) { return; } + if (m_in_delay_scope) { + internalize_assertions(); + m_context.push(); + m_pushed = true; + m_in_delay_scope = false; + } + + if (m_pushed) + { m_context.assert_expr(e); } + else { + m_flat.push_back(e); + flatten_and(m_flat); + m_assertions.append(m_flat); + m_flat.reset(); + } +} +void virtual_solver::internalize_assertions() +{ + SASSERT(!m_pushed || m_head == m_assertions.size()); + for (unsigned sz = m_assertions.size(); m_head < sz; ++m_head) { + expr_ref f(m); + f = m.mk_implies(m_pred, (m_assertions.get(m_head))); + m_context.assert_expr(f); + } +} +void virtual_solver::refresh() +{ + SASSERT(!m_pushed); + m_head = 0; +} + +void virtual_solver::reset() +{ + SASSERT(!m_pushed); + m_head = 0; + m_assertions.reset(); + m_factory.refresh(); +} + +void virtual_solver::get_labels(svector &r) +{ + r.reset(); + buffer tmp; + m_context.get_relevant_labels(0, tmp); + r.append(tmp.size(), tmp.c_ptr()); +} + +solver* virtual_solver::translate(ast_manager& m, params_ref const& p) +{ + UNREACHABLE(); + return 0; +} +void virtual_solver::updt_params(params_ref const &p) +{ m_factory.updt_params(p); } +void virtual_solver::collect_param_descrs(param_descrs &r) +{ m_factory.collect_param_descrs(r); } +void virtual_solver::set_produce_models(bool f) +{ m_factory.set_produce_models(f); } +bool virtual_solver::get_produce_models() +{return m_factory.get_produce_models(); } +smt_params &virtual_solver::fparams() +{return m_factory.fparams();} + +void virtual_solver::to_smt2_benchmark(std::ostream &out, + smt::kernel &context, + unsigned num_assumptions, + expr * const * assumptions, + char const * name, + symbol const &logic, + char const * status, + char const * attributes) +{ + ast_pp_util pp(m); + expr_ref_vector asserts(m); + + + for (unsigned i = 0, sz = context.size(); i < sz; ++i) { + asserts.push_back(context.get_formula(i)); + pp.collect(asserts.back()); + } + pp.collect(num_assumptions, assumptions); + pp.display_decls(out); + pp.display_asserts(out, asserts); + out << "(check-sat "; + for (unsigned i = 0; i < num_assumptions; ++i) + { out << mk_pp(assumptions[i], m) << " "; } + out << ")\n"; +} + + +virtual_solver_factory::virtual_solver_factory(ast_manager &mgr, smt_params &fparams) : + m_fparams(fparams), m(mgr), m_context(m, m_fparams) +{ + m_stats.reset(); +} + +virtual_solver* virtual_solver_factory::mk_solver() +{ + std::stringstream name; + name << "vsolver#" << m_solvers.size(); + app_ref pred(m); + pred = m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()); + SASSERT(m_context.get_scope_level() == 0); + m_solvers.push_back(alloc(virtual_solver, *this, m_context, pred)); + return m_solvers.back(); +} + +void virtual_solver_factory::collect_statistics(statistics &st) const +{ + m_context.collect_statistics(st); + st.update("time.virtual_solver.smt.total", m_check_watch.get_seconds()); + st.update("time.virtual_solver.smt.total.sat", m_check_sat_watch.get_seconds()); + st.update("time.virtual_solver.smt.total.undef", m_check_undef_watch.get_seconds()); + st.update("time.virtual_solver.proof", m_proof_watch.get_seconds()); + st.update("virtual_solver.checks", m_stats.m_num_smt_checks); + st.update("virtual_solver.checks.sat", m_stats.m_num_sat_smt_checks); + st.update("virtual_solver.checks.undef", m_stats.m_num_undef_smt_checks); +} +void virtual_solver_factory::reset_statistics() +{ + m_context.reset_statistics(); + m_stats.reset(); + m_check_sat_watch.reset(); + m_check_undef_watch.reset(); + m_check_watch.reset(); + m_proof_watch.reset(); +} + +void virtual_solver_factory::refresh() +{ + m_context.reset(); + for (unsigned i = 0, e = m_solvers.size(); i < e; ++i) + { m_solvers [i]->refresh(); } +} + +virtual_solver_factory::~virtual_solver_factory() +{ + for (unsigned i = 0, e = m_solvers.size(); i < e; ++i) + { dealloc(m_solvers [i]); } +} + + + +} diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h new file mode 100644 index 000000000..fed64c589 --- /dev/null +++ b/src/muz/spacer/spacer_virtual_solver.h @@ -0,0 +1,154 @@ +/** +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_virtual_solver.h + +Abstract: + + multi-solver view of a single smt::kernel + +Author: + + Arie Gurfinkel + +Notes: + +--*/ +#ifndef SPACER_VIRTUAL_SOLVER_H_ +#define SPACER_VIRTUAL_SOLVER_H_ +#include"ast/ast.h" +#include"util/params.h" +#include"solver/solver_na2as.h" +#include"smt/smt_kernel.h" +#include"smt/params/smt_params.h" +#include"util/stopwatch.h" +namespace spacer { +class virtual_solver_factory; + +class virtual_solver : public solver_na2as { + friend class virtual_solver_factory; + +private: + virtual_solver_factory &m_factory; + ast_manager &m; + smt::kernel &m_context; + app_ref m_pred; + + bool m_virtual; + expr_ref_vector m_assertions; + unsigned m_head; + // temporary to flatten conjunction + expr_ref_vector m_flat; + + bool m_pushed; + bool m_in_delay_scope; + bool m_dump_benchmarks; + unsigned m_dump_counter; + + proof_ref m_proof; + + virtual_solver(virtual_solver_factory &factory, smt::kernel &context, app* pred); + + bool is_aux_predicate(expr *p); + void internalize_assertions(); + void to_smt2_benchmark(std::ostream &out, + smt::kernel &context, + unsigned num_assumptions, + expr * const * assumptions, + char const * name = "benchmarks", + symbol const &logic = symbol::null, + char const * status = "unknown", + char const * attributes = ""); + + void refresh(); + +public: + virtual ~virtual_solver(); + virtual unsigned get_num_assumptions() const + { + unsigned sz = solver_na2as::get_num_assumptions(); + return m_virtual ? sz - 1 : sz; + } + virtual expr* get_assumption(unsigned idx) const + { + if(m_virtual) { idx++; } + return solver_na2as::get_assumption(idx); + } + + virtual void get_unsat_core(ptr_vector &r); + virtual void assert_expr(expr *e); + virtual void collect_statistics(statistics &st) const {} + virtual void get_model(model_ref &m) {m_context.get_model(m);} + virtual proof* get_proof(); + virtual std::string reason_unknown() const + {return m_context.last_failure_as_string();} + virtual void set_reason_unknown(char const *msg) + {m_context.set_reason_unknown(msg);} + virtual ast_manager& get_manager() const {return m;} + virtual void get_labels(svector &r); + virtual void set_produce_models(bool f); + virtual bool get_produce_models(); + virtual smt_params &fparams(); + virtual void reset(); + virtual void set_progress_callback(progress_callback *callback) + {UNREACHABLE();} + + virtual solver *translate(ast_manager &m, params_ref const &p); + + virtual void updt_params(params_ref const &p); + virtual void collect_param_descrs(param_descrs &r); + + +protected: + virtual lbool check_sat_core(unsigned num_assumptions, expr *const * assumptions); + virtual void push_core(); + virtual void pop_core(unsigned n); +}; + +/// multi-solver abstraction on top of a single smt::kernel +class virtual_solver_factory { + friend class virtual_solver; +private: + smt_params &m_fparams; + ast_manager &m; + smt::kernel m_context; + /// solvers managed by this factory + ptr_vector m_solvers; + + struct stats { + unsigned m_num_smt_checks; + unsigned m_num_sat_smt_checks; + unsigned m_num_undef_smt_checks; + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + }; + + stats m_stats; + stopwatch m_check_watch; + stopwatch m_check_sat_watch; + stopwatch m_check_undef_watch; + stopwatch m_proof_watch; + + + void refresh(); + + smt_params &fparams() { return m_fparams; } + +public: + virtual_solver_factory(ast_manager &mgr, smt_params &fparams); + virtual ~virtual_solver_factory(); + virtual_solver* mk_solver(); + void collect_statistics(statistics &st) const; + void reset_statistics(); + void updt_params(params_ref const &p) { m_fparams.updt_params(p); } + void collect_param_descrs(param_descrs &r) { /* empty */ } + void set_produce_models(bool f) { m_fparams.m_model = f; } + bool get_produce_models() { return m_fparams.m_model; } +}; + +} + + +#endif diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index 35eb5d936..8809c0dc7 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -17,21 +17,21 @@ Revision History: --*/ -#include "tab_context.h" -#include "trail.h" -#include "dl_rule_set.h" -#include "dl_context.h" -#include "dl_mk_rule_inliner.h" -#include "smt_kernel.h" -#include "qe_lite.h" -#include "bool_rewriter.h" -#include "th_rewriter.h" -#include "datatype_decl_plugin.h" -#include "for_each_expr.h" -#include "matcher.h" -#include "scoped_proof.h" -#include "fixedpoint_params.hpp" -#include "ast_util.h" +#include "muz/tab/tab_context.h" +#include "util/trail.h" +#include "muz/base/dl_rule_set.h" +#include "muz/base/dl_context.h" +#include "muz/transforms/dl_mk_rule_inliner.h" +#include "smt/smt_kernel.h" +#include "qe/qe_lite.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/for_each_expr.h" +#include "ast/substitution/matcher.h" +#include "ast/scoped_proof.h" +#include "muz/base/fixedpoint_params.hpp" +#include "ast/ast_util.h" namespace tb { diff --git a/src/muz/tab/tab_context.h b/src/muz/tab/tab_context.h index 703109475..329234524 100644 --- a/src/muz/tab/tab_context.h +++ b/src/muz/tab/tab_context.h @@ -19,10 +19,10 @@ Revision History: #ifndef TAB_CONTEXT_H_ #define TAB_CONTEXT_H_ -#include "ast.h" -#include "lbool.h" -#include "statistics.h" -#include "dl_engine_base.h" +#include "ast/ast.h" +#include "util/lbool.h" +#include "util/statistics.h" +#include "muz/base/dl_engine_base.h" namespace datalog { class context; diff --git a/src/muz/transforms/CMakeLists.txt b/src/muz/transforms/CMakeLists.txt index 6a0a1ac9c..5e8829d42 100644 --- a/src/muz/transforms/CMakeLists.txt +++ b/src/muz/transforms/CMakeLists.txt @@ -21,6 +21,8 @@ z3_add_component(transforms dl_mk_unbound_compressor.cpp dl_mk_unfold.cpp dl_transforms.cpp + dl_mk_array_eq_rewrite.cpp + dl_mk_array_instantiation.cpp COMPONENT_DEPENDENCIES dataflow hilbert diff --git a/src/muz/transforms/dl_mk_array_blast.cpp b/src/muz/transforms/dl_mk_array_blast.cpp index 031c5098e..8fe3f0e43 100644 --- a/src/muz/transforms/dl_mk_array_blast.cpp +++ b/src/muz/transforms/dl_mk_array_blast.cpp @@ -17,9 +17,9 @@ Revision History: --*/ -#include "dl_mk_array_blast.h" -#include "ast_util.h" -#include "scoped_proof.h" +#include "muz/transforms/dl_mk_array_blast.h" +#include "ast/ast_util.h" +#include "ast/scoped_proof.h" namespace datalog { @@ -319,6 +319,9 @@ namespace datalog { rule_set * mk_array_blast::operator()(rule_set const & source) { + if (!m_ctx.array_blast ()) { + return 0; + } rule_set* rules = alloc(rule_set, m_ctx); rules->inherit_predicates(source); rule_set::iterator it = source.begin(), end = source.end(); diff --git a/src/muz/transforms/dl_mk_array_blast.h b/src/muz/transforms/dl_mk_array_blast.h index 0bec9ae14..e7b951168 100644 --- a/src/muz/transforms/dl_mk_array_blast.h +++ b/src/muz/transforms/dl_mk_array_blast.h @@ -19,13 +19,13 @@ Revision History: #ifndef DL_MK_ARRAY_BLAST_H_ #define DL_MK_ARRAY_BLAST_H_ -#include"dl_context.h" -#include"dl_rule_set.h" -#include"dl_rule_transformer.h" -#include"dl_mk_interp_tail_simplifier.h" -#include "equiv_proof_converter.h" -#include "array_decl_plugin.h" -#include "expr_safe_replace.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_set.h" +#include "muz/base/dl_rule_transformer.h" +#include "muz/transforms/dl_mk_interp_tail_simplifier.h" +#include "tactic/equiv_proof_converter.h" +#include "ast/array_decl_plugin.h" +#include "ast/rewriter/expr_safe_replace.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_array_eq_rewrite.cpp b/src/muz/transforms/dl_mk_array_eq_rewrite.cpp new file mode 100644 index 000000000..c33cecda9 --- /dev/null +++ b/src/muz/transforms/dl_mk_array_eq_rewrite.cpp @@ -0,0 +1,121 @@ +/*++ + +Module Name: + + dl_mk_array_eq_rewrite.h + +Abstract: + Selects a representative for array equivalence classes. + +Author: + + Julien Braine + +Revision History: + +--*/ + +#include "ast/pattern/pattern_inference.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/expr_abstract.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_context.h" +#include "muz/base/fixedpoint_params.hpp" +#include "muz/transforms/dl_mk_array_eq_rewrite.h" +#include "ast/factor_equivs.h" + +namespace datalog { + + mk_array_eq_rewrite::mk_array_eq_rewrite( + context & ctx, unsigned priority): + plugin(priority), + m(ctx.get_manager()), + m_ctx(ctx), + m_a(m) + { + } + + rule_set * mk_array_eq_rewrite::operator()(rule_set const & source) + { + m_src_set = &source; + rule_set * result = alloc(rule_set, m_ctx); + result->inherit_predicates(source); + m_dst = result; + m_src_manager = &source.get_rule_manager(); + for (rule * rp : source) { + instantiate_rule(*rp, *result); + } + return result; + } + + void mk_array_eq_rewrite::instantiate_rule(const rule& r, rule_set & dest) + { + //Reset everything + m_cnt = m_src_manager->get_counter().get_max_rule_var(r)+1; + + + expr_ref_vector new_tail(m); + unsigned nb_predicates = r.get_uninterpreted_tail_size(); + unsigned tail_size = r.get_tail_size(); + for (unsigned i = 0; i < nb_predicates; i++) { + new_tail.push_back(r.get_tail(i)); + } + + expr_equiv_class array_eq_classes(m); + for(unsigned i = nb_predicates; i < tail_size; i++) { + expr* cond = r.get_tail(i); + expr* e1, *e2; + if (m.is_eq(cond, e1, e2) && m_a.is_array(get_sort(e1))) { + array_eq_classes.merge(e1, e2); + } + else { + new_tail.push_back(cond); + } + } + + for (auto c_eq : array_eq_classes) { + expr* representative = *(c_eq.begin()); + for (expr * v : c_eq) { + if (!is_var(v)) { + representative = v; + break; + } + } + for (expr * v : c_eq) { + for (unsigned i = 0; i < new_tail.size(); i++) + new_tail[i] = replace(new_tail[i].get(), representative, v); + } + for (expr * v : c_eq) { + new_tail.push_back(m.mk_eq(v, representative)); + } + } + params_ref select_over_store; + select_over_store.set_bool("expand_select_store", true); + th_rewriter t(m, select_over_store); + expr_ref_vector res_conjs(m); + for (expr* e : new_tail) { + expr_ref tmp(m); + t(e, tmp); + res_conjs.push_back(tmp); + } + proof_ref pr(m); + m_src_manager->mk_rule(m.mk_implies(m.mk_and(res_conjs.size(), res_conjs.c_ptr()), r.get_head()), pr, dest, r.name()); + } + + // NSB Code review: use substitution facility, such as expr_safe_replace or expr_replacer. + expr* mk_array_eq_rewrite::replace(expr* e, expr* new_val, expr* old_val) + { + if (e == old_val) + return new_val; + else if (!is_app(e)) { + return e; + } + app* f = to_app(e); + ptr_vector n_args; + for (expr * arg : *f) { + n_args.push_back(replace(arg, new_val, old_val)); + } + return m.mk_app(f->get_decl(), n_args.size(), n_args.c_ptr()); + } + +} diff --git a/src/muz/transforms/dl_mk_array_eq_rewrite.h b/src/muz/transforms/dl_mk_array_eq_rewrite.h new file mode 100644 index 000000000..166c01142 --- /dev/null +++ b/src/muz/transforms/dl_mk_array_eq_rewrite.h @@ -0,0 +1,51 @@ +/*++ + +Module Name: + + dl_mk_array_eq_rewrite.h + +Abstract: + Selects a representative for array equivalence classes. + +Author: + + Julien Braine + +Revision History: + +--*/ + +#ifndef DL_MK_ARRAY_EQ_REWRITE_H_ +#define DL_MK_ARRAY_EQ_REWRITE_H_ + +#include "muz/base/dl_rule_transformer.h" + +namespace datalog { + + class context; + class mk_array_eq_rewrite : public rule_transformer::plugin { + //Context objects + ast_manager& m; + context& m_ctx; + array_util m_a; + + //Rule set context + const rule_set* m_src_set; + rule_set* m_dst; + rule_manager* m_src_manager; + unsigned m_cnt;//Index for new variables + + expr* replace(expr* e, expr* new_val, expr* old_val); + void instantiate_rule(const rule& r, rule_set & dest); + + public: + mk_array_eq_rewrite(context & ctx, unsigned priority); + rule_set * operator()(rule_set const & source); + virtual ~mk_array_eq_rewrite(){} + }; + + + +}; + +#endif /* DL_MK_ARRAY_EQ_REWRITE_H_ */ diff --git a/src/muz/transforms/dl_mk_array_instantiation.cpp b/src/muz/transforms/dl_mk_array_instantiation.cpp new file mode 100644 index 000000000..362d83865 --- /dev/null +++ b/src/muz/transforms/dl_mk_array_instantiation.cpp @@ -0,0 +1,323 @@ +/*++ + +Module Name: + + dl_mk_array_instantiation.h + +Abstract: + + Does array instantiation + +Author: + + Julien Braine + +Revision History: + +--*/ + + +#include "muz/transforms/dl_mk_array_instantiation.h" +#include "muz/base/dl_context.h" +#include "ast/pattern/pattern_inference.h" +#include "muz/base/dl_context.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/expr_abstract.h" +#include "muz/base/fixedpoint_params.hpp" + +namespace datalog { + + mk_array_instantiation::mk_array_instantiation( + context & ctx, unsigned priority): + plugin(priority), + m(ctx.get_manager()), + m_ctx(ctx), + m_a(m), + eq_classes(m), + ownership(m) + { + } + + rule_set * mk_array_instantiation::operator()(rule_set const & source) + { + std::cout<<"Array Instantiation called with parameters :" + <<" enforce="<display(std::cout); + return result; + } + + void mk_array_instantiation::instantiate_rule(const rule& r, rule_set & dest) + { + //Reset everything + selects.reset(); + eq_classes.reset(); + cnt = src_manager->get_counter().get_max_rule_var(r)+1; + done_selects.reset(); + ownership.reset(); + + expr_ref_vector phi(m); + expr_ref_vector preds(m); + expr_ref new_head = create_head(to_app(r.get_head())); + unsigned nb_predicates = r.get_uninterpreted_tail_size(); + unsigned tail_size = r.get_tail_size(); + for(unsigned i=0;i::iterator it = done_selects.begin(); it!=done_selects.end(); ++it) + { + expr_ref tmp(m); + tmp = &it->get_key(); + new_tail.push_back(m.mk_eq(it->get_value(), tmp)); + } + proof_ref pr(m); + src_manager->mk_rule(m.mk_implies(m.mk_and(new_tail.size(), new_tail.c_ptr()), new_head), pr, dest, r.name()); + } + + expr_ref mk_array_instantiation::create_head(app* old_head) + { + expr_ref_vector new_args(m); + for(unsigned i=0;iget_num_args();i++) + { + expr*arg = old_head->get_arg(i); + if(m_a.is_array(get_sort(arg))) + { + for(unsigned k=0; k< m_ctx.get_params().xform_instantiate_arrays_nb_quantifier();k++) + { + expr_ref_vector dummy_args(m); + dummy_args.push_back(arg); + for(unsigned i=0;i()); + selects[arg].push_back(select); + } + if(!m_ctx.get_params().xform_instantiate_arrays_enforce()) + new_args.push_back(arg); + } + else + new_args.push_back(arg); + } + return create_pred(old_head, new_args); + } + + + void mk_array_instantiation::retrieve_selects(expr* e) + { + //If the expression is not a function application, we ignore it + if (!is_app(e)) { + return; + } + app*f=to_app(e); + //Call the function recursively on all arguments + unsigned nbargs = f->get_num_args(); + for(unsigned i=0;iget_arg(i)); + } + //If it is a select, then add it to selects + if(m_a.is_select(f)) + { + SASSERT(!m_a.is_array(get_sort(e))); + selects.insert_if_not_there(f->get_arg(0), ptr_vector()); + selects[f->get_arg(0)].push_back(e); + } + //If it is a condition between arrays, for example the result of a store, then add it to the equiv_classes + if(m_a.is_store(f)) + { + eq_classes.merge(e, f->get_arg(0)); + } + else if(m.is_eq(f) && m_a.is_array(get_sort(f->get_arg(0)))) + { + eq_classes.merge(f->get_arg(0), f->get_arg(1)); + } + } + + + expr_ref_vector mk_array_instantiation::getId(app*old_pred, const expr_ref_vector& n_args) + { + expr_ref_vector res(m); + for(unsigned i=0;iget_num_args();j++) + { + res.push_back(select->get_arg(j)); + } + } + } + return res; + } + + expr_ref mk_array_instantiation::create_pred(app*old_pred, expr_ref_vector& n_args) + { + expr_ref_vector new_args(m); + new_args.append(n_args); + new_args.append(getId(old_pred, n_args)); + for(unsigned i=0;iget_decl()->get_name().str()+"!inst").c_str()), new_sorts.size(), new_sorts.c_ptr(), old_pred->get_decl()->get_range()); + m_ctx.register_predicate(fun_decl, false); + if(src_set->is_output_predicate(old_pred->get_decl())) + dst->set_output_predicate(fun_decl); + res=m.mk_app(fun_decl,new_args.size(), new_args.c_ptr()); + return res; + } + + var * mk_array_instantiation::mk_select_var(expr* select) + { + var*result; + if(!done_selects.find(select, result)) + { + ownership.push_back(select); + result = m.mk_var(cnt, get_sort(select)); + cnt++; + done_selects.insert(select, result); + } + return result; + } + + expr_ref mk_array_instantiation::rewrite_select(expr*array, expr*select) + { + app*s = to_app(select); + expr_ref res(m); + expr_ref_vector args(m); + args.push_back(array); + for(unsigned i=1; iget_num_args();i++) + { + args.push_back(s->get_arg(i)); + } + res = m_a.mk_select(args.size(), args.c_ptr()); + return res; + } + + expr_ref_vector mk_array_instantiation::retrieve_all_selects(expr*array) + { + expr_ref_vector all_selects(m); + for(expr_equiv_class::iterator it = eq_classes.begin(array); + it != eq_classes.end(array); ++it) + { + selects.insert_if_not_there(*it, ptr_vector()); + ptr_vector& select_ops = selects[*it]; + for(unsigned i=0;iget_num_args(); + //Stores, for each old position, the list of a new possible arguments + vector arg_correspondance; + for(unsigned i=0;iget_arg(i), m); + if(m_a.is_array(get_sort(arg))) + { + vector arg_possibilities(m_ctx.get_params().xform_instantiate_arrays_nb_quantifier(), retrieve_all_selects(arg)); + arg_correspondance.append(arg_possibilities); + if(!m_ctx.get_params().xform_instantiate_arrays_enforce()) + { + expr_ref_vector tmp(m); + tmp.push_back(arg); + arg_correspondance.push_back(tmp); + } + } + else + { + expr_ref_vector tmp(m); + tmp.push_back(arg); + arg_correspondance.push_back(tmp); + } + } + //Now, we need to deal with every combination + + expr_ref_vector res(m); + + svector chosen(arg_correspondance.size(), 0u); + while(1) + { + expr_ref_vector new_args(m); + for(unsigned i=0;i=arg_correspondance[pos].size()); + chosen[pos]++; + } + } +} diff --git a/src/muz/transforms/dl_mk_array_instantiation.h b/src/muz/transforms/dl_mk_array_instantiation.h new file mode 100644 index 000000000..b87f679fc --- /dev/null +++ b/src/muz/transforms/dl_mk_array_instantiation.h @@ -0,0 +1,123 @@ +/*++ + +Module Name: + + dl_mk_array_instantiation.h + +Abstract: + Transforms predicates so that array invariants can be discovered. + + Motivation : Given a predicate P(a), no quantifier-free solution can express that P(a) <=> forall i, P(a[i]) = 0 + + Solution : Introduce a fresh variable i, and transform P(a) into P!inst(i, a). + Now, (P!inst(i,a) := a[i] = 0) <=> P(a) := forall i, a[i] = 0. + + Transformation on Horn rules: + P(a, args) /\ phi(a, args, args') => P'(args') (for simplicity, assume there are no arrays in args'). + Is transformed into: + (/\_r in read_indices(phi) P!inst(r, a, args)) /\ phi(a, args, args') => P'(args') + + Limitations : This technique can only discover invariants on arrays that depend on one quantifier. + Related work : Techniques relying on adding quantifiers and eliminating them. See dl_mk_quantifier_abstraction and dl_mk_quantifier_instantiation + +Implementation: + The implementation follows the solution suggested above, with more options. The addition of options implies that in the simple + case described above, we in fact have P(a) transformed into P(i, a[i], a). + + 1) Dealing with multiple quantifiers -> The options fixedpoint.xform.instantiate_arrays.nb_quantifier gives the number of quantifiers per array. + + 2) Inforcing the instantiation -> We suggest an option (enforce_instantiation) to enforce this abstraction. This transforms + P(a) into P(i, a[i]). This enforces the solver to limit the space search at the cost of imprecise results. This option + corresponds to fixedpoint.xform.instantiate_arrays.enforce + + 3) Adding slices in the mix -> We wish to have the possibility to further restrict the search space: we want to smash cells, given a smashing rule. + For example, in for loops j=0; j P'(...) is transformed into + (/\_r in read_indices(phi) P!inst(id_r, a[r], a) /\ GetId(r) = id_r) /\ phi(a, ...) => P'(...). + Note : when no slicing is done, GetId(i) = i. + This option corresponds to fixedpoint.xform.instantiate_arrays.slice_technique + + Although we described GetId as returning integers, there is no reason to restrict the type of ids to integers. A more direct method, + for the 0<=i > selects; + expr_equiv_class eq_classes; + unsigned cnt;//Index for new variables + obj_map done_selects; + expr_ref_vector ownership; + + //Helper functions + void instantiate_rule(const rule& r, rule_set & dest);//Instantiates the rule + void retrieve_selects(expr* e);//Retrieves all selects (fills the selects and eq_classes members) + expr_ref rewrite_select(expr*array, expr*select);//Rewrites select(a, args) to select(array, args) + expr_ref_vector retrieve_all_selects(expr*array);//Retrieves all selects linked to a given array (using eq classes and selects) + expr_ref_vector instantiate_pred(app*old_pred);//Returns all the instantiation of a given predicate + expr_ref create_pred(app*old_pred, expr_ref_vector& new_args);//Creates a predicate + expr_ref create_head(app* old_head);//Creates the new head + var * mk_select_var(expr* select); + + /*Given the old predicate, and the new arguments for the new predicate, returns the new setId arguments. + By default getId(P(x, y, a, b), (x, y, a[i], a[j], a, b[k], b[l], b)) (nb_quantifier=2, enforce=false) + returns (i,j,k,l) + So that the final created predicate is P!inst(x, y, a[i], a[j], a, b[k], b[l], b, i, j, k, l) + */ + expr_ref_vector getId(app*old_pred, const expr_ref_vector& new_args); + public: + mk_array_instantiation(context & ctx, unsigned priority); + rule_set * operator()(rule_set const & source); + virtual ~mk_array_instantiation(){} + }; + + + +}; + +#endif /* DL_MK_ARRAY_INSTANTIATION_H_ */ diff --git a/src/muz/transforms/dl_mk_backwards.cpp b/src/muz/transforms/dl_mk_backwards.cpp index 771de0dc3..986367337 100644 --- a/src/muz/transforms/dl_mk_backwards.cpp +++ b/src/muz/transforms/dl_mk_backwards.cpp @@ -17,8 +17,8 @@ Revision History: --*/ -#include"dl_mk_backwards.h" -#include"dl_context.h" +#include "muz/transforms/dl_mk_backwards.h" +#include "muz/base/dl_context.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_backwards.h b/src/muz/transforms/dl_mk_backwards.h index 135f89a18..ca441fd0a 100644 --- a/src/muz/transforms/dl_mk_backwards.h +++ b/src/muz/transforms/dl_mk_backwards.h @@ -19,7 +19,7 @@ Revision History: #ifndef DL_MK_BACKWARDS_H_ #define DL_MK_BACKWARDS_H_ -#include"dl_rule_transformer.h" +#include "muz/base/dl_rule_transformer.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 98172f041..3c8045e34 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -17,16 +17,16 @@ Revision History: --*/ -#include "dl_mk_bit_blast.h" -#include "bit_blaster_rewriter.h" -#include "rewriter_def.h" -#include "ast_pp.h" -#include "expr_safe_replace.h" -#include "filter_model_converter.h" -#include "dl_mk_interp_tail_simplifier.h" -#include "fixedpoint_params.hpp" -#include "scoped_proof.h" -#include "model_v2_pp.h" +#include "muz/transforms/dl_mk_bit_blast.h" +#include "ast/rewriter/bit_blaster/bit_blaster_rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "tactic/filter_model_converter.h" +#include "muz/transforms/dl_mk_interp_tail_simplifier.h" +#include "muz/base/fixedpoint_params.hpp" +#include "ast/scoped_proof.h" +#include "model/model_v2_pp.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_bit_blast.h b/src/muz/transforms/dl_mk_bit_blast.h index 8111e8849..31df57567 100644 --- a/src/muz/transforms/dl_mk_bit_blast.h +++ b/src/muz/transforms/dl_mk_bit_blast.h @@ -19,7 +19,7 @@ Revision History: #ifndef DL_MK_BIT_BLAST_H_ #define DL_MK_BIT_BLAST_H_ -#include"dl_rule_transformer.h" +#include "muz/base/dl_rule_transformer.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_coalesce.cpp b/src/muz/transforms/dl_mk_coalesce.cpp index 7476a5655..670a65e21 100644 --- a/src/muz/transforms/dl_mk_coalesce.cpp +++ b/src/muz/transforms/dl_mk_coalesce.cpp @@ -26,8 +26,8 @@ Notes: --*/ -#include "dl_mk_coalesce.h" -#include "bool_rewriter.h" +#include "muz/transforms/dl_mk_coalesce.h" +#include "ast/rewriter/bool_rewriter.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_coalesce.h b/src/muz/transforms/dl_mk_coalesce.h index 9b4d009ae..47d702fbb 100644 --- a/src/muz/transforms/dl_mk_coalesce.h +++ b/src/muz/transforms/dl_mk_coalesce.h @@ -20,11 +20,11 @@ Revision History: #ifndef DL_MK_COALESCE_H_ #define DL_MK_COALESCE_H_ -#include"dl_context.h" -#include"dl_rule_set.h" -#include"uint_set.h" -#include"dl_rule_transformer.h" -#include"dl_mk_rule_inliner.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_set.h" +#include "util/uint_set.h" +#include "muz/base/dl_rule_transformer.h" +#include "muz/transforms/dl_mk_rule_inliner.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index 0f155f65b..31188bf43 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -17,11 +17,11 @@ Author: --*/ -#include "dl_mk_coi_filter.h" -#include "dataflow.h" -#include "reachability.h" -#include "ast_pp.h" -#include "extension_model_converter.h" +#include "muz/transforms/dl_mk_coi_filter.h" +#include "muz/dataflow/dataflow.h" +#include "muz/dataflow/reachability.h" +#include "ast/ast_pp.h" +#include "tactic/extension_model_converter.h" namespace datalog { rule_set * mk_coi_filter::operator()(rule_set const & source) { diff --git a/src/muz/transforms/dl_mk_coi_filter.h b/src/muz/transforms/dl_mk_coi_filter.h index 16abe2f52..c03308b6a 100644 --- a/src/muz/transforms/dl_mk_coi_filter.h +++ b/src/muz/transforms/dl_mk_coi_filter.h @@ -20,8 +20,8 @@ Author: #ifndef DL_MK_COI_FILTER_H_ #define DL_MK_COI_FILTER_H_ -#include "dl_rule_transformer.h" -#include "dl_context.h" +#include "muz/base/dl_rule_transformer.h" +#include "muz/base/dl_context.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_different.h b/src/muz/transforms/dl_mk_different.h index 47a00edc0..2190d38cd 100644 --- a/src/muz/transforms/dl_mk_different.h +++ b/src/muz/transforms/dl_mk_different.h @@ -19,7 +19,7 @@ Revision History: #ifndef DL_MK_DIFFERENT_SYMBOLIC_H_ #define DL_MK_DIFFERENT_SYMBOLIC_H_ -#include"dl_rule_transformer.h" +#include "muz/base/dl_rule_transformer.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_filter_rules.cpp b/src/muz/transforms/dl_mk_filter_rules.cpp index 0d118a589..a8c13fc17 100644 --- a/src/muz/transforms/dl_mk_filter_rules.cpp +++ b/src/muz/transforms/dl_mk_filter_rules.cpp @@ -17,10 +17,10 @@ Revision History: --*/ -#include"dl_mk_filter_rules.h" -#include"dl_context.h" -#include"for_each_expr.h" -#include"ast_pp.h" +#include "muz/transforms/dl_mk_filter_rules.h" +#include "muz/base/dl_context.h" +#include "ast/for_each_expr.h" +#include "ast/ast_pp.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_filter_rules.h b/src/muz/transforms/dl_mk_filter_rules.h index 60ee80e90..b81921d59 100644 --- a/src/muz/transforms/dl_mk_filter_rules.h +++ b/src/muz/transforms/dl_mk_filter_rules.h @@ -19,10 +19,10 @@ Revision History: #ifndef DL_MK_FILTER_RULES_H_ #define DL_MK_FILTER_RULES_H_ -#include"map.h" +#include "util/map.h" -#include"dl_rule_set.h" -#include"dl_rule_transformer.h" +#include "muz/base/dl_rule_set.h" +#include "muz/base/dl_rule_transformer.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp index 1ed847e89..7bd35b4ef 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp @@ -19,14 +19,15 @@ Revision History: #include -#include"ast_pp.h" -#include"bool_rewriter.h" -#include"rewriter.h" -#include"rewriter_def.h" -#include"dl_mk_rule_inliner.h" -#include"dl_mk_interp_tail_simplifier.h" -#include"ast_util.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "muz/transforms/dl_mk_rule_inliner.h" +#include "muz/transforms/dl_mk_interp_tail_simplifier.h" +#include "ast/ast_util.h" +#include "muz/base/fixedpoint_params.hpp" namespace datalog { // ----------------------------------- @@ -397,6 +398,8 @@ namespace datalog { } bool mk_interp_tail_simplifier::propagate_variable_equivalences(rule * r, rule_ref& res) { + if (!m_context.get_params ().xform_tail_simplifier_pve ()) + return false; unsigned u_len = r->get_uninterpreted_tail_size(); unsigned len = r->get_tail_size(); if (u_len == len) { diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.h b/src/muz/transforms/dl_mk_interp_tail_simplifier.h index 568fcff3f..a8a7393cd 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.h +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.h @@ -20,11 +20,11 @@ Revision History: #ifndef DL_MK_INTERP_TAIL_SIMPLIFIER_H_ #define DL_MK_INTERP_TAIL_SIMPLIFIER_H_ -#include "dl_context.h" -#include "dl_rule_transformer.h" -#include "unifier.h" -#include "substitution.h" -#include "arith_decl_plugin.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_transformer.h" +#include "ast/substitution/unifier.h" +#include "ast/substitution/substitution.h" +#include "ast/arith_decl_plugin.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_karr_invariants.cpp b/src/muz/transforms/dl_mk_karr_invariants.cpp index 99b1c0aea..48219eeb9 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.cpp +++ b/src/muz/transforms/dl_mk_karr_invariants.cpp @@ -32,13 +32,13 @@ Revision History: --*/ -#include"expr_safe_replace.h" -#include"bool_rewriter.h" -#include"for_each_expr.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/for_each_expr.h" -#include"dl_mk_karr_invariants.h" -#include"dl_mk_backwards.h" -#include"dl_mk_loop_counter.h" +#include "muz/transforms/dl_mk_karr_invariants.h" +#include "muz/transforms/dl_mk_backwards.h" +#include "muz/transforms/dl_mk_loop_counter.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_karr_invariants.h b/src/muz/transforms/dl_mk_karr_invariants.h index bf0ba9021..b31f1f8d9 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.h +++ b/src/muz/transforms/dl_mk_karr_invariants.h @@ -19,11 +19,11 @@ Revision History: #ifndef DL_MK_KARR_INVARIANTS_H_ #define DL_MK_KARR_INVARIANTS_H_ -#include"dl_context.h" -#include"dl_rule_set.h" -#include"dl_rule_transformer.h" -#include"arith_decl_plugin.h" -#include"hilbert_basis.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_set.h" +#include "muz/base/dl_rule_transformer.h" +#include "ast/arith_decl_plugin.h" +#include "math/hilbert/hilbert_basis.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_loop_counter.cpp b/src/muz/transforms/dl_mk_loop_counter.cpp index f97670ad0..62568640c 100644 --- a/src/muz/transforms/dl_mk_loop_counter.cpp +++ b/src/muz/transforms/dl_mk_loop_counter.cpp @@ -17,8 +17,8 @@ Revision History: --*/ -#include"dl_mk_loop_counter.h" -#include"dl_context.h" +#include "muz/transforms/dl_mk_loop_counter.h" +#include "muz/base/dl_context.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_loop_counter.h b/src/muz/transforms/dl_mk_loop_counter.h index 6694ffb52..fb4b6d704 100644 --- a/src/muz/transforms/dl_mk_loop_counter.h +++ b/src/muz/transforms/dl_mk_loop_counter.h @@ -19,8 +19,8 @@ Revision History: #ifndef DL_MK_LOOP_COUNTER_H_ #define DL_MK_LOOP_COUNTER_H_ -#include"dl_rule_transformer.h" -#include"arith_decl_plugin.h" +#include "muz/base/dl_rule_transformer.h" +#include "ast/arith_decl_plugin.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_magic_sets.cpp b/src/muz/transforms/dl_mk_magic_sets.cpp index 19dccf417..15a4c1093 100644 --- a/src/muz/transforms/dl_mk_magic_sets.cpp +++ b/src/muz/transforms/dl_mk_magic_sets.cpp @@ -19,8 +19,8 @@ Revision History: #include #include -#include"ast_pp.h" -#include"dl_mk_magic_sets.h" +#include "ast/ast_pp.h" +#include "muz/transforms/dl_mk_magic_sets.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_magic_sets.h b/src/muz/transforms/dl_mk_magic_sets.h index f71af3649..73b5e94f6 100644 --- a/src/muz/transforms/dl_mk_magic_sets.h +++ b/src/muz/transforms/dl_mk_magic_sets.h @@ -21,12 +21,12 @@ Revision History: #include -#include"map.h" -#include"obj_pair_hashtable.h" +#include "util/map.h" +#include "util/obj_pair_hashtable.h" -#include"dl_context.h" -#include"dl_rule_set.h" -#include"dl_rule_transformer.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_set.h" +#include "muz/base/dl_rule_transformer.h" namespace datalog { @@ -93,7 +93,7 @@ namespace datalog { typedef obj_map pred_adornment_map; typedef obj_map pred2pred; - context & m_context; + context & m_context; ast_manager & m; rule_manager& rm; ast_ref_vector m_pinned; diff --git a/src/muz/transforms/dl_mk_magic_symbolic.cpp b/src/muz/transforms/dl_mk_magic_symbolic.cpp index 1d269cff0..2edc57375 100644 --- a/src/muz/transforms/dl_mk_magic_symbolic.cpp +++ b/src/muz/transforms/dl_mk_magic_symbolic.cpp @@ -52,8 +52,8 @@ Revision History: --*/ -#include"dl_mk_magic_symbolic.h" -#include"dl_context.h" +#include "muz/transforms/dl_mk_magic_symbolic.h" +#include "muz/base/dl_context.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_magic_symbolic.h b/src/muz/transforms/dl_mk_magic_symbolic.h index db3137c90..9c51a5287 100644 --- a/src/muz/transforms/dl_mk_magic_symbolic.h +++ b/src/muz/transforms/dl_mk_magic_symbolic.h @@ -19,7 +19,7 @@ Revision History: #ifndef DL_MK_MAGIC_SYMBOLIC_H_ #define DL_MK_MAGIC_SYMBOLIC_H_ -#include"dl_rule_transformer.h" +#include "muz/base/dl_rule_transformer.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index a22a67416..b171aaa7c 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -19,11 +19,11 @@ Revision History: --*/ -#include "dl_mk_quantifier_abstraction.h" -#include "dl_context.h" -#include "expr_safe_replace.h" -#include "expr_abstract.h" -#include"fixedpoint_params.hpp" +#include "muz/transforms/dl_mk_quantifier_abstraction.h" +#include "muz/base/dl_context.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/expr_abstract.h" +#include "muz/base/fixedpoint_params.hpp" namespace datalog { diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.h b/src/muz/transforms/dl_mk_quantifier_abstraction.h index d4a588127..593e458b9 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.h +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.h @@ -26,8 +26,8 @@ Revision History: #define DL_MK_QUANTIFIER_ABSTRACTION_H_ -#include"dl_rule_transformer.h" -#include"array_decl_plugin.h" +#include "muz/base/dl_rule_transformer.h" +#include "ast/array_decl_plugin.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index 586c52cd6..8986bf506 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -23,9 +23,11 @@ Revision History: --*/ -#include "dl_mk_quantifier_instantiation.h" -#include "dl_context.h" -#include "pattern_inference.h" +#include "muz/transforms/dl_mk_quantifier_instantiation.h" +#include "muz/base/dl_context.h" +#include "ast/pattern/pattern_inference.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_util.h" namespace datalog { @@ -70,7 +72,7 @@ namespace datalog { if (q->get_num_patterns() == 0) { proof_ref new_pr(m); pattern_inference_params params; - pattern_inference infer(m, params); + pattern_inference_rw infer(m, params); infer(q, qe, new_pr); q = to_quantifier(qe); } diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.h b/src/muz/transforms/dl_mk_quantifier_instantiation.h index b9ef5189e..4f1626ec6 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.h +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.h @@ -26,9 +26,9 @@ Revision History: #define DL_MK_QUANTIFIER_INSTANTIATION_H_ -#include "dl_rule_transformer.h" -#include "expr_safe_replace.h" -#include "union_find.h" +#include "muz/base/dl_rule_transformer.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "util/union_find.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index c6b3e8be7..30ff330ab 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -48,11 +48,11 @@ Subsumption transformation (remove rule): #include -#include "ast_pp.h" -#include "rewriter.h" -#include "rewriter_def.h" -#include "dl_mk_rule_inliner.h" -#include "fixedpoint_params.hpp" +#include "ast/ast_pp.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "muz/transforms/dl_mk_rule_inliner.h" +#include "muz/base/fixedpoint_params.hpp" namespace datalog { diff --git a/src/muz/transforms/dl_mk_rule_inliner.h b/src/muz/transforms/dl_mk_rule_inliner.h index 66d17fdc8..55b9b9487 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.h +++ b/src/muz/transforms/dl_mk_rule_inliner.h @@ -20,12 +20,12 @@ Revision History: #ifndef DL_MK_RULE_INLINER_H_ #define DL_MK_RULE_INLINER_H_ -#include "dl_context.h" -#include "dl_rule_transformer.h" -#include "dl_mk_interp_tail_simplifier.h" -#include "unifier.h" -#include "substitution.h" -#include "substitution_tree.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_transformer.h" +#include "muz/transforms/dl_mk_interp_tail_simplifier.h" +#include "ast/substitution/unifier.h" +#include "ast/substitution/substitution.h" +#include "ast/substitution/substitution_tree.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index 271bf5f62..5bc10b957 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -16,9 +16,9 @@ Revision History: --*/ -#include"dl_mk_scale.h" -#include"dl_context.h" -#include"fixedpoint_params.hpp" +#include "muz/transforms/dl_mk_scale.h" +#include "muz/base/dl_context.h" +#include "muz/base/fixedpoint_params.hpp" namespace datalog { diff --git a/src/muz/transforms/dl_mk_scale.h b/src/muz/transforms/dl_mk_scale.h index 0e4ccf7ea..10a5ea8b2 100644 --- a/src/muz/transforms/dl_mk_scale.h +++ b/src/muz/transforms/dl_mk_scale.h @@ -21,8 +21,8 @@ Revision History: #ifndef DL_MK_SCALE_H_ #define DL_MK_SCALE_H_ -#include"dl_rule_transformer.h" -#include"arith_decl_plugin.h" +#include "muz/base/dl_rule_transformer.h" +#include "ast/arith_decl_plugin.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_separate_negated_tails.cpp b/src/muz/transforms/dl_mk_separate_negated_tails.cpp index 9a78c0d4d..3da759f9b 100644 --- a/src/muz/transforms/dl_mk_separate_negated_tails.cpp +++ b/src/muz/transforms/dl_mk_separate_negated_tails.cpp @@ -17,8 +17,8 @@ Revision History: --*/ -#include "dl_mk_separate_negated_tails.h" -#include "dl_context.h" +#include "muz/transforms/dl_mk_separate_negated_tails.h" +#include "muz/base/dl_context.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_separate_negated_tails.h b/src/muz/transforms/dl_mk_separate_negated_tails.h index 1d2e57e2c..a5cdda003 100644 --- a/src/muz/transforms/dl_mk_separate_negated_tails.h +++ b/src/muz/transforms/dl_mk_separate_negated_tails.h @@ -32,8 +32,8 @@ Revision History: #ifndef DL_MK_SEPARAT_NEGATED_TAILS_H_ #define DL_MK_SEPARAT_NEGATED_TAILS_H_ -#include "dl_rule_transformer.h" -#include "dl_context.h" +#include "muz/base/dl_rule_transformer.h" +#include "muz/base/dl_context.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index cefda74e8..c094e5520 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -50,12 +50,12 @@ Revision History: --*/ -#include "dl_mk_slice.h" -#include "ast_pp.h" -#include "ast_util.h" -#include "expr_functors.h" -#include "dl_mk_rule_inliner.h" -#include "model_smt2_pp.h" +#include "muz/transforms/dl_mk_slice.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "ast/expr_functors.h" +#include "muz/transforms/dl_mk_rule_inliner.h" +#include "model/model_smt2_pp.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_slice.h b/src/muz/transforms/dl_mk_slice.h index b1b9cb46e..4a7d4a81a 100644 --- a/src/muz/transforms/dl_mk_slice.h +++ b/src/muz/transforms/dl_mk_slice.h @@ -19,10 +19,10 @@ Revision History: #ifndef DL_MK_SLICE_H_ #define DL_MK_SLICE_H_ -#include"dl_context.h" -#include"dl_rule_set.h" -#include"uint_set.h" -#include"dl_rule_transformer.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_set.h" +#include "util/uint_set.h" +#include "muz/base/dl_rule_transformer.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_subsumption_checker.cpp b/src/muz/transforms/dl_mk_subsumption_checker.cpp index 8fae4ee35..e26f105c6 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.cpp +++ b/src/muz/transforms/dl_mk_subsumption_checker.cpp @@ -20,11 +20,12 @@ Revision History: #include -#include"ast_pp.h" -#include "rewriter.h" -#include "rewriter_def.h" -#include"dl_mk_subsumption_checker.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "muz/transforms/dl_mk_subsumption_checker.h" +#include "muz/base/fixedpoint_params.hpp" namespace datalog { @@ -328,6 +329,8 @@ namespace datalog { rule_set * mk_subsumption_checker::operator()(rule_set const & source) { // TODO mc + if (!m_context.get_params ().xform_subsumption_checker()) + return 0; m_have_new_total_rule = false; collect_ground_unconditional_rule_heads(source); diff --git a/src/muz/transforms/dl_mk_subsumption_checker.h b/src/muz/transforms/dl_mk_subsumption_checker.h index 270418508..01d828d6e 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.h +++ b/src/muz/transforms/dl_mk_subsumption_checker.h @@ -21,9 +21,9 @@ Revision History: #ifndef DL_MK_SUBSUMPTION_CHECKER_H_ #define DL_MK_SUBSUMPTION_CHECKER_H_ -#include "dl_context.h" -#include "dl_rule_transformer.h" -#include "dl_rule_subsumption_index.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_transformer.h" +#include "muz/base/dl_rule_subsumption_index.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_unbound_compressor.cpp b/src/muz/transforms/dl_mk_unbound_compressor.cpp index 78133aab7..47ce20a76 100644 --- a/src/muz/transforms/dl_mk_unbound_compressor.cpp +++ b/src/muz/transforms/dl_mk_unbound_compressor.cpp @@ -19,7 +19,7 @@ Revision History: #include #include -#include"dl_mk_unbound_compressor.h" +#include "muz/transforms/dl_mk_unbound_compressor.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_unbound_compressor.h b/src/muz/transforms/dl_mk_unbound_compressor.h index 51ac1fda8..6f53e0707 100644 --- a/src/muz/transforms/dl_mk_unbound_compressor.h +++ b/src/muz/transforms/dl_mk_unbound_compressor.h @@ -21,12 +21,12 @@ Revision History: #include -#include"map.h" -#include"obj_pair_hashtable.h" +#include "util/map.h" +#include "util/obj_pair_hashtable.h" -#include"dl_context.h" -#include"dl_rule_set.h" -#include"dl_rule_transformer.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_set.h" +#include "muz/base/dl_rule_transformer.h" namespace datalog { @@ -50,7 +50,7 @@ namespace datalog { typedef hashtable > in_progress_table; typedef svector todo_stack; - context & m_context; + context & m_context; ast_manager & m; rule_manager & rm; rule_ref_vector m_rules; diff --git a/src/muz/transforms/dl_mk_unfold.cpp b/src/muz/transforms/dl_mk_unfold.cpp index cc460bca1..c9b8becde 100644 --- a/src/muz/transforms/dl_mk_unfold.cpp +++ b/src/muz/transforms/dl_mk_unfold.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include "dl_mk_unfold.h" +#include "muz/transforms/dl_mk_unfold.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_unfold.h b/src/muz/transforms/dl_mk_unfold.h index 554ed69e0..8ebe2d328 100644 --- a/src/muz/transforms/dl_mk_unfold.h +++ b/src/muz/transforms/dl_mk_unfold.h @@ -19,11 +19,11 @@ Revision History: #ifndef DL_MK_UNFOLD_H_ #define DL_MK_UNFOLD_H_ -#include"dl_context.h" -#include"dl_rule_set.h" -#include"uint_set.h" -#include"dl_rule_transformer.h" -#include"dl_mk_rule_inliner.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule_set.h" +#include "util/uint_set.h" +#include "muz/base/dl_rule_transformer.h" +#include "muz/transforms/dl_mk_rule_inliner.h" namespace datalog { diff --git a/src/muz/transforms/dl_transforms.cpp b/src/muz/transforms/dl_transforms.cpp index 81f9d6f64..95b0f6cd6 100644 --- a/src/muz/transforms/dl_transforms.cpp +++ b/src/muz/transforms/dl_transforms.cpp @@ -19,21 +19,23 @@ Revision History: --*/ -#include"dl_transforms.h" -#include"dl_rule_transformer.h" -#include"dl_mk_coi_filter.h" -#include"dl_mk_filter_rules.h" -#include"dl_mk_interp_tail_simplifier.h" -#include"dl_mk_rule_inliner.h" -#include"dl_mk_bit_blast.h" -#include"dl_mk_array_blast.h" -#include"dl_mk_karr_invariants.h" -#include"dl_mk_magic_symbolic.h" -#include"dl_mk_quantifier_abstraction.h" -#include"dl_mk_quantifier_instantiation.h" -#include"dl_mk_subsumption_checker.h" -#include"dl_mk_scale.h" -#include"fixedpoint_params.hpp" +#include "muz/transforms/dl_transforms.h" +#include "muz/base/dl_rule_transformer.h" +#include "muz/transforms/dl_mk_coi_filter.h" +#include "muz/transforms/dl_mk_filter_rules.h" +#include "muz/transforms/dl_mk_interp_tail_simplifier.h" +#include "muz/transforms/dl_mk_rule_inliner.h" +#include "muz/transforms/dl_mk_bit_blast.h" +#include "muz/transforms/dl_mk_array_blast.h" +#include "muz/transforms/dl_mk_karr_invariants.h" +#include "muz/transforms/dl_mk_magic_symbolic.h" +#include "muz/transforms/dl_mk_quantifier_abstraction.h" +#include "muz/transforms/dl_mk_quantifier_instantiation.h" +#include "muz/transforms/dl_mk_subsumption_checker.h" +#include "muz/transforms/dl_mk_scale.h" +#include "muz/transforms/dl_mk_array_eq_rewrite.h" +#include "muz/transforms/dl_mk_array_instantiation.h" +#include "muz/base/fixedpoint_params.hpp" namespace datalog { @@ -46,22 +48,32 @@ namespace datalog { transf.register_plugin(alloc(datalog::mk_coi_filter, ctx)); transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, ctx)); + if (ctx.get_params().xform_instantiate_arrays()) { + transf.register_plugin(alloc(datalog::mk_array_instantiation, ctx, 34999)); + } + if(ctx.get_params().xform_transform_arrays()) + transf.register_plugin(alloc(datalog::mk_array_eq_rewrite, ctx, 34998)); if (ctx.get_params().xform_quantify_arrays()) { transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, ctx, 38000)); } transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, ctx, 37000)); + if (ctx.get_params().datalog_subsumption()) { transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 35005)); + } transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 35000)); transf.register_plugin(alloc(datalog::mk_coi_filter, ctx, 34990)); transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, ctx, 34980)); //and another round of inlining + if (ctx.get_params().datalog_subsumption()) { transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34975)); + } transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34970)); transf.register_plugin(alloc(datalog::mk_coi_filter, ctx, 34960)); transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, ctx, 34950)); + if (ctx.get_params().datalog_subsumption()) { transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34940)); transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34930)); transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34920)); @@ -69,12 +81,16 @@ namespace datalog { transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34900)); transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34890)); transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34880)); + } + else { + transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34930)); + } transf.register_plugin(alloc(datalog::mk_bit_blast, ctx, 35000)); transf.register_plugin(alloc(datalog::mk_karr_invariants, ctx, 36010)); transf.register_plugin(alloc(datalog::mk_scale, ctx, 36030)); if (!ctx.get_params().xform_quantify_arrays()) { - transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 36000)); + transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 35999)); } if (ctx.get_params().xform_magic()) { transf.register_plugin(alloc(datalog::mk_magic_symbolic, ctx, 36020)); diff --git a/src/muz/transforms/dl_transforms.h b/src/muz/transforms/dl_transforms.h index 71131c99f..df34d2c1d 100644 --- a/src/muz/transforms/dl_transforms.h +++ b/src/muz/transforms/dl_transforms.h @@ -21,7 +21,7 @@ Revision History: #ifndef DL_TRANSFORMS_H_ #define DL_TRANSFORMS_H_ -#include "dl_context.h" +#include "muz/base/dl_context.h" namespace datalog { void apply_default_transformation(context& ctx); diff --git a/src/nlsat/nlsat_assignment.h b/src/nlsat/nlsat_assignment.h index a52a84f3b..097ad76b6 100644 --- a/src/nlsat/nlsat_assignment.h +++ b/src/nlsat/nlsat_assignment.h @@ -19,8 +19,8 @@ Revision History: #ifndef NLSAT_ASSIGNMENT_H_ #define NLSAT_ASSIGNMENT_H_ -#include"nlsat_types.h" -#include"algebraic_numbers.h" +#include "nlsat/nlsat_types.h" +#include "math/polynomial/algebraic_numbers.h" namespace nlsat { diff --git a/src/nlsat/nlsat_clause.cpp b/src/nlsat/nlsat_clause.cpp index b83485ba3..a64ec2856 100644 --- a/src/nlsat/nlsat_clause.cpp +++ b/src/nlsat/nlsat_clause.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"nlsat_clause.h" +#include "nlsat/nlsat_clause.h" namespace nlsat { diff --git a/src/nlsat/nlsat_clause.h b/src/nlsat/nlsat_clause.h index 95928eb1a..898c32449 100644 --- a/src/nlsat/nlsat_clause.h +++ b/src/nlsat/nlsat_clause.h @@ -19,8 +19,8 @@ Revision History: #ifndef NLSAT_CLAUSE_H_ #define NLSAT_CLAUSE_H_ -#include"nlsat_types.h" -#include"vector.h" +#include "nlsat/nlsat_types.h" +#include "util/vector.h" namespace nlsat { diff --git a/src/nlsat/nlsat_evaluator.cpp b/src/nlsat/nlsat_evaluator.cpp index db18d8854..a93c4fb3e 100644 --- a/src/nlsat/nlsat_evaluator.cpp +++ b/src/nlsat/nlsat_evaluator.cpp @@ -17,8 +17,8 @@ Author: Revision History: --*/ -#include"nlsat_evaluator.h" -#include"nlsat_solver.h" +#include "nlsat/nlsat_evaluator.h" +#include "nlsat/nlsat_solver.h" namespace nlsat { diff --git a/src/nlsat/nlsat_evaluator.h b/src/nlsat/nlsat_evaluator.h index a82ce79fb..e43eec80a 100644 --- a/src/nlsat/nlsat_evaluator.h +++ b/src/nlsat/nlsat_evaluator.h @@ -20,9 +20,9 @@ Revision History: #ifndef NLSAT_EVALUATOR_H_ #define NLSAT_EVALUATOR_H_ -#include"nlsat_types.h" -#include"nlsat_assignment.h" -#include"nlsat_interval_set.h" +#include "nlsat/nlsat_types.h" +#include "nlsat/nlsat_assignment.h" +#include "nlsat/nlsat_interval_set.h" namespace nlsat { diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index 5d9491da2..3a6c3f067 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include"nlsat_explain.h" -#include"nlsat_assignment.h" -#include"nlsat_evaluator.h" -#include"algebraic_numbers.h" -#include"ref_buffer.h" +#include "nlsat/nlsat_explain.h" +#include "nlsat/nlsat_assignment.h" +#include "nlsat/nlsat_evaluator.h" +#include "math/polynomial/algebraic_numbers.h" +#include "util/ref_buffer.h" namespace nlsat { diff --git a/src/nlsat/nlsat_explain.h b/src/nlsat/nlsat_explain.h index 4309a0090..37580e7bc 100644 --- a/src/nlsat/nlsat_explain.h +++ b/src/nlsat/nlsat_explain.h @@ -19,10 +19,10 @@ Revision History: #ifndef NLSAT_EXPLAIN_H_ #define NLSAT_EXPLAIN_H_ -#include"nlsat_solver.h" -#include"nlsat_scoped_literal_vector.h" -#include"polynomial_cache.h" -#include"algebraic_numbers.h" +#include "nlsat/nlsat_solver.h" +#include "nlsat/nlsat_scoped_literal_vector.h" +#include "math/polynomial/polynomial_cache.h" +#include "math/polynomial/algebraic_numbers.h" namespace nlsat { class evaluator; diff --git a/src/nlsat/nlsat_interval_set.cpp b/src/nlsat/nlsat_interval_set.cpp index 44e1128d1..2028095f4 100644 --- a/src/nlsat/nlsat_interval_set.cpp +++ b/src/nlsat/nlsat_interval_set.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"nlsat_interval_set.h" -#include"algebraic_numbers.h" -#include"buffer.h" +#include "nlsat/nlsat_interval_set.h" +#include "math/polynomial/algebraic_numbers.h" +#include "util/buffer.h" namespace nlsat { diff --git a/src/nlsat/nlsat_interval_set.h b/src/nlsat/nlsat_interval_set.h index a308c8637..24b2ab37f 100644 --- a/src/nlsat/nlsat_interval_set.h +++ b/src/nlsat/nlsat_interval_set.h @@ -19,7 +19,7 @@ Revision History: #ifndef NLSAT_INTERVAL_SET_H_ #define NLSAT_INTERVAL_SET_H_ -#include"nlsat_types.h" +#include "nlsat/nlsat_types.h" namespace nlsat { diff --git a/src/nlsat/nlsat_justification.h b/src/nlsat/nlsat_justification.h index b226dc522..13759e035 100644 --- a/src/nlsat/nlsat_justification.h +++ b/src/nlsat/nlsat_justification.h @@ -20,8 +20,8 @@ Revision History: #ifndef NLSAT_JUSTIFICATION_H_ #define NLSAT_JUSTIFICATION_H_ -#include"nlsat_types.h" -#include"tptr.h" +#include "nlsat/nlsat_types.h" +#include "util/tptr.h" namespace nlsat { diff --git a/src/nlsat/nlsat_scoped_literal_vector.h b/src/nlsat/nlsat_scoped_literal_vector.h index 442853377..61760f06d 100644 --- a/src/nlsat/nlsat_scoped_literal_vector.h +++ b/src/nlsat/nlsat_scoped_literal_vector.h @@ -20,7 +20,7 @@ Revision History: #ifndef NLSAT_SCOPED_LITERAL_VECTOR_H_ #define NLSAT_SCOPED_LITERAL_VECTOR_H_ -#include"nlsat_solver.h" +#include "nlsat/nlsat_solver.h" namespace nlsat { diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 7582c8389..c5e9babae 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -18,20 +18,20 @@ Author: Revision History: --*/ -#include"nlsat_solver.h" -#include"nlsat_clause.h" -#include"nlsat_assignment.h" -#include"nlsat_justification.h" -#include"nlsat_evaluator.h" -#include"nlsat_explain.h" -#include"algebraic_numbers.h" -#include"z3_exception.h" -#include"chashtable.h" -#include"id_gen.h" -#include"dependency.h" -#include"polynomial_cache.h" -#include"permutation.h" -#include"nlsat_params.hpp" +#include "nlsat/nlsat_solver.h" +#include "nlsat/nlsat_clause.h" +#include "nlsat/nlsat_assignment.h" +#include "nlsat/nlsat_justification.h" +#include "nlsat/nlsat_evaluator.h" +#include "nlsat/nlsat_explain.h" +#include "math/polynomial/algebraic_numbers.h" +#include "util/z3_exception.h" +#include "util/chashtable.h" +#include "util/id_gen.h" +#include "util/dependency.h" +#include "math/polynomial/polynomial_cache.h" +#include "util/permutation.h" +#include "nlsat/nlsat_params.hpp" #define NLSAT_EXTRA_VERBOSE diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index 3668629cd..ac503c603 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -21,10 +21,10 @@ Revision History: #ifndef NLSAT_SOLVER_H_ #define NLSAT_SOLVER_H_ -#include"nlsat_types.h" -#include"params.h" -#include"statistics.h" -#include"rlimit.h" +#include "nlsat/nlsat_types.h" +#include "util/params.h" +#include "util/statistics.h" +#include "util/rlimit.h" namespace nlsat { diff --git a/src/nlsat/nlsat_types.cpp b/src/nlsat/nlsat_types.cpp index 956be4c5e..dbf7ab360 100644 --- a/src/nlsat/nlsat_types.cpp +++ b/src/nlsat/nlsat_types.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"nlsat_types.h" -#include"debug.h" -#include"hash.h" -#include"polynomial.h" +#include "nlsat/nlsat_types.h" +#include "util/debug.h" +#include "util/hash.h" +#include "math/polynomial/polynomial.h" namespace nlsat { diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index 11e063a17..8704f4444 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -19,10 +19,10 @@ Revision History: #ifndef NLSAT_TYPES_H_ #define NLSAT_TYPES_H_ -#include"polynomial.h" -#include"buffer.h" -#include"sat_types.h" -#include"z3_exception.h" +#include "math/polynomial/polynomial.h" +#include "util/buffer.h" +#include "sat/sat_types.h" +#include "util/z3_exception.h" namespace algebraic_numbers { class anum; diff --git a/src/nlsat/tactic/goal2nlsat.cpp b/src/nlsat/tactic/goal2nlsat.cpp index a76cd1213..6d7e1c767 100644 --- a/src/nlsat/tactic/goal2nlsat.cpp +++ b/src/nlsat/tactic/goal2nlsat.cpp @@ -21,17 +21,17 @@ Author: Notes: --*/ -#include"goal2nlsat.h" -#include"goal.h" -#include"goal_util.h" -#include"nlsat_solver.h" -#include"expr2polynomial.h" -#include"expr2var.h" -#include"arith_decl_plugin.h" -#include"tactic.h" -#include"ast_pp.h" -#include"polynomial.h" -#include"algebraic_numbers.h" +#include "nlsat/tactic/goal2nlsat.h" +#include "tactic/goal.h" +#include "tactic/goal_util.h" +#include "nlsat/nlsat_solver.h" +#include "ast/expr2polynomial.h" +#include "ast/expr2var.h" +#include "ast/arith_decl_plugin.h" +#include "tactic/tactic.h" +#include "ast/ast_pp.h" +#include "math/polynomial/polynomial.h" +#include "math/polynomial/algebraic_numbers.h" struct goal2nlsat::imp { struct nlsat_expr2polynomial : public expr2polynomial { diff --git a/src/nlsat/tactic/goal2nlsat.h b/src/nlsat/tactic/goal2nlsat.h index bdb71a6a3..58d85946e 100644 --- a/src/nlsat/tactic/goal2nlsat.h +++ b/src/nlsat/tactic/goal2nlsat.h @@ -24,8 +24,8 @@ Notes: #ifndef GOAL2NLSAT_H_ #define GOAL2NLSAT_H_ -#include"nlsat_types.h" -#include"model_converter.h" +#include "nlsat/nlsat_types.h" +#include "tactic/model_converter.h" class goal; class expr2var; diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 4ecdade38..510f503e7 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -16,16 +16,16 @@ Author: Notes: --*/ -#include"tactical.h" -#include"goal2nlsat.h" -#include"nlsat_solver.h" -#include"model.h" -#include"expr2var.h" -#include"arith_decl_plugin.h" -#include"ast_smt2_pp.h" -#include"z3_exception.h" -#include"algebraic_numbers.h" -#include"ast_pp.h" +#include "tactic/tactical.h" +#include "nlsat/tactic/goal2nlsat.h" +#include "nlsat/nlsat_solver.h" +#include "model/model.h" +#include "ast/expr2var.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_smt2_pp.h" +#include "util/z3_exception.h" +#include "math/polynomial/algebraic_numbers.h" +#include "ast/ast_pp.h" class nlsat_tactic : public tactic { struct expr_display_var_proc : public nlsat::display_var_proc { diff --git a/src/nlsat/tactic/nlsat_tactic.h b/src/nlsat/tactic/nlsat_tactic.h index 5f0022026..fe7737c4b 100644 --- a/src/nlsat/tactic/nlsat_tactic.h +++ b/src/nlsat/tactic/nlsat_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef NLSAT_TACTIC_H_ #define NLSAT_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp index b05636541..22f64af47 100644 --- a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp +++ b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp @@ -16,18 +16,18 @@ Author: Notes: --*/ -#include"tactical.h" +#include "tactic/tactical.h" -#include"tseitin_cnf_tactic.h" -#include"degree_shift_tactic.h" -#include"purify_arith_tactic.h" -#include"nlsat_tactic.h" -#include"factor_tactic.h" -#include"simplify_tactic.h" -#include"elim_uncnstr_tactic.h" -#include"propagate_values_tactic.h" -#include"solve_eqs_tactic.h" -#include"elim_term_ite_tactic.h" +#include "tactic/core/tseitin_cnf_tactic.h" +#include "tactic/arith/degree_shift_tactic.h" +#include "tactic/arith/purify_arith_tactic.h" +#include "nlsat/tactic/nlsat_tactic.h" +#include "tactic/arith/factor_tactic.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/elim_term_ite_tactic.h" tactic * mk_qfnra_nlsat_tactic(ast_manager & m, params_ref const & p) { params_ref main_p = p; diff --git a/src/nlsat/tactic/qfnra_nlsat_tactic.h b/src/nlsat/tactic/qfnra_nlsat_tactic.h index fa106ca93..b1a4d8392 100644 --- a/src/nlsat/tactic/qfnra_nlsat_tactic.h +++ b/src/nlsat/tactic/qfnra_nlsat_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef QFNRA_NLSAT_TACTIC_H_ #define QFNRA_NLSAT_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 7e9381e1d..b06773223 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -52,18 +52,18 @@ Notes: --*/ -#include "solver.h" -#include "maxsmt.h" -#include "maxres.h" -#include "ast_pp.h" -#include "mus.h" -#include "mss.h" -#include "inc_sat_solver.h" -#include "opt_context.h" -#include "pb_decl_plugin.h" -#include "opt_params.hpp" -#include "ast_util.h" -#include "smt_solver.h" +#include "solver/solver.h" +#include "opt/maxsmt.h" +#include "opt/maxres.h" +#include "ast/ast_pp.h" +#include "solver/mus.h" +#include "opt/mss.h" +#include "sat/sat_solver/inc_sat_solver.h" +#include "opt/opt_context.h" +#include "ast/pb_decl_plugin.h" +#include "opt/opt_params.hpp" +#include "ast/ast_util.h" +#include "smt/smt_solver.h" using namespace opt; @@ -315,14 +315,13 @@ public: void found_optimum() { IF_VERBOSE(1, verbose_stream() << "found optimum\n";); - rational upper(0); + m_lower.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { m_assignment[i] = is_true(m_soft[i]); if (!m_assignment[i]) { - upper += m_weights[i]; + m_lower += m_weights[i]; } } - SASSERT(upper == m_lower); m_upper = m_lower; m_found_feasible_optimum = true; } @@ -397,10 +396,11 @@ public: void get_current_correction_set(model* mdl, exprs& cs) { cs.reset(); if (!mdl) return; - for (unsigned i = 0; i < m_asms.size(); ++i) { - if (is_false(mdl, m_asms[i].get())) { - cs.push_back(m_asms[i].get()); + for (expr* a : m_asms) { + if (is_false(mdl, a)) { + cs.push_back(a); } + TRACE("opt", expr_ref tmp(m); mdl->eval(a, tmp, true); tout << mk_pp(a, m) << ": " << tmp << "\n";); } TRACE("opt", display_vec(tout << "new correction set: ", cs);); } @@ -509,6 +509,7 @@ public: trace(); if (m_c.num_objectives() == 1 && m_pivot_on_cs && m_csmodel.get() && m_correction_set_size < core.size()) { exprs cs; + TRACE("opt", tout << "cs " << m_correction_set_size << " " << core.size() << "\n";); get_current_correction_set(m_csmodel.get(), cs); m_correction_set_size = cs.size(); if (m_correction_set_size < core.size()) { diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index f93291599..8df6c04a6 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -18,16 +18,16 @@ Notes: --*/ #include -#include "maxsmt.h" -#include "maxres.h" -#include "wmax.h" -#include "ast_pp.h" -#include "uint_set.h" -#include "opt_context.h" -#include "theory_wmaxsat.h" -#include "theory_pb.h" -#include "ast_util.h" -#include "pb_decl_plugin.h" +#include "opt/maxsmt.h" +#include "opt/maxres.h" +#include "opt/wmax.h" +#include "ast/ast_pp.h" +#include "util/uint_set.h" +#include "opt/opt_context.h" +#include "smt/theory_wmaxsat.h" +#include "smt/theory_pb.h" +#include "ast/ast_util.h" +#include "ast/pb_decl_plugin.h" namespace opt { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 358ff4995..0541a9a88 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -19,15 +19,15 @@ Notes: #ifndef OPT_MAXSMT_H_ #define OPT_MAXSMT_H_ -#include"ast.h" -#include"params.h" -#include"solver.h" -#include"filter_model_converter.h" -#include"statistics.h" -#include"smt_context.h" -#include"smt_theory.h" -#include"theory_wmaxsat.h" -#include"opt_solver.h" +#include "ast/ast.h" +#include "util/params.h" +#include "solver/solver.h" +#include "tactic/filter_model_converter.h" +#include "util/statistics.h" +#include "smt/smt_context.h" +#include "smt/smt_theory.h" +#include "smt/theory_wmaxsat.h" +#include "opt/opt_solver.h" namespace opt { diff --git a/src/opt/mss.cpp b/src/opt/mss.cpp index 863834b85..cc0fa8d7d 100644 --- a/src/opt/mss.cpp +++ b/src/opt/mss.cpp @@ -18,10 +18,10 @@ Notes: --*/ -#include "solver.h" -#include "mss.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" +#include "solver/solver.h" +#include "opt/mss.h" +#include "ast/ast_pp.h" +#include "model/model_smt2_pp.h" namespace opt { diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 0264a6a24..89264a9c8 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -21,16 +21,16 @@ Notes: - Deal with push/pop (later) --*/ -#include "opt_cmds.h" -#include "cmd_context.h" -#include "ast_pp.h" -#include "opt_context.h" -#include "cancel_eh.h" -#include "scoped_ctrl_c.h" -#include "scoped_timer.h" -#include "parametric_cmd.h" -#include "opt_params.hpp" -#include "model_smt2_pp.h" +#include "opt/opt_cmds.h" +#include "cmd_context/cmd_context.h" +#include "ast/ast_pp.h" +#include "opt/opt_context.h" +#include "util/cancel_eh.h" +#include "util/scoped_ctrl_c.h" +#include "util/scoped_timer.h" +#include "cmd_context/parametric_cmd.h" +#include "opt/opt_params.hpp" +#include "model/model_smt2_pp.h" static opt::context& get_opt(cmd_context& cmd, opt::context* opt) { if (opt) { @@ -96,6 +96,9 @@ public: } virtual void execute(cmd_context & ctx) { + if (!m_formula) { + throw cmd_exception("assert-soft requires a formulas as argument."); + } symbol w("weight"); rational weight = ps().get_rat(symbol("weight"), rational::one()); symbol id = ps().get_sym(symbol("id"), symbol::null); diff --git a/src/opt/opt_cmds.h b/src/opt/opt_cmds.h index f0da778df..60f83d201 100644 --- a/src/opt/opt_cmds.h +++ b/src/opt/opt_cmds.h @@ -18,8 +18,8 @@ Notes: #ifndef OPT_CMDS_H_ #define OPT_CMDS_H_ -#include "ast.h" -#include "opt_context.h" +#include "ast/ast.h" +#include "opt/opt_context.h" class cmd_context; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 0e1c150c0..8d73ea7c8 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -17,32 +17,32 @@ Notes: --*/ -#include "opt_context.h" -#include "ast_pp.h" -#include "opt_solver.h" -#include "opt_params.hpp" -#include "for_each_expr.h" -#include "goal.h" -#include "tactic.h" -#include "lia2card_tactic.h" -#include "elim01_tactic.h" -#include "solve_eqs_tactic.h" -#include "simplify_tactic.h" -#include "propagate_values_tactic.h" -#include "solve_eqs_tactic.h" -#include "elim_uncnstr_tactic.h" -#include "tactical.h" -#include "model_smt2_pp.h" -#include "card2bv_tactic.h" -#include "eq2bv_tactic.h" -#include "dt2bv_tactic.h" -#include "inc_sat_solver.h" -#include "bv_decl_plugin.h" -#include "pb_decl_plugin.h" -#include "ast_smt_pp.h" -#include "filter_model_converter.h" -#include "ast_pp_util.h" -#include "qsat.h" +#include "opt/opt_context.h" +#include "ast/ast_pp.h" +#include "opt/opt_solver.h" +#include "opt/opt_params.hpp" +#include "ast/for_each_expr.h" +#include "tactic/goal.h" +#include "tactic/tactic.h" +#include "tactic/arith/lia2card_tactic.h" +#include "tactic/arith/elim01_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "tactic/tactical.h" +#include "model/model_smt2_pp.h" +#include "tactic/arith/card2bv_tactic.h" +#include "tactic/arith/eq2bv_tactic.h" +#include "tactic/bv/dt2bv_tactic.h" +#include "sat/sat_solver/inc_sat_solver.h" +#include "ast/bv_decl_plugin.h" +#include "ast/pb_decl_plugin.h" +#include "ast/ast_smt_pp.h" +#include "tactic/filter_model_converter.h" +#include "ast/ast_pp_util.h" +#include "qe/qsat.h" namespace opt { @@ -819,7 +819,7 @@ namespace opt { bool is_max = is_maximize(fml, term, orig_term, index); bool is_min = !is_max && is_minimize(fml, term, orig_term, index); if (is_min && get_pb_sum(term, terms, weights, offset)) { - TRACE("opt", tout << "try to convert minimization" << mk_pp(term, m) << "\n";); + TRACE("opt", tout << "try to convert minimization\n" << mk_pp(term, m) << "\n";); // minimize 2*x + 3*y // <=> // (assert-soft (not x) 2) diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 66f0ef015..ad40db074 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -18,17 +18,17 @@ Notes: #ifndef OPT_CONTEXT_H_ #define OPT_CONTEXT_H_ -#include "ast.h" -#include "opt_solver.h" -#include "opt_pareto.h" -#include "optsmt.h" -#include "maxsmt.h" -#include "model_converter.h" -#include "tactic.h" -#include "arith_decl_plugin.h" -#include "bv_decl_plugin.h" -#include "cmd_context.h" -#include "qsat.h" +#include "ast/ast.h" +#include "opt/opt_solver.h" +#include "opt/opt_pareto.h" +#include "opt/optsmt.h" +#include "opt/maxsmt.h" +#include "tactic/model_converter.h" +#include "tactic/tactic.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "cmd_context/cmd_context.h" +#include "qe/qsat.h" namespace opt { diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 13bf51313..cfcc5e47e 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -2,7 +2,7 @@ def_module_params('opt', description='optimization parameters', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), - ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), + ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), diff --git a/src/opt/opt_pareto.cpp b/src/opt/opt_pareto.cpp index 1418eb0f9..026d10abc 100644 --- a/src/opt/opt_pareto.cpp +++ b/src/opt/opt_pareto.cpp @@ -18,9 +18,9 @@ Notes: --*/ -#include "opt_pareto.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" +#include "opt/opt_pareto.h" +#include "ast/ast_pp.h" +#include "model/model_smt2_pp.h" namespace opt { diff --git a/src/opt/opt_pareto.h b/src/opt/opt_pareto.h index 25b327045..c0ccc93da 100644 --- a/src/opt/opt_pareto.h +++ b/src/opt/opt_pareto.h @@ -20,8 +20,8 @@ Notes: #ifndef OPT_PARETO_H_ #define OPT_PARETO_H_ -#include "solver.h" -#include "model.h" +#include "solver/solver.h" +#include "model/model.h" namespace opt { diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 5b7f630b4..a736c77a2 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -20,11 +20,11 @@ Notes: #ifndef OPT_SLS_SOLVER_H_ #define OPT_SLS_SOLVER_H_ -#include "solver_na2as.h" -#include "card2bv_tactic.h" -#include "nnf_tactic.h" -#include "pb_sls.h" -#include "bvsls_opt_engine.h" +#include "solver/solver_na2as.h" +#include "tactic/arith/card2bv_tactic.h" +#include "tactic/core/nnf_tactic.h" +#include "opt/pb_sls.h" +#include "tactic/sls/bvsls_opt_engine.h" namespace opt { diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 458a5c540..49b48e68f 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -19,20 +19,20 @@ Notes: --*/ #include -#include "reg_decl_plugins.h" -#include "opt_solver.h" -#include "smt_context.h" -#include "theory_arith.h" -#include "theory_diff_logic.h" -#include "theory_dense_diff_logic.h" -#include "theory_pb.h" -#include "theory_lra.h" -#include "ast_pp.h" -#include "ast_smt_pp.h" -#include "pp_params.hpp" -#include "opt_params.hpp" -#include "model_smt2_pp.h" -#include "stopwatch.h" +#include "ast/reg_decl_plugins.h" +#include "opt/opt_solver.h" +#include "smt/smt_context.h" +#include "smt/theory_arith.h" +#include "smt/theory_diff_logic.h" +#include "smt/theory_dense_diff_logic.h" +#include "smt/theory_pb.h" +#include "smt/theory_lra.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt_pp.h" +#include "ast/pp_params.hpp" +#include "opt/opt_params.hpp" +#include "model/model_smt2_pp.h" +#include "util/stopwatch.h" namespace opt { @@ -47,8 +47,9 @@ namespace opt { m_dump_benchmarks(false), m_first(true), m_was_unknown(false) { + solver::updt_params(p); m_params.updt_params(p); - if (m_params.m_case_split_strategy == CS_ACTIVITY_DELAY_NEW) { + if (m_params.m_case_split_strategy == CS_ACTIVITY_DELAY_NEW) { m_params.m_relevancy_lvl = 0; } // m_params.m_auto_config = false; @@ -161,7 +162,7 @@ namespace opt { TRACE("opt_verbose", { tout << "context size: " << m_context.size() << "\n"; for (unsigned i = 0; i < m_context.size(); ++i) { - tout << mk_pp(m_context.get_formulas()[i], m_context.m()) << "\n"; + tout << mk_pp(m_context.get_formula(i), m_context.m()) << "\n"; } }); stopwatch w; @@ -330,7 +331,7 @@ namespace opt { expr * opt_solver::get_assertion(unsigned idx) const { SASSERT(idx < get_num_assertions()); - return m_context.get_formulas()[idx]; + return m_context.get_formula(idx); } smt::theory_var opt_solver::add_objective(app* term) { diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 27168e2ca..4bd23c120 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -21,16 +21,16 @@ Notes: #ifndef OPT_SOLVER_H_ #define OPT_SOLVER_H_ -#include"inf_rational.h" -#include"inf_eps_rational.h" -#include"ast.h" -#include"params.h" -#include"solver_na2as.h" -#include"smt_kernel.h" -#include"smt_params.h" -#include"smt_types.h" -#include"theory_opt.h" -#include"filter_model_converter.h" +#include "util/inf_rational.h" +#include "util/inf_eps_rational.h" +#include "ast/ast.h" +#include "util/params.h" +#include "solver/solver_na2as.h" +#include "smt/smt_kernel.h" +#include "smt/params/smt_params.h" +#include "smt/smt_types.h" +#include "smt/theory_opt.h" +#include "tactic/filter_model_converter.h" namespace opt { diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index d2363b36e..f8f75fbfd 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -29,15 +29,15 @@ Notes: --*/ #include -#include "optsmt.h" -#include "opt_solver.h" -#include "arith_decl_plugin.h" -#include "theory_arith.h" -#include "ast_pp.h" -#include "ast_util.h" -#include "model_pp.h" -#include "th_rewriter.h" -#include "opt_params.hpp" +#include "opt/optsmt.h" +#include "opt/opt_solver.h" +#include "ast/arith_decl_plugin.h" +#include "smt/theory_arith.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "model/model_pp.h" +#include "ast/rewriter/th_rewriter.h" +#include "opt/opt_params.hpp" namespace opt { diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index f90bd1c81..921352898 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -19,7 +19,7 @@ Notes: #ifndef OPTSMT_H_ #define OPTSMT_H_ -#include "opt_solver.h" +#include "opt/opt_solver.h" namespace opt { /** diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index 32c144652..e28c3cd3d 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -16,11 +16,11 @@ Author: Notes: --*/ -#include "pb_sls.h" -#include "smt_literal.h" -#include "ast_pp.h" -#include "th_rewriter.h" -#include "sat_types.h" +#include "opt/pb_sls.h" +#include "smt/smt_literal.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/th_rewriter.h" +#include "sat/sat_types.h" namespace smt { diff --git a/src/opt/pb_sls.h b/src/opt/pb_sls.h index 0ed7e30cc..f83057ce5 100644 --- a/src/opt/pb_sls.h +++ b/src/opt/pb_sls.h @@ -19,11 +19,11 @@ Notes: #ifndef PB_SLS_H_ #define PB_SLS_H_ -#include "pb_decl_plugin.h" -#include "model.h" -#include "lbool.h" -#include "params.h" -#include "statistics.h" +#include "ast/pb_decl_plugin.h" +#include "model/model.h" +#include "util/lbool.h" +#include "util/params.h" +#include "util/statistics.h" namespace smt { diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index e3cf59de4..00cab488c 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -16,15 +16,15 @@ Author: Notes: --*/ -#include "maxsmt.h" -#include "uint_set.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" -#include "smt_theory.h" -#include "smt_context.h" -#include "opt_context.h" -#include "sorting_network.h" -#include "filter_model_converter.h" +#include "opt/maxsmt.h" +#include "util/uint_set.h" +#include "ast/ast_pp.h" +#include "model/model_smt2_pp.h" +#include "smt/smt_theory.h" +#include "smt/smt_context.h" +#include "opt/opt_context.h" +#include "util/sorting_network.h" +#include "tactic/filter_model_converter.h" namespace opt { diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 15b723c8c..afc0334eb 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -16,14 +16,14 @@ Author: Notes: --*/ -#include "wmax.h" -#include "uint_set.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" -#include "smt_theory.h" -#include "smt_context.h" -#include "theory_wmaxsat.h" -#include "opt_context.h" +#include "opt/wmax.h" +#include "util/uint_set.h" +#include "ast/ast_pp.h" +#include "model/model_smt2_pp.h" +#include "smt/smt_theory.h" +#include "smt/smt_context.h" +#include "smt/theory_wmaxsat.h" +#include "opt/opt_context.h" namespace opt { // ---------------------------------------------------------- diff --git a/src/opt/wmax.h b/src/opt/wmax.h index 3d9d206ad..aabbe3a64 100644 --- a/src/opt/wmax.h +++ b/src/opt/wmax.h @@ -20,7 +20,7 @@ Notes: #ifndef WMAX_H_ #define WMAX_H_ -#include "maxsmt.h" +#include "opt/maxsmt.h" namespace opt { maxsmt_solver_base* mk_wmax(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); diff --git a/src/parsers/smt/smtlib.cpp b/src/parsers/smt/smtlib.cpp index b743b5b0f..71dd48156 100644 --- a/src/parsers/smt/smtlib.cpp +++ b/src/parsers/smt/smtlib.cpp @@ -5,9 +5,9 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include"smtlib.h" -#include"ast_pp.h" -#include"ast_smt2_pp.h" +#include "parsers/smt/smtlib.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt2_pp.h" #ifdef _WINDOWS #ifdef ARRAYSIZE diff --git a/src/parsers/smt/smtlib.h b/src/parsers/smt/smtlib.h index 62799ea25..f037e3d74 100644 --- a/src/parsers/smt/smtlib.h +++ b/src/parsers/smt/smtlib.h @@ -19,10 +19,10 @@ Revision History: #ifndef SMTLIB_H_ #define SMTLIB_H_ -#include "ast.h" -#include "symbol_table.h" -#include "map.h" -#include "arith_decl_plugin.h" +#include "ast/ast.h" +#include "util/symbol_table.h" +#include "util/map.h" +#include "ast/arith_decl_plugin.h" namespace smtlib { diff --git a/src/parsers/smt/smtlib_solver.cpp b/src/parsers/smt/smtlib_solver.cpp index 7c8572ad8..339be2ddd 100644 --- a/src/parsers/smt/smtlib_solver.cpp +++ b/src/parsers/smt/smtlib_solver.cpp @@ -17,24 +17,24 @@ Revision History: --*/ -#include"smtparser.h" -#include"smtlib_solver.h" -#include"warning.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"well_sorted.h" -#include"model.h" -#include"model_v2_pp.h" -#include"solver.h" -#include"smt_strategic_solver.h" -#include"cmd_context.h" -#include"model_params.hpp" -#include"parser_params.hpp" +#include "parsers/smt/smtparser.h" +#include "parsers/smt/smtlib_solver.h" +#include "util/warning.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/well_sorted.h" +#include "model/model.h" +#include "model/model_v2_pp.h" +#include "solver/solver.h" +#include "tactic/portfolio/smt_strategic_solver.h" +#include "cmd_context/cmd_context.h" +#include "model/model_params.hpp" +#include "parsers/util/parser_params.hpp" namespace smtlib { solver::solver(): - m_ast_manager(m_params.m_proof ? PGM_FINE : PGM_DISABLED, + m_ast_manager(m_params.m_proof ? PGM_ENABLED : PGM_DISABLED, m_params.m_trace ? m_params.m_trace_file_name.c_str() : 0), m_ctx(0), m_error_code(0) { diff --git a/src/parsers/smt/smtlib_solver.h b/src/parsers/smt/smtlib_solver.h index fce5ff67f..6288c360b 100644 --- a/src/parsers/smt/smtlib_solver.h +++ b/src/parsers/smt/smtlib_solver.h @@ -19,9 +19,9 @@ Revision History: #ifndef SMTLIB_SOLVER_H_ #define SMTLIB_SOLVER_H_ -#include"smtparser.h" -#include"context_params.h" -#include"lbool.h" +#include "parsers/smt/smtparser.h" +#include "cmd_context/context_params.h" +#include "util/lbool.h" class cmd_context; diff --git a/src/parsers/smt/smtparser.cpp b/src/parsers/smt/smtparser.cpp index c9b20850c..15f094e33 100644 --- a/src/parsers/smt/smtparser.cpp +++ b/src/parsers/smt/smtparser.cpp @@ -21,23 +21,23 @@ Revision History: #include #include #include -#include"region.h" -#include"scanner.h" -#include"symbol.h" -#include"vector.h" -#include"symbol_table.h" -#include"smtlib.h" -#include"smtparser.h" -#include"ast_pp.h" -#include"bv_decl_plugin.h" -#include"array_decl_plugin.h" -#include"warning.h" -#include"error_codes.h" -#include"pattern_validation.h" -#include"var_subst.h" -#include"well_sorted.h" -#include"str_hashtable.h" -#include"stopwatch.h" +#include "util/region.h" +#include "parsers/util/scanner.h" +#include "util/symbol.h" +#include "util/vector.h" +#include "util/symbol_table.h" +#include "parsers/smt/smtlib.h" +#include "parsers/smt/smtparser.h" +#include "ast/ast_pp.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "util/warning.h" +#include "util/error_codes.h" +#include "parsers/util/pattern_validation.h" +#include "ast/rewriter/var_subst.h" +#include "ast/well_sorted.h" +#include "util/str_hashtable.h" +#include "util/stopwatch.h" class id_param_info { symbol m_string; diff --git a/src/parsers/smt/smtparser.h b/src/parsers/smt/smtparser.h index 9a09d1f4f..d8999e8ab 100644 --- a/src/parsers/smt/smtparser.h +++ b/src/parsers/smt/smtparser.h @@ -20,9 +20,9 @@ Revision History: #define SMT_PARSER_H_ #include -#include"ast.h" -#include"vector.h" -#include"smtlib.h" +#include "ast/ast.h" +#include "util/vector.h" +#include "parsers/smt/smtlib.h" namespace smtlib { class parser { diff --git a/src/parsers/smt2/CMakeLists.txt b/src/parsers/smt2/CMakeLists.txt index 1467d95c6..022cce2f2 100644 --- a/src/parsers/smt2/CMakeLists.txt +++ b/src/parsers/smt2/CMakeLists.txt @@ -1,5 +1,6 @@ z3_add_component(smt2parser SOURCES + marshal.cpp smt2parser.cpp smt2scanner.cpp COMPONENT_DEPENDENCIES diff --git a/src/parsers/smt2/marshal.cpp b/src/parsers/smt2/marshal.cpp new file mode 100644 index 000000000..ae144e491 --- /dev/null +++ b/src/parsers/smt2/marshal.cpp @@ -0,0 +1,50 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel +Module Name: + + marshal.cpp + +Abstract: + + marshaling and unmarshaling of expressions + + --*/ +#include "parsers/smt2/marshal.h" + +#include + +#include "cmd_context/cmd_context.h" +#include "parsers/smt2/smt2parser.h" +#include "util/vector.h" +#include "ast/ast_smt_pp.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" + +std::ostream &marshal(std::ostream &os, expr_ref e, ast_manager &m) { + ast_smt_pp pp(m); + pp.display_smt2(os, e); + return os; +} + +std::string marshal(expr_ref e, ast_manager &m) { + std::stringstream ss; + marshal(ss, e, m); + return ss.str(); +} + + +expr_ref unmarshal(std::istream &is, ast_manager &m) { + cmd_context ctx(false, &m); + ctx.set_ignore_check(true); + if (!parse_smt2_commands(ctx, is)) { return expr_ref(0, m); } + + ptr_vector::const_iterator it = ctx.begin_assertions(); + ptr_vector::const_iterator end = ctx.end_assertions(); + unsigned size = static_cast(end - it); + return expr_ref(mk_and(m, size, it), m); +} + +expr_ref unmarshal(std::string s, ast_manager &m) { + std::istringstream is(s); + return unmarshal(is, m); +} diff --git a/src/parsers/smt2/marshal.h b/src/parsers/smt2/marshal.h new file mode 100644 index 000000000..ebc2c0426 --- /dev/null +++ b/src/parsers/smt2/marshal.h @@ -0,0 +1,27 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel +Module Name: + + marshal.h + +Abstract: + + marshaling and unmarshaling of expressions + + --*/ +#ifndef _SPACER_MARSHAL_H_ +#define _SPACER_MARSHAL_H_ + +#include +#include + +#include "ast/ast.h" + +std::ostream &marshal(std::ostream &os, expr_ref e, ast_manager &m); +std::string marshal(expr_ref e, ast_manager &m); +expr_ref unmarshal(std::string s, ast_manager &m); +expr_ref unmarshal(std::istream &is, ast_manager &m); + + + +#endif diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 08bb6bbee..fd592f7c7 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -16,20 +16,21 @@ Author: Revision History: --*/ -#include"smt2parser.h" -#include"smt2scanner.h" -#include"stack.h" -#include"datatype_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"arith_decl_plugin.h" -#include"seq_decl_plugin.h" -#include"ast_pp.h" -#include"well_sorted.h" -#include"pattern_validation.h" -#include"rewriter.h" -#include"has_free_vars.h" -#include"ast_smt2_pp.h" -#include"parser_params.hpp" +#include "util/stack.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "ast/seq_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/var_subst.h" +#include "ast/has_free_vars.h" +#include "ast/ast_smt2_pp.h" +#include "parsers/smt2/smt2parser.h" +#include "parsers/smt2/smt2scanner.h" +#include "parsers/util/pattern_validation.h" +#include "parsers/util/parser_params.hpp" #include namespace smt2 { @@ -68,6 +69,7 @@ namespace smt2 { scoped_ptr m_bv_util; scoped_ptr m_arith_util; + scoped_ptr m_datatype_util; scoped_ptr m_seq_util; scoped_ptr m_pattern_validator; scoped_ptr m_var_shifter; @@ -108,6 +110,7 @@ namespace smt2 { symbol m_check_sat_assuming; symbol m_define_fun_rec; symbol m_define_funs_rec; + symbol m_match; symbol m_underscore; typedef std::pair named_expr; @@ -135,7 +138,7 @@ namespace smt2 { typedef psort_frame sort_frame; - enum expr_frame_kind { EF_APP, EF_LET, EF_LET_DECL, EF_QUANT, EF_ATTR_EXPR, EF_PATTERN }; + enum expr_frame_kind { EF_APP, EF_LET, EF_LET_DECL, EF_MATCH, EF_QUANT, EF_ATTR_EXPR, EF_PATTERN }; struct expr_frame { expr_frame_kind m_kind; @@ -172,6 +175,10 @@ namespace smt2 { m_expr_spos(expr_spos) {} }; + struct match_frame : public expr_frame { + match_frame():expr_frame(EF_MATCH) {} + }; + struct let_frame : public expr_frame { bool m_in_decls; unsigned m_sym_spos; @@ -275,6 +282,12 @@ namespace smt2 { return *(m_arith_util.get()); } + datatype_util & dtutil() { + if (m_datatype_util.get() == 0) + m_datatype_util = alloc(datatype_util, m()); + return *(m_datatype_util.get()); + } + seq_util & sutil() { if (m_seq_util.get() == 0) m_seq_util = alloc(seq_util, m()); @@ -389,6 +402,7 @@ namespace smt2 { bool curr_id_is_underscore() const { SASSERT(curr_is_identifier()); return curr_id() == m_underscore; } bool curr_id_is_as() const { SASSERT(curr_is_identifier()); return curr_id() == m_as; } + bool curr_id_is_match() const { SASSERT(curr_is_identifier()); return curr_id() == m_match; } bool curr_id_is_forall() const { SASSERT(curr_is_identifier()); return curr_id() == m_forall; } bool curr_id_is_exists() const { SASSERT(curr_is_identifier()); return curr_id() == m_exists; } bool curr_id_is_bang() const { SASSERT(curr_is_identifier()); return curr_id() == m_bang; } @@ -430,7 +444,10 @@ namespace smt2 { m_ctx.regular_stream()<< "line " << line << " column " << pos << ": " << escaped(msg, true) << "\")" << std::endl; } if (m_ctx.exit_on_error()) { - exit(1); + // WORKAROUND: ASan's LeakSanitizer reports many false positives when + // calling `exit()` so call `_Exit()` instead which avoids invoking leak + // checking. + _Exit(1); } } @@ -617,16 +634,8 @@ namespace smt2 { SASSERT(curr_is_identifier()); symbol id = curr_id(); psort_decl * d = m_ctx.find_psort_decl(id); - int idx = 0; if (d == 0) { - if (m_dt_name2idx.find(id, idx)) { - throw parser_exception("smtlib 2.6 parametric datatype sorts are not supported"); - // unsigned num_params = m_dt_name2arity.find(id); - // d = pm().mk_psort_dt_decl(num_params, id); - } - else { - unknown_sort(id); - } + unknown_sort(id); } next(); void * mem = m_stack.allocate(sizeof(psort_frame)); @@ -885,6 +894,7 @@ namespace smt2 { } else if (sz == 1) { check_missing(new_dt_decls[0], line, pos); + new_dt_decls[0]->commit(pm()); } else { SASSERT(sz > 1); @@ -897,22 +907,20 @@ namespace smt2 { err_msg += "'"; throw parser_exception(err_msg, line, pos); } + dts->commit(pm()); m_ctx.insert_aux_pdecl(dts.get()); } for (unsigned i = 0; i < sz; i++) { pdatatype_decl * d = new_dt_decls[i]; - SASSERT(d != 0); symbol duplicated; check_duplicate(d, line, pos); - m_ctx.insert(d); - if (d->get_num_params() == 0) { - // if datatype is not parametric... then force instantiation to register accessor, recognizers and constructors... - sort_ref s(m()); - s = d->instantiate(pm(), 0, 0); + if (!is_smt2_6) { + // datatypes are inserted up front in SMT2.6 mode, so no need to re-insert them. + m_ctx.insert(d); } - } + } TRACE("declare_datatypes", tout << "i: " << i << " new_dt_decls.size(): " << sz << "\n"; - for (unsigned i = 0; i < sz; i++) tout << new_dt_decls[i]->get_name() << "\n";); + for (unsigned j = 0; j < new_dt_decls.size(); ++j) tout << new_dt_decls[j]->get_name() << "\n";); m_ctx.print_success(); next(); } @@ -940,12 +948,7 @@ namespace smt2 { check_missing(d, line, pos); check_duplicate(d, line, pos); - m_ctx.insert(d); - if (d->get_num_params() == 0) { - // if datatype is not parametric... then force instantiation to register accessor, recognizers and constructors... - sort_ref s(m()); - s = d->instantiate(pm(), 0, 0); - } + d->commit(pm()); check_rparen_next("invalid end of datatype declaration, ')' expected"); m_ctx.print_success(); } @@ -992,7 +995,7 @@ namespace smt2 { TRACE("name_expr", tout << "naming: " << s << " ->\n" << mk_pp(n, m()) << "\n";); if (!is_ground(n) && has_free_vars(n)) throw parser_exception("invalid named expression, expression contains free variables"); - m_ctx.insert(s, 0, n); + m_ctx.insert(s, 0, 0, n); m_last_named_expr.first = s; m_last_named_expr.second = n; } @@ -1272,6 +1275,23 @@ namespace smt2 { return num; } + void push_let_frame() { + next(); + check_lparen_next("invalid let declaration, '(' expected"); + void * mem = m_stack.allocate(sizeof(let_frame)); + new (mem) let_frame(symbol_stack().size(), expr_stack().size()); + m_num_expr_frames++; + } + + void push_bang_frame(expr_frame * curr) { + TRACE("consume_attributes", tout << "begin bang, expr_stack.size(): " << expr_stack().size() << "\n";); + next(); + void * mem = m_stack.allocate(sizeof(attr_expr_frame)); + new (mem) attr_expr_frame(curr, symbol_stack().size(), expr_stack().size()); + m_num_expr_frames++; + } + + void push_quant_frame(bool is_forall) { SASSERT(curr_is_identifier()); SASSERT(curr_id_is_forall() || curr_id_is_exists()); @@ -1287,6 +1307,202 @@ namespace smt2 { throw parser_exception("invalid quantifier, list of sorted variables is empty"); } + /** + * SMT-LIB 2.6 pattern matches are of the form + * (match t ((p1 t1) ... (pm+1 tm+1))) + */ + void push_match_frame() { + SASSERT(curr_is_identifier()); + SASSERT(curr_id() == m_match); + next(); + void * mem = m_stack.allocate(sizeof(match_frame)); + new (mem) match_frame(); + unsigned num_frames = m_num_expr_frames; + + parse_expr(); + expr_ref t(expr_stack().back(), m()); + expr_stack().pop_back(); + expr_ref_vector patterns(m()), cases(m()); + sort* srt = m().get_sort(t); + + check_lparen_next("pattern bindings should be enclosed in a parenthesis"); + while (!curr_is_rparen()) { + m_env.begin_scope(); + unsigned num_bindings = m_num_bindings; + check_lparen_next("invalid pattern binding, '(' expected"); + parse_match_pattern(srt); + patterns.push_back(expr_stack().back()); + expr_stack().pop_back(); + parse_expr(); + cases.push_back(expr_stack().back()); + expr_stack().pop_back(); + m_num_bindings = num_bindings; + m_env.end_scope(); + check_rparen_next("invalid pattern binding, ')' expected"); + } + next(); + m_num_expr_frames = num_frames + 1; + expr_stack().push_back(compile_patterns(t, patterns, cases)); + } + + void pop_match_frame(match_frame* fr) { + m_stack.deallocate(fr); + m_num_expr_frames--; + } + + expr_ref compile_patterns(expr* t, expr_ref_vector const& patterns, expr_ref_vector const& cases) { + expr_ref result(m()); + var_subst sub(m(), false); + TRACE("parse_expr", tout << "term\n" << expr_ref(t, m()) << "\npatterns\n" << patterns << "\ncases\n" << cases << "\n";); + check_patterns(patterns, m().get_sort(t)); + for (unsigned i = patterns.size(); i > 0; ) { + --i; + expr_ref_vector subst(m()); + expr_ref cond = bind_match(t, patterns[i], subst); + expr_ref new_case(m()); + if (subst.empty()) { + new_case = cases[i]; + } + else { + sub(cases[i], subst.size(), subst.c_ptr(), new_case); + inv_var_shifter inv(m()); + inv(new_case, subst.size(), new_case); + } + if (result) { + result = m().mk_ite(cond, new_case, result); + } + else { + // pattern match binding is ignored. + result = new_case; + } + } + TRACE("parse_expr", tout << result << "\n";); + return result; + } + + void check_patterns(expr_ref_vector const& patterns, sort* s) { + if (!dtutil().is_datatype(s)) + throw parser_exception("pattern matching is only supported for algebraic datatypes"); + ptr_vector 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 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 vars; + expr_ref_vector args(m()); + symbol C(check_identifier_next("constructor symbol expected")); + while (!curr_is_rparen()) { + symbol v(check_identifier_next("variable symbol expected")); + if (v != m_underscore && vars.contains(v)) { + throw parser_exception("unexpected repeated variable in pattern expression"); + } + vars.push_back(v); + } + next(); + + // now have C, vars + // look up constructor C, + // create bound variables based on constructor type. + // store expression in expr_stack(). + // ensure that bound variables are adjusted to vars + + func_decl* f = m_ctx.find_func_decl(C, 0, nullptr, vars.size(), nullptr, srt); + if (!f) { + throw parser_exception("expecting a constructor that has been declared"); + } + if (!dtutil().is_constructor(f)) { + throw parser_exception("expecting a constructor"); + } + if (f->get_arity() != vars.size()) { + throw parser_exception("mismatching number of variables supplied to constructor"); + } + m_num_bindings += vars.size(); + for (unsigned i = 0; i < vars.size(); ++i) { + var * v = m().mk_var(i, f->get_domain(i)); + args.push_back(v); + if (vars[i] != m_underscore) { + m_env.insert(vars[i], local(v, m_num_bindings)); + } + } + expr_stack().push_back(m().mk_app(f, args.size(), args.c_ptr())); + return true; + } + + void parse_match_pattern(sort* srt) { + if (parse_constructor_pattern(srt)) { + // done + } + else if (curr_id() == m_underscore) { + // we have a wild-card. + // store dummy variable in expr_stack() + next(); + var* v = m().mk_var(0, srt); + expr_stack().push_back(v); + } + else { + symbol xC(check_identifier_next("constructor symbol or variable expected")); + // check if xC is a constructor, otherwise make it a variable + // of sort srt. + try { + func_decl* f = m_ctx.find_func_decl(xC, 0, nullptr, 0, nullptr, srt); + if (!dtutil().is_constructor(f)) { + throw parser_exception("expecting a constructor, got a previously declared function"); + } + if (f->get_arity() > 0) { + throw parser_exception("constructor expects arguments, but no arguments were supplied in pattern"); + } + expr_stack().push_back(m().mk_const(f)); + } + catch (cmd_exception &) { + var* v = m().mk_var(0, srt); + expr_stack().push_back(v); + m_env.insert(xC, local(v, m_num_bindings++)); + } + } + } + symbol parse_indexed_identifier_core() { check_underscore_next("invalid indexed identifier, '_' expected"); check_identifier("invalid indexed identifier, symbol expected"); @@ -1578,8 +1794,7 @@ namespace smt2 { new (mem) app_frame(f, expr_spos, param_spos, has_as); m_num_expr_frames++; } - - // return true if a new frame was created. + void push_expr_frame(expr_frame * curr) { SASSERT(curr_is_lparen()); next(); @@ -1587,11 +1802,7 @@ namespace smt2 { if (curr_is_identifier()) { TRACE("push_expr_frame", tout << "push_expr_frame(), curr_id(): " << curr_id() << "\n";); if (curr_id_is_let()) { - next(); - check_lparen_next("invalid let declaration, '(' expected"); - void * mem = m_stack.allocate(sizeof(let_frame)); - new (mem) let_frame(symbol_stack().size(), expr_stack().size()); - m_num_expr_frames++; + push_let_frame(); } else if (curr_id_is_forall()) { push_quant_frame(true); @@ -1600,19 +1811,17 @@ namespace smt2 { push_quant_frame(false); } else if (curr_id_is_bang()) { - TRACE("consume_attributes", tout << "begin bang, expr_stack.size(): " << expr_stack().size() << "\n";); - next(); - void * mem = m_stack.allocate(sizeof(attr_expr_frame)); - new (mem) attr_expr_frame(curr, symbol_stack().size(), expr_stack().size()); - m_num_expr_frames++; + push_bang_frame(curr); } else if (curr_id_is_as() || curr_id_is_underscore()) { - TRACE("push_expr_frame", tout << "push_expr_frame(): parse_qualified_name\n";); parse_qualified_name(); } else if (curr_id_is_root_obj()) { parse_root_obj(); } + else if (curr_id_is_match()) { + push_match_frame(); + } else { push_app_frame(); } @@ -1656,7 +1865,9 @@ namespace smt2 { fr->m_in_decls = false; SASSERT(symbol_stack().size() >= fr->m_sym_spos); SASSERT(expr_stack().size() >= fr->m_expr_spos); - SASSERT(symbol_stack().size() - fr->m_sym_spos == expr_stack().size() - fr->m_expr_spos); + if (symbol_stack().size() - fr->m_sym_spos != expr_stack().size() - fr->m_expr_spos) { + throw parser_exception("malformed let expression"); + } unsigned num_decls = expr_stack().size() - fr->m_expr_spos; symbol * sym_it = symbol_stack().c_ptr() + fr->m_sym_spos; expr ** expr_it = expr_stack().c_ptr() + fr->m_expr_spos; @@ -1670,6 +1881,8 @@ namespace smt2 { // the resultant expression is on the top of the stack TRACE("let_frame", tout << "let result expr: " << mk_pp(expr_stack().back(), m()) << "\n";); expr_ref r(m()); + if (expr_stack().empty()) + throw parser_exception("invalid let expression"); r = expr_stack().back(); expr_stack().pop_back(); // remove local declarations from the stack @@ -1785,6 +1998,9 @@ namespace smt2 { m_stack.deallocate(static_cast(fr)); m_num_expr_frames--; break; + case EF_MATCH: + pop_match_frame(static_cast(fr)); + break; case EF_QUANT: pop_quant_frame(static_cast(fr)); break; @@ -1907,6 +2123,8 @@ namespace smt2 { m_dt_name2idx.insert(dt_name, i); m_dt_name2arity.insert(dt_name, u); m_dt_names.push_back(dt_name); + psort_decl * decl = pm().mk_psort_dt_decl(u, dt_name); + m_ctx.insert(decl); check_rparen("invalid sort declaration, ')' expected"); } else { @@ -1982,7 +2200,7 @@ namespace smt2 { parse_expr(); if (m().get_sort(expr_stack().back()) != sort_stack().back()) throw parser_exception("invalid function/constant definition, sort mismatch"); - m_ctx.insert(id, num_vars, expr_stack().back()); + m_ctx.insert(id, num_vars, sort_stack().c_ptr() + sort_spos, expr_stack().back()); check_rparen("invalid function/constant definition, ')' expected"); // restore stacks & env symbol_stack().shrink(sym_spos); @@ -2133,7 +2351,7 @@ namespace smt2 { parse_expr(); if (m().get_sort(expr_stack().back()) != sort_stack().back()) throw parser_exception("invalid constant definition, sort mismatch"); - m_ctx.insert(id, 0, expr_stack().back()); + m_ctx.insert(id, 0, 0, expr_stack().back()); check_rparen("invalid constant definition, ')' expected"); expr_stack().pop_back(); sort_stack().pop_back(); @@ -2238,9 +2456,14 @@ namespace smt2 { m_assert_expr = m_scanner.cached_str(0, m_cache_end); m_scanner.stop_caching(); } + if (expr_stack().empty()) { + throw cmd_exception("invalid assert command, expression required as argument"); + } expr * f = expr_stack().back(); - if (!m().is_bool(f)) + if (!m().is_bool(f)) { + TRACE("smt2parser", tout << expr_ref(f, m()) << "\n";); throw cmd_exception("invalid assert command, term is not Boolean"); + } if (f == m_last_named_expr.second) { m_ctx.assert_expr(m_last_named_expr.first, f); } @@ -2737,6 +2960,7 @@ namespace smt2 { m_check_sat_assuming("check-sat-assuming"), m_define_fun_rec("define-fun-rec"), m_define_funs_rec("define-funs-rec"), + m_match("match"), m_underscore("_"), m_num_open_paren(0), m_current_file(filename) { diff --git a/src/parsers/smt2/smt2parser.h b/src/parsers/smt2/smt2parser.h index 77fd41d5d..0976fc5f4 100644 --- a/src/parsers/smt2/smt2parser.h +++ b/src/parsers/smt2/smt2parser.h @@ -19,7 +19,7 @@ Revision History: #ifndef SMT2_PARSER_H_ #define SMT2_PARSER_H_ -#include"cmd_context.h" +#include "cmd_context/cmd_context.h" bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive = false, params_ref const & p = params_ref(), char const * filename = 0); diff --git a/src/parsers/smt2/smt2scanner.cpp b/src/parsers/smt2/smt2scanner.cpp index 1763a4fa5..9a9e69b67 100644 --- a/src/parsers/smt2/smt2scanner.cpp +++ b/src/parsers/smt2/smt2scanner.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"smt2scanner.h" -#include"parser_params.hpp" +#include "parsers/smt2/smt2scanner.h" +#include "parsers/util/parser_params.hpp" namespace smt2 { @@ -124,7 +124,7 @@ namespace smt2 { next(); bool is_float = false; - while (true) { + while (!m_at_eof) { char c = curr(); if ('0' <= c && c <= '9') { m_number = rational(10)*m_number + rational(c - '0'); diff --git a/src/parsers/smt2/smt2scanner.h b/src/parsers/smt2/smt2scanner.h index 3ad47dfb1..5283c57cf 100644 --- a/src/parsers/smt2/smt2scanner.h +++ b/src/parsers/smt2/smt2scanner.h @@ -20,10 +20,10 @@ Revision History: #define SMT2SCANNER_H_ #include -#include"symbol.h" -#include"vector.h" -#include"rational.h" -#include"cmd_context.h" +#include "util/symbol.h" +#include "util/vector.h" +#include "util/rational.h" +#include "cmd_context/cmd_context.h" namespace smt2 { diff --git a/src/parsers/util/cost_parser.cpp b/src/parsers/util/cost_parser.cpp index a13e9b107..765b8ade9 100644 --- a/src/parsers/util/cost_parser.cpp +++ b/src/parsers/util/cost_parser.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"cost_parser.h" +#include "parsers/util/cost_parser.h" cost_parser::cost_parser(ast_manager & m): simple_parser(m), diff --git a/src/parsers/util/cost_parser.h b/src/parsers/util/cost_parser.h index 37e9ea3a1..f0330d824 100644 --- a/src/parsers/util/cost_parser.h +++ b/src/parsers/util/cost_parser.h @@ -19,8 +19,8 @@ Revision History: #ifndef COST_PARSER_H_ #define COST_PARSER_H_ -#include"simple_parser.h" -#include"arith_decl_plugin.h" +#include "parsers/util/simple_parser.h" +#include "ast/arith_decl_plugin.h" class cost_parser : public simple_parser { arith_util m_util; diff --git a/src/parsers/util/pattern_validation.cpp b/src/parsers/util/pattern_validation.cpp index 0e90e8126..0d076aadd 100644 --- a/src/parsers/util/pattern_validation.cpp +++ b/src/parsers/util/pattern_validation.cpp @@ -17,11 +17,11 @@ Revision History: --*/ -#include"pattern_validation.h" -#include"for_each_expr.h" -#include"warning.h" +#include "parsers/util/pattern_validation.h" +#include "ast/for_each_expr.h" +#include "util/warning.h" -#include"ast_pp.h" +#include "ast/ast_pp.h" struct pattern_validation_functor { uint_set & m_found_vars; diff --git a/src/parsers/util/pattern_validation.h b/src/parsers/util/pattern_validation.h index 939781936..11656e1df 100644 --- a/src/parsers/util/pattern_validation.h +++ b/src/parsers/util/pattern_validation.h @@ -19,9 +19,9 @@ Revision History: #ifndef PATTERN_VALIDATION_H_ #define PATTERN_VALIDATION_H_ -#include"ast.h" -#include"uint_set.h" -#include"vector.h" +#include "ast/ast.h" +#include "util/uint_set.h" +#include "util/vector.h" class pattern_validator { family_id m_bfid; diff --git a/src/parsers/util/scanner.cpp b/src/parsers/util/scanner.cpp index 690c068e4..4ed47e81f 100644 --- a/src/parsers/util/scanner.cpp +++ b/src/parsers/util/scanner.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"scanner.h" +#include "parsers/util/scanner.h" inline char scanner::read_char() { if (m_is_interactive) { diff --git a/src/parsers/util/scanner.h b/src/parsers/util/scanner.h index f434da164..cd074479c 100644 --- a/src/parsers/util/scanner.h +++ b/src/parsers/util/scanner.h @@ -19,7 +19,7 @@ Revision History: #ifndef SCANNER_H_ #define SCANNER_H_ -#include"ast.h" +#include "ast/ast.h" class scanner { public: diff --git a/src/parsers/util/simple_parser.cpp b/src/parsers/util/simple_parser.cpp index 045a45b24..770da9dbb 100644 --- a/src/parsers/util/simple_parser.cpp +++ b/src/parsers/util/simple_parser.cpp @@ -18,9 +18,9 @@ Revision History: --*/ #include #include -#include"simple_parser.h" -#include"warning.h" -#include"scanner.h" +#include "parsers/util/simple_parser.h" +#include "util/warning.h" +#include "parsers/util/scanner.h" simple_parser::simple_parser(ast_manager & m): m_manager(m), diff --git a/src/parsers/util/simple_parser.h b/src/parsers/util/simple_parser.h index 8589f140b..671412579 100644 --- a/src/parsers/util/simple_parser.h +++ b/src/parsers/util/simple_parser.h @@ -19,8 +19,8 @@ Revision History: #ifndef SIMPLE_PARSER_H_ #define SIMPLE_PARSER_H_ -#include"ast.h" -#include"map.h" +#include "ast/ast.h" +#include "util/map.h" class scanner; diff --git a/src/qe/CMakeLists.txt b/src/qe/CMakeLists.txt index 2d2cf9579..2e6052382 100644 --- a/src/qe/CMakeLists.txt +++ b/src/qe/CMakeLists.txt @@ -18,7 +18,6 @@ z3_add_component(qe qe_sat_tactic.cpp qe_tactic.cpp qsat.cpp - vsubst_tactic.cpp COMPONENT_DEPENDENCIES nlsat_tactic nlsat @@ -31,5 +30,4 @@ z3_add_component(qe qe_sat_tactic.h qe_tactic.h qsat.h - vsubst_tactic.h ) diff --git a/src/qe/nlarith_util.cpp b/src/qe/nlarith_util.cpp index b7c1aef5d..4f07b59dd 100644 --- a/src/qe/nlarith_util.cpp +++ b/src/qe/nlarith_util.cpp @@ -4,15 +4,16 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "ast.h" -#include "nlarith_util.h" -#include "arith_decl_plugin.h" -#include "ast_pp.h" -#include "qe.h" -#include "expr_replacer.h" -#include "arith_rewriter.h" -#include "arith_simplifier_plugin.h" -#include "expr_functors.h" +#include "ast/ast.h" +#include "qe/nlarith_util.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_pp.h" +#include "qe/qe.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/rewriter/arith_rewriter.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/expr_functors.h" namespace nlarith { @@ -79,9 +80,8 @@ namespace nlarith { app_ref m_zero; app_ref m_one; smt_params m_params; - basic_simplifier_plugin m_bs; - arith_simplifier_plugin m_rw; - arith_rewriter m_rw1; + bool_rewriter m_bs; + arith_rewriter m_rw; expr_ref_vector m_trail; ast_manager& m() const { return m_manager; } @@ -105,8 +105,7 @@ namespace nlarith { m_enable_linear(false), m_zero(num(0),m), m_one(num(1),m), m_bs(m), - m_rw(m, m_bs, m_params), - m_rw1(m), m_trail(m) { + m_rw(m), m_trail(m) { } // diff --git a/src/qe/nlarith_util.h b/src/qe/nlarith_util.h index 5854088ab..7106d2a27 100644 --- a/src/qe/nlarith_util.h +++ b/src/qe/nlarith_util.h @@ -20,8 +20,8 @@ Notes: #ifndef NLARITH_UTIL_H_ #define NLARITH_UTIL_H_ -#include "ast.h" -#include "lbool.h" +#include "ast/ast.h" +#include "util/lbool.h" namespace nlarith { diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index fbff2e583..1f9c89f89 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -18,22 +18,22 @@ Revision History: --*/ -#include "nlqsat.h" -#include "nlsat_solver.h" -#include "nlsat_explain.h" -#include "nlsat_assignment.h" -#include "qsat.h" -#include "quant_hoist.h" -#include "goal2nlsat.h" -#include "expr2var.h" -#include "uint_set.h" -#include "ast_util.h" -#include "tseitin_cnf_tactic.h" -#include "expr_safe_replace.h" -#include "ast_pp.h" -#include "for_each_expr.h" -#include "rewriter.h" -#include "rewriter_def.h" +#include "util/uint_set.h" +#include "ast/expr2var.h" +#include "ast/ast_util.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/ast_pp.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/quant_hoist.h" +#include "qe/nlqsat.h" +#include "qe/qsat.h" +#include "nlsat/nlsat_solver.h" +#include "nlsat/nlsat_explain.h" +#include "nlsat/nlsat_assignment.h" +#include "nlsat/tactic/goal2nlsat.h" +#include "tactic/core/tseitin_cnf_tactic.h" namespace qe { @@ -292,8 +292,8 @@ namespace qe { nlsat::var_vector vs; m_solver.vars(l, vs); TRACE("qe", m_solver.display(tout, l); tout << "\n";); - for (unsigned i = 0; i < vs.size(); ++i) { - level.merge(m_rvar2level[vs[i]]); + for (unsigned v : vs) { + level.merge(m_rvar2level[v]); } set_level(l.var(), level); return level; @@ -429,22 +429,25 @@ namespace qe { } struct div { - expr_ref num, den, name; - div(ast_manager& m, expr* n, expr* d, expr* nm): + expr_ref num, den; + app_ref name; + div(ast_manager& m, expr* n, expr* d, app* nm): num(n, m), den(d, m), name(nm, m) {} }; class div_rewriter_cfg : public default_rewriter_cfg { ast_manager& m; arith_util a; + expr_ref m_zero; vector
m_divs; public: - div_rewriter_cfg(nlqsat& s): m(s.m), a(s.m) {} + div_rewriter_cfg(nlqsat& s): m(s.m), a(s.m), m_zero(a.mk_real(0), m) {} ~div_rewriter_cfg() {} br_status reduce_app(func_decl* f, unsigned sz, expr* const* args, expr_ref& result, proof_ref& pr) { - if (is_decl_of(f, a.get_family_id(), OP_DIV) && sz == 2 && !a.is_numeral(args[1]) && is_ground(args[0]) && is_ground(args[1])) { + rational r(1); + if (is_decl_of(f, a.get_family_id(), OP_DIV) && sz == 2 && (!a.is_numeral(args[1], r) || r.is_zero())) { result = m.mk_fresh_const("div", a.mk_real()); - m_divs.push_back(div(m, args[0], args[1], result)); + m_divs.push_back(div(m, args[0], args[1], to_app(result))); return BR_DONE; } return BR_FAILED; @@ -496,7 +499,7 @@ namespace qe { if (a.is_power(n, n1, n2) && a.is_numeral(n2, r) && r.is_unsigned()) { return; } - if (a.is_div(n, n1, n2) && is_ground(n1) && is_ground(n2) && s.m_mode == qsat_t) { + if (a.is_div(n) && s.m_mode == qsat_t) { m_has_divs = true; return; } @@ -508,7 +511,7 @@ namespace qe { bool has_divs() const { return m_has_divs; } }; - void purify(expr_ref& fml) { + void purify(expr_ref& fml, app_ref_vector& pvars, expr_ref_vector& paxioms) { is_pure_proc is_pure(*this); { expr_fast_mark1 visited; @@ -520,22 +523,38 @@ namespace qe { proof_ref pr(m); rw(fml, fml, pr); vector
const& divs = rw.divs(); - expr_ref_vector axioms(m); for (unsigned i = 0; i < divs.size(); ++i) { - axioms.push_back( + pvars.push_back(divs[i].name); + paxioms.push_back( m.mk_or(m.mk_eq(divs[i].den, arith.mk_numeral(rational(0), false)), m.mk_eq(divs[i].num, arith.mk_mul(divs[i].den, divs[i].name)))); for (unsigned j = i + 1; j < divs.size(); ++j) { - axioms.push_back(m.mk_or(m.mk_not(m.mk_eq(divs[i].den, divs[j].den)), - m.mk_not(m.mk_eq(divs[i].num, divs[j].num)), - m.mk_eq(divs[i].name, divs[j].name))); + paxioms.push_back(m.mk_or(m.mk_not(m.mk_eq(divs[i].den, divs[j].den)), + m.mk_not(m.mk_eq(divs[i].num, divs[j].num)), + m.mk_eq(divs[i].name, divs[j].name))); } } - axioms.push_back(fml); - fml = mk_and(axioms); } } + void ackermanize_div(bool is_forall, vector& qvars, expr_ref& fml) { + app_ref_vector pvars(m); + expr_ref_vector paxioms(m); + purify(fml, pvars, paxioms); + if (paxioms.empty()) { + return; + } + expr_ref ante = mk_and(paxioms); + qvars[qvars.size()-2].append(pvars); + if (!is_forall) { + fml = m.mk_implies(ante, fml); + } + else { + fml = m.mk_and(fml, ante); + } + } + + void reset() { //m_solver.reset(); m_asms.reset(); @@ -602,11 +621,12 @@ namespace qe { app_ref_vector vars(m); bool is_forall = false; pred_abs abs(m); - purify(fml); + abs.get_free_vars(fml, vars); insert_set(m_free_vars, vars); qvars.push_back(vars); vars.reset(); + if (m_mode == elim_t) { is_forall = true; hoist.pull_quantifier(is_forall, fml, vars); @@ -623,9 +643,14 @@ namespace qe { qvars.push_back(vars); } while (!vars.empty()); + SASSERT(qvars.size() >= 2); SASSERT(qvars.back().empty()); + + ackermanize_div(is_forall, qvars, fml); + init_expr2var(qvars); + goal2nlsat g2s; expr_ref is_true(m), fml1(m), fml2(m); diff --git a/src/qe/nlqsat.h b/src/qe/nlqsat.h index 9d0cb6af4..25cee55e3 100644 --- a/src/qe/nlqsat.h +++ b/src/qe/nlqsat.h @@ -21,7 +21,7 @@ Revision History: #ifndef QE_NLQSAT_H__ #define QE_NLQSAT_H__ -#include "tactic.h" +#include "tactic/tactic.h" tactic * mk_nlqsat_tactic(ast_manager & m, params_ref const& p = params_ref()); diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 4bf3c1580..061f403e3 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -18,33 +18,33 @@ Revision History: --*/ -#include "qe.h" -#include "smt_theory.h" -#include "bv_decl_plugin.h" -#include "smt_context.h" -#include "theory_bv.h" -#include "ast_ll_pp.h" -#include "ast_pp.h" -#include "ast_smt_pp.h" -#include "expr_abstract.h" -#include "var_subst.h" -#include "for_each_expr.h" -#include "dl_decl_plugin.h" -#include "nlarith_util.h" -#include "expr_replacer.h" -#include "factor_rewriter.h" -#include "expr_functors.h" -#include "quant_hoist.h" -#include "bool_rewriter.h" -#include "th_rewriter.h" -#include "smt_kernel.h" -#include "model_evaluator.h" -#include "has_free_vars.h" -#include "rewriter_def.h" -#include "cooperate.h" -#include "tactical.h" -#include "model_v2_pp.h" -#include "obj_hashtable.h" +#include "qe/qe.h" +#include "smt/smt_theory.h" +#include "ast/bv_decl_plugin.h" +#include "smt/smt_context.h" +#include "smt/theory_bv.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt_pp.h" +#include "ast/expr_abstract.h" +#include "ast/rewriter/var_subst.h" +#include "ast/for_each_expr.h" +#include "ast/dl_decl_plugin.h" +#include "qe/nlarith_util.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/rewriter/factor_rewriter.h" +#include "ast/expr_functors.h" +#include "ast/rewriter/quant_hoist.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/th_rewriter.h" +#include "smt/smt_kernel.h" +#include "model/model_evaluator.h" +#include "ast/has_free_vars.h" +#include "ast/rewriter/rewriter_def.h" +#include "util/cooperate.h" +#include "tactic/tactical.h" +#include "model/model_v2_pp.h" +#include "util/obj_hashtable.h" namespace qe { @@ -1272,7 +1272,7 @@ namespace qe { family_id fid = p->get_family_id(); SASSERT(fid != null_family_id); if (static_cast(m_plugins.size()) <= fid) { - m_plugins.resize(fid+1,0); + m_plugins.resize(fid+1); } SASSERT(!m_plugins[fid]); m_plugins[fid] = p; @@ -1310,6 +1310,10 @@ namespace qe { m_s.mk_atom(e, p, result); } + void i_solver_context::collect_statistics(statistics& st) const { + // tbd + } + typedef ref_vector_ptr_hash expr_ref_vector_hash; typedef ref_vector_ptr_eq expr_ref_vector_eq; typedef hashtable clause_table; @@ -2393,6 +2397,7 @@ namespace qe { +#if 0 // ------------------------------------------------ // expr_quant_elim_star1 @@ -2433,13 +2438,7 @@ namespace qe { simplifier(m), m_quant_elim(m, p), m_assumption(m.mk_true()) { } - - void expr_quant_elim_star1::reduce_with_assumption(expr* ctx, expr* fml, expr_ref& result) { - proof_ref pr(m); - m_assumption = ctx; - (*this)(fml, result, pr); - m_assumption = m.mk_true(); - } +#endif void hoist_exists(expr_ref& fml, app_ref_vector& vars) { @@ -2488,6 +2487,7 @@ namespace qe { virtual ~simplify_solver_context() { reset(); } + void solve(expr_ref& fml, app_ref_vector& vars) { init(fml, vars); bool solved = true; @@ -2580,6 +2580,10 @@ namespace qe { m_ctx.updt_params(p); } + void collect_statistics(statistics & st) const { + m_ctx.collect_statistics(st); + } + bool reduce_quantifier( quantifier * old_q, expr * new_body, @@ -2647,6 +2651,10 @@ namespace qe { imp->updt_params(p); } + void simplify_rewriter_cfg::collect_statistics(statistics & st) const { + imp->collect_statistics(st); + } + bool simplify_rewriter_cfg::pre_visit(expr* e) { if (!is_quantifier(e)) return true; quantifier * q = to_quantifier(e); diff --git a/src/qe/qe.h b/src/qe/qe.h index a75af19c5..b6754b384 100644 --- a/src/qe/qe.h +++ b/src/qe/qe.h @@ -21,15 +21,14 @@ Revision History: #ifndef QE_H_ #define QE_H_ -#include "ast.h" -#include "smt_params.h" -#include "statistics.h" -#include "lbool.h" -#include "expr_functors.h" -#include "simplifier.h" -#include "rewriter.h" -#include "model.h" -#include "params.h" +#include "ast/ast.h" +#include "smt/params/smt_params.h" +#include "util/statistics.h" +#include "util/lbool.h" +#include "ast/expr_functors.h" +#include "ast/rewriter/rewriter.h" +#include "model/model.h" +#include "util/params.h" namespace qe { @@ -106,6 +105,9 @@ namespace qe { i_expr_pred& get_is_relevant() { return m_is_relevant; } i_nnf_atom& get_mk_atom() { return m_mk_atom; } + + void collect_statistics(statistics & st) const; + }; class conj_enum { @@ -322,30 +324,6 @@ namespace qe { void init_qe(); }; - class expr_quant_elim_star1 : public simplifier { - protected: - expr_quant_elim m_quant_elim; - expr* m_assumption; - virtual bool visit_quantifier(quantifier * q); - virtual void reduce1_quantifier(quantifier * q); - virtual bool is_target(quantifier * q) const { return q->get_num_patterns() == 0 && q->get_num_no_patterns() == 0; } - public: - expr_quant_elim_star1(ast_manager & m, smt_params const& p); - virtual ~expr_quant_elim_star1() {} - - void collect_statistics(statistics & st) const { - m_quant_elim.collect_statistics(st); - } - - void reduce_with_assumption(expr* ctx, expr* fml, expr_ref& result); - - lbool first_elim(unsigned num_vars, app* const* vars, expr_ref& fml, def_vector& defs) { - return m_quant_elim.first_elim(num_vars, vars, fml, defs); - } - - - }; - void hoist_exists(expr_ref& fml, app_ref_vector& vars); void mk_exists(unsigned num_vars, app* const* vars, expr_ref& fml); @@ -372,6 +350,7 @@ namespace qe { void updt_params(params_ref const& p); + void collect_statistics(statistics & st) const; }; class simplify_rewriter_star : public rewriter_tpl { @@ -382,6 +361,11 @@ namespace qe { m_cfg(m) {} void updt_params(params_ref const& p) { m_cfg.updt_params(p); } + + void collect_statistics(statistics & st) const { + m_cfg.collect_statistics(st); + } + }; }; diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index d98f36d7d..6b3b3a11f 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -19,17 +19,17 @@ Revision History: --*/ -#include "qe_arith.h" -#include "qe_mbp.h" -#include "ast_util.h" -#include "arith_decl_plugin.h" -#include "ast_pp.h" -#include "model_v2_pp.h" -#include "th_rewriter.h" -#include "expr_functors.h" -#include "expr_safe_replace.h" -#include "model_based_opt.h" -#include "model_evaluator.h" +#include "qe/qe_arith.h" +#include "qe/qe_mbp.h" +#include "ast/ast_util.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_pp.h" +#include "model/model_v2_pp.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/expr_functors.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "math/simplex/model_based_opt.h" +#include "model/model_evaluator.h" namespace qe { @@ -90,8 +90,8 @@ namespace qe { rational r1, r2; expr_ref val1 = eval(e1); expr_ref val2 = eval(e2); - VERIFY(a.is_numeral(val1, r1)); - VERIFY(a.is_numeral(val2, r2)); + if (!a.is_numeral(val1, r1)) return false; + if (!a.is_numeral(val2, r2)) return false; SASSERT(r1 != r2); if (r1 < r2) { std::swap(e1, e2); @@ -105,10 +105,10 @@ namespace qe { rational r; app* alit = to_app(lit); vector > nums; - for (unsigned i = 0; i < alit->get_num_args(); ++i) { - val = eval(alit->get_arg(i)); - VERIFY(a.is_numeral(val, r)); - nums.push_back(std::make_pair(alit->get_arg(i), r)); + for (expr* arg : *alit) { + val = eval(arg); + if (!a.is_numeral(val, r)) return false; + nums.push_back(std::make_pair(arg, r)); } std::sort(nums.begin(), nums.end(), compare_second()); for (unsigned i = 0; i + 1 < nums.size(); ++i) { @@ -129,7 +129,7 @@ namespace qe { expr* arg1 = to_app(lit)->get_arg(i), *arg2 = 0; rational r; expr_ref val = eval(arg1); - VERIFY(a.is_numeral(val, r)); + if (!a.is_numeral(val, r)) return false; if (values.find(r, arg2)) { ty = opt::t_eq; linearize(mbo, eval, mul, arg1, c, fmls, ts, tids); @@ -168,8 +168,8 @@ namespace qe { } else if (a.is_add(t)) { app* ap = to_app(t); - for (unsigned i = 0; i < ap->get_num_args(); ++i) { - linearize(mbo, eval, mul, ap->get_arg(i), c, fmls, ts, tids); + for (expr* arg : *ap) { + linearize(mbo, eval, mul, arg, c, fmls, ts, tids); } } else if (a.is_sub(t, t1, t2)) { @@ -196,7 +196,7 @@ namespace qe { linearize(mbo, eval, mul, t3, c, fmls, ts, tids); } } - else if (a.is_mod(t, t1, t2) && is_numeral(t2, mul1)) { + else if (a.is_mod(t, t1, t2) && is_numeral(t2, mul1) && !mul1.is_zero()) { rational r; val = eval(t); VERIFY(a.is_numeral(val, r)); @@ -226,16 +226,16 @@ namespace qe { else if (a.is_mul(t)) { app* ap = to_app(t); r = rational(1); - for (unsigned i = 0; i < ap->get_num_args(); ++i) { - if (!is_numeral(ap->get_arg(i), r1)) return false; + for (expr * arg : *ap) { + if (!is_numeral(arg, r1)) return false; r *= r1; } } else if (a.is_add(t)) { app* ap = to_app(t); r = rational(0); - for (unsigned i = 0; i < ap->get_num_args(); ++i) { - if (!is_numeral(ap->get_arg(i), r1)) return false; + for (expr * arg : *ap) { + if (!is_numeral(arg, r1)) return false; r += r1; } } @@ -297,6 +297,7 @@ namespace qe { opt::model_based_opt mbo; obj_map tids; + expr_ref_vector pinned(m); unsigned j = 0; for (unsigned i = 0; i < fmls.size(); ++i) { expr* fml = fmls[i].get(); @@ -308,6 +309,7 @@ namespace qe { } else { TRACE("qe", tout << mk_pp(fml, m) << "\n";); + pinned.push_back(fml); } } fmls.resize(j); @@ -321,8 +323,7 @@ namespace qe { // return those to fmls. expr_mark var_mark, fmls_mark; - for (unsigned i = 0; i < vars.size(); ++i) { - app* v = vars[i].get(); + for (app * v : vars) { var_mark.mark(v); if (is_arith(v) && !tids.contains(v)) { rational r; @@ -332,17 +333,16 @@ namespace qe { tids.insert(v, mbo.add_var(r, a.is_int(v))); } } - for (unsigned i = 0; i < fmls.size(); ++i) { - fmls_mark.mark(fmls[i].get()); + for (expr* fml : fmls) { + fmls_mark.mark(fml); } - obj_map::iterator it = tids.begin(), end = tids.end(); ptr_vector index2expr; - for (; it != end; ++it) { - expr* e = it->m_key; + for (auto& kv : tids) { + expr* e = kv.m_key; if (!var_mark.is_marked(e)) { mark_rec(fmls_mark, e); } - index2expr.setx(it->m_value, e, 0); + index2expr.setx(kv.m_value, e, 0); } j = 0; unsigned_vector real_vars; @@ -360,8 +360,7 @@ namespace qe { } vars.resize(j); TRACE("qe", tout << "remaining vars: " << vars << "\n"; - for (unsigned i = 0; i < real_vars.size(); ++i) { - unsigned v = real_vars[i]; + for (unsigned v : real_vars) { tout << "v" << v << " " << mk_pp(index2expr[v], m) << "\n"; } mbo.display(tout);); @@ -449,8 +448,8 @@ namespace qe { // extract linear constraints - for (unsigned i = 0; i < fmls.size(); ++i) { - linearize(mbo, eval, fmls[i].get(), fmls, tids); + for (expr * fml : fmls) { + linearize(mbo, eval, fml, fmls, tids); } // find optimal value @@ -459,11 +458,10 @@ namespace qe { // update model to use new values that satisfy optimality ptr_vector vars; - obj_map::iterator it = tids.begin(), end = tids.end(); - for (; it != end; ++it) { - expr* e = it->m_key; + for (auto& kv : tids) { + expr* e = kv.m_key; if (is_uninterp_const(e)) { - unsigned id = it->m_value; + unsigned id = kv.m_value; func_decl* f = to_app(e)->get_decl(); expr_ref val(a.mk_numeral(mbo.get_value(id), false), m); mdl.register_decl(f, val); @@ -509,10 +507,9 @@ namespace qe { void extract_coefficients(opt::model_based_opt& mbo, model_evaluator& eval, obj_map const& ts, obj_map& tids, vars& coeffs) { coeffs.reset(); eval.set_model_completion(true); - obj_map::iterator it = ts.begin(), end = ts.end(); - for (; it != end; ++it) { + for (auto& kv : ts) { unsigned id; - expr* v = it->m_key; + expr* v = kv.m_key; if (!tids.find(v, id)) { rational r; expr_ref val = eval(v); @@ -520,9 +517,9 @@ namespace qe { id = mbo.add_var(r, a.is_int(v)); tids.insert(v, id); } - CTRACE("qe", it->m_value.is_zero(), tout << mk_pp(v, m) << " has coefficeint 0\n";); - if (!it->m_value.is_zero()) { - coeffs.push_back(var(id, it->m_value)); + CTRACE("qe", kv.m_value.is_zero(), tout << mk_pp(v, m) << " has coefficeint 0\n";); + if (!kv.m_value.is_zero()) { + coeffs.push_back(var(id, kv.m_value)); } } } diff --git a/src/qe/qe_arith.h b/src/qe/qe_arith.h index 616d1a8d0..88675d5a4 100644 --- a/src/qe/qe_arith.h +++ b/src/qe/qe_arith.h @@ -8,9 +8,9 @@ Copyright (c) 2015 Microsoft Corporation #ifndef QE_ARITH_H_ #define QE_ARITH_H_ -#include "model.h" -#include "arith_decl_plugin.h" -#include "qe_mbp.h" +#include "model/model.h" +#include "ast/arith_decl_plugin.h" +#include "qe/qe_mbp.h" namespace qe { diff --git a/src/qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp index d8ae75256..1085ec3c2 100644 --- a/src/qe/qe_arith_plugin.cpp +++ b/src/qe/qe_arith_plugin.cpp @@ -18,21 +18,21 @@ Revision History: --*/ -#include "qe.h" -#include "ast_pp.h" -#include "expr_safe_replace.h" -#include "bool_rewriter.h" -#include "bv_decl_plugin.h" -#include "arith_decl_plugin.h" -#include "arith_eq_solver.h" -#include "arith_rewriter.h" -#include "th_rewriter.h" -#include "factor_rewriter.h" -#include "obj_pair_hashtable.h" -#include "nlarith_util.h" -#include "model_evaluator.h" -#include "smt_kernel.h" -#include "qe_arith.h" +#include "qe/qe.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/bv_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "smt/arith_eq_solver.h" +#include "ast/rewriter/arith_rewriter.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/factor_rewriter.h" +#include "util/obj_pair_hashtable.h" +#include "qe/nlarith_util.h" +#include "model/model_evaluator.h" +#include "smt/smt_kernel.h" +#include "qe/qe_arith.h" namespace qe { diff --git a/src/qe/qe_array_plugin.cpp b/src/qe/qe_array_plugin.cpp index e7cbe65b9..9eeccd6a4 100644 --- a/src/qe/qe_array_plugin.cpp +++ b/src/qe/qe_array_plugin.cpp @@ -5,11 +5,11 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "qe.h" -#include "array_decl_plugin.h" -#include "expr_safe_replace.h" -#include "ast_pp.h" -#include "arith_decl_plugin.h" +#include "qe/qe.h" +#include "ast/array_decl_plugin.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" namespace qe { // --------------------- diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index a010c4ae4..6d0bf82bf 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -18,13 +18,13 @@ Revision History: --*/ -#include "qe_arrays.h" -#include "rewriter_def.h" -#include "expr_functors.h" -#include "expr_safe_replace.h" -#include "lbool.h" -#include "ast_util.h" -#include "ast_pp.h" +#include "qe/qe_arrays.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/expr_functors.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "util/lbool.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" namespace qe { diff --git a/src/qe/qe_arrays.h b/src/qe/qe_arrays.h index 182d82255..e100ebce4 100644 --- a/src/qe/qe_arrays.h +++ b/src/qe/qe_arrays.h @@ -21,8 +21,8 @@ Revision History: #ifndef __QE_ARRAYS_H_ #define __QE_ARRAYS_H_ -#include "array_decl_plugin.h" -#include "qe_mbp.h" +#include "ast/array_decl_plugin.h" +#include "qe/qe_mbp.h" namespace qe { diff --git a/src/qe/qe_bool_plugin.cpp b/src/qe/qe_bool_plugin.cpp index 39a46ae55..82e09bbed 100644 --- a/src/qe/qe_bool_plugin.cpp +++ b/src/qe/qe_bool_plugin.cpp @@ -24,10 +24,10 @@ Notes: --*/ -#include "qe.h" -#include "expr_safe_replace.h" -#include "ast_pp.h" -#include "model_evaluator.h" +#include "qe/qe.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/ast_pp.h" +#include "model/model_evaluator.h" namespace qe { diff --git a/src/qe/qe_bv_plugin.cpp b/src/qe/qe_bv_plugin.cpp index df1f8c619..6678d6fcf 100644 --- a/src/qe/qe_bv_plugin.cpp +++ b/src/qe/qe_bv_plugin.cpp @@ -20,10 +20,10 @@ Notes: --*/ -#include "qe.h" -#include "expr_safe_replace.h" -#include "bv_decl_plugin.h" -#include "model_evaluator.h" +#include "qe/qe.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/bv_decl_plugin.h" +#include "model/model_evaluator.h" namespace qe { diff --git a/src/qe/qe_cmd.cpp b/src/qe/qe_cmd.cpp index 9144c708c..3c55c0f49 100644 --- a/src/qe/qe_cmd.cpp +++ b/src/qe/qe_cmd.cpp @@ -4,10 +4,10 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "qe_cmd.h" -#include "qe.h" -#include "cmd_context.h" -#include "parametric_cmd.h" +#include "qe/qe_cmd.h" +#include "qe/qe.h" +#include "cmd_context/cmd_context.h" +#include "cmd_context/parametric_cmd.h" class qe_cmd : public parametric_cmd { expr * m_target; @@ -44,9 +44,8 @@ public: } virtual void execute(cmd_context & ctx) { - smt_params par; proof_ref pr(ctx.m()); - qe::expr_quant_elim_star1 qe(ctx.m(), par); + qe::simplify_rewriter_star qe(ctx.m()); expr_ref result(ctx.m()); qe(m_target, result, pr); diff --git a/src/qe/qe_datatype_plugin.cpp b/src/qe/qe_datatype_plugin.cpp index 78562cf00..c3525aa33 100644 --- a/src/qe/qe_datatype_plugin.cpp +++ b/src/qe/qe_datatype_plugin.cpp @@ -99,13 +99,13 @@ Copyright (c) 2015 Microsoft Corporation // maintain set of equations and disequations with x. // -#include "qe.h" -#include "datatype_decl_plugin.h" -#include "expr_safe_replace.h" -#include "obj_pair_hashtable.h" -#include "for_each_expr.h" -#include "ast_pp.h" -#include "ast_ll_pp.h" +#include "qe/qe.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "util/obj_pair_hashtable.h" +#include "ast/for_each_expr.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" namespace qe { @@ -626,7 +626,7 @@ namespace qe { // If 'x' does not yet have a recognizer, then branch according to recognizers. // if (!has_recognizer(x, fml, r, c)) { - c = (*m_datatype_util.get_datatype_constructors(s))[vl.get_unsigned()]; + c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned()); r = m_datatype_util.get_constructor_recognizer(c); app* is_c = m.mk_app(r, x); // assert v => r(x) @@ -673,7 +673,7 @@ namespace qe { // Introduce auxiliary variable to eliminate. // if (!has_recognizer(x, fml, r, c)) { - c = (*m_datatype_util.get_datatype_constructors(s))[vl.get_unsigned()]; + c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned()); r = m_datatype_util.get_constructor_recognizer(c); app* is_c = m.mk_app(r, x); fml = m.mk_and(is_c, fml); @@ -774,7 +774,7 @@ namespace qe { return; } - c = (*m_datatype_util.get_datatype_constructors(s))[vl.get_unsigned()]; + c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned()); r = m_datatype_util.get_constructor_recognizer(c); app* is_c = m.mk_app(r, x); @@ -794,7 +794,7 @@ namespace qe { else { SASSERT(vl.is_unsigned()); SASSERT(vl.get_unsigned() < m_datatype_util.get_datatype_num_constructors(s)); - c = (*m_datatype_util.get_datatype_constructors(s))[vl.get_unsigned()]; + c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned()); } subst_constructor(x, c, fml, def); } diff --git a/src/qe/qe_datatypes.cpp b/src/qe/qe_datatypes.cpp index 8536e337f..db1e6ec85 100644 --- a/src/qe/qe_datatypes.cpp +++ b/src/qe/qe_datatypes.cpp @@ -17,14 +17,14 @@ Revision History: --*/ -#include "qe_arith.h" -#include "ast_pp.h" -#include "th_rewriter.h" -#include "expr_functors.h" -#include "model_v2_pp.h" -#include "expr_safe_replace.h" -#include "obj_pair_hashtable.h" -#include "qe_datatypes.h" +#include "qe/qe_arith.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/expr_functors.h" +#include "model/model_v2_pp.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "util/obj_pair_hashtable.h" +#include "qe/qe_datatypes.h" namespace qe { diff --git a/src/qe/qe_datatypes.h b/src/qe/qe_datatypes.h index f616e7f2e..7352b4ca7 100644 --- a/src/qe/qe_datatypes.h +++ b/src/qe/qe_datatypes.h @@ -21,8 +21,8 @@ Revision History: #ifndef __QE_DATATYPES_H_ #define __QE_DATATYPES_H_ -#include "datatype_decl_plugin.h" -#include "qe_mbp.h" +#include "ast/datatype_decl_plugin.h" +#include "qe/qe_mbp.h" namespace qe { diff --git a/src/qe/qe_dl_plugin.cpp b/src/qe/qe_dl_plugin.cpp index e04f4cbde..7ff7bc11e 100644 --- a/src/qe/qe_dl_plugin.cpp +++ b/src/qe/qe_dl_plugin.cpp @@ -5,11 +5,11 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "qe.h" -#include "expr_safe_replace.h" -#include "dl_decl_plugin.h" -#include "obj_pair_hashtable.h" -#include "ast_pp.h" +#include "qe/qe.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/dl_decl_plugin.h" +#include "util/obj_pair_hashtable.h" +#include "ast/ast_pp.h" namespace qe { diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index ce182a97b..257331161 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -17,26 +17,26 @@ Revision History: --*/ -#include "qe_lite.h" -#include "expr_abstract.h" -#include "used_vars.h" -#include "occurs.h" -#include "rewriter_def.h" -#include "ast_pp.h" -#include "ast_ll_pp.h" -#include "ast_smt2_pp.h" -#include "tactical.h" -#include "bool_rewriter.h" -#include "var_subst.h" -#include "uint_set.h" -#include "ast_util.h" -#include "th_rewriter.h" -#include "for_each_expr.h" -#include "expr_safe_replace.h" -#include "cooperate.h" -#include "datatype_decl_plugin.h" +#include "qe/qe_lite.h" +#include "ast/expr_abstract.h" +#include "ast/used_vars.h" +#include "ast/occurs.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt2_pp.h" +#include "tactic/tactical.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/var_subst.h" +#include "util/uint_set.h" +#include "ast/ast_util.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "util/cooperate.h" +#include "ast/datatype_decl_plugin.h" -#include "qe_vartest.h" +#include "qe/qe_vartest.h" namespace eq { class der { @@ -2342,6 +2342,7 @@ private: elim_star m_elim_star; th_rewriter m_rewriter; + bool m_use_array_der; bool has_unique_non_ground(expr_ref_vector const& fmls, unsigned& index) { index = fmls.size(); if (index <= 1) { @@ -2359,13 +2360,14 @@ private: } public: - impl(ast_manager & m, params_ref const & p): + impl(ast_manager & m, params_ref const & p, bool use_array_der): m(m), m_der(m, p), m_fm(m), m_array_der(m), m_elim_star(*this), - m_rewriter(m) {} + m_rewriter(m), + m_use_array_der(use_array_der) {} void operator()(app_ref_vector& vars, expr_ref& fml) { if (vars.empty()) { @@ -2445,14 +2447,15 @@ public: m_array_der.set_is_variable_proc(is_var); m_der(fmls); m_fm(fmls); - m_array_der(fmls); + // AG: disalble m_array_der() since it interferes with other array handling + if (m_use_array_der) m_array_der(fmls); TRACE("qe_lite", for (unsigned i = 0; i < fmls.size(); ++i) tout << mk_pp(fmls[i].get(), m) << "\n";); } }; -qe_lite::qe_lite(ast_manager & m, params_ref const & p) { - m_impl = alloc(impl, m, p); +qe_lite::qe_lite(ast_manager & m, params_ref const & p, bool use_array_der) { + m_impl = alloc(impl, m, p, use_array_der); } qe_lite::~qe_lite() { @@ -2484,7 +2487,7 @@ class qe_lite_tactic : public tactic { imp(ast_manager& m, params_ref const & p): m(m), - m_qe(m, p) + m_qe(m, p, true) {} void checkpoint() { diff --git a/src/qe/qe_lite.h b/src/qe/qe_lite.h index cff547f36..4fc5572a2 100644 --- a/src/qe/qe_lite.h +++ b/src/qe/qe_lite.h @@ -21,9 +21,9 @@ Revision History: #ifndef QE_LITE_H_ #define QE_LITE_H_ -#include "ast.h" -#include "uint_set.h" -#include "params.h" +#include "ast/ast.h" +#include "util/uint_set.h" +#include "util/params.h" class tactic; @@ -31,7 +31,10 @@ class qe_lite { class impl; impl * m_impl; public: - qe_lite(ast_manager & m, params_ref const & p); + /** + use_array_der controls whether equalities over array reads are simplified + */ + qe_lite(ast_manager& m, params_ref const & p, bool use_array_der = true); ~qe_lite(); diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index f4c0c9339..329687a36 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -18,18 +18,18 @@ Revision History: --*/ -#include "qe_mbp.h" -#include "qe_arith.h" -#include "qe_arrays.h" -#include "qe_datatypes.h" -#include "expr_safe_replace.h" -#include "ast_pp.h" -#include "ast_util.h" -#include "th_rewriter.h" -#include "model_v2_pp.h" -#include "expr_functors.h" -#include "for_each_expr.h" -#include "model_evaluator.h" +#include "qe/qe_mbp.h" +#include "qe/qe_arith.h" +#include "qe/qe_arrays.h" +#include "qe/qe_datatypes.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "ast/rewriter/th_rewriter.h" +#include "model/model_v2_pp.h" +#include "ast/expr_functors.h" +#include "ast/for_each_expr.h" +#include "model/model_evaluator.h" using namespace qe; diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index b195d3a35..d1695843c 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -21,10 +21,10 @@ Revision History: #ifndef __QE_MBP_H__ #define __QE_MBP_H__ -#include "ast.h" -#include "params.h" -#include "model.h" -#include "model_based_opt.h" +#include "ast/ast.h" +#include "util/params.h" +#include "model/model.h" +#include "math/simplex/model_based_opt.h" namespace qe { diff --git a/src/qe/qe_sat_tactic.cpp b/src/qe/qe_sat_tactic.cpp index c2912692c..69ebc1a42 100644 --- a/src/qe/qe_sat_tactic.cpp +++ b/src/qe/qe_sat_tactic.cpp @@ -20,16 +20,16 @@ Revision History: --*/ -#include "qe_sat_tactic.h" -#include "quant_hoist.h" -#include "ast_pp.h" -#include "smt_kernel.h" -#include "qe.h" -#include "cooperate.h" -#include "model_v2_pp.h" -#include "expr_replacer.h" -#include "th_rewriter.h" -#include "expr_context_simplifier.h" +#include "qe/qe_sat_tactic.h" +#include "ast/rewriter/quant_hoist.h" +#include "ast/ast_pp.h" +#include "smt/smt_kernel.h" +#include "qe/qe.h" +#include "util/cooperate.h" +#include "model/model_v2_pp.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/rewriter/th_rewriter.h" +#include "smt/expr_context_simplifier.h" // plugin registration. // solver specific projection operators. diff --git a/src/qe/qe_sat_tactic.h b/src/qe/qe_sat_tactic.h index 0b276fe8d..57279ed05 100644 --- a/src/qe/qe_sat_tactic.h +++ b/src/qe/qe_sat_tactic.h @@ -22,7 +22,7 @@ Revision History: #ifndef QE_SAT_H_ #define QE_SAT_H_ -#include"tactic.h" +#include "tactic/tactic.h" namespace qe { diff --git a/src/qe/qe_tactic.cpp b/src/qe/qe_tactic.cpp index 935af8550..5d1a74813 100644 --- a/src/qe/qe_tactic.cpp +++ b/src/qe/qe_tactic.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"filter_model_converter.h" -#include"cooperate.h" -#include"qe.h" +#include "tactic/tactical.h" +#include "tactic/filter_model_converter.h" +#include "util/cooperate.h" +#include "qe/qe.h" class qe_tactic : public tactic { statistics m_st; diff --git a/src/qe/qe_tactic.h b/src/qe/qe_tactic.h index 68860f488..c50cc84de 100644 --- a/src/qe/qe_tactic.h +++ b/src/qe/qe_tactic.h @@ -19,7 +19,7 @@ Revision History: #ifndef QE_TACTIC_H_ #define QE_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/qe/qe_vartest.h b/src/qe/qe_vartest.h index b2b4be649..047964825 100644 --- a/src/qe/qe_vartest.h +++ b/src/qe/qe_vartest.h @@ -19,8 +19,8 @@ Revision History: #ifndef QE_VARTEST_H_ #define QE_VARTEST_H_ -#include "ast.h" -#include "uint_set.h" +#include "ast/ast.h" +#include "util/uint_set.h" class is_variable_proc { public: diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 841bdde9b..713ecfe77 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -20,23 +20,23 @@ Notes: --*/ -#include "smt_kernel.h" -#include "qe_mbp.h" -#include "smt_params.h" -#include "ast_util.h" -#include "quant_hoist.h" -#include "ast_pp.h" -#include "model_v2_pp.h" -#include "qsat.h" -#include "expr_abstract.h" -#include "qe.h" -#include "label_rewriter.h" -#include "expr_replacer.h" -#include "th_rewriter.h" -#include "model_evaluator.h" -#include "smt_solver.h" -#include "solver.h" -#include "mus.h" +#include "ast/expr_abstract.h" +#include "ast/ast_util.h" +#include "ast/rewriter/quant_hoist.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/expr_replacer.h" +#include "model/model_v2_pp.h" +#include "model/model_evaluator.h" +#include "smt/smt_kernel.h" +#include "smt/params/smt_params.h" +#include "smt/smt_solver.h" +#include "solver/solver.h" +#include "solver/mus.h" +#include "qe/qsat.h" +#include "qe/qe_mbp.h" +#include "qe/qe.h" +#include "ast/rewriter/label_rewriter.h" namespace qe { diff --git a/src/qe/qsat.h b/src/qe/qsat.h index b6d21db1e..85a8181d6 100644 --- a/src/qe/qsat.h +++ b/src/qe/qsat.h @@ -21,9 +21,9 @@ Revision History: #ifndef QE_QSAT_H__ #define QE_QSAT_H__ -#include "tactic.h" -#include "filter_model_converter.h" -#include "qe_mbp.h" +#include "tactic/tactic.h" +#include "tactic/filter_model_converter.h" +#include "qe/qe_mbp.h" namespace qe { diff --git a/src/qe/vsubst_tactic.cpp b/src/qe/vsubst_tactic.cpp deleted file mode 100644 index c389d9a66..000000000 --- a/src/qe/vsubst_tactic.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - vsubst_tactic.cpp - -Abstract: - - Check satisfiability of QF_NRA problems using virtual subsititution quantifier-elimination. - -Author: - - Nikolaj (nbjorner) 2011-05-16 - -Notes: - Ported to tactic framework on 2012-02-28 - It was qfnra_vsubst.cpp - - This goal transformation checks satsifiability - of quantifier-free non-linear constraints using - virtual substitutions (applies to second-degree polynomials). - . identify non-linear variables - . use the identified variables as non-linear variables. - . give up if there are non-linear variables under uninterpreted scope. - give up if there are no non-linear variables. - . call quantifier elimination with - - non-linear elimination option. - - get-first-branch option. - . if the first branch is linear, then done. - if the result is unsat, then done. - if the first branch is non-linear then, - check candidate model, - perhaps iterate using rewriting or just give up. - - . helpful facilities: - . linearize_rewriter - a*a*b + a*b = 0 <=> (b+1) = 0 \/ a = 0 \/ b = 0 - . sign analysis: - a*a + b*b + c < 0 => c < 0 - ---*/ -#include"tactic.h" -#include"qe.h" -#include"arith_decl_plugin.h" -#include"for_each_expr.h" -#include"extension_model_converter.h" -#include"ast_smt2_pp.h" - -class vsubst_tactic : public tactic { - params_ref m_params; - - class get_var_proc { - arith_util m_arith; - ptr_vector& m_vars; - public: - get_var_proc(ast_manager & m, ptr_vector& vars) : m_arith(m), m_vars(vars) {} - - void operator()(expr* e) { - if (is_app(e)) { - app* a = to_app(e); - if (m_arith.is_real(e) && - a->get_num_args() == 0 && - a->get_family_id() == null_family_id) { - m_vars.push_back(a); - } - } - } - }; - - void get_vars(ast_manager & m, expr* fml, ptr_vector& vars) { - get_var_proc proc(m, vars); - for_each_expr(proc, fml); - } - - void main(goal & s, model_converter_ref & mc, params_ref const & p) { - ast_manager & m = s.m(); - - ptr_vector fs; - for (unsigned i = 0; i < s.size(); ++i) { - fs.push_back(s.form(i)); - } - app_ref f(m.mk_and(fs.size(), fs.c_ptr()), m); - TRACE("vsubst", - s.display(tout); - tout << "goal: " << mk_ismt2_pp(f.get(), m) << "\n";); - ptr_vector vars; - get_vars(m, f.get(), vars); - - if (vars.empty()) { - TRACE("vsubst", tout << "no real variables\n";); - throw tactic_exception("there are no real variables"); - } - - smt_params params; - params.updt_params(p); - params.m_model = false; - flet fl1(params.m_nlquant_elim, true); - flet fl2(params.m_nl_arith_gb, false); - TRACE("quant_elim", tout << "Produce models: " << params.m_model << "\n";); - - qe::expr_quant_elim_star1 qelim(m, params); - expr_ref g(f, m); - qe::def_vector defs(m); - lbool is_sat = qelim.first_elim(vars.size(), vars.c_ptr(), g, defs); - if (is_sat == l_undef) { - TRACE("vsubst", tout << mk_ismt2_pp(g, m) << "\n";); - throw tactic_exception("elimination was not successful"); - } - if (!defs.empty()) { - extension_model_converter * ev = alloc(extension_model_converter, m); - mc = ev; - for (unsigned i = defs.size(); i > 0; ) { - --i; - ev->insert(defs.var(i), defs.def(i)); - } - } - - s.reset(); - // TBD: wasteful as we already know it is sat or unsat. - // TBD: extract model from virtual substitution. - s.assert_expr(g); - - TRACE("qfnra_vsubst", - tout << "v-subst result:\n"; - s.display(tout);); - } - - -public: - vsubst_tactic(params_ref const & p):m_params(p) {} - - virtual tactic * translate(ast_manager & m) { - return alloc(vsubst_tactic, m_params); - } - - virtual ~vsubst_tactic() {} - - virtual void updt_params(params_ref const & p) { - m_params = p; - } - - /** - \brief Check satisfiability of an assertion set of QF_NRA - by using virtual substitutions. - */ - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { - SASSERT(g->is_well_sorted()); - fail_if_proof_generation("vsubst", g); - fail_if_unsat_core_generation("vsubst", g); - fail_if_model_generation("vsubst", g); // disable for now due to problems with infinitesimals. - mc = 0; pc = 0; core = 0; result.reset(); - - main(*(g.get()), mc, m_params); - - result.push_back(g.get()); - SASSERT(g->is_well_sorted()); - } - - virtual void cleanup(void) {} -}; - -tactic * mk_vsubst_tactic(ast_manager & m, params_ref const & p) { - return alloc(vsubst_tactic, p); -} diff --git a/src/qe/vsubst_tactic.h b/src/qe/vsubst_tactic.h deleted file mode 100644 index 8c0cb682f..000000000 --- a/src/qe/vsubst_tactic.h +++ /dev/null @@ -1,33 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - vsubst_tactic.h - -Abstract: - - Check satisfiability of QF_NRA problems using virtual subsititution quantifier-elimination. - -Author: - - Nikolaj (nbjorner) 2011-05-16 - -Notes: - - ---*/ -#ifndef VSUBST_TACTIC_H_ -#define VSUBST_TACTIC_H_ - -#include"params.h" -class ast_manager; -class tactic; - -tactic * mk_vsubst_tactic(ast_manager & m, params_ref const & p = params_ref()); -/* - ADD_TACTIC("vsubst", "checks satsifiability of quantifier-free non-linear constraints using virtual substitution.", "mk_vsubst_tactic(m, p)") -*/ - -#endif - diff --git a/src/sat/dimacs.cpp b/src/sat/dimacs.cpp index 3aa8591f9..512be5f4b 100644 --- a/src/sat/dimacs.cpp +++ b/src/sat/dimacs.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"dimacs.h" +#include "sat/dimacs.h" #undef max #undef min -#include"sat_solver.h" +#include "sat/sat_solver.h" class stream_buffer { std::istream & m_stream; diff --git a/src/sat/dimacs.h b/src/sat/dimacs.h index 9d7bb0679..50ebec0c8 100644 --- a/src/sat/dimacs.h +++ b/src/sat/dimacs.h @@ -19,7 +19,7 @@ Revision History: #ifndef DIMACS_H_ #define DIMACS_H_ -#include"sat_types.h" +#include "sat/sat_types.h" void parse_dimacs(std::istream & s, sat::solver & solver); diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index cca0c5c1b..8d5778f0b 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include"sat_asymm_branch.h" -#include"sat_asymm_branch_params.hpp" -#include"sat_solver.h" -#include"stopwatch.h" -#include"trace.h" +#include "sat/sat_asymm_branch.h" +#include "sat/sat_asymm_branch_params.hpp" +#include "sat/sat_solver.h" +#include "util/stopwatch.h" +#include "util/trace.h" namespace sat { diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index 4ad702c5c..9e28d1600 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -19,9 +19,9 @@ Revision History: #ifndef SAT_ASYMM_BRANCH_H_ #define SAT_ASYMM_BRANCH_H_ -#include"sat_types.h" -#include"statistics.h" -#include"params.h" +#include "sat/sat_types.h" +#include "util/statistics.h" +#include "util/params.h" namespace sat { class solver; diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 1efbd6758..c5829ae4e 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -17,9 +17,9 @@ Revision History: --*/ #include -#include"sat_clause.h" -#include"z3_exception.h" -#include"trace.h" +#include "sat/sat_clause.h" +#include "util/z3_exception.h" +#include "util/trace.h" namespace sat { diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 27a0ed739..5ad08e52a 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -19,10 +19,10 @@ Revision History: #ifndef SAT_CLAUSE_H_ #define SAT_CLAUSE_H_ -#include"sat_types.h" -#include"small_object_allocator.h" -#include"id_gen.h" -#include"map.h" +#include "sat/sat_types.h" +#include "util/small_object_allocator.h" +#include "util/id_gen.h" +#include "util/map.h" #ifdef _MSC_VER #pragma warning(disable : 4200) diff --git a/src/sat/sat_clause_set.cpp b/src/sat/sat_clause_set.cpp index 1c424cce3..c223009d6 100644 --- a/src/sat/sat_clause_set.cpp +++ b/src/sat/sat_clause_set.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"sat_clause_set.h" +#include "sat/sat_clause_set.h" namespace sat { diff --git a/src/sat/sat_clause_set.h b/src/sat/sat_clause_set.h index e63c92d08..f9da6a00d 100644 --- a/src/sat/sat_clause_set.h +++ b/src/sat/sat_clause_set.h @@ -19,7 +19,7 @@ Revision History: #ifndef SAT_CLAUSE_SET_H_ #define SAT_CLAUSE_SET_H_ -#include"sat_clause.h" +#include "sat/sat_clause.h" namespace sat { diff --git a/src/sat/sat_clause_use_list.cpp b/src/sat/sat_clause_use_list.cpp index f22e6a822..5ee5b4cda 100644 --- a/src/sat/sat_clause_use_list.cpp +++ b/src/sat/sat_clause_use_list.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"sat_clause.h" -#include"sat_clause_use_list.h" +#include "sat/sat_clause.h" +#include "sat/sat_clause_use_list.h" namespace sat { diff --git a/src/sat/sat_clause_use_list.h b/src/sat/sat_clause_use_list.h index ec283f4c4..121345f21 100644 --- a/src/sat/sat_clause_use_list.h +++ b/src/sat/sat_clause_use_list.h @@ -19,8 +19,8 @@ Revision History: #ifndef SAT_CLAUSE_USE_LIST_H_ #define SAT_CLAUSE_USE_LIST_H_ -#include"sat_types.h" -#include"trace.h" +#include "sat/sat_types.h" +#include "util/trace.h" namespace sat { diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index 959f5e94f..9dd53d8f6 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"sat_cleaner.h" -#include"sat_solver.h" -#include"trace.h" -#include"stopwatch.h" +#include "sat/sat_cleaner.h" +#include "sat/sat_solver.h" +#include "util/trace.h" +#include "util/stopwatch.h" namespace sat { diff --git a/src/sat/sat_cleaner.h b/src/sat/sat_cleaner.h index d886453df..4ffc0be10 100644 --- a/src/sat/sat_cleaner.h +++ b/src/sat/sat_cleaner.h @@ -19,8 +19,8 @@ Revision History: #ifndef SAT_CLEANER_H_ #define SAT_CLEANER_H_ -#include"sat_types.h" -#include"statistics.h" +#include "sat/sat_types.h" +#include "util/statistics.h" namespace sat { diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 9206ea8bc..c67511275 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"sat_config.h" -#include"sat_types.h" -#include"sat_params.hpp" +#include "sat/sat_config.h" +#include "sat/sat_types.h" +#include "sat/sat_params.hpp" namespace sat { @@ -35,7 +35,7 @@ namespace sat { m_glue("glue"), m_glue_psm("glue_psm"), m_psm_glue("psm_glue") { - m_num_parallel = 1; + m_num_parallel = 1; updt_params(p); } @@ -114,6 +114,7 @@ namespace sat { m_core_minimize = p.core_minimize(); m_core_minimize_partial = p.core_minimize_partial(); m_dyn_sub_res = p.dyn_sub_res(); + m_dimacs_display = p.dimacs_display(); } void config::collect_param_descrs(param_descrs & r) { diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 405cbd092..36f22e83f 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -20,7 +20,7 @@ Revision History: #ifndef SAT_CONFIG_H_ #define SAT_CONFIG_H_ -#include"params.h" +#include "util/params.h" namespace sat { @@ -74,6 +74,7 @@ namespace sat { bool m_core_minimize; bool m_core_minimize_partial; + bool m_dimacs_display; symbol m_always_true; symbol m_always_false; diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index b7f83df6c..4cb2fa8ae 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"sat_elim_eqs.h" -#include"sat_solver.h" -#include"trace.h" +#include "sat/sat_elim_eqs.h" +#include "sat/sat_solver.h" +#include "util/trace.h" namespace sat { diff --git a/src/sat/sat_elim_eqs.h b/src/sat/sat_elim_eqs.h index 6f81d6ecb..0422b60df 100644 --- a/src/sat/sat_elim_eqs.h +++ b/src/sat/sat_elim_eqs.h @@ -19,7 +19,7 @@ Revision History: #ifndef SAT_ELIM_EQS_H_ #define SAT_ELIM_EQS_H_ -#include"sat_types.h" +#include "sat/sat_types.h" namespace sat { class solver; diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index b0b1c5d96..80144e00d 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -19,8 +19,8 @@ Revision History: #ifndef SAT_EXTENSION_H_ #define SAT_EXTENSION_H_ -#include"sat_types.h" -#include"params.h" +#include "sat/sat_types.h" +#include "util/params.h" namespace sat { diff --git a/src/sat/sat_iff3_finder.cpp b/src/sat/sat_iff3_finder.cpp index 789f5dec0..e889af164 100644 --- a/src/sat/sat_iff3_finder.cpp +++ b/src/sat/sat_iff3_finder.cpp @@ -29,8 +29,8 @@ Author: Revision History: --*/ -#include"sat_iff3_finder.h" -#include"sat_solver.h" +#include "sat/sat_iff3_finder.h" +#include "sat/sat_solver.h" namespace sat { diff --git a/src/sat/sat_iff3_finder.h b/src/sat/sat_iff3_finder.h index a74ad1eb1..27cd6de05 100644 --- a/src/sat/sat_iff3_finder.h +++ b/src/sat/sat_iff3_finder.h @@ -29,7 +29,7 @@ Revision History: #ifndef SAT_IFF3_FINDER_H_ #define SAT_IFF3_FINDER_H_ -#include"sat_types.h" +#include "sat/sat_types.h" namespace sat { diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index f7cd371f8..08a6072b6 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -17,9 +17,9 @@ Author: Revision History: --*/ -#include"sat_integrity_checker.h" -#include"sat_solver.h" -#include"trace.h" +#include "sat/sat_integrity_checker.h" +#include "sat/sat_solver.h" +#include "util/trace.h" namespace sat { diff --git a/src/sat/sat_integrity_checker.h b/src/sat/sat_integrity_checker.h index 5eef1748e..640fce068 100644 --- a/src/sat/sat_integrity_checker.h +++ b/src/sat/sat_integrity_checker.h @@ -20,7 +20,7 @@ Revision History: #ifndef SAT_INTEGRITY_CHECKER_H_ #define SAT_INTEGRITY_CHECKER_H_ -#include"sat_types.h" +#include "sat/sat_types.h" namespace sat { class integrity_checker { diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 525d084dc..1a881618a 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"sat_model_converter.h" -#include"sat_clause.h" -#include"trace.h" +#include "sat/sat_model_converter.h" +#include "sat/sat_clause.h" +#include "util/trace.h" namespace sat { diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index eb2237707..9a5ebc0ff 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -19,7 +19,7 @@ Revision History: #ifndef SAT_MODEL_CONVERTER_H_ #define SAT_MODEL_CONVERTER_H_ -#include"sat_types.h" +#include "sat/sat_types.h" namespace sat { /** diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 06851d10d..9c455a219 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -18,8 +18,8 @@ Notes: --*/ -#include "sat_solver.h" -#include "sat_mus.h" +#include "sat/sat_solver.h" +#include "sat/sat_mus.h" namespace sat { diff --git a/src/sat/sat_par.cpp b/src/sat/sat_par.cpp index 7a185a3b5..e3d5727ed 100644 --- a/src/sat/sat_par.cpp +++ b/src/sat/sat_par.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include "sat_par.h" +#include "sat/sat_par.h" namespace sat { diff --git a/src/sat/sat_par.h b/src/sat/sat_par.h index 2b2592de7..001036a98 100644 --- a/src/sat/sat_par.h +++ b/src/sat/sat_par.h @@ -19,9 +19,9 @@ Revision History: #ifndef SAT_PAR_H_ #define SAT_PAR_H_ -#include"sat_types.h" -#include"hashtable.h" -#include"map.h" +#include "sat/sat_types.h" +#include "util/hashtable.h" +#include "util/map.h" namespace sat { diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 60708fd5c..2b1dc6646 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -23,4 +23,5 @@ def_module_params('sat', ('core.minimize', BOOL, False, 'minimize computed core'), ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('parallel_threads', UINT, 1, 'number of parallel threads to use'), - ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) + ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), + ('dimacs.display', BOOL, False, 'display SAT instance in DIMACS format and return unknown instead of solving'))) diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index f54ee9f89..b23d57164 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -17,8 +17,8 @@ Author: Revision History: --*/ -#include"sat_probing.h" -#include"sat_solver.h" +#include "sat/sat_probing.h" +#include "sat/sat_solver.h" namespace sat { probing::probing(solver & _s, params_ref const & p): diff --git a/src/sat/sat_probing.h b/src/sat/sat_probing.h index cce165a34..391098ef7 100644 --- a/src/sat/sat_probing.h +++ b/src/sat/sat_probing.h @@ -20,9 +20,9 @@ Revision History: #ifndef SAT_PROBING_H_ #define SAT_PROBING_H_ -#include"sat_types.h" -#include"params.h" -#include"statistics.h" +#include "sat/sat_types.h" +#include "util/params.h" +#include "util/statistics.h" namespace sat { diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index ffbdb31c6..9682da4e8 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -16,12 +16,12 @@ Author: Revision History: --*/ -#include"sat_scc.h" -#include"sat_solver.h" -#include"sat_elim_eqs.h" -#include"stopwatch.h" -#include"trace.h" -#include"sat_scc_params.hpp" +#include "sat/sat_scc.h" +#include "sat/sat_solver.h" +#include "sat/sat_elim_eqs.h" +#include "util/stopwatch.h" +#include "util/trace.h" +#include "sat/sat_scc_params.hpp" namespace sat { diff --git a/src/sat/sat_scc.h b/src/sat/sat_scc.h index f44c39742..c8392685e 100644 --- a/src/sat/sat_scc.h +++ b/src/sat/sat_scc.h @@ -19,9 +19,9 @@ Revision History: #ifndef SAT_SCC_H_ #define SAT_SCC_H_ -#include"sat_types.h" -#include"statistics.h" -#include"params.h" +#include "sat/sat_types.h" +#include "util/statistics.h" +#include "util/params.h" namespace sat { class solver; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 923f5ae49..84534bf3f 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -18,11 +18,11 @@ Author: Revision History: --*/ -#include"sat_simplifier.h" -#include"sat_simplifier_params.hpp" -#include"sat_solver.h" -#include"stopwatch.h" -#include"trace.h" +#include "sat/sat_simplifier.h" +#include "sat/sat_simplifier_params.hpp" +#include "sat/sat_solver.h" +#include "util/stopwatch.h" +#include "util/trace.h" namespace sat { @@ -1311,7 +1311,6 @@ namespace sat { clause_use_list & neg_occs = m_use_list.get(neg_l); unsigned num_pos = pos_occs.size() + num_bin_pos; 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";); @@ -1352,8 +1351,6 @@ namespace sat { collect_clauses(pos_l, m_pos_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";); unsigned before_clauses = num_pos + num_neg; unsigned after_clauses = 0; @@ -1376,7 +1373,7 @@ namespace sat { } } 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 model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index d26d0041f..44e4276e0 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -21,15 +21,15 @@ Revision History: #ifndef SAT_SIMPLIFIER_H_ #define SAT_SIMPLIFIER_H_ -#include"sat_types.h" -#include"sat_clause.h" -#include"sat_clause_set.h" -#include"sat_clause_use_list.h" -#include"sat_watched.h" -#include"sat_model_converter.h" -#include"heap.h" -#include"statistics.h" -#include"params.h" +#include "sat/sat_types.h" +#include "sat/sat_clause.h" +#include "sat/sat_clause_set.h" +#include "sat/sat_clause_use_list.h" +#include "sat/sat_watched.h" +#include "sat/sat_model_converter.h" +#include "util/heap.h" +#include "util/statistics.h" +#include "util/params.h" namespace sat { class solver; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index fbfa0ec6b..03c17aaf0 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include"sat_solver.h" -#include"sat_integrity_checker.h" -#include"luby.h" -#include"trace.h" -#include"max_cliques.h" +#include "sat/sat_solver.h" +#include "sat/sat_integrity_checker.h" +#include "util/luby.h" +#include "util/trace.h" +#include "util/max_cliques.h" // define to update glue during propagation #define UPDATE_GLUE @@ -724,6 +724,13 @@ namespace sat { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(scope_lvl() == 0); + if (m_config.m_dimacs_display) { + display_dimacs(std::cout); + for (unsigned i = 0; i < num_lits; ++i) { + std::cout << dimacs_lit(lits[i]) << " 0\n"; + } + return l_undef; + } if (m_config.m_num_parallel > 1 && !m_par) { return check_par(num_lits, lits); } @@ -1242,10 +1249,7 @@ namespace sat { } void solver::sort_watch_lits() { - vector::iterator it = m_watches.begin(); - vector::iterator end = m_watches.end(); - for (; it != end; ++it) { - watch_list & wlist = *it; + for (watch_list & wlist : m_watches) { std::stable_sort(wlist.begin(), wlist.end(), watched_lt()); } } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index a26abe1e0..c011eb46d 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -19,26 +19,26 @@ Revision History: #ifndef SAT_SOLVER_H_ #define SAT_SOLVER_H_ -#include"sat_types.h" -#include"sat_clause.h" -#include"sat_watched.h" -#include"sat_justification.h" -#include"sat_var_queue.h" -#include"sat_extension.h" -#include"sat_config.h" -#include"sat_cleaner.h" -#include"sat_simplifier.h" -#include"sat_scc.h" -#include"sat_asymm_branch.h" -#include"sat_iff3_finder.h" -#include"sat_probing.h" -#include"sat_mus.h" -#include"sat_par.h" -#include"params.h" -#include"statistics.h" -#include"stopwatch.h" -#include"trace.h" -#include"rlimit.h" +#include "sat/sat_types.h" +#include "sat/sat_clause.h" +#include "sat/sat_watched.h" +#include "sat/sat_justification.h" +#include "sat/sat_var_queue.h" +#include "sat/sat_extension.h" +#include "sat/sat_config.h" +#include "sat/sat_cleaner.h" +#include "sat/sat_simplifier.h" +#include "sat/sat_scc.h" +#include "sat/sat_asymm_branch.h" +#include "sat/sat_iff3_finder.h" +#include "sat/sat_probing.h" +#include "sat/sat_mus.h" +#include "sat/sat_par.h" +#include "util/params.h" +#include "util/statistics.h" +#include "util/stopwatch.h" +#include "util/trace.h" +#include "util/rlimit.h" namespace sat { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index baac9f37b..191c49294 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -17,24 +17,24 @@ Notes: --*/ -#include "solver.h" -#include "tactical.h" -#include "sat_solver.h" -#include "tactic2solver.h" -#include "aig_tactic.h" -#include "propagate_values_tactic.h" -#include "max_bv_sharing_tactic.h" -#include "card2bv_tactic.h" -#include "bit_blaster_tactic.h" -#include "simplify_tactic.h" -#include "goal2sat.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" -#include "filter_model_converter.h" -#include "bit_blaster_model_converter.h" -#include "ast_translation.h" -#include "ast_util.h" -#include "propagate_values_tactic.h" +#include "solver/solver.h" +#include "tactic/tactical.h" +#include "sat/sat_solver.h" +#include "solver/tactic2solver.h" +#include "tactic/aig/aig_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/bv/max_bv_sharing_tactic.h" +#include "tactic/arith/card2bv_tactic.h" +#include "tactic/bv/bit_blaster_tactic.h" +#include "tactic/core/simplify_tactic.h" +#include "sat/tactic/goal2sat.h" +#include "ast/ast_pp.h" +#include "model/model_smt2_pp.h" +#include "tactic/filter_model_converter.h" +#include "tactic/bv/bit_blaster_model_converter.h" +#include "ast/ast_translation.h" +#include "ast/ast_util.h" +#include "tactic/core/propagate_values_tactic.h" // incremental SAT solver. class inc_sat_solver : public solver { @@ -69,7 +69,7 @@ class inc_sat_solver : public solver { public: inc_sat_solver(ast_manager& m, params_ref const& p): m(m), m_solver(p, m.limit(), 0), - m_params(p), m_optimize_model(false), + m_optimize_model(false), m_fmls(m), m_asmsf(m), m_fmls_head(0), @@ -79,7 +79,7 @@ public: m_dep_core(m), m_unknown("no reason given") { m_params.set_bool("elim_vars", false); - m_solver.updt_params(m_params); + updt_params(p); init_preprocess(); } @@ -105,7 +105,6 @@ public: virtual void set_progress_callback(progress_callback * callback) {} - void display_weighted(std::ostream& out, unsigned sz, expr * const * assumptions, unsigned const* weights) { if (weights != 0) { for (unsigned i = 0; i < sz; ++i) m_weights.push_back(weights[i]); @@ -163,6 +162,11 @@ public: if (r != l_true) return r; r = m_solver.check(m_asms.size(), m_asms.c_ptr()); + if (r == l_undef && m_solver.get_config().m_dimacs_display) { + for (auto const& kv : m_map) { + std::cout << "c " << kv.m_value << " " << mk_pp(kv.m_key, m) << "\n"; + } + } switch (r) { case l_true: @@ -233,7 +237,7 @@ public: sat::solver::collect_param_descrs(r); } virtual void updt_params(params_ref const & p) { - m_params = p; + solver::updt_params(p); m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); m_optimize_model = m_params.get_bool("optimize_model", false); @@ -388,6 +392,9 @@ private: m_subgoals.reset(); init_preprocess(); SASSERT(g->models_enabled()); + if (g->proofs_enabled()) { + throw default_exception("generation of proof objects is not supported in this mode"); + } SASSERT(!g->proofs_enabled()); TRACE("sat", g->display(tout);); try { @@ -641,14 +648,12 @@ private: } sat::model const & ll_m = m_solver.get_model(); model_ref md = alloc(model, m); - atom2bool_var::iterator it = m_map.begin(); - atom2bool_var::iterator end = m_map.end(); - for (; it != end; ++it) { - expr * n = it->m_key; + for (auto const& kv : m_map) { + expr * n = kv.m_key; if (is_app(n) && to_app(n)->get_num_args() > 0) { continue; } - sat::bool_var v = it->m_value; + sat::bool_var v = kv.m_value; switch (sat::value_at(v, ll_m)) { case l_true: md->register_decl(to_app(n)->get_decl(), m.mk_true()); diff --git a/src/sat/sat_solver/inc_sat_solver.h b/src/sat/sat_solver/inc_sat_solver.h index 4b0bea50e..658c0583d 100644 --- a/src/sat/sat_solver/inc_sat_solver.h +++ b/src/sat/sat_solver/inc_sat_solver.h @@ -20,7 +20,7 @@ Notes: #ifndef HS_INC_SAT_SOLVER_H_ #define HS_INC_SAT_SOLVER_H_ -#include "solver.h" +#include "solver/solver.h" solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p); diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 28d8d761a..6652fb3b0 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -19,12 +19,12 @@ Revision History: #ifndef SAT_TYPES_H_ #define SAT_TYPES_H_ -#include"debug.h" -#include"approx_set.h" -#include"lbool.h" -#include"z3_exception.h" -#include"common_msgs.h" -#include"vector.h" +#include "util/debug.h" +#include "util/approx_set.h" +#include "util/lbool.h" +#include "util/z3_exception.h" +#include "util/common_msgs.h" +#include "util/vector.h" #include namespace sat { diff --git a/src/sat/sat_var_queue.h b/src/sat/sat_var_queue.h index f008fbb88..a14eb4cff 100644 --- a/src/sat/sat_var_queue.h +++ b/src/sat/sat_var_queue.h @@ -19,8 +19,8 @@ Revision History: #ifndef SAT_VAR_QUEUE_H_ #define SAT_VAR_QUEUE_H_ -#include"heap.h" -#include"sat_types.h" +#include "util/heap.h" +#include "sat/sat_types.h" namespace sat { diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index cc442571c..6335d37fc 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"sat_watched.h" -#include"sat_clause.h" +#include "sat/sat_watched.h" +#include "sat/sat_clause.h" namespace sat { diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index 2c48b6c9b..639d3e6a8 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -19,8 +19,8 @@ Revision History: #ifndef SAT_WATCHED_H_ #define SAT_WATCHED_H_ -#include"sat_types.h" -#include"vector.h" +#include "sat/sat_types.h" +#include "util/vector.h" namespace sat { /** @@ -109,10 +109,10 @@ namespace sat { bool operator!=(watched const & w) const { return !operator==(w); } }; - COMPILE_TIME_ASSERT(0 <= watched::BINARY && watched::BINARY <= 3); - COMPILE_TIME_ASSERT(0 <= watched::TERNARY && watched::TERNARY <= 3); - COMPILE_TIME_ASSERT(0 <= watched::CLAUSE && watched::CLAUSE <= 3); - COMPILE_TIME_ASSERT(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 3); + static_assert(0 <= watched::BINARY && watched::BINARY <= 3, ""); + static_assert(0 <= watched::TERNARY && watched::TERNARY <= 3, ""); + static_assert(0 <= watched::CLAUSE && watched::CLAUSE <= 3, ""); + static_assert(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 3, ""); struct watched_lt { bool operator()(watched const & w1, watched const & w2) const { diff --git a/src/sat/tactic/atom2bool_var.cpp b/src/sat/tactic/atom2bool_var.cpp index 48ad85152..26f3448d3 100644 --- a/src/sat/tactic/atom2bool_var.cpp +++ b/src/sat/tactic/atom2bool_var.cpp @@ -16,10 +16,10 @@ Author: Notes: --*/ -#include"atom2bool_var.h" -#include"ast_smt2_pp.h" -#include"ref_util.h" -#include"goal.h" +#include "sat/tactic/atom2bool_var.h" +#include "ast/ast_smt2_pp.h" +#include "util/ref_util.h" +#include "tactic/goal.h" void atom2bool_var::mk_inv(expr_ref_vector & lit2expr) const { obj_map::iterator it = m_mapping.begin(); diff --git a/src/sat/tactic/atom2bool_var.h b/src/sat/tactic/atom2bool_var.h index 3435a1e2c..d360d3fe0 100644 --- a/src/sat/tactic/atom2bool_var.h +++ b/src/sat/tactic/atom2bool_var.h @@ -19,8 +19,8 @@ Notes: #ifndef ATOM2BOOL_VAR_H_ #define ATOM2BOOL_VAR_H_ -#include"expr2var.h" -#include"sat_types.h" +#include "ast/expr2var.h" +#include "sat/sat_types.h" /** \brief Mapping from atoms into SAT boolean variables. diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 742a4fb1d..1f9dd91d1 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -26,16 +26,16 @@ Author: Notes: --*/ -#include"goal2sat.h" -#include"ast_smt2_pp.h" -#include"ref_util.h" -#include"cooperate.h" -#include"filter_model_converter.h" -#include"model_evaluator.h" -#include"for_each_expr.h" -#include"model_v2_pp.h" -#include"tactic.h" -#include"ast_pp.h" +#include "sat/tactic/goal2sat.h" +#include "ast/ast_smt2_pp.h" +#include "util/ref_util.h" +#include "util/cooperate.h" +#include "tactic/filter_model_converter.h" +#include "model/model_evaluator.h" +#include "ast/for_each_expr.h" +#include "model/model_v2_pp.h" +#include "tactic/tactic.h" +#include "ast/ast_pp.h" #include struct goal2sat::imp { @@ -248,6 +248,7 @@ struct goal2sat::imp { for (unsigned i = 0; i < num; ++i) { m_result_stack[i].neg(); } + mk_clause(m_result_stack.size(), m_result_stack.c_ptr()); } else { for (unsigned i = 0; i < num; ++i) { @@ -278,6 +279,7 @@ struct goal2sat::imp { if (sign) l.neg(); m_result_stack.push_back(l); + TRACE("goal2sat", tout << m_result_stack << "\n";); } } diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index cd63cd497..199d79f9d 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -29,10 +29,10 @@ Notes: #ifndef GOAL2SAT_H_ #define GOAL2SAT_H_ -#include"goal.h" -#include"sat_solver.h" -#include"model_converter.h" -#include"atom2bool_var.h" +#include "tactic/goal.h" +#include "sat/sat_solver.h" +#include "tactic/model_converter.h" +#include "sat/tactic/atom2bool_var.h" class goal2sat { struct imp; diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index f99e46851..4a6171f70 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -16,12 +16,12 @@ Author: Notes: --*/ -#include"tactical.h" -#include"goal2sat.h" -#include"sat_solver.h" -#include"filter_model_converter.h" -#include"ast_smt2_pp.h" -#include"model_v2_pp.h" +#include "ast/ast_pp.h" +#include "tactic/tactical.h" +#include "tactic/filter_model_converter.h" +#include "sat/tactic/goal2sat.h" +#include "sat/sat_solver.h" +#include "model/model_v2_pp.h" class sat_tactic : public tactic { @@ -56,11 +56,9 @@ class sat_tactic : public tactic { sat::literal_vector assumptions; m_goal2sat(*g, m_params, m_solver, map, dep2asm); TRACE("sat_solver_unknown", tout << "interpreted_atoms: " << map.interpreted_atoms() << "\n"; - atom2bool_var::iterator it = map.begin(); - atom2bool_var::iterator end = map.end(); - for (; it != end; ++it) { - if (!is_uninterp_const(it->m_key)) - tout << mk_ismt2_pp(it->m_key, m) << "\n"; + for (auto const& kv : map) { + if (!is_uninterp_const(kv.m_key)) + tout << mk_ismt2_pp(kv.m_key, m) << "\n"; }); g->reset(); g->m().compact_memory(); @@ -70,6 +68,11 @@ class sat_tactic : public tactic { TRACE("sat_dimacs", m_solver.display_dimacs(tout);); dep2assumptions(dep2asm, assumptions); lbool r = m_solver.check(assumptions.size(), assumptions.c_ptr()); + if (r == l_undef && m_solver.get_config().m_dimacs_display) { + for (auto const& kv : map) { + std::cout << "c " << kv.m_value << " " << mk_pp(kv.m_key, g->m()) << "\n"; + } + } if (r == l_false) { expr_dependency * lcore = 0; if (produce_core) { @@ -90,11 +93,9 @@ class sat_tactic : public tactic { model_ref md = alloc(model, m); sat::model const & ll_m = m_solver.get_model(); TRACE("sat_tactic", for (unsigned i = 0; i < ll_m.size(); i++) tout << i << ":" << ll_m[i] << " "; tout << "\n";); - atom2bool_var::iterator it = map.begin(); - atom2bool_var::iterator end = map.end(); - for (; it != end; ++it) { - expr * n = it->m_key; - sat::bool_var v = it->m_value; + for (auto const& kv : map) { + expr * n = kv.m_key; + sat::bool_var v = kv.m_value; TRACE("sat_tactic", tout << "extracting value of " << mk_ismt2_pp(n, m) << "\nvar: " << v << "\n";); switch (sat::value_at(v, ll_m)) { case l_true: @@ -126,17 +127,15 @@ class sat_tactic : public tactic { void dep2assumptions(obj_map& dep2asm, sat::literal_vector& assumptions) { - obj_map::iterator it = dep2asm.begin(), end = dep2asm.end(); - for (; it != end; ++it) { - assumptions.push_back(it->m_value); + for (auto const& kv : dep2asm) { + assumptions.push_back(kv.m_value); } } void mk_asm2dep(obj_map& dep2asm, u_map& lit2asm) { - obj_map::iterator it = dep2asm.begin(), end = dep2asm.end(); - for (; it != end; ++it) { - lit2asm.insert(it->m_value.index(), it->m_key); + for (auto const& kv : dep2asm) { + lit2asm.insert(kv.m_value.index(), kv.m_key); } } }; diff --git a/src/sat/tactic/sat_tactic.h b/src/sat/tactic/sat_tactic.h index 115b01a71..8525f1179 100644 --- a/src/sat/tactic/sat_tactic.h +++ b/src/sat/tactic/sat_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef SAT_TACTIC_H_ #define SAT_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 83b900c5c..b2b181977 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -20,22 +20,22 @@ Revision History: #include #include #include -#include"stopwatch.h" +#include "util/stopwatch.h" #ifdef _CYGWIN #undef min #undef max #endif -#include"smt_params.h" -#include"arith_decl_plugin.h" -#include"dl_compiler.h" -#include"dl_mk_filter_rules.h" -#include"dl_finite_product_relation.h" -#include"dl_context.h" -#include"rel_context.h" -#include"dl_register_engine.h" -#include"datalog_parser.h" -#include"datalog_frontend.h" -#include"timeout.h" +#include "smt/params/smt_params.h" +#include "ast/arith_decl_plugin.h" +#include "muz/rel/dl_compiler.h" +#include "muz/transforms/dl_mk_filter_rules.h" +#include "muz/rel/dl_finite_product_relation.h" +#include "muz/base/dl_context.h" +#include "muz/rel/rel_context.h" +#include "muz/fp/dl_register_engine.h" +#include "muz/fp/datalog_parser.h" +#include "shell/datalog_frontend.h" +#include "util/timeout.h" static stopwatch g_overall_time; static stopwatch g_piece_timer; diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 09645a25a..999574f1e 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -19,11 +19,11 @@ Revision History: #include #include #include -#include"timeout.h" -#include"rlimit.h" -#include"dimacs.h" -#include"sat_solver.h" -#include"gparams.h" +#include "util/timeout.h" +#include "util/rlimit.h" +#include "sat/dimacs.h" +#include "sat/sat_solver.h" +#include "util/gparams.h" extern bool g_display_statistics; static sat::solver * g_solver = 0; diff --git a/src/shell/lp_frontend.cpp b/src/shell/lp_frontend.cpp index 8acbd28ff..95f9e1eb3 100644 --- a/src/shell/lp_frontend.cpp +++ b/src/shell/lp_frontend.cpp @@ -1,23 +1,23 @@ /*++ Copyright (c) 2016 Microsoft Corporation -Author: +Author: Lev Nachmanson 2016-10-27 --*/ -#include "lp_params.hpp" +#include "util/lp/lp_params.hpp" #include "util/lp/lp_settings.h" #include "util/lp/mps_reader.h" -#include "timeout.h" -#include "cancel_eh.h" -#include "scoped_timer.h" -#include "rlimit.h" -#include "gparams.h" +#include "util/timeout.h" +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" +#include "util/rlimit.h" +#include "util/gparams.h" #include -static lean::lp_solver* g_solver = 0; +static lp::lp_solver* g_solver = 0; static void display_statistics() { if (g_solver && g_solver->settings().print_statistics) { @@ -42,7 +42,7 @@ static void on_timeout() { } } -struct front_end_resource_limit : public lean::lp_resource_limit { +struct front_end_resource_limit : public lp::lp_resource_limit { reslimit& m_reslim; front_end_resource_limit(reslimit& lim): @@ -54,7 +54,7 @@ struct front_end_resource_limit : public lean::lp_resource_limit { void run_solver(lp_params & params, char const * mps_file_name) { - reslimit rlim; + reslimit rlim; unsigned timeout = gparams::get().get_uint("timeout", 0); unsigned rlimit = gparams::get().get_uint("rlimit", 0); front_end_resource_limit lp_limit(rlim); @@ -64,14 +64,14 @@ void run_solver(lp_params & params, char const * mps_file_name) { scoped_timer timer(timeout, &eh); std::string fn(mps_file_name); - lean::mps_reader reader(fn); + lp::mps_reader reader(fn); reader.set_message_stream(&std::cout); // can be redirected reader.read(); if (!reader.is_ok()) { std::cerr << "cannot process " << mps_file_name << std::endl; return; } - lean::lp_solver * solver = reader.create_solver(false); // false - to create the primal solver + lp::lp_solver * solver = reader.create_solver(false); // false - to create the primal solver solver->settings().set_resource_limit(lp_limit); g_solver = solver; if (params.min()) { @@ -80,20 +80,20 @@ void run_solver(lp_params & params, char const * mps_file_name) { solver->settings().set_message_ostream(&std::cout); solver->settings().report_frequency = params.rep_freq(); solver->settings().print_statistics = params.print_stats(); - solver->settings().simplex_strategy() = lean:: simplex_strategy_enum::lu; - + solver->settings().simplex_strategy() = lp:: simplex_strategy_enum::lu; + solver->find_maximal_solution(); *(solver->settings().get_message_ostream()) << "status is " << lp_status_to_string(solver->get_status()) << std::endl; - if (solver->get_status() == lean::OPTIMAL) { + if (solver->get_status() == lp::OPTIMAL) { if (params.min()) { solver->flip_costs(); } solver->print_model(std::cout); } - + // #pragma omp critical (g_display_stats) - { + { display_statistics(); register_on_timeout_proc(0); g_solver = 0; diff --git a/src/shell/main.cpp b/src/shell/main.cpp index b29586f8d..3d2609c4f 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -18,24 +18,24 @@ Revision History: --*/ #include -#include"memory_manager.h" -#include"trace.h" -#include"debug.h" -#include"util.h" -#include"pp.h" -#include"smtlib_frontend.h" -#include"z3_log_frontend.h" -#include"warning.h" -#include"version.h" -#include"dimacs_frontend.h" -#include"datalog_frontend.h" -#include"opt_frontend.h" -#include"timeout.h" -#include"z3_exception.h" -#include"error_codes.h" -#include"gparams.h" -#include"env_params.h" -#include "lp_frontend.h" +#include "util/memory_manager.h" +#include "util/trace.h" +#include "util/debug.h" +#include "util/util.h" +#include "ast/pp.h" +#include "shell/smtlib_frontend.h" +#include "shell/z3_log_frontend.h" +#include "util/warning.h" +#include "util/version.h" +#include "shell/dimacs_frontend.h" +#include "shell/datalog_frontend.h" +#include "shell/opt_frontend.h" +#include "util/timeout.h" +#include "util/z3_exception.h" +#include "util/error_codes.h" +#include "util/gparams.h" +#include "util/env_params.h" +#include "shell/lp_frontend.h" typedef enum { IN_UNSPECIFIED, IN_SMTLIB, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_Z3_LOG, IN_MPS } input_kind; diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 278dad287..e1aff8669 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -7,12 +7,12 @@ Copyright (c) 2015 Microsoft Corporation #include #include #include -#include"opt_context.h" -#include"ast_util.h" -#include"arith_decl_plugin.h" -#include"gparams.h" -#include"timeout.h" -#include"reg_decl_plugins.h" +#include "opt/opt_context.h" +#include "ast/ast_util.h" +#include "ast/arith_decl_plugin.h" +#include "util/gparams.h" +#include "util/timeout.h" +#include "ast/reg_decl_plugins.h" extern bool g_display_statistics; static bool g_first_interrupt = true; diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index c9fa69221..666a1e1fe 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -21,17 +21,17 @@ Revision History: #include #include #include -#include"smtlib_solver.h" -#include"timeout.h" -#include"smt2parser.h" -#include"dl_cmds.h" -#include"dbg_cmds.h" -#include"opt_cmds.h" -#include"polynomial_cmds.h" -#include"subpaving_cmds.h" -#include"smt2_extra_cmds.h" -#include"smt_strategic_solver.h" -#include"smt_solver.h" +#include "parsers/smt/smtlib_solver.h" +#include "util/timeout.h" +#include "parsers/smt2/smt2parser.h" +#include "muz/fp/dl_cmds.h" +#include "cmd_context/extra_cmds/dbg_cmds.h" +#include "opt/opt_cmds.h" +#include "cmd_context/extra_cmds/polynomial_cmds.h" +#include "cmd_context/extra_cmds/subpaving_cmds.h" +#include "smt/smt2_extra_cmds.h" +#include "tactic/portfolio/smt_strategic_solver.h" +#include "smt/smt_solver.h" extern bool g_display_statistics; static clock_t g_start_time; diff --git a/src/shell/z3_log_frontend.cpp b/src/shell/z3_log_frontend.cpp index 0b5686c66..4a0ce2c3e 100644 --- a/src/shell/z3_log_frontend.cpp +++ b/src/shell/z3_log_frontend.cpp @@ -20,9 +20,9 @@ Revision History: #include #include #include -#include"util.h" -#include"error_codes.h" -#include"z3_replayer.h" +#include "util/util.h" +#include "util/error_codes.h" +#include "api/z3_replayer.h" static void solve(char const * stream_name, std::istream & in) { clock_t start_time = clock(); diff --git a/src/smt/CMakeLists.txt b/src/smt/CMakeLists.txt index 41890dd05..e102bd28b 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -75,7 +75,7 @@ z3_add_component(smt normal_forms parser_util pattern - proof_checker + proofs proto_model simplex substitution diff --git a/src/smt/arith_eq_adapter.cpp b/src/smt/arith_eq_adapter.cpp index ce831f9ae..307bdc671 100644 --- a/src/smt/arith_eq_adapter.cpp +++ b/src/smt/arith_eq_adapter.cpp @@ -17,13 +17,12 @@ Revision History: --*/ -#include"smt_context.h" -#include"arith_eq_adapter.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"stats.h" -#include"simplifier.h" -#include"ast_smt2_pp.h" +#include "smt/smt_context.h" +#include "smt/arith_eq_adapter.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "util/stats.h" +#include "ast/ast_smt2_pp.h" namespace smt { diff --git a/src/smt/arith_eq_adapter.h b/src/smt/arith_eq_adapter.h index 7e9a645e6..4a8a293e3 100644 --- a/src/smt/arith_eq_adapter.h +++ b/src/smt/arith_eq_adapter.h @@ -19,11 +19,10 @@ Revision History: #ifndef ARITH_EQ_ADAPTER_H_ #define ARITH_EQ_ADAPTER_H_ -#include"smt_theory.h" -#include"obj_pair_hashtable.h" -#include"arith_decl_plugin.h" -#include"statistics.h" -#include"arith_simplifier_plugin.h" +#include "smt/smt_theory.h" +#include "util/obj_pair_hashtable.h" +#include "ast/arith_decl_plugin.h" +#include "util/statistics.h" namespace smt { diff --git a/src/smt/arith_eq_solver.cpp b/src/smt/arith_eq_solver.cpp index de88d37bb..128b35dd1 100644 --- a/src/smt/arith_eq_solver.cpp +++ b/src/smt/arith_eq_solver.cpp @@ -14,7 +14,7 @@ Author: Nikolaj Bjorner (nbjorner) 2012-02-25 --*/ -#include"arith_eq_solver.h" +#include "smt/arith_eq_solver.h" arith_eq_solver::~arith_eq_solver() { diff --git a/src/smt/arith_eq_solver.h b/src/smt/arith_eq_solver.h index 8b7e99fcc..b2db35ee1 100644 --- a/src/smt/arith_eq_solver.h +++ b/src/smt/arith_eq_solver.h @@ -17,8 +17,8 @@ Author: #ifndef ARITH_EQ_SOLVER_H_ #define ARITH_EQ_SOLVER_H_ -#include"arith_decl_plugin.h" -#include"arith_rewriter.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/arith_rewriter.h" /** \brief Simplifier for the arith family. diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 5c7ed33f8..dd92f250a 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -16,66 +16,59 @@ Author: Revision History: --*/ -#include"asserted_formulas.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" -#include"arith_simplifier_plugin.h" -#include"array_simplifier_plugin.h" -#include"datatype_simplifier_plugin.h" -#include"fpa_simplifier_plugin.h" -#include"seq_simplifier_plugin.h" -#include"bv_simplifier_plugin.h" -#include"for_each_expr.h" -#include"well_sorted.h" -#include"pull_quant.h" -#include"pull_ite_tree.h" -#include"push_app_ite.h" -#include"elim_term_ite.h" -#include"pattern_inference.h" -#include"nnf.h" -#include"bv_elim.h" -#include"inj_axiom.h" -#include"der.h" -#include"elim_bounds.h" -#include"warning.h" -#include"bit2int.h" -#include"distribute_forall.h" -#include"quasi_macros.h" +#include "util/warning.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "ast/for_each_expr.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/normal_forms/nnf.h" +#include "ast/pattern/pattern_inference.h" +#include "ast/macros/quasi_macros.h" +#include "smt/asserted_formulas.h" asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p): m(m), m_params(p), - m_pre_simplifier(m), - m_simplifier(m), + m_rewriter(m), + m_substitution(m), + m_scoped_substitution(m_substitution), m_defined_names(m), m_static_features(m), - m_asserted_formulas(m), - m_asserted_formula_prs(m), - m_asserted_qhead(0), - m_macro_manager(m, m_simplifier), - m_bit2int(m), + m_qhead(0), + m_macro_manager(m), m_bv_sharing(m), - m_inconsistent(false){ + m_inconsistent(false), + m_has_quantifiers(false), + m_reduce_asserted_formulas(*this), + m_distribute_forall(*this), + m_pattern_inference(*this), + m_refine_inj_axiom(*this), + m_max_bv_sharing_fn(*this), + m_elim_term_ite(*this), + m_pull_cheap_ite_trees(*this), + m_pull_nested_quantifiers(*this), + m_elim_bvs_from_quantifiers(*this), + m_cheap_quant_fourier_motzkin(*this), + m_apply_bit2int(*this), + m_lift_ite(*this), + m_ng_lift_ite(*this), + m_find_macros(*this), + m_propagate_values(*this), + m_nnf_cnf(*this), + m_apply_quasi_macros(*this) { - m_bsimp = 0; - m_bvsimp = 0; - arith_simplifier_plugin * arith_simp = 0; - setup_simplifier_plugins(m_simplifier, m_bsimp, arith_simp, m_bvsimp); - SASSERT(m_bsimp != 0); - SASSERT(arith_simp != 0); m_macro_finder = alloc(macro_finder, m, m_macro_manager); - basic_simplifier_plugin * basic_simp = 0; - bv_simplifier_plugin * bv_simp = 0; - setup_simplifier_plugins(m_pre_simplifier, basic_simp, arith_simp, bv_simp); - m_bit2int.set_bv_simplifier(bv_simp); - m_pre_simplifier.enable_presimp(); + m_elim_and = true; + set_eliminate_and(false); + } void asserted_formulas::setup() { switch (m_params.m_lift_ite) { case LI_FULL: - m_params.m_ng_lift_ite = LI_NONE; + m_params.m_ng_lift_ite = LI_NONE; break; case LI_CONSERVATIVE: if (m_params.m_ng_lift_ite == LI_CONSERVATIVE) @@ -84,257 +77,237 @@ void asserted_formulas::setup() { default: break; } - + if (m_params.m_relevancy_lvl == 0) m_params.m_relevancy_lemma = false; } -void asserted_formulas::setup_simplifier_plugins(simplifier & s, basic_simplifier_plugin * & bsimp, arith_simplifier_plugin * & asimp, bv_simplifier_plugin * & bvsimp) { - bsimp = alloc(basic_simplifier_plugin, m); - s.register_plugin(bsimp); - asimp = alloc(arith_simplifier_plugin, m, *bsimp, m_params); - s.register_plugin(asimp); - s.register_plugin(alloc(array_simplifier_plugin, m, *bsimp, s, m_params)); - bvsimp = alloc(bv_simplifier_plugin, m, *bsimp, m_params); - s.register_plugin(bvsimp); - s.register_plugin(alloc(datatype_simplifier_plugin, m, *bsimp)); - s.register_plugin(alloc(fpa_simplifier_plugin, m, *bsimp)); - s.register_plugin(alloc(seq_simplifier_plugin, m, *bsimp)); -} - -void asserted_formulas::init(unsigned num_formulas, expr * const * formulas, proof * const * prs) { - SASSERT(m_asserted_formulas.empty()); - SASSERT(m_asserted_formula_prs.empty()); - SASSERT(!m_inconsistent); - SASSERT(m_scopes.empty()); - m_asserted_formulas.append(num_formulas, formulas); - if (m.proofs_enabled()) - m_asserted_formula_prs.append(num_formulas, prs); -} - -bool asserted_formulas::has_bv() const { - // approaximated answer... assume the formula has bit-vectors if the bv_simplifier_plugin was invoked at least once. - return m_bvsimp->reduce_invoked(); -} asserted_formulas::~asserted_formulas() { } -void asserted_formulas::push_assertion(expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) { +void asserted_formulas::push_assertion(expr * e, proof * pr, vector& result) { if (inconsistent()) { - SASSERT(!result.empty()); return; } - if (m.is_false(e)) + expr* e1 = 0; + if (m.is_false(e)) { + result.push_back(justified_expr(m, e, pr)); m_inconsistent = true; - ::push_assertion(m, e, pr, result, result_prs); + } + else if (m.is_true(e)) { + // skip + } + else if (m.is_and(e)) { + for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { + expr* arg = to_app(e)->get_arg(i); + proof_ref _pr(m.proofs_enabled() ? m.mk_and_elim(pr, i) : 0, m); + push_assertion(arg, _pr, result); + } + } + else if (m.is_not(e, e1) && m.is_or(e1)) { + for (unsigned i = 0; i < to_app(e1)->get_num_args(); ++i) { + expr* arg = to_app(e1)->get_arg(i); + proof_ref _pr(m.proofs_enabled() ? m.mk_not_or_elim(pr, i) : 0, m); + expr_ref narg(mk_not(m, arg), m); + push_assertion(narg, _pr, result); + } + } + else { + result.push_back(justified_expr(m, e, pr)); + } } void asserted_formulas::set_eliminate_and(bool flag) { - if (m_bsimp->eliminate_and() == flag) - return; - TRACE("eliminate_and", tout << "flushing cache...\n";); + if (flag == m_elim_and) return; + m_elim_and = flag; + params_ref p; + p.set_bool("pull_cheap_ite", false); + p.set_bool("elim_and", flag); + p.set_bool("arith_ineq_lhs", true); + p.set_bool("sort_sums", true); + p.set_bool("rewrite_patterns", true); + p.set_bool("eq2ineq", m_params.m_arith_eq2ineq); + p.set_bool("gcd_rounding", true); + p.set_bool("expand_select_store", true); + p.set_bool("bv_sort_ac", true); + m_rewriter.updt_params(p); flush_cache(); - m_bsimp->set_eliminate_and(flag); } + void asserted_formulas::assert_expr(expr * e, proof * _in_pr) { - if (inconsistent()) - return; - if (!m_params.m_preprocess) { - push_assertion(e, _in_pr, m_asserted_formulas, m_asserted_formula_prs); + proof_ref in_pr(_in_pr, m), pr(_in_pr, m); + expr_ref r(e, m); + + if (inconsistent()) return; + + if (m_params.m_preprocess) { + TRACE("assert_expr_bug", tout << r << "\n";); + set_eliminate_and(false); // do not eliminate and before nnf. + m_rewriter(e, r, pr); + if (m.proofs_enabled()) { + if (e == r) + pr = in_pr; + else + pr = m.mk_modus_ponens(in_pr, pr); + } + TRACE("assert_expr_bug", tout << "after...\n" << r << "\n";); } - proof_ref in_pr(_in_pr, m); - expr_ref r1(m); - proof_ref pr1(m); - expr_ref r2(m); - proof_ref pr2(m); - TRACE("assert_expr_before_simp", tout << mk_ll_pp(e, m) << "\n";); - TRACE("assert_expr_bug", tout << mk_pp(e, m) << "\n";); - if (m_params.m_pre_simplifier) { - m_pre_simplifier(e, r1, pr1); - } - else { - r1 = e; - pr1 = 0; - } - set_eliminate_and(false); // do not eliminate and before nnf. - m_simplifier(r1, r2, pr2); - TRACE("assert_expr_bug", tout << "after...\n" << mk_pp(r1, m) << "\n";); - if (m.proofs_enabled()) { - if (e == r2) - pr2 = in_pr; - else - pr2 = m.mk_modus_ponens(in_pr, m.mk_transitivity(pr1, pr2)); - } - TRACE("assert_expr_after_simp", tout << mk_ll_pp(r1, m) << "\n";); - push_assertion(r2, pr2, m_asserted_formulas, m_asserted_formula_prs); + + m_has_quantifiers |= ::has_quantifiers(e); + + push_assertion(r, pr, m_formulas); TRACE("asserted_formulas_bug", tout << "after assert_expr\n"; display(tout);); } void asserted_formulas::assert_expr(expr * e) { - if (inconsistent()) - return; - assert_expr(e, m.mk_asserted(e)); + assert_expr(e, m.proofs_enabled() ? m.mk_asserted(e) : nullptr); } -void asserted_formulas::get_assertions(ptr_vector & result) { - result.append(m_asserted_formulas.size(), m_asserted_formulas.c_ptr()); +void asserted_formulas::get_assertions(ptr_vector & result) const { + for (justified_expr const& je : m_formulas) result.push_back(je.get_fml()); } void asserted_formulas::push_scope() { - SASSERT(inconsistent() || m_asserted_qhead == m_asserted_formulas.size() || m.canceled()); - TRACE("asserted_formulas_scopes", tout << "push:\n"; display(tout);); + SASSERT(inconsistent() || m_qhead == m_formulas.size() || m.canceled()); + TRACE("asserted_formulas_scopes", tout << "before push: " << m_scopes.size() << "\n";); + m_scoped_substitution.push(); m_scopes.push_back(scope()); - m_macro_manager.push_scope(); scope & s = m_scopes.back(); - s.m_asserted_formulas_lim = m_asserted_formulas.size(); - SASSERT(inconsistent() || s.m_asserted_formulas_lim == m_asserted_qhead || m.canceled()); - s.m_inconsistent_old = m_inconsistent; + s.m_formulas_lim = m_formulas.size(); + SASSERT(inconsistent() || s.m_formulas_lim == m_qhead || m.canceled()); + s.m_inconsistent_old = m_inconsistent; m_defined_names.push(); m_bv_sharing.push_scope(); + m_macro_manager.push_scope(); commit(); + TRACE("asserted_formulas_scopes", tout << "after push: " << m_scopes.size() << "\n";); } - + void asserted_formulas::pop_scope(unsigned num_scopes) { - TRACE("asserted_formulas_scopes", tout << "before pop " << num_scopes << "\n"; display(tout);); + TRACE("asserted_formulas_scopes", tout << "before pop " << num_scopes << " of " << m_scopes.size() << "\n";); m_bv_sharing.pop_scope(num_scopes); m_macro_manager.pop_scope(num_scopes); unsigned new_lvl = m_scopes.size() - num_scopes; scope & s = m_scopes[new_lvl]; m_inconsistent = s.m_inconsistent_old; m_defined_names.pop(num_scopes); - m_asserted_formulas.shrink(s.m_asserted_formulas_lim); - if (m.proofs_enabled()) - m_asserted_formula_prs.shrink(s.m_asserted_formulas_lim); - m_asserted_qhead = s.m_asserted_formulas_lim; + m_scoped_substitution.pop(num_scopes); + m_formulas.shrink(s.m_formulas_lim); + m_qhead = s.m_formulas_lim; m_scopes.shrink(new_lvl); flush_cache(); - TRACE("asserted_formulas_scopes", tout << "after pop " << num_scopes << "\n"; display(tout);); + TRACE("asserted_formulas_scopes", tout << "after pop " << num_scopes << "\n";); } void asserted_formulas::reset() { m_defined_names.reset(); - m_asserted_qhead = 0; - m_asserted_formulas.reset(); - m_asserted_formula_prs.reset(); + m_qhead = 0; + m_formulas.reset(); m_macro_manager.reset(); m_bv_sharing.reset(); + m_rewriter.reset(); m_inconsistent = false; } - -#ifdef Z3DEBUG bool asserted_formulas::check_well_sorted() const { - for (unsigned i = 0; i < m_asserted_formulas.size(); i++) { - if (!is_well_sorted(m, m_asserted_formulas.get(i))) return false; + for (justified_expr const& je : m_formulas) { + if (!is_well_sorted(m, je.get_fml())) return false; } return true; } -#endif void asserted_formulas::reduce() { - if (inconsistent()) + if (inconsistent()) return; - if (canceled()) { + if (canceled()) return; - } - if (m_asserted_qhead == m_asserted_formulas.size()) + if (m_qhead == m_formulas.size()) return; if (!m_params.m_preprocess) return; - if (m_macro_manager.has_macros()) - expand_macros(); + invoke(m_find_macros); + TRACE("before_reduce", display(tout);); CASSERT("well_sorted", check_well_sorted()); - -#define INVOKE(COND, FUNC) if (COND) { FUNC; IF_VERBOSE(10000, verbose_stream() << "total size: " << get_total_size() << "\n";); } TRACE("reduce_step_ll", ast_mark visited; display_ll(tout, visited);); TRACE("reduce_step", display(tout << #FUNC << " ");); CASSERT("well_sorted",check_well_sorted()); if (inconsistent() || canceled()) { TRACE("after_reduce", display(tout);); TRACE("after_reduce_ll", ast_mark visited; display_ll(tout, visited);); return; } - set_eliminate_and(false); // do not eliminate and before nnf. - INVOKE(m_params.m_propagate_booleans, propagate_booleans()); - INVOKE(m_params.m_propagate_values, propagate_values()); - INVOKE(m_params.m_macro_finder && has_quantifiers(), find_macros()); - INVOKE(m_params.m_nnf_cnf || (m_params.m_mbqi && has_quantifiers()), nnf_cnf()); - INVOKE(m_params.m_eliminate_and, eliminate_and()); - INVOKE(m_params.m_pull_cheap_ite_trees, pull_cheap_ite_trees()); - INVOKE(m_params.m_pull_nested_quantifiers && has_quantifiers(), pull_nested_quantifiers()); - INVOKE(m_params.m_ng_lift_ite != LI_NONE, ng_lift_ite()); - INVOKE(m_params.m_lift_ite != LI_NONE, lift_ite()); - INVOKE(m_params.m_eliminate_term_ite && m_params.m_lift_ite != LI_FULL, eliminate_term_ite()); - INVOKE(m_params.m_refine_inj_axiom && has_quantifiers(), refine_inj_axiom()); - INVOKE(m_params.m_distribute_forall && has_quantifiers(), apply_distribute_forall()); - TRACE("qbv_bug", tout << "after distribute_forall:\n"; display(tout);); - INVOKE(m_params.m_macro_finder && has_quantifiers(), find_macros()); - INVOKE(m_params.m_quasi_macros && has_quantifiers(), apply_quasi_macros()); - INVOKE(m_params.m_simplify_bit2int, apply_bit2int()); - INVOKE(m_params.m_eliminate_bounds && has_quantifiers(), cheap_quant_fourier_motzkin()); - INVOKE(m_params.m_ematching && has_quantifiers(), infer_patterns()); - INVOKE(m_params.m_max_bv_sharing && has_bv(), max_bv_sharing()); - INVOKE(m_params.m_bb_quantifiers, elim_bvs_from_quantifiers()); - // temporary HACK: make sure that arith & bv are list-assoc - // this may destroy some simplification steps such as max_bv_sharing - reduce_asserted_formulas(); - - CASSERT("well_sorted",check_well_sorted()); + if (!invoke(m_propagate_values)) return; + if (!invoke(m_find_macros)) return; + if (!invoke(m_nnf_cnf)) return; + set_eliminate_and(true); + if (!invoke(m_reduce_asserted_formulas)) return; + if (!invoke(m_pull_cheap_ite_trees)) return; + if (!invoke(m_pull_nested_quantifiers)) return; + if (!invoke(m_lift_ite)) return; + if (!invoke(m_ng_lift_ite)) return; + if (!invoke(m_elim_term_ite)) return; + if (!invoke(m_refine_inj_axiom)) return; + if (!invoke(m_distribute_forall)) return; + if (!invoke(m_find_macros)) return; + if (!invoke(m_apply_quasi_macros)) return; + if (!invoke(m_apply_bit2int)) return; + if (!invoke(m_cheap_quant_fourier_motzkin)) return; + if (!invoke(m_pattern_inference)) return; + if (!invoke(m_max_bv_sharing_fn)) return; + if (!invoke(m_elim_bvs_from_quantifiers)) return; + if (!invoke(m_reduce_asserted_formulas)) return; IF_VERBOSE(10, verbose_stream() << "(smt.simplifier-done)\n";); TRACE("after_reduce", display(tout);); TRACE("after_reduce_ll", ast_mark visited; display_ll(tout, visited);); TRACE("macros", m_macro_manager.display(tout);); flush_cache(); + CASSERT("well_sorted",check_well_sorted()); } -void asserted_formulas::eliminate_and() { - IF_IVERBOSE(10, verbose_stream() << "(smt.eliminating-and)\n";); - set_eliminate_and(true); - reduce_asserted_formulas(); - TRACE("after_elim_and", display(tout);); -} unsigned asserted_formulas::get_formulas_last_level() const { if (m_scopes.empty()) { return 0; } else { - return m_scopes.back().m_asserted_formulas_lim; + return m_scopes.back().m_formulas_lim; } } -void asserted_formulas::collect_static_features() { - if (m_params.m_display_features) { - unsigned sz = m_asserted_formulas.size(); - unsigned head = m_asserted_qhead; - while (head < sz) { - expr * f = m_asserted_formulas.get(head); - head++; - m_static_features.collect(f); - } - m_static_features.display_primitive(std::cout); - m_static_features.display(std::cout); +bool asserted_formulas::invoke(simplify_fmls& s) { + if (!s.should_apply()) return true; + IF_VERBOSE(10, verbose_stream() << "(smt." << s.id() << ")\n";); + s(); + IF_VERBOSE(10000, verbose_stream() << "total size: " << get_total_size() << "\n";); + TRACE("reduce_step_ll", ast_mark visited; display_ll(tout, visited);); + CASSERT("well_sorted",check_well_sorted()); + if (inconsistent() || canceled()) { + TRACE("after_reduce", display(tout);); + TRACE("after_reduce_ll", ast_mark visited; display_ll(tout, visited);); + return false; + } + else { + return true; } } void asserted_formulas::display(std::ostream & out) const { out << "asserted formulas:\n"; - for (unsigned i = 0; i < m_asserted_formulas.size(); i++) { - if (i == m_asserted_qhead) + for (unsigned i = 0; i < m_formulas.size(); i++) { + if (i == m_qhead) out << "[HEAD] ==>\n"; - out << mk_pp(m_asserted_formulas.get(i), m) << "\n"; + out << mk_pp(m_formulas[i].get_fml(), m) << "\n"; } out << "inconsistent: " << inconsistent() << "\n"; } void asserted_formulas::display_ll(std::ostream & out, ast_mark & pp_visited) const { - if (!m_asserted_formulas.empty()) { - unsigned sz = m_asserted_formulas.size(); - for (unsigned i = 0; i < sz; i++) - ast_def_ll_pp(out, m, m_asserted_formulas.get(i), pp_visited, true, false); + if (!m_formulas.empty()) { + for (justified_expr const& f : m_formulas) + ast_def_ll_pp(out, m, f.get_fml(), pp_visited, true, false); out << "asserted formulas:\n"; - for (unsigned i = 0; i < sz; i++) - out << "#" << m_asserted_formulas[i]->get_id() << " "; + for (justified_expr const& f : m_formulas) + out << "#" << f.get_fml()->get_id() << " "; out << "\n"; } } @@ -342,109 +315,57 @@ void asserted_formulas::display_ll(std::ostream & out, ast_mark & pp_visited) co void asserted_formulas::collect_statistics(statistics & st) const { } -void asserted_formulas::reduce_asserted_formulas() { - if (inconsistent()) { - return; - } - expr_ref_vector new_exprs(m); - proof_ref_vector new_prs(m); - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); - for (; i < sz && !inconsistent(); i++) { - expr * n = m_asserted_formulas.get(i); - SASSERT(n != 0); - proof * pr = m_asserted_formula_prs.get(i, 0); - expr_ref new_n(m); - proof_ref new_pr(m); - m_simplifier(n, new_n, new_pr); - TRACE("reduce_asserted_formulas", tout << mk_pp(n, m) << " -> " << mk_pp(new_n, m) << "\n";); - if (n == new_n.get()) { - push_assertion(n, pr, new_exprs, new_prs); - } - else { - new_pr = m.mk_modus_ponens(pr, new_pr); - push_assertion(new_n, new_pr, new_exprs, new_prs); - } - if (canceled()) { - return; - } - } - swap_asserted_formulas(new_exprs, new_prs); + +void asserted_formulas::swap_asserted_formulas(vector& formulas) { + SASSERT(!inconsistent() || !formulas.empty()); + m_formulas.shrink(m_qhead); + m_formulas.append(formulas); } -void asserted_formulas::swap_asserted_formulas(expr_ref_vector & new_exprs, proof_ref_vector & new_prs) { - SASSERT(!inconsistent() || !new_exprs.empty()); - m_asserted_formulas.shrink(m_asserted_qhead); - m_asserted_formulas.append(new_exprs); - if (m.proofs_enabled()) { - m_asserted_formula_prs.shrink(m_asserted_qhead); - m_asserted_formula_prs.append(new_prs); - } -} void asserted_formulas::find_macros_core() { - expr_ref_vector new_exprs(m); - proof_ref_vector new_prs(m); - unsigned sz = m_asserted_formulas.size(); - m_macro_finder->operator()(sz - m_asserted_qhead, m_asserted_formulas.c_ptr() + m_asserted_qhead, - m_asserted_formula_prs.c_ptr() + m_asserted_qhead, new_exprs, new_prs); - swap_asserted_formulas(new_exprs, new_prs); + vector new_fmls; + unsigned sz = m_formulas.size(); + (*m_macro_finder)(sz - m_qhead, m_formulas.c_ptr() + m_qhead, new_fmls); + swap_asserted_formulas(new_fmls); reduce_and_solve(); } -void asserted_formulas::find_macros() { - IF_IVERBOSE(10, verbose_stream() << "(smt.find-macros)\n";); - TRACE("before_find_macros", display(tout);); - find_macros_core(); - TRACE("after_find_macros", display(tout);); -} - -void asserted_formulas::expand_macros() { - IF_IVERBOSE(10, verbose_stream() << "(smt.expand-macros)\n";); - find_macros_core(); -} - void asserted_formulas::apply_quasi_macros() { - IF_IVERBOSE(10, verbose_stream() << "(smt.find-quasi-macros)\n";); TRACE("before_quasi_macros", display(tout);); - expr_ref_vector new_exprs(m); - proof_ref_vector new_prs(m); - quasi_macros proc(m, m_macro_manager, m_simplifier); - while (proc(m_asserted_formulas.size() - m_asserted_qhead, - m_asserted_formulas.c_ptr() + m_asserted_qhead, - m_asserted_formula_prs.c_ptr() + m_asserted_qhead, - new_exprs, new_prs)) { - swap_asserted_formulas(new_exprs, new_prs); - new_exprs.reset(); - new_prs.reset(); + vector new_fmls; + quasi_macros proc(m, m_macro_manager); + while (proc(m_formulas.size() - m_qhead, + m_formulas.c_ptr() + m_qhead, + new_fmls)) { + swap_asserted_formulas(new_fmls); + new_fmls.reset(); } TRACE("after_quasi_macros", display(tout);); reduce_and_solve(); } void asserted_formulas::nnf_cnf() { - IF_IVERBOSE(10, verbose_stream() << "(smt.nnf)\n";); nnf apply_nnf(m, m_defined_names); - expr_ref_vector new_exprs(m); - proof_ref_vector new_prs(m); + vector new_fmls; expr_ref_vector push_todo(m); proof_ref_vector push_todo_prs(m); - - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); + + unsigned i = m_qhead; + unsigned sz = m_formulas.size(); TRACE("nnf_bug", tout << "i: " << i << " sz: " << sz << "\n";); for (; i < sz; i++) { - expr * n = m_asserted_formulas.get(i); + expr * n = m_formulas[i].get_fml(); TRACE("nnf_bug", tout << "processing:\n" << mk_pp(n, m) << "\n";); - proof * pr = m_asserted_formula_prs.get(i, 0); + proof * pr = m_formulas[i].get_proof(); expr_ref r1(m); proof_ref pr1(m); - CASSERT("well_sorted",is_well_sorted(m, n)); push_todo.reset(); push_todo_prs.reset(); + CASSERT("well_sorted", is_well_sorted(m, n)); apply_nnf(n, push_todo, push_todo_prs, r1, pr1); CASSERT("well_sorted",is_well_sorted(m, r1)); - pr = m.mk_modus_ponens(pr, pr1); + pr = m.proofs_enabled() ? m.mk_modus_ponens(pr, pr1) : nullptr; push_todo.push_back(r1); push_todo_prs.push_back(pr); @@ -454,416 +375,258 @@ void asserted_formulas::nnf_cnf() { unsigned sz2 = push_todo.size(); for (unsigned k = 0; k < sz2; k++) { expr * n = push_todo.get(k); - proof * pr = 0; - m_simplifier(n, r1, pr1); + pr = 0; + m_rewriter(n, r1, pr1); CASSERT("well_sorted",is_well_sorted(m, r1)); if (canceled()) { return; - } - + } if (m.proofs_enabled()) pr = m.mk_modus_ponens(push_todo_prs.get(k), pr1); - else - pr = 0; - push_assertion(r1, pr, new_exprs, new_prs); + push_assertion(r1, pr, new_fmls); } } - swap_asserted_formulas(new_exprs, new_prs); + swap_asserted_formulas(new_fmls); } -#define MK_SIMPLE_SIMPLIFIER(NAME, FUNCTOR_DEF, LABEL, MSG) \ -void asserted_formulas::NAME() { \ - IF_IVERBOSE(10, verbose_stream() << "(smt." << MSG << ")\n";); \ - TRACE(LABEL, tout << "before:\n"; display(tout);); \ - FUNCTOR_DEF; \ - expr_ref_vector new_exprs(m); \ - proof_ref_vector new_prs(m); \ - unsigned i = m_asserted_qhead; \ - unsigned sz = m_asserted_formulas.size(); \ - for (; i < sz; i++) { \ - expr * n = m_asserted_formulas.get(i); \ - proof * pr = m_asserted_formula_prs.get(i, 0); \ - expr_ref new_n(m); \ - functor(n, new_n); \ - TRACE("simplifier_simple_step", tout << mk_pp(n, m) << "\n" << mk_pp(new_n, m) << "\n";); \ - if (n == new_n.get()) { \ - push_assertion(n, pr, new_exprs, new_prs); \ - } \ - else if (m.proofs_enabled()) { \ - proof_ref new_pr(m); \ - new_pr = m.mk_rewrite_star(n, new_n, 0, 0); \ - new_pr = m.mk_modus_ponens(pr, new_pr); \ - push_assertion(new_n, new_pr, new_exprs, new_prs); \ - } \ - else { \ - push_assertion(new_n, 0, new_exprs, new_prs); \ - } \ - } \ - swap_asserted_formulas(new_exprs, new_prs); \ - TRACE(LABEL, display(tout);); \ - reduce_and_solve(); \ - TRACE(LABEL, display(tout);); \ +void asserted_formulas::simplify_fmls::operator()() { + vector new_fmls; + unsigned sz = af.m_formulas.size(); + for (unsigned i = af.m_qhead; i < sz; i++) { + auto& j = af.m_formulas[i]; + expr_ref result(m); + proof_ref result_pr(m); + simplify(j, result, result_pr); + if (m.proofs_enabled()) { + if (!result_pr) result_pr = m.mk_rewrite(j.get_fml(), result); + result_pr = m.mk_modus_ponens(j.get_proof(), result_pr); + } + if (j.get_fml() == result) { + new_fmls.push_back(j); + } + else { + af.push_assertion(result, result_pr, new_fmls); + } + if (af.canceled()) return; + } + af.swap_asserted_formulas(new_fmls); + TRACE("asserted_formulas", af.display(tout);); + post_op(); } -MK_SIMPLE_SIMPLIFIER(apply_distribute_forall, distribute_forall functor(m), "distribute_forall", "distribute-forall"); void asserted_formulas::reduce_and_solve() { IF_IVERBOSE(10, verbose_stream() << "(smt.reducing)\n";); flush_cache(); // collect garbage - reduce_asserted_formulas(); + m_reduce_asserted_formulas(); } -void asserted_formulas::infer_patterns() { - IF_IVERBOSE(10, verbose_stream() << "(smt.pattern-inference)\n";); - TRACE("before_pattern_inference", display(tout);); - pattern_inference infer(m, m_params); - expr_ref_vector new_exprs(m); - proof_ref_vector new_prs(m); - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); - for (; i < sz; i++) { - expr * n = m_asserted_formulas.get(i); - proof * pr = m_asserted_formula_prs.get(i, 0); - expr_ref new_n(m); - proof_ref new_pr(m); - infer(n, new_n, new_pr); - if (n == new_n.get()) { - push_assertion(n, pr, new_exprs, new_prs); - } - else if (m.proofs_enabled()) { - new_pr = m.mk_modus_ponens(pr, new_pr); - push_assertion(new_n, new_pr, new_exprs, new_prs); - } - else { - push_assertion(new_n, 0, new_exprs, new_prs); - } - } - swap_asserted_formulas(new_exprs, new_prs); - TRACE("after_pattern_inference", display(tout);); -} void asserted_formulas::commit() { - commit(m_asserted_formulas.size()); + commit(m_formulas.size()); } void asserted_formulas::commit(unsigned new_qhead) { - m_macro_manager.mark_forbidden(new_qhead - m_asserted_qhead, m_asserted_formulas.c_ptr() + m_asserted_qhead); - m_asserted_qhead = new_qhead; -} - -void asserted_formulas::eliminate_term_ite() { - IF_IVERBOSE(10, verbose_stream() << "(smt.eliminating-ite-term)\n";); - TRACE("before_elim_term_ite", display(tout);); - elim_term_ite elim(m, m_defined_names); - expr_ref_vector new_exprs(m); - proof_ref_vector new_prs(m); - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); - for (; i < sz; i++) { - expr * n = m_asserted_formulas.get(i); - proof * pr = m_asserted_formula_prs.get(i, 0); - expr_ref new_n(m); - proof_ref new_pr(m); - elim(n, new_exprs, new_prs, new_n, new_pr); - SASSERT(new_n.get() != 0); - DEBUG_CODE({ - for (unsigned i = 0; i < new_exprs.size(); i++) { - SASSERT(new_exprs.get(i) != 0); - } - }); - if (n == new_n.get()) { - push_assertion(n, pr, new_exprs, new_prs); - } - else if (m.proofs_enabled()) { - new_pr = m.mk_modus_ponens(pr, new_pr); - push_assertion(new_n, new_pr, new_exprs, new_prs); - } - else { - push_assertion(new_n, 0, new_exprs, new_prs); - } + m_macro_manager.mark_forbidden(new_qhead - m_qhead, m_formulas.c_ptr() + m_qhead); + m_expr2depth.reset(); + for (unsigned i = m_qhead; i < new_qhead; ++i) { + justified_expr const& j = m_formulas[i]; + update_substitution(j.get_fml(), j.get_proof()); } - swap_asserted_formulas(new_exprs, new_prs); - TRACE("after_elim_term_ite", display(tout);); - reduce_and_solve(); - TRACE("after_elim_term_ite", display(tout);); + m_qhead = new_qhead; } void asserted_formulas::propagate_values() { - IF_IVERBOSE(10, verbose_stream() << "(smt.constant-propagation)\n";); - TRACE("propagate_values", tout << "before:\n"; display(tout);); flush_cache(); - bool found = false; - // Separate the formulas in two sets: C and R - // C is a set which contains formulas of the form - // { x = n }, where x is a variable and n a numeral. - // R contains the rest. - // - // - new_exprs1 is the set C - // - new_exprs2 is the set R - // - // The loop also updates the m_cache. It adds the entries x -> n to it. - expr_ref_vector new_exprs1(m); - proof_ref_vector new_prs1(m); - expr_ref_vector new_exprs2(m); - proof_ref_vector new_prs2(m); - unsigned sz = m_asserted_formulas.size(); - for (unsigned i = 0; i < sz; i++) { - expr_ref n(m_asserted_formulas.get(i), m); - proof_ref pr(m_asserted_formula_prs.get(i, 0), m); - TRACE("simplifier", tout << mk_pp(n, m) << "\n";); - expr* lhs, *rhs; - if (m.is_eq(n, lhs, rhs) && - (m.is_value(lhs) || m.is_value(rhs))) { - if (m.is_value(lhs)) { - std::swap(lhs, rhs); - n = m.mk_eq(lhs, rhs); - pr = m.mk_symmetry(pr); + + unsigned num_prop = 0; + unsigned num_iterations = 0; + while (!inconsistent() && ++num_iterations < 2) { + m_expr2depth.reset(); + m_scoped_substitution.push(); + unsigned prop = num_prop; + TRACE("propagate_values", tout << "before:\n"; display(tout);); + unsigned i = m_qhead; + unsigned sz = m_formulas.size(); + for (; i < sz; i++) { + prop += propagate_values(i); + } + flush_cache(); + m_scoped_substitution.pop(1); + m_expr2depth.reset(); + m_scoped_substitution.push(); + TRACE("propagate_values", tout << "middle:\n"; display(tout);); + i = sz; + while (i > m_qhead) { + --i; + prop += propagate_values(i); + } + m_scoped_substitution.pop(1); + flush_cache(); + TRACE("propagate_values", tout << "after:\n"; display(tout);); + if (num_prop == prop) { + break; + } + num_prop = prop; + } + if (num_prop > 0) + m_reduce_asserted_formulas(); +} + +unsigned asserted_formulas::propagate_values(unsigned i) { + expr_ref n(m_formulas[i].get_fml(), m); + expr_ref new_n(m); + proof_ref new_pr(m); + m_rewriter(n, new_n, new_pr); + if (m.proofs_enabled()) { + proof * pr = m_formulas[i].get_proof(); + new_pr = m.mk_modus_ponens(pr, new_pr); + } + justified_expr j(m, new_n, new_pr); + m_formulas[i] = j; + if (m_formulas[i].get_fml() != new_n) { + std::cout << "NOT updated\n"; + } + if (m.is_false(j.get_fml())) { + m_inconsistent = true; + } + update_substitution(new_n, new_pr); + return n != new_n ? 1 : 0; +} + +void asserted_formulas::update_substitution(expr* n, proof* pr) { + expr* lhs, *rhs, *n1; + if (is_ground(n) && (m.is_eq(n, lhs, rhs) || m.is_iff(n, lhs, rhs))) { + compute_depth(lhs); + compute_depth(rhs); + if (is_gt(lhs, rhs)) { + TRACE("propagate_values", tout << "insert " << mk_pp(lhs, m) << " -> " << mk_pp(rhs, m) << "\n";); + m_scoped_substitution.insert(lhs, rhs, pr); + return; + } + if (is_gt(rhs, lhs)) { + TRACE("propagate_values", tout << "insert " << mk_pp(rhs, m) << " -> " << mk_pp(lhs, m) << "\n";); + m_scoped_substitution.insert(rhs, lhs, m.proofs_enabled() ? m.mk_symmetry(pr) : nullptr); + return; + } + TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";); + } + if (m.is_not(n, n1)) { + m_scoped_substitution.insert(n1, m.mk_false(), m.proofs_enabled() ? m.mk_iff_false(pr) : nullptr); + } + else { + m_scoped_substitution.insert(n, m.mk_true(), m.proofs_enabled() ? m.mk_iff_true(pr) : nullptr); + } +} + +/** + \brief implement a Knuth-Bendix ordering on expressions. +*/ + +bool asserted_formulas::is_gt(expr* lhs, expr* rhs) { + if (lhs == rhs) { + return false; + } + // values are always less in ordering than non-values. + bool v1 = m.is_value(lhs); + bool v2 = m.is_value(rhs); + if (!v1 && v2) { + return true; + } + if (v1 && !v2) { + return false; + } + SASSERT(is_ground(lhs) && is_ground(rhs)); + if (depth(lhs) > depth(rhs)) { + return true; + } + if (depth(lhs) == depth(rhs) && is_app(lhs) && is_app(rhs)) { + app* l = to_app(lhs); + app* r = to_app(rhs); + if (l->get_decl()->get_id() != r->get_decl()->get_id()) { + return l->get_decl()->get_id() > r->get_decl()->get_id(); + } + if (l->get_num_args() != r->get_num_args()) { + return l->get_num_args() > r->get_num_args(); + } + for (unsigned i = 0; i < l->get_num_args(); ++i) { + if (l->get_arg(i) != r->get_arg(i)) { + return is_gt(l->get_arg(i), r->get_arg(i)); } - if (!m.is_value(lhs) && !m_simplifier.is_cached(lhs)) { - if (i >= m_asserted_qhead) { - new_exprs1.push_back(n); - if (m.proofs_enabled()) - new_prs1.push_back(pr); + } + UNREACHABLE(); + } + + return false; +} + +void asserted_formulas::compute_depth(expr* e) { + ptr_vector todo; + todo.push_back(e); + while (!todo.empty()) { + e = todo.back(); + unsigned d = 0; + if (m_expr2depth.contains(e)) { + todo.pop_back(); + continue; + } + if (is_app(e)) { + app* a = to_app(e); + bool visited = true; + for (expr* arg : *a) { + unsigned d1 = 0; + if (m_expr2depth.find(arg, d1)) { + d = std::max(d, d1); } - TRACE("propagate_values", tout << "found:\n" << mk_pp(lhs, m) << "\n->\n" << mk_pp(rhs, m) << "\n"; - if (pr) tout << "proof: " << mk_pp(pr, m) << "\n";); - m_simplifier.cache_result(lhs, rhs, pr); - found = true; + else { + visited = false; + todo.push_back(arg); + } + } + if (!visited) { continue; } } - if (i >= m_asserted_qhead) { - new_exprs2.push_back(n); - if (m.proofs_enabled()) - new_prs2.push_back(pr); - } + todo.pop_back(); + m_expr2depth.insert(e, d + 1); } - TRACE("propagate_values", tout << "found: " << found << "\n";); - // If C is not empty, then reduce R using the updated simplifier cache with entries - // x -> n for each constraint 'x = n' in C. - if (found) { - unsigned sz = new_exprs2.size(); - for (unsigned i = 0; i < sz; i++) { - expr * n = new_exprs2.get(i); - proof * pr = new_prs2.get(i, 0); - expr_ref new_n(m); - proof_ref new_pr(m); - m_simplifier(n, new_n, new_pr); - if (n == new_n.get()) { - push_assertion(n, pr, new_exprs1, new_prs1); - } - else { - new_pr = m.mk_modus_ponens(pr, new_pr); - push_assertion(new_n, new_pr, new_exprs1, new_prs1); - } - } - swap_asserted_formulas(new_exprs1, new_prs1); - // IMPORTANT: the cache MUST be flushed. This guarantees that all entries - // x->n will be removed from m_cache. If we don't do that, the next transformation - // may simplify constraints in C using these entries, and the variables x in C - // will be (silently) eliminated, and models produced by Z3 will not contain them. - flush_cache(); - } - TRACE("propagate_values", tout << "after:\n"; display(tout);); } -void asserted_formulas::propagate_booleans() { - bool cont = true; - bool modified = false; - flush_cache(); - while (cont) { - TRACE("propagate_booleans", tout << "before:\n"; display(tout);); - IF_IVERBOSE(10, verbose_stream() << "(smt.propagate-booleans)\n";); - cont = false; - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); -#define PROCESS() { \ - expr * n = m_asserted_formulas.get(i); \ - proof * pr = m_asserted_formula_prs.get(i, 0); \ - expr_ref new_n(m); \ - proof_ref new_pr(m); \ - m_simplifier(n, new_n, new_pr); \ - m_asserted_formulas.set(i, new_n); \ - if (m.proofs_enabled()) { \ - new_pr = m.mk_modus_ponens(pr, new_pr); \ - m_asserted_formula_prs.set(i, new_pr); \ - } \ - if (n != new_n) { \ - cont = true; \ - modified = true; \ - } \ - if (m.is_not(new_n)) \ - m_simplifier.cache_result(to_app(new_n)->get_arg(0), m.mk_false(), m.mk_iff_false(new_pr)); \ - else \ - m_simplifier.cache_result(new_n, m.mk_true(), m.mk_iff_true(new_pr)); \ - } - for (; i < sz; i++) { - PROCESS(); - } - flush_cache(); - TRACE("propagate_booleans", tout << "middle:\n"; display(tout);); - i = sz; - while (i > m_asserted_qhead) { - --i; - PROCESS(); - } - flush_cache(); - TRACE("propagate_booleans", tout << "after:\n"; display(tout);); - } - if (modified) - reduce_asserted_formulas(); -} - -#define MK_SIMPLIFIER(NAME, FUNCTOR, TAG, MSG, REDUCE) \ - bool asserted_formulas::NAME() { \ - IF_IVERBOSE(10, verbose_stream() << "(smt." << MSG << ")\n";); \ - TRACE(TAG, ast_mark visited; display_ll(tout, visited);); \ - FUNCTOR; \ - bool changed = false; \ - expr_ref_vector new_exprs(m); \ - proof_ref_vector new_prs(m); \ - unsigned i = m_asserted_qhead; \ - unsigned sz = m_asserted_formulas.size(); \ - for (; i < sz; i++) { \ - expr * n = m_asserted_formulas.get(i); \ - proof * pr = m_asserted_formula_prs.get(i, 0); \ - expr_ref new_n(m); \ - proof_ref new_pr(m); \ - functor(n, new_n, new_pr); \ - if (n == new_n.get()) { \ - push_assertion(n, pr, new_exprs, new_prs); \ - } \ - else if (m.proofs_enabled()) { \ - changed = true; \ - if (!new_pr) new_pr = m.mk_rewrite(n, new_n); \ - new_pr = m.mk_modus_ponens(pr, new_pr); \ - push_assertion(new_n, new_pr, new_exprs, new_prs); \ - } \ - else { \ - changed = true; \ - push_assertion(new_n, 0, new_exprs, new_prs); \ - } \ - } \ - swap_asserted_formulas(new_exprs, new_prs); \ - TRACE(TAG, ast_mark visited; display_ll(tout, visited);); \ - if (changed && REDUCE) { \ - reduce_and_solve(); \ - TRACE(TAG, ast_mark visited; display_ll(tout, visited);); \ - } \ - return changed; \ - } - -MK_SIMPLIFIER(pull_cheap_ite_trees, pull_cheap_ite_tree_star functor(m, m_simplifier), "pull_cheap_ite_trees", "pull-cheap-ite-trees", false); - -MK_SIMPLIFIER(pull_nested_quantifiers, pull_nested_quant functor(m), "pull_nested_quantifiers", "pull-nested-quantifiers", false); - proof * asserted_formulas::get_inconsistency_proof() const { if (!inconsistent()) return 0; if (!m.proofs_enabled()) return 0; - unsigned sz = m_asserted_formulas.size(); - for (unsigned i = 0; i < sz; i++) { - expr * f = m_asserted_formulas.get(i); - if (m.is_false(f)) - return m_asserted_formula_prs.get(i); + for (justified_expr const& j : m_formulas) { + if (m.is_false(j.get_fml())) + return j.get_proof(); } UNREACHABLE(); return 0; } -void asserted_formulas::refine_inj_axiom() { - IF_IVERBOSE(10, verbose_stream() << "(smt.refine-injectivity)\n";); - TRACE("inj_axiom", display(tout);); - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); - for (; i < sz; i++) { - expr * n = m_asserted_formulas.get(i); - proof * pr = m_asserted_formula_prs.get(i, 0); - expr_ref new_n(m); - if (is_quantifier(n) && simplify_inj_axiom(m, to_quantifier(n), new_n)) { - TRACE("inj_axiom", tout << "simplifying...\n" << mk_pp(n, m) << "\n" << mk_pp(new_n, m) << "\n";); - m_asserted_formulas.set(i, new_n); - if (m.proofs_enabled()) { - proof_ref new_pr(m); - new_pr = m.mk_rewrite(n, new_n); - new_pr = m.mk_modus_ponens(pr, new_pr); - m_asserted_formula_prs.set(i, new_pr); - } - } +void asserted_formulas::refine_inj_axiom_fn::simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { + expr* f = j.get_fml(); + if (is_quantifier(f) && simplify_inj_axiom(m, to_quantifier(f), n)) { + TRACE("inj_axiom", tout << "simplifying...\n" << mk_pp(f, m) << "\n" << n << "\n";); + } + else { + n = j.get_fml(); } - TRACE("inj_axiom", display(tout);); } -MK_SIMPLIFIER(apply_bit2int, bit2int& functor = m_bit2int, "bit2int", "propagate-bit-vector-over-integers", true); - -MK_SIMPLIFIER(cheap_quant_fourier_motzkin, elim_bounds_star functor(m), "elim_bounds", "cheap-fourier-motzkin", true); - - - -MK_SIMPLIFIER(elim_bvs_from_quantifiers, bv_elim_star functor(m), "bv_elim", "eliminate-bit-vectors-from-quantifiers", true); - -#define LIFT_ITE(NAME, FUNCTOR, MSG) \ - void asserted_formulas::NAME() { \ - IF_IVERBOSE(10, verbose_stream() << "(smt." << MSG << ")\n";); \ - TRACE("lift_ite", display(tout);); \ - FUNCTOR; \ - unsigned i = m_asserted_qhead; \ - unsigned sz = m_asserted_formulas.size(); \ - for (; i < sz; i++) { \ - expr * n = m_asserted_formulas.get(i); \ - proof * pr = m_asserted_formula_prs.get(i, 0); \ - expr_ref new_n(m); \ - proof_ref new_pr(m); \ - functor(n, new_n, new_pr); \ - TRACE("lift_ite_step", tout << mk_pp(n, m) << "\n";); \ - IF_IVERBOSE(10000, verbose_stream() << "lift before: " << get_num_exprs(n) << ", after: " << get_num_exprs(new_n) << "\n";); \ - m_asserted_formulas.set(i, new_n); \ - if (m.proofs_enabled()) { \ - new_pr = m.mk_modus_ponens(pr, new_pr); \ - m_asserted_formula_prs.set(i, new_pr); \ - } \ - } \ - TRACE("lift_ite", display(tout);); \ - reduce_and_solve(); \ - } - -LIFT_ITE(lift_ite, push_app_ite functor(m_simplifier, m_params.m_lift_ite == LI_CONSERVATIVE), "lifting ite"); -LIFT_ITE(ng_lift_ite, ng_push_app_ite functor(m_simplifier, m_params.m_ng_lift_ite == LI_CONSERVATIVE), "lifting ng ite"); unsigned asserted_formulas::get_total_size() const { expr_mark visited; unsigned r = 0; - unsigned sz = m_asserted_formulas.size(); - for (unsigned i = 0; i < sz; i++) - r += get_num_exprs(m_asserted_formulas.get(i), visited); + for (justified_expr const& j : m_formulas) + r += get_num_exprs(j.get_fml(), visited); return r; } -void asserted_formulas::max_bv_sharing() { - IF_IVERBOSE(10, verbose_stream() << "(smt.maximizing-bv-sharing)\n";); - TRACE("bv_sharing", display(tout);); - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); - for (; i < sz; i++) { - expr * n = m_asserted_formulas.get(i); - proof * pr = m_asserted_formula_prs.get(i, 0); - expr_ref new_n(m); - proof_ref new_pr(m); - m_bv_sharing(n, new_n, new_pr); - m_asserted_formulas.set(i, new_n); - if (m.proofs_enabled()) { - new_pr = m.mk_modus_ponens(pr, new_pr); - m_asserted_formula_prs.set(i, new_pr); - } - } - reduce_asserted_formulas(); - TRACE("bv_sharing", display(tout);); - -} - #ifdef Z3DEBUG void pp(asserted_formulas & f) { f.display(std::cout); } #endif + diff --git a/src/smt/asserted_formulas.h b/src/smt/asserted_formulas.h index 6ad36cc70..88c9e13a7 100644 --- a/src/smt/asserted_formulas.h +++ b/src/smt/asserted_formulas.h @@ -19,87 +19,215 @@ Revision History: #ifndef ASSERTED_FORMULAS_H_ #define ASSERTED_FORMULAS_H_ -#include"smt_params.h" -#include"simplifier.h" -#include"basic_simplifier_plugin.h" -#include"static_features.h" -#include"macro_manager.h" -#include"macro_finder.h" -#include"defined_names.h" -#include"maximise_ac_sharing.h" -#include"bit2int.h" -#include"statistics.h" -#include"pattern_inference.h" +#include "util/statistics.h" +#include "ast/static_features.h" +#include "ast/expr_substitution.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/bit2int.h" +#include "ast/rewriter/maximize_ac_sharing.h" +#include "ast/rewriter/distribute_forall.h" +#include "ast/rewriter/pull_ite_tree.h" +#include "ast/rewriter/push_app_ite.h" +#include "ast/rewriter/inj_axiom.h" +#include "ast/rewriter/bv_elim.h" +#include "ast/rewriter/der.h" +#include "ast/rewriter/elim_bounds.h" +#include "ast/macros/macro_manager.h" +#include "ast/macros/macro_finder.h" +#include "ast/normal_forms/defined_names.h" +#include "ast/normal_forms/pull_quant.h" +#include "ast/pattern/pattern_inference.h" +#include "smt/params/smt_params.h" +#include "smt/elim_term_ite.h" -class arith_simplifier_plugin; -class bv_simplifier_plugin; class asserted_formulas { - ast_manager & m; - smt_params & m_params; - simplifier m_pre_simplifier; - simplifier m_simplifier; - basic_simplifier_plugin * m_bsimp; - bv_simplifier_plugin * m_bvsimp; - defined_names m_defined_names; - static_features m_static_features; - expr_ref_vector m_asserted_formulas; // formulas asserted by user - proof_ref_vector m_asserted_formula_prs; // proofs for the asserted formulas. - unsigned m_asserted_qhead; - - macro_manager m_macro_manager; - scoped_ptr m_macro_finder; - bit2int m_bit2int; - - maximise_bv_sharing m_bv_sharing; - + ast_manager & m; + smt_params & m_params; + th_rewriter m_rewriter; + expr_substitution m_substitution; + scoped_expr_substitution m_scoped_substitution; + defined_names m_defined_names; + static_features m_static_features; + vector m_formulas; + unsigned m_qhead; + bool m_elim_and; + macro_manager m_macro_manager; + scoped_ptr m_macro_finder; + maximize_bv_sharing_rw m_bv_sharing; bool m_inconsistent; - + bool m_has_quantifiers; struct scope { - unsigned m_asserted_formulas_lim; + unsigned m_formulas_lim; bool m_inconsistent_old; }; svector m_scopes; + obj_map m_expr2depth; + + class simplify_fmls { + protected: + asserted_formulas& af; + ast_manager& m; + char const* m_id; + public: + simplify_fmls(asserted_formulas& af, char const* id): af(af), m(af.m), m_id(id) {} + char const* id() const { return m_id; } + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) = 0; + virtual bool should_apply() const { return true;} + virtual void post_op() {} + virtual void operator()(); + }; + + class reduce_asserted_formulas_fn : public simplify_fmls { + public: + reduce_asserted_formulas_fn(asserted_formulas& af): simplify_fmls(af, "reduce-asserted") {} + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { af.m_rewriter(j.get_fml(), n, p); } + }; + + class find_macros_fn : public simplify_fmls { + public: + find_macros_fn(asserted_formulas& af): simplify_fmls(af, "find-macros") {} + virtual void operator()() { af.find_macros_core(); } + virtual bool should_apply() const { return af.m_params.m_macro_finder && af.has_quantifiers(); } + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { UNREACHABLE(); } + }; + + class apply_quasi_macros_fn : public simplify_fmls { + public: + apply_quasi_macros_fn(asserted_formulas& af): simplify_fmls(af, "find-quasi-macros") {} + virtual void operator()() { af.apply_quasi_macros(); } + virtual bool should_apply() const { return af.m_params.m_quasi_macros && af.has_quantifiers(); } + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { UNREACHABLE(); } + }; + + class nnf_cnf_fn : public simplify_fmls { + public: + nnf_cnf_fn(asserted_formulas& af): simplify_fmls(af, "nnf-cnf") {} + virtual void operator()() { af.nnf_cnf(); } + virtual bool should_apply() const { return af.m_params.m_nnf_cnf || (af.m_params.m_mbqi && af.has_quantifiers()); } + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { UNREACHABLE(); } + }; + + class propagate_values_fn : public simplify_fmls { + public: + propagate_values_fn(asserted_formulas& af): simplify_fmls(af, "propagate-values") {} + virtual void operator()() { af.propagate_values(); } + virtual bool should_apply() const { return af.m_params.m_propagate_values; } + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { UNREACHABLE(); } + }; + + class distribute_forall_fn : public simplify_fmls { + distribute_forall m_functor; + public: + distribute_forall_fn(asserted_formulas& af): simplify_fmls(af, "distribute-forall"), m_functor(af.m) {} + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { m_functor(j.get_fml(), n); } + virtual bool should_apply() const { return af.m_params.m_distribute_forall && af.has_quantifiers(); } + virtual void post_op() { af.reduce_and_solve(); TRACE("asserted_formulas", af.display(tout);); } + }; + + class pattern_inference_fn : public simplify_fmls { + pattern_inference_rw m_infer; + public: + pattern_inference_fn(asserted_formulas& af): simplify_fmls(af, "pattern-inference"), m_infer(af.m, af.m_params) {} + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { m_infer(j.get_fml(), n, p); } + virtual bool should_apply() const { return af.m_params.m_ematching && af.has_quantifiers(); } + }; + + class refine_inj_axiom_fn : public simplify_fmls { + public: + refine_inj_axiom_fn(asserted_formulas& af): simplify_fmls(af, "refine-injectivity") {} + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p); + virtual bool should_apply() const { return af.m_params.m_refine_inj_axiom && af.has_quantifiers(); } + }; + + class max_bv_sharing_fn : public simplify_fmls { + public: + max_bv_sharing_fn(asserted_formulas& af): simplify_fmls(af, "maximizing-bv-sharing") {} + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { af.m_bv_sharing(j.get_fml(), n, p); } + virtual bool should_apply() const { return af.m_params.m_max_bv_sharing; } + virtual void post_op() { af.m_reduce_asserted_formulas(); } + }; + + class elim_term_ite_fn : public simplify_fmls { + elim_term_ite_rw m_elim; + public: + elim_term_ite_fn(asserted_formulas& af): simplify_fmls(af, "elim-term-ite"), m_elim(af.m, af.m_defined_names) {} + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { m_elim(j.get_fml(), n, p); } + virtual bool should_apply() const { return af.m_params.m_eliminate_term_ite && af.m_params.m_lift_ite != LI_FULL; } + virtual void post_op() { af.m_formulas.append(m_elim.new_defs()); af.reduce_and_solve(); m_elim.reset(); } + }; + +#define MK_SIMPLIFIERA(NAME, FUNCTOR, MSG, APP, ARG, REDUCE) \ + class NAME : public simplify_fmls { \ + FUNCTOR m_functor; \ + public: \ + NAME(asserted_formulas& af):simplify_fmls(af, MSG), m_functor ARG {} \ + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { \ + m_functor(j.get_fml(), n, p); \ + } \ + virtual void post_op() { if (REDUCE) af.reduce_and_solve(); } \ + virtual bool should_apply() const { return APP; } \ + }; \ + +#define MK_SIMPLIFIERF(NAME, FUNCTOR, MSG, APP, REDUCE) MK_SIMPLIFIERA(NAME, FUNCTOR, MSG, APP, (af.m), REDUCE) + + MK_SIMPLIFIERF(pull_cheap_ite_trees, pull_cheap_ite_tree_rw, "pull-cheap-ite-trees", af.m_params.m_pull_cheap_ite_trees, false); + MK_SIMPLIFIERF(pull_nested_quantifiers, pull_nested_quant, "pull-nested-quantifiers", af.m_params.m_pull_nested_quantifiers && af.has_quantifiers(), false); + MK_SIMPLIFIERF(cheap_quant_fourier_motzkin, elim_bounds_rw, "cheap-fourier-motzkin", af.m_params.m_eliminate_bounds && af.has_quantifiers(), true); + MK_SIMPLIFIERF(elim_bvs_from_quantifiers, bv_elim_rw, "eliminate-bit-vectors-from-quantifiers", af.m_params.m_bb_quantifiers, true); + MK_SIMPLIFIERF(apply_bit2int, bit2int, "propagate-bit-vector-over-integers", af.m_params.m_simplify_bit2int, true); + MK_SIMPLIFIERA(lift_ite, push_app_ite_rw, "lift-ite", af.m_params.m_lift_ite != LI_NONE, (af.m, af.m_params.m_lift_ite == LI_CONSERVATIVE), true); + MK_SIMPLIFIERA(ng_lift_ite, ng_push_app_ite_rw, "lift-ite", af.m_params.m_ng_lift_ite != LI_NONE, (af.m, af.m_params.m_ng_lift_ite == LI_CONSERVATIVE), true); + + + reduce_asserted_formulas_fn m_reduce_asserted_formulas; + distribute_forall_fn m_distribute_forall; + pattern_inference_fn m_pattern_inference; + refine_inj_axiom_fn m_refine_inj_axiom; + max_bv_sharing_fn m_max_bv_sharing_fn; + elim_term_ite_fn m_elim_term_ite; + pull_cheap_ite_trees m_pull_cheap_ite_trees; + pull_nested_quantifiers m_pull_nested_quantifiers; + elim_bvs_from_quantifiers m_elim_bvs_from_quantifiers; + cheap_quant_fourier_motzkin m_cheap_quant_fourier_motzkin; + apply_bit2int m_apply_bit2int; + lift_ite m_lift_ite; + ng_lift_ite m_ng_lift_ite; + find_macros_fn m_find_macros; + propagate_values_fn m_propagate_values; + nnf_cnf_fn m_nnf_cnf; + apply_quasi_macros_fn m_apply_quasi_macros; + + bool invoke(simplify_fmls& s); + void swap_asserted_formulas(vector& new_fmls); + void push_assertion(expr * e, proof * pr, vector& result); + bool canceled() { return m.canceled(); } + bool check_well_sorted() const; + unsigned get_total_size() const; - void setup_simplifier_plugins(simplifier & s, basic_simplifier_plugin * & bsimp, arith_simplifier_plugin * & asimp, bv_simplifier_plugin * & bvsimp); - void reduce_asserted_formulas(); - void swap_asserted_formulas(expr_ref_vector & new_exprs, proof_ref_vector & new_prs); void find_macros_core(); - void find_macros(); void expand_macros(); void apply_quasi_macros(); void nnf_cnf(); - void infer_patterns(); - void eliminate_term_ite(); void reduce_and_solve(); - void flush_cache() { m_pre_simplifier.reset(); m_simplifier.reset(); } + void flush_cache() { m_rewriter.reset(); m_rewriter.set_substitution(&m_substitution); } void set_eliminate_and(bool flag); void propagate_values(); - void propagate_booleans(); + unsigned propagate_values(unsigned i); + void update_substitution(expr* n, proof* p); + bool is_gt(expr* lhs, expr* rhs); + void compute_depth(expr* e); + unsigned depth(expr* e) { return m_expr2depth[e]; } bool pull_cheap_ite_trees(); - bool pull_nested_quantifiers(); - void push_assertion(expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs); - void eliminate_and(); - void refine_inj_axiom(); - bool cheap_quant_fourier_motzkin(); - void apply_distribute_forall(); - bool apply_bit2int(); - void lift_ite(); - bool elim_bvs_from_quantifiers(); - void ng_lift_ite(); -#ifdef Z3DEBUG - bool check_well_sorted() const; -#endif - unsigned get_total_size() const; - bool has_bv() const; - void max_bv_sharing(); - bool canceled() { return m.canceled(); } + + void init(unsigned num_formulas, expr * const * formulas, proof * const * prs); public: asserted_formulas(ast_manager & m, smt_params & p); ~asserted_formulas(); + bool has_quantifiers() const { return m_has_quantifiers; } void setup(); void assert_expr(expr * e, proof * in_pr); void assert_expr(expr * e); @@ -109,26 +237,20 @@ public: bool inconsistent() const { return m_inconsistent; } proof * get_inconsistency_proof() const; void reduce(); - unsigned get_num_formulas() const { return m_asserted_formulas.size(); } + unsigned get_num_formulas() const { return m_formulas.size(); } unsigned get_formulas_last_level() const; - unsigned get_qhead() const { return m_asserted_qhead; } + unsigned get_qhead() const { return m_qhead; } void commit(); void commit(unsigned new_qhead); - expr * get_formula(unsigned idx) const { return m_asserted_formulas.get(idx); } - proof * get_formula_proof(unsigned idx) const { return m.proofs_enabled() ? m_asserted_formula_prs.get(idx) : 0; } - expr * const * get_formulas() const { return m_asserted_formulas.c_ptr(); } - proof * const * get_formula_proofs() const { return m_asserted_formula_prs.c_ptr(); } - void init(unsigned num_formulas, expr * const * formulas, proof * const * prs); - void register_simplifier_plugin(simplifier_plugin * p) { m_simplifier.register_plugin(p); } - simplifier & get_simplifier() { return m_simplifier; } - void get_assertions(ptr_vector & result); - bool empty() const { return m_asserted_formulas.empty(); } - void collect_static_features(); + expr * get_formula(unsigned idx) const { return m_formulas[idx].get_fml(); } + proof * get_formula_proof(unsigned idx) const { return m_formulas[idx].get_proof(); } + + th_rewriter & get_rewriter() { return m_rewriter; } + void get_assertions(ptr_vector & result) const; + bool empty() const { return m_formulas.empty(); } void display(std::ostream & out) const; void display_ll(std::ostream & out, ast_mark & pp_visited) const; void collect_statistics(statistics & st) const; - // TODO: improve precision of the following method. - bool has_quantifiers() const { return m_simplifier.visited_quantifier(); /* approximation */ } // ----------------------------------- // @@ -142,6 +264,7 @@ public: quantifier * get_macro_quantifier(func_decl * f) const { return m_macro_manager.get_macro_quantifier(f); } // auxiliary function used to create a logic context based on a model. void insert_macro(func_decl * f, quantifier * m, proof * pr) { m_macro_manager.insert(f, m, pr); } + void insert_macro(func_decl * f, quantifier * m, proof * pr, expr_dependency* dep) { m_macro_manager.insert(f, m, pr, dep); } }; diff --git a/src/smt/cached_var_subst.cpp b/src/smt/cached_var_subst.cpp index c36eb6dd2..7c0997bc5 100644 --- a/src/smt/cached_var_subst.cpp +++ b/src/smt/cached_var_subst.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"cached_var_subst.h" +#include "smt/cached_var_subst.h" bool cached_var_subst::key_eq_proc::operator()(cached_var_subst::key * k1, cached_var_subst::key * k2) const { if (k1->m_qa != k2->m_qa) diff --git a/src/smt/cached_var_subst.h b/src/smt/cached_var_subst.h index f9a08a810..6f39841b6 100644 --- a/src/smt/cached_var_subst.h +++ b/src/smt/cached_var_subst.h @@ -19,9 +19,9 @@ Revision History: #ifndef CACHED_VAR_SUBST_H_ #define CACHED_VAR_SUBST_H_ -#include"var_subst.h" -#include"map.h" -#include"smt_enode.h" +#include "ast/rewriter/var_subst.h" +#include "util/map.h" +#include "smt/smt_enode.h" class cached_var_subst { struct key { diff --git a/src/smt/cost_evaluator.cpp b/src/smt/cost_evaluator.cpp index fe30f9261..94151f2b3 100644 --- a/src/smt/cost_evaluator.cpp +++ b/src/smt/cost_evaluator.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"cost_evaluator.h" -#include"warning.h" +#include "smt/cost_evaluator.h" +#include "util/warning.h" cost_evaluator::cost_evaluator(ast_manager & m): m_manager(m), diff --git a/src/smt/cost_evaluator.h b/src/smt/cost_evaluator.h index e6f7fa6e0..73b307fbe 100644 --- a/src/smt/cost_evaluator.h +++ b/src/smt/cost_evaluator.h @@ -19,8 +19,8 @@ Revision History: #ifndef COST_EVALUATOR_H_ #define COST_EVALUATOR_H_ -#include"ast.h" -#include"arith_decl_plugin.h" +#include "ast/ast.h" +#include "ast/arith_decl_plugin.h" class cost_evaluator { ast_manager & m_manager; diff --git a/src/smt/database.smt b/src/smt/database.smt index 2f5e5e1c9..27955badf 100644 --- a/src/smt/database.smt +++ b/src/smt/database.smt @@ -11,7 +11,7 @@ :formula (forall (a Int) (i Int) (e Int) (= (?select (?store a i e) i) e) :pats { (?store a i e) } - :weight { 0 }) + :weight { 0 }) :formula (forall (a Int) (i Int) (j Int) (e Int) (or (= i j) (= (?select (?store a i e) j) (?select a j))) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index f55945ce4..44e858219 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -19,12 +19,12 @@ Revision History: #ifndef DIFF_LOGIC_H_ #define DIFF_LOGIC_H_ -#include"vector.h" -#include"heap.h" -#include"statistics.h" -#include"trace.h" -#include"warning.h" -#include"uint_set.h" +#include "util/vector.h" +#include "util/heap.h" +#include "util/statistics.h" +#include "util/trace.h" +#include "util/warning.h" +#include "util/uint_set.h" #include typedef int dl_var; @@ -956,8 +956,8 @@ public: } void get_neighbours_undirected(dl_var current, svector & neighbours) { - neighbours.reset(); - edge_id_vector & out_edges = m_out_edges[current]; + neighbours.reset(); + edge_id_vector & out_edges = m_out_edges[current]; typename edge_id_vector::iterator it = out_edges.begin(), end = out_edges.end(); for (; it != end; ++it) { edge_id e_id = *it; @@ -968,7 +968,7 @@ public: } edge_id_vector & in_edges = m_in_edges[current]; typename edge_id_vector::iterator it2 = in_edges.begin(), end2 = in_edges.end(); - for (; it2 != end2; ++it2) { + for (; it2 != end2; ++it2) { edge_id e_id = *it2; edge & e = m_edges[e_id]; SASSERT(e.get_target() == current); @@ -980,19 +980,19 @@ public: void dfs_undirected(dl_var start, svector & threads) { threads.reset(); threads.resize(get_num_nodes()); - uint_set discovered, explored; - svector nodes; + uint_set discovered, explored; + svector nodes; discovered.insert(start); - nodes.push_back(start); - dl_var prev = start; - while(!nodes.empty()) { - dl_var current = nodes.back(); + nodes.push_back(start); + dl_var prev = start; + while(!nodes.empty()) { + dl_var current = nodes.back(); SASSERT(discovered.contains(current) && !explored.contains(current)); - svector neighbours; - get_neighbours_undirected(current, neighbours); + svector neighbours; + get_neighbours_undirected(current, neighbours); SASSERT(!neighbours.empty()); bool found = false; - for (unsigned i = 0; i < neighbours.size(); ++i) { + for (unsigned i = 0; i < neighbours.size(); ++i) { dl_var next = neighbours[i]; DEBUG_CODE( edge_id id; @@ -1002,18 +1002,18 @@ public: threads[prev] = next; prev = next; discovered.insert(next); - nodes.push_back(next); + nodes.push_back(next); found = true; break; } - } + } SASSERT(!nodes.empty()); if (!found) { explored.insert(current); nodes.pop_back(); } - } - threads[prev] = start; + } + threads[prev] = start; } void bfs_undirected(dl_var start, svector & parents, svector & depths) { @@ -1022,31 +1022,31 @@ public: parents[start] = -1; depths.reset(); depths.resize(get_num_nodes()); - uint_set visited; - std::deque nodes; - visited.insert(start); - nodes.push_front(start); - while(!nodes.empty()) { + uint_set visited; + std::deque nodes; + visited.insert(start); + nodes.push_front(start); + while(!nodes.empty()) { dl_var current = nodes.back(); nodes.pop_back(); - SASSERT(visited.contains(current)); + SASSERT(visited.contains(current)); svector neighbours; - get_neighbours_undirected(current, neighbours); + get_neighbours_undirected(current, neighbours); SASSERT(!neighbours.empty()); - for (unsigned i = 0; i < neighbours.size(); ++i) { - dl_var next = neighbours[i]; + for (unsigned i = 0; i < neighbours.size(); ++i) { + dl_var next = neighbours[i]; DEBUG_CODE( edge_id id; SASSERT(get_edge_id(current, next, id) || get_edge_id(next, current, id));); if (!visited.contains(next)) { TRACE("diff_logic", tout << "parents[" << next << "] --> " << current << std::endl;); - parents[next] = current; - depths[next] = depths[current] + 1; - visited.insert(next); - nodes.push_front(next); + parents[next] = current; + depths[next] = depths[current] + 1; + visited.insert(next); + nodes.push_front(next); } - } - } + } + } } template diff --git a/src/smt/dyn_ack.cpp b/src/smt/dyn_ack.cpp index 533d143c3..baa8129bb 100644 --- a/src/smt/dyn_ack.cpp +++ b/src/smt/dyn_ack.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"dyn_ack.h" -#include"ast_pp.h" +#include "smt/smt_context.h" +#include "smt/dyn_ack.h" +#include "ast/ast_pp.h" namespace smt { diff --git a/src/smt/dyn_ack.h b/src/smt/dyn_ack.h index 0c390f0ba..9986dd498 100644 --- a/src/smt/dyn_ack.h +++ b/src/smt/dyn_ack.h @@ -19,12 +19,12 @@ Revision History: #ifndef DYN_ACK_H_ #define DYN_ACK_H_ -#include"ast.h" -#include"dyn_ack_params.h" -#include"obj_hashtable.h" -#include"obj_pair_hashtable.h" -#include"obj_triple_hashtable.h" -#include"smt_clause.h" +#include "ast/ast.h" +#include "smt/params/dyn_ack_params.h" +#include "util/obj_hashtable.h" +#include "util/obj_pair_hashtable.h" +#include "util/obj_triple_hashtable.h" +#include "smt/smt_clause.h" namespace smt { diff --git a/src/smt/elim_term_ite.cpp b/src/smt/elim_term_ite.cpp index 74b804c21..e8b70fc59 100644 --- a/src/smt/elim_term_ite.cpp +++ b/src/smt/elim_term_ite.cpp @@ -16,145 +16,25 @@ Author: Revision History: --*/ -#include"elim_term_ite.h" -#include"ast_smt2_pp.h" +#include "smt/elim_term_ite.h" +#include "ast/ast_smt2_pp.h" -void elim_term_ite::operator()(expr * n, - expr_ref_vector & new_defs, - proof_ref_vector & new_def_proofs, - expr_ref & r, - proof_ref & pr) { - - m_coarse_proofs.reset(); - m_new_defs = &new_defs; - m_new_def_proofs = &new_def_proofs; - reduce_core(n); - expr * r2; - proof * pr2; - get_cached(n, r2, pr2); - r = r2; - switch (m.proof_mode()) { - case PGM_DISABLED: - pr = m.mk_undef_proof(); - break; - case PGM_COARSE: - remove_duplicates(m_coarse_proofs); - pr = n == r2 ? m.mk_oeq_reflexivity(n) : m.mk_apply_defs(n, r, m_coarse_proofs.size(), m_coarse_proofs.c_ptr()); - break; - case PGM_FINE: - pr = pr2 == 0 ? m.mk_oeq_reflexivity(n) : pr2; - break; +br_status elim_term_ite_cfg::reduce_app(func_decl* f, unsigned n, expr * const* args, expr_ref& result, proof_ref& result_pr) { + if (!m.is_term_ite(f)) { + return BR_FAILED; } - m_coarse_proofs.reset(); + + expr_ref new_def(m); + proof_ref new_def_pr(m); + app_ref r(m.mk_app(f, n, args), m); + app_ref new_r(m); + if (!m_defined_names.mk_name(r, new_def, new_def_pr, new_r, result_pr)) { + return BR_FAILED; + } + result = new_r; + + CTRACE("elim_term_ite_bug", new_def.get() == 0, tout << mk_ismt2_pp(r, m) << "\n";); + m_new_defs.push_back(justified_expr(m, new_def, new_def_pr)); + return BR_DONE; } -void elim_term_ite::reduce_core(expr * n) { - m_todo.reset(); - if (!is_cached(n)) { - m_todo.push_back(n); - while (!m_todo.empty()) { - expr * n = m_todo.back(); - if (is_cached(n)) { - m_todo.pop_back(); - } - else if (visit_children(n)) { - m_todo.pop_back(); - reduce1(n); - } - } - } -} - -bool elim_term_ite::visit_children(expr * n) { - bool visited = true; - unsigned j; - switch(n->get_kind()) { - case AST_VAR: - return true; - case AST_APP: - j = to_app(n)->get_num_args(); - while (j > 0) { - --j; - visit(to_app(n)->get_arg(j), visited); - } - return visited; - case AST_QUANTIFIER: - visit(to_quantifier(n)->get_expr(), visited); - return visited; - default: - UNREACHABLE(); - return true; - } -} - -void elim_term_ite::reduce1(expr * n) { - switch (n->get_kind()) { - case AST_VAR: - cache_result(n, n, 0); - break; - case AST_APP: - reduce1_app(to_app(n)); - break; - case AST_QUANTIFIER: - reduce1_quantifier(to_quantifier(n)); - break; - default: - UNREACHABLE(); - } -} - -void elim_term_ite::reduce1_app(app * n) { - m_args.reset(); - - func_decl * decl = n->get_decl(); - proof_ref p1(m); - get_args(n, m_args, p1); - if (!m.fine_grain_proofs()) - p1 = 0; - - expr_ref r(m); - r = m.mk_app(decl, m_args.size(), m_args.c_ptr()); - if (m.is_term_ite(r)) { - expr_ref new_def(m); - proof_ref new_def_pr(m); - app_ref new_r(m); - proof_ref new_pr(m); - if (m_defined_names.mk_name(r, new_def, new_def_pr, new_r, new_pr)) { - CTRACE("elim_term_ite_bug", new_def.get() == 0, tout << mk_ismt2_pp(r, m) << "\n";); - SASSERT(new_def.get() != 0); - m_new_defs->push_back(new_def); - if (m.fine_grain_proofs()) { - m_new_def_proofs->push_back(new_def_pr); - new_pr = m.mk_transitivity(p1, new_pr); - } - else { - // [Leo] This looks fishy... why do we add 0 into m_coarse_proofs when fine_grain_proofs are disabled? - new_pr = 0; - if (m.proofs_enabled()) - m_coarse_proofs.push_back(new_pr); - } - } - else { - SASSERT(new_def.get() == 0); - if (!m.fine_grain_proofs()) - new_pr = 0; - } - cache_result(n, new_r, new_pr); - } - else { - cache_result(n, r, p1); - } -} - -void elim_term_ite::reduce1_quantifier(quantifier * q) { - expr * new_body; - proof * new_body_pr; - get_cached(q->get_expr(), new_body, new_body_pr); - - quantifier * new_q = m.update_quantifier(q, new_body); - proof * p = q == new_q ? 0 : m.mk_oeq_quant_intro(q, new_q, new_body_pr); - cache_result(q, new_q, p); -} - - - diff --git a/src/smt/elim_term_ite.h b/src/smt/elim_term_ite.h index fc682b39a..8e8340dc0 100644 --- a/src/smt/elim_term_ite.h +++ b/src/smt/elim_term_ite.h @@ -19,32 +19,36 @@ Revision History: #ifndef ELIM_TERM_ITE_H_ #define ELIM_TERM_ITE_H_ -#include"simplifier.h" -#include"defined_names.h" +#include "ast/normal_forms/defined_names.h" +#include "ast/rewriter/rewriter.h" +#include "ast/justified_expr.h" -class elim_term_ite : public simplifier { - defined_names & m_defined_names; - proof_ref_vector m_coarse_proofs; - expr_ref_vector * m_new_defs; - proof_ref_vector * m_new_def_proofs; - void reduce_core(expr * n); - bool visit_children(expr * n); - void reduce1(expr * n); - void reduce1_app(app * n); - void reduce1_quantifier(quantifier * q); +class elim_term_ite_cfg : public default_rewriter_cfg { + ast_manager& m; + defined_names & m_defined_names; + vector m_new_defs; public: - elim_term_ite(ast_manager & m, defined_names & d):simplifier(m), m_defined_names(d), m_coarse_proofs(m) { - m_use_oeq = true; - enable_ac_support(false); + elim_term_ite_cfg(ast_manager & m, defined_names & d): m(m), m_defined_names(d) { + // TBD enable_ac_support(false); } - virtual ~elim_term_ite() {} - void operator()(expr * n, // [IN] - expr_ref_vector & new_defs, // [OUT] new definitions - proof_ref_vector & new_def_proofs, // [OUT] proofs of the new definitions - expr_ref & r, // [OUT] resultant expression - proof_ref & pr // [OUT] proof for (~ n r) - ); + virtual ~elim_term_ite_cfg() {} + vector const& new_defs() const { return m_new_defs; } + void reset() { m_new_defs.reset(); } + br_status reduce_app(func_decl* f, unsigned n, expr *const* args, expr_ref& result, proof_ref& result_pr); }; +class elim_term_ite_rw : public rewriter_tpl { + elim_term_ite_cfg m_cfg; +public: + elim_term_ite_rw(ast_manager& m, defined_names & dn): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, dn) + {} + vector const& new_defs() const { return m_cfg.new_defs(); } + void reset() { m_cfg.reset(); } +}; + + + #endif /* ELIM_TERM_ITE_H_ */ diff --git a/src/smt/expr_context_simplifier.cpp b/src/smt/expr_context_simplifier.cpp index 66252c3cf..c420543e1 100644 --- a/src/smt/expr_context_simplifier.cpp +++ b/src/smt/expr_context_simplifier.cpp @@ -17,11 +17,11 @@ Revision History: --*/ -#include "expr_context_simplifier.h" -#include "ast_pp.h" -#include "obj_hashtable.h" -#include "smt_kernel.h" -#include "for_each_expr.h" +#include "smt/expr_context_simplifier.h" +#include "ast/ast_pp.h" +#include "util/obj_hashtable.h" +#include "smt/smt_kernel.h" +#include "ast/for_each_expr.h" // table lookup before/after simplification. diff --git a/src/smt/expr_context_simplifier.h b/src/smt/expr_context_simplifier.h index 7745bffff..b412d8646 100644 --- a/src/smt/expr_context_simplifier.h +++ b/src/smt/expr_context_simplifier.h @@ -19,12 +19,12 @@ Revision History: #ifndef EXPR_CONTEXT_SIMPLIFIER_H_ #define EXPR_CONTEXT_SIMPLIFIER_H_ -#include "ast.h" -#include "obj_hashtable.h" -#include "basic_simplifier_plugin.h" -#include "smt_params.h" -#include "smt_kernel.h" -#include "arith_decl_plugin.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "smt/params/smt_params.h" +#include "smt/smt_kernel.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/bool_rewriter.h" class expr_context_simplifier { typedef obj_map context_map; @@ -33,7 +33,7 @@ class expr_context_simplifier { arith_util m_arith; context_map m_context; expr_ref_vector m_trail; - basic_simplifier_plugin m_simp; + bool_rewriter m_simp; expr_mark m_mark; bool m_forward; public: diff --git a/src/smt/fingerprints.cpp b/src/smt/fingerprints.cpp index 6cb0bfd2a..435350396 100644 --- a/src/smt/fingerprints.cpp +++ b/src/smt/fingerprints.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"fingerprints.h" +#include "smt/fingerprints.h" namespace smt { diff --git a/src/smt/fingerprints.h b/src/smt/fingerprints.h index 80905f8be..fc3259ca7 100644 --- a/src/smt/fingerprints.h +++ b/src/smt/fingerprints.h @@ -19,7 +19,7 @@ Revision History: #ifndef FINGERPRINTS_H_ #define FINGERPRINTS_H_ -#include"smt_enode.h" +#include "smt/smt_enode.h" namespace smt { diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index ba9f970a2..96334e3ce 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -16,14 +16,14 @@ Author: Revision History: --*/ -#include"mam.h" -#include"smt_context.h" -#include"pool.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"trail.h" -#include"stopwatch.h" -#include"ast_smt2_pp.h" +#include "smt/mam.h" +#include "smt/smt_context.h" +#include "util/pool.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "util/trail.h" +#include "util/stopwatch.h" +#include "ast/ast_smt2_pp.h" #include // #define _PROFILE_MAM @@ -34,7 +34,7 @@ Revision History: // send profiling information to stdout #define _PROFILE_MAM_TO_STDOUT // threshold in secs for being considered expensive -#define _PROFILE_MAM_THRESHOLD 30.0 +#define _PROFILE_MAM_THRESHOLD 30.0 // dump expensive (> _PROFILE_MAM_THRESHOLD) code trees whenever execute_core is executed. #define _PROFILE_MAM_EXPENSIVE // @@ -60,7 +60,7 @@ namespace smt { // ------------------------------------ class mam_impl; - + typedef trail_stack mam_trail_stack; typedef trail mam_trail; @@ -70,8 +70,8 @@ namespace smt { public: mam_value_trail(T & value):value_trail(value) {} }; - - + + // ------------------------------------ // // Auxiliary @@ -79,7 +79,7 @@ namespace smt { // ------------------------------------ class label_hasher { svector m_lbl2hash; // cache: lbl_id -> hash - + void mk_lbl_hash(unsigned lbl_id) { unsigned a = 17; unsigned b = 3; @@ -124,19 +124,19 @@ namespace smt { typedef enum { INIT1=0, INIT2, INIT3, INIT4, INIT5, INIT6, INITN, BIND1, BIND2, BIND3, BIND4, BIND5, BIND6, BINDN, - YIELD1, YIELD2, YIELD3, YIELD4, YIELD5, YIELD6, YIELDN, + YIELD1, YIELD2, YIELD3, YIELD4, YIELD5, YIELD6, YIELDN, COMPARE, CHECK, FILTER, CFILTER, PFILTER, CHOOSE, NOOP, CONTINUE, - GET_ENODE, + GET_ENODE, GET_CGR1, GET_CGR2, GET_CGR3, GET_CGR4, GET_CGR5, GET_CGR6, GET_CGRN, IS_CGR } opcode; - + struct instruction { opcode m_opcode; instruction * m_next; #ifdef _PROFILE_MAM unsigned m_counter; // how often it was executed -#endif +#endif bool is_init() const { return m_opcode >= INIT1 && m_opcode <= INITN; } @@ -147,7 +147,7 @@ namespace smt { // operators (e.g., + and *) are represented using n-ary // applications. // We do not need the extra field for INIT1, ..., INIT6. - unsigned m_num_args; + unsigned m_num_args; }; struct compare : public instruction { @@ -162,7 +162,7 @@ namespace smt { struct filter : public instruction { unsigned m_reg; - approx_set m_lbl_set; + approx_set m_lbl_set; }; struct pcheck : public instruction { @@ -211,15 +211,15 @@ namespace smt { approx_set m_lbl_set; // singleton set containing m_label /* The following field is an array of tagged pointers. - Each positon contains: + Each positon contains: 1- null (no joint), NULL_TAG 2- a boxed integer (i.e., register that contains the variable bind) VAR_TAG 3- an enode pointer (ground term) GROUND_TERM_TAG 4- or, a joint2 pointer. NESTED_VAR_TAG - + The size of the array is m_num_args. */ - enode * m_joints[0]; + enode * m_joints[0]; }; struct bind : public instruction { @@ -294,7 +294,7 @@ namespace smt { void display_joints(std::ostream & out, unsigned num_joints, enode * const * joints) { for (unsigned i = 0; i < num_joints; i++) { - if (i > 0) + if (i > 0) out << " "; enode * bare = joints[i]; switch (GET_TAG(bare)) { @@ -307,7 +307,7 @@ namespace smt { } void display_continue(std::ostream & out, const cont & c) { - out << "(CONTINUE " << c.m_label->get_name() << " " << c.m_num_args << " " << c.m_oreg << " " + out << "(CONTINUE " << c.m_label->get_name() << " " << c.m_num_args << " " << c.m_oreg << " " << c.m_lbl_set << " ("; display_joints(out, c.m_num_args, c.m_joints); out << "))"; @@ -317,38 +317,38 @@ namespace smt { out << "(" << op << " " << instr.m_reg << " " << instr.m_lbl_set << ")"; } - + std::ostream & operator<<(std::ostream & out, const instruction & instr) { switch (instr.m_opcode) { - case INIT1: case INIT2: case INIT3: case INIT4: case INIT5: case INIT6: case INITN: + case INIT1: case INIT2: case INIT3: case INIT4: case INIT5: case INIT6: case INITN: out << "(INIT"; - if (instr.m_opcode <= INIT6) + if (instr.m_opcode <= INIT6) out << (instr.m_opcode - INIT1 + 1); else out << "N"; out << ")"; break; - case BIND1: case BIND2: case BIND3: case BIND4: case BIND5: case BIND6: case BINDN: - display_bind(out, static_cast(instr)); + case BIND1: case BIND2: case BIND3: case BIND4: case BIND5: case BIND6: case BINDN: + display_bind(out, static_cast(instr)); break; case GET_CGR1: case GET_CGR2: case GET_CGR3: case GET_CGR4: case GET_CGR5: case GET_CGR6: case GET_CGRN: - display_get_cgr(out, static_cast(instr)); + display_get_cgr(out, static_cast(instr)); break; case IS_CGR: display_is_cgr(out, static_cast(instr)); break; - case YIELD1: case YIELD2: case YIELD3: case YIELD4: case YIELD5: case YIELD6: case YIELDN: - display_yield(out, static_cast(instr)); + case YIELD1: case YIELD2: case YIELD3: case YIELD4: case YIELD5: case YIELD6: case YIELDN: + display_yield(out, static_cast(instr)); break; case CONTINUE: display_continue(out, static_cast(instr)); break; - case COMPARE: - out << "(COMPARE " << static_cast(instr).m_reg1 << " " + case COMPARE: + out << "(COMPARE " << static_cast(instr).m_reg1 << " " << static_cast(instr).m_reg2 << ")"; break; case CHECK: - out << "(CHECK " << static_cast(instr).m_reg + out << "(CHECK " << static_cast(instr).m_reg << " #" << static_cast(instr).m_enode->get_owner_id() << ")"; break; case FILTER: @@ -361,14 +361,14 @@ namespace smt { display_filter(out, "PFILTER", static_cast(instr)); break; case GET_ENODE: - out << "(GET_ENODE " << static_cast(instr).m_oreg << " #" << + out << "(GET_ENODE " << static_cast(instr).m_oreg << " #" << static_cast(instr).m_enode->get_owner_id() << ")"; break; - case CHOOSE: + case CHOOSE: out << "(CHOOSE)"; break; - case NOOP: - out << "(NOOP)"; + case NOOP: + out << "(NOOP)"; break; } #ifdef _PROFILE_MAM @@ -379,7 +379,7 @@ namespace smt { // ------------------------------------ // - // Code Tree + // Code Tree // // ------------------------------------ @@ -404,11 +404,11 @@ namespace smt { unsigned m_num_regs; unsigned m_num_choices; instruction * m_root; - enode_vector m_candidates; + enode_vector m_candidates; #ifdef Z3DEBUG context * m_context; ptr_vector m_patterns; -#endif +#endif #ifdef _PROFILE_MAM stopwatch m_watch; unsigned m_counter; @@ -476,7 +476,7 @@ namespace smt { } } #endif - + public: code_tree(label_hasher & h, func_decl * lbl, unsigned short num_args, bool filter_candidates): m_lbl_hasher(h), @@ -500,8 +500,8 @@ namespace smt { #endif } - stopwatch & get_watch() { - return m_watch; + stopwatch & get_watch() { + return m_watch; } void inc_counter() { @@ -512,7 +512,7 @@ namespace smt { return m_counter; } #endif - + unsigned expected_num_args() const { return m_num_args; } @@ -532,7 +532,7 @@ namespace smt { bool filter_candidates() const { return m_filter_candidates != 0; } - + const instruction * get_root() const { return m_root; } @@ -558,7 +558,7 @@ namespace smt { SASSERT(m_context == 0); m_context = ctx; } - + ptr_vector & get_patterns() { return m_patterns; } @@ -614,7 +614,7 @@ namespace smt { return r; } - instruction * mk_init(unsigned n) { + instruction * mk_init(unsigned n) { SASSERT(n >= 1); opcode op = n <= 6 ? static_cast(INIT1 + n - 1) : INITN; if (op == INITN) { @@ -637,7 +637,7 @@ namespace smt { m_trail_stack(s), m_region(s.get_region()) { } - + code_tree * mk_code_tree(func_decl * lbl, unsigned short num_args, bool filter_candidates) { code_tree * r = alloc(code_tree,m_lbl_hasher, lbl, num_args, filter_candidates); r->m_root = mk_init(num_args); @@ -648,22 +648,22 @@ namespace smt { return new (m_region) joint2(f, pos, reg); } - compare * mk_compare(unsigned reg1, unsigned reg2) { - compare * r = mk_instr(COMPARE, sizeof(compare)); + compare * mk_compare(unsigned reg1, unsigned reg2) { + compare * r = mk_instr(COMPARE, sizeof(compare)); r->m_reg1 = reg1; r->m_reg2 = reg2; return r; } - - check * mk_check(unsigned reg, enode * n) { - check * r = mk_instr(CHECK, sizeof(check)); + + check * mk_check(unsigned reg, enode * n) { + check * r = mk_instr(CHECK, sizeof(check)); r->m_reg = reg; r->m_enode = n; return r; } filter * mk_filter_core(opcode op, unsigned reg, approx_set s) { - filter * r = mk_instr(op, sizeof(filter)); + filter * r = mk_instr(op, sizeof(filter)); r->m_reg = reg; r->m_lbl_set = s; return r; @@ -744,7 +744,7 @@ namespace smt { return y; } - cont * mk_cont(func_decl * lbl, unsigned short num_args, unsigned oreg, + cont * mk_cont(func_decl * lbl, unsigned short num_args, unsigned oreg, approx_set const & s, enode * const * joints) { SASSERT(num_args >= 1); cont * r = mk_instr(CONTINUE, sizeof(cont) + num_args * sizeof(enode*)); @@ -764,11 +764,11 @@ namespace smt { void save_num_regs(code_tree * tree) { m_trail_stack.push(mam_value_trail(tree->m_num_regs)); } - + void save_num_choices(code_tree * tree) { m_trail_stack.push(mam_value_trail(tree->m_num_choices)); } - + void insert_new_lbl_hash(filter * instr, unsigned h) { m_trail_stack.push(mam_value_trail(instr->m_lbl_set)); instr->m_lbl_set.insert(h); @@ -795,18 +795,18 @@ namespace smt { app * m_mp; code_tree * m_tree; unsigned m_num_choices; - bool m_is_tmp_tree; + bool m_is_tmp_tree; svector m_mp_already_processed; obj_map m_matched_exprs; - + struct pcheck_checked { func_decl * m_label; enode * m_enode; }; - - typedef enum { NOT_CHECKED, - CHECK_SET, + + typedef enum { NOT_CHECKED, + CHECK_SET, CHECK_SINGLETON } check_mark; svector m_mark; @@ -827,7 +827,7 @@ namespace smt { void set_check_mark(unsigned reg, check_mark m) { m_mark.setx(reg, m, NOT_CHECKED); } - + void init(code_tree * t, quantifier * qa, app * mp, unsigned first_idx) { SASSERT(m_ast_manager.is_pattern(mp)); #ifdef Z3DEBUG @@ -843,7 +843,7 @@ namespace smt { m_num_choices = 0; m_todo.reset(); m_registers.fill(0); - + app * p = to_app(mp->get_arg(first_idx)); SASSERT(t->get_root_lbl() == p->get_decl()); unsigned num_args = p->get_num_args(); @@ -861,7 +861,7 @@ namespace smt { } /** - \brief Return true if all arguments of n are bound variables. + \brief Return true if all arguments of n are bound variables. That is, during execution time, the variables will be already bound */ bool all_args_are_bound_vars(app * n) { @@ -877,7 +877,7 @@ namespace smt { } /** - \see get_stats + \see get_stats */ void get_stats_core(app * n, unsigned & sz, unsigned & num_unbound_vars) { sz++; @@ -912,7 +912,7 @@ namespace smt { /** \brief Process registers in m_todo. The registers in m_todo that produce non-BIND operations are processed first. Then, - a single BIND operation b is produced. + a single BIND operation b is produced. After executing this method m_todo will contain the registers in m_todo that produce BIND operations and were @@ -942,7 +942,7 @@ namespace smt { m_vars[var_id] = reg; continue; } - + SASSERT(is_app(p)); if (to_app(p)->is_ground()) { @@ -988,7 +988,7 @@ namespace smt { // change the first_app m_aux.push_back(first_app_reg); first_app = to_app(p); - first_app_reg = reg; + first_app_reg = reg; first_app_sz = sz; first_app_num_unbound_vars = num_unbound_vars; } @@ -1000,7 +1000,7 @@ namespace smt { } else { first_app = to_app(p); - first_app_reg = reg; + first_app_reg = reg; get_stats(first_app, first_app_sz, first_app_num_unbound_vars); } } @@ -1069,7 +1069,7 @@ namespace smt { has_unbound_vars = false; return get_num_bound_vars_core(n, has_unbound_vars); } - + /** \brief Compile a pattern where all free variables are already bound. Return the register where the enode congruent to f will be stored. @@ -1141,7 +1141,7 @@ namespace smt { approx_set s; if (m_use_filters) s.insert(m_lbl_hasher(lbl)); - + if (found_bounded_mp) { gen_mp_filter(p); } @@ -1156,17 +1156,17 @@ namespace smt { SASSERT(!is_quantifier(curr)); set_register(oreg + j, curr); m_todo.push_back(oreg + j); - + if ((is_var(curr) && m_vars[to_var(curr)->get_idx()] >= 0) || (is_app(curr) && (to_app(curr)->is_ground()))) has_depth1_joint = true; } - + if (has_depth1_joint) { for (unsigned j = 0; j < num_args; j++) { expr * curr = p->get_arg(j); - + if (is_var(curr)) { unsigned var_id = to_var(curr)->get_idx(); if (m_vars[var_id] >= 0) @@ -1175,15 +1175,15 @@ namespace smt { joints.push_back(NULL_TAG); continue; } - + SASSERT(is_app(curr)); - + if (to_app(curr)->is_ground()) { enode * e = mk_enode(m_context, m_qa, to_app(curr)); joints.push_back(TAG(enode *, e, GROUND_TERM_TAG)); continue; } - + joints.push_back(0); } } @@ -1236,7 +1236,7 @@ namespace smt { m_mp_already_processed[first_idx] = true; linearise_multi_pattern(first_idx); } - + #ifdef Z3DEBUG for (unsigned i = 0; i < m_qa->get_num_decls(); i++) { CTRACE("mam_new_bug", m_vars[i] < 0, tout << mk_ismt2_pp(m_qa, m_ast_manager) << "\ni: " << i << " m_vars[i]: " << m_vars[i] << "\n"; @@ -1248,7 +1248,7 @@ namespace smt { #endif SASSERT(head->m_next == 0); m_seq.push_back(m_ct_manager.mk_yield(m_qa, m_mp, m_qa->get_num_decls(), reinterpret_cast(m_vars.begin()))); - + ptr_vector::iterator it = m_seq.begin(); ptr_vector::iterator end = m_seq.end(); for (; it != end; ++it) { @@ -1268,7 +1268,7 @@ namespace smt { /* The nodes in the bottom of the code-tree can have a lot of children in big examples. Example: - parent-node: + parent-node: (CHOOSE) (CHECK #1 10) (YIELD ...) (CHOOSE) (CHECK #2 10) (YIELD ...) (CHOOSE) (CHECK #3 10) (YIELD ...) @@ -1277,9 +1277,9 @@ namespace smt { (CHOOSE) (CHECK #6 10) (YIELD ...) (CHOOSE) (CHECK #7 10) (YIELD ...) (CHOOSE) (CHECK #8 10) (YIELD ...) - ... + ... The method find_best_child will traverse this big list, and usually will not find - a compatible child. So, I limit the number of simple code sequences that can be + a compatible child. So, I limit the number of simple code sequences that can be traversed. */ #define FIND_BEST_CHILD_THRESHOLD 64 @@ -1305,11 +1305,11 @@ namespace smt { } return best_child; } - + bool is_compatible(bind * instr) const { unsigned ireg = instr->m_ireg; expr * n = m_registers[ireg]; - return + return n != 0 && is_app(n) && // It is wasteful to use a bind of a ground term. @@ -1318,15 +1318,15 @@ namespace smt { to_app(n)->get_decl() == instr->m_label && to_app(n)->get_num_args() == instr->m_num_args; } - + bool is_compatible(compare * instr) const { unsigned reg1 = instr->m_reg1; unsigned reg2 = instr->m_reg2; - return + return m_registers[reg1] != 0 && m_registers[reg1] == m_registers[reg2]; } - + bool is_compatible(check * instr) const { unsigned reg = instr->m_reg; enode * n = instr->m_enode; @@ -1366,25 +1366,25 @@ namespace smt { } /** - \brief We say a check operation is semi compatible if + \brief We say a check operation is semi compatible if it access a register that was not yet processed, and given reg = instr->m_reg 1- is_ground(m_registers[reg]) 2- get_pat_lbl_hash(reg) == m_enode->get_lbl_hash() - + If that is the case, then a CFILTER is created */ bool is_semi_compatible(check * instr) const { unsigned reg = instr->m_reg; - return + return m_registers[reg] != 0 && // if the register was already checked by another filter, then it doesn't make sense // to check it again. - get_check_mark(reg) == NOT_CHECKED && - is_ground(m_registers[reg]) && + get_check_mark(reg) == NOT_CHECKED && + is_ground(m_registers[reg]) && get_pat_lbl_hash(reg) == instr->m_enode->get_lbl_hash(); } - + /** \brief FILTER is not compatible with ground terms anymore. See CFILTER is the filter used for ground terms. @@ -1411,20 +1411,20 @@ namespace smt { } return false; } - + /** \brief See comments at is_semi_compatible(check * instr) and is_compatible(filter * instr). Remark: FILTER is not compatible with ground terms anymore */ bool is_semi_compatible(filter * instr) const { unsigned reg = instr->m_reg; - return + return m_registers[reg] != 0 && get_check_mark(reg) == NOT_CHECKED && is_app(m_registers[reg]) && !is_ground(m_registers[reg]); } - + bool is_compatible(cont * instr) const { unsigned oreg = instr->m_oreg; for (unsigned i = 0; i < instr->m_num_args; i++) @@ -1441,7 +1441,7 @@ namespace smt { many operations in the branch starting at child are compatible with the patterns in the registers stored in m_todo. - Set simple to true, if the tree starting at child is too simple + Set simple to true, if the tree starting at child is too simple (no branching and less than SIMPLE_SEQ_THRESHOLD instructions) */ unsigned get_compatibility_measure(choose * child, bool & simple) { @@ -1453,7 +1453,7 @@ namespace smt { while (curr != 0 && curr->m_opcode != CHOOSE && curr->m_opcode != NOOP) { num_instr++; switch (curr->m_opcode) { - case BIND1: case BIND2: case BIND3: case BIND4: case BIND5: case BIND6: case BINDN: + case BIND1: case BIND2: case BIND3: case BIND4: case BIND5: case BIND6: case BINDN: if (is_compatible(static_cast(curr))) { weight += 4; // the weight of BIND is bigger than COMPARE and CHECK unsigned ireg = static_cast(curr)->m_ireg; @@ -1512,7 +1512,7 @@ namespace smt { while (curr != 0 && curr->m_opcode != CHOOSE && curr->m_opcode != NOOP) { TRACE("mam_compiler_detail", tout << "processing instr: " << *curr << "\n";); switch (curr->m_opcode) { - case BIND1: case BIND2: case BIND3: case BIND4: case BIND5: case BIND6: case BINDN: + case BIND1: case BIND2: case BIND3: case BIND4: case BIND5: case BIND6: case BINDN: if (is_compatible(static_cast(curr))) { TRACE("mam_compiler_detail", tout << "compatible\n";); unsigned ireg = static_cast(curr)->m_ireg; @@ -1613,7 +1613,7 @@ namespace smt { TRACE("mam_compiler_detail", tout << "compatible\n";); unsigned reg = static_cast(curr)->m_reg; CTRACE("mam_compiler_bug", !m_todo.contains(reg), { - for (unsigned i = 0; i < m_todo.size(); i++) { tout << m_todo[i] << " "; } + for (unsigned i = 0; i < m_todo.size(); i++) { tout << m_todo[i] << " "; } tout << "\nregisters:\n"; for (unsigned i = 0; i < m_registers.size(); i++) { if (m_registers[i]) { tout << i << ":\n" << mk_pp(m_registers[i], m_ast_manager) << "\n"; } } tout << "quantifier:\n" << mk_pp(m_qa, m_ast_manager) << "\n"; @@ -1630,7 +1630,7 @@ namespace smt { TRACE("mam_compiler_detail", tout << "semi compatible\n";); unsigned reg = static_cast(curr)->m_reg; CTRACE("mam_compiler_bug", !m_todo.contains(reg), { - for (unsigned i = 0; i < m_todo.size(); i++) { tout << m_todo[i] << " "; } + for (unsigned i = 0; i < m_todo.size(); i++) { tout << m_todo[i] << " "; } tout << "\nregisters:\n"; for (unsigned i = 0; i < m_registers.size(); i++) { if (m_registers[i]) { tout << i << ":\n" << mk_pp(m_registers[i], m_ast_manager) << "\n"; } } tout << "quantifier:\n" << mk_pp(m_qa, m_ast_manager) << "\n"; @@ -1638,7 +1638,7 @@ namespace smt { }); SASSERT(m_todo.contains(reg)); unsigned h = get_pat_lbl_hash(reg); - TRACE("mam_lbl_bug", + TRACE("mam_lbl_bug", tout << "curr_set: " << static_cast(curr)->m_lbl_set << "\n"; tout << "new hash: " << h << "\n";); set_check_mark(reg, CHECK_SET); @@ -1650,7 +1650,7 @@ namespace smt { else { SASSERT(s.size() == 1); approx_set new_s(s); - new_s.insert(h); + new_s.insert(h); filter * new_instr = m_ct_manager.mk_filter(reg, new_s); m_compatible.push_back(new_instr); m_incompatible.push_back(curr); @@ -1669,11 +1669,11 @@ namespace smt { last = curr; curr = curr->m_next; } - + TRACE("mam_compiler", tout << *head << " " << head << "\n"; tout << "m_compatible.size(): " << m_compatible.size() << "\n"; tout << "m_incompatible.size(): " << m_incompatible.size() << "\n";); - + if (m_incompatible.empty()) { // sequence starting at head is fully compatible SASSERT(curr != 0); @@ -1753,22 +1753,18 @@ namespace smt { m_use_filters(use_filters) { } - context & get_context() { - return m_context; - } - /** \brief Create a new code tree for the given quantifier. - mp: is a pattern of qa that will be used to create the code tree - + - first_idx: index of mp that will be the "head" (first to be processed) of the multi-pattern. */ code_tree * mk_tree(quantifier * qa, app * mp, unsigned first_idx, bool filter_candidates) { SASSERT(m_ast_manager.is_pattern(mp)); app * p = to_app(mp->get_arg(first_idx)); unsigned num_args = p->get_num_args(); - code_tree * r = m_ct_manager.mk_code_tree(p->get_decl(), num_args, filter_candidates); + code_tree * r = m_ct_manager.mk_code_tree(p->get_decl(), num_args, filter_candidates); init(r, qa, mp, first_idx); linearise(r->m_root, first_idx); r->m_num_choices = m_num_choices; @@ -1795,12 +1791,12 @@ namespace smt { if (!is_tmp_tree) m_ct_manager.save_num_regs(tree); init(tree, qa, mp, first_idx); - m_num_choices = tree->m_num_choices; + m_num_choices = tree->m_num_choices; insert(tree->m_root, first_idx); TRACE("mam_bug", tout << "m_num_choices: " << m_num_choices << "\n";); if (m_num_choices > tree->m_num_choices) { - if (!is_tmp_tree) + if (!is_tmp_tree) m_ct_manager.save_num_choices(tree); tree->m_num_choices = m_num_choices; } @@ -1848,7 +1844,7 @@ namespace smt { }; typedef svector backtrack_stack; - + class interpreter { context & m_context; ast_manager & m_ast_manager; @@ -1893,7 +1889,7 @@ namespace smt { if (m_ast_manager.has_trace_stream()) m_used_enodes.push_back(n); } - + // We have to provide the number of expected arguments because we have flat-assoc applications such as +. // Flat-assoc applications may have arbitrary number of arguments. enode * get_first_f_app(func_decl * lbl, unsigned num_expected_args, enode * curr) { @@ -1950,7 +1946,7 @@ namespace smt { SASSERT(n != 0); do { if (n->get_decl() == f && - n->get_arg(0)->get_root() == m_args[0] && + n->get_arg(0)->get_root() == m_args[0] && n->get_arg(1)->get_root() == m_args[1]) { update_max_generation(n); return true; @@ -2001,9 +1997,9 @@ namespace smt { interpreter(context & ctx, mam & m, bool use_filters): m_context(ctx), m_ast_manager(ctx.get_manager()), - m_mam(m), + m_mam(m), m_use_filters(use_filters) { - m_args.resize(INIT_ARGS_SIZE, 0); + m_args.resize(INIT_ARGS_SIZE); } ~interpreter() { @@ -2016,30 +2012,24 @@ namespace smt { if (m_backtrack_stack.size() < t->get_num_choices()) m_backtrack_stack.resize(t->get_num_choices()); } - + void execute(code_tree * t) { TRACE("trigger_bug", tout << "execute for code tree:\n"; t->display(tout);); init(t); - enode_vector::const_iterator it = t->get_candidates().begin(); - enode_vector::const_iterator end = t->get_candidates().end(); if (t->filter_candidates()) { - for (; it != end; ++it) { - enode * app = *it; + for (enode * app : t->get_candidates()) { if (!app->is_marked() && app->is_cgr()) { execute_core(t, app); app->set_mark(); } } - it = t->get_candidates().begin(); - for (; it != end; ++it) { - enode * app = *it; + for (enode * app : t->get_candidates()) { if (app->is_marked()) app->unset_mark(); } } else { - for (; it != end; ++it) { - enode * app = *it; + for (enode * app : t->get_candidates()) { TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_owner(), m_ast_manager) << "\n";); if (app->is_cgr()) { TRACE("trigger_bug", tout << "is_cgr\n";); @@ -2048,7 +2038,7 @@ namespace smt { } } } - + // init(t) must be invoked before execute_core void execute_core(code_tree * t, enode * n); @@ -2086,8 +2076,9 @@ namespace smt { for (; it != end; ++it) { enode * p = *it; if (p->get_decl() == f && + i < p->get_num_args() && m_context.is_relevant(p) && - p->is_cgr() && + p->is_cgr() && p->get_arg(i)->get_root() == n) { v->push_back(p); } @@ -2104,6 +2095,7 @@ namespace smt { enode * n = m_registers[j2->m_reg]->get_root(); if (n->get_num_parents() == 0) return 0; + unsigned num_args = n->get_num_args(); enode_vector * v = mk_enode_vector(); enode_vector::const_iterator it1 = n->begin_parents(); enode_vector::const_iterator end1 = n->end_parents(); @@ -2111,7 +2103,7 @@ namespace smt { enode * p = *it1; if (p->get_decl() == j2->m_decl && m_context.is_relevant(p) && - p->is_cgr() && + p->is_cgr() && p->get_arg(j2->m_arg_pos)->get_root() == n) { // p is in joint2 p = p->get_root(); @@ -2120,8 +2112,9 @@ namespace smt { for (; it2 != end2; ++it2) { enode * p2 = *it2; if (p2->get_decl() == f && + num_args == n->get_num_args() && m_context.is_relevant(p2) && - p2->is_cgr() && + p2->is_cgr() && p2->get_arg(i)->get_root() == p) { v->push_back(p2); } @@ -2153,14 +2146,14 @@ namespace smt { goto non_depth1; } r = n->get_root(); - if (m_use_filters && r->get_plbls().empty_intersection(c->m_lbl_set)) + if (m_use_filters && r->get_plbls().empty_intersection(c->m_lbl_set)) return 0; if (r->get_num_parents() == 0) return 0; non_depth1: ; } - // traverse each joint and select the best one. + // traverse each joint and select the best one. enode_vector * best_v = 0; for (unsigned i = 0; i < num_args; i++) { enode * bare = c->m_joints[i]; @@ -2238,16 +2231,16 @@ namespace smt { out << mk_pp(n->get_owner(), m_ast_manager) << "\n"; } } - + void interpreter::display_instr_input_reg(std::ostream & out, const instruction * instr) { switch (instr->m_opcode) { - case INIT1: case INIT2: case INIT3: case INIT4: case INIT5: case INIT6: case INITN: - display_reg(out, 0); + case INIT1: case INIT2: case INIT3: case INIT4: case INIT5: case INIT6: case INITN: + display_reg(out, 0); break; - case BIND1: case BIND2: case BIND3: case BIND4: case BIND5: case BIND6: case BINDN: + case BIND1: case BIND2: case BIND3: case BIND4: case BIND5: case BIND6: case BINDN: display_reg(out, static_cast(instr)->m_ireg); break; - case COMPARE: + case COMPARE: display_reg(out, static_cast(instr)->m_reg1); display_reg(out, static_cast(instr)->m_reg2); break; @@ -2257,7 +2250,7 @@ namespace smt { case FILTER: display_reg(out, static_cast(instr)->m_reg); break; - case YIELD1: case YIELD2: case YIELD3: case YIELD4: case YIELD5: case YIELD6: case YIELDN: + case YIELD1: case YIELD2: case YIELD3: case YIELD4: case YIELD5: case YIELD6: case YIELDN: for (unsigned i = 0; i < static_cast(instr)->m_num_bindings; i++) { display_reg(out, static_cast(instr)->m_bindings[i]); } @@ -2308,7 +2301,7 @@ namespace smt { m_registers[0] = n; m_top = 0; - + main_loop: TRACE("mam_int", display_pc_info(tout);); @@ -2323,7 +2316,7 @@ namespace smt { m_registers[1] = m_app->get_arg(0); m_pc = m_pc->m_next; goto main_loop; - + case INIT2: m_app = m_registers[0]; if (m_app->get_num_args() != 2) @@ -2332,7 +2325,7 @@ namespace smt { m_registers[2] = m_app->get_arg(1); m_pc = m_pc->m_next; goto main_loop; - + case INIT3: m_app = m_registers[0]; if (m_app->get_num_args() != 3) @@ -2342,7 +2335,7 @@ namespace smt { m_registers[3] = m_app->get_arg(2); m_pc = m_pc->m_next; goto main_loop; - + case INIT4: m_app = m_registers[0]; if (m_app->get_num_args() != 4) @@ -2353,9 +2346,9 @@ namespace smt { m_registers[4] = m_app->get_arg(3); m_pc = m_pc->m_next; goto main_loop; - + case INIT5: - m_app = m_registers[0]; + m_app = m_registers[0]; if (m_app->get_num_args() != 5) goto backtrack; m_registers[1] = m_app->get_arg(0); @@ -2365,8 +2358,8 @@ namespace smt { m_registers[5] = m_app->get_arg(4); m_pc = m_pc->m_next; goto main_loop; - - case INIT6: + + case INIT6: m_app = m_registers[0]; if (m_app->get_num_args() != 6) goto backtrack; @@ -2378,7 +2371,7 @@ namespace smt { m_registers[6] = m_app->get_arg(5); m_pc = m_pc->m_next; goto main_loop; - + case INITN: m_app = m_registers[0]; m_num_args = m_app->get_num_args(); @@ -2388,7 +2381,7 @@ namespace smt { m_registers[i+1] = m_app->get_arg(i); m_pc = m_pc->m_next; goto main_loop; - + case COMPARE: m_n1 = m_registers[static_cast(m_pc)->m_reg1]; m_n2 = m_registers[static_cast(m_pc)->m_reg2]; @@ -2398,7 +2391,7 @@ namespace smt { goto backtrack; m_pc = m_pc->m_next; goto main_loop; - + case CHECK: m_n1 = m_registers[static_cast(m_pc)->m_reg]; m_n2 = static_cast(m_pc)->m_enode; @@ -2413,21 +2406,21 @@ namespace smt { The compiler will never merge two CFILTERs with different m_lbl_set fields. Essentially, CFILTER is used to combine CHECK statements, and FILTER for BIND */ - case CFILTER: + case CFILTER: case FILTER: m_n1 = m_registers[static_cast(m_pc)->m_reg]->get_root(); - if (static_cast(m_pc)->m_lbl_set.empty_intersection(m_n1->get_lbls())) + if (static_cast(m_pc)->m_lbl_set.empty_intersection(m_n1->get_lbls())) goto backtrack; m_pc = m_pc->m_next; goto main_loop; case PFILTER: m_n1 = m_registers[static_cast(m_pc)->m_reg]->get_root(); - if (static_cast(m_pc)->m_lbl_set.empty_intersection(m_n1->get_plbls())) + if (static_cast(m_pc)->m_lbl_set.empty_intersection(m_n1->get_plbls())) goto backtrack; m_pc = m_pc->m_next; goto main_loop; - + case CHOOSE: m_backtrack_stack[m_top].m_instr = m_pc; m_backtrack_stack[m_top].m_old_max_generation = m_max_generation; @@ -2439,7 +2432,7 @@ namespace smt { SASSERT(static_cast(m_pc)->m_alt == 0); m_pc = m_pc->m_next; goto main_loop; - + case BIND1: #define BIND_COMMON() \ m_n1 = m_registers[static_cast(m_pc)->m_ireg]; \ @@ -2456,19 +2449,19 @@ namespace smt { m_backtrack_stack[m_top].m_old_used_enodes_size = m_curr_used_enodes_size; \ m_backtrack_stack[m_top].m_curr = m_app; \ m_top++; - + BIND_COMMON(); m_registers[m_oreg] = m_app->get_arg(0); m_pc = m_pc->m_next; goto main_loop; - + case BIND2: BIND_COMMON(); m_registers[m_oreg] = m_app->get_arg(0); m_registers[m_oreg+1] = m_app->get_arg(1); m_pc = m_pc->m_next; goto main_loop; - + case BIND3: BIND_COMMON(); m_registers[m_oreg] = m_app->get_arg(0); @@ -2476,7 +2469,7 @@ namespace smt { m_registers[m_oreg+2] = m_app->get_arg(2); m_pc = m_pc->m_next; goto main_loop; - + case BIND4: BIND_COMMON(); m_registers[m_oreg] = m_app->get_arg(0); @@ -2485,7 +2478,7 @@ namespace smt { m_registers[m_oreg+3] = m_app->get_arg(3); m_pc = m_pc->m_next; goto main_loop; - + case BIND5: BIND_COMMON(); m_registers[m_oreg] = m_app->get_arg(0); @@ -2495,7 +2488,7 @@ namespace smt { m_registers[m_oreg+4] = m_app->get_arg(4); m_pc = m_pc->m_next; goto main_loop; - + case BIND6: BIND_COMMON(); m_registers[m_oreg] = m_app->get_arg(0); @@ -2506,7 +2499,7 @@ namespace smt { m_registers[m_oreg+5] = m_app->get_arg(5); m_pc = m_pc->m_next; goto main_loop; - + case BINDN: BIND_COMMON(); m_num_args = static_cast(m_pc)->m_num_args; @@ -2529,20 +2522,20 @@ namespace smt { m_max_generation, m_used_enodes) ON_MATCH(1); goto backtrack; - + case YIELD2: m_bindings[0] = m_registers[static_cast(m_pc)->m_bindings[1]]; m_bindings[1] = m_registers[static_cast(m_pc)->m_bindings[0]]; ON_MATCH(2); goto backtrack; - + case YIELD3: m_bindings[0] = m_registers[static_cast(m_pc)->m_bindings[2]]; m_bindings[1] = m_registers[static_cast(m_pc)->m_bindings[1]]; m_bindings[2] = m_registers[static_cast(m_pc)->m_bindings[0]]; ON_MATCH(3); goto backtrack; - + case YIELD4: m_bindings[0] = m_registers[static_cast(m_pc)->m_bindings[3]]; m_bindings[1] = m_registers[static_cast(m_pc)->m_bindings[2]]; @@ -2550,7 +2543,7 @@ namespace smt { m_bindings[3] = m_registers[static_cast(m_pc)->m_bindings[0]]; ON_MATCH(4); goto backtrack; - + case YIELD5: m_bindings[0] = m_registers[static_cast(m_pc)->m_bindings[4]]; m_bindings[1] = m_registers[static_cast(m_pc)->m_bindings[3]]; @@ -2559,7 +2552,7 @@ namespace smt { m_bindings[4] = m_registers[static_cast(m_pc)->m_bindings[0]]; ON_MATCH(5); goto backtrack; - + case YIELD6: m_bindings[0] = m_registers[static_cast(m_pc)->m_bindings[5]]; m_bindings[1] = m_registers[static_cast(m_pc)->m_bindings[4]]; @@ -2569,10 +2562,10 @@ namespace smt { m_bindings[5] = m_registers[static_cast(m_pc)->m_bindings[0]]; ON_MATCH(6); goto backtrack; - + case YIELDN: m_num_args = static_cast(m_pc)->m_num_bindings; - for (unsigned i = 0; i < m_num_args; i++) + for (unsigned i = 0; i < m_num_args; i++) m_bindings[i] = m_registers[static_cast(m_pc)->m_bindings[m_num_args - i - 1]]; ON_MATCH(m_num_args); goto backtrack; @@ -2590,7 +2583,7 @@ namespace smt { m_registers[static_cast(m_pc)->m_oreg] = m_n1; \ m_pc = m_pc->m_next; \ goto main_loop; - + #define SET_VAR(IDX) \ m_args[IDX] = m_registers[static_cast(m_pc)->m_iregs[IDX]]; \ if (m_use_filters && static_cast(m_pc)->m_lbl_set.empty_intersection(m_args[IDX]->get_root()->get_plbls())) { \ @@ -2599,7 +2592,7 @@ namespace smt { tout << "node set: "; m_args[IDX]->get_root()->get_plbls().display(tout); tout << "\n";); \ goto backtrack; \ } - + SET_VAR(0); GET_CGR_COMMON(); @@ -2644,11 +2637,11 @@ namespace smt { for (unsigned i = 0; i < m_num_args; i++) m_args[i] = m_registers[static_cast(m_pc)->m_iregs[i]]; GET_CGR_COMMON(); - + case IS_CGR: - if (!exec_is_cgr(static_cast(m_pc))) - goto backtrack; - m_pc = m_pc->m_next; + if (!exec_is_cgr(static_cast(m_pc))) + goto backtrack; + m_pc = m_pc->m_next; goto main_loop; case CONTINUE: @@ -2659,13 +2652,13 @@ namespace smt { goto backtrack; m_pattern_instances.push_back(m_app); TRACE("mam_int", tout << "continue candidate:\n" << mk_ll_pp(m_app->get_owner(), m_ast_manager);); - for (unsigned i = 0; i < m_num_args; i++) + for (unsigned i = 0; i < m_num_args; i++) m_registers[m_oreg+i] = m_app->get_arg(i); m_pc = m_pc->m_next; goto main_loop; } - + backtrack: TRACE("mam_int", tout << "backtracking.\n";); if (m_top == 0) { @@ -2723,19 +2716,19 @@ namespace smt { bp.m_curr = m_app; \ TRACE("mam_int", tout << "bind next candidate:\n" << mk_ll_pp(m_app->get_owner(), m_ast_manager);); \ m_oreg = m_b->m_oreg - + BBIND_COMMON(); m_registers[m_oreg] = m_app->get_arg(0); m_pc = m_b->m_next; goto main_loop; - + case BIND2: BBIND_COMMON(); m_registers[m_oreg] = m_app->get_arg(0); m_registers[m_oreg+1] = m_app->get_arg(1); m_pc = m_b->m_next; goto main_loop; - + case BIND3: BBIND_COMMON(); m_registers[m_oreg] = m_app->get_arg(0); @@ -2743,7 +2736,7 @@ namespace smt { m_registers[m_oreg+2] = m_app->get_arg(2); m_pc = m_b->m_next; goto main_loop; - + case BIND4: BBIND_COMMON(); m_registers[m_oreg] = m_app->get_arg(0); @@ -2752,7 +2745,7 @@ namespace smt { m_registers[m_oreg+3] = m_app->get_arg(3); m_pc = m_b->m_next; goto main_loop; - + case BIND5: BBIND_COMMON(); m_registers[m_oreg] = m_app->get_arg(0); @@ -2762,7 +2755,7 @@ namespace smt { m_registers[m_oreg+4] = m_app->get_arg(4); m_pc = m_b->m_next; goto main_loop; - + case BIND6: BBIND_COMMON(); m_registers[m_oreg] = m_app->get_arg(0); @@ -2773,7 +2766,7 @@ namespace smt { m_registers[m_oreg+5] = m_app->get_arg(5); m_pc = m_b->m_next; goto main_loop; - + case BINDN: BBIND_COMMON(); m_num_args = m_b->m_num_args; @@ -2781,7 +2774,7 @@ namespace smt { m_registers[m_oreg+i] = m_app->get_arg(i); m_pc = m_b->m_next; goto main_loop; - + case CONTINUE: ++bp.m_it; for (; bp.m_it != bp.m_end; ++bp.m_it) { @@ -2815,28 +2808,26 @@ namespace smt { recycle_enode_vector(bp.m_to_recycle); m_top--; goto backtrack; - + default: UNREACHABLE(); } } // end of execute_core void display_trees(std::ostream & out, const ptr_vector & trees) { - ptr_vector::const_iterator it = trees.begin(); - ptr_vector::const_iterator end = trees.end(); unsigned lbl = 0; - for (; it != end; ++it, ++lbl) { - code_tree * tree = *it; + for (code_tree* tree : trees) { if (tree) { out << "tree for f" << lbl << "\n"; out << *tree; } + ++lbl; } } // ------------------------------------ - // - // A mapping from func_label -> code tree. + // + // A mapping from func_label -> code tree. // // ------------------------------------ class code_tree_map { @@ -2858,7 +2849,7 @@ namespace smt { m_trees[m_lbl_id] = 0; } }; - + public: code_tree_map(ast_manager & m, compiler & c, mam_trail_stack & s): m_ast_manager(m), @@ -2876,9 +2867,9 @@ namespace smt { /** \brief Add a pattern to the code tree map. - + - mp: is used a pattern for qa. - + - first_idx: index to be used as head of the multi-pattern mp */ void add_pattern(quantifier * qa, app * mp, unsigned first_idx) { @@ -2933,11 +2924,11 @@ namespace smt { }; // ------------------------------------ - // + // // Path trees AKA inverted path index // // ------------------------------------ - + /** \brief Temporary object used to encode a path of the form: @@ -2948,7 +2939,7 @@ namespace smt { parents p_0 of n that are f-applications, and n is the second argument, then for each such p_0, I want to follow the parents p_1 of p_0 that are g-applications, and p_0 is the third argument. Finally, I want to - follow the p_2 parents of p_1 that are h-applications and p_1 is the + follow the p_2 parents of p_1 that are h-applications and p_1 is the first argument of p_2. To improve the filtering power of the inverse path index, I'm also @@ -2961,11 +2952,11 @@ namespace smt { The idea is that I want only the f-parents s.t. the third argument is equal to t. */ struct path { - func_decl * m_label; + func_decl * m_label; unsigned short m_arg_idx; unsigned short m_ground_arg_idx; enode * m_ground_arg; - unsigned m_pattern_idx; + unsigned m_pattern_idx; path * m_child; path (func_decl * lbl, unsigned short arg_idx, unsigned short ground_arg_idx, enode * ground_arg, unsigned pat_idx, path * child): m_label(lbl), @@ -2977,7 +2968,7 @@ namespace smt { SASSERT(ground_arg != 0 || ground_arg_idx == 0); } }; - + bool is_equal(path const * p1, path const * p2) { for (;;) { if (p1->m_label != p2->m_label || @@ -2986,15 +2977,15 @@ namespace smt { (p1->m_child == 0) != (p2->m_child == 0)) { return false; } - + if (p1->m_child == 0 && p2->m_child == 0) return true; - + p1 = p1->m_child; p2 = p2->m_child; } } - + typedef ptr_vector paths; /** @@ -3009,7 +3000,7 @@ namespace smt { approx_set m_filter; path_tree * m_sibling; path_tree * m_first_child; - enode_vector * m_todo; // temporary field used to collect candidates + enode_vector * m_todo; // temporary field used to collect candidates #ifdef _PROFILE_PATH_TREE stopwatch m_watch; unsigned m_counter; @@ -3017,7 +3008,7 @@ namespace smt { unsigned m_num_neq_visited; bool m_already_displayed; //!< true if the path_tree was already displayed after reaching _PROFILE_PATH_TREE_THRESHOLD #endif - + path_tree(path * p, label_hasher & h): m_label(p->m_label), m_arg_idx(p->m_arg_idx), @@ -3047,7 +3038,7 @@ namespace smt { #ifdef _PROFILE_PATH_TREE out << ", counter: " << m_counter << ", num_eq_visited: " << m_num_eq_visited << ", num_neq_visited: " << m_num_neq_visited << ", avg. : " << static_cast(m_num_neq_visited)/static_cast(m_num_neq_visited+m_num_eq_visited); -#endif +#endif out << "\n"; curr->m_first_child->display(out, indent+1); curr = curr->m_sibling; @@ -3058,7 +3049,7 @@ namespace smt { typedef std::pair path_tree_pair; // ------------------------------------ - // + // // Matching Abstract Machine Implementation // // ------------------------------------ @@ -3071,8 +3062,8 @@ namespace smt { code_tree_manager m_ct_manager; compiler m_compiler; interpreter m_interpreter; - code_tree_map m_trees; - + code_tree_map m_trees; + ptr_vector m_tmp_trees; ptr_vector m_tmp_trees_to_delete; ptr_vector m_to_match; @@ -3088,11 +3079,11 @@ namespace smt { // auxiliary field used to update data-structures... typedef ptr_vector func_decls; - vector m_var_parent_labels; + vector m_var_parent_labels; region & m_region; region m_tmp_region; - path_tree_pair m_pp[APPROX_SET_CAPACITY][APPROX_SET_CAPACITY]; + path_tree_pair m_pp[APPROX_SET_CAPACITY][APPROX_SET_CAPACITY]; path_tree * m_pc[APPROX_SET_CAPACITY][APPROX_SET_CAPACITY]; pool m_pool; @@ -3105,7 +3096,7 @@ namespace smt { enode * m_r1; // temp field enode * m_r2; // temp field - + class add_shared_enode_trail; friend class add_shared_enode_trail; @@ -3125,7 +3116,7 @@ namespace smt { r->reset(); return r; } - + void recycle(enode_vector * v) { m_pool.recycle(v); } @@ -3133,12 +3124,12 @@ namespace smt { void add_candidate(code_tree * t, enode * app) { if (t != 0) { TRACE("mam_candidate", tout << "adding candidate:\n" << mk_ll_pp(app->get_owner(), m_ast_manager);); - if (!t->has_candidates()) + if (!t->has_candidates()) m_to_match.push_back(t); t->add_candidate(app); } } - + void add_candidate(enode * app) { func_decl * lbl = app->get_decl(); add_candidate(m_trees.get_code_tree_for(lbl), app); @@ -3152,7 +3143,7 @@ namespace smt { unsigned lbl_id = lbl->get_decl_id(); return lbl_id < m_is_clbl.size() && m_is_clbl[lbl_id]; } - + void update_lbls(enode * n, unsigned elem) { approx_set & r_lbls = n->get_root()->get_lbls(); if (!r_lbls.may_contain(elem)) { @@ -3203,14 +3194,14 @@ namespace smt { } } } - + void update_plbls(func_decl * lbl) { unsigned lbl_id = lbl->get_decl_id(); m_is_plbl.reserve(lbl_id+1, false); TRACE("trigger_bug", tout << "update_plbls: " << lbl->get_name() << " is already plbl: " << m_is_plbl[lbl_id] << ", lbl_id: " << lbl_id << "\n"; tout << "mam: " << this << "\n";); TRACE("mam_bug", tout << "update_plbls: " << lbl->get_name() << " is already plbl: " << m_is_plbl[lbl_id] << "\n";); - if (m_is_plbl[lbl_id]) + if (m_is_plbl[lbl_id]) return; m_trail_stack.push(set_bitvector_trail(m_is_plbl, lbl_id)); SASSERT(m_is_plbl[lbl_id]); @@ -3220,7 +3211,7 @@ namespace smt { enode_vector::const_iterator end = m_context.end_enodes_of(lbl); for (; it != end; ++it) { enode * app = *it; - if (m_context.is_relevant(app)) + if (m_context.is_relevant(app)) update_children_plbls(app, h); } } @@ -3234,12 +3225,12 @@ namespace smt { } } } - + code_tree * mk_code(quantifier * qa, app * mp, unsigned pat_idx) { SASSERT(m_ast_manager.is_pattern(mp)); - return m_compiler.mk_tree(qa, mp, pat_idx, true); + return m_compiler.mk_tree(qa, mp, pat_idx, true); } - + void insert_code(path_tree * t, quantifier * qa, app * mp, unsigned pat_idx) { SASSERT(m_ast_manager.is_pattern(mp)); m_compiler.insert(t->m_code, qa, mp, pat_idx, false); @@ -3254,7 +3245,7 @@ namespace smt { path_tree * prev = 0; while (p != 0) { curr = new (m_region) path_tree(p, m_lbl_hasher); - if (prev) + if (prev) prev->m_first_child = curr; if (!head) head = curr; @@ -3274,7 +3265,7 @@ namespace smt { while (t != 0) { if (t->m_label == p->m_label) { found_label = true; - if (t->m_arg_idx == p->m_arg_idx && + if (t->m_arg_idx == p->m_arg_idx && t->m_ground_arg == p->m_ground_arg && t->m_ground_arg_idx == p->m_ground_arg_idx ) { @@ -3326,7 +3317,7 @@ namespace smt { m_trail_stack.push(set_ptr_trail(m_pc[h1][h2])); m_pc[h1][h2] = mk_path_tree(p, qa, mp); } - TRACE("mam_path_tree_updt", + TRACE("mam_path_tree_updt", tout << "updated path tree:\n"; m_pc[h1][h2]->display(tout, 2);); } @@ -3343,7 +3334,7 @@ namespace smt { m_trail_stack.push(set_ptr_trail(m_pp[h1][h2].first)); m_pp[h1][h2].first = mk_path_tree(p1, qa, mp); insert(m_pp[h1][h2].first, p2, qa, mp); - } + } } else { if (h1 > h2) { @@ -3364,7 +3355,7 @@ namespace smt { m_pp[h1][h2].second = mk_path_tree(p2, qa, mp); } } - TRACE("mam_path_tree_updt", + TRACE("mam_path_tree_updt", tout << "updated path tree:\n"; SASSERT(h1 <= h2); m_pp[h1][h2].first->display(tout, 2); @@ -3418,28 +3409,28 @@ namespace smt { for (unsigned short i = 0; i < num_args; i++) { expr * child = pat->get_arg(i); path * new_path = new (m_tmp_region) path(plbl, i, ground_arg_pos, ground_arg, pat_idx, p); - + if (is_var(child)) { update_vars(to_var(child)->get_idx(), new_path, qa, mp); continue; } SASSERT(is_app(child)); - + if (to_app(child)->is_ground()) { enode * n = mk_enode(m_context, qa, to_app(child)); update_plbls(plbl); if (!n->has_lbl_hash()) n->set_lbl_hash(m_context); - TRACE("mam_bug", - tout << "updating pc labels " << plbl->get_name() << " " << + TRACE("mam_bug", + tout << "updating pc labels " << plbl->get_name() << " " << static_cast(n->get_lbl_hash()) << "\n"; tout << "#" << n->get_owner_id() << " " << n->get_root()->get_lbls() << "\n"; tout << "relevant: " << m_context.is_relevant(n) << "\n";); update_pc(m_lbl_hasher(plbl), n->get_lbl_hash(), new_path, qa, mp); continue; } - + func_decl * clbl = to_app(child)->get_decl(); TRACE("mam_bug", tout << "updating pc labels " << plbl->get_name() << " " << clbl->get_name() << "\n";); update_plbls(plbl); @@ -3468,7 +3459,7 @@ namespace smt { // (p_n, p_2, ..., p_1) unsigned num_patterns = mp->get_num_args(); for (unsigned i = 0; i < num_patterns; i++) { - app * pat = to_app(mp->get_arg(i)); + app * pat = to_app(mp->get_arg(i)); update_filters(pat, 0, qa, mp, i); } } @@ -3495,7 +3486,7 @@ namespace smt { \brief Check equality modulo the equality m_r1 = m_r2 */ bool is_eq(enode * n1, enode * n2) { - return + return n1->get_root() == n2->get_root() || (n1->get_root() == m_r1 && n2->get_root() == m_r2) || (n2->get_root() == m_r1 && n1->get_root() == m_r2); @@ -3524,7 +3515,7 @@ namespace smt { #ifdef _PROFILE_PATH_TREE t->m_counter++; #endif - TRACE("mam_path_tree", + TRACE("mam_path_tree", tout << "processing:\n"; t->display(tout, 2);); enode_vector * v = t->m_todo; @@ -3552,13 +3543,13 @@ namespace smt { // // In a previous version of Z3, the "enode mark field" was used to mark both cases. This is incorrect, // and Z3 may fail to find potential new matches. - // + // // The file regression\acu.sx exposed this problem. enode * curr_child = (*it1)->get_root(); - + if (m_use_filters && curr_child->get_plbls().empty_intersection(filter)) continue; - + #ifdef _PROFILE_PATH_TREE static unsigned counter2 = 0; static unsigned total_sz2 = 0; @@ -3571,7 +3562,7 @@ namespace smt { std::cout << "Avg2. " << static_cast(total_sz2)/static_cast(counter2) << ", Max2. " << max_sz2 << "\n"; #endif - TRACE("mam_path_tree", tout << "processing: #" << curr_child->get_owner_id() << "\n";); + TRACE("mam_path_tree", tout << "processing: #" << curr_child->get_owner_id() << "\n";); enode_vector::const_iterator it2 = curr_child->begin_parents(); enode_vector::const_iterator end2 = curr_child->end_parents(); for (; it2 != end2; ++it2) { @@ -3594,7 +3585,7 @@ namespace smt { if (filter.may_contain(m_lbl_hasher(lbl)) && !curr_parent->is_marked() && (curr_parent_cg == curr_parent || !is_eq(curr_parent_cg, curr_parent_root)) && - m_context.is_relevant(curr_parent) + m_context.is_relevant(curr_parent) ) { path_tree * curr_tree = t; while (curr_tree) { @@ -3693,14 +3684,14 @@ namespace smt { } if (n_plbl1 == n_plbl2) { SASSERT(m_pp[n_plbl1][n_plbl2].second == 0); - if (n_r1->get_num_parents() <= n_r2->get_num_parents()) + if (n_r1->get_num_parents() <= n_r2->get_num_parents()) collect_parents(n_r1, m_pp[n_plbl1][n_plbl2].first); else collect_parents(n_r2, m_pp[n_plbl1][n_plbl2].first); } else { SASSERT(n_plbl1 < n_plbl2); - if (n_r1->get_num_parents() <= n_r2->get_num_parents()) + if (n_r1->get_num_parents() <= n_r2->get_num_parents()) collect_parents(n_r1, m_pp[n_plbl1][n_plbl2].first); else collect_parents(n_r2, m_pp[n_plbl1][n_plbl2].second); @@ -3773,7 +3764,7 @@ namespace smt { enode_vector::const_iterator end3 = m_context.end_enodes_of(lbl); for (; it3 != end3; ++it3) { enode * app = *it3; - if (m_context.is_relevant(app)) + if (m_context.is_relevant(app)) m_interpreter.execute_core(tmp_tree, app); } m_tmp_trees[lbl_id] = 0; @@ -3786,7 +3777,7 @@ namespace smt { ptr_buffer todo; unsigned num_patterns = mp->get_num_args(); for (unsigned i = 0; i < num_patterns; i++) { - app * pat = to_app(mp->get_arg(i)); + app * pat = to_app(mp->get_arg(i)); TRACE("mam_pat", tout << mk_ismt2_pp(qa, m_ast_manager) << "\npat:\n" << mk_ismt2_pp(pat, m_ast_manager) << "\n";); SASSERT(!pat->is_ground()); todo.push_back(pat); @@ -3812,7 +3803,7 @@ namespace smt { public: mam_impl(context & ctx, bool use_filters): - mam(ctx), + mam(ctx), m_ast_manager(ctx.get_manager()), m_use_filters(use_filters), m_trail_stack(*this), @@ -3827,7 +3818,7 @@ namespace smt { DEBUG_CODE(m_check_missing_instances = false;); reset_pp_pc(); } - + virtual ~mam_impl() { m_trail_stack.reset(); } @@ -3854,11 +3845,11 @@ namespace smt { for (unsigned i = 0; i < num_patterns; i++) m_trees.add_pattern(qa, mp, i); } - + virtual void push_scope() { m_trail_stack.push_scope(); } - + virtual void pop_scope(unsigned num_scopes) { if (!m_to_match.empty()) { ptr_vector::iterator it = m_to_match.begin(); @@ -3894,8 +3885,8 @@ namespace smt { (*it)->display(out); } } - - virtual void match() { + + virtual void match() { TRACE("trigger_bug", tout << "match\n"; display(tout);); ptr_vector::iterator it = m_to_match.begin(); ptr_vector::iterator end = m_to_match.end(); @@ -3925,7 +3916,7 @@ namespace smt { enode_vector::const_iterator end2 = m_context.end_enodes_of(lbl); for (; it2 != end2; ++it2) { enode * curr = *it2; - if (use_irrelevant || m_context.is_relevant(curr)) + if (use_irrelevant || m_context.is_relevant(curr)) m_interpreter.execute_core(t, curr); } } @@ -3940,13 +3931,13 @@ namespace smt { return true; } #endif - + virtual void on_match(quantifier * qa, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, ptr_vector & used_enodes) { TRACE("trigger_bug", tout << "found match " << mk_pp(qa, m_ast_manager) << "\n";); #ifdef Z3DEBUG if (m_check_missing_instances) { if (!m_context.slow_contains_instance(qa, num_bindings, bindings)) { - TRACE("missing_instance", + TRACE("missing_instance", tout << "qa:\n" << mk_ll_pp(qa, m_ast_manager) << "\npat:\n" << mk_ll_pp(pat, m_ast_manager); for (unsigned i = 0; i < num_bindings; i++) tout << "#" << bindings[i]->get_owner_id() << "\n" << mk_ll_pp(bindings[i]->get_owner(), m_ast_manager) << "\n"; @@ -3967,23 +3958,23 @@ namespace smt { virtual bool is_shared(enode * n) const { return !m_shared_enodes.empty() && m_shared_enodes.contains(n); } - + // This method is invoked when n becomes relevant. // If lazy == true, then n is not added to the list of candidate enodes for matching. That is, the method just updates the lbls. virtual void relevant_eh(enode * n, bool lazy) { TRACE("trigger_bug", tout << "relevant_eh:\n" << mk_ismt2_pp(n->get_owner(), m_ast_manager) << "\n"; tout << "mam: " << this << "\n";); TRACE("mam", tout << "relevant_eh: #" << n->get_owner_id() << "\n";); - if (n->has_lbl_hash()) + if (n->has_lbl_hash()) update_lbls(n, n->get_lbl_hash()); - + if (n->get_num_args() > 0) { func_decl * lbl = n->get_decl(); unsigned h = m_lbl_hasher(lbl); - TRACE("trigger_bug", tout << "lbl: " << lbl->get_name() << " is_clbl(lbl): " << is_clbl(lbl) + TRACE("trigger_bug", tout << "lbl: " << lbl->get_name() << " is_clbl(lbl): " << is_clbl(lbl) << ", is_plbl(lbl): " << is_plbl(lbl) << ", h: " << h << "\n"; tout << "lbl_id: " << lbl->get_decl_id() << "\n";); - if (is_clbl(lbl)) + if (is_clbl(lbl)) update_lbls(n, h); if (is_plbl(lbl)) update_children_plbls(n, h); @@ -4002,28 +3993,28 @@ namespace smt { flet l2(m_r2, r2); TRACE("mam", tout << "add_eq_eh: #" << r1->get_owner_id() << " #" << r2->get_owner_id() << "\n";); - TRACE("mam_inc_bug_detail", m_context.display(tout);); - TRACE("mam_inc_bug", + TRACE("mam_inc_bug_detail", m_context.display(tout);); + TRACE("mam_inc_bug", tout << "before:\n#" << r1->get_owner_id() << " #" << r2->get_owner_id() << "\n"; tout << "r1.lbls: " << r1->get_lbls() << "\n"; tout << "r2.lbls: " << r2->get_lbls() << "\n"; tout << "r1.plbls: " << r1->get_plbls() << "\n"; tout << "r2.plbls: " << r2->get_plbls() << "\n";); - + process_pc(r1, r2); process_pc(r2, r1); process_pp(r1, r2); - + approx_set r1_plbls = r1->get_plbls(); approx_set & r2_plbls = r2->get_plbls(); approx_set r1_lbls = r1->get_lbls(); approx_set & r2_lbls = r2->get_lbls(); - + m_trail_stack.push(mam_value_trail(r2_lbls)); m_trail_stack.push(mam_value_trail(r2_plbls)); r2_lbls |= r1_lbls; - r2_plbls |= r1_plbls; - TRACE("mam_inc_bug", + r2_plbls |= r1_plbls; + TRACE("mam_inc_bug", tout << "after:\n"; tout << "r1.lbls: " << r1->get_lbls() << "\n"; tout << "r2.lbls: " << r2->get_lbls() << "\n"; diff --git a/src/smt/mam.h b/src/smt/mam.h index dd56d7984..635cb30e7 100644 --- a/src/smt/mam.h +++ b/src/smt/mam.h @@ -19,8 +19,8 @@ Revision History: #ifndef MAM_H_ #define MAM_H_ -#include"ast.h" -#include"smt_types.h" +#include "ast/ast.h" +#include "smt/smt_types.h" namespace smt { /** diff --git a/src/smt/old_interval.cpp b/src/smt/old_interval.cpp index da03bc03e..d126c2f32 100644 --- a/src/smt/old_interval.cpp +++ b/src/smt/old_interval.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"old_interval.h" +#include "smt/old_interval.h" void ext_numeral::neg() { switch (m_kind) { diff --git a/src/smt/old_interval.h b/src/smt/old_interval.h index b2f1d8fbd..e9cb73b8f 100644 --- a/src/smt/old_interval.h +++ b/src/smt/old_interval.h @@ -19,8 +19,8 @@ Revision History: #ifndef OLD_INTERVAL_H_ #define OLD_INTERVAL_H_ -#include"rational.h" -#include"dependency.h" +#include "util/rational.h" +#include "util/dependency.h" class ext_numeral { public: diff --git a/src/smt/params/CMakeLists.txt b/src/smt/params/CMakeLists.txt index 500423dcc..c965f0a62 100644 --- a/src/smt/params/CMakeLists.txt +++ b/src/smt/params/CMakeLists.txt @@ -13,7 +13,6 @@ z3_add_component(smt_params ast bit_blaster pattern - simplifier PYG_FILES smt_params_helper.pyg ) diff --git a/src/smt/params/dyn_ack_params.cpp b/src/smt/params/dyn_ack_params.cpp index b62530fbf..4ba230a47 100644 --- a/src/smt/params/dyn_ack_params.cpp +++ b/src/smt/params/dyn_ack_params.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"dyn_ack_params.h" -#include"smt_params_helper.hpp" +#include "smt/params/dyn_ack_params.h" +#include "smt/params/smt_params_helper.hpp" void dyn_ack_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); diff --git a/src/smt/params/dyn_ack_params.h b/src/smt/params/dyn_ack_params.h index 017b7fe94..223242788 100644 --- a/src/smt/params/dyn_ack_params.h +++ b/src/smt/params/dyn_ack_params.h @@ -19,7 +19,7 @@ Revision History: #ifndef DYN_ACK_PARAMS_H_ #define DYN_ACK_PARAMS_H_ -#include"params.h" +#include "util/params.h" enum dyn_ack_strategy { DACK_DISABLED, diff --git a/src/smt/params/preprocessor_params.cpp b/src/smt/params/preprocessor_params.cpp index 7a0e96248..93ea794fa 100644 --- a/src/smt/params/preprocessor_params.cpp +++ b/src/smt/params/preprocessor_params.cpp @@ -16,20 +16,20 @@ Author: Revision History: --*/ -#include"preprocessor_params.h" -#include"smt_params_helper.hpp" +#include "smt/params/preprocessor_params.h" +#include "smt/params/smt_params_helper.hpp" void preprocessor_params::updt_local_params(params_ref const & _p) { smt_params_helper p(_p); m_macro_finder = p.macro_finder(); + m_quasi_macros = p.quasi_macros(); + m_restricted_quasi_macros = p.restricted_quasi_macros(); m_pull_nested_quantifiers = p.pull_nested_quantifiers(); m_refine_inj_axiom = p.refine_inj_axioms(); } void preprocessor_params::updt_params(params_ref const & p) { pattern_inference_params::updt_params(p); - bv_simplifier_params::updt_params(p); - arith_simplifier_params::updt_params(p); updt_local_params(p); } @@ -38,15 +38,12 @@ void preprocessor_params::updt_params(params_ref const & p) { void preprocessor_params::display(std::ostream & out) const { pattern_inference_params::display(out); bit_blaster_params::display(out); - bv_simplifier_params::display(out); - arith_simplifier_params::display(out); DISPLAY_PARAM(m_lift_ite); DISPLAY_PARAM(m_ng_lift_ite); DISPLAY_PARAM(m_pull_cheap_ite_trees); DISPLAY_PARAM(m_pull_nested_quantifiers); DISPLAY_PARAM(m_eliminate_term_ite); - DISPLAY_PARAM(m_eliminate_and); DISPLAY_PARAM(m_macro_finder); DISPLAY_PARAM(m_propagate_values); DISPLAY_PARAM(m_propagate_booleans); diff --git a/src/smt/params/preprocessor_params.h b/src/smt/params/preprocessor_params.h index 4ffad48a2..dc16d6244 100644 --- a/src/smt/params/preprocessor_params.h +++ b/src/smt/params/preprocessor_params.h @@ -19,10 +19,8 @@ Revision History: #ifndef PREPROCESSOR_PARAMS_H_ #define PREPROCESSOR_PARAMS_H_ -#include"pattern_inference_params.h" -#include"bit_blaster_params.h" -#include"bv_simplifier_params.h" -#include"arith_simplifier_params.h" +#include "ast/pattern/pattern_inference_params.h" +#include "ast/rewriter/bit_blaster/bit_blaster_params.h" enum lift_ite_kind { LI_NONE, @@ -31,15 +29,12 @@ enum lift_ite_kind { }; struct preprocessor_params : public pattern_inference_params, - public bit_blaster_params, - public bv_simplifier_params, - public arith_simplifier_params { + public bit_blaster_params { lift_ite_kind m_lift_ite; lift_ite_kind m_ng_lift_ite; // lift ite for non ground terms bool m_pull_cheap_ite_trees; bool m_pull_nested_quantifiers; bool m_eliminate_term_ite; - bool m_eliminate_and; // represent (and a b) as (not (or (not a) (not b))) bool m_macro_finder; bool m_propagate_values; bool m_propagate_booleans; @@ -62,7 +57,6 @@ public: m_pull_cheap_ite_trees(false), m_pull_nested_quantifiers(false), m_eliminate_term_ite(false), - m_eliminate_and(true), m_macro_finder(false), m_propagate_values(true), m_propagate_booleans(false), // TODO << check peformance diff --git a/src/smt/params/qi_params.cpp b/src/smt/params/qi_params.cpp index 8182222e4..a9cff6e8c 100644 --- a/src/smt/params/qi_params.cpp +++ b/src/smt/params/qi_params.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"qi_params.h" -#include"smt_params_helper.hpp" +#include "smt/params/qi_params.h" +#include "smt/params/smt_params_helper.hpp" void qi_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); diff --git a/src/smt/params/qi_params.h b/src/smt/params/qi_params.h index c9736909a..2cee6dc72 100644 --- a/src/smt/params/qi_params.h +++ b/src/smt/params/qi_params.h @@ -19,8 +19,8 @@ Revision History: #ifndef QI_PARAMS_H_ #define QI_PARAMS_H_ -#include"util.h" -#include"params.h" +#include "util/util.h" +#include "util/params.h" enum quick_checker_mode { MC_NO, // do not use (cheap) model checking based instantiation diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp index 92ff1de90..a8eb81a2e 100644 --- a/src/smt/params/smt_params.cpp +++ b/src/smt/params/smt_params.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"smt_params.h" -#include"smt_params_helper.hpp" -#include"model_params.hpp" -#include"gparams.h" +#include "smt/params/smt_params.h" +#include "smt/params/smt_params_helper.hpp" +#include "model/model_params.hpp" +#include "util/gparams.h" void smt_params::updt_local_params(params_ref const & _p) { smt_params_helper p(_p); @@ -49,6 +49,9 @@ void smt_params::updt_local_params(params_ref const & _p) { else if (_p.get_bool("arith.least_error_pivot", false)) m_arith_pivot_strategy = ARITH_PIVOT_LEAST_ERROR; theory_array_params::updt_params(_p); + m_dump_benchmarks = false; + m_dump_min_time = 0.5; + m_dump_recheck = false; } void smt_params::updt_params(params_ref const & p) { diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index 4b7c924e4..b01499c04 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -19,19 +19,19 @@ Revision History: #ifndef SMT_PARAMS_H_ #define SMT_PARAMS_H_ -#include"ast.h" -#include"dyn_ack_params.h" -#include"qi_params.h" -#include"theory_arith_params.h" -#include"theory_array_params.h" -#include"theory_bv_params.h" -#include"theory_str_params.h" -#include"theory_pb_params.h" -#include"theory_datatype_params.h" -#include"preprocessor_params.h" -#include"context_params.h" +#include "ast/ast.h" +#include "smt/params/dyn_ack_params.h" +#include "smt/params/qi_params.h" +#include "smt/params/theory_arith_params.h" +#include "smt/params/theory_array_params.h" +#include "smt/params/theory_bv_params.h" +#include "smt/params/theory_str_params.h" +#include "smt/params/theory_pb_params.h" +#include "smt/params/theory_datatype_params.h" +#include "smt/params/preprocessor_params.h" +#include "cmd_context/context_params.h" -enum phase_selection { +enum phase_selection { PS_ALWAYS_FALSE, PS_ALWAYS_TRUE, PS_CACHING, @@ -52,7 +52,8 @@ enum restart_strategy { enum lemma_gc_strategy { LGC_FIXED, LGC_GEOMETRIC, - LGC_AT_RESTART + LGC_AT_RESTART, + LGC_NONE }; enum initial_activity { @@ -71,11 +72,11 @@ enum case_split_strategy { CS_ACTIVITY_THEORY_AWARE_BRANCHING // activity-based case split, but theory solvers can manipulate activity }; -struct smt_params : public preprocessor_params, - public dyn_ack_params, - public qi_params, - public theory_arith_params, - public theory_array_params, +struct smt_params : public preprocessor_params, + public dyn_ack_params, + public qi_params, + public theory_arith_params, + public theory_array_params, public theory_bv_params, public theory_str_params, public theory_pb_params, @@ -153,12 +154,12 @@ struct smt_params : public preprocessor_params, unsigned m_lemma_gc_initial; double m_lemma_gc_factor; unsigned m_new_old_ratio; //!< the ratio of new and old clauses. - unsigned m_new_clause_activity; + unsigned m_new_clause_activity; unsigned m_old_clause_activity; unsigned m_new_clause_relevancy; //!< Max. number of unassigned literals to be considered relevant. unsigned m_old_clause_relevancy; //!< Max. number of unassigned literals to be considered relevant. double m_inv_clause_decay; //!< clause activity decay - + // ----------------------------------- // // SMT-LIB (debug) pretty printer @@ -166,7 +167,7 @@ struct smt_params : public preprocessor_params, // ----------------------------------- bool m_smtlib_dump_lemmas; symbol m_logic; - + // ----------------------------------- // // Statistics for Profiling @@ -179,10 +180,10 @@ struct smt_params : public preprocessor_params, // ----------------------------------- // - // Model generation + // Model generation // // ----------------------------------- - bool m_model; + bool m_model; bool m_model_compact; bool m_model_on_timeout; bool m_model_on_final_check; @@ -213,10 +214,19 @@ struct smt_params : public preprocessor_params, unsigned m_timeout; unsigned m_rlimit; bool m_at_labels_cex; // only use labels which contains the @ symbol when building multiple counterexamples. - bool m_check_at_labels; // check that @ labels are inserted to generate unique counter-examples. + bool m_check_at_labels; // check that @ labels are inserted to generate unique counter-examples. bool m_dump_goal_as_smt; bool m_auto_config; + // ----------------------------------- + // + // Spacer hacking + // + // ----------------------------------- + bool m_dump_benchmarks; + double m_dump_min_time; + bool m_dump_recheck; + // ----------------------------------- // // Solver selection @@ -228,7 +238,7 @@ struct smt_params : public preprocessor_params, m_display_proof(false), m_display_dot_proof(false), m_display_unsat_core(false), - m_check_proof(false), + m_check_proof(false), m_eq_propagation(true), m_binary_clause_opt(true), m_relevancy_lvl(2), @@ -270,7 +280,7 @@ struct smt_params : public preprocessor_params, m_new_old_ratio(16), m_new_clause_activity(10), m_old_clause_activity(500), - m_new_clause_relevancy(45), + m_new_clause_relevancy(45), m_old_clause_relevancy(6), m_inv_clause_decay(1), m_smtlib_dump_lemmas(false), diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index a501f474a..d6ca8c9b2 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -7,6 +7,8 @@ def_module_params(module_name='smt', ('random_seed', UINT, 0, 'random seed for the smt solver'), ('relevancy', UINT, 2, 'relevancy propagation heuristic: 0 - disabled, 1 - relevancy is tracked by only affects quantifier instantiation, 2 - relevancy is tracked, and an atom is only asserted if it is relevant'), ('macro_finder', BOOL, False, 'try to find universally quantified formulas that can be viewed as macros'), + ('quasi_macros', BOOL, False, 'try to find universally quantified formulas that are quasi-macros'), + ('restricted_quasi_macros', BOOL, False, 'try to find universally quantified formulas that are restricted quasi-macros'), ('ematching', BOOL, True, 'E-Matching based quantifier instantiation'), ('phase_selection', UINT, 3, 'phase selection heuristic: 0 - always false, 1 - always true, 2 - phase caching, 3 - phase caching conservative, 4 - phase caching conservative 2, 5 - random, 6 - number of occurrences'), ('restart_strategy', UINT, 1, '0 - geometric, 1 - inner-outer-geometric, 2 - luby, 3 - fixed, 4 - arithmetic'), @@ -80,5 +82,6 @@ def_module_params(module_name='smt', ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'), ('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'), ('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core'), - ('core.extend_nonlocal_patterns', BOOL, False, 'extend unsat cores with literals that have quantifiers with patterns that contain symbols which are not in the quantifier\'s body') + ('core.extend_nonlocal_patterns', BOOL, False, 'extend unsat cores with literals that have quantifiers with patterns that contain symbols which are not in the quantifier\'s body'), + ('lemma_gc_strategy', UINT, 0, 'lemma garbage collection strategy: 0 - fixed, 1 - geometric, 2 - at restart, 3 - none') )) diff --git a/src/smt/params/theory_arith_params.cpp b/src/smt/params/theory_arith_params.cpp index 944911f9b..250848db4 100644 --- a/src/smt/params/theory_arith_params.cpp +++ b/src/smt/params/theory_arith_params.cpp @@ -16,8 +16,9 @@ Author: Revision History: --*/ -#include"theory_arith_params.h" -#include"smt_params_helper.hpp" +#include "smt/params/theory_arith_params.h" +#include "smt/params/smt_params_helper.hpp" +#include "ast/rewriter/arith_rewriter_params.hpp" void theory_arith_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); @@ -36,12 +37,16 @@ void theory_arith_params::updt_params(params_ref const & _p) { m_arith_bound_prop = static_cast(p.arith_propagation_mode()); m_arith_dump_lemmas = p.arith_dump_lemmas(); m_arith_reflect = p.arith_reflect(); + arith_rewriter_params ap(_p); + m_arith_eq2ineq = ap.eq2ineq(); } #define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; void theory_arith_params::display(std::ostream & out) const { + DISPLAY_PARAM(m_arith_eq2ineq); + DISPLAY_PARAM(m_arith_process_all_eqs); DISPLAY_PARAM(m_arith_mode); DISPLAY_PARAM(m_arith_auto_config_simplex); //!< force simplex solver in auto_config DISPLAY_PARAM(m_arith_blands_rule_threshold); diff --git a/src/smt/params/theory_arith_params.h b/src/smt/params/theory_arith_params.h index 943bd711e..1fe7e1163 100644 --- a/src/smt/params/theory_arith_params.h +++ b/src/smt/params/theory_arith_params.h @@ -20,7 +20,7 @@ Revision History: #define THEORY_ARITH_PARAMS_H_ #include -#include"params.h" +#include "util/params.h" enum arith_solver_id { AS_NO_ARITH, @@ -49,6 +49,8 @@ enum arith_pivot_strategy { }; struct theory_arith_params { + bool m_arith_eq2ineq; + bool m_arith_process_all_eqs; arith_solver_id m_arith_mode; bool m_arith_auto_config_simplex; //!< force simplex solver in auto_config unsigned m_arith_blands_rule_threshold; @@ -108,6 +110,8 @@ struct theory_arith_params { theory_arith_params(params_ref const & p = params_ref()): + m_arith_eq2ineq(false), + m_arith_process_all_eqs(false), m_arith_mode(AS_ARITH), m_arith_auto_config_simplex(false), m_arith_blands_rule_threshold(1000), diff --git a/src/smt/params/theory_array_params.cpp b/src/smt/params/theory_array_params.cpp index c0015bf2c..9a9e5aa7b 100644 --- a/src/smt/params/theory_array_params.cpp +++ b/src/smt/params/theory_array_params.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"theory_array_params.h" -#include"smt_params_helper.hpp" +#include "smt/params/theory_array_params.h" +#include "smt/params/smt_params_helper.hpp" void theory_array_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); diff --git a/src/smt/params/theory_array_params.h b/src/smt/params/theory_array_params.h index af51427c4..edda4d7cf 100644 --- a/src/smt/params/theory_array_params.h +++ b/src/smt/params/theory_array_params.h @@ -19,7 +19,7 @@ Revision History: #ifndef THEORY_ARRAY_PARAMS_H_ #define THEORY_ARRAY_PARAMS_H_ -#include"array_simplifier_params.h" +#include "util/params.h" enum array_solver_id { AR_NO_ARRAY, @@ -28,7 +28,9 @@ enum array_solver_id { AR_FULL }; -struct theory_array_params : public array_simplifier_params { +struct theory_array_params { + bool m_array_canonize_simplify; + bool m_array_simplify; // temporary hack for disabling array simplifier plugin. array_solver_id m_array_mode; bool m_array_weak; bool m_array_extensional; @@ -40,6 +42,8 @@ struct theory_array_params : public array_simplifier_params { unsigned m_array_lazy_ieq_delay; theory_array_params(): + m_array_canonize_simplify(false), + m_array_simplify(true), m_array_mode(AR_FULL), m_array_weak(false), m_array_extensional(true), diff --git a/src/smt/params/theory_bv_params.cpp b/src/smt/params/theory_bv_params.cpp index 631c5765b..156fda592 100644 --- a/src/smt/params/theory_bv_params.cpp +++ b/src/smt/params/theory_bv_params.cpp @@ -16,11 +16,14 @@ Author: Revision History: --*/ -#include"theory_bv_params.h" -#include"smt_params_helper.hpp" +#include "smt/params/theory_bv_params.h" +#include "smt/params/smt_params_helper.hpp" +#include "ast/rewriter/bv_rewriter_params.hpp" void theory_bv_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); + bv_rewriter_params rp(_p); + m_hi_div0 = rp.hi_div0(); m_bv_reflect = p.bv_reflect(); m_bv_enable_int2bv2int = p.bv_enable_int2bv(); } @@ -29,9 +32,10 @@ void theory_bv_params::updt_params(params_ref const & _p) { void theory_bv_params::display(std::ostream & out) const { DISPLAY_PARAM(m_bv_mode); + DISPLAY_PARAM(m_hi_div0); DISPLAY_PARAM(m_bv_reflect); DISPLAY_PARAM(m_bv_lazy_le); DISPLAY_PARAM(m_bv_cc); DISPLAY_PARAM(m_bv_blast_max_size); DISPLAY_PARAM(m_bv_enable_int2bv2int); -} \ No newline at end of file +} diff --git a/src/smt/params/theory_bv_params.h b/src/smt/params/theory_bv_params.h index 5830e5176..e0bff3f17 100644 --- a/src/smt/params/theory_bv_params.h +++ b/src/smt/params/theory_bv_params.h @@ -19,7 +19,7 @@ Revision History: #ifndef THEORY_BV_PARAMS_H_ #define THEORY_BV_PARAMS_H_ -#include"params.h" +#include "util/params.h" enum bv_solver_id { BS_NO_BV, @@ -28,6 +28,7 @@ enum bv_solver_id { struct theory_bv_params { bv_solver_id m_bv_mode; + bool m_hi_div0; //!< if true, uses the hardware interpretation for div0, mod0, ... if false, div0, mod0, ... are considered uninterpreted. bool m_bv_reflect; bool m_bv_lazy_le; bool m_bv_cc; @@ -35,6 +36,7 @@ struct theory_bv_params { bool m_bv_enable_int2bv2int; theory_bv_params(params_ref const & p = params_ref()): m_bv_mode(BS_BLASTER), + m_hi_div0(false), m_bv_reflect(true), m_bv_lazy_le(false), m_bv_cc(false), diff --git a/src/smt/params/theory_pb_params.cpp b/src/smt/params/theory_pb_params.cpp index a1e13a6e7..b285429d9 100644 --- a/src/smt/params/theory_pb_params.cpp +++ b/src/smt/params/theory_pb_params.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"theory_pb_params.h" -#include"smt_params_helper.hpp" +#include "smt/params/theory_pb_params.h" +#include "smt/params/smt_params_helper.hpp" void theory_pb_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); diff --git a/src/smt/params/theory_pb_params.h b/src/smt/params/theory_pb_params.h index 6a129e601..9bfd262c4 100644 --- a/src/smt/params/theory_pb_params.h +++ b/src/smt/params/theory_pb_params.h @@ -19,7 +19,7 @@ Revision History: #ifndef THEORY_PB_PARAMS_H_ #define THEORY_PB_PARAMS_H_ -#include"params.h" +#include "util/params.h" struct theory_pb_params { diff --git a/src/smt/params/theory_str_params.cpp b/src/smt/params/theory_str_params.cpp index 6090086b8..afbfc33fc 100644 --- a/src/smt/params/theory_str_params.cpp +++ b/src/smt/params/theory_str_params.cpp @@ -15,8 +15,8 @@ Revision History: --*/ -#include"theory_str_params.h" -#include"smt_params_helper.hpp" +#include "smt/params/theory_str_params.h" +#include "smt/params/smt_params_helper.hpp" void theory_str_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); diff --git a/src/smt/params/theory_str_params.h b/src/smt/params/theory_str_params.h index 207b635d7..c841609db 100644 --- a/src/smt/params/theory_str_params.h +++ b/src/smt/params/theory_str_params.h @@ -18,7 +18,7 @@ Revision History: #ifndef THEORY_STR_PARAMS_H #define THEORY_STR_PARAMS_H -#include"params.h" +#include "util/params.h" struct theory_str_params { /* diff --git a/src/smt/proto_model/CMakeLists.txt b/src/smt/proto_model/CMakeLists.txt index 0539c0fb0..c5f6c4b18 100644 --- a/src/smt/proto_model/CMakeLists.txt +++ b/src/smt/proto_model/CMakeLists.txt @@ -8,6 +8,6 @@ z3_add_component(proto_model value_factory.cpp COMPONENT_DEPENDENCIES model - simplifier + rewriter smt_params ) diff --git a/src/smt/proto_model/array_factory.cpp b/src/smt/proto_model/array_factory.cpp index a929f6d9a..d112331f0 100644 --- a/src/smt/proto_model/array_factory.cpp +++ b/src/smt/proto_model/array_factory.cpp @@ -17,11 +17,11 @@ Revision History: --*/ -#include"array_factory.h" -#include"array_decl_plugin.h" -#include"proto_model.h" -#include"func_interp.h" -#include"ast_pp.h" +#include "smt/proto_model/array_factory.h" +#include "ast/array_decl_plugin.h" +#include "smt/proto_model/proto_model.h" +#include "model/func_interp.h" +#include "ast/ast_pp.h" func_decl * mk_aux_decl_for_array_sort(ast_manager & m, sort * s) { ptr_buffer domain; diff --git a/src/smt/proto_model/array_factory.h b/src/smt/proto_model/array_factory.h index 6801ae081..4d4f52944 100644 --- a/src/smt/proto_model/array_factory.h +++ b/src/smt/proto_model/array_factory.h @@ -19,7 +19,7 @@ Revision History: #ifndef ARRAY_FACTORY_H_ #define ARRAY_FACTORY_H_ -#include"struct_factory.h" +#include "smt/proto_model/struct_factory.h" class func_interp; diff --git a/src/smt/proto_model/datatype_factory.cpp b/src/smt/proto_model/datatype_factory.cpp index 3b0ec8e5f..550b694da 100644 --- a/src/smt/proto_model/datatype_factory.cpp +++ b/src/smt/proto_model/datatype_factory.cpp @@ -16,11 +16,10 @@ Author: Revision History: --*/ -#include"datatype_factory.h" -#include"proto_model.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"expr_functors.h" +#include "smt/proto_model/datatype_factory.h" +#include "smt/proto_model/proto_model.h" +#include "ast/ast_pp.h" +#include "ast/expr_functors.h" datatype_factory::datatype_factory(ast_manager & m, proto_model & md): struct_factory(m, m.mk_family_id("datatype"), md), @@ -39,7 +38,7 @@ expr * datatype_factory::get_some_value(sort * s) { } expr * r = m_manager.mk_app(c, args.size(), args.c_ptr()); register_value(r); - TRACE("datatype_factory", tout << mk_pp(r, m_util.get_manager()) << "\n";); + TRACE("datatype", tout << mk_pp(r, m_util.get_manager()) << "\n";); return r; } @@ -49,7 +48,7 @@ expr * datatype_factory::get_some_value(sort * s) { expr * datatype_factory::get_last_fresh_value(sort * s) { expr * val = 0; if (m_last_fresh_value.find(s, val)) { - TRACE("datatype_factory", tout << "cached fresh value: " << mk_pp(val, m_manager) << "\n";); + TRACE("datatype", tout << "cached fresh value: " << mk_pp(val, m_manager) << "\n";); return val; } value_set * set = get_value_set(s); @@ -69,7 +68,7 @@ bool datatype_factory::is_subterm_of_last_value(app* e) { } contains_app contains(m_manager, e); bool result = contains(last); - TRACE("datatype_factory", tout << mk_pp(e, m_manager) << " in " << mk_pp(last, m_manager) << " " << result << "\n";); + TRACE("datatype", tout << mk_pp(e, m_manager) << " in " << mk_pp(last, m_manager) << " " << result << "\n";); return result; } @@ -89,11 +88,8 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) { // Traverse constructors, and try to invoke get_fresh_value of one of the arguments (if the argument is not a sibling datatype of s). // If the argumet is a sibling datatype of s, then // use get_last_fresh_value. - ptr_vector const * constructors = m_util.get_datatype_constructors(s); - ptr_vector::const_iterator it = constructors->begin(); - ptr_vector::const_iterator end = constructors->end(); - for (; it != end; ++it) { - func_decl * constructor = *it; + ptr_vector const & constructors = *m_util.get_datatype_constructors(s); + for (func_decl * constructor : constructors) { expr_ref_vector args(m_manager); bool found_fresh_arg = false; bool recursive = false; @@ -130,7 +126,7 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) { m_last_fresh_value.insert(s, new_value); } } - TRACE("datatype_factory", tout << "almost fresh: " << mk_pp(new_value, m_manager) << "\n";); + TRACE("datatype", tout << "almost fresh: " << mk_pp(new_value, m_manager) << "\n";); return new_value; } } @@ -140,7 +136,7 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) { expr * datatype_factory::get_fresh_value(sort * s) { - TRACE("datatype_factory", tout << "generating fresh value for: " << s->get_name() << "\n";); + TRACE("datatype", tout << "generating fresh value for: " << s->get_name() << "\n";); value_set * set = get_value_set(s); // Approach 0) // if no value for s was generated so far, then used get_some_value @@ -148,18 +144,15 @@ expr * datatype_factory::get_fresh_value(sort * s) { expr * val = get_some_value(s); if (m_util.is_recursive(s)) m_last_fresh_value.insert(s, val); - TRACE("datatype_factory", tout << "0. result: " << mk_pp(val, m_manager) << "\n";); + TRACE("datatype", tout << "0. result: " << mk_pp(val, m_manager) << "\n";); return val; } // Approach 1) // Traverse constructors, and try to invoke get_fresh_value of one of the // arguments (if the argument is not a sibling datatype of s). // Two datatypes are siblings if they were defined together in the same mutually recursive definition. - ptr_vector const * constructors = m_util.get_datatype_constructors(s); - ptr_vector::const_iterator it = constructors->begin(); - ptr_vector::const_iterator end = constructors->end(); - for (; it != end; ++it) { - func_decl * constructor = *it; + ptr_vector const & constructors = *m_util.get_datatype_constructors(s); + for (func_decl * constructor : constructors) { expr_ref_vector args(m_manager); bool found_fresh_arg = false; unsigned num = constructor->get_arity(); @@ -178,13 +171,13 @@ expr * datatype_factory::get_fresh_value(sort * s) { } expr_ref new_value(m_manager); new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr()); - CTRACE("datatype_factory", found_fresh_arg && set->contains(new_value), tout << mk_pp(new_value, m_manager) << "\n";); + CTRACE("datatype", found_fresh_arg && set->contains(new_value), tout << mk_pp(new_value, m_manager) << "\n";); SASSERT(!found_fresh_arg || !set->contains(new_value)); if (!set->contains(new_value)) { register_value(new_value); if (m_util.is_recursive(s)) m_last_fresh_value.insert(s, new_value); - TRACE("datatype_factory", tout << "1. result: " << mk_pp(new_value, m_manager) << "\n";); + TRACE("datatype", tout << "1. result: " << mk_pp(new_value, m_manager) << "\n";); return new_value; } } @@ -195,19 +188,16 @@ expr * datatype_factory::get_fresh_value(sort * s) { if (m_util.is_recursive(s)) { while(true) { ++num_iterations; - TRACE("datatype_factory", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";); - ptr_vector const * constructors = m_util.get_datatype_constructors(s); - ptr_vector::const_iterator it = constructors->begin(); - ptr_vector::const_iterator end = constructors->end(); - for (; it != end; ++it) { - func_decl * constructor = *it; + TRACE("datatype", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";); + ptr_vector const & constructors = *m_util.get_datatype_constructors(s); + for (func_decl * constructor : constructors) { expr_ref_vector args(m_manager); bool found_sibling = false; unsigned num = constructor->get_arity(); - TRACE("datatype_factory", tout << "checking constructor: " << constructor->get_name() << "\n";); + TRACE("datatype", tout << "checking constructor: " << constructor->get_name() << "\n";); for (unsigned i = 0; i < num; i++) { sort * s_arg = constructor->get_domain(i); - TRACE("datatype_factory", tout << mk_pp(s, m_manager) << " " + TRACE("datatype", tout << mk_pp(s, m_manager) << " " << mk_pp(s_arg, m_manager) << " are_siblings " << m_util.are_siblings(s, s_arg) << " is_datatype " << m_util.is_datatype(s_arg) << " found_sibling " @@ -222,7 +212,7 @@ expr * datatype_factory::get_fresh_value(sort * s) { maybe_new_arg = get_fresh_value(s_arg); } if (!maybe_new_arg) { - TRACE("datatype_factory", + TRACE("datatype", tout << "no argument found for " << mk_pp(s_arg, m_manager) << "\n";); maybe_new_arg = m_model.get_some_value(s_arg); found_sibling = false; @@ -239,11 +229,11 @@ expr * datatype_factory::get_fresh_value(sort * s) { if (found_sibling) { expr_ref new_value(m_manager); new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr()); - TRACE("datatype_factory", tout << "potential new value: " << mk_pp(new_value, m_manager) << "\n";); + TRACE("datatype", tout << "potential new value: " << mk_pp(new_value, m_manager) << "\n";); m_last_fresh_value.insert(s, new_value); if (!set->contains(new_value)) { register_value(new_value); - TRACE("datatype_factory", tout << "2. result: " << mk_pp(new_value, m_manager) << "\n";); + TRACE("datatype", tout << "2. result: " << mk_pp(new_value, m_manager) << "\n";); return new_value; } } diff --git a/src/smt/proto_model/datatype_factory.h b/src/smt/proto_model/datatype_factory.h index 3dddb843d..9f64b8daa 100644 --- a/src/smt/proto_model/datatype_factory.h +++ b/src/smt/proto_model/datatype_factory.h @@ -19,8 +19,8 @@ Revision History: #ifndef DATATYPE_FACTORY_H_ #define DATATYPE_FACTORY_H_ -#include"struct_factory.h" -#include"datatype_decl_plugin.h" +#include "smt/proto_model/struct_factory.h" +#include "ast/datatype_decl_plugin.h" class datatype_factory : public struct_factory { datatype_util m_util; diff --git a/src/smt/proto_model/numeral_factory.cpp b/src/smt/proto_model/numeral_factory.cpp index 49ff15167..a5d5ac18a 100644 --- a/src/smt/proto_model/numeral_factory.cpp +++ b/src/smt/proto_model/numeral_factory.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"numeral_factory.h" -#include"ast_pp.h" +#include "smt/proto_model/numeral_factory.h" +#include "ast/ast_pp.h" app * arith_factory::mk_value_core(rational const & val, sort * s) { return m_util.mk_numeral(val, s); diff --git a/src/smt/proto_model/numeral_factory.h b/src/smt/proto_model/numeral_factory.h index 9b1ff6a81..f1b68223b 100644 --- a/src/smt/proto_model/numeral_factory.h +++ b/src/smt/proto_model/numeral_factory.h @@ -19,9 +19,9 @@ Revision History: #ifndef NUMERAL_FACTORY_H_ #define NUMERAL_FACTORY_H_ -#include"value_factory.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" +#include "smt/proto_model/value_factory.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" class numeral_factory : public simple_factory { public: diff --git a/src/smt/proto_model/proto_model.cpp b/src/smt/proto_model/proto_model.cpp index 129bed87e..0a75ff700 100644 --- a/src/smt/proto_model/proto_model.cpp +++ b/src/smt/proto_model/proto_model.cpp @@ -10,41 +10,40 @@ Abstract: Author: - + Leonardo de Moura (leonardo) 2007-03-08. Revision History: --*/ -#include"proto_model.h" -#include"model_params.hpp" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"var_subst.h" -#include"array_decl_plugin.h" -#include"well_sorted.h" -#include"used_symbols.h" -#include"model_v2_pp.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/rewriter/var_subst.h" +#include "ast/well_sorted.h" +#include "ast/used_symbols.h" +#include "model/model_params.hpp" +#include "model/model_v2_pp.h" +#include "smt/proto_model/proto_model.h" proto_model::proto_model(ast_manager & m, params_ref const & p): model_core(m), - m_afid(m.mk_family_id(symbol("array"))), m_eval(*this), m_rewrite(m) { register_factory(alloc(basic_factory, m)); m_user_sort_factory = alloc(user_sort_factory, m); register_factory(m_user_sort_factory); - m_model_partial = model_params(p).partial(); } - - void proto_model::register_aux_decl(func_decl * d, func_interp * fi) { model_core::register_decl(d, fi); m_aux_decls.insert(d); } +void proto_model::register_aux_decl(func_decl * d) { + m_aux_decls.insert(d); +} + /** \brief Set new_fi as the new interpretation for f. If f_aux != 0, then assign the old interpretation of f to f_aux. @@ -84,21 +83,11 @@ expr * proto_model::mk_some_interp_for(func_decl * d) { } -bool proto_model::is_select_of_model_value(expr* e) const { - return - is_app_of(e, m_afid, OP_SELECT) && - is_as_array(to_app(e)->get_arg(0)) && - has_interpretation(array_util(m_manager).get_as_array_func_decl(to_app(to_app(e)->get_arg(0)))); -} - bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) { m_eval.set_model_completion(model_completion); m_eval.set_expand_array_equalities(false); try { m_eval(e, result); -#if 0 - std::cout << mk_pp(e, m_manager) << "\n===>\n" << result << "\n"; -#endif return true; } catch (model_evaluator_exception & ex) { @@ -158,12 +147,11 @@ void proto_model::cleanup_func_interp(func_interp * fi, func_decl_set & found_au app * t = to_app(a); bool visited = true; args.reset(); - unsigned num_args = t->get_num_args(); - for (unsigned i = 0; i < num_args; ++i) { + for (expr* t_arg : *t) { expr * arg = 0; - if (!cache.find(t->get_arg(i), arg)) { + if (!cache.find(t_arg, arg)) { visited = false; - todo.push_back(t->get_arg(i)); + todo.push_back(t_arg); } else { args.push_back(arg); @@ -173,10 +161,12 @@ void proto_model::cleanup_func_interp(func_interp * fi, func_decl_set & found_au continue; } func_decl * f = t->get_decl(); - if (m_aux_decls.contains(f)) + if (m_aux_decls.contains(f)) { + TRACE("model_bug", tout << f->get_name() << "\n";); found_aux_fs.insert(f); + } expr_ref new_t(m_manager); - new_t = m_rewrite.mk_app(f, num_args, args.c_ptr()); + new_t = m_rewrite.mk_app(f, args.size(), args.c_ptr()); if (t != new_t.get()) trail.push_back(new_t); todo.pop_back(); @@ -192,9 +182,7 @@ void proto_model::cleanup_func_interp(func_interp * fi, func_decl_set & found_au } } - if (!cache.find(fi_else, a)) { - UNREACHABLE(); - } + VERIFY(cache.find(fi_else, a)); fi->set_else(a); } @@ -219,11 +207,11 @@ void proto_model::remove_aux_decls_not_in_set(ptr_vector & decls, fun by their interpretations. */ void proto_model::cleanup() { + TRACE("model_bug", model_v2_pp(tout, *this);); func_decl_set found_aux_fs; - decl2finterp::iterator it = m_finterp.begin(); - decl2finterp::iterator end = m_finterp.end(); - for (; it != end; ++it) { - func_interp * fi = (*it).m_value; + for (auto const& kv : m_finterp) { + TRACE("model_bug", tout << kv.m_key->get_name() << "\n";); + func_interp * fi = kv.m_value; cleanup_func_interp(fi, found_aux_fs); } @@ -232,18 +220,10 @@ void proto_model::cleanup() { remove_aux_decls_not_in_set(m_decls, found_aux_fs); remove_aux_decls_not_in_set(m_func_decls, found_aux_fs); - func_decl_set::iterator it2 = m_aux_decls.begin(); - func_decl_set::iterator end2 = m_aux_decls.end(); - for (; it2 != end2; ++it2) { - func_decl * faux = *it2; + for (func_decl* faux : m_aux_decls) { if (!found_aux_fs.contains(faux)) { TRACE("cleanup_bug", tout << "eliminating " << faux->get_name() << "\n";); - func_interp * fi = 0; - m_finterp.find(faux, fi); - SASSERT(fi != 0); - m_finterp.erase(faux); - m_manager.dec_ref(faux); - dealloc(fi); + unregister_decl(faux); } } m_aux_decls.swap(found_aux_fs); @@ -270,10 +250,9 @@ ptr_vector const & proto_model::get_universe(sort * s) const { ptr_vector & tmp = const_cast(this)->m_tmp; tmp.reset(); obj_hashtable const & u = get_known_universe(s); - obj_hashtable::iterator it = u.begin(); - obj_hashtable::iterator end = u.end(); - for (; it != end; ++it) - tmp.push_back(*it); + for (expr * e : u) { + tmp.push_back(e); + } return tmp; } @@ -351,15 +330,8 @@ void proto_model::register_value(expr * n) { } } -bool proto_model::is_as_array(expr * v) const { - return is_app_of(v, m_afid, OP_AS_ARRAY); -} - void proto_model::compress() { - ptr_vector::iterator it = m_func_decls.begin(); - ptr_vector::iterator end = m_func_decls.end(); - for (; it != end; ++it) { - func_decl * f = *it; + for (func_decl* f : m_func_decls) { func_interp * fi = get_func_interp(f); SASSERT(fi != 0); fi->compress(); @@ -373,23 +345,9 @@ void proto_model::compress() { void proto_model::complete_partial_func(func_decl * f) { func_interp * fi = get_func_interp(f); if (fi && fi->is_partial()) { - expr * else_value = 0; -#if 0 - // For UFBV benchmarks, setting the "else" to false is not a good idea. - // TODO: find a permanent solution. A possibility is to add another option. - if (m_manager.is_bool(f->get_range())) { - else_value = m_manager.mk_false(); - } - else { - else_value = fi->get_max_occ_result(); - if (else_value == 0) - else_value = get_some_value(f->get_range()); - } -#else - else_value = fi->get_max_occ_result(); + expr * else_value = fi->get_max_occ_result(); if (else_value == 0) else_value = get_some_value(f->get_range()); -#endif fi->set_else(else_value); } } @@ -409,20 +367,16 @@ void proto_model::complete_partial_funcs() { } model * proto_model::mk_model() { - TRACE("proto_model", tout << "mk_model\n"; model_v2_pp(tout, *this);); + TRACE("proto_model", model_v2_pp(tout << "mk_model\n", *this);); model * m = alloc(model, m_manager); - decl2expr::iterator it1 = m_interp.begin(); - decl2expr::iterator end1 = m_interp.end(); - for (; it1 != end1; ++it1) { - m->register_decl(it1->m_key, it1->m_value); + for (auto const& kv : m_interp) { + m->register_decl(kv.m_key, kv.m_value); } - decl2finterp::iterator it2 = m_finterp.begin(); - decl2finterp::iterator end2 = m_finterp.end(); - for (; it2 != end2; ++it2) { - m->register_decl(it2->m_key, it2->m_value); - m_manager.dec_ref(it2->m_key); + for (auto const& kv : m_finterp) { + m->register_decl(kv.m_key, kv.m_value); + m_manager.dec_ref(kv.m_key); } m_finterp.reset(); // m took the ownership of the func_interp's @@ -437,245 +391,3 @@ model * proto_model::mk_model() { return m; } - - -#if 0 - -#include"simplifier.h" -#include"basic_simplifier_plugin.h" - -// Auxiliary function for computing fi(args[0], ..., args[fi.get_arity() - 1]). -// The result is stored in result. -// Return true if succeeded, and false otherwise. -// It uses the simplifier s during the computation. -bool eval(func_interp & fi, simplifier & s, expr * const * args, expr_ref & result) { - bool actuals_are_values = true; - - if (fi.num_entries() != 0) { - for (unsigned i = 0; actuals_are_values && i < fi.get_arity(); i++) { - actuals_are_values = fi.m().is_value(args[i]); - } - } - - func_entry * entry = fi.get_entry(args); - if (entry != 0) { - result = entry->get_result(); - return true; - } - - TRACE("func_interp", tout << "failed to find entry for: "; - for(unsigned i = 0; i < fi.get_arity(); i++) - tout << mk_pp(args[i], fi.m()) << " "; - tout << "\nis partial: " << fi.is_partial() << "\n";); - - if (!fi.eval_else(args, result)) { - return false; - } - - if (actuals_are_values && fi.args_are_values()) { - // cheap case... we are done - return true; - } - - // build symbolic result... the actuals may be equal to the args of one of the entries. - basic_simplifier_plugin * bs = static_cast(s.get_plugin(fi.m().get_basic_family_id())); - for (unsigned k = 0; k < fi.num_entries(); k++) { - func_entry const * curr = fi.get_entry(k); - SASSERT(!curr->eq_args(fi.m(), fi.get_arity(), args)); - if (!actuals_are_values || !curr->args_are_values()) { - expr_ref_buffer eqs(fi.m()); - unsigned i = fi.get_arity(); - while (i > 0) { - --i; - expr_ref new_eq(fi.m()); - bs->mk_eq(curr->get_arg(i), args[i], new_eq); - eqs.push_back(new_eq); - } - SASSERT(eqs.size() == fi.get_arity()); - expr_ref new_cond(fi.m()); - bs->mk_and(eqs.size(), eqs.c_ptr(), new_cond); - bs->mk_ite(new_cond, curr->get_result(), result, result); - } - } - return true; -} - - -bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) { - bool is_ok = true; - SASSERT(is_well_sorted(m_manager, e)); - TRACE("model_eval", tout << mk_pp(e, m_manager) << "\n"; - tout << "sort: " << mk_pp(m_manager.get_sort(e), m_manager) << "\n";); - - obj_map eval_cache; - expr_ref_vector trail(m_manager); - sbuffer, 128> todo; - ptr_buffer args; - expr * null = static_cast(0); - todo.push_back(std::make_pair(e, null)); - - simplifier m_simplifier(m_manager); - - expr * a; - expr * expanded_a; - while (!todo.empty()) { - std::pair & p = todo.back(); - a = p.first; - expanded_a = p.second; - if (expanded_a != 0) { - expr * r = 0; - eval_cache.find(expanded_a, r); - SASSERT(r != 0); - todo.pop_back(); - eval_cache.insert(a, r); - TRACE("model_eval", - tout << "orig:\n" << mk_pp(a, m_manager) << "\n"; - tout << "after beta reduction:\n" << mk_pp(expanded_a, m_manager) << "\n"; - tout << "new:\n" << mk_pp(r, m_manager) << "\n";); - } - else { - switch(a->get_kind()) { - case AST_APP: { - app * t = to_app(a); - bool visited = true; - args.reset(); - unsigned num_args = t->get_num_args(); - for (unsigned i = 0; i < num_args; ++i) { - expr * arg = 0; - if (!eval_cache.find(t->get_arg(i), arg)) { - visited = false; - todo.push_back(std::make_pair(t->get_arg(i), null)); - } - else { - args.push_back(arg); - } - } - if (!visited) { - continue; - } - SASSERT(args.size() == t->get_num_args()); - expr_ref new_t(m_manager); - func_decl * f = t->get_decl(); - - if (!has_interpretation(f)) { - // the model does not assign an interpretation to f. - SASSERT(new_t.get() == 0); - if (f->get_family_id() == null_family_id) { - if (model_completion) { - // create an interpretation for f. - new_t = mk_some_interp_for(f); - } - else { - TRACE("model_eval", tout << f->get_name() << " is uninterpreted\n";); - is_ok = false; - } - } - if (new_t.get() == 0) { - // t is interpreted or model completion is disabled. - m_simplifier.mk_app(f, num_args, args.c_ptr(), new_t); - TRACE("model_eval", tout << mk_pp(t, m_manager) << " -> " << new_t << "\n";); - trail.push_back(new_t); - if (!is_app(new_t) || to_app(new_t)->get_decl() != f || is_select_of_model_value(new_t)) { - // if the result is not of the form (f ...), then assume we must simplify it. - expr * new_new_t = 0; - if (!eval_cache.find(new_t.get(), new_new_t)) { - todo.back().second = new_t; - todo.push_back(std::make_pair(new_t, null)); - continue; - } - else { - new_t = new_new_t; - } - } - } - } - else { - // the model has an interpretaion for f. - if (num_args == 0) { - // t is a constant - new_t = get_const_interp(f); - } - else { - // t is a function application - SASSERT(new_t.get() == 0); - // try to use function graph first - func_interp * fi = get_func_interp(f); - SASSERT(fi->get_arity() == num_args); - expr_ref r1(m_manager); - // fi may be partial... - if (!::eval(*fi, m_simplifier, args.c_ptr(), r1)) { - SASSERT(fi->is_partial()); // fi->eval only fails when fi is partial. - if (model_completion) { - expr * r = get_some_value(f->get_range()); - fi->set_else(r); - SASSERT(!fi->is_partial()); - new_t = r; - } - else { - // f is an uninterpreted function, there is no need to use m_simplifier.mk_app - new_t = m_manager.mk_app(f, num_args, args.c_ptr()); - trail.push_back(new_t); - TRACE("model_eval", tout << f->get_name() << " is uninterpreted\n";); - is_ok = false; - } - } - else { - SASSERT(r1); - trail.push_back(r1); - TRACE("model_eval", tout << mk_pp(a, m_manager) << "\nevaluates to: " << r1 << "\n";); - expr * r2 = 0; - if (!eval_cache.find(r1.get(), r2)) { - todo.back().second = r1; - todo.push_back(std::make_pair(r1, null)); - continue; - } - else { - new_t = r2; - } - } - } - } - TRACE("model_eval", - tout << "orig:\n" << mk_pp(t, m_manager) << "\n"; - tout << "new:\n" << mk_pp(new_t, m_manager) << "\n";); - todo.pop_back(); - SASSERT(new_t.get() != 0); - eval_cache.insert(t, new_t); - break; - } - case AST_VAR: - SASSERT(a != 0); - eval_cache.insert(a, a); - todo.pop_back(); - break; - case AST_QUANTIFIER: - TRACE("model_eval", tout << "found quantifier\n" << mk_pp(a, m_manager) << "\n";); - is_ok = false; // evaluator does not handle quantifiers. - SASSERT(a != 0); - eval_cache.insert(a, a); - todo.pop_back(); - break; - default: - UNREACHABLE(); - break; - } - } - } - - if (!eval_cache.find(e, a)) { - TRACE("model_eval", tout << "FAILED e: " << mk_bounded_pp(e, m_manager) << "\n";); - UNREACHABLE(); - } - - result = a; - std::cout << mk_pp(e, m_manager) << "\n===>\n" << result << "\n"; - TRACE("model_eval", - ast_ll_pp(tout << "original: ", m_manager, e); - ast_ll_pp(tout << "evaluated: ", m_manager, a); - ast_ll_pp(tout << "reduced: ", m_manager, result.get()); - tout << "sort: " << mk_pp(m_manager.get_sort(e), m_manager) << "\n"; - ); - SASSERT(is_well_sorted(m_manager, result.get())); - return is_ok; -} -#endif diff --git a/src/smt/proto_model/proto_model.h b/src/smt/proto_model/proto_model.h index 78dc457f5..05af0091c 100644 --- a/src/smt/proto_model/proto_model.h +++ b/src/smt/proto_model/proto_model.h @@ -28,20 +28,19 @@ Revision History: #ifndef PROTO_MODEL_H_ #define PROTO_MODEL_H_ -#include"model_core.h" -#include"model_evaluator.h" -#include"value_factory.h" -#include"plugin_manager.h" -#include"arith_decl_plugin.h" -#include"func_decl_dependencies.h" -#include"model.h" -#include"params.h" -#include"th_rewriter.h" +#include "model/model_core.h" +#include "model/model_evaluator.h" +#include "smt/proto_model/value_factory.h" +#include "util/plugin_manager.h" +#include "ast/arith_decl_plugin.h" +#include "ast/func_decl_dependencies.h" +#include "model/model.h" +#include "util/params.h" +#include "ast/rewriter/th_rewriter.h" class proto_model : public model_core { plugin_manager m_factories; user_sort_factory * m_user_sort_factory; - family_id m_afid; //!< array family id: hack for displaying models in V1.x style func_decl_set m_aux_decls; ptr_vector m_tmp; model_evaluator m_eval; @@ -58,7 +57,6 @@ class proto_model : public model_core { void remove_aux_decls_not_in_set(ptr_vector & decls, func_decl_set const & s); void cleanup_func_interp(func_interp * fi, func_decl_set & found_aux_fs); - bool is_select_of_model_value(expr* e) const; public: proto_model(ast_manager & m, params_ref const & p = params_ref()); @@ -68,7 +66,6 @@ public: bool eval(expr * e, expr_ref & result, bool model_completion = false); - bool is_as_array(expr * v) const; value_factory * get_factory(family_id fid); @@ -84,6 +81,7 @@ public: // Primitives for building models // void register_aux_decl(func_decl * f, func_interp * fi); + void register_aux_decl(func_decl * f); void reregister_decl(func_decl * f, func_interp * new_fi, func_decl * f_aux); void compress(); void cleanup(); diff --git a/src/smt/proto_model/struct_factory.cpp b/src/smt/proto_model/struct_factory.cpp index 173554b83..8d85c6485 100644 --- a/src/smt/proto_model/struct_factory.cpp +++ b/src/smt/proto_model/struct_factory.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"struct_factory.h" -#include"proto_model.h" +#include "smt/proto_model/struct_factory.h" +#include "smt/proto_model/proto_model.h" struct_factory::value_set * struct_factory::get_value_set(sort * s) { value_set * set = 0; diff --git a/src/smt/proto_model/struct_factory.h b/src/smt/proto_model/struct_factory.h index f18121af8..bfbd90ede 100644 --- a/src/smt/proto_model/struct_factory.h +++ b/src/smt/proto_model/struct_factory.h @@ -19,8 +19,8 @@ Revision History: #ifndef STRUCT_FACTORY_H_ #define STRUCT_FACTORY_H_ -#include"value_factory.h" -#include"obj_hashtable.h" +#include "smt/proto_model/value_factory.h" +#include "util/obj_hashtable.h" class proto_model; diff --git a/src/smt/proto_model/value_factory.cpp b/src/smt/proto_model/value_factory.cpp index 93294d898..e41696165 100644 --- a/src/smt/proto_model/value_factory.cpp +++ b/src/smt/proto_model/value_factory.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"value_factory.h" +#include "smt/proto_model/value_factory.h" value_factory::value_factory(ast_manager & m, family_id fid): m_manager(m), diff --git a/src/smt/proto_model/value_factory.h b/src/smt/proto_model/value_factory.h index f841e18ea..e81c63306 100644 --- a/src/smt/proto_model/value_factory.h +++ b/src/smt/proto_model/value_factory.h @@ -19,8 +19,8 @@ Revision History: #ifndef VALUE_FACTORY_H_ #define VALUE_FACTORY_H_ -#include"ast.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" /** \brief Auxiliary object used during model construction. diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 70a3041d2..2a8d9d199 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -16,13 +16,13 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"qi_queue.h" -#include"warning.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"var_subst.h" -#include"stats.h" +#include "smt/smt_context.h" +#include "smt/qi_queue.h" +#include "util/warning.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/rewriter/var_subst.h" +#include "util/stats.h" namespace smt { @@ -148,11 +148,8 @@ namespace smt { } void qi_queue::instantiate() { - svector::iterator it = m_new_entries.begin(); - svector::iterator end = m_new_entries.end(); unsigned since_last_check = 0; - for (; it != end; ++it) { - entry & curr = *it; + for (entry & curr : m_new_entries) { fingerprint * f = curr.m_qb; quantifier * qa = static_cast(f->get_data()); @@ -227,9 +224,8 @@ namespace smt { TRACE("qi_queue_instance", tout << "new instance:\n" << mk_pp(instance, m_manager) << "\n";); expr_ref s_instance(m_manager); proof_ref pr(m_manager); - simplifier & simp = m_context.get_simplifier(); - simp(instance, s_instance, pr); - TRACE("qi_queue_bug", tout << "new instance after simplification:\n" << mk_pp(s_instance, m_manager) << "\n";); + m_context.get_rewriter()(instance, s_instance, pr); + TRACE("qi_queue_bug", tout << "new instance after simplification:\n" << s_instance << "\n";); if (m_manager.is_true(s_instance)) { TRACE("checker", tout << "reduced to true, before:\n" << mk_ll_pp(instance, m_manager);); diff --git a/src/smt/qi_queue.h b/src/smt/qi_queue.h index 0db12d537..171466e42 100644 --- a/src/smt/qi_queue.h +++ b/src/smt/qi_queue.h @@ -19,16 +19,16 @@ Revision History: #ifndef QI_QUEUE_H_ #define QI_QUEUE_H_ -#include"ast.h" -#include"smt_quantifier_stat.h" -#include"smt_checker.h" -#include"smt_quantifier.h" -#include"qi_params.h" -#include"fingerprints.h" -#include"cost_parser.h" -#include"cost_evaluator.h" -#include"cached_var_subst.h" -#include"statistics.h" +#include "ast/ast.h" +#include "smt/smt_quantifier_stat.h" +#include "smt/smt_checker.h" +#include "smt/smt_quantifier.h" +#include "smt/params/qi_params.h" +#include "smt/fingerprints.h" +#include "parsers/util/cost_parser.h" +#include "smt/cost_evaluator.h" +#include "smt/cached_var_subst.h" +#include "util/statistics.h" namespace smt { class context; diff --git a/src/smt/smt2_extra_cmds.cpp b/src/smt/smt2_extra_cmds.cpp index 61b247207..136805e43 100644 --- a/src/smt/smt2_extra_cmds.cpp +++ b/src/smt/smt2_extra_cmds.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"cmd_context.h" -#include"smt2parser.h" -#include"smt2_extra_cmds.h" +#include "cmd_context/cmd_context.h" +#include "parsers/smt2/smt2parser.h" +#include "smt/smt2_extra_cmds.h" class include_cmd : public cmd { char const * m_filename; diff --git a/src/smt/smt_almost_cg_table.cpp b/src/smt/smt_almost_cg_table.cpp index 66eb8c533..4d24ea0d0 100644 --- a/src/smt/smt_almost_cg_table.cpp +++ b/src/smt/smt_almost_cg_table.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"smt_almost_cg_table.h" +#include "smt/smt_almost_cg_table.h" namespace smt { diff --git a/src/smt/smt_almost_cg_table.h b/src/smt/smt_almost_cg_table.h index aee36c2a0..7807f705a 100644 --- a/src/smt/smt_almost_cg_table.h +++ b/src/smt/smt_almost_cg_table.h @@ -19,8 +19,8 @@ Revision History: #ifndef SMT_ALMOST_CG_TABLE_H_ #define SMT_ALMOST_CG_TABLE_H_ -#include"smt_enode.h" -#include"map.h" +#include "smt/smt_enode.h" +#include "util/map.h" namespace smt { diff --git a/src/smt/smt_b_justification.h b/src/smt/smt_b_justification.h index 7e77d301b..700c41807 100644 --- a/src/smt/smt_b_justification.h +++ b/src/smt/smt_b_justification.h @@ -19,8 +19,8 @@ Revision History: #ifndef SMT_B_JUSTIFICATION_H_ #define SMT_B_JUSTIFICATION_H_ -#include"smt_literal.h" -#include"smt_clause.h" +#include "smt/smt_literal.h" +#include "smt/smt_clause.h" namespace smt { diff --git a/src/smt/smt_bool_var_data.h b/src/smt/smt_bool_var_data.h index af0b7f9d2..4f83ece49 100644 --- a/src/smt/smt_bool_var_data.h +++ b/src/smt/smt_bool_var_data.h @@ -19,7 +19,7 @@ Revision History: #ifndef SMT_BOOL_VAR_DATA_H_ #define SMT_BOOL_VAR_DATA_H_ -#include"smt_b_justification.h" +#include "smt/smt_b_justification.h" namespace smt { diff --git a/src/smt/smt_case_split_queue.cpp b/src/smt/smt_case_split_queue.cpp index 41a269820..6aef5f0a9 100644 --- a/src/smt/smt_case_split_queue.cpp +++ b/src/smt/smt_case_split_queue.cpp @@ -16,14 +16,14 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"smt_case_split_queue.h" -#include"warning.h" -#include"stopwatch.h" -#include"for_each_expr.h" -#include"ast_pp.h" -#include"map.h" -#include"hashtable.h" +#include "smt/smt_context.h" +#include "smt/smt_case_split_queue.h" +#include "util/warning.h" +#include "util/stopwatch.h" +#include "ast/for_each_expr.h" +#include "ast/ast_pp.h" +#include "util/map.h" +#include "util/hashtable.h" namespace smt { @@ -51,9 +51,9 @@ namespace smt { if (!m_theory_var_priority.find(v2, p_v2)) { p_v2 = 0.0; } - // add clause activity - p_v1 += m_activity[v1]; - p_v2 += m_activity[v2]; + // add clause activity + p_v1 += m_activity[v1]; + p_v2 += m_activity[v2]; return p_v1 > p_v2; } }; @@ -82,6 +82,7 @@ namespace smt { virtual void mk_var_eh(bool_var v) { m_queue.reserve(v+1); + SASSERT(!m_queue.contains(v)); m_queue.insert(v); } @@ -130,10 +131,7 @@ namespace smt { virtual void display(std::ostream & out) { bool first = true; - bool_var_act_queue::const_iterator it = m_queue.begin(); - bool_var_act_queue::const_iterator end = m_queue.end(); - for (; it != end ; ++it) { - unsigned v = *it; + for (unsigned v : m_queue) { if (m_context.get_assignment(v) == l_undef) { if (first) { out << "remaining case-splits:\n"; @@ -143,8 +141,7 @@ namespace smt { } } if (!first) - out << "\n"; - + out << "\n"; } virtual ~act_case_split_queue() {}; @@ -166,11 +163,15 @@ namespace smt { act_case_split_queue::activity_increased_eh(v); if (m_queue.contains(v)) m_queue.decreased(v); + if (m_delayed_queue.contains(v)) + m_delayed_queue.decreased(v); } virtual void mk_var_eh(bool_var v) { m_queue.reserve(v+1); m_delayed_queue.reserve(v+1); + SASSERT(!m_delayed_queue.contains(v)); + SASSERT(!m_queue.contains(v)); if (m_context.is_searching()) m_delayed_queue.insert(v); else @@ -1099,8 +1100,6 @@ namespace smt { #endif GOAL_STOP(); - - //std::cout << "goal set, time " << m_goal_time.get_seconds() << "\n"; } void set_global_generation() diff --git a/src/smt/smt_case_split_queue.h b/src/smt/smt_case_split_queue.h index 9a3a93cc6..cfa33bfe2 100644 --- a/src/smt/smt_case_split_queue.h +++ b/src/smt/smt_case_split_queue.h @@ -19,9 +19,9 @@ Revision History: #ifndef SMT_CASE_SPLIT_QUEUE_H_ #define SMT_CASE_SPLIT_QUEUE_H_ -#include"smt_types.h" -#include"heap.h" -#include"smt_params.h" +#include "smt/smt_types.h" +#include "util/heap.h" +#include "smt/params/smt_params.h" namespace smt { class context; diff --git a/src/smt/smt_cg_table.cpp b/src/smt/smt_cg_table.cpp index 83d137ff0..ad15fd819 100644 --- a/src/smt/smt_cg_table.cpp +++ b/src/smt/smt_cg_table.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"smt_cg_table.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" +#include "smt/smt_cg_table.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" namespace smt { diff --git a/src/smt/smt_cg_table.h b/src/smt/smt_cg_table.h index c4674034a..1e3fd8b83 100644 --- a/src/smt/smt_cg_table.h +++ b/src/smt/smt_cg_table.h @@ -19,9 +19,9 @@ Revision History: #ifndef SMT_CG_TABLE_H_ #define SMT_CG_TABLE_H_ -#include"smt_enode.h" -#include"hashtable.h" -#include"chashtable.h" +#include "smt/smt_enode.h" +#include "util/hashtable.h" +#include "util/chashtable.h" namespace smt { diff --git a/src/smt/smt_checker.cpp b/src/smt/smt_checker.cpp index 176769d77..a7a25037c 100644 --- a/src/smt/smt_checker.cpp +++ b/src/smt/smt_checker.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"smt_checker.h" -#include"ast_ll_pp.h" +#include "smt/smt_context.h" +#include "smt/smt_checker.h" +#include "ast/ast_ll_pp.h" namespace smt { diff --git a/src/smt/smt_checker.h b/src/smt/smt_checker.h index f6df63c59..5e841f572 100644 --- a/src/smt/smt_checker.h +++ b/src/smt/smt_checker.h @@ -19,8 +19,8 @@ Revision History: #ifndef SMT_CHECKER_H_ #define SMT_CHECKER_H_ -#include"ast.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" namespace smt { diff --git a/src/smt/smt_clause.cpp b/src/smt/smt_clause.cpp index d0f6bdeaa..ccb336941 100644 --- a/src/smt/smt_clause.cpp +++ b/src/smt/smt_clause.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"smt_clause.h" -#include"smt_justification.h" -#include"ast_ll_pp.h" +#include "smt/smt_clause.h" +#include "smt/smt_justification.h" +#include "ast/ast_ll_pp.h" namespace smt { /** diff --git a/src/smt/smt_clause.h b/src/smt/smt_clause.h index 17d13a1dc..d4b9ee02f 100644 --- a/src/smt/smt_clause.h +++ b/src/smt/smt_clause.h @@ -19,11 +19,11 @@ Revision History: #ifndef SMT_CLAUSE_H_ #define SMT_CLAUSE_H_ -#include"ast.h" -#include"smt_literal.h" -#include"tptr.h" -#include"obj_hashtable.h" -#include"smt_justification.h" +#include "ast/ast.h" +#include "smt/smt_literal.h" +#include "util/tptr.h" +#include "util/obj_hashtable.h" +#include "smt/smt_justification.h" namespace smt { diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index ade667e34..80168df18 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"smt_conflict_resolution.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" +#include "smt/smt_context.h" +#include "smt/smt_conflict_resolution.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" namespace smt { @@ -348,10 +348,8 @@ namespace smt { literal_vector & antecedents = m_tmp_literal_vector; antecedents.reset(); justification2literals_core(js, antecedents); - literal_vector::iterator it = antecedents.begin(); - literal_vector::iterator end = antecedents.end(); - for(; it != end; ++it) - process_antecedent(*it, num_marks); + for (literal l : antecedents) + process_antecedent(l, num_marks); } /** @@ -517,11 +515,13 @@ namespace smt { } TRACE("conflict", tout << "processing consequent: "; m_ctx.display_literal_verbose(tout, consequent); tout << "\n"; - tout << "num_marks: " << num_marks << ", js kind: " << js.get_kind() << "\n";); + tout << "num_marks: " << num_marks << ", js kind: " << js.get_kind() << " level: " << m_ctx.get_assign_level(consequent) << "\n"; + ); SASSERT(js != null_b_justification); switch (js.get_kind()) { case b_justification::CLAUSE: { clause * cls = js.get_clause(); + TRACE("conflict", m_ctx.display_clause_detail(tout, cls);); if (cls->is_lemma()) cls->inc_clause_activity(); unsigned num_lits = cls->get_num_literals(); @@ -566,7 +566,7 @@ namespace smt { if (m_ctx.is_marked(l.var())) break; CTRACE("conflict", m_ctx.get_assign_level(l) != m_conflict_lvl && m_ctx.get_assign_level(l) != m_ctx.get_base_level(), - tout << "assign_level(l): " << m_ctx.get_assign_level(l) << ", conflict_lvl: " << m_conflict_lvl << ", l: "; m_ctx.display_literal(tout, l); + tout << "assign_level(l): " << m_ctx.get_assign_level(l) << ", conflict_lvl: " << m_conflict_lvl << ", l: "; m_ctx.display_literal_verbose(tout, l); tout << "\n";); SASSERT(m_ctx.get_assign_level(l) == m_conflict_lvl || // it may also be an (out-of-order) asserted literal @@ -810,8 +810,6 @@ namespace smt { m_new_proofs.push_back(pr); return pr; } - if (m_manager.coarse_grain_proofs()) - return pr; TRACE("norm_eq_proof", tout << "#" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n"; tout << mk_ll_pp(pr, m_manager, true, false);); @@ -1217,7 +1215,7 @@ namespace smt { mk_proof(rhs, c, prs2); while (!prs2.empty()) { proof * pr = prs2.back(); - if (m_manager.fine_grain_proofs()) { + if (m_manager.proofs_enabled()) { pr = m_manager.mk_symmetry(pr); m_new_proofs.push_back(pr); prs1.push_back(pr); diff --git a/src/smt/smt_conflict_resolution.h b/src/smt/smt_conflict_resolution.h index fad3ab50d..b5b857184 100644 --- a/src/smt/smt_conflict_resolution.h +++ b/src/smt/smt_conflict_resolution.h @@ -19,17 +19,17 @@ Revision History: #ifndef SMT_CONFLICT_RESOLUTION_H_ #define SMT_CONFLICT_RESOLUTION_H_ -#include"smt_literal.h" -#include"smt_bool_var_data.h" -#include"smt_justification.h" -#include"smt_enode.h" -#include"dyn_ack.h" -#include"obj_pair_hashtable.h" -#include"smt_params.h" -#include"obj_pair_hashtable.h" -#include"map.h" -#include"watch_list.h" -#include"obj_pair_set.h" +#include "smt/smt_literal.h" +#include "smt/smt_bool_var_data.h" +#include "smt/smt_justification.h" +#include "smt/smt_enode.h" +#include "smt/dyn_ack.h" +#include "util/obj_pair_hashtable.h" +#include "smt/params/smt_params.h" +#include "util/obj_pair_hashtable.h" +#include "util/map.h" +#include "smt/watch_list.h" +#include "util/obj_pair_set.h" typedef approx_set_tpl level_approx_set; diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 20813602e..0bf2a2939 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -16,12 +16,13 @@ Author: Revision History: --*/ -#include "smt_context.h" -#include "ast_util.h" -#include "datatype_decl_plugin.h" -#include "model_pp.h" -#include "max_cliques.h" -#include "stopwatch.h" +#include "util/max_cliques.h" +#include "util/stopwatch.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" +#include "ast/datatype_decl_plugin.h" +#include "model/model_pp.h" +#include "smt/smt_context.h" namespace smt { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 4e56d3004..c508a65cb 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -17,26 +17,26 @@ Revision History: --*/ #include -#include"smt_context.h" -#include"luby.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"warning.h" -#include"smt_quick_checker.h" -#include"proof_checker.h" -#include"ast_util.h" -#include"uses_theory.h" -#include"model.h" -#include"smt_for_each_relevant_expr.h" -#include"timeit.h" -#include"well_sorted.h" -#include"union_find.h" -#include"smt_model_generator.h" -#include"smt_model_checker.h" -#include"smt_model_finder.h" -#include"model_pp.h" -#include"ast_smt2_pp.h" -#include"ast_translation.h" +#include "smt/smt_context.h" +#include "util/luby.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "util/warning.h" +#include "smt/smt_quick_checker.h" +#include "ast/proofs/proof_checker.h" +#include "ast/ast_util.h" +#include "smt/uses_theory.h" +#include "model/model.h" +#include "smt/smt_for_each_relevant_expr.h" +#include "util/timeit.h" +#include "ast/well_sorted.h" +#include "util/union_find.h" +#include "smt/smt_model_generator.h" +#include "smt/smt_model_checker.h" +#include "smt/smt_model_finder.h" +#include "model/model_pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_translation.h" namespace smt { @@ -95,7 +95,7 @@ namespace smt { if (!relevancy()) m_fparams.m_relevancy_lemma = false; - + m_model_generator->set_context(this); } @@ -106,26 +106,30 @@ namespace smt { ast_manager& src_m = src_ctx.get_manager(); expr_ref dst_f(dst_m); - SASSERT(lit != false_literal && lit != true_literal); - bool_var v = b2v.get(lit.var(), null_bool_var); - if (v == null_bool_var) { - expr* e = src_ctx.m_bool_var2expr.get(lit.var(), 0); - SASSERT(e); - dst_f = tr(e); + SASSERT(lit != false_literal && lit != true_literal); + bool_var v = b2v.get(lit.var(), null_bool_var); + if (v == null_bool_var) { + expr* e = src_ctx.m_bool_var2expr.get(lit.var(), 0); + SASSERT(e); + dst_f = tr(e); v = dst_ctx.get_bool_var_of_id_option(dst_f->get_id()); - if (v != null_bool_var) { - } + if (v != null_bool_var) { + } else if (src_m.is_not(e) || src_m.is_and(e) || src_m.is_or(e) || - src_m.is_iff(e) || src_m.is_ite(e)) { - v = dst_ctx.mk_bool_var(dst_f); - } - else { - dst_ctx.internalize_formula(dst_f, false); - v = dst_ctx.get_bool_var(dst_f); - } - b2v.setx(lit.var(), v, null_bool_var); - } - return literal(v, lit.sign()); + src_m.is_iff(e) || src_m.is_ite(e)) { + v = dst_ctx.mk_bool_var(dst_f); + } + else { + dst_ctx.internalize_formula(dst_f, false); + v = dst_ctx.get_bool_var(dst_f); + } + b2v.setx(lit.var(), v, null_bool_var); + } + return literal(v, lit.sign()); + } + + bool context::get_cancel_flag() { + return !m_manager.limit().inc(); } @@ -133,12 +137,12 @@ namespace smt { ast_manager& dst_m = dst_ctx.get_manager(); ast_manager& src_m = src_ctx.get_manager(); src_ctx.pop_to_base_lvl(); - + if (src_ctx.m_base_lvl > 0) { throw default_exception("Cloning contexts within a user-scope is not allowed"); } SASSERT(src_ctx.m_base_lvl == 0); - + ast_translation tr(src_m, dst_m, false); dst_ctx.set_logic(src_ctx.m_setup.get_logic()); @@ -147,7 +151,7 @@ namespace smt { asserted_formulas& src_af = src_ctx.m_asserted_formulas; asserted_formulas& dst_af = dst_ctx.m_asserted_formulas; - // Copy asserted formulas. + // Copy asserted formulas. for (unsigned i = 0; i < src_af.get_num_formulas(); ++i) { expr_ref fml(dst_m); proof_ref pr(dst_m); @@ -156,7 +160,7 @@ namespace smt { if (pr_src) { pr = tr(pr_src); } - dst_af.assert_expr(fml, pr); + dst_af.assert_expr(fml, pr); } if (!src_ctx.m_setup.already_configured()) { @@ -187,7 +191,7 @@ namespace smt { lits.push_back(lit); } dst_ctx.mk_clause(lits.size(), lits.c_ptr(), 0, src_cls.get_kind(), 0); - } + } vector::const_iterator it = src_ctx.m_watches.begin(); vector::const_iterator end = src_ctx.m_watches.end(); literal ls[2]; @@ -203,12 +207,12 @@ namespace smt { ls[0] = TRANSLATE(neg_l1); ls[1] = TRANSLATE(l2); dst_ctx.mk_clause(2, ls, 0, CLS_AUX, 0); - } + } } } #endif - - TRACE("smt_context", + + TRACE("smt_context", src_ctx.display(tout); dst_ctx.display(tout);); } @@ -220,25 +224,9 @@ namespace smt { void context::copy_plugins(context& src, context& dst) { - // copy missing simplifier_plugins - // remark: some simplifier_plugins are automatically created by the asserted_formulas class. - simplifier & src_s = src.get_simplifier(); - simplifier & dst_s = dst.get_simplifier(); - ptr_vector::const_iterator it1 = src_s.begin_plugins(); - ptr_vector::const_iterator end1 = src_s.end_plugins(); - for (; it1 != end1; ++it1) { - simplifier_plugin * p = *it1; - if (dst_s.get_plugin(p->get_family_id()) == 0) { - dst.register_plugin(p->mk_fresh()); - } - SASSERT(dst_s.get_plugin(p->get_family_id()) != 0); - } - // copy theory plugins - ptr_vector::iterator it2 = src.m_theory_set.begin(); - ptr_vector::iterator end2 = src.m_theory_set.end(); - for (; it2 != end2; ++it2) { - theory * new_th = (*it2)->mk_fresh(&dst); + for (theory* old_th : src.m_theory_set) { + theory * new_th = old_th->mk_fresh(&dst); dst.register_plugin(new_th); } } @@ -246,12 +234,10 @@ namespace smt { context * context::mk_fresh(symbol const * l, smt_params * p) { context * new_ctx = alloc(context, m_manager, p == 0 ? m_fparams : *p); new_ctx->set_logic(l == 0 ? m_setup.get_logic() : *l); - copy_plugins(*this, *new_ctx); + copy_plugins(*this, *new_ctx); return new_ctx; } - - void context::init() { app * t = m_manager.mk_true(); mk_bool_var(t); @@ -299,9 +285,9 @@ namespace smt { d.set_justification(j); } - + void context::assign_core(literal l, b_justification j, bool decision) { - TRACE("assign_core", tout << (decision?"decision: ":"propagating: ") << l << " "; + TRACE("assign_core", tout << (decision?"decision: ":"propagating: ") << l << " "; display_literal_verbose(tout, l); tout << " level: " << m_scope_lvl << "\n"; display(tout, j);); m_assigned_literals.push_back(l); @@ -319,7 +305,7 @@ namespace smt { d.m_phase = !l.sign(); TRACE("phase_selection", tout << "saving phase, is_pos: " << d.m_phase << " l: " << l << "\n";); - TRACE("relevancy", + TRACE("relevancy", tout << "is_atom: " << d.is_atom() << " is relevant: " << is_relevant_core(l) << "\n";); if (d.is_atom() && (m_fparams.m_relevancy_lvl == 0 || (m_fparams.m_relevancy_lvl == 1 && !d.is_quantifier()) || is_relevant_core(l))) m_atom_propagation_queue.push_back(l); @@ -331,12 +317,12 @@ namespace smt { // a unit is asserted at search level. Mark it as relevant. // this addresses bug... where a literal becomes fixed to true (false) // as a conflict gets assigned misses relevancy (and quantifier instantiation). - // + // if (false && !decision && relevancy() && at_search_level() && !is_relevant_core(l)) { mark_as_relevant(l); } } - + bool context::bcp() { SASSERT(!inconsistent()); while (m_qhead < m_assigned_literals.size()) { @@ -385,17 +371,17 @@ namespace smt { cls->set_literal(0, cls->get_literal(1)); cls->set_literal(1, not_l); } - + SASSERT(cls->get_literal(1) == not_l); - - literal first_lit = cls->get_literal(0); + + literal first_lit = cls->get_literal(0); lbool first_lit_val = get_assignment(first_lit); - - if (first_lit_val == l_true) { - *it2 = *it; // clause is already satisfied, keep it + + if (first_lit_val == l_true) { + *it2 = *it; // clause is already satisfied, keep it it2++; } - else { + else { literal * it3 = cls->begin_literals() + 2; literal * end3 = cls->end_literals(); for(; it3 != end3; ++it3) { @@ -408,7 +394,7 @@ namespace smt { goto found_watch; } } - // did not find watch... + // did not find watch... if (first_lit_val == l_false) { // CONFLICT // copy remaining watches @@ -427,8 +413,8 @@ namespace smt { // PROPAGATION SASSERT(first_lit_val == l_undef); SASSERT(get_assignment(first_lit) == l_undef); - SASSERT(is_unit_clause(cls)); - *it2 = *it; + SASSERT(is_unit_clause(cls)); + *it2 = *it; it2++; // keep clause m_stats.m_num_propagations++; // It is safe to call assign_core instead of assign because first_lit is unassigned @@ -440,13 +426,13 @@ namespace smt { //if (!(m_manager.is_eq(e) && m_manager.get_sort(to_app(e)->get_arg(0))->get_family_id() == m_manager.get_family_id("array"))) mark_as_relevant(e); } - } - found_watch:; - } + } + found_watch:; + } } - SASSERT(it2 <= end); + SASSERT(it2 <= end); w.set_end_clause(it2); - } + } return true; } @@ -473,7 +459,7 @@ namespace smt { theory * t = get_theory(th); if (t->get_enode(lhs)->is_interpreted() && t->get_enode(rhs)->is_interpreted()) return; - TRACE("add_diseq", + TRACE("add_diseq", tout << "#" << t->get_enode(lhs)->get_owner_id() << " != " << "#" << t->get_enode(rhs)->get_owner_id() << "\n";); @@ -490,7 +476,7 @@ namespace smt { m_n1(n1), m_r2_num_parents(r2_num_parents) { } - + virtual void undo(context & ctx) { ctx.undo_add_eq(m_r1, m_n1, m_r2_num_parents); } @@ -501,32 +487,33 @@ namespace smt { */ void context::add_eq(enode * n1, enode * n2, eq_justification js) { unsigned old_trail_size = m_trail_stack.size(); + scoped_suspend_rlimit _suspend_cancel(m_manager.limit()); try { TRACE("add_eq", tout << "assigning: #" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n";); TRACE("add_eq_detail", tout << "assigning\n" << mk_pp(n1->get_owner(), m_manager) << "\n" << mk_pp(n2->get_owner(), m_manager) << "\n"; tout << "kind: " << js.get_kind() << "\n";); - + m_stats.m_num_add_eq++; enode * r1 = n1->get_root(); enode * r2 = n2->get_root(); - + if (r1 == r2) { TRACE("add_eq", tout << "redundant constraint.\n";); return; } - + if (r1->is_interpreted() && r2->is_interpreted()) { TRACE("add_eq", tout << "interpreted roots conflict.\n";); set_conflict(mk_justification(eq_conflict_justification(n1, n2, js))); return; } - + // Swap r1 and r2: // 1. if the "equivalence" class of r1 is bigger than the equivalence class of r2 // OR // 2. r1 is interpreted but r2 is not. - // + // // The second condition is used to enforce the invariant that if a class contain // an interepreted enode then the root is also interpreted. if ((r1->get_class_size() > r2->get_class_size() && !r2->is_interpreted()) || r1->is_interpreted()) { @@ -534,10 +521,10 @@ namespace smt { std::swap(n1, n2); std::swap(r1, r2); } - - TRACE("add_eq", tout << "merging: #" << r1->get_owner_id() << " #" << r2->get_owner_id() << + + TRACE("add_eq", tout << "merging: #" << r1->get_owner_id() << " #" << r2->get_owner_id() << " n1: #" << n1->get_owner_id() << "\n";); - + // It is necessary to propagate relevancy to other elements of // the equivalence class. This is nessary to enforce the invariant // in the field m_parent of the enode class. @@ -554,13 +541,17 @@ namespace smt { else if (is_relevant(r2)) { // && !m_manager.is_eq(r2->get_owner())) { // !is_eq HACK mark_as_relevant(r1); } - + + TRACE("add_eq", tout << "to trail\n";); + push_trail(add_eq_trail(r1, n1, r2->get_num_parents())); - + + TRACE("add_eq", tout << "qmanager add_eq\n";); m_qmanager->add_eq_eh(r1, r2); - + + TRACE("add_eq", tout << "merge theory_vars\n";); merge_theory_vars(n2, n1, js); - + // 'Proof' tree // n1 -> ... -> r1 // n2 -> ... -> r2 @@ -571,8 +562,8 @@ namespace smt { SASSERT(r1->trans_reaches(n1)); // --------------- // r1 -> .. -> n1 -> n2 -> ... -> r2 - - + + #if 0 { static unsigned counter = 0; @@ -584,40 +575,44 @@ namespace smt { num_bad_adds++; } if (num_adds % 100000 == 0) { - verbose_stream() << "[add-eq]: " << num_bad_adds << " " << num_adds << " " + verbose_stream() << "[add-eq]: " << num_bad_adds << " " << num_adds << " " << static_cast(num_bad_adds)/static_cast(num_adds) << "\n"; } } #endif - - + + + TRACE("add_eq", tout << "remove_parents_from_cg_table\n";); remove_parents_from_cg_table(r1); - + enode * curr = r1; do { curr->m_root = r2; curr = curr->m_next; } while(curr != r1); - + SASSERT(r1->get_root() == r2); - + + TRACE("add_eq", tout << "reinsert_parents_into_cg_table\n";); reinsert_parents_into_cg_table(r1, r2, n1, n2, js); - + + TRACE("add_eq", tout << "propagate_bool_enode_assignment\n";); if (n2->is_bool()) propagate_bool_enode_assignment(r1, r2, n1, n2); - + // Merge "equivalence" classes std::swap(r1->m_next, r2->m_next); - + // Update "equivalence" class size r2->m_class_size += r1->m_class_size; - + CASSERT("add_eq", check_invariant()); } catch (...) { // Restore trail size since procedure was interrupted in the middle. // If the add_eq_trail remains on the trail stack, then Z3 may crash when the destructor is invoked. + TRACE("add_eq", tout << "add_eq interrupted. This is unsafe " << m_manager.limit().get_cancel_flag() << "\n";); m_trail_stack.shrink(old_trail_size); throw; } @@ -642,12 +637,12 @@ namespace smt { num_eqs++; num_parents++; if (num_parents % 100000 == 0) { - verbose_stream() << "[remove-cg] " << num_eqs << " " << num_parents << " " + verbose_stream() << "[remove-cg] " << num_eqs << " " << num_parents << " " << static_cast(num_eqs)/static_cast(num_parents) << "\n"; } } #endif - SASSERT(parent->is_marked() || !parent->is_cgc_enabled() || + SASSERT(parent->is_marked() || !parent->is_cgc_enabled() || (!parent->is_true_eq() && parent->is_cgr() == m_cg_table.contains_ptr(parent)) || (parent->is_true_eq() && !m_cg_table.contains_ptr(parent))); if (!parent->is_marked() && parent->is_cgr() && !parent->is_true_eq()) { @@ -667,12 +662,12 @@ namespace smt { cg_table at remove_parents_from_cg_table. Some of these parents will become congruent to other enodes, and a new equality will be propagated. Moreover, this method is also used for doing equality propagation. - + The parents of r1 that remain as congruence roots are copied to the r2->m_parents. The n1, n2, js arguments are used to implement dynamic ackermanization. - js is a justification for n1 and n2 being equal, and the equality n1 = n2 is + js is a justification for n1 and n2 being equal, and the equality n1 = n2 is the one that implied r1 = r2. */ void context::reinsert_parents_into_cg_table(enode * r1, enode * r2, enode * n1, enode * n2, eq_justification js) { @@ -737,7 +732,7 @@ namespace smt { the following sequence starting at n and ending at n->get_root. - N1 = n + N1 = n N_{i+1} = N_i->m_trans.m_target and, there is an k such that N_k = n->get_root() @@ -768,12 +763,12 @@ namespace smt { This method is used to improve the quality of the conflict clauses produced by the logical context. - + Consider the following example: - Consider the following sequence of equalities: n1 = n2 = n3 = n4 = n5 = n6 - + - Now, assume that n1 is the root of the equivalence class after each merge. So, the 'proof' branch will have the following shape: @@ -782,12 +777,12 @@ namespace smt { - Assuming that all nodes are attached to theory variable, then the following sequence of equalities is sent to the theory if the method get_closest_var is not used: - + n1 = n2, n1 = n3, n1 = n4, n1 = n5, n1 = n6 - This sequence is bad, and bad justifications may be produced by theory. For example, assume the following arithmetic constraint - + n5 < n6 For the arithmetic module, the best justification will be: @@ -798,7 +793,7 @@ namespace smt { When the method get_closest_var is used in the communication with theories, the logical context will send the natural sequence of equalities to the theories: - + n1 = n2 = n3 = n4 = n5 = n6 */ theory_var context::get_closest_var(enode * n, theory_id th_id) { @@ -816,7 +811,7 @@ namespace smt { /** \brief Merge the theory variables of n2->get_root() and n1->get_root(), the result is stored in n2->get_root(). New th_var equalities are propagated to the theories. - + \remark In most cases, an enode is attached to at most one theory var. */ void context::merge_theory_vars(enode * n2, enode * n1, eq_justification js) { @@ -826,7 +821,7 @@ namespace smt { TRACE("merge_theory_vars", tout << "Neither have theory vars #" << n1->get_owner()->get_id() << " #" << n2->get_owner()->get_id() << "\n";); return; } - + theory_id from_th = null_theory_id; if (js.get_kind() == eq_justification::JUSTIFICATION) @@ -839,8 +834,8 @@ namespace smt { // verbose_stream() << "[merge_theory_vars] t2: " << t2 << ", t1: " << t1 << "\n"; theory_var v2 = m_fparams.m_new_core2th_eq ? get_closest_var(n2, t2) : r2->m_th_var_list.get_th_var(); theory_var v1 = m_fparams.m_new_core2th_eq ? get_closest_var(n1, t1) : r1->m_th_var_list.get_th_var(); - TRACE("merge_theory_vars", - tout << "v2: " << v2 << " #" << r2->get_owner_id() << ", v1: " << v1 << " #" << r1->get_owner_id() + TRACE("merge_theory_vars", + tout << "v2: " << v2 << " #" << r2->get_owner_id() << ", v1: " << v1 << " #" << r1->get_owner_id() << ", t2: " << t2 << ", t1: " << t1 << "\n";); if (v2 != null_theory_var && v1 != null_theory_var) { if (t1 == t2) { @@ -867,7 +862,7 @@ namespace smt { } else { // r1 and/or r2 have more than one theory variable. - TRACE("merge_theory_vars", + TRACE("merge_theory_vars", tout << "#" << r1->get_owner_id() << " == #" << r2->get_owner_id() << "\n";); @@ -889,7 +884,7 @@ namespace smt { } l2 = l2->get_next(); } - + theory_var_list * l1 = r1->get_th_var_list(); while (l1) { theory_id t1 = l1->get_th_id(); @@ -905,7 +900,7 @@ namespace smt { } } } - + /** \brief Propabate the boolean assignment when two equivalence classes are merged. */ @@ -959,7 +954,7 @@ namespace smt { bool_var v2 = enode2bool_var(target); lbool val2 = get_assignment(v2); if (val2 != val) { - if (val2 != l_undef && congruent(source, target) && source->get_num_args() > 0) + if (val2 != l_undef && congruent(source, target) && source->get_num_args() > 0) m_dyn_ack_manager.cg_conflict_eh(source->get_owner(), target->get_owner()); assign(literal(v2, sign), mk_justification(mp_iff_justification(source, target))); } @@ -986,7 +981,7 @@ namespace smt { enode * parent = *it; if (parent->is_cgc_enabled()) { TRACE("add_eq_parents", tout << "removing: #" << parent->get_owner_id() << "\n";); - CTRACE("add_eq", !parent->is_cgr(), + CTRACE("add_eq", !parent->is_cgr() || !m_cg_table.contains_ptr(parent), tout << "old num_parents: " << r2_num_parents << ", num_parents: " << r2->m_parents.size() << ", parent: #" << parent->get_owner_id() << ", parents: \n"; for (unsigned i = 0; i < r2->m_parents.size(); i++) { @@ -1017,10 +1012,10 @@ namespace smt { TRACE("add_eq_parents", tout << "visiting: #" << parent->get_owner_id() << "\n";); if (parent->is_cgc_enabled()) { enode * cg = parent->m_cg; - if (!parent->is_true_eq() && + if (!parent->is_true_eq() && (parent == cg || // parent was root of the congruence class before and after the merge !congruent(parent, cg) // parent was root of the congruence class before but not after the merge - )) { + )) { TRACE("add_eq_parents", tout << "trying to reinsert\n";); m_cg_table.insert(parent); parent->m_cg = parent; @@ -1057,17 +1052,17 @@ namespace smt { // n2 -> ... -> r2 SASSERT(n1->trans_reaches(r1)); SASSERT(r1->m_trans.m_target == 0); - + CASSERT("add_eq", check_invariant()); } /** - \brief Auxiliary method for undo_add_eq. + \brief Auxiliary method for undo_add_eq. It restores the theory variables of a given root enode. This method deletes any theory variable v2 of r2 (for a theory t2) whenever: - get_theory(t2)->get_enode(v2)->get_root() != r2 + get_theory(t2)->get_enode(v2)->get_root() != r2 That is, v2 is not equivalent to r2 anymore. */ @@ -1078,7 +1073,7 @@ namespace smt { while (l2) { theory_var v2 = l2->get_th_var(); theory_id t2 = l2->get_th_id(); - + if (get_theory(t2)->get_enode(v2)->get_root() != r2) { SASSERT(get_theory(t2)->get_enode(v2)->get_root() == r1); l2 = l2->get_next(); @@ -1122,7 +1117,7 @@ namespace smt { #ifdef Z3DEBUG push_trail(push_back_trail(m_diseq_vector)); m_diseq_vector.push_back(enode_pair(n1, n2)); -#endif +#endif if (r1 == r2) { TRACE("add_diseq_inconsistent", tout << "add_diseq #" << n1->get_owner_id() << " #" << n2->get_owner_id() << " inconsistency, scope_lvl: " << m_scope_lvl << "\n";); @@ -1166,7 +1161,7 @@ namespace smt { } return true; } - + /** \brief Return true if n1 and n2 are known to be disequal in the logical context. @@ -1215,7 +1210,7 @@ namespace smt { if (parent->is_eq() && is_relevant(parent->get_owner()) && get_assignment(enode2bool_var(parent)) == l_false && ((parent->get_arg(0)->get_root() == n1->get_root() && parent->get_arg(1)->get_root() == n2->get_root()) || (parent->get_arg(1)->get_root() == n1->get_root() && parent->get_arg(0)->get_root() == n2->get_root()))) { - TRACE("is_diseq_bug", tout << "parent: #" << parent->get_owner_id() << ", parent->root: #" << + TRACE("is_diseq_bug", tout << "parent: #" << parent->get_owner_id() << ", parent->root: #" << parent->get_root()->get_owner_id() << " assignment(parent): " << get_assignment(enode2bool_var(parent)) << " args: #" << parent->get_arg(0)->get_owner_id() << " #" << parent->get_arg(1)->get_owner_id() << "\n";); return true; @@ -1274,7 +1269,7 @@ namespace smt { enode * arg2 = p2->get_arg(j)->get_root(); if (arg1 == arg2) continue; - if ((arg1 == r1 || arg1 == r2) && + if ((arg1 == r1 || arg1 == r2) && (arg2 == r1 || arg2 == r2)) continue; break; @@ -1291,7 +1286,7 @@ namespace smt { else { if (depth >= m_almost_cg_tables.size()) { unsigned old_sz = m_almost_cg_tables.size(); - m_almost_cg_tables.resize(depth+1, 0); + m_almost_cg_tables.resize(depth+1); for (unsigned i = old_sz; i < depth + 1; i++) m_almost_cg_tables[i] = alloc(almost_cg_table); } @@ -1353,8 +1348,8 @@ namespace smt { expr * arg = r->get_owner()->get_arg(i); SASSERT(e_internalized(arg)); enode * _arg = get_enode(arg); - CTRACE("eq_to_bug", args[i]->get_root() != _arg->get_root(), - tout << "#" << args[i]->get_owner_id() << " #" << args[i]->get_root()->get_owner_id() + CTRACE("eq_to_bug", args[i]->get_root() != _arg->get_root(), + tout << "#" << args[i]->get_owner_id() << " #" << args[i]->get_root()->get_owner_id() << " #" << _arg->get_owner_id() << " #" << _arg->get_root()->get_owner_id() << "\n"; tout << "#" << r->get_owner_id() << "\n"; display(tout);); @@ -1367,8 +1362,8 @@ namespace smt { } /** - \brief Process the equality propagation queue. - + \brief Process the equality propagation queue. + \remark The method assign_eq adds a new entry on this queue. */ bool context::propagate_eqs() { @@ -1385,7 +1380,7 @@ namespace smt { std::cout << counter1 << " " << counter2 << "\n"; #endif add_eq(entry.m_lhs, entry.m_rhs, entry.m_justification); - if (inconsistent()) + if (inconsistent()) return false; } m_eq_propagation_queue.reset(); @@ -1403,7 +1398,7 @@ namespace smt { bool_var v = l.var(); bool_var_data & d = get_bdata(v); lbool val = get_assignment(v); - TRACE("propagate_atoms", tout << "propagating atom, #" << bool_var2expr(v)->get_id() << ", is_enode(): " << d.is_enode() + TRACE("propagate_atoms", tout << "propagating atom, #" << bool_var2expr(v)->get_id() << ", is_enode(): " << d.is_enode() << " tag: " << (d.is_eq()?"eq":"") << (d.is_theory_atom()?"th":"") << (d.is_quantifier()?"q":"") << " " << l << "\n";); SASSERT(val != l_undef); if (d.is_enode()) @@ -1435,7 +1430,7 @@ namespace smt { // Remark: when RELEVANCY_LEMMA is true, a quantifier can be asserted to false and marked as relevant. // This happens when a quantifier is part of a lemma (conflict-clause), and this conflict clause // becomes an unit-clause and the remaining literal is the negation of a quantifier. - CTRACE("assign_quantifier_bug", get_assignment(v) != l_true, + CTRACE("assign_quantifier_bug", get_assignment(v) != l_true, tout << "#" << bool_var2expr(v)->get_id() << " val: " << get_assignment(v) << "\n"; tout << mk_pp(bool_var2expr(v), m_manager) << "\n"; display(tout);); @@ -1562,7 +1557,7 @@ namespace smt { /** \brief Return the truth assignment for an expression that is attached to a boolean variable. - + \pre The expression must be attached to a boolean variable. */ inline lbool context::get_assignment_core(expr * n) const { @@ -1582,7 +1577,7 @@ namespace smt { lbool context::get_assignment(expr * n) const { if (m_manager.is_false(n)) return l_false; - if (m_manager.is_not(n)) + if (m_manager.is_not(n)) return ~get_assignment_core(to_app(n)->get_arg(0)); return get_assignment_core(n); } @@ -1621,14 +1616,14 @@ namespace smt { */ void context::get_assignments(expr_ref_vector& assignments) { literal_vector::const_iterator it = m_assigned_literals.begin(); - literal_vector::const_iterator end = m_assigned_literals.end(); + literal_vector::const_iterator end = m_assigned_literals.end(); for (; it != end; ++it) { expr_ref e(m_manager); literal2expr(*it, e); assignments.push_back(e); } } - + void context::relevant_eh(expr * n) { if (b_internalized(n)) { bool_var v = get_bool_var(n); @@ -1646,7 +1641,7 @@ namespace smt { #ifndef SMTCOMP m_case_split_queue->relevant_eh(n); #endif - + if (is_app(n)) { if (e_internalized(n)) { SASSERT(relevancy()); @@ -1663,15 +1658,15 @@ namespace smt { propagated_th = th; // <<< mark that relevancy_eh was already invoked for theory th. } } - + if (e_internalized(n)) { - enode * e = get_enode(n); + enode * e = get_enode(n); theory_var_list * l = e->get_th_var_list(); while (l) { theory_id th_id = l->get_th_id(); theory * th = get_theory(th_id); // I don't want to invoke relevant_eh twice for the same n. - if (th != propagated_th) + if (th != propagated_th) th->relevant_eh(to_app(n)); l = l->get_next(); } @@ -1749,7 +1744,7 @@ namespace smt { } bool context::can_propagate() const { - return + return m_qhead != m_assigned_literals.size() || m_relevancy_propagator->can_propagate() || !m_atom_propagation_queue.empty() || @@ -1776,7 +1771,7 @@ namespace smt { } SASSERT(!inconsistent()); propagate_relevancy(qhead); - if (inconsistent()) + if (inconsistent()) return false; if (!propagate_atoms()) return false; @@ -1784,7 +1779,7 @@ namespace smt { return false; propagate_th_eqs(); propagate_th_diseqs(); - if (inconsistent()) + if (inconsistent()) return false; if (!propagate_theories()) return false; @@ -1820,12 +1815,13 @@ namespace smt { return m_fingerprints.contains(q, q->get_id(), num_bindings, bindings); } - bool context::add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, + bool context::add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, ptr_vector & used_enodes) { return m_qmanager->add_instance(q, pat, num_bindings, bindings, max_generation, min_top_generation, max_top_generation, used_enodes); } - + void context::rescale_bool_var_activity() { + TRACE("case_split", tout << "rescale\n";); svector::iterator it = m_activity.begin(); svector::iterator end = m_activity.end(); for (; it != end; ++it) @@ -1850,15 +1846,15 @@ namespace smt { static unsigned counter = 0; counter++; if (counter % 100 == 0) { - TRACE("activity_profile", + TRACE("activity_profile", for (unsigned i=0; i m_lit_occs[(~l).index()].size(); + is_pos = m_lit_occs[l.index()].size() > m_lit_occs[(~l).index()].size(); break; } default: @@ -1971,7 +1967,7 @@ namespace smt { m_fingerprints.push_scope(); m_case_split_queue->push_scope(); m_asserted_formulas.push_scope(); - + ptr_vector::iterator it = m_theory_set.begin(); ptr_vector::iterator end = m_theory_set.end(); for (; it != end; ++it) @@ -1988,7 +1984,7 @@ namespace smt { /** \brief Remove watch literal idx from the given clause. - + \pre idx must be 0 or 1. */ void context::remove_watch_literal(clause * cls, unsigned idx) { @@ -2014,13 +2010,13 @@ namespace smt { } /** - \brief Delete the given clause. - + \brief Delete the given clause. + \pre Clause is not in the reinit stack. */ void context::del_clause(clause * cls) { SASSERT(m_flushing || !cls->in_reinit_stack()); - if (!cls->deleted()) + if (!cls->deleted()) remove_cls_occs(cls); cls->deallocate(m_manager); m_stats.m_num_del_clause++; @@ -2066,7 +2062,7 @@ namespace smt { d.set_null_justification(); m_case_split_queue->unassign_var_eh(v); } - + m_assigned_literals.shrink(old_lim); m_qhead = old_lim; SASSERT(m_qhead == m_assigned_literals.size()); @@ -2136,8 +2132,8 @@ namespace smt { /** \brief When a clause is reinitialized (see reinit_clauses) enodes and literals may need to be recreated. When an enode is recreated, I want to use the same generation - number it had before being deleted. Otherwise the generation will be 0, and will affect - the loop prevetion heuristics used to control quantifier instantiation. + number it had before being deleted. Otherwise the generation will be 0, and will affect + the loop prevetion heuristics used to control quantifier instantiation. Thus, I cache the generation number of enodes that will be deleted during backtracking and recreated by reinit_clauses. */ @@ -2183,11 +2179,11 @@ namespace smt { for(unsigned i = 0; i < num_lits; i++) { bool_var v = lits[i].var(); unsigned ilvl = get_intern_level(v); - if (ilvl > new_scope_lvl) + if (ilvl > new_scope_lvl) cache_generation(bool_var2expr(v), new_scope_lvl); } } - + /** \brief See cache_generation(unsigned new_scope_lvl) */ @@ -2222,7 +2218,7 @@ namespace smt { } } } - + /** \brief See cache_generation(unsigned new_scope_lvl) */ @@ -2234,7 +2230,7 @@ namespace smt { /** \brief Reinitialize learned clauses (lemmas) that contain boolean variables that were deleted during backtracking. - + \remark num_bool_vars contains the number of boolean variables alive after backtracking. So, a clause contains a dead variable if it contains a literal l where l.var() >= num_bool_vars. @@ -2289,20 +2285,20 @@ namespace smt { } } } - + unsigned ilvl = 0; (void)ilvl; for (unsigned j = 0; j < num; j++) { expr * atom = cls->get_atom(j); bool sign = cls->get_atom_sign(j); - // Atom can be (NOT foo). This can happen, for example, when + // Atom can be (NOT foo). This can happen, for example, when // the NOT-application is a child of an uninterpreted function symbol. // So, when reinternalizing the NOT-atom I should set the gate_ctx to false, // and force expression to be reinternalized. // Otherwise I set gate_ctx to true bool gate_ctx = !m_manager.is_not(atom); internalize(atom, gate_ctx); - SASSERT(b_internalized(atom)); + SASSERT(b_internalized(atom)); bool_var v = get_bool_var(atom); DEBUG_CODE({ if (get_intern_level(v) > ilvl) @@ -2321,7 +2317,7 @@ namespace smt { if (lit_occs_enabled()) add_lit_occs(cls); - + literal l1 = cls->get_literal(0); literal l2 = cls->get_literal(1); @@ -2329,9 +2325,9 @@ namespace smt { set_conflict(b_justification(cls)); else if (get_assignment(l2) == l_false) assign(l1, b_justification(cls)); - + TRACE("reinit_clauses", tout << "reinit clause:\n"; display_clause_detail(tout, cls); tout << "\n"; - tout << "activity: " << cls->get_activity() << ", num_bool_vars: " << num_bool_vars << ", scope_lvl: " + tout << "activity: " << cls->get_activity() << ", num_bool_vars: " << num_bool_vars << ", scope_lvl: " << m_scope_lvl << "\n";); keep = true; } @@ -2348,8 +2344,8 @@ namespace smt { keep = true; } } - - // SASSERT(!(cls->get_num_literals() == 3 && + + // SASSERT(!(cls->get_num_literals() == 3 && // (cls->get_literal(0).index() == 624 || cls->get_literal(0).index() == 103 || cls->get_literal(0).index() == 629) && // (cls->get_literal(1).index() == 624 || cls->get_literal(1).index() == 103 || cls->get_literal(1).index() == 629) && // (cls->get_literal(2).index() == 624 || cls->get_literal(2).index() == 103 || cls->get_literal(2).index() == 629))); @@ -2397,86 +2393,91 @@ namespace smt { of boolean variables before reinitializing clauses. This value is useful because it can be used to detect which boolean variables were deleted. - + \warning This method will not invoke reset_cache_generation. */ unsigned context::pop_scope_core(unsigned num_scopes) { - if (m_manager.has_trace_stream()) - m_manager.trace_stream() << "[pop] " << num_scopes << " " << m_scope_lvl << "\n"; + try { + if (m_manager.has_trace_stream()) + m_manager.trace_stream() << "[pop] " << num_scopes << " " << m_scope_lvl << "\n"; - TRACE("context", tout << "backtracking: " << num_scopes << "\n";); - TRACE("pop_scope_detail", display(tout);); - SASSERT(num_scopes > 0); - SASSERT(num_scopes <= m_scope_lvl); - SASSERT(m_scopes.size() == m_scope_lvl); + TRACE("context", tout << "backtracking: " << num_scopes << " from " << m_scope_lvl << "\n";); + TRACE("pop_scope_detail", display(tout);); + SASSERT(num_scopes > 0); + SASSERT(num_scopes <= m_scope_lvl); + SASSERT(m_scopes.size() == m_scope_lvl); - unsigned new_lvl = m_scope_lvl - num_scopes; - - cache_generation(new_lvl); - m_qmanager->pop(num_scopes); - m_case_split_queue->pop_scope(num_scopes); + unsigned new_lvl = m_scope_lvl - num_scopes; - TRACE("pop_scope", tout << "backtracking: " << num_scopes << ", new_lvl: " << new_lvl << "\n";); - scope & s = m_scopes[new_lvl]; - TRACE("context", tout << "backtracking new_lvl: " << new_lvl << "\n";); + cache_generation(new_lvl); + m_qmanager->pop(num_scopes); + m_case_split_queue->pop_scope(num_scopes); - unsigned units_to_reassert_lim = s.m_units_to_reassert_lim; + TRACE("pop_scope", tout << "backtracking: " << num_scopes << ", new_lvl: " << new_lvl << "\n";); + scope & s = m_scopes[new_lvl]; + TRACE("context", tout << "backtracking new_lvl: " << new_lvl << "\n";); - if (new_lvl < m_base_lvl) { - base_scope & bs = m_base_scopes[new_lvl]; - del_clauses(m_lemmas, bs.m_lemmas_lim); - m_simp_qhead = bs.m_simp_qhead_lim; - if (!bs.m_inconsistent) { - m_conflict = null_b_justification; - m_not_l = null_literal; - m_unsat_proof = 0; + unsigned units_to_reassert_lim = s.m_units_to_reassert_lim; + + if (new_lvl < m_base_lvl) { + base_scope & bs = m_base_scopes[new_lvl]; + del_clauses(m_lemmas, bs.m_lemmas_lim); + m_simp_qhead = bs.m_simp_qhead_lim; + if (!bs.m_inconsistent) { + m_conflict = null_b_justification; + m_not_l = null_literal; + m_unsat_proof = 0; + } + m_base_scopes.shrink(new_lvl); } - m_base_scopes.shrink(new_lvl); - } - else { - m_conflict = null_b_justification; - m_not_l = null_literal; + else { + m_conflict = null_b_justification; + m_not_l = null_literal; + } + del_clauses(m_aux_clauses, s.m_aux_clauses_lim); + + m_relevancy_propagator->pop(num_scopes); + + m_fingerprints.pop_scope(num_scopes); + unassign_vars(s.m_assigned_literals_lim); + undo_trail_stack(s.m_trail_stack_lim); + + for (theory* th : m_theory_set) { + th->pop_scope_eh(num_scopes); + } + + del_justifications(m_justifications, s.m_justifications_lim); + + m_asserted_formulas.pop_scope(num_scopes); + + m_eq_propagation_queue.reset(); + m_th_eq_propagation_queue.reset(); + m_th_diseq_propagation_queue.reset(); + m_atom_propagation_queue.reset(); + + m_region.pop_scope(num_scopes); + m_scopes.shrink(new_lvl); + + m_scope_lvl = new_lvl; + if (new_lvl < m_base_lvl) { + m_base_lvl = new_lvl; + m_search_lvl = new_lvl; // Remark: not really necessary + } + + unsigned num_bool_vars = get_num_bool_vars(); + // any variable >= num_bool_vars was deleted during backtracking. + reinit_clauses(num_scopes, num_bool_vars); + reassert_units(units_to_reassert_lim); + TRACE("pop_scope_detail", tout << "end of pop_scope: \n"; display(tout);); + CASSERT("context", check_invariant()); + return num_bool_vars; } - del_clauses(m_aux_clauses, s.m_aux_clauses_lim); - - m_relevancy_propagator->pop(num_scopes); - - m_fingerprints.pop_scope(num_scopes); - unassign_vars(s.m_assigned_literals_lim); - undo_trail_stack(s.m_trail_stack_lim); - - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) { - (*it)->pop_scope_eh(num_scopes); + catch (...) { + // throwing inside pop is just not cool. + UNREACHABLE(); + throw; } - - del_justifications(m_justifications, s.m_justifications_lim); - - m_asserted_formulas.pop_scope(num_scopes); - - m_eq_propagation_queue.reset(); - m_th_eq_propagation_queue.reset(); - m_th_diseq_propagation_queue.reset(); - m_atom_propagation_queue.reset(); - - m_region.pop_scope(num_scopes); - m_scopes.shrink(new_lvl); - - m_scope_lvl = new_lvl; - if (new_lvl < m_base_lvl) { - m_base_lvl = new_lvl; - m_search_lvl = new_lvl; // Remark: not really necessary - } - - unsigned num_bool_vars = get_num_bool_vars(); - // any variable >= num_bool_vars was deleted during backtracking. - reinit_clauses(num_scopes, num_bool_vars); - reassert_units(units_to_reassert_lim); - TRACE("pop_scope_detail", tout << "end of pop_scope: \n"; display(tout);); - CASSERT("context", check_invariant()); - return num_bool_vars; } void context::pop_scope(unsigned num_scopes) { @@ -2510,32 +2511,32 @@ namespace smt { bool context::simplify_clause(clause * cls) { SASSERT(m_scope_lvl == m_base_lvl); unsigned s = cls->get_num_literals(); - if (get_assignment(cls->get_literal(0)) == l_true || + if (get_assignment(cls->get_literal(0)) == l_true || get_assignment(cls->get_literal(1)) == l_true) { // clause is already satisfied. - return true; + return true; } - + literal_buffer simp_lits; unsigned i = 2; - unsigned j = i; - for(; i < s; i++) { + unsigned j = i; + for(; i < s; i++) { literal l = cls->get_literal(i); switch(get_assignment(l)) { - case l_false: - if (m_manager.proofs_enabled()) + case l_false: + if (m_manager.proofs_enabled()) simp_lits.push_back(~l); - if (lit_occs_enabled()) + if (lit_occs_enabled()) m_lit_occs[l.index()].erase(cls); break; - case l_undef: + case l_undef: cls->set_literal(j, l); j++; break; - case l_true: + case l_true: return true; - } + } } if (j < s) { @@ -2548,15 +2549,15 @@ namespace smt { justification * js = cls->get_justification(); justification * new_js = 0; if (js->in_region()) - new_js = mk_justification(unit_resolution_justification(m_region, - js, + new_js = mk_justification(unit_resolution_justification(m_region, + js, simp_lits.size(), simp_lits.c_ptr())); else new_js = alloc(unit_resolution_justification, js, simp_lits.size(), simp_lits.c_ptr()); cls->set_justification(new_js); } - return false; + return false; } /** @@ -2592,7 +2593,7 @@ namespace smt { SASSERT(m_search_lvl == m_base_lvl); literal_buffer simp_lits; unsigned num_lits = cls->get_num_literals(); - for(unsigned i = 0; i < num_lits; i++) { + for(unsigned i = 0; i < num_lits; i++) { if (i != idx) { literal l = cls->get_literal(i); SASSERT(l != l0); @@ -2604,13 +2605,13 @@ namespace smt { if (!cls_js || cls_js->in_region()) { // If cls_js is 0 or is allocated in a region, then // we can allocate the new justification in a region too. - js = mk_justification(unit_resolution_justification(m_region, + js = mk_justification(unit_resolution_justification(m_region, cls_js, simp_lits.size(), - simp_lits.c_ptr())); + simp_lits.c_ptr())); } else { - js = alloc(unit_resolution_justification, cls_js, simp_lits.size(), simp_lits.c_ptr()); + js = alloc(unit_resolution_justification, cls_js, simp_lits.size(), simp_lits.c_ptr()); // js took ownership of the justification object. cls->set_justification(0); m_justifications.push_back(js); @@ -2642,7 +2643,7 @@ namespace smt { // Remark: when assumptions are used m_scope_lvl >= m_search_lvl > m_base_lvl. Therefore, no simplification is performed. if (m_scope_lvl > m_base_lvl) return; - + unsigned sz = m_assigned_literals.size(); SASSERT(m_simp_qhead <= sz); @@ -2672,7 +2673,7 @@ namespace smt { // a variable during propagation. // m_simp_counter = 0; - // the field m_simp_qhead is used to check whether there are + // the field m_simp_qhead is used to check whether there are // new assigned literals at the base level. m_simp_qhead = m_assigned_literals.size(); @@ -2703,13 +2704,15 @@ namespace smt { \brief Delete low activity lemmas */ inline void context::del_inactive_lemmas() { - if (m_fparams.m_lemma_gc_half) + if (m_fparams.m_lemma_gc_strategy == LGC_NONE) + return; + else if (m_fparams.m_lemma_gc_half) del_inactive_lemmas1(); else del_inactive_lemmas2(); m_num_conflicts_since_lemma_gc = 0; - if (m_fparams.m_lemma_gc_strategy == LGC_GEOMETRIC) + if (m_fparams.m_lemma_gc_strategy == LGC_GEOMETRIC) m_lemma_gc_threshold = static_cast(m_lemma_gc_threshold * m_fparams.m_lemma_gc_factor); } @@ -2731,12 +2734,12 @@ namespace smt { unsigned i = start_del_at; unsigned j = i; unsigned num_del_cls = 0; - TRACE("del_inactive_lemmas", tout << "sz: " << sz << ", start_at: " << start_at << ", end_at: " << end_at + TRACE("del_inactive_lemmas", tout << "sz: " << sz << ", start_at: " << start_at << ", end_at: " << end_at << ", start_del_at: " << start_del_at << "\n";); for (; i < end_at; i++) { clause * cls = m_lemmas[i]; if (can_delete(cls)) { - TRACE("del_inactive_lemmas", tout << "deleting: "; display_clause(tout, cls); tout << ", activity: " << + TRACE("del_inactive_lemmas", tout << "deleting: "; display_clause(tout, cls); tout << ", activity: " << cls->get_activity() << "\n";); del_clause(cls); num_del_cls++; @@ -2757,7 +2760,7 @@ namespace smt { m_lemmas[j] = cls; j++; } - } + } m_lemmas.shrink(j); if (m_fparams.m_clause_decay > 1) { // rescale activity @@ -2799,7 +2802,7 @@ namespace smt { } // A clause is deleted if it has low activity and the number of unknowns is greater than a threshold. // The activity threshold depends on how old the clause is. - unsigned act_threshold = m_fparams.m_old_clause_activity - + unsigned act_threshold = m_fparams.m_old_clause_activity - (m_fparams.m_old_clause_activity - m_fparams.m_new_clause_activity) * ((i - start_at) / real_sz); if (cls->get_activity() < act_threshold) { unsigned rel_threshold = (i >= new_first_idx ? m_fparams.m_new_clause_relevancy : m_fparams.m_old_clause_relevancy); @@ -2837,11 +2840,6 @@ namespace smt { return false; } - void context::register_plugin(simplifier_plugin * s) { - SASSERT(!already_internalized()); - SASSERT(m_scope_lvl == 0); - m_asserted_formulas.register_simplifier_plugin(s); - } #ifdef Z3DEBUG /** @@ -2867,7 +2865,7 @@ namespace smt { } #endif - void context::register_plugin(theory * th) { + void context::register_plugin(theory * th) { if (m_theories.get_plugin(th->get_family_id()) != 0) { dealloc(th); return; // context already has a theory for the given family id. @@ -2875,7 +2873,7 @@ namespace smt { SASSERT(std::find(m_theory_set.begin(), m_theory_set.end(), th) == m_theory_set.end()); SASSERT(!already_internalized_theory(th)); th->init(this); - m_theories.register_plugin(th); + m_theories.register_plugin(th); m_theory_set.push_back(th); { #ifdef Z3DEBUG @@ -2900,10 +2898,10 @@ namespace smt { } push_scope(); m_base_scopes.push_back(base_scope()); - base_scope & bs = m_base_scopes.back(); - bs.m_lemmas_lim = m_lemmas.size(); - bs.m_inconsistent = inconsistent(); - bs.m_simp_qhead_lim = m_simp_qhead; + base_scope & bs = m_base_scopes.back(); + bs.m_lemmas_lim = m_lemmas.size(); + bs.m_inconsistent = inconsistent(); + bs.m_simp_qhead_lim = m_simp_qhead; m_base_lvl++; m_search_lvl++; // Not really necessary. But, it is useful to enforce the invariant m_search_lvl >= m_base_lvl SASSERT(m_base_lvl <= m_scope_lvl); @@ -2911,6 +2909,7 @@ namespace smt { void context::pop(unsigned num_scopes) { SASSERT (num_scopes > 0); + if (num_scopes > m_scope_lvl) return; pop_to_base_lvl(); pop_scope(num_scopes); } @@ -2926,18 +2925,18 @@ namespace smt { ptr_vector::iterator it = m_theory_set.begin(); ptr_vector::iterator end = m_theory_set.end(); for (; it != end; ++it) - (*it)->flush_eh(); + (*it)->flush_eh(); undo_trail_stack(0); m_qmanager = 0; del_clauses(m_aux_clauses, 0); del_clauses(m_lemmas, 0); del_justifications(m_justifications, 0); - if (m_is_diseq_tmp) { + if (m_is_diseq_tmp) { m_is_diseq_tmp->del_eh(m_manager, false); - m_manager.dec_ref(m_is_diseq_tmp->get_owner()); + m_manager.dec_ref(m_is_diseq_tmp->get_owner()); enode::del_dummy(m_is_diseq_tmp); - m_is_diseq_tmp = 0; - } + m_is_diseq_tmp = 0; + } std::for_each(m_almost_cg_tables.begin(), m_almost_cg_tables.end(), delete_proc()); } @@ -3035,7 +3034,7 @@ namespace smt { // not counting any literals that get assigned by this method // this relies on bcp() to give us its old m_qhead and therefore // bcp() should always be called before this method - + unsigned assigned_literal_end = m_assigned_literals.size(); for (; qhead < assigned_literal_end; ++qhead) { literal l = m_assigned_literals[qhead]; @@ -3122,7 +3121,7 @@ namespace smt { return true; if (m.is_not(assumption, arg) && is_uninterp_const(arg)) return true; - if (!is_app(assumption)) + if (!is_app(assumption)) return false; if (to_app(assumption)->get_num_args() == 0) return true; @@ -3139,7 +3138,7 @@ namespace smt { SASSERT(assumptions[i]); if (!is_valid_assumption(m_manager, assumptions[i])) { warning_msg("an assumption must be a propositional variable or the negation of one"); - return false; + return false; } } return true; @@ -3151,11 +3150,11 @@ namespace smt { m_unsat_core.reset(); if (num_assumptions > 0) { // We must give a chance to the theories to propagate before we create a new scope... - propagate(); + propagate(); // Internal backtracking scopes (created with push_scope()) must only be created when we are // in a consistent context. if (inconsistent()) - return; + return; if (get_cancel_flag()) return; push_scope(); @@ -3263,9 +3262,9 @@ namespace smt { /** \brief Setup the logical context based on the current set of asserted formulas and execute the check command. - + \remark A logical context can only be configured at scope level 0, - and before internalizing any formulas. + and before internalizing any formulas. */ lbool context::setup_and_check(bool reset_cancel) { if (!check_preamble(reset_cancel)) @@ -3283,11 +3282,11 @@ namespace smt { internalize_assertions(); lbool r = l_undef; + TRACE("before_search", display(tout);); if (m_asserted_formulas.inconsistent()) { r = l_false; } else { - TRACE("after_internalization", display(tout);); if (inconsistent()) { VERIFY(!resolve_conflict()); // build the proof r = l_false; @@ -3364,7 +3363,7 @@ namespace smt { expr_ref_vector all_assumptions(m_manager, ext_num_assumptions, ext_assumptions); if (!already_did_theory_assumptions) { - add_theory_assumptions(all_assumptions); + add_theory_assumptions(all_assumptions); } unsigned num_assumptions = all_assumptions.size(); @@ -3416,10 +3415,9 @@ namespace smt { } void context::init_search() { - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) - (*it)->init_search_eh(); + for (theory* th : m_theory_set) { + th->init_search_eh(); + } m_qmanager->init_search_eh(); m_assumption_core.reset(); m_incomplete_theories.reset(); @@ -3478,7 +3476,7 @@ namespace smt { lbool context::search() { -#ifndef _EXTERNAL_RELEASE +#ifndef _EXTERNAL_RELEASE if (m_fparams.m_abort_after_preproc) { exit(1); } @@ -3501,16 +3499,16 @@ namespace smt { status = bounded_search(); TRACE("search_bug", tout << "status: " << status << ", inconsistent: " << inconsistent() << "\n";); - TRACE("assigned_literals_per_lvl", display_num_assigned_literals_per_lvl(tout); + TRACE("assigned_literals_per_lvl", display_num_assigned_literals_per_lvl(tout); tout << ", num_assigned: " << m_assigned_literals.size() << "\n";); - + if (!restart(status, curr_lvl)) { break; } } - + TRACE("search_lite", tout << "status: " << status << "\n";); - TRACE("guessed_literals", + TRACE("guessed_literals", expr_ref_vector guessed_lits(m_manager); get_guessed_literals(guessed_lits); unsigned sz = guessed_lits.size(); @@ -3541,12 +3539,12 @@ namespace smt { // possible outcomes DONE l_true, DONE l_undef, CONTINUE quantifier_manager::check_model_result cmr = m_qmanager->check_model(m_proto_model.get(), m_model_generator->get_root2value()); if (cmr == quantifier_manager::SAT) { - // done + // done status = l_true; return false; } if (cmr == quantifier_manager::UNKNOWN) { - IF_VERBOSE(1, verbose_stream() << "(smt.giveup quantifiers)\n";); + IF_VERBOSE(2, verbose_stream() << "(smt.giveup quantifiers)\n";); // giving up m_last_search_failure = QUANTIFIERS; status = l_undef; @@ -3556,7 +3554,7 @@ namespace smt { inc_limits(); if (status == l_true || !m_fparams.m_restart_adaptive || m_agility < m_fparams.m_restart_agility_threshold) { SASSERT(!inconsistent()); - IF_VERBOSE(1, verbose_stream() << "(smt.restarting :propagations " << m_stats.m_num_propagations + IF_VERBOSE(2, verbose_stream() << "(smt.restarting :propagations " << m_stats.m_num_propagations << " :decisions " << m_stats.m_num_decisions << " :conflicts " << m_stats.m_num_conflicts << " :restart " << m_restart_threshold; if (m_fparams.m_restart_strategy == RS_IN_OUT_GEOMETRIC) { @@ -3576,9 +3574,9 @@ namespace smt { ptr_vector::iterator end = m_theory_set.end(); for (; it != end && !inconsistent(); ++it) (*it)->restart_eh(); - TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";); + TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";); if (!inconsistent()) { - m_qmanager->restart_eh(); + m_qmanager->restart_eh(); } if (inconsistent()) { VERIFY(!resolve_conflict()); @@ -3594,7 +3592,7 @@ namespace smt { status = l_undef; return true; } - + void context::tick(unsigned & counter) const { counter++; if (counter > m_fparams.m_tick) { @@ -3611,7 +3609,7 @@ namespace smt { lbool context::bounded_search() { unsigned counter = 0; - + TRACE("bounded_search", tout << "starting bounded search...\n";); while (true) { @@ -3630,14 +3628,14 @@ namespace smt { return l_false; SASSERT(m_scope_lvl >= m_base_lvl); - + if (!inconsistent()) { if (resource_limits_exceeded()) return l_undef; if (get_cancel_flag()) return l_undef; - + if (m_num_conflicts_since_restart > m_restart_threshold && m_scope_lvl - m_base_lvl > 2) { TRACE("search_bug", tout << "bounded-search return undef, inconsistent: " << inconsistent() << "\n";); return l_undef; // restart @@ -3658,7 +3656,7 @@ namespace smt { m_dyn_ack_manager.propagate_eh(); CASSERT("dyn_ack", check_clauses(m_lemmas) && check_clauses(m_aux_clauses)); } - + if (resource_limits_exceeded() && !inconsistent()) { return l_undef; } @@ -3668,7 +3666,7 @@ namespace smt { if (m_base_lvl == m_scope_lvl && m_fparams.m_simplify_clauses) simplify_clauses(); - + if (!decide()) { final_check_status fcs = final_check(); TRACE("final_check_result", tout << "fcs: " << fcs << " last_search_failure: " << m_last_search_failure << "\n";); @@ -3691,11 +3689,11 @@ namespace smt { bool context::resource_limits_exceeded() { if (m_searching) { - // Some of the flags only make sense to check when searching. + // Some of the flags only make sense to check when searching. // For example, the timer is only started in init_search(). if (m_last_search_failure != OK) return true; - + if (m_timer.ms_timeout(m_fparams.m_timeout)) { m_last_search_failure = TIMEOUT; return true; @@ -3709,12 +3707,12 @@ namespace smt { } } } - + if (get_cancel_flag()) { m_last_search_failure = CANCELED; return true; } - + if (memory::above_high_watermark()) { m_last_search_failure = MEMOUT; return true; @@ -3765,15 +3763,15 @@ namespace smt { ok = m_qmanager->final_check_eh(true); TRACE("final_check_step", tout << "quantifier ok: " << ok << " " << "inconsistent " << inconsistent() << "\n";); } - + m_final_check_idx = (m_final_check_idx + 1) % range; // IF_VERBOSE(1000, verbose_stream() << "final check status: " << ok << "\n";); - + switch (ok) { - case FC_DONE: + case FC_DONE: break; case FC_GIVEUP: - result = FC_GIVEUP; + result = FC_GIVEUP; break; case FC_CONTINUE: return FC_CONTINUE; @@ -3838,23 +3836,23 @@ namespace smt { unsigned new_lvl = m_conflict_resolution->get_new_scope_lvl(); unsigned num_lits = m_conflict_resolution->get_lemma_num_literals(); literal * lits = m_conflict_resolution->get_lemma_literals(); - + SASSERT(num_lits > 0); unsigned conflict_lvl = get_assign_level(lits[0]); SASSERT(conflict_lvl <= m_scope_lvl); - // When num_lits == 1, then the default behavior is to go + // When num_lits == 1, then the default behavior is to go // to base-level. If the problem has quantifiers, it may be // too expensive to do that, since all instances will need to // be recreated. If that is the case, I store the assertions in // a special vector and keep reasserting whenever I backtrack. // Moreover, I backtrack only one level. - bool delay_forced_restart = + bool delay_forced_restart = m_fparams.m_delay_units && - internalized_quantifiers() && - num_lits == 1 && - conflict_lvl > m_search_lvl + 1 && - !m_manager.proofs_enabled() && + internalized_quantifiers() && + num_lits == 1 && + conflict_lvl > m_search_lvl + 1 && + !m_manager.proofs_enabled() && m_units_to_reassert.size() < m_fparams.m_delay_units_threshold; if (delay_forced_restart) { new_lvl = conflict_lvl - 1; @@ -3862,20 +3860,20 @@ namespace smt { // Some of the literals/enodes of the conflict clause will be destroyed during // backtracking, and will need to be recreated. However, I want to keep - // the generation number for enodes that are going to be recreated. See + // the generation number for enodes that are going to be recreated. See // comment in cache_generation(unsigned). if (m_conflict_resolution->get_lemma_intern_lvl() > new_lvl) cache_generation(num_lits, lits, new_lvl); SASSERT(new_lvl < m_scope_lvl); - TRACE("resolve_conflict_bug", + TRACE("resolve_conflict_bug", tout << "m_scope_lvl: " << m_scope_lvl << ", new_lvl: " << new_lvl << ", lemma_intern_lvl: " << m_conflict_resolution->get_lemma_intern_lvl() << "\n"; tout << "num_lits: " << num_lits << "\n"; for (unsigned i = 0; i < num_lits; i++) { literal l = lits[i]; tout << l << " "; - display_literal(tout, l); - tout << ", ilvl: " << get_intern_level(l.var()) << "\n" + display_literal(tout, l); + tout << ", ilvl: " << get_intern_level(l.var()) << "\n" << mk_pp(bool_var2expr(l.var()), m_manager) << "\n"; }); @@ -3885,7 +3883,7 @@ namespace smt { m_manager.trace_stream() << "\n"; } -#ifdef Z3DEBUG +#ifdef Z3DEBUG expr_ref_vector expr_lits(m_manager); svector expr_signs; for (unsigned i = 0; i < num_lits; i++) { @@ -3900,7 +3898,7 @@ namespace smt { pr = m_conflict_resolution->get_lemma_proof(); // check_proof(pr); TRACE("context_proof", tout << mk_ll_pp(pr, m_manager);); - TRACE("context_proof_hack", + TRACE("context_proof_hack", static ast_mark visited; ast_ll_pp(tout, m_manager, pr, visited);); } @@ -3942,15 +3940,15 @@ namespace smt { if (relevancy()) restore_relevancy(num_lits, lits); // Resetting the cache manually because I did not invoke pop_scope, but pop_scope_core reset_cache_generation(); - TRACE("resolve_conflict_bug", - tout << "AFTER m_scope_lvl: " << m_scope_lvl << ", new_lvl: " << new_lvl << ", lemma_intern_lvl: " << + TRACE("resolve_conflict_bug", + tout << "AFTER m_scope_lvl: " << m_scope_lvl << ", new_lvl: " << new_lvl << ", lemma_intern_lvl: " << m_conflict_resolution->get_lemma_intern_lvl() << "\n"; tout << "num_lits: " << num_lits << "\n"; for (unsigned i = 0; i < num_lits; i++) { literal l = lits[i]; tout << l << " "; - display_literal(tout, l); - tout << ", ilvl: " << get_intern_level(l.var()) << "\n" + display_literal(tout, l); + tout << ", ilvl: " << get_intern_level(l.var()) << "\n" << mk_pp(bool_var2expr(l.var()), m_manager) << "\n"; }); #ifdef Z3DEBUG @@ -3974,7 +3972,7 @@ namespace smt { } #if 0 { - static unsigned counter = 0; + static unsigned counter = 0; static uint64 total = 0; static unsigned max = 0; counter++; @@ -4000,13 +3998,13 @@ namespace smt { m_units_to_reassert_sign.push_back(unit_sign); TRACE("reassert_units", tout << "asserting #" << unit->get_id() << " " << unit_sign << " @ " << m_scope_lvl << "\n";); } - + m_conflict_resolution->release_lemma_atoms(); - TRACE("context_lemma", tout << "new lemma: "; + TRACE("context_lemma", tout << "new lemma: "; literal_vector v(num_lits, lits); std::sort(v.begin(), v.end()); for (unsigned i = 0; i < num_lits; i++) { - display_literal(tout, v[i]); + display_literal(tout, v[i]); tout << "\n"; v[i].display(tout, m_manager, m_bool_var2expr.c_ptr()); tout << "\n\n"; @@ -4022,7 +4020,7 @@ namespace smt { } return false; } - + /* \brief we record and restore relevancy information for literals in conflict clauses. A literal may have been marked relevant within the scope that gets popped during @@ -4058,11 +4056,11 @@ namespace smt { if (!checker.check(fml)) { warning_msg("Boogie generated formula that can require multiple '@' labels in a counter-example"); break; - } + } } } } - + SASSERT(!inconsistent()); unsigned sz = m_b_internalized_stack.size(); for (unsigned i = 0; i < sz; i++) { @@ -4073,7 +4071,7 @@ namespace smt { } } } - + /** \brief Collect relevant literals that may be used to block the current assignment. If at_lbls is true, then only labels that contains '@' are considered. (This is a hack for Boogie). @@ -4186,7 +4184,7 @@ namespace smt { } bool r = false; if (!b_internalized(eq)) { - // I do not invoke internalize(eq, true), because I want to + // I do not invoke internalize(eq, true), because I want to // mark the try_true_first flag before invoking theory::internalize_eq_eh. // Reason: Theories like arithmetic should be able to know if the try_true_first flag is // marked or not. They use this information to also mark auxiliary atoms such as: @@ -4248,13 +4246,13 @@ namespace smt { if (m_qmanager->is_shared(n)) { return true; } - - // the variabe is shared if the equivalence class of n + + // the variabe is shared if the equivalence class of n // contains a parent application. - + theory_var_list * l = n->get_th_var_list(); theory_id th_id = l->get_th_id(); - + enode_vector::const_iterator it = n->begin_parents(); enode_vector::const_iterator end = n->end_parents(); for (; it != end; ++it) { @@ -4265,12 +4263,12 @@ namespace smt { return true; } } - + // Some theories implement families of theories. Examples: // Arrays and Tuples. For example, array theory is a // parametric theory, that is, it implements several theories: // (array int int), (array int (array int int)), ... - // + // // Example: // // a : (array int int) @@ -4317,18 +4315,18 @@ namespace smt { if (fcs == FC_DONE) { mk_proto_model(l_true); m_model = m_proto_model->mk_model(); - add_rec_funs_to_model(); + add_rec_funs_to_model(); } - + return fcs == FC_DONE; } void context::mk_proto_model(lbool r) { - TRACE("get_model", - display(tout); + TRACE("get_model", + display(tout); display_normalized_enodes(tout); display_enodes_lbls(tout); - m_fingerprints.display(tout); + m_fingerprints.display(tout); ); failure fl = get_last_search_failure(); if (fl == MEMOUT || fl == CANCELED || fl == TIMEOUT || fl == NUM_CONFLICTS || fl == RESOURCE_LIMIT) { @@ -4345,7 +4343,7 @@ namespace smt { if (m_fparams.m_model_compact) m_proto_model->compress(); TRACE("mbqi_bug", tout << "after cleanup:\n"; model_pp(tout, *m_proto_model);); - } + } else { } @@ -4357,19 +4355,19 @@ namespace smt { return m_unsat_proof; } - void context::get_model(model_ref & m) const { + void context::get_model(model_ref & m) const { if (inconsistent()) m = 0; else - m = const_cast(m_model.get()); + m = const_cast(m_model.get()); } void context::get_proto_model(proto_model_ref & m) const { m = const_cast(m_proto_model.get()); } - failure context::get_last_search_failure() const { - return m_last_search_failure; + failure context::get_last_search_failure() const { + return m_last_search_failure; } void context::add_rec_funs_to_model() { @@ -4385,10 +4383,18 @@ namespace smt { expr* fn = to_app(q->get_pattern(0))->get_arg(0); expr* body = to_app(q->get_pattern(1))->get_arg(0); SASSERT(is_app(fn)); + // reverse argument order so that variable 0 starts at the beginning. + expr_ref_vector subst(m); + for (expr* arg : *to_app(fn)) { + subst.push_back(arg); + } + expr_ref bodyr(m); + var_subst sub(m, false); + sub(body, subst.size(), subst.c_ptr(), bodyr); func_decl* f = to_app(fn)->get_decl(); func_interp* fi = alloc(func_interp, m, f->get_arity()); - fi->set_else(body); - m_model->register_decl(f, fi); + fi->set_else(bodyr); + m_model->register_decl(f, fi); } } } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 9c70f5999..3cc577b29 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -19,36 +19,36 @@ Revision History: #ifndef SMT_CONTEXT_H_ #define SMT_CONTEXT_H_ -#include"smt_clause.h" -#include"smt_setup.h" -#include"smt_enode.h" -#include"smt_cg_table.h" -#include"smt_b_justification.h" -#include"smt_eq_justification.h" -#include"smt_justification.h" -#include"smt_bool_var_data.h" -#include"smt_theory.h" -#include"smt_quantifier.h" -#include"smt_quantifier_stat.h" -#include"smt_statistics.h" -#include"smt_conflict_resolution.h" -#include"smt_relevancy.h" -#include"smt_case_split_queue.h" -#include"smt_almost_cg_table.h" -#include"smt_failure.h" -#include"asserted_formulas.h" -#include"smt_types.h" -#include"dyn_ack.h" -#include"ast_smt_pp.h" -#include"watch_list.h" -#include"trail.h" -#include"fingerprints.h" -#include"ref.h" -#include"proto_model.h" -#include"model.h" -#include"timer.h" -#include"statistics.h" -#include"progress_callback.h" +#include "smt/smt_clause.h" +#include "smt/smt_setup.h" +#include "smt/smt_enode.h" +#include "smt/smt_cg_table.h" +#include "smt/smt_b_justification.h" +#include "smt/smt_eq_justification.h" +#include "smt/smt_justification.h" +#include "smt/smt_bool_var_data.h" +#include "smt/smt_theory.h" +#include "smt/smt_quantifier.h" +#include "smt/smt_quantifier_stat.h" +#include "smt/smt_statistics.h" +#include "smt/smt_conflict_resolution.h" +#include "smt/smt_relevancy.h" +#include "smt/smt_case_split_queue.h" +#include "smt/smt_almost_cg_table.h" +#include "smt/smt_failure.h" +#include "smt/asserted_formulas.h" +#include "smt/smt_types.h" +#include "smt/dyn_ack.h" +#include "ast/ast_smt_pp.h" +#include "smt/watch_list.h" +#include "util/trail.h" +#include "smt/fingerprints.h" +#include "util/ref.h" +#include "smt/proto_model/proto_model.h" +#include "model/model.h" +#include "util/timer.h" +#include "util/statistics.h" +#include "solver/progress_callback.h" // there is a significant space overhead with allocating 1000+ contexts in // the case that each context only references a few expressions. @@ -209,7 +209,7 @@ namespace smt { ~scoped_mk_model() { if (m_ctx.m_proto_model.get() != 0) { m_ctx.m_model = m_ctx.m_proto_model->mk_model(); - m_ctx.add_rec_funs_to_model(); + m_ctx.add_rec_funs_to_model(); m_ctx.m_proto_model = 0; // proto_model is not needed anymore. } } @@ -245,8 +245,8 @@ namespace smt { return m_manager; } - simplifier & get_simplifier() { - return m_asserted_formulas.get_simplifier(); + th_rewriter & get_rewriter() { + return m_asserted_formulas.get_rewriter(); } smt_params & get_fparams() { @@ -257,7 +257,7 @@ namespace smt { return m_params; } - bool get_cancel_flag() { return !m_manager.limit().inc(); } + bool get_cancel_flag(); region & get_region() { return m_region; @@ -1040,6 +1040,7 @@ namespace smt { if (act > ACTIVITY_LIMIT) rescale_bool_var_activity(); m_case_split_queue->activity_increased_eh(v); + TRACE("case_split", tout << "v" << v << " " << m_bvar_inc << " -> " << act << "\n";); } protected: @@ -1466,8 +1467,6 @@ namespace smt { bool set_logic(symbol const& logic) { return m_setup.set_logic(logic); } - void register_plugin(simplifier_plugin * s); - void register_plugin(theory * th); void assert_expr(expr * e); @@ -1539,9 +1538,9 @@ namespace smt { proof * get_asserted_formula_proof(unsigned idx) const { return m_asserted_formulas.get_formula_proof(idx); } - expr * const * get_asserted_formulas() const { return m_asserted_formulas.get_formulas(); } + void get_asserted_formulas(ptr_vector& r) const { m_asserted_formulas.get_assertions(r); } - proof * const * get_asserted_formula_proofs() const { return m_asserted_formulas.get_formula_proofs(); } + //proof * const * get_asserted_formula_proofs() const { return m_asserted_formulas.get_formula_proofs(); } void get_assumptions_core(ptr_vector & result); @@ -1567,7 +1566,7 @@ namespace smt { func_decl * get_macro_func_decl(unsigned i) const { return m_asserted_formulas.get_macro_func_decl(i); } func_decl * get_macro_interpretation(unsigned i, expr_ref & interp) const { return m_asserted_formulas.get_macro_interpretation(i, interp); } quantifier * get_macro_quantifier(func_decl * f) const { return m_asserted_formulas.get_macro_quantifier(f); } - void insert_macro(func_decl * f, quantifier * m, proof * pr) { m_asserted_formulas.insert_macro(f, m, pr); } + void insert_macro(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep) { m_asserted_formulas.insert_macro(f, m, pr, dep); } }; }; diff --git a/src/smt/smt_context_inv.cpp b/src/smt/smt_context_inv.cpp index e6551b8da..cf09c996a 100644 --- a/src/smt/smt_context_inv.cpp +++ b/src/smt/smt_context_inv.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"ast_smt2_pp.h" +#include "smt/smt_context.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt2_pp.h" namespace smt { diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 73d822fb4..6d66368ff 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" -#include"ast_smt_pp.h" -#include"stats.h" +#include "smt/smt_context.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt_pp.h" +#include "util/stats.h" namespace smt { diff --git a/src/smt/smt_context_stat.cpp b/src/smt/smt_context_stat.cpp index 3838a88b5..968d84b73 100644 --- a/src/smt/smt_context_stat.cpp +++ b/src/smt/smt_context_stat.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"ast_pp.h" +#include "smt/smt_context.h" +#include "ast/ast_pp.h" namespace smt { diff --git a/src/smt/smt_enode.cpp b/src/smt/smt_enode.cpp index 679c46720..1452dc610 100644 --- a/src/smt/smt_enode.cpp +++ b/src/smt/smt_enode.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"smt_enode.h" +#include "smt/smt_context.h" +#include "smt/smt_enode.h" namespace smt { diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index 69a882c99..f471314fa 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -19,11 +19,11 @@ Revision History: #ifndef SMT_ENODE_H_ #define SMT_ENODE_H_ -#include"ast.h" -#include"smt_types.h" -#include"smt_eq_justification.h" -#include"smt_theory_var_list.h" -#include"approx_set.h" +#include "ast/ast.h" +#include "smt/smt_types.h" +#include "smt/smt_eq_justification.h" +#include "smt/smt_theory_var_list.h" +#include "util/approx_set.h" namespace smt { /** @@ -40,10 +40,10 @@ namespace smt { /** \ brief Use sparse maps in SMT solver. - Define this to use hash maps rather than vectors over ast - nodes. This is useful in the case there are many solvers, each - referencing few nodes from a large ast manager. There is some - unknown performance penalty for this. */ + Define this to use hash maps rather than vectors over ast + nodes. This is useful in the case there are many solvers, each + referencing few nodes from a large ast manager. There is some + unknown performance penalty for this. */ // #define SPARSE_MAP diff --git a/src/smt/smt_eq_justification.h b/src/smt/smt_eq_justification.h index b12eda192..af538a130 100644 --- a/src/smt/smt_eq_justification.h +++ b/src/smt/smt_eq_justification.h @@ -19,8 +19,8 @@ Revision History: #ifndef SMT_EQ_JUSTIFICATION_H_ #define SMT_EQ_JUSTIFICATION_H_ -#include"smt_literal.h" -#include"tptr.h" +#include "smt/smt_literal.h" +#include "util/tptr.h" namespace smt { diff --git a/src/smt/smt_farkas_util.cpp b/src/smt/smt_farkas_util.cpp index c5ff42e3e..ff415ad0c 100644 --- a/src/smt/smt_farkas_util.cpp +++ b/src/smt/smt_farkas_util.cpp @@ -19,10 +19,10 @@ Revision History: --*/ -#include "smt_farkas_util.h" -#include "ast_pp.h" -#include "th_rewriter.h" -#include "bool_rewriter.h" +#include "smt/smt_farkas_util.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/bool_rewriter.h" namespace smt { diff --git a/src/smt/smt_farkas_util.h b/src/smt/smt_farkas_util.h index 575df45ee..1fc6a3681 100644 --- a/src/smt/smt_farkas_util.h +++ b/src/smt/smt_farkas_util.h @@ -22,7 +22,7 @@ Revision History: #ifndef FARKAS_UTIL_H_ #define FARKAS_UTIL_H_ -#include "arith_decl_plugin.h" +#include "ast/arith_decl_plugin.h" namespace smt { diff --git a/src/smt/smt_for_each_relevant_expr.cpp b/src/smt/smt_for_each_relevant_expr.cpp index 84f93dd33..30b69a149 100644 --- a/src/smt/smt_for_each_relevant_expr.cpp +++ b/src/smt/smt_for_each_relevant_expr.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"smt_for_each_relevant_expr.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" +#include "smt/smt_context.h" +#include "smt/smt_for_each_relevant_expr.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" namespace smt { diff --git a/src/smt/smt_for_each_relevant_expr.h b/src/smt/smt_for_each_relevant_expr.h index abbc1894d..b81023349 100644 --- a/src/smt/smt_for_each_relevant_expr.h +++ b/src/smt/smt_for_each_relevant_expr.h @@ -19,9 +19,9 @@ Revision History: #ifndef SMT_FOR_EACH_RELEVANT_EXPR_H_ #define SMT_FOR_EACH_RELEVANT_EXPR_H_ -#include"ast.h" -#include"obj_hashtable.h" -#include"vector.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "util/vector.h" namespace smt { diff --git a/src/smt/smt_implied_equalities.cpp b/src/smt/smt_implied_equalities.cpp index 888827754..d021708fc 100644 --- a/src/smt/smt_implied_equalities.cpp +++ b/src/smt/smt_implied_equalities.cpp @@ -19,16 +19,16 @@ Revision History: --*/ -#include "smt_implied_equalities.h" -#include "union_find.h" -#include "ast_pp.h" -#include "array_decl_plugin.h" -#include "uint_set.h" -#include "smt_value_sort.h" -#include "model_smt2_pp.h" -#include "stopwatch.h" -#include "model.h" -#include "solver.h" +#include "smt/smt_implied_equalities.h" +#include "util/union_find.h" +#include "ast/ast_pp.h" +#include "ast/array_decl_plugin.h" +#include "util/uint_set.h" +#include "smt/smt_value_sort.h" +#include "model/model_smt2_pp.h" +#include "util/stopwatch.h" +#include "model/model.h" +#include "solver/solver.h" namespace smt { @@ -284,7 +284,7 @@ namespace smt { } lbool reduce_cond(model_ref& model, expr* e) { - expr* e1, *e2; + expr* e1 = 0, *e2 = 0; if (m.is_eq(e, e1, e2) && m_array_util.is_as_array(e1) && m_array_util.is_as_array(e2)) { if (e1 == e2) { return l_true; diff --git a/src/smt/smt_implied_equalities.h b/src/smt/smt_implied_equalities.h index 0dd76e439..cc7acf22b 100644 --- a/src/smt/smt_implied_equalities.h +++ b/src/smt/smt_implied_equalities.h @@ -23,9 +23,9 @@ Revision History: #ifndef SMT_IMPLIED_EQUALITIES_H_ #define SMT_IMPLIED_EQUALITIES_H_ -#include"smt_solver.h" -#include"lbool.h" -#include"ast.h" +#include "smt/smt_solver.h" +#include "util/lbool.h" +#include "ast/ast.h" namespace smt { diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 5fbdb2477..ffaee434f 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -16,13 +16,13 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"expr_stat.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"ast_smt2_pp.h" -#include"smt_model_finder.h" -#include"for_each_expr.h" +#include "smt/smt_context.h" +#include "ast/expr_stat.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt2_pp.h" +#include "smt/smt_model_finder.h" +#include "ast/for_each_expr.h" namespace smt { @@ -198,19 +198,19 @@ namespace smt { if (get_depth(n) > DEEP_EXPR_THRESHOLD) { // if the expression is deep, then execute topological sort to avoid // stack overflow. + // a caveat is that theory internalizers do rely on recursive descent so + // internalization over these follows top-down TRACE("deep_internalize", tout << "expression is deep: #" << n->get_id() << "\n" << mk_ll_pp(n, m_manager);); svector sorted_exprs; top_sort_expr(n, sorted_exprs); - TRACE("deep_internalize", - svector::const_iterator it = sorted_exprs.begin(); - svector::const_iterator end = sorted_exprs.end(); - for (; it != end; ++it) { - tout << "#" << it->first->get_id() << " " << it->second << "\n"; - }); - svector::const_iterator it = sorted_exprs.begin(); - svector::const_iterator end = sorted_exprs.end(); - for (; it != end; ++it) - internalize(it->first, it->second); + TRACE("deep_internalize", for (auto & kv : sorted_exprs) tout << "#" << kv.first->get_id() << " " << kv.second << "\n"; ); + for (auto & kv : sorted_exprs) { + expr* e = kv.first; + if (!is_app(e) || + to_app(e)->get_family_id() == null_family_id || + to_app(e)->get_family_id() == m_manager.get_basic_family_id()) + internalize(e, kv.second); + } } SASSERT(m_manager.is_bool(n)); if (is_gate(m_manager, n)) { diff --git a/src/smt/smt_justification.cpp b/src/smt/smt_justification.cpp index 7a9938cd0..440da7297 100644 --- a/src/smt/smt_justification.cpp +++ b/src/smt/smt_justification.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"smt_conflict_resolution.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" +#include "smt/smt_context.h" +#include "smt/smt_conflict_resolution.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" namespace smt { @@ -129,7 +129,7 @@ namespace smt { if (m_node1 != m_node1->get_root()) { proof * pr = cr.get_proof(m_node1, m_node1->get_root()); - if (pr && m.fine_grain_proofs()) + if (pr && m.proofs_enabled()) pr = m.mk_symmetry(pr); prs.push_back(pr); if (!pr) diff --git a/src/smt/smt_justification.h b/src/smt/smt_justification.h index ea969d1db..0af8e61ff 100644 --- a/src/smt/smt_justification.h +++ b/src/smt/smt_justification.h @@ -19,10 +19,10 @@ Revision History: #ifndef SMT_JUSTIFICATION_H_ #define SMT_JUSTIFICATION_H_ -#include"ast.h" -#include"smt_types.h" -#include"smt_literal.h" -#include"smt_eq_justification.h" +#include "ast/ast.h" +#include "smt/smt_types.h" +#include "smt/smt_literal.h" +#include "smt/smt_eq_justification.h" namespace smt { @@ -181,6 +181,7 @@ namespace smt { enode * m_node2; public: eq_propagation_justification(enode * n1, enode * n2):m_node1(n1), m_node2(n2) { + SASSERT(n1 != n2); } virtual void get_antecedents(conflict_resolution & cr); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 9bdf962ec..a7948725c 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"smt_kernel.h" -#include"smt_context.h" -#include"ast_smt2_pp.h" -#include"smt_params_helper.hpp" +#include "smt/smt_kernel.h" +#include "smt/smt_context.h" +#include "ast/ast_smt2_pp.h" +#include "smt/params/smt_params_helper.hpp" namespace smt { @@ -60,10 +60,10 @@ namespace smt { // m_kernel.display(out); <<< for external users it is just junk // TODO: it will be replaced with assertion_stack.display unsigned num = m_kernel.get_num_asserted_formulas(); - expr * const * fms = m_kernel.get_asserted_formulas(); out << "(kernel"; for (unsigned i = 0; i < num; i++) { - out << "\n " << mk_ismt2_pp(fms[i], m(), 2); + expr* f = m_kernel.get_asserted_formula(i); + out << "\n " << mk_ismt2_pp(f, m(), 2); } out << ")"; } @@ -81,8 +81,12 @@ namespace smt { return m_kernel.get_num_asserted_formulas(); } - expr * const * get_formulas() const { - return m_kernel.get_asserted_formulas(); + void get_formulas(ptr_vector& fmls) const { + m_kernel.get_asserted_formulas(fmls); + } + + expr* get_formula(unsigned i) const { + return m_kernel.get_asserted_formula(i); } void push() { @@ -241,8 +245,8 @@ namespace smt { return m_imp->size(); } - expr * const * kernel::get_formulas() const { - return m_imp->get_formulas(); + expr* kernel::get_formula(unsigned i) const { + return m_imp->get_formula(i); } diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 264fae011..d10cab4f3 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -27,12 +27,12 @@ Revision History: #ifndef SMT_KERNEL_H_ #define SMT_KERNEL_H_ -#include"ast.h" -#include"params.h" -#include"model.h" -#include"lbool.h" -#include"statistics.h" -#include"smt_failure.h" +#include "ast/ast.h" +#include "util/params.h" +#include "model/model.h" +#include "util/lbool.h" +#include "util/statistics.h" +#include "smt/smt_failure.h" struct smt_params; class progress_callback; @@ -85,7 +85,12 @@ namespace smt { /** \brief Return the array of asserted formulas. */ - expr * const * get_formulas() const; + void get_formulas(ptr_vector& r) const; + + /** + \brief return the formula at index idx. + */ + expr* get_formula(unsigned idx) const; /** \brief Create a backtracking point (aka scope level). diff --git a/src/smt/smt_literal.cpp b/src/smt/smt_literal.cpp index e6e795ed4..86a9f0b0c 100644 --- a/src/smt/smt_literal.cpp +++ b/src/smt/smt_literal.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"smt_literal.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" +#include "smt/smt_literal.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" namespace smt { diff --git a/src/smt/smt_literal.h b/src/smt/smt_literal.h index 3dbd6911e..7f554d740 100644 --- a/src/smt/smt_literal.h +++ b/src/smt/smt_literal.h @@ -19,9 +19,9 @@ Revision History: #ifndef SMT_LITERAL_H_ #define SMT_LITERAL_H_ -#include"ast.h" -#include"smt_types.h" -#include"approx_set.h" +#include "ast/ast.h" +#include "smt/smt_types.h" +#include "util/approx_set.h" namespace smt { /** diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index b50527acf..f72485d0e 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -17,16 +17,15 @@ Revision History: --*/ -#include"smt_model_checker.h" -#include"smt_context.h" -#include"smt_model_finder.h" -#include"pull_quant.h" -#include"for_each_expr.h" -#include"var_subst.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"model_pp.h" -#include"ast_smt2_pp.h" +#include "ast/normal_forms/pull_quant.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/var_subst.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt2_pp.h" +#include "smt/smt_model_checker.h" +#include "smt/smt_context.h" +#include "smt/smt_model_finder.h" +#include "model/model_pp.h" namespace smt { @@ -40,7 +39,7 @@ namespace smt { m_max_cexs(1), m_iteration_idx(0), m_curr_model(0), - m_new_instances_bindings(m) { + m_pinned_exprs(m) { } model_checker::~model_checker() { @@ -53,8 +52,8 @@ namespace smt { } void model_checker::set_qm(quantifier_manager & qm) { - SASSERT(m_qm == 0); - SASSERT(m_context == 0); + SASSERT(m_qm == 0); + SASSERT(m_context == 0); m_qm = &qm; m_context = &(m_qm->get_context()); } @@ -65,11 +64,9 @@ namespace smt { expr * model_checker::get_term_from_ctx(expr * val) { if (m_value2expr.empty()) { // populate m_value2expr - obj_map::iterator it = m_root2value->begin(); - obj_map::iterator end = m_root2value->end(); - for (; it != end; ++it) { - enode * n = (*it).m_key; - expr * val = (*it).m_value; + for (auto const& kv : *m_root2value) { + enode * n = kv.m_key; + expr * val = kv.m_value; n = n->get_eq_enode_with_min_gen(); m_value2expr.insert(val, n->get_owner()); } @@ -89,10 +86,7 @@ namespace smt { void model_checker::restrict_to_universe(expr * sk, obj_hashtable const & universe) { SASSERT(!universe.empty()); ptr_buffer eqs; - obj_hashtable::iterator it = universe.begin(); - obj_hashtable::iterator end = universe.end(); - for (; it != end; ++it) { - expr * e = *it; + for (expr * e : universe) { eqs.push_back(m.mk_eq(sk, e)); } expr_ref fml(m.mk_or(eqs.size(), eqs.c_ptr()), m); @@ -112,7 +106,7 @@ namespace smt { if (!m_curr_model->eval(q->get_expr(), tmp, true)) { return; } - TRACE("model_checker", tout << "q after applying interpretation:\n" << mk_ismt2_pp(tmp, m) << "\n";); + TRACE("model_checker", tout << "q after applying interpretation:\n" << mk_ismt2_pp(tmp, m) << "\n";); ptr_buffer subst_args; unsigned num_decls = q->get_num_decls(); subst_args.resize(num_decls, 0); @@ -139,7 +133,7 @@ namespace smt { bool model_checker::add_instance(quantifier * q, model * cex, expr_ref_vector & sks, bool use_inv) { if (cex == 0) { TRACE("model_checker", tout << "no model is available\n";); - return false; + return false; } unsigned num_decls = q->get_num_decls(); // Remark: sks were created for the flat version of q. @@ -187,21 +181,24 @@ namespace smt { } bindings.set(num_decls - i - 1, sk_value); } - + TRACE("model_checker", tout << q->get_qid() << " found (use_inv: " << use_inv << ") new instance: "; for (unsigned i = 0; i < num_decls; i++) { tout << mk_ismt2_pp(bindings[i].get(), m) << " "; } tout << "\n";); - + max_generation = std::max(m_qm->get_generation(q), max_generation); add_instance(q, bindings, max_generation); return true; } void model_checker::add_instance(quantifier* q, expr_ref_vector const& bindings, unsigned max_generation) { - for (unsigned i = 0; i < bindings.size(); i++) - m_new_instances_bindings.push_back(bindings[i]); + SASSERT(q->get_num_decls() == bindings.size()); + for (expr* b : bindings) + m_pinned_exprs.push_back(b); + m_pinned_exprs.push_back(q); + void * mem = m_new_instances_region.allocate(instance::get_obj_size(q->get_num_decls())); instance * new_inst = new (mem) instance(q, bindings.c_ptr(), max_generation); m_new_instances.push_back(new_inst); @@ -233,10 +230,8 @@ namespace smt { bool model_checker::add_blocking_clause(model * cex, expr_ref_vector & sks) { SASSERT(cex != 0); - unsigned num_sks = sks.size(); expr_ref_buffer diseqs(m); - for (unsigned i = 0; i < num_sks; i++) { - expr * sk = sks.get(i); + for (expr * sk : sks) { func_decl * sk_d = to_app(sk)->get_decl(); expr_ref sk_value(m); sk_value = cex->get_const_interp(sk_d); @@ -260,39 +255,38 @@ namespace smt { bool model_checker::check(quantifier * q) { SASSERT(!m_aux_context->relevancy()); m_aux_context->push(); - + quantifier * flat_q = get_flat_quantifier(q); - TRACE("model_checker", tout << "model checking:\n" << mk_ismt2_pp(q->get_expr(), m) << "\n" << + TRACE("model_checker", tout << "model checking:\n" << mk_ismt2_pp(q->get_expr(), m) << "\n" << mk_ismt2_pp(flat_q->get_expr(), m) << "\n";); expr_ref_vector sks(m); assert_neg_q_m(flat_q, sks); - TRACE("model_checker", tout << "skolems:\n"; - for (unsigned i = 0; i < sks.size(); i++) { - expr * sk = sks.get(i); + TRACE("model_checker", tout << "skolems:\n"; + for (expr* sk : sks) { tout << mk_ismt2_pp(sk, m) << " " << mk_pp(m.get_sort(sk), m) << "\n"; }); - + lbool r = m_aux_context->check(); TRACE("model_checker", tout << "[complete] model-checker result: " << to_sat_str(r) << "\n";); if (r != l_true) { m_aux_context->pop(1); return r == l_false; // quantifier is satisfied by m_curr_model } - + model_ref complete_cex; - m_aux_context->get_model(complete_cex); - + m_aux_context->get_model(complete_cex); + // try to find new instances using instantiation sets. m_model_finder.restrict_sks_to_inst_set(m_aux_context.get(), q, sks); - + unsigned num_new_instances = 0; while (true) { lbool r = m_aux_context->check(); - TRACE("model_checker", tout << "[restricted] model-checker (" << (num_new_instances+1) << ") result: " << to_sat_str(r) << "\n";); + TRACE("model_checker", tout << "[restricted] model-checker (" << (num_new_instances+1) << ") result: " << to_sat_str(r) << "\n";); if (r != l_true) - break; + break; model_ref cex; m_aux_context->get_model(cex); if (!add_instance(q, cex.get(), sks, true)) { @@ -302,7 +296,7 @@ namespace smt { if (num_new_instances >= m_max_cexs || !add_blocking_clause(cex.get(), sks)) { TRACE("model_checker", tout << "Add blocking clause failed new-instances: " << num_new_instances << " max-cex: " << m_max_cexs << "\n";); // add_blocking_clause failed... stop the search for new counter-examples... - break; + break; } } @@ -395,17 +389,17 @@ namespace smt { check_quantifiers(false, found_relevant, num_failures); - + if (found_relevant) m_iteration_idx++; TRACE("model_checker", tout << "model after check:\n"; model_pp(tout, *md);); - TRACE("model_checker", tout << "model checker result: " << (num_failures == 0) << "\n";); + TRACE("model_checker", tout << "model checker result: " << (num_failures == 0) << "\n";); m_max_cexs += m_params.m_mbqi_max_cexs; if (num_failures == 0 && !m_context->validate_model()) { num_failures = 1; - // this time force expanding recursive function definitions + // this time force expanding recursive function definitions // that are not forced true in the current model. check_quantifiers(true, found_relevant, num_failures); } @@ -426,7 +420,7 @@ namespace smt { for (; it != end; ++it) { quantifier * q = *it; if(!m_qm->mbqi_enabled(q)) continue; - TRACE("model_checker", + TRACE("model_checker", tout << "Check: " << mk_pp(q, m) << "\n"; tout << m_context->get_assignment(q) << "\n";); @@ -469,8 +463,9 @@ namespace smt { } void model_checker::reset_new_instances() { - m_new_instances_region.reset(); + m_pinned_exprs.reset(); m_new_instances.reset(); + m_new_instances_region.reset(); } void model_checker::reset() { @@ -481,10 +476,7 @@ namespace smt { TRACE("model_checker_bug_detail", tout << "assert_new_instances, inconsistent: " << m_context->inconsistent() << "\n";); ptr_buffer bindings; ptr_vector dummy; - ptr_vector::iterator it = m_new_instances.begin(); - ptr_vector::iterator end = m_new_instances.end(); - for (; it != end; ++it) { - instance * inst = *it; + for (instance* inst : m_new_instances) { quantifier * q = inst->m_q; if (m_context->b_internalized(q)) { bindings.reset(); @@ -505,7 +497,7 @@ namespace smt { expr * b = inst->m_bindings[i]; tout << mk_pp(b, m) << "\n"; }); - TRACE("model_checker_instance", + TRACE("model_checker_instance", expr_ref inst_expr(m); instantiate(m, q, inst->m_bindings, inst_expr); tout << "(assert " << mk_ismt2_pp(inst_expr, m) << ")\n";); diff --git a/src/smt/smt_model_checker.h b/src/smt/smt_model_checker.h index 1b7713d59..778f913c3 100644 --- a/src/smt/smt_model_checker.h +++ b/src/smt/smt_model_checker.h @@ -21,11 +21,11 @@ Revision History: #ifndef SMT_MODEL_CHECKER_H_ #define SMT_MODEL_CHECKER_H_ -#include"ast.h" -#include"obj_hashtable.h" -#include"qi_params.h" -#include"smt_params.h" -#include"region.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "smt/params/qi_params.h" +#include "smt/params/smt_params.h" +#include "util/region.h" class proto_model; class model; @@ -39,7 +39,7 @@ namespace smt { class model_checker { ast_manager & m; // _manager; qi_params const & m_params; - // copy of smt_params for auxiliary context. + // copy of smt_params for auxiliary context. // the idea is to use a different configuration for the aux context (e.g., disable relevancy) scoped_ptr m_fparams; quantifier_manager * m_qm; @@ -73,8 +73,8 @@ namespace smt { }; region m_new_instances_region; - expr_ref_vector m_new_instances_bindings; ptr_vector m_new_instances; + expr_ref_vector m_pinned_exprs; bool add_instance(quantifier * q, model * cex, expr_ref_vector & sks, bool use_inv); void reset_new_instances(); void assert_new_instances(); @@ -83,8 +83,8 @@ namespace smt { struct is_model_value {}; expr_mark m_visited; - bool contains_model_value(expr* e); - void add_instance(quantifier* q, expr_ref_vector const& bindings, unsigned max_generation); + bool contains_model_value(expr * e); + void add_instance(quantifier * q, expr_ref_vector const & bindings, unsigned max_generation); public: model_checker(ast_manager & m, qi_params const & p, model_finder & mf); diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index ff84992e1..0536c200d 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -16,26 +16,24 @@ Author: Revision History: --*/ -#include"smt_model_finder.h" -#include"smt_context.h" -#include"ast_util.h" -#include"macro_util.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"array_decl_plugin.h" -#include"arith_simplifier_plugin.h" -#include"bv_simplifier_plugin.h" -#include"pull_quant.h" -#include"var_subst.h" -#include"backtrackable_set.h" -#include"for_each_expr.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"well_sorted.h" -#include"model_pp.h" -#include"ast_smt2_pp.h" -#include"cooperate.h" -#include"tactic_exception.h" +#include "util/cooperate.h" +#include "util/backtrackable_set.h" +#include "ast/ast_util.h" +#include "ast/macros/macro_util.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/normal_forms/pull_quant.h" +#include "ast/rewriter/var_subst.h" +#include "ast/for_each_expr.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/well_sorted.h" +#include "ast/ast_smt2_pp.h" +#include "model/model_pp.h" +#include "smt/smt_model_finder.h" +#include "smt/smt_context.h" +#include "tactic/tactic_exception.h" namespace smt { @@ -56,11 +54,9 @@ namespace smt { v1.swap(v2); return; } - typename ptr_vector::iterator it = v2.begin(); - typename ptr_vector::iterator end = v2.end(); - for (; it != end; ++it) { - if (!v1.contains(*it)) - v1.push_back(*it); + for (T* t : v2) { + if (!v1.contains(t)) + v1.push_back(t); } v2.finalize(); } @@ -86,12 +82,10 @@ namespace smt { expr_mark m_visited; public: instantiation_set(ast_manager & m):m_manager(m) {} - - ~instantiation_set() { - obj_map::iterator it = m_elems.begin(); - obj_map::iterator end = m_elems.end(); - for (; it != end; ++it) { - m_manager.dec_ref((*it).m_key); + + ~instantiation_set() { + for (auto const& kv : m_elems) { + m_manager.dec_ref(kv.m_key); } m_elems.reset(); } @@ -114,18 +108,14 @@ namespace smt { m_elems.erase(n); m_manager.dec_ref(n); } - + void display(std::ostream & out) const { - obj_map::iterator it = m_elems.begin(); - obj_map::iterator end = m_elems.end(); - for (; it != end; ++it) { - out << mk_bounded_pp((*it).m_key, m_manager) << " [" << (*it).m_value << "]\n"; + for (auto const& kv : m_elems) { + out << mk_bounded_pp(kv.m_key, m_manager) << " [" << kv.m_value << "]\n"; } out << "inverse:\n"; - obj_map::iterator it2 = m_inv.begin(); - obj_map::iterator end2 = m_inv.end(); - for (; it2 != end2; ++it2) { - out << mk_bounded_pp((*it2).m_key, m_manager) << " -> " << mk_bounded_pp((*it2).m_value, m_manager) << "\n"; + for (auto const& kv : m_inv) { + out << mk_bounded_pp(kv.m_key, m_manager) << " -> " << mk_bounded_pp(kv.m_value, m_manager) << "\n"; } } @@ -134,7 +124,7 @@ namespace smt { m_inv.find(v, t); return t; } - + unsigned get_generation(expr * t) const { unsigned gen = 0; m_elems.find(t, gen); @@ -142,12 +132,10 @@ namespace smt { } void mk_inverse(evaluator & ev) { - obj_map::iterator it = m_elems.begin(); - obj_map::iterator end = m_elems.end(); - for (; it != end; ++it) { - expr * t = (*it).m_key; + for (auto const& kv : m_elems) { + expr * t = kv.m_key; SASSERT(!contains_model_value(t)); - unsigned gen = (*it).m_value; + unsigned gen = kv.m_value; expr * t_val = ev.eval(t, true); if (!t_val) break; TRACE("model_finder", tout << mk_pp(t, m_manager) << " " << mk_pp(t_val, m_manager) << "\n";); @@ -197,15 +185,15 @@ namespace smt { }; /** - During model construction time, + During model construction time, we solve several constraints that impose restrictions on how the model for the ground formulas may be extended to a model to the relevant universal quantifiers. - + The class node and its subclasses are used to solve these constraints. */ - + // ----------------------------------- // // nodes @@ -219,14 +207,14 @@ namespace smt { unsigned m_id; node * m_find; unsigned m_eqc_size; - + sort * m_sort; // sort of the elements in the instantiation set. - + bool m_mono_proj; // relevant for integers & reals & bit-vectors bool m_signed_proj; // relevant for bit-vectors. ptr_vector m_avoid_set; ptr_vector m_exceptions; - + instantiation_set * m_set; expr * m_else; @@ -296,7 +284,7 @@ namespace smt { if (!ex.contains(n)) ex.push_back(n); } - + void set_mono_proj() { get_root()->m_mono_proj = true; } @@ -329,17 +317,13 @@ namespace smt { out << "root node ------\n"; out << "@" << m_id << " mono: " << m_mono_proj << " signed: " << m_signed_proj << ", sort: " << mk_pp(m_sort, m) << "\n"; out << "avoid-set: "; - ptr_vector::const_iterator it1 = m_avoid_set.begin(); - ptr_vector::const_iterator end1 = m_avoid_set.end(); - for (; it1 != end1; ++it1) { - out << "@" << (*it1)->get_root()->get_id() << " "; + for (node* n : m_avoid_set) { + out << "@" << n->get_root()->get_id() << " "; } out << "\n"; out << "exceptions: "; - ptr_vector::const_iterator it2 = m_exceptions.begin(); - ptr_vector::const_iterator end2 = m_exceptions.end(); - for (; it2 != end2; ++it2) { - out << mk_bounded_pp((*it2), m) << " "; + for (expr * e : m_exceptions) { + out << mk_bounded_pp(e, m) << " "; } out << "\n"; if (m_else) @@ -362,16 +346,14 @@ namespace smt { instantiation_set * get_instantiation_set() { return get_root()->m_set; } ptr_vector const & get_exceptions() const { return get_root()->m_exceptions; } - + ptr_vector const & get_avoid_set() const { return get_root()->m_avoid_set; } // return true if m_avoid_set.contains(this) bool must_avoid_itself() const { node * r = get_root(); - ptr_vector::const_iterator it = m_avoid_set.begin(); - ptr_vector::const_iterator end = m_avoid_set.end(); - for (; it != end; ++it) { - if (r == (*it)->get_root()) + for (node* n : m_avoid_set) { + if (r == n->get_root()) return true; } return false; @@ -382,8 +364,8 @@ namespace smt { SASSERT(get_root()->m_else == 0); get_root()->m_else = e; } - - expr * get_else() const { + + expr * get_else() const { return get_root()->m_else; } @@ -391,7 +373,7 @@ namespace smt { SASSERT(get_root()->m_proj == 0); get_root()->m_proj = f; } - + func_decl * get_proj() const { return get_root()->m_proj; } @@ -400,7 +382,7 @@ namespace smt { typedef std::pair ast_idx_pair; typedef pair_hash, unsigned_hash> ast_idx_pair_hash; typedef map > key2node; - + /** \brief Auxiliary class for processing the "Almost uninterpreted fragment" described in the paper: Complete instantiation for quantified SMT formulas @@ -408,9 +390,9 @@ namespace smt { The idea is to create node objects based on the information produced by the quantifier_analyzer. */ class auf_solver : public evaluator { - ast_manager & m_manager; - arith_simplifier_plugin * m_asimp; - bv_simplifier_plugin * m_bvsimp; + ast_manager & m; + arith_util m_arith; + bv_util m_bv; ptr_vector m_nodes; unsigned m_next_node_id; key2node m_uvars; @@ -418,16 +400,16 @@ namespace smt { context * m_context; - // Mapping from sort to auxiliary constant. - // This auxiliary constant is used as a "witness" that is asserted as different from a - // finite number of terms. + // Mapping from sort to auxiliary constant. + // This auxiliary constant is used as a "witness" that is asserted as different from a + // finite number of terms. // It is only safe to use this constant for infinite sorts. - obj_map m_sort2k; + obj_map m_sort2k; expr_ref_vector m_ks; // range of m_sort2k - + // Support for evaluating expressions in the current model. proto_model * m_model; - obj_map m_eval_cache[2]; + obj_map m_eval_cache[2]; expr_ref_vector m_eval_cache_range; ptr_vector m_root_nodes; @@ -444,7 +426,7 @@ namespace smt { m_eval_cache[1].reset(); m_eval_cache_range.reset(); } - + node * mk_node(key2node & m, ast * n, unsigned i, sort * s) { node * r = 0; ast_idx_pair k(n, i); @@ -460,23 +442,19 @@ namespace smt { } void display_key2node(std::ostream & out, key2node const & m) const { - key2node::iterator it = m.begin(); - key2node::iterator end = m.end(); - for (; it != end; ++it) { - ast * a = (*it).m_key.first; - unsigned i = (*it).m_key.second; - node * n = (*it).m_value; + for (auto const& kv : m) { + ast * a = kv.m_key.first; + unsigned i = kv.m_key.second; + node * n = kv.m_value; out << "#" << a->get_id() << ":" << i << " -> @" << n->get_id() << "\n"; } } void display_A_f_is(std::ostream & out) const { - key2node::iterator it = m_A_f_is.begin(); - key2node::iterator end = m_A_f_is.end(); - for (; it != end; ++it) { - func_decl * f = static_cast((*it).m_key.first); - unsigned i = (*it).m_key.second; - node * n = (*it).m_value; + for (auto const& kv : m_A_f_is) { + func_decl * f = static_cast(kv.m_key.first); + unsigned i = kv.m_key.second; + node * n = kv.m_value; out << f->get_name() << ":" << i << " -> @" << n->get_id() << "\n"; } } @@ -486,34 +464,30 @@ namespace smt { } public: - auf_solver(ast_manager & m, simplifier & s): - m_manager(m), + auf_solver(ast_manager & m): + m(m), + m_arith(m), + m_bv(m), m_next_node_id(0), m_context(0), m_ks(m), m_model(0), m_eval_cache_range(m), m_new_constraints(0) { - m_asimp = static_cast(s.get_plugin(m.mk_family_id("arith"))); - m_bvsimp = static_cast(s.get_plugin(m.mk_family_id("bv"))); } virtual ~auf_solver() { flush_nodes(); reset_eval_cache(); } - + void set_context(context * ctx) { SASSERT(m_context==0); m_context = ctx; } - ast_manager & get_manager() const { return m_manager; } - - arith_simplifier_plugin * get_arith_simp() const { return m_asimp; } - - bv_simplifier_plugin * get_bv_simp() const { return m_bvsimp; } - + ast_manager & get_manager() const { return m; } + void reset() { flush_nodes(); m_nodes.reset(); @@ -529,21 +503,21 @@ namespace smt { m_model = m; } - proto_model * get_model() const { + proto_model * get_model() const { SASSERT(m_model); return m_model; } - - node * get_uvar(quantifier * q, unsigned i) { + + node * get_uvar(quantifier * q, unsigned i) { SASSERT(i < q->get_num_decls()); sort * s = q->get_decl_sort(q->get_num_decls() - i - 1); - return mk_node(m_uvars, q, i, s); + return mk_node(m_uvars, q, i, s); } - node * get_A_f_i(func_decl * f, unsigned i) { + node * get_A_f_i(func_decl * f, unsigned i) { SASSERT(i < f->get_arity()); sort * s = f->get_domain(i); - return mk_node(m_A_f_is, f, i, s); + return mk_node(m_A_f_is, f, i, s); } instantiation_set const * get_uvar_inst_set(quantifier * q, unsigned i) const { @@ -554,14 +528,11 @@ namespace smt { return r->get_instantiation_set(); return 0; } - + void mk_instantiation_sets() { - ptr_vector::const_iterator it = m_nodes.begin(); - ptr_vector::const_iterator end = m_nodes.end(); - for (; it != end; ++it) { - node * curr = *it; + for (node* curr : m_nodes) { if (curr->is_root()) { - curr->mk_instantiation_set(m_manager); + curr->mk_instantiation_set(m); } } } @@ -569,22 +540,19 @@ namespace smt { // For each instantiation_set, reemove entries that do not evaluate to values. void cleanup_instantiation_sets() { ptr_vector to_delete; - ptr_vector::const_iterator it = m_nodes.begin(); - ptr_vector::const_iterator end = m_nodes.end(); - for (; it != end; ++it) { - node * curr = *it; + for (node * curr : m_nodes) { if (curr->is_root()) { instantiation_set * s = curr->get_instantiation_set(); to_delete.reset(); obj_map const & elems = s->get_elems(); - for (obj_map::iterator it = elems.begin(); it != elems.end(); it++) { - expr * n = it->m_key; + for (auto const& kv : elems) { + expr * n = kv.m_key; expr * n_val = eval(n, true); - if (!n_val || !m_manager.is_value(n_val)) + if (!n_val || !m.is_value(n_val)) to_delete.push_back(n); } - for (ptr_vector::iterator it = to_delete.begin(); it != to_delete.end(); it++) { - s->remove(*it); + for (expr* e : to_delete) { + s->remove(e); } } } @@ -592,11 +560,9 @@ namespace smt { void display_nodes(std::ostream & out) const { display_key2node(out, m_uvars); - display_A_f_is(out); - ptr_vector::const_iterator it = m_nodes.begin(); - ptr_vector::const_iterator end = m_nodes.end(); - for (; it != end; ++it) { - (*it)->display(out, m_manager); + display_A_f_is(out); + for (node* n : m_nodes) { + n->display(out, m); } } @@ -605,14 +571,14 @@ namespace smt { if (m_eval_cache[model_completion].find(n, r)) { return r; } - expr_ref tmp(m_manager); + expr_ref tmp(m); if (!m_model->eval(n, tmp, model_completion)) { r = 0; - TRACE("model_finder", tout << "eval\n" << mk_pp(n, m_manager) << "\n-----> null\n";); + TRACE("model_finder", tout << "eval\n" << mk_pp(n, m) << "\n-----> null\n";); } else { r = tmp; - TRACE("model_finder", tout << "eval\n" << mk_pp(n, m_manager) << "\n----->\n" << mk_pp(r, m_manager) << "\n";); + TRACE("model_finder", tout << "eval\n" << mk_pp(n, m) << "\n----->\n" << mk_pp(r, m) << "\n";); } m_eval_cache[model_completion].insert(n, r); m_eval_cache_range.push_back(r); @@ -627,19 +593,15 @@ namespace smt { void collect_exceptions_values(node * n, ptr_buffer & r) { ptr_vector const & exceptions = n->get_exceptions(); ptr_vector const & avoid_set = n->get_avoid_set(); - - ptr_vector::const_iterator it1 = exceptions.begin(); - ptr_vector::const_iterator end1 = exceptions.end(); - for (; it1 != end1; ++it1) { - expr * val = eval(*it1, true); + + for (expr* e : exceptions) { + expr * val = eval(e, true); SASSERT(val != 0); r.push_back(val); } - - ptr_vector::const_iterator it2 = avoid_set.begin(); - ptr_vector::const_iterator end2 = avoid_set.end(); - for (; it2 != end2; ++it2) { - node * n = (*it2)->get_root(); + + for (node* a : avoid_set) { + node * n = a->get_root(); if (!n->is_mono_proj() && n->get_else() != 0) { expr * val = eval(n->get_else(), true); SASSERT(val != 0); @@ -660,21 +622,20 @@ namespace smt { obj_map const & elems = s->get_elems(); expr * t_result = 0; - unsigned gen_result = UINT_MAX; - obj_map::iterator it1 = elems.begin(); - obj_map::iterator end1 = elems.end(); - for (; it1 != end1; ++it1) { - expr * t = (*it1).m_key; - unsigned gen = (*it1).m_value; + unsigned gen_result = UINT_MAX; + for (auto const& kv : elems) { + expr * t = kv.m_key; + unsigned gen = kv.m_value; expr * t_val = eval(t, true); SASSERT(t_val != 0); - ptr_buffer::const_iterator it2 = ex_vals.begin(); - ptr_buffer::const_iterator end2 = ex_vals.end(); - for (; it2 != end2; ++it2) { - if (!m_manager.are_distinct(t_val, *it2)) + bool found = false; + for (expr* v : ex_vals) { + if (!m.are_distinct(t_val, v)) { + found = true; break; + } } - if (it2 == end2 && (t_result == 0 || gen < gen_result)) { + if (!found && (t_result == 0 || gen < gen_result)) { t_result = t; gen_result = gen; } @@ -685,12 +646,12 @@ namespace smt { bool is_infinite(sort * s) const { // we should not assume that uninterpreted sorts are infinite in benchmarks with quantifiers. return - !m_manager.is_uninterp(s) && + !m.is_uninterp(s) && s->is_infinite(); } /** - \brief Return a fresh constant k that is used as a witness for elements that must be different from + \brief Return a fresh constant k that is used as a witness for elements that must be different from a set of values. */ app * get_k_for(sort * s) { @@ -698,7 +659,8 @@ namespace smt { app * r = 0; if (m_sort2k.find(s, r)) return r; - r = m_manager.mk_fresh_const("k", s); + r = m.mk_fresh_const("k", s); + m_model->register_aux_decl(r->get_decl()); m_sort2k.insert(s, r); m_ks.push_back(r); return r; @@ -706,13 +668,13 @@ namespace smt { /** \brief Get the interpretation for k in m_model. - If m_model does not provide an interpretation for k, then + If m_model does not provide an interpretation for k, then create a fresh one. Remark: this method uses get_fresh_value, so it may fail. */ expr * get_k_interp(app * k) { - sort * s = m_manager.get_sort(k); + sort * s = m.get_sort(k); SASSERT(is_infinite(s)); func_decl * k_decl = k->get_decl(); expr * r = m_model->get_const_interp(k_decl); @@ -723,7 +685,7 @@ namespace smt { return 0; m_model->register_decl(k_decl, r); SASSERT(m_model->get_const_interp(k_decl) == r); - TRACE("model_finder", tout << mk_pp(r, m_manager) << "\n";); + TRACE("model_finder", tout << mk_pp(r, m) << "\n";); return r; } @@ -733,26 +695,23 @@ namespace smt { It invokes get_k_interp that may fail. */ bool assert_k_diseq_exceptions(app * k, ptr_vector const & exceptions) { - TRACE("assert_k_diseq_exceptions", tout << "assert_k_diseq_exceptions, " << "k: " << mk_pp(k, m_manager) << "\nexceptions:\n"; - for (unsigned i = 0; i < exceptions.size(); i++) tout << mk_pp(exceptions[i], m_manager) << "\n";); + TRACE("assert_k_diseq_exceptions", tout << "assert_k_diseq_exceptions, " << "k: " << mk_pp(k, m) << "\nexceptions:\n"; + for (expr * e : exceptions) tout << mk_pp(e, m) << "\n";); expr * k_interp = get_k_interp(k); if (k_interp == 0) return false; - ptr_vector::const_iterator it = exceptions.begin(); - ptr_vector::const_iterator end = exceptions.end(); - for (; it != end; ++it) { - expr * ex = *it; + for (expr * ex : exceptions) { expr * ex_val = eval(ex, true); - if (!m_manager.are_distinct(k_interp, ex_val)) { + if (!m.are_distinct(k_interp, ex_val)) { SASSERT(m_new_constraints); // This constraint cannot be asserted into m_context during model construction. // We must save it, and assert it during a restart. - m_new_constraints->push_back(m_manager.mk_not(m_manager.mk_eq(k, ex))); + m_new_constraints->push_back(m.mk_not(m.mk_eq(k, ex))); } } return true; } - + void set_projection_else(node * n) { SASSERT(n->is_root()); SASSERT(!n->is_mono_proj()); @@ -760,7 +719,7 @@ namespace smt { ptr_vector const & exceptions = n->get_exceptions(); ptr_vector const & avoid_set = n->get_avoid_set(); obj_map const & elems = s->get_elems(); - SASSERT(!elems.empty()); + if (elems.empty()) return; if (!exceptions.empty() || !avoid_set.empty()) { ptr_buffer ex_vals; collect_exceptions_values(n, ex_vals); @@ -770,7 +729,7 @@ namespace smt { return; } sort * s = n->get_sort(); - TRACE("model_finder", tout << "trying to create k for " << mk_pp(s, m_manager) << ", is_infinite: " << is_infinite(s) << "\n";); + TRACE("model_finder", tout << "trying to create k for " << mk_pp(s, m) << ", is_infinite: " << is_infinite(s) << "\n";); if (is_infinite(s)) { app * k = get_k_for(s); if (assert_k_diseq_exceptions(k, exceptions)) { @@ -779,7 +738,7 @@ namespace smt { return; } } - // TBD: add support for the else of bitvectors. + // TBD: add support for the else of bitvectors. // Idea: get the term t with the minimal interpreation and use t - 1. } n->set_else((*(elems.begin())).m_key); @@ -793,31 +752,36 @@ namespace smt { void add_mono_exceptions(node * n) { SASSERT(n->is_mono_proj()); sort * s = n->get_sort(); - arith_simplifier_plugin * as = get_arith_simp(); - bv_simplifier_plugin * bs = get_bv_simp(); - bool is_int = as->is_int_sort(s); - bool is_bv = bs->is_bv_sort(s); - if (!is_int && !is_bv) - return; - poly_simplifier_plugin * ps = as; - if (is_bv) - ps = bs; - ps->set_curr_sort(s); - expr_ref one(m_manager); - one = ps->mk_one(); + arith_rewriter arw(m); + bv_rewriter brw(m); ptr_vector const & exceptions = n->get_exceptions(); - ptr_vector::const_iterator it = exceptions.begin(); - ptr_vector::const_iterator end = exceptions.end(); - for (; it != end; ++it) { - expr * e = *it; - expr_ref e_plus_1(m_manager); - expr_ref e_minus_1(m_manager); - TRACE("mf_simp_bug", tout << "e:\n" << mk_ismt2_pp(e, m_manager) << "\none:\n" << mk_ismt2_pp(one, m_manager) << "\n";); - ps->mk_add(e, one, e_plus_1); - ps->mk_sub(e, one, e_minus_1); - // Note: exceptions come from quantifiers bodies. So, they have generation 0. - n->insert(e_plus_1, 0); - n->insert(e_minus_1, 0); + expr_ref e_minus_1(m), e_plus_1(m); + if (m_arith.is_int(s)) { + expr_ref one(m_arith.mk_int(1), m); + arith_rewriter arith_rw(m); + for (expr * e : exceptions) { + arith_rw.mk_sub(e, one, e_minus_1); + arith_rw.mk_add(e, one, e_plus_1); + TRACE("mf_simp_bug", tout << "e:\n" << mk_ismt2_pp(e, m) << "\none:\n" << mk_ismt2_pp(one, m) << "\n";); + // Note: exceptions come from quantifiers bodies. So, they have generation 0. + n->insert(e_plus_1, 0); + n->insert(e_minus_1, 0); + } + } + else if (m_bv.is_bv_sort(s)) { + expr_ref one(m_bv.mk_numeral(rational(1), s), m); + bv_rewriter bv_rw(m); + for (expr * e : exceptions) { + bv_rw.mk_add(e, one, e_plus_1); + bv_rw.mk_sub(e, one, e_minus_1); + TRACE("mf_simp_bug", tout << "e:\n" << mk_ismt2_pp(e, m) << "\none:\n" << mk_ismt2_pp(one, m) << "\n";); + // Note: exceptions come from quantifiers bodies. So, they have generation 0. + n->insert(e_plus_1, 0); + n->insert(e_minus_1, 0); + } + } + else { + return; } } @@ -825,10 +789,8 @@ namespace smt { instantiation_set const * s = n->get_instantiation_set(); obj_hashtable already_found; obj_map const & elems = s->get_elems(); - obj_map::iterator it = elems.begin(); - obj_map::iterator end = elems.end(); - for (; it != end; ++it) { - expr * t = (*it).m_key; + for (auto const& kv : elems) { + expr * t = kv.m_key; expr * t_val = eval(t, true); if (t_val && !already_found.contains(t_val)) { values.push_back(t_val); @@ -836,20 +798,18 @@ namespace smt { } } TRACE("model_finder_bug", tout << "values for the instantiation_set of @" << n->get_id() << "\n"; - ptr_buffer::const_iterator it = values.begin(); - ptr_buffer::const_iterator end = values.end(); - for (; it != end; ++it) { - expr * v = *it; - tout << mk_pp(v, m_manager) << "\n"; + for (expr * v : values) { + tout << mk_pp(v, m) << "\n"; }); } + template struct numeral_lt { - poly_simplifier_plugin * m_p; - numeral_lt(poly_simplifier_plugin * p):m_p(p) {} - bool operator()(expr * e1, expr * e2) { + T& m_util; + numeral_lt(T& a): m_util(a) {} + bool operator()(expr* e1, expr* e2) { rational v1, v2; - if (m_p->is_numeral(e1, v1) && m_p->is_numeral(e2, v2)) { + if (m_util.is_numeral(e1, v1) && m_util.is_numeral(e2, v2)) { return v1 < v2; } else { @@ -858,15 +818,16 @@ namespace smt { } }; + struct signed_bv_lt { - bv_simplifier_plugin * m_bs; + bv_util& m_bv; unsigned m_bv_size; - signed_bv_lt(bv_simplifier_plugin * bs, unsigned sz):m_bs(bs), m_bv_size(sz) {} + signed_bv_lt(bv_util& bv, unsigned sz):m_bv(bv), m_bv_size(sz) {} bool operator()(expr * e1, expr * e2) { rational v1, v2; - if (m_bs->is_numeral(e1, v1) && m_bs->is_numeral(e2, v2)) { - v1 = m_bs->norm(v1, m_bv_size, true); - v2 = m_bs->norm(v2, m_bv_size, true); + if (m_bv.is_numeral(e1, v1) && m_bv.is_numeral(e2, v2)) { + v1 = m_bv.norm(v1, m_bv_size, true); + v2 = m_bv.norm(v2, m_bv_size, true); return v1 < v2; } else { @@ -877,15 +838,14 @@ namespace smt { void sort_values(node * n, ptr_buffer & values) { sort * s = n->get_sort(); - if (get_arith_simp()->is_arith_sort(s)) { - std::sort(values.begin(), values.end(), numeral_lt(get_arith_simp())); + if (m_arith.is_int(s) || m_arith.is_real(s)) { + std::sort(values.begin(), values.end(), numeral_lt(m_arith)); } else if (!n->is_signed_proj()) { - std::sort(values.begin(), values.end(), numeral_lt(get_bv_simp())); + std::sort(values.begin(), values.end(), numeral_lt(m_bv)); } else { - bv_simplifier_plugin * bs = get_bv_simp(); - std::sort(values.begin(), values.end(), signed_bv_lt(bs, bs->get_bv_size(s))); + std::sort(values.begin(), values.end(), signed_bv_lt(m_bv, m_bv.get_bv_size(s))); } } @@ -896,27 +856,25 @@ namespace smt { if (values.empty()) return; sort_values(n, values); sort * s = n->get_sort(); - arith_simplifier_plugin * as = get_arith_simp(); - bv_simplifier_plugin * bs = get_bv_simp(); - bool is_arith = as->is_arith_sort(s); + bool is_arith = m_arith.is_int(s) || m_arith.is_real(s); bool is_signed = n->is_signed_proj(); unsigned sz = values.size(); SASSERT(sz > 0); - func_decl * p = m_manager.mk_fresh_func_decl(1, &s, s); + func_decl * p = m.mk_fresh_func_decl(1, &s, s); expr * pi = values[sz - 1]; - expr_ref var(m_manager); - var = m_manager.mk_var(0, s); + expr_ref var(m); + var = m.mk_var(0, s); for (unsigned i = sz - 1; i >= 1; i--) { - expr_ref c(m_manager); + expr_ref c(m); if (is_arith) - as->mk_lt(var, values[i], c); + c = m_arith.mk_lt(var, values[i]); else if (!is_signed) - bs->mk_ult(var, values[i], c); + c = m.mk_not(m_bv.mk_ule(values[i], var)); else - bs->mk_slt(var, values[i], c); - pi = m_manager.mk_ite(c, values[i-1], pi); + c = m.mk_not(m_bv.mk_sle(values[i], var)); + pi = m.mk_ite(c, values[i-1], pi); } - func_interp * rpi = alloc(func_interp, m_manager, 1); + func_interp * rpi = alloc(func_interp, m, 1); rpi->set_else(pi); m_model->register_aux_decl(p, rpi); n->set_proj(p); @@ -927,25 +885,21 @@ namespace smt { ptr_buffer values; get_instantiation_set_values(n, values); sort * s = n->get_sort(); - expr * else_val = eval(n->get_else(), true); - func_decl * p = m_manager.mk_fresh_func_decl(1, &s, s); - func_interp * pi = alloc(func_interp, m_manager, 1); - pi->set_else(else_val); + func_decl * p = m.mk_fresh_func_decl(1, &s, s); + func_interp * pi = alloc(func_interp, m, 1); m_model->register_aux_decl(p, pi); - ptr_buffer::const_iterator it = values.begin(); - ptr_buffer::const_iterator end = values.end(); - for (; it != end; ++it) { - expr * v = *it; + if (n->get_else()) { + expr * else_val = eval(n->get_else(), true); + pi->set_else(else_val); + } + for (expr * v : values) { pi->insert_new_entry(&v, v); } n->set_proj(p); } - + void mk_projections() { - ptr_vector::const_iterator it = m_root_nodes.begin(); - ptr_vector::const_iterator end = m_root_nodes.end(); - for (; it != end; ++it) { - node * n = *it; + for (node * n : m_root_nodes) { SASSERT(n->is_root()); if (n->is_mono_proj()) mk_mono_proj(n); @@ -953,19 +907,17 @@ namespace smt { mk_simple_proj(n); } } - + /** \brief Store in r the partial functions that have A_f_i nodes. */ void collect_partial_funcs(func_decl_set & r) { - key2node::iterator it = m_A_f_is.begin(); - key2node::iterator end = m_A_f_is.end(); - for (; it != end; ++it) { - func_decl * f = to_func_decl((*it).m_key.first); + for (auto const& kv : m_A_f_is) { + func_decl * f = to_func_decl(kv.m_key.first); if (!r.contains(f)) { func_interp * fi = m_model->get_func_interp(f); if (fi == 0) { - fi = alloc(func_interp, m_manager, f->get_arity()); + fi = alloc(func_interp, m, f->get_arity()); m_model->register_decl(f, fi); SASSERT(fi->is_partial()); } @@ -975,7 +927,7 @@ namespace smt { } } } - + /** \brief Make sorts associated with nodes that must avoid themselves finite. Only uninterpreted sorts are considered. @@ -984,15 +936,12 @@ namespace smt { for more details. */ void mk_sorts_finite() { - ptr_vector::const_iterator it = m_root_nodes.begin(); - ptr_vector::const_iterator end = m_root_nodes.end(); - for (; it != end; ++it) { - node * n = *it; + for (node * n : m_root_nodes) { SASSERT(n->is_root()); sort * s = n->get_sort(); - if (m_manager.is_uninterp(s) && + if (m.is_uninterp(s) && // Making all uninterpreted sorts finite. - // n->must_avoid_itself() && + // n->must_avoid_itself() && !m_model->is_finite(s)) { m_model->freeze_universe(s); } @@ -1000,24 +949,21 @@ namespace smt { } void add_elem_to_empty_inst_sets() { - ptr_vector::const_iterator it = m_root_nodes.begin(); - ptr_vector::const_iterator end = m_root_nodes.end(); obj_map sort2elems; ptr_vector need_fresh; - for (; it != end; ++it) { - node * n = *it; + for (node * n : m_root_nodes) { SASSERT(n->is_root()); instantiation_set const * s = n->get_instantiation_set(); TRACE("model_finder", s->display(tout);); obj_map const & elems = s->get_elems(); if (elems.empty()) { - // The method get_some_value cannot be used if n->get_sort() is an uninterpreted sort or is a sort built using uninterpreted sorts + // The method get_some_value cannot be used if n->get_sort() is an uninterpreted sort or is a sort built using uninterpreted sorts // (e.g., (Array S S) where S is uninterpreted). The problem is that these sorts do not have a fixed interpretation. // Moreover, a model assigns an arbitrary intepretation to these sorts using "model_values" a model value. // If these module values "leak" inside the logical context, they may affect satisfiability. - // + // sort * ns = n->get_sort(); - if (m_manager.is_fully_interp(ns)) { + if (m.is_fully_interp(ns)) { n->insert(m_model->get_some_value(ns), 0); } else { @@ -1028,18 +974,18 @@ namespace smt { sort2elems.insert(n->get_sort(), elems.begin()->m_key); } } - expr_ref_vector trail(m_manager); + expr_ref_vector trail(m); for (unsigned i = 0; i < need_fresh.size(); ++i) { expr * e; node* n = need_fresh[i]; sort* s = n->get_sort(); if (!sort2elems.find(s, e)) { - e = m_manager.mk_fresh_const("elem", s); + e = m.mk_fresh_const("elem", s); trail.push_back(e); sort2elems.insert(s, e); } n->insert(e, 0); - TRACE("model_finder", tout << "fresh constant: " << mk_pp(e, m_manager) << "\n";); + TRACE("model_finder", tout << "fresh constant: " << mk_pp(e, m) << "\n";); } } @@ -1048,22 +994,19 @@ namespace smt { */ void collect_root_nodes() { m_root_nodes.reset(); - ptr_vector::const_iterator it = m_nodes.begin(); - ptr_vector::const_iterator end = m_nodes.end(); - for (; it != end; ++it) { - node * n = *it; + for (node * n : m_nodes) { if (n->is_root()) m_root_nodes.push_back(n); } } - + /** \brief Return the projection function for f at argument i. - Return 0, if there is none. + Return 0, if there is none. \remark This method assumes that mk_projections was already invoked. - + \remark f may have a non partial interpretation on m_model. This may happen because the evaluator uses model_completion. In the beginning of fix_model() we collected all f with @@ -1080,31 +1023,28 @@ namespace smt { return 0; return r->get_proj(); } - + /** - \brief Complete the interpretation of the functions that were + \brief Complete the interpretation of the functions that were collected in the beginning of fix_model(). */ void complete_partial_funcs(func_decl_set const & partial_funcs) { - func_decl_set::iterator it = partial_funcs.begin(); - func_decl_set::iterator end = partial_funcs.end(); - for (; it != end; ++it) { - func_decl * f = *it; + for (func_decl * f : partial_funcs) { // Complete the current interpretation m_model->complete_partial_func(f); - + unsigned arity = f->get_arity(); func_interp * fi = m_model->get_func_interp(f); if (fi->is_constant()) continue; // there is no point in using the projection for fi, since fi is the constant function. - expr_ref_vector args(m_manager); + expr_ref_vector args(m); bool has_proj = false; for (unsigned i = 0; i < arity; i++) { - var * v = m_manager.mk_var(i, f->get_domain(i)); + var * v = m.mk_var(i, f->get_domain(i)); func_decl * pi = get_f_i_proj(f, i); if (pi != 0) { - args.push_back(m_manager.mk_app(pi, v)); + args.push_back(m.mk_app(pi, v)); has_proj = true; } else { @@ -1113,11 +1053,11 @@ namespace smt { } if (has_proj) { // f_aux will be assigned to the old interpretation of f. - func_decl * f_aux = m_manager.mk_fresh_func_decl(f->get_name(), symbol::null, arity, f->get_domain(), f->get_range()); - func_interp * new_fi = alloc(func_interp, m_manager, arity); - new_fi->set_else(m_manager.mk_app(f_aux, args.size(), args.c_ptr())); + func_decl * f_aux = m.mk_fresh_func_decl(f->get_name(), symbol::null, arity, f->get_domain(), f->get_range()); + func_interp * new_fi = alloc(func_interp, m, arity); + new_fi->set_else(m.mk_app(f_aux, args.size(), args.c_ptr())); TRACE("model_finder", tout << "Setting new interpretation for " << f->get_name() << "\n" << - mk_pp(new_fi->get_else(), m_manager) << "\n";); + mk_pp(new_fi->get_else(), m) << "\n";); m_model->reregister_decl(f, new_fi, f_aux); } } @@ -1128,12 +1068,9 @@ namespace smt { instantiation_set * s = n->get_instantiation_set(); s->mk_inverse(*this); } - + void mk_inverses() { - ptr_vector::const_iterator it = m_root_nodes.begin(); - ptr_vector::const_iterator end = m_root_nodes.end(); - for (; it != end; ++it) { - node * n = *it; + for (node * n : m_root_nodes) { SASSERT(n->is_root()); mk_inverse(n); } @@ -1171,7 +1108,7 @@ namespace smt { information about the quantifier structure. These bits are instances of subclasses of qinfo. */ - + /** \brief Generic bit of information collected when analyzing quantifiers. The subclasses are defined in the .cpp file. @@ -1182,7 +1119,7 @@ namespace smt { virtual char const * get_kind() const = 0; virtual bool is_equal(qinfo const * qi) const = 0; virtual void display(std::ostream & out) const { out << "[" << get_kind() << "]"; } - + // AUF fragment solver virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) = 0; virtual void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) = 0; @@ -1203,17 +1140,17 @@ namespace smt { f_var(func_decl * f, unsigned i, unsigned j):m_f(f), m_arg_i(i), m_var_j(j) {} virtual ~f_var() {} - virtual char const * get_kind() const { - return "f_var"; + virtual char const * get_kind() const { + return "f_var"; } - + virtual bool is_equal(qinfo const * qi) const { if (qi->get_kind() != get_kind()) return false; f_var const * other = static_cast(qi); return m_f == other->m_f && m_arg_i == other->m_arg_i && m_var_j == other->m_var_j; } - + virtual void display(std::ostream & out) const { out << "(" << m_f->get_name() << ":" << m_arg_i << " -> v!" << m_var_j << ")"; } @@ -1233,7 +1170,7 @@ namespace smt { for (unsigned i = 0; i < m_f->get_arity(); i++) tout << mk_pp(m_f->get_domain(i), m) << " "; tout << "-> " << mk_pp(m_f->get_range(), m) << "\n"; ); - + n1->merge(n2); } @@ -1255,7 +1192,7 @@ namespace smt { // a necessary instantiation. enode * e_arg = n->get_arg(m_arg_i); expr * arg = e_arg->get_owner(); - A_f_i->insert(arg, e_arg->get_generation()); + A_f_i->insert(arg, e_arg->get_generation()); } } } @@ -1268,7 +1205,7 @@ namespace smt { uvar_inst_sets[m_var_j] = alloc(instantiation_set, ctx->get_manager()); instantiation_set * s = uvar_inst_sets[m_var_j]; SASSERT(s != 0); - + enode_vector::const_iterator it = ctx->begin_enodes_of(m_f); enode_vector::const_iterator end = ctx->end_enodes_of(m_f); for (; it != end; it++) { @@ -1276,7 +1213,7 @@ namespace smt { if (ctx->is_relevant(n)) { enode * e_arg = n->get_arg(m_arg_i); expr * arg = e_arg->get_owner(); - s->insert(arg, e_arg->get_generation()); + s->insert(arg, e_arg->get_generation()); } } } @@ -1291,19 +1228,19 @@ namespace smt { } virtual ~f_var_plus_offset() {} - virtual char const * get_kind() const { - return "f_var_plus_offset"; + virtual char const * get_kind() const { + return "f_var_plus_offset"; } - + virtual bool is_equal(qinfo const * qi) const { if (qi->get_kind() != get_kind()) return false; f_var_plus_offset const * other = static_cast(qi); return m_f == other->m_f && m_arg_i == other->m_arg_i && m_var_j == other->m_var_j && m_offset.get() == other->m_offset.get(); } - + virtual void display(std::ostream & out) const { - out << "(" << m_f->get_name() << ":" << m_arg_i << " - " << + out << "(" << m_f->get_name() << ":" << m_arg_i << " - " << mk_bounded_pp(m_offset.get(), m_offset.get_manager()) << " -> v!" << m_var_j << ")"; } @@ -1320,21 +1257,22 @@ namespace smt { if (A_f_i == S_j) { // there is no finite fixpoint... we just copy the i-th arguments of A_f_i - m_offset // hope for the best... - arith_simplifier_plugin * as = s.get_arith_simp(); - bv_simplifier_plugin * bs = s.get_bv_simp(); node * S_j = s.get_uvar(q, m_var_j); enode_vector::const_iterator it = ctx->begin_enodes_of(m_f); enode_vector::const_iterator end = ctx->end_enodes_of(m_f); for (; it != end; it++) { enode * n = *it; if (ctx->is_relevant(n)) { + arith_rewriter arith_rw(ctx->get_manager()); + bv_util bv(ctx->get_manager()); + bv_rewriter bv_rw(ctx->get_manager()); enode * e_arg = n->get_arg(m_arg_i); expr * arg = e_arg->get_owner(); expr_ref arg_minus_k(ctx->get_manager()); - if (bs->is_bv(arg)) - bs->mk_sub(arg, m_offset, arg_minus_k); + if (bv.is_bv(arg)) + bv_rw.mk_sub(arg, m_offset, arg_minus_k); else - as->mk_sub(arg, m_offset, arg_minus_k); + arith_rw.mk_sub(arg, m_offset, arg_minus_k); S_j->insert(arg_minus_k, e_arg->get_generation()); } } @@ -1354,23 +1292,33 @@ namespace smt { template void copy_instances(node * from, node * to, auf_solver & s) { - arith_simplifier_plugin * as = s.get_arith_simp(); - bv_simplifier_plugin * bs = s.get_bv_simp(); - poly_simplifier_plugin * ps = as; - if (bs->is_bv_sort(from->get_sort())) - ps = bs; instantiation_set const * from_s = from->get_instantiation_set(); obj_map const & elems_s = from_s->get_elems(); - obj_map::iterator it = elems_s.begin(); - obj_map::iterator end = elems_s.end(); - for (; it != end; ++it) { - expr * n = (*it).m_key; + + arith_rewriter arith_rw(m_offset.get_manager()); + bv_rewriter bv_rw(m_offset.get_manager()); + bool is_bv = bv_util(m_offset.get_manager()).is_bv_sort(from->get_sort()); + + for (auto const& kv : elems_s) { + expr * n = kv.m_key; expr_ref n_k(m_offset.get_manager()); - if (PLUS) - ps->mk_add(n, m_offset, n_k); - else - ps->mk_sub(n, m_offset, n_k); - to->insert(n_k, (*it).m_value); + if (PLUS) { + if (is_bv) { + bv_rw.mk_add(n, m_offset, n_k); + } + else { + arith_rw.mk_add(n, m_offset, n_k); + } + } + else { + if (is_bv) { + bv_rw.mk_sub(n, m_offset, n_k); + } + else { + arith_rw.mk_sub(n, m_offset, n_k); + } + } + to->insert(n_k, kv.m_value); } } @@ -1396,11 +1344,11 @@ namespace smt { /** \brief auf_arr is a term (pattern) of the form: - + FORM := GROUND-TERM | (select FORM VAR) - - Store in arrays, all enodes that match the pattern + + Store in arrays, all enodes that match the pattern */ void get_auf_arrays(app * auf_arr, context * ctx, ptr_buffer & arrays) { if (is_ground(auf_arr)) { @@ -1415,10 +1363,7 @@ namespace smt { app * nested_array = to_app(auf_arr->get_arg(0)); ptr_buffer nested_arrays; get_auf_arrays(nested_array, ctx, nested_arrays); - ptr_buffer::const_iterator it = nested_arrays.begin(); - ptr_buffer::const_iterator end = nested_arrays.end(); - for (; it != end; ++it) { - enode * curr = *it; + for (enode * curr : nested_arrays) { enode_vector::iterator it2 = curr->begin_parents(); enode_vector::iterator end2 = curr->end_parents(); for (; it2 != end2; ++it2) { @@ -1430,10 +1375,11 @@ namespace smt { } } } - + class select_var : public qinfo { protected: - ast_manager & m_manager; + ast_manager & m_manager; + array_util m_array; app * m_select; // It must satisfy is_auf_select... see bool is_auf_select(expr * t) const unsigned m_arg_i; unsigned m_var_j; @@ -1442,26 +1388,26 @@ namespace smt { func_decl * get_array_func_decl(app * ground_array, auf_solver & s) { expr * ground_array_interp = s.eval(ground_array, false); - if (ground_array_interp != 0 && s.get_model()->is_as_array(ground_array_interp)) - return to_func_decl(to_app(ground_array_interp)->get_decl()->get_parameter(0).get_ast()); + if (ground_array_interp != 0 && m_array.is_as_array(ground_array_interp)) + return m_array.get_as_array_func_decl(ground_array_interp); return 0; } public: - select_var(ast_manager & m, app * s, unsigned i, unsigned j):m_manager(m), m_select(s), m_arg_i(i), m_var_j(j) {} + select_var(ast_manager & m, app * s, unsigned i, unsigned j):m_manager(m), m_array(m), m_select(s), m_arg_i(i), m_var_j(j) {} virtual ~select_var() {} virtual char const * get_kind() const { - return "select_var"; + return "select_var"; } - + virtual bool is_equal(qinfo const * qi) const { if (qi->get_kind() != get_kind()) return false; select_var const * other = static_cast(qi); return m_select == other->m_select && m_arg_i == other->m_arg_i && m_var_j == other->m_var_j; } - + virtual void display(std::ostream & out) const { out << "(" << mk_bounded_pp(m_select, m_manager) << ":" << m_arg_i << " -> v!" << m_var_j << ")"; } @@ -1469,18 +1415,14 @@ namespace smt { virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) { ptr_buffer arrays; get_auf_arrays(get_array(), ctx, arrays); - TRACE("select_var", + TRACE("select_var", tout << "enodes matching: "; display(tout); tout << "\n"; - ptr_buffer::const_iterator it = arrays.begin(); - ptr_buffer::const_iterator end = arrays.end(); - for (; it != end; ++it) { - tout << "#" << (*it)->get_owner()->get_id() << "\n" << mk_pp((*it)->get_owner(), m_manager) << "\n"; + for (enode* n : arrays) { + tout << "#" << n->get_owner()->get_id() << "\n" << mk_pp(n->get_owner(), m_manager) << "\n"; }); - node * n1 = s.get_uvar(q, m_var_j); - ptr_buffer::const_iterator it = arrays.begin(); - ptr_buffer::const_iterator end = arrays.end(); - for (; it != end; ++it) { - app * ground_array = (*it)->get_owner(); + node * n1 = s.get_uvar(q, m_var_j); + for (enode* n : arrays) { + app * ground_array = n->get_owner(); func_decl * f = get_array_func_decl(ground_array, s); if (f) { SASSERT(m_arg_i >= 1); @@ -1493,10 +1435,7 @@ namespace smt { virtual void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) { ptr_buffer arrays; get_auf_arrays(get_array(), ctx, arrays); - ptr_buffer::const_iterator it = arrays.begin(); - ptr_buffer::const_iterator end = arrays.end(); - for (; it != end; ++it) { - enode * curr = (*it); + for (enode * curr : arrays) { app * ground_array = curr->get_owner(); func_decl * f = get_array_func_decl(ground_array, s); if (f) { @@ -1504,7 +1443,7 @@ namespace smt { enode_vector::iterator it2 = curr->begin_parents(); enode_vector::iterator end2 = curr->end_parents(); for (; it2 != end2; ++it2) { - enode * p = *it2; + enode * p = *it2; if (ctx->is_relevant(p) && p->get_owner()->get_decl() == m_select->get_decl()) { SASSERT(m_arg_i < p->get_owner()->get_num_args()); enode * e_arg = p->get_arg(m_arg_i); @@ -1515,7 +1454,7 @@ namespace smt { } } }; - + class var_pair : public qinfo { protected: unsigned m_var_i; @@ -1525,16 +1464,16 @@ namespace smt { if (m_var_i > m_var_j) std::swap(m_var_i, m_var_j); } - + virtual ~var_pair() {} virtual bool is_equal(qinfo const * qi) const { if (qi->get_kind() != get_kind()) return false; var_pair const * other = static_cast(qi); - return m_var_i == other->m_var_i && m_var_j == other->m_var_j; + return m_var_i == other->m_var_i && m_var_j == other->m_var_j; } - + virtual void display(std::ostream & out) const { out << "(" << get_kind() << ":v!" << m_var_i << ":v!" << m_var_j << ")"; } @@ -1569,7 +1508,7 @@ namespace smt { n1->merge(n2); } }; - + class x_leq_y : public var_pair { public: x_leq_y(unsigned i, unsigned j):var_pair(i, j) {} @@ -1588,7 +1527,7 @@ namespace smt { public: x_sleq_y(unsigned i, unsigned j):x_leq_y(i, j) {} virtual char const * get_kind() const { return "x_sleq_y"; } - + virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) { node * n1 = s.get_uvar(q, m_var_i); node * n2 = s.get_uvar(q, m_var_j); @@ -1597,7 +1536,7 @@ namespace smt { n1->set_signed_proj(); } }; - + class var_expr_pair : public qinfo { protected: unsigned m_var_i; @@ -1606,19 +1545,19 @@ namespace smt { var_expr_pair(ast_manager & m, unsigned i, expr * t): m_var_i(i), m_t(t, m) {} ~var_expr_pair() {} - + virtual bool is_equal(qinfo const * qi) const { if (qi->get_kind() != get_kind()) return false; var_expr_pair const * other = static_cast(qi); return m_var_i == other->m_var_i && m_t.get() == other->m_t.get(); } - + virtual void display(std::ostream & out) const { out << "(" << get_kind() << ":v!" << m_var_i << ":" << mk_bounded_pp(m_t.get(), m_t.get_manager()) << ")"; } }; - + class x_eq_t : public var_expr_pair { public: x_eq_t(ast_manager & m, unsigned i, expr * t): @@ -1666,7 +1605,7 @@ namespace smt { S_q_i->insert(m_t, 0); } }; - + class x_gle_t : public var_expr_pair { public: x_gle_t(ast_manager & m, unsigned i, expr * t): @@ -1709,16 +1648,16 @@ namespace smt { m_manager.inc_ref(m_cond); SASSERT(!m_hint || m_cond == 0); } - + ~cond_macro() { m_manager.dec_ref(m_def); m_manager.dec_ref(m_cond); } func_decl * get_f() const { return m_f; } - + expr * get_def() const { return m_def; } - + expr * get_cond() const { return m_cond; } bool is_unconditional() const { return m_cond == 0 || m_manager.is_true(m_cond); } @@ -1735,7 +1674,7 @@ namespace smt { out << "[" << m_f->get_name() << " -> " << mk_bounded_pp(m_def, m_manager, 6); if (m_hint) out << " *hint*"; - else + else out << " when " << mk_bounded_pp(m_cond, m_manager, 6); out << "] weight: " << m_weight; } @@ -1750,7 +1689,7 @@ namespace smt { // ----------------------------------- class quantifier_analyzer; - + /** \brief Store relevant information regarding a particular universal quantifier. This information is populated by quantifier_analyzer. @@ -1779,11 +1718,9 @@ namespace smt { void insert_qinfo(qinfo * qi) { // I'm assuming the number of qinfo's per quantifier is small. So, the linear search is not a big deal. scoped_ptr q(qi); - ptr_vector::iterator it = m_qinfo_vect.begin(); - ptr_vector::iterator end = m_qinfo_vect.end(); - for (; it != end; ++it) { + for (qinfo* qi2 : m_qinfo_vect) { checkpoint(); - if (qi->is_equal(*it)) { + if (qi->is_equal(qi2)) { return; } } @@ -1826,7 +1763,7 @@ namespace smt { tout << mk_pp(q, m) << "\n" << mk_pp(m_flat_q, m) << "\n";); SASSERT(!has_quantifiers(m_flat_q->get_expr())); } - + ~quantifier_info() { std::for_each(m_qinfo_vect.begin(), m_qinfo_vect.end(), delete_proc()); std::for_each(m_cond_macros.begin(), m_cond_macros.end(), delete_proc()); @@ -1836,7 +1773,7 @@ namespace smt { bool is_auf() const { return m_is_auf; } quantifier * get_flat_q() const { return m_flat_q; } - + bool unary_function_fragment() const { unsigned sz = m_ng_decls.size(); if (sz > 1) @@ -1877,22 +1814,16 @@ namespace smt { out << "IS_AUF: " << m_is_auf << ", has x=y: " << m_has_x_eq_y << "\n"; out << "unary function fragment: " << unary_function_fragment() << "\n"; out << "ng decls: "; - func_decl_set::iterator it1 = m_ng_decls.begin(); - func_decl_set::iterator end1 = m_ng_decls.end(); - for (; it1 != end1; ++it1) { - out << (*it1)->get_name() << " "; + for (func_decl * f : m_ng_decls) { + out << f->get_name() << " "; } out << "\ninfo bits:\n"; - ptr_vector::const_iterator it2 = m_qinfo_vect.begin(); - ptr_vector::const_iterator end2 = m_qinfo_vect.end(); - for (; it2 != end2; ++it2) { - out << " "; (*it2)->display(out); out << "\n"; + for (qinfo* qi : m_qinfo_vect) { + out << " "; qi->display(out); out << "\n"; } out << "\nmacros:\n"; - ptr_vector::const_iterator it3 = m_cond_macros.begin(); - ptr_vector::const_iterator end3 = m_cond_macros.end(); - for (; it3 != end3; ++it3) { - out << " "; (*it3)->display(out); out << "\n"; + for (cond_macro* cm : m_cond_macros) { + out << " "; cm->display(out); out << "\n"; } } @@ -1901,23 +1832,19 @@ namespace smt { // make sure a node exists for each variable. s.get_uvar(m_flat_q, i); } - ptr_vector::const_iterator it = m_qinfo_vect.begin(); - ptr_vector::const_iterator end = m_qinfo_vect.end(); - for (; it != end; ++it) { - (*it)->process_auf(m_flat_q, s, ctx); + for (qinfo * qi : m_qinfo_vect) { + qi->process_auf(m_flat_q, s, ctx); } } void populate_inst_sets(auf_solver & s, context * ctx) { - ptr_vector::const_iterator it = m_qinfo_vect.begin(); - ptr_vector::const_iterator end = m_qinfo_vect.end(); - for (; it != end; ++it) - (*it)->populate_inst_sets(m_flat_q, s, ctx); + for (qinfo * qi : m_qinfo_vect) { + qi->populate_inst_sets(m_flat_q, s, ctx); + } // second pass - it = m_qinfo_vect.begin(); - for (; it != end; ++it) { + for (qinfo * qi : m_qinfo_vect) { checkpoint(); - (*it)->populate_inst_sets2(m_flat_q, s, ctx); + qi->populate_inst_sets2(m_flat_q, s, ctx); } } @@ -1930,14 +1857,9 @@ namespace smt { if (m_uvar_inst_sets != 0) return; m_uvar_inst_sets = alloc(ptr_vector); - ptr_vector::const_iterator it = m_qinfo_vect.begin(); - ptr_vector::const_iterator end = m_qinfo_vect.end(); - for (; it != end; ++it) - (*it)->populate_inst_sets(m_flat_q, m_the_one, *m_uvar_inst_sets, ctx); - ptr_vector::iterator it2 = m_uvar_inst_sets->begin(); - ptr_vector::iterator end2 = m_uvar_inst_sets->end(); - for (; it2 != end2; ++it2) { - instantiation_set * s = *it2; + for (qinfo* qi : m_qinfo_vect) + qi->populate_inst_sets(m_flat_q, m_the_one, *m_uvar_inst_sets, ctx); + for (instantiation_set * s : *m_uvar_inst_sets) { if (s != 0) s->mk_inverse(ev); } @@ -1959,7 +1881,7 @@ namespace smt { } } }; - + /** \brief Functor used to traverse/analyze a quantifier and fill the structure quantifier_info. @@ -1975,9 +1897,9 @@ namespace smt { quantifier_info * m_info; typedef enum { POS, NEG } polarity; - + polarity neg(polarity p) { return p == POS ? NEG : POS; } - + obj_hashtable m_pos_cache; obj_hashtable m_neg_cache; typedef std::pair entry; @@ -1989,11 +1911,8 @@ namespace smt { m_info->insert_qinfo(qi); } - arith_simplifier_plugin * get_arith_simp() const { return m_mutil.get_arith_simp(); } - bv_simplifier_plugin * get_bv_simp() const { return m_mutil.get_bv_simp(); } - - bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) const { - return get_arith_simp()->is_var_plus_ground(n, inv, v, t) || get_bv_simp()->is_var_plus_ground(n, inv, v, t); + bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) { + return m_mutil.is_var_plus_ground(n, inv, v, t); } bool is_var_plus_ground(expr * n, var * & v, expr_ref & t) { @@ -2009,32 +1928,29 @@ namespace smt { } bool is_zero(expr * n) const { - if (get_bv_simp()->is_bv(n)) - return get_bv_simp()->is_zero_safe(n); - else - return get_arith_simp()->is_zero_safe(n); + return m_mutil.is_zero_safe(n); } bool is_times_minus_one(expr * n, expr * & arg) const { return m_mutil.is_times_minus_one(n, arg); } - bool is_le(expr * n) const { + bool is_le(expr * n) const { return m_mutil.is_le(n); } - + bool is_le_ge(expr * n) const { return m_mutil.is_le_ge(n); } - bool is_signed_le(expr * n) const { - return m_bv_util.is_bv_sle(n); + bool is_signed_le(expr * n) const { + return m_bv_util.is_bv_sle(n); } - - expr * mk_one(sort * s) { - return m_bv_util.is_bv_sort(s) ? m_bv_util.mk_numeral(rational(1), s) : m_arith_util.mk_numeral(rational(1), s); + + expr * mk_one(sort * s) { + return m_bv_util.is_bv_sort(s) ? m_bv_util.mk_numeral(rational(1), s) : m_arith_util.mk_numeral(rational(1), s); } - + void mk_sub(expr * t1, expr * t2, expr_ref & r) const { m_mutil.mk_sub(t1, t2, r); } @@ -2043,7 +1959,7 @@ namespace smt { m_mutil.mk_add(t1, t2, r); } - bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t, bool & inv) const { + bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t, bool & inv) { inv = false; // true if invert the sign TRACE("is_var_and_ground", tout << "is_var_and_ground: " << mk_ismt2_pp(lhs, m_manager) << " " << mk_ismt2_pp(rhs, m_manager) << "\n";); if (is_var(lhs) && is_ground(rhs)) { @@ -2078,12 +1994,12 @@ namespace smt { return false; } - bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t) const { + bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t) { bool inv; return is_var_and_ground(lhs, rhs, v, t, inv); } - bool is_x_eq_t_atom(expr * n, var * & v, expr_ref & t) const { + bool is_x_eq_t_atom(expr * n, var * & v, expr_ref & t) { if (!is_app(n)) return false; if (m_manager.is_eq(n)) @@ -2091,7 +2007,7 @@ namespace smt { return false; } - bool is_var_minus_var(expr * n, var * & v1, var * & v2) const { + bool is_var_minus_var(expr * n, var * & v1, var * & v2) { if (!is_add(n)) return false; expr * arg1 = to_app(n)->get_arg(0); @@ -2110,22 +2026,22 @@ namespace smt { return true; } - bool is_var_and_var(expr * lhs, expr * rhs, var * & v1, var * & v2) const { + bool is_var_and_var(expr * lhs, expr * rhs, var * & v1, var * & v2) { if (is_var(lhs) && is_var(rhs)) { v1 = to_var(lhs); v2 = to_var(rhs); return true; } - return + return (is_var_minus_var(lhs, v1, v2) && is_zero(rhs)) || (is_var_minus_var(rhs, v1, v2) && is_zero(lhs)); } - bool is_x_eq_y_atom(expr * n, var * & v1, var * & v2) const { + bool is_x_eq_y_atom(expr * n, var * & v1, var * & v2) { return m_manager.is_eq(n) && is_var_and_var(to_app(n)->get_arg(0), to_app(n)->get_arg(1), v1, v2); } - bool is_x_gle_y_atom(expr * n, var * & v1, var * & v2) const { + bool is_x_gle_y_atom(expr * n, var * & v1, var * & v2) { return is_le_ge(n) && is_var_and_var(to_app(n)->get_arg(0), to_app(n)->get_arg(1), v1, v2); } @@ -2134,7 +2050,7 @@ namespace smt { return false; if (sign) { bool r = is_le_ge(atom) && is_var_and_ground(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1), v, t); - CTRACE("is_x_gle_t", r, tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m_manager) << "\n--->\n" + CTRACE("is_x_gle_t", r, tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m_manager) << "\n--->\n" << mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n"; tout << "sign: " << sign << "\n";); return r; @@ -2154,7 +2070,7 @@ namespace smt { mk_add(tmp, one, t); else mk_sub(tmp, one, t); - TRACE("is_x_gle_t", tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m_manager) << "\n--->\n" + TRACE("is_x_gle_t", tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m_manager) << "\n--->\n" << mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n"; tout << "sign: " << sign << "\n";); return true; @@ -2168,19 +2084,19 @@ namespace smt { m_pos_cache.reset(); m_neg_cache.reset(); } - - obj_hashtable & get_cache(polarity pol) { - return pol == POS ? m_pos_cache : m_neg_cache; + + obj_hashtable & get_cache(polarity pol) { + return pol == POS ? m_pos_cache : m_neg_cache; } void visit_formula(expr * n, polarity pol) { if (is_ground(n)) return; // ground terms do not need to be visited. obj_hashtable & c = get_cache(pol); - if (!c.contains(n)) { - m_ftodo.push_back(entry(n, pol)); + if (!c.contains(n)) { + m_ftodo.push_back(entry(n, pol)); c.insert(n); - } + } } void visit_term(expr * n) { @@ -2190,7 +2106,7 @@ namespace smt { m_pos_cache.insert(n); } } - + /** \brief Process unintrepreted applications. */ @@ -2203,14 +2119,14 @@ namespace smt { insert_qinfo(alloc(f_var, t->get_decl(), i, to_var(arg)->get_idx())); continue; } - + var * v; expr_ref k(m_manager); if (is_var_plus_ground(arg, v, k)) { insert_qinfo(alloc(f_var_plus_offset, m_manager, t->get_decl(), i, v->get_idx(), k.get())); continue; } - + visit_term(arg); } } @@ -2219,9 +2135,9 @@ namespace smt { /** \brief A term \c t is said to be a auf_select if it is of ther form - + (select a i) Where: - + where a is ground or is_auf_select(a) == true and the indices are ground terms or variables. */ @@ -2231,9 +2147,7 @@ namespace smt { expr * a = to_app(t)->get_arg(0); if (!is_ground(a) && !is_auf_select(a)) return false; - unsigned num_args = to_app(t)->get_num_args(); - for (unsigned i = 1; i < num_args; i++) { - expr * arg = to_app(t)->get_arg(i); + for (expr * arg : *to_app(t)) { if (!is_ground(arg) && !is_var(arg)) return false; } @@ -2259,19 +2173,19 @@ namespace smt { } } else { - unsigned num_args = t->get_num_args(); - for (unsigned i = 0; i < num_args; i++) - visit_term(t->get_arg(i)); + for (expr * arg : *t) { + visit_term(arg); + } } } void process_app(app * t) { SASSERT(!is_ground(t)); - + if (t->get_family_id() != m_manager.get_basic_family_id()) { m_info->m_ng_decls.insert(t->get_decl()); } - + if (is_uninterp(t)) { process_u_app(t); } @@ -2279,19 +2193,19 @@ namespace smt { process_i_app(t); } } - + void process_terms_on_stack() { while (!m_ttodo.empty()) { expr * curr = m_ttodo.back(); m_ttodo.pop_back(); - + if (m_manager.is_bool(curr)) { // formula nested in a term. visit_formula(curr, POS); visit_formula(curr, NEG); continue; } - + if (is_app(curr)) { process_app(to_app(curr)); } @@ -2309,7 +2223,7 @@ namespace smt { CTRACE("model_finder_bug", is_ground(atom), tout << mk_pp(atom, m_manager) << "\n";); SASSERT(!is_ground(atom)); SASSERT(m_manager.is_bool(atom)); - + if (is_var(atom)) { if (sign) { // atom (not X) can be viewed as X != true @@ -2321,7 +2235,7 @@ namespace smt { } return; } - + if (is_app(atom)) { var * v, * v1, * v2; expr_ref t(m_manager); @@ -2353,18 +2267,18 @@ namespace smt { } return; } - + SASSERT(is_quantifier(atom)); UNREACHABLE(); } - void process_literal(expr * atom, polarity pol) { - process_literal(atom, pol == NEG); + void process_literal(expr * atom, polarity pol) { + process_literal(atom, pol == NEG); } - + void process_or(app * n, polarity p) { unsigned num_args = n->get_num_args(); - for (unsigned i = 0; i < num_args; i++) + for (unsigned i = 0; i < num_args; i++) visit_formula(n->get_arg(i), p); } @@ -2385,7 +2299,7 @@ namespace smt { void checkpoint() { m_mf.checkpoint("quantifier_analyzer"); } - + void process_formulas_on_stack() { while (!m_ftodo.empty()) { checkpoint(); @@ -2445,7 +2359,7 @@ namespace smt { SASSERT(m_manager.is_bool(n)); visit_formula(n, POS); } - + void process_clause(expr * cls) { SASSERT(is_clause(m_manager, cls)); unsigned num_lits = get_clause_num_literals(m_manager, cls); @@ -2465,25 +2379,25 @@ namespace smt { m_mutil.collect_macro_candidates(q, candidates); unsigned num_candidates = candidates.size(); for (unsigned i = 0; i < num_candidates; i++) { - cond_macro * m = alloc(cond_macro, m_manager, candidates.get_f(i), candidates.get_def(i), candidates.get_cond(i), + cond_macro * m = alloc(cond_macro, m_manager, candidates.get_f(i), candidates.get_def(i), candidates.get_cond(i), candidates.ineq(i), candidates.satisfy_atom(i), candidates.hint(i), q->get_weight()); m_info->insert_macro(m); } } - - + + public: - quantifier_analyzer(model_finder& mf, ast_manager & m, simplifier & s): + quantifier_analyzer(model_finder& mf, ast_manager & m): m_mf(mf), m_manager(m), - m_mutil(m, s), + m_mutil(m), m_array_util(m), m_arith_util(m), m_bv_util(m), m_info(0) { } - - + + void operator()(quantifier_info * d) { m_info = d; quantifier * q = d->get_flat_q(); @@ -2492,7 +2406,7 @@ namespace smt { reset_cache(); SASSERT(m_ttodo.empty()); SASSERT(m_ftodo.empty()); - + if (is_clause(m_manager, e)) { process_clause(e); } @@ -2506,7 +2420,7 @@ namespace smt { } collect_macro_candidates(q); - + m_info = 0; } @@ -2546,7 +2460,7 @@ namespace smt { m_q2info(q2i), m_model(0) { } - + virtual ~base_macro_solver() {} /** @@ -2564,13 +2478,13 @@ namespace smt { } }; - + /** \brief The simple macro solver satisfies quantifiers that contain (conditional) macros for a function f that does not occur in any other quantifier. - + Since f does not occur in any other quantifier, I don't need to track the dependencies - of f. That is, recursive definition cannot be created. + of f. That is, recursive definition cannot be created. */ class simple_macro_solver : public base_macro_solver { protected: @@ -2578,10 +2492,7 @@ namespace smt { \brief Return true if \c f is in (qs\{q}) */ bool contains(func_decl * f, ptr_vector const & qs, quantifier * q) { - ptr_vector::const_iterator it = qs.begin(); - ptr_vector::const_iterator end = qs.end(); - for (; it != end; ++it) { - quantifier * other = *it; + for (quantifier * other : qs) { if (q == other) continue; quantifier_info * other_qi = get_qinfo(other); @@ -2608,7 +2519,7 @@ namespace smt { // I know the (partial) interpretation of f satisfied the ground part. // MBQI will force extra instantiations if the the (partial) interpretation of f // does not satisfy the quantifier. - // In all other cases the "else" of f will satisfy the quantifier. + // In all other cases the "else" of f will satisfy the quantifier. set_else_interp(f, f_else); TRACE("model_finder", tout << "satisfying the quantifier using simple macro:\n"; m->display(tout); tout << "\n";); @@ -2620,13 +2531,11 @@ namespace smt { virtual bool process(ptr_vector const & qs, ptr_vector & new_qs, ptr_vector & residue) { bool removed = false; - ptr_vector::const_iterator it = qs.begin(); - ptr_vector::const_iterator end = qs.end(); - for (; it != end; ++it) { - if (process(*it, qs)) + for (quantifier* q : qs) { + if (process(q, qs)) removed = true; else - new_qs.push_back(*it); + new_qs.push_back(q); } return removed; } @@ -2646,7 +2555,7 @@ namespace smt { Let Q_{f_i = def_i} be the set of quantifiers where f_i = def_i is a macro. Then, the set Q can be satisfied using f_1 = def_1 ... f_n = d_n when - + Q_{f_1} union ... union Q_{f_n} = Q_{f_1 = def_1} ... Q_{f_n = d_n} (*) So, given a set of macros f_1 = def_1, ..., f_n = d_n, it is very easy to check @@ -2682,8 +2591,8 @@ namespace smt { typedef obj_pair_map q_f_def; typedef obj_pair_hashtable f_def_set; typedef obj_hashtable expr_set; - typedef obj_map f2defs; - + typedef obj_map f2defs; + q_f m_q_f; q_f_def m_q_f_def; ptr_vector m_qsets; @@ -2775,20 +2684,15 @@ namespace smt { void register_decls_as_forbidden(quantifier * q) { quantifier_info * qi = get_qinfo(q); func_decl_set const & ng_decls = qi->get_ng_decls(); - func_decl_set::iterator it = ng_decls.begin(); - func_decl_set::iterator end = ng_decls.end(); - for (; it != end; ++it) { - m_forbidden.insert(*it); + for (func_decl* f : ng_decls) { + m_forbidden.insert(f); } } void preprocess(ptr_vector const & qs, ptr_vector & qcandidates, ptr_vector & non_qcandidates) { ptr_vector curr(qs); while (true) { - ptr_vector::iterator it = curr.begin(); - ptr_vector::iterator end = curr.end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier * q : curr) { if (is_candidate(q)) { qcandidates.push_back(q); } @@ -2806,16 +2710,10 @@ namespace smt { } void mk_q_f_defs(ptr_vector const & qs) { - ptr_vector::const_iterator it = qs.begin(); - ptr_vector::const_iterator end = qs.end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier * q : qs) { quantifier_info * qi = get_qinfo(q); func_decl_set const & ng_decls = qi->get_ng_decls(); - func_decl_set::iterator it2 = ng_decls.begin(); - func_decl_set::iterator end2 = ng_decls.end(); - for (; it2 != end2; ++it2) { - func_decl * f = *it2; + for (func_decl* f : ng_decls) { if (!m_forbidden.contains(f)) insert_q_f(q, f); } @@ -2830,53 +2728,43 @@ namespace smt { } } } - + static void display_quantifier_set(std::ostream & out, quantifier_set const * s) { - quantifier_set::iterator it = s->begin(); - quantifier_set::iterator end = s->end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier* q : *s) { out << q->get_qid() << " "; } out << "\n"; } - + void display_qcandidates(std::ostream & out, ptr_vector const & qcandidates) const { - ptr_vector::const_iterator it1 = qcandidates.begin(); - ptr_vector::const_iterator end1 = qcandidates.end(); - for (; it1 != end1; ++it1) { - quantifier * q = *it1; + for (quantifier * q : qcandidates) { out << q->get_qid() << " ->\n" << mk_pp(q, m_manager) << "\n"; quantifier_info * qi = get_qinfo(q); qi->display(out); out << "------\n"; } out << "Sets Q_f\n"; - q_f::iterator it2 = m_q_f.begin(); - q_f::iterator end2 = m_q_f.end(); - for (; it2 != end2; ++it2) { - func_decl * f = (*it2).m_key; - quantifier_set * s = (*it2).m_value; + for (auto const& kv : m_q_f) { + func_decl * f = kv.m_key; + quantifier_set * s = kv.m_value; out << f->get_name() << " -> "; display_quantifier_set(out, s); } out << "Sets Q_{f = def}\n"; - q_f_def::iterator it3 = m_q_f_def.begin(); - q_f_def::iterator end3 = m_q_f_def.end(); - for (; it3 != end3; ++it3) { - func_decl * f = (*it3).get_key1(); - expr * def = (*it3).get_key2(); - quantifier_set * s = (*it3).get_value(); + for (auto const& kv : m_q_f_def) { + func_decl * f = kv.get_key1(); + expr * def = kv.get_key2(); + quantifier_set * s = kv.get_value(); out << f->get_name() << " " << mk_pp(def, m_manager) << " ->\n"; display_quantifier_set(out, s); } } - + // // Search: main procedures // struct ev_handler { hint_solver * m_owner; - + void operator()(quantifier * q, bool ins) { quantifier_info * qi = m_owner->get_qinfo(q); qi->set_the_one(0); @@ -2889,7 +2777,7 @@ namespace smt { typedef backtrackable_set qset; - typedef backtrackable_set qsset; + typedef backtrackable_set qsset; typedef obj_map f2def; qset m_residue; @@ -2900,32 +2788,23 @@ namespace smt { void display_search_state(std::ostream & out) const { out << "fs:\n"; - f2def::iterator it3 = m_fs.begin(); - f2def::iterator end3 = m_fs.end(); - for (; it3 != end3; ++it3) { - out << (*it3).m_key->get_name() << " "; + for (auto const& kv : m_fs) { + out << kv.m_key->get_name() << " "; } out << "\nsatisfied:\n"; - qsset::iterator it = m_satisfied.begin(); - qsset::iterator end = m_satisfied.end(); - for (; it != end; ++it) { - out << (*it)->get_qid() << " "; + for (auto q : m_satisfied) { + out << q->get_qid() << " "; } out << "\nresidue:\n"; - qset::iterator it2 = m_residue.begin(); - qset::iterator end2 = m_residue.end(); - for (; it2 != end2; ++it2) { - out << (*it2)->get_qid() << " "; + for (auto q : m_residue) { + out << q->get_qid() << " "; } out << "\n"; } - + bool check_satisfied_residue_invariant() { DEBUG_CODE( - qsset::iterator it = m_satisfied.begin(); - qsset::iterator end = m_satisfied.end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier * q : m_satisfied) { SASSERT(!m_residue.contains(q)); quantifier_info * qi = get_qinfo(q); SASSERT(qi != 0); @@ -2934,16 +2813,13 @@ namespace smt { return true; } - + bool update_satisfied_residue(func_decl * f, expr * def) { bool useful = false; SASSERT(check_satisfied_residue_invariant()); quantifier_set * q_f = get_q_f(f); quantifier_set * q_f_def = get_q_f_def(f, def); - quantifier_set::iterator it = q_f_def->begin(); - quantifier_set::iterator end = q_f_def->end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier * q : *q_f_def) { if (!m_satisfied.contains(q)) { useful = true; m_residue.erase(q); @@ -2955,10 +2831,7 @@ namespace smt { } if (!useful) return false; - it = q_f->begin(); - end = q_f->end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier * q : *q_f) { if (!m_satisfied.contains(q)) { m_residue.insert(q); } @@ -2966,16 +2839,13 @@ namespace smt { SASSERT(check_satisfied_residue_invariant()); return true; } - + /** \brief Extract from m_residue, func_decls that can be used as macros to satisfy it. The candidates must not be elements of m_fs. */ void get_candidates_from_residue(func_decl_set & candidates) { - qset::iterator it = m_residue.begin(); - qset::iterator end = m_residue.end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier * q : m_residue) { quantifier_info * qi = get_qinfo(q); quantifier_info::macro_iterator it2 = qi->begin_macros(); @@ -2999,16 +2869,13 @@ namespace smt { if (depth >= GREEDY_MAX_DEPTH) return; // failed - TRACE("model_finder_hint", + TRACE("model_finder_hint", tout << "greedy depth: " << depth << ", f: " << f->get_name() << "\n"; display_search_state(tout);); expr_set * s = get_f_defs(f); - expr_set::iterator it = s->begin(); - expr_set::iterator end = s->end(); - for (; it != end; ++it) { - expr * def = *it; - + for (expr * def : *s) { + SASSERT(!m_fs.contains(f)); m_satisfied.push_scope(); @@ -3020,7 +2887,7 @@ namespace smt { greedy(depth + 1); // greedy throws exception in case of success // reachable iff greedy failed. } - + m_satisfied.pop_scope(); m_residue.pop_scope(); m_fs.erase(f); @@ -3033,7 +2900,7 @@ namespace smt { */ void greedy(unsigned depth) { if (m_residue.empty()) { - TRACE("model_finder_hint", + TRACE("model_finder_hint", tout << "found subset that is satisfied by macros\n"; display_search_state(tout);); throw found_satisfied_subset(); @@ -3042,17 +2909,13 @@ namespace smt { get_candidates_from_residue(candidates); TRACE("model_finder_hint", tout << "candidates from residue:\n"; - func_decl_set::iterator it = candidates.begin(); - func_decl_set::iterator end = candidates.end(); - for (; it != end; ++it) { - tout << (*it)->get_name() << " "; + for (func_decl * f : candidates) { + tout << f->get_name() << " "; } tout << "\n";); - func_decl_set::iterator it = candidates.begin(); - func_decl_set::iterator end = candidates.end(); - for (; it != end; ++it) { - greedy(*it, depth); + for (func_decl* f : candidates) { + greedy(f, depth); } } @@ -3072,10 +2935,7 @@ namespace smt { \brief Copy the quantifiers from qcandidates to new_qs that are not in m_satisfied. */ void copy_non_satisfied(ptr_vector const & qcandidates, ptr_vector & new_qs) { - ptr_vector::const_iterator it = qcandidates.begin(); - ptr_vector::const_iterator end = qcandidates.end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier * q : qcandidates) { if (!m_satisfied.contains(q)) new_qs.push_back(q); } @@ -3086,11 +2946,9 @@ namespace smt { quantifiers in m_satisfied. */ void set_interp() { - f2def::iterator it = m_fs.begin(); - f2def::iterator end = m_fs.end(); - for (; it != end; ++it) { - func_decl * f = (*it).m_key; - expr * def = (*it).m_value; + for (auto const& kv : m_fs) { + func_decl * f = kv.m_key; + expr * def = kv.m_value; set_else_interp(f, def); } } @@ -3114,10 +2972,7 @@ namespace smt { } mk_q_f_defs(qcandidates); TRACE("model_finder_hint", tout << "starting hint-solver search using:\n"; display_qcandidates(tout, qcandidates);); - func_decl_set::iterator it = m_candidates.begin(); - func_decl_set::iterator end = m_candidates.end(); - for (; it != end; ++it) { - func_decl * f = *it; + for (func_decl * f : m_candidates) { try { process(f); } @@ -3179,7 +3034,7 @@ namespace smt { return true; return false; } - + cond_macro * get_macro_for(func_decl * f, quantifier * q) { cond_macro * r = 0; quantifier_info * qi = get_qinfo(q); @@ -3196,10 +3051,7 @@ namespace smt { typedef std::pair mq_pair; void collect_candidates(ptr_vector const & qs, obj_map & full_macros, func_decl_set & cond_macros) { - ptr_vector::const_iterator it = qs.begin(); - ptr_vector::const_iterator end = qs.end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier * q : qs) { quantifier_info * qi = get_qinfo(q); quantifier_info::macro_iterator it2 = qi->begin_macros(); quantifier_info::macro_iterator end2 = qi->end_macros(); @@ -3222,12 +3074,10 @@ namespace smt { } void process_full_macros(obj_map const & full_macros, obj_hashtable & removed) { - obj_map::iterator it = full_macros.begin(); - obj_map::iterator end = full_macros.end(); - for (; it != end; ++it) { - func_decl * f = (*it).m_key; - cond_macro * m = (*it).m_value.first; - quantifier * q = (*it).m_value.second; + for (auto const& kv : full_macros) { + func_decl * f = kv.m_key; + cond_macro * m = kv.m_value.first; + quantifier * q = kv.m_value.second; SASSERT(m->is_unconditional()); if (add_macro(f, m->get_def())) { get_qinfo(q)->set_the_one(f); @@ -3239,10 +3089,7 @@ namespace smt { void process(func_decl * f, ptr_vector const & qs, obj_hashtable & removed) { expr_ref fi_else(m_manager); ptr_buffer to_remove; - ptr_vector::const_iterator it = qs.begin(); - ptr_vector::const_iterator end = qs.end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier * q : qs) { if (removed.contains(q)) continue; cond_macro * m = get_macro_for(f, q); @@ -3260,20 +3107,16 @@ namespace smt { } } if (fi_else.get() != 0 && add_macro(f, fi_else)) { - ptr_buffer::iterator it2 = to_remove.begin(); - ptr_buffer::iterator end2 = to_remove.end(); - for (; it2 != end2; ++it2) { - get_qinfo(*it2)->set_the_one(f); - removed.insert(*it2); + for (quantifier * q : to_remove) { + get_qinfo(q)->set_the_one(f); + removed.insert(q); } } } void process_cond_macros(func_decl_set const & cond_macros, ptr_vector const & qs, obj_hashtable & removed) { - func_decl_set::iterator it = cond_macros.begin(); - func_decl_set::iterator end = cond_macros.end(); - for (; it != end; ++it) { - process(*it, qs, removed); + for (func_decl * f : cond_macros) { + process(f, qs, removed); } } @@ -3288,10 +3131,7 @@ namespace smt { process_full_macros(full_macros, removed); process_cond_macros(cond_macros, qs, removed); - ptr_vector::const_iterator it = qs.begin(); - ptr_vector::const_iterator end = qs.end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier * q : qs) { if (removed.contains(q)) continue; new_qs.push_back(q); @@ -3313,29 +3153,29 @@ namespace smt { } }; }; - + // ----------------------------------- // - // model finder + // model finder // // ----------------------------------- - model_finder::model_finder(ast_manager & m, simplifier & s): + model_finder::model_finder(ast_manager & m): m_manager(m), m_context(0), - m_analyzer(alloc(quantifier_analyzer, *this, m, s)), - m_auf_solver(alloc(auf_solver, m, s)), + m_analyzer(alloc(quantifier_analyzer, *this, m)), + m_auf_solver(alloc(auf_solver, m)), m_dependencies(m), m_sm_solver(alloc(simple_macro_solver, m, m_q2info)), m_hint_solver(alloc(hint_solver, m, m_q2info)), m_nm_solver(alloc(non_auf_macro_solver, m, m_q2info, m_dependencies)), m_new_constraints(m) { } - + model_finder::~model_finder() { reset(); } - + void model_finder::checkpoint() { checkpoint("model_finder"); } @@ -3352,14 +3192,14 @@ namespace smt { SASSERT(info != 0); return info; } - + void model_finder::set_context(context * ctx) { - SASSERT(m_context == 0); + SASSERT(m_context == 0); m_context = ctx; m_auf_solver->set_context(ctx); m_nm_solver->set_params(ctx->get_fparams()); } - + void model_finder::register_quantifier(quantifier * q) { TRACE("model_finder", tout << "registering:\n" << mk_pp(q, m_manager) << "\n";); quantifier_info * new_info = alloc(quantifier_info, *this, m_manager, q); @@ -3368,15 +3208,15 @@ namespace smt { m_analyzer->operator()(new_info); TRACE("model_finder", tout << "after analyzer:\n"; new_info->display(tout);); } - + void model_finder::push_scope() { m_scopes.push_back(scope()); scope & s = m_scopes.back(); s.m_quantifiers_lim = m_quantifiers.size(); } - + void model_finder::restore_quantifiers(unsigned old_size) { - unsigned curr_size = m_quantifiers.size(); + unsigned curr_size = m_quantifiers.size(); SASSERT(old_size <= curr_size); for (unsigned i = old_size; i < curr_size; i++) { quantifier * q = m_quantifiers[i]; @@ -3387,7 +3227,7 @@ namespace smt { } m_quantifiers.shrink(old_size); } - + void model_finder::pop_scope(unsigned num_scopes) { unsigned lvl = m_scopes.size(); SASSERT(num_scopes <= lvl); @@ -3396,7 +3236,7 @@ namespace smt { restore_quantifiers(s.m_quantifiers_lim); m_scopes.shrink(new_lvl); } - + void model_finder::reset() { m_scopes.reset(); m_dependencies.reset(); @@ -3404,16 +3244,13 @@ namespace smt { SASSERT(m_q2info.empty()); SASSERT(m_quantifiers.empty()); } - + void model_finder::init_search_eh() { // do nothing in the current version } void model_finder::collect_relevant_quantifiers(ptr_vector & qs) const { - ptr_vector::const_iterator it = m_quantifiers.begin(); - ptr_vector::const_iterator end = m_quantifiers.end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier * q : m_quantifiers) { if (m_context->is_relevant(q) && m_context->get_assignment(q) == l_true) qs.push_back(q); } @@ -3423,26 +3260,19 @@ namespace smt { m_auf_solver->reset(); m_auf_solver->set_model(m); - ptr_vector::const_iterator it = qs.begin(); - ptr_vector::const_iterator end = qs.end(); - for (; it != end; ++it) { - quantifier * q = *it; + for (quantifier * q : qs) { quantifier_info * qi = get_quantifier_info(q); qi->process_auf(*(m_auf_solver.get()), m_context); } m_auf_solver->mk_instantiation_sets(); - it = qs.begin(); - for (; it != end; ++it) { - quantifier * q = *it; + + for (quantifier * q : qs) { quantifier_info * qi = get_quantifier_info(q); qi->populate_inst_sets(*(m_auf_solver.get()), m_context); } m_auf_solver->fix_model(m_new_constraints); - TRACE("model_finder", - ptr_vector::const_iterator it = qs.begin(); - ptr_vector::const_iterator end = qs.end(); - for (; it != end; ++it) { - quantifier * q = *it; + TRACE("model_finder", + for (quantifier * q : qs) { quantifier_info * qi = get_quantifier_info(q); quantifier * fq = qi->get_flat_q(); tout << "#" << fq->get_id() << " ->\n" << mk_pp(fq, m_manager) << "\n"; @@ -3463,7 +3293,7 @@ namespace smt { qs.swap(new_qs); TRACE("model_finder", tout << "model after processing simple macros:\n"; model_pp(tout, *m);); } - + void model_finder::process_non_auf_macros(ptr_vector & qs, ptr_vector & residue, proto_model * m) { ptr_vector new_qs; m_nm_solver->operator()(m, qs, new_qs, residue); @@ -3525,12 +3355,12 @@ namespace smt { << "\ni: " << i << " " << flat_q->get_num_decls() - q->get_num_decls() + i << "\n";); if (r != 0) return r; - // quantifier was not processed by AUF solver... + // quantifier was not processed by AUF solver... // it must have been satisfied by "macro"/"hint". quantifier_info * qinfo = get_quantifier_info(q); SASSERT(qinfo); SASSERT(qinfo->get_the_one() != 0); - + return qinfo->get_macro_based_inst_set(i, m_context, *(m_auf_solver.get())); } @@ -3551,11 +3381,11 @@ namespace smt { } return t; } - + /** \brief Assert constraints restricting the possible values of the skolem constants can be assigned to. The idea is to restrict them to the values in the instantiation sets. - + \remark q is the quantifier before flattening. Return true if something was asserted. @@ -3603,7 +3433,7 @@ namespace smt { TRACE("model_finder_bug_detail", tout << "asserting new constraint: " << mk_pp(c, m_manager) << "\n";); m_context->internalize(c, true); literal l(m_context->get_literal(c)); - m_context->mark_as_relevant(l); + m_context->mark_as_relevant(l); // asserting it as an AXIOM m_context->assign(l, b_justification()); } diff --git a/src/smt/smt_model_finder.h b/src/smt/smt_model_finder.h index 0694b008b..2b79ab265 100644 --- a/src/smt/smt_model_finder.h +++ b/src/smt/smt_model_finder.h @@ -46,12 +46,11 @@ Revision History: #ifndef SMT_MODEL_FINDER_H_ #define SMT_MODEL_FINDER_H_ -#include"ast.h" -#include"func_decl_dependencies.h" -#include"simplifier.h" -#include"proto_model.h" -#include"cooperate.h" -#include"tactic_exception.h" +#include "ast/ast.h" +#include "ast/func_decl_dependencies.h" +#include "smt/proto_model/proto_model.h" +#include "util/cooperate.h" +#include "tactic/tactic_exception.h" namespace smt { class context; @@ -107,7 +106,7 @@ namespace smt { public: - model_finder(ast_manager & m, simplifier & s); + model_finder(ast_manager & m); ~model_finder(); void set_context(context * ctx); diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index b9c1ac453..df6865f1e 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -17,14 +17,13 @@ Revision History: --*/ -#include"smt_context.h" -#include"smt_model_generator.h" -#include"proto_model.h" -#include"ref_util.h" -#include"for_each_expr.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" -#include"ast_smt2_pp.h" +#include "util/ref_util.h" +#include "ast/for_each_expr.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt2_pp.h" +#include "smt/smt_context.h" +#include "smt/smt_model_generator.h" +#include "smt/proto_model/proto_model.h" namespace smt { @@ -55,7 +54,7 @@ namespace smt { ptr_vector::const_iterator it = m_context->begin_theories(); ptr_vector::const_iterator end = m_context->end_theories(); for (; it != end; ++it) { - TRACE("model_generator_bug", tout << "init_model for theory: " << (*it)->get_name() << "\n";); + TRACE("model", tout << "init_model for theory: " << (*it)->get_name() << "\n";); (*it)->init_model(*this); } } @@ -92,7 +91,7 @@ namespace smt { sort * s = m_manager.get_sort(r->get_owner()); model_value_proc * proc = 0; if (m_manager.is_bool(s)) { - CTRACE("func_interp_bug", m_context->get_assignment(r) == l_undef, + CTRACE("model", m_context->get_assignment(r) == l_undef, tout << mk_pp(r->get_owner(), m_manager) << "\n";); SASSERT(m_context->get_assignment(r) != l_undef); if (m_context->get_assignment(r) == l_true) @@ -109,7 +108,7 @@ namespace smt { SASSERT(proc); } else { - TRACE("model_bug", tout << "creating fresh value for #" << r->get_owner_id() << "\n";); + TRACE("model", tout << "creating fresh value for #" << r->get_owner_id() << "\n";); proc = alloc(fresh_value_proc, mk_extra_fresh_value(m_manager.get_sort(r->get_owner()))); } } @@ -131,7 +130,7 @@ namespace smt { if (!m_manager.is_model_value(n)) { sort * s = m_manager.get_sort(r->get_owner()); n = m_model->get_fresh_value(s); - CTRACE("model_generator_bug", n == 0, + CTRACE("model", n == 0, tout << mk_pp(r->get_owner(), m_manager) << "\nsort:\n" << mk_pp(s, m_manager) << "\n"; tout << "is_finite: " << m_model->is_finite(s) << "\n";); } @@ -407,9 +406,11 @@ namespace smt { */ bool model_generator::include_func_interp(func_decl * f) const { family_id fid = f->get_family_id(); + TRACE("model", tout << f->get_name() << " " << fid << "\n";); if (fid == null_family_id) return !m_hidden_ufs.contains(f); if (fid == m_manager.get_basic_family_id()) return false; theory * th = m_context->get_theory(fid); + TRACE("model", tout << th << "\n";); if (!th) return true; return th->include_func_interp(f); } @@ -444,7 +445,7 @@ namespace smt { SASSERT(m_model->has_interpretation(f)); SASSERT(m_model->get_func_interp(f) == fi); // The entry must be new because n->get_cg() == n - TRACE("func_interp_bug", + TRACE("model", tout << "insert new entry for:\n" << mk_ismt2_pp(n->get_owner(), m_manager) << "\nargs: "; for (unsigned i = 0; i < num_args; i++) { tout << "#" << n->get_arg(i)->get_owner_id() << " "; @@ -508,20 +509,20 @@ namespace smt { void model_generator::register_macros() { unsigned num = m_context->get_num_macros(); - TRACE("register_macros", tout << "num. macros: " << num << "\n";); + TRACE("model", tout << "num. macros: " << num << "\n";); expr_ref v(m_manager); for (unsigned i = 0; i < num; i++) { func_decl * f = m_context->get_macro_interpretation(i, v); func_interp * fi = alloc(func_interp, m_manager, f->get_arity()); fi->set_else(v); - TRACE("register_macros", tout << f->get_name() << "\n" << mk_pp(v, m_manager) << "\n";); + TRACE("model", tout << f->get_name() << "\n" << mk_pp(v, m_manager) << "\n";); m_model->register_decl(f, fi); } } proto_model * model_generator::mk_model() { SASSERT(!m_model); - TRACE("func_interp_bug", m_context->display(tout);); + TRACE("model", m_context->display(tout);); init_model(); register_existing_model_values(); mk_bool_model(); diff --git a/src/smt/smt_model_generator.h b/src/smt/smt_model_generator.h index f360dbd7e..ee133482d 100644 --- a/src/smt/smt_model_generator.h +++ b/src/smt/smt_model_generator.h @@ -28,10 +28,10 @@ Revision History: #ifndef SMT_MODEL_GENERATOR_H_ #define SMT_MODEL_GENERATOR_H_ -#include"ast.h" -#include"smt_types.h" -#include"obj_hashtable.h" -#include"map.h" +#include "ast/ast.h" +#include "smt/smt_types.h" +#include "util/obj_hashtable.h" +#include "util/map.h" class value_factory; class proto_model; diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 1c8f94edf..1d58e2bb3 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -16,15 +16,16 @@ Author: Revision History: --*/ -#include"smt_quantifier.h" -#include"smt_context.h" -#include"smt_quantifier_stat.h" -#include"smt_model_finder.h" -#include"smt_model_checker.h" -#include"smt_quick_checker.h" -#include"mam.h" -#include"qi_queue.h" -#include"ast_smt2_pp.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt2_pp.h" +#include "smt/smt_quantifier.h" +#include "smt/smt_context.h" +#include "smt/smt_quantifier_stat.h" +#include "smt/smt_model_finder.h" +#include "smt/smt_model_checker.h" +#include "smt/smt_quick_checker.h" +#include "smt/mam.h" +#include "smt/qi_queue.h" namespace smt { @@ -207,10 +208,8 @@ namespace smt { IF_VERBOSE(10, verbose_stream() << "quick checking quantifiers (unsat)...\n";); quick_checker mc(m_context); bool result = true; - ptr_vector::const_iterator it = m_quantifiers.begin(); - ptr_vector::const_iterator end = m_quantifiers.end(); - for (; it != end; ++it) - if (check_quantifier(*it) && mc.instantiate_unsat(*it)) + for (quantifier* q : m_quantifiers) + if (check_quantifier(q) && mc.instantiate_unsat(q)) result = false; if (m_params.m_qi_quick_checker == MC_UNSAT || !result) { m_qi_queue.instantiate(); @@ -219,9 +218,8 @@ namespace smt { // MC_NO_SAT is too expensive (it creates too many irrelevant instances). // we should use MBQI=true instead. IF_VERBOSE(10, verbose_stream() << "quick checking quantifiers (not sat)...\n";); - it = m_quantifiers.begin(); - for (; it != end; ++it) - if (check_quantifier(*it) && mc.instantiate_not_sat(*it)) + for (quantifier* q : m_quantifiers) + if (check_quantifier(q) && mc.instantiate_not_sat(q)) result = false; m_qi_queue.instantiate(); return result; @@ -434,7 +432,7 @@ namespace smt { m_mam = mk_mam(*m_context); m_lazy_mam = mk_mam(*m_context); - m_model_finder = alloc(model_finder, m, m_context->get_simplifier()); + m_model_finder = alloc(model_finder, m); m_model_checker = alloc(model_checker, m, *m_fparams, *(m_model_finder.get())); m_model_finder->set_context(m_context); @@ -492,10 +490,11 @@ namespace smt { virtual void assign_eh(quantifier * q) { m_active = true; + ast_manager& m = m_context->get_manager(); if (!m_fparams->m_ematching) { return; } - if (false && m_context->get_manager().is_rec_fun_def(q) && mbqi_enabled(q)) { + if (false && m.is_rec_fun_def(q) && mbqi_enabled(q)) { return; } bool has_unary_pattern = false; @@ -512,16 +511,20 @@ namespace smt { num_eager_multi_patterns++; for (unsigned i = 0, j = 0; i < num_patterns; i++) { app * mp = to_app(q->get_pattern(i)); - SASSERT(m_context->get_manager().is_pattern(mp)); + SASSERT(m.is_pattern(mp)); bool unary = (mp->get_num_args() == 1); - if (!unary && j >= num_eager_multi_patterns) { - TRACE("quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n" + if (m.is_rec_fun_def(q) && i > 0) { + // add only the first pattern + TRACE("quantifier", tout << "skip recursive function body " << mk_ismt2_pp(mp, m) << "\n";); + } + else if (!unary && j >= num_eager_multi_patterns) { + TRACE("quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m) << "\n" << "j: " << j << " unary: " << unary << " m_params.m_qi_max_eager_multipatterns: " << m_fparams->m_qi_max_eager_multipatterns << " num_eager_multi_patterns: " << num_eager_multi_patterns << "\n";); m_lazy_mam->add_pattern(q, mp); } else { - TRACE("quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n";); + TRACE("quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m) << "\n";); m_mam->add_pattern(q, mp); } if (!unary) diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index 96af9909a..d89f3f6a4 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -19,10 +19,10 @@ Revision History: #ifndef SMT_QUANTIFIER_H_ #define SMT_QUANTIFIER_H_ -#include"ast.h" -#include"statistics.h" -#include"params.h" -#include"smt_types.h" +#include "ast/ast.h" +#include "util/statistics.h" +#include "util/params.h" +#include "smt/smt_types.h" class proto_model; struct smt_params; @@ -149,7 +149,7 @@ namespace smt { /** \brief Is "model based" instantiate allowed to instantiate this quantifier? */ - virtual bool mbqi_enabled(quantifier *q) const {return true;} + virtual bool mbqi_enabled(quantifier *q) const {return true;} /** \brief Give a change to the plugin to adjust the interpretation of unintepreted functions. diff --git a/src/smt/smt_quantifier_stat.cpp b/src/smt/smt_quantifier_stat.cpp index d34a7c0ac..7d73ea27c 100644 --- a/src/smt/smt_quantifier_stat.cpp +++ b/src/smt/smt_quantifier_stat.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"smt_quantifier_stat.h" +#include "smt/smt_quantifier_stat.h" namespace smt { diff --git a/src/smt/smt_quantifier_stat.h b/src/smt/smt_quantifier_stat.h index 1d5919433..308534833 100644 --- a/src/smt/smt_quantifier_stat.h +++ b/src/smt/smt_quantifier_stat.h @@ -19,10 +19,10 @@ Revision History: #ifndef SMT_QUANTIFIER_STAT_H_ #define SMT_QUANTIFIER_STAT_H_ -#include"ast.h" -#include"obj_hashtable.h" -#include"approx_nat.h" -#include"region.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "util/approx_nat.h" +#include "util/region.h" namespace smt { diff --git a/src/smt/smt_quick_checker.cpp b/src/smt/smt_quick_checker.cpp index 462f784bd..72c28fd7d 100644 --- a/src/smt/smt_quick_checker.cpp +++ b/src/smt/smt_quick_checker.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"smt_quick_checker.h" -#include"ast_pp.h" +#include "smt/smt_context.h" +#include "smt/smt_quick_checker.h" +#include "ast/ast_pp.h" namespace smt { @@ -164,7 +164,6 @@ namespace smt { quick_checker::quick_checker(context & c): m_context(c), m_manager(c.get_manager()), - m_simplifier(c.get_simplifier()), m_collector(c), m_new_exprs(m_manager) { } @@ -411,7 +410,7 @@ namespace smt { } } expr_ref new_expr(m_manager); - m_simplifier.mk_app(to_app(n)->get_decl(), num_args, new_args.c_ptr(), new_expr); + new_expr = m_context.get_rewriter().mk_app(to_app(n)->get_decl(), num_args, new_args.c_ptr()); m_new_exprs.push_back(new_expr); m_canonize_cache.insert(n, new_expr); return new_expr; diff --git a/src/smt/smt_quick_checker.h b/src/smt/smt_quick_checker.h index 0963874a0..21a570c3c 100644 --- a/src/smt/smt_quick_checker.h +++ b/src/smt/smt_quick_checker.h @@ -19,9 +19,9 @@ Revision History: #ifndef SMT_QUICK_CHECKER_H_ #define SMT_QUICK_CHECKER_H_ -#include"ast.h" -#include"simplifier.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "ast/rewriter/th_rewriter.h" +#include "util/obj_hashtable.h" namespace smt { class context; @@ -77,7 +77,6 @@ namespace smt { context & m_context; ast_manager & m_manager; - simplifier & m_simplifier; collector m_collector; expr_ref_vector m_new_exprs; vector m_candidate_vectors; diff --git a/src/smt/smt_relevancy.cpp b/src/smt/smt_relevancy.cpp index 176314ae1..00457c643 100644 --- a/src/smt/smt_relevancy.cpp +++ b/src/smt/smt_relevancy.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"smt_relevancy.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"ast_smt2_pp.h" +#include "smt/smt_context.h" +#include "smt/smt_relevancy.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt2_pp.h" namespace smt { diff --git a/src/smt/smt_relevancy.h b/src/smt/smt_relevancy.h index e81989044..75019b110 100644 --- a/src/smt/smt_relevancy.h +++ b/src/smt/smt_relevancy.h @@ -19,7 +19,7 @@ Revision History: #ifndef SMT_RELEVANCY_H_ #define SMT_RELEVANCY_H_ -#include"ast.h" +#include "ast/ast.h" namespace smt { class context; diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 4dd1e2510..631805b4d 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -16,25 +16,25 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"smt_setup.h" -#include"static_features.h" -#include"theory_arith.h" -#include"theory_lra.h" -#include"theory_dense_diff_logic.h" -#include"theory_diff_logic.h" -#include"theory_utvpi.h" -#include"theory_array.h" -#include"theory_array_full.h" -#include"theory_bv.h" -#include"theory_datatype.h" -#include"theory_dummy.h" -#include"theory_dl.h" -#include"theory_seq_empty.h" -#include"theory_seq.h" -#include"theory_pb.h" -#include"theory_fpa.h" -#include"theory_str.h" +#include "smt/smt_context.h" +#include "smt/smt_setup.h" +#include "ast/static_features.h" +#include "smt/theory_arith.h" +#include "smt/theory_lra.h" +#include "smt/theory_dense_diff_logic.h" +#include "smt/theory_diff_logic.h" +#include "smt/theory_utvpi.h" +#include "smt/theory_array.h" +#include "smt/theory_array_full.h" +#include "smt/theory_bv.h" +#include "smt/theory_datatype.h" +#include "smt/theory_dummy.h" +#include "smt/theory_dl.h" +#include "smt/theory_seq_empty.h" +#include "smt/theory_seq.h" +#include "smt/theory_pb.h" +#include "smt/theory_fpa.h" +#include "smt/theory_str.h" namespace smt { @@ -53,7 +53,8 @@ namespace smt { // warning_msg("ignoring MODEL_COMPACT=true because it cannot be used with MBQI=true"); // m_params.m_model_compact = false; // } - TRACE("setup", tout << "configuring logical context, logic: " << m_logic << "\n";); + TRACE("setup", tout << "configuring logical context, logic: " << m_logic << " " << cm << "\n";); + m_already_configured = true; switch (cm) { @@ -124,6 +125,8 @@ namespace smt { setup_QF_FPBV(); else if (m_logic == "QF_S") setup_QF_S(); + else if (m_logic == "QF_DT") + setup_QF_DT(); else setup_unknown(); } @@ -141,7 +144,9 @@ namespace smt { } else { IF_VERBOSE(100, verbose_stream() << "(smt.collecting-features)\n";); - st.collect(m_context.get_num_asserted_formulas(), m_context.get_asserted_formulas()); + ptr_vector fmls; + m_context.get_asserted_formulas(fmls); + st.collect(fmls.size(), fmls.c_ptr()); IF_VERBOSE(1000, st.display_primitive(verbose_stream());); if (m_logic == "QF_UF") setup_QF_UF(st); @@ -187,6 +192,8 @@ namespace smt { setup_AUFLIRA(); else if (m_logic == "UFNIA") setup_UFNIA(); + else if (m_logic == "QF_DT") + setup_QF_DT(); else if (m_logic == "LRA") setup_LRA(); else @@ -202,6 +209,14 @@ namespace smt { void setup::setup_QF_UF() { m_params.m_relevancy_lvl = 0; m_params.m_nnf_cnf = false; + m_params.m_restart_strategy = RS_LUBY; + m_params.m_phase_selection = PS_CACHING_CONSERVATIVE2; + m_params.m_random_initial_activity = IA_RANDOM; + } + + void setup::setup_QF_DT() { + setup_QF_UF(); + setup_datatypes(); } void setup::setup_QF_BVRE() { @@ -210,13 +225,9 @@ namespace smt { m_context.register_plugin(alloc(theory_seq, m_manager)); } - void setup::setup_QF_UF(static_features const & st) { + void setup::setup_QF_UF(static_features const & st) { check_no_arithmetic(st, "QF_UF"); - m_params.m_relevancy_lvl = 0; - m_params.m_nnf_cnf = false; - m_params.m_restart_strategy = RS_LUBY; - m_params.m_phase_selection = PS_CACHING_CONSERVATIVE2; - m_params.m_random_initial_activity = IA_RANDOM; + setup_QF_UF(); TRACE("setup", tout << "st.m_num_theories: " << st.m_num_theories << "\n"; tout << "st.m_num_uninterpreted_functions: " << st.m_num_uninterpreted_functions << "\n";); @@ -224,7 +235,7 @@ namespace smt { void setup::setup_QF_RDL() { m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_nnf_cnf = false; @@ -264,7 +275,7 @@ namespace smt { TRACE("setup", tout << "setup_QF_RDL(st)\n";); check_no_uninterpreted_functions(st, "QF_RDL"); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_nnf_cnf = false; @@ -316,7 +327,7 @@ namespace smt { void setup::setup_QF_IDL() { TRACE("setup", tout << "setup_QF_IDL()\n";); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_arith_small_lemma_size = 30; @@ -334,7 +345,7 @@ namespace smt { TRACE("setup", tout << "setup_QF_IDL(st)\n";); check_no_uninterpreted_functions(st, "QF_IDL"); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_arith_small_lemma_size = 30; @@ -388,7 +399,7 @@ namespace smt { m_params.m_arith_reflect = false; m_params.m_nnf_cnf = false; m_params.m_arith_eq_bounds = true; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_phase_selection = PS_ALWAYS_FALSE; m_params.m_restart_strategy = RS_GEOMETRIC; m_params.m_restart_factor = 1.5; @@ -404,8 +415,8 @@ namespace smt { m_params.m_arith_reflect = false; m_params.m_nnf_cnf = false; if (st.m_num_uninterpreted_functions == 0) { - m_params.m_arith_expand_eqs = true; - m_params.m_arith_propagate_eqs = false; + m_params.m_arith_eq2ineq = true; + m_params.m_arith_propagate_eqs = false; if (is_dense(st)) { m_params.m_arith_small_lemma_size = 128; m_params.m_lemma_gc_half = true; @@ -438,7 +449,7 @@ namespace smt { void setup::setup_QF_LRA() { TRACE("setup", tout << "setup_QF_LRA(st)\n";); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_eliminate_term_ite = true; @@ -449,7 +460,7 @@ namespace smt { void setup::setup_QF_LRA(static_features const & st) { check_no_uninterpreted_functions(st, "QF_LRA"); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_eliminate_term_ite = true; @@ -478,7 +489,7 @@ namespace smt { void setup::setup_QF_LIA() { TRACE("setup", tout << "setup_QF_LIA(st)\n";); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_nnf_cnf = false; @@ -490,12 +501,12 @@ namespace smt { TRACE("setup", tout << "QF_LIA setup\n";); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_nnf_cnf = false; if (st.m_max_ite_tree_depth > 50) { - m_params.m_arith_expand_eqs = false; + m_params.m_arith_eq2ineq = false; m_params.m_pull_cheap_ite_trees = true; m_params.m_arith_propagate_eqs = true; m_params.m_relevancy_lvl = 2; @@ -505,7 +516,7 @@ namespace smt { m_params.m_arith_gcd_test = false; m_params.m_arith_branch_cut_ratio = 4; m_params.m_relevancy_lvl = 2; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_eliminate_term_ite = true; // if (st.m_num_exprs < 5000 && st.m_num_ite_terms < 50) { // safeguard to avoid high memory consumption // TODO: implement analsysis function to decide where lift ite is too expensive. @@ -548,6 +559,7 @@ namespace smt { } void setup::setup_QF_BV() { + TRACE("setup", tout << "qf-bv\n";); m_params.m_relevancy_lvl = 0; m_params.m_arith_reflect = false; m_params.m_bv_cc = false; @@ -720,7 +732,7 @@ namespace smt { } void setup::setup_i_arith() { - m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); + m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); } void setup::setup_r_arith() { @@ -741,7 +753,9 @@ namespace smt { void setup::setup_arith() { static_features st(m_manager); IF_VERBOSE(100, verbose_stream() << "(smt.collecting-features)\n";); - st.collect(m_context.get_num_asserted_formulas(), m_context.get_asserted_formulas()); + ptr_vector fmls; + m_context.get_asserted_formulas(fmls); + st.collect(fmls.size(), fmls.c_ptr()); IF_VERBOSE(1000, st.display_primitive(verbose_stream());); bool fixnum = st.arith_k_sum_is_small() && m_params.m_arith_fixnum; bool int_only = !st.m_has_rational && !st.m_has_real && m_params.m_arith_int_only; @@ -750,7 +764,7 @@ namespace smt { m_context.register_plugin(alloc(smt::theory_dummy, m_manager.mk_family_id("arith"), "no arithmetic")); break; case AS_DIFF_LOGIC: - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; if (fixnum) { if (int_only) m_context.register_plugin(alloc(smt::theory_fidl, m_manager, m_params)); @@ -765,7 +779,7 @@ namespace smt { } break; case AS_DENSE_DIFF_LOGIC: - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; if (fixnum) { if (int_only) m_context.register_plugin(alloc(smt::theory_dense_si, m_manager, m_params)); @@ -780,7 +794,7 @@ namespace smt { } break; case AS_UTVPI: - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; if (int_only) m_context.register_plugin(alloc(smt::theory_iutvpi, m_manager)); else @@ -876,8 +890,10 @@ namespace smt { void setup::setup_unknown() { static_features st(m_manager); - st.collect(m_context.get_num_asserted_formulas(), m_context.get_asserted_formulas()); - + ptr_vector fmls; + m_context.get_asserted_formulas(fmls); + st.collect(fmls.size(), fmls.c_ptr()); + TRACE("setup", tout << "setup_unknown\n";); setup_arith(); setup_arrays(); setup_bv(); @@ -916,7 +932,7 @@ namespace smt { tout << "has fpa: " << st.m_has_fpa << "\n"; tout << "has arrays: " << st.m_has_arrays << "\n";); - if (st.num_non_uf_theories() == 0) { + if (st.num_non_uf_theories() == 0) { setup_QF_UF(st); return; } diff --git a/src/smt/smt_setup.h b/src/smt/smt_setup.h index f12cc5e09..924c2caec 100644 --- a/src/smt/smt_setup.h +++ b/src/smt/smt_setup.h @@ -19,8 +19,8 @@ Revision History: #ifndef SMT_SETUP_H_ #define SMT_SETUP_H_ -#include"ast.h" -#include"smt_params.h" +#include "ast/ast.h" +#include "smt/params/smt_params.h" struct static_features; namespace smt { @@ -54,6 +54,7 @@ namespace smt { // setup_(static_features & st) can only be used if the logical context will perform a single // check. // + void setup_QF_DT(); void setup_QF_UF(); void setup_QF_UF(static_features const & st); void setup_QF_RDL(); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index cd912b72e..1f9ad3ef7 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -16,22 +16,21 @@ Author: Notes: --*/ -#include"solver_na2as.h" -#include"smt_kernel.h" -#include"reg_decl_plugins.h" -#include"smt_params.h" -#include"smt_params_helper.hpp" -#include"mus.h" -#include"for_each_expr.h" -#include"ast_smt2_pp.h" -#include"func_decl_dependencies.h" -#include"dec_ref_util.h" +#include "solver/solver_na2as.h" +#include "smt/smt_kernel.h" +#include "ast/reg_decl_plugins.h" +#include "smt/params/smt_params.h" +#include "smt/params/smt_params_helper.hpp" +#include "solver/mus.h" +#include "ast/for_each_expr.h" +#include "ast/ast_smt2_pp.h" +#include "ast/func_decl_dependencies.h" +#include "util/dec_ref_util.h" namespace smt { - class solver : public solver_na2as { + class smt_solver : public solver_na2as { smt_params m_smt_params; - params_ref m_params; smt::kernel m_context; progress_callback * m_callback; symbol m_logic; @@ -42,45 +41,40 @@ namespace smt { obj_map m_name2assertion; public: - solver(ast_manager & m, params_ref const & p, symbol const & l) : + smt_solver(ast_manager & m, params_ref const & p, symbol const & l) : solver_na2as(m), m_smt_params(p), - m_params(p), m_context(m, m_smt_params), m_minimizing_core(false), m_core_extend_patterns(false), m_core_extend_patterns_max_distance(UINT_MAX), - m_core_extend_nonlocal_patterns(false) { + m_core_extend_nonlocal_patterns(false) { m_logic = l; if (m_logic != symbol::null) m_context.set_logic(m_logic); - smt_params_helper smth(p); - m_core_extend_patterns = smth.core_extend_patterns(); - m_core_extend_patterns_max_distance = smth.core_extend_patterns_max_distance(); - m_core_extend_nonlocal_patterns = smth.core_extend_nonlocal_patterns(); + updt_params(p); } virtual solver * translate(ast_manager & m, params_ref const & p) { - solver * result = alloc(solver, m, p, m_logic); + ast_translation translator(get_manager(), m); + + smt_solver * result = alloc(smt_solver, m, p, m_logic); smt::kernel::copy(m_context, result->m_context); - ast_translation translator(get_manager(), m); - obj_map::iterator it = m_name2assertion.begin(); - obj_map::iterator end = m_name2assertion.end(); - for (; it != end; it++) - result->m_name2assertion.insert(translator(it->m_key), - translator(it->m_value)); + for (auto & kv : m_name2assertion) + result->m_name2assertion.insert(translator(kv.m_key), + translator(kv.m_value)); return result; } - virtual ~solver() { + virtual ~smt_solver() { dec_ref_values(get_manager(), m_name2assertion); } virtual void updt_params(params_ref const & p) { + solver::updt_params(p); m_smt_params.updt_params(p); - m_params.copy(p); m_context.updt_params(p); smt_params_helper smth(p); m_core_extend_patterns = smth.core_extend_patterns(); @@ -110,8 +104,10 @@ namespace smt { } virtual void assert_expr(expr * t, expr * a) { + if (m_name2assertion.contains(a)) { + throw default_exception("named assertion defined twice"); + } solver_na2as::assert_expr(t, a); - SASSERT(!m_name2assertion.contains(a)); get_manager().inc_ref(t); m_name2assertion.insert(a, t); } @@ -145,9 +141,9 @@ namespace smt { } struct scoped_minimize_core { - solver& s; + smt_solver& s; expr_ref_vector m_assumptions; - scoped_minimize_core(solver& s) : s(s), m_assumptions(s.m_assumptions) { + scoped_minimize_core(smt_solver& s) : s(s), m_assumptions(s.m_assumptions) { s.m_minimizing_core = true; s.m_assumptions.reset(); } @@ -164,7 +160,7 @@ namespace smt { r.push_back(m_context.get_unsat_core_expr(i)); } - if (m_minimizing_core && smt_params_helper(m_params).core_minimize()) { + if (m_minimizing_core && smt_params_helper(get_params()).core_minimize()) { scoped_minimize_core scm(*this); mus mus(*this); mus.add_soft(r.size(), r.c_ptr()); @@ -216,7 +212,7 @@ namespace smt { virtual expr * get_assertion(unsigned idx) const { SASSERT(idx < get_num_assertions()); - return m_context.get_formulas()[idx]; + return m_context.get_formula(idx); } struct collect_fds_proc { @@ -264,23 +260,20 @@ namespace smt { } void compute_assrtn_fds(ptr_vector & core, vector & assrtn_fds) { - assrtn_fds.resize(m_name2assertion.size()); - obj_map::iterator ait = m_name2assertion.begin(); - obj_map::iterator aend = m_name2assertion.end(); - for (unsigned i = 0; ait != aend; ait++, i++) { - if (core.contains(ait->m_key)) - continue; - collect_fds_proc p(m, assrtn_fds[i]); - expr_fast_mark1 visited; - quick_for_each_expr(p, visited, ait->m_value); + assrtn_fds.resize(m_name2assertion.size()); + unsigned i = 0; + for (auto & kv : m_name2assertion) { + if (!core.contains(kv.m_key)) { + collect_fds_proc p(m, assrtn_fds[i]); + expr_fast_mark1 visited; + quick_for_each_expr(p, visited, kv.m_value); + } + ++i; } } bool fds_intersect(func_decl_set & pattern_fds, func_decl_set & assrtn_fds) { - func_decl_set::iterator it = pattern_fds.begin(); - func_decl_set::iterator end = pattern_fds.end(); - for (; it != end; it++) { - func_decl * fd = *it; + for (func_decl * fd : pattern_fds) { if (assrtn_fds.contains(fd)) return true; } @@ -297,9 +290,8 @@ namespace smt { for (unsigned d = 0; d < m_core_extend_patterns_max_distance; d++) { new_core_literals.reset(); - unsigned sz = core.size(); - for (unsigned i = 0; i < sz; i++) { - expr_ref name(core[i], m); + for (expr* c : core) { + expr_ref name(c, m); SASSERT(m_name2assertion.contains(name)); expr_ref assrtn(m_name2assertion.find(name), m); collect_pattern_fds(assrtn, pattern_fds); @@ -309,12 +301,12 @@ namespace smt { if (assrtn_fds.empty()) compute_assrtn_fds(core, assrtn_fds); - obj_map::iterator ait = m_name2assertion.begin(); - obj_map::iterator aend = m_name2assertion.end(); - for (unsigned i = 0; ait != aend; ait++, i++) { - if (!core.contains(ait->m_key) && + unsigned i = 0; + for (auto & kv : m_name2assertion) { + if (!core.contains(kv.m_key) && fds_intersect(pattern_fds, assrtn_fds[i])) - new_core_literals.push_back(ait->m_key); + new_core_literals.push_back(kv.m_key); + ++i; } } @@ -349,22 +341,16 @@ namespace smt { void add_nonlocal_pattern_literals_to_core(ptr_vector & core) { ast_manager & m = get_manager(); - - obj_map::iterator it = m_name2assertion.begin(); - obj_map::iterator end = m_name2assertion.end(); - for (unsigned i = 0; it != end; it++, i++) { - expr_ref name(it->m_key, m); - expr_ref assrtn(it->m_value, m); + for (auto const& kv : m_name2assertion) { + expr_ref name(kv.m_key, m); + expr_ref assrtn(kv.m_value, m); if (!core.contains(name)) { func_decl_set pattern_fds, body_fds; collect_pattern_fds(assrtn, pattern_fds); collect_body_func_decls(assrtn, body_fds); - func_decl_set::iterator pit = pattern_fds.begin(); - func_decl_set::iterator pend= pattern_fds.end(); - for (; pit != pend; pit++) { - func_decl * fd = *pit; + for (func_decl *fd : pattern_fds) { if (!body_fds.contains(fd)) { core.insert(name); break; @@ -377,7 +363,7 @@ namespace smt { }; solver * mk_smt_solver(ast_manager & m, params_ref const & p, symbol const & logic) { - return alloc(smt::solver, m, p, logic); + return alloc(smt::smt_solver, m, p, logic); } class smt_solver_factory : public solver_factory { diff --git a/src/smt/smt_solver.h b/src/smt/smt_solver.h index 6ec83810e..7d2677b35 100644 --- a/src/smt/smt_solver.h +++ b/src/smt/smt_solver.h @@ -21,8 +21,8 @@ Notes: #ifndef SMT_SOLVER_H_ #define SMT_SOLVER_H_ -#include"ast.h" -#include"params.h" +#include "ast/ast.h" +#include "util/params.h" class solver; class solver_factory; diff --git a/src/smt/smt_statistics.cpp b/src/smt/smt_statistics.cpp index 5201e48b3..95acd4819 100644 --- a/src/smt/smt_statistics.cpp +++ b/src/smt/smt_statistics.cpp @@ -17,7 +17,7 @@ Revision History: --*/ #include -#include"smt_statistics.h" +#include "smt/smt_statistics.h" namespace smt { diff --git a/src/smt/smt_theory.cpp b/src/smt/smt_theory.cpp index 2263699f9..515503d41 100644 --- a/src/smt/smt_theory.cpp +++ b/src/smt/smt_theory.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"buffer.h" -#include"ast_ll_pp.h" +#include "smt/smt_context.h" +#include "util/buffer.h" +#include "ast/ast_ll_pp.h" namespace smt { diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index c943a85d8..2ee0db322 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -19,9 +19,9 @@ Revision History: #ifndef SMT_THEORY_H_ #define SMT_THEORY_H_ -#include"smt_enode.h" -#include"obj_hashtable.h" -#include"statistics.h" +#include "smt/smt_enode.h" +#include "util/obj_hashtable.h" +#include "util/statistics.h" #include namespace smt { @@ -192,7 +192,7 @@ namespace smt { virtual lbool validate_unsat_core(expr_ref_vector & unsat_core) { return l_false; } - + /** \brief This method is invoked before the search starts. */ diff --git a/src/smt/smt_theory_var_list.h b/src/smt/smt_theory_var_list.h index 5f963102b..aa2816786 100644 --- a/src/smt/smt_theory_var_list.h +++ b/src/smt/smt_theory_var_list.h @@ -19,7 +19,7 @@ Revision History: #ifndef SMT_THEORY_VAR_LIST_H_ #define SMT_THEORY_VAR_LIST_H_ -#include"smt_types.h" +#include "smt/smt_types.h" namespace smt { @@ -67,9 +67,9 @@ namespace smt { }; // 32 bit machine - COMPILE_TIME_ASSERT(sizeof(expr*) != 4 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int)); + static_assert(sizeof(expr*) != 4 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int), "32 bit"); // 64 bit machine - COMPILE_TIME_ASSERT(sizeof(expr*) != 8 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int) + /* a structure must be aligned */ sizeof(int)); + static_assert(sizeof(expr*) != 8 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int) + /* a structure must be aligned */ sizeof(int), "64 bit"); }; #endif /* SMT_THEORY_VAR_LIST_H_ */ diff --git a/src/smt/smt_types.h b/src/smt/smt_types.h index 7f2076045..6300bd43c 100644 --- a/src/smt/smt_types.h +++ b/src/smt/smt_types.h @@ -19,9 +19,9 @@ Revision History: #ifndef SMT_TYPES_H_ #define SMT_TYPES_H_ -#include"list.h" -#include"vector.h" -#include"lbool.h" +#include "util/list.h" +#include "util/vector.h" +#include "util/lbool.h" class model; diff --git a/src/smt/smt_value_sort.cpp b/src/smt/smt_value_sort.cpp index a840b77b7..56768b91a 100644 --- a/src/smt/smt_value_sort.cpp +++ b/src/smt/smt_value_sort.cpp @@ -18,10 +18,10 @@ Revision History: --*/ -#include "smt_value_sort.h" -#include "bv_decl_plugin.h" -#include "arith_decl_plugin.h" -#include "datatype_decl_plugin.h" +#include "smt/smt_value_sort.h" +#include "ast/bv_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" namespace smt { diff --git a/src/smt/smt_value_sort.h b/src/smt/smt_value_sort.h index e9327fca6..d7228f21c 100644 --- a/src/smt/smt_value_sort.h +++ b/src/smt/smt_value_sort.h @@ -22,7 +22,7 @@ Revision History: #ifndef SMT_VALUE_SORT_H_ #define SMT_VALUE_SORT_H_ -#include "ast.h" +#include "ast/ast.h" namespace smt { diff --git a/src/smt/spanning_tree.h b/src/smt/spanning_tree.h index fd5e68d54..78b556130 100644 --- a/src/smt/spanning_tree.h +++ b/src/smt/spanning_tree.h @@ -19,8 +19,8 @@ Notes: #ifndef SPANNING_TREE_H_ #define SPANNING_TREE_H_ -#include "diff_logic.h" -#include "spanning_tree_base.h" +#include "smt/diff_logic.h" +#include "smt/spanning_tree_base.h" namespace smt { diff --git a/src/smt/spanning_tree_base.h b/src/smt/spanning_tree_base.h index b86e5caa2..1ad98b79c 100644 --- a/src/smt/spanning_tree_base.h +++ b/src/smt/spanning_tree_base.h @@ -20,8 +20,8 @@ Notes: #ifndef SPANNING_TREE_BASE_H_ #define SPANNING_TREE_BASE_H_ -#include "util.h" -#include "vector.h" +#include "util/util.h" +#include "util/vector.h" namespace smt { template diff --git a/src/smt/spanning_tree_def.h b/src/smt/spanning_tree_def.h index ca7607119..c49ffcd3c 100644 --- a/src/smt/spanning_tree_def.h +++ b/src/smt/spanning_tree_def.h @@ -19,7 +19,7 @@ Notes: #ifndef SPANNING_TREE_DEF_H_ #define SPANNING_TREE_DEF_H_ -#include "spanning_tree.h" +#include "smt/spanning_tree.h" namespace smt { diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index d59ef5254..edc4b4ff5 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -17,13 +17,13 @@ Notes: --*/ -#include"ctx_solver_simplify_tactic.h" -#include"arith_decl_plugin.h" -#include"smt_params.h" -#include"smt_kernel.h" -#include"ast_pp.h" -#include"mk_simplified_app.h" -#include"ast_util.h" +#include "smt/tactic/ctx_solver_simplify_tactic.h" +#include "ast/arith_decl_plugin.h" +#include "smt/params/smt_params.h" +#include "smt/smt_kernel.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/mk_simplified_app.h" +#include "ast/ast_util.h" class ctx_solver_simplify_tactic : public tactic { ast_manager& m; diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.h b/src/smt/tactic/ctx_solver_simplify_tactic.h index 51b81603d..28006cefc 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.h +++ b/src/smt/tactic/ctx_solver_simplify_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef CTX_SOLVER_SIMPLIFY_TACTIC_H_ #define CTX_SOLVER_SIMPLIFY_TACTIC_H_ -#include"tactical.h" +#include "tactic/tactical.h" tactic * mk_ctx_solver_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()); /* diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 64bae0a48..57ac7b34b 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -16,19 +16,19 @@ Author: Notes: --*/ -#include"tactic.h" -#include"tactical.h" -#include"smt_kernel.h" -#include"smt_params.h" -#include"smt_params_helper.hpp" -#include"lp_params.hpp" -#include"rewriter_types.h" -#include"filter_model_converter.h" -#include"ast_util.h" -#include"solver2tactic.h" -#include"smt_solver.h" -#include"solver.h" -#include"mus.h" +#include "tactic/tactic.h" +#include "tactic/tactical.h" +#include "smt/smt_kernel.h" +#include "smt/params/smt_params.h" +#include "smt/params/smt_params_helper.hpp" +#include "util/lp/lp_params.hpp" +#include "ast/rewriter/rewriter_types.h" +#include "tactic/filter_model_converter.h" +#include "ast/ast_util.h" +#include "solver/solver2tactic.h" +#include "smt/smt_solver.h" +#include "solver/solver.h" +#include "solver/mus.h" typedef obj_map expr2expr_map; @@ -150,6 +150,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) { try { + IF_VERBOSE(10, verbose_stream() << "(smt.tactic start)\n";); mc = 0; pc = 0; core = 0; SASSERT(in->is_well_sorted()); ast_manager & m = in->m(); diff --git a/src/smt/tactic/smt_tactic.h b/src/smt/tactic/smt_tactic.h index a23695fd1..c7b91d032 100644 --- a/src/smt/tactic/smt_tactic.h +++ b/src/smt/tactic/smt_tactic.h @@ -19,10 +19,10 @@ Notes: #ifndef SMT_TACTIC_H_ #define SMT_TACTIC_H_ -#include"params.h" -#include"ast.h" -#include"obj_hashtable.h" -#include"goal.h" +#include "util/params.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "tactic/goal.h" class tactic; class filter_model_converter; diff --git a/src/smt/tactic/unit_subsumption_tactic.cpp b/src/smt/tactic/unit_subsumption_tactic.cpp index 745bfa2de..68a34cea8 100644 --- a/src/smt/tactic/unit_subsumption_tactic.cpp +++ b/src/smt/tactic/unit_subsumption_tactic.cpp @@ -15,8 +15,8 @@ Author: --*/ -#include "unit_subsumption_tactic.h" -#include "smt_context.h" +#include "smt/tactic/unit_subsumption_tactic.h" +#include "smt/smt_context.h" struct unit_subsumption_tactic : public tactic { ast_manager& m; diff --git a/src/smt/tactic/unit_subsumption_tactic.h b/src/smt/tactic/unit_subsumption_tactic.h index 499bb44c6..09db59295 100644 --- a/src/smt/tactic/unit_subsumption_tactic.h +++ b/src/smt/tactic/unit_subsumption_tactic.h @@ -23,7 +23,7 @@ Notes: --*/ #ifndef UNIT_SUBSUMPTION_TACTIC_H_ #define UNIT_SUBSUMPTION_TACTIC_H_ -#include "tactic.h" +#include "tactic/tactic.h" tactic * mk_unit_subsumption_tactic(ast_manager & m, params_ref const & p = params_ref()); /* diff --git a/src/smt/theory_arith.cpp b/src/smt/theory_arith.cpp index 9a7d08151..6aee87408 100644 --- a/src/smt/theory_arith.cpp +++ b/src/smt/theory_arith.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"theory_arith_def.h" +#include "smt/theory_arith_def.h" namespace smt { diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index cdc1a3933..5f4e58a1b 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -20,24 +20,23 @@ Revision History: #ifndef THEORY_ARITH_H_ #define THEORY_ARITH_H_ -#include"smt_theory.h" -#include"map.h" -#include"heap.h" -#include"nat_set.h" -#include"inf_rational.h" -#include"s_integer.h" -#include"inf_s_integer.h" -#include"arith_decl_plugin.h" -#include"theory_arith_params.h" -#include"arith_eq_adapter.h" -#include"numeral_factory.h" -#include"obj_pair_hashtable.h" -#include"old_interval.h" -#include"grobner.h" -#include"arith_simplifier_plugin.h" -#include"arith_eq_solver.h" -#include"theory_opt.h" -#include"uint_set.h" +#include "smt/smt_theory.h" +#include "util/map.h" +#include "util/heap.h" +#include "util/nat_set.h" +#include "util/inf_rational.h" +#include "util/s_integer.h" +#include "util/inf_s_integer.h" +#include "ast/arith_decl_plugin.h" +#include "smt/params/theory_arith_params.h" +#include "smt/arith_eq_adapter.h" +#include "smt/proto_model/numeral_factory.h" +#include "util/obj_pair_hashtable.h" +#include "smt/old_interval.h" +#include "math/grobner/grobner.h" +#include "smt/arith_eq_solver.h" +#include "smt/theory_opt.h" +#include "util/uint_set.h" namespace smt { diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index f94de7eba..a1558e5e5 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -19,11 +19,11 @@ Revision History: #ifndef THEORY_ARITH_AUX_H_ #define THEORY_ARITH_AUX_H_ -#include"inf_eps_rational.h" -#include"theory_arith.h" -#include"smt_farkas_util.h" -#include"th_rewriter.h" -#include"filter_model_converter.h" +#include "util/inf_eps_rational.h" +#include "smt/theory_arith.h" +#include "smt/smt_farkas_util.h" +#include "ast/rewriter/th_rewriter.h" +#include "tactic/filter_model_converter.h" namespace smt { @@ -2106,6 +2106,7 @@ namespace smt { template void theory_arith::mutate_assignment() { + SASSERT(m_to_patch.empty()); remove_fixed_vars_from_base(); int num_vars = get_num_vars(); m_var_value_table.reset(); @@ -2131,12 +2132,9 @@ namespace smt { } if (candidates.empty()) return; - typename sbuffer::iterator it = candidates.begin(); - typename sbuffer::iterator end = candidates.end(); m_tmp_var_set.reset(); m_tmp_var_set2.reset(); - for (; it != end; ++it) { - theory_var v = *it; + for (theory_var v : candidates) { SASSERT(!is_fixed(v)); if (is_base(v)) { row & r = m_rows[get_var_row(v)]; diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index bee744c34..aa512a2be 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -19,12 +19,12 @@ Revision History: #ifndef THEORY_ARITH_CORE_H_ #define THEORY_ARITH_CORE_H_ -#include"smt_context.h" -#include"theory_arith.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"smt_model_generator.h" -#include"ast_smt2_pp.h" +#include "smt/smt_context.h" +#include "smt/theory_arith.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "smt/smt_model_generator.h" +#include "ast/ast_smt2_pp.h" namespace smt { @@ -395,7 +395,8 @@ namespace smt { template theory_var theory_arith::internalize_div(app * n) { - if (!m_util.is_numeral(n->get_arg(1))) found_underspecified_op(n); + rational r(1); + if (!m_util.is_numeral(n->get_arg(1), r) || r.is_zero()) found_underspecified_op(n); found_underspecified_op(n); theory_var s = mk_binary_op(n); context & ctx = get_context(); @@ -406,7 +407,8 @@ namespace smt { template theory_var theory_arith::internalize_idiv(app * n) { - found_underspecified_op(n); + rational r; + if (!m_util.is_numeral(n->get_arg(1), r) || r.is_zero()) found_underspecified_op(n); theory_var s = mk_binary_op(n); context & ctx = get_context(); app * mod = m_util.mk_mod(n->get_arg(0), n->get_arg(1)); @@ -419,7 +421,8 @@ namespace smt { template theory_var theory_arith::internalize_mod(app * n) { TRACE("arith_mod", tout << "internalizing...\n" << mk_pp(n, get_manager()) << "\n";); - if (!m_util.is_numeral(n->get_arg(1))) found_underspecified_op(n); + rational r(1); + if (!m_util.is_numeral(n->get_arg(1), r) || r.is_zero()) found_underspecified_op(n); theory_var s = mk_binary_op(n); context & ctx = get_context(); if (!ctx.relevancy()) @@ -429,7 +432,8 @@ namespace smt { template theory_var theory_arith::internalize_rem(app * n) { - if (!m_util.is_numeral(n->get_arg(1))) found_underspecified_op(n); + rational r(1); + if (!m_util.is_numeral(n->get_arg(1), r) || r.is_zero()) found_underspecified_op(n); theory_var s = mk_binary_op(n); context & ctx = get_context(); if (!ctx.relevancy()) { @@ -442,20 +446,21 @@ namespace smt { void theory_arith::mk_axiom(expr * ante, expr * conseq) { ast_manager & m = get_manager(); context & ctx = get_context(); - simplifier & s = ctx.get_simplifier(); + th_rewriter & s = ctx.get_rewriter(); expr_ref s_ante(m), s_conseq(m); expr* s_conseq_n, * s_ante_n; bool negated; - proof_ref pr(m); - s(ante, s_ante, pr); + s(ante, s_ante); + if (ctx.get_cancel_flag()) return; negated = m.is_not(s_ante, s_ante_n); if (negated) s_ante = s_ante_n; ctx.internalize(s_ante, false); literal l_ante = ctx.get_literal(s_ante); if (negated) l_ante.neg(); - s(conseq, s_conseq, pr); + s(conseq, s_conseq); + if (ctx.get_cancel_flag()) return; negated = m.is_not(s_conseq, s_conseq_n); if (negated) s_conseq = s_conseq_n; ctx.internalize(s_conseq, false); @@ -732,11 +737,6 @@ namespace smt { return internalize_div(n); else if (m_util.is_idiv(n)) return internalize_idiv(n); - else if (is_app_of(n, get_id(), OP_IDIV_0) || is_app_of(n, get_id(), OP_DIV_0)) { - ctx.internalize(n->get_arg(0), false); - enode * e = mk_enode(n); - return mk_var(e); - } else if (m_util.is_mod(n)) return internalize_mod(n); else if (m_util.is_rem(n)) @@ -1224,7 +1224,10 @@ namespace smt { app * rhs = to_app(n->get_arg(1)); expr * rhs2; if (m_util.is_to_real(rhs, rhs2) && is_app(rhs2)) { rhs = to_app(rhs2); } - SASSERT(m_util.is_numeral(rhs)); + if (!m_util.is_numeral(rhs)) { + UNREACHABLE(); + throw default_exception("malformed atomic constraint"); + } theory_var v = internalize_term_core(lhs); if (v == null_theory_var) { TRACE("arith_internalize", tout << "failed to internalize: #" << n->get_id() << "\n";); @@ -1411,6 +1414,12 @@ namespace smt { final_check_status result = FC_DONE; final_check_status ok; do { + if (get_context().get_cancel_flag()) { + return FC_GIVEUP; + } + + SASSERT(m_to_patch.empty()); + TRACE("arith", tout << "m_final_check_idx: " << m_final_check_idx << ", result: " << result << "\n";); switch (m_final_check_idx) { case 0: @@ -2305,7 +2314,7 @@ namespace smt { return false; } TRACE("arith_make_feasible_detail", display(tout);); - if (get_context().get_cancel_flag()) { + if (get_context().get_cancel_flag()) { return true; } } diff --git a/src/smt/theory_arith_def.h b/src/smt/theory_arith_def.h index 531a03bd3..962f55f02 100644 --- a/src/smt/theory_arith_def.h +++ b/src/smt/theory_arith_def.h @@ -19,14 +19,14 @@ Revision History: #ifndef THEORY_ARITH_DEF_H_ #define THEORY_ARITH_DEF_H_ -#include"theory_arith.h" -#include"theory_arith_core.h" -#include"theory_arith_aux.h" -#include"theory_arith_inv.h" -#include"theory_arith_pp.h" -#include"theory_arith_int.h" -#include"theory_arith_eq.h" -#include"theory_arith_nl.h" +#include "smt/theory_arith.h" +#include "smt/theory_arith_core.h" +#include "smt/theory_arith_aux.h" +#include "smt/theory_arith_inv.h" +#include "smt/theory_arith_pp.h" +#include "smt/theory_arith_int.h" +#include "smt/theory_arith_eq.h" +#include "smt/theory_arith_nl.h" #endif /* THEORY_ARITH_DEF_H_ */ diff --git a/src/smt/theory_arith_eq.h b/src/smt/theory_arith_eq.h index ae0f17757..a7f7fae59 100644 --- a/src/smt/theory_arith_eq.h +++ b/src/smt/theory_arith_eq.h @@ -22,7 +22,7 @@ Revision History: // #define PROFILE_OFFSET_ROW #ifdef PROFILE_OFFSET_ROW -#include"stopwatch.h" +#include "util/stopwatch.h" #undef max #undef min #endif diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index e6e9e863c..4f15a6156 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -19,12 +19,11 @@ Revision History: #ifndef THEORY_ARITH_INT_H_ #define THEORY_ARITH_INT_H_ -#include"ast_ll_pp.h" -#include"arith_simplifier_plugin.h" -#include"well_sorted.h" -#include"euclidean_solver.h" -#include"numeral_buffer.h" -#include"ast_smt2_pp.h" +#include "util/numeral_buffer.h" +#include "ast/ast_ll_pp.h" +#include "ast/well_sorted.h" +#include "ast/ast_smt2_pp.h" +#include "math/euclid/euclidean_solver.h" namespace smt { @@ -239,7 +238,7 @@ namespace smt { for (; it != end; ++it) { theory_var b = it->get_base_var(); if (b == null_theory_var) { - TRACE("theory_arith_int", display_row(tout << "null: ", *it, true); ); + TRACE("arith_int", display_row(tout << "null: ", *it, true); ); continue; } bool is_tight = false; @@ -257,7 +256,7 @@ namespace smt { const_coeff = u->get_value().get_rational(); } if (!is_tight) { - TRACE("theory_arith_int", + TRACE("arith_int", display_row(tout << "!tight: ", *it, true); display_var(tout, b); ); @@ -455,9 +454,8 @@ namespace smt { pol = m_util.mk_add(_args.size(), _args.c_ptr()); result = m_util.mk_ge(pol, m_util.mk_numeral(k, all_int)); TRACE("arith_mk_polynomial", tout << "before simplification:\n" << result << "\n";); - simplifier & s = get_context().get_simplifier(); proof_ref pr(m); - s(result, result, pr); + get_context().get_rewriter()(result, result, pr); TRACE("arith_mk_polynomial", tout << "after simplification:\n" << result << "\n";); SASSERT(is_well_sorted(get_manager(), result)); } diff --git a/src/smt/theory_arith_inv.h b/src/smt/theory_arith_inv.h index b547168e0..987d075c3 100644 --- a/src/smt/theory_arith_inv.h +++ b/src/smt/theory_arith_inv.h @@ -19,8 +19,8 @@ Revision History: #ifndef THEORY_ARITH_INV_H_ #define THEORY_ARITH_INV_H_ -#include"theory_arith.h" -#include"ast_pp.h" +#include "smt/theory_arith.h" +#include "ast/ast_pp.h" namespace smt { diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 8a632cf48..230b6de77 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -19,7 +19,7 @@ Revision History: #ifndef THEORY_ARITH_NL_H_ #define THEORY_ARITH_NL_H_ -#include"ast_smt2_pp.h" +#include "ast/ast_smt2_pp.h" namespace smt { @@ -681,8 +681,7 @@ namespace smt { SASSERT(is_pure_monomial(var2expr(v))); expr * m = var2expr(v); rational val(1), v_val; - for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { - expr * arg = to_app(m)->get_arg(i); + for (expr* arg : *to_app(m)) { theory_var curr = expr2var(arg); SASSERT(curr != null_theory_var); v_val = get_value(curr, computed_epsilon); @@ -742,7 +741,6 @@ namespace smt { continue; bool computed_epsilon = false; bool r = check_monomial_assignment(v, computed_epsilon); - SASSERT(!computed_epsilon); // integer variables do not use epsilon if (!r) { expr * m = get_enode(v)->get_owner(); SASSERT(is_pure_monomial(m)); @@ -782,7 +780,7 @@ namespace smt { of a non linear monomial that is not satisfied by the current assignment. if v >= l, then create the case split v >= l+1 else v <= u, then create the case split v <= u-1 - else do nothing and return false. + else create the bound v = 0 and case split on it. */ template bool theory_arith::branch_nl_int_var(theory_var v) { @@ -1249,11 +1247,9 @@ namespace smt { } // Update the number of occurrences in the result vector. - typename var2num_occs::iterator it2 = m_var2num_occs.begin(); - typename var2num_occs::iterator end2 = m_var2num_occs.end(); - for (; it2 != end2; ++it2) { - if ((*it2).m_value > 1) - varinfo.push_back(var_num_occs((*it2).m_key, (*it2).m_value)); + for (auto const& vn : m_var2num_occs) { + if (vn.m_value > 1) + varinfo.push_back(var_num_occs(vn.m_key, vn.m_value)); } } @@ -1265,18 +1261,16 @@ namespace smt { SASSERT(!p.empty()); TRACE("p2expr_bug", display_coeff_exprs(tout, p);); ptr_buffer args; - sbuffer::const_iterator it = p.begin(); - sbuffer::const_iterator end = p.end(); - for (; it != end; ++it) { - rational const & c = it->first; - expr * var = it->second; + for (coeff_expr const& ce : p) { + rational const & c = ce.first; + expr * var = ce.second; if (!c.is_one()) { rational c2; expr * m = 0; if (m_util.is_numeral(var, c2)) - m = m_util.mk_numeral(c*c2, m_util.is_int(var)); + m = m_util.mk_numeral(c*c2, m_util.is_int(var) && c.is_int() && c2.is_int()); else - m = m_util.mk_mul(m_util.mk_numeral(c, m_util.is_int(var)), var); + m = m_util.mk_mul(m_util.mk_numeral(c, c.is_int() && m_util.is_int(var)), var); m_nl_new_exprs.push_back(m); args.push_back(m); } @@ -1453,8 +1447,7 @@ namespace smt { SASSERT(is_pure_monomial(m)); unsigned idx = 0; ptr_buffer new_args; - for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { - expr * arg = to_app(m)->get_arg(i); + for (expr * arg : *to_app(m)) { if (arg == var) { if (idx < d) idx++; @@ -1487,17 +1480,15 @@ namespace smt { tout << "min_degree: " << d << "\n";); sbuffer e; // monomials/x^d where var occurs with degree d sbuffer r; // rest - sbuffer::const_iterator it = p.begin(); - sbuffer::const_iterator end = p.end(); - for (; it != end; ++it) { - expr * m = it->second; + for (auto const& kv : p) { + expr * m = kv.second; expr * f = factor(m, var, d); if (get_degree_of(m, var) == d) { - e.push_back(coeff_expr(it->first, f)); + e.push_back(coeff_expr(kv.first, f)); } else { SASSERT(get_degree_of(m, var) > d); - r.push_back(coeff_expr(it->first, f)); + r.push_back(coeff_expr(kv.first, f)); } } expr * s = cross_nested(e, 0); @@ -1623,16 +1614,12 @@ namespace smt { return true; std::stable_sort(varinfo.begin(), varinfo.end(), var_num_occs_lt()); TRACE("cross_nested", tout << "var num occs:\n"; - sbuffer::const_iterator it = varinfo.begin(); - sbuffer::const_iterator end = varinfo.end(); - for (; it != end ; ++it) { - tout << mk_bounded_pp(it->first, get_manager()) << " -> " << it->second << "\n"; + for (auto const& kv : varinfo) { + tout << mk_bounded_pp(kv.first, get_manager()) << " -> " << kv.second << "\n"; }); - sbuffer::const_iterator it = varinfo.begin(); - sbuffer::const_iterator end = varinfo.end(); - for (; it != end; ++it) { + for (auto const& kv : varinfo) { m_nl_new_exprs.reset(); - expr * var = it->first; + expr * var = kv.first; expr * cn = cross_nested(p, var); // Remark: cn may not be well-sorted because, since a row may contain mixed integer/real monomials. // This is not really a problem, since evaluate_as_interval will work even if cn is not well-sorted. @@ -1731,10 +1718,7 @@ namespace smt { */ template bool theory_arith::is_cross_nested_consistent(svector const & nl_cluster) { - svector::const_iterator it = nl_cluster.begin(); - svector::const_iterator end = nl_cluster.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (theory_var v : nl_cluster) { if (!is_base(v)) continue; m_stats.m_nl_cross_nested++; @@ -1765,10 +1749,7 @@ namespace smt { template void theory_arith::init_grobner_var_order(svector const & nl_cluster, grobner & gb) { // Initialize variable order - svector::const_iterator it = nl_cluster.begin(); - svector::const_iterator end = nl_cluster.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (theory_var v : nl_cluster) { expr * var = var2expr(v); if (is_fixed(v)) { @@ -1905,10 +1886,7 @@ namespace smt { template void theory_arith::init_grobner(svector const & nl_cluster, grobner & gb) { init_grobner_var_order(nl_cluster, gb); - svector::const_iterator it = nl_cluster.begin(); - svector::const_iterator end = nl_cluster.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (theory_var v : nl_cluster) { if (is_base(v)) { row const & r = m_rows[get_var_row(v)]; add_row_to_gb(r, gb); @@ -2227,7 +2205,7 @@ namespace smt { args.push_back(monomial2expr(eq->get_monomial(i), is_int)); } context & ctx = get_context(); - simplifier & s = ctx.get_simplifier(); + th_rewriter& s = ctx.get_rewriter(); expr_ref pol(get_manager()); SASSERT(!args.empty()); pol = mk_nary_add(args.size(), args.c_ptr()); @@ -2296,10 +2274,7 @@ namespace smt { eqs.reset(); gb.get_equations(eqs); TRACE("grobner_bug", tout << "after gb\n";); - ptr_vector::const_iterator it = eqs.begin(); - ptr_vector::const_iterator end = eqs.end(); - for (; it != end; ++it) { - grobner::equation * eq = *it; + for (grobner::equation* eq : eqs) { TRACE("grobner_bug", gb.display_equation(tout, *eq);); if (is_inconsistent(eq, gb)) return GB_PROGRESS; @@ -2310,9 +2285,7 @@ namespace smt { // then assert bounds for x, and continue gb_result result = GB_FAIL; if (m_params.m_nl_arith_gb_eqs) { - it = eqs.begin(); - for (; it != end; ++it) { - grobner::equation * eq = *it; + for (grobner::equation* eq : eqs) { if (!eq->is_linear_combination()) { TRACE("non_linear", tout << "processing new equality:\n"; gb.display_equation(tout, *eq);); TRACE("non_linear_bug", tout << "processing new equality:\n"; gb.display_equation(tout, *eq);); @@ -2331,9 +2304,8 @@ namespace smt { // I only consider linear equations... (HACK) // Moreover, I do not change the weight of a variable more than once in this loop. bool modified = false; - it = eqs.begin(); - for (; it != end; ++it) { - grobner::equation const * eq = *it; + + for (grobner::equation const* eq : eqs) { unsigned num_monomials = eq->get_num_monomials(); CTRACE("grobner_bug", num_monomials <= 0, gb.display_equation(tout, *eq);); if (num_monomials == 0) @@ -2370,13 +2342,11 @@ namespace smt { bool theory_arith::max_min_nl_vars() { var_set already_found; svector vars; - for (unsigned j = 0; j < m_nl_monomials.size(); ++j) { - theory_var v = m_nl_monomials[j]; + for (theory_var v : m_nl_monomials) { mark_var(v, vars, already_found); expr * n = var2expr(v); SASSERT(is_pure_monomial(n)); - for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) { - expr * curr = to_app(n)->get_arg(i); + for (expr * curr : *to_app(n)) { theory_var v = expr2var(curr); SASSERT(v != null_theory_var); mark_var(v, vars, already_found); diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index 7b657d9c2..67fe5a572 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -19,9 +19,9 @@ Revision History: #ifndef THEORY_ARITH_PP_H_ #define THEORY_ARITH_PP_H_ -#include"theory_arith.h" -#include"ast_smt_pp.h" -#include"stats.h" +#include "smt/theory_arith.h" +#include "ast/ast_smt_pp.h" +#include "util/stats.h" namespace smt { template diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index b06e50d2a..b8f76f9ad 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -16,10 +16,11 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"theory_array.h" -#include"ast_ll_pp.h" -#include"stats.h" +#include "smt/smt_context.h" +#include "smt/theory_array.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "util/stats.h" namespace smt { @@ -52,18 +53,12 @@ namespace smt { var_data * d2 = m_var_data[v2]; if (!d1->m_prop_upward && d2->m_prop_upward) set_prop_upward(v1); - ptr_vector::iterator it = d2->m_stores.begin(); - ptr_vector::iterator end = d2->m_stores.end(); - for (; it != end; ++it) - add_store(v1, *it); - it = d2->m_parent_stores.begin(); - end = d2->m_parent_stores.end(); - for (; it != end; ++it) - add_parent_store(v1, *it); - it = d2->m_parent_selects.begin(); - end = d2->m_parent_selects.end(); - for (; it != end; ++it) - add_parent_select(v1, *it); + for (enode* n : d2->m_stores) + add_store(v1, n); + for (enode* n : d2->m_parent_stores) + add_parent_store(v1, n); + for (enode* n : d2->m_parent_selects) + add_parent_select(v1, n); TRACE("array", tout << "after merge\n"; display_var(tout, v1);); } @@ -102,16 +97,11 @@ namespace smt { d->m_parent_selects.push_back(s); TRACE("array", tout << mk_pp(s->get_owner(), get_manager()) << " " << mk_pp(get_enode(v)->get_owner(), get_manager()) << "\n";); m_trail_stack.push(push_back_trail(d->m_parent_selects)); - ptr_vector::iterator it = d->m_stores.begin(); - ptr_vector::iterator end = d->m_stores.end(); - for (; it != end; ++it) { - instantiate_axiom2a(s, *it); + for (enode* n : d->m_stores) { + instantiate_axiom2a(s, n); } if (!m_params.m_array_weak && !m_params.m_array_delay_exp_axiom && d->m_prop_upward) { - it = d->m_parent_stores.begin(); - end = d->m_parent_stores.end(); - for (; it != end; ++it) { - enode * store = *it; + for (enode* store : d->m_parent_stores) { SASSERT(is_store(store)); if (!m_params.m_array_cg || store->is_cgr()) { instantiate_axiom2b(s, store); @@ -128,27 +118,19 @@ namespace smt { var_data * d = m_var_data[v]; d->m_parent_stores.push_back(s); m_trail_stack.push(push_back_trail(d->m_parent_stores)); - if (!m_params.m_array_weak && !m_params.m_array_delay_exp_axiom && d->m_prop_upward) { - ptr_vector::iterator it = d->m_parent_selects.begin(); - ptr_vector::iterator end = d->m_parent_selects.end(); - for (; it != end; ++it) - if (!m_params.m_array_cg || (*it)->is_cgr()) - instantiate_axiom2b(*it, s); - } + if (!m_params.m_array_weak && !m_params.m_array_delay_exp_axiom && d->m_prop_upward) + for (enode* n : d->m_parent_selects) + if (!m_params.m_array_cg || n->is_cgr()) + instantiate_axiom2b(n, s); } bool theory_array::instantiate_axiom2b_for(theory_var v) { bool result = false; var_data * d = m_var_data[v]; - ptr_vector::iterator it = d->m_parent_stores.begin(); - ptr_vector::iterator end = d->m_parent_stores.end(); - for (; it != end; ++it) { - ptr_vector::iterator it2 = d->m_parent_selects.begin(); - ptr_vector::iterator end2 = d->m_parent_selects.end(); - for (; it2 != end2; ++it2) - if (instantiate_axiom2b(*it2, *it)) + for (enode* n1 : d->m_parent_stores) + for (enode * n2 : d->m_parent_selects) + if (instantiate_axiom2b(n2, n1)) result = true; - } return result; } @@ -166,10 +148,8 @@ namespace smt { d->m_prop_upward = true; if (!m_params.m_array_delay_exp_axiom) instantiate_axiom2b_for(v); - ptr_vector::iterator it = d->m_stores.begin(); - ptr_vector::iterator end = d->m_stores.end(); - for (; it != end; ++it) - set_prop_upward(*it); + for (enode * n : d->m_stores) + set_prop_upward(n); } } @@ -208,11 +188,9 @@ namespace smt { } d->m_stores.push_back(s); m_trail_stack.push(push_back_trail(d->m_stores)); - ptr_vector::iterator it = d->m_parent_selects.begin(); - ptr_vector::iterator end = d->m_parent_selects.end(); - for (; it != end; ++it) { - SASSERT(is_select(*it)); - instantiate_axiom2a(*it, s); + for (enode * n : d->m_parent_selects) { + SASSERT(is_select(n)); + instantiate_axiom2a(n, s); } if (m_params.m_array_always_prop_upward || lambda_equiv_class_size >= 1) set_prop_upward(s); @@ -373,7 +351,7 @@ namespace smt { final_check_status theory_array::final_check_eh() { m_final_check_idx++; - final_check_status r; + final_check_status r = FC_DONE; if (m_params.m_array_lazy_ieq) { // Delay the creation of interface equalities... The // motivation is too give other theories and quantifier diff --git a/src/smt/theory_array.h b/src/smt/theory_array.h index 4e45f77f2..3a013cf73 100644 --- a/src/smt/theory_array.h +++ b/src/smt/theory_array.h @@ -19,9 +19,9 @@ Revision History: #ifndef THEORY_ARRAY_H_ #define THEORY_ARRAY_H_ -#include"theory_array_base.h" -#include"theory_array_params.h" -#include"union_find.h" +#include "smt/theory_array_base.h" +#include "smt/params/theory_array_params.h" +#include "util/union_find.h" namespace smt { diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 6c47bf855..472053fdc 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -16,13 +16,13 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"theory_array_base.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" -#include"smt_model_generator.h" -#include"func_interp.h" -#include"ast_smt2_pp.h" +#include "smt/smt_context.h" +#include "smt/theory_array_base.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "smt/smt_model_generator.h" +#include "model/func_interp.h" +#include "ast/ast_smt2_pp.h" namespace smt { @@ -210,17 +210,15 @@ namespace smt { - func_decl_ref_vector * theory_array_base::register_sort(sort * s_array) { unsigned dimension = get_dimension(s_array); func_decl_ref_vector * ext_skolems = 0; if (!m_sort2skolem.find(s_array, ext_skolems)) { + array_util util(get_manager()); ast_manager & m = get_manager(); ext_skolems = alloc(func_decl_ref_vector, m); for (unsigned i = 0; i < dimension; ++i) { - sort * ext_sk_domain[2] = { s_array, s_array }; - parameter p(i); - func_decl * ext_sk_decl = m.mk_func_decl(get_id(), OP_ARRAY_EXT, 1, &p, 2, ext_sk_domain); + func_decl * ext_sk_decl = util.mk_array_ext(s_array, i); ext_skolems->push_back(ext_sk_decl); } m_sort2skolem.insert(s_array, ext_skolems); @@ -617,8 +615,8 @@ namespace smt { m_else_values.reset(); m_parents.reset(); m_parents.resize(num_vars, -1); - m_defaults.resize(num_vars, 0); - m_else_values.resize(num_vars, 0); + m_defaults.resize(num_vars); + m_else_values.resize(num_vars); if (m_use_unspecified_default) return; diff --git a/src/smt/theory_array_base.h b/src/smt/theory_array_base.h index e0d16f0f2..197ad9d2f 100644 --- a/src/smt/theory_array_base.h +++ b/src/smt/theory_array_base.h @@ -19,9 +19,9 @@ Revision History: #ifndef THEORY_ARRAY_BASE_H_ #define THEORY_ARRAY_BASE_H_ -#include"smt_theory.h" -#include"array_decl_plugin.h" -#include"array_factory.h" +#include "smt/smt_theory.h" +#include "ast/array_decl_plugin.h" +#include "smt/proto_model/array_factory.h" namespace smt { diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index a9dc657dd..274f89e8b 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -17,12 +17,13 @@ Revision History: --*/ -#include "smt_context.h" -#include "theory_array_full.h" -#include "ast_ll_pp.h" -#include "ast_pp.h" -#include "ast_smt2_pp.h" -#include "stats.h" +#include "smt/smt_context.h" +#include "smt/theory_array_full.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "ast/ast_smt2_pp.h" +#include "util/stats.h" namespace smt { @@ -515,7 +516,8 @@ namespace smt { expr_ref sel1(m), sel2(m); sel1 = mk_select(args1.size(), args1.c_ptr()); - m_simp->mk_app(f, args2.size(), args2.c_ptr(), sel2); + sel2 = m.mk_app(f, args2.size(), args2.c_ptr()); + ctx.get_rewriter()(sel2); ctx.internalize(sel1, false); ctx.internalize(sel2, false); @@ -536,6 +538,7 @@ namespace smt { SASSERT(is_map(mp)); app* map = mp->get_owner(); + ast_manager& m = get_manager(); context& ctx = get_context(); if (!ctx.add_fingerprint(this, 0, 1, &mp)) { return false; @@ -551,9 +554,9 @@ namespace smt { args2.push_back(mk_default(map->get_arg(i))); } + expr_ref def2(m.mk_app(f, args2.size(), args2.c_ptr()), m); + ctx.get_rewriter()(def2); expr* def1 = mk_default(map); - expr_ref def2(get_manager()); - m_simp->mk_app(f, args2.size(), args2.c_ptr(), def2); ctx.internalize(def1, false); ctx.internalize(def2, false); return try_assign_eq(def1, def2); @@ -722,9 +725,7 @@ namespace smt { } expr_ref eq(m); - simplifier_plugin* p = m_simp->get_plugin(m.get_basic_family_id()); - basic_simplifier_plugin* bp = static_cast(p); - bp->mk_and(eqs.size(), eqs.c_ptr(), eq); + eq = mk_and(eqs); expr* defA = mk_default(store_app->get_arg(0)); def2 = m.mk_ite(eq, store_app->get_arg(num_args-1), defA); #if 0 diff --git a/src/smt/theory_array_full.h b/src/smt/theory_array_full.h index 1200275a2..2cad3acbd 100644 --- a/src/smt/theory_array_full.h +++ b/src/smt/theory_array_full.h @@ -19,9 +19,8 @@ Revision History: #ifndef THEORY_ARRAY_FULL_H_ #define THEORY_ARRAY_FULL_H_ -#include "theory_array.h" -#include "simplifier.h" -#include "ast_trail.h" +#include "smt/theory_array.h" +#include "ast/ast_trail.h" namespace smt { @@ -37,7 +36,6 @@ namespace smt { ptr_vector m_var_data_full; ast2ast_trailmap m_sort2epsilon; - simplifier* m_simp; obj_pair_map m_eqs; svector m_eqsv; @@ -100,7 +98,6 @@ namespace smt { // the parent class is theory_array. // theory::init(ctx); theory_array::init(ctx); - m_simp = &ctx->get_simplifier(); } }; diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 255e2044f..ec3913415 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -16,19 +16,18 @@ Author: Revision History: --*/ -#include"smt_context.h" -#include"theory_bv.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" -#include"smt_model_generator.h" -#include"stats.h" +#include "smt/smt_context.h" +#include "smt/theory_bv.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "smt/smt_model_generator.h" +#include "util/stats.h" namespace smt { void theory_bv::init(context * ctx) { theory::init(ctx); - m_simplifier = &(ctx->get_simplifier()); } theory_var theory_bv::mk_var(enode * n) { @@ -300,7 +299,7 @@ namespace smt { void theory_bv::simplify_bit(expr * s, expr_ref & r) { // proof_ref p(get_manager()); // if (get_context().at_base_level()) - // m_simplifier->operator()(s, r, p); + // ctx.get_rewriter()(s, r, p); // else r = s; } @@ -605,8 +604,9 @@ namespace smt { args.push_back(m.mk_ite(b, n, zero)); num *= numeral(2); } - expr_ref sum(m); - arith_simp().mk_add(sz, args.c_ptr(), sum); + expr_ref sum(m_autil.mk_add(sz, args.c_ptr()), m); + arith_rewriter arw(m); + ctx.get_rewriter()(sum); literal l(mk_eq(n, sum, false)); TRACE("bv", tout << mk_pp(n, m) << "\n"; @@ -1366,7 +1366,6 @@ namespace smt { m_params(params), m_util(m), m_autil(m), - m_simplifier(0), m_bb(m, bb_params), m_trail_stack(*this), m_find(*this), diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index 50e4f9c30..c35078ace 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -19,16 +19,13 @@ Revision History: #ifndef THEORY_BV_H_ #define THEORY_BV_H_ -#include"smt_theory.h" -#include"theory_bv_params.h" -#include"bit_blaster.h" -#include"trail.h" -#include"union_find.h" -#include"simplifier.h" -#include"bv_simplifier_plugin.h" -#include"arith_decl_plugin.h" -#include"arith_simplifier_plugin.h" -#include"numeral_factory.h" +#include "smt/smt_theory.h" +#include "smt/params/theory_bv_params.h" +#include "ast/rewriter/bit_blaster/bit_blaster.h" +#include "util/trail.h" +#include "util/union_find.h" +#include "ast/arith_decl_plugin.h" +#include "smt/proto_model/numeral_factory.h" namespace smt { @@ -112,7 +109,6 @@ namespace smt { theory_bv_params const & m_params; bv_util m_util; arith_util m_autil; - simplifier * m_simplifier; bit_blaster m_bb; th_trail_stack m_trail_stack; th_union_find m_find; @@ -218,12 +214,6 @@ namespace smt { void assign_bit(literal consequent, theory_var v1, theory_var v2, unsigned idx, literal antecedent, bool propagate_eqc); void assert_int2bv_axiom(app* n); void assert_bv2int_axiom(app* n); - arith_simplifier_plugin & arith_simp() const { - SASSERT(m_simplifier != 0); - arith_simplifier_plugin * as = static_cast(m_simplifier->get_plugin(m_autil.get_family_id())); - SASSERT(as != 0); - return *as; - } protected: virtual void init(context * ctx); diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 8e140661b..bbed6840d 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -17,13 +17,13 @@ Revision History: --*/ -#include"smt_context.h" -#include"theory_datatype.h" -#include"smt_model_generator.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"stats.h" -#include"ast_smt2_pp.h" +#include "util/stats.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt2_pp.h" +#include "smt/smt_context.h" +#include "smt/theory_datatype.h" +#include "smt/smt_model_generator.h" namespace smt { @@ -97,12 +97,9 @@ namespace smt { SASSERT(m_util.is_datatype(get_manager().get_sort(n->get_owner()))); ast_manager & m = get_manager(); ptr_vector args; - ptr_vector const * accessors = m_util.get_constructor_accessors(c); - SASSERT(c->get_arity() == accessors->size()); - ptr_vector::const_iterator it = accessors->begin(); - ptr_vector::const_iterator end = accessors->end(); - for (; it != end; ++it) { - func_decl * d = *it; + ptr_vector const & accessors = *m_util.get_constructor_accessors(c); + SASSERT(c->get_arity() == accessors.size()); + for (func_decl * d : accessors) { SASSERT(d->get_arity() == 1); expr * acc = m.mk_app(d, n->get_owner()); args.push_back(acc); @@ -123,15 +120,14 @@ namespace smt { SASSERT(is_constructor(n)); ast_manager & m = get_manager(); func_decl * d = n->get_decl(); - ptr_vector const * accessors = m_util.get_constructor_accessors(d); - SASSERT(n->get_num_args() == accessors->size()); - ptr_vector::const_iterator it = accessors->begin(); - ptr_vector::const_iterator end = accessors->end(); - for (unsigned i = 0; it != end; ++it, ++i) { - func_decl * acc = *it; + ptr_vector const & accessors = *m_util.get_constructor_accessors(d); + SASSERT(n->get_num_args() == accessors.size()); + unsigned i = 0; + for (func_decl * acc : accessors) { app * acc_app = m.mk_app(acc, n->get_owner()); enode * arg = n->get_arg(i); assert_eq_axiom(arg, acc_app, null_literal); + ++i; } } @@ -172,15 +168,12 @@ namespace smt { func_decl * acc = to_func_decl(upd->get_parameter(0).get_ast()); func_decl * con = m_util.get_accessor_constructor(acc); func_decl * rec = m_util.get_constructor_recognizer(con); - ptr_vector const * accessors = m_util.get_constructor_accessors(con); - ptr_vector::const_iterator it = accessors->begin(); - ptr_vector::const_iterator end = accessors->end(); + ptr_vector const & accessors = *m_util.get_constructor_accessors(con); app_ref rec_app(m.mk_app(rec, arg1), m); ctx.internalize(rec_app, false); literal is_con(ctx.get_bool_var(rec_app)); - for (; it != end; ++it) { + for (func_decl* acc1 : accessors) { enode* arg; - func_decl * acc1 = *it; if (acc1 == acc) { arg = n->get_arg(1); } @@ -437,10 +430,7 @@ namespace smt { ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), r, 0, 0, m_used_eqs.size(), m_used_eqs.c_ptr()))); TRACE("occurs_check", tout << "occurs_check: true\n"; - enode_pair_vector::const_iterator it = m_used_eqs.begin(); - enode_pair_vector::const_iterator end = m_used_eqs.end(); - for(; it != end; ++it) { - enode_pair const & p = *it; + for (enode_pair const& p : m_used_eqs) { tout << "eq: #" << p.first->get_owner_id() << " #" << p.second->get_owner_id() << "\n"; tout << mk_bounded_pp(p.first->get_owner(), get_manager()) << " " << mk_bounded_pp(p.second->get_owner(), get_manager()) << "\n"; }); @@ -613,11 +603,9 @@ namespace smt { d1->m_constructor = d2->m_constructor; } } - ptr_vector::iterator it = d2->m_recognizers.begin(); - ptr_vector::iterator end = d2->m_recognizers.end(); - for (; it != end; ++it) - if (*it) - add_recognizer(v1, *it); + for (enode* e : d2->m_recognizers) + if (e) + add_recognizer(v1, e); } void theory_datatype::unmerge_eh(theory_var v1, theory_var v2) { @@ -632,7 +620,7 @@ namespace smt { sort * s = recognizer->get_decl()->get_domain(0); if (d->m_recognizers.empty()) { SASSERT(m_util.is_datatype(s)); - d->m_recognizers.resize(m_util.get_datatype_num_constructors(s), 0); + d->m_recognizers.resize(m_util.get_datatype_num_constructors(s)); } SASSERT(d->m_recognizers.size() == m_util.get_datatype_num_constructors(s)); unsigned c_idx = m_util.get_recognizer_constructor_idx(recognizer->get_decl()); @@ -721,8 +709,8 @@ namespace smt { enode * r = d->m_recognizers[unassigned_idx]; literal consequent; if (!r) { - ptr_vector const * constructors = m_util.get_datatype_constructors(dt); - func_decl * rec = m_util.get_constructor_recognizer(constructors->get(unassigned_idx)); + ptr_vector const & constructors = *m_util.get_datatype_constructors(dt); + func_decl * rec = m_util.get_constructor_recognizer(constructors[unassigned_idx]); app * rec_app = get_manager().mk_app(rec, n->get_owner()); ctx.internalize(rec_app, false); consequent = literal(ctx.get_bool_var(rec_app)); @@ -786,9 +774,9 @@ namespace smt { for (unsigned idx = 0; it != end; ++it, ++idx) { enode * curr = *it; if (curr == 0) { - ptr_vector const * constructors = m_util.get_datatype_constructors(s); + ptr_vector const & constructors = *m_util.get_datatype_constructors(s); // found empty slot... - r = m_util.get_constructor_recognizer(constructors->get(idx)); + r = m_util.get_constructor_recognizer(constructors[idx]); break; } else if (!ctx.is_relevant(curr)) { @@ -805,7 +793,7 @@ namespace smt { } SASSERT(r != 0); app * r_app = m.mk_app(r, n->get_owner()); - TRACE("datatype", tout << "creating split: " << mk_bounded_pp(r_app, m) << "\n";); + TRACE("datatype", tout << "creating split: " << mk_pp(r_app, m) << "\n";); ctx.internalize(r_app, false); bool_var bv = ctx.get_bool_var(r_app); ctx.set_true_first_flag(bv); diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index b97adacfe..20fa371fa 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -19,11 +19,11 @@ Revision History: #ifndef THEORY_DATATYPE_H_ #define THEORY_DATATYPE_H_ -#include"smt_theory.h" -#include"union_find.h" -#include"theory_datatype_params.h" -#include"datatype_decl_plugin.h" -#include"datatype_factory.h" +#include "smt/smt_theory.h" +#include "util/union_find.h" +#include "smt/params/theory_datatype_params.h" +#include "ast/datatype_decl_plugin.h" +#include "smt/proto_model/datatype_factory.h" namespace smt { diff --git a/src/smt/theory_dense_diff_logic.cpp b/src/smt/theory_dense_diff_logic.cpp index db2ffd38b..3d352ee84 100644 --- a/src/smt/theory_dense_diff_logic.cpp +++ b/src/smt/theory_dense_diff_logic.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"theory_dense_diff_logic_def.h" +#include "smt/theory_dense_diff_logic_def.h" namespace smt { template class theory_dense_diff_logic; diff --git a/src/smt/theory_dense_diff_logic.h b/src/smt/theory_dense_diff_logic.h index c2be89bc3..980830447 100644 --- a/src/smt/theory_dense_diff_logic.h +++ b/src/smt/theory_dense_diff_logic.h @@ -21,11 +21,11 @@ TODO: eager equality propagation #ifndef THEORY_DENSE_DIFF_LOGIC_H_ #define THEORY_DENSE_DIFF_LOGIC_H_ -#include"theory_arith.h" -#include"theory_arith_params.h" -#include"arith_decl_plugin.h" -#include"arith_eq_adapter.h" -#include"theory_opt.h" +#include "smt/theory_arith.h" +#include "smt/params/theory_arith_params.h" +#include "ast/arith_decl_plugin.h" +#include "smt/arith_eq_adapter.h" +#include "smt/theory_opt.h" namespace smt { diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index addb5d92b..78fb4d03d 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -19,12 +19,12 @@ Revision History: #ifndef THEORY_DENSE_DIFF_LOGIC_DEF_H_ #define THEORY_DENSE_DIFF_LOGIC_DEF_H_ -#include"smt_context.h" -#include"theory_dense_diff_logic.h" -#include"ast_pp.h" -#include"smt_model_generator.h" -#include"simplex.h" -#include"simplex_def.h" +#include "smt/smt_context.h" +#include "smt/theory_dense_diff_logic.h" +#include "ast/ast_pp.h" +#include "smt/smt_model_generator.h" +#include "math/simplex/simplex.h" +#include "math/simplex/simplex_def.h" namespace smt { @@ -127,7 +127,7 @@ namespace smt { if (!m_non_diff_logic_exprs) { TRACE("non_diff_logic", tout << "found non diff logic expression:\n" << mk_pp(n, get_manager()) << "\n";); get_context().push_trail(value_trail(m_non_diff_logic_exprs)); - IF_VERBOSE(0, verbose_stream() << "(smt.diff_logic: non-diff logic expression " << mk_pp(n, get_manager()) << ")\n";); + IF_VERBOSE(0, verbose_stream() << "(smt.diff_logic: non-diff logic expression " << mk_pp(n, get_manager()) << ")\n";); m_non_diff_logic_exprs = true; } } @@ -151,11 +151,15 @@ namespace smt { m_autil.is_numeral(rhs, _k); numeral offset(_k); app * s, * t; - if (m_autil.is_add(lhs) && to_app(lhs)->get_num_args() == 2 && is_times_minus_one(to_app(lhs)->get_arg(1), s)) { - t = to_app(to_app(lhs)->get_arg(0)); + expr *arg1, *arg2; + if (m_autil.is_add(lhs, arg1, arg2) && is_times_minus_one(arg2, s)) { + t = to_app(arg1); } - else if (m_autil.is_mul(lhs) && to_app(lhs)->get_num_args() == 2 && m_autil.is_minus_one(to_app(lhs)->get_arg(0))) { - s = to_app(to_app(lhs)->get_arg(1)); + else if (m_autil.is_add(lhs, arg1, arg2) && is_times_minus_one(arg1, s)) { + t = to_app(arg2); + } + else if (m_autil.is_mul(lhs, arg1, arg2) && m_autil.is_minus_one(arg1)) { + s = to_app(arg2); t = mk_zero_for(s); } else if (!m_autil.is_arith_expr(lhs)) { @@ -167,6 +171,7 @@ namespace smt { found_non_diff_logic_expr(n); return false; } + TRACE("arith", tout << expr_ref(lhs, get_manager()) << " " << expr_ref(s, get_manager()) << " " << expr_ref(t, get_manager()) << "\n";); source = internalize_term_core(s); target = internalize_term_core(t); if (source == null_theory_var || target == null_theory_var) { @@ -909,6 +914,8 @@ namespace smt { } verbose_stream() << " + " << m_objective_consts[v] << "\n";); + unsynch_mpq_manager mgr; + unsynch_mpq_inf_manager inf_mgr; unsigned num_nodes = get_num_vars(); unsigned num_edges = m_edges.size(); S.ensure_var(num_nodes + num_edges + m_objectives.size()); @@ -916,8 +923,9 @@ namespace smt { numeral const& a = m_assignment[i]; rational fin = a.get_rational().to_rational(); rational inf = a.get_infinitesimal().to_rational(); - mpq_inf q(fin.to_mpq(), inf.to_mpq()); + mpq_inf q(mgr.dup(fin.to_mpq()), mgr.dup(inf.to_mpq())); S.set_value(i, q); + inf_mgr.del(q); } for (unsigned i = 0; i < num_nodes; ++i) { enode * n = get_enode(i); @@ -928,7 +936,6 @@ namespace smt { } } svector vars; - unsynch_mpq_manager mgr; scoped_mpq_vector coeffs(mgr); coeffs.push_back(mpq(1)); coeffs.push_back(mpq(-1)); @@ -949,8 +956,9 @@ namespace smt { numeral const& w = e.m_offset; rational fin = w.get_rational().to_rational(); rational inf = w.get_infinitesimal().to_rational(); - mpq_inf q(fin.to_mpq(),inf.to_mpq()); + mpq_inf q(mgr.dup(fin.to_mpq()), mgr.dup(inf.to_mpq())); S.set_upper(base_var, q); + inf_mgr.del(q); } unsigned w = num_nodes + num_edges + v; diff --git a/src/smt/theory_diff_logic.cpp b/src/smt/theory_diff_logic.cpp index f1f00833b..1664dbfe2 100644 --- a/src/smt/theory_diff_logic.cpp +++ b/src/smt/theory_diff_logic.cpp @@ -17,11 +17,11 @@ Author: Revision History: --*/ -#include "theory_diff_logic.h" +#include "smt/theory_diff_logic.h" -#include"rational.h" -#include"theory_diff_logic_def.h" -#include"sparse_matrix_def.h" +#include "util/rational.h" +#include "smt/theory_diff_logic_def.h" +#include "math/simplex/sparse_matrix_def.h" namespace smt { diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index f47e61548..1ad239e58 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -22,24 +22,24 @@ Revision History: #ifndef THEORY_DIFF_LOGIC_H_ #define THEORY_DIFF_LOGIC_H_ -#include"rational.h" -#include"inf_rational.h" -#include"inf_int_rational.h" -#include"s_integer.h" -#include"inf_s_integer.h" -#include"smt_theory.h" -#include"diff_logic.h" -#include"arith_decl_plugin.h" -#include"smt_justification.h" -#include"map.h" -#include"smt_params.h" -#include"arith_eq_adapter.h" -#include"smt_model_generator.h" -#include"numeral_factory.h" -#include"smt_clause.h" -#include"theory_opt.h" -#include"simplex.h" -#include"simplex_def.h" +#include "util/rational.h" +#include "util/inf_rational.h" +#include "util/inf_int_rational.h" +#include "util/s_integer.h" +#include "util/inf_s_integer.h" +#include "smt/smt_theory.h" +#include "smt/diff_logic.h" +#include "ast/arith_decl_plugin.h" +#include "smt/smt_justification.h" +#include "util/map.h" +#include "smt/params/smt_params.h" +#include "smt/arith_eq_adapter.h" +#include "smt/smt_model_generator.h" +#include "smt/proto_model/numeral_factory.h" +#include "smt/smt_clause.h" +#include "smt/theory_opt.h" +#include "math/simplex/simplex.h" +#include "math/simplex/simplex_def.h" // The DL theory can represent term such as n + k, where n is an enode and k is a numeral. namespace smt { diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 372786c01..203dd24d2 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -22,13 +22,13 @@ Revision History: #ifndef THEORY_DIFF_LOGIC_DEF_H_ #define THEORY_DIFF_LOGIC_DEF_H_ -#include"theory_diff_logic.h" -#include"smt_context.h" -#include"map.h" -#include"ast_pp.h" -#include"warning.h" -#include"smt_model_generator.h" -#include"model_implicant.h" +#include "smt/theory_diff_logic.h" +#include "smt/smt_context.h" +#include "util/map.h" +#include "ast/ast_pp.h" +#include "util/warning.h" +#include "smt/smt_model_generator.h" +#include "model/model_implicant.h" using namespace smt; @@ -733,7 +733,6 @@ theory_var theory_diff_logic::mk_term(app* n) { source = mk_var(a); for (unsigned i = 0; i < n->get_num_args(); ++i) { expr* arg = n->get_arg(i); - std::cout << "internalize: " << mk_pp(arg, get_manager()) << " " << ctx.e_internalized(arg) << "\n"; if (!ctx.e_internalized(arg)) { ctx.internalize(arg, false); } @@ -1108,6 +1107,8 @@ unsigned theory_diff_logic::simplex2edge(unsigned e) { template void theory_diff_logic::update_simplex(Simplex& S) { + unsynch_mpq_manager mgr; + unsynch_mpq_inf_manager inf_mgr; unsigned num_nodes = m_graph.get_num_nodes(); vector > const& es = m_graph.get_all_edges(); S.ensure_var(num_simplex_vars()); @@ -1115,13 +1116,13 @@ void theory_diff_logic::update_simplex(Simplex& S) { numeral const& a = m_graph.get_assignment(i); rational fin = a.get_rational().to_rational(); rational inf = a.get_infinitesimal().to_rational(); - mpq_inf q(fin.to_mpq(), inf.to_mpq()); + mpq_inf q(mgr.dup(fin.to_mpq()), mgr.dup(inf.to_mpq())); S.set_value(node2simplex(i), q); + inf_mgr.del(q); } S.set_lower(node2simplex(get_zero()), mpq_inf(mpq(0), mpq(0))); S.set_upper(node2simplex(get_zero()), mpq_inf(mpq(0), mpq(0))); svector vars; - unsynch_mpq_manager mgr; scoped_mpq_vector coeffs(mgr); coeffs.push_back(mpq(1)); coeffs.push_back(mpq(-1)); @@ -1146,8 +1147,9 @@ void theory_diff_logic::update_simplex(Simplex& S) { numeral const& w = e.get_weight(); rational fin = w.get_rational().to_rational(); rational inf = w.get_infinitesimal().to_rational(); - mpq_inf q(fin.to_mpq(),inf.to_mpq()); + mpq_inf q(mgr.dup(fin.to_mpq()), mgr.dup(inf.to_mpq())); S.set_upper(base_var, q); + inf_mgr.del(q); } else { S.unset_upper(base_var); diff --git a/src/smt/theory_dl.cpp b/src/smt/theory_dl.cpp index 588b134b7..ea02121d9 100644 --- a/src/smt/theory_dl.cpp +++ b/src/smt/theory_dl.cpp @@ -22,14 +22,14 @@ Revision History: --*/ -#include "smt_theory.h" -#include "dl_decl_plugin.h" -#include "value_factory.h" -#include "smt_model_generator.h" -#include "bv_decl_plugin.h" -#include "theory_bv.h" -#include "smt_context.h" -#include "ast_pp.h" +#include "smt/smt_theory.h" +#include "ast/dl_decl_plugin.h" +#include "smt/proto_model/value_factory.h" +#include "smt/smt_model_generator.h" +#include "ast/bv_decl_plugin.h" +#include "smt/theory_bv.h" +#include "smt/smt_context.h" +#include "ast/ast_pp.h" // Basic approach: reduce theory to bit-vectors: // diff --git a/src/smt/theory_dummy.cpp b/src/smt/theory_dummy.cpp index c8b9c3b0a..d1695134e 100644 --- a/src/smt/theory_dummy.cpp +++ b/src/smt/theory_dummy.cpp @@ -17,8 +17,8 @@ Revision History: --*/ -#include"smt_context.h" -#include"theory_dummy.h" +#include "smt/smt_context.h" +#include "smt/theory_dummy.h" namespace smt { diff --git a/src/smt/theory_dummy.h b/src/smt/theory_dummy.h index fc25fc0b7..b20d86270 100644 --- a/src/smt/theory_dummy.h +++ b/src/smt/theory_dummy.h @@ -19,7 +19,7 @@ Revision History: #ifndef THEORY_DUMMY_H_ #define THEORY_DUMMY_H_ -#include"smt_theory.h" +#include "smt/smt_theory.h" namespace smt { diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index a3bf77180..cc9b0017d 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -16,12 +16,12 @@ Author: Revision History: --*/ -#include"ast_smt2_pp.h" -#include"smt_context.h" -#include"theory_fpa.h" -#include"theory_bv.h" -#include"smt_model_generator.h" -#include"bv2fpa_converter.h" +#include "ast/ast_smt2_pp.h" +#include "smt/smt_context.h" +#include "smt/theory_fpa.h" +#include "smt/theory_bv.h" +#include "smt/smt_model_generator.h" +#include "ast/fpa/bv2fpa_converter.h" namespace smt { @@ -119,6 +119,7 @@ namespace smt { SASSERT(m_conversions.empty()); SASSERT(m_is_added_to_model.empty()); } + void theory_fpa::init(context * ctx) { smt::theory::init(ctx); m_is_initialized = true; @@ -237,8 +238,9 @@ namespace smt { if (m_fpa_util.is_fp(e)) { expr * cargs[3] = { to_app(e)->get_arg(0), to_app(e)->get_arg(1), to_app(e)->get_arg(2) }; - res = m_bv_util.mk_concat(3, cargs); - m_th_rw((expr_ref&)res); + expr_ref tmp(m_bv_util.mk_concat(3, cargs), m); + m_th_rw(tmp); + res = to_app(tmp); } else { sort * es = m.get_sort(e); @@ -254,7 +256,7 @@ namespace smt { } func_decl_ref wrap_fd(m); - wrap_fd = m.mk_func_decl(get_family_id(), OP_FPA_INTERNAL_BVWRAP, 0, 0, 1, &es, bv_srt); + wrap_fd = m.mk_func_decl(get_family_id(), OP_FPA_BVWRAP, 0, 0, 1, &es, bv_srt); res = m.mk_app(wrap_fd, e); } @@ -384,7 +386,6 @@ namespace smt { { ast_manager & m = get_manager(); context & ctx = get_context(); - simplifier & simp = ctx.get_simplifier(); expr_ref res(m), t(m); proof_ref t_pr(m); @@ -393,7 +394,7 @@ namespace smt { expr_ref_vector::iterator it = m_converter.m_extra_assertions.begin(); expr_ref_vector::iterator end = m_converter.m_extra_assertions.end(); for (; it != end; it++) { - simp(*it, t, t_pr); + ctx.get_rewriter()(*it, t, t_pr); res = m.mk_and(res, t); } m_converter.m_extra_assertions.reset(); @@ -883,26 +884,4 @@ namespace smt { out << r->get_id() << " --> " << mk_ismt2_pp(n, m) << std::endl; } } - - bool theory_fpa::include_func_interp(func_decl * f) { - TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;); - - if (f->get_family_id() == get_family_id()) { - bool include = - m_fpa_util.is_min_unspecified(f) || - m_fpa_util.is_max_unspecified(f) || - m_fpa_util.is_to_ubv_unspecified(f) || - m_fpa_util.is_to_sbv_unspecified(f) || - m_fpa_util.is_to_ieee_bv_unspecified(f) || - m_fpa_util.is_to_real_unspecified(f); - if (include && !m_is_added_to_model.contains(f)) { - m_is_added_to_model.insert(f); - get_manager().inc_ref(f); - return true; - } - return false; - } - else - return true; - } }; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 998f2be3c..9e9801ee0 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -19,13 +19,13 @@ Revision History: #ifndef THEORY_FPA_H_ #define THEORY_FPA_H_ -#include"smt_theory.h" -#include"trail.h" -#include"fpa2bv_converter.h" -#include"fpa2bv_rewriter.h" -#include"th_rewriter.h" -#include"value_factory.h" -#include"smt_model_generator.h" +#include "smt/smt_theory.h" +#include "util/trail.h" +#include "ast/fpa/fpa2bv_converter.h" +#include "ast/fpa/fpa2bv_rewriter.h" +#include "ast/rewriter/th_rewriter.h" +#include "smt/proto_model/value_factory.h" +#include "smt/smt_model_generator.h" namespace smt { @@ -82,7 +82,7 @@ namespace smt { m_th(*th) {} virtual ~fpa2bv_converter_wrapped() {} 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); }; class fpa_value_proc : public model_value_proc { @@ -108,7 +108,7 @@ namespace smt { result.append(m_deps); } - virtual app * mk_value(model_generator & mg, ptr_vector & values); + virtual app * mk_value(model_generator & mg, ptr_vector & values); }; class fpa_rm_value_proc : public model_value_proc { @@ -158,7 +158,6 @@ namespace smt { virtual char const * get_name() const { return "fpa"; } virtual model_value_proc * mk_value(enode * n, model_generator & mg); - virtual bool include_func_interp(func_decl * f); void assign_eh(bool_var v, bool is_true); virtual void relevant_eh(app * n); @@ -179,9 +178,6 @@ namespace smt { expr_ref convert_atom(expr * e); expr_ref convert_term(expr * e); expr_ref convert_conversion_term(expr * e); - expr_ref convert_unwrap(expr * e); - - void add_trail(ast * a); void attach_new_th_var(enode * n); void assert_cnstr(expr * e); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 9e4f544c1..292d2ab0d 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -26,8 +26,9 @@ Revision History: #include "util/lp/lar_solver.h" #include "util/nat_set.h" #include "util/optional.h" -#include "lp_params.hpp" +#include "util/lp/lp_params.hpp" #include "util/inf_rational.h" +#include "ast/ast_pp.h" #include "smt/smt_theory.h" #include "smt/smt_context.h" #include "smt/theory_lra.h" @@ -37,7 +38,7 @@ Revision History: #include "util/nat_set.h" #include "tactic/filter_model_converter.h" -namespace lp { +namespace lra_lp { enum bound_kind { lower_t, upper_t }; std::ostream& operator<<(std::ostream& out, bound_kind const& k) { @@ -48,8 +49,8 @@ namespace lp { return out; } - class bound { - smt::bool_var m_bv; + class bound { + smt::bool_var m_bv; smt::theory_var m_var; rational m_value; bound_kind m_bound_kind; @@ -66,11 +67,11 @@ namespace lp { smt::bool_var get_bv() const { return m_bv; } bound_kind get_bound_kind() const { return m_bound_kind; } rational const& get_value() const { return m_value; } - inf_rational get_value(bool is_true) const { + inf_rational get_value(bool is_true) const { if (is_true) return inf_rational(m_value); // v >= value or v <= value if (m_bound_kind == lower_t) return inf_rational(m_value, false); // v <= value - epsilon return inf_rational(m_value, true); // v >= value + epsilon - } + } virtual std::ostream& display(std::ostream& out) const { return out << "v" << get_var() << " " << get_bound_kind() << " " << m_value; } @@ -110,13 +111,13 @@ namespace lp { namespace smt { - typedef ptr_vector lp_bounds; - - class theory_lra::imp { + typedef ptr_vector lp_bounds; + + class theory_lra::imp { struct scope { unsigned m_bounds_lim; - unsigned m_asserted_qhead; + unsigned m_asserted_qhead; unsigned m_asserted_atoms_lim; unsigned m_delayed_terms_lim; unsigned m_delayed_equalities_lim; @@ -132,7 +133,7 @@ namespace smt { delayed_atom(unsigned b, bool t): m_bv(b), m_is_true(t) {} }; - class resource_limit : public lean::lp_resource_limit { + class resource_limit : public lp::lp_resource_limit { imp& m_imp; public: resource_limit(imp& i): m_imp(i) { } @@ -150,7 +151,7 @@ namespace smt { vector m_columns; // temporary values kept during internalization struct internalize_state { - expr_ref_vector m_terms; + expr_ref_vector m_terms; vector m_coeffs; svector m_vars; rational m_coeff; @@ -182,22 +183,22 @@ namespace smt { public: scoped_internalize_state(imp& i): m_imp(i), m_st(push_internalize(i)) {} ~scoped_internalize_state() { --m_imp.m_internalize_head; } - expr_ref_vector& terms() { return m_st.m_terms; } + expr_ref_vector& terms() { return m_st.m_terms; } vector& coeffs() { return m_st.m_coeffs; } svector& vars() { return m_st.m_vars; } rational& coeff() { return m_st.m_coeff; } - ptr_vector& terms_to_internalize() { return m_st.m_terms_to_internalize; } + ptr_vector& terms_to_internalize() { return m_st.m_terms_to_internalize; } void push(expr* e, rational c) { m_st.m_terms.push_back(e); m_st.m_coeffs.push_back(c); } - void set_back(unsigned i) { + void set_back(unsigned i) { if (terms().size() == i + 1) return; - terms()[i] = terms().back(); + terms()[i] = terms().back(); coeffs()[i] = coeffs().back(); terms().pop_back(); coeffs().pop_back(); } }; - - typedef vector> var_coeffs; + + typedef vector> var_coeffs; struct delayed_def { vector m_coeffs; svector m_vars; @@ -207,11 +208,11 @@ namespace smt { m_coeffs(coeffs), m_vars(vars), m_coeff(r), m_var(v) {} }; - svector m_theory_var2var_index; // translate from theory variables to lar vars - svector m_var_index2theory_var; // reverse map from lp_solver variables to theory variables - svector m_term_index2theory_var; // reverse map from lp_solver variables to theory variables + svector m_theory_var2var_index; // translate from theory variables to lar vars + svector m_var_index2theory_var; // reverse map from lp_solver variables to theory variables + svector m_term_index2theory_var; // reverse map from lp_solver variables to theory variables var_coeffs m_left_side; // constraint left side - mutable std::unordered_map m_variable_values; // current model + mutable std::unordered_map m_variable_values; // current model enum constraint_source { inequality_source, @@ -225,17 +226,17 @@ namespace smt { svector m_definitions; // asserted rows corresponding to definitions bool m_delay_constraints; // configuration - svector m_asserted_atoms; - app_ref_vector m_delayed_terms; + svector m_asserted_atoms; + app_ref_vector m_delayed_terms; svector> m_delayed_equalities; vector m_delayed_defs; expr* m_not_handled; ptr_vector m_underspecified; unsigned_vector m_var_trail; - vector > m_use_list; // bounds where variables are used. + vector > m_use_list; // bounds where variables are used. // attributes for incremental version: - u_map m_bool_var2bound; + u_map m_bool_var2bound; vector m_bounds; unsigned_vector m_unassigned_bounds; unsigned_vector m_bounds_trail; @@ -243,7 +244,7 @@ namespace smt { svector m_to_check; // rows that should be checked for theory propagation - svector > m_assume_eq_candidates; + svector > m_assume_eq_candidates; unsigned m_assume_eq_head; unsigned m_num_conflicts; @@ -257,15 +258,15 @@ namespace smt { struct var_value_hash { imp & m_th; var_value_hash(imp & th):m_th(th) {} - unsigned operator()(theory_var v) const { return (unsigned)std::hash()(m_th.get_ivalue(v)); } + unsigned operator()(theory_var v) const { return (unsigned)std::hash()(m_th.get_ivalue(v)); } }; int_hashtable m_model_eqs; svector m_scopes; - lp::stats m_stats; - arith_factory* m_factory; - scoped_ptr m_solver; + lra_lp::stats m_stats; + arith_factory* m_factory; + scoped_ptr m_solver; resource_limit m_resource_limit; lp_bounds m_new_bounds; @@ -276,15 +277,15 @@ namespace smt { bool is_int(enode* n) const { return a.is_int(n->get_owner()); } enode* get_enode(theory_var v) const { return th.get_enode(v); } enode* get_enode(expr* e) const { return ctx().get_enode(e); } - expr* get_owner(theory_var v) const { return get_enode(v)->get_owner(); } + expr* get_owner(theory_var v) const { return get_enode(v)->get_owner(); } void init_solver() { if (m_solver) return; lp_params lp(ctx().get_params()); - m_solver = alloc(lean::lar_solver); + m_solver = alloc(lp::lar_solver); m_theory_var2var_index.reset(); m_solver->settings().set_resource_limit(m_resource_limit); - m_solver->settings().simplex_strategy() = static_cast(lp.simplex_strategy()); + m_solver->settings().simplex_strategy() = static_cast(lp.simplex_strategy()); reset_variable_values(); m_solver->settings().bound_propagation() = BP_NONE != propagation_mode(); m_solver->set_propagate_bounds_on_pivoted_rows_mode(lp.bprop_on_pivoted_rows()); @@ -292,9 +293,6 @@ namespace smt { } void found_not_handled(expr* n) { - if (a.is_div0(n)) { - return; - } m_not_handled = n; if (is_app(n) && is_underspecified(to_app(n))) { m_underspecified.push_back(to_app(n)); @@ -315,7 +313,7 @@ namespace smt { } if (a.is_to_real(term, term)) { continue; - } + } return false; } while (false); @@ -325,15 +323,15 @@ namespace smt { void linearize_term(expr* term, scoped_internalize_state& st) { st.push(term, rational::one()); linearize(st); - } - + } + void linearize_ineq(expr* lhs, expr* rhs, scoped_internalize_state& st) { st.push(lhs, rational::one()); st.push(rhs, rational::minus_one()); linearize(st); } - - void linearize(scoped_internalize_state& st) { + + void linearize(scoped_internalize_state& st) { expr_ref_vector & terms = st.terms(); svector& vars = st.vars(); vector& coeffs = st.coeffs(); @@ -354,7 +352,7 @@ namespace smt { } else if (a.is_sub(n)) { unsigned sz = to_app(n)->get_num_args(); - terms[index] = to_app(n)->get_arg(0); + terms[index] = to_app(n)->get_arg(0); for (unsigned i = 1; i < sz; ++i) { st.push(to_app(n)->get_arg(i), -coeffs[index]); } @@ -379,7 +377,12 @@ namespace smt { } else if (is_app(n) && a.get_family_id() == to_app(n)->get_family_id()) { app* t = to_app(n); - found_not_handled(n); + if (a.is_div(n, n1, n2) && is_numeral(n2, r)) { + // skip + } + else { + found_not_handled(n); + } internalize_args(t); mk_enode(t); theory_var v = mk_var(n); @@ -423,7 +426,7 @@ namespace smt { return get_enode(n); } else { - return ctx().mk_enode(n, !reflect(n), false, enable_cgc_for(n)); + return ctx().mk_enode(n, !reflect(n), false, enable_cgc_for(n)); } } @@ -459,12 +462,12 @@ namespace smt { } bool reflect(app* n) const { - return m_arith_params.m_arith_reflect || is_underspecified(n); + return m_arith_params.m_arith_reflect || is_underspecified(n); } theory_var mk_var(expr* n, bool internalize = true) { if (!ctx().e_internalized(n)) { - ctx().internalize(n, false); + ctx().internalize(n, false); } enode* e = get_enode(n); theory_var v; @@ -478,14 +481,14 @@ namespace smt { ctx().attach_th_var(e, &th, v); } else { - v = e->get_th_var(get_id()); + v = e->get_th_var(get_id()); } SASSERT(null_theory_var != v); return v; } - - lean::var_index get_var_index(theory_var v) { - lean::var_index result = UINT_MAX; + + lp::var_index get_var_index(theory_var v) { + lp::var_index result = UINT_MAX; if (m_theory_var2var_index.size() > static_cast(v)) { result = m_theory_var2var_index[v]; } @@ -497,7 +500,7 @@ namespace smt { } return result; } - + void init_left_side(scoped_internalize_state& st) { SASSERT(all_zeros(m_columns)); svector const& vars = st.vars(); @@ -510,7 +513,7 @@ namespace smt { } else { m_columns[var] += coeff; - } + } } m_left_side.clear(); // reset the coefficients after they have been used. @@ -519,12 +522,12 @@ namespace smt { rational const& r = m_columns[var]; if (!r.is_zero()) { m_left_side.push_back(std::make_pair(r, get_var_index(var))); - m_columns[var].reset(); + m_columns[var].reset(); } } SASSERT(all_zeros(m_columns)); } - + bool all_zeros(vector const& v) const { for (unsigned i = 0; i < v.size(); ++i) { if (!v[i].is_zero()) { @@ -533,21 +536,21 @@ namespace smt { } return true; } - - void add_eq_constraint(lean::constraint_index index, enode* n1, enode* n2) { + + void add_eq_constraint(lp::constraint_index index, enode* n1, enode* n2) { m_constraint_sources.setx(index, equality_source, null_source); m_equalities.setx(index, enode_pair(n1, n2), enode_pair(0, 0)); ++m_stats.m_add_rows; } - - void add_ineq_constraint(lean::constraint_index index, literal lit) { + + void add_ineq_constraint(lp::constraint_index index, literal lit) { m_constraint_sources.setx(index, inequality_source, null_source); m_inequalities.setx(index, lit, null_literal); ++m_stats.m_add_rows; TRACE("arith", m_solver->print_constraint(index, tout); tout << "\n";); } - - void add_def_constraint(lean::constraint_index index, theory_var v) { + + void add_def_constraint(lp::constraint_index index, theory_var v) { m_constraint_sources.setx(index, definition_source, null_source); m_definitions.setx(index, v, null_theory_var); ++m_stats.m_add_rows; @@ -556,12 +559,12 @@ namespace smt { void internalize_eq(delayed_def const& d) { scoped_internalize_state st(*this); st.vars().append(d.m_vars); - st.coeffs().append(d.m_coeffs); + st.coeffs().append(d.m_coeffs); init_left_side(st); - add_def_constraint(m_solver->add_constraint(m_left_side, lean::EQ, -d.m_coeff), d.m_var); + add_def_constraint(m_solver->add_constraint(m_left_side, lp::EQ, -d.m_coeff), d.m_var); } - - void internalize_eq(theory_var v1, theory_var v2) { + + void internalize_eq(theory_var v1, theory_var v2) { enode* n1 = get_enode(v1); enode* n2 = get_enode(v2); scoped_internalize_state st(*this); @@ -570,8 +573,8 @@ namespace smt { st.coeffs().push_back(rational::one()); st.coeffs().push_back(rational::minus_one()); init_left_side(st); - add_eq_constraint(m_solver->add_constraint(m_left_side, lean::EQ, rational::zero()), n1, n2); - TRACE("arith", + add_eq_constraint(m_solver->add_constraint(m_left_side, lp::EQ, rational::zero()), n1, n2); + TRACE("arith", tout << "v" << v1 << " = " << "v" << v2 << ": " << mk_pp(n1->get_owner(), m) << " = " << mk_pp(n2->get_owner(), m) << "\n";); } @@ -580,10 +583,10 @@ namespace smt { for (unsigned i = m_bounds_trail.size(); i > old_size; ) { --i; unsigned v = m_bounds_trail[i]; - lp::bound* b = m_bounds[v].back(); + lra_lp::bound* b = m_bounds[v].back(); // del_use_lists(b); dealloc(b); - m_bounds[v].pop_back(); + m_bounds[v].pop_back(); } m_bounds_trail.shrink(old_size); } @@ -591,9 +594,9 @@ namespace smt { void updt_unassigned_bounds(theory_var v, int inc) { TRACE("arith", tout << "v" << v << " " << m_unassigned_bounds[v] << " += " << inc << "\n";); ctx().push_trail(vector_value_trail(m_unassigned_bounds, v)); - m_unassigned_bounds[v] += inc; + m_unassigned_bounds[v] += inc; } - + bool is_unit_var(scoped_internalize_state& st) { return st.coeff().is_zero() && st.vars().size() == 1 && st.coeffs()[0].is_one(); } @@ -623,7 +626,7 @@ namespace smt { else { init_left_side(st); theory_var v = mk_var(term); - lean::var_index vi = m_theory_var2var_index.get(v, UINT_MAX); + lp::var_index vi = m_theory_var2var_index.get(v, UINT_MAX); if (vi == UINT_MAX) { vi = m_solver->add_term(m_left_side, st.coeff()); m_theory_var2var_index.setx(v, vi, UINT_MAX); @@ -644,26 +647,26 @@ namespace smt { return v; } } - + public: - imp(theory_lra& th, ast_manager& m, theory_arith_params& ap): - th(th), m(m), - m_arith_params(ap), - a(m), - m_arith_eq_adapter(th, ap, a), + imp(theory_lra& th, ast_manager& m, theory_arith_params& ap): + th(th), m(m), + m_arith_params(ap), + a(m), + m_arith_eq_adapter(th, ap, a), m_internalize_head(0), - m_delay_constraints(false), + m_delay_constraints(false), m_delayed_terms(m), m_not_handled(0), - m_asserted_qhead(0), + m_asserted_qhead(0), m_assume_eq_head(0), m_num_conflicts(0), m_model_eqs(DEFAULT_HASHTABLE_INITIAL_CAPACITY, var_value_hash(*this), var_value_eq(*this)), m_solver(0), m_resource_limit(*this) { } - + ~imp() { del_bounds(0); std::for_each(m_internalize_states.begin(), m_internalize_states.end(), delete_proc()); @@ -672,7 +675,7 @@ namespace smt { void init(context* ctx) { init_solver(); } - + bool internalize_atom(app * atom, bool gate_ctx) { if (m_delay_constraints) { return internalize_atom_lazy(atom, gate_ctx); @@ -686,24 +689,24 @@ namespace smt { SASSERT(!ctx().b_internalized(atom)); bool_var bv = ctx().mk_bool_var(atom); ctx().set_var_theory(bv, get_id()); - expr* n1, *n2; + expr* n1 = 0, *n2 = 0; rational r; - lp::bound_kind k; + lra_lp::bound_kind k; theory_var v = null_theory_var; if (a.is_le(atom, n1, n2) && is_numeral(n2, r) && is_app(n1)) { v = internalize_def(to_app(n1)); - k = lp::upper_t; + k = lra_lp::upper_t; } else if (a.is_ge(atom, n1, n2) && is_numeral(n2, r) && is_app(n1)) { v = internalize_def(to_app(n1)); - k = lp::lower_t; - } + k = lra_lp::lower_t; + } else { TRACE("arith", tout << "Could not internalize " << mk_pp(atom, m) << "\n";); found_not_handled(atom); return true; } - lp::bound* b = alloc(lp::bound, bv, v, r, k); + lra_lp::bound* b = alloc(lra_lp::bound, bv, v, r, k); m_bounds[v].push_back(b); updt_unassigned_bounds(v, +1); m_bounds_trail.push_back(v); @@ -718,36 +721,36 @@ namespace smt { SASSERT(!ctx().b_internalized(atom)); bool_var bv = ctx().mk_bool_var(atom); ctx().set_var_theory(bv, get_id()); - expr* n1, *n2; + expr* n1 = 0, *n2 = 0; rational r; - lp::bound_kind k; + lra_lp::bound_kind k; theory_var v = null_theory_var; scoped_internalize_state st(*this); if (a.is_le(atom, n1, n2) && is_numeral(n2, r) && is_app(n1)) { v = internalize_def(to_app(n1), st); - k = lp::upper_t; + k = lra_lp::upper_t; } else if (a.is_ge(atom, n1, n2) && is_numeral(n2, r) && is_app(n1)) { v = internalize_def(to_app(n1), st); - k = lp::lower_t; - } + k = lra_lp::lower_t; + } else { TRACE("arith", tout << "Could not internalize " << mk_pp(atom, m) << "\n";); found_not_handled(atom); return true; } - lp::bound* b = alloc(lp::bound, bv, v, r, k); + lra_lp::bound* b = alloc(lra_lp::bound, bv, v, r, k); m_bounds[v].push_back(b); updt_unassigned_bounds(v, +1); m_bounds_trail.push_back(v); m_bool_var2bound.insert(bv, b); TRACE("arith", tout << "Internalized " << mk_pp(atom, m) << "\n";); if (!is_unit_var(st) && m_bounds[v].size() == 1) { - m_delayed_defs.push_back(delayed_def(st.vars(), st.coeffs(), st.coeff(), v)); + m_delayed_defs.push_back(delayed_def(st.vars(), st.coeffs(), st.coeff(), v)); } return true; } - + bool internalize_term(app * term) { if (ctx().e_internalized(term) && th.is_attached_to_var(ctx().get_enode(term))) { // skip @@ -766,7 +769,7 @@ namespace smt { } return true; } - + void internalize_eq_eh(app * atom, bool_var) { expr* lhs = 0, *rhs = 0; VERIFY(m.is_eq(atom, lhs, rhs)); @@ -827,7 +830,7 @@ namespace smt { unsigned old_size = m_scopes.size() - num_scopes; del_bounds(m_scopes[old_size].m_bounds_lim); for (unsigned i = m_scopes[old_size].m_var_trail_lim; i < m_var_trail.size(); ++i) { - lean::var_index vi = m_theory_var2var_index[m_var_trail[i]]; + lp::var_index vi = m_theory_var2var_index[m_var_trail[i]]; if (m_solver->is_term(vi)) { unsigned ti = m_solver->adjust_term_index(vi); m_term_index2theory_var[ti] = UINT_MAX; @@ -845,7 +848,7 @@ namespace smt { m_underspecified.shrink(m_scopes[old_size].m_underspecified_lim); m_var_trail.shrink(m_scopes[old_size].m_var_trail_lim); m_not_handled = m_scopes[old_size].m_not_handled; - m_scopes.resize(old_size); + m_scopes.resize(old_size); if (!m_delay_constraints) m_solver->pop(num_scopes); // VERIFY(l_false != make_feasible()); m_new_bounds.reset(); @@ -859,17 +862,17 @@ namespace smt { void relevant_eh(app* n) { TRACE("arith", tout << mk_pp(n, m) << "\n";); - expr* n1, *n2; - if (a.is_mod(n, n1, n2)) + expr* n1 = 0, *n2 = 0; + if (a.is_mod(n, n1, n2)) mk_idiv_mod_axioms(n1, n2); else if (a.is_rem(n, n1, n2)) mk_rem_axiom(n1, n2); - else if (a.is_div(n, n1, n2)) + else if (a.is_div(n, n1, n2)) mk_div_axiom(n1, n2); - else if (a.is_to_int(n)) + else if (a.is_to_int(n)) mk_to_int_axiom(n); else if (a.is_is_int(n)) - mk_is_int_axiom(n); + mk_is_int_axiom(n); } // n < 0 || rem(a, n) = mod(a, n) @@ -881,7 +884,7 @@ namespace smt { expr_ref mmod(a.mk_uminus(mod), m); literal dgez = mk_literal(a.mk_ge(divisor, zero)); mk_axiom(~dgez, th.mk_eq(rem, mod, false)); - mk_axiom( dgez, th.mk_eq(rem, mmod, false)); + mk_axiom( dgez, th.mk_eq(rem, mmod, false)); } // q = 0 or q * (p div q) = p @@ -896,7 +899,7 @@ namespace smt { // to_real(to_int(x)) <= x < to_real(to_int(x)) + 1 void mk_to_int_axiom(app* n) { expr* x = 0, *y = 0; - VERIFY (a.is_to_int(n, x)); + VERIFY (a.is_to_int(n, x)); if (a.is_to_real(x, y)) { mk_axiom(th.mk_eq(y, n, false)); } @@ -945,7 +948,7 @@ namespace smt { mk_axiom(q_le_0, ~mk_literal(a.mk_ge(a.mk_sub(mod, q), zero))); mk_axiom(q_ge_0, ~mk_literal(a.mk_ge(a.mk_add(mod, q), zero))); rational k; - if (m_arith_params.m_arith_enum_const_mod && a.is_numeral(q, k) && + if (m_arith_params.m_arith_enum_const_mod && a.is_numeral(q, k) && k.is_pos() && k < rational(8)) { unsigned _k = k.get_unsigned(); literal_buffer lits; @@ -954,8 +957,8 @@ namespace smt { lits.push_back(mod_j); ctx().mark_as_relevant(mod_j); } - ctx().mk_th_axiom(get_id(), lits.size(), lits.begin()); - } + ctx().mk_th_axiom(get_id(), lits.size(), lits.begin()); + } } void mk_axiom(literal l) { @@ -1006,43 +1009,43 @@ namespace smt { } bool can_get_value(theory_var v) const { - return + return (v != null_theory_var) && - (v < static_cast(m_theory_var2var_index.size())) && - (UINT_MAX != m_theory_var2var_index[v]) && + (v < static_cast(m_theory_var2var_index.size())) && + (UINT_MAX != m_theory_var2var_index[v]) && (m_solver->is_term(m_theory_var2var_index[v]) || m_variable_values.count(m_theory_var2var_index[v]) > 0); } - + bool can_get_ivalue(theory_var v) const { if (v == null_theory_var || (v >= static_cast(m_theory_var2var_index.size()))) return false; return m_solver->var_is_registered(m_theory_var2var_index[v]); } - lean::impq get_ivalue(theory_var v) const { - lean_assert(can_get_ivalue(v)); - lean::var_index vi = m_theory_var2var_index[v]; + lp::impq get_ivalue(theory_var v) const { + SASSERT(can_get_ivalue(v)); + lp::var_index vi = m_theory_var2var_index[v]; if (!m_solver->is_term(vi)) return m_solver->get_value(vi); - const lean::lar_term& term = m_solver->get_term(vi); - lean::impq result(term.m_v); + const lp::lar_term& term = m_solver->get_term(vi); + lp::impq result(term.m_v); for (const auto & i: term.m_coeffs) { result += m_solver->get_value(i.first) * i.second; } return result; } - + rational get_value(theory_var v) const { if (!can_get_value(v)) return rational::zero(); - lean::var_index vi = m_theory_var2var_index[v]; + lp::var_index vi = m_theory_var2var_index[v]; if (m_variable_values.count(vi) > 0) { return m_variable_values[vi]; } if (m_solver->is_term(vi)) { - const lean::lar_term& term = m_solver->get_term(vi); + const lp::lar_term& term = m_solver->get_term(vi); rational result = term.m_v; for (auto i = term.m_coeffs.begin(); i != term.m_coeffs.end(); ++i) { result += m_variable_values[i->first] * i->second; @@ -1051,7 +1054,7 @@ namespace smt { return result; } UNREACHABLE(); - return m_variable_values[vi]; + return m_variable_values[vi]; } void init_variable_values() { @@ -1064,20 +1067,20 @@ namespace smt { m_variable_values.clear(); } - bool assume_eqs() { - svector vars; + bool assume_eqs() { + svector vars; theory_var sz = static_cast(th.get_num_vars()); for (theory_var v = 0; v < sz; ++v) { - if (th.is_relevant_and_shared(get_enode(v))) { + if (th.is_relevant_and_shared(get_enode(v))) { vars.push_back(m_theory_var2var_index[v]); } } if (vars.empty()) { return false; } - TRACE("arith", + TRACE("arith", for (theory_var v = 0; v < sz; ++v) { - if (th.is_relevant_and_shared(get_enode(v))) { + if (th.is_relevant_and_shared(get_enode(v))) { tout << "v" << v << " " << m_theory_var2var_index[v] << " "; } } @@ -1086,14 +1089,14 @@ namespace smt { m_solver->random_update(vars.size(), vars.c_ptr()); m_model_eqs.reset(); TRACE("arith", display(tout);); - + unsigned old_sz = m_assume_eq_candidates.size(); bool result = false; int start = ctx().get_random_value(); for (theory_var i = 0; i < sz; ++i) { theory_var v = (i + start) % sz; enode* n1 = get_enode(v); - if (!th.is_relevant_and_shared(n1)) { + if (!th.is_relevant_and_shared(n1)) { continue; } if (!can_get_ivalue(v)) { @@ -1112,7 +1115,7 @@ namespace smt { result = true; } } - + if (result) { ctx().push_trail(restore_size_trail, false>(m_assume_eq_candidates, old_sz)); } @@ -1123,7 +1126,7 @@ namespace smt { bool delayed_assume_eqs() { if (m_assume_eq_head == m_assume_eq_candidates.size()) return false; - + ctx().push_trail(value_trail(m_assume_eq_head)); while (m_assume_eq_head < m_assume_eq_candidates.size()) { std::pair const & p = m_assume_eq_candidates[m_assume_eq_head]; @@ -1132,7 +1135,7 @@ namespace smt { enode* n1 = get_enode(v1); enode* n2 = get_enode(v2); m_assume_eq_head++; - CTRACE("arith", + CTRACE("arith", get_ivalue(v1) == get_ivalue(v2) && n1->get_root() != n2->get_root(), tout << "assuming eq: v" << v1 << " = v" << v2 << "\n";); if (get_ivalue(v1) == get_ivalue(v2) && n1->get_root() != n2->get_root() && th.assume_eq(n1, n2)) { @@ -1166,7 +1169,7 @@ namespace smt { } is_sat = make_feasible(); } - else if (m_solver->get_status() != lean::lp_status::OPTIMAL) { + else if (m_solver->get_status() != lp::lp_status::OPTIMAL) { is_sat = make_feasible(); } switch (is_sat) { @@ -1177,7 +1180,7 @@ namespace smt { if (assume_eqs()) { return FC_CONTINUE; } - if (m_not_handled != 0) { + if (m_not_handled != 0) { return FC_GIVEUP; } return FC_DONE; @@ -1201,7 +1204,7 @@ namespace smt { Thus, 'a' must be considered a shared var if it is the child of an underspecified operator. if merge(a / b, x + y) and a / b is root, then x + y become shared and all z + u in equivalence class of x + y. - + TBD: when the set of underspecified subterms is small, compute the shared variables below it. Recompute the set if there are merges that invalidate it. @@ -1256,14 +1259,14 @@ namespace smt { while (m_asserted_qhead < m_asserted_atoms.size() && !ctx().inconsistent()) { bool_var bv = m_asserted_atoms[m_asserted_qhead].m_bv; bool is_true = m_asserted_atoms[m_asserted_qhead].m_is_true; - + #if 1 m_to_check.push_back(bv); #else propagate_bound(bv, is_true, b); #endif if (!m_delay_constraints) { - lp::bound& b = *m_bool_var2bound.find(bv); + lra_lp::bound& b = *m_bool_var2bound.find(bv); assert_bound(bv, is_true, b); } @@ -1276,12 +1279,12 @@ namespace smt { /*for (; qhead < m_asserted_atoms.size() && !ctx().inconsistent(); ++qhead) { bool_var bv = m_asserted_atoms[qhead].m_bv; bool is_true = m_asserted_atoms[qhead].m_is_true; - lp::bound& b = *m_bool_var2bound.find(bv); + lra_lp::bound& b = *m_bool_var2bound.find(bv); propagate_bound_compound(bv, is_true, b); }*/ lbool lbl = make_feasible(); - + switch(lbl) { case l_false: TRACE("arith", tout << "propagation conflict\n";); @@ -1294,7 +1297,7 @@ namespace smt { case l_undef: break; } - + } void propagate_bounds_with_lp_solver() { @@ -1311,7 +1314,7 @@ namespace smt { int new_num_of_p = m_solver->settings().st().m_num_of_implied_bounds; (void)new_num_of_p; CTRACE("arith", new_num_of_p > num_of_p, tout << "found " << new_num_of_p << " implied bounds\n";); - if (m_solver->get_status() == lean::lp_status::INFEASIBLE) { + if (m_solver->get_status() == lp::lp_status::INFEASIBLE) { set_conflict(); } else { @@ -1321,7 +1324,7 @@ namespace smt { } } - bool bound_is_interesting(unsigned vi, lean::lconstraint_kind kind, const rational & bval) const { + bool bound_is_interesting(unsigned vi, lp::lconstraint_kind kind, const rational & bval) const { theory_var v; if (m_solver->is_term(vi)) { v = m_term_index2theory_var.get(m_solver->adjust_term_index(vi), null_theory_var); @@ -1338,7 +1341,7 @@ namespace smt { } lp_bounds const& bounds = m_bounds[v]; for (unsigned i = 0; i < bounds.size(); ++i) { - lp::bound* b = bounds[i]; + lra_lp::bound* b = bounds[i]; if (ctx().get_assignment(b->get_bv()) != l_undef) { continue; } @@ -1351,11 +1354,11 @@ namespace smt { return false; } - struct local_bound_propagator: public lean::bound_propagator { + struct local_bound_propagator: public lp::lp_bound_propagator { imp & m_imp; - local_bound_propagator(imp& i) : bound_propagator(*i.m_solver), m_imp(i) {} + local_bound_propagator(imp& i) : lp_bound_propagator(*i.m_solver), m_imp(i) {} - bool bound_is_interesting(unsigned j, lean::lconstraint_kind kind, const rational & v) { + bool bound_is_interesting(unsigned j, lp::lconstraint_kind kind, const rational & v) { return m_imp.bound_is_interesting(j, kind, v); } @@ -1364,11 +1367,11 @@ namespace smt { } }; - - void propagate_lp_solver_bound(lean::implied_bound& be) { + + void propagate_lp_solver_bound(lp::implied_bound& be) { theory_var v; - lean::var_index vi = be.m_j; + lp::var_index vi = be.m_j; if (m_solver->is_term(vi)) { v = m_term_index2theory_var.get(m_solver->adjust_term_index(vi), null_theory_var); } @@ -1381,7 +1384,7 @@ namespace smt { // if (m_unassigned_bounds[v] == 0) m_solver->print_bound_evidence(be, tout); ); - + if (m_unassigned_bounds[v] == 0 || m_bounds.size() <= static_cast(v)) { TRACE("arith", tout << "return\n";); return; @@ -1389,7 +1392,7 @@ namespace smt { lp_bounds const& bounds = m_bounds[v]; bool first = true; for (unsigned i = 0; i < bounds.size(); ++i) { - lp::bound* b = bounds[i]; + lra_lp::bound* b = bounds[i]; if (ctx().get_assignment(b->get_bv()) != l_undef) { continue; } @@ -1447,33 +1450,33 @@ namespace smt { ctx().assign( lit, ctx().mk_justification( ext_theory_propagation_justification( - get_id(), ctx().get_region(), m_core.size(), m_core.c_ptr(), - m_eqs.size(), m_eqs.c_ptr(), lit, m_params.size(), m_params.c_ptr()))); + get_id(), ctx().get_region(), m_core.size(), m_core.c_ptr(), + m_eqs.size(), m_eqs.c_ptr(), lit, m_params.size(), m_params.c_ptr()))); } } - literal is_bound_implied(lean::lconstraint_kind k, rational const& value, lp::bound const& b) const { - if ((k == lean::LE || k == lean::LT) && b.get_bound_kind() == lp::upper_t && value <= b.get_value()) { - // v <= value <= b.get_value() => v <= b.get_value() + literal is_bound_implied(lp::lconstraint_kind k, rational const& value, lra_lp::bound const& b) const { + if ((k == lp::LE || k == lp::LT) && b.get_bound_kind() == lra_lp::upper_t && value <= b.get_value()) { + // v <= value <= b.get_value() => v <= b.get_value() return literal(b.get_bv(), false); } - if ((k == lean::GE || k == lean::GT) && b.get_bound_kind() == lp::lower_t && b.get_value() <= value) { - // b.get_value() <= value <= v => b.get_value() <= v + if ((k == lp::GE || k == lp::GT) && b.get_bound_kind() == lra_lp::lower_t && b.get_value() <= value) { + // b.get_value() <= value <= v => b.get_value() <= v return literal(b.get_bv(), false); } - if (k == lean::LE && b.get_bound_kind() == lp::lower_t && value < b.get_value()) { + if (k == lp::LE && b.get_bound_kind() == lra_lp::lower_t && value < b.get_value()) { // v <= value < b.get_value() => v < b.get_value() return literal(b.get_bv(), true); } - if (k == lean::LT && b.get_bound_kind() == lp::lower_t && value <= b.get_value()) { + if (k == lp::LT && b.get_bound_kind() == lra_lp::lower_t && value <= b.get_value()) { // v < value <= b.get_value() => v < b.get_value() return literal(b.get_bv(), true); } - if (k == lean::GE && b.get_bound_kind() == lp::upper_t && b.get_value() < value) { + if (k == lp::GE && b.get_bound_kind() == lra_lp::upper_t && b.get_value() < value) { // b.get_value() < value <= v => b.get_value() < v return literal(b.get_bv(), true); } - if (k == lean::GT && b.get_bound_kind() == lp::upper_t && b.get_value() <= value) { + if (k == lp::GT && b.get_bound_kind() == lra_lp::upper_t && b.get_value() <= value) { // b.get_value() <= value < v => b.get_value() < v return literal(b.get_bv(), true); } @@ -1481,30 +1484,30 @@ namespace smt { return null_literal; } - void mk_bound_axioms(lp::bound& b) { + void mk_bound_axioms(lra_lp::bound& b) { if (!ctx().is_searching()) { // - // NB. We make an assumption that user push calls propagation - // before internal scopes are pushed. This flushes all newly + // NB. We make an assumption that user push calls propagation + // before internal scopes are pushed. This flushes all newly // asserted atoms into the right context. // m_new_bounds.push_back(&b); return; } theory_var v = b.get_var(); - lp::bound_kind kind1 = b.get_bound_kind(); + lra_lp::bound_kind kind1 = b.get_bound_kind(); rational const& k1 = b.get_value(); lp_bounds & bounds = m_bounds[v]; - lp::bound* end = 0; - lp::bound* lo_inf = end, *lo_sup = end; - lp::bound* hi_inf = end, *hi_sup = end; - + lra_lp::bound* end = 0; + lra_lp::bound* lo_inf = end, *lo_sup = end; + lra_lp::bound* hi_inf = end, *hi_sup = end; + for (unsigned i = 0; i < bounds.size(); ++i) { - lp::bound& other = *bounds[i]; + lra_lp::bound& other = *bounds[i]; if (&other == &b) continue; if (b.get_bv() == other.get_bv()) continue; - lp::bound_kind kind2 = other.get_bound_kind(); + lra_lp::bound_kind kind2 = other.get_bound_kind(); rational const& k2 = other.get_value(); if (k1 == k2 && kind1 == kind2) { // the bounds are equivalent. @@ -1512,7 +1515,7 @@ namespace smt { } SASSERT(k1 != k2 || kind1 != kind2); - if (kind2 == lp::lower_t) { + if (kind2 == lra_lp::lower_t) { if (k2 < k1) { if (lo_inf == end || k2 > lo_inf->get_value()) { lo_inf = &other; @@ -1530,7 +1533,7 @@ namespace smt { else if (hi_sup == end || k2 < hi_sup->get_value()) { hi_sup = &other; } - } + } if (lo_inf != end) mk_bound_axiom(b, *lo_inf); if (lo_sup != end) mk_bound_axiom(b, *lo_sup); if (hi_inf != end) mk_bound_axiom(b, *hi_inf); @@ -1538,23 +1541,23 @@ namespace smt { } - void mk_bound_axiom(lp::bound& b1, lp::bound& b2) { + void mk_bound_axiom(lra_lp::bound& b1, lra_lp::bound& b2) { theory_var v = b1.get_var(); literal l1(b1.get_bv()); literal l2(b2.get_bv()); rational const& k1 = b1.get_value(); rational const& k2 = b2.get_value(); - lp::bound_kind kind1 = b1.get_bound_kind(); - lp::bound_kind kind2 = b2.get_bound_kind(); + lra_lp::bound_kind kind1 = b1.get_bound_kind(); + lra_lp::bound_kind kind2 = b2.get_bound_kind(); bool v_is_int = is_int(v); SASSERT(v == b2.get_var()); if (k1 == k2 && kind1 == kind2) return; SASSERT(k1 != k2 || kind1 != kind2); - parameter coeffs[3] = { parameter(symbol("farkas")), + parameter coeffs[3] = { parameter(symbol("farkas")), parameter(rational(1)), parameter(rational(1)) }; - - if (kind1 == lp::lower_t) { - if (kind2 == lp::lower_t) { + + if (kind1 == lra_lp::lower_t) { + if (kind2 == lra_lp::lower_t) { if (k2 <= k1) { mk_clause(~l1, l2, 3, coeffs); } @@ -1575,19 +1578,19 @@ namespace smt { } } } - else if (kind2 == lp::lower_t) { + else if (kind2 == lra_lp::lower_t) { if (k1 >= k2) { // k1 >= lo_inf, k1 >= x or lo_inf <= x mk_clause(l1, l2, 3, coeffs); } else { // k1 < k2, k2 <= x => ~(x <= k1) - mk_clause(~l1, ~l2, 3, coeffs); + mk_clause(~l1, ~l2, 3, coeffs); if (v_is_int && k1 == k2 - rational(1)) { // x <= k1 or k1+l <= x mk_clause(l1, l2, 3, coeffs); } - + } } else { @@ -1600,7 +1603,7 @@ namespace smt { // k1 <= hi_sup , x <= k1 => x <= hi_sup mk_clause(~l1, l2, 3, coeffs); } - } + } } typedef lp_bounds::iterator iterator; @@ -1609,7 +1612,7 @@ namespace smt { CTRACE("arith", !m_new_bounds.empty(), tout << "flush bound axioms\n";); while (!m_new_bounds.empty()) { - lp_bounds atoms; + lp_bounds atoms; atoms.push_back(m_new_bounds.back()); m_new_bounds.pop_back(); theory_var v = atoms.back()->get_var(); @@ -1620,38 +1623,38 @@ namespace smt { m_new_bounds.pop_back(); --i; } - } - CTRACE("arith_verbose", !atoms.empty(), + } + CTRACE("arith_verbose", !atoms.empty(), for (unsigned i = 0; i < atoms.size(); ++i) { atoms[i]->display(tout); tout << "\n"; }); lp_bounds occs(m_bounds[v]); - + std::sort(atoms.begin(), atoms.end(), compare_bounds()); std::sort(occs.begin(), occs.end(), compare_bounds()); - + iterator begin1 = occs.begin(); iterator begin2 = occs.begin(); iterator end = occs.end(); - begin1 = first(lp::lower_t, begin1, end); - begin2 = first(lp::upper_t, begin2, end); - + begin1 = first(lra_lp::lower_t, begin1, end); + begin2 = first(lra_lp::upper_t, begin2, end); + iterator lo_inf = begin1, lo_sup = begin1; iterator hi_inf = begin2, hi_sup = begin2; iterator lo_inf1 = begin1, lo_sup1 = begin1; iterator hi_inf1 = begin2, hi_sup1 = begin2; bool flo_inf, fhi_inf, flo_sup, fhi_sup; - ptr_addr_hashtable visited; + ptr_addr_hashtable visited; for (unsigned i = 0; i < atoms.size(); ++i) { - lp::bound* a1 = atoms[i]; - lo_inf1 = next_inf(a1, lp::lower_t, lo_inf, end, flo_inf); - hi_inf1 = next_inf(a1, lp::upper_t, hi_inf, end, fhi_inf); - lo_sup1 = next_sup(a1, lp::lower_t, lo_sup, end, flo_sup); - hi_sup1 = next_sup(a1, lp::upper_t, hi_sup, end, fhi_sup); - if (lo_inf1 != end) lo_inf = lo_inf1; - if (lo_sup1 != end) lo_sup = lo_sup1; - if (hi_inf1 != end) hi_inf = hi_inf1; - if (hi_sup1 != end) hi_sup = hi_sup1; + lra_lp::bound* a1 = atoms[i]; + lo_inf1 = next_inf(a1, lra_lp::lower_t, lo_inf, end, flo_inf); + hi_inf1 = next_inf(a1, lra_lp::upper_t, hi_inf, end, fhi_inf); + lo_sup1 = next_sup(a1, lra_lp::lower_t, lo_sup, end, flo_sup); + hi_sup1 = next_sup(a1, lra_lp::upper_t, hi_sup, end, fhi_sup); + if (lo_inf1 != end) lo_inf = lo_inf1; + if (lo_sup1 != end) lo_sup = lo_sup1; + if (hi_inf1 != end) hi_inf = hi_inf1; + if (hi_sup1 != end) hi_sup = hi_sup1; if (!flo_inf) lo_inf = end; if (!fhi_inf) hi_inf = end; if (!flo_sup) lo_sup = end; @@ -1661,37 +1664,37 @@ namespace smt { if (lo_sup1 != end && lo_sup != end && !visited.contains(*lo_sup)) mk_bound_axiom(*a1, **lo_sup); if (hi_inf1 != end && hi_inf != end && !visited.contains(*hi_inf)) mk_bound_axiom(*a1, **hi_inf); if (hi_sup1 != end && hi_sup != end && !visited.contains(*hi_sup)) mk_bound_axiom(*a1, **hi_sup); - } + } } } struct compare_bounds { - bool operator()(lp::bound* a1, lp::bound* a2) const { return a1->get_value() < a2->get_value(); } + bool operator()(lra_lp::bound* a1, lra_lp::bound* a2) const { return a1->get_value() < a2->get_value(); } }; lp_bounds::iterator first( - lp::bound_kind kind, - iterator it, + lra_lp::bound_kind kind, + iterator it, iterator end) { for (; it != end; ++it) { - lp::bound* a = *it; + lra_lp::bound* a = *it; if (a->get_bound_kind() == kind) return it; } return end; } lp_bounds::iterator next_inf( - lp::bound* a1, - lp::bound_kind kind, - iterator it, + lra_lp::bound* a1, + lra_lp::bound_kind kind, + iterator it, iterator end, bool& found_compatible) { rational const & k1(a1->get_value()); iterator result = end; found_compatible = false; for (; it != end; ++it) { - lp::bound * a2 = *it; + lra_lp::bound * a2 = *it; if (a1 == a2) continue; if (a2->get_bound_kind() != kind) continue; rational const & k2(a2->get_value()); @@ -1707,15 +1710,15 @@ namespace smt { } lp_bounds::iterator next_sup( - lp::bound* a1, - lp::bound_kind kind, - iterator it, + lra_lp::bound* a1, + lra_lp::bound_kind kind, + iterator it, iterator end, bool& found_compatible) { rational const & k1(a1->get_value()); found_compatible = false; for (; it != end; ++it) { - lp::bound * a2 = *it; + lra_lp::bound * a2 = *it; if (a1 == a2) continue; if (a2->get_bound_kind() != kind) continue; rational const & k2(a2->get_value()); @@ -1728,27 +1731,27 @@ namespace smt { } void propagate_basic_bounds() { - for (auto const& bv : m_to_check) { - lp::bound& b = *m_bool_var2bound.find(bv); + for (auto const& bv : m_to_check) { + lra_lp::bound& b = *m_bool_var2bound.find(bv); propagate_bound(bv, ctx().get_assignment(bv) == l_true, b); if (ctx().inconsistent()) break; } m_to_check.reset(); } - + // for glb lo': lo' < lo: - // lo <= x -> lo' <= x + // lo <= x -> lo' <= x // lo <= x -> ~(x <= lo') // for lub hi': hi' > hi // x <= hi -> x <= hi' // x <= hi -> ~(x >= hi') - void propagate_bound(bool_var bv, bool is_true, lp::bound& b) { + void propagate_bound(bool_var bv, bool is_true, lra_lp::bound& b) { if (BP_NONE == propagation_mode()) { return; } - lp::bound_kind k = b.get_bound_kind(); + lra_lp::bound_kind k = b.get_bound_kind(); theory_var v = b.get_var(); inf_rational val = b.get_value(is_true); lp_bounds const& bounds = m_bounds[v]; @@ -1758,12 +1761,12 @@ namespace smt { literal lit1(bv, !is_true); literal lit2 = null_literal; - bool find_glb = (is_true == (k == lp::lower_t)); + bool find_glb = (is_true == (k == lra_lp::lower_t)); if (find_glb) { rational glb; - lp::bound* lb = 0; + lra_lp::bound* lb = 0; for (unsigned i = 0; i < bounds.size(); ++i) { - lp::bound* b2 = bounds[i]; + lra_lp::bound* b2 = bounds[i]; if (b2 == &b) continue; rational const& val2 = b2->get_value(); if ((is_true ? val2 < val : val2 <= val) && (!lb || glb < val2)) { @@ -1772,14 +1775,14 @@ namespace smt { } } if (!lb) return; - bool sign = lb->get_bound_kind() != lp::lower_t; - lit2 = literal(lb->get_bv(), sign); + bool sign = lb->get_bound_kind() != lra_lp::lower_t; + lit2 = literal(lb->get_bv(), sign); } else { rational lub; - lp::bound* ub = 0; + lra_lp::bound* ub = 0; for (unsigned i = 0; i < bounds.size(); ++i) { - lp::bound* b2 = bounds[i]; + lra_lp::bound* b2 = bounds[i]; if (b2 == &b) continue; rational const& val2 = b2->get_value(); if ((is_true ? val < val2 : val <= val2) && (!ub || val2 < lub)) { @@ -1788,10 +1791,10 @@ namespace smt { } } if (!ub) return; - bool sign = ub->get_bound_kind() != lp::upper_t; + bool sign = ub->get_bound_kind() != lra_lp::upper_t; lit2 = literal(ub->get_bv(), sign); } - TRACE("arith", + TRACE("arith", ctx().display_literal_verbose(tout, lit1); ctx().display_literal_verbose(tout << " => ", lit2); tout << "\n";); @@ -1808,27 +1811,27 @@ namespace smt { ++m_stats.m_bounds_propagations; } - void add_use_lists(lp::bound* b) { + void add_use_lists(lra_lp::bound* b) { theory_var v = b->get_var(); - lean::var_index vi = get_var_index(v); + lp::var_index vi = get_var_index(v); if (m_solver->is_term(vi)) { - lean::lar_term const& term = m_solver->get_term(vi); + lp::lar_term const& term = m_solver->get_term(vi); for (auto i = term.m_coeffs.begin(); i != term.m_coeffs.end(); ++i) { - lean::var_index wi = i->first; + lp::var_index wi = i->first; unsigned w = m_var_index2theory_var[wi]; - m_use_list.reserve(w + 1, ptr_vector()); + m_use_list.reserve(w + 1, ptr_vector()); m_use_list[w].push_back(b); } } } - void del_use_lists(lp::bound* b) { + void del_use_lists(lra_lp::bound* b) { theory_var v = b->get_var(); - lean::var_index vi = m_theory_var2var_index[v]; + lp::var_index vi = m_theory_var2var_index[v]; if (m_solver->is_term(vi)) { - lean::lar_term const& term = m_solver->get_term(vi); + lp::lar_term const& term = m_solver->get_term(vi); for (auto i = term.m_coeffs.begin(); i != term.m_coeffs.end(); ++i) { - lean::var_index wi = i->first; + lp::var_index wi = i->first; unsigned w = m_var_index2theory_var[wi]; SASSERT(m_use_list[w].back() == b); m_use_list[w].pop_back(); @@ -1841,8 +1844,8 @@ namespace smt { // The idea is that if bounds on all variables in an inequality ax + by + cz >= k // have been assigned we may know the truth value of the inequality by using simple // bounds propagation. - // - void propagate_bound_compound(bool_var bv, bool is_true, lp::bound& b) { + // + void propagate_bound_compound(bool_var bv, bool is_true, lra_lp::bound& b) { theory_var v = b.get_var(); TRACE("arith", tout << mk_pp(get_owner(v), m) << "\n";); if (static_cast(v) >= m_use_list.size()) { @@ -1858,7 +1861,7 @@ namespace smt { // x >= 0, y >= 1 -> x + y >= 1 // x <= 0, y <= 2 -> x + y <= 2 literal lit = null_literal; - if (lp::lower_t == vb->get_bound_kind()) { + if (lra_lp::lower_t == vb->get_bound_kind()) { if (get_glb(*vb, r) && r >= vb->get_value()) { // vb is assigned true lit = literal(vb->get_bv(), false); } @@ -1866,15 +1869,15 @@ namespace smt { lit = literal(vb->get_bv(), true); } } - else { + else { if (get_glb(*vb, r) && r > vb->get_value()) { // VB <= value < val(VB) lit = literal(vb->get_bv(), true); } else if (get_lub(*vb, r) && r <= vb->get_value()) { // val(VB) <= value lit = literal(vb->get_bv(), false); } - } - + } + if (lit != null_literal) { TRACE("arith", ctx().display_literals_verbose(tout, m_core); @@ -1882,7 +1885,7 @@ namespace smt { ctx().display_literal_verbose(tout, lit); tout << "\n"; ); - + assign(lit); } @@ -1892,30 +1895,30 @@ namespace smt { } } - bool get_lub(lp::bound const& b, inf_rational& lub) { + bool get_lub(lra_lp::bound const& b, inf_rational& lub) { return get_bound(b, lub, true); } - bool get_glb(lp::bound const& b, inf_rational& glb) { + bool get_glb(lra_lp::bound const& b, inf_rational& glb) { return get_bound(b, glb, false); } - std::ostream& display_bound(std::ostream& out, lp::bound const& b) { + std::ostream& display_bound(std::ostream& out, lra_lp::bound const& b) { return out << mk_pp(ctx().bool_var2expr(b.get_bv()), m); } - bool get_bound(lp::bound const& b, inf_rational& r, bool is_lub) { + bool get_bound(lra_lp::bound const& b, inf_rational& r, bool is_lub) { m_core.reset(); m_eqs.reset(); m_params.reset(); r.reset(); theory_var v = b.get_var(); - lean::var_index vi = m_theory_var2var_index[v]; + lp::var_index vi = m_theory_var2var_index[v]; SASSERT(m_solver->is_term(vi)); - lean::lar_term const& term = m_solver->get_term(vi); + lp::lar_term const& term = m_solver->get_term(vi); for (auto const coeff : term.m_coeffs) { - lean::var_index wi = coeff.first; - lean::constraint_index ci; + lp::var_index wi = coeff.first; + lp::constraint_index ci; rational value; bool is_strict; if (coeff.second.is_neg() == is_lub) { @@ -1934,32 +1937,32 @@ namespace smt { if (is_strict) { r += inf_rational(rational::zero(), coeff.second.is_pos()); } - } + } r += value * coeff.second; - set_evidence(ci); + set_evidence(ci); } TRACE("arith_verbose", tout << (is_lub?"lub":"glb") << " is " << r << "\n";); return true; } - void assert_bound(bool_var bv, bool is_true, lp::bound& b) { - if (m_solver->get_status() == lean::lp_status::INFEASIBLE) { + void assert_bound(bool_var bv, bool is_true, lra_lp::bound& b) { + if (m_solver->get_status() == lp::lp_status::INFEASIBLE) { return; } scoped_internalize_state st(*this); st.vars().push_back(b.get_var()); st.coeffs().push_back(rational::one()); init_left_side(st); - lean::lconstraint_kind k = lean::EQ; + lp::lconstraint_kind k = lp::EQ; switch (b.get_bound_kind()) { - case lp::lower_t: - k = is_true ? lean::GE : lean::LT; + case lra_lp::lower_t: + k = is_true ? lp::GE : lp::LT; break; - case lp::upper_t: - k = is_true ? lean::LE : lean::GT; + case lra_lp::upper_t: + k = is_true ? lp::LE : lp::GT; break; - } - if (k == lean::LT || k == lean::LE) { + } + if (k == lp::LT || k == lp::LE) { ++m_stats.m_assert_lower; } else { @@ -1978,9 +1981,9 @@ namespace smt { // A fixed equality is inferred if there are two variables v1, v2 whose // upper and lower bounds coincide. // Then the equality v1 == v2 is propagated to the core. - // + // - typedef std::pair constraint_bound; + typedef std::pair constraint_bound; vector m_lower_terms; vector m_upper_terms; typedef std::pair value_sort_pair; @@ -1988,16 +1991,16 @@ namespace smt { typedef map > value2var; value2var m_fixed_var_table; - void propagate_eqs(lean::var_index vi, lean::constraint_index ci, lean::lconstraint_kind k, lp::bound& b) { + void propagate_eqs(lp::var_index vi, lp::constraint_index ci, lp::lconstraint_kind k, lra_lp::bound& b) { if (propagate_eqs()) { rational const& value = b.get_value(); - if (k == lean::GE) { + if (k == lp::GE) { set_lower_bound(vi, ci, value); if (has_upper_bound(vi, ci, value)) { fixed_var_eh(b.get_var(), value); } } - else if (k == lean::LE) { + else if (k == lp::LE) { set_upper_bound(vi, ci, value); if (has_lower_bound(vi, ci, value)) { fixed_var_eh(b.get_var(), value); @@ -2018,16 +2021,16 @@ namespace smt { bool use_tableau() const { return lp_params(ctx().get_params()).simplex_strategy() < 2; } - void set_upper_bound(lean::var_index vi, lean::constraint_index ci, rational const& v) { set_bound(vi, ci, v, false); } + void set_upper_bound(lp::var_index vi, lp::constraint_index ci, rational const& v) { set_bound(vi, ci, v, false); } - void set_lower_bound(lean::var_index vi, lean::constraint_index ci, rational const& v) { set_bound(vi, ci, v, true); } + void set_lower_bound(lp::var_index vi, lp::constraint_index ci, rational const& v) { set_bound(vi, ci, v, true); } - void set_bound(lean::var_index vi, lean::constraint_index ci, rational const& v, bool is_lower) { + void set_bound(lp::var_index vi, lp::constraint_index ci, rational const& v, bool is_lower) { if (!m_solver->is_term(vi)) { // m_solver already tracks bounds on proper variables, but not on terms. return; } - lean::var_index ti = m_solver->adjust_term_index(vi); + lp::var_index ti = m_solver->adjust_term_index(vi); auto& vec = is_lower ? m_lower_terms : m_upper_terms; if (vec.size() <= ti) { vec.resize(ti + 1, constraint_bound(UINT_MAX, rational())); @@ -2040,15 +2043,15 @@ namespace smt { } } - bool has_upper_bound(lean::var_index vi, lean::constraint_index& ci, rational const& bound) { return has_bound(vi, ci, bound, false); } + bool has_upper_bound(lp::var_index vi, lp::constraint_index& ci, rational const& bound) { return has_bound(vi, ci, bound, false); } - bool has_lower_bound(lean::var_index vi, lean::constraint_index& ci, rational const& bound) { return has_bound(vi, ci, bound, true); } - - bool has_bound(lean::var_index vi, lean::constraint_index& ci, rational const& bound, bool is_lower) { + bool has_lower_bound(lp::var_index vi, lp::constraint_index& ci, rational const& bound) { return has_bound(vi, ci, bound, true); } + + bool has_bound(lp::var_index vi, lp::constraint_index& ci, rational const& bound, bool is_lower) { if (m_solver->is_term(vi)) { - - lean::var_index ti = m_solver->adjust_term_index(vi); + + lp::var_index ti = m_solver->adjust_term_index(vi); theory_var v = m_term_index2theory_var.get(ti, null_theory_var); rational val; TRACE("arith", tout << vi << " " << v << "\n";); @@ -2091,7 +2094,7 @@ namespace smt { if (static_cast(v2) < th.get_num_vars() && !is_equal(v1, v2)) { auto vi1 = get_var_index(v1); auto vi2 = get_var_index(v2); - lean::constraint_index ci1, ci2, ci3, ci4; + lp::constraint_index ci1, ci2, ci3, ci4; TRACE("arith", tout << "fixed: " << mk_pp(get_owner(v1), m) << " " << mk_pp(get_owner(v2), m) << " " << bound << " " << has_lower_bound(vi2, ci3, bound) << "\n";); if (has_lower_bound(vi2, ci3, bound) && has_upper_bound(vi2, ci4, bound)) { VERIFY (has_lower_bound(vi1, ci1, bound)); @@ -2105,7 +2108,7 @@ namespace smt { set_evidence(ci4); enode* x = get_enode(v1); enode* y = get_enode(v2); - justification* js = + justification* js = ctx().mk_justification( ext_theory_eq_propagation_justification( get_id(), ctx().get_region(), m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), x, y, 0, 0)); @@ -2114,10 +2117,10 @@ namespace smt { for (unsigned i = 0; i < m_core.size(); ++i) { ctx().display_detailed_literal(tout, m_core[i]); tout << "\n"; - } + } for (unsigned i = 0; i < m_eqs.size(); ++i) { tout << mk_pp(m_eqs[i].first->get_owner(), m) << " = " << mk_pp(m_eqs[i].second->get_owner(), m) << "\n"; - } + } tout << " ==> "; tout << mk_pp(x->get_owner(), m) << " = " << mk_pp(y->get_owner(), m) << "\n"; ); @@ -2145,36 +2148,36 @@ namespace smt { if (m_solver->A_r().row_count() > m_stats.m_max_rows) m_stats.m_max_rows = m_solver->A_r().row_count(); TRACE("arith_verbose", display(tout);); - lean::lp_status status = m_solver->find_feasible_solution(); + lp::lp_status status = m_solver->find_feasible_solution(); m_stats.m_num_iterations = m_solver->settings().st().m_total_iterations; m_stats.m_num_factorizations = m_solver->settings().st().m_num_factorizations; m_stats.m_need_to_solve_inf = m_solver->settings().st().m_need_to_solve_inf; switch (status) { - case lean::lp_status::INFEASIBLE: + case lp::lp_status::INFEASIBLE: return l_false; - case lean::lp_status::FEASIBLE: - case lean::lp_status::OPTIMAL: + case lp::lp_status::FEASIBLE: + case lp::lp_status::OPTIMAL: // SASSERT(m_solver->all_constraints_hold()); return l_true; - case lean::lp_status::TIME_EXHAUSTED: - + case lp::lp_status::TIME_EXHAUSTED: + default: TRACE("arith", tout << "status treated as inconclusive: " << status << "\n";); - // TENTATIVE_UNBOUNDED, UNBOUNDED, TENTATIVE_DUAL_UNBOUNDED, DUAL_UNBOUNDED, + // TENTATIVE_UNBOUNDED, UNBOUNDED, TENTATIVE_DUAL_UNBOUNDED, DUAL_UNBOUNDED, // FLOATING_POINT_ERROR, TIME_EXAUSTED, ITERATIONS_EXHAUSTED, EMPTY, UNSTABLE return l_undef; } } - - vector> m_explanation; + + vector> m_explanation; literal_vector m_core; svector m_eqs; vector m_params; - // lean::constraint_index const null_constraint_index = UINT_MAX; // not sure what a correct fix is + // lp::constraint_index const null_constraint_index = UINT_MAX; // not sure what a correct fix is - void set_evidence(lean::constraint_index idx) { + void set_evidence(lp::constraint_index idx) { if (idx == UINT_MAX) { return; } @@ -2188,7 +2191,7 @@ namespace smt { case equality_source: { SASSERT(m_equalities[idx].first != nullptr); SASSERT(m_equalities[idx].second != nullptr); - m_eqs.push_back(m_equalities[idx]); + m_eqs.push_back(m_equalities[idx]); break; } case definition_source: { @@ -2219,7 +2222,7 @@ namespace smt { TRACE("arith", tout << "scope: " << ctx().get_scope_level() << "\n"; display_evidence(tout, m_explanation); ); TRACE("arith", display(tout);); for (auto const& ev : m_explanation) { - if (!ev.first.is_zero()) { + if (!ev.first.is_zero()) { set_evidence(ev.second); } } @@ -2227,8 +2230,8 @@ namespace smt { ctx().set_conflict( ctx().mk_justification( ext_theory_conflict_justification( - get_id(), ctx().get_region(), - m_core.size(), m_core.c_ptr(), + get_id(), ctx().get_region(), + m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), m_params.size(), m_params.c_ptr()))); } @@ -2261,7 +2264,7 @@ namespace smt { } bool get_value(enode* n, expr_ref& r) { - theory_var v = n->get_th_var(get_id()); + theory_var v = n->get_th_var(get_id()); if (can_get_value(v)) { r = a.mk_numeral(get_value(v), is_int(n)); return true; @@ -2269,7 +2272,7 @@ namespace smt { else { return false; } - } + } bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const { SASSERT(v1 != null_theory_var); @@ -2287,12 +2290,12 @@ namespace smt { add_background(nctx); bool result = l_true != nctx.check(); CTRACE("arith", !result, ctx().display_lemma_as_smt_problem(tout, m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), false_literal); - display(tout);); + display(tout);); return result; } bool validate_assign(literal lit) { - if (dump_lemmas()) { + if (dump_lemmas()) { ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit); } context nctx(m, ctx().get_fparams(), ctx().get_params()); @@ -2301,7 +2304,7 @@ namespace smt { m_core.pop_back(); bool result = l_true != nctx.check(); CTRACE("arith", !result, ctx().display_lemma_as_smt_problem(tout, m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit); - display(tout);); + display(tout);); return result; } @@ -2321,19 +2324,24 @@ namespace smt { for (unsigned i = 0; i < m_eqs.size(); ++i) { nctx.assert_expr(m.mk_eq(m_eqs[i].first->get_owner(), m_eqs[i].second->get_owner())); } - } + } theory_lra::inf_eps value(theory_var v) { - lean::impq ival = get_ivalue(v); + lp::impq ival = get_ivalue(v); return inf_eps(0, inf_rational(ival.x, ival.y)); } theory_lra::inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared) { - lean::var_index vi = m_theory_var2var_index.get(v, UINT_MAX); - vector > coeffs; + lp::var_index vi = m_theory_var2var_index.get(v, UINT_MAX); + vector > coeffs; rational coeff; - if (m_solver->is_term(vi)) { - const lean::lar_term& term = m_solver->get_term(vi); + if (vi == UINT_MAX) { + has_shared = false; + blocker = m.mk_false(); + return inf_eps(rational::one(), inf_rational()); + } + else if (m_solver->is_term(vi)) { + const lp::lar_term& term = m_solver->get_term(vi); for (auto & ti : term.m_coeffs) { coeffs.push_back(std::make_pair(ti.second, ti.first)); } @@ -2343,7 +2351,7 @@ namespace smt { coeffs.push_back(std::make_pair(rational::one(), vi)); coeff = rational::zero(); } - lean::impq term_max; + lp::impq term_max; if (m_solver->maximize_term(coeffs, term_max)) { blocker = mk_gt(v); inf_rational val(term_max.x + coeff, term_max.y); @@ -2358,7 +2366,7 @@ namespace smt { } expr_ref mk_gt(theory_var v) { - lean::impq val = get_ivalue(v); + lp::impq val = get_ivalue(v); expr* obj = get_enode(v)->get_owner(); rational r = val.x; expr_ref e(m); @@ -2390,11 +2398,11 @@ namespace smt { } app_ref mk_obj(theory_var v) { - lean::var_index vi = m_theory_var2var_index[v]; + lp::var_index vi = m_theory_var2var_index[v]; bool is_int = a.is_int(get_enode(v)->get_owner()); - if (m_solver->is_term(vi)) { + if (m_solver->is_term(vi)) { expr_ref_vector args(m); - const lean::lar_term& term = m_solver->get_term(vi); + const lp::lar_term& term = m_solver->get_term(vi); for (auto & ti : term.m_coeffs) { theory_var w = m_var_index2theory_var[ti.first]; expr* o = get_enode(w)->get_owner(); @@ -2425,9 +2433,9 @@ namespace smt { bool_var bv = ctx().mk_bool_var(b); ctx().set_var_theory(bv, get_id()); // ctx().set_enode_flag(bv, true); - lp::bound_kind bkind = lp::bound_kind::lower_t; - if (is_strict) bkind = lp::bound_kind::upper_t; - lp::bound* a = alloc(lp::bound, bv, v, r, bkind); + lra_lp::bound_kind bkind = lra_lp::bound_kind::lower_t; + if (is_strict) bkind = lra_lp::bound_kind::upper_t; + lra_lp::bound* a = alloc(lra_lp::bound, bv, v, r, bkind); mk_bound_axioms(*a); updt_unassigned_bounds(v, +1); m_bounds[v].push_back(a); @@ -2440,7 +2448,7 @@ namespace smt { } TRACE("arith", tout << b << "\n";); return expr_ref(b, m); - + } @@ -2452,18 +2460,18 @@ namespace smt { unsigned nv = th.get_num_vars(); for (unsigned v = 0; v < nv; ++v) { out << "v" << v; - if (can_get_value(v)) out << ", value: " << get_value(v); - out << ", shared: " << ctx().is_shared(get_enode(v)) - << ", rel: " << ctx().is_relevant(get_enode(v)) + if (can_get_value(v)) out << ", value: " << get_value(v); + out << ", shared: " << ctx().is_shared(get_enode(v)) + << ", rel: " << ctx().is_relevant(get_enode(v)) << ", def: "; th.display_var_flat_def(out, v) << "\n"; } } - void display_evidence(std::ostream& out, vector> const& evidence) { + void display_evidence(std::ostream& out, vector> const& evidence) { for (auto const& ev : evidence) { expr_ref e(m); - SASSERT(!ev.first.is_zero()); - if (ev.first.is_zero()) { + SASSERT(!ev.first.is_zero()); + if (ev.first.is_zero()) { continue; } unsigned idx = ev.second; @@ -2474,23 +2482,23 @@ namespace smt { out << e << " " << ctx().get_assignment(lit) << "\n"; break; } - case equality_source: - out << mk_pp(m_equalities[idx].first->get_owner(), m) << " = " - << mk_pp(m_equalities[idx].second->get_owner(), m) << "\n"; + case equality_source: + out << mk_pp(m_equalities[idx].first->get_owner(), m) << " = " + << mk_pp(m_equalities[idx].second->get_owner(), m) << "\n"; break; case definition_source: { theory_var v = m_definitions[idx]; out << "def: v" << v << " := " << mk_pp(th.get_enode(v)->get_owner(), m) << "\n"; break; } - case null_source: + case null_source: default: UNREACHABLE(); - break; + break; } } for (auto const& ev : evidence) { - m_solver->print_constraint(ev.second, out << ev.first << ": "); + m_solver->print_constraint(ev.second, out << ev.first << ": "); } } @@ -2512,16 +2520,16 @@ namespace smt { st.update("arith-make-feasible", m_stats.m_make_feasible); st.update("arith-max-columns", m_stats.m_max_cols); st.update("arith-max-rows", m_stats.m_max_rows); - } + } }; - + theory_lra::theory_lra(ast_manager& m, theory_arith_params& ap): theory(m.get_family_id("arith")) { m_imp = alloc(imp, *this, m, ap); - } + } theory_lra::~theory_lra() { dealloc(m_imp); - } + } theory* theory_lra::mk_fresh(context* new_ctx) { return alloc(theory_lra, new_ctx->get_manager(), new_ctx->get_fparams()); } diff --git a/src/smt/theory_lra.h b/src/smt/theory_lra.h index beb5c8387..774ec15ad 100644 --- a/src/smt/theory_lra.h +++ b/src/smt/theory_lra.h @@ -20,7 +20,7 @@ Revision History: --*/ #pragma once -#include "theory_opt.h" +#include "smt/theory_opt.h" namespace smt { class theory_lra : public theory, public theory_opt { diff --git a/src/smt/theory_opt.cpp b/src/smt/theory_opt.cpp index 9e6fa452c..365315bf2 100644 --- a/src/smt/theory_opt.cpp +++ b/src/smt/theory_opt.cpp @@ -18,10 +18,10 @@ Notes: --*/ -#include "arith_decl_plugin.h" -#include "smt_types.h" -#include "smt_theory.h" -#include "theory_opt.h" +#include "ast/arith_decl_plugin.h" +#include "smt/smt_types.h" +#include "smt/smt_theory.h" +#include "smt/theory_opt.h" namespace smt { bool theory_opt::is_linear(ast_manager& m, expr* term) { diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index 421e6feca..49f436ea5 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -18,9 +18,9 @@ Notes: --*/ -#include "inf_rational.h" -#include "inf_eps_rational.h" -#include "arith_decl_plugin.h" +#include "util/inf_rational.h" +#include "util/inf_eps_rational.h" +#include "ast/arith_decl_plugin.h" #ifndef THEORY_OPT_H_ #define THEORY_OPT_H_ diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 507cb6d43..9d2059f55 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -19,15 +19,15 @@ Notes: --*/ #include -#include "theory_pb.h" -#include "smt_context.h" -#include "ast_pp.h" -#include "sorting_network.h" -#include "uint_set.h" -#include "smt_model_generator.h" -#include "pb_rewriter_def.h" -#include "sparse_matrix_def.h" -#include "simplex_def.h" +#include "smt/theory_pb.h" +#include "smt/smt_context.h" +#include "ast/ast_pp.h" +#include "util/sorting_network.h" +#include "util/uint_set.h" +#include "smt/smt_model_generator.h" +#include "ast/rewriter/pb_rewriter_def.h" +#include "math/simplex/sparse_matrix_def.h" +#include "math/simplex/simplex_def.h" namespace smt { @@ -806,8 +806,9 @@ namespace smt { if (c != 0) { if (m_enable_simplex) { row_info const& info = m_ineq_row_info.find(v); + unsynch_mpq_manager mgr; scoped_eps_numeral coeff(m_mpq_inf_mgr); - coeff = std::make_pair(info.m_bound.to_mpq(), mpq(0)); + coeff = std::make_pair(mgr.dup(info.m_bound.to_mpq()), mpq(0)); unsigned slack = info.m_slack; if (is_true) { update_bound(slack, literal(v), true, coeff); diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index ee68bd26e..662378bdf 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -20,11 +20,11 @@ Notes: sorting circuits if it keeps having to propagate (create new clauses). --*/ -#include "smt_theory.h" -#include "pb_decl_plugin.h" -#include "smt_clause.h" -#include "theory_pb_params.h" -#include "simplex.h" +#include "smt/smt_theory.h" +#include "ast/pb_decl_plugin.h" +#include "smt/smt_clause.h" +#include "smt/params/theory_pb_params.h" +#include "math/simplex/simplex.h" namespace smt { class theory_pb : public theory { @@ -279,7 +279,6 @@ namespace smt { // void compile_ineq(ineq& c); void inc_propagations(ineq& c); - unsigned get_compilation_threshold(ineq& c); // // Conflict resolution, cutting plane derivation. diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 832995994..d55484384 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -18,13 +18,15 @@ Revision History: --*/ -#include "value_factory.h" -#include "smt_context.h" -#include "smt_model_generator.h" -#include "theory_seq.h" -#include "ast_trail.h" -#include "theory_arith.h" -#include "smt_kernel.h" +#include +#include "ast/ast_pp.h" +#include "ast/ast_trail.h" +#include "smt/proto_model/value_factory.h" +#include "smt/smt_context.h" +#include "smt/smt_model_generator.h" +#include "smt/theory_seq.h" +#include "smt/theory_arith.h" +#include "smt/smt_kernel.h" using namespace smt; @@ -149,9 +151,8 @@ void theory_seq::solution_map::pop_scope(unsigned num_scopes) { } void theory_seq::solution_map::display(std::ostream& out) const { - eqdep_map_t::iterator it = m_map.begin(), end = m_map.end(); - for (; it != end; ++it) { - out << mk_pp(it->m_key, m) << " |-> " << mk_pp(it->m_value.first, m) << "\n"; + for (auto const& kv : m_map) { + out << mk_pp(kv.m_key, m) << " |-> " << mk_pp(kv.m_value.first, m) << "\n"; } } @@ -185,9 +186,8 @@ void theory_seq::exclusion_table::pop_scope(unsigned num_scopes) { } void theory_seq::exclusion_table::display(std::ostream& out) const { - table_t::iterator it = m_table.begin(), end = m_table.end(); - for (; it != end; ++it) { - out << mk_pp(it->first, m) << " != " << mk_pp(it->second, m) << "\n"; + for (auto const& kv : m_table) { + out << mk_pp(kv.first, m) << " != " << mk_pp(kv.second, m) << "\n"; } } @@ -212,6 +212,7 @@ theory_seq::theory_seq(ast_manager& m): m_trail_stack(*this), m_ls(m), m_rs(m), m_lhs(m), m_rhs(m), + m_res(m), m_atoms_qhead(0), m_new_solution(false), m_new_propagation(false), @@ -275,7 +276,22 @@ final_check_status theory_seq::final_check_eh() { TRACE("seq", tout << ">>int_string\n";); return FC_CONTINUE; } - if (reduce_length_eq() || branch_unit_variable() || branch_binary_variable() || branch_variable_mb() || branch_variable()) { + if (reduce_length_eq()) { + ++m_stats.m_branch_variable; + TRACE("seq", tout << ">>reduce length\n";); + return FC_CONTINUE; + } + if (branch_unit_variable()) { + ++m_stats.m_branch_variable; + TRACE("seq", tout << ">>branch_unit_variable\n";); + return FC_CONTINUE; + } + if (branch_binary_variable() || branch_variable_mb()) { + ++m_stats.m_branch_variable; + TRACE("seq", tout << ">>branch_variable\n";); + return FC_CONTINUE; + } + if (branch_variable()) { ++m_stats.m_branch_variable; TRACE("seq", tout << ">>branch_variable\n";); return FC_CONTINUE; @@ -318,10 +334,9 @@ bool theory_seq::reduce_length_eq() { } bool theory_seq::branch_binary_variable() { - unsigned sz = m_eqs.size(); - for (unsigned i = 0; i < sz; ++i) { - eq const& e = m_eqs[i]; + for (eq const& e : m_eqs) { if (branch_binary_variable(e)) { + TRACE("seq", display_equation(tout, e);); return true; } } @@ -399,19 +414,21 @@ bool theory_seq::branch_binary_variable(eq const& e) { } bool theory_seq::branch_unit_variable() { - unsigned sz = m_eqs.size(); - for (unsigned i = 0; i < sz; ++i) { - eq const& e = m_eqs[i]; + bool result = false; + for (eq const& e : m_eqs) { if (is_unit_eq(e.ls(), e.rs())) { branch_unit_variable(e.dep(), e.ls()[0], e.rs()); - return true; + result = true; + break; } else if (is_unit_eq(e.rs(), e.ls())) { branch_unit_variable(e.dep(), e.rs()[0], e.ls()); - return true; + result = true; + break; } } - return false; + CTRACE("seq", result, tout << "branch unit variable";); + return result; } /** @@ -434,17 +451,20 @@ void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector context& ctx = get_context(); rational lenX; if (!get_length(X, lenX)) { + TRACE("seq", tout << "enforce length on " << mk_pp(X, m) << "\n";); enforce_length(ensure_enode(X)); return; } if (lenX > rational(units.size())) { expr_ref le(m_autil.mk_le(m_util.str.mk_length(X), m_autil.mk_int(units.size())), m); + TRACE("seq", tout << "propagate length on " << mk_pp(X, m) << "\n";); propagate_lit(dep, 0, 0, mk_literal(le)); return; } SASSERT(lenX.is_unsigned()); unsigned lX = lenX.get_unsigned(); if (lX == 0) { + TRACE("seq", tout << "set empty length " << mk_pp(X, m) << "\n";); set_empty(X); } else { @@ -454,8 +474,10 @@ void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector literal_vector lits; lits.push_back(lit); propagate_eq(dep, lits, X, R, true); + TRACE("seq", tout << "propagate " << mk_pp(X, m) << " " << R << "\n";); } else { + TRACE("seq", tout << "set phase " << mk_pp(X, m) << "\n";); ctx.mark_as_relevant(lit); ctx.force_phase(lit); } @@ -494,9 +516,11 @@ bool theory_seq::branch_variable_mb() { } if (split_lengths(e.dep(), e.ls(), e.rs(), len1, len2)) { TRACE("seq", tout << "split lengths\n";); - return true; + change = true; + break; } } + CTRACE("seq", change, tout << "branch_variable_mb\n";); return change; } @@ -651,6 +675,7 @@ bool theory_seq::branch_variable() { eq const& e = m_eqs[k]; if (branch_variable(e)) { + TRACE("seq", tout << "branch variable\n";); return true; } @@ -911,18 +936,14 @@ bool theory_seq::check_length_coherence0(expr* e) { bool theory_seq::check_length_coherence() { - obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); #if 1 - for (; it != end; ++it) { - expr* e = *it; + for (expr* e : m_length) { if (check_length_coherence0(e)) { return true; } } - it = m_length.begin(); #endif - for (; it != end; ++it) { - expr* e = *it; + for (expr* e : m_length) { if (check_length_coherence(e)) { return true; } @@ -931,10 +952,9 @@ bool theory_seq::check_length_coherence() { } bool theory_seq::fixed_length() { - obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); bool found = false; - for (; it != end; ++it) { - if (fixed_length(*it)) { + for (expr* e : m_length) { + if (fixed_length(e)) { found = true; } } @@ -1577,6 +1597,7 @@ bool theory_seq::reduce_length_eq(expr_ref_vector const& ls, expr_ref_vector con len2 += len; } if (len1 == len2 && 0 < j && j < rs.size() && reduce_length(1, j, true, ls, rs, deps)) { + TRACE("seq", tout << "l equal\n";); return true; } } @@ -1586,6 +1607,7 @@ bool theory_seq::reduce_length_eq(expr_ref_vector const& ls, expr_ref_vector con len2 += len; } if (len1 == len2 && 0 < j && j < ls.size() && reduce_length(j, 1, true, ls, rs, deps)) { + TRACE("seq", tout << "r equal\n";); return true; } } @@ -1595,6 +1617,7 @@ bool theory_seq::reduce_length_eq(expr_ref_vector const& ls, expr_ref_vector con len2 += len; } if (len1 == len2 && 0 < j && j < rs.size() && reduce_length(ls.size()-1, rs.size()-j, false, ls, rs, deps)) { + TRACE("seq", tout << "l suffix equal\n";); return true; } } @@ -1604,6 +1627,7 @@ bool theory_seq::reduce_length_eq(expr_ref_vector const& ls, expr_ref_vector con len2 += len; } if (len1 == len2 && 0 < j && j < ls.size() && reduce_length(ls.size()-j, rs.size()-1, false, ls, rs, deps)) { + TRACE("seq", tout << "r suffix equal\n";); return true; } } @@ -1641,6 +1665,7 @@ bool theory_seq::reduce_length(unsigned i, unsigned j, bool front, expr_ref_vect deps = mk_join(deps, lit); m_eqs.push_back(eq(m_eq_id++, lhs, rhs, deps)); propagate_eq(deps, lits, l, r, true); + TRACE("seq", tout << "propagate eq\nlhs: " << lhs << "\nrhs: " << rhs << "\n";); return true; } else { @@ -1681,6 +1706,7 @@ bool theory_seq::solve_binary_eq(expr_ref_vector const& ls, expr_ref_vector cons bool has_conflict = false; for (unsigned j = 0; !has_conflict && j < sz; ++j) { unsigned j1 = (offset + j) % sz; + if (xs[j] == ys[j1]) continue; literal eq = mk_eq(xs[j], ys[j1], false); switch (ctx.get_assignment(eq)) { case l_false: @@ -1891,7 +1917,7 @@ bool theory_seq::solve_ne(unsigned idx) { new_ls.push_back(ls); new_rs.push_back(rs); } - else { + else if (nl != nr) { literal lit(mk_eq(nl, nr, false)); ctx.mark_as_relevant(lit); new_lits.push_back(lit); @@ -2317,7 +2343,14 @@ bool theory_seq::add_stoi_axiom(expr* e) { rational val; TRACE("seq", tout << mk_pp(e, m) << "\n";); VERIFY(m_util.str.is_stoi(e, n)); - if (get_num_value(e, val) && !m_stoi_axioms.contains(val)) { + if (!get_num_value(e, val)) { + literal l = mk_literal(m_autil.mk_ge(e, arith_util(m).mk_int(-1))); + add_axiom(l); + TRACE("seq", tout << l << " " << ctx.get_assignment(l) << "\n"; + ctx.display(tout);); + return true; + } + if (!m_stoi_axioms.contains(val)) { m_stoi_axioms.insert(val); if (!val.is_minus_one()) { app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m); @@ -2463,12 +2496,11 @@ void theory_seq::display(std::ostream & out) const { } if (!m_re2aut.empty()) { out << "Regex\n"; - obj_map::iterator it = m_re2aut.begin(), end = m_re2aut.end(); - for (; it != end; ++it) { - out << mk_pp(it->m_key, m) << "\n"; + for (auto const& kv : m_re2aut) { + out << mk_pp(kv.m_key, m) << "\n"; display_expr disp(m); - if (it->m_value) { - it->m_value->display(out, disp); + if (kv.m_value) { + kv.m_value->display(out, disp); } } } @@ -2482,9 +2514,7 @@ void theory_seq::display(std::ostream & out) const { } if (!m_length.empty()) { - obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); - for (; it != end; ++it) { - expr* e = *it; + for (expr* e : m_length) { rational lo(-1), hi(-1); lower_bound(e, lo); upper_bound(e, hi); @@ -2509,8 +2539,8 @@ void theory_seq::display_nc(std::ostream& out, nc const& nc) const { } void theory_seq::display_equations(std::ostream& out) const { - for (unsigned i = 0; i < m_eqs.size(); ++i) { - display_equation(out, m_eqs[i]); + for (eq const& e : m_eqs) { + display_equation(out, e); } } @@ -2521,10 +2551,10 @@ void theory_seq::display_equation(std::ostream& out, eq const& e) const { void theory_seq::display_disequations(std::ostream& out) const { bool first = true; - for (unsigned i = 0; i < m_nqs.size(); ++i) { + for (ne const& n : m_nqs) { if (first) out << "Disequations:\n"; first = false; - display_disequation(out, m_nqs[i]); + display_disequation(out, n); } } @@ -2597,6 +2627,12 @@ void theory_seq::collect_statistics(::statistics & st) const { st.update("seq int.to.str", m_stats.m_int_string); } +void theory_seq::init_search_eh() { + m_re2aut.reset(); + m_res.reset(); + m_automata.reset(); +} + void theory_seq::init_model(expr_ref_vector const& es) { expr_ref new_s(m); for (expr* e : es) { @@ -3186,26 +3222,32 @@ void theory_seq::add_indexof_axiom(expr* i) { /* let r = replace(a, s, t) + a = "" => s = "" or r = a + contains(a, s) or r = a + s = "" => r = t+a + tightest_prefix(s, x) (contains(a, s) -> r = xty & a = xsy) & (!contains(a, s) -> r = a) */ void theory_seq::add_replace_axiom(expr* r) { + context& ctx = get_context(); expr* a = 0, *s = 0, *t = 0; VERIFY(m_util.str.is_replace(r, a, s, t)); expr_ref x = mk_skolem(m_indexof_left, a, s); expr_ref y = mk_skolem(m_indexof_right, a, s); expr_ref xty = mk_concat(x, t, y); expr_ref xsy = mk_concat(x, s, y); + literal a_emp = mk_eq_empty(a, true); + literal s_emp = mk_eq_empty(s, true); literal cnt = mk_literal(m_util.str.mk_contains(a, s)); - literal a_emp = mk_eq_empty(a); - literal s_emp = mk_eq_empty(s); add_axiom(~a_emp, s_emp, mk_seq_eq(r, a)); add_axiom(cnt, mk_seq_eq(r, a)); add_axiom(~s_emp, mk_seq_eq(r, mk_concat(t, a))); add_axiom(~cnt, a_emp, s_emp, mk_seq_eq(a, xsy)); add_axiom(~cnt, a_emp, s_emp, mk_seq_eq(r, xty)); + ctx.force_phase(cnt); tightest_prefix(s, x); } @@ -3347,15 +3389,21 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { return; } - eautomaton* a = get_automaton(e2); + expr_ref e3(e2, m); + context& ctx = get_context(); + literal lit = ctx.get_literal(n); + if (!is_true) { + e3 = m_util.re.mk_complement(e2); + lit.neg(); + } + eautomaton* a = get_automaton(e3); if (!a) return; - context& ctx = get_context(); expr_ref len(m_util.str.mk_length(e1), m); for (unsigned i = 0; i < a->num_states(); ++i) { - literal acc = mk_accept(e1, len, e2, i); - literal rej = mk_reject(e1, len, e2, i); + literal acc = mk_accept(e1, len, e3, i); + literal rej = mk_reject(e1, len, e3, i); add_axiom(a->is_final_state(i)?acc:~acc); add_axiom(a->is_final_state(i)?~rej:rej); } @@ -3364,27 +3412,17 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { unsigned_vector states; a->get_epsilon_closure(a->init(), states); literal_vector lits; - literal lit = ctx.get_literal(n); - if (is_true) { - lits.push_back(~lit); - } + lits.push_back(~lit); + for (unsigned i = 0; i < states.size(); ++i) { - if (is_true) { - lits.push_back(mk_accept(e1, zero, e2, states[i])); - } - else { - literal nlit = ~lit; - propagate_lit(0, 1, &nlit, mk_reject(e1, zero, e2, states[i])); - } + lits.push_back(mk_accept(e1, zero, e3, states[i])); } - if (is_true) { - if (lits.size() == 2) { - propagate_lit(0, 1, &lit, lits[1]); - } - else { - TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";); - ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); - } + if (lits.size() == 2) { + propagate_lit(0, 1, &lit, lits[1]); + } + else { + TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";); + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } } @@ -3405,56 +3443,71 @@ enode* theory_seq::ensure_enode(expr* e) { return n; } -static theory_mi_arith* get_th_arith(context& ctx, theory_id afid, expr* e) { +template +static T* get_th_arith(context& ctx, theory_id afid, expr* e) { theory* th = ctx.get_theory(afid); if (th && ctx.e_internalized(e)) { - return dynamic_cast(th); + return dynamic_cast(th); } else { return 0; } } +static bool get_arith_value(context& ctx, theory_id afid, expr* e, expr_ref& v) { + theory_mi_arith* tha = get_th_arith(ctx, afid, e); + if (tha) return tha->get_value(ctx.get_enode(e), v); + theory_i_arith* thi = get_th_arith(ctx, afid, e); + if (thi) return thi->get_value(ctx.get_enode(e), v); + TRACE("seq", tout << "no arithmetic theory\n";); + return false; +} + bool theory_seq::get_num_value(expr* e, rational& val) const { context& ctx = get_context(); - theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); expr_ref _val(m); - if (!tha) return false; + if (!ctx.e_internalized(e)) + return false; enode* next = ctx.get_enode(e), *n = next; do { - if (tha->get_value(next, _val) && m_autil.is_numeral(_val, val) && val.is_int()) { + if (get_arith_value(ctx, m_autil.get_family_id(), next->get_owner(), _val) && m_autil.is_numeral(_val, val) && val.is_int()) { return true; } next = next->get_next(); } while (next != n); + TRACE("seq", tout << "no value for " << mk_pp(e, m) << "\n";); return false; } bool theory_seq::lower_bound(expr* _e, rational& lo) const { context& ctx = get_context(); expr_ref e(m_util.str.mk_length(_e), m); - theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); expr_ref _lo(m); - if (!tha || !tha->get_lower(ctx.get_enode(e), _lo)) return false; + theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); + if (tha && !tha->get_lower(ctx.get_enode(e), _lo)) return false; + if (!tha) { + theory_i_arith* thi = get_th_arith(ctx, m_autil.get_family_id(), e); + if (!thi || !thi->get_lower(ctx.get_enode(e), _lo)) return false; + } return m_autil.is_numeral(_lo, lo) && lo.is_int(); } bool theory_seq::upper_bound(expr* _e, rational& hi) const { context& ctx = get_context(); expr_ref e(m_util.str.mk_length(_e), m); - theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); + theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); expr_ref _hi(m); - if (!tha || !tha->get_upper(ctx.get_enode(e), _hi)) return false; + if (tha && !tha->get_upper(ctx.get_enode(e), _hi)) return false; + if (!tha) { + theory_i_arith* thi = get_th_arith(ctx, m_autil.get_family_id(), e); + if (!thi || !thi->get_upper(ctx.get_enode(e), _hi)) return false; + } return m_autil.is_numeral(_hi, hi) && hi.is_int(); } bool theory_seq::get_length(expr* e, rational& val) const { context& ctx = get_context(); - theory* th = ctx.get_theory(m_autil.get_family_id()); - if (!th) return false; - theory_mi_arith* tha = dynamic_cast(th); - if (!tha) return false; rational val1; expr_ref len(m), len_val(m); expr* e1 = 0, *e2 = 0; @@ -3479,20 +3532,23 @@ bool theory_seq::get_length(expr* e, rational& val) const { val += rational(s.length()); } else if (!has_length(c)) { + TRACE("seq", tout << "literal has no length " << mk_pp(c, m) << "\n";); return false; } else { len = m_util.str.mk_length(c); if (ctx.e_internalized(len) && - tha->get_value(ctx.get_enode(len), len_val) && + get_arith_value(ctx, m_autil.get_family_id(), len, len_val) && m_autil.is_numeral(len_val, val1)) { val += val1; } else { + TRACE("seq", tout << "length has not been internalized " << mk_pp(c, m) << "\n";); return false; } } } + CTRACE("seq", !val.is_int(), tout << "length is not an integer\n";); return val.is_int(); } @@ -4113,10 +4169,8 @@ eautomaton* theory_seq::get_automaton(expr* re) { TRACE("seq", result->display(tout, disp);); } m_automata.push_back(result); - m_trail_stack.push(push_back_vector >(m_automata)); - m_re2aut.insert(re, result); - m_trail_stack.push(insert_obj_map(m_re2aut, re)); + m_res.push_back(re); return result; } @@ -4197,6 +4251,10 @@ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { if (m_util.str.is_length(idx)) return; SASSERT(m_autil.is_numeral(idx)); SASSERT(get_context().get_assignment(lit) == l_true); + if (aut->is_sink_state(src)) { + propagate_lit(0, 1, &lit, false_literal); + return; + } bool is_final = aut->is_final_state(src); if (is_final == is_acc) { propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index f7212e608..2ad257fd7 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -19,16 +19,16 @@ Revision History: #ifndef THEORY_SEQ_H_ #define THEORY_SEQ_H_ -#include "smt_theory.h" -#include "seq_decl_plugin.h" -#include "theory_seq_empty.h" -#include "th_rewriter.h" -#include "ast_trail.h" -#include "scoped_vector.h" -#include "scoped_ptr_vector.h" -#include "automaton.h" -#include "seq_rewriter.h" -#include "union_find.h" +#include "smt/smt_theory.h" +#include "ast/seq_decl_plugin.h" +#include "smt/theory_seq_empty.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/ast_trail.h" +#include "util/scoped_vector.h" +#include "util/scoped_ptr_vector.h" +#include "math/automata/automaton.h" +#include "ast/rewriter/seq_rewriter.h" +#include "util/union_find.h" namespace smt { @@ -45,7 +45,7 @@ namespace smt { typedef trail_stack th_trail_stack; typedef std::pair expr_dep; typedef obj_map eqdep_map_t; - typedef union_find th_union_find; + typedef union_find th_union_find; class seq_value_proc; @@ -298,8 +298,8 @@ namespace smt { scoped_vector m_eqs; // set of current equations. scoped_vector m_nqs; // set of current disequalities. scoped_vector m_ncs; // set of non-contains constraints. - unsigned m_eq_id; - th_union_find m_find; + unsigned m_eq_id; + th_union_find m_find; seq_factory* m_factory; // value factory exclusion_table m_exclude; // set of asserted disequalities. @@ -328,6 +328,7 @@ namespace smt { // maintain automata with regular expressions. scoped_ptr_vector m_automata; obj_map m_re2aut; + expr_ref_vector m_res; // queue of asserted atoms ptr_vector m_atoms; @@ -361,6 +362,7 @@ namespace smt { virtual void collect_statistics(::statistics & st) const; virtual model_value_proc * mk_value(enode * n, model_generator & mg); virtual void init_model(model_generator & mg); + virtual void init_search_eh(); void init_model(expr_ref_vector const& es); // final check @@ -582,7 +584,7 @@ namespace smt { // model building app* mk_value(app* a); - th_trail_stack& get_trail_stack() { return m_trail_stack; } + th_trail_stack& get_trail_stack() { return m_trail_stack; } void merge_eh(theory_var, theory_var, theory_var v1, theory_var v2) {} void after_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) { } void unmerge_eh(theory_var v1, theory_var v2) {} diff --git a/src/smt/theory_seq_empty.h b/src/smt/theory_seq_empty.h index 3f6c7f3e2..85408f7e5 100644 --- a/src/smt/theory_seq_empty.h +++ b/src/smt/theory_seq_empty.h @@ -19,8 +19,8 @@ Revision History: #ifndef THEORY_SEQ_EMPTY_H_ #define THEORY_SEQ_EMPTY_H_ -#include "smt_theory.h" -#include "seq_decl_plugin.h" +#include "smt/smt_theory.h" +#include "ast/seq_decl_plugin.h" namespace smt { class seq_factory : public value_factory { diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 0322b736d..ef8a65c2d 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -189,17 +189,18 @@ namespace smt { m_trail.push_back(e); //TRACE("str", tout << "done asserting " << mk_ismt2_pp(e, get_manager()) << std::endl;); + } expr * theory_str::rewrite_implication(expr * premise, expr * conclusion) { ast_manager & m = get_manager(); - return m.mk_or(m.mk_not(premise), conclusion); + return m.mk_or(mk_not(m, premise), conclusion); } void theory_str::assert_implication(expr * premise, expr * conclusion) { ast_manager & m = get_manager(); TRACE("str", tout << "asserting implication " << mk_ismt2_pp(premise, m) << " -> " << mk_ismt2_pp(conclusion, m) << std::endl;); - expr_ref axiom(m.mk_or(m.mk_not(premise), conclusion), m); + expr_ref axiom(m.mk_or(mk_not(m, premise), conclusion), m); assert_axiom(axiom); } @@ -318,6 +319,7 @@ namespace smt { m_trail.push_back(node); if (!cut_var_map.contains(baseNode)) { T_cut * varInfo = alloc(T_cut); + m_cut_allocs.push_back(varInfo); varInfo->level = slevel; varInfo->vars[node] = 1; cut_var_map.insert(baseNode, std::stack()); @@ -326,6 +328,7 @@ namespace smt { } else { if (cut_var_map[baseNode].empty()) { T_cut * varInfo = alloc(T_cut); + m_cut_allocs.push_back(varInfo); varInfo->level = slevel; varInfo->vars[node] = 1; cut_var_map[baseNode].push(varInfo); @@ -333,6 +336,7 @@ namespace smt { } else { if (cut_var_map[baseNode].top()->level < slevel) { T_cut * varInfo = alloc(T_cut); + m_cut_allocs.push_back(varInfo); varInfo->level = slevel; cut_vars_map_copy(varInfo->vars, cut_var_map[baseNode].top()->vars); varInfo->vars[node] = 1; @@ -362,6 +366,7 @@ namespace smt { if (!cut_var_map.contains(destNode)) { T_cut * varInfo = alloc(T_cut); + m_cut_allocs.push_back(varInfo); varInfo->level = slevel; cut_vars_map_copy(varInfo->vars, cut_var_map[srcNode].top()->vars); cut_var_map.insert(destNode, std::stack()); @@ -370,6 +375,7 @@ namespace smt { } else { if (cut_var_map[destNode].empty() || cut_var_map[destNode].top()->level < slevel) { T_cut * varInfo = alloc(T_cut); + m_cut_allocs.push_back(varInfo); varInfo->level = slevel; cut_vars_map_copy(varInfo->vars, cut_var_map[destNode].top()->vars); cut_vars_map_copy(varInfo->vars, cut_var_map[srcNode].top()->vars); @@ -543,7 +549,7 @@ namespace smt { context & ctx = get_context(); ast_manager & m = get_manager(); - expr_ref ax1(m.mk_not(ctx.mk_eq_atom(s, mk_string(""))), m); + expr_ref ax1(mk_not(m, ctx.mk_eq_atom(s, mk_string(""))), m); assert_axiom(ax1); { @@ -555,7 +561,7 @@ namespace smt { SASSERT(zero); // build LHS > RHS and assert // we have to build !(LHS <= RHS) instead - expr_ref lhs_gt_rhs(m.mk_not(m_autil.mk_le(len_str, zero)), m); + expr_ref lhs_gt_rhs(mk_not(m, m_autil.mk_le(len_str, zero)), m); SASSERT(lhs_gt_rhs); assert_axiom(lhs_gt_rhs); } @@ -590,7 +596,7 @@ namespace smt { SASSERT(zero); // build LHS > RHS and assert // we have to build !(LHS <= RHS) instead - expr_ref lhs_gt_rhs(m.mk_not(m_autil.mk_le(len_str, zero)), m); + expr_ref lhs_gt_rhs(mk_not(m, m_autil.mk_le(len_str, zero)), m); SASSERT(lhs_gt_rhs); assert_axiom(lhs_gt_rhs); } @@ -1087,7 +1093,7 @@ namespace smt { m_autil.mk_ge(expr->get_arg(1), mk_int(0)), // REWRITE for arithmetic theory: // m_autil.mk_lt(expr->get_arg(1), mk_strlen(expr->get_arg(0))) - m.mk_not(m_autil.mk_ge(m_autil.mk_add(expr->get_arg(1), m_autil.mk_mul(mk_int(-1), mk_strlen(expr->get_arg(0)))), mk_int(0))) + mk_not(m, m_autil.mk_ge(m_autil.mk_add(expr->get_arg(1), m_autil.mk_mul(mk_int(-1), mk_strlen(expr->get_arg(0)))), mk_int(0))) ), m); expr_ref_vector and_item(m); @@ -1128,7 +1134,7 @@ namespace smt { expr_ref_vector innerItems(m); innerItems.push_back(ctx.mk_eq_atom(expr->get_arg(1), mk_concat(ts0, ts1))); innerItems.push_back(ctx.mk_eq_atom(mk_strlen(ts0), mk_strlen(expr->get_arg(0)))); - innerItems.push_back(m.mk_ite(ctx.mk_eq_atom(ts0, expr->get_arg(0)), expr, m.mk_not(expr))); + innerItems.push_back(m.mk_ite(ctx.mk_eq_atom(ts0, expr->get_arg(0)), expr, mk_not(m, expr))); expr_ref then1(m.mk_and(innerItems.size(), innerItems.c_ptr()), m); SASSERT(then1); @@ -1141,7 +1147,7 @@ namespace smt { , m); SASSERT(topLevelCond); - expr_ref finalAxiom(m.mk_ite(topLevelCond, then1, m.mk_not(expr)), m); + expr_ref finalAxiom(m.mk_ite(topLevelCond, then1, mk_not(m, expr)), m); SASSERT(finalAxiom); assert_axiom(finalAxiom); } @@ -1165,7 +1171,7 @@ namespace smt { expr_ref_vector innerItems(m); innerItems.push_back(ctx.mk_eq_atom(expr->get_arg(1), mk_concat(ts0, ts1))); innerItems.push_back(ctx.mk_eq_atom(mk_strlen(ts1), mk_strlen(expr->get_arg(0)))); - innerItems.push_back(m.mk_ite(ctx.mk_eq_atom(ts1, expr->get_arg(0)), expr, m.mk_not(expr))); + innerItems.push_back(m.mk_ite(ctx.mk_eq_atom(ts1, expr->get_arg(0)), expr, mk_not(m, expr))); expr_ref then1(m.mk_and(innerItems.size(), innerItems.c_ptr()), m); SASSERT(then1); @@ -1178,7 +1184,7 @@ namespace smt { , m); SASSERT(topLevelCond); - expr_ref finalAxiom(m.mk_ite(topLevelCond, then1, m.mk_not(expr)), m); + expr_ref finalAxiom(m.mk_ite(topLevelCond, then1, mk_not(m, expr)), m); SASSERT(finalAxiom); assert_axiom(finalAxiom); } @@ -1202,7 +1208,7 @@ namespace smt { if (haystackStr.contains(needleStr)) { assert_axiom(ex); } else { - assert_axiom(m.mk_not(ex)); + assert_axiom(mk_not(m, ex)); } return; } @@ -1263,7 +1269,7 @@ namespace smt { SASSERT(tmpLen); thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); - thenItems.push_back(m.mk_not(mk_contains(x3, expr->get_arg(1)))); + thenItems.push_back(mk_not(m, mk_contains(x3, expr->get_arg(1)))); expr_ref thenBranch(m.mk_and(thenItems.size(), thenItems.c_ptr()), m); SASSERT(thenBranch); @@ -1339,7 +1345,7 @@ namespace smt { expr_ref ite1(m.mk_ite( //m_autil.mk_lt(expr->get_arg(2), zeroAst), - m.mk_not(m_autil.mk_ge(expr->get_arg(2), zeroAst)), + mk_not(m, m_autil.mk_ge(expr->get_arg(2), zeroAst)), ctx.mk_eq_atom(resAst, mk_indexof(expr->get_arg(0), expr->get_arg(1))), ite2 ), m); @@ -1382,7 +1388,7 @@ namespace smt { thenItems.push_back(m_autil.mk_ge(indexAst, mk_int(0))); // args[0] = x1 . args[1] . x2 // x1 doesn't contain args[1] - thenItems.push_back(m.mk_not(mk_contains(x2, expr->get_arg(1)))); + thenItems.push_back(mk_not(m, mk_contains(x2, expr->get_arg(1)))); thenItems.push_back(ctx.mk_eq_atom(indexAst, mk_strlen(x1))); bool canSkip = false; @@ -1400,7 +1406,7 @@ namespace smt { expr_ref tmpLen(m_autil.mk_add(indexAst, mk_int(1)), m); thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); - thenItems.push_back(m.mk_not(mk_contains(x4, expr->get_arg(1)))); + thenItems.push_back(mk_not(m, mk_contains(x4, expr->get_arg(1)))); } //---------------------------- // else branch @@ -1448,9 +1454,10 @@ namespace smt { argumentsValid_terms.push_back(m_autil.mk_ge(substrPos, zero)); // pos < strlen(base) // --> pos + -1*strlen(base) < 0 - argumentsValid_terms.push_back(m.mk_not(m_autil.mk_ge( + argumentsValid_terms.push_back(mk_not(m, m_autil.mk_ge( m_autil.mk_add(substrPos, m_autil.mk_mul(minusOne, substrLen)), zero))); + // len >= 0 argumentsValid_terms.push_back(m_autil.mk_ge(substrLen, zero)); @@ -1480,6 +1487,7 @@ namespace smt { // Case 3: (pos >= 0 and pos < strlen(base) and len >= 0) and (pos+len) < strlen(base) // ==> base = t2.t3.t4 AND len(t2) = pos AND len(t3) = len AND (Substr ...) = t3 + expr_ref t2(mk_str_var("t2"), m); expr_ref t3(mk_str_var("t3"), m); expr_ref t4(mk_str_var("t4"), m); @@ -1541,7 +1549,7 @@ namespace smt { expr_ref tmpLen(m_autil.mk_add(i1, mk_strlen(expr->get_arg(1)), mk_int(-1)), m); thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); - thenItems.push_back(m.mk_not(mk_contains(x3, expr->get_arg(1)))); + thenItems.push_back(mk_not(m, mk_contains(x3, expr->get_arg(1)))); thenItems.push_back(ctx.mk_eq_atom(result, mk_concat(x1, mk_concat(expr->get_arg(2), x2)))); // ----------------------- // false branch @@ -1599,7 +1607,7 @@ namespace smt { expr_ref tl(mk_str_var("tl"), m); expr_ref conclusion1(ctx.mk_eq_atom(S, mk_concat(hd, tl)), m); expr_ref conclusion2(ctx.mk_eq_atom(mk_strlen(hd), m_autil.mk_numeral(rational::one(), true)), m); - expr_ref conclusion3(m.mk_not(ctx.mk_eq_atom(hd, mk_string("0"))), m); + expr_ref conclusion3(mk_not(m, ctx.mk_eq_atom(hd, mk_string("0"))), m); expr_ref conclusion(m.mk_and(conclusion1, conclusion2, conclusion3), m); SASSERT(premise); SASSERT(conclusion); @@ -1623,7 +1631,7 @@ namespace smt { // axiom 1: N < 0 <==> (str.from-int N) = "" expr * N = ex->get_arg(0); { - expr_ref axiom1_lhs(m.mk_not(m_autil.mk_ge(N, m_autil.mk_numeral(rational::zero(), true))), m); + expr_ref axiom1_lhs(mk_not(m, m_autil.mk_ge(N, m_autil.mk_numeral(rational::zero(), true))), m); expr_ref axiom1_rhs(ctx.mk_eq_atom(ex, mk_string("")), m); expr_ref axiom1(ctx.mk_eq_atom(axiom1_lhs, axiom1_rhs), m); SASSERT(axiom1); @@ -1686,6 +1694,8 @@ namespace smt { u.str.is_string(range1, range1val); u.str.is_string(range2, range2val); return zstring("[") + range1val + zstring("-") + range2val + zstring("]"); + } else if (u.re.is_full(a_regex)) { + return zstring("(.*)"); } else { TRACE("str", tout << "BUG: unrecognized regex term " << mk_pp(regex, get_manager()) << std::endl;); UNREACHABLE(); return zstring(""); @@ -1716,6 +1726,12 @@ namespace smt { expr_ref str(ex->get_arg(0), m); app * regex = to_app(ex->get_arg(1)); + // quick reference for the following code: + // - ex: top-level regex membership term + // - str: string term appearing in ex + // - regex: regex term appearing in ex + // ex ::= (str.in.re str regex) + if (u.re.is_to_re(regex)) { expr_ref rxStr(regex->get_arg(0), m); // want to assert 'expr IFF (str == rxStr)' @@ -1795,6 +1811,9 @@ namespace smt { expr_ref finalAxiom(m.mk_iff(ex, rhs), m); SASSERT(finalAxiom); assert_axiom(finalAxiom); + } else if (u.re.is_full(regex)) { + // trivially true for any string! + assert_axiom(ex); } else { TRACE("str", tout << "ERROR: unknown regex expression " << mk_pp(regex, m) << "!" << std::endl;); NOT_IMPLEMENTED_YET(); @@ -1851,7 +1870,7 @@ namespace smt { // inconsistency check: value if (!can_two_nodes_eq(eqc_nn1, eqc_nn2)) { TRACE("str", tout << "inconsistency detected: " << mk_pp(eqc_nn1, m) << " cannot be equal to " << mk_pp(eqc_nn2, m) << std::endl;); - expr_ref to_assert(m.mk_not(ctx.mk_eq_atom(eqc_nn1, eqc_nn2)), m); + expr_ref to_assert(mk_not(m, ctx.mk_eq_atom(eqc_nn1, eqc_nn2)), m); assert_axiom(to_assert); // this shouldn't use the integer theory at all, so we don't allow the option of quick-return return false; @@ -2064,7 +2083,7 @@ namespace smt { expr_ref implyR11(ctx.mk_eq_atom(mk_strlen(arg1), mk_int(makeUpLenArg1)), m); assert_implication(implyL11, implyR11); } else { - expr_ref neg(m.mk_not(implyL11), m); + expr_ref neg(mk_not(m, implyL11), m); assert_axiom(neg); } } @@ -2135,7 +2154,7 @@ namespace smt { expr_ref implyR11(ctx.mk_eq_atom(mk_strlen(arg0), mk_int(makeUpLenArg0)), m); assert_implication(implyL11, implyR11); } else { - expr_ref neg(m.mk_not(implyL11), m); + expr_ref neg(mk_not(m, implyL11), m); assert_axiom(neg); } } @@ -2666,7 +2685,7 @@ namespace smt { } if (!can_two_nodes_eq(new_nn1, new_nn2)) { - expr_ref detected(m.mk_not(ctx.mk_eq_atom(new_nn1, new_nn2)), m); + expr_ref detected(mk_not(m, ctx.mk_eq_atom(new_nn1, new_nn2)), m); TRACE("str", tout << "inconsistency detected: " << mk_ismt2_pp(detected, m) << std::endl;); assert_axiom(detected); return; @@ -4656,12 +4675,10 @@ namespace smt { bool theory_str::get_arith_value(expr* e, rational& val) const { context& ctx = get_context(); ast_manager & m = get_manager(); - - // safety - if (!ctx.e_internalized(e)) { + // safety + if (!ctx.e_internalized(e)) { return false; - } - + } // if an integer constant exists in the eqc, it should be the root enode * en_e = ctx.get_enode(e); enode * root_e = en_e->get_root(); @@ -4671,6 +4688,11 @@ namespace smt { } else { TRACE("str", tout << "root of eqc of " << mk_pp(e, m) << " is not a numeral" << std::endl;); return false; + theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); + if (!tha) return false; + expr_ref val_e(m); + if (tha->get_value(root_e, val_e) && m_autil.is_numeral(val_e, val) && val.is_int()) return true; + return false; } } @@ -4907,7 +4929,7 @@ namespace smt { implyR = boolVar; } else { //implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx)); - implyR = m.mk_not(boolVar); + implyR = mk_not(m, boolVar); } } else { // ------------------------------------------------------------------------------------------------ @@ -4936,7 +4958,7 @@ namespace smt { litems.push_back(ctx.mk_eq_atom(substrAst, aConcat)); } //implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx)); - implyR = m.mk_not(boolVar); + implyR = mk_not(m, boolVar); break; } } @@ -4975,7 +4997,7 @@ namespace smt { implyR = boolVar; } else { // implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx)); - implyR = m.mk_not(boolVar); + implyR = mk_not(m, boolVar); } } @@ -5045,7 +5067,7 @@ namespace smt { litems.push_back(ctx.mk_eq_atom(substrAst, aConcat)); } expr_ref implyLHS(mk_and(litems), m); - expr_ref implyR(m.mk_not(boolVar), m); + expr_ref implyR(mk_not(m, boolVar), m); assert_implication(implyLHS, implyR); break; } @@ -6190,24 +6212,31 @@ namespace smt { expr * arg_str = a->get_arg(0); zstring str; if (u.str.is_string(arg_str, str)) { - TRACE("str", tout << "build NFA for '" << str << "'" << "\n";); - /* - * For an n-character string, we make (n-1) intermediate states, - * labelled i_(0) through i_(n-2). - * Then we construct the following transitions: - * start --str[0]--> i_(0) --str[1]--> i_(1) --...--> i_(n-2) --str[n-1]--> final - */ - unsigned last = start; - for (int i = 0; i <= ((int)str.length()) - 2; ++i) { - unsigned i_state = next_id(); - make_transition(last, str[i], i_state); - TRACE("str", tout << "string transition " << last << "--" << str[i] << "--> " << i_state << "\n";); - last = i_state; + if (str.length() == 0) { + // transitioning on the empty string is handled specially + TRACE("str", tout << "empty string epsilon-move " << start << " --> " << end << std::endl;); + make_epsilon_move(start, end); + } else { + TRACE("str", tout << "build NFA for '" << str << "'" << "\n";); + /* + * For an n-character string, we make (n-1) intermediate states, + * labelled i_(0) through i_(n-2). + * Then we construct the following transitions: + * start --str[0]--> i_(0) --str[1]--> i_(1) --...--> i_(n-2) --str[n-1]--> final + */ + unsigned last = start; + for (int i = 0; i <= ((int)str.length()) - 2; ++i) { + unsigned i_state = next_id(); + make_transition(last, str[i], i_state); + TRACE("str", tout << "string transition " << last << "--" << str[i] << "--> " << i_state << "\n";); + last = i_state; + } + make_transition(last, str[(str.length() - 1)], end); + TRACE("str", tout << "string transition " << last << "--" << str[(str.length() - 1)] << "--> " << end << "\n";); } - make_transition(last, str[(str.length() - 1)], end); - TRACE("str", tout << "string transition " << last << "--" << str[(str.length() - 1)] << "--> " << end << "\n";); - } else { - TRACE("str", tout << "invalid string constant in Str2Reg" << std::endl;); + } else { // ! u.str.is_string(arg_str, str) + TRACE("str", tout << "WARNING: invalid string constant in str.to.re! Cancelling." << std::endl;); + u.get_manager().raise_exception("invalid term in str.to.re, argument must be a string constant"); m_valid = false; return; } @@ -6279,6 +6308,19 @@ namespace smt { } TRACE("str", tout << "range NFA: start = " << start << ", end = " << end << std::endl;); + } else if (u.re.is_full(e)) { + // effectively the same as .* where . can be any single character + // start --e--> tmp + // tmp --e--> end + // tmp --C--> tmp for every character C + unsigned tmp = next_id(); + make_epsilon_move(start, tmp); + make_epsilon_move(tmp, end); + for (unsigned int i = 0; i < 256; ++i) { + char ch = (char)i; + make_transition(tmp, ch, tmp); + } + TRACE("str", tout << "re.all NFA: start = " << start << ", end = " << end << std::endl;); } else { TRACE("str", tout << "invalid regular expression" << std::endl;); m_valid = false; @@ -6394,7 +6436,7 @@ namespace smt { if (matchRes) { assert_implication(implyL, boolVar); } else { - assert_implication(implyL, m.mk_not(boolVar)); + assert_implication(implyL, mk_not(m, boolVar)); } } } @@ -6482,7 +6524,7 @@ namespace smt { << arg1_str << "\" + \"" << arg2_str << "\" != \"" << const_str << "\"" << "\n";); expr_ref equality(ctx.mk_eq_atom(concat, str), m); - expr_ref diseq(m.mk_not(equality), m); + expr_ref diseq(mk_not(m, equality), m); assert_axiom(diseq); return; } @@ -6500,7 +6542,7 @@ namespace smt { "\" is longer than \"" << const_str << "\"," << " so cannot be concatenated with anything to form it" << "\n";); expr_ref equality(ctx.mk_eq_atom(newConcat, str), m); - expr_ref diseq(m.mk_not(equality), m); + expr_ref diseq(mk_not(m, equality), m); assert_axiom(diseq); return; } else { @@ -6514,7 +6556,7 @@ namespace smt { << "actually \"" << arg2_str << "\"" << "\n";); expr_ref equality(ctx.mk_eq_atom(newConcat, str), m); - expr_ref diseq(m.mk_not(equality), m); + expr_ref diseq(mk_not(m, equality), m); assert_axiom(diseq); return; } else { @@ -6912,7 +6954,7 @@ namespace smt { ast_manager & m = get_manager(); if (lenTester_fvar_map.contains(lenTester)) { expr * fVar = lenTester_fvar_map[lenTester]; - expr_ref toAssert(gen_len_val_options_for_free_var(fVar, lenTester, lenTesterValue), m); + expr_ref toAssert(gen_len_val_options_for_free_var(fVar, lenTester, lenTesterValue), m); TRACE("str", tout << "asserting more length tests for free variable " << mk_ismt2_pp(fVar, m) << std::endl;); if (toAssert) { assert_axiom(toAssert); @@ -8451,7 +8493,7 @@ namespace smt { } else { TRACE("str", tout << "integer theory has no assignment for " << mk_pp(a, m) << std::endl;); expr_ref is_zero(ctx.mk_eq_atom(a, m_autil.mk_int(0)), m); - literal is_zero_l = mk_literal(is_zero); + /* literal is_zero_l = */ mk_literal(is_zero); axiomAdd = true; TRACE("str", ctx.display(tout);); // NOT_IMPLEMENTED_YET(); @@ -8767,15 +8809,30 @@ namespace smt { if (concat_lhs_haseqc && concat_rhs_haseqc && !var_haseqc) { TRACE("str", tout << "backpropagate into " << mk_pp(var, m) << " = " << mk_pp(concat, m) << std::endl << "LHS ~= " << mk_pp(concat_lhs_str, m) << " RHS ~= " << mk_pp(concat_rhs_str, m) << std::endl;); + zstring lhsString, rhsString; u.str.is_string(concat_lhs_str, lhsString); u.str.is_string(concat_rhs_str, rhsString); zstring concatString = lhsString + rhsString; - expr_ref lhs1(ctx.mk_eq_atom(concat_lhs, concat_lhs_str), m); - expr_ref lhs2(ctx.mk_eq_atom(concat_rhs, concat_rhs_str), m); - expr_ref lhs(m.mk_and(lhs1, lhs2), m); - expr_ref rhs(ctx.mk_eq_atom(concat, mk_string(concatString)), m); - assert_implication(lhs, rhs); + + // special handling: don't assert that string constants are equal to themselves + expr_ref_vector lhs_terms(m); + if (!u.str.is_string(concat_lhs)) { + lhs_terms.push_back(ctx.mk_eq_atom(concat_lhs, concat_lhs_str)); + } + if (!u.str.is_string(concat_rhs)) { + lhs_terms.push_back(ctx.mk_eq_atom(concat_rhs, concat_rhs_str)); + } + + if (lhs_terms.empty()) { + // no assumptions on LHS + expr_ref rhs(ctx.mk_eq_atom(concat, mk_string(concatString)), m); + assert_axiom(rhs); + } else { + expr_ref lhs(mk_and(lhs_terms), m); + expr_ref rhs(ctx.mk_eq_atom(concat, mk_string(concatString)), m); + assert_implication(lhs, rhs); + } backpropagation_occurred = true; } } diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 7f39efa70..acac8cad1 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -17,19 +17,21 @@ #ifndef _THEORY_STR_H_ #define _THEORY_STR_H_ -#include"smt_theory.h" -#include"theory_str_params.h" -#include"trail.h" -#include"th_rewriter.h" -#include"value_factory.h" -#include"smt_model_generator.h" -#include"arith_decl_plugin.h" +#include "util/trail.h" +#include "util/union_find.h" +#include "util/scoped_ptr_vector.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/seq_decl_plugin.h" +#include "smt/smt_theory.h" +#include "smt/params/theory_str_params.h" +#include "smt/proto_model/value_factory.h" +#include "smt/smt_model_generator.h" #include #include #include #include -#include"seq_decl_plugin.h" -#include"union_find.h" namespace smt { @@ -291,6 +293,7 @@ protected: bool avoidLoopCut; bool loopDetected; obj_map > cut_var_map; + scoped_ptr_vector m_cut_allocs; expr_ref m_theoryStrOverlapAssumption_term; obj_hashtable variable_set; diff --git a/src/smt/theory_utvpi.cpp b/src/smt/theory_utvpi.cpp index 9da82c9e6..1f56b748b 100644 --- a/src/smt/theory_utvpi.cpp +++ b/src/smt/theory_utvpi.cpp @@ -14,8 +14,8 @@ Revision History: The implementaton is derived from theory_diff_logic. --*/ -#include "theory_utvpi.h" -#include "theory_utvpi_def.h" +#include "smt/theory_utvpi.h" +#include "smt/theory_utvpi_def.h" namespace smt { diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h index 35ebd440b..55bbb9838 100644 --- a/src/smt/theory_utvpi.h +++ b/src/smt/theory_utvpi.h @@ -22,7 +22,7 @@ Revision History: #ifndef THEORY_UTVPI_H_ #define THEORY_UTVPI_H_ -#include"theory_diff_logic.h" +#include "smt/theory_diff_logic.h" namespace smt { diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index 5f370c29c..7c1edb585 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -49,10 +49,10 @@ Revision History: #ifndef THEORY_UTVPI_DEF_H_ #define THEORY_UTVPI_DEF_H_ -#include "theory_utvpi.h" -#include "heap.h" -#include "ast_pp.h" -#include "smt_context.h" +#include "smt/theory_utvpi.h" +#include "util/heap.h" +#include "ast/ast_pp.h" +#include "smt/smt_context.h" namespace smt { diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 3f153f500..88ba89610 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -18,10 +18,10 @@ Notes: --*/ #include -#include "smt_context.h" -#include "ast_pp.h" -#include "theory_wmaxsat.h" -#include "smt_justification.h" +#include "smt/smt_context.h" +#include "ast/ast_pp.h" +#include "smt/theory_wmaxsat.h" +#include "smt/smt_justification.h" namespace smt { diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index 0f711b9f8..739a22c71 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -20,9 +20,9 @@ Notes: #ifndef THEORY_WMAXSAT_H_ #define THEORY_WMAXSAT_H_ -#include "smt_theory.h" -#include "smt_clause.h" -#include "filter_model_converter.h" +#include "smt/smt_theory.h" +#include "smt/smt_clause.h" +#include "tactic/filter_model_converter.h" namespace smt { class theory_wmaxsat : public theory { diff --git a/src/smt/uses_theory.cpp b/src/smt/uses_theory.cpp index 5b736f75a..517951a7b 100644 --- a/src/smt/uses_theory.cpp +++ b/src/smt/uses_theory.cpp @@ -17,8 +17,8 @@ Revision History: --*/ -#include"uses_theory.h" -#include"for_each_expr.h" +#include "smt/uses_theory.h" +#include "ast/for_each_expr.h" bool uses_theory(expr * n, family_id fid) { expr_mark visited; diff --git a/src/smt/uses_theory.h b/src/smt/uses_theory.h index 8f3760e3e..948d05f77 100644 --- a/src/smt/uses_theory.h +++ b/src/smt/uses_theory.h @@ -19,7 +19,7 @@ Revision History: #ifndef USES_THEORY_H_ #define USES_THEORY_H_ -#include"ast.h" +#include "ast/ast.h" /** \brief Return true if the given expression contains a symbol of the given theory. diff --git a/src/smt/watch_list.cpp b/src/smt/watch_list.cpp index ed73b9ed5..edd6923d7 100644 --- a/src/smt/watch_list.cpp +++ b/src/smt/watch_list.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"watch_list.h" +#include "smt/watch_list.h" namespace smt { @@ -36,10 +36,10 @@ namespace smt { void watch_list::expand() { if (m_data == 0) { - unsigned size = DEFAULT_WATCH_LIST_SIZE + HEADER_SIZE; + unsigned size = DEFAULT_WATCH_LIST_SIZE + HEADER_SIZE; unsigned * mem = reinterpret_cast(alloc_svect(char, size)); #ifdef _AMD64_ - ++mem; // make sure data is aligned in 64 bit machines + ++mem; // make sure data is aligned in 64 bit machines #endif *mem = 0; ++mem; @@ -62,9 +62,9 @@ namespace smt { unsigned * mem = reinterpret_cast(alloc_svect(char, new_capacity + HEADER_SIZE)); unsigned curr_end_cls = end_cls_core(); #ifdef _AMD64_ - ++mem; // make sure data is aligned in 64 bit machines + ++mem; // make sure data is aligned in 64 bit machines #endif - *mem = curr_end_cls; + *mem = curr_end_cls; ++mem; SASSERT(bin_bytes <= new_capacity); unsigned new_begin_bin = new_capacity - bin_bytes; diff --git a/src/smt/watch_list.h b/src/smt/watch_list.h index 2af26695f..1cc29da5a 100644 --- a/src/smt/watch_list.h +++ b/src/smt/watch_list.h @@ -19,8 +19,8 @@ Revision History: #ifndef WATCH_LIST_H_ #define WATCH_LIST_H_ -#include"smt_clause.h" -#include"memory_manager.h" +#include "smt/smt_clause.h" +#include "util/memory_manager.h" namespace smt { @@ -85,6 +85,10 @@ namespace smt { watch_list(): m_data(0) { } + + watch_list(watch_list && other) : m_data(0) { + std::swap(m_data, other.m_data); + } ~watch_list() { destroy(); diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index 56864a691..1ffdc35e1 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -6,6 +6,7 @@ z3_add_component(solver smt_logics.cpp solver.cpp solver_na2as.cpp + solver_pool.cpp solver2tactic.cpp tactic2solver.cpp COMPONENT_DEPENDENCIES diff --git a/src/solver/check_sat_result.cpp b/src/solver/check_sat_result.cpp index 7a248e8b1..f1bedfc08 100644 --- a/src/solver/check_sat_result.cpp +++ b/src/solver/check_sat_result.cpp @@ -16,7 +16,25 @@ Author: Notes: --*/ -#include"check_sat_result.h" +#include "solver/check_sat_result.h" + +void check_sat_result::set_reason_unknown(event_handler& eh) { + switch (eh.caller_id()) { + case UNSET_EH_CALLER: break; + case CTRL_C_EH_CALLER: + set_reason_unknown("interrupted from keyboard"); + break; + case TIMEOUT_EH_CALLER: + set_reason_unknown("timeout"); + break; + case RESLIMIT_EH_CALLER: + set_reason_unknown("max. resource limit exceeded"); + break; + case API_INTERRUPT_EH_CALLER: + set_reason_unknown("interrupted"); + break; + } +} simple_check_sat_result::simple_check_sat_result(ast_manager & m): m_core(m), diff --git a/src/solver/check_sat_result.h b/src/solver/check_sat_result.h index 36eadd97d..38720a5e9 100644 --- a/src/solver/check_sat_result.h +++ b/src/solver/check_sat_result.h @@ -19,9 +19,10 @@ Notes: #ifndef CHECK_SAT_RESULT_H_ #define CHECK_SAT_RESULT_H_ -#include"model.h" -#include"lbool.h" -#include"statistics.h" +#include "model/model.h" +#include "util/lbool.h" +#include "util/statistics.h" +#include "util/event_handler.h" /** \brief Abstract interface for the result of a (check-sat) like command. @@ -57,6 +58,7 @@ public: virtual proof * get_proof() = 0; virtual std::string reason_unknown() const = 0; virtual void set_reason_unknown(char const* msg) = 0; + void set_reason_unknown(event_handler& eh); virtual void get_labels(svector & r) = 0; virtual ast_manager& get_manager() const = 0; diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index d67643edf..81e10e443 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -18,10 +18,10 @@ Author: Notes: --*/ -#include"solver.h" -#include"scoped_timer.h" -#include"combined_solver_params.hpp" -#include"common_msgs.h" +#include "solver/solver.h" +#include "util/scoped_timer.h" +#include "solver/combined_solver_params.hpp" +#include "util/common_msgs.h" #define PS_VB_LVL 15 /** @@ -89,8 +89,8 @@ private: m_solver->get_manager().limit().dec_cancel(); } } - virtual void operator()() { - m_canceled = true; + virtual void operator()(event_handler_caller_t caller_id) { + m_canceled = true; m_solver->get_manager().limit().inc_cancel(); } }; @@ -147,6 +147,7 @@ public: } virtual void updt_params(params_ref const & p) { + solver::updt_params(p); m_solver1->updt_params(p); m_solver2->updt_params(p); updt_local_params(p); @@ -280,8 +281,8 @@ public: return m_solver2->get_assumption(idx - c1); } - virtual std::ostream& display(std::ostream & out) const { - return m_solver1->display(out); + virtual std::ostream& display(std::ostream & out, unsigned n, expr* const* es) const { + return m_solver1->display(out, n, es); } virtual void collect_statistics(statistics & st) const { diff --git a/src/solver/combined_solver.h b/src/solver/combined_solver.h index a10bf343f..70637070c 100644 --- a/src/solver/combined_solver.h +++ b/src/solver/combined_solver.h @@ -21,7 +21,7 @@ Notes: #ifndef COMBINED_SOLVER_H_ #define COMBINED_SOLVER_H_ -#include"params.h" +#include "util/params.h" class solver; class solver_factory; diff --git a/src/solver/mus.cpp b/src/solver/mus.cpp index d536a191b..7eb692567 100644 --- a/src/solver/mus.cpp +++ b/src/solver/mus.cpp @@ -18,11 +18,11 @@ Notes: --*/ -#include "solver.h" -#include "mus.h" -#include "ast_pp.h" -#include "ast_util.h" -#include "model_evaluator.h" +#include "solver/solver.h" +#include "solver/mus.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "model/model_evaluator.h" struct mus::imp { diff --git a/src/solver/smt_logics.cpp b/src/solver/smt_logics.cpp index 2bb364b6a..874f1cfcc 100644 --- a/src/solver/smt_logics.cpp +++ b/src/solver/smt_logics.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include "symbol.h" -#include "smt_logics.h" +#include "util/symbol.h" +#include "solver/smt_logics.h" @@ -141,7 +141,7 @@ bool smt_logics::logic_has_fpa(symbol const & s) { } bool smt_logics::logic_has_uf(symbol const & s) { - return s == "QF_UF" || s == "UF"; + return s == "QF_UF" || s == "UF" || s == "QF_DT"; } bool smt_logics::logic_has_horn(symbol const& s) { @@ -153,5 +153,5 @@ bool smt_logics::logic_has_pb(symbol const& s) { } bool smt_logics::logic_has_datatype(symbol const& s) { - return s == "QF_FD" || s == "ALL"; + return s == "QF_FD" || s == "ALL" || s == "QF_DT"; } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 9163cfeda..bf53cb669 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -16,12 +16,12 @@ Author: Notes: --*/ -#include"solver.h" -#include"model_evaluator.h" -#include"ast_util.h" -#include"ast_pp.h" -#include"ast_pp_util.h" -#include "common_msgs.h" +#include "solver/solver.h" +#include "model/model_evaluator.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" +#include "ast/ast_pp_util.h" +#include "util/common_msgs.h" unsigned solver::get_num_assertions() const { @@ -34,11 +34,12 @@ expr * solver::get_assertion(unsigned idx) const { return 0; } -std::ostream& solver::display(std::ostream & out) const { +std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assumptions) const { expr_ref_vector fmls(get_manager()); get_assertions(fmls); ast_pp_util visitor(get_manager()); visitor.collect(fmls); + visitor.collect(n, assumptions); visitor.display_decls(out); visitor.display_asserts(out, fmls, true); return out; diff --git a/src/solver/solver.h b/src/solver/solver.h index 6b9d38f29..0a406455b 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -19,9 +19,9 @@ Notes: #ifndef SOLVER_H_ #define SOLVER_H_ -#include"check_sat_result.h" -#include"progress_callback.h" -#include"params.h" +#include "solver/check_sat_result.h" +#include "solver/progress_callback.h" +#include "util/params.h" class solver; @@ -43,6 +43,7 @@ public: - results based on check_sat_result API */ class solver : public check_sat_result { + params_ref m_params; public: virtual ~solver() {} @@ -54,7 +55,12 @@ public: /** \brief Update the solver internal settings. */ - virtual void updt_params(params_ref const & p) { } + virtual void updt_params(params_ref const & p) { m_params.copy(p); } + + /** + \brief Retrieve set of parameters set on solver. + */ + virtual params_ref const& get_params() { return m_params; } /** \brief Store in \c r a description of the configuration @@ -175,7 +181,7 @@ public: /** \brief Display the content of this solver. */ - virtual std::ostream& display(std::ostream & out) const; + virtual std::ostream& display(std::ostream & out, unsigned n = 0, expr* const* assumptions = nullptr) const; class scoped_push { solver& s; diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 1a02c97e6..fa0711d70 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -17,11 +17,11 @@ Notes: --*/ -#include "solver.h" -#include "tactic.h" -#include"filter_model_converter.h" -#include "solver2tactic.h" -#include "ast_util.h" +#include "solver/solver.h" +#include "tactic/tactic.h" +#include "tactic/filter_model_converter.h" +#include "solver/solver2tactic.h" +#include "ast/ast_util.h" typedef obj_map expr2expr_map; diff --git a/src/solver/solver2tactic.h b/src/solver/solver2tactic.h index 65fbd37b1..647a1cee4 100644 --- a/src/solver/solver2tactic.h +++ b/src/solver/solver2tactic.h @@ -19,8 +19,8 @@ Notes: #ifndef SOLVER2TACTIC_H_ #define SOLVER2TACTIC_H_ -#include "tactic.h" -#include "filter_model_converter.h" +#include "tactic/tactic.h" +#include "tactic/filter_model_converter.h" class solver; tactic * mk_solver2tactic(solver* s); diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index 31895b8ef..2628380c5 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -19,8 +19,8 @@ Author: Notes: --*/ -#include"solver_na2as.h" -#include"ast_smt2_pp.h" +#include "solver/solver_na2as.h" +#include "ast/ast_smt2_pp.h" solver_na2as::solver_na2as(ast_manager & m): diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index aaa48efe7..3e726be12 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -22,7 +22,7 @@ Notes: #ifndef SOLVER_NA2AS_H_ #define SOLVER_NA2AS_H_ -#include"solver.h" +#include "solver/solver.h" class solver_na2as : public solver { protected: diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp new file mode 100644 index 000000000..c6c85ec29 --- /dev/null +++ b/src/solver/solver_pool.cpp @@ -0,0 +1,320 @@ +/** +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + solver_pool.cpp + +Abstract: + + Maintain a pool of solvers + +Author: + + Nikolaj Bjorner + +Notes: + +--*/ + +#include "solver/solver_pool.h" +#include "solver/solver_na2as.h" +#include "ast/proofs/proof_utils.h" +#include "ast/ast_util.h" + +class pool_solver : public solver_na2as { + solver_pool& m_pool; + app_ref m_pred; + proof_ref m_proof; + ref m_base; + expr_ref_vector m_assertions; + unsigned m_head; + expr_ref_vector m_flat; + bool m_pushed; + bool m_in_delayed_scope; + unsigned m_dump_counter; + + bool is_virtual() const { return !m.is_true(m_pred); } +public: + pool_solver(solver* b, solver_pool& pool, app_ref& pred): + solver_na2as(pred.get_manager()), + m_pool(pool), + m_pred(pred), + m_proof(m), + m_base(b), + m_assertions(m), + m_head(0), + m_flat(m), + m_pushed(false), + m_in_delayed_scope(false), + m_dump_counter(0) { + if (is_virtual()) { + solver_na2as::assert_expr(m.mk_true(), pred); + } + } + + virtual ~pool_solver() { + if (m_pushed) pop(get_scope_level()); + if (is_virtual()) { + m_pred = m.mk_not(m_pred); + m_base->assert_expr(m_pred); + } + } + + solver* base_solver() { return m_base.get(); } + + virtual solver* translate(ast_manager& m, params_ref const& p) { UNREACHABLE(); return nullptr; } + virtual void updt_params(params_ref const& p) { solver::updt_params(p); m_base->updt_params(p); } + virtual void collect_param_descrs(param_descrs & r) { m_base->collect_param_descrs(r); } + virtual void collect_statistics(statistics & st) const { m_base->collect_statistics(st); } + + virtual void get_unsat_core(ptr_vector & r) { + m_base->get_unsat_core(r); + unsigned j = 0; + for (unsigned i = 0; i < r.size(); ++i) + if (m_pred != r[i]) + r[j++] = r[i]; + r.shrink(j); + } + + virtual unsigned get_num_assumptions() const { + unsigned sz = solver_na2as::get_num_assumptions(); + return is_virtual() ? sz - 1 : sz; + } + + virtual proof * get_proof() { + scoped_watch _t_(m_pool.m_proof_watch); + if (!m_proof.get()) { + elim_aux_assertions pc(m_pred); + m_proof = m_base->get_proof(); + pc(m, m_proof, m_proof); + } + return m_proof; + } + + void internalize_assertions() { + SASSERT(!m_pushed || m_head == m_assertions.size()); + for (unsigned sz = m_assertions.size(); m_head < sz; ++m_head) { + expr_ref f(m); + f = m.mk_implies(m_pred, (m_assertions.get(m_head))); + m_base->assert_expr(f); + } + } + + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + SASSERT(!m_pushed || get_scope_level() > 0); + m_proof.reset(); + scoped_watch _t_(m_pool.m_check_watch); + m_pool.m_stats.m_num_checks++; + + stopwatch sw; + sw.start(); + internalize_assertions(); + lbool res = m_base->check_sat(num_assumptions, assumptions); + sw.stop(); + switch (res) { + case l_true: + m_pool.m_check_sat_watch.add(sw); + m_pool.m_stats.m_num_sat_checks++; + break; + case l_undef: + m_pool.m_check_undef_watch.add(sw); + m_pool.m_stats.m_num_undef_checks++; + break; + default: + break; + } + set_status(res); + + if (false /*m_dump_benchmarks && sw.get_seconds() >= m_pool.fparams().m_dump_min_time*/) { + std::stringstream file_name; + file_name << "virt_solver"; + if (is_virtual()) { file_name << "_" << m_pred->get_decl()->get_name(); } + file_name << "_" << (m_dump_counter++) << ".smt2"; + + std::ofstream out(file_name.str().c_str()); + if (!out) { verbose_stream() << "could not open file " << file_name.str() << " for output\n"; } + + out << "(set-info :status "; + switch (res) { + case l_true: out << "sat"; break; + case l_false: out << "unsat"; break; + case l_undef: out << "unknown"; break; + } + out << ")\n"; + m_base->display(out, num_assumptions, assumptions); + bool first = true; + out << "(check-sat"; + for (unsigned i = 0; i < num_assumptions; ++i) { + out << " " << mk_pp(assumptions[i], m); + } + out << ")"; + out << "(exit)\n"; + ::statistics st; + m_base->collect_statistics(st); + st.update("time", sw.get_seconds()); + st.display_smt2(out); + out.close(); + } + return res; + } + + virtual void push_core() { + SASSERT(!m_pushed || get_scope_level() > 0); + if (m_in_delayed_scope) { + // second push + internalize_assertions(); + m_base->push(); + m_pushed = true; + m_in_delayed_scope = false; + } + + if (!m_pushed) { + m_in_delayed_scope = true; + } + else { + SASSERT(m_pushed); + SASSERT(!m_in_delayed_scope); + m_base->push(); + } + } + + virtual void pop_core(unsigned n) { + SASSERT(!m_pushed || get_scope_level() > 0); + if (m_pushed) { + SASSERT(!m_in_delayed_scope); + m_base->pop(n); + m_pushed = get_scope_level() - n > 0; + } + else { + m_in_delayed_scope = get_scope_level() - n > 0; + } + } + + virtual void assert_expr(expr * e) { + SASSERT(!m_pushed || get_scope_level() > 0); + if (m.is_true(e)) return; + if (m_in_delayed_scope) { + internalize_assertions(); + m_base->push(); + m_pushed = true; + m_in_delayed_scope = false; + } + + if (m_pushed) { + m_base->assert_expr(e); + } + else { + m_flat.push_back(e); + flatten_and(m_flat); + m_assertions.append(m_flat); + m_flat.reset(); + } + } + + virtual void get_model(model_ref & _m) { m_base->get_model(_m); } + + virtual expr * get_assumption(unsigned idx) const { + return solver_na2as::get_assumption(idx + is_virtual()); + } + + virtual std::string reason_unknown() const { return m_base->reason_unknown(); } + virtual void set_reason_unknown(char const* msg) { return m_base->set_reason_unknown(msg); } + virtual void get_labels(svector & r) { return m_base->get_labels(r); } + virtual void set_progress_callback(progress_callback * callback) { m_base->set_progress_callback(callback); } + + virtual ast_manager& get_manager() const { return m_base->get_manager(); } + + void refresh(solver* new_base) { + SASSERT(!m_pushed); + m_head = 0; + m_base = new_base; + } + + void reset() { + SASSERT(!m_pushed); + m_head = 0; + m_assertions.reset(); + m_pool.refresh(m_base.get()); + } +}; + +solver_pool::solver_pool(solver* base_solver, unsigned num_solvers_per_pool): + m_base_solver(base_solver), + m_num_solvers_per_pool(num_solvers_per_pool), + m_num_solvers_in_last_pool(0) +{} + + +ptr_vector solver_pool::get_base_solvers() const { + ptr_vector solvers; + for (solver* s0 : m_solvers) { + pool_solver* s = dynamic_cast(s0); + if (!solvers.contains(s->base_solver())) { + solvers.push_back(s->base_solver()); + } + } + return solvers; +} + +void solver_pool::collect_statistics(statistics &st) const { + ptr_vector solvers = get_base_solvers(); + for (solver* s : solvers) s->collect_statistics(st); + st.update("time.pool_solver.smt.total", m_check_watch.get_seconds()); + st.update("time.pool_solver.smt.total.sat", m_check_sat_watch.get_seconds()); + st.update("time.pool_solver.smt.total.undef", m_check_undef_watch.get_seconds()); + st.update("time.pool_solver.proof", m_proof_watch.get_seconds()); + st.update("pool_solver.checks", m_stats.m_num_checks); + st.update("pool_solver.checks.sat", m_stats.m_num_sat_checks); + st.update("pool_solver.checks.undef", m_stats.m_num_undef_checks); +} + +void solver_pool::reset_statistics() { +#if 0 + ptr_vector solvers = get_base_solvers(); + for (solver* s : solvers) { + s->reset_statistics(); + } +#endif + m_stats.reset(); + m_check_sat_watch.reset(); + m_check_undef_watch.reset(); + m_check_watch.reset(); + m_proof_watch.reset(); +} + +solver* solver_pool::mk_solver() { + ref base_solver; + ast_manager& m = m_base_solver->get_manager(); + if (m_solvers.empty() || m_num_solvers_in_last_pool == m_num_solvers_per_pool) { + base_solver = m_base_solver->translate(m, m_base_solver->get_params()); + m_num_solvers_in_last_pool = 0; + } + else { + base_solver = dynamic_cast(m_solvers.back())->base_solver(); + } + m_num_solvers_in_last_pool++; + std::stringstream name; + name << "vsolver#" << m_solvers.size(); + app_ref pred(m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()), m); + pool_solver* solver = alloc(pool_solver, base_solver.get(), *this, pred); + m_solvers.push_back(solver); + return solver; +} + +void solver_pool::reset_solver(solver* s) { + pool_solver* ps = dynamic_cast(s); + SASSERT(ps); + if (ps) ps->reset(); +} + +void solver_pool::refresh(solver* base_solver) { + ast_manager& m = m_base_solver->get_manager(); + ref new_base = m_base_solver->translate(m, m_base_solver->get_params()); + for (solver* s0 : m_solvers) { + pool_solver* s = dynamic_cast(s0); + if (base_solver == s->base_solver()) { + s->refresh(new_base.get()); + } + } +} diff --git a/src/solver/solver_pool.h b/src/solver/solver_pool.h new file mode 100644 index 000000000..d676ca54d --- /dev/null +++ b/src/solver/solver_pool.h @@ -0,0 +1,69 @@ +/** +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + solver_pool.h + +Abstract: + + Maintain a pool of solvers + +Author: + + Nikolaj Bjorner + Arie Gurfinkel + +Notes: + + This is a revision of spacer_virtual_solver by Arie Gurfinkel + +--*/ +#ifndef SOLVER_POOL_H_ +#define SOLVER_POOL_H_ + +#include "solver/solver.h" +#include "util/stopwatch.h" + +class pool_solver; + +class solver_pool { + + friend class pool_solver; + + struct stats { + unsigned m_num_checks; + unsigned m_num_sat_checks; + unsigned m_num_undef_checks; + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + }; + + ref m_base_solver; + unsigned m_num_solvers_per_pool; + unsigned m_num_solvers_in_last_pool; + sref_vector m_solvers; + stats m_stats; + + stopwatch m_check_watch; + stopwatch m_check_sat_watch; + stopwatch m_check_undef_watch; + stopwatch m_proof_watch; + + void refresh(solver* s); + + ptr_vector get_base_solvers() const; + +public: + solver_pool(solver* base_solver, unsigned num_solvers_per_pool); + + void collect_statistics(statistics &st) const; + void reset_statistics(); + + solver* mk_solver(); + + void reset_solver(solver* s); +}; + + +#endif diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index e451f57d4..a24f1d4c7 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -19,10 +19,10 @@ Author: Notes: --*/ -#include"solver_na2as.h" -#include"tactic.h" -#include"ast_translation.h" -#include"mus.h" +#include "solver/solver_na2as.h" +#include "tactic/tactic.h" +#include "ast/ast_translation.h" +#include "solver/mus.h" /** \brief Simulates the incremental solver interface using a tactic. @@ -37,7 +37,6 @@ class tactic2solver : public solver_na2as { ref m_result; tactic_ref m_tactic; symbol m_logic; - params_ref m_params; bool m_produce_models; bool m_produce_proofs; bool m_produce_unsat_cores; @@ -85,7 +84,7 @@ tactic2solver::tactic2solver(ast_manager & m, tactic * t, params_ref const & p, m_tactic = t; m_logic = logic; - m_params = p; + solver::updt_params(p); m_produce_models = produce_models; m_produce_proofs = produce_proofs; @@ -96,7 +95,7 @@ tactic2solver::~tactic2solver() { } void tactic2solver::updt_params(params_ref const & p) { - m_params.append(p); + solver::updt_params(p); } void tactic2solver::collect_param_descrs(param_descrs & r) { @@ -129,7 +128,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass m_result = alloc(simple_check_sat_result, m); m_tactic->cleanup(); m_tactic->set_logic(m_logic); - m_tactic->updt_params(m_params); // parameters are allowed to overwrite logic. + m_tactic->updt_params(get_params()); // parameters are allowed to overwrite logic. goal_ref g = alloc(goal, m, m_produce_proofs, m_produce_models, m_produce_unsat_cores); unsigned sz = m_assertions.size(); diff --git a/src/solver/tactic2solver.h b/src/solver/tactic2solver.h index 9158a00b7..2da0f69eb 100644 --- a/src/solver/tactic2solver.h +++ b/src/solver/tactic2solver.h @@ -22,7 +22,7 @@ Notes: #ifndef TACTIC2SOLVER_H_ #define TACTIC2SOLVER_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; class tactic_factory; diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index 6e289d969..e8226e159 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -16,10 +16,10 @@ Author: Notes: --*/ -#include"aig.h" -#include"goal.h" -#include"ast_smt2_pp.h" -#include"cooperate.h" +#include "tactic/aig/aig.h" +#include "tactic/goal.h" +#include "ast/ast_smt2_pp.h" +#include "util/cooperate.h" #define USE_TWO_LEVEL_RULES #define FIRST_NODE_ID (UINT_MAX/2) diff --git a/src/tactic/aig/aig.h b/src/tactic/aig/aig.h index fbbde7de6..5e0add752 100644 --- a/src/tactic/aig/aig.h +++ b/src/tactic/aig/aig.h @@ -19,8 +19,8 @@ Notes: #ifndef AIG_H_ #define AIG_H_ -#include"ast.h" -#include"tactic_exception.h" +#include "ast/ast.h" +#include "tactic/tactic_exception.h" class goal; class aig_lit; diff --git a/src/tactic/aig/aig_tactic.cpp b/src/tactic/aig/aig_tactic.cpp index 59d114ed6..37ffc6124 100644 --- a/src/tactic/aig/aig_tactic.cpp +++ b/src/tactic/aig/aig_tactic.cpp @@ -16,8 +16,8 @@ Author: Notes: --*/ -#include"tactical.h" -#include"aig.h" +#include "tactic/tactical.h" +#include "tactic/aig/aig.h" class aig_manager; diff --git a/src/tactic/aig/aig_tactic.h b/src/tactic/aig/aig_tactic.h index d9584ad02..2ba97e3b4 100644 --- a/src/tactic/aig/aig_tactic.h +++ b/src/tactic/aig/aig_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef AIG_TACTIC_H_ #define AIG_TACTIC_H_ -#include"params.h" +#include "util/params.h" class tactic; tactic * mk_aig_tactic(params_ref const & p = params_ref()); diff --git a/src/tactic/arith/add_bounds_tactic.cpp b/src/tactic/arith/add_bounds_tactic.cpp index 8ff82af17..ac105eb06 100644 --- a/src/tactic/arith/add_bounds_tactic.cpp +++ b/src/tactic/arith/add_bounds_tactic.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"arith_decl_plugin.h" -#include"ast_smt2_pp.h" -#include"bound_manager.h" +#include "tactic/tactical.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_smt2_pp.h" +#include "tactic/arith/bound_manager.h" struct is_unbounded_proc { struct found {}; diff --git a/src/tactic/arith/add_bounds_tactic.h b/src/tactic/arith/add_bounds_tactic.h index 7cb146fc7..b7b8f419c 100644 --- a/src/tactic/arith/add_bounds_tactic.h +++ b/src/tactic/arith/add_bounds_tactic.h @@ -19,7 +19,7 @@ Revision History: #ifndef ADD_BOUNDS_H_ #define ADD_BOUNDS_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class goal; diff --git a/src/tactic/arith/arith_bounds_tactic.cpp b/src/tactic/arith/arith_bounds_tactic.cpp index fe054aaea..b750689b1 100644 --- a/src/tactic/arith/arith_bounds_tactic.cpp +++ b/src/tactic/arith/arith_bounds_tactic.cpp @@ -6,8 +6,8 @@ Copyright (c) 2015 Microsoft Corporation -#include"arith_bounds_tactic.h" -#include"arith_decl_plugin.h" +#include "tactic/arith/arith_bounds_tactic.h" +#include "ast/arith_decl_plugin.h" struct arith_bounds_tactic : public tactic { diff --git a/src/tactic/arith/arith_bounds_tactic.h b/src/tactic/arith/arith_bounds_tactic.h index 78da93867..92bc85564 100644 --- a/src/tactic/arith/arith_bounds_tactic.h +++ b/src/tactic/arith/arith_bounds_tactic.h @@ -30,7 +30,7 @@ Notes: --*/ #ifndef ARITH_BOUNDS_TACTIC_H_ #define ARITH_BOUNDS_TACTIC_H_ -#include "tactic.h" +#include "tactic/tactic.h" tactic * mk_arith_bounds_tactic(ast_manager & m, params_ref const & p = params_ref()); diff --git a/src/tactic/arith/bound_manager.cpp b/src/tactic/arith/bound_manager.cpp index 97d93658c..da507ea10 100644 --- a/src/tactic/arith/bound_manager.cpp +++ b/src/tactic/arith/bound_manager.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"bound_manager.h" -#include"ast_smt2_pp.h" -#include"goal.h" +#include "tactic/arith/bound_manager.h" +#include "ast/ast_smt2_pp.h" +#include "tactic/goal.h" bound_manager::bound_manager(ast_manager & m): m_util(m) { diff --git a/src/tactic/arith/bound_manager.h b/src/tactic/arith/bound_manager.h index 6a4dc2c96..a08a53614 100644 --- a/src/tactic/arith/bound_manager.h +++ b/src/tactic/arith/bound_manager.h @@ -19,8 +19,8 @@ Notes: #ifndef BOUND_MANAGER_H_ #define BOUND_MANAGER_H_ -#include"ast.h" -#include"arith_decl_plugin.h" +#include "ast/ast.h" +#include "ast/arith_decl_plugin.h" class goal; diff --git a/src/tactic/arith/bound_propagator.cpp b/src/tactic/arith/bound_propagator.cpp index dbd7c5f69..51499674b 100644 --- a/src/tactic/arith/bound_propagator.cpp +++ b/src/tactic/arith/bound_propagator.cpp @@ -17,7 +17,7 @@ Author: Revision History: --*/ -#include"bound_propagator.h" +#include "tactic/arith/bound_propagator.h" #include // ------------------------------- diff --git a/src/tactic/arith/bound_propagator.h b/src/tactic/arith/bound_propagator.h index 2781bed55..042e39e5f 100644 --- a/src/tactic/arith/bound_propagator.h +++ b/src/tactic/arith/bound_propagator.h @@ -20,12 +20,12 @@ Revision History: #ifndef BOUND_PROPAGATOR_H_ #define BOUND_PROPAGATOR_H_ -#include"mpq.h" -#include"vector.h" -#include"params.h" -#include"statistics.h" -#include"numeral_buffer.h" -#include"linear_equation.h" +#include "util/mpq.h" +#include "util/vector.h" +#include "util/params.h" +#include "util/statistics.h" +#include "util/numeral_buffer.h" +#include "tactic/arith/linear_equation.h" class bound_propagator { public: diff --git a/src/tactic/arith/bv2int_rewriter.cpp b/src/tactic/arith/bv2int_rewriter.cpp index 098e04a8d..4315b0f5f 100644 --- a/src/tactic/arith/bv2int_rewriter.cpp +++ b/src/tactic/arith/bv2int_rewriter.cpp @@ -16,10 +16,10 @@ Author: Notes: --*/ -#include "bv2int_rewriter.h" -#include "rewriter_def.h" -#include "ast_pp.h" -#include "ast_util.h" +#include "tactic/arith/bv2int_rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" void bv2int_rewriter_ctx::update_params(params_ref const& p) { m_max_size = p.get_uint("max_bv_size", UINT_MAX); diff --git a/src/tactic/arith/bv2int_rewriter.h b/src/tactic/arith/bv2int_rewriter.h index 15a425857..9ef256197 100644 --- a/src/tactic/arith/bv2int_rewriter.h +++ b/src/tactic/arith/bv2int_rewriter.h @@ -19,12 +19,12 @@ Notes: #ifndef BV2INT_REWRITER_H_ #define BV2INT_REWRITER_H_ -#include"ast.h" -#include"rewriter.h" -#include"bv_decl_plugin.h" -#include"arith_decl_plugin.h" -#include"params.h" -#include"goal.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter.h" +#include "ast/bv_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "util/params.h" +#include "tactic/goal.h" class bv2int_rewriter_ctx { unsigned m_max_size; diff --git a/src/tactic/arith/bv2real_rewriter.cpp b/src/tactic/arith/bv2real_rewriter.cpp index 4f952b697..5839ff7a2 100644 --- a/src/tactic/arith/bv2real_rewriter.cpp +++ b/src/tactic/arith/bv2real_rewriter.cpp @@ -16,10 +16,10 @@ Author: Notes: --*/ -#include"bv2real_rewriter.h" -#include"rewriter_def.h" -#include"ast_pp.h" -#include"for_each_expr.h" +#include "tactic/arith/bv2real_rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_pp.h" +#include "ast/for_each_expr.h" bv2real_util::bv2real_util(ast_manager& m, rational const& default_root, rational const& default_divisor, unsigned max_num_bits) : diff --git a/src/tactic/arith/bv2real_rewriter.h b/src/tactic/arith/bv2real_rewriter.h index 5f80db4a3..f020f9f1e 100644 --- a/src/tactic/arith/bv2real_rewriter.h +++ b/src/tactic/arith/bv2real_rewriter.h @@ -19,10 +19,10 @@ Notes: #ifndef BV2REAL_REWRITER_H_ #define BV2REAL_REWRITER_H_ -#include"ast.h" -#include"rewriter.h" -#include"bv_decl_plugin.h" -#include"arith_decl_plugin.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter.h" +#include "ast/bv_decl_plugin.h" +#include "ast/arith_decl_plugin.h" // // bv2real[d,r](n,m) has interpretation: diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 096e52981..d2453eba2 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -16,14 +16,14 @@ Author: Notes: --*/ -#include"tactical.h" -#include"cooperate.h" -#include"ast_smt2_pp.h" -#include"card2bv_tactic.h" -#include"pb2bv_rewriter.h" -#include"ast_util.h" -#include"ast_pp.h" -#include"filter_model_converter.h" +#include "tactic/tactical.h" +#include "util/cooperate.h" +#include "ast/ast_smt2_pp.h" +#include "tactic/arith/card2bv_tactic.h" +#include "ast/rewriter/pb2bv_rewriter.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" +#include "tactic/filter_model_converter.h" class card2bv_tactic : public tactic { ast_manager & m; diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index 9bf21d2c3..287dfa27e 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -19,12 +19,12 @@ Notes: #ifndef CARD2BV_TACTIC_H_ #define CARD2BV_TACTIC_H_ -#include"params.h" -#include"pb_decl_plugin.h" -#include"th_rewriter.h" -#include"rewriter.h" +#include "util/params.h" +#include "ast/pb_decl_plugin.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/rewriter.h" #include -#include"sorting_network.h" +#include "util/sorting_network.h" class ast_manager; diff --git a/src/tactic/arith/degree_shift_tactic.cpp b/src/tactic/arith/degree_shift_tactic.cpp index 6c5527d12..6344c4c51 100644 --- a/src/tactic/arith/degree_shift_tactic.cpp +++ b/src/tactic/arith/degree_shift_tactic.cpp @@ -19,14 +19,14 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"filter_model_converter.h" -#include"extension_model_converter.h" -#include"cooperate.h" -#include"arith_decl_plugin.h" -#include"simplify_tactic.h" -#include"ast_smt2_pp.h" -#include"rewriter_def.h" +#include "tactic/tactical.h" +#include "tactic/filter_model_converter.h" +#include "tactic/extension_model_converter.h" +#include "util/cooperate.h" +#include "ast/arith_decl_plugin.h" +#include "tactic/core/simplify_tactic.h" +#include "ast/ast_smt2_pp.h" +#include "ast/rewriter/rewriter_def.h" class degree_shift_tactic : public tactic { struct imp { diff --git a/src/tactic/arith/degree_shift_tactic.h b/src/tactic/arith/degree_shift_tactic.h index efc0d442e..3456e19e5 100644 --- a/src/tactic/arith/degree_shift_tactic.h +++ b/src/tactic/arith/degree_shift_tactic.h @@ -22,7 +22,7 @@ Revision History: #ifndef DEGREE_SHIFT_TACTIC_H_ #define DEGREE_SHIFT_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/diff_neq_tactic.cpp b/src/tactic/arith/diff_neq_tactic.cpp index d63c2fcf4..651000297 100644 --- a/src/tactic/arith/diff_neq_tactic.cpp +++ b/src/tactic/arith/diff_neq_tactic.cpp @@ -20,10 +20,10 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"arith_decl_plugin.h" -#include"ast_smt2_pp.h" -#include"model.h" +#include "tactic/tactical.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_smt2_pp.h" +#include "model/model.h" class diff_neq_tactic : public tactic { struct imp { diff --git a/src/tactic/arith/diff_neq_tactic.h b/src/tactic/arith/diff_neq_tactic.h index 205fb7bb5..3fbe616dc 100644 --- a/src/tactic/arith/diff_neq_tactic.h +++ b/src/tactic/arith/diff_neq_tactic.h @@ -23,7 +23,7 @@ Revision History: #ifndef DIFF_NEQ_TACTIC_H_ #define DIFF_NEQ_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp index e00b1e9c0..b6fd5eee7 100644 --- a/src/tactic/arith/elim01_tactic.cpp +++ b/src/tactic/arith/elim01_tactic.cpp @@ -16,15 +16,15 @@ Author: Notes: --*/ -#include"tactical.h" -#include"cooperate.h" -#include"bound_manager.h" -#include"ast_pp.h" -#include"expr_safe_replace.h" // NB: should use proof-producing expr_substitute in polished version. -#include"arith_decl_plugin.h" -#include"elim01_tactic.h" -#include"model_smt2_pp.h" -#include"th_rewriter.h" +#include "tactic/tactical.h" +#include "util/cooperate.h" +#include "tactic/arith/bound_manager.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/arith_decl_plugin.h" +#include "tactic/arith/elim01_tactic.h" +#include "model/model_smt2_pp.h" +#include "ast/rewriter/th_rewriter.h" class bool2int_model_converter : public model_converter { ast_manager& m; diff --git a/src/tactic/arith/elim01_tactic.h b/src/tactic/arith/elim01_tactic.h index 210f2b9fc..d9cd3a2ed 100644 --- a/src/tactic/arith/elim01_tactic.h +++ b/src/tactic/arith/elim01_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef ELIM01_TACTIC_H_ #define ELIM01_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/eq2bv_tactic.cpp b/src/tactic/arith/eq2bv_tactic.cpp index ac1ee9afd..255665b56 100644 --- a/src/tactic/arith/eq2bv_tactic.cpp +++ b/src/tactic/arith/eq2bv_tactic.cpp @@ -17,15 +17,15 @@ Author: Notes: --*/ -#include"tactical.h" -#include"cooperate.h" -#include"bound_manager.h" -#include"ast_pp.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"rewriter_def.h" -#include"ast_util.h" -#include"ast_pp_util.h" +#include "tactic/tactical.h" +#include "util/cooperate.h" +#include "tactic/arith/bound_manager.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_util.h" +#include "ast/ast_pp_util.h" class eq2bv_tactic : public tactic { struct eq_rewriter_cfg : public default_rewriter_cfg { diff --git a/src/tactic/arith/eq2bv_tactic.h b/src/tactic/arith/eq2bv_tactic.h index e336b1e0a..9441bfed3 100644 --- a/src/tactic/arith/eq2bv_tactic.h +++ b/src/tactic/arith/eq2bv_tactic.h @@ -20,7 +20,7 @@ Notes: #ifndef EQ2BV_TACTIC_H_ #define EQ2BV_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/factor_tactic.cpp b/src/tactic/arith/factor_tactic.cpp index 70bff2610..d187c0078 100644 --- a/src/tactic/arith/factor_tactic.cpp +++ b/src/tactic/arith/factor_tactic.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"expr2polynomial.h" -#include"rewriter_def.h" +#include "tactic/tactical.h" +#include "ast/expr2polynomial.h" +#include "ast/rewriter/rewriter_def.h" class factor_tactic : public tactic { diff --git a/src/tactic/arith/factor_tactic.h b/src/tactic/arith/factor_tactic.h index 0948606e0..3b48f9f6d 100644 --- a/src/tactic/arith/factor_tactic.h +++ b/src/tactic/arith/factor_tactic.h @@ -19,7 +19,7 @@ Revision History: #ifndef FACTOR_TACTIC_H_ #define FACTOR_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/fix_dl_var_tactic.cpp b/src/tactic/arith/fix_dl_var_tactic.cpp index 1a9a18c44..7ff7bd835 100644 --- a/src/tactic/arith/fix_dl_var_tactic.cpp +++ b/src/tactic/arith/fix_dl_var_tactic.cpp @@ -21,12 +21,12 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"th_rewriter.h" -#include"extension_model_converter.h" -#include"arith_decl_plugin.h" -#include"expr_substitution.h" -#include"ast_smt2_pp.h" +#include "tactic/tactical.h" +#include "ast/rewriter/th_rewriter.h" +#include "tactic/extension_model_converter.h" +#include "ast/arith_decl_plugin.h" +#include "ast/expr_substitution.h" +#include "ast/ast_smt2_pp.h" class fix_dl_var_tactic : public tactic { diff --git a/src/tactic/arith/fix_dl_var_tactic.h b/src/tactic/arith/fix_dl_var_tactic.h index 3cee418cb..9e204bf1b 100644 --- a/src/tactic/arith/fix_dl_var_tactic.h +++ b/src/tactic/arith/fix_dl_var_tactic.h @@ -24,7 +24,7 @@ Notes: #ifndef FIX_DL_VAR_TACTIC_H_ #define FIX_DL_VAR_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index 6db0f5ad3..48f584169 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -21,17 +21,17 @@ Author: Revision History: --*/ -#include"fm_tactic.h" -#include"tactical.h" -#include"arith_decl_plugin.h" -#include"for_each_expr.h" -#include"cooperate.h" -#include"ast_smt2_pp.h" -#include"ast_pp.h" -#include"id_gen.h" -#include"model_evaluator.h" -#include"model_v2_pp.h" -#include"simplify_tactic.h" +#include "tactic/arith/fm_tactic.h" +#include "tactic/tactical.h" +#include "ast/arith_decl_plugin.h" +#include "ast/for_each_expr.h" +#include "util/cooperate.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_pp.h" +#include "util/id_gen.h" +#include "model/model_evaluator.h" +#include "model/model_v2_pp.h" +#include "tactic/core/simplify_tactic.h" class fm_tactic : public tactic { typedef ptr_vector clauses; diff --git a/src/tactic/arith/fm_tactic.h b/src/tactic/arith/fm_tactic.h index f45ab2475..0b59ab98f 100644 --- a/src/tactic/arith/fm_tactic.h +++ b/src/tactic/arith/fm_tactic.h @@ -24,7 +24,7 @@ Revision History: #ifndef FM_TACTIC_H_ #define FM_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 8f37a8d5e..ec41f5845 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -34,15 +34,15 @@ Author: Notes: --*/ -#include"tactical.h" -#include"cooperate.h" -#include"bound_manager.h" -#include"ast_pp.h" -#include"pb_decl_plugin.h" -#include"arith_decl_plugin.h" -#include"rewriter_def.h" -#include"ast_util.h" -#include"ast_pp_util.h" +#include "tactic/tactical.h" +#include "util/cooperate.h" +#include "tactic/arith/bound_manager.h" +#include "ast/ast_pp.h" +#include "ast/pb_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_util.h" +#include "ast/ast_pp_util.h" class lia2card_tactic : public tactic { struct lia_rewriter_cfg : public default_rewriter_cfg { diff --git a/src/tactic/arith/lia2card_tactic.h b/src/tactic/arith/lia2card_tactic.h index 93adb6f46..4a8334f10 100644 --- a/src/tactic/arith/lia2card_tactic.h +++ b/src/tactic/arith/lia2card_tactic.h @@ -20,7 +20,7 @@ Notes: #ifndef LIA2CARD_TACTIC_H_ #define LIA2CARD_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index 2b54dd463..d303463db 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -16,15 +16,15 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"bound_manager.h" -#include"th_rewriter.h" -#include"for_each_expr.h" -#include"extension_model_converter.h" -#include"filter_model_converter.h" -#include"arith_decl_plugin.h" -#include"expr_substitution.h" -#include"ast_smt2_pp.h" +#include "tactic/tactical.h" +#include "tactic/arith/bound_manager.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/for_each_expr.h" +#include "tactic/extension_model_converter.h" +#include "tactic/filter_model_converter.h" +#include "ast/arith_decl_plugin.h" +#include "ast/expr_substitution.h" +#include "ast/ast_smt2_pp.h" class lia2pb_tactic : public tactic { struct imp { diff --git a/src/tactic/arith/lia2pb_tactic.h b/src/tactic/arith/lia2pb_tactic.h index 273949825..29c05d52a 100644 --- a/src/tactic/arith/lia2pb_tactic.h +++ b/src/tactic/arith/lia2pb_tactic.h @@ -19,7 +19,7 @@ Revision History: #ifndef LIA2PB_TACTIC_H_ #define LIA2PB_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/linear_equation.cpp b/src/tactic/arith/linear_equation.cpp index 0b8828674..ed158b778 100644 --- a/src/tactic/arith/linear_equation.cpp +++ b/src/tactic/arith/linear_equation.cpp @@ -18,7 +18,7 @@ Author: Revision History: --*/ -#include"linear_equation.h" +#include "tactic/arith/linear_equation.h" /** \brief Return the position of variable x_i in the linear equation. diff --git a/src/tactic/arith/linear_equation.h b/src/tactic/arith/linear_equation.h index 1de3969ca..1bfa94d1a 100644 --- a/src/tactic/arith/linear_equation.h +++ b/src/tactic/arith/linear_equation.h @@ -21,10 +21,10 @@ Revision History: #ifndef LINEAR_EQUATION_H_ #define LINEAR_EQUATION_H_ -#include"mpq.h" -#include"small_object_allocator.h" -#include"numeral_buffer.h" -#include"double_manager.h" +#include "util/mpq.h" +#include "util/small_object_allocator.h" +#include "util/numeral_buffer.h" +#include "util/double_manager.h" class linear_equation { public: diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 1399d6549..6f5f49aee 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -18,19 +18,19 @@ Notes: The original file was called qfnla2bv.cpp --*/ -#include "tactical.h" -#include "arith_decl_plugin.h" -#include "bv_decl_plugin.h" -#include "for_each_expr.h" -#include "expr_replacer.h" -#include "optional.h" -#include "bv2int_rewriter.h" -#include "bv2real_rewriter.h" -#include "extension_model_converter.h" -#include "filter_model_converter.h" -#include "bound_manager.h" -#include "obj_pair_hashtable.h" -#include "ast_smt2_pp.h" +#include "tactic/tactical.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/expr_replacer.h" +#include "util/optional.h" +#include "tactic/arith/bv2int_rewriter.h" +#include "tactic/arith/bv2real_rewriter.h" +#include "tactic/extension_model_converter.h" +#include "tactic/filter_model_converter.h" +#include "tactic/arith/bound_manager.h" +#include "util/obj_pair_hashtable.h" +#include "ast/ast_smt2_pp.h" // // diff --git a/src/tactic/arith/nla2bv_tactic.h b/src/tactic/arith/nla2bv_tactic.h index e2d207520..c6be722a3 100644 --- a/src/tactic/arith/nla2bv_tactic.h +++ b/src/tactic/arith/nla2bv_tactic.h @@ -20,7 +20,7 @@ Notes: #ifndef NLA2BV_TACTIC_H_ #define NLA2BV_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index 06f1368a2..2b3ff5ab0 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -18,14 +18,14 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"bound_manager.h" -#include"th_rewriter.h" -#include"extension_model_converter.h" -#include"filter_model_converter.h" -#include"arith_decl_plugin.h" -#include"expr_substitution.h" -#include"ast_smt2_pp.h" +#include "tactic/tactical.h" +#include "tactic/arith/bound_manager.h" +#include "ast/rewriter/th_rewriter.h" +#include "tactic/extension_model_converter.h" +#include "tactic/filter_model_converter.h" +#include "ast/arith_decl_plugin.h" +#include "ast/expr_substitution.h" +#include "ast/ast_smt2_pp.h" class normalize_bounds_tactic : public tactic { struct imp { diff --git a/src/tactic/arith/normalize_bounds_tactic.h b/src/tactic/arith/normalize_bounds_tactic.h index 1ecbf88d8..f8473842f 100644 --- a/src/tactic/arith/normalize_bounds_tactic.h +++ b/src/tactic/arith/normalize_bounds_tactic.h @@ -21,7 +21,7 @@ Revision History: #ifndef NORMALIZE_BOUNDS_TACTIC_H_ #define NORMALIZE_BOUNDS_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/pb2bv_model_converter.cpp b/src/tactic/arith/pb2bv_model_converter.cpp index 8dbacc6cd..df5bd5745 100644 --- a/src/tactic/arith/pb2bv_model_converter.cpp +++ b/src/tactic/arith/pb2bv_model_converter.cpp @@ -16,10 +16,10 @@ Author: Notes: --*/ -#include"trace.h" -#include"arith_decl_plugin.h" -#include"model_v2_pp.h" -#include"pb2bv_model_converter.h" +#include "util/trace.h" +#include "ast/arith_decl_plugin.h" +#include "model/model_v2_pp.h" +#include "tactic/arith/pb2bv_model_converter.h" pb2bv_model_converter::pb2bv_model_converter(ast_manager & _m) : m(_m) { diff --git a/src/tactic/arith/pb2bv_model_converter.h b/src/tactic/arith/pb2bv_model_converter.h index 8b6256ccc..0c2826573 100644 --- a/src/tactic/arith/pb2bv_model_converter.h +++ b/src/tactic/arith/pb2bv_model_converter.h @@ -19,8 +19,8 @@ Notes: #ifndef PB2BV_MODEL_CONVERTER_H_ #define PB2BV_MODEL_CONVERTER_H_ -#include"model_converter.h" -#include"bound_manager.h" +#include "tactic/model_converter.h" +#include "tactic/arith/bound_manager.h" class pb2bv_model_converter : public model_converter { typedef std::pair func_decl_pair; diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index 3931a1ea4..259cbc0c8 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -16,20 +16,20 @@ Author: Notes: --*/ -#include"tactical.h" -#include"cooperate.h" -#include"bound_manager.h" -#include"bool_rewriter.h" -#include"rewriter_def.h" -#include"ref_util.h" -#include"arith_decl_plugin.h" -#include"trace.h" -#include"ast_smt2_pp.h" -#include"expr_substitution.h" -#include"filter_model_converter.h" -#include"pb2bv_model_converter.h" -#include"pb2bv_tactic.h" -#include"ast_pp.h" +#include "tactic/tactical.h" +#include "util/cooperate.h" +#include "tactic/arith/bound_manager.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "util/ref_util.h" +#include "ast/arith_decl_plugin.h" +#include "util/trace.h" +#include "ast/ast_smt2_pp.h" +#include "ast/expr_substitution.h" +#include "tactic/filter_model_converter.h" +#include "tactic/arith/pb2bv_model_converter.h" +#include "tactic/arith/pb2bv_tactic.h" +#include "ast/ast_pp.h" class pb2bv_tactic : public tactic { public: diff --git a/src/tactic/arith/pb2bv_tactic.h b/src/tactic/arith/pb2bv_tactic.h index 7d7e8919c..49e87a8f7 100644 --- a/src/tactic/arith/pb2bv_tactic.h +++ b/src/tactic/arith/pb2bv_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef PB2BV_TACTIC_H_ #define PB2BV_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/probe_arith.cpp b/src/tactic/arith/probe_arith.cpp index 5d5590263..edd4483e7 100644 --- a/src/tactic/arith/probe_arith.cpp +++ b/src/tactic/arith/probe_arith.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include"probe.h" -#include"expr2polynomial.h" -#include"for_each_expr.h" -#include"arith_decl_plugin.h" -#include"goal_util.h" +#include "tactic/probe.h" +#include "ast/expr2polynomial.h" +#include "ast/for_each_expr.h" +#include "ast/arith_decl_plugin.h" +#include "tactic/goal_util.h" class arith_degree_probe : public probe { struct proc { @@ -392,24 +392,27 @@ struct is_non_nira_functor { is_non_nira_functor(ast_manager & _m, bool _int, bool _real, bool _quant, bool linear):m(_m), u(m), m_int(_int), m_real(_real), m_quant(_quant), m_linear(linear) {} - void throw_found() { + void throw_found(expr* e) { + TRACE("probe", tout << expr_ref(e, m) << ": " << sort_ref(m.get_sort(e), m) << "\n";); throw found(); } void operator()(var * x) { if (!m_quant) - throw_found(); + throw_found(x); sort * s = x->get_sort(); if (m_int && u.is_int(s)) return; if (m_real && u.is_real(s)) return; - throw_found(); + if (m.is_bool(s)) + return; + throw_found(x); } - void operator()(quantifier *) { + void operator()(quantifier * q) { if (!m_quant) - throw_found(); + throw_found(q); } bool compatible_sort(app * n) const { @@ -424,7 +427,7 @@ struct is_non_nira_functor { void operator()(app * n) { if (!compatible_sort(n)) - throw_found(); + throw_found(n); family_id fid = n->get_family_id(); if (fid == m.get_basic_family_id()) return; @@ -437,39 +440,39 @@ struct is_non_nira_functor { case OP_MUL: if (m_linear) { if (n->get_num_args() != 2) - throw_found(); + throw_found(n); if (!u.is_numeral(n->get_arg(0))) - throw_found(); + throw_found(n); } return; case OP_IDIV: case OP_DIV: case OP_REM: case OP_MOD: if (m_linear && !u.is_numeral(n->get_arg(1))) - throw_found(); + throw_found(n); return; case OP_IS_INT: if (m_real) - throw_found(); + throw_found(n); return; case OP_TO_INT: case OP_TO_REAL: return; case OP_POWER: if (m_linear) - throw_found(); + throw_found(n); return; case OP_IRRATIONAL_ALGEBRAIC_NUM: if (m_linear || !m_real) - throw_found(); + throw_found(n); return; default: - throw_found(); + throw_found(n); } return; } if (is_uninterp_const(n)) return; - throw_found(); + throw_found(n); } }; diff --git a/src/tactic/arith/propagate_ineqs_tactic.cpp b/src/tactic/arith/propagate_ineqs_tactic.cpp index 1a3447f38..d7209740f 100644 --- a/src/tactic/arith/propagate_ineqs_tactic.cpp +++ b/src/tactic/arith/propagate_ineqs_tactic.cpp @@ -30,11 +30,11 @@ Author: Notes: --*/ -#include"tactical.h" -#include"bound_propagator.h" -#include"arith_decl_plugin.h" -#include"simplify_tactic.h" -#include"ast_smt2_pp.h" +#include "tactic/tactical.h" +#include "tactic/arith/bound_propagator.h" +#include "ast/arith_decl_plugin.h" +#include "tactic/core/simplify_tactic.h" +#include "ast/ast_smt2_pp.h" class propagate_ineqs_tactic : public tactic { struct imp; diff --git a/src/tactic/arith/propagate_ineqs_tactic.h b/src/tactic/arith/propagate_ineqs_tactic.h index 1027bd09f..fb5e370c6 100644 --- a/src/tactic/arith/propagate_ineqs_tactic.h +++ b/src/tactic/arith/propagate_ineqs_tactic.h @@ -33,7 +33,7 @@ Notes: #ifndef PROPAGATE_INEQS_TACTIC_H_ #define PROPAGATE_INEQS_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 463e1a9e8..7e89794ce 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -20,17 +20,17 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"rewriter_def.h" -#include"arith_decl_plugin.h" -#include"algebraic_numbers.h" -#include"nnf_tactic.h" -#include"simplify_tactic.h" -#include"th_rewriter.h" -#include"filter_model_converter.h" -#include"extension_model_converter.h" -#include"ast_smt2_pp.h" -#include"expr_replacer.h" +#include "tactic/tactical.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/arith_decl_plugin.h" +#include "math/polynomial/algebraic_numbers.h" +#include "tactic/core/nnf_tactic.h" +#include "tactic/core/simplify_tactic.h" +#include "ast/rewriter/th_rewriter.h" +#include "tactic/filter_model_converter.h" +#include "tactic/extension_model_converter.h" +#include "ast/ast_smt2_pp.h" +#include "ast/rewriter/expr_replacer.h" /* ---- @@ -297,11 +297,11 @@ struct purify_arith_proc { push_cnstr(OR(EQ(y, mk_real_zero()), EQ(u().mk_mul(y, k), x))); push_cnstr_pr(result_pr); - - if (complete()) { + rational r; + if (complete() && (!u().is_numeral(y, r) || r.is_zero())) { // y != 0 \/ k = div-0(x) push_cnstr(OR(NOT(EQ(y, mk_real_zero())), - EQ(k, u().mk_div0(x)))); + EQ(k, u().mk_div(x, mk_real_zero())))); push_cnstr_pr(result_pr); } } @@ -348,11 +348,12 @@ struct purify_arith_proc { push_cnstr(OR(u().mk_ge(y, zero), u().mk_lt(k2, u().mk_mul(u().mk_numeral(rational(-1), true), y)))); push_cnstr_pr(mod_pr); - if (complete()) { - push_cnstr(OR(NOT(EQ(y, zero)), EQ(k1, u().mk_idiv0(x)))); + rational r; + if (complete() && (!u().is_numeral(y, r) || r.is_zero())) { + push_cnstr(OR(NOT(EQ(y, zero)), EQ(k1, u().mk_idiv(x, zero)))); push_cnstr_pr(result_pr); - push_cnstr(OR(NOT(EQ(y, zero)), EQ(k2, u().mk_mod0(x)))); + push_cnstr(OR(NOT(EQ(y, zero)), EQ(k2, u().mk_mod(x, zero)))); push_cnstr_pr(mod_pr); } } @@ -414,7 +415,7 @@ struct purify_arith_proc { // (^ x 0) --> k | x != 0 implies k = 1, x = 0 implies k = 0^0 push_cnstr(OR(EQ(x, zero), EQ(k, one))); push_cnstr_pr(result_pr); - push_cnstr(OR(NOT(EQ(x, zero)), EQ(k, is_int ? u().mk_0_pw_0_int() : u().mk_0_pw_0_real()))); + push_cnstr(OR(NOT(EQ(x, zero)), EQ(k, u().mk_power(zero, zero)))); push_cnstr_pr(result_pr); } else if (!is_int) { diff --git a/src/tactic/arith/purify_arith_tactic.h b/src/tactic/arith/purify_arith_tactic.h index 9d4c927ff..bbb62710c 100644 --- a/src/tactic/arith/purify_arith_tactic.h +++ b/src/tactic/arith/purify_arith_tactic.h @@ -48,7 +48,7 @@ Revision History: #ifndef PURIFY_ARITH_TACTIC_H_ #define PURIFY_ARITH_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index 393d30b58..d3b9ecc3e 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -30,14 +30,14 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"th_rewriter.h" -#include"extension_model_converter.h" -#include"filter_model_converter.h" -#include"arith_decl_plugin.h" -#include"expr_substitution.h" -#include"dec_ref_util.h" -#include"ast_smt2_pp.h" +#include "tactic/tactical.h" +#include "ast/rewriter/th_rewriter.h" +#include "tactic/extension_model_converter.h" +#include "tactic/filter_model_converter.h" +#include "ast/arith_decl_plugin.h" +#include "ast/expr_substitution.h" +#include "util/dec_ref_util.h" +#include "ast/ast_smt2_pp.h" class recover_01_tactic : public tactic { struct imp { diff --git a/src/tactic/arith/recover_01_tactic.h b/src/tactic/arith/recover_01_tactic.h index baa8ae06f..898586481 100644 --- a/src/tactic/arith/recover_01_tactic.h +++ b/src/tactic/arith/recover_01_tactic.h @@ -33,7 +33,7 @@ Revision History: #ifndef RECOVER_01_TACTIC_H_ #define RECOVER_01_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index a18862ee8..373cf3113 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -16,11 +16,11 @@ Author: Notes: --*/ -#include"model.h" -#include"model_pp.h" -#include"model_converter.h" -#include"bv_decl_plugin.h" -#include"ast_smt2_pp.h" +#include "model/model.h" +#include "model/model_pp.h" +#include "tactic/model_converter.h" +#include "ast/bv_decl_plugin.h" +#include "ast/ast_smt2_pp.h" /** If TO_BOOL == true, then bit-vectors of size n were blasted into n-tuples of Booleans. diff --git a/src/tactic/bv/bit_blaster_model_converter.h b/src/tactic/bv/bit_blaster_model_converter.h index 87a12a89e..f7dd254b4 100644 --- a/src/tactic/bv/bit_blaster_model_converter.h +++ b/src/tactic/bv/bit_blaster_model_converter.h @@ -19,7 +19,7 @@ Notes: #ifndef BIT_BLASTER_MODEL_CONVERTER_H_ #define BIT_BLASTER_MODEL_CONVERTER_H_ -#include"model_converter.h" +#include "tactic/model_converter.h" model_converter * mk_bit_blaster_model_converter(ast_manager & m, obj_map const & const2bits); model_converter * mk_bv1_blaster_model_converter(ast_manager & m, obj_map const & const2bits); diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index 7e19585d9..5c6c43778 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -16,12 +16,12 @@ Author: Notes: --*/ -#include"tactical.h" -#include"bit_blaster_model_converter.h" -#include"bit_blaster_rewriter.h" -#include"ast_pp.h" -#include"model_pp.h" -#include"rewriter_types.h" +#include "tactic/tactical.h" +#include "tactic/bv/bit_blaster_model_converter.h" +#include "ast/rewriter/bit_blaster/bit_blaster_rewriter.h" +#include "ast/ast_pp.h" +#include "model/model_pp.h" +#include "ast/rewriter/rewriter_types.h" class bit_blaster_tactic : public tactic { diff --git a/src/tactic/bv/bit_blaster_tactic.h b/src/tactic/bv/bit_blaster_tactic.h index d840154b9..2dccafb6d 100644 --- a/src/tactic/bv/bit_blaster_tactic.h +++ b/src/tactic/bv/bit_blaster_tactic.h @@ -19,8 +19,8 @@ Copyright (c) 2011 Microsoft Corporation #ifndef BIT_BLASTER_TACTIC_H_ #define BIT_BLASTER_TACTIC_H_ - #include"params.h" - #include"bit_blaster_rewriter.h" +#include "util/params.h" +#include "ast/rewriter/bit_blaster/bit_blaster_rewriter.h" class ast_manager; class tactic; diff --git a/src/tactic/bv/bv1_blaster_tactic.cpp b/src/tactic/bv/bv1_blaster_tactic.cpp index e7327e7a9..e7e374184 100644 --- a/src/tactic/bv/bv1_blaster_tactic.cpp +++ b/src/tactic/bv/bv1_blaster_tactic.cpp @@ -22,13 +22,13 @@ Author: Notes: --*/ -#include"tactical.h" -#include"bit_blaster_model_converter.h" -#include"bv_decl_plugin.h" -#include"rewriter_def.h" -#include"for_each_expr.h" -#include"cooperate.h" -#include"bv_rewriter.h" +#include "tactic/tactical.h" +#include "tactic/bv/bit_blaster_model_converter.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/for_each_expr.h" +#include "util/cooperate.h" +#include "ast/rewriter/bv_rewriter.h" class bv1_blaster_tactic : public tactic { diff --git a/src/tactic/bv/bv1_blaster_tactic.h b/src/tactic/bv/bv1_blaster_tactic.h index cad1d59b6..5c8632fbc 100644 --- a/src/tactic/bv/bv1_blaster_tactic.h +++ b/src/tactic/bv/bv1_blaster_tactic.h @@ -25,7 +25,7 @@ Notes: #ifndef BV1_BLASTER_TACTIC_H_ #define BV1_BLASTER_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index 1b90e05b1..b71b44bd0 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -14,14 +14,14 @@ Revision History: --*/ -#include"bv_bound_chk_tactic.h" -#include"ast.h" -#include"rewriter.h" -#include"rewriter_def.h" -#include"bv_bounds.h" -#include"rewriter_params.hpp" -#include"bool_rewriter.h" -#include"cooperate.h" +#include "tactic/bv/bv_bound_chk_tactic.h" +#include "ast/ast.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/bv_bounds.h" +#include "ast/rewriter/rewriter_params.hpp" +#include "ast/rewriter/bool_rewriter.h" +#include "util/cooperate.h" struct bv_bound_chk_stats { unsigned m_unsats; diff --git a/src/tactic/bv/bv_bound_chk_tactic.h b/src/tactic/bv/bv_bound_chk_tactic.h index f134d42ab..0cdadb0de 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.h +++ b/src/tactic/bv/bv_bound_chk_tactic.h @@ -17,9 +17,9 @@ #ifndef BV_BOUND_CHK_TACTIC_H_ #define BV_BOUND_CHK_TACTIC_H_ -#include"tactical.h" -#include"params.h" -#include"ast.h" +#include "tactic/tactical.h" +#include "util/params.h" +#include "ast/ast.h" tactic* mk_bv_bound_chk_tactic(ast_manager & m, params_ref const & p = params_ref()); diff --git a/src/tactic/bv/bv_bounds_tactic.cpp b/src/tactic/bv/bv_bounds_tactic.cpp index 94c9935b9..a279e441b 100644 --- a/src/tactic/bv/bv_bounds_tactic.cpp +++ b/src/tactic/bv/bv_bounds_tactic.cpp @@ -11,15 +11,18 @@ Abstract: Author: - Nikolaj Bjorner (nbjorner) 2016-2-12 + Nuno Lopes (nlopes) 2016-2-12 + + Nikolaj Bjorner (nbjorner) --*/ -#include "bv_bounds_tactic.h" -#include "ctx_simplify_tactic.h" -#include "bv_decl_plugin.h" -#include "ast_pp.h" +#include "tactic/bv/bv_bounds_tactic.h" +#include "tactic/core/ctx_simplify_tactic.h" +#include "tactic/core/dom_simplify_tactic.h" +#include "ast/bv_decl_plugin.h" +#include "ast/ast_pp.h" #include static uint64 uMaxInt(unsigned sz) { @@ -29,507 +32,793 @@ static uint64 uMaxInt(unsigned sz) { namespace { -struct interval { - // l < h: [l, h] - // l > h: [0, h] U [l, UMAX_INT] - uint64 l, h; - unsigned sz; - bool tight; + struct interval { + // l < h: [l, h] + // l > h: [0, h] U [l, UMAX_INT] + uint64 l, h; + unsigned sz; + bool tight; - interval() {} - interval(uint64 l, uint64 h, unsigned sz, bool tight = false) : l(l), h(h), sz(sz), tight(tight) { - // canonicalize full set - if (is_wrapped() && l == h + 1) { - this->l = 0; - this->h = uMaxInt(sz); - } - SASSERT(invariant()); - } - - bool invariant() const { - return l <= uMaxInt(sz) && h <= uMaxInt(sz) && - (!is_wrapped() || l != h+1); - } - - bool is_full() const { return l == 0 && h == uMaxInt(sz); } - bool is_wrapped() const { return l > h; } - bool is_singleton() const { return l == h; } - - bool operator==(const interval& b) const { - SASSERT(sz == b.sz); - return l == b.l && h == b.h && tight == b.tight; - } - bool operator!=(const interval& b) const { return !(*this == b); } - - bool implies(const interval& b) const { - if (b.is_full()) - return true; - if (is_full()) - return false; - - if (is_wrapped()) { - // l >= b.l >= b.h >= h - return b.is_wrapped() && h <= b.h && l >= b.l; - } else if (b.is_wrapped()) { - // b.l > b.h >= h >= l - // h >= l >= b.l > b.h - return h <= b.h || l >= b.l; - } else { - // - return l >= b.l && h <= b.h; - } - } - - /// return false if intersection is unsat - bool intersect(const interval& b, interval& result) const { - if (is_full() || *this == b) { - result = b; - return true; - } - if (b.is_full()) { - result = *this; - return true; + interval() {} + interval(uint64 l, uint64 h, unsigned sz, bool tight = false) : l(l), h(h), sz(sz), tight(tight) { + // canonicalize full set + if (is_wrapped() && l == h + 1) { + this->l = 0; + this->h = uMaxInt(sz); + } + SASSERT(invariant()); } - if (is_wrapped()) { - if (b.is_wrapped()) { - if (h >= b.l) { - result = b; - } else if (b.h >= l) { - result = *this; + bool invariant() const { + return l <= uMaxInt(sz) && h <= uMaxInt(sz) && + (!is_wrapped() || l != h+1); + } + + bool is_full() const { return l == 0 && h == uMaxInt(sz); } + bool is_wrapped() const { return l > h; } + bool is_singleton() const { return l == h; } + + bool operator==(const interval& b) const { + SASSERT(sz == b.sz); + return l == b.l && h == b.h && tight == b.tight; + } + bool operator!=(const interval& b) const { return !(*this == b); } + + bool implies(const interval& b) const { + if (b.is_full()) + return true; + if (is_full()) + return false; + + if (is_wrapped()) { + // l >= b.l >= b.h >= h + return b.is_wrapped() && h <= b.h && l >= b.l; + } + else if (b.is_wrapped()) { + // b.l > b.h >= h >= l + // h >= l >= b.l > b.h + return h <= b.h || l >= b.l; + } + else { + // + return l >= b.l && h <= b.h; + } + } + + /// return false if intersection is unsat + bool intersect(const interval& b, interval& result) const { + if (is_full() || *this == b) { + result = b; + return true; + } + if (b.is_full()) { + result = *this; + return true; + } + + if (is_wrapped()) { + if (b.is_wrapped()) { + if (h >= b.l) { + result = b; + } else if (b.h >= l) { + result = *this; + } else { + result = interval(std::max(l, b.l), std::min(h, b.h), sz); + } } else { - result = interval(std::max(l, b.l), std::min(h, b.h), sz); + return b.intersect(*this, result); + } + } + else if (b.is_wrapped()) { + // ... b.h ... l ... h ... b.l .. + if (h < b.l && l > b.h) { + return false; + } + // ... l ... b.l ... h ... + if (h >= b.l && l <= b.h) { + result = b; + } else if (h >= b.l) { + result = interval(b.l, h, sz); + } else { + // ... l .. b.h .. h .. b.l ... + SASSERT(l <= b.h); + result = interval(l, std::min(h, b.h), sz); } } else { - return b.intersect(*this, result); - } - } else if (b.is_wrapped()) { - // ... b.h ... l ... h ... b.l .. - if (h < b.l && l > b.h) { - return false; - } - // ... l ... b.l ... h ... - if (h >= b.l && l <= b.h) { - result = b; - } else if (h >= b.l) { - result = interval(b.l, h, sz); - } else { - // ... l .. b.h .. h .. b.l ... - SASSERT(l <= b.h); - result = interval(l, std::min(h, b.h), sz); - } - } else { - if (l > b.h || h < b.l) - return false; + if (l > b.h || h < b.l) + return false; - // 0 .. l.. l' ... h ... h' - result = interval(std::max(l, b.l), std::min(h, b.h), sz, tight && b.tight); - } - return true; - } - - /// return false if negation is empty - bool negate(interval& result) const { - if (!tight) { - result = interval(0, uMaxInt(sz), true); + // 0 .. l.. l' ... h ... h' + result = interval(std::max(l, b.l), std::min(h, b.h), sz, tight && b.tight); + } return true; } - if (is_full()) - return false; - if (l == 0) { - result = interval(h + 1, uMaxInt(sz), sz); - } else if (uMaxInt(sz) == h) { - result = interval(0, l - 1, sz); - } else { - result = interval(h + 1, l - 1, sz); + /// return false if negation is empty + bool negate(interval& result) const { + if (!tight) { + result = interval(0, uMaxInt(sz), true); + return true; + } + + if (is_full()) + return false; + if (l == 0) { + result = interval(h + 1, uMaxInt(sz), sz); + } else if (uMaxInt(sz) == h) { + result = interval(0, l - 1, sz); + } else { + result = interval(h + 1, l - 1, sz); + } + return true; } - return true; - } -}; + }; #ifdef _TRACE -std::ostream& operator<<(std::ostream& o, const interval& I) { - o << "[" << I.l << ", " << I.h << "]"; - return o; -} -#endif - - -struct undo_bound { - expr* e; - interval b; - bool fresh; - undo_bound(expr* e, const interval& b, bool fresh) : e(e), b(b), fresh(fresh) {} -}; - -class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier { - typedef obj_map map; - typedef obj_map expr_set; - typedef obj_map expr_cnt; - - ast_manager& m; - params_ref m_params; - bool m_propagate_eq; - bv_util m_bv; - vector m_scopes; - map m_bound; - svector m_expr_vars; - svector m_bound_exprs; - - bool is_number(expr *e, uint64& n, unsigned& sz) const { - rational r; - if (m_bv.is_numeral(e, r, sz) && sz <= 64) { - n = r.get_uint64(); - return true; - } - return false; - } - - bool is_bound(expr *e, expr*& v, interval& b) const { - uint64 n; - expr *lhs, *rhs; - unsigned sz; - - if (m_bv.is_bv_ule(e, lhs, rhs)) { - if (is_number(lhs, n, sz)) { // C ule x <=> x uge C - if (m_bv.is_numeral(rhs)) - return false; - b = interval(n, uMaxInt(sz), sz, true); - v = rhs; - return true; - } - if (is_number(rhs, n, sz)) { // x ule C - b = interval(0, n, sz, true); - v = lhs; - return true; - } - } else if (m_bv.is_bv_sle(e, lhs, rhs)) { - if (is_number(lhs, n, sz)) { // C sle x <=> x sge C - if (m_bv.is_numeral(rhs)) - return false; - b = interval(n, (1ull << (sz-1)) - 1, sz, true); - v = rhs; - return true; - } - if (is_number(rhs, n, sz)) { // x sle C - b = interval(1ull << (sz-1), n, sz, true); - v = lhs; - return true; - } - } else if (m.is_eq(e, lhs, rhs)) { - if (is_number(lhs, n, sz)) { - if (m_bv.is_numeral(rhs)) - return false; - b = interval(n, n, sz, true); - v = rhs; - return true; - } - if (is_number(rhs, n, sz)) { - b = interval(n, n, sz, true); - v = lhs; - return true; - } - } - return false; - } - -#if 0 - expr_set* get_expr_vars(expr* t) { - unsigned id = t->get_id(); - m_expr_vars.reserve(id + 1); - expr_set*& entry = m_expr_vars[id]; - if (entry) - return entry; - - expr_set* set = alloc(expr_set); - entry = set; - - if (!m_bv.is_numeral(t)) - set->insert(t, true); - - if (!is_app(t)) - return set; - - app* a = to_app(t); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - expr_set* set_arg = get_expr_vars(a->get_arg(i)); - for (expr_set::iterator I = set_arg->begin(), E = set_arg->end(); I != E; ++I) { - set->insert(I->m_key, true); - } - } - return set; + std::ostream& operator<<(std::ostream& o, const interval& I) { + o << "[" << I.l << ", " << I.h << "]"; + return o; } #endif -#if 0 - expr_cnt* get_expr_bounds(expr* t) { - unsigned id = t->get_id(); - m_bound_exprs.reserve(id + 1); - expr_cnt*& entry = m_bound_exprs[id]; - if (entry) - return entry; - expr_cnt* set = alloc(expr_cnt); - entry = set; - - if (!is_app(t)) - return set; - - interval b; + struct undo_bound { expr* e; - if (is_bound(t, e, b)) { - set->insert_if_not_there2(e, 0)->get_data().m_value++; + interval b; + bool fresh; + undo_bound(expr* e, const interval& b, bool fresh) : e(e), b(b), fresh(fresh) {} + }; + + class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier { + typedef obj_map map; + typedef obj_map expr_set; + typedef obj_map expr_cnt; + + ast_manager& m; + params_ref m_params; + bool m_propagate_eq; + bv_util m_bv; + vector m_scopes; + map m_bound; + svector m_expr_vars; + svector m_bound_exprs; + + bool is_number(expr *e, uint64& n, unsigned& sz) const { + rational r; + if (m_bv.is_numeral(e, r, sz) && sz <= 64) { + n = r.get_uint64(); + return true; + } + return false; } - app* a = to_app(t); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - expr_cnt* set_arg = get_expr_bounds(a->get_arg(i)); - for (expr_cnt::iterator I = set_arg->begin(), E = set_arg->end(); I != E; ++I) { - set->insert_if_not_there2(I->m_key, 0)->get_data().m_value += I->m_value; + bool is_bound(expr *e, expr*& v, interval& b) const { + uint64 n; + expr *lhs = 0, *rhs = 0; + unsigned sz; + + if (m_bv.is_bv_ule(e, lhs, rhs)) { + if (is_number(lhs, n, sz)) { // C ule x <=> x uge C + if (m_bv.is_numeral(rhs)) + return false; + b = interval(n, uMaxInt(sz), sz, true); + v = rhs; + return true; + } + if (is_number(rhs, n, sz)) { // x ule C + b = interval(0, n, sz, true); + v = lhs; + return true; + } + } + else if (m_bv.is_bv_sle(e, lhs, rhs)) { + if (is_number(lhs, n, sz)) { // C sle x <=> x sge C + if (m_bv.is_numeral(rhs)) + return false; + b = interval(n, (1ull << (sz-1)) - 1, sz, true); + v = rhs; + return true; + } + if (is_number(rhs, n, sz)) { // x sle C + b = interval(1ull << (sz-1), n, sz, true); + v = lhs; + return true; + } + } else if (m.is_eq(e, lhs, rhs)) { + if (is_number(lhs, n, sz)) { + if (m_bv.is_numeral(rhs)) + return false; + b = interval(n, n, sz, true); + v = rhs; + return true; + } + if (is_number(rhs, n, sz)) { + b = interval(n, n, sz, true); + v = lhs; + return true; + } } + return false; + } + +#if 0 + expr_set* get_expr_vars(expr* t) { + unsigned id = t->get_id(); + m_expr_vars.reserve(id + 1); + expr_set*& entry = m_expr_vars[id]; + if (entry) + return entry; + + expr_set* set = alloc(expr_set); + entry = set; + + if (!m_bv.is_numeral(t)) + set->insert(t, true); + + if (!is_app(t)) + return set; + + app* a = to_app(t); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + expr_set* set_arg = get_expr_vars(a->get_arg(i)); + for (expr_set::iterator I = set_arg->begin(), E = set_arg->end(); I != E; ++I) { + set->insert(I->m_key, true); + } + } + return set; } - return set; - } #endif -public: - bv_bounds_simplifier(ast_manager& m, params_ref const& p) : m(m), m_params(p), m_bv(m) { - updt_params(p); - } +#if 0 + expr_cnt* get_expr_bounds(expr* t) { + unsigned id = t->get_id(); + m_bound_exprs.reserve(id + 1); + expr_cnt*& entry = m_bound_exprs[id]; + if (entry) + return entry; - virtual void updt_params(params_ref const & p) { - m_propagate_eq = p.get_bool("propagate_eq", false); - } + expr_cnt* set = alloc(expr_cnt); + entry = set; - static void get_param_descrs(param_descrs& r) { - r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities"); - } + if (!is_app(t)) + return set; - virtual ~bv_bounds_simplifier() { - for (unsigned i = 0, e = m_expr_vars.size(); i < e; ++i) { - dealloc(m_expr_vars[i]); - } - for (unsigned i = 0, e = m_bound_exprs.size(); i < e; ++i) { - dealloc(m_bound_exprs[i]); - } - } - - virtual bool assert_expr(expr * t, bool sign) { - while (m.is_not(t, t)) { - sign = !sign; - } - - interval b; - expr* t1; - if (is_bound(t, t1, b)) { - SASSERT(!m_bv.is_numeral(t1)); - if (sign) - VERIFY(b.negate(b)); - - TRACE("bv", tout << (sign?"(not ":"") << mk_pp(t, m) << (sign ? ")" : "") << ": " << mk_pp(t1, m) << " in " << b << "\n";); - map::obj_map_entry* e = m_bound.find_core(t1); - if (e) { - interval& old = e->get_data().m_value; - interval intr; - if (!old.intersect(b, intr)) - return false; - if (old == intr) - return true; - m_scopes.insert(undo_bound(t1, old, false)); - old = intr; - } else { - m_bound.insert(t1, b); - m_scopes.insert(undo_bound(t1, interval(), true)); - } - } - return true; - } - - virtual bool simplify(expr* t, expr_ref& result) { - expr* t1; - interval b; - - if (m_bound.find(t, b) && b.is_singleton()) { - result = m_bv.mk_numeral(b.l, m_bv.get_bv_size(t)); - return true; - } - - if (!m.is_bool(t)) - return false; - - bool sign = false; - while (m.is_not(t, t)) { - sign = !sign; - } - - if (!is_bound(t, t1, b)) - return false; - - if (sign && b.tight) { - sign = false; - if (!b.negate(b)) { - result = m.mk_false(); - return true; - } - } - - interval ctx, intr; - result = 0; - - if (b.is_full() && b.tight) { - result = m.mk_true(); - } else if (m_bound.find(t1, ctx)) { - if (ctx.implies(b)) { - result = m.mk_true(); - } else if (!b.intersect(ctx, intr)) { - result = m.mk_false(); - } else if (m_propagate_eq && intr.is_singleton()) { - result = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()), - m.get_sort(t1))); - } - } - - CTRACE("bv", result != 0, tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << result << "\n";); - if (sign && result != 0) - result = m.mk_not(result); - return result != 0; - } - - // check if t contains v - ptr_vector todo; - bool contains(expr* t, expr* v) { - ast_fast_mark1 mark; - todo.push_back(t); - while (!todo.empty()) { - t = todo.back(); - todo.pop_back(); - if (mark.is_marked(t)) { - continue; - } - if (t == v) { - todo.reset(); - return true; - } - mark.mark(t); - - if (!is_app(t)) { - continue; - } - app* a = to_app(t); - todo.append(a->get_num_args(), a->get_args()); - } - return false; - } - - bool contains_bound(expr* t) { - ast_fast_mark1 mark1; - ast_fast_mark2 mark2; - - todo.push_back(t); - while (!todo.empty()) { - t = todo.back(); - todo.pop_back(); - if (mark1.is_marked(t)) { - continue; - } - mark1.mark(t); - - if (!is_app(t)) { - continue; - } interval b; expr* e; if (is_bound(t, e, b)) { - if (mark2.is_marked(e)) { - todo.reset(); - return true; - } - mark2.mark(e); - if (m_bound.contains(e)) { - todo.reset(); - return true; - } + set->insert_if_not_there2(e, 0)->get_data().m_value++; } app* a = to_app(t); - todo.append(a->get_num_args(), a->get_args()); - } - return false; - } - - virtual bool may_simplify(expr* t) { - if (m_bv.is_numeral(t)) - return false; - - while (m.is_not(t, t)); - - for (auto & v : m_bound) { - if (contains(t, v.m_key)) return true; - } - -#if 0 - expr_set* used_exprs = get_expr_vars(t); - for (map::iterator I = m_bound.begin(), E = m_bound.end(); I != E; ++I) { - if (contains(t, I->m_key)) return true; - if (I->m_value.is_singleton() && used_exprs->contains(I->m_key)) - return true; + for (unsigned i = 0; i < a->get_num_args(); ++i) { + expr_cnt* set_arg = get_expr_bounds(a->get_arg(i)); + for (expr_cnt::iterator I = set_arg->begin(), E = set_arg->end(); I != E; ++I) { + set->insert_if_not_there2(I->m_key, 0)->get_data().m_value += I->m_value; + } + } + return set; } #endif - expr* t1; - interval b; - // skip common case: single bound constraint without any context for simplification - if (is_bound(t, t1, b)) { - return b.is_full() || m_bound.contains(t1); + public: + bv_bounds_simplifier(ast_manager& m, params_ref const& p) : m(m), m_params(p), m_bv(m) { + updt_params(p); } - if (contains_bound(t)) { - return true; + virtual void updt_params(params_ref const & p) { + m_propagate_eq = p.get_bool("propagate_eq", false); } -#if 0 - expr_cnt* bounds = get_expr_bounds(t); - for (expr_cnt::iterator I = bounds->begin(), E = bounds->end(); I != E; ++I) { - if (I->m_value > 1 || m_bound.contains(I->m_key)) - return true; - } -#endif - return false; - } - virtual void pop(unsigned num_scopes) { - TRACE("bv", tout << "pop: " << num_scopes << "\n";); - if (m_scopes.empty()) - return; - unsigned target = m_scopes.size() - num_scopes; - if (target == 0) { - m_bound.reset(); - m_scopes.reset(); - return; + static void get_param_descrs(param_descrs& r) { + r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities"); } - for (unsigned i = m_scopes.size()-1; i >= target; --i) { - undo_bound& undo = m_scopes[i]; - SASSERT(m_bound.contains(undo.e)); - if (undo.fresh) { - m_bound.erase(undo.e); - } else { - m_bound.insert(undo.e, undo.b); + + virtual ~bv_bounds_simplifier() { + for (unsigned i = 0, e = m_expr_vars.size(); i < e; ++i) { + dealloc(m_expr_vars[i]); + } + for (unsigned i = 0, e = m_bound_exprs.size(); i < e; ++i) { + dealloc(m_bound_exprs[i]); } } - m_scopes.shrink(target); - } - virtual simplifier * translate(ast_manager & m) { - return alloc(bv_bounds_simplifier, m, m_params); - } + virtual bool assert_expr(expr * t, bool sign) { + while (m.is_not(t, t)) { + sign = !sign; + } - virtual unsigned scope_level() const { - return m_scopes.size(); - } -}; + interval b; + expr* t1; + if (is_bound(t, t1, b)) { + SASSERT(!m_bv.is_numeral(t1)); + if (sign) + VERIFY(b.negate(b)); + + TRACE("bv", tout << (sign?"(not ":"") << mk_pp(t, m) << (sign ? ")" : "") << ": " << mk_pp(t1, m) << " in " << b << "\n";); + map::obj_map_entry* e = m_bound.find_core(t1); + if (e) { + interval& old = e->get_data().m_value; + interval intr; + if (!old.intersect(b, intr)) + return false; + if (old == intr) + return true; + m_scopes.insert(undo_bound(t1, old, false)); + old = intr; + } else { + m_bound.insert(t1, b); + m_scopes.insert(undo_bound(t1, interval(), true)); + } + } + return true; + } + + virtual bool simplify(expr* t, expr_ref& result) { + expr* t1; + interval b; + + if (m_bound.find(t, b) && b.is_singleton()) { + result = m_bv.mk_numeral(b.l, m_bv.get_bv_size(t)); + return true; + } + + if (!m.is_bool(t)) + return false; + + bool sign = false; + while (m.is_not(t, t)) { + sign = !sign; + } + + if (!is_bound(t, t1, b)) + return false; + + if (sign && b.tight) { + sign = false; + if (!b.negate(b)) { + result = m.mk_false(); + return true; + } + } + + interval ctx, intr; + result = 0; + + if (b.is_full() && b.tight) { + result = m.mk_true(); + } else if (m_bound.find(t1, ctx)) { + if (ctx.implies(b)) { + result = m.mk_true(); + } else if (!b.intersect(ctx, intr)) { + result = m.mk_false(); + } else if (m_propagate_eq && intr.is_singleton()) { + result = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()), + m.get_sort(t1))); + } + } + + CTRACE("bv", result != 0, tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << result << "\n";); + if (sign && result != 0) + result = m.mk_not(result); + return result != 0; + } + + // check if t contains v + ptr_vector todo; + bool contains(expr* t, expr* v) { + ast_fast_mark1 mark; + todo.push_back(t); + while (!todo.empty()) { + t = todo.back(); + todo.pop_back(); + if (mark.is_marked(t)) { + continue; + } + if (t == v) { + todo.reset(); + return true; + } + mark.mark(t); + + if (!is_app(t)) { + continue; + } + app* a = to_app(t); + todo.append(a->get_num_args(), a->get_args()); + } + return false; + } + + bool contains_bound(expr* t) { + ast_fast_mark1 mark1; + ast_fast_mark2 mark2; + + todo.push_back(t); + while (!todo.empty()) { + t = todo.back(); + todo.pop_back(); + if (mark1.is_marked(t)) { + continue; + } + mark1.mark(t); + + if (!is_app(t)) { + continue; + } + interval b; + expr* e; + if (is_bound(t, e, b)) { + if (mark2.is_marked(e)) { + todo.reset(); + return true; + } + mark2.mark(e); + if (m_bound.contains(e)) { + todo.reset(); + return true; + } + } + + app* a = to_app(t); + todo.append(a->get_num_args(), a->get_args()); + } + return false; + } + + virtual bool may_simplify(expr* t) { + if (m_bv.is_numeral(t)) + return false; + + while (m.is_not(t, t)); + + for (auto & v : m_bound) { + if (contains(t, v.m_key)) return true; + } + +#if 0 + expr_set* used_exprs = get_expr_vars(t); + for (map::iterator I = m_bound.begin(), E = m_bound.end(); I != E; ++I) { + if (contains(t, I->m_key)) return true; + if (I->m_value.is_singleton() && used_exprs->contains(I->m_key)) + return true; + } +#endif + + expr* t1; + interval b; + // skip common case: single bound constraint without any context for simplification + if (is_bound(t, t1, b)) { + return b.is_full() || m_bound.contains(t1); + } + + if (contains_bound(t)) { + return true; + } +#if 0 + expr_cnt* bounds = get_expr_bounds(t); + for (expr_cnt::iterator I = bounds->begin(), E = bounds->end(); I != E; ++I) { + if (I->m_value > 1 || m_bound.contains(I->m_key)) + return true; + } +#endif + return false; + } + + virtual void pop(unsigned num_scopes) { + TRACE("bv", tout << "pop: " << num_scopes << "\n";); + if (m_scopes.empty()) + return; + unsigned target = m_scopes.size() - num_scopes; + if (target == 0) { + m_bound.reset(); + m_scopes.reset(); + return; + } + for (unsigned i = m_scopes.size()-1; i >= target; --i) { + undo_bound& undo = m_scopes[i]; + SASSERT(m_bound.contains(undo.e)); + if (undo.fresh) { + m_bound.erase(undo.e); + } else { + m_bound.insert(undo.e, undo.b); + } + } + m_scopes.shrink(target); + } + + virtual simplifier * translate(ast_manager & m) { + return alloc(bv_bounds_simplifier, m, m_params); + } + + virtual unsigned scope_level() const { + return m_scopes.size(); + } + }; + + + class dom_bv_bounds_simplifier : public dom_simplifier { + typedef obj_map map; + typedef obj_map expr_set; + typedef obj_map expr_cnt; + + ast_manager& m; + params_ref m_params; + bool m_propagate_eq; + bv_util m_bv; + vector m_scopes; + map m_bound; + svector m_expr_vars; + svector m_bound_exprs; + + bool is_number(expr *e, uint64& n, unsigned& sz) const { + rational r; + if (m_bv.is_numeral(e, r, sz) && sz <= 64) { + n = r.get_uint64(); + return true; + } + return false; + } + + bool is_bound(expr *e, expr*& v, interval& b) const { + uint64 n; + expr *lhs = 0, *rhs = 0; + unsigned sz = 0; + + if (m_bv.is_bv_ule(e, lhs, rhs)) { + if (is_number(lhs, n, sz)) { // C ule x <=> x uge C + if (m_bv.is_numeral(rhs)) + return false; + b = interval(n, uMaxInt(sz), sz, true); + v = rhs; + return true; + } + if (is_number(rhs, n, sz)) { // x ule C + b = interval(0, n, sz, true); + v = lhs; + return true; + } + } + else if (m_bv.is_bv_sle(e, lhs, rhs)) { + if (is_number(lhs, n, sz)) { // C sle x <=> x sge C + if (m_bv.is_numeral(rhs)) + return false; + b = interval(n, (1ull << (sz-1)) - 1, sz, true); + v = rhs; + return true; + } + if (is_number(rhs, n, sz)) { // x sle C + b = interval(1ull << (sz-1), n, sz, true); + v = lhs; + return true; + } + } else if (m.is_eq(e, lhs, rhs)) { + if (is_number(lhs, n, sz)) { + if (m_bv.is_numeral(rhs)) + return false; + b = interval(n, n, sz, true); + v = rhs; + return true; + } + if (is_number(rhs, n, sz)) { + b = interval(n, n, sz, true); + v = lhs; + return true; + } + } + return false; + } + + + public: + dom_bv_bounds_simplifier(ast_manager& m, params_ref const& p) : m(m), m_params(p), m_bv(m) { + updt_params(p); + } + + virtual void updt_params(params_ref const & p) { + m_propagate_eq = p.get_bool("propagate_eq", false); + } + + static void get_param_descrs(param_descrs& r) { + r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities"); + } + + virtual ~dom_bv_bounds_simplifier() { + for (unsigned i = 0, e = m_expr_vars.size(); i < e; ++i) { + dealloc(m_expr_vars[i]); + } + for (unsigned i = 0, e = m_bound_exprs.size(); i < e; ++i) { + dealloc(m_bound_exprs[i]); + } + } + + virtual bool assert_expr(expr * t, bool sign) { + while (m.is_not(t, t)) { + sign = !sign; + } + + interval b; + expr* t1; + if (is_bound(t, t1, b)) { + SASSERT(!m_bv.is_numeral(t1)); + if (sign) + VERIFY(b.negate(b)); + + TRACE("bv", tout << (sign?"(not ":"") << mk_pp(t, m) << (sign ? ")" : "") << ": " << mk_pp(t1, m) << " in " << b << "\n";); + map::obj_map_entry* e = m_bound.find_core(t1); + if (e) { + interval& old = e->get_data().m_value; + interval intr; + if (!old.intersect(b, intr)) + return false; + if (old == intr) + return true; + m_scopes.push_back(undo_bound(t1, old, false)); + old = intr; + } else { + m_bound.insert(t1, b); + m_scopes.push_back(undo_bound(t1, interval(), true)); + } + } + return true; + } + + virtual void operator()(expr_ref& r) { + expr* t1, * t = r; + interval b; + + if (m_bound.find(t, b) && b.is_singleton()) { + r = m_bv.mk_numeral(b.l, m_bv.get_bv_size(t)); + return; + } + + if (!m.is_bool(t)) + return; + + bool sign = false; + while (m.is_not(t, t)) { + sign = !sign; + } + + if (!is_bound(t, t1, b)) + return; + + if (sign && b.tight) { + sign = false; + if (!b.negate(b)) { + r = m.mk_false(); + return; + } + } + + interval ctx, intr; + bool was_updated = true; + if (b.is_full() && b.tight) { + r = m.mk_true(); + } + else if (m_bound.find(t1, ctx)) { + if (ctx.implies(b)) { + r = m.mk_true(); + } + else if (!b.intersect(ctx, intr)) { + r = m.mk_false(); + } + else if (m_propagate_eq && intr.is_singleton()) { + r = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()), + m.get_sort(t1))); + } + else { + was_updated = false; + } + } + else { + was_updated = false; + } + + TRACE("bv", tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << r << "\n";); + if (sign && was_updated) + r = m.mk_not(r); + } + + // check if t contains v + ptr_vector todo; + bool contains(expr* t, expr* v) { + ast_fast_mark1 mark; + todo.push_back(t); + while (!todo.empty()) { + t = todo.back(); + todo.pop_back(); + if (mark.is_marked(t)) { + continue; + } + if (t == v) { + todo.reset(); + return true; + } + mark.mark(t); + + if (!is_app(t)) { + continue; + } + app* a = to_app(t); + todo.append(a->get_num_args(), a->get_args()); + } + return false; + } + + bool contains_bound(expr* t) { + ast_fast_mark1 mark1; + ast_fast_mark2 mark2; + + todo.push_back(t); + while (!todo.empty()) { + t = todo.back(); + todo.pop_back(); + if (mark1.is_marked(t)) { + continue; + } + mark1.mark(t); + + if (!is_app(t)) { + continue; + } + interval b; + expr* e; + if (is_bound(t, e, b)) { + if (mark2.is_marked(e)) { + todo.reset(); + return true; + } + mark2.mark(e); + if (m_bound.contains(e)) { + todo.reset(); + return true; + } + } + + app* a = to_app(t); + todo.append(a->get_num_args(), a->get_args()); + } + return false; + } + + virtual void pop(unsigned num_scopes) { + TRACE("bv", tout << "pop: " << num_scopes << "\n";); + if (m_scopes.empty()) + return; + unsigned target = m_scopes.size() - num_scopes; + if (target == 0) { + m_bound.reset(); + m_scopes.reset(); + return; + } + for (unsigned i = m_scopes.size()-1; i >= target; --i) { + undo_bound& undo = m_scopes[i]; + SASSERT(m_bound.contains(undo.e)); + if (undo.fresh) { + m_bound.erase(undo.e); + } else { + m_bound.insert(undo.e, undo.b); + } + } + m_scopes.shrink(target); + } + + virtual dom_simplifier * translate(ast_manager & m) { + return alloc(dom_bv_bounds_simplifier, m, m_params); + } + + virtual unsigned scope_level() const { + return m_scopes.size(); + } + + }; } tactic * mk_bv_bounds_tactic(ast_manager & m, params_ref const & p) { return clean(alloc(ctx_simplify_tactic, m, alloc(bv_bounds_simplifier, m, p), p)); } + +tactic * mk_dom_bv_bounds_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(dom_simplify_tactic, m, alloc(dom_bv_bounds_simplifier, m, p), p)); +} diff --git a/src/tactic/bv/bv_bounds_tactic.h b/src/tactic/bv/bv_bounds_tactic.h index 4793f474f..1d6748b27 100644 --- a/src/tactic/bv/bv_bounds_tactic.h +++ b/src/tactic/bv/bv_bounds_tactic.h @@ -11,18 +11,26 @@ Abstract: Author: - Nikolaj Bjorner (nbjorner) 2016-2-12 + Nuno Lopes (nlopes) 2016-2-12 + Nikolaj Bjorner (nbjorner) --*/ #ifndef BV_BOUNDS_TACTIC_H_ #define BV_BOUNDS_TACTIC_H_ -#include "tactic.h" +#include "tactic/tactic.h" tactic * mk_bv_bounds_tactic(ast_manager & m, params_ref const & p = params_ref()); +tactic * mk_dom_bv_bounds_tactic(ast_manager & m, params_ref const & p = params_ref()); + /* ADD_TACTIC("propagate-bv-bounds", "propagate bit-vector bounds by simplifying implied or contradictory bounds.", "mk_bv_bounds_tactic(m, p)") + + + ADD_TACTIC("propagate-bv-bounds-new", "propagate bit-vector bounds by simplifying implied or contradictory bounds.", "mk_dom_bv_bounds_tactic(m, p)") + + */ #endif diff --git a/src/tactic/bv/bv_size_reduction_tactic.cpp b/src/tactic/bv/bv_size_reduction_tactic.cpp index c010ed0af..9401f74c1 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.cpp +++ b/src/tactic/bv/bv_size_reduction_tactic.cpp @@ -21,12 +21,12 @@ Author: Notes: --*/ -#include"tactical.h" -#include"bv_decl_plugin.h" -#include"expr_replacer.h" -#include"extension_model_converter.h" -#include"filter_model_converter.h" -#include"ast_smt2_pp.h" +#include "tactic/tactical.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/expr_replacer.h" +#include "tactic/extension_model_converter.h" +#include "tactic/filter_model_converter.h" +#include "ast/ast_smt2_pp.h" class bv_size_reduction_tactic : public tactic { struct imp; diff --git a/src/tactic/bv/bv_size_reduction_tactic.h b/src/tactic/bv/bv_size_reduction_tactic.h index 619794fc0..4a24a1d78 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.h +++ b/src/tactic/bv/bv_size_reduction_tactic.h @@ -24,7 +24,7 @@ Notes: #ifndef BV_SIZE_REDUCTION_TACTIC_H_ #define BV_SIZE_REDUCTION_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/bv/bvarray2uf_rewriter.cpp b/src/tactic/bv/bvarray2uf_rewriter.cpp index db60f3fcd..b92092739 100644 --- a/src/tactic/bv/bvarray2uf_rewriter.cpp +++ b/src/tactic/bv/bvarray2uf_rewriter.cpp @@ -18,14 +18,14 @@ Notes: --*/ -#include"cooperate.h" -#include"bv_decl_plugin.h" -#include"array_decl_plugin.h" -#include"params.h" -#include"ast_pp.h" -#include"bvarray2uf_rewriter.h" -#include"rewriter_def.h" -#include"ref_util.h" +#include "util/cooperate.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "util/params.h" +#include "ast/ast_pp.h" +#include "tactic/bv/bvarray2uf_rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "util/ref_util.h" // [1] C. M. Wintersteiger, Y. Hamadi, and L. de Moura: Efficiently Solving // Quantified Bit-Vector Formulas, in Formal Methods in System Design, @@ -117,7 +117,7 @@ func_decl_ref bvarray2uf_rewriter_cfg::mk_uf_for_array(expr * e) { if (is_uninterp_const(e)) { if (m_emc) m_emc->insert(to_app(e)->get_decl(), - m_array_util.mk_as_array(m_manager.get_sort(e), bv_f)); + m_array_util.mk_as_array(bv_f)); } else if (m_fmc) m_fmc->insert(bv_f); @@ -193,7 +193,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr if (is_uninterp_const(e)) { if (m_emc) m_emc->insert(e->get_decl(), - m_array_util.mk_as_array(m_manager.get_sort(e), bv_f)); + m_array_util.mk_as_array(bv_f)); } else if (m_fmc) m_fmc->insert(bv_f); @@ -207,7 +207,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr q = m_manager.mk_forall(1, sorts, names, body); extra_assertions.push_back(q); - result = m_array_util.mk_as_array(f->get_range(), bv_f); + result = m_array_util.mk_as_array(bv_f); TRACE("bvarray2uf_rw", tout << "result: " << mk_ismt2_pp(result, m_manager) << ")" << std::endl;); res = BR_DONE; @@ -234,7 +234,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr if (is_bv_array(t)) { // From [1]: For every array term t we create a fresh uninterpreted function f_t. f_t = mk_uf_for_array(t); - result = m_array_util.mk_as_array(m_manager.get_sort(t), f_t); + result = m_array_util.mk_as_array(f_t); res = BR_DONE; } else if (has_bv_arrays) { @@ -274,7 +274,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr expr * v = args[0]; func_decl_ref f_t(mk_uf_for_array(t), m_manager); - result = m_array_util.mk_as_array(f->get_range(), f_t); + result = m_array_util.mk_as_array(f_t); res = BR_DONE; // Add \forall x . f_t(x) = v @@ -321,7 +321,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr expr_ref frllx(m_manager.mk_forall(1, sorts, names, body), m_manager); extra_assertions.push_back(frllx); - result = m_array_util.mk_as_array(f->get_range(), f_t); + result = m_array_util.mk_as_array(f_t); res = BR_DONE; } else if (m_array_util.is_store(f)) { @@ -342,7 +342,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr func_decl_ref f_s(mk_uf_for_array(s), m_manager); func_decl_ref f_t(mk_uf_for_array(t), m_manager); - result = m_array_util.mk_as_array(f->get_range(), f_t); + result = m_array_util.mk_as_array(f_t); res = BR_DONE; sort * sorts[1] = { get_index_sort(f->get_range()) }; diff --git a/src/tactic/bv/bvarray2uf_rewriter.h b/src/tactic/bv/bvarray2uf_rewriter.h index 81b53ddd7..bc4014b5b 100644 --- a/src/tactic/bv/bvarray2uf_rewriter.h +++ b/src/tactic/bv/bvarray2uf_rewriter.h @@ -20,9 +20,9 @@ Notes: #ifndef BVARRAY2UF_REWRITER_H_ #define BVARRAY2UF_REWRITER_H_ -#include"rewriter.h" -#include"extension_model_converter.h" -#include"filter_model_converter.h" +#include "ast/rewriter/rewriter.h" +#include "tactic/extension_model_converter.h" +#include "tactic/filter_model_converter.h" class bvarray2uf_rewriter_cfg : public default_rewriter_cfg { ast_manager & m_manager; diff --git a/src/tactic/bv/bvarray2uf_tactic.cpp b/src/tactic/bv/bvarray2uf_tactic.cpp index ecf1889a2..87f43ae8d 100644 --- a/src/tactic/bv/bvarray2uf_tactic.cpp +++ b/src/tactic/bv/bvarray2uf_tactic.cpp @@ -17,15 +17,15 @@ Author: Notes: --*/ -#include"tactical.h" -#include"bv_decl_plugin.h" -#include"expr_replacer.h" -#include"extension_model_converter.h" -#include"filter_model_converter.h" -#include"ast_smt2_pp.h" +#include "tactic/tactical.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/expr_replacer.h" +#include "tactic/extension_model_converter.h" +#include "tactic/filter_model_converter.h" +#include "ast/ast_smt2_pp.h" -#include"bvarray2uf_tactic.h" -#include"bvarray2uf_rewriter.h" +#include "tactic/bv/bvarray2uf_tactic.h" +#include "tactic/bv/bvarray2uf_rewriter.h" class bvarray2uf_tactic : public tactic { diff --git a/src/tactic/bv/bvarray2uf_tactic.h b/src/tactic/bv/bvarray2uf_tactic.h index 336911bf7..84ad413f6 100644 --- a/src/tactic/bv/bvarray2uf_tactic.h +++ b/src/tactic/bv/bvarray2uf_tactic.h @@ -20,7 +20,7 @@ Notes: #ifndef BV_ARRAY2UF_TACTIC_H_ #define BV_ARRAY2UF_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 3ae72215f..fe59480e7 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -19,18 +19,18 @@ Revision History: --*/ -#include "dt2bv_tactic.h" -#include "tactical.h" -#include "filter_model_converter.h" -#include "datatype_decl_plugin.h" -#include "bv_decl_plugin.h" -#include "rewriter_def.h" -#include "filter_model_converter.h" -#include "extension_model_converter.h" -#include "var_subst.h" -#include "ast_util.h" -#include "enum2bv_rewriter.h" -#include "ast_pp.h" +#include "tactic/bv/dt2bv_tactic.h" +#include "tactic/tactical.h" +#include "tactic/filter_model_converter.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/rewriter_def.h" +#include "tactic/filter_model_converter.h" +#include "tactic/extension_model_converter.h" +#include "ast/rewriter/var_subst.h" +#include "ast/ast_util.h" +#include "ast/rewriter/enum2bv_rewriter.h" +#include "ast/ast_pp.h" class dt2bv_tactic : public tactic { diff --git a/src/tactic/bv/dt2bv_tactic.h b/src/tactic/bv/dt2bv_tactic.h index 10ce0724f..1e6567995 100644 --- a/src/tactic/bv/dt2bv_tactic.h +++ b/src/tactic/bv/dt2bv_tactic.h @@ -19,8 +19,8 @@ Revision History: #ifndef DT2BV_TACTIC_H_ #define DT2BV_TACTIC_H_ -#include"params.h" -#include"obj_hashtable.h" +#include "util/params.h" +#include "util/obj_hashtable.h" class ast_manager; class tactic; diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index 8cfc27950..ab4b3920d 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -16,19 +16,17 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"rewriter_def.h" -#include"filter_model_converter.h" -#include"cooperate.h" -#include"bv_decl_plugin.h" -#include"used_vars.h" -#include"well_sorted.h" -#include"var_subst.h" -#include"simplifier.h" -#include"basic_simplifier_plugin.h" -#include"bv_simplifier_plugin.h" +#include "tactic/tactical.h" +#include "ast/rewriter/rewriter_def.h" +#include "tactic/filter_model_converter.h" +#include "util/cooperate.h" +#include "ast/bv_decl_plugin.h" +#include "ast/used_vars.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/th_rewriter.h" -#include"elim_small_bv_tactic.h" +#include "tactic/bv/elim_small_bv_tactic.h" class elim_small_bv_tactic : public tactic { @@ -36,7 +34,7 @@ class elim_small_bv_tactic : public tactic { ast_manager & m; params_ref m_params; bv_util m_util; - simplifier m_simp; + th_rewriter m_simp; ref m_mc; goal * m_goal; unsigned m_max_bits; @@ -56,14 +54,6 @@ class elim_small_bv_tactic : public tactic { updt_params(p); m_goal = 0; m_max_steps = UINT_MAX; - - basic_simplifier_plugin * bsimp = alloc(basic_simplifier_plugin, m); - // bsimp->set_eliminate_and(true); - m_simp.register_plugin(bsimp); - - bv_simplifier_params bv_params; - bv_simplifier_plugin * bvsimp = alloc(bv_simplifier_plugin, m, *bsimp, bv_params); - m_simp.register_plugin(bvsimp); } bool max_steps_exceeded(unsigned long long num_steps) const { @@ -307,9 +297,8 @@ public: virtual void cleanup() { ast_manager & m = m_imp->m; - imp * d = alloc(imp, m, m_params); - std::swap(d, m_imp); - dealloc(d); + m_imp->~imp(); + m_imp = new (m_imp) imp(m, m_params); } }; diff --git a/src/tactic/bv/elim_small_bv_tactic.h b/src/tactic/bv/elim_small_bv_tactic.h index bcdd8aad6..675ec3de7 100644 --- a/src/tactic/bv/elim_small_bv_tactic.h +++ b/src/tactic/bv/elim_small_bv_tactic.h @@ -19,7 +19,7 @@ Revision History: #ifndef ELIM_SMALL_BV_H_ #define ELIM_SMALL_BV_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/bv/max_bv_sharing_tactic.cpp b/src/tactic/bv/max_bv_sharing_tactic.cpp index 675f26ace..b0affeb4b 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.cpp +++ b/src/tactic/bv/max_bv_sharing_tactic.cpp @@ -19,12 +19,12 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"bv_decl_plugin.h" -#include"rewriter_def.h" -#include"obj_pair_hashtable.h" -#include"ast_lt.h" -#include"cooperate.h" +#include "tactic/tactical.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/rewriter_def.h" +#include "util/obj_pair_hashtable.h" +#include "ast/ast_lt.h" +#include "util/cooperate.h" class max_bv_sharing_tactic : public tactic { diff --git a/src/tactic/bv/max_bv_sharing_tactic.h b/src/tactic/bv/max_bv_sharing_tactic.h index ffe5b025c..b8bc0753d 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.h +++ b/src/tactic/bv/max_bv_sharing_tactic.h @@ -22,7 +22,7 @@ Revision History: #ifndef MAX_BV_SHARING_TACTIC_H_ #define MAX_BV_SHARING_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/converter.h b/src/tactic/converter.h index bed191bc2..9de8218c3 100644 --- a/src/tactic/converter.h +++ b/src/tactic/converter.h @@ -19,9 +19,9 @@ Notes: #ifndef CONVERTER_H_ #define CONVERTER_H_ -#include"vector.h" -#include"ref.h" -#include"ast_translation.h" +#include "util/vector.h" +#include "util/ref.h" +#include "ast/ast_translation.h" class converter { unsigned m_ref_count; diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index 1f766bd47..16778d8dd 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -7,8 +7,10 @@ z3_add_component(core_tactics ctx_simplify_tactic.cpp der_tactic.cpp distribute_forall_tactic.cpp + dom_simplify_tactic.cpp elim_term_ite_tactic.cpp elim_uncnstr_tactic.cpp + injectivity_tactic.cpp nnf_tactic.cpp occf_tactic.cpp pb_preprocess_tactic.cpp @@ -22,6 +24,7 @@ z3_add_component(core_tactics collect_occs.cpp COMPONENT_DEPENDENCIES normal_forms + rewriter tactic TACTIC_HEADERS blast_term_ite_tactic.h @@ -30,8 +33,10 @@ z3_add_component(core_tactics ctx_simplify_tactic.h der_tactic.h distribute_forall_tactic.h + dom_simplify_tactic.h elim_term_ite_tactic.h elim_uncnstr_tactic.h + injectivity_tactic.h nnf_tactic.h occf_tactic.h pb_preprocess_tactic.h diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index 483b59776..ae0ea019b 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -16,12 +16,12 @@ Author: Notes: --*/ -#include"tactical.h" -#include"defined_names.h" -#include"rewriter_def.h" -#include"filter_model_converter.h" -#include"cooperate.h" -#include"scoped_proof.h" +#include "tactic/tactical.h" +#include "ast/normal_forms/defined_names.h" +#include "ast/rewriter/rewriter_def.h" +#include "tactic/filter_model_converter.h" +#include "util/cooperate.h" +#include "ast/scoped_proof.h" diff --git a/src/tactic/core/blast_term_ite_tactic.h b/src/tactic/core/blast_term_ite_tactic.h index ac94723d8..1ecab98be 100644 --- a/src/tactic/core/blast_term_ite_tactic.h +++ b/src/tactic/core/blast_term_ite_tactic.h @@ -23,7 +23,7 @@ Notes: #ifndef BLAST_TERM_ITE_TACTIC_H_ #define BLAST_TERM_ITE_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/core/cofactor_elim_term_ite.cpp b/src/tactic/core/cofactor_elim_term_ite.cpp index 15f0e06ea..b90be82b5 100644 --- a/src/tactic/core/cofactor_elim_term_ite.cpp +++ b/src/tactic/core/cofactor_elim_term_ite.cpp @@ -16,14 +16,14 @@ Author: Revision History: --*/ -#include"cofactor_elim_term_ite.h" -#include"mk_simplified_app.h" -#include"rewriter_def.h" -#include"cooperate.h" -#include"for_each_expr.h" -#include"ast_smt2_pp.h" -#include"ast_ll_pp.h" -#include"tactic.h" +#include "tactic/core/cofactor_elim_term_ite.h" +#include "ast/rewriter/mk_simplified_app.h" +#include "ast/rewriter/rewriter_def.h" +#include "util/cooperate.h" +#include "ast/for_each_expr.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_ll_pp.h" +#include "tactic/tactic.h" struct cofactor_elim_term_ite::imp { ast_manager & m; diff --git a/src/tactic/core/cofactor_elim_term_ite.h b/src/tactic/core/cofactor_elim_term_ite.h index 98142837c..dfbb66a63 100644 --- a/src/tactic/core/cofactor_elim_term_ite.h +++ b/src/tactic/core/cofactor_elim_term_ite.h @@ -19,8 +19,8 @@ Revision History: #ifndef COFACTOR_ELIM_TERM_ITE_H_ #define COFACTOR_ELIM_TERM_ITE_H_ -#include"ast.h" -#include"params.h" +#include "ast/ast.h" +#include "util/params.h" class cofactor_elim_term_ite { struct imp; diff --git a/src/tactic/core/cofactor_term_ite_tactic.cpp b/src/tactic/core/cofactor_term_ite_tactic.cpp index 2286281f4..65cdef147 100644 --- a/src/tactic/core/cofactor_term_ite_tactic.cpp +++ b/src/tactic/core/cofactor_term_ite_tactic.cpp @@ -17,8 +17,8 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"cofactor_elim_term_ite.h" +#include "tactic/tactical.h" +#include "tactic/core/cofactor_elim_term_ite.h" /** \brief Wrapper for applying cofactor_elim_term_ite in an assertion set. diff --git a/src/tactic/core/cofactor_term_ite_tactic.h b/src/tactic/core/cofactor_term_ite_tactic.h index 4e0342853..c6e2dfff2 100644 --- a/src/tactic/core/cofactor_term_ite_tactic.h +++ b/src/tactic/core/cofactor_term_ite_tactic.h @@ -20,7 +20,7 @@ Revision History: #ifndef COFACTOR_TERM_ITE_TACTIC_H_ #define COFACTOR_TERM_ITE_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/core/collect_occs.cpp b/src/tactic/core/collect_occs.cpp index 69c538db6..27de476f7 100644 --- a/src/tactic/core/collect_occs.cpp +++ b/src/tactic/core/collect_occs.cpp @@ -17,10 +17,10 @@ Notes: --*/ -#include "ast.h" -#include "goal.h" -#include "hashtable.h" -#include "collect_occs.h" +#include "ast/ast.h" +#include "tactic/goal.h" +#include "util/hashtable.h" +#include "tactic/core/collect_occs.h" bool collect_occs::visit(expr * t) { if (m_visited.is_marked(t)) { diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index 3b820de7a..26f6842e3 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -20,17 +20,17 @@ Notes: #include #include -#include"ast.h" -#include"params.h" -#include"arith_decl_plugin.h" -#include"array_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"datatype_decl_plugin.h" -#include"fpa_decl_plugin.h" -#include"tactical.h" -#include"stats.h" +#include "ast/ast.h" +#include "util/params.h" +#include "ast/arith_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/fpa_decl_plugin.h" +#include "tactic/tactical.h" +#include "util/stats.h" -#include"collect_statistics_tactic.h" +#include "tactic/core/collect_statistics_tactic.h" class collect_statistics_tactic : public tactic { ast_manager & m; diff --git a/src/tactic/core/collect_statistics_tactic.h b/src/tactic/core/collect_statistics_tactic.h index 5734af3c7..a71ddc376 100644 --- a/src/tactic/core/collect_statistics_tactic.h +++ b/src/tactic/core/collect_statistics_tactic.h @@ -20,7 +20,7 @@ Notes: #ifndef COLLECT_STATISTICS_H_ #define COLLECT_STATISTICS_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 3e2790fe3..5bb54073d 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -16,11 +16,11 @@ Author: Notes: --*/ -#include"ctx_simplify_tactic.h" -#include"mk_simplified_app.h" -#include"cooperate.h" -#include"ast_ll_pp.h" -#include"ast_pp.h" +#include "tactic/core/ctx_simplify_tactic.h" +#include "ast/rewriter/mk_simplified_app.h" +#include "util/cooperate.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" class ctx_propagate_assertions : public ctx_simplify_tactic::simplifier { diff --git a/src/tactic/core/ctx_simplify_tactic.h b/src/tactic/core/ctx_simplify_tactic.h index d6ebf5cbd..9efa7e7db 100644 --- a/src/tactic/core/ctx_simplify_tactic.h +++ b/src/tactic/core/ctx_simplify_tactic.h @@ -19,8 +19,8 @@ Notes: #ifndef CTX_SIMPLIFY_TACTIC_H_ #define CTX_SIMPLIFY_TACTIC_H_ -#include"tactical.h" -#include"goal_num_occurs.h" +#include "tactic/tactical.h" +#include "tactic/goal_num_occurs.h" class ctx_simplify_tactic : public tactic { public: diff --git a/src/tactic/core/der_tactic.cpp b/src/tactic/core/der_tactic.cpp index ece1ec42f..5df009969 100644 --- a/src/tactic/core/der_tactic.cpp +++ b/src/tactic/core/der_tactic.cpp @@ -14,8 +14,8 @@ Author: Leonardo de Moura (leonardo) 2012-10-20 --*/ -#include"der.h" -#include"tactical.h" +#include "ast/rewriter/der.h" +#include "tactic/tactical.h" class der_tactic : public tactic { struct imp { diff --git a/src/tactic/core/distribute_forall_tactic.cpp b/src/tactic/core/distribute_forall_tactic.cpp index 5d525a836..3ee2697c4 100644 --- a/src/tactic/core/distribute_forall_tactic.cpp +++ b/src/tactic/core/distribute_forall_tactic.cpp @@ -14,9 +14,9 @@ Author: Leonardo de Moura (leonardo) 2012-02-18. --*/ -#include"tactical.h" -#include"rewriter_def.h" -#include"var_subst.h" +#include "tactic/tactical.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/var_subst.h" class distribute_forall_tactic : public tactic { diff --git a/src/tactic/core/distribute_forall_tactic.h b/src/tactic/core/distribute_forall_tactic.h index 6c781c7df..a58a53d4e 100644 --- a/src/tactic/core/distribute_forall_tactic.h +++ b/src/tactic/core/distribute_forall_tactic.h @@ -17,7 +17,7 @@ Author: #ifndef DISTRIBUTE_FORALL_TACTIC_H_ #define DISTRIBUTE_FORALL_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp new file mode 100644 index 000000000..2099eebf0 --- /dev/null +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -0,0 +1,556 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + dom_simplify_tactic.cpp + +Abstract: + + Dominator-based context simplifer. + +Author: + + Nikolaj and Nuno + +Notes: + +--*/ + + +#include "ast/ast_util.h" +#include "ast/ast_pp.h" +#include "tactic/core/dom_simplify_tactic.h" + + +/** + \brief compute a post-order traversal for e. + Also populate the set of parents +*/ +void expr_dominators::compute_post_order() { + unsigned post_num = 0; + SASSERT(m_post2expr.empty()); + SASSERT(m_expr2post.empty()); + ast_mark mark; + ptr_vector todo; + todo.push_back(m_root); + while (!todo.empty()) { + expr* e = todo.back(); + if (mark.is_marked(e)) { + todo.pop_back(); + continue; + } + if (is_app(e)) { + app* a = to_app(e); + bool done = true; + for (expr* arg : *a) { + if (!mark.is_marked(arg)) { + todo.push_back(arg); + done = false; + } + } + if (done) { + mark.mark(e, true); + m_expr2post.insert(e, post_num++); + m_post2expr.push_back(e); + todo.pop_back(); + for (expr* arg : *a) { + add_edge(m_parents, arg, a); + } + } + } + else { + mark.mark(e, true); + todo.pop_back(); + } + } +} + +expr* expr_dominators::intersect(expr* x, expr * y) { + unsigned n1 = m_expr2post[x]; + unsigned n2 = m_expr2post[y]; + while (n1 != n2) { + if (n1 < n2) { + x = m_doms[x]; + n1 = m_expr2post[x]; + } + else if (n1 > n2) { + y = m_doms[y]; + n2 = m_expr2post[y]; + } + } + SASSERT(x == y); + return x; +} + +bool expr_dominators::compute_dominators() { + expr * e = m_root; + SASSERT(m_doms.empty()); + m_doms.insert(e, e); + bool change = true; + unsigned iterations = 1; + while (change) { + change = false; + TRACE("simplify", + for (auto & kv : m_doms) { + tout << expr_ref(kv.m_key, m) << " |-> " << expr_ref(kv.m_value, m) << "\n"; + }); + + SASSERT(m_post2expr.empty() || m_post2expr.back() == e); + for (unsigned i = 0; i + 1 < m_post2expr.size(); ++i) { + expr * child = m_post2expr[i]; + ptr_vector const& p = m_parents[child]; + expr * new_idom = 0, *idom2 = 0; + + for (expr * pred : p) { + if (m_doms.contains(pred)) { + new_idom = !new_idom ? pred : intersect(new_idom, pred); + } + } + if (!new_idom) { + m_doms.insert(child, p[0]); + change = true; + } + else if (!m_doms.find(child, idom2) || idom2 != new_idom) { + m_doms.insert(child, new_idom); + change = true; + } + } + iterations *= 2; + if (change && iterations > m_post2expr.size()) { + return false; + } + } + return true; +} + +void expr_dominators::extract_tree() { + for (auto const& kv : m_doms) { + add_edge(m_tree, kv.m_value, kv.m_key); + } +} + +bool expr_dominators::compile(expr * e) { + reset(); + m_root = e; + compute_post_order(); + if (!compute_dominators()) return false; + extract_tree(); + TRACE("simplify", display(tout);); + return true; +} + +bool expr_dominators::compile(unsigned sz, expr * const* es) { + expr_ref e(m.mk_and(sz, es), m); + return compile(e); +} + +void expr_dominators::reset() { + m_expr2post.reset(); + m_post2expr.reset(); + m_parents.reset(); + m_doms.reset(); + m_tree.reset(); + m_root.reset(); +} + +std::ostream& expr_dominators::display(std::ostream& out) { + return display(out, 0, m_root); +} + +std::ostream& expr_dominators::display(std::ostream& out, unsigned indent, expr* r) { + for (unsigned i = 0; i < indent; ++i) out << " "; + out << expr_ref(r, m); + if (m_tree.contains(r)) { + for (expr* child : m_tree[r]) { + if (child != r) + display(out, indent + 1, child); + } + } + out << "\n"; + return out; +} + + +// ----------------------- +// dom_simplify_tactic + +dom_simplify_tactic::~dom_simplify_tactic() { + dealloc(m_simplifier); +} + +tactic * dom_simplify_tactic::translate(ast_manager & m) { + return alloc(dom_simplify_tactic, m, m_simplifier->translate(m), m_params); +} + +void dom_simplify_tactic::operator()( + goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + mc = 0; pc = 0; core = 0; + + tactic_report report("dom-simplify", *in.get()); + simplify_goal(*(in.get())); + in->inc_depth(); + result.push_back(in.get()); + +} + +void dom_simplify_tactic::cleanup() { + m_trail.reset(); + m_args.reset(); + m_result.reset(); + m_dominators.reset(); +} + +expr_ref dom_simplify_tactic::simplify_ite(app * ite) { + expr_ref r(m); + expr * c = 0, *t = 0, *e = 0; + VERIFY(m.is_ite(ite, c, t, e)); + unsigned old_lvl = scope_level(); + expr_ref new_c = simplify_arg(c); + if (m.is_true(new_c)) { + r = simplify_arg(t); + } + else if (m.is_false(new_c) || !assert_expr(new_c, false)) { + r = simplify_arg(e); + } + else { + for (expr * child : tree(ite)) { + if (is_subexpr(child, t) && !is_subexpr(child, e)) { + simplify_rec(child); + } + } + pop(scope_level() - old_lvl); + expr_ref new_t = simplify_arg(t); + if (!assert_expr(new_c, true)) { + return new_t; + } + for (expr * child : tree(ite)) { + if (is_subexpr(child, e) && !is_subexpr(child, t)) { + simplify_rec(child); + } + } + pop(scope_level() - old_lvl); + expr_ref new_e = simplify_arg(e); + if (c == new_c && t == new_t && e == new_e) { + r = ite; + } + else if (new_t == new_e) { + r = new_t; + } + else { + TRACE("simplify", tout << new_c << "\n" << new_t << "\n" << new_e << "\n";); + r = m.mk_ite(new_c, new_t, new_e); + } + } + return r; +} + +expr_ref dom_simplify_tactic::simplify_arg(expr * e) { + expr_ref r(m); + r = get_cached(e); + (*m_simplifier)(r); + TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e, m) << " -> " << r << "\n";); + return r; +} + +/** + \brief simplify e recursively. +*/ +expr_ref dom_simplify_tactic::simplify_rec(expr * e0) { + expr_ref r(m); + expr* e = 0; + + TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << "\n";); + if (!m_result.find(e0, e)) { + e = e0; + } + + ++m_depth; + if (m_depth > m_max_depth) { + r = e; + } + else if (m.is_ite(e)) { + r = simplify_ite(to_app(e)); + } + else if (m.is_and(e)) { + r = simplify_and(to_app(e)); + } + else if (m.is_or(e)) { + r = simplify_or(to_app(e)); + } + else { + for (expr * child : tree(e)) { + simplify_rec(child); + } + if (is_app(e)) { + m_args.reset(); + for (expr* arg : *to_app(e)) { + m_args.push_back(simplify_arg(arg)); + } + r = m.mk_app(to_app(e)->get_decl(), m_args.size(), m_args.c_ptr()); + } + else { + r = e; + } + } + (*m_simplifier)(r); + cache(e0, r); + TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << " -> " << r << "\n";); + --m_depth; + m_subexpr_cache.reset(); + return r; +} + +expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) { + expr_ref r(m); + unsigned old_lvl = scope_level(); + + auto is_subexpr_arg = [&](expr * child, expr * except) { + if (!is_subexpr(child, except)) + return false; + for (expr * arg : *e) { + if (arg != except && is_subexpr(child, arg)) + return false; + } + return true; + }; + + expr_ref_vector args(m); + if (m_forward) { + for (expr * arg : *e) { +#define _SIMP_ARG(arg) \ + for (expr * child : tree(arg)) { \ + if (is_subexpr_arg(child, arg)) { \ + simplify_rec(child); \ + } \ + } \ + r = simplify_arg(arg); \ + args.push_back(r); \ + if (!assert_expr(r, !is_and)) { \ + r = is_and ? m.mk_false() : m.mk_true(); \ + return r; \ + } + _SIMP_ARG(arg); + } + } + else { + for (unsigned i = e->get_num_args(); i > 0; ) { + --i; + expr* arg = e->get_arg(i); + _SIMP_ARG(arg); + } + args.reverse(); + } + pop(scope_level() - old_lvl); + r = is_and ? mk_and(args) : mk_or(args); + return r; +} + + +bool dom_simplify_tactic::init(goal& g) { + expr_ref_vector args(m); + unsigned sz = g.size(); + for (unsigned i = 0; i < sz; ++i) args.push_back(g.form(i)); + expr_ref fml = mk_and(args); + m_result.reset(); + m_trail.reset(); + return m_dominators.compile(fml); +} + +void dom_simplify_tactic::simplify_goal(goal& g) { + + SASSERT(scope_level() == 0); + bool change = true; + m_depth = 0; + while (change) { + change = false; + + // go forwards + m_forward = true; + if (!init(g)) return; + unsigned sz = g.size(); + for (unsigned i = 0; !g.inconsistent() && i < sz; ++i) { + expr_ref r = simplify_rec(g.form(i)); + if (i < sz - 1 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) { + r = m.mk_false(); + } + CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";); + change |= r != g.form(i); + proof* new_pr = 0; + if (g.proofs_enabled()) { + new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, 0)); + } + g.update(i, r, new_pr, g.dep(i)); + } + pop(scope_level()); + + // go backwards + m_forward = false; + if (!init(g)) return; + sz = g.size(); + for (unsigned i = sz; !g.inconsistent() && i > 0; ) { + --i; + expr_ref r = simplify_rec(g.form(i)); + if (i > 0 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) { + r = m.mk_false(); + } + change |= r != g.form(i); + CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";); + proof* new_pr = 0; + if (g.proofs_enabled()) { + new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, 0)); + } + g.update(i, r, new_pr, g.dep(i)); + } + pop(scope_level()); + } + SASSERT(scope_level() == 0); +} + +/** + \brief determine if a is dominated by b. + Walk the immediate dominators of a upwards until hitting b or a term that is deeper than b. + Save intermediary results in a cache to avoid recomputations. +*/ + +bool dom_simplify_tactic::is_subexpr(expr * a, expr * b) { + if (a == b) + return true; + + bool r; + if (m_subexpr_cache.find(a, b, r)) + return r; + + if (get_depth(a) >= get_depth(b)) { + return false; + } + SASSERT(a != idom(a) && get_depth(idom(a)) > get_depth(a)); + r = is_subexpr(idom(a), b); + m_subexpr_cache.insert(a, b, r); + return r; +} + +ptr_vector const & dom_simplify_tactic::tree(expr * e) { + if (auto p = m_dominators.get_tree().find_core(e)) + return p->get_data().get_value(); + return m_empty; +} + + +// --------------------- +// expr_substitution_simplifier + +bool expr_substitution_simplifier::assert_expr(expr * t, bool sign) { + m_scoped_substitution.push(); + expr* tt; + if (!sign) { + update_substitution(t, 0); + } + else if (m.is_not(t, tt)) { + update_substitution(tt, 0); + } + else { + expr_ref nt(m.mk_not(t), m); + update_substitution(nt, 0); + } + return true; +} + + +bool expr_substitution_simplifier::is_gt(expr* lhs, expr* rhs) { + if (lhs == rhs) { + return false; + } + if (m.is_value(rhs)) { + return true; + } + SASSERT(is_ground(lhs) && is_ground(rhs)); + if (depth(lhs) > depth(rhs)) { + return true; + } + if (depth(lhs) == depth(rhs) && is_app(lhs) && is_app(rhs)) { + app* l = to_app(lhs); + app* r = to_app(rhs); + if (l->get_decl()->get_id() != r->get_decl()->get_id()) { + return l->get_decl()->get_id() > r->get_decl()->get_id(); + } + if (l->get_num_args() != r->get_num_args()) { + return l->get_num_args() > r->get_num_args(); + } + for (unsigned i = 0; i < l->get_num_args(); ++i) { + if (l->get_arg(i) != r->get_arg(i)) { + return is_gt(l->get_arg(i), r->get_arg(i)); + } + } + UNREACHABLE(); + } + + return false; +} + +void expr_substitution_simplifier::update_substitution(expr* n, proof* pr) { + expr* lhs, *rhs, *n1; + if (is_ground(n) && (m.is_eq(n, lhs, rhs) || m.is_iff(n, lhs, rhs))) { + compute_depth(lhs); + compute_depth(rhs); + m_trail.push_back(lhs); + m_trail.push_back(rhs); + if (is_gt(lhs, rhs)) { + TRACE("propagate_values", tout << "insert " << mk_pp(lhs, m) << " -> " << mk_pp(rhs, m) << "\n";); + m_scoped_substitution.insert(lhs, rhs, pr); + return; + } + if (is_gt(rhs, lhs)) { + TRACE("propagate_values", tout << "insert " << mk_pp(rhs, m) << " -> " << mk_pp(lhs, m) << "\n";); + m_scoped_substitution.insert(rhs, lhs, m.mk_symmetry(pr)); + return; + } + TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";); + } + if (m.is_not(n, n1)) { + m_scoped_substitution.insert(n1, m.mk_false(), m.mk_iff_false(pr)); + } + else { + m_scoped_substitution.insert(n, m.mk_true(), m.mk_iff_true(pr)); + } +} + +void expr_substitution_simplifier::compute_depth(expr* e) { + ptr_vector todo; + todo.push_back(e); + while (!todo.empty()) { + e = todo.back(); + unsigned d = 0; + if (m_expr2depth.contains(e)) { + todo.pop_back(); + continue; + } + if (is_app(e)) { + app* a = to_app(e); + bool visited = true; + for (expr* arg : *a) { + unsigned d1 = 0; + if (m_expr2depth.find(arg, d1)) { + d = std::max(d, d1); + } + else { + visited = false; + todo.push_back(arg); + } + } + if (!visited) { + continue; + } + } + todo.pop_back(); + m_expr2depth.insert(e, d + 1); + } +} + +tactic * mk_dom_simplify_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(dom_simplify_tactic, m, alloc(expr_substitution_simplifier, m), p)); +} diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h new file mode 100644 index 000000000..56eea8d9a --- /dev/null +++ b/src/tactic/core/dom_simplify_tactic.h @@ -0,0 +1,187 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + dom_simplify_tactic.cpp + +Abstract: + + Dominator-based context simplifer. + +Author: + + Nikolaj and Nuno + +Notes: + +--*/ + +#ifndef DOM_SIMPLIFY_TACTIC_H_ +#define DOM_SIMPLIFY_TACTIC_H_ + +#include "ast/ast.h" +#include "ast/expr_substitution.h" +#include "tactic/tactic.h" +#include "tactic/tactical.h" +#include "util/obj_pair_hashtable.h" + + +class expr_dominators { +public: + typedef obj_map> tree_t; +private: + ast_manager& m; + expr_ref m_root; + obj_map m_expr2post; // reverse post-order number + ptr_vector m_post2expr; + tree_t m_parents; + obj_map m_doms; + tree_t m_tree; + + void add_edge(tree_t& tree, expr * src, expr* dst) { + tree.insert_if_not_there2(src, ptr_vector())->get_data().m_value.push_back(dst); + } + + void compute_post_order(); + expr* intersect(expr* x, expr * y); + bool compute_dominators(); + void extract_tree(); + + std::ostream& display(std::ostream& out, unsigned indent, expr* r); + +public: + expr_dominators(ast_manager& m): m(m), m_root(m) {} + + bool compile(expr * e); + bool compile(unsigned sz, expr * const* es); + tree_t const& get_tree() { return m_tree; } + void reset(); + expr* idom(expr *e) const { return m_doms[e]; } + + std::ostream& display(std::ostream& out); +}; + +class dom_simplifier { + public: + dom_simplifier() {} + + virtual ~dom_simplifier() {} + /** + \brief assert_expr performs an implicit push + */ + virtual bool assert_expr(expr * t, bool sign) = 0; + + /** + \brief apply simplification. + */ + virtual void operator()(expr_ref& r) = 0; + + /** + \brief pop scopes accumulated from assertions. + */ + virtual void pop(unsigned num_scopes) = 0; + + virtual dom_simplifier * translate(ast_manager & m) = 0; + + virtual unsigned scope_level() const = 0; + +}; + +class dom_simplify_tactic : public tactic { + ast_manager& m; + dom_simplifier* m_simplifier; + params_ref m_params; + expr_ref_vector m_trail, m_args; + obj_map m_result; + expr_dominators m_dominators; + unsigned m_depth; + unsigned m_max_depth; + ptr_vector m_empty; + obj_pair_map m_subexpr_cache; + bool m_forward; + + expr_ref simplify_rec(expr* t); + expr_ref simplify_arg(expr* t); + expr_ref simplify_ite(app * ite); + expr_ref simplify_and(app * ite) { return simplify_and_or(true, ite); } + expr_ref simplify_or(app * ite) { return simplify_and_or(false, ite); } + expr_ref simplify_and_or(bool is_and, app * ite); + void simplify_goal(goal& g); + + bool is_subexpr(expr * a, expr * b); + + expr_ref get_cached(expr* t) { expr* r = 0; if (!m_result.find(t, r)) r = t; return expr_ref(r, m); } + void cache(expr *t, expr* r) { m_result.insert(t, r); m_trail.push_back(r); } + + ptr_vector const & tree(expr * e); + expr* idom(expr *e) const { return m_dominators.idom(e); } + + unsigned scope_level() { return m_simplifier->scope_level(); } + void pop(unsigned n) { SASSERT(n <= m_simplifier->scope_level()); m_simplifier->pop(n); } + bool assert_expr(expr* f, bool sign) { return m_simplifier->assert_expr(f, sign); } + + bool init(goal& g); + +public: + dom_simplify_tactic(ast_manager & m, dom_simplifier* s, params_ref const & p = params_ref()): + m(m), m_simplifier(s), m_params(p), + m_trail(m), m_args(m), + m_dominators(m), m_depth(0), m_max_depth(1024), m_forward(true) {} + + + virtual ~dom_simplify_tactic(); + + virtual tactic * translate(ast_manager & m); + virtual void updt_params(params_ref const & p) {} + static void get_param_descrs(param_descrs & r) {} + virtual void collect_param_descrs(param_descrs & r) { get_param_descrs(r); } + + virtual void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core); + + virtual void cleanup(); +}; + +class expr_substitution_simplifier : public dom_simplifier { + ast_manager& m; + expr_substitution m_subst; + scoped_expr_substitution m_scoped_substitution; + obj_map m_expr2depth; + expr_ref_vector m_trail; + + // move from asserted_formulas to here.. + void compute_depth(expr* e); + bool is_gt(expr* lhs, expr* rhs); + unsigned depth(expr* e) { return m_expr2depth[e]; } + +public: + expr_substitution_simplifier(ast_manager& m): m(m), m_subst(m), m_scoped_substitution(m_subst), m_trail(m) {} + virtual ~expr_substitution_simplifier() {} + virtual bool assert_expr(expr * t, bool sign); + + void update_substitution(expr* n, proof* pr); + + virtual void operator()(expr_ref& r) { r = m_scoped_substitution.find(r); } + + virtual void pop(unsigned num_scopes) { m_scoped_substitution.pop(num_scopes); } + + virtual unsigned scope_level() const { return m_scoped_substitution.scope_level(); } + + virtual dom_simplifier * translate(ast_manager & m) { + SASSERT(m_subst.empty()); + return alloc(expr_substitution_simplifier, m); + } +}; + + +tactic * mk_dom_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* +ADD_TACTIC("dom-simplify", "apply dominator simplification rules.", "mk_dom_simplify_tactic(m, p)") +*/ + +#endif diff --git a/src/tactic/core/elim_term_ite_tactic.cpp b/src/tactic/core/elim_term_ite_tactic.cpp index 6cc989d0f..79526a101 100644 --- a/src/tactic/core/elim_term_ite_tactic.cpp +++ b/src/tactic/core/elim_term_ite_tactic.cpp @@ -17,11 +17,11 @@ Author: Notes: --*/ -#include"tactical.h" -#include"defined_names.h" -#include"rewriter_def.h" -#include"filter_model_converter.h" -#include"cooperate.h" +#include "tactic/tactical.h" +#include "ast/normal_forms/defined_names.h" +#include "ast/rewriter/rewriter_def.h" +#include "tactic/filter_model_converter.h" +#include "util/cooperate.h" class elim_term_ite_tactic : public tactic { @@ -171,9 +171,8 @@ public: virtual void cleanup() { ast_manager & m = m_imp->m; - imp * d = alloc(imp, m, m_params); - std::swap(d, m_imp); - dealloc(d); + m_imp->~imp(); + m_imp = new (m_imp) imp(m, m_params); } }; diff --git a/src/tactic/core/elim_term_ite_tactic.h b/src/tactic/core/elim_term_ite_tactic.h index 3a89edaa9..4a98947c9 100644 --- a/src/tactic/core/elim_term_ite_tactic.h +++ b/src/tactic/core/elim_term_ite_tactic.h @@ -20,7 +20,7 @@ Notes: #ifndef ELIM_TERM_ITE_TACTIC_H_ #define ELIM_TERM_ITE_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index df3b9f0f5..6a38f787e 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -16,18 +16,18 @@ Author: Notes: --*/ -#include"tactical.h" -#include"extension_model_converter.h" -#include"filter_model_converter.h" -#include"rewriter_def.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"array_decl_plugin.h" -#include"datatype_decl_plugin.h" -#include"collect_occs.h" -#include"cooperate.h" -#include"ast_smt2_pp.h" -#include"ast_ll_pp.h" +#include "tactic/tactical.h" +#include "tactic/extension_model_converter.h" +#include "tactic/filter_model_converter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "tactic/core/collect_occs.h" +#include "util/cooperate.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_ll_pp.h" class elim_uncnstr_tactic : public tactic { @@ -174,11 +174,8 @@ class elim_uncnstr_tactic : public tactic { if (fid == m_dt_util.get_family_id()) { // In the current implementation, I only handle the case where // the datatype has a recursive constructor. - ptr_vector const * constructors = m_dt_util.get_datatype_constructors(s); - ptr_vector::const_iterator it = constructors->begin(); - ptr_vector::const_iterator end = constructors->end(); - for (; it != end; ++it) { - func_decl * constructor = *it; + ptr_vector const & constructors = *m_dt_util.get_datatype_constructors(s); + for (func_decl * constructor : constructors) { unsigned num = constructor->get_arity(); unsigned target = UINT_MAX; for (unsigned i = 0; i < num; i++) { @@ -707,10 +704,10 @@ class elim_uncnstr_tactic : public tactic { app * u; if (!mk_fresh_uncnstr_var_for(f, num, args, u)) return u; - ptr_vector const * accs = m_dt_util.get_constructor_accessors(c); + ptr_vector const & accs = *m_dt_util.get_constructor_accessors(c); ptr_buffer new_args; - for (unsigned i = 0; i < accs->size(); i++) { - if (accs->get(i) == f) + for (unsigned i = 0; i < accs.size(); i++) { + if (accs[i] == f) new_args.push_back(u); else new_args.push_back(m().get_some_value(c->get_domain(i))); @@ -726,9 +723,9 @@ class elim_uncnstr_tactic : public tactic { return u; if (!m_mc) return u; - ptr_vector const * accs = m_dt_util.get_constructor_accessors(f); + ptr_vector const & accs = *m_dt_util.get_constructor_accessors(f); for (unsigned i = 0; i < num; i++) { - add_def(args[i], m().mk_app(accs->get(i), u)); + add_def(args[i], m().mk_app(accs[i], u)); } return u; } diff --git a/src/tactic/core/elim_uncnstr_tactic.h b/src/tactic/core/elim_uncnstr_tactic.h index 46bcdca16..19f9021ac 100644 --- a/src/tactic/core/elim_uncnstr_tactic.h +++ b/src/tactic/core/elim_uncnstr_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef ELIM_UNCNSTR_TACTIC_H_ #define ELIM_UNCNSTR_TACTIC_H_ -#include"params.h" +#include "util/params.h" class tactic; class ast_manager; diff --git a/src/tactic/core/injectivity_tactic.cpp b/src/tactic/core/injectivity_tactic.cpp new file mode 100644 index 000000000..7d90a2155 --- /dev/null +++ b/src/tactic/core/injectivity_tactic.cpp @@ -0,0 +1,303 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + injectivity_tactic.cpp + +Abstract: + + Injectivity tactics + - Discover axioms of the form `forall x. (= (g (f x)) x` + Mark `f` as injective + - Rewrite (sub)terms of the form `(= (f x) (f y))` to `(= x y)` whenever `f` is injective. + +Author: + + Nicolas Braud-Santoni (t-nibrau) 2017-08-10 + +Notes: + +--*/ +#include +#include +#include "tactic/tactical.h" +#include "ast/rewriter/rewriter_def.h" +#include "tactic/core/injectivity_tactic.h" +#include "util/dec_ref_util.h" + + +class injectivity_tactic : public tactic { + + struct InjHelper : public obj_map*> { + ast_manager & m_manager; + + void insert(func_decl* const f, func_decl* const g) { + obj_hashtable *m; + if (! obj_map::find(f, m)) { + m_manager.inc_ref(f); + m = alloc(obj_hashtable); // TODO: Check we don't leak memory + obj_map::insert(f, m); + } + if (!m->contains(g)) { + m_manager.inc_ref(g); + m->insert(g); + } + } + + bool find(func_decl* const f, func_decl* const g) const { + obj_hashtable *m; + if(! obj_map::find(f, m)) + return false; + + return m->contains(g); + } + + InjHelper(ast_manager& m) : obj_map*>(), m_manager(m) {} + ~InjHelper() { + for(auto m : *this) { + for (func_decl* f : *m.get_value()) + m_manager.dec_ref(f); + + m_manager.dec_ref(m.m_key); + dealloc(m.m_value); + } + } + + }; + + struct finder { + ast_manager & m_manager; + InjHelper & inj_map; + + finder(ast_manager & m, InjHelper & map, params_ref const & p) : + m_manager(m), + inj_map(map) { + updt_params(p); + } + + ast_manager & m() const { return m_manager; } + + bool is_axiom(expr* n, func_decl* &f, func_decl* &g) { + if (!is_quantifier(n)) + return false; + + quantifier* const q = to_quantifier(n); + if (!q->is_forall() || q->get_num_decls() != 1) + return false; + + const expr * const body = q->get_expr(); + + // n ~= forall x. body + + if (!m().is_eq(body)) + return false; + + const app * const body_a = to_app(body); + if (body_a->get_num_args() != 2) + return false; + + const expr* a = body_a->get_arg(0); + const expr* b = body_a->get_arg(1); + + // n ~= forall x. (= a b) + + if (is_app(a) && is_var(b)) { + // Do nothing + } + else if (is_app(b) && is_var(a)) { + std::swap(a, b); + } + else + return false; + + const app* const a_app = to_app(a); + const var* const b_var = to_var(b); + + if (b_var->get_idx() != 0) // idx is the De Bruijn's index + return false; + + if (a_app->get_num_args() != 1) + return false; + + g = a_app->get_decl(); + const expr* const a_body = a_app->get_arg(0); + + // n ~= forall x. (= (g a_body) x) + + if (!is_app(a_body)) + return false; + const app* const a_body_app = to_app(a_body); + if (a_body_app->get_num_args() != 1) // Maybe TODO: support multi-argument functions + return false; + + f = a_body_app->get_decl(); + const expr* const a_body_body = a_body_app->get_arg(0); + + // n ~= forall x. (= (g (f a_body_body)) x) + if (a_body_body != b_var) + return false; + + // n ~= forall x. (= (g (f x)) x) + + return true; + } + + void operator()(goal_ref const & goal, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + SASSERT(goal->is_well_sorted()); + mc = 0; pc = 0; core = 0; + tactic_report report("injectivity", *goal); + fail_if_unsat_core_generation("injectivity", goal); // TODO: Support UNSAT cores + fail_if_proof_generation("injectivity", goal); + + for (unsigned i = 0; i < goal->size(); ++i) { + func_decl *f, *g; + if (!is_axiom(goal->form(i), f, g)) continue; + TRACE("injectivity", tout << "Marking " << f->get_name() << " as injective" << std::endl;); + inj_map.insert(f, g); + // TODO: Record that g is f's pseudoinverse + } + } + + void updt_params(params_ref const & p) {} + }; + + struct rewriter_eq_cfg : public default_rewriter_cfg { + ast_manager & m_manager; + InjHelper & inj_map; +// expr_ref_vector m_out; +// sort_ref_vector m_bindings; + + ast_manager & m() const { return m_manager; } + + rewriter_eq_cfg(ast_manager & m, InjHelper & map, params_ref const & p) : m_manager(m), inj_map(map) { + } + + ~rewriter_eq_cfg() { + } + + void cleanup_buffers() { +// m_out.finalize(); + } + + void reset() { + } + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + if(num != 2) + return BR_FAILED; + + if (!m().is_eq(f)) + return BR_FAILED; + + // We are rewriting (= a b) + if (!is_app(args[0]) || !is_app(args[1])) + return BR_FAILED; + + const app* const a = to_app(args[0]); + const app* const b = to_app(args[1]); + + // a and b are applications of the same function + if (a->get_decl() != b->get_decl()) + return BR_FAILED; + + // Maybe TODO: Generalize to multi-parameter functions ? + if (a->get_num_args() != 1 || b->get_num_args() != 1) + return BR_FAILED; + + if (!inj_map.contains(a->get_decl())) + return BR_FAILED; + + SASSERT(m().get_sort(a->get_arg(0)) == m().get_sort(b->get_arg(0))); + TRACE("injectivity", tout << "Rewriting (= " << mk_ismt2_pp(args[0], m()) << + " " << mk_ismt2_pp(args[1], m()) << ")" << std::endl;); + result = m().mk_eq(a->get_arg(0), b->get_arg(0)); + result_pr = nullptr; + return BR_DONE; + } + + }; + + struct rewriter_eq : public rewriter_tpl { + rewriter_eq_cfg m_cfg; + rewriter_eq(ast_manager & m, InjHelper & map, params_ref const & p) : + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, map, p) { + } + }; + + struct rewriter_inverse { }; + + finder * m_finder; + rewriter_eq * m_eq; + InjHelper * m_map; +// rewriter_inverse * m_inverse; + + params_ref m_params; + ast_manager & m_manager; + +public: + injectivity_tactic(ast_manager & m, params_ref const & p): + m_params(p), + m_manager(m) { + TRACE("injectivity", tout << "constructed new tactic" << std::endl;); + m_map = alloc(InjHelper, m); + m_finder = alloc(finder, m, *m_map, p); + m_eq = alloc(rewriter_eq, m, *m_map, p); + } + + virtual tactic * translate(ast_manager & m) { + return alloc(injectivity_tactic, m, m_params); + } + + virtual ~injectivity_tactic() { + dealloc(m_finder); + dealloc(m_eq); + dealloc(m_map); + } + + virtual void updt_params(params_ref const & p) { + m_params = p; + m_finder->updt_params(p); + } + + virtual void collect_param_descrs(param_descrs & r) { + insert_max_memory(r); + insert_produce_models(r); + } + + virtual void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + (*m_finder)(g, result, mc, pc, core); + + for (unsigned i = 0; i < g->size(); ++i) { + expr* curr = g->form(i); + expr_ref rw(m_manager); + proof_ref pr(m_manager); + (*m_eq)(curr, rw, pr); + g->update(i, rw, pr, g->dep(i)); + } + result.push_back(g.get()); + } + + virtual void cleanup() { + InjHelper * m = alloc(InjHelper, m_manager); + finder * f = alloc(finder, m_manager, *m, m_params); + rewriter_eq * r = alloc(rewriter_eq, m_manager, *m, m_params); + std::swap(m, m_map), std::swap(f, m_finder), std::swap(r, m_eq); + dealloc(m), dealloc(f), dealloc(r); + } + + +}; + +tactic * mk_injectivity_tactic(ast_manager & m, params_ref const & p) { + return alloc(injectivity_tactic, m, p); +} diff --git a/src/tactic/core/injectivity_tactic.h b/src/tactic/core/injectivity_tactic.h new file mode 100644 index 000000000..447357912 --- /dev/null +++ b/src/tactic/core/injectivity_tactic.h @@ -0,0 +1,32 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + injectivity_tactic.h + +Abstract: + + Injectivity tactics + +Author: + + Nicolas Braud-Santoni (t-nibrau) 2017-08-10 + +Notes: + +--*/ +#ifndef INJECTIVITY_TACTIC_H_ +#define INJECTIVITY_TACTIC_H_ + +#include "util/params.h" +class ast_manager; +class tactic; + +tactic * mk_injectivity_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("injectivity", "Identifies and applies injectivity axioms.", "mk_injectivity_tactic(m, p)") +*/ + +#endif diff --git a/src/tactic/core/nnf_tactic.cpp b/src/tactic/core/nnf_tactic.cpp index f9244f8e7..6b360e711 100644 --- a/src/tactic/core/nnf_tactic.cpp +++ b/src/tactic/core/nnf_tactic.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"nnf.h" -#include"tactical.h" -#include"filter_model_converter.h" +#include "ast/normal_forms/nnf.h" +#include "tactic/tactical.h" +#include "tactic/filter_model_converter.h" class nnf_tactic : public tactic { params_ref m_params; diff --git a/src/tactic/core/nnf_tactic.h b/src/tactic/core/nnf_tactic.h index b5363f830..2070db32e 100644 --- a/src/tactic/core/nnf_tactic.h +++ b/src/tactic/core/nnf_tactic.h @@ -19,7 +19,7 @@ Revision History: #ifndef NNF_TACTIC_H_ #define NNF_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/core/occf_tactic.cpp b/src/tactic/core/occf_tactic.cpp index c080ee915..6d9d63971 100644 --- a/src/tactic/core/occf_tactic.cpp +++ b/src/tactic/core/occf_tactic.cpp @@ -21,10 +21,10 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"occf_tactic.h" -#include"filter_model_converter.h" -#include"cooperate.h" +#include "tactic/tactical.h" +#include "tactic/core/occf_tactic.h" +#include "tactic/filter_model_converter.h" +#include "util/cooperate.h" class occf_tactic : public tactic { struct imp { diff --git a/src/tactic/core/occf_tactic.h b/src/tactic/core/occf_tactic.h index f876f638f..80f8f6042 100644 --- a/src/tactic/core/occf_tactic.h +++ b/src/tactic/core/occf_tactic.h @@ -24,7 +24,7 @@ Revision History: #ifndef OCCF_TACTIC_H_ #define OCCF_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index a7e381576..6a0d7205b 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -31,13 +31,13 @@ Notes: --*/ -#include "pb_preprocess_tactic.h" -#include "tactical.h" -#include "for_each_expr.h" -#include "pb_decl_plugin.h" -#include "th_rewriter.h" -#include "expr_substitution.h" -#include "ast_pp.h" +#include "tactic/core/pb_preprocess_tactic.h" +#include "tactic/tactical.h" +#include "ast/for_each_expr.h" +#include "ast/pb_decl_plugin.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/expr_substitution.h" +#include "ast/ast_pp.h" class pb_preproc_model_converter : public model_converter { ast_manager& m; diff --git a/src/tactic/core/pb_preprocess_tactic.h b/src/tactic/core/pb_preprocess_tactic.h index 8b70437a4..765fc1545 100644 --- a/src/tactic/core/pb_preprocess_tactic.h +++ b/src/tactic/core/pb_preprocess_tactic.h @@ -20,7 +20,7 @@ Notes: #ifndef PB_PREPROCESS_TACTIC_H_ #define PB_PREPROCESS_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 90beabf24..7baac0b99 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -17,12 +17,12 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"propagate_values_tactic.h" -#include"th_rewriter.h" -#include"ast_smt2_pp.h" -#include"expr_substitution.h" -#include"goal_shared_occs.h" +#include "tactic/tactical.h" +#include "tactic/core/propagate_values_tactic.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/ast_smt2_pp.h" +#include "ast/expr_substitution.h" +#include "tactic/goal_shared_occs.h" class propagate_values_tactic : public tactic { struct imp { diff --git a/src/tactic/core/propagate_values_tactic.h b/src/tactic/core/propagate_values_tactic.h index 2d1d311b2..635b0a36f 100644 --- a/src/tactic/core/propagate_values_tactic.h +++ b/src/tactic/core/propagate_values_tactic.h @@ -20,7 +20,7 @@ Revision History: #ifndef PROPAGATE_VALUES_TACTIC_H_ #define PROPAGATE_VALUES_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp index ec7353044..476c21232 100644 --- a/src/tactic/core/reduce_args_tactic.cpp +++ b/src/tactic/core/reduce_args_tactic.cpp @@ -16,14 +16,14 @@ Author: Notes: --*/ -#include"tactical.h" -#include"cooperate.h" -#include"ast_smt2_pp.h" -#include"has_free_vars.h" -#include"map.h" -#include"rewriter_def.h" -#include"extension_model_converter.h" -#include"filter_model_converter.h" +#include "tactic/tactical.h" +#include "util/cooperate.h" +#include "ast/ast_smt2_pp.h" +#include "ast/has_free_vars.h" +#include "util/map.h" +#include "ast/rewriter/rewriter_def.h" +#include "tactic/extension_model_converter.h" +#include "tactic/filter_model_converter.h" /** \brief Reduce the number of arguments in function applications. @@ -502,9 +502,8 @@ void reduce_args_tactic::operator()(goal_ref const & g, } void reduce_args_tactic::cleanup() { - ast_manager & m = m_imp->m(); - imp * d = alloc(imp, m); - std::swap(d, m_imp); - dealloc(d); + ast_manager & m = m_imp->m(); + m_imp->~imp(); + m_imp = new (m_imp) imp(m); } diff --git a/src/tactic/core/reduce_args_tactic.h b/src/tactic/core/reduce_args_tactic.h index c22e0c675..394d7d4ab 100644 --- a/src/tactic/core/reduce_args_tactic.h +++ b/src/tactic/core/reduce_args_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef REDUCE_ARGS_TACTIC_H_ #define REDUCE_ARGS_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/core/simplify_tactic.cpp b/src/tactic/core/simplify_tactic.cpp index be89d356a..9deff968e 100644 --- a/src/tactic/core/simplify_tactic.cpp +++ b/src/tactic/core/simplify_tactic.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"simplify_tactic.h" -#include"th_rewriter.h" -#include"ast_pp.h" +#include "tactic/core/simplify_tactic.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/ast_pp.h" struct simplify_tactic::imp { ast_manager & m_manager; diff --git a/src/tactic/core/simplify_tactic.h b/src/tactic/core/simplify_tactic.h index ec72404dd..1e8420c62 100644 --- a/src/tactic/core/simplify_tactic.h +++ b/src/tactic/core/simplify_tactic.h @@ -19,8 +19,8 @@ Notes: #ifndef SIMPLIFY_TACTIC_H_ #define SIMPLIFY_TACTIC_H_ -#include"tactic.h" -#include"tactical.h" +#include "tactic/tactic.h" +#include "tactic/tactical.h" class simplify_tactic : public tactic { struct imp; diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index f23d874a6..65d474182 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -16,13 +16,13 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"expr_replacer.h" -#include"extension_model_converter.h" -#include"occurs.h" -#include"cooperate.h" -#include"goal_shared_occs.h" -#include"ast_pp.h" +#include "tactic/tactical.h" +#include "ast/rewriter/expr_replacer.h" +#include "tactic/extension_model_converter.h" +#include "ast/occurs.h" +#include "util/cooperate.h" +#include "tactic/goal_shared_occs.h" +#include "ast/ast_pp.h" class solve_eqs_tactic : public tactic { struct imp { diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index 8d543da42..084942ed2 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -19,7 +19,7 @@ Revision History: #ifndef SOLVE_EQS_TACTIC_H_ #define SOLVE_EQS_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; class expr_replacer; diff --git a/src/tactic/core/split_clause_tactic.cpp b/src/tactic/core/split_clause_tactic.cpp index 5699aa178..7a2df81b5 100644 --- a/src/tactic/core/split_clause_tactic.cpp +++ b/src/tactic/core/split_clause_tactic.cpp @@ -17,8 +17,8 @@ Author: Notes: --*/ -#include"tactical.h" -#include"split_clause_tactic.h" +#include "tactic/tactical.h" +#include "tactic/core/split_clause_tactic.h" class split_clause_tactic : public tactic { bool m_largest_clause; diff --git a/src/tactic/core/split_clause_tactic.h b/src/tactic/core/split_clause_tactic.h index 34d1eb497..fcbdbf857 100644 --- a/src/tactic/core/split_clause_tactic.h +++ b/src/tactic/core/split_clause_tactic.h @@ -20,7 +20,7 @@ Notes: #ifndef SPLIT_CLAUSE_TACTIC_H_ #define SPLIT_CLAUSE_TACTIC_H_ -#include"params.h" +#include "util/params.h" class tactic; tactic * mk_split_clause_tactic(params_ref const & p = params_ref()); diff --git a/src/tactic/core/symmetry_reduce_tactic.cpp b/src/tactic/core/symmetry_reduce_tactic.cpp index 873dc55bc..8e87a6741 100644 --- a/src/tactic/core/symmetry_reduce_tactic.cpp +++ b/src/tactic/core/symmetry_reduce_tactic.cpp @@ -19,12 +19,12 @@ Notes: adaption of the algorithms proposed for veriT. --*/ -#include"tactical.h" -#include"for_each_expr.h" -#include"map.h" -#include"expr_replacer.h" -#include"rewriter_def.h" -#include"ast_pp.h" +#include "tactic/tactical.h" +#include "ast/for_each_expr.h" +#include "util/map.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_pp.h" class symmetry_reduce_tactic : public tactic { class imp; diff --git a/src/tactic/core/symmetry_reduce_tactic.h b/src/tactic/core/symmetry_reduce_tactic.h index 552baa7f1..0e92b5e29 100644 --- a/src/tactic/core/symmetry_reduce_tactic.h +++ b/src/tactic/core/symmetry_reduce_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef SYMMETRY_REDUCE_TACTIC_H_ #define SYMMETRY_REDUCE_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index 03e9ce7fa..dbfc748b0 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -49,12 +49,12 @@ Author: Notes: --*/ -#include"tactical.h" -#include"goal_shared_occs.h" -#include"filter_model_converter.h" -#include"bool_rewriter.h" -#include"simplify_tactic.h" -#include"cooperate.h" +#include "tactic/tactical.h" +#include "tactic/goal_shared_occs.h" +#include "tactic/filter_model_converter.h" +#include "ast/rewriter/bool_rewriter.h" +#include "tactic/core/simplify_tactic.h" +#include "util/cooperate.h" static void swap_if_gt(expr * & n1, expr * & n2) { if (n1->get_id() > n2->get_id()) diff --git a/src/tactic/core/tseitin_cnf_tactic.h b/src/tactic/core/tseitin_cnf_tactic.h index 76eeae283..5dd4f6c02 100644 --- a/src/tactic/core/tseitin_cnf_tactic.h +++ b/src/tactic/core/tseitin_cnf_tactic.h @@ -20,7 +20,7 @@ Notes: #ifndef TSEITIN_CNF_TACTIC_H_ #define TSEITIN_CNF_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/equiv_proof_converter.cpp b/src/tactic/equiv_proof_converter.cpp index 13b759f7e..8bec082d3 100644 --- a/src/tactic/equiv_proof_converter.cpp +++ b/src/tactic/equiv_proof_converter.cpp @@ -17,9 +17,9 @@ Revision History: --*/ -#include "equiv_proof_converter.h" -#include "ast_pp.h" -#include "scoped_proof.h" +#include "tactic/equiv_proof_converter.h" +#include "ast/ast_pp.h" +#include "ast/scoped_proof.h" void equiv_proof_converter::insert(expr* fml1, expr* fml2) { if (fml1 != fml2) { diff --git a/src/tactic/equiv_proof_converter.h b/src/tactic/equiv_proof_converter.h index 7571ae9d4..79f5142b2 100644 --- a/src/tactic/equiv_proof_converter.h +++ b/src/tactic/equiv_proof_converter.h @@ -24,7 +24,7 @@ Revision History: #ifndef EQUIV_PROOF_CONVERTER_H_ #define EQUIV_PROOF_CONVERTER_H_ -#include "replace_proof_converter.h" +#include "tactic/replace_proof_converter.h" class equiv_proof_converter : public proof_converter { ast_manager& m; diff --git a/src/tactic/extension_model_converter.cpp b/src/tactic/extension_model_converter.cpp index 18b5b6288..38f0100ee 100644 --- a/src/tactic/extension_model_converter.cpp +++ b/src/tactic/extension_model_converter.cpp @@ -16,11 +16,11 @@ Author: Notes: --*/ -#include"extension_model_converter.h" -#include"model_evaluator.h" -#include"ast_smt2_pp.h" -#include"model_v2_pp.h" -#include"ast_pp.h" +#include "tactic/extension_model_converter.h" +#include "model/model_evaluator.h" +#include "ast/ast_smt2_pp.h" +#include "model/model_v2_pp.h" +#include "ast/ast_pp.h" extension_model_converter::~extension_model_converter() { } diff --git a/src/tactic/extension_model_converter.h b/src/tactic/extension_model_converter.h index 46644eec2..dbd7a7e3b 100644 --- a/src/tactic/extension_model_converter.h +++ b/src/tactic/extension_model_converter.h @@ -20,8 +20,8 @@ Notes: #ifndef EXTENSION_MODEL_CONVERTER_H_ #define EXTENSION_MODEL_CONVERTER_H_ -#include"ast.h" -#include"model_converter.h" +#include "ast/ast.h" +#include "tactic/model_converter.h" class extension_model_converter : public model_converter { diff --git a/src/tactic/filter_model_converter.cpp b/src/tactic/filter_model_converter.cpp index 247f2e91d..46328186d 100644 --- a/src/tactic/filter_model_converter.cpp +++ b/src/tactic/filter_model_converter.cpp @@ -16,8 +16,8 @@ Author: Notes: --*/ -#include"filter_model_converter.h" -#include"model_v2_pp.h" +#include "tactic/filter_model_converter.h" +#include "model/model_v2_pp.h" filter_model_converter::~filter_model_converter() { } diff --git a/src/tactic/filter_model_converter.h b/src/tactic/filter_model_converter.h index 0b67a6c5a..b5d6b86f4 100644 --- a/src/tactic/filter_model_converter.h +++ b/src/tactic/filter_model_converter.h @@ -19,7 +19,7 @@ Notes: #ifndef FILTER_MODEL_CONVERTER_H_ #define FILTER_MODEL_CONVERTER_H_ -#include"model_converter.h" +#include "tactic/model_converter.h" class filter_model_converter : public model_converter { func_decl_ref_vector m_decls; diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 88224d2f2..5e952eb6e 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"ast_smt2_pp.h" -#include"fpa_rewriter.h" -#include"fpa2bv_model_converter.h" +#include "ast/ast_smt2_pp.h" +#include "ast/rewriter/fpa_rewriter.h" +#include "tactic/fpa/fpa2bv_model_converter.h" void fpa2bv_model_converter::display(std::ostream & out) { out << "(fpa2bv-model-converter"; @@ -33,12 +33,29 @@ model_converter * fpa2bv_model_converter::translate(ast_translation & translator } void fpa2bv_model_converter::convert(model_core * mc, model * float_mdl) { + TRACE("fpa2bv_mc", tout << "BV Model: " << std::endl; + for (unsigned i = 0; i < mc->get_num_constants(); i++) + tout << mc->get_constant(i)->get_name() << " --> " << + mk_ismt2_pp(mc->get_const_interp(mc->get_constant(i)), m) << std::endl; + for (unsigned i = 0; i < mc->get_num_functions(); i++) { + func_decl * f = mc->get_function(i); + tout << f->get_name() << "(...) := " << std::endl; + func_interp * fi = mc->get_func_interp(f); + for (unsigned j = 0; j < fi->num_entries(); j++) { + func_entry const * fe = fi->get_entry(j); + for (unsigned k = 0; k < f->get_arity(); k++) + tout << mk_ismt2_pp(fe->get_arg(k), m) << " "; + tout << "--> " << mk_ismt2_pp(fe->get_result(), m) << std::endl; + } + tout << "else " << mk_ismt2_pp(fi->get_else(), m) << std::endl; + }); + obj_hashtable seen; m_bv2fp->convert_consts(mc, float_mdl, seen); m_bv2fp->convert_rm_consts(mc, float_mdl, seen); m_bv2fp->convert_min_max_specials(mc, float_mdl, seen); m_bv2fp->convert_uf2bvuf(mc, float_mdl, seen); - + // Keep all the non-float constants. unsigned sz = mc->get_num_constants(); for (unsigned i = 0; i < sz; i++) { @@ -46,7 +63,7 @@ void fpa2bv_model_converter::convert(model_core * mc, model * float_mdl) { if (!seen.contains(c)) float_mdl->register_decl(c, mc->get_const_interp(c)); } - + // And keep everything else sz = mc->get_num_functions(); for (unsigned i = 0; i < sz; i++) { @@ -57,7 +74,7 @@ void fpa2bv_model_converter::convert(model_core * mc, model * float_mdl) { float_mdl->register_decl(f, val); } } - + sz = mc->get_num_uninterpreted_sorts(); for (unsigned i = 0; i < sz; i++) { sort * s = mc->get_uninterpreted_sort(i); diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index 1f482478b..989caaa58 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -19,14 +19,14 @@ Notes: #ifndef FPA2BV_MODEL_CONVERTER_H_ #define FPA2BV_MODEL_CONVERTER_H_ -#include"fpa2bv_converter.h" -#include"model_converter.h" -#include"bv2fpa_converter.h" +#include "ast/fpa/fpa2bv_converter.h" +#include "tactic/model_converter.h" +#include "ast/fpa/bv2fpa_converter.h" class fpa2bv_model_converter : public model_converter { ast_manager & m; bv2fpa_converter * m_bv2fp; - + public: fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv): m(m), @@ -53,10 +53,10 @@ public: virtual model_converter * translate(ast_translation & translator); protected: - fpa2bv_model_converter(ast_manager & m) : + fpa2bv_model_converter(ast_manager & m) : m(m), m_bv2fp(0) {} - + void convert(model_core * mc, model * float_mdl); }; diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index d55a2e25c..6d90b46ea 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -16,11 +16,11 @@ Author: Notes: --*/ -#include"tactical.h" -#include"fpa2bv_rewriter.h" -#include"simplify_tactic.h" -#include"fpa2bv_tactic.h" -#include"fpa2bv_model_converter.h" +#include "tactic/tactical.h" +#include "ast/fpa/fpa2bv_rewriter.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/fpa/fpa2bv_tactic.h" +#include "tactic/fpa/fpa2bv_model_converter.h" class fpa2bv_tactic : public tactic { struct imp { diff --git a/src/tactic/fpa/fpa2bv_tactic.h b/src/tactic/fpa/fpa2bv_tactic.h index 633009d59..e7e472d8d 100644 --- a/src/tactic/fpa/fpa2bv_tactic.h +++ b/src/tactic/fpa/fpa2bv_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef FPA2BV_TACTIC_H_ #define FPA2BV_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp index f839110f0..cdc363453 100644 --- a/src/tactic/fpa/qffp_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -16,18 +16,18 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"bit_blaster_tactic.h" -#include"sat_tactic.h" -#include"fpa2bv_tactic.h" -#include"smt_tactic.h" -#include"propagate_values_tactic.h" -#include"ackermannize_bv_tactic.h" -#include"probe_arith.h" -#include"qfnra_tactic.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/bv/bit_blaster_tactic.h" +#include "sat/tactic/sat_tactic.h" +#include "tactic/fpa/fpa2bv_tactic.h" +#include "smt/tactic/smt_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "ackermannization/ackermannize_bv_tactic.h" +#include "tactic/arith/probe_arith.h" +#include "tactic/smtlogics/qfnra_tactic.h" -#include"qffp_tactic.h" +#include "tactic/fpa/qffp_tactic.h" struct is_non_fp_qfnra_predicate { diff --git a/src/tactic/fpa/qffp_tactic.h b/src/tactic/fpa/qffp_tactic.h index 42e4f94e7..f696ba2d6 100644 --- a/src/tactic/fpa/qffp_tactic.h +++ b/src/tactic/fpa/qffp_tactic.h @@ -20,7 +20,7 @@ Notes: #ifndef QFFP_TACTIC_H_ #define QFFP_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index a3cac9e2e..ea8d14bd0 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include"goal.h" -#include"ast_ll_pp.h" -#include"ast_smt2_pp.h" -#include"for_each_expr.h" -#include"well_sorted.h" +#include "tactic/goal.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/for_each_expr.h" +#include "ast/well_sorted.h" goal::precision goal::mk_union(precision p1, precision p2) { if (p1 == PRECISE) return p2; diff --git a/src/tactic/goal.h b/src/tactic/goal.h index ea02dfa17..c9de9c037 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -28,13 +28,13 @@ Revision History: #ifndef GOAL_H_ #define GOAL_H_ -#include"ast.h" -#include"ast_translation.h" -#include"ast_printer.h" -#include"for_each_expr.h" -#include"ref.h" -#include"ref_vector.h" -#include"ref_buffer.h" +#include "ast/ast.h" +#include "ast/ast_translation.h" +#include "ast/ast_printer.h" +#include "ast/for_each_expr.h" +#include "util/ref.h" +#include "util/ref_vector.h" +#include "util/ref_buffer.h" class goal { public: diff --git a/src/tactic/goal_num_occurs.cpp b/src/tactic/goal_num_occurs.cpp index 6c94e307c..4c7006d75 100644 --- a/src/tactic/goal_num_occurs.cpp +++ b/src/tactic/goal_num_occurs.cpp @@ -15,8 +15,8 @@ Author: Revision History: --*/ -#include"goal_num_occurs.h" -#include"goal.h" +#include "tactic/goal_num_occurs.h" +#include "tactic/goal.h" void goal_num_occurs::operator()(goal const & g) { expr_fast_mark1 visited; diff --git a/src/tactic/goal_num_occurs.h b/src/tactic/goal_num_occurs.h index e5f97f8cd..14c92e468 100644 --- a/src/tactic/goal_num_occurs.h +++ b/src/tactic/goal_num_occurs.h @@ -18,7 +18,7 @@ Revision History: #ifndef GOAL_NUM_OCCURS_H_ #define GOAL_NUM_OCCURS_H_ -#include"num_occurs.h" +#include "ast/num_occurs.h" class goal; diff --git a/src/tactic/goal_shared_occs.cpp b/src/tactic/goal_shared_occs.cpp index 48c79f739..0048e642a 100644 --- a/src/tactic/goal_shared_occs.cpp +++ b/src/tactic/goal_shared_occs.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"goal_shared_occs.h" +#include "tactic/goal_shared_occs.h" void goal_shared_occs::operator()(goal const & g) { m_occs.reset(); diff --git a/src/tactic/goal_shared_occs.h b/src/tactic/goal_shared_occs.h index 902d1d027..8280cef43 100644 --- a/src/tactic/goal_shared_occs.h +++ b/src/tactic/goal_shared_occs.h @@ -19,8 +19,8 @@ Revision History: #ifndef GOAL_SHARED_OCCS_H_ #define GOAL_SHARED_OCCS_H_ -#include"goal.h" -#include"shared_occs.h" +#include "tactic/goal.h" +#include "ast/shared_occs.h" /** \brief Functor for computing the set of shared occurrences in a goal. diff --git a/src/tactic/goal_util.cpp b/src/tactic/goal_util.cpp index d0dfc11f6..965860cf9 100644 --- a/src/tactic/goal_util.cpp +++ b/src/tactic/goal_util.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"goal_util.h" -#include"goal.h" +#include "tactic/goal_util.h" +#include "tactic/goal.h" struct has_term_ite_functor { struct found {}; diff --git a/src/tactic/horn_subsume_model_converter.cpp b/src/tactic/horn_subsume_model_converter.cpp index 25da094fa..cb56f9b7b 100644 --- a/src/tactic/horn_subsume_model_converter.cpp +++ b/src/tactic/horn_subsume_model_converter.cpp @@ -18,14 +18,14 @@ Revision History: --*/ -#include "horn_subsume_model_converter.h" -#include "var_subst.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" -#include "bool_rewriter.h" -#include "th_rewriter.h" -#include "for_each_expr.h" -#include "well_sorted.h" +#include "tactic/horn_subsume_model_converter.h" +#include "ast/rewriter/var_subst.h" +#include "ast/ast_pp.h" +#include "model/model_smt2_pp.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/for_each_expr.h" +#include "ast/well_sorted.h" void horn_subsume_model_converter::insert(app* head, expr* body) { m_delay_head.push_back(head); diff --git a/src/tactic/horn_subsume_model_converter.h b/src/tactic/horn_subsume_model_converter.h index d56802349..1c1ae9feb 100644 --- a/src/tactic/horn_subsume_model_converter.h +++ b/src/tactic/horn_subsume_model_converter.h @@ -35,8 +35,8 @@ Subsumption transformation (remove Horn clause): #ifndef HORN_SUBSUME_MODEL_CONVERTER_H_ #define HORN_SUBSUME_MODEL_CONVERTER_H_ -#include "model_converter.h" -#include "th_rewriter.h" +#include "tactic/model_converter.h" +#include "ast/rewriter/th_rewriter.h" class horn_subsume_model_converter : public model_converter { ast_manager& m; diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 6f6dd3da1..4269946a1 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -16,8 +16,8 @@ Author: Notes: --*/ -#include"model_converter.h" -#include"model_v2_pp.h" +#include "tactic/model_converter.h" +#include "model/model_v2_pp.h" class concat_model_converter : public concat_converter { public: diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index e2bc3cf83..5e549344e 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -19,9 +19,9 @@ Notes: #ifndef MODEL_CONVERTER_H_ #define MODEL_CONVERTER_H_ -#include"model.h" -#include"converter.h" -#include"ref.h" +#include "model/model.h" +#include "tactic/converter.h" +#include "util/ref.h" class labels_vec : public svector {}; diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index 46b5a51b0..c99ea545a 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -44,22 +44,22 @@ Author: Revision History: --*/ -#include "tactical.h" -#include "nl_purify_tactic.h" -#include "smt_tactic.h" -#include "rewriter.h" -#include "nlsat_tactic.h" -#include "filter_model_converter.h" -#include "obj_pair_hashtable.h" -#include "rewriter_def.h" -#include "ast_pp.h" -#include "trace.h" -#include "smt_solver.h" -#include "solver.h" -#include "model_smt2_pp.h" -#include "expr_safe_replace.h" -#include "ast_util.h" -#include "solver2tactic.h" +#include "tactic/tactical.h" +#include "tactic/nlsat_smt/nl_purify_tactic.h" +#include "smt/tactic/smt_tactic.h" +#include "ast/rewriter/rewriter.h" +#include "nlsat/tactic/nlsat_tactic.h" +#include "tactic/filter_model_converter.h" +#include "util/obj_pair_hashtable.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_pp.h" +#include "util/trace.h" +#include "smt/smt_solver.h" +#include "solver/solver.h" +#include "model/model_smt2_pp.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/ast_util.h" +#include "solver/solver2tactic.h" class nl_purify_tactic : public tactic { diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.h b/src/tactic/nlsat_smt/nl_purify_tactic.h index 87e37b4ad..85d033921 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.h +++ b/src/tactic/nlsat_smt/nl_purify_tactic.h @@ -21,7 +21,7 @@ Revision History: #ifndef NL_PURIFY_TACTIC_H_ #define NL_PURIFY_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index e293ade17..58078e106 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -17,23 +17,22 @@ Notes: --*/ -#include "bounded_int2bv_solver.h" -#include "solver_na2as.h" -#include "tactic.h" -#include "pb2bv_rewriter.h" -#include "filter_model_converter.h" -#include "extension_model_converter.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" -#include "bound_manager.h" -#include "bv2int_rewriter.h" -#include "expr_safe_replace.h" -#include "bv_decl_plugin.h" -#include "arith_decl_plugin.h" +#include "tactic/portfolio/bounded_int2bv_solver.h" +#include "solver/solver_na2as.h" +#include "tactic/tactic.h" +#include "ast/rewriter/pb2bv_rewriter.h" +#include "tactic/filter_model_converter.h" +#include "tactic/extension_model_converter.h" +#include "ast/ast_pp.h" +#include "model/model_smt2_pp.h" +#include "tactic/arith/bound_manager.h" +#include "tactic/arith/bv2int_rewriter.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/bv_decl_plugin.h" +#include "ast/arith_decl_plugin.h" class bounded_int2bv_solver : public solver_na2as { ast_manager& m; - params_ref m_params; mutable bv_util m_bv; mutable arith_util m_arith; mutable expr_ref_vector m_assertions; @@ -53,7 +52,6 @@ public: bounded_int2bv_solver(ast_manager& m, params_ref const& p, solver* s): solver_na2as(m), m(m), - m_params(p), m_bv(m), m_arith(m), m_assertions(m), @@ -63,6 +61,7 @@ public: m_rewriter_ctx(m, p), m_rewriter(m, m_rewriter_ctx) { + solver::updt_params(p); m_bounds.push_back(alloc(bound_manager, m)); } @@ -131,7 +130,7 @@ public: return m_solver->check_sat(num_assumptions, assumptions); } - virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } + virtual void updt_params(params_ref const & p) { solver::updt_params(p); m_solver->updt_params(p); } virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } diff --git a/src/tactic/portfolio/bounded_int2bv_solver.h b/src/tactic/portfolio/bounded_int2bv_solver.h index 5fcf2cd65..1d048d54e 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.h +++ b/src/tactic/portfolio/bounded_int2bv_solver.h @@ -19,8 +19,8 @@ Notes: #ifndef BOUNDED_INT2BV_SOLVER_H_ #define BOUNDED_INT2BV_SOLVER_H_ -#include"ast.h" -#include"params.h" +#include "ast/ast.h" +#include "util/params.h" class solver; diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 4f5eb5ed0..420cb961a 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -16,21 +16,21 @@ Author: Notes: --*/ -#include"default_tactic.h" -#include"simplify_tactic.h" -#include"qfbv_tactic.h" -#include"smt_tactic.h" -#include"qflia_tactic.h" -#include"qflra_tactic.h" -#include"qfnia_tactic.h" -#include"qfnra_tactic.h" -#include"nra_tactic.h" -#include"probe_arith.h" -#include"quant_tactics.h" -#include"qffp_tactic.h" -#include"qfaufbv_tactic.h" -#include"qfauflia_tactic.h" -#include"qfufnra_tactic.h" +#include "tactic/portfolio/default_tactic.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/smtlogics/qfbv_tactic.h" +#include "smt/tactic/smt_tactic.h" +#include "tactic/smtlogics/qflia_tactic.h" +#include "tactic/smtlogics/qflra_tactic.h" +#include "tactic/smtlogics/qfnia_tactic.h" +#include "tactic/smtlogics/qfnra_tactic.h" +#include "tactic/smtlogics/nra_tactic.h" +#include "tactic/arith/probe_arith.h" +#include "tactic/smtlogics/quant_tactics.h" +#include "tactic/fpa/qffp_tactic.h" +#include "tactic/smtlogics/qfaufbv_tactic.h" +#include "tactic/smtlogics/qfauflia_tactic.h" +#include "tactic/smtlogics/qfufnra_tactic.h" tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(mk_simplify_tactic(m), diff --git a/src/tactic/portfolio/default_tactic.h b/src/tactic/portfolio/default_tactic.h index 2f40fa145..8992cfee3 100644 --- a/src/tactic/portfolio/default_tactic.h +++ b/src/tactic/portfolio/default_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef DEFAULT_TACTIC_H_ #define DEFAULT_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 8c9ff122d..dd0ee7c4b 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -20,20 +20,19 @@ Notes: --*/ -#include "solver_na2as.h" -#include "tactic.h" -#include "bv_decl_plugin.h" -#include "datatype_decl_plugin.h" -#include "enum2bv_rewriter.h" -#include "extension_model_converter.h" -#include "filter_model_converter.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" -#include "enum2bv_solver.h" +#include "solver/solver_na2as.h" +#include "tactic/tactic.h" +#include "ast/bv_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/rewriter/enum2bv_rewriter.h" +#include "tactic/extension_model_converter.h" +#include "tactic/filter_model_converter.h" +#include "ast/ast_pp.h" +#include "model/model_smt2_pp.h" +#include "tactic/portfolio/enum2bv_solver.h" class enum2bv_solver : public solver_na2as { ast_manager& m; - params_ref m_params; ref m_solver; enum2bv_rewriter m_rewriter; @@ -42,10 +41,10 @@ public: enum2bv_solver(ast_manager& m, params_ref const& p, solver* s): solver_na2as(m), m(m), - m_params(p), m_solver(s), m_rewriter(m, p) { + solver::updt_params(p); } virtual ~enum2bv_solver() {} @@ -78,7 +77,7 @@ public: return m_solver->check_sat(num_assumptions, assumptions); } - virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } + virtual void updt_params(params_ref const & p) { solver::updt_params(p); m_solver->updt_params(p); } virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } @@ -97,7 +96,6 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { datatype_util dt(m); bv_util bv(m); diff --git a/src/tactic/portfolio/enum2bv_solver.h b/src/tactic/portfolio/enum2bv_solver.h index b113c6747..08f753cc5 100644 --- a/src/tactic/portfolio/enum2bv_solver.h +++ b/src/tactic/portfolio/enum2bv_solver.h @@ -19,8 +19,8 @@ Notes: #ifndef ENUM2BV_SOLVER_H_ #define ENUM2BV_SOLVER_H_ -#include"ast.h" -#include"params.h" +#include "ast/ast.h" +#include "util/params.h" class solver; diff --git a/src/tactic/portfolio/fd_solver.cpp b/src/tactic/portfolio/fd_solver.cpp index a534337bc..b29fb20c1 100644 --- a/src/tactic/portfolio/fd_solver.cpp +++ b/src/tactic/portfolio/fd_solver.cpp @@ -17,12 +17,12 @@ Notes: --*/ -#include "fd_solver.h" -#include "tactic.h" -#include "inc_sat_solver.h" -#include "enum2bv_solver.h" -#include "pb2bv_solver.h" -#include "bounded_int2bv_solver.h" +#include "tactic/portfolio/fd_solver.h" +#include "tactic/tactic.h" +#include "sat/sat_solver/inc_sat_solver.h" +#include "tactic/portfolio/enum2bv_solver.h" +#include "tactic/portfolio/pb2bv_solver.h" +#include "tactic/portfolio/bounded_int2bv_solver.h" solver * mk_fd_solver(ast_manager & m, params_ref const & p) { solver* s = mk_inc_sat_solver(m, p); diff --git a/src/tactic/portfolio/fd_solver.h b/src/tactic/portfolio/fd_solver.h index 51abb087f..53cae16d1 100644 --- a/src/tactic/portfolio/fd_solver.h +++ b/src/tactic/portfolio/fd_solver.h @@ -19,8 +19,8 @@ Notes: #ifndef FD_SOLVER_H_ #define FD_SOLVER_H_ -#include"ast.h" -#include"params.h" +#include "ast/ast.h" +#include "util/params.h" class solver; diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 090ea9f76..a06ff77c0 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -16,17 +16,16 @@ Notes: --*/ -#include "pb2bv_solver.h" -#include "solver_na2as.h" -#include "tactic.h" -#include "pb2bv_rewriter.h" -#include "filter_model_converter.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" +#include "tactic/portfolio/pb2bv_solver.h" +#include "solver/solver_na2as.h" +#include "tactic/tactic.h" +#include "ast/rewriter/pb2bv_rewriter.h" +#include "tactic/filter_model_converter.h" +#include "ast/ast_pp.h" +#include "model/model_smt2_pp.h" class pb2bv_solver : public solver_na2as { ast_manager& m; - params_ref m_params; mutable expr_ref_vector m_assertions; mutable ref m_solver; mutable pb2bv_rewriter m_rewriter; @@ -36,11 +35,11 @@ public: pb2bv_solver(ast_manager& m, params_ref const& p, solver* s): solver_na2as(m), m(m), - m_params(p), m_assertions(m), m_solver(s), m_rewriter(m, p) { + solver::updt_params(p); } virtual ~pb2bv_solver() {} @@ -70,7 +69,7 @@ public: return m_solver->check_sat(num_assumptions, assumptions); } - virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } + virtual void updt_params(params_ref const & p) { solver::updt_params(p); m_solver->updt_params(p); } virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } diff --git a/src/tactic/portfolio/pb2bv_solver.h b/src/tactic/portfolio/pb2bv_solver.h index e861e769b..ea53d8d89 100644 --- a/src/tactic/portfolio/pb2bv_solver.h +++ b/src/tactic/portfolio/pb2bv_solver.h @@ -19,8 +19,8 @@ Notes: #ifndef PB2BV_SOLVER_H_ #define PB2BV_SOLVER_H_ -#include"ast.h" -#include"params.h" +#include "ast/ast.h" +#include "util/params.h" class solver; diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index a4a579ddd..3e77b7abc 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -17,30 +17,31 @@ Author: Notes: --*/ -#include"cmd_context.h" -#include"combined_solver.h" -#include"tactic2solver.h" -#include"qfbv_tactic.h" -#include"qflia_tactic.h" -#include"qfnia_tactic.h" -#include"qfnra_tactic.h" -#include"qfuf_tactic.h" -#include"qflra_tactic.h" -#include"quant_tactics.h" -#include"qfauflia_tactic.h" -#include"qfaufbv_tactic.h" -#include"qfufbv_tactic.h" -#include"qfidl_tactic.h" -#include"default_tactic.h" -#include"ufbv_tactic.h" -#include"qffp_tactic.h" -#include"qfufnra_tactic.h" -#include"horn_tactic.h" -#include"smt_solver.h" -#include"inc_sat_solver.h" -#include"fd_solver.h" -#include"bv_rewriter.h" -#include"solver2tactic.h" +#include "cmd_context/cmd_context.h" +#include "solver/combined_solver.h" +#include "solver/tactic2solver.h" +#include "tactic/smtlogics/qfbv_tactic.h" +#include "tactic/smtlogics/qflia_tactic.h" +#include "tactic/smtlogics/qfnia_tactic.h" +#include "tactic/smtlogics/qfnra_tactic.h" +#include "tactic/smtlogics/qfuf_tactic.h" +#include "tactic/smtlogics/qflra_tactic.h" +#include "tactic/smtlogics/quant_tactics.h" +#include "tactic/smtlogics/qfauflia_tactic.h" +#include "tactic/smtlogics/qfaufbv_tactic.h" +#include "tactic/smtlogics/qfufbv_tactic.h" +#include "tactic/smtlogics/qfidl_tactic.h" +#include "tactic/smtlogics/nra_tactic.h" +#include "tactic/portfolio/default_tactic.h" +#include "tactic/portfolio/fd_solver.h" +#include "tactic/ufbv/ufbv_tactic.h" +#include "tactic/fpa/qffp_tactic.h" +#include "tactic/smtlogics/qfufnra_tactic.h" +#include "muz/fp/horn_tactic.h" +#include "smt/smt_solver.h" +#include "sat/sat_solver/inc_sat_solver.h" +#include "ast/rewriter/bv_rewriter.h" +#include "solver/solver2tactic.h" tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const & logic) { @@ -78,6 +79,8 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const return mk_uflra_tactic(m, p); else if (logic=="LRA") return mk_lra_tactic(m, p); + else if (logic=="NRA") + return mk_nra_tactic(m, p); else if (logic=="LIA") return mk_lia_tactic(m, p); else if (logic=="UFBV") @@ -90,7 +93,7 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const return mk_qffpbv_tactic(m, p); else if (logic=="HORN") return mk_horn_tactic(m, p); - else if (logic == "QF_FD") + else if ((logic == "QF_FD" || logic == "SAT") && !m.proofs_enabled()) return mk_solver2tactic(mk_fd_solver(m, p)); //else if (logic=="QF_UFNRA") // return mk_qfufnra_tactic(m, p); @@ -99,7 +102,7 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const } static solver* mk_special_solver_for_logic(ast_manager & m, params_ref const & p, symbol const& logic) { - if (logic == "QF_FD") + if ((logic == "QF_FD" || logic == "SAT") && !m.proofs_enabled()) return mk_fd_solver(m, p); return 0; } diff --git a/src/tactic/probe.cpp b/src/tactic/probe.cpp index 677438cdf..072b866b1 100644 --- a/src/tactic/probe.cpp +++ b/src/tactic/probe.cpp @@ -19,11 +19,11 @@ Author: Revision History: --*/ -#include"probe.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"goal_util.h" -#include"bv_rewriter.h" +#include "tactic/probe.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "tactic/goal_util.h" +#include "ast/rewriter/bv_rewriter.h" class memory_probe : public probe { public: diff --git a/src/tactic/probe.h b/src/tactic/probe.h index 3f7229d36..294a6cbd0 100644 --- a/src/tactic/probe.h +++ b/src/tactic/probe.h @@ -24,7 +24,7 @@ Revision History: #ifndef PROBE_H_ #define PROBE_H_ -#include"goal.h" +#include "tactic/goal.h" class probe { public: diff --git a/src/tactic/proof_converter.cpp b/src/tactic/proof_converter.cpp index fa58d5208..095488415 100644 --- a/src/tactic/proof_converter.cpp +++ b/src/tactic/proof_converter.cpp @@ -16,8 +16,8 @@ Author: Notes: --*/ -#include"proof_converter.h" -#include"ast_smt2_pp.h" +#include "tactic/proof_converter.h" +#include "ast/ast_smt2_pp.h" class concat_proof_converter : public concat_converter { public: diff --git a/src/tactic/proof_converter.h b/src/tactic/proof_converter.h index 44928e046..e925436d2 100644 --- a/src/tactic/proof_converter.h +++ b/src/tactic/proof_converter.h @@ -19,9 +19,9 @@ Notes: #ifndef PROOF_CONVERTER_H_ #define PROOF_CONVERTER_H_ -#include"ast.h" -#include"converter.h" -#include"ref.h" +#include "ast/ast.h" +#include "tactic/converter.h" +#include "util/ref.h" class proof_converter : public converter { public: diff --git a/src/tactic/replace_proof_converter.cpp b/src/tactic/replace_proof_converter.cpp index 45ec6fc2e..98f28bb1b 100644 --- a/src/tactic/replace_proof_converter.cpp +++ b/src/tactic/replace_proof_converter.cpp @@ -17,10 +17,10 @@ Revision History: --*/ -#include "replace_proof_converter.h" -#include "expr_functors.h" -#include "ast_pp.h" -#include "for_each_expr.h" +#include "tactic/replace_proof_converter.h" +#include "ast/expr_functors.h" +#include "ast/ast_pp.h" +#include "ast/for_each_expr.h" /** \brief Replace expressions by other expressions. diff --git a/src/tactic/replace_proof_converter.h b/src/tactic/replace_proof_converter.h index 96f25aab4..b768a18a0 100644 --- a/src/tactic/replace_proof_converter.h +++ b/src/tactic/replace_proof_converter.h @@ -23,7 +23,7 @@ Revision History: #ifndef REPLACE_PROOF_CONVERTER_H_ #define REPLACE_PROOF_CONVERTER_H_ -#include "proof_converter.h" +#include "tactic/proof_converter.h" class replace_proof_converter : public proof_converter { ast_manager& m; diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index f2d6a9653..ba35bac84 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -16,17 +16,17 @@ Author: Revision History: --*/ -#include "sine_filter.h" -#include "tactical.h" -#include "filter_model_converter.h" -#include "datatype_decl_plugin.h" -#include "rewriter_def.h" -#include "filter_model_converter.h" -#include "extension_model_converter.h" -#include "var_subst.h" -#include "ast_util.h" -#include "obj_pair_hashtable.h" -#include "ast_pp.h" +#include "tactic/sine_filter.h" +#include "tactic/tactical.h" +#include "tactic/filter_model_converter.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/rewriter/rewriter_def.h" +#include "tactic/filter_model_converter.h" +#include "tactic/extension_model_converter.h" +#include "ast/rewriter/var_subst.h" +#include "ast/ast_util.h" +#include "util/obj_pair_hashtable.h" +#include "ast/ast_pp.h" class sine_tactic : public tactic { diff --git a/src/tactic/sine_filter.h b/src/tactic/sine_filter.h index 769ef474f..72964219e 100644 --- a/src/tactic/sine_filter.h +++ b/src/tactic/sine_filter.h @@ -19,7 +19,7 @@ Revision History: #ifndef SINE_TACTIC_H_ #define SINE_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/sls/bvsls_opt_engine.cpp b/src/tactic/sls/bvsls_opt_engine.cpp index 96fad9a5a..502bcbde6 100644 --- a/src/tactic/sls/bvsls_opt_engine.cpp +++ b/src/tactic/sls/bvsls_opt_engine.cpp @@ -16,8 +16,8 @@ Author: Notes: --*/ -#include "nnf.h" -#include "bvsls_opt_engine.h" +#include "ast/normal_forms/nnf.h" +#include "tactic/sls/bvsls_opt_engine.h" bvsls_opt_engine::bvsls_opt_engine(ast_manager & m, params_ref const & p) : sls_engine(m, p), @@ -238,7 +238,7 @@ bool bvsls_opt_engine::what_if( mpz bvsls_opt_engine::find_best_move( ptr_vector & to_evaluate, - mpz score, + mpz & score, unsigned & best_const, mpz & best_value, unsigned & new_bit, diff --git a/src/tactic/sls/bvsls_opt_engine.h b/src/tactic/sls/bvsls_opt_engine.h index 8ea666ed0..9487130d3 100644 --- a/src/tactic/sls/bvsls_opt_engine.h +++ b/src/tactic/sls/bvsls_opt_engine.h @@ -19,7 +19,7 @@ Notes: #ifndef BVSLS_OPT_ENGINE_H_ #define BVSLS_OPT_ENGINE_H_ -#include "sls_engine.h" +#include "tactic/sls/sls_engine.h" class bvsls_opt_engine : public sls_engine { sls_tracker & m_hard_tracker; @@ -61,7 +61,7 @@ protected: bool what_if(func_decl * fd, const unsigned & fd_inx, const mpz & temp, mpz & best_score, unsigned & best_const, mpz & best_value); - mpz find_best_move(ptr_vector & to_evaluate, mpz score, + mpz find_best_move(ptr_vector & to_evaluate, mpz & score, unsigned & best_const, mpz & best_value, unsigned & new_bit, move_type & move, mpz const & max_score, expr * objective); diff --git a/src/tactic/sls/sls_engine.cpp b/src/tactic/sls/sls_engine.cpp index 4418808dd..4e1c6a693 100644 --- a/src/tactic/sls/sls_engine.cpp +++ b/src/tactic/sls/sls_engine.cpp @@ -18,17 +18,17 @@ Notes: --*/ #include // Need DBL_MAX -#include"map.h" -#include"ast_smt2_pp.h" -#include"ast_pp.h" -#include"var_subst.h" -#include"model_pp.h" -#include"tactic.h" -#include"cooperate.h" -#include"luby.h" +#include "util/map.h" +#include "ast/ast_smt2_pp.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/var_subst.h" +#include "model/model_pp.h" +#include "tactic/tactic.h" +#include "util/cooperate.h" +#include "util/luby.h" -#include"sls_params.hpp" -#include"sls_engine.h" +#include "tactic/sls/sls_params.hpp" +#include "tactic/sls/sls_engine.h" sls_engine::sls_engine(ast_manager & m, params_ref const & p) : diff --git a/src/tactic/sls/sls_engine.h b/src/tactic/sls/sls_engine.h index ccd4f5b5a..0c4fb4d39 100644 --- a/src/tactic/sls/sls_engine.h +++ b/src/tactic/sls/sls_engine.h @@ -19,14 +19,14 @@ Notes: #ifndef SLS_ENGINE_H_ #define SLS_ENGINE_H_ -#include"stopwatch.h" -#include"lbool.h" -#include"model_converter.h" -#include"goal.h" +#include "util/stopwatch.h" +#include "util/lbool.h" +#include "tactic/model_converter.h" +#include "tactic/goal.h" -#include"sls_tracker.h" -#include"sls_evaluator.h" -#include"statistics.h" +#include "tactic/sls/sls_tracker.h" +#include "tactic/sls/sls_evaluator.h" +#include "util/statistics.h" class sls_engine { public: diff --git a/src/tactic/sls/sls_evaluator.h b/src/tactic/sls/sls_evaluator.h index 59b9fd7a5..4e006d219 100644 --- a/src/tactic/sls/sls_evaluator.h +++ b/src/tactic/sls/sls_evaluator.h @@ -20,10 +20,10 @@ Notes: #ifndef SLS_EVALUATOR_H_ #define SLS_EVALUATOR_H_ -#include"model_evaluator.h" +#include "model/model_evaluator.h" -#include"sls_powers.h" -#include"sls_tracker.h" +#include "tactic/sls/sls_powers.h" +#include "tactic/sls/sls_tracker.h" class sls_evaluator { ast_manager & m_manager; diff --git a/src/tactic/sls/sls_params.pyg b/src/tactic/sls/sls_params.pyg index bf5bd181a..05405ef24 100644 --- a/src/tactic/sls/sls_params.pyg +++ b/src/tactic/sls/sls_params.pyg @@ -2,25 +2,25 @@ def_module_params('sls', export=True, description='Experimental Stochastic Local Search Solver (for QFBV only).', params=(max_memory_param(), - ('max_restarts', UINT, UINT_MAX, 'maximum number of restarts'), - ('walksat', BOOL, 1, 'use walksat assertion selection (instead of gsat)'), - ('walksat_ucb', BOOL, 1, 'use bandit heuristic for walksat assertion selection (instead of random)'), - ('walksat_ucb_constant', DOUBLE, 20.0, 'the ucb constant c in the term score + c * f(touched)'), - ('walksat_ucb_init', BOOL, 0, 'initialize total ucb touched to formula size'), - ('walksat_ucb_forget', DOUBLE, 1.0, 'scale touched by this factor every base restart interval'), - ('walksat_ucb_noise', DOUBLE, 0.0002, 'add noise 0 <= 256 * ucb_noise to ucb score for assertion selection'), - ('walksat_repick', BOOL, 1, 'repick assertion if randomizing in local minima'), - ('scale_unsat', DOUBLE, 0.5, 'scale score of unsat expressions by this factor'), - ('paws_init', UINT, 40, 'initial/minimum assertion weights'), - ('paws_sp', UINT, 52, 'smooth assertion weights with probability paws_sp / 1024'), - ('wp', UINT, 100, 'random walk with probability wp / 1024'), - ('vns_mc', UINT, 0, 'in local minima, try Monte Carlo sampling vns_mc many 2-bit-flips per bit'), - ('vns_repick', BOOL, 0, 'in local minima, try picking a different assertion (only for walksat)'), - ('restart_base', UINT, 100, 'base restart interval given by moves per run'), - ('restart_init', BOOL, 0, 'initialize to 0 or random value (= 1) after restart'), - ('early_prune', BOOL, 1, 'use early pruning for score prediction'), - ('random_offset', BOOL, 1, 'use random offset for candidate evaluation'), - ('rescore', BOOL, 1, 'rescore/normalize top-level score every base restart interval'), - ('track_unsat', BOOL, 0, 'keep a list of unsat assertions as done in SAT - currently disabled internally'), - ('random_seed', UINT, 0, 'random seed') - )) + ('max_restarts', UINT, UINT_MAX, 'maximum number of restarts'), + ('walksat', BOOL, 1, 'use walksat assertion selection (instead of gsat)'), + ('walksat_ucb', BOOL, 1, 'use bandit heuristic for walksat assertion selection (instead of random)'), + ('walksat_ucb_constant', DOUBLE, 20.0, 'the ucb constant c in the term score + c * f(touched)'), + ('walksat_ucb_init', BOOL, 0, 'initialize total ucb touched to formula size'), + ('walksat_ucb_forget', DOUBLE, 1.0, 'scale touched by this factor every base restart interval'), + ('walksat_ucb_noise', DOUBLE, 0.0002, 'add noise 0 <= 256 * ucb_noise to ucb score for assertion selection'), + ('walksat_repick', BOOL, 1, 'repick assertion if randomizing in local minima'), + ('scale_unsat', DOUBLE, 0.5, 'scale score of unsat expressions by this factor'), + ('paws_init', UINT, 40, 'initial/minimum assertion weights'), + ('paws_sp', UINT, 52, 'smooth assertion weights with probability paws_sp / 1024'), + ('wp', UINT, 100, 'random walk with probability wp / 1024'), + ('vns_mc', UINT, 0, 'in local minima, try Monte Carlo sampling vns_mc many 2-bit-flips per bit'), + ('vns_repick', BOOL, 0, 'in local minima, try picking a different assertion (only for walksat)'), + ('restart_base', UINT, 100, 'base restart interval given by moves per run'), + ('restart_init', BOOL, 0, 'initialize to 0 or random value (= 1) after restart'), + ('early_prune', BOOL, 1, 'use early pruning for score prediction'), + ('random_offset', BOOL, 1, 'use random offset for candidate evaluation'), + ('rescore', BOOL, 1, 'rescore/normalize top-level score every base restart interval'), + ('track_unsat', BOOL, 0, 'keep a list of unsat assertions as done in SAT - currently disabled internally'), + ('random_seed', UINT, 0, 'random seed') + )) diff --git a/src/tactic/sls/sls_powers.h b/src/tactic/sls/sls_powers.h index b632e7100..81e9540a0 100644 --- a/src/tactic/sls/sls_powers.h +++ b/src/tactic/sls/sls_powers.h @@ -20,7 +20,7 @@ Notes: #ifndef SLS_POWERS_H_ #define SLS_POWERS_H_ -#include"mpz.h" +#include "util/mpz.h" class powers : public u_map { unsynch_mpz_manager & m; diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index f4ef300e4..19937e8b0 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -16,19 +16,19 @@ Author: Notes: --*/ -#include"nnf.h" -#include"solve_eqs_tactic.h" -#include"bv_size_reduction_tactic.h" -#include"max_bv_sharing_tactic.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"ctx_simplify_tactic.h" -#include"elim_uncnstr_tactic.h" -#include"nnf_tactic.h" -#include"stopwatch.h" -#include"sls_tactic.h" -#include"sls_params.hpp" -#include"sls_engine.h" +#include "ast/normal_forms/nnf.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/bv/bv_size_reduction_tactic.h" +#include "tactic/bv/max_bv_sharing_tactic.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/core/ctx_simplify_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "tactic/core/nnf_tactic.h" +#include "util/stopwatch.h" +#include "tactic/sls/sls_tactic.h" +#include "tactic/sls/sls_params.hpp" +#include "tactic/sls/sls_engine.h" class sls_tactic : public tactic { ast_manager & m; diff --git a/src/tactic/sls/sls_tactic.h b/src/tactic/sls/sls_tactic.h index ba415d547..ab79bfc0f 100644 --- a/src/tactic/sls/sls_tactic.h +++ b/src/tactic/sls/sls_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef SLS_TACTIC_H_ #define SLS_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/sls/sls_tracker.h b/src/tactic/sls/sls_tracker.h index dfdbd4685..15f06f096 100644 --- a/src/tactic/sls/sls_tracker.h +++ b/src/tactic/sls/sls_tracker.h @@ -21,13 +21,13 @@ Notes: #define SLS_TRACKER_H_ #include -#include"for_each_expr.h" -#include"ast_smt2_pp.h" -#include"bv_decl_plugin.h" -#include"model.h" +#include "ast/for_each_expr.h" +#include "ast/ast_smt2_pp.h" +#include "ast/bv_decl_plugin.h" +#include "model/model.h" -#include"sls_params.hpp" -#include"sls_powers.h" +#include "tactic/sls/sls_params.hpp" +#include "tactic/sls/sls_powers.h" class sls_tracker { ast_manager & m_manager; @@ -41,7 +41,24 @@ class sls_tracker { struct value_score { value_score() : m(0), value(unsynch_mpz_manager::mk_z(0)), score(0.0), score_prune(0.0), has_pos_occ(0), has_neg_occ(0), distance(0), touched(1) {}; + value_score(value_score && other) : + m(other.m), + value(std::move(other.value)), + score(other.score), + score_prune(other.score_prune), + has_pos_occ(other.has_pos_occ), + has_neg_occ(other.has_neg_occ), + distance(other.distance), + touched(other.touched) {} ~value_score() { if (m) m->del(value); } + void operator=(value_score && other) { + this->~value_score(); + new (this) value_score(std::move(other)); + } + value_score& operator=(value_score& other) { + UNREACHABLE(); + return *this; + } unsynch_mpz_manager * m; mpz value; double score; @@ -50,15 +67,6 @@ class sls_tracker { unsigned has_neg_occ; unsigned distance; // max distance from any root unsigned touched; - value_score & operator=(const value_score & other) { - SASSERT(m == 0 || m == other.m); - if (m) m->set(value, 0); else m = other.m; - m->set(value, other.value); - score = other.score; - distance = other.distance; - touched = other.touched; - return *this; - } }; public: @@ -68,7 +76,7 @@ private: typedef obj_map scores_type; typedef obj_map > uplinks_type; typedef obj_map > occ_type; - obj_hashtable m_top_expr; + obj_hashtable m_top_expr; scores_type m_scores; uplinks_type m_uplinks; entry_point_type m_entry_points; @@ -85,11 +93,11 @@ private: unsigned m_touched; double m_scale_unsat; unsigned m_paws_init; - obj_map m_where_false; - expr** m_list_false; + obj_map m_where_false; + expr** m_list_false; unsigned m_track_unsat; obj_map m_weights; - double m_top_sum; + double m_top_sum; obj_hashtable m_temp_seen; public: @@ -294,7 +302,7 @@ public: if (!m_scores.contains(n)) { value_score vs; vs.m = & m_mpz_manager; - m_scores.insert(n, vs); + m_scores.insert(n, std::move(vs)); } // Update uplinks @@ -450,7 +458,7 @@ public: m_list_false = new expr*[sz]; for (unsigned i = 0; i < sz; i++) { - if (m_mpz_manager.eq(get_value(as[i]), m_zero)) + if (m_mpz_manager.eq(get_value(as[i]), m_zero)) break_assertion(as[i]); } } @@ -462,7 +470,7 @@ public: // initialize weights if (!m_weights.contains(e)) - m_weights.insert(e, m_paws_init); + m_weights.insert(e, m_paws_init); // positive/negative occurrences used for early pruning setup_occs(as[i]); @@ -539,7 +547,7 @@ public: rational r_val; unsigned bv_sz; m_bv_util.is_numeral(val, r_val, bv_sz); - mpq q = r_val.to_mpq(); + const mpq& q = r_val.to_mpq(); SASSERT(m_mpz_manager.is_one(q.denominator())); set_value(fd, q.numerator()); } @@ -630,7 +638,7 @@ public: if (m_bv_util.is_bv_sort(s)) return get_random_bv(s); else if (m_manager.is_bool(s)) - return get_random_bool(); + return m_mpz_manager.dup(get_random_bool()); else NOT_IMPLEMENTED_YET(); // This only works for bit-vectors for now. } @@ -653,9 +661,7 @@ public: TRACE("sls", tout << "Abandoned model:" << std::endl; show_model(tout); ); for (entry_point_type::iterator it = m_entry_points.begin(); it != m_entry_points.end(); it++) { - mpz temp = m_zero; - set_value(it->m_value, temp); - m_mpz_manager.del(temp); + set_value(it->m_value, m_zero); } } @@ -931,7 +937,7 @@ public: rational q; if (!m_bv_util.is_numeral(n, q, bv_sz)) NOT_IMPLEMENTED_YET(); - mpq temp = q.to_mpq(); + const mpq& temp = q.to_mpq(); SASSERT(m_mpz_manager.is_one(temp.denominator())); m_mpz_manager.set(result, temp.numerator()); } @@ -1039,7 +1045,6 @@ public: unsigned pos = -1; if (m_ucb) { - value_score vscore; double max = -1.0; // Andreas: Commented things here might be used for track_unsat data structures as done in SLS for SAT. But seems to have no benefit. /* for (unsigned i = 0; i < m_where_false.size(); i++) { @@ -1048,7 +1053,7 @@ public: expr * e = as[i]; if (m_mpz_manager.neq(get_value(e), m_one)) { - vscore = m_scores.find(e); + value_score & vscore = m_scores.find(e); // Andreas: Select the assertion with the greatest ucb score. Potentially add some noise. // double q = vscore.score + m_ucb_constant * sqrt(log((double)m_touched) / vscore.touched); double q = vscore.score + m_ucb_constant * sqrt(log((double)m_touched) / vscore.touched) + m_ucb_noise * get_random_uint(8); @@ -1075,7 +1080,7 @@ public: unsigned cnt_unsat = 0; for (unsigned i = 0; i < sz; i++) - if (m_mpz_manager.neq(get_value(as[i]), m_one) && (get_random_uint(16) % ++cnt_unsat == 0)) pos = i; + if (m_mpz_manager.neq(get_value(as[i]), m_one) && (get_random_uint(16) % ++cnt_unsat == 0)) pos = i; if (pos == static_cast(-1)) return 0; } @@ -1092,7 +1097,7 @@ public: unsigned cnt_unsat = 0, pos = -1; for (unsigned i = 0; i < sz; i++) - if ((i != m_last_pos) && m_mpz_manager.neq(get_value(as[i]), m_one) && (get_random_uint(16) % ++cnt_unsat == 0)) pos = i; + if ((i != m_last_pos) && m_mpz_manager.neq(get_value(as[i]), m_one) && (get_random_uint(16) % ++cnt_unsat == 0)) pos = i; if (pos == static_cast(-1)) return 0; diff --git a/src/tactic/smtlogics/nra_tactic.cpp b/src/tactic/smtlogics/nra_tactic.cpp index 063e0775a..381bc4bb6 100644 --- a/src/tactic/smtlogics/nra_tactic.cpp +++ b/src/tactic/smtlogics/nra_tactic.cpp @@ -16,16 +16,16 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"smt_tactic.h" -#include"nnf_tactic.h" -#include"qe_tactic.h" -#include"nlqsat.h" -#include"qfnra_nlsat_tactic.h" -#include"qe_lite.h" -#include"probe_arith.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "smt/tactic/smt_tactic.h" +#include "tactic/core/nnf_tactic.h" +#include "qe/qe_tactic.h" +#include "qe/nlqsat.h" +#include "nlsat/tactic/qfnra_nlsat_tactic.h" +#include "qe/qe_lite.h" +#include "tactic/arith/probe_arith.h" tactic * mk_nra_tactic(ast_manager & m, params_ref const& p) { params_ref p1 = p; diff --git a/src/tactic/smtlogics/qfaufbv_tactic.cpp b/src/tactic/smtlogics/qfaufbv_tactic.cpp index cb14fa778..601f872aa 100644 --- a/src/tactic/smtlogics/qfaufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfaufbv_tactic.cpp @@ -16,16 +16,16 @@ Author: Notes: --*/ -#include"solve_eqs_tactic.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"bit_blaster_tactic.h" -#include"elim_uncnstr_tactic.h" -#include"max_bv_sharing_tactic.h" -#include"bv_size_reduction_tactic.h" -#include"ctx_simplify_tactic.h" -#include"sat_tactic.h" -#include"smt_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/bv/bit_blaster_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "tactic/bv/max_bv_sharing_tactic.h" +#include "tactic/bv/bv_size_reduction_tactic.h" +#include "tactic/core/ctx_simplify_tactic.h" +#include "sat/tactic/sat_tactic.h" +#include "smt/tactic/smt_tactic.h" tactic * mk_qfaufbv_tactic(ast_manager & m, params_ref const & p) { params_ref main_p; diff --git a/src/tactic/smtlogics/qfaufbv_tactic.h b/src/tactic/smtlogics/qfaufbv_tactic.h index 1e4a7419f..06b046bd3 100644 --- a/src/tactic/smtlogics/qfaufbv_tactic.h +++ b/src/tactic/smtlogics/qfaufbv_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef QFAUFBV_TACTIC_H_ #define QFAUFBV_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/smtlogics/qfauflia_tactic.cpp b/src/tactic/smtlogics/qfauflia_tactic.cpp index 89f96d354..4a0e9eb34 100644 --- a/src/tactic/smtlogics/qfauflia_tactic.cpp +++ b/src/tactic/smtlogics/qfauflia_tactic.cpp @@ -16,13 +16,13 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"propagate_ineqs_tactic.h" -#include"solve_eqs_tactic.h" -#include"elim_uncnstr_tactic.h" -#include"smt_tactic.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/arith/propagate_ineqs_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "smt/tactic/smt_tactic.h" tactic * mk_qfauflia_tactic(ast_manager & m, params_ref const & p) { params_ref main_p; diff --git a/src/tactic/smtlogics/qfauflia_tactic.h b/src/tactic/smtlogics/qfauflia_tactic.h index fbf19fec0..f1b3c74e0 100644 --- a/src/tactic/smtlogics/qfauflia_tactic.h +++ b/src/tactic/smtlogics/qfauflia_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef QFAUFLIA_TACTIC_H_ #define QFAUFLIA_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index ca6390c9c..b69069864 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -16,19 +16,19 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"solve_eqs_tactic.h" -#include"elim_uncnstr_tactic.h" -#include"smt_tactic.h" -#include"bit_blaster_tactic.h" -#include"bv1_blaster_tactic.h" -#include"max_bv_sharing_tactic.h" -#include"bv_size_reduction_tactic.h" -#include"aig_tactic.h" -#include"sat_tactic.h" -#include"ackermannize_bv_tactic.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "smt/tactic/smt_tactic.h" +#include "tactic/bv/bit_blaster_tactic.h" +#include "tactic/bv/bv1_blaster_tactic.h" +#include "tactic/bv/max_bv_sharing_tactic.h" +#include "tactic/bv/bv_size_reduction_tactic.h" +#include "tactic/aig/aig_tactic.h" +#include "sat/tactic/sat_tactic.h" +#include "ackermannization/ackermannize_bv_tactic.h" #define MEMLIMIT 300 diff --git a/src/tactic/smtlogics/qfbv_tactic.h b/src/tactic/smtlogics/qfbv_tactic.h index 4de623e0f..52f07f2a6 100644 --- a/src/tactic/smtlogics/qfbv_tactic.h +++ b/src/tactic/smtlogics/qfbv_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef QFBV_TACTIC_H_ #define QFBV_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/smtlogics/qfidl_tactic.cpp b/src/tactic/smtlogics/qfidl_tactic.cpp index de05797e8..a34a25e67 100644 --- a/src/tactic/smtlogics/qfidl_tactic.cpp +++ b/src/tactic/smtlogics/qfidl_tactic.cpp @@ -16,22 +16,22 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"propagate_ineqs_tactic.h" -#include"solve_eqs_tactic.h" -#include"elim_uncnstr_tactic.h" -#include"normalize_bounds_tactic.h" -#include"fix_dl_var_tactic.h" -#include"smt_tactic.h" -#include"lia2pb_tactic.h" -#include"pb2bv_tactic.h" -#include"diff_neq_tactic.h" -#include"bit_blaster_tactic.h" -#include"max_bv_sharing_tactic.h" -#include"aig_tactic.h" -#include"sat_tactic.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/arith/propagate_ineqs_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "tactic/arith/normalize_bounds_tactic.h" +#include "tactic/arith/fix_dl_var_tactic.h" +#include "smt/tactic/smt_tactic.h" +#include "tactic/arith/lia2pb_tactic.h" +#include "tactic/arith/pb2bv_tactic.h" +#include "tactic/arith/diff_neq_tactic.h" +#include "tactic/bv/bit_blaster_tactic.h" +#include "tactic/bv/max_bv_sharing_tactic.h" +#include "tactic/aig/aig_tactic.h" +#include "sat/tactic/sat_tactic.h" #define BIG_PROBLEM 5000 diff --git a/src/tactic/smtlogics/qfidl_tactic.h b/src/tactic/smtlogics/qfidl_tactic.h index f892bb8a5..c36b857d4 100644 --- a/src/tactic/smtlogics/qfidl_tactic.h +++ b/src/tactic/smtlogics/qfidl_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef QFIDL_TACTIC_H_ #define QFIDL_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index fd10d8ecb..248829c49 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -16,25 +16,25 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"propagate_ineqs_tactic.h" -#include"normalize_bounds_tactic.h" -#include"solve_eqs_tactic.h" -#include"elim_uncnstr_tactic.h" -#include"smt_tactic.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/arith/propagate_ineqs_tactic.h" +#include "tactic/arith/normalize_bounds_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "smt/tactic/smt_tactic.h" // include"mip_tactic.h" -#include"add_bounds_tactic.h" -#include"pb2bv_tactic.h" -#include"lia2pb_tactic.h" -#include"ctx_simplify_tactic.h" -#include"bit_blaster_tactic.h" -#include"max_bv_sharing_tactic.h" -#include"aig_tactic.h" -#include"sat_tactic.h" -#include"bound_manager.h" -#include"probe_arith.h" +#include "tactic/arith/add_bounds_tactic.h" +#include "tactic/arith/pb2bv_tactic.h" +#include "tactic/arith/lia2pb_tactic.h" +#include "tactic/core/ctx_simplify_tactic.h" +#include "tactic/bv/bit_blaster_tactic.h" +#include "tactic/bv/max_bv_sharing_tactic.h" +#include "tactic/aig/aig_tactic.h" +#include "sat/tactic/sat_tactic.h" +#include "tactic/arith/bound_manager.h" +#include "tactic/arith/probe_arith.h" struct quasi_pb_probe : public probe { virtual result operator()(goal const & g) { diff --git a/src/tactic/smtlogics/qflia_tactic.h b/src/tactic/smtlogics/qflia_tactic.h index 36e7cf9f9..ee9b859ae 100644 --- a/src/tactic/smtlogics/qflia_tactic.h +++ b/src/tactic/smtlogics/qflia_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef QFLIA_TACTIC_H_ #define QFLIA_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/smtlogics/qflra_tactic.cpp b/src/tactic/smtlogics/qflra_tactic.cpp index 0865f3b47..b44ace7b1 100644 --- a/src/tactic/smtlogics/qflra_tactic.cpp +++ b/src/tactic/smtlogics/qflra_tactic.cpp @@ -16,15 +16,15 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"solve_eqs_tactic.h" -#include"elim_uncnstr_tactic.h" -#include"smt_tactic.h" -#include"recover_01_tactic.h" -#include"ctx_simplify_tactic.h" -#include"probe_arith.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "smt/tactic/smt_tactic.h" +#include "tactic/arith/recover_01_tactic.h" +#include "tactic/core/ctx_simplify_tactic.h" +#include "tactic/arith/probe_arith.h" tactic * mk_qflra_tactic(ast_manager & m, params_ref const & p) { params_ref pivot_p; diff --git a/src/tactic/smtlogics/qflra_tactic.h b/src/tactic/smtlogics/qflra_tactic.h index f8b311aba..42829e390 100644 --- a/src/tactic/smtlogics/qflra_tactic.h +++ b/src/tactic/smtlogics/qflra_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef QFLRA_TACTIC_H_ #define QFLRA_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 5a71281fb..3fb733ca4 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -16,18 +16,18 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"solve_eqs_tactic.h" -#include"elim_uncnstr_tactic.h" -#include"smt_tactic.h" -#include"bit_blaster_tactic.h" -#include"max_bv_sharing_tactic.h" -#include"sat_tactic.h" -#include"nla2bv_tactic.h" -#include"ctx_simplify_tactic.h" -#include"cofactor_term_ite_tactic.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "smt/tactic/smt_tactic.h" +#include "tactic/bv/bit_blaster_tactic.h" +#include "tactic/bv/max_bv_sharing_tactic.h" +#include "sat/tactic/sat_tactic.h" +#include "tactic/arith/nla2bv_tactic.h" +#include "tactic/core/ctx_simplify_tactic.h" +#include "tactic/core/cofactor_term_ite_tactic.h" static tactic * mk_qfnia_bv_solver(ast_manager & m, params_ref const & p_ref) { params_ref p = p_ref; diff --git a/src/tactic/smtlogics/qfnia_tactic.h b/src/tactic/smtlogics/qfnia_tactic.h index 0770b4eee..84a35e6ec 100644 --- a/src/tactic/smtlogics/qfnia_tactic.h +++ b/src/tactic/smtlogics/qfnia_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef QFNIA_TACTIC_H_ #define QFNIA_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/smtlogics/qfnra_tactic.cpp b/src/tactic/smtlogics/qfnra_tactic.cpp index 716b4868b..63c09c19c 100644 --- a/src/tactic/smtlogics/qfnra_tactic.cpp +++ b/src/tactic/smtlogics/qfnra_tactic.cpp @@ -16,12 +16,12 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"nla2bv_tactic.h" -#include"smt_tactic.h" -#include"qfnra_nlsat_tactic.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/arith/nla2bv_tactic.h" +#include "smt/tactic/smt_tactic.h" +#include "nlsat/tactic/qfnra_nlsat_tactic.h" static tactic * mk_qfnra_sat_solver(ast_manager& m, params_ref const& p, unsigned bv_size) { params_ref nra2sat_p = p; diff --git a/src/tactic/smtlogics/qfnra_tactic.h b/src/tactic/smtlogics/qfnra_tactic.h index cae314553..34381d47a 100644 --- a/src/tactic/smtlogics/qfnra_tactic.h +++ b/src/tactic/smtlogics/qfnra_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef QFNRA_TACTIC_H_ #define QFNRA_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/smtlogics/qfuf_tactic.cpp b/src/tactic/smtlogics/qfuf_tactic.cpp index 7648e20fe..2de9612c6 100644 --- a/src/tactic/smtlogics/qfuf_tactic.cpp +++ b/src/tactic/smtlogics/qfuf_tactic.cpp @@ -17,12 +17,12 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"symmetry_reduce_tactic.h" -#include"solve_eqs_tactic.h" -#include"propagate_values_tactic.h" -#include"smt_tactic.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/symmetry_reduce_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "smt/tactic/smt_tactic.h" tactic * mk_qfuf_tactic(ast_manager & m, params_ref const & p) { params_ref s2_p; diff --git a/src/tactic/smtlogics/qfuf_tactic.h b/src/tactic/smtlogics/qfuf_tactic.h index 0c81ad57b..98ddd3422 100644 --- a/src/tactic/smtlogics/qfuf_tactic.h +++ b/src/tactic/smtlogics/qfuf_tactic.h @@ -20,7 +20,7 @@ Notes: #ifndef QFUF_TACTIC_H_ #define QFUF_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/smtlogics/qfufbv_ackr_model_converter.cpp b/src/tactic/smtlogics/qfufbv_ackr_model_converter.cpp index 4d20631b1..50c9b6a46 100644 --- a/src/tactic/smtlogics/qfufbv_ackr_model_converter.cpp +++ b/src/tactic/smtlogics/qfufbv_ackr_model_converter.cpp @@ -14,8 +14,8 @@ Revision History: --*/ -#include"qfufbv_ackr_model_converter.h" -#include"ackr_model_converter.h" +#include "tactic/smtlogics/qfufbv_ackr_model_converter.h" +#include "ackermannization/ackr_model_converter.h" model_converter * mk_qfufbv_ackr_model_converter(ast_manager & m, const ackr_info_ref& info, model_ref& abstr_model) { return mk_ackr_model_converter(m, info, abstr_model); diff --git a/src/tactic/smtlogics/qfufbv_ackr_model_converter.h b/src/tactic/smtlogics/qfufbv_ackr_model_converter.h index a361a78e0..efc039560 100644 --- a/src/tactic/smtlogics/qfufbv_ackr_model_converter.h +++ b/src/tactic/smtlogics/qfufbv_ackr_model_converter.h @@ -17,8 +17,8 @@ #ifndef QFUFBV_ACKR_MODEL_CONVERTER_H_ #define QFUFBV_ACKR_MODEL_CONVERTER_H_ -#include"model_converter.h" -#include"ackr_info.h" +#include "tactic/model_converter.h" +#include "ackermannization/ackr_info.h" model_converter * mk_qfufbv_ackr_model_converter(ast_manager & m, const ackr_info_ref& info, model_ref& abstr_model); diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index e0e1a60e4..e89da3631 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -17,29 +17,29 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"solve_eqs_tactic.h" -#include"elim_uncnstr_tactic.h" -#include"smt_tactic.h" -#include"max_bv_sharing_tactic.h" -#include"bv_size_reduction_tactic.h" -#include"reduce_args_tactic.h" -#include"qfbv_tactic.h" -#include"qfufbv_tactic_params.hpp" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "smt/tactic/smt_tactic.h" +#include "tactic/bv/max_bv_sharing_tactic.h" +#include "tactic/bv/bv_size_reduction_tactic.h" +#include "tactic/core/reduce_args_tactic.h" +#include "tactic/smtlogics/qfbv_tactic.h" +#include "tactic/smtlogics/qfufbv_tactic_params.hpp" /////////////// -#include"model_smt2_pp.h" -#include"cooperate.h" -#include"lackr.h" -#include"ackermannization_params.hpp" -#include"qfufbv_ackr_model_converter.h" +#include "model/model_smt2_pp.h" +#include "util/cooperate.h" +#include "ackermannization/lackr.h" +#include "ackermannization/ackermannization_params.hpp" +#include "tactic/smtlogics/qfufbv_ackr_model_converter.h" /////////////// -#include"inc_sat_solver.h" -#include"qfaufbv_tactic.h" -#include"qfbv_tactic.h" -#include"tactic2solver.h" -#include"bv_bound_chk_tactic.h" +#include "sat/sat_solver/inc_sat_solver.h" +#include "tactic/smtlogics/qfaufbv_tactic.h" +#include "tactic/smtlogics/qfbv_tactic.h" +#include "solver/tactic2solver.h" +#include "tactic/bv/bv_bound_chk_tactic.h" /////////////// class qfufbv_ackr_tactic : public tactic { diff --git a/src/tactic/smtlogics/qfufbv_tactic.h b/src/tactic/smtlogics/qfufbv_tactic.h index 1f1431d70..3e6d9d817 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.h +++ b/src/tactic/smtlogics/qfufbv_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef QFUFBV_TACTIC_H_ #define QFUFBV_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/smtlogics/qfufnra_tactic.cpp b/src/tactic/smtlogics/qfufnra_tactic.cpp index 4ca241e19..e031b0f52 100644 --- a/src/tactic/smtlogics/qfufnra_tactic.cpp +++ b/src/tactic/smtlogics/qfufnra_tactic.cpp @@ -16,18 +16,18 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"nl_purify_tactic.h" -#include"qfufnra_tactic.h" -#include"purify_arith_tactic.h" -#include"solve_eqs_tactic.h" -#include"elim_term_ite_tactic.h" -#include"elim_uncnstr_tactic.h" -#include"simplify_tactic.h" -#include"nnf_tactic.h" -#include"tseitin_cnf_tactic.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/nlsat_smt/nl_purify_tactic.h" +#include "tactic/smtlogics/qfufnra_tactic.h" +#include "tactic/arith/purify_arith_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/elim_term_ite_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/nnf_tactic.h" +#include "tactic/core/tseitin_cnf_tactic.h" tactic * mk_qfufnra_tactic(ast_manager & m, params_ref const& p) { params_ref main_p = p; diff --git a/src/tactic/smtlogics/qfufnra_tactic.h b/src/tactic/smtlogics/qfufnra_tactic.h index 4cc2b372d..026ab5c5c 100644 --- a/src/tactic/smtlogics/qfufnra_tactic.h +++ b/src/tactic/smtlogics/qfufnra_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef QFUFNRA_TACTIC_H_ #define QFUFNRA_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index 7d428b369..400089a0c 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -16,19 +16,19 @@ Author: Revision History: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"solve_eqs_tactic.h" -#include"elim_uncnstr_tactic.h" -#include"qe_tactic.h" -#include"qe_lite.h" -#include"qsat.h" -#include"nlqsat.h" -#include"ctx_simplify_tactic.h" -#include"smt_tactic.h" -#include"elim_term_ite_tactic.h" -#include"probe_arith.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/elim_uncnstr_tactic.h" +#include "qe/qe_tactic.h" +#include "qe/qe_lite.h" +#include "qe/qsat.h" +#include "qe/nlqsat.h" +#include "tactic/core/ctx_simplify_tactic.h" +#include "smt/tactic/smt_tactic.h" +#include "tactic/core/elim_term_ite_tactic.h" +#include "tactic/arith/probe_arith.h" static tactic * mk_quant_preprocessor(ast_manager & m, bool disable_gaussian = false) { params_ref pull_ite_p; diff --git a/src/tactic/smtlogics/quant_tactics.h b/src/tactic/smtlogics/quant_tactics.h index b78730236..da3594500 100644 --- a/src/tactic/smtlogics/quant_tactics.h +++ b/src/tactic/smtlogics/quant_tactics.h @@ -19,7 +19,7 @@ Revision History: #ifndef QUANT_TACTICS_H_ #define QUANT_TACTICS_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index ac63a2d24..6c4ca7476 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -17,10 +17,10 @@ Notes: --*/ #include -#include"tactic.h" -#include"probe.h" -#include"stopwatch.h" -#include"model_v2_pp.h" +#include "tactic/tactic.h" +#include "tactic/probe.h" +#include "util/stopwatch.h" +#include "model/model_v2_pp.h" struct tactic_report::imp { diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index 645b53681..0e4c61611 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -21,13 +21,13 @@ Notes: #ifndef TACTIC_H_ #define TACTIC_H_ -#include"goal.h" -#include"params.h" -#include"statistics.h" -#include"model_converter.h" -#include"proof_converter.h" -#include"tactic_exception.h" -#include"lbool.h" +#include "tactic/goal.h" +#include "util/params.h" +#include "util/statistics.h" +#include "tactic/model_converter.h" +#include "tactic/proof_converter.h" +#include "tactic/tactic_exception.h" +#include "util/lbool.h" class progress_callback; diff --git a/src/tactic/tactic_exception.h b/src/tactic/tactic_exception.h index 6dbd39ff9..e989ed2bf 100644 --- a/src/tactic/tactic_exception.h +++ b/src/tactic/tactic_exception.h @@ -19,8 +19,8 @@ Notes: #ifndef TACTIC_EXCEPTION_H_ #define TACTIC_EXCEPTION_H_ -#include"z3_exception.h" -#include"common_msgs.h" +#include "util/z3_exception.h" +#include "util/common_msgs.h" class tactic_exception : public z3_exception { protected: diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 33f8325fb..c5a70c0db 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -16,12 +16,12 @@ Author: Notes: --*/ -#include"tactical.h" -#include"scoped_timer.h" -#include"cancel_eh.h" -#include"cooperate.h" -#include"scoped_ptr_vector.h" -#include"z3_omp.h" +#include "tactic/tactical.h" +#include "util/scoped_timer.h" +#include "util/cancel_eh.h" +#include "util/cooperate.h" +#include "util/scoped_ptr_vector.h" +#include "util/z3_omp.h" class binary_tactical : public tactic { protected: diff --git a/src/tactic/tactical.h b/src/tactic/tactical.h index 4b4274b0c..169566f39 100644 --- a/src/tactic/tactical.h +++ b/src/tactic/tactical.h @@ -19,8 +19,8 @@ Notes: #ifndef TACTICAL_H_ #define TACTICAL_H_ -#include"tactic.h" -#include"probe.h" +#include "tactic/tactic.h" +#include "tactic/probe.h" tactic * and_then(unsigned num, tactic * const * ts); tactic * and_then(tactic * t1, tactic * t2); diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index e31682cd0..3a482f37c 100644 --- a/src/tactic/ufbv/macro_finder_tactic.cpp +++ b/src/tactic/ufbv/macro_finder_tactic.cpp @@ -16,70 +16,58 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplifier.h" -#include"basic_simplifier_plugin.h" -#include"arith_simplifier_plugin.h" -#include"bv_simplifier_plugin.h" -#include"macro_manager.h" -#include"macro_finder.h" -#include"extension_model_converter.h" -#include"macro_finder_tactic.h" +#include "tactic/tactical.h" +#include "ast/macros/macro_manager.h" +#include "ast/macros/macro_finder.h" +#include "tactic/extension_model_converter.h" +#include "tactic/ufbv/macro_finder_tactic.h" -class macro_finder_tactic : public tactic { +class macro_finder_tactic : public tactic { struct imp { ast_manager & m_manager; bool m_elim_and; - imp(ast_manager & m, params_ref const & p) : + imp(ast_manager & m, params_ref const & p) : m_manager(m), m_elim_and(false) { updt_params(p); } - + ast_manager & m() const { return m_manager; } - - - void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, + + + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; tactic_report report("macro-finder", *g); - fail_if_unsat_core_generation("macro-finder", g); bool produce_proofs = g->proofs_enabled(); - - simplifier simp(m_manager); - basic_simplifier_plugin * bsimp = alloc(basic_simplifier_plugin, m_manager); - bsimp->set_eliminate_and(m_elim_and); - simp.register_plugin(bsimp); - arith_simplifier_params a_params; - arith_simplifier_plugin * asimp = alloc(arith_simplifier_plugin, m_manager, *bsimp, a_params); - simp.register_plugin(asimp); - bv_simplifier_params bv_params; - bv_simplifier_plugin * bvsimp = alloc(bv_simplifier_plugin, m_manager, *bsimp, bv_params); - simp.register_plugin(bvsimp); - - macro_manager mm(m_manager, simp); + bool unsat_core_enabled = g->unsat_core_enabled(); + macro_manager mm(m_manager); macro_finder mf(m_manager, mm); - + expr_ref_vector forms(m_manager), new_forms(m_manager); - proof_ref_vector proofs(m_manager), new_proofs(m_manager); - unsigned size = g->size(); + proof_ref_vector proofs(m_manager), new_proofs(m_manager); + expr_dependency_ref_vector deps(m_manager), new_deps(m_manager); + unsigned size = g->size(); for (unsigned idx = 0; idx < size; idx++) { forms.push_back(g->form(idx)); - proofs.push_back(g->pr(idx)); + proofs.push_back(g->pr(idx)); + deps.push_back(g->dep(idx)); } - mf(forms.size(), forms.c_ptr(), proofs.c_ptr(), new_forms, new_proofs); - + mf(forms.size(), forms.c_ptr(), proofs.c_ptr(), deps.c_ptr(), new_forms, new_proofs, new_deps); + g->reset(); for (unsigned i = 0; i < new_forms.size(); i++) - g->assert_expr(new_forms.get(i), produce_proofs ? new_proofs.get(i) : 0, 0); + g->assert_expr(new_forms.get(i), + produce_proofs ? new_proofs.get(i) : 0, + unsat_core_enabled ? new_deps.get(i) : 0); extension_model_converter * evmc = alloc(extension_model_converter, mm.get_manager()); unsigned num = mm.get_num_macros(); @@ -89,7 +77,7 @@ class macro_finder_tactic : public tactic { evmc->insert(f, f_interp); } mc = evmc; - + g->inc_depth(); result.push_back(g.get()); TRACE("macro-finder", g->display(tout);); @@ -102,7 +90,7 @@ class macro_finder_tactic : public tactic { }; imp * m_imp; - params_ref m_params; + params_ref m_params; public: macro_finder_tactic(ast_manager & m, params_ref const & p): m_params(p) { @@ -112,7 +100,7 @@ public: virtual tactic * translate(ast_manager & m) { return alloc(macro_finder_tactic, m, m_params); } - + virtual ~macro_finder_tactic() { dealloc(m_imp); } @@ -128,19 +116,19 @@ public: insert_produce_proofs(r); r.insert("elim_and", CPK_BOOL, "(default: false) eliminate conjunctions during (internal) calls to the simplifier."); } - - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, + + virtual void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { (*m_imp)(in, result, mc, pc, core); } - + virtual void cleanup() { ast_manager & m = m_imp->m(); imp * d = alloc(imp, m, m_params); - std::swap(d, m_imp); + std::swap(d, m_imp); dealloc(d); } diff --git a/src/tactic/ufbv/macro_finder_tactic.h b/src/tactic/ufbv/macro_finder_tactic.h index d763d4567..659748dec 100644 --- a/src/tactic/ufbv/macro_finder_tactic.h +++ b/src/tactic/ufbv/macro_finder_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef MACRO_FINDER_TACTIC_H_ #define MACRO_FINDER_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index d1320bc0d..925b5a5e3 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -16,16 +16,12 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplifier.h" -#include"basic_simplifier_plugin.h" -#include"arith_simplifier_plugin.h" -#include"bv_simplifier_plugin.h" -#include"macro_manager.h" -#include"macro_finder.h" -#include"extension_model_converter.h" -#include"quasi_macros.h" -#include"quasi_macros_tactic.h" +#include "tactic/tactical.h" +#include "ast/macros/macro_manager.h" +#include "ast/macros/macro_finder.h" +#include "tactic/extension_model_converter.h" +#include "ast/macros/quasi_macros.h" +#include "tactic/ufbv/quasi_macros_tactic.h" class quasi_macros_tactic : public tactic { @@ -35,60 +31,55 @@ class quasi_macros_tactic : public tactic { imp(ast_manager & m, params_ref const & p) : m_manager(m) { updt_params(p); } - + ast_manager & m() const { return m_manager; } - - - void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, + + + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; tactic_report report("quasi-macros", *g); - fail_if_unsat_core_generation("quasi-macros", g); bool produce_proofs = g->proofs_enabled(); - - simplifier simp(m_manager); - basic_simplifier_plugin * bsimp = alloc(basic_simplifier_plugin, m_manager); - bsimp->set_eliminate_and(true); - simp.register_plugin(bsimp); - arith_simplifier_params a_params; - arith_simplifier_plugin * asimp = alloc(arith_simplifier_plugin, m_manager, *bsimp, a_params); - simp.register_plugin(asimp); - bv_simplifier_params bv_params; - bv_simplifier_plugin * bvsimp = alloc(bv_simplifier_plugin, m_manager, *bsimp, bv_params); - simp.register_plugin(bvsimp); - - macro_manager mm(m_manager, simp); - quasi_macros qm(m_manager, mm, simp); + bool produce_unsat_cores = g->unsat_core_enabled(); + + macro_manager mm(m_manager); + quasi_macros qm(m_manager, mm); bool more = true; - + expr_ref_vector forms(m_manager), new_forms(m_manager); proof_ref_vector proofs(m_manager), new_proofs(m_manager); + expr_dependency_ref_vector deps(m_manager), new_deps(m_manager); unsigned size = g->size(); for (unsigned i = 0; i < size; i++) { forms.push_back(g->form(i)); proofs.push_back(g->pr(i)); + deps.push_back(g->dep(i)); } - + while (more) { // CMW: use repeat(...) ? if (m().canceled()) throw tactic_exception(m().limit().get_cancel_msg()); - + new_forms.reset(); new_proofs.reset(); - more = qm(forms.size(), forms.c_ptr(), proofs.c_ptr(), new_forms, new_proofs); + new_deps.reset(); + more = qm(forms.size(), forms.c_ptr(), proofs.c_ptr(), deps.c_ptr(), new_forms, new_proofs, new_deps); forms.swap(new_forms); - proofs.swap(new_proofs); + proofs.swap(new_proofs); + deps.swap(new_deps); } g->reset(); for (unsigned i = 0; i < new_forms.size(); i++) - g->assert_expr(new_forms.get(i), produce_proofs ? new_proofs.get(i) : 0, 0); + g->assert_expr(forms.get(i), + produce_proofs ? proofs.get(i) : 0, + produce_unsat_cores ? deps.get(i) : 0); extension_model_converter * evmc = alloc(extension_model_converter, mm.get_manager()); unsigned num = mm.get_num_macros(); @@ -108,7 +99,7 @@ class quasi_macros_tactic : public tactic { void updt_params(params_ref const & p) { } }; - + imp * m_imp; params_ref m_params; @@ -121,7 +112,7 @@ public: virtual tactic * translate(ast_manager & m) { return alloc(quasi_macros_tactic, m, m_params); } - + virtual ~quasi_macros_tactic() { dealloc(m_imp); } @@ -136,19 +127,19 @@ public: insert_produce_models(r); insert_produce_proofs(r); } - - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, + + virtual void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { (*m_imp)(in, result, mc, pc, core); } - + virtual void cleanup() { ast_manager & m = m_imp->m(); imp * d = alloc(imp, m, m_params); - std::swap(d, m_imp); + std::swap(d, m_imp); dealloc(d); } diff --git a/src/tactic/ufbv/quasi_macros_tactic.h b/src/tactic/ufbv/quasi_macros_tactic.h index 2dff246a1..55fc5fcfb 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.h +++ b/src/tactic/ufbv/quasi_macros_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef QUASI_MACROS_TACTIC_H_ #define QUASI_MACROS_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/ufbv/ufbv_rewriter.cpp b/src/tactic/ufbv/ufbv_rewriter.cpp index f5f18d234..446d1a49c 100644 --- a/src/tactic/ufbv/ufbv_rewriter.cpp +++ b/src/tactic/ufbv/ufbv_rewriter.cpp @@ -20,20 +20,23 @@ Revision History: --*/ -#include"ast_pp.h" -#include"ufbv_rewriter.h" -#include"for_each_expr.h" -#include"var_subst.h" -#include"uint_set.h" +#include "util/uint_set.h" +#include "ast/ast_pp.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/var_subst.h" +#include "tactic/ufbv/ufbv_rewriter.h" -ufbv_rewriter::ufbv_rewriter(ast_manager & m, basic_simplifier_plugin & p): +ufbv_rewriter::ufbv_rewriter(ast_manager & m): m_manager(m), m_match_subst(m), - m_bsimp(p), + m_bsimp(m), m_todo(m), m_rewrite_todo(m), m_rewrite_cache(m), m_new_exprs(m) { + params_ref p; + p.set_bool("elim_and", true); + m_bsimp.updt_params(p); } ufbv_rewriter::~ufbv_rewriter() { @@ -396,7 +399,7 @@ expr * ufbv_rewriter::rewrite(expr * n) { if (f->get_family_id() != m_manager.get_basic_family_id()) na = m_manager.mk_app(f, m_new_args.size(), m_new_args.c_ptr()); else - m_bsimp.reduce(f, m_new_args.size(), m_new_args.c_ptr(), na); + m_bsimp.mk_app(f, m_new_args.size(), m_new_args.c_ptr(), na); TRACE("demodulator_bug", tout << "e:\n" << mk_pp(e, m_manager) << "\nnew_args: \n"; for (unsigned i = 0; i < m_new_args.size(); i++) { tout << mk_pp(m_new_args[i], m_manager) << "\n"; } tout << "=====>\n"; diff --git a/src/tactic/ufbv/ufbv_rewriter.h b/src/tactic/ufbv/ufbv_rewriter.h index 13234799e..1e13f4fa4 100644 --- a/src/tactic/ufbv/ufbv_rewriter.h +++ b/src/tactic/ufbv/ufbv_rewriter.h @@ -21,12 +21,12 @@ Revision History: #ifndef UFBV_REWRITER_H_ #define UFBV_REWRITER_H_ -#include"ast.h" -#include"substitution.h" -#include"obj_hashtable.h" -#include"obj_pair_hashtable.h" -#include"array_map.h" -#include"basic_simplifier_plugin.h" +#include "ast/ast.h" +#include "ast/substitution/substitution.h" +#include "ast/rewriter/bool_rewriter.h" +#include "util/obj_hashtable.h" +#include "util/obj_pair_hashtable.h" +#include "util/array_map.h" /** \brief Apply demodulators as a preprocessing technique. @@ -159,7 +159,7 @@ class ufbv_rewriter { ast_manager & m_manager; match_subst m_match_subst; - basic_simplifier_plugin & m_bsimp; + bool_rewriter m_bsimp; fwd_idx_map m_fwd_idx; back_idx_map m_back_idx; demodulator2lhs_rhs m_demodulator2lhs_rhs; @@ -194,7 +194,7 @@ protected: virtual int is_subset(expr * e1, expr * e2) const; public: - ufbv_rewriter(ast_manager & m, basic_simplifier_plugin & p); + ufbv_rewriter(ast_manager & m); virtual ~ufbv_rewriter(); void operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp index 37ad9c73c..615593317 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp @@ -16,11 +16,9 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplifier.h" -#include"basic_simplifier_plugin.h" -#include"ufbv_rewriter.h" -#include"ufbv_rewriter_tactic.h" +#include "tactic/tactical.h" +#include "tactic/ufbv/ufbv_rewriter.h" +#include "tactic/ufbv/ufbv_rewriter_tactic.h" class ufbv_rewriter_tactic : public tactic { @@ -45,9 +43,7 @@ class ufbv_rewriter_tactic : public tactic { bool produce_proofs = g->proofs_enabled(); - basic_simplifier_plugin bsimp(m_manager); - bsimp.set_eliminate_and(true); - ufbv_rewriter dem(m_manager, bsimp); + ufbv_rewriter dem(m_manager); expr_ref_vector forms(m_manager), new_forms(m_manager); proof_ref_vector proofs(m_manager), new_proofs(m_manager); diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.h b/src/tactic/ufbv/ufbv_rewriter_tactic.h index 78e34bae2..d0bdcd021 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.h +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef UFBV_REWRITER_TACTIC_H_ #define UFBV_REWRITER_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/tactic/ufbv/ufbv_tactic.cpp b/src/tactic/ufbv/ufbv_tactic.cpp index 19d41be68..1fb4486ec 100644 --- a/src/tactic/ufbv/ufbv_tactic.cpp +++ b/src/tactic/ufbv/ufbv_tactic.cpp @@ -16,19 +16,19 @@ Author: Notes: --*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"propagate_values_tactic.h" -#include"solve_eqs_tactic.h" -#include"distribute_forall_tactic.h" -#include"der_tactic.h" -#include"reduce_args_tactic.h" -#include"smt_tactic.h" -#include"nnf_tactic.h" -#include"macro_finder_tactic.h" -#include"ufbv_rewriter_tactic.h" -#include"quasi_macros_tactic.h" -#include"ufbv_tactic.h" +#include "tactic/tactical.h" +#include "tactic/core/simplify_tactic.h" +#include "tactic/core/propagate_values_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/distribute_forall_tactic.h" +#include "tactic/core/der_tactic.h" +#include "tactic/core/reduce_args_tactic.h" +#include "smt/tactic/smt_tactic.h" +#include "tactic/core/nnf_tactic.h" +#include "tactic/ufbv/macro_finder_tactic.h" +#include "tactic/ufbv/ufbv_rewriter_tactic.h" +#include "tactic/ufbv/quasi_macros_tactic.h" +#include "tactic/ufbv/ufbv_tactic.h" static tactic * mk_der_fp_tactic(ast_manager & m, params_ref const & p) { diff --git a/src/tactic/ufbv/ufbv_tactic.h b/src/tactic/ufbv/ufbv_tactic.h index 300fdd84a..ee97cd35e 100644 --- a/src/tactic/ufbv/ufbv_tactic.h +++ b/src/tactic/ufbv/ufbv_tactic.h @@ -19,7 +19,7 @@ Notes: #ifndef UFBV_TACTIC_H_ #define UFBV_TACTIC_H_ -#include"params.h" +#include "util/params.h" class ast_manager; class tactic; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index b395c09e6..fbcaec5ef 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -20,7 +20,6 @@ add_executable(test-z3 bits.cpp bit_vector.cpp buffer.cpp - bv_simplifier_plugin.cpp chashtable.cpp check_assumptions.cpp cnf_backbones.cpp diff --git a/src/test/algebraic.cpp b/src/test/algebraic.cpp index af7270825..b893b5ee2 100644 --- a/src/test/algebraic.cpp +++ b/src/test/algebraic.cpp @@ -16,10 +16,10 @@ Author: Notes: --*/ -#include"algebraic_numbers.h" -#include"polynomial_var2value.h" -#include"mpbq.h" -#include"rlimit.h" +#include "math/polynomial/algebraic_numbers.h" +#include "math/polynomial/polynomial_var2value.h" +#include "util/mpbq.h" +#include "util/rlimit.h" static void display_anums(std::ostream & out, scoped_anum_vector const & rs) { out << "numbers in decimal:\n"; @@ -54,7 +54,7 @@ static void tst1() { std::cout << "p: " << p << "\n"; am.isolate_roots(p, rs1); display_anums(std::cout, rs1); - SASSERT(rs1.size() == 1); + ENSURE(rs1.size() == 1); std::cout.flush(); p = (x^2) - 2; @@ -62,7 +62,7 @@ static void tst1() { rs1.reset(); am.isolate_roots(p, rs1); display_anums(std::cout, rs1); - SASSERT(rs1.size() == 2); + ENSURE(rs1.size() == 2); scoped_anum sqrt2(am); am.set(sqrt2, rs1[1]); @@ -88,7 +88,7 @@ static void tst1() { rs1.reset(); am.isolate_roots(p, rs1); display_anums(std::cout, rs1); - SASSERT(rs1.size() == 3); + ENSURE(rs1.size() == 3); scoped_anum gauss(am); am.set(gauss, rs1[1]); @@ -104,7 +104,7 @@ static void tst1() { rs1.reset(); am.isolate_roots(p, rs1); display_anums(std::cout, rs1); - SASSERT(rs1.size() == 4); + ENSURE(rs1.size() == 4); scoped_anum hidden_sqrt2(am); am.set(hidden_sqrt2, rs1[2]); @@ -116,8 +116,8 @@ static void tst1() { std::cout << "sqrt(2)^4: " << (sqrt2^4) << "\n"; - SASSERT(is_int(power(sqrt2, 4))); - SASSERT(power(sqrt2, 4) == 4); + ENSURE(is_int(power(sqrt2, 4))); + ENSURE(power(sqrt2, 4) == 4); scoped_anum sqrt2_gauss(am); am.add(sqrt2, gauss, sqrt2_gauss); @@ -242,9 +242,9 @@ static void tst_wilkinson() { std::cout << "p: " << p << "\n"; am.isolate_roots(p, rs1); display_anums(std::cout, rs1); - SASSERT(rs1.size() == 20); + ENSURE(rs1.size() == 20); for (unsigned i = 0; i < rs1.size(); i++) { - SASSERT(am.is_int(rs1[i])); + ENSURE(am.is_int(rs1[i])); } } @@ -328,9 +328,9 @@ static void tst_eval_sign(polynomial_ref const & p, anum_manager & am, std::cout << "x1 -> "; am.display_root(std::cout, v1); std::cout << "\n"; std::cout << "x2 -> "; am.display_root(std::cout, v2); std::cout << "\n"; int s = am.eval_sign_at(p, x2v); - SASSERT((s == 0) == (expected == 0)); - SASSERT((s < 0) == (expected < 0)); - SASSERT((s > 0) == (expected > 0)); + ENSURE((s == 0) == (expected == 0)); + ENSURE((s < 0) == (expected < 0)); + ENSURE((s > 0) == (expected > 0)); std::cout << "sign: " << s << "\n"; } @@ -399,7 +399,7 @@ static void tst_isolate_roots(polynomial_ref const & p, anum_manager & am, scoped_anum_vector roots(am); svector signs; am.isolate_roots(p, x2v, roots, signs); - SASSERT(roots.size() + 1 == signs.size()); + ENSURE(roots.size() + 1 == signs.size()); std::cout << "roots:\n"; for (unsigned i = 0; i < roots.size(); i++) { am.display_root(std::cout, roots[i]); std::cout << " "; am.display_decimal(std::cout, roots[i]); std::cout << "\n"; diff --git a/src/test/api.cpp b/src/test/api.cpp index 667d10bc5..2b6cda0ea 100644 --- a/src/test/api.cpp +++ b/src/test/api.cpp @@ -5,13 +5,13 @@ Copyright (c) 2015 Microsoft Corporation --*/ #ifdef _WINDOWS -#include "z3.h" -#include "z3_private.h" +#include "api/z3.h" +#include "api/z3_private.h" #include -#include "util.h" -#include "trace.h" +#include "util/util.h" +#include "util/trace.h" #include -#include "trace.h" +#include "util/trace.h" void test_apps() { Z3_config cfg = Z3_mk_config(); @@ -101,7 +101,7 @@ static void test_mk_distinct() { Z3_sort bv32 = Z3_mk_bv_sort(ctx, 32); Z3_ast args[] = { Z3_mk_int64(ctx, 0, bv8), Z3_mk_int64(ctx, 0, bv32) }; Z3_ast d = Z3_mk_distinct(ctx, 2, args); - SASSERT(cb_called); + ENSURE(cb_called); Z3_del_config(cfg); Z3_del_context(ctx); diff --git a/src/test/api_bug.cpp b/src/test/api_bug.cpp index cd7feec56..44721700b 100644 --- a/src/test/api_bug.cpp +++ b/src/test/api_bug.cpp @@ -5,7 +5,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ #include -#include"z3.h" +#include "api/z3.h" void tst_api_bug() { unsigned vmajor, vminor, vbuild, vrevision; diff --git a/src/test/argument_parser.h b/src/test/argument_parser.h index 706167f49..c8566ce34 100644 --- a/src/test/argument_parser.h +++ b/src/test/argument_parser.h @@ -1,9 +1,22 @@ -/* -Copyright (c) 2013 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. +/*++ +Copyright (c) 2017 Microsoft Corporation -Author: Lev Nachmanson -*/ +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include @@ -11,7 +24,7 @@ Author: Lev Nachmanson #include #include -namespace lean { +namespace lp { class argument_parser { std::unordered_map m_options; std::unordered_map m_options_with_after_string; diff --git a/src/test/arith_rewriter.cpp b/src/test/arith_rewriter.cpp index 5ed7c3501..a279d58b2 100644 --- a/src/test/arith_rewriter.cpp +++ b/src/test/arith_rewriter.cpp @@ -4,14 +4,14 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "arith_rewriter.h" -#include "bv_decl_plugin.h" -#include "ast_pp.h" -#include "reg_decl_plugins.h" -#include "th_rewriter.h" -#include "model.h" -#include "pdr_util.h" -#include "smt2parser.h" +#include "ast/rewriter/arith_rewriter.h" +#include "ast/bv_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/reg_decl_plugins.h" +#include "ast/rewriter/th_rewriter.h" +#include "model/model.h" +#include "muz/pdr/pdr_util.h" +#include "parsers/smt2/smt2parser.h" static expr_ref parse_fml(ast_manager& m, char const* str) { @@ -27,7 +27,7 @@ static expr_ref parse_fml(ast_manager& m, char const* str) { << "(assert " << str << ")\n"; std::istringstream is(buffer.str()); VERIFY(parse_smt2_commands(ctx, is)); - SASSERT(ctx.begin_assertions() != ctx.end_assertions()); + ENSURE(ctx.begin_assertions() != ctx.end_assertions()); result = *ctx.begin_assertions(); return result; } diff --git a/src/test/arith_simplifier_plugin.cpp b/src/test/arith_simplifier_plugin.cpp index 8464fd830..63a6838d4 100644 --- a/src/test/arith_simplifier_plugin.cpp +++ b/src/test/arith_simplifier_plugin.cpp @@ -4,8 +4,8 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "arith_eq_solver.h" -#include "smt_params.h" +#include "smt/arith_eq_solver.h" +#include "smt/params/smt_params.h" typedef rational numeral; typedef vector row; diff --git a/src/test/ast.cpp b/src/test/ast.cpp index b59e2a612..59bdfc8e4 100644 --- a/src/test/ast.cpp +++ b/src/test/ast.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include "ast.h" +#include "ast/ast.h" static void tst1() { ast_manager m; @@ -29,21 +29,21 @@ static void tst1() { expr_ref i1(m.mk_app(fid, OP_AND, a.get(), c.get()), m); expr_ref i2(m.mk_app(fid, OP_AND, a.get(), c.get()), m); expr_ref i3(m.mk_app(fid, OP_OR, a.get(), c.get()), m); - SASSERT(i1.get() == i2.get()); - SASSERT(i1.get() != i3.get()); + ENSURE(i1.get() == i2.get()); + ENSURE(i1.get() != i3.get()); // TODO use smart pointers to track references // ast_manager m; // ast_ref n1(m.mk_numeral(rational(2,3)), m); // ast_ref n2(m.mk_numeral(rational(2,3)), m); -// SASSERT(n1 == n2); +// ENSURE(n1 == n2); // ast_ref n3(m.mk_numeral(rational(1,2)), m); -// SASSERT(n1 != n3); +// ENSURE(n1 != n3); // ast_ref v1 (m.mk_var(1), m); // ast_ref v2 (m.mk_var(2), m); // ast_ref v3 (m.mk_var(1), m); -// SASSERT(v1 != v2); -// SASSERT(v1 == v3); +// ENSURE(v1 != v2); +// ENSURE(v1 == v3); // TRACE("ast", tout << "reseting v1\n";); // v1.reset(); // TRACE("ast", tout << "overwriting v3\n";); @@ -59,7 +59,7 @@ static void tst1() { // ast_ref foo_x(m.mk_const(foo_decl.get(), x.get()), m); // ast_ref foo_foo_x(m.mk_const(foo_decl.get(), foo_x.get()), m); // ast_ref foo_foo_x2(m.mk_const(foo_decl.get(), m.mk_const(foo_decl.get(), m.mk_const(x_decl.get()))), m); -// SASSERT(foo_foo_x2 == foo_foo_x); +// ENSURE(foo_foo_x2 == foo_foo_x); } static void tst2() { @@ -70,13 +70,13 @@ static void tst2() { // m_nodes.push_back(m.mk_numeral(rational(1,2))); // m_nodes.push_back(m.mk_var(2)); // m_nodes[1] = m.mk_var(3); -// SASSERT(m_nodes[1]->kind() == AST_VAR); -// SASSERT(m_nodes.get(1)->kind() == AST_VAR); +// ENSURE(m_nodes[1]->kind() == AST_VAR); +// ENSURE(m_nodes.get(1)->kind() == AST_VAR); // m_nodes.pop_back(); -// SASSERT(m_nodes.size() == 2); -// SASSERT(!m_nodes.empty()); +// ENSURE(m_nodes.size() == 2); +// ENSURE(!m_nodes.empty()); // m_nodes.set(1, m.mk_var(4)); -// SASSERT(&(m_nodes.get_manager()) == &m); +// ENSURE(&(m_nodes.get_manager()) == &m); } static void tst3() { @@ -95,16 +95,16 @@ static void tst4() { // #ifdef Z3DEBUG // int r; // #endif -// SASSERT(!wm1.find(n1, r)); +// ENSURE(!wm1.find(n1, r)); // wm1.insert(n2, 10); -// SASSERT(!wm1.find(n1, r)); -// SASSERT(wm1.find(n2, r) && r == 10); +// ENSURE(!wm1.find(n1, r)); +// ENSURE(wm1.find(n2, r) && r == 10); // wm1.insert(n2, 20); -// SASSERT(!wm1.find(n1, r)); -// SASSERT(wm1.find(n2, r) && r == 20); +// ENSURE(!wm1.find(n1, r)); +// ENSURE(wm1.find(n2, r) && r == 20); // wm1.insert(n1, 0); -// SASSERT(wm1.find(n1, r) && r == 0); -// SASSERT(wm1.find(n2, r) && r == 20); +// ENSURE(wm1.find(n1, r) && r == 0); +// ENSURE(wm1.find(n2, r) && r == 20); } static void tst5() { @@ -119,13 +119,13 @@ static void tst5() { m.push_back(arr1, a2); m.pop_back(arr1, arr2); m.set(arr2, 0, a2, arr3); - SASSERT(m.size(arr1) == 2); - SASSERT(m.size(arr2) == 1); - SASSERT(m.size(arr3) == 1); - SASSERT(m.get(arr1, 0) == a1); - SASSERT(m.get(arr1, 1) == a2); - SASSERT(m.get(arr2, 0) == a1); - SASSERT(m.get(arr3, 0) == a2); + ENSURE(m.size(arr1) == 2); + ENSURE(m.size(arr2) == 1); + ENSURE(m.size(arr3) == 1); + ENSURE(m.get(arr1, 0) == a1); + ENSURE(m.get(arr1, 1) == a2); + ENSURE(m.get(arr2, 0) == a1); + ENSURE(m.get(arr3, 0) == a2); m.del(arr1); m.del(arr2); m.del(arr3); diff --git a/src/test/bit_blaster.cpp b/src/test/bit_blaster.cpp index d864032f5..c6853ae1e 100644 --- a/src/test/bit_blaster.cpp +++ b/src/test/bit_blaster.cpp @@ -17,9 +17,9 @@ Revision History: --*/ -#include"bit_blaster.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" +#include "ast/rewriter/bit_blaster/bit_blaster.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" void mk_bits(ast_manager & m, char const * prefix, unsigned sz, expr_ref_vector & r) { sort_ref b(m); diff --git a/src/test/bit_vector.cpp b/src/test/bit_vector.cpp index 6f83bb328..487f6cdd0 100644 --- a/src/test/bit_vector.cpp +++ b/src/test/bit_vector.cpp @@ -18,8 +18,8 @@ Revision History: --*/ #include #include -#include"bit_vector.h" -#include"vector.h" +#include "util/bit_vector.h" +#include "util/vector.h" static void tst1() { bit_vector v1; @@ -27,36 +27,36 @@ static void tst1() { unsigned n = rand()%10000; for (unsigned i = 0; i < n; i++) { int op = rand()%6; - if (op <= 1) { - bool val = (rand()%2) != 0; - v1.push_back(val); - v2.push_back(val); - SASSERT(v1.size() == v2.size()); - } - else if (op <= 3) { - SASSERT(v1.size() == v2.size()); - if (v1.size() > 0) { - bool val = (rand()%2) != 0; - unsigned idx = rand()%v1.size(); - SASSERT(v1.get(idx) == v2[idx]); - v1.set(idx, val); - v2[idx] = val; - SASSERT(v1.get(idx) == v2[idx]); - } - } - else if (op <= 4) { - SASSERT(v1.size() == v2.size()); - if (v1.size() > 0) { - unsigned idx = rand()%v1.size(); - VERIFY(v1.get(idx) == v2[idx]); - } - } - else if (op <= 5) { - SASSERT(v1.size() == v2.size()); - for (unsigned j = 0; j < v1.size(); j++) { - SASSERT(v1.get(j) == v2[j]); - } - } + if (op <= 1) { + bool val = (rand()%2) != 0; + v1.push_back(val); + v2.push_back(val); + ENSURE(v1.size() == v2.size()); + } + else if (op <= 3) { + ENSURE(v1.size() == v2.size()); + if (v1.size() > 0) { + bool val = (rand()%2) != 0; + unsigned idx = rand()%v1.size(); + ENSURE(v1.get(idx) == v2[idx]); + v1.set(idx, val); + v2[idx] = val; + ENSURE(v1.get(idx) == v2[idx]); + } + } + else if (op <= 4) { + ENSURE(v1.size() == v2.size()); + if (v1.size() > 0) { + unsigned idx = rand()%v1.size(); + VERIFY(v1.get(idx) == v2[idx]); + } + } + else if (op <= 5) { + ENSURE(v1.size() == v2.size()); + for (unsigned j = 0; j < v1.size(); j++) { + ENSURE(v1.get(j) == v2[j]); + } + } } } @@ -66,11 +66,11 @@ static void tst2() { b.push_back(false); b.push_back(true); b.resize(30); - SASSERT(b.get(0) == true); - SASSERT(b.get(1) == false); - SASSERT(b.get(2) == true); - SASSERT(b.get(3) == false); - SASSERT(b.get(29) == false); + ENSURE(b.get(0) == true); + ENSURE(b.get(1) == false); + ENSURE(b.get(2) == true); + ENSURE(b.get(3) == false); + ENSURE(b.get(29) == false); } static void tst_shift() { @@ -116,14 +116,14 @@ static void tst_or() { std::cout << b1 << "\n"; std::cout << b2 << "\n"; b1 |= b2; - SASSERT(b1.size() == 10); + ENSURE(b1.size() == 10); std::cout << b1 << "\n"; - SASSERT(b1 != b2); - SASSERT(b1 != b2); + ENSURE(b1 != b2); + ENSURE(b1 != b2); b1.unset(4); - SASSERT(b1 == b2); + ENSURE(b1 == b2); b1.unset(3); - SASSERT(b1 != b2); + ENSURE(b1 != b2); } { bit_vector b1; @@ -133,9 +133,9 @@ static void tst_or() { b1.set(0); b2.set(4); b1 |= b2; - SASSERT(b1 != b2); + ENSURE(b1 != b2); b2.set(0); - SASSERT(b1 == b2); + ENSURE(b1 == b2); std::cout << "-----\n"; std::cout << b1 << "\n"; } @@ -149,9 +149,9 @@ static void tst_or() { b2.set(3); b2.resize(5); b1 |= b2; - SASSERT(!b1.get(8)); - SASSERT(b1.get(5)); - SASSERT(b1.get(3)); + ENSURE(!b1.get(8)); + ENSURE(b1.get(5)); + ENSURE(b1.get(3)); } { bit_vector b1; @@ -166,17 +166,17 @@ static void tst_or() { b2.set(80); b1.set(4); b2.set(4); - SASSERT(b1!=b2); + ENSURE(b1!=b2); b2.resize(123); - SASSERT(b1!=b2); + ENSURE(b1!=b2); b1.resize(120); b2.resize(120); - SASSERT(b1==b2); + ENSURE(b1==b2); b1.unset(80); b1.unset(100); - SASSERT(b1!=b2); + ENSURE(b1!=b2); b1 |= b2; - SASSERT(b1 == b2); + ENSURE(b1 == b2); } { bit_vector b1; @@ -188,8 +188,8 @@ static void tst_or() { b2.set(1); b1.set(0); b1 |= b2; - SASSERT(b1.size() == 10); - SASSERT(b1.get(8) && b1.get(4) && b1.get(1) && b1.get(0) && !b1.get(9)); + ENSURE(b1.size() == 10); + ENSURE(b1.get(8) && b1.get(4) && b1.get(1) && b1.get(0) && !b1.get(9)); } { bit_vector b1; @@ -201,7 +201,7 @@ static void tst_or() { b2.set(8); b2.set(0); b1 |= b2; - SASSERT(b1.get(1) && b1.get(5) && b1.get(8) && b1.get(0) && !b1.get(11)); + ENSURE(b1.get(1) && b1.get(5) && b1.get(8) && b1.get(0) && !b1.get(11)); std::cout << "b1(size32): " << b1 << "\n"; } } @@ -218,8 +218,8 @@ static void tst_and() { std::cout << "------\nb1: " << b1 << "\n"; b1 &= b2; std::cout << "------\nb1: " << b1 << "\n"; - SASSERT(!b1.get(4)); - SASSERT(b1.get(2)); + ENSURE(!b1.get(4)); + ENSURE(b1.get(2)); } { bit_vector b1; @@ -234,7 +234,7 @@ static void tst_and() { b2.set(127); b2.set(5); b1 &= b2; - SASSERT(!b1.get(240) && !b1.get(232) && !b1.get(128) && b1.get(127) && !b1.get(8) && !b1.get(5)); + ENSURE(!b1.get(240) && !b1.get(232) && !b1.get(128) && b1.get(127) && !b1.get(8) && !b1.get(5)); } } @@ -243,17 +243,17 @@ static void tst_crash() { bit_vector b; b.push_back(true); b.resize(64); - SASSERT(!b.get(63)); - SASSERT(b.get(0)); - SASSERT(!b.get(1)); + ENSURE(!b.get(63)); + ENSURE(b.get(0)); + ENSURE(!b.get(1)); } { bit_vector b; b.push_back(false); b.resize(64, true); - SASSERT(b.get(63)); - SASSERT(!b.get(0)); - SASSERT(b.get(1)); + ENSURE(b.get(63)); + ENSURE(!b.get(0)); + ENSURE(b.get(1)); } } @@ -264,12 +264,12 @@ static void tst_bv_reset() { b.reset(); b.resize(sz, bit); for (unsigned i = 0; i < sz; ++i) { - SASSERT(bit == b.get(i)); + ENSURE(bit == b.get(i)); } for (unsigned sz2 = sz; sz2 < sz+10; ++sz2) { b.resize(sz2, !bit); for (unsigned i = sz; i < sz2; ++i) { - SASSERT(bit != b.get(i)); + ENSURE(bit != b.get(i)); } } bit = !bit; @@ -283,19 +283,19 @@ static void tst_eq() { b3.resize(32); b1.set(3, true); - SASSERT(b1 != b2); - SASSERT(!(b1 == b2)); - SASSERT(b2 == b3); + ENSURE(b1 != b2); + ENSURE(!(b1 == b2)); + ENSURE(b2 == b3); b3.set(3, true); - SASSERT(b1 == b3); - SASSERT(!(b1 != b3)); + ENSURE(b1 == b3); + ENSURE(!(b1 != b3)); b2.set(31, true); b3.set(31); b3.unset(3); - SASSERT(b2 == b3); - SASSERT(!(b2 != b3)); + ENSURE(b2 == b3); + ENSURE(!(b2 != b3)); } void tst_bit_vector() { @@ -309,6 +309,6 @@ void tst_bit_vector() { tst2(); for (unsigned i = 0; i < 20; i++) { std::cerr << i << std::endl; - tst1(); + tst1(); } } diff --git a/src/test/bits.cpp b/src/test/bits.cpp index f32871a5a..f0f04f661 100644 --- a/src/test/bits.cpp +++ b/src/test/bits.cpp @@ -5,11 +5,11 @@ Copyright (c) 2015 Microsoft Corporation --*/ // Test some bit hacks -#include"util.h" -#include"debug.h" -#include"vector.h" -#include"mpz.h" -#include"bit_util.h" +#include "util/util.h" +#include "util/debug.h" +#include "util/vector.h" +#include "util/mpz.h" +#include "util/bit_util.h" static void tst_shl(unsigned src_sz, unsigned const * src, unsigned k, unsigned dst_sz, unsigned const * dst, bool trace = true) { @@ -27,11 +27,11 @@ static void tst_shl(unsigned src_sz, unsigned const * src, unsigned k, if (trace) std::cout << " for sz = " << sz << std::endl; shl(src_sz, src, k, sz, actual_dst.c_ptr()); - SASSERT(!has_one_at_first_k_bits(sz, actual_dst.c_ptr(), k)); + ENSURE(!has_one_at_first_k_bits(sz, actual_dst.c_ptr(), k)); for (unsigned i = 0; i < sz; i++) { if (trace && dst[i] != actual_dst[i]) std::cout << "UNEXPECTED RESULT at [" << i << "]: " << actual_dst[i] << ", expected: " << dst[i] << "\n"; - SASSERT(dst[i] == actual_dst[i]); + ENSURE(dst[i] == actual_dst[i]); } if (sz == src_sz) { unsigned nz1 = nlz(sz, src); @@ -52,7 +52,7 @@ static void tst_shl(unsigned src_sz, unsigned const * src, unsigned k, if (trace && src[i] != new_src[i]) { std::cout << "shr BUG, inverting shl, at bit[" << i << "], " << new_src[i] << ", expected: " << src[i] << std::endl; } - SASSERT(src[i] == new_src[i]); + ENSURE(src[i] == new_src[i]); } } } @@ -65,7 +65,7 @@ static void tst_shl(unsigned src_sz, unsigned const * src, unsigned k, for (unsigned i = 0; i < dst_sz; i++) { if (trace && dst[i] != actual_dst[i]) std::cout << "UNEXPECTED RESULT at [" << i << "]: " << actual_dst[i] << ", expected: " << dst[i] << "\n"; - SASSERT(dst[i] == actual_dst[i]); + ENSURE(dst[i] == actual_dst[i]); } if (src_sz <= dst_sz) { if (trace) @@ -74,7 +74,7 @@ static void tst_shl(unsigned src_sz, unsigned const * src, unsigned k, for (unsigned i = 0; i < src_sz; i++) { if (trace && src[i] != dst[i]) std::cout << "UNEXPECTED RESULT at [" << i << "]: " << src[i] << ", expected: " << dst[i] << "\n"; - SASSERT(src[i] == actual_dst[i]); + ENSURE(src[i] == actual_dst[i]); } } } @@ -134,7 +134,7 @@ static void tst_shr(unsigned src_sz, unsigned const * src, unsigned k, for (unsigned i = 0; i < src_sz; i++) { if (trace && dst[i] != actual_dst[i]) std::cout << "UNEXPECTED RESULT at [" << i << "]: " << actual_dst[i] << ", expected: " << dst[i] << "\n"; - SASSERT(dst[i] == actual_dst[i]); + ENSURE(dst[i] == actual_dst[i]); } } @@ -172,7 +172,7 @@ static void tst_shl_rand(unsynch_mpz_manager & m, unsigned sz, unsigned k, bool m.mul2k(max, 32); while (!m.is_zero(_dst)) { m.mod(_dst, max, tmp); - SASSERT(m.is_uint64(tmp) && m.get_uint64(tmp) < UINT_MAX); + ENSURE(m.is_uint64(tmp) && m.get_uint64(tmp) < UINT_MAX); dst.push_back(static_cast(m.get_uint64(tmp))); m.div(_dst, max, _dst); } diff --git a/src/test/buffer.cpp b/src/test/buffer.cpp index a23fb3c74..4ab9754c2 100644 --- a/src/test/buffer.cpp +++ b/src/test/buffer.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"ptr_scoped_buffer.h" +#include "util/ptr_scoped_buffer.h" typedef std::pair point; @@ -24,22 +24,22 @@ template class ptr_scoped_buffer; static void tst1() { ptr_scoped_buffer b; - SASSERT(b.empty()); + ENSURE(b.empty()); b.push_back(alloc(point, 10, 20)); - SASSERT(!b.empty()); + ENSURE(!b.empty()); point * p1 = alloc(point, 30, 20); b.push_back(p1); - SASSERT(b.get(1) == p1); + ENSURE(b.get(1) == p1); b.push_back(alloc(point, 40, 20)); - SASSERT(b.size() == 3); + ENSURE(b.size() == 3); b.pop_back(); - SASSERT(b.get(0) != p1); - SASSERT(b.get(1) == p1); + ENSURE(b.get(0) != p1); + ENSURE(b.get(1) == p1); point * p2 = alloc(point, 30, 20); - SASSERT(b.get(0) != p2); + ENSURE(b.get(0) != p2); b.set(0, p2); - SASSERT(b.get(0) == p2); - SASSERT(b.size() == 2); + ENSURE(b.get(0) == p2); + ENSURE(b.size() == 2); b.push_back(alloc(point, 40, 40)); } diff --git a/src/test/bv_simplifier_plugin.cpp b/src/test/bv_simplifier_plugin.cpp deleted file mode 100644 index 69b97a9cc..000000000 --- a/src/test/bv_simplifier_plugin.cpp +++ /dev/null @@ -1,326 +0,0 @@ - -/*++ -Copyright (c) 2015 Microsoft Corporation - ---*/ - -#include "bv_simplifier_plugin.h" -#include "arith_decl_plugin.h" -#include "ast_pp.h" -#include "reg_decl_plugins.h" - -class tst_bv_simplifier_plugin_cls { - class mgr { - public: - mgr(ast_manager& m) { - reg_decl_plugins(m); - } - }; - ast_manager m_manager; - mgr m_mgr; - bv_simplifier_params m_bv_params; - basic_simplifier_plugin m_bsimp; - arith_util m_arith; - bv_simplifier_plugin m_simp; - bv_util m_bv_util; - family_id m_fid; - - void get_num(expr* e, unsigned bv_size, rational& r) { - unsigned bv_size0; - if (!m_bv_util.is_numeral(e, r, bv_size0)) { - UNREACHABLE(); - } - SASSERT(bv_size == bv_size0); - } - - unsigned u32(expr* e) { - rational r; - std::cout << mk_pp(e,m_manager) << "\n"; - get_num(e, 32, r); - return r.get_unsigned(); - } - - unsigned char u8(expr* e) { - rational r; - get_num(e, 8, r); - return static_cast(r.get_unsigned()); - } - int i32(expr* e) { - return static_cast(u32(e)); - } - - uint64 u64(expr* e) { - rational r; - get_num(e, 64, r); - return r.get_uint64(); - } - - int64 i64(expr* e) { - rational r; - get_num(e, 64, r); - if (r >= power(rational(2), 63)) { - r -= power(rational(2), 64); - } - return r.get_int64(); - } - - bool ast2bool(expr* e) { - if (m_manager.is_true(e)) { - return true; - } - if (m_manager.is_false(e)) { - return false; - } - UNREACHABLE(); - return false; - } - - bool bit2bool(expr* e) { - rational r; - get_num(e, 1, r); - return 0 != r.get_unsigned(); - } - - expr* mk_int(unsigned i) { - return m_arith.mk_numeral(rational(i), true); - } - -public: - - tst_bv_simplifier_plugin_cls() : - m_mgr(m_manager), - m_bsimp(m_manager), - m_arith(m_manager), - m_simp(m_manager, m_bsimp, m_bv_params), - m_bv_util(m_manager), - m_fid(0) { - m_fid = m_manager.mk_family_id("bv"); - } - - ~tst_bv_simplifier_plugin_cls() {} - - void test_num(unsigned a) { - expr_ref e(m_manager), e1(m_manager); - app_ref ar(m_manager); - uint64 a64 = static_cast(a); - - e1 = m_bv_util.mk_numeral(rational(a), 32); - expr* const es[1] = { e1.get() }; - - ar = m_manager.mk_app(m_fid, OP_BNEG, e1.get()); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - SASSERT((0-a) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BNOT, e1.get()); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - SASSERT((~a) == u32(e.get())); - - parameter params[2] = { parameter(32), parameter(32) }; - ar = m_manager.mk_app(m_fid, OP_SIGN_EXT, 1, params, 1, es); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - SASSERT(((int64)(int)a) == i64(e.get())); - - ar = m_manager.mk_app(m_fid, OP_ZERO_EXT, 1, params, 1, es); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - SASSERT(((uint64)a) == u64(e.get())); - - params[0] = parameter(7); - params[1] = parameter(0); - ar = m_manager.mk_app(m_fid, OP_EXTRACT, 2, params, 1, es); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - SASSERT(((unsigned char)a) == u8(e.get())); - - params[0] = parameter(2); - ar = m_manager.mk_app(m_fid, OP_REPEAT, 1, params, 1, es); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(((a64 << 32) | a64) == u64(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BREDOR, e1.get()); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - SASSERT((a != 0) == bit2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BREDAND, e1.get()); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - SASSERT((a == 0xFFFFFFFF) == bit2bool(e.get())); - - params[0] = parameter(8); - - ar = m_manager.mk_app(m_fid, OP_ROTATE_LEFT, 1, params, 1, es); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - SASSERT(((a << 8) | (a >> 24)) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_ROTATE_RIGHT, 1, params, 1, es); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - SASSERT(((a >> 8) | (a << 24)) == u32(e.get())); - - params[0] = parameter(m_manager.mk_sort(m_manager.mk_family_id("arith"), INT_SORT)); - ar = m_manager.mk_app(m_fid, OP_BV2INT, 1, params, 1, es); - expr* es2[1] = { ar.get() }; - params[0] = parameter(32); - ar = m_manager.mk_app(m_fid, OP_INT2BV, 1, params, 1, es2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - SASSERT(a == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BIT0); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(!bit2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BIT1); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(bit2bool(e.get())); - - } - - void test_pair(unsigned a, unsigned b) { - - expr_ref e(m_manager), e1(m_manager), e2(m_manager); - app_ref ar(m_manager); - int sa = static_cast(a); - int sb = static_cast(b); - uint64 a64 = static_cast(a); - uint64 b64 = static_cast(b); - - e1 = m_bv_util.mk_numeral(rational(a), 32); - e2 = m_bv_util.mk_numeral(rational(b), 32); - expr* const e1e2[] = { e1.get(), e2.get() }; - - - ar = m_manager.mk_app(m_fid, OP_BADD, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a + b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BSUB, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a - b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BMUL, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a * b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BAND, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a & b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BOR, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a | b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BNOR, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(~(a | b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BXOR, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a ^ b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BXNOR, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((~(a ^ b)) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BNAND, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((~(a & b)) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_ULEQ, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a <= b) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_UGEQ, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a >= b) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_ULT, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a < b) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_UGT, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a > b) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_SLEQ, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((sa <= sb) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_SGEQ, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((sa >= sb) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_SLT, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((sa < sb) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_SGT, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((sa > sb) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BSHL, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(((b>=32)?0:(a << b)) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BLSHR, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(((b>=32)?0:(a >> b)) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BASHR, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - - std::cout << "compare: " << sa << " >> " << b << " = " << (sa >> b) << " with " << i32(e.get()) << "\n"; - VERIFY(b >= 32 || ((sa >> b) == i32(e.get()))); - - if (b != 0) { - ar = m_manager.mk_app(m_fid, OP_BSDIV, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((sa / sb) == i32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BUDIV, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a / b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BSREM, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - //VERIFY((sa % sb) == i32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BUREM, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a % b) == u32(e.get())); - - // TBD: BSMOD. - } - - ar = m_manager.mk_app(m_fid, OP_CONCAT, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(((a64 << 32) | b64) == u64(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BCOMP, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a == b) == bit2bool(e.get())); - } - - void test() { - unsigned_vector nums; - nums.push_back(0); - nums.push_back(1); - nums.push_back(-1); - nums.push_back(2); - nums.push_back(31); - nums.push_back(32); - nums.push_back(33); - nums.push_back(435562); - nums.push_back(-43556211); - // TBD add some random numbers. - - - for (unsigned i = 0; i < nums.size(); ++i) { - test_num(nums[i]); - for (unsigned j = 0; j < nums.size(); ++j) { - test_pair(nums[i], nums[j]); - } - } - } -}; - - -void tst_bv_simplifier_plugin() { - tst_bv_simplifier_plugin_cls tst_cls; - tst_cls.test(); -} diff --git a/src/test/chashtable.cpp b/src/test/chashtable.cpp index 7d55fe01f..0ccf2c177 100644 --- a/src/test/chashtable.cpp +++ b/src/test/chashtable.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"chashtable.h" -#include"hashtable.h" -#include"hash.h" -#include"util.h" +#include "util/chashtable.h" +#include "util/hashtable.h" +#include "util/hash.h" +#include "util/util.h" typedef chashtable > int_table; typedef cmap > int_map; @@ -37,16 +37,16 @@ static void display(T const & beg, T const & end) { static void tst1() { int_table t; t.insert(10); - SASSERT(t.contains(10)); + ENSURE(t.contains(10)); t.insert(20); - SASSERT(t.contains(20)); + ENSURE(t.contains(20)); t.insert(30); - SASSERT(t.contains(30)); - SASSERT(t.size() == 3); + ENSURE(t.contains(30)); + ENSURE(t.size() == 3); display(t.begin(), t.end()); t.erase(20); - SASSERT(!t.contains(20)); - SASSERT(t.size() == 2); + ENSURE(!t.contains(20)); + ENSURE(t.size() == 2); } struct dummy_hash { @@ -61,54 +61,54 @@ static void tst2() { dint_table t; t.insert(10); t.insert(12); - SASSERT(t.used_slots() == 1); + ENSURE(t.used_slots() == 1); display(t.begin(), t.end()); t.insert(13); display(t.begin(), t.end()); - SASSERT(t.used_slots() == 2); + ENSURE(t.used_slots() == 2); t.insert(14); - SASSERT(t.used_slots() == 2); - SASSERT(t.size() == 4); + ENSURE(t.used_slots() == 2); + ENSURE(t.size() == 4); display(t.begin(), t.end()); t.erase(12); - SASSERT(!t.contains(12)); - SASSERT(t.size() == 3); - SASSERT(t.contains(10)); - SASSERT(!t.contains(12)); - SASSERT(t.contains(14)); - SASSERT(t.contains(13)); + ENSURE(!t.contains(12)); + ENSURE(t.size() == 3); + ENSURE(t.contains(10)); + ENSURE(!t.contains(12)); + ENSURE(t.contains(14)); + ENSURE(t.contains(13)); t.insert(16); - SASSERT(t.size() == 4); + ENSURE(t.size() == 4); t.insert(18); - SASSERT(t.size() == 5); - SASSERT(t.used_slots() == 2); + ENSURE(t.size() == 5); + ENSURE(t.used_slots() == 2); display(t.begin(), t.end()); t.erase(10); display(t.begin(), t.end()); - SASSERT(!t.contains(10)); - SASSERT(!t.contains(12)); - SASSERT(t.contains(14)); - SASSERT(t.contains(13)); - SASSERT(t.contains(16)); - SASSERT(t.contains(18)); + ENSURE(!t.contains(10)); + ENSURE(!t.contains(12)); + ENSURE(t.contains(14)); + ENSURE(t.contains(13)); + ENSURE(t.contains(16)); + ENSURE(t.contains(18)); } static void tst3() { dint_table t; t.insert(10); t.insert(12); - SASSERT(t.used_slots() == 1); - SASSERT(t.contains(10)); - SASSERT(t.contains(12)); + ENSURE(t.used_slots() == 1); + ENSURE(t.contains(10)); + ENSURE(t.contains(12)); t.erase(12); t.erase(10); - SASSERT(t.size() == 0); - SASSERT(t.empty()); - SASSERT(t.used_slots() == 0); + ENSURE(t.size() == 0); + ENSURE(t.empty()); + ENSURE(t.used_slots() == 0); t.insert(10); - SASSERT(t.used_slots() == 1); - SASSERT(t.contains(10)); - SASSERT(t.size() == 1); + ENSURE(t.used_slots() == 1); + ENSURE(t.contains(10)); + ENSURE(t.size() == 1); } typedef int_hashtable > int_set; @@ -123,29 +123,29 @@ static void tst4(unsigned num, unsigned N) { TRACE("chashtable", tout << "erase " << v << "\n";); s.erase(v); t.erase(v); - SASSERT(!t.contains(v)); + ENSURE(!t.contains(v)); } else { TRACE("chashtable", tout << "insert " << v << "\n";); s.insert(v); t.insert(v); - SASSERT(t.contains(v)); + ENSURE(t.contains(v)); } - SASSERT(s.size() == t.size()); - SASSERT(s.empty() == t.empty()); + ENSURE(s.size() == t.size()); + ENSURE(s.empty() == t.empty()); } std::cout << "size: " << s.size() << " " << t.size() << "\n"; int_set::iterator it1 = s.begin(); int_set::iterator end1 = s.end(); for(; it1 != end1; ++it1) { - SASSERT(t.contains(*it1)); + ENSURE(t.contains(*it1)); } typename T::iterator it2 = t.begin(); typename T::iterator end2 = t.end(); for(; it2 != end2; ++it2) { - SASSERT(s.contains(*it2)); - SASSERT(t.contains(*it2)); + ENSURE(s.contains(*it2)); + ENSURE(t.contains(*it2)); } } @@ -164,10 +164,10 @@ static void tst5() { static void tst6() { int_map m; m.insert(10, 4); - SASSERT(m.contains(10)); + ENSURE(m.contains(10)); DEBUG_CODE({ int r; - SASSERT(m.find(10, r) && r == 4); + ENSURE(m.find(10, r) && r == 4); }); } diff --git a/src/test/check_assumptions.cpp b/src/test/check_assumptions.cpp index 918513ca0..020b3e277 100644 --- a/src/test/check_assumptions.cpp +++ b/src/test/check_assumptions.cpp @@ -4,13 +4,13 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "memory_manager.h" -#include "smt_params.h" -#include "ast.h" -#include "arith_decl_plugin.h" -#include "bv_decl_plugin.h" -#include "smt_context.h" -#include "reg_decl_plugins.h" +#include "util/memory_manager.h" +#include "smt/params/smt_params.h" +#include "ast/ast.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "smt/smt_context.h" +#include "ast/reg_decl_plugins.h" void tst_check_assumptions() { diff --git a/src/test/cnf_backbones.cpp b/src/test/cnf_backbones.cpp index 3fdf96f87..3e9a106b5 100644 --- a/src/test/cnf_backbones.cpp +++ b/src/test/cnf_backbones.cpp @@ -5,11 +5,11 @@ Copyright (c) 2017 Microsoft Corporation #include #include #include -#include"timeout.h" -#include"rlimit.h" -#include"dimacs.h" -#include"sat_solver.h" -#include"gparams.h" +#include "util/timeout.h" +#include "util/rlimit.h" +#include "sat/dimacs.h" +#include "sat/sat_solver.h" +#include "util/gparams.h" static sat::solver * g_solver = 0; static clock_t g_start_time; diff --git a/src/test/datalog_parser.cpp b/src/test/datalog_parser.cpp index 800f21717..ca5e94f75 100644 --- a/src/test/datalog_parser.cpp +++ b/src/test/datalog_parser.cpp @@ -4,13 +4,13 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "datalog_parser.h" -#include "ast_pp.h" -#include "arith_decl_plugin.h" -#include "dl_context.h" -#include "dl_register_engine.h" -#include "smt_params.h" -#include "reg_decl_plugins.h" +#include "muz/fp/datalog_parser.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" +#include "muz/base/dl_context.h" +#include "muz/fp/dl_register_engine.h" +#include "smt/params/smt_params.h" +#include "ast/reg_decl_plugins.h" using namespace datalog; diff --git a/src/test/ddnf.cpp b/src/test/ddnf.cpp index 31503842d..c9eb6aa08 100644 --- a/src/test/ddnf.cpp +++ b/src/test/ddnf.cpp @@ -3,8 +3,8 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "ddnf.h" -#include "tbv.h" +#include "muz/ddnf/ddnf.h" +#include "muz/rel/tbv.h" #include #include #include @@ -200,6 +200,24 @@ void tst_ddnf(char ** argv, int argc, int& i) { dealloc(ddnf); } - +void tst_ddnf1() { + enable_trace("ddnf"); + unsigned W = 2; + datalog::ddnf_core ddnf(W); + tbv_manager& tbvm = ddnf.get_tbv_manager(); + tbv* tXX = tbvm.allocate("xx"); + tbv* t1X = tbvm.allocate("1x"); + tbv* tX1 = tbvm.allocate("x1"); + tbv* t11 = tbvm.allocate("11"); + ddnf.insert(*tXX); + ddnf.insert(*t11); + ddnf.insert(*tX1); + ddnf.insert(*t1X); + ddnf.display(std::cout); + tbvm.deallocate(tXX); + tbvm.deallocate(t1X); + tbvm.deallocate(tX1); + tbvm.deallocate(t11); +} diff --git a/src/test/diff_logic.cpp b/src/test/diff_logic.cpp index 70345c2d6..0564fbfbe 100644 --- a/src/test/diff_logic.cpp +++ b/src/test/diff_logic.cpp @@ -17,11 +17,11 @@ Revision History: --*/ #ifdef _WINDOWS -#include"rational.h" -#include"diff_logic.h" -#include"smt_literal.h" -#include"util.h" -#include"debug.h" +#include "util/rational.h" +#include "smt/diff_logic.h" +#include "smt/smt_literal.h" +#include "util/util.h" +#include "util/debug.h" struct diff_logic_ext { typedef rational numeral; @@ -33,7 +33,7 @@ template class dl_graph; typedef dl_graph dlg; struct tst_dl_functor { - smt::literal_vector m_literals; + smt::literal_vector m_literals; void operator()(smt::literal l) { m_literals.push_back(l); } @@ -70,20 +70,20 @@ static void tst2() { g.init_var(3); g.init_var(4); smt::literal d; - SASSERT(g.enable_edge(g.add_edge(1, 2, rational(-1), l1))); - SASSERT(g.get_edge_weight(1, 2, w, d) && w == rational(-1)); - SASSERT(!g.get_edge_weight(2, 3, w, d)); - SASSERT(g.enable_edge(g.add_edge(2, 3, rational(-2), l2))); - SASSERT(g.enable_edge(g.add_edge(1, 4, rational(1), l3))); - SASSERT(g.get_edge_weight(1, 2, w, d) && w == rational(-1)); - SASSERT(g.get_edge_weight(1, 4, w, d) && w == rational(1)); - SASSERT(!g.get_edge_weight(1, 3, w, d)); - SASSERT(g.enable_edge(g.add_edge(2, 4, rational(10), l6))); - SASSERT(g.is_feasible()); + ENSURE(g.enable_edge(g.add_edge(1, 2, rational(-1), l1))); + ENSURE(g.get_edge_weight(1, 2, w, d) && w == rational(-1)); + ENSURE(!g.get_edge_weight(2, 3, w, d)); + ENSURE(g.enable_edge(g.add_edge(2, 3, rational(-2), l2))); + ENSURE(g.enable_edge(g.add_edge(1, 4, rational(1), l3))); + ENSURE(g.get_edge_weight(1, 2, w, d) && w == rational(-1)); + ENSURE(g.get_edge_weight(1, 4, w, d) && w == rational(1)); + ENSURE(!g.get_edge_weight(1, 3, w, d)); + ENSURE(g.enable_edge(g.add_edge(2, 4, rational(10), l6))); + ENSURE(g.is_feasible()); g.push(); - SASSERT(g.enable_edge(g.add_edge(3, 0, rational(2), l4))); - SASSERT(!g.enable_edge(g.add_edge(0, 1, rational(-1), l5))); - SASSERT(!g.is_feasible()); + ENSURE(g.enable_edge(g.add_edge(3, 0, rational(2), l4))); + ENSURE(!g.enable_edge(g.add_edge(0, 1, rational(-1), l5))); + ENSURE(!g.is_feasible()); TRACE("diff_logic", g.display(tout);); struct proc { svector found; @@ -96,22 +96,22 @@ static void tst2() { }; proc p; g.traverse_neg_cycle(true, p); - SASSERT(p.found[0] == false); - SASSERT(p.found[1] == true); - SASSERT(p.found[2] == true); - SASSERT(p.found[3] == false); - SASSERT(p.found[4] == true); - SASSERT(p.found[5] == true); - SASSERT(p.found[6] == false); + ENSURE(p.found[0] == false); + ENSURE(p.found[1] == true); + ENSURE(p.found[2] == true); + ENSURE(p.found[3] == false); + ENSURE(p.found[4] == true); + ENSURE(p.found[5] == true); + ENSURE(p.found[6] == false); g.pop(1); - SASSERT(g.is_feasible()); + ENSURE(g.is_feasible()); TRACE("diff_logic", g.display(tout);); } static int add_edge(dlg& g, dl_var src, dl_var dst, int weight, unsigned lit) { int id = g.add_edge(src, dst, rational(weight), smt::literal(lit)); bool ok = g.enable_edge(id); - SASSERT(ok); + ENSURE(ok); return id; } @@ -147,7 +147,7 @@ static void tst3() { for (unsigned i = 0; i < subsumed.size(); ++i) { std::cout << "subsumed: " << subsumed[i] << "\n"; - SASSERT(e38 == subsumed[i]); + ENSURE(e38 == subsumed[i]); tst_dl_functor tst_fn; diff --git a/src/test/dl_context.cpp b/src/test/dl_context.cpp index 8a62dcb7d..e44c92f30 100644 --- a/src/test/dl_context.cpp +++ b/src/test/dl_context.cpp @@ -4,12 +4,12 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "datalog_parser.h" -#include "ast_pp.h" -#include "arith_decl_plugin.h" -#include "dl_context.h" -#include "smt_params.h" -#include "dl_register_engine.h" +#include "muz/fp/datalog_parser.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" +#include "muz/base/dl_context.h" +#include "smt/params/smt_params.h" +#include "muz/fp/dl_register_engine.h" using namespace datalog; @@ -51,12 +51,12 @@ static lbool dl_context_eval_unary_predicate(ast_manager & m, context & ctx, cha dealloc(p); func_decl * pred = ctx.try_get_predicate_decl(symbol(pred_name)); - SASSERT(pred); - SASSERT(pred->get_arity()==1); + ENSURE(pred); + ENSURE(pred->get_arity()==1); app_ref query_app(m.mk_app(pred, m.mk_var(0, pred->get_domain()[0])), m); lbool status = ctx.query(query_app); - SASSERT(status != l_undef); + ENSURE(status != l_undef); return status; } @@ -77,9 +77,9 @@ static void dl_context_simple_query_test(params_ref & params) { app_ref c_1(decl_util.mk_constant(1, res1->get_signature()[0]), m); relation_fact f(m); f.push_back(c_0); - SASSERT(res1->contains_fact(f)); + ENSURE(res1->contains_fact(f)); f[0]=c_1; - SASSERT(!res1->contains_fact(f)); + ENSURE(!res1->contains_fact(f)); #endif } diff --git a/src/test/dl_product_relation.cpp b/src/test/dl_product_relation.cpp index c375587fb..7cbbde450 100644 --- a/src/test/dl_product_relation.cpp +++ b/src/test/dl_product_relation.cpp @@ -5,11 +5,11 @@ Copyright (c) 2015 Microsoft Corporation --*/ #ifdef _WINDOWS -#include "dl_context.h" -#include "dl_register_engine.h" -#include "dl_finite_product_relation.h" -#include "dl_sparse_table.h" -#include "rel_context.h" +#include "muz/base/dl_context.h" +#include "muz/fp/dl_register_engine.h" +#include "muz/rel/dl_finite_product_relation.h" +#include "muz/rel/dl_sparse_table.h" +#include "muz/rel/rel_context.h" namespace datalog { @@ -37,12 +37,12 @@ namespace datalog { sparse_table_plugin & plugin = static_cast(*rctx.get_rmanager().get_table_plugin(symbol("sparse"))); - SASSERT(&plugin); + ENSURE(&plugin); table_signature sig2; sig2.push_back(2); sig2.push_back(2); sig2.set_functional_columns(1); - SASSERT(plugin.can_handle_signature(sig2)); + ENSURE(plugin.can_handle_signature(sig2)); table_fact f00; f00.push_back(0); @@ -56,32 +56,32 @@ namespace datalog { { table_aptr t0 = plugin.mk_empty(sig2); - SASSERT(t0->empty()); + ENSURE(t0->empty()); t0->add_fact(f00); - SASSERT(!t0->empty()); - SASSERT(t0->get_size_estimate_rows()==1); + ENSURE(!t0->empty()); + ENSURE(t0->get_size_estimate_rows()==1); t0->add_fact(f01); - SASSERT(t0->get_size_estimate_rows()==1); + ENSURE(t0->get_size_estimate_rows()==1); t0->add_fact(f11); - SASSERT(t0->get_size_estimate_rows()==2); + ENSURE(t0->get_size_estimate_rows()==2); unsigned rem_cols0[]={0}; scoped_ptr project0 = rmgr.mk_project_fn(*t0, 1, rem_cols0); table_aptr t1 = (*project0)(*t0); - SASSERT(t1->get_size_estimate_rows()==2); - SASSERT(t1->get_signature().functional_columns()==0); //project on non-functional column cancels functional + ENSURE(t1->get_size_estimate_rows()==2); + ENSURE(t1->get_signature().functional_columns()==0); //project on non-functional column cancels functional unsigned rem_cols1[]={1}; scoped_ptr project1 = rmgr.mk_project_fn(*t0, 1, rem_cols1); table_aptr t2 = (*project1)(*t0); - SASSERT(t2->get_size_estimate_rows()==2); + ENSURE(t2->get_size_estimate_rows()==2); idx_set acc; collector_of_reduced * reducer = alloc(collector_of_reduced, acc); scoped_ptr rproject = rmgr.mk_project_with_reduce_fn(*t0, 1, rem_cols0, reducer); table_aptr rt = (*rproject)(*t0); - SASSERT(acc.num_elems()==1); - SASSERT(rt->get_size_estimate_rows()==1); + ENSURE(acc.num_elems()==1); + ENSURE(rt->get_size_estimate_rows()==1); } { table_aptr t0 = plugin.mk_empty(sig2); @@ -90,44 +90,44 @@ namespace datalog { unsigned join_cols[]={1}; scoped_ptr join0 = rmgr.mk_join_fn(*t0, *t0, 1, join_cols, join_cols); table_aptr t1 = (*join0)(*t0, *t0); - SASSERT(t1->get_signature().size()==4); - SASSERT(t1->get_signature().functional_columns()==2); + ENSURE(t1->get_signature().size()==4); + ENSURE(t1->get_signature().functional_columns()==2); table_fact f0011; f0011.push_back(0); f0011.push_back(0); f0011.push_back(1); f0011.push_back(1); - SASSERT(t1->contains_fact(f0011)); + ENSURE(t1->contains_fact(f0011)); table_fact f0111 = f0011; f0111[1] = 1; - SASSERT(!t1->contains_fact(f0111)); + ENSURE(!t1->contains_fact(f0111)); } { table_aptr t0 = plugin.mk_empty(sig2); t0->display(std::cout<<"0:"); - SASSERT(t0->get_signature().functional_columns()==1); + ENSURE(t0->get_signature().functional_columns()==1); table_fact aux_fact; aux_fact = f01; TRUSTME( t0->suggest_fact(aux_fact) ); t0->display(std::cout<<"1:"); - SASSERT(t0->contains_fact(f01)); - SASSERT(aux_fact[1]==1); + ENSURE(t0->contains_fact(f01)); + ENSURE(aux_fact[1]==1); aux_fact = f00; TRUSTME( !t0->suggest_fact(aux_fact) ); t0->display(std::cout<<"2:"); - SASSERT(t0->contains_fact(f01)); - SASSERT(!t0->contains_fact(f00)); - SASSERT(aux_fact[1]==1); + ENSURE(t0->contains_fact(f01)); + ENSURE(!t0->contains_fact(f00)); + ENSURE(aux_fact[1]==1); t0->ensure_fact(f00); t0->display(std::cout<<"3:"); - SASSERT(t0->contains_fact(f00)); - SASSERT(!t0->contains_fact(f01)); + ENSURE(t0->contains_fact(f00)); + ENSURE(!t0->contains_fact(f01)); } } @@ -140,7 +140,7 @@ namespace datalog { relation_manager & rmgr = ctx.get_rel_context()->get_rmanager(); relation_plugin & rel_plugin = *rmgr.get_relation_plugin(params.get_sym("default_relation", symbol("sparse"))); - SASSERT(&rel_plugin); + ENSURE(&rel_plugin); finite_product_relation_plugin plg(rel_plugin, rmgr); sort_ref byte_srt_ref(dl_util.mk_sort(symbol("BYTE"), 256), m); @@ -194,9 +194,9 @@ namespace datalog { scoped_rel r2 = r1->clone(); scoped_rel r3 = r2->clone(); - SASSERT(!r1->contains_fact(f77)); + ENSURE(!r1->contains_fact(f77)); r1->add_fact(f77); - SASSERT(r1->contains_fact(f77)); + ENSURE(r1->contains_fact(f77)); r2->add_fact(f79); r3->add_fact(f99); @@ -207,34 +207,34 @@ namespace datalog { r2->display( std::cout << "r2 1\n"); r4->display( std::cout << "r4 0\n"); - SASSERT(!r4->contains_fact(f77)); - SASSERT(r4->contains_fact(f79)); + ENSURE(!r4->contains_fact(f77)); + ENSURE(r4->contains_fact(f79)); r4->add_fact(f77); r4->display( std::cout << "r4 1\n"); - SASSERT(r4->contains_fact(f77)); - SASSERT(r4->contains_fact(f79)); + ENSURE(r4->contains_fact(f77)); + ENSURE(r4->contains_fact(f79)); r4->add_fact(f99); r4->display( std::cout << "r4 2\n"); - SASSERT(r4->contains_fact(f99)); + ENSURE(r4->contains_fact(f99)); std::cout << "------ testing union ------\n"; r2->display( std::cout << "r2\n"); scoped_ptr union_op = rmgr.mk_union_fn(*r1, *r2, r3.get()); - SASSERT(union_op); + ENSURE(union_op); (*union_op)(*r1, *r2, r3.get()); r1->display( std::cout << "r1\n"); r2->display( std::cout << "r2\n"); r3->display( std::cout << "r3\n"); - SASSERT(r1->contains_fact(f77)); - SASSERT(r1->contains_fact(f79)); - SASSERT(!r1->contains_fact(f99)); + ENSURE(r1->contains_fact(f77)); + ENSURE(r1->contains_fact(f79)); + ENSURE(!r1->contains_fact(f99)); - SASSERT(!r3->contains_fact(f77)); - SASSERT(r3->contains_fact(f79)); - SASSERT(r3->contains_fact(f99)); + ENSURE(!r3->contains_fact(f77)); + ENSURE(r3->contains_fact(f79)); + ENSURE(r3->contains_fact(f99)); std::cout << "------ testing join ------\n"; @@ -264,9 +264,9 @@ namespace datalog { jr_rr->display( std::cout << "rr\n"); - SASSERT(!jr_tt->contains_fact(f7797)); - SASSERT(jr_tr->contains_fact(f7797)); - SASSERT(jr_rr->contains_fact(f7797)); + ENSURE(!jr_tt->contains_fact(f7797)); + ENSURE(jr_tr->contains_fact(f7797)); + ENSURE(jr_rr->contains_fact(f7797)); std::cout << "------ testing project ------\n"; @@ -288,17 +288,17 @@ namespace datalog { scoped_rel sr_2r = (*proj_2r)(*r31); scoped_rel sr_1t = (*proj_1t)(*r31); - SASSERT(sr_1r->contains_fact(f79)); - SASSERT(sr_1r->contains_fact(f97)); - SASSERT(!sr_1r->contains_fact(f77)); + ENSURE(sr_1r->contains_fact(f79)); + ENSURE(sr_1r->contains_fact(f97)); + ENSURE(!sr_1r->contains_fact(f77)); - SASSERT(sr_2r->contains_fact(f7)); - SASSERT(sr_2r->contains_fact(f9)); + ENSURE(sr_2r->contains_fact(f7)); + ENSURE(sr_2r->contains_fact(f9)); - SASSERT(sr_1t->contains_fact(f79)); - SASSERT(!sr_1t->contains_fact(f97)); - SASSERT(sr_1t->contains_fact(f77)); - SASSERT(sr_1t->contains_fact(f99)); + ENSURE(sr_1t->contains_fact(f79)); + ENSURE(!sr_1t->contains_fact(f97)); + ENSURE(sr_1t->contains_fact(f77)); + ENSURE(sr_1t->contains_fact(f99)); std::cout << "------ testing filter_interpreted ------\n"; @@ -314,8 +314,8 @@ namespace datalog { scoped_ptr i_filter = rmgr.mk_filter_interpreted_fn(*r41, cond); (*i_filter)(*r41); - SASSERT(r41->contains_fact(f7797)); - SASSERT(!r41->contains_fact(f7997)); + ENSURE(r41->contains_fact(f7797)); + ENSURE(!r41->contains_fact(f7997)); std::cout << "------ testing filter_by_negation ------\n"; @@ -334,9 +334,9 @@ namespace datalog { nf_r31_cols, nf_r1_cols); (*neg_filter)(*r31, *r1); - SASSERT(!r31->contains_fact(f779)); - SASSERT(r31->contains_fact(f977)); - SASSERT(r31->contains_fact(f799)); + ENSURE(!r31->contains_fact(f779)); + ENSURE(r31->contains_fact(f977)); + ENSURE(r31->contains_fact(f799)); } diff --git a/src/test/dl_query.cpp b/src/test/dl_query.cpp index e69f1fb13..c5765bd6b 100644 --- a/src/test/dl_query.cpp +++ b/src/test/dl_query.cpp @@ -4,15 +4,15 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "datalog_parser.h" -#include "ast_pp.h" -#include "dl_table_relation.h" -#include "dl_context.h" -#include "dl_register_engine.h" -#include "smt_params.h" -#include "stopwatch.h" -#include "reg_decl_plugins.h" -#include "dl_relation_manager.h" +#include "muz/fp/datalog_parser.h" +#include "ast/ast_pp.h" +#include "muz/rel/dl_table_relation.h" +#include "muz/base/dl_context.h" +#include "muz/fp/dl_register_engine.h" +#include "smt/params/smt_params.h" +#include "util/stopwatch.h" +#include "ast/reg_decl_plugins.h" +#include "muz/rel/dl_relation_manager.h" using namespace datalog; @@ -23,7 +23,7 @@ void dl_query_ask_ground_query(context & ctx, func_decl * pred, relation_fact & lbool is_sat = ctx.query(query); std::cerr << "@@ query should succeed: " << should_be_successful << "\n"; - SASSERT(is_sat != l_undef); + ENSURE(is_sat != l_undef); if((is_sat != l_true) == should_be_successful) { std::cerr<<"wrong ground query answer!\n"; UNREACHABLE(); @@ -80,13 +80,13 @@ void dl_query_test(ast_manager & m, smt_params & fparams, params_ref& params, func_decl * pred_b = *it; std::cerr << "Checking queries on relation " << pred_b->get_name() << "\n"; func_decl * pred_q = ctx_q.try_get_predicate_decl(symbol(pred_b->get_name().bare_str())); - SASSERT(pred_q); + ENSURE(pred_q); relation_base & rel_b = ctx_b.get_rel_context()->get_relation(pred_b); relation_signature sig_b = rel_b.get_signature(); relation_signature sig_q = ctx_q.get_rel_context()->get_relation(pred_q).get_signature(); - SASSERT(sig_b.size()==sig_q.size()); + ENSURE(sig_b.size()==sig_q.size()); std::cerr << "Queries on random facts...\n"; relation_fact f_b(m); @@ -164,7 +164,7 @@ void dl_query_test_wpa(smt_params & fparams, params_ref& params) { const unsigned attempts = 10; func_decl * v_pred = ctx.try_get_predicate_decl(symbol("V")); - SASSERT(v_pred); + ENSURE(v_pred); sort * var_sort = v_pred->get_domain(0); uint64 var_sz; @@ -180,7 +180,7 @@ void dl_query_test_wpa(smt_params & fparams, params_ref& params) { app_ref query_lit(m.mk_app(v_pred, q_args.c_ptr()), m); lbool is_sat = ctx.query(query_lit); - SASSERT(is_sat != l_undef); + ENSURE(is_sat != l_undef); bool found = is_sat == l_true; std::cerr<<"query finished: "<get_rmanager(); m.register_plugin(alloc(interval_relation_plugin, m)); interval_relation_plugin& ip = dynamic_cast(*m.get_relation_plugin(symbol("interval_relation"))); - SASSERT(&ip); + ENSURE(&ip); relation_signature sig; sort* int_sort = autil.mk_int(); @@ -38,8 +38,8 @@ namespace datalog { i1.display(std::cout); i2.display(std::cout); - SASSERT(i1.empty()); - SASSERT(!i2.empty()); + ENSURE(i1.empty()); + ENSURE(!i2.empty()); app_ref cond1(ast_m), cond2(ast_m), cond3(ast_m); app_ref cond4(ast_m), cond5(ast_m), cond6(ast_m); @@ -84,11 +84,11 @@ namespace datalog { fact1.push_back(autil.mk_numeral(rational(4), true)); fact1.push_back(autil.mk_numeral(rational(4), true)); fact1.push_back(autil.mk_numeral(rational(5), true)); - SASSERT(i2.contains_fact(fact1)); + ENSURE(i2.contains_fact(fact1)); fact1[0] = autil.mk_numeral(rational(-1), true); - SASSERT(i2.contains_fact(fact1)); + ENSURE(i2.contains_fact(fact1)); fact1[0] = autil.mk_numeral(rational(1), true); - SASSERT(!i2.contains_fact(fact1)); + ENSURE(!i2.contains_fact(fact1)); relation_base* i5 = (*ren1)(i2); i2.display(std::cout << "Orig\n"); @@ -97,7 +97,7 @@ namespace datalog { (*filterCond1)(i2); i2.display(std::cout); // empty - SASSERT(i2.empty()); + ENSURE(i2.empty()); relation_base* i4 = (*proj2)(*i3); i4->display(std::cout); @@ -128,7 +128,7 @@ namespace datalog { relation_manager & m = ctx.get_rel_context()->get_rmanager(); m.register_plugin(alloc(bound_relation_plugin, m)); bound_relation_plugin& br = dynamic_cast(*m.get_relation_plugin(symbol("bound_relation"))); - SASSERT(&br); + ENSURE(&br); relation_signature sig; sort* int_sort = autil.mk_int(); @@ -142,8 +142,8 @@ namespace datalog { i1.display(std::cout << "empty:\n"); i2.display(std::cout << "full:\n"); - SASSERT(i1.empty()); - SASSERT(!i2.empty()); + ENSURE(i1.empty()); + ENSURE(!i2.empty()); app_ref cond1(ast_m), cond2(ast_m), cond3(ast_m); app_ref cond4(ast_m), cond5(ast_m), cond6(ast_m); @@ -201,7 +201,7 @@ namespace datalog { relation_base* i5 = (*ren1)(i2); i5->display(std::cout); - //SASSERT(i2.empty()); + //ENSURE(i2.empty()); relation_base* i4 = (*proj2)(*i3); i4->display(std::cout); diff --git a/src/test/dl_table.cpp b/src/test/dl_table.cpp index 62eec34bc..326be5d04 100644 --- a/src/test/dl_table.cpp +++ b/src/test/dl_table.cpp @@ -3,16 +3,16 @@ Copyright (c) 2015 Microsoft Corporation --*/ #if defined(_WINDOWS) || defined(_CYGWIN) -#include "dl_context.h" -#include "dl_table.h" -#include "dl_register_engine.h" -#include "dl_relation_manager.h" +#include "muz/base/dl_context.h" +#include "muz/rel/dl_table.h" +#include "muz/fp/dl_register_engine.h" +#include "muz/rel/dl_relation_manager.h" typedef datalog::table_base* (*mk_table_fn)(datalog::relation_manager& m, datalog::table_signature& sig); static datalog::table_base* mk_bv_table(datalog::relation_manager& m, datalog::table_signature& sig) { datalog::table_plugin * p = m.get_table_plugin(symbol("bitvector")); - SASSERT(p); + ENSURE(p); return p->mk_empty(sig); } @@ -57,12 +57,12 @@ static void test_table(mk_table_fn mk_table) { std::cout << "\n"; } - SASSERT(table.contains_fact(row1)); - SASSERT(table.contains_fact(row2)); - SASSERT(!table.contains_fact(row3)); + ENSURE(table.contains_fact(row1)); + ENSURE(table.contains_fact(row2)); + ENSURE(!table.contains_fact(row3)); #if 0 table.remove_facts(1, &row1); - SASSERT(!table.contains_fact(row1)); + ENSURE(!table.contains_fact(row1)); #endif table.add_fact(row1); diff --git a/src/test/dl_util.cpp b/src/test/dl_util.cpp index 02e40bbd9..d30b23e47 100644 --- a/src/test/dl_util.cpp +++ b/src/test/dl_util.cpp @@ -4,7 +4,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "dl_util.h" +#include "muz/base/dl_util.h" using namespace datalog; @@ -22,7 +22,7 @@ void dl_util_two_array_sort() { datalog::sort_two_arrays(num, a1, a2); for(unsigned i=0; i result; // VERIFY(!m.intersect(*d1,*d0, result)); // m.subtract(*d1,*d0, result); - SASSERT(result.empty()); + ENSURE(result.empty()); dX = m.allocateX(); m.display(std::cout, *d0) << "\n"; m.display(std::cout, *dX) << "\n"; - SASSERT(m.contains(*dX,*d1)); - SASSERT(m.contains(*dX,*d0)); - SASSERT(!m.contains(*d0,*d1)); - SASSERT(!m.contains(*d1,*d0)); + ENSURE(m.contains(*dX,*d1)); + ENSURE(m.contains(*dX,*d0)); + ENSURE(!m.contains(*d0,*d1)); + ENSURE(!m.contains(*d1,*d0)); d1->neg().push_back(m.tbvm().allocate0()); @@ -88,14 +88,14 @@ static void tst_doc1(unsigned n) { doc_ref d1_2(m1, m1.allocate1()); m.display(std::cout, *d1) << " -> "; m1.display(std::cout, *d1_1) << "\n"; - SASSERT(m1.equals(*d1_1,*d1_2)); + ENSURE(m1.equals(*d1_1,*d1_2)); m.set(*d1,2,BIT_x); m.set(*d1,4,BIT_x); d1_1 = m.project(m1, to_delete, *d1); m.display(std::cout, *d1) << " -> "; m1.display(std::cout, *d1_1) << "\n"; d1->neg().push_back(m.tbvm().allocate1()); - SASSERT(m.well_formed(*d1)); + ENSURE(m.well_formed(*d1)); d1_1 = m.project(m1, to_delete, *d1); m.display(std::cout, *d1) << " -> "; m1.display(std::cout, *d1_1) << "\n"; @@ -146,11 +146,11 @@ class test_doc_cls { tbv_ref t(dm.tbvm()); t = mk_rand_tbv(); doc* result = dm.allocate(*t); - SASSERT(dm.tbvm().equals(*t, result->pos())); + ENSURE(dm.tbvm().equals(*t, result->pos())); for (unsigned i = 0; i < num_diff; ++i) { result->neg().push_back(mk_rand_tbv(result->pos())); } - SASSERT(dm.well_formed(*result)); + ENSURE(dm.well_formed(*result)); return result; } @@ -181,7 +181,7 @@ class test_doc_cls { expr_ref result(m); expr_ref_vector conjs(m); unsigned n = m2.num_tbits(); - SASSERT(n <= m_vars.size()); + ENSURE(n <= m_vars.size()); for (unsigned i = 0; i < n; ++i) { switch (t[i]) { case BIT_x: @@ -347,7 +347,7 @@ class test_doc_cls { tout << mk_pp(fml2, m) << "\n"; ); } - SASSERT(res == l_false); + ENSURE(res == l_false); } @@ -464,7 +464,7 @@ public: d2.display(dm, tout) << "\n";); d1.intersect(dm, d2); TRACE("doc", d1.display(dm, tout) << "\n";); - SASSERT(d1.well_formed(dm)); + ENSURE(d1.well_formed(dm)); fml3 = to_formula(d1, dm); fml1 = m.mk_and(fml1, fml2); check_equiv(fml1, fml3); diff --git a/src/test/escaped.cpp b/src/test/escaped.cpp index c776bd600..fe8f733bf 100644 --- a/src/test/escaped.cpp +++ b/src/test/escaped.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"util.h" +#include "util/util.h" void tst_escaped() { std::cout << "[" << escaped("\"hello\"\"world\"\n\n") << "]\n"; diff --git a/src/test/ex.cpp b/src/test/ex.cpp index e9243dd5b..591813814 100644 --- a/src/test/ex.cpp +++ b/src/test/ex.cpp @@ -17,7 +17,7 @@ Revision History: --*/ #include -#include"z3_exception.h" +#include "util/z3_exception.h" class ex { public: diff --git a/src/test/expr_rand.cpp b/src/test/expr_rand.cpp index 96d21a44c..f1b20ba8e 100644 --- a/src/test/expr_rand.cpp +++ b/src/test/expr_rand.cpp @@ -4,15 +4,15 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "expr_rand.h" -#include "ast_pp.h" -#include "bv_decl_plugin.h" -#include "array_decl_plugin.h" -#include "arith_decl_plugin.h" -#include "ast_smt_pp.h" +#include "test/fuzzing/expr_rand.h" +#include "ast/ast_pp.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_smt_pp.h" #include #include -#include "reg_decl_plugins.h" +#include "ast/reg_decl_plugins.h" static unsigned rand_seed = 1; @@ -98,8 +98,8 @@ void tst_expr_rand(char** argv, int argc, int& i) { i += 1; if (i + 1 < argc && 0 == strncmp(argv[i+1],"/rs:",3)) { rand_seed = atol(argv[i+1]+4); - std::cout << "random seed:" << rand_seed << "\n"; - i += 1; + std::cout << "random seed:" << rand_seed << "\n"; + i += 1; } if (i + 1 < argc && 0 == strcmp(argv[i+1],"/arith")) { diff --git a/src/test/expr_substitution.cpp b/src/test/expr_substitution.cpp index fdf1d6dc2..3b74535e7 100644 --- a/src/test/expr_substitution.cpp +++ b/src/test/expr_substitution.cpp @@ -4,15 +4,15 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "expr_substitution.h" -#include "smt_params.h" -#include "substitution.h" -#include "unifier.h" -#include "bv_decl_plugin.h" -#include "ast_pp.h" -#include "arith_decl_plugin.h" -#include "reg_decl_plugins.h" -#include "th_rewriter.h" +#include "ast/expr_substitution.h" +#include "smt/params/smt_params.h" +#include "ast/substitution/substitution.h" +#include "ast/substitution/unifier.h" +#include "ast/bv_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" +#include "ast/reg_decl_plugins.h" +#include "ast/rewriter/th_rewriter.h" expr* mk_bv_xor(bv_util& bv, expr* a, expr* b) { expr* args[2]; diff --git a/src/test/ext_numeral.cpp b/src/test/ext_numeral.cpp index 6f92b1372..003aa272f 100644 --- a/src/test/ext_numeral.cpp +++ b/src/test/ext_numeral.cpp @@ -17,8 +17,8 @@ Notes: --*/ #include -#include"mpq.h" -#include"ext_numeral.h" +#include "util/mpq.h" +#include "util/ext_numeral.h" #define MK_TST_UNARY(NAME) \ static void tst_ ## NAME(int a, ext_numeral_kind ak, int expected_c, ext_numeral_kind expected_ck) { \ @@ -26,11 +26,11 @@ static void tst_ ## NAME(int a, ext_numeral_kind ak, int expected_c, ext_numeral scoped_mpq _a(m); \ m.set(_a, a); \ NAME(m, _a, ak); \ - SASSERT(ak == expected_ck); \ + ENSURE(ak == expected_ck); \ if (expected_ck == EN_NUMERAL) { \ scoped_mpq _expected_c(m); \ m.set(_expected_c, expected_c); \ - SASSERT(m.eq(_a, _expected_c)); \ + ENSURE(m.eq(_a, _expected_c)); \ } \ } @@ -43,13 +43,13 @@ static void FUN_NAME(int a, ext_numeral_kind ak, int b, ext_numeral_kind bk, int scoped_mpq _a(m), _b(m), _c(m); \ m.set(_a, a); \ m.set(_b, b); \ - ext_numeral_kind ck; \ + ext_numeral_kind ck(EN_NUMERAL); \ OP_NAME(m, _a, ak, _b, bk, _c, ck); \ - SASSERT(ck == expected_ck); \ + ENSURE(ck == expected_ck); \ if (expected_ck == EN_NUMERAL) { \ scoped_mpq _expected_c(m); \ m.set(_expected_c, expected_c); \ - SASSERT(m.eq(_c, _expected_c)); \ + ENSURE(m.eq(_c, _expected_c)); \ } \ } @@ -340,52 +340,52 @@ static void tst2() { static void tst3() { unsynch_mpq_manager m; scoped_mpq a(m); - SASSERT(is_zero(m, a, EN_NUMERAL)); - SASSERT(!is_zero(m, a, EN_PLUS_INFINITY)); - SASSERT(!is_zero(m, a, EN_MINUS_INFINITY)); - SASSERT(!is_pos(m, a, EN_NUMERAL)); - SASSERT(is_pos(m, a, EN_PLUS_INFINITY)); - SASSERT(!is_pos(m, a, EN_MINUS_INFINITY)); - SASSERT(!is_infinite(EN_NUMERAL)); - SASSERT(is_infinite(EN_PLUS_INFINITY)); - SASSERT(is_infinite(EN_MINUS_INFINITY)); - SASSERT(!is_neg(m, a, EN_NUMERAL)); - SASSERT(!is_neg(m, a, EN_PLUS_INFINITY)); - SASSERT(is_neg(m, a, EN_MINUS_INFINITY)); + ENSURE(is_zero(m, a, EN_NUMERAL)); + ENSURE(!is_zero(m, a, EN_PLUS_INFINITY)); + ENSURE(!is_zero(m, a, EN_MINUS_INFINITY)); + ENSURE(!is_pos(m, a, EN_NUMERAL)); + ENSURE(is_pos(m, a, EN_PLUS_INFINITY)); + ENSURE(!is_pos(m, a, EN_MINUS_INFINITY)); + ENSURE(!is_infinite(EN_NUMERAL)); + ENSURE(is_infinite(EN_PLUS_INFINITY)); + ENSURE(is_infinite(EN_MINUS_INFINITY)); + ENSURE(!is_neg(m, a, EN_NUMERAL)); + ENSURE(!is_neg(m, a, EN_PLUS_INFINITY)); + ENSURE(is_neg(m, a, EN_MINUS_INFINITY)); m.set(a, 10); - SASSERT(!is_zero(m, a, EN_NUMERAL)); - SASSERT(is_pos(m, a, EN_NUMERAL)); - SASSERT(!is_neg(m, a, EN_NUMERAL)); - SASSERT(!is_infinite(EN_NUMERAL)); + ENSURE(!is_zero(m, a, EN_NUMERAL)); + ENSURE(is_pos(m, a, EN_NUMERAL)); + ENSURE(!is_neg(m, a, EN_NUMERAL)); + ENSURE(!is_infinite(EN_NUMERAL)); m.set(a, -5); - SASSERT(!is_zero(m, a, EN_NUMERAL)); - SASSERT(!is_pos(m, a, EN_NUMERAL)); - SASSERT(is_neg(m, a, EN_NUMERAL)); - SASSERT(!is_infinite(EN_NUMERAL)); + ENSURE(!is_zero(m, a, EN_NUMERAL)); + ENSURE(!is_pos(m, a, EN_NUMERAL)); + ENSURE(is_neg(m, a, EN_NUMERAL)); + ENSURE(!is_infinite(EN_NUMERAL)); ext_numeral_kind ak; ak = EN_MINUS_INFINITY; reset(m, a, ak); - SASSERT(is_zero(m, a, EN_NUMERAL)); + ENSURE(is_zero(m, a, EN_NUMERAL)); { std::ostringstream buffer; display(buffer, m, a, ak); - SASSERT(buffer.str() == "0"); + ENSURE(buffer.str() == "0"); } { std::ostringstream buffer; m.set(a, -10); display(buffer, m, a, ak); - SASSERT(buffer.str() == "-10"); + ENSURE(buffer.str() == "-10"); } { std::ostringstream buffer; display(buffer, m, a, EN_PLUS_INFINITY); - SASSERT(buffer.str() == "+oo"); + ENSURE(buffer.str() == "+oo"); } { std::ostringstream buffer; display(buffer, m, a, EN_MINUS_INFINITY); - SASSERT(buffer.str() == "-oo"); + ENSURE(buffer.str() == "-oo"); } } diff --git a/src/test/f2n.cpp b/src/test/f2n.cpp index 0ae9ea1dd..7831a31cf 100644 --- a/src/test/f2n.cpp +++ b/src/test/f2n.cpp @@ -15,9 +15,9 @@ Author: Revision History: --*/ -#include"f2n.h" -#include"hwf.h" -#include"mpf.h" +#include "util/f2n.h" +#include "util/hwf.h" +#include "util/mpf.h" static void tst1() { hwf_manager hm; diff --git a/src/test/factor_rewriter.cpp b/src/test/factor_rewriter.cpp index 3bcdcd9e9..486221e5b 100644 --- a/src/test/factor_rewriter.cpp +++ b/src/test/factor_rewriter.cpp @@ -4,10 +4,10 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "factor_rewriter.h" -#include "bv_decl_plugin.h" -#include "ast_pp.h" -#include "reg_decl_plugins.h" +#include "ast/rewriter/factor_rewriter.h" +#include "ast/bv_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/reg_decl_plugins.h" void tst_factor_rewriter() { ast_manager m; diff --git a/src/test/fixed_bit_vector.cpp b/src/test/fixed_bit_vector.cpp index 7bd9e62c3..f1c52a6a8 100644 --- a/src/test/fixed_bit_vector.cpp +++ b/src/test/fixed_bit_vector.cpp @@ -20,8 +20,8 @@ Revision History: --*/ #include #include -#include"fixed_bit_vector.h" -#include"vector.h" +#include "util/fixed_bit_vector.h" +#include "util/vector.h" static void tst1() { @@ -31,11 +31,11 @@ static void tst1() { m.set(*b, 0, true); m.set(*b, 1, false); m.set(*b, 2, true); - SASSERT(b->get(0) == true); - SASSERT(b->get(1) == false); - SASSERT(b->get(2) == true); - SASSERT(b->get(3) == false); - SASSERT(b->get(29) == false); + ENSURE(b->get(0) == true); + ENSURE(b->get(1) == false); + ENSURE(b->get(2) == true); + ENSURE(b->get(3) == false); + ENSURE(b->get(29) == false); m.deallocate(b); } @@ -55,11 +55,11 @@ static void tst_or() { m.display(std::cout, *b2) << "\n"; m.set_or(*b1, *b2); m.display(std::cout, *b1) << "\n"; - SASSERT(!m.equals(*b1, *b2)); + ENSURE(!m.equals(*b1, *b2)); m.unset(*b1, 4); - SASSERT(m.equals(*b1, *b2)); + ENSURE(m.equals(*b1, *b2)); m.unset(*b1, 3); - SASSERT(!m.equals(*b1, *b2)); + ENSURE(!m.equals(*b1, *b2)); m.deallocate(b1); m.deallocate(b2); } @@ -78,25 +78,25 @@ static void tst_eq(unsigned num_bits) { fixed_bit_vector* b3 = m.allocate0(); m.set(*b1, 3, true); - SASSERT(!m.equals(*b1, *b2)); - SASSERT(m.equals(*b2, *b3)); + ENSURE(!m.equals(*b1, *b2)); + ENSURE(m.equals(*b2, *b3)); m.set(*b3, 3, true); - SASSERT(m.equals(*b1, *b3)); + ENSURE(m.equals(*b1, *b3)); m.set(*b2, num_bits-1, true); m.set(*b3, num_bits-1); m.unset(*b3, 3); - SASSERT(m.equals(*b2, *b3)); + ENSURE(m.equals(*b2, *b3)); m.fill0(*b1); m.set_neg(*b1); m.fill1(*b2); - SASSERT(m.equals(*b1, *b2)); + ENSURE(m.equals(*b1, *b2)); m.fill0(*b1); for (unsigned i = 0; i < num_bits; ++i) { m.set(*b1, i, true); } - SASSERT(m.equals(*b1, *b2)); + ENSURE(m.equals(*b1, *b2)); m.deallocate(b1); m.deallocate(b2); m.deallocate(b3); diff --git a/src/test/for_each_file.cpp b/src/test/for_each_file.cpp index d217aa5f1..eeec69156 100644 --- a/src/test/for_each_file.cpp +++ b/src/test/for_each_file.cpp @@ -21,7 +21,7 @@ Revision History: #include #include #include -#include "for_each_file.h" +#include "test/for_each_file.h" bool for_each_file(for_each_file_proc& proc, const char* base, const char* suffix) { diff --git a/src/test/fuzzing/expr_delta.cpp b/src/test/fuzzing/expr_delta.cpp index fd5117a74..8e94a84ce 100644 --- a/src/test/fuzzing/expr_delta.cpp +++ b/src/test/fuzzing/expr_delta.cpp @@ -4,8 +4,8 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "expr_delta.h" -#include "ast_pp.h" +#include "test/fuzzing/expr_delta.h" +#include "ast/ast_pp.h" expr_delta::expr_delta(ast_manager& m) : m_manager(m), m_exprs(m) {} diff --git a/src/test/fuzzing/expr_delta.h b/src/test/fuzzing/expr_delta.h index 2c68efb40..d69ed33f1 100644 --- a/src/test/fuzzing/expr_delta.h +++ b/src/test/fuzzing/expr_delta.h @@ -20,7 +20,7 @@ Revision History: #ifndef EXPR_DELTA_H_ #define EXPR_DELTA_H_ -#include "ast.h" +#include "ast/ast.h" class expr_delta { ast_manager& m_manager; diff --git a/src/test/fuzzing/expr_rand.cpp b/src/test/fuzzing/expr_rand.cpp index ccc4a9e5c..1d425e9e1 100644 --- a/src/test/fuzzing/expr_rand.cpp +++ b/src/test/fuzzing/expr_rand.cpp @@ -4,11 +4,11 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "expr_rand.h" -#include "bv_decl_plugin.h" -#include "array_decl_plugin.h" -#include "arith_decl_plugin.h" -#include "ast_pp.h" +#include "test/fuzzing/expr_rand.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_pp.h" expr_rand::expr_rand(ast_manager& m): diff --git a/src/test/fuzzing/expr_rand.h b/src/test/fuzzing/expr_rand.h index bbadd587e..4cdee81fd 100644 --- a/src/test/fuzzing/expr_rand.h +++ b/src/test/fuzzing/expr_rand.h @@ -19,8 +19,8 @@ Revision History: #ifndef EXPR_RAND_H_ #define EXPR_RAND_H_ -#include"ast.h" -#include"obj_hashtable.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" class expr_rand { ast_manager& m_manager; diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index f7da4edd7..6d600f594 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -3,15 +3,15 @@ Copyright (c) 2016 Microsoft Corporation --*/ -#include "inc_sat_solver.h" -#include "bv_decl_plugin.h" -#include "datatype_decl_plugin.h" -#include "reg_decl_plugins.h" -#include "ast_pp.h" -#include "dt2bv_tactic.h" -#include "tactic.h" -#include "model_smt2_pp.h" -#include "fd_solver.h" +#include "sat/sat_solver/inc_sat_solver.h" +#include "ast/bv_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" +#include "ast/reg_decl_plugins.h" +#include "ast/ast_pp.h" +#include "tactic/bv/dt2bv_tactic.h" +#include "tactic/tactic.h" +#include "model/model_smt2_pp.h" +#include "tactic/portfolio/fd_solver.h" static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { return expr_ref(m.mk_const(symbol(name), s), m); @@ -65,9 +65,8 @@ void test2() { constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, 0); constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, 0); constructor_decl* constrs[3] = { R, G, B }; - datatype_decl * enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs); - VERIFY(dt.mk_datatypes(1, &enum_sort, 0, 0, new_sorts)); - del_constructor_decls(3, constrs); + datatype_decl * enum_sort = mk_datatype_decl(dtutil, symbol("RGB"), 0, nullptr, 3, constrs); + VERIFY(dt.mk_datatypes(1, &enum_sort, 0, nullptr, new_sorts)); sort* rgb = new_sorts[0].get(); expr_ref x = mk_const(m, "x", rgb), y = mk_const(m, "y", rgb), z = mk_const(m, "z", rgb); @@ -104,7 +103,7 @@ void test2() { VERIFY(l_true == fd_solver->check_sat(0,0)); fd_solver->get_model(mr); - SASSERT(mr.get()); + ENSURE(mr.get()); model_smt2_pp(std::cout, m, *mr.get(), 0); } diff --git a/src/test/get_implied_equalities.cpp b/src/test/get_implied_equalities.cpp index 37fbe2004..952fb121a 100644 --- a/src/test/get_implied_equalities.cpp +++ b/src/test/get_implied_equalities.cpp @@ -4,9 +4,9 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "z3.h" -#include "trace.h" -#include "debug.h" +#include "api/z3.h" +#include "util/trace.h" +#include "util/debug.h" static Z3_ast mk_var(Z3_context ctx, char const* name, Z3_sort s) { return Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, name), s); @@ -47,13 +47,13 @@ static void tst_get_implied_equalities1() { for (i = 0; i < num_terms; ++i) { printf("Class %s |-> %d\n", Z3_ast_to_string(ctx, terms[i]), class_ids[i]); } - SASSERT(class_ids[1] == class_ids[0]); - SASSERT(class_ids[2] != class_ids[0]); - SASSERT(class_ids[3] == class_ids[0]); - SASSERT(class_ids[4] != class_ids[0]); - SASSERT(class_ids[5] != class_ids[0]); - SASSERT(class_ids[6] != class_ids[0]); - SASSERT(class_ids[4] == class_ids[5]); + ENSURE(class_ids[1] == class_ids[0]); + ENSURE(class_ids[2] != class_ids[0]); + ENSURE(class_ids[3] == class_ids[0]); + ENSURE(class_ids[4] != class_ids[0]); + ENSURE(class_ids[5] != class_ids[0]); + ENSURE(class_ids[6] != class_ids[0]); + ENSURE(class_ids[4] == class_ids[5]); printf("asserting b <= f(a)\n"); Z3_solver_assert(ctx, solver, Z3_mk_le(ctx, b, fa)); @@ -61,12 +61,12 @@ static void tst_get_implied_equalities1() { for (i = 0; i < num_terms; ++i) { printf("Class %s |-> %d\n", Z3_ast_to_string(ctx, terms[i]), class_ids[i]); } - SASSERT(class_ids[1] == class_ids[0]); - SASSERT(class_ids[2] != class_ids[0]); - SASSERT(class_ids[3] == class_ids[0]); - SASSERT(class_ids[4] == class_ids[0]); - SASSERT(class_ids[5] == class_ids[0]); - SASSERT(class_ids[6] == class_ids[0]); + ENSURE(class_ids[1] == class_ids[0]); + ENSURE(class_ids[2] != class_ids[0]); + ENSURE(class_ids[3] == class_ids[0]); + ENSURE(class_ids[4] == class_ids[0]); + ENSURE(class_ids[5] == class_ids[0]); + ENSURE(class_ids[6] == class_ids[0]); Z3_solver_dec_ref(ctx, solver); @@ -103,15 +103,15 @@ static void tst_get_implied_equalities2() { printf("Class %s |-> %d\n", Z3_ast_to_string(ctx, terms[i]), class_ids[i]); } - SASSERT(class_ids[1] != class_ids[0]); - SASSERT(class_ids[2] != class_ids[0]); - SASSERT(class_ids[3] != class_ids[0]); - SASSERT(class_ids[4] != class_ids[0]); - SASSERT(class_ids[4] == class_ids[2]); - SASSERT(class_ids[2] != class_ids[1]); - SASSERT(class_ids[3] != class_ids[1]); - SASSERT(class_ids[4] != class_ids[1]); - SASSERT(class_ids[3] != class_ids[2]); + ENSURE(class_ids[1] != class_ids[0]); + ENSURE(class_ids[2] != class_ids[0]); + ENSURE(class_ids[3] != class_ids[0]); + ENSURE(class_ids[4] != class_ids[0]); + ENSURE(class_ids[4] == class_ids[2]); + ENSURE(class_ids[2] != class_ids[1]); + ENSURE(class_ids[3] != class_ids[1]); + ENSURE(class_ids[4] != class_ids[1]); + ENSURE(class_ids[3] != class_ids[2]); /* delete logical context */ Z3_solver_dec_ref(ctx, solver); diff --git a/src/test/hashtable.cpp b/src/test/hashtable.cpp index 47fae454a..befd0b8e9 100644 --- a/src/test/hashtable.cpp +++ b/src/test/hashtable.cpp @@ -21,12 +21,8 @@ Revision History: #include #include -#include"hashtable.h" +#include "util/hashtable.h" -#ifndef Z3DEBUG -#undef SASSERT -#define SASSERT(COND) { if (!(COND)) std::cerr << "ERROR: " << #COND << "\n"; } ((void) 0) -#endif struct int_hash_proc { unsigned operator()(int x) const { return x * 3; } }; typedef int_hashtable > int_set; @@ -48,16 +44,16 @@ static void tst1() { int v = rand() % (N / 2); h1.insert(v); vals[i] = v; - SASSERT(contains(h1, v)); + ENSURE(contains(h1, v)); } std::cout << "step1\n"; std::cout.flush(); for (int i = 1; i < N; i ++) { - SASSERT(contains(h1, vals[i])); + ENSURE(contains(h1, vals[i])); } std::cout << "step2\n"; std::cout.flush(); for (int i = 1; i < N; i += 2) { h1.erase(vals[i]); - SASSERT(!contains(h1, vals[i])); + ENSURE(!contains(h1, vals[i])); } std::cout << "step3\n"; std::cout.flush(); for (int i = 1; i < N; i += 2) { @@ -65,7 +61,7 @@ static void tst1() { } std::cout << "step4\n"; std::cout.flush(); for (int i = 1; i < N; i ++) { - SASSERT(contains(h1, vals[i])); + ENSURE(contains(h1, vals[i])); } } @@ -78,19 +74,19 @@ static void tst2() { if (rand() % 3 == 2) { h1.erase(v); h2.erase(v); - SASSERT(!contains(h1, v)); + ENSURE(!contains(h1, v)); } else { h1.insert(v); h2.insert(v); - SASSERT(contains(h1, v)); + ENSURE(contains(h1, v)); } } { safe_int_set::iterator it = h2.begin(); safe_int_set::iterator end = h2.end(); for(; it != end; ++it) { - SASSERT(contains(h1, *it)); + ENSURE(contains(h1, *it)); } } { @@ -98,12 +94,12 @@ static void tst2() { int_set::iterator end = h1.end(); int n = 0; for (; it != end; ++it) { - SASSERT(contains(h1, *it)); + ENSURE(contains(h1, *it)); n++; } - SASSERT(n == h1.size()); + ENSURE(n == h1.size()); } - SASSERT(h1.size() == h2.size()); + ENSURE(h1.size() == h2.size()); // std::cout << "size: " << h1.size() << ", capacity: " << h1.capacity() << "\n"; std::cout.flush(); } @@ -114,13 +110,13 @@ static void tst3() { h1.insert(30); h1.erase(20); int_set h2(h1); - SASSERT(h1.contains(10)); - SASSERT(!h1.contains(20)); - SASSERT(h1.contains(30)); - SASSERT(h2.contains(10)); - SASSERT(!h2.contains(20)); - SASSERT(h2.contains(30)); - SASSERT(h2.size() == 2); + ENSURE(h1.contains(10)); + ENSURE(!h1.contains(20)); + ENSURE(h1.contains(30)); + ENSURE(h2.contains(10)); + ENSURE(!h2.contains(20)); + ENSURE(h2.contains(30)); + ENSURE(h2.size() == 2); } void tst_hashtable() { diff --git a/src/test/heap.cpp b/src/test/heap.cpp index 17f9cfaa0..39353af76 100644 --- a/src/test/heap.cpp +++ b/src/test/heap.cpp @@ -17,9 +17,10 @@ Revision History: --*/ #include -#include"heap.h" -#include"hashtable.h" -#include"trace.h" +#include "util/util.h" +#include "util/heap.h" +#include "util/hashtable.h" +#include "util/trace.h" struct lt_proc { bool operator()(int v1, int v2) const { return v1 < v2; } }; typedef heap int_heap; @@ -27,46 +28,49 @@ struct int_hash_proc { unsigned operator()(int v) const { return v * 17; }}; typedef int_hashtable > int_set; #define N 10000 +static random_gen heap_rand(1); + static void tst1() { int_heap h(N); int_set t; for (int i = 0; i < N * 3; i++) { - int val = rand() % N; + int val = heap_rand() % N; if (!h.contains(val)) { - SASSERT(!t.contains(val)); + ENSURE(!t.contains(val)); h.insert(val); t.insert(val); } else { - SASSERT(t.contains(val)); + ENSURE(t.contains(val)); } } - SASSERT(h.check_invariant()); + ENSURE(h.check_invariant()); int_set::iterator it = t.begin(); int_set::iterator end = t.end(); for (; it != end; ++it) { - SASSERT(h.contains(*it)); + ENSURE(h.contains(*it)); } while (!h.empty()) { int m1 = h.min_value(); int m2 = h.erase_min(); (void)m1; (void)m2; - SASSERT(m1 == m2); - SASSERT(-1 < m2); + ENSURE(m1 == m2); + ENSURE(-1 < m2); } } int g_value[N]; -struct lt_proc2 { bool operator()(int v1, int v2) const { SASSERT(v1 < N && v2 < N); return g_value[v1] < g_value[v2]; } }; +struct lt_proc2 { bool operator()(int v1, int v2) const { ENSURE(v1 < N && v2 < N); return g_value[v1] < g_value[v2]; } }; typedef heap int_heap2; static void init_values() { for (unsigned i = 0; i < N; i++) - g_value[i] = rand(); + g_value[i] = heap_rand(); } +#ifdef _TRACE static void dump_heap(const int_heap2 & h, std::ostream & out) { // int_heap2::const_iterator it = h.begin(); // int_heap2::const_iterator end = h.end(); @@ -75,37 +79,37 @@ static void dump_heap(const int_heap2 & h, std::ostream & out) { // } // out << "\n"; } +#endif static void tst2() { - (void)dump_heap; int_heap2 h(N); for (int i = 0; i < N * 10; i++) { if (i % 1000 == 0) std::cout << "i: " << i << std::endl; - int cmd = rand() % 10; + int cmd = heap_rand() % 10; if (cmd <= 3) { // insert - int val = rand() % N; + int val = heap_rand() % N; if (!h.contains(val)) { TRACE("heap", tout << "inserting: " << val << "\n";); h.insert(val); TRACE("heap", dump_heap(h, tout);); - SASSERT(h.contains(val)); + ENSURE(h.contains(val)); } } else if (cmd <= 6) { - int val = rand() % N; + int val = heap_rand() % N; if (h.contains(val)) { TRACE("heap", tout << "removing: " << val << "\n";); h.erase(val); TRACE("heap", dump_heap(h, tout);); - SASSERT(!h.contains(val)); + ENSURE(!h.contains(val)); } } else if (cmd <= 8) { // increased & decreased - int val = rand() % N; + int val = heap_rand() % N; int old_v = g_value[val]; - int new_v = rand(); + int new_v = heap_rand(); if (h.contains(val)) { g_value[val] = new_v; if (old_v < new_v) { @@ -119,17 +123,21 @@ static void tst2() { } } else { - SASSERT(h.check_invariant()); + ENSURE(h.check_invariant()); } } - SASSERT(h.check_invariant()); + ENSURE(h.check_invariant()); } void tst_heap() { // enable_debug("heap"); enable_trace("heap"); - tst1(); - init_values(); - tst2(); + unsigned i = 0; + while (i < 3) { + heap_rand.set_seed(i++); + tst1(); + init_values(); + tst2(); + } } diff --git a/src/test/heap_trie.cpp b/src/test/heap_trie.cpp index 5b0047e82..b6f651633 100644 --- a/src/test/heap_trie.cpp +++ b/src/test/heap_trie.cpp @@ -4,7 +4,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "heap_trie.h" +#include "math/hilbert/heap_trie.h" struct unsigned_le { static bool le(unsigned i, unsigned j) { return i <= j; } diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index b46ede849..7329b1d3d 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -4,15 +4,15 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "hilbert_basis.h" -#include "ast_pp.h" -#include "reg_decl_plugins.h" -#include "arith_decl_plugin.h" -#include "quant_tactics.h" -#include "tactic.h" -#include "tactic2solver.h" -#include "solver.h" -#include "rlimit.h" +#include "math/hilbert/hilbert_basis.h" +#include "ast/ast_pp.h" +#include "ast/reg_decl_plugins.h" +#include "ast/arith_decl_plugin.h" +#include "tactic/smtlogics/quant_tactics.h" +#include "tactic/tactic.h" +#include "solver/tactic2solver.h" +#include "solver/solver.h" +#include "util/rlimit.h" #include #include #include @@ -286,8 +286,8 @@ static void gorrila_test(unsigned seed, unsigned n, unsigned k, unsigned bound, random_gen rand(seed); reslimit rl; hilbert_basis hb(rl); - SASSERT(0 < bound); - SASSERT(k <= n); + ENSURE(0 < bound); + ENSURE(k <= n); int ibound = static_cast(bound); for (unsigned i = 0; i < num_ineqs; ++i) { vector nv; diff --git a/src/test/horn_subsume_model_converter.cpp b/src/test/horn_subsume_model_converter.cpp index 4b653e3a8..a361cfb2a 100644 --- a/src/test/horn_subsume_model_converter.cpp +++ b/src/test/horn_subsume_model_converter.cpp @@ -5,10 +5,10 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "horn_subsume_model_converter.h" -#include "arith_decl_plugin.h" -#include "model_smt2_pp.h" -#include "reg_decl_plugins.h" +#include "tactic/horn_subsume_model_converter.h" +#include "ast/arith_decl_plugin.h" +#include "model/model_smt2_pp.h" +#include "ast/reg_decl_plugins.h" void tst_horn_subsume_model_converter() { ast_manager m; diff --git a/src/test/hwf.cpp b/src/test/hwf.cpp index 7a030a452..697673473 100644 --- a/src/test/hwf.cpp +++ b/src/test/hwf.cpp @@ -16,25 +16,25 @@ Author: Revision History: --*/ -#include"hwf.h" -#include"f2n.h" -#include"rational.h" +#include "util/hwf.h" +#include "util/f2n.h" +#include "util/rational.h" static void bug_set_double() { hwf_manager m; hwf a; m.set(a, 0.1); - SASSERT(m.is_regular(a)); + ENSURE(m.is_regular(a)); m.set(a, 1.1); - SASSERT(m.is_regular(a)); + ENSURE(m.is_regular(a)); m.set(a, 11.3); - SASSERT(m.is_regular(a)); + ENSURE(m.is_regular(a)); m.set(a, 0.0); - SASSERT(m.is_regular(a)); + ENSURE(m.is_regular(a)); } static void bug_to_rational() { @@ -62,31 +62,31 @@ static void bug_to_rational() { m.to_rational(a, r); ad = m.to_double(a); rd = mq.get_double(r); - SASSERT(ad == rd); + ENSURE(ad == rd); m.set(a, 0.875); m.to_rational(a, r); ad = m.to_double(a); rd = mq.get_double(r); - SASSERT(ad == rd); + ENSURE(ad == rd); m.set(a, -1.0); m.to_rational(a, r); ad = m.to_double(a); rd = mq.get_double(r); - SASSERT(ad == rd); + ENSURE(ad == rd); m.set(a, -1.5); m.to_rational(a, r); ad = m.to_double(a); rd = mq.get_double(r); - SASSERT(ad == rd); + ENSURE(ad == rd); m.set(a, -0.875); m.to_rational(a, r); ad = m.to_double(a); rd = mq.get_double(r); - SASSERT(ad == rd); + ENSURE(ad == rd); m.set(a, 0.1); m.to_rational(a, r); @@ -96,7 +96,7 @@ static void bug_to_rational() { // CMW: This one depends on the rounding mode, // which is implicit in both hwf::set and in mpq::to_double. double diff = (ad-rd); - SASSERT(diff >= -DBL_EPSILON && diff <= DBL_EPSILON); + ENSURE(diff >= -DBL_EPSILON && diff <= DBL_EPSILON); #endif } @@ -107,7 +107,7 @@ static void bug_is_int() { hwf_manager m; hwf a; m.set(a, val); - SASSERT(!m.is_int(a)); + ENSURE(!m.is_int(a)); } void tst_hwf() { diff --git a/src/test/im_float_config.h b/src/test/im_float_config.h index 2f33172a1..3905358ea 100644 --- a/src/test/im_float_config.h +++ b/src/test/im_float_config.h @@ -19,9 +19,9 @@ Revision History: #ifndef IM_FLOAT_CONFIG_H_ #define IM_FLOAT_CONFIG_H_ -#include"f2n.h" -#include"mpf.h" -#include"hwf.h" +#include "util/f2n.h" +#include "util/mpf.h" +#include "util/hwf.h" template class im_float_config { @@ -63,10 +63,4 @@ public: numeral_manager & m() const { return const_cast(m_manager); } }; -template -inline void del_f_interval(im_float_config & cfg, typename im_float_config::interval & a) { - cfg.m().del(a.m_lower); - cfg.m().del(a.m_upper); -} - #endif diff --git a/src/test/inf_rational.cpp b/src/test/inf_rational.cpp index 1b0a293ce..634bae7c1 100644 --- a/src/test/inf_rational.cpp +++ b/src/test/inf_rational.cpp @@ -18,13 +18,13 @@ Revision History: --*/ -#include"inf_rational.h" +#include "util/inf_rational.h" static void tst0() { inf_rational n(rational(0), false); TRACE("inf_rational", tout << n << "\n";); - SASSERT(n < inf_rational::zero()); - SASSERT(!(n >= inf_rational::zero())); + ENSURE(n < inf_rational::zero()); + ENSURE(!(n >= inf_rational::zero())); } void test_inc_dec( @@ -36,44 +36,44 @@ void test_inc_dec( ) { r += rational(1,5); - SASSERT (r == b_8_5); + ENSURE (r == b_8_5); r -= rational(1,5); - SASSERT (r == b_7_5); + ENSURE (r == b_7_5); r += inf_rational(1,5); - SASSERT (r == b_8_5); + ENSURE (r == b_8_5); r -= inf_rational(1,5); - SASSERT (r == b_7_5); + ENSURE (r == b_7_5); r /= rational(2,1); - SASSERT (r == b_7_10); + ENSURE (r == b_7_10); inf_rational r_pre = r++; - SASSERT (r_pre == b_7_10); - SASSERT (r == b_17_10); + ENSURE (r_pre == b_7_10); + ENSURE (r == b_17_10); inf_rational r_post = --r; - SASSERT (r_post == b_7_10); - SASSERT (r == b_7_10); + ENSURE (r_post == b_7_10); + ENSURE (r == b_7_10); r_post = ++r; - SASSERT (r_post == b_17_10); - SASSERT (r == b_17_10); + ENSURE (r_post == b_17_10); + ENSURE (r == b_17_10); r_pre = r--; - SASSERT (r_pre == b_17_10); - SASSERT (r == b_7_10); + ENSURE (r_pre == b_17_10); + ENSURE (r == b_7_10); r_pre = r; r_pre += inf_rational(1,2); r_post = r_pre; r_post -= inf_rational(1,2); - SASSERT(r == r_post); - SASSERT(r + inf_rational(1,2) == r_pre); + ENSURE(r == r_post); + ENSURE(r + inf_rational(1,2) == r_pre); r_pre = r; r_pre /= rational(2,1); r_post = r_pre; r_post /= rational(1,2); - SASSERT(r == r_post); - SASSERT(rational(1,2) * r == r_pre); - SASSERT(r == r_pre / rational(1,2)); + ENSURE(r == r_post); + ENSURE(rational(1,2) * r == r_pre); + ENSURE(r == r_pre / rational(1,2)); } @@ -84,27 +84,27 @@ tst_inf_rational() inf_rational r1; inf_rational r2(r1); - SASSERT (r1 == r2); + ENSURE (r1 == r2); inf_rational r3(1); inf_rational r4(0); - SASSERT (r4 == r1); - SASSERT (r3 != r4); + ENSURE (r4 == r1); + ENSURE (r3 != r4); inf_rational r5(0,1); inf_rational r6(1,1); inf_rational r7(2,2); inf_rational r8(7,5); - SASSERT (r1 == r5); - SASSERT (r6 == r3); - SASSERT (r7 == r3); + ENSURE (r1 == r5); + ENSURE (r6 == r3); + ENSURE (r7 == r3); inf_rational r9(rational(7,5)); - SASSERT (r8 == r9); + ENSURE (r8 == r9); r9.reset(); - SASSERT (r1 == r9); - SASSERT (r1.is_int()); - SASSERT (!r8.is_int()); - SASSERT (0 == r1.get_int64()); + ENSURE (r1 == r9); + ENSURE (r1.is_int()); + ENSURE (!r8.is_int()); + ENSURE (0 == r1.get_int64()); r9 = r8; - SASSERT (r8 == r9); + ENSURE (r8 == r9); inf_rational n = numerator(r7); inf_rational d = denominator(r7); @@ -130,50 +130,50 @@ tst_inf_rational() } - SASSERT(inf_rational(rational(1,2),true) > inf_rational(rational(1,2))); - SASSERT(inf_rational(rational(1,2),false) < inf_rational(rational(1,2))); - SASSERT(inf_rational(rational(1,2),true) >= inf_rational(rational(1,2))); - SASSERT(inf_rational(rational(1,2)) >= inf_rational(rational(1,2),false)); - SASSERT(inf_rational(rational(1,2),false) != inf_rational(rational(1,2))); - SASSERT(inf_rational(rational(1,2),true) != inf_rational(rational(1,2))); - SASSERT(inf_rational(rational(1,2),false) != inf_rational(rational(1,2),true)); + ENSURE(inf_rational(rational(1,2),true) > inf_rational(rational(1,2))); + ENSURE(inf_rational(rational(1,2),false) < inf_rational(rational(1,2))); + ENSURE(inf_rational(rational(1,2),true) >= inf_rational(rational(1,2))); + ENSURE(inf_rational(rational(1,2)) >= inf_rational(rational(1,2),false)); + ENSURE(inf_rational(rational(1,2),false) != inf_rational(rational(1,2))); + ENSURE(inf_rational(rational(1,2),true) != inf_rational(rational(1,2))); + ENSURE(inf_rational(rational(1,2),false) != inf_rational(rational(1,2),true)); inf_rational h_neg(rational(1,2),false); inf_rational h_pos(rational(1,2),true); h_neg.neg(); - SASSERT(h_neg == -inf_rational(rational(1,2),false)); + ENSURE(h_neg == -inf_rational(rational(1,2),false)); h_neg.neg(); - SASSERT(h_neg == inf_rational(rational(1,2),false)); + ENSURE(h_neg == inf_rational(rational(1,2),false)); - SASSERT(r1.is_zero() && !r1.is_one() && !r1.is_neg() && r1.is_nonneg() && r1.is_nonpos() && !r1.is_pos()); - SASSERT(!r3.is_zero() && r3.is_one() && !r3.is_neg() && r3.is_nonneg() && !r3.is_nonpos() && r3.is_pos()); + ENSURE(r1.is_zero() && !r1.is_one() && !r1.is_neg() && r1.is_nonneg() && r1.is_nonpos() && !r1.is_pos()); + ENSURE(!r3.is_zero() && r3.is_one() && !r3.is_neg() && r3.is_nonneg() && !r3.is_nonpos() && r3.is_pos()); - SASSERT(floor(inf_rational(rational(1,2),false)) == rational()); - SASSERT(floor(inf_rational(rational(1,2))) == rational()); - SASSERT(floor(inf_rational(rational(),false)) == rational(-1)); - SASSERT(floor(inf_rational(rational())) == rational()); - SASSERT(floor(inf_rational(rational(),true)) == rational()); - SASSERT(floor(inf_rational(rational(1),false)) == rational()); - SASSERT(floor(inf_rational(rational(1))) == rational(1)); - SASSERT(floor(inf_rational(rational(1),true)) == rational(1)); + ENSURE(floor(inf_rational(rational(1,2),false)) == rational()); + ENSURE(floor(inf_rational(rational(1,2))) == rational()); + ENSURE(floor(inf_rational(rational(),false)) == rational(-1)); + ENSURE(floor(inf_rational(rational())) == rational()); + ENSURE(floor(inf_rational(rational(),true)) == rational()); + ENSURE(floor(inf_rational(rational(1),false)) == rational()); + ENSURE(floor(inf_rational(rational(1))) == rational(1)); + ENSURE(floor(inf_rational(rational(1),true)) == rational(1)); - SASSERT(ceil(inf_rational(rational(1,2),false)) == rational(1)); - SASSERT(ceil(inf_rational(rational(1,2))) == rational(1)); - SASSERT(ceil(inf_rational(rational(),false)) == rational()); - SASSERT(ceil(inf_rational(rational())) == rational()); - SASSERT(ceil(inf_rational(rational(),true)) == rational(1)); - SASSERT(ceil(inf_rational(rational(1),false)) == rational(1)); - SASSERT(ceil(inf_rational(rational(1))) == rational(1)); - SASSERT(ceil(inf_rational(rational(1),true)) == rational(2)); + ENSURE(ceil(inf_rational(rational(1,2),false)) == rational(1)); + ENSURE(ceil(inf_rational(rational(1,2))) == rational(1)); + ENSURE(ceil(inf_rational(rational(),false)) == rational()); + ENSURE(ceil(inf_rational(rational())) == rational()); + ENSURE(ceil(inf_rational(rational(),true)) == rational(1)); + ENSURE(ceil(inf_rational(rational(1),false)) == rational(1)); + ENSURE(ceil(inf_rational(rational(1))) == rational(1)); + ENSURE(ceil(inf_rational(rational(1),true)) == rational(2)); inf_rational x(rational(1,2),true); inf_rational y(1,2); x.swap(y); - SASSERT (x == inf_rational(1,2)); - SASSERT (y == inf_rational(rational(1,2),true)); + ENSURE (x == inf_rational(1,2)); + ENSURE (y == inf_rational(rational(1,2),true)); - SASSERT(inf_rational(1,2) == abs(-inf_rational(1,2))); + ENSURE(inf_rational(1,2) == abs(-inf_rational(1,2))); } diff --git a/src/test/interval.cpp b/src/test/interval.cpp index ac242cc60..21b25a9be 100644 --- a/src/test/interval.cpp +++ b/src/test/interval.cpp @@ -17,12 +17,12 @@ Revision History: --*/ #include -#include"interval_def.h" -#include"dependency.h" -#include"mpq.h" -#include"ast.h" -#include"debug.h" -#include"rlimit.h" +#include "math/interval/interval_def.h" +#include "util/dependency.h" +#include "util/mpq.h" +#include "ast/ast.h" +#include "util/debug.h" +#include "util/rlimit.h" template class interval_manager; typedef im_default_config::interval interval; @@ -125,7 +125,8 @@ static bool mk_interval(im_default_config & cfg, interval & a, bool l_inf, bool } #endif -static void mk_random_interval(im_default_config & cfg, interval & a, unsigned magnitude) { +template +static void mk_random_interval(T & cfg, interval & a, unsigned magnitude) { switch (rand()%3) { case 0: // Neg, Neg @@ -195,11 +196,6 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m } } -static void del_interval(im_default_config & cfg, interval & a) { - cfg.m().del(a.m_lower); - cfg.m().del(a.m_upper); -} - #define BUFFER_SZ 256 static int g_problem_id = 0; static char g_buffer[BUFFER_SZ]; @@ -238,19 +234,18 @@ static void display_lemmas(unsynch_mpq_manager & nm, char const * result_term, static void tst_ ## NAME(unsigned N, unsigned magnitude) { \ reslimit rl; \ unsynch_mpq_manager nm; \ - im_default_config imc(nm); \ - interval_manager im(rl, imc); \ + interval_manager im(rl, nm); \ interval a, b, r; \ \ for (unsigned i = 0; i < N; i++) { \ - mk_random_interval(imc, a, magnitude); \ - mk_random_interval(imc, b, magnitude); \ + mk_random_interval(im, a, magnitude); \ + mk_random_interval(im, b, magnitude); \ interval_deps deps; \ im.NAME(a, b, r, deps); \ \ display_lemmas(nm, RES_TERM, a, b, r, deps); \ } \ - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); \ + im.del(a); im.del(b); im.del(r); \ } MK_BINARY(mul, "(* a b)"); @@ -260,56 +255,52 @@ MK_BINARY(sub, "(- a b)"); static void tst_neg(unsigned N, unsigned magnitude) { reslimit rl; unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(rl, imc); + interval_manager im(rl, nm); interval a, b, r; for (unsigned i = 0; i < N; i++) { - mk_random_interval(imc, a, magnitude); + mk_random_interval(im, a, magnitude); interval_deps deps; im.neg(a, r, deps); display_lemmas(nm, "(- a)", a, b, r, deps); } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); + im.del(a); im.del(b); im.del(r); } static void tst_pw_2(unsigned N, unsigned magnitude) { reslimit rl; unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(rl, imc); + interval_manager im(rl, nm); interval a, b, r; for (unsigned i = 0; i < N; i++) { - mk_random_interval(imc, a, magnitude); + mk_random_interval(im, a, magnitude); interval_deps deps; im.power(a, 2, r, deps); display_lemmas(nm, "(* a a)", a, b, r, deps); } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); + im.del(a); im.del(b); im.del(r); } static void tst_pw_3(unsigned N, unsigned magnitude) { reslimit rl; unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(rl, imc); + interval_manager im(rl, nm); interval a, b, r; for (unsigned i = 0; i < N; i++) { - mk_random_interval(imc, a, magnitude); + mk_random_interval(im, a, magnitude); interval_deps deps; im.power(a, 3, r, deps); display_lemmas(nm, "(* a a a)", a, b, r, deps); } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); + im.del(a); im.del(b); im.del(r); } static void tst_root_2(unsigned N, unsigned magnitude, unsigned precision) { reslimit rl; unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(rl, imc); + interval_manager im(rl, nm); interval a, b, r; scoped_mpq p(nm); p = precision; @@ -317,7 +308,7 @@ static void tst_root_2(unsigned N, unsigned magnitude, unsigned precision) { unsigned i = 0; while (i < N) { - mk_random_interval(imc, a, magnitude); + mk_random_interval(im, a, magnitude); if (!im.lower_is_neg(a)) { i++; interval_deps deps; @@ -325,14 +316,13 @@ static void tst_root_2(unsigned N, unsigned magnitude, unsigned precision) { display_lemmas(nm, "(^ a (/ 1.0 2.0))", a, b, r, deps); } } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); + im.del(a); im.del(b); im.del(r); } static void tst_root_3(unsigned N, unsigned magnitude, unsigned precision) { reslimit rl; unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(rl, imc); + interval_manager im(rl, nm); interval a, b, r; scoped_mpq p(nm); p = precision; @@ -340,25 +330,24 @@ static void tst_root_3(unsigned N, unsigned magnitude, unsigned precision) { unsigned i = 0; while (i < N) { - mk_random_interval(imc, a, magnitude); + mk_random_interval(im, a, magnitude); i++; interval_deps deps; im.nth_root(a, 3, p, r, deps); display_lemmas(nm, "(^ a (/ 1.0 3.0))", a, b, r, deps); } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); + im.del(a); im.del(b); im.del(r); } static void tst_inv(unsigned N, unsigned magnitude) { reslimit rl; unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(rl, imc); + interval_manager im(rl, nm); interval a, b, r; for (unsigned i = 0; i < N; i++) { while (true) { - mk_random_interval(imc, a, magnitude); + mk_random_interval(im, a, magnitude); if (!im.contains_zero(a)) break; } @@ -366,20 +355,19 @@ static void tst_inv(unsigned N, unsigned magnitude) { im.inv(a, r, deps); display_lemmas(nm, "(/ 1 a)", a, b, r, deps); } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); + im.del(a); im.del(b); im.del(r); } static void tst_div(unsigned N, unsigned magnitude) { reslimit rl; unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(rl, imc); + interval_manager im(rl, nm); interval a, b, r; for (unsigned i = 0; i < N; i++) { - mk_random_interval(imc, a, magnitude); + mk_random_interval(im, a, magnitude); while (true) { - mk_random_interval(imc, b, magnitude); + mk_random_interval(im, b, magnitude); if (!im.contains_zero(b)) break; } @@ -387,17 +375,16 @@ static void tst_div(unsigned N, unsigned magnitude) { im.div(a, b, r, deps); display_lemmas(nm, "(/ a b)", a, b, r, deps); } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); + im.del(a); im.del(b); im.del(r); } -#include"im_float_config.h" +#include "test/im_float_config.h" #if 0 static void tst_float() { unsynch_mpq_manager qm; mpf_manager fm; - im_float_config ifc(fm); - interval_manager > im(ifc); + interval_manager > im(fm); im_float_config::interval a, b, c; scoped_mpq minus_one_third(qm), one_third(qm), two_third(qm), minus_two_third(qm); qm.set(minus_one_third, -1, 3); @@ -424,23 +411,22 @@ static void tst_float() { im.display(std::cout, c); std::cout << "\n"; - del_f_interval(ifc, a); del_f_interval(ifc, b); del_f_interval(ifc, c); + im.del(a); im.del(b); im.del(r); } #endif void tst_pi() { reslimit rl; unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(rl, imc); + interval_manager im(rl, nm); interval r; for (unsigned i = 0; i < 8; i++) { im.pi(i, r); nm.display_decimal(std::cout, im.lower(r), 32); std::cout << " "; nm.display_decimal(std::cout, im.upper(r), 32); std::cout << "\n"; - SASSERT(nm.lt(im.lower(r), im.upper(r))); + ENSURE(nm.lt(im.lower(r), im.upper(r))); } - del_interval(imc, r); + im.del(r); } #if 0 diff --git a/src/test/karr.cpp b/src/test/karr.cpp index c69932e22..dc18f7e19 100644 --- a/src/test/karr.cpp +++ b/src/test/karr.cpp @@ -3,8 +3,8 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include"rlimit.h" -#include "hilbert_basis.h" +#include "util/rlimit.h" +#include "math/hilbert/hilbert_basis.h" /* Test generation of linear congruences a la Karr. @@ -131,7 +131,7 @@ namespace karr { matrix T; // length of rows in Ab are twice as long as // length of rows in src. - SASSERT(2*src.A[0].size() == Ab.A[0].size()); + ENSURE(2*src.A[0].size() == Ab.A[0].size()); vector zeros; for (unsigned i = 0; i < src.A[0].size(); ++i) { zeros.push_back(rational(0)); diff --git a/src/test/list.cpp b/src/test/list.cpp index a7ad76972..4cfa16801 100644 --- a/src/test/list.cpp +++ b/src/test/list.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"trace.h" -#include"util.h" -#include"region.h" -#include"list.h" +#include "util/trace.h" +#include "util/util.h" +#include "util/region.h" +#include "util/list.h" static void tst1() { region r; @@ -27,10 +27,10 @@ static void tst1() { list * l2 = new (r) list(20, l1); list * l3 = new (r) list(30); list * l4 = new (r) list(40, l3); - SASSERT(append(r, l1, static_cast *>(0)) == l1); - SASSERT(append(r, l2, static_cast *>(0)) == l2); - SASSERT(append(r, static_cast *>(0), l2) == l2); - SASSERT(append(r, static_cast *>(0), static_cast *>(0)) == 0); + ENSURE(append(r, l1, static_cast *>(0)) == l1); + ENSURE(append(r, l2, static_cast *>(0)) == l2); + ENSURE(append(r, static_cast *>(0), l2) == l2); + ENSURE(append(r, static_cast *>(0), static_cast *>(0)) == 0); TRACE("list", display(tout, l2->begin(), l2->end()); tout << "\n";); list * l5 = append(r, l4, l2); TRACE("list", display(tout, l5->begin(), l5->end()); tout << "\n";); diff --git a/src/test/lp.cpp b/src/test/lp.cpp index 9e05112f5..0f4186252 100644 --- a/src/test/lp.cpp +++ b/src/test/lp.cpp @@ -1,7 +1,23 @@ -/* -Copyright (c) 2017 Microsoft Corporation. All rights reserved. -Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ + #include #if _LINUX_ #include @@ -19,10 +35,10 @@ Author: Lev Nachmanson #include "util/lp/lp_utils.h" #include "util/lp/lp_primal_simplex.h" #include "util/lp/mps_reader.h" -#include "smt_reader.h" +#include "test/smt_reader.h" #include "util/lp/binary_heap_priority_queue.h" -#include "argument_parser.h" -#include "test_file_reader.h" +#include "test/argument_parser.h" +#include "test/test_file_reader.h" #include "util/lp/indexed_value.h" #include "util/lp/lar_solver.h" #include "util/lp/numeric_pair.h" @@ -31,8 +47,9 @@ Author: Lev Nachmanson #include "util/lp/stacked_unordered_set.h" #include "util/lp/int_set.h" #include "util/stopwatch.h" -namespace lean { -unsigned seed = 1; + +namespace lp { + unsigned seed = 1; random_gen g_rand; static unsigned my_random() { @@ -78,7 +95,7 @@ void test_matrix(sparse_matrix & a) { a.set(i, j, t); - lean_assert(a.get(i, j) == t); + SASSERT(a.get(i, j) == t); unsigned j1; if (j < m - 1) { @@ -155,7 +172,7 @@ void tst1() { test_matrix(m10by9); std::cout <<"zeroing m10by9\n"; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG for (unsigned int i = 0; i < m10by9.dimension(); i++) for (unsigned int j = 0; j < m10by9.column_count(); j++) m10by9.set(i, j, 0); @@ -170,7 +187,7 @@ vector allocate_basis_heading(unsigned count) { // the rest of initilizatio void init_basic_part_of_basis_heading(vector & basis, vector & basis_heading) { - lean_assert(basis_heading.size() >= basis.size()); + SASSERT(basis_heading.size() >= basis.size()); unsigned m = basis.size(); for (unsigned i = 0; i < m; i++) { unsigned column = basis[i]; @@ -205,7 +222,7 @@ void change_basis(unsigned entering, unsigned leaving, vector& basis, } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG void test_small_lu(lp_settings & settings) { std::cout << " test_small_lu" << std::endl; static_matrix m(3, 6); @@ -218,61 +235,61 @@ void test_small_lu(lp_settings & settings) { m(1, 1) = 4; m(1, 4) = 7; m(2, 0) = 1.8; m(2, 2) = 5; m(2, 4) = 2; m(2, 5) = 8; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG print_matrix(m, std::cout); #endif vector heading = allocate_basis_heading(m.column_count()); vector non_basic_columns; init_basis_heading_and_non_basic_columns_vector(basis, heading, non_basic_columns); lu l(m, basis, settings); - lean_assert(l.is_correct(basis)); + SASSERT(l.is_correct(basis)); indexed_vector w(m.row_count()); std::cout << "entering 2, leaving 0" << std::endl; l.prepare_entering(2, w); // to init vector w l.replace_column(0, w, heading[0]); change_basis(2, 0, basis, non_basic_columns, heading); - // #ifdef LEAN_DEBUG + // #ifdef Z3DEBUG // std::cout << "we were factoring " << std::endl; // print_matrix(get_B(l)); // #endif - lean_assert(l.is_correct(basis)); + SASSERT(l.is_correct(basis)); std::cout << "entering 4, leaving 3" << std::endl; l.prepare_entering(4, w); // to init vector w l.replace_column(0, w, heading[3]); change_basis(4, 3, basis, non_basic_columns, heading); std::cout << "we were factoring " << std::endl; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG { auto bl = get_B(l, basis); print_matrix(&bl, std::cout); } #endif - lean_assert(l.is_correct(basis)); + SASSERT(l.is_correct(basis)); std::cout << "entering 5, leaving 1" << std::endl; l.prepare_entering(5, w); // to init vector w l.replace_column(0, w, heading[1]); change_basis(5, 1, basis, non_basic_columns, heading); std::cout << "we were factoring " << std::endl; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG { auto bl = get_B(l, basis); print_matrix(&bl, std::cout); } #endif - lean_assert(l.is_correct(basis)); + SASSERT(l.is_correct(basis)); std::cout << "entering 3, leaving 2" << std::endl; l.prepare_entering(3, w); // to init vector w l.replace_column(0, w, heading[2]); change_basis(3, 2, basis, non_basic_columns, heading); std::cout << "we were factoring " << std::endl; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG { auto bl = get_B(l, basis); print_matrix(&bl, std::cout); } #endif - lean_assert(l.is_correct(basis)); + SASSERT(l.is_correct(basis)); m.add_row(); m.add_column(); @@ -291,7 +308,7 @@ void test_small_lu(lp_settings & settings) { auto columns_to_replace = l.get_set_of_columns_to_replace_for_add_last_rows(heading); l.add_last_rows_to_B(heading, columns_to_replace); std::cout << "here" << std::endl; - lean_assert(l.is_correct(basis)); + SASSERT(l.is_correct(basis)); } #endif @@ -351,7 +368,7 @@ void fill_larger_sparse_matrix(static_matrix & m){ int perm_id = 0; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG void test_larger_lu_exp(lp_settings & settings) { std::cout << " test_larger_lu_exp" << std::endl; static_matrix m(6, 12); @@ -373,7 +390,7 @@ void test_larger_lu_exp(lp_settings & settings) { dense_matrix left_side = l.get_left_side(basis); dense_matrix right_side = l.get_right_side(); - lean_assert(left_side == right_side); + SASSERT(left_side == right_side); int leaving = 3; int entering = 8; for (unsigned i = 0; i < m.row_count(); i++) { @@ -385,12 +402,12 @@ void test_larger_lu_exp(lp_settings & settings) { l.prepare_entering(entering, w); l.replace_column(0, w, heading[leaving]); change_basis(entering, leaving, basis, non_basic_columns, heading); - lean_assert(l.is_correct(basis)); + SASSERT(l.is_correct(basis)); l.prepare_entering(11, w); // to init vector w l.replace_column(0, w, heading[0]); change_basis(11, 0, basis, non_basic_columns, heading); - lean_assert(l.is_correct(basis)); + SASSERT(l.is_correct(basis)); } void test_larger_lu_with_holes(lp_settings & settings) { @@ -432,7 +449,7 @@ void test_larger_lu_with_holes(lp_settings & settings) { l.prepare_entering(8, w); // to init vector w l.replace_column(0, w, heading[0]); change_basis(8, 0, basis, non_basic_columns, heading); - lean_assert(l.is_correct(basis)); + SASSERT(l.is_correct(basis)); } @@ -479,7 +496,7 @@ void test_larger_lu(lp_settings& settings) { l.prepare_entering(9, w); // to init vector w l.replace_column(0, w, heading[0]); change_basis(9, 0, basis, non_basic_columns, heading); - lean_assert(l.is_correct(basis)); + SASSERT(l.is_correct(basis)); } @@ -550,7 +567,7 @@ void test_lp_1() { m(1, 0) = -1; m(1, 2) = 3; m(1, 4) = 1; m(2, 0) = 2; m(2, 1) = -1; m(2, 2) = 2; m(2, 5) = 1; m(3, 0) = 2; m(3, 1) = 3; m(3, 2) = -1; m(3, 6) = 1; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG print_matrix(m, std::cout); #endif vector x_star(7); @@ -604,7 +621,7 @@ void test_lp_primal_core_solver() { } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template void test_swap_rows_with_permutation(sparse_matrix& m){ std::cout << "testing swaps" << std::endl; @@ -612,7 +629,7 @@ void test_swap_rows_with_permutation(sparse_matrix& m){ dense_matrix original(&m); permutation_matrix q(dim); print_matrix(m, std::cout); - lean_assert(original == q * m); + SASSERT(original == q * m); for (int i = 0; i < 100; i++) { unsigned row1 = my_random() % dim; unsigned row2 = my_random() % dim; @@ -620,7 +637,7 @@ void test_swap_rows_with_permutation(sparse_matrix& m){ std::cout << "swap " << row1 << " " << row2 << std::endl; m.swap_rows(row1, row2); q.transpose_from_left(row1, row2); - lean_assert(original == q * m); + SASSERT(original == q * m); print_matrix(m, std::cout); std::cout << std::endl; } @@ -628,7 +645,7 @@ void test_swap_rows_with_permutation(sparse_matrix& m){ #endif template void fill_matrix(sparse_matrix& m); // forward definition -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template void test_swap_cols_with_permutation(sparse_matrix& m){ std::cout << "testing swaps" << std::endl; @@ -636,7 +653,7 @@ void test_swap_cols_with_permutation(sparse_matrix& m){ dense_matrix original(&m); permutation_matrix q(dim); print_matrix(m, std::cout); - lean_assert(original == q * m); + SASSERT(original == q * m); for (int i = 0; i < 100; i++) { unsigned row1 = my_random() % dim; unsigned row2 = my_random() % dim; @@ -644,7 +661,7 @@ void test_swap_cols_with_permutation(sparse_matrix& m){ std::cout << "swap " << row1 << " " << row2 << std::endl; m.swap_rows(row1, row2); q.transpose_from_right(row1, row2); - lean_assert(original == q * m); + SASSERT(original == q * m); print_matrix(m, std::cout); std::cout << std::endl; } @@ -663,8 +680,8 @@ void test_swap_rows(sparse_matrix& m, unsigned i0, unsigned i1){ m.swap_rows(i0, i1); for (unsigned j = 0; j < m.dimension(); j++) { - lean_assert(mcopy(i0, j) == m(i1, j)); - lean_assert(mcopy(i1, j) == m(i0, j)); + SASSERT(mcopy(i0, j) == m(i1, j)); + SASSERT(mcopy(i1, j) == m(i0, j)); } } template @@ -678,15 +695,15 @@ void test_swap_columns(sparse_matrix& m, unsigned i0, unsigned i1){ m.swap_columns(i0, i1); for (unsigned j = 0; j < m.dimension(); j++) { - lean_assert(mcopy(j, i0) == m(j, i1)); - lean_assert(mcopy(j, i1) == m(j, i0)); + SASSERT(mcopy(j, i0) == m(j, i1)); + SASSERT(mcopy(j, i1) == m(j, i0)); } for (unsigned i = 0; i < m.dimension(); i++) { if (i == i0 || i == i1) continue; for (unsigned j = 0; j < m.dimension(); j++) { - lean_assert(mcopy(j, i)== m(j, i)); + SASSERT(mcopy(j, i)== m(j, i)); } } } @@ -731,7 +748,7 @@ void test_pivot_like_swaps_and_pivot(){ m(target_row, 3) = 0; m(target_row, 5) = 0; m(pivot_row, 6) = 0; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG print_matrix(m, std::cout); #endif @@ -748,11 +765,11 @@ void test_pivot_like_swaps_and_pivot(){ m.pivot_row_to_row(pivot_row_0, beta, target_row, settings); // print_matrix(m); for (unsigned j = 0; j < m.dimension(); j++) { - lean_assert(abs(row[j] - m(target_row, j)) < 0.00000001); + SASSERT(abs(row[j] - m(target_row, j)) < 0.00000001); } } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG void test_swap_rows() { sparse_matrix m(10); fill_matrix(m); @@ -853,57 +870,57 @@ void sparse_matrix_with_permutaions_test() { m.multiply_from_left(q0); for (unsigned i = 0; i < dim; i++) { for (unsigned j = 0; j < dim; j++) { - lean_assert(m(i, j) == dm0.get_elem(q0[i], j)); + SASSERT(m(i, j) == dm0.get_elem(q0[i], j)); } } auto q0_dm = q0 * dm; - lean_assert(m == q0_dm); + SASSERT(m == q0_dm); m.multiply_from_left(q1); for (unsigned i = 0; i < dim; i++) { for (unsigned j = 0; j < dim; j++) { - lean_assert(m(i, j) == dm0.get_elem(q0[q1[i]], j)); + SASSERT(m(i, j) == dm0.get_elem(q0[q1[i]], j)); } } auto q1_q0_dm = q1 * q0_dm; - lean_assert(m == q1_q0_dm); + SASSERT(m == q1_q0_dm); m.multiply_from_right(p0); for (unsigned i = 0; i < dim; i++) { for (unsigned j = 0; j < dim; j++) { - lean_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p0[j])); + SASSERT(m(i, j) == dm0.get_elem(q0[q1[i]], p0[j])); } } auto q1_q0_dm_p0 = q1_q0_dm * p0; - lean_assert(m == q1_q0_dm_p0); + SASSERT(m == q1_q0_dm_p0); m.multiply_from_right(p1); for (unsigned i = 0; i < dim; i++) { for (unsigned j = 0; j < dim; j++) { - lean_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p0[j]])); + SASSERT(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p0[j]])); } } auto q1_q0_dm_p0_p1 = q1_q0_dm_p0 * p1; - lean_assert(m == q1_q0_dm_p0_p1); + SASSERT(m == q1_q0_dm_p0_p1); m.multiply_from_right(p1); for (unsigned i = 0; i < dim; i++) { for (unsigned j = 0; j < dim; j++) { - lean_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p1[p0[j]]])); + SASSERT(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p1[p0[j]]])); } } auto q1_q0_dm_p0_p1_p1 = q1_q0_dm_p0_p1 * p1; - lean_assert(m == q1_q0_dm_p0_p1_p1); + SASSERT(m == q1_q0_dm_p0_p1_p1); } void test_swap_columns() { @@ -1021,10 +1038,10 @@ void test_apply_reverse_from_right_to_perm(permutation_matrix & pclone[4] = 1; p.multiply_by_reverse_from_right(l); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG auto rev = l.get_inverse(); auto rs = pclone * rev; - lean_assert(p == rs) + SASSERT(p == rs); #endif } @@ -1051,8 +1068,8 @@ void test_permutations() { p.apply_reverse_from_right_to_T(v); p.apply_reverse_from_right_to_T(vi); - lean_assert(vectors_are_equal(v, vi.m_data)); - lean_assert(vi.is_OK()); + SASSERT(vectors_are_equal(v, vi.m_data)); + SASSERT(vi.is_OK()); } void lp_solver_test() { @@ -1200,7 +1217,7 @@ void solve_mps_double(std::string file_name, bool look_for_min, unsigned max_ite compare_solutions(reader, primal_solver, solver); print_x(reader, primal_solver); std::cout << "dual cost is " << cost << ", but primal cost is " << primal_cost << std::endl; - lean_assert(false); + SASSERT(false); } } } @@ -1210,7 +1227,7 @@ void solve_mps_double(std::string file_name, bool look_for_min, unsigned max_ite } void solve_mps_rational(std::string file_name, bool look_for_min, unsigned max_iterations, unsigned time_limit, bool dual, argument_parser & args_parser) { - mps_reader reader(file_name); + mps_reader reader(file_name); reader.read(); if (reader.is_ok()) { auto * solver = reader.create_solver(dual); @@ -1224,7 +1241,7 @@ void solve_mps_rational(std::string file_name, bool look_for_min, unsigned max_i // for (auto name: reader.column_names()) { // std::cout << name << "=" << solver->get_column_value_by_name(name) << ' '; // } - lean::mpq cost = solver->get_current_cost(); + lp::mpq cost = solver->get_current_cost(); if (look_for_min) { cost = -cost; } @@ -1262,7 +1279,7 @@ void solve_mps(std::string file_name, argument_parser & args_parser) { void solve_mps_in_rational(std::string file_name, bool dual, argument_parser & /*args_parser*/) { std::cout << "solving " << file_name << std::endl; - mps_reader reader(file_name); + mps_reader reader(file_name); reader.read(); if (reader.is_ok()) { auto * solver = reader.create_solver(dual); @@ -1274,7 +1291,7 @@ void solve_mps_in_rational(std::string file_name, bool dual, argument_parser & / std::cout << name << "=" << solver->get_column_value_by_name(name).get_double() << ' '; } } - std::cout << std::endl << "cost = " << numeric_traits::get_double(solver->get_current_cost()) << std::endl; + std::cout << std::endl << "cost = " << numeric_traits::get_double(solver->get_current_cost()) << std::endl; } delete solver; } else { @@ -1318,7 +1335,7 @@ void test_binary_priority_queue() { for (unsigned i = 0; i < 10; i++) { unsigned de = q.dequeue(); - lean_assert(i == de); + SASSERT(i == de); std::cout << de << std::endl; } q.enqueue(2, 2); @@ -1337,11 +1354,11 @@ void test_binary_priority_queue() { q.dequeue(); q.remove(33); q.enqueue(0, 0); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG unsigned t = 0; while (q.size() > 0) { unsigned d =q.dequeue(); - lean_assert(t++ == d); + SASSERT(t++ == d); std::cout << d << std::endl; } #endif @@ -1370,7 +1387,7 @@ void solve_mps_with_known_solution(std::string file_name, std::unordered_mapget_status()) << std::endl; if (status != solver->get_status()){ std::cout << "status should be " << lp_status_to_string(status) << std::endl; - lean_assert(status == solver->get_status()); + SASSERT(status == solver->get_status()); throw "status is wrong"; } if (solver->get_status() == lp_status::OPTIMAL) { @@ -1381,7 +1398,7 @@ void solve_mps_with_known_solution(std::string file_name, std::unordered_mapget_column_value_by_name(it.first) << std::endl; } - lean_assert(fabs(it.second - solver->get_column_value_by_name(it.first)) < 0.000001); + SASSERT(fabs(it.second - solver->get_column_value_by_name(it.first)) < 0.000001); } } if (reader.column_names().size() < 20) { @@ -1706,48 +1723,48 @@ void solve_some_mps(argument_parser & args_parser) { #endif void solve_rational() { - lp_primal_simplex solver; - solver.add_constraint(lp_relation::Equal, lean::mpq(7), 0); - solver.add_constraint(lp_relation::Equal, lean::mpq(-3), 1); + lp_primal_simplex solver; + solver.add_constraint(lp_relation::Equal, lp::mpq(7), 0); + solver.add_constraint(lp_relation::Equal, lp::mpq(-3), 1); // setting the cost int cost[] = {-3, -1, -1, 2, -1, 1, 1, -4}; std::string var_names[8] = {"x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8"}; for (unsigned i = 0; i < 8; i++) { - solver.set_cost_for_column(i, lean::mpq(cost[i])); + solver.set_cost_for_column(i, lp::mpq(cost[i])); solver.give_symbolic_name_to_column(var_names[i], i); } int row0[] = {1, 0, 3, 1, -5, -2 , 4, -6}; for (unsigned i = 0; i < 8; i++) { - solver.set_row_column_coefficient(0, i, lean::mpq(row0[i])); + solver.set_row_column_coefficient(0, i, lp::mpq(row0[i])); } int row1[] = {0, 1, -2, -1, 4, 1, -3, 5}; for (unsigned i = 0; i < 8; i++) { - solver.set_row_column_coefficient(1, i, lean::mpq(row1[i])); + solver.set_row_column_coefficient(1, i, lp::mpq(row1[i])); } int bounds[] = {8, 6, 4, 15, 2, 10, 10, 3}; for (unsigned i = 0; i < 8; i++) { - solver.set_low_bound(i, lean::mpq(0)); - solver.set_upper_bound(i, lean::mpq(bounds[i])); + solver.set_low_bound(i, lp::mpq(0)); + solver.set_upper_bound(i, lp::mpq(bounds[i])); } - std::unordered_map expected_sol; - expected_sol["x1"] = lean::mpq(0); - expected_sol["x2"] = lean::mpq(6); - expected_sol["x3"] = lean::mpq(0); - expected_sol["x4"] = lean::mpq(15); - expected_sol["x5"] = lean::mpq(2); - expected_sol["x6"] = lean::mpq(1); - expected_sol["x7"] = lean::mpq(1); - expected_sol["x8"] = lean::mpq(0); + std::unordered_map expected_sol; + expected_sol["x1"] = lp::mpq(0); + expected_sol["x2"] = lp::mpq(6); + expected_sol["x3"] = lp::mpq(0); + expected_sol["x4"] = lp::mpq(15); + expected_sol["x5"] = lp::mpq(2); + expected_sol["x6"] = lp::mpq(1); + expected_sol["x7"] = lp::mpq(1); + expected_sol["x8"] = lp::mpq(0); solver.find_maximal_solution(); - lean_assert(solver.get_status() == OPTIMAL); + SASSERT(solver.get_status() == OPTIMAL); for (auto it : expected_sol) { - lean_assert(it.second == solver.get_column_value_by_name(it.first)); + SASSERT(it.second == solver.get_column_value_by_name(it.first)); } } @@ -1805,7 +1822,7 @@ std::unordered_map * get_solution_from_glpsol_output(std::s return ret; } - lean_assert(split.size() > 3); + SASSERT(split.size() > 3); (*ret)[split[1]] = atof(split[3].c_str()); } while (true); } @@ -1817,7 +1834,7 @@ void test_init_U() { m(0, 0) = 10; m(0, 1) = 11; m(0, 2) = 12; m(0, 3) = 13; m(0, 4) = 14; m(1, 0) = 20; m(1, 1) = 21; m(1, 2) = 22; m(1, 3) = 23; m(1, 5) = 24; m(2, 0) = 30; m(2, 1) = 31; m(2, 2) = 32; m(2, 3) = 33; m(2, 6) = 34; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG print_matrix(m, std::cout); #endif vector basis(3); @@ -1829,7 +1846,7 @@ void test_init_U() { for (unsigned i = 0; i < 3; i++) { for (unsigned j = 0; j < 3; j ++) { - lean_assert(m(i, basis[j]) == u(i, j)); + SASSERT(m(i, basis[j]) == u(i, j)); } } @@ -1857,7 +1874,7 @@ void test_replace_column() { for (unsigned column_to_replace = 0; column_to_replace < m.dimension(); column_to_replace ++) { m.replace_column(column_to_replace, w, settings); for (unsigned i = 0; i < m.dimension(); i++) { - lean_assert(abs(w[i] - m(i, column_to_replace)) < 0.00000001); + SASSERT(abs(w[i] - m(i, column_to_replace)) < 0.00000001); } } } @@ -1961,7 +1978,7 @@ void test_stacked_unsigned() { v = 3; v = 4; v.pop(); - lean_assert(v == 2); + SASSERT(v == 2); v ++; v++; std::cout << "before push v=" << v << std::endl; @@ -1971,7 +1988,7 @@ void test_stacked_unsigned() { v+=1; std::cout << "v = " << v << std::endl; v.pop(2); - lean_assert(v == 4); + SASSERT(v == 4); const unsigned & rr = v; std::cout << rr << std:: endl; @@ -2010,7 +2027,7 @@ void test_stacked_vector() { } void test_stacked_set() { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG std::cout << "test_stacked_set" << std::endl; stacked_unordered_set s; s.insert(1); @@ -2020,7 +2037,7 @@ void test_stacked_set() { s.push(); s.insert(4); s.pop(); - lean_assert(s() == scopy); + SASSERT(s() == scopy); s.push(); s.push(); s.insert(4); @@ -2028,7 +2045,7 @@ void test_stacked_set() { s.push(); s.insert(4); s.pop(3); - lean_assert(s() == scopy); + SASSERT(s() == scopy); #endif } @@ -2397,15 +2414,15 @@ void test_files_from_directory(std::string test_file_dir, argument_parser & args } -std::unordered_map get_solution_map(lp_solver * lps, mps_reader & reader) { - std::unordered_map ret; +std::unordered_map get_solution_map(lp_solver * lps, mps_reader & reader) { + std::unordered_map ret; for (auto it : reader.column_names()) { ret[it] = lps->get_column_value_by_name(it); } return ret; } -void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_reader * reader) { +void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_reader * reader) { std::string maxng = args_parser.get_option_value("--maxng"); if (maxng.size() > 0) { solver->settings().max_number_of_iterations_with_no_improvements = atoi(maxng.c_str()); @@ -2425,7 +2442,7 @@ void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_read } auto * lps = reader->create_solver(false); lps->find_maximal_solution(); - std::unordered_map sol = get_solution_map(lps, *reader); + std::unordered_map sol = get_solution_map(lps, *reader); std::cout << "status = " << lp_status_to_string(solver->get_status()) << std::endl; return; } @@ -2434,7 +2451,7 @@ void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_read lp_status status = solver->solve(); std::cout << "status is " << lp_status_to_string(status) << ", processed for " << sw.get_current_seconds() <<" seconds, and " << solver->get_total_iterations() << " iterations" << std::endl; if (solver->get_status() == INFEASIBLE) { - vector> evidence; + vector> evidence; solver->get_infeasibility_explanation(evidence); } if (args_parser.option_is_used("--randomize_lar")) { @@ -2467,7 +2484,7 @@ lar_solver * create_lar_solver_from_file(std::string file_name, argument_parser } return reader.create_lar_solver(); } - mps_reader reader(file_name); + mps_reader reader(file_name); reader.read(); if (!reader.is_ok()) { std::cout << "cannot process " << file_name << std::endl; @@ -2478,8 +2495,8 @@ lar_solver * create_lar_solver_from_file(std::string file_name, argument_parser void test_lar_on_file(std::string file_name, argument_parser & args_parser) { lar_solver * solver = create_lar_solver_from_file(file_name, args_parser); - mps_reader reader(file_name); - mps_reader * mps_reader = nullptr; + mps_reader reader(file_name); + mps_reader * mps_reader = nullptr; reader.read(); if (reader.is_ok()) { mps_reader = & reader; @@ -2524,28 +2541,28 @@ void test_lar_solver(argument_parser & args_parser) { } void test_numeric_pair() { - numeric_pair a; - numeric_pair b(2, lean::mpq(6, 2)); + numeric_pair a; + numeric_pair b(2, lp::mpq(6, 2)); a = b; - numeric_pair c(0.1, 0.5); + numeric_pair c(0.1, 0.5); a += 2*c; a -= c; - lean_assert (a == b + c); - numeric_pair d = a * 2; + SASSERT (a == b + c); + numeric_pair d = a * 2; std::cout << a << std::endl; - lean_assert(b == b); - lean_assert(b < a); - lean_assert(b <= a); - lean_assert(a > b); - lean_assert(a != b); - lean_assert(a >= b); - lean_assert(-a < b); - lean_assert(a < 2 * b); - lean_assert(b + b > a); - lean_assert(lean::mpq(2.1) * b + b > a); - lean_assert(-b * lean::mpq(2.1) - b < lean::mpq(0.99) * a); - std::cout << - b * lean::mpq(2.1) - b << std::endl; - lean_assert(-b *(lean::mpq(2.1) + 1) == - b * lean::mpq(2.1) - b); + SASSERT(b == b); + SASSERT(b < a); + SASSERT(b <= a); + SASSERT(a > b); + SASSERT(a != b); + SASSERT(a >= b); + SASSERT(-a < b); + SASSERT(a < 2 * b); + SASSERT(b + b > a); + SASSERT(lp::mpq(2.1) * b + b > a); + SASSERT(-b * lp::mpq(2.1) - b < lp::mpq(0.99) * a); + std::cout << - b * lp::mpq(2.1) - b << std::endl; + SASSERT(-b *(lp::mpq(2.1) + 1) == - b * lp::mpq(2.1) - b); } void get_matrix_dimensions(std::ifstream & f, unsigned & m, unsigned & n) { @@ -2566,7 +2583,7 @@ void read_row_cols(unsigned i, static_matrix& A, std::ifstream & if (line== "row_end") break; auto r = split_and_trim(line); - lean_assert(r.size() == 4); + SASSERT(r.size() == 4); unsigned j = atoi(r[1].c_str()); double v = atof(r[3].c_str()); A.set(i, j, v); @@ -2594,7 +2611,7 @@ void read_basis(vector & basis, std::ifstream & f) { std::cout << "reading basis" << std::endl; std::string line; getline(f, line); - lean_assert(line == "basis_start"); + SASSERT(line == "basis_start"); do { getline(f, line); if (line == "basis_end") @@ -2607,7 +2624,7 @@ void read_basis(vector & basis, std::ifstream & f) { void read_indexed_vector(indexed_vector & v, std::ifstream & f) { std::string line; getline(f, line); - lean_assert(line == "vector_start"); + SASSERT(line == "vector_start"); do { getline(f, line); if (line == "vector_end") break; @@ -2641,13 +2658,13 @@ void check_lu_from_file(std::string lufile_name) { indexed_vector d(A.row_count()); unsigned entering = 26; lsuhl.solve_Bd(entering, d, v); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG auto B = get_B(lsuhl, basis); vector a(m); A.copy_column_to_vector(entering, a); indexed_vector cd(d); B.apply_from_left(cd.m_data, settings); - lean_assert(vectors_are_equal(cd.m_data , a)); + SASSERT(vectors_are_equal(cd.m_data , a)); #endif } @@ -2662,7 +2679,7 @@ void test_square_dense_submatrix() { for (unsigned i = index_start; i < parent_dim; i++) for (unsigned j = index_start; j < parent_dim; j++) d[i][j] = i*3+j*2; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG unsigned dim = parent_dim - index_start; dense_matrix m(dim, dim); for (unsigned i = index_start; i < parent_dim; i++) @@ -2673,7 +2690,7 @@ void test_square_dense_submatrix() { for (unsigned i = index_start; i < parent_dim; i++) for (unsigned j = index_start; j < parent_dim; j++) d[i][j] = d[j][i]; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG for (unsigned i = index_start; i < parent_dim; i++) for (unsigned j = index_start; j < parent_dim; j++) m[i-index_start][j-index_start] = d[i][j]; @@ -2738,7 +2755,7 @@ void test_evidence_for_total_inf_simple(argument_parser & args_parser) { auto status = solver.solve(); std::cout << lp_status_to_string(status) << std::endl; std::unordered_map model; - lean_assert(solver.get_status() == INFEASIBLE); + SASSERT(solver.get_status() == INFEASIBLE); } void test_bound_propagation_one_small_sample1() { /* @@ -2779,7 +2796,7 @@ If b becomes basic variable, then it is likely the old solver ends up with a row vector ev; ls.add_var_bound(a, LE, mpq(1)); ls.solve(); - bound_propagator bp(ls); + lp_bound_propagator bp(ls); ls.propagate_bounds_for_touched_rows(bp); std::cout << " bound ev from test_bound_propagation_one_small_sample1" << std::endl; for (auto & be : bp.m_ibounds) { @@ -2832,7 +2849,7 @@ void test_bound_propagation_one_row() { vector ev; ls.add_var_bound(x0, LE, mpq(1)); ls.solve(); - bound_propagator bp(ls); + lp_bound_propagator bp(ls); ls.propagate_bounds_for_touched_rows(bp); } void test_bound_propagation_one_row_with_bounded_vars() { @@ -2848,7 +2865,7 @@ void test_bound_propagation_one_row_with_bounded_vars() { ls.add_var_bound(x0, LE, mpq(3)); ls.add_var_bound(x0, LE, mpq(1)); ls.solve(); - bound_propagator bp(ls); + lp_bound_propagator bp(ls); ls.propagate_bounds_for_touched_rows(bp); } void test_bound_propagation_one_row_mixed() { @@ -2862,7 +2879,7 @@ void test_bound_propagation_one_row_mixed() { vector ev; ls.add_var_bound(x1, LE, mpq(1)); ls.solve(); - bound_propagator bp(ls); + lp_bound_propagator bp(ls); ls.propagate_bounds_for_touched_rows(bp); } @@ -2885,7 +2902,7 @@ void test_bound_propagation_two_rows() { vector ev; ls.add_var_bound(y, LE, mpq(1)); ls.solve(); - bound_propagator bp(ls); + lp_bound_propagator bp(ls); ls.propagate_bounds_for_touched_rows(bp); } @@ -2905,7 +2922,7 @@ void test_total_case_u() { vector ev; ls.add_var_bound(z, GE, zero_of_type()); ls.solve(); - bound_propagator bp(ls); + lp_bound_propagator bp(ls); ls.propagate_bounds_for_touched_rows(bp); } bool contains_j_kind(unsigned j, lconstraint_kind kind, const mpq & rs, const vector & ev) { @@ -2932,10 +2949,10 @@ void test_total_case_l(){ vector ev; ls.add_var_bound(z, LE, zero_of_type()); ls.solve(); - bound_propagator bp(ls); + lp_bound_propagator bp(ls); ls.propagate_bounds_for_touched_rows(bp); - lean_assert(ev.size() == 4); - lean_assert(contains_j_kind(x, GE, - one_of_type(), ev)); + SASSERT(ev.size() == 4); + SASSERT(contains_j_kind(x, GE, - one_of_type(), ev)); } void test_bound_propagation() { test_total_case_u(); @@ -2955,17 +2972,17 @@ void test_int_set() { s.insert(1); s.insert(2); s.print(std::cout); - lean_assert(s.contains(2)); - lean_assert(s.size() == 2); + SASSERT(s.contains(2)); + SASSERT(s.size() == 2); s.erase(2); - lean_assert(s.size() == 1); + SASSERT(s.size() == 1); s.erase(2); - lean_assert(s.size() == 1); + SASSERT(s.size() == 1); s.print(std::cout); s.insert(3); s.insert(2); s.clear(); - lean_assert(s.size() == 0); + SASSERT(s.size() == 0); } @@ -3112,7 +3129,7 @@ void test_lp_local(int argn, char**argv) { return finalize(0); } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG if (args_parser.option_is_used("--test_swaps")) { sparse_matrix m(10); fill_matrix(m); @@ -3142,7 +3159,7 @@ void test_lp_local(int argn, char**argv) { return finalize(ret); } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG lp_settings settings; update_settings(args_parser, settings); if (args_parser.option_is_used("--test_lu")) { @@ -3219,11 +3236,11 @@ void test_lp_local(int argn, char**argv) { ret = 0; return finalize(ret); } - // lean::ccc = 0; + // lp::ccc = 0; return finalize(0); test_init_U(); test_replace_column(); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG sparse_matrix_with_permutaions_test(); test_dense_matrix(); test_swap_operations(); @@ -3236,5 +3253,5 @@ void test_lp_local(int argn, char**argv) { } } void tst_lp(char ** argv, int argc, int& i) { - lean::test_lp_local(argc - 2, argv + 2); + lp::test_lp_local(argc - 2, argv + 2); } diff --git a/src/test/main.cpp b/src/test/main.cpp index c05488370..98be722e3 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -2,13 +2,14 @@ #include #include #include -#include"util.h" -#include"trace.h" -#include"debug.h" -#include"timeit.h" -#include"warning.h" -#include "memory_manager.h" -#include"gparams.h" +#include "util/util.h" +#include "util/trace.h" +#include "util/debug.h" +#include "util/timeit.h" +#include "util/warning.h" +#include "util/memory_manager.h" +#include "util/gparams.h" + // // Unit tests fail by asserting. @@ -16,21 +17,21 @@ // and print "PASS" to indicate success. // -#define TST(MODULE) { \ - std::string s("test "); \ - s += #MODULE; \ - void tst_##MODULE(); \ - if (do_display_usage) \ - std::cout << #MODULE << "\n"; \ - for (int i = 0; i < argc; i++) \ - if (test_all || strcmp(argv[i], #MODULE) == 0) { \ - enable_trace(#MODULE); \ - enable_debug(#MODULE); \ - timeit timeit(true, s.c_str()); \ - tst_##MODULE(); \ - std::cout << "PASS" << std::endl; \ - } \ -} +#define TST(MODULE) { \ + std::string s("test "); \ + s += #MODULE; \ + void tst_##MODULE(); \ + if (do_display_usage) \ + std::cout << #MODULE << "\n"; \ + for (int i = 0; i < argc; i++) \ + if (test_all || strcmp(argv[i], #MODULE) == 0) { \ + enable_trace(#MODULE); \ + enable_debug(#MODULE); \ + timeit timeit(true, s.c_str()); \ + tst_##MODULE(); \ + std::cout << "PASS" << std::endl; \ + } \ + } #define TST_ARGV(MODULE) { \ std::string s("test "); \ @@ -39,13 +40,13 @@ if (do_display_usage) \ std::cout << #MODULE << "\n"; \ for (int i = 0; i < argc; i++) \ - if (strcmp(argv[i], #MODULE) == 0) { \ + if (strcmp(argv[i], #MODULE) == 0) { \ enable_trace(#MODULE); \ - enable_debug(#MODULE); \ - timeit timeit(true, s.c_str()); \ - tst_##MODULE(argv, argc, i); \ + enable_debug(#MODULE); \ + timeit timeit(true, s.c_str()); \ + tst_##MODULE(argv, argc, i); \ std::cout << "PASS" << std::endl; \ - } \ + } \ } void error(const char * msg) { @@ -76,49 +77,49 @@ void display_usage() { void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage, bool& test_all) { int i = 1; while (i < argc) { - char * arg = argv[i], *eq_pos = 0; + char * arg = argv[i], *eq_pos = 0; - if (arg[0] == '-' || arg[0] == '/') { - char * opt_name = arg + 1; - char * opt_arg = 0; - char * colon = strchr(arg, ':'); - if (colon) { - opt_arg = colon + 1; - *colon = 0; - } - if (strcmp(opt_name, "h") == 0 || + if (arg[0] == '-' || arg[0] == '/') { + char * opt_name = arg + 1; + char * opt_arg = 0; + char * colon = strchr(arg, ':'); + if (colon) { + opt_arg = colon + 1; + *colon = 0; + } + if (strcmp(opt_name, "h") == 0 || strcmp(opt_name, "?") == 0) { - display_usage(); + display_usage(); do_display_usage = true; return; - } - else if (strcmp(opt_name, "v") == 0) { - if (!opt_arg) - error("option argument (/v:level) is missing."); - long lvl = strtol(opt_arg, 0, 10); - set_verbosity_level(lvl); - } - else if (strcmp(opt_name, "w") == 0) { + } + else if (strcmp(opt_name, "v") == 0) { + if (!opt_arg) + error("option argument (/v:level) is missing."); + long lvl = strtol(opt_arg, 0, 10); + set_verbosity_level(lvl); + } + else if (strcmp(opt_name, "w") == 0) { enable_warning_messages(true); - } - else if (strcmp(opt_name, "a") == 0) { + } + else if (strcmp(opt_name, "a") == 0) { test_all = true; - } + } #ifdef _TRACE - else if (strcmp(opt_name, "tr") == 0) { - if (!opt_arg) - error("option argument (/tr:tag) is missing."); - enable_trace(opt_arg); - } + else if (strcmp(opt_name, "tr") == 0) { + if (!opt_arg) + error("option argument (/tr:tag) is missing."); + enable_trace(opt_arg); + } #endif #ifdef Z3DEBUG - else if (strcmp(opt_name, "dbg") == 0) { - if (!opt_arg) - error("option argument (/dbg:tag) is missing."); - enable_debug(opt_arg); - } + else if (strcmp(opt_name, "dbg") == 0) { + if (!opt_arg) + error("option argument (/dbg:tag) is missing."); + enable_debug(opt_arg); + } #endif - } + } else if (arg[0] != '"' && (eq_pos = strchr(arg, '='))) { char * key = arg; *eq_pos = 0; @@ -130,7 +131,7 @@ void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage, bool& t std::cerr << ex.msg() << "\n"; } } - i++; + i++; } } @@ -166,7 +167,6 @@ int main(int argc, char ** argv) { TST(timeout); TST(proof_checker); TST(simplifier); - TST(bv_simplifier_plugin); TST(bit_blaster); TST(var_subst); TST(simple_parser); @@ -208,6 +208,7 @@ int main(int argc, char ** argv) { TST(prime_generator); TST(permutation); TST(nlsat); + if (test_all) return 0; TST(ext_numeral); TST(interval); TST(f2n); @@ -223,7 +224,7 @@ int main(int argc, char ** argv) { TST(heap_trie); TST(karr); TST(no_overflow); - TST(memory); + // TST(memory); TST(datalog_parser); TST_ARGV(datalog_parser_file); TST(dl_query); @@ -238,6 +239,7 @@ int main(int argc, char ** argv) { TST(sat_user_scope); TST(pdr); TST_ARGV(ddnf); + TST(ddnf1); TST(model_evaluator); TST_ARGV(lp); TST(get_consequences); diff --git a/src/test/map.cpp b/src/test/map.cpp index 7e2cc7e70..5d59e1e2f 100644 --- a/src/test/map.cpp +++ b/src/test/map.cpp @@ -16,28 +16,28 @@ Author: Revision History: --*/ -#include"map.h" -#include"str_hashtable.h" +#include "util/map.h" +#include "util/str_hashtable.h" static void tst1() { map str2int; str2int.insert("foo", 35); - SASSERT(str2int.contains("foo")); - SASSERT(str2int.find_iterator("foo") != str2int.end()); - SASSERT((*(str2int.find_iterator("foo"))).m_value == 35); - SASSERT(str2int.size() == 1); + ENSURE(str2int.contains("foo")); + ENSURE(str2int.find_iterator("foo") != str2int.end()); + ENSURE((*(str2int.find_iterator("foo"))).m_value == 35); + ENSURE(str2int.size() == 1); str2int.insert("boo", 32); - SASSERT(str2int.contains("foo")); - SASSERT(str2int.find_iterator("foo") != str2int.end()); - SASSERT((*(str2int.find_iterator("foo"))).m_value == 35); - SASSERT(str2int.contains("boo")); - SASSERT(str2int.find_iterator("boo") != str2int.end()); - SASSERT((*(str2int.find_iterator("boo"))).m_value == 32); - SASSERT(str2int.size() == 2); + ENSURE(str2int.contains("foo")); + ENSURE(str2int.find_iterator("foo") != str2int.end()); + ENSURE((*(str2int.find_iterator("foo"))).m_value == 35); + ENSURE(str2int.contains("boo")); + ENSURE(str2int.find_iterator("boo") != str2int.end()); + ENSURE((*(str2int.find_iterator("boo"))).m_value == 32); + ENSURE(str2int.size() == 2); str2int.remove("boo"); - SASSERT(str2int.size() == 1); - SASSERT(!str2int.contains("boo")); - SASSERT(str2int.contains("foo")); + ENSURE(str2int.size() == 1); + ENSURE(!str2int.contains("boo")); + ENSURE(str2int.contains("foo")); } void tst_map() { diff --git a/src/test/matcher.cpp b/src/test/matcher.cpp index 598a82ae3..cd220a9c6 100644 --- a/src/test/matcher.cpp +++ b/src/test/matcher.cpp @@ -17,9 +17,9 @@ Revision History: --*/ #ifdef _WINDOWS -#include"matcher.h" -#include"ast_pp.h" -#include "reg_decl_plugins.h" +#include "ast/substitution/matcher.h" +#include "ast/ast_pp.h" +#include "ast/reg_decl_plugins.h" void tst_match(ast_manager & m, app * t, app * i) { diff --git a/src/test/memory.cpp b/src/test/memory.cpp index 340a1929c..48ba35b78 100644 --- a/src/test/memory.cpp +++ b/src/test/memory.cpp @@ -5,11 +5,11 @@ Copyright (c) 2015 Microsoft Corporation --*/ #ifdef _WINDOWS -#include "z3.h" -#include "z3_private.h" +#include "api/z3.h" +#include "api/z3_private.h" #include -#include "util.h" -#include "trace.h" +#include "util/util.h" +#include "util/trace.h" static bool oom = false; diff --git a/src/test/model2expr.cpp b/src/test/model2expr.cpp index f96cee55f..457fc1751 100644 --- a/src/test/model2expr.cpp +++ b/src/test/model2expr.cpp @@ -4,11 +4,11 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "model2expr.h" -#include "ast_pp.h" -#include "arith_decl_plugin.h" -#include "model_smt2_pp.h" -#include "reg_decl_plugins.h" +#include "model/model2expr.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" +#include "model/model_smt2_pp.h" +#include "ast/reg_decl_plugins.h" void tst_model2expr() { ast_manager m; diff --git a/src/test/model_based_opt.cpp b/src/test/model_based_opt.cpp index 5ee671a4a..7b3b95afd 100644 --- a/src/test/model_based_opt.cpp +++ b/src/test/model_based_opt.cpp @@ -1,6 +1,6 @@ -#include "model_based_opt.h" -#include "util.h" -#include "uint_set.h" +#include "math/simplex/model_based_opt.h" +#include "util/util.h" +#include "util/uint_set.h" typedef opt::model_based_opt::var var; @@ -54,7 +54,7 @@ static void add_random_ineq(opt::model_based_opt& mbo, continue; } unsigned sign = r(2); - coeff = sign == 0 ? coeff : -coeff; + coeff = sign == 0 ? coeff : -coeff; vars.push_back(var(x, rational(coeff))); value += coeff*values[x]; } diff --git a/src/test/model_evaluator.cpp b/src/test/model_evaluator.cpp index 00048b230..68a24e792 100644 --- a/src/test/model_evaluator.cpp +++ b/src/test/model_evaluator.cpp @@ -1,9 +1,9 @@ -#include "model.h" -#include "model_evaluator.h" -#include "model_pp.h" -#include "arith_decl_plugin.h" -#include "reg_decl_plugins.h" -#include "ast_pp.h" +#include "model/model.h" +#include "model/model_evaluator.h" +#include "model/model_pp.h" +#include "ast/arith_decl_plugin.h" +#include "ast/reg_decl_plugins.h" +#include "ast/ast_pp.h" void tst_model_evaluator() { diff --git a/src/test/model_retrieval.cpp b/src/test/model_retrieval.cpp index e42e22539..e0fd28088 100644 --- a/src/test/model_retrieval.cpp +++ b/src/test/model_retrieval.cpp @@ -5,14 +5,14 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "ast.h" -#include "smt_params.h" -#include "smt_context.h" -#include "arith_decl_plugin.h" -#include "bv_decl_plugin.h" -#include "array_decl_plugin.h" -#include "model_v2_pp.h" -#include "reg_decl_plugins.h" +#include "ast/ast.h" +#include "smt/params/smt_params.h" +#include "smt/smt_context.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "model/model_v2_pp.h" +#include "ast/reg_decl_plugins.h" void tst_model_retrieval() { diff --git a/src/test/mpbq.cpp b/src/test/mpbq.cpp index 97f8822a9..4dc92d80d 100644 --- a/src/test/mpbq.cpp +++ b/src/test/mpbq.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include "mpbq.h" +#include "util/mpbq.h" static void tst1() { unsynch_mpz_manager zm; diff --git a/src/test/mpf.cpp b/src/test/mpf.cpp index d12675b6d..6e3dfb67f 100644 --- a/src/test/mpf.cpp +++ b/src/test/mpf.cpp @@ -16,46 +16,46 @@ Author: Revision History: --*/ -#include"mpf.h" -#include"f2n.h" +#include "util/mpf.h" +#include "util/f2n.h" static void bug_set_int() { mpf_manager fm; scoped_mpf a(fm); fm.set(a, 11, 53, 3); - SASSERT(fm.to_double(a) == 3.0); + ENSURE(fm.to_double(a) == 3.0); fm.set(a, 11, 53, 0); - SASSERT(fm.to_double(a) == 0.0); + ENSURE(fm.to_double(a) == 0.0); fm.set(a, 11, 53, -1); - SASSERT(fm.to_double(a) == -1.0); + ENSURE(fm.to_double(a) == -1.0); fm.set(a, 11, 53, INT_MAX); - SASSERT(fm.to_double(a) == (double)INT_MAX); + ENSURE(fm.to_double(a) == (double)INT_MAX); fm.set(a, 11, 53, INT_MIN); - SASSERT(fm.to_double(a) == (double)INT_MIN); + ENSURE(fm.to_double(a) == (double)INT_MIN); fm.set(a, 8, 24, 3); - SASSERT(fm.to_float(a) == 3.0); - SASSERT(fm.to_double(a) == 3.0); + ENSURE(fm.to_float(a) == 3.0); + ENSURE(fm.to_double(a) == 3.0); fm.set(a, 8, 24, 0); - SASSERT(fm.to_float(a) == 0.0); - SASSERT(fm.to_double(a) == 0.0); + ENSURE(fm.to_float(a) == 0.0); + ENSURE(fm.to_double(a) == 0.0); fm.set(a, 8, 24, -1); - SASSERT(fm.to_float(a) == -1.0); - SASSERT(fm.to_double(a) == -1.0); + ENSURE(fm.to_float(a) == -1.0); + ENSURE(fm.to_double(a) == -1.0); fm.set(a, 8, 24, INT_MIN); - SASSERT(fm.to_float(a) == (float)INT_MIN); + ENSURE(fm.to_float(a) == (float)INT_MIN); // CMW: This one depends on the rounding mode, but fm.set(..., int) doesn't have one. // fm.set(a, 8, 24, INT_MAX); - // SASSERT(fm.to_float(a) == (float)INT_MAX); + // ENSURE(fm.to_float(a) == (float)INT_MAX); } static void bug_set_double() { @@ -63,22 +63,22 @@ static void bug_set_double() { scoped_mpf a(fm); fm.set(a, 11, 53, 2.5); - SASSERT(fm.to_double(a) == 2.5); + ENSURE(fm.to_double(a) == 2.5); fm.set(a, 11, 53, -42.25); - SASSERT(fm.to_double(a) == -42.25); + ENSURE(fm.to_double(a) == -42.25); fm.set(a, 8, 24, (double)2.5); - SASSERT(fm.to_double(a) == 2.5); + ENSURE(fm.to_double(a) == 2.5); fm.set(a, 8, 24, (double)-42.25); - SASSERT(fm.to_double(a) == -42.25); + ENSURE(fm.to_double(a) == -42.25); fm.set(a, 8, 24, (float)2.5); - SASSERT(fm.to_float(a) == 2.5); + ENSURE(fm.to_float(a) == 2.5); fm.set(a, 8, 24, (float)-42.25); - SASSERT(fm.to_float(a) == -42.25); + ENSURE(fm.to_float(a) == -42.25); } void tst_mpf() { diff --git a/src/test/mpff.cpp b/src/test/mpff.cpp index ca2354b8b..73ed114a7 100644 --- a/src/test/mpff.cpp +++ b/src/test/mpff.cpp @@ -17,9 +17,9 @@ Revision History: --*/ #include -#include"mpff.h" -#include"mpz.h" -#include"mpq.h" +#include "util/mpff.h" +#include "util/mpz.h" +#include "util/mpq.h" static void tst1() { try { @@ -77,10 +77,10 @@ static void tst5() { scoped_mpff a(m), b(m); m.set(a, static_cast(1) << 63); m.display_raw(std::cout, a); std::cout << "\n"; - SASSERT(m.is_zero(b)); - SASSERT(m.lt(b, a)); + ENSURE(m.is_zero(b)); + ENSURE(m.lt(b, a)); m.set(b, -1); - SASSERT(m.lt(b, a)); + ENSURE(m.lt(b, a)); } static void tst6() { @@ -90,10 +90,10 @@ static void tst6() { std::cout << "mpff(1/3) " << a << "\n"; b = a; m.next(b); - SASSERT(m.lt(a, b)); + ENSURE(m.lt(a, b)); std::cout << "b: " << b << "\n"; m.prev(b); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); m.ceil(b); std::cout << "b: " << b << "\n"; m.set(b, 4, 3); @@ -135,15 +135,15 @@ static void tst_ ## OP ## _core(int64 n1, uint64 d1, int64 n2, uint64 d2, unsign fm.round_to_plus_inf(); \ fm.OP(fa, fb, fc1); \ fm.to_mpq(fc1, qm, qt); \ - SASSERT(qm.le(qc, qt)); \ + ENSURE(qm.le(qc, qt)); \ } \ { \ fm.round_to_minus_inf(); \ fm.OP(fa, fb, fc2); \ fm.to_mpq(fc2, qm, qt); \ - SASSERT(qm.le(qt, qc)); \ + ENSURE(qm.le(qt, qc)); \ } \ - SASSERT(fm.le(fc2, fc1)); \ + ENSURE(fm.le(fc2, fc1)); \ } MK_BIN_OP(add); @@ -182,7 +182,7 @@ static void tst_bug() { scoped_mpq b(qm), c(qm); qm.set(b, 41, 36); fm.to_mpq(a, qm, c); - SASSERT(qm.le(b, c)); + ENSURE(qm.le(b, c)); } static void tst_bug2() { @@ -191,16 +191,16 @@ static void tst_bug2() { fm.set(b, 1); fm.sub(a, b, b); fm.set(a, -1); - SASSERT(fm.eq(a, b)); + ENSURE(fm.eq(a, b)); fm.set(a, 1); fm.set(b, 0); fm.sub(a, b, a); fm.set(b, 1); - SASSERT(fm.eq(a, b)); + ENSURE(fm.eq(a, b)); fm.set(a, 1); fm.set(b, 1); fm.sub(a, b, a); - SASSERT(fm.is_zero(a)); + ENSURE(fm.is_zero(a)); } static void tst_set64(unsigned N, unsigned prec) { @@ -208,69 +208,69 @@ static void tst_set64(unsigned N, unsigned prec) { scoped_mpff a(fm); fm.set(a, static_cast(INT64_MAX)); - SASSERT(fm.is_int64(a)); - SASSERT(fm.is_uint64(a)); + ENSURE(fm.is_int64(a)); + ENSURE(fm.is_uint64(a)); fm.inc(a); - SASSERT(!fm.is_int64(a)); - SASSERT(fm.is_uint64(a)); - SASSERT(fm.is_int(a)); + ENSURE(!fm.is_int64(a)); + ENSURE(fm.is_uint64(a)); + ENSURE(fm.is_int(a)); fm.dec(a); - SASSERT(fm.is_int64(a)); - SASSERT(fm.is_uint64(a)); + ENSURE(fm.is_int64(a)); + ENSURE(fm.is_uint64(a)); fm.dec(a); - SASSERT(fm.is_int64(a)); - SASSERT(fm.is_uint64(a)); + ENSURE(fm.is_int64(a)); + ENSURE(fm.is_uint64(a)); fm.set(a, static_cast(INT64_MIN)); - SASSERT(fm.is_int64(a)); - SASSERT(!fm.is_uint64(a)); + ENSURE(fm.is_int64(a)); + ENSURE(!fm.is_uint64(a)); fm.dec(a); - SASSERT(!fm.is_int64(a)); - SASSERT(!fm.is_uint64(a)); - SASSERT(fm.is_int(a)); + ENSURE(!fm.is_int64(a)); + ENSURE(!fm.is_uint64(a)); + ENSURE(fm.is_int(a)); fm.inc(a); - SASSERT(fm.is_int64(a)); - SASSERT(!fm.is_uint64(a)); + ENSURE(fm.is_int64(a)); + ENSURE(!fm.is_uint64(a)); fm.inc(a); - SASSERT(fm.is_int64(a)); - SASSERT(!fm.is_uint64(a)); + ENSURE(fm.is_int64(a)); + ENSURE(!fm.is_uint64(a)); fm.set(a, static_cast(UINT64_MAX)); - SASSERT(fm.is_uint64(a)); - SASSERT(!fm.is_int64(a)); + ENSURE(fm.is_uint64(a)); + ENSURE(!fm.is_int64(a)); fm.inc(a); - SASSERT(!fm.is_uint64(a)); - SASSERT(!fm.is_int64(a)); + ENSURE(!fm.is_uint64(a)); + ENSURE(!fm.is_int64(a)); fm.dec(a); - SASSERT(fm.is_uint64(a)); - SASSERT(!fm.is_int64(a)); + ENSURE(fm.is_uint64(a)); + ENSURE(!fm.is_int64(a)); fm.dec(a); - SASSERT(fm.is_uint64(a)); - SASSERT(!fm.is_int64(a)); + ENSURE(fm.is_uint64(a)); + ENSURE(!fm.is_int64(a)); for (unsigned i = 0; i < N; i++) { { uint64 v = (static_cast(rand()) << 32) + static_cast(rand()); fm.set(a, v); - SASSERT(fm.is_uint64(a)); + ENSURE(fm.is_uint64(a)); v = (static_cast(rand() % 3) << 32) + static_cast(rand()); fm.set(a, v); - SASSERT(fm.is_uint64(a)); + ENSURE(fm.is_uint64(a)); } { int64 v = (static_cast(rand() % INT_MAX) << 32) + static_cast(rand()); if (rand()%2 == 0) v = -v; fm.set(a, v); - SASSERT(fm.is_int64(a)); + ENSURE(fm.is_int64(a)); v = (static_cast(rand() % 3) << 32) + static_cast(rand()); if (rand()%2 == 0) v = -v; fm.set(a, v); - SASSERT(fm.is_int64(a)); + ENSURE(fm.is_int64(a)); } } } @@ -282,12 +282,12 @@ static void tst_capacity(unsigned prec = 2) { for (unsigned i = 0; i < 50000; i++) { m.set(a, i); v.push_back(a); - SASSERT(m.is_int(v.back())); - SASSERT(m.is_int64(v.back())); - SASSERT(m.is_uint64(v.back())); + ENSURE(m.is_int(v.back())); + ENSURE(m.is_int64(v.back())); + ENSURE(m.is_uint64(v.back())); } for (unsigned i = 0; i < 50000; i++) { - SASSERT(m.get_int64(v[i]) == i); + ENSURE(m.get_int64(v[i]) == i); } } @@ -296,140 +296,138 @@ static void tst_power(unsigned prec = 2) { scoped_mpff a(m), b(m); // 0^k == 0 - SASSERT(m.is_zero(a)); + ENSURE(m.is_zero(a)); m.power(a, 10, a); - SASSERT(m.is_zero(a)); + ENSURE(m.is_zero(a)); // a != 0 ==> a^0 == 1 m.set(a, 33); m.power(a, 0, a); - SASSERT(m.is_one(a)); + ENSURE(m.is_one(a)); m.set(a, -33); m.power(a, 0, a); - SASSERT(m.is_one(a)); + ENSURE(m.is_one(a)); // a^1 == a m.set(a, 33); m.power(a, 1, b); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); m.set(a, -33); m.power(a, 1, b); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); // checking special support for powers of 2 -#ifdef Z3DEBUG unsigned k; -#endif m.set(a, 1); - SASSERT(m.is_power_of_two(a, k) && k == 0); + ENSURE(m.is_power_of_two(a, k) && k == 0); m.set(a, 2); - SASSERT(m.is_power_of_two(a, k) && k == 1); + ENSURE(m.is_power_of_two(a, k) && k == 1); m.set(a, 3); - SASSERT(!m.is_power_of_two(a, k)); + ENSURE(!m.is_power_of_two(a, k)); m.set(a, 4); - SASSERT(m.is_power_of_two(a, k) && k == 2); + ENSURE(m.is_power_of_two(a, k) && k == 2); m.set(a, -4); - SASSERT(!m.is_power_of_two(a, k)); + ENSURE(!m.is_power_of_two(a, k)); m.set(a, 8); - SASSERT(m.is_power_of_two(a, k) && k == 3); + ENSURE(m.is_power_of_two(a, k) && k == 3); m.set(a, 0); - SASSERT(!m.is_power_of_two(a)); + ENSURE(!m.is_power_of_two(a)); m.set(a, UINT_MAX); m.inc(a); - SASSERT(m.is_power_of_two(a, k) && k == 32); - SASSERT(m.get_uint64(a) == static_cast(UINT_MAX) + 1); + ENSURE(m.is_power_of_two(a, k) && k == 32); + ENSURE(m.get_uint64(a) == static_cast(UINT_MAX) + 1); m.power(a, 2, a); - SASSERT(m.is_power_of_two(a, k) && k == 64); + ENSURE(m.is_power_of_two(a, k) && k == 64); m.power(a, 4, a); - SASSERT(m.is_power_of_two(a, k) && k == 256); + ENSURE(m.is_power_of_two(a, k) && k == 256); m.round_to_plus_inf(); m.inc(a); - SASSERT(!m.is_power_of_two(a, k)); + ENSURE(!m.is_power_of_two(a, k)); m.set(a, -4); m.power(a, 3, a); m.set(b, -64); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); m.set(a, -4); m.power(a, 4, a); m.set(b, 256); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); // additional tests m.set(a, 5); m.power(a, 3, a); m.set(b, 5*5*5); - SASSERT(m.eq(a,b)); + ENSURE(m.eq(a,b)); m.set(a, -5); m.power(a, 3, a); m.set(b, -5*5*5); - SASSERT(m.eq(a,b)); + ENSURE(m.eq(a,b)); } static void tst_sgn(unsigned prec) { mpff_manager m(prec); scoped_mpff a(m), b(m); - SASSERT(m.is_zero(a) && !m.is_pos(a) && !m.is_neg(a) && m.is_nonpos(a) && m.is_nonneg(a)); + ENSURE(m.is_zero(a) && !m.is_pos(a) && !m.is_neg(a) && m.is_nonpos(a) && m.is_nonneg(a)); m.set(a, 3); - SASSERT(!m.is_zero(a) && m.is_pos(a) && !m.is_neg(a) && !m.is_nonpos(a) && m.is_nonneg(a)); + ENSURE(!m.is_zero(a) && m.is_pos(a) && !m.is_neg(a) && !m.is_nonpos(a) && m.is_nonneg(a)); m.set(a, -3); - SASSERT(!m.is_zero(a) && !m.is_pos(a) && m.is_neg(a) && m.is_nonpos(a) && !m.is_nonneg(a)); + ENSURE(!m.is_zero(a) && !m.is_pos(a) && m.is_neg(a) && m.is_nonpos(a) && !m.is_nonneg(a)); m.set(a, 8); m.power(a, 256, a); - SASSERT(!m.is_zero(a) && m.is_pos(a) && !m.is_neg(a) && !m.is_nonpos(a) && m.is_nonneg(a)); + ENSURE(!m.is_zero(a) && m.is_pos(a) && !m.is_neg(a) && !m.is_nonpos(a) && m.is_nonneg(a)); b = a; m.neg(a); - SASSERT(m.neq(a, b)); - SASSERT(!m.is_zero(a) && !m.is_pos(a) && m.is_neg(a) && m.is_nonpos(a) && !m.is_nonneg(a)); + ENSURE(m.neq(a, b)); + ENSURE(!m.is_zero(a) && !m.is_pos(a) && m.is_neg(a) && m.is_nonpos(a) && !m.is_nonneg(a)); m.neg(a); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); m.set(a, 1); - SASSERT(m.is_one(a) && !m.is_zero(a) && !m.is_minus_one(a) && m.is_abs_one(a)); + ENSURE(m.is_one(a) && !m.is_zero(a) && !m.is_minus_one(a) && m.is_abs_one(a)); m.neg(a); - SASSERT(!m.is_one(a) && !m.is_zero(a) && m.is_minus_one(a) && m.is_abs_one(a)); + ENSURE(!m.is_one(a) && !m.is_zero(a) && m.is_minus_one(a) && m.is_abs_one(a)); m.set(a, 3); - SASSERT(!m.is_one(a) && !m.is_zero(a) && !m.is_minus_one(a)); + ENSURE(!m.is_one(a) && !m.is_zero(a) && !m.is_minus_one(a)); m.set(a, 3); b = a; m.abs(a); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); m.set(a, -3); b = a; m.abs(a); - SASSERT(!m.eq(a,b) && m.is_pos(a)); + ENSURE(!m.eq(a,b) && m.is_pos(a)); m.set(a, 1); m.swap(a, a); - SASSERT(m.is_one(a)); + ENSURE(m.is_one(a)); m.set(b, -1); m.swap(a, b); - SASSERT(m.is_one(b) && m.is_minus_one(a)); + ENSURE(m.is_one(b) && m.is_minus_one(a)); m.neg(a); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); } static void tst_limits(unsigned prec) { mpff_manager m(prec); scoped_mpff a(m), b(m), two(m); m.set_max(a); - SASSERT(m.is_pos(a)); + ENSURE(m.is_pos(a)); m.set_min(b); - SASSERT(m.is_neg(b)); + ENSURE(m.is_neg(b)); m.neg(a); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); m.set_max(a); m.set_max(b); m.round_to_minus_inf(); m.inc(a); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); m.dec(a); - SASSERT(m.lt(a, b)); + ENSURE(m.lt(a, b)); m.set_max(a); m.round_to_plus_inf(); bool overflow = false; @@ -438,99 +436,99 @@ static void tst_limits(unsigned prec) { VERIFY(overflow); m.set_max(a); m.dec(a); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); m.set_min(a); m.set_min(b); m.round_to_minus_inf(); m.inc(a); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); overflow = true; try { m.dec(a); } catch (mpff_manager::overflow_exception) { overflow = true; } - SASSERT(overflow); + ENSURE(overflow); m.round_to_plus_inf(); m.set_min(a); m.inc(a); - SASSERT(m.gt(a,b)); + ENSURE(m.gt(a,b)); m.set_min(a); m.dec(a); - SASSERT(m.eq(a,b)); + ENSURE(m.eq(a,b)); m.set_plus_epsilon(a); m.set_plus_epsilon(b); - SASSERT(!m.is_zero(a) && m.is_pos(a)); + ENSURE(!m.is_zero(a) && m.is_pos(a)); m.set(two, 2); m.round_to_plus_inf(); m.div(a, two, a); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); m.round_to_minus_inf(); m.div(a, two, a); - SASSERT(m.is_zero(a)); + ENSURE(m.is_zero(a)); m.round_to_plus_inf(); m.set_plus_epsilon(a); m.add(a, a, a); - SASSERT(m.gt(a, b)); + ENSURE(m.gt(a, b)); m.round_to_minus_inf(); m.set_plus_epsilon(a); m.add(a, a, a); - SASSERT(m.gt(a, b)); + ENSURE(m.gt(a, b)); m.set_plus_epsilon(a); m.sub(a, a, a); - SASSERT(m.is_zero(a)); + ENSURE(m.is_zero(a)); m.set_plus_epsilon(a); - SASSERT(m.is_plus_epsilon(a)); - SASSERT(!m.is_minus_epsilon(a)); + ENSURE(m.is_plus_epsilon(a)); + ENSURE(!m.is_minus_epsilon(a)); m.neg(a); - SASSERT(!m.is_plus_epsilon(a)); - SASSERT(m.is_minus_epsilon(a)); + ENSURE(!m.is_plus_epsilon(a)); + ENSURE(m.is_minus_epsilon(a)); for (unsigned i = 0; i < 2; i++) { m.set_rounding(i == 0); m.set_plus_epsilon(a); m.floor(a); - SASSERT(m.is_zero(a)); + ENSURE(m.is_zero(a)); m.set_plus_epsilon(a); m.ceil(a); - SASSERT(m.is_one(a)); + ENSURE(m.is_one(a)); m.set_minus_epsilon(a); m.floor(a); - SASSERT(m.is_minus_one(a)); + ENSURE(m.is_minus_one(a)); m.set_minus_epsilon(a); m.ceil(a); - SASSERT(m.is_zero(a)); + ENSURE(m.is_zero(a)); } m.set_minus_epsilon(a); m.set_minus_epsilon(b); - SASSERT(!m.is_zero(a) && m.is_neg(a)); + ENSURE(!m.is_zero(a) && m.is_neg(a)); m.set(two, 2); m.round_to_minus_inf(); m.div(a, two, a); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); m.round_to_plus_inf(); m.div(a, two, a); - SASSERT(m.is_zero(a)); + ENSURE(m.is_zero(a)); m.round_to_plus_inf(); m.set_minus_epsilon(a); m.add(a, a, a); - SASSERT(m.lt(a, b)); + ENSURE(m.lt(a, b)); m.round_to_minus_inf(); m.set_minus_epsilon(a); m.add(a, a, a); - SASSERT(m.lt(a, b)); + ENSURE(m.lt(a, b)); m.set_minus_epsilon(a); m.sub(a, a, a); - SASSERT(m.is_zero(a)); + ENSURE(m.is_zero(a)); m.set_minus_epsilon(a); - SASSERT(!m.is_plus_epsilon(a)); - SASSERT(m.is_minus_epsilon(a)); + ENSURE(!m.is_plus_epsilon(a)); + ENSURE(m.is_minus_epsilon(a)); m.neg(a); - SASSERT(m.is_plus_epsilon(a)); - SASSERT(!m.is_minus_epsilon(a)); + ENSURE(m.is_plus_epsilon(a)); + ENSURE(!m.is_minus_epsilon(a)); } #if 0 @@ -549,7 +547,7 @@ static void tst_decimal(int64 n, uint64 d, bool to_plus_inf, unsigned prec, char m.display_decimal(std::cout, a, decimal_places); std::cout << std::endl; std::ostringstream buffer; m.display_decimal(buffer, a, decimal_places); - SASSERT(strcmp(expected, buffer.str().c_str()) == 0); + ENSURE(strcmp(expected, buffer.str().c_str()) == 0); } static void tst_decimal() { @@ -573,7 +571,7 @@ static void tst_prev_power_2(int64 n, uint64 d, unsigned expected) { mpff_manager m; scoped_mpff a(m); m.set(a, n, d); - SASSERT(m.prev_power_of_two(a) == expected); + ENSURE(m.prev_power_of_two(a) == expected); } static void tst_prev_power_2() { diff --git a/src/test/mpfx.cpp b/src/test/mpfx.cpp index 9e8882a26..f9dc123f5 100644 --- a/src/test/mpfx.cpp +++ b/src/test/mpfx.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"mpfx.h" +#include "util/mpfx.h" static void tst1() { mpfx_manager m; @@ -39,7 +39,7 @@ static void tst_prev_power_2(int64 n, uint64 d, unsigned expected) { mpfx_manager m; scoped_mpfx a(m); m.set(a, n, d); - SASSERT(m.prev_power_of_two(a) == expected); + ENSURE(m.prev_power_of_two(a) == expected); } static void tst_prev_power_2() { diff --git a/src/test/mpq.cpp b/src/test/mpq.cpp index 68c7d8bb3..7b60d9dcb 100644 --- a/src/test/mpq.cpp +++ b/src/test/mpq.cpp @@ -17,9 +17,9 @@ Revision History: --*/ -#include"mpq.h" -#include"rational.h" -#include"timeit.h" +#include "util/mpq.h" +#include "util/rational.h" +#include "util/timeit.h" static void tst0() { synch_mpq_manager m; @@ -27,7 +27,7 @@ static void tst0() { m.set(a, 2, 3); m.set(b, 4, 3); m.div(a, b, b); - SASSERT(m.eq(b, m.mk_q(1, 2))); + ENSURE(m.eq(b, m.mk_q(1, 2))); } static void tst1() { @@ -41,15 +41,15 @@ static void tst1() { std::cout << "*-2 = \n" << m.to_string(v2) << "\n"; m.add(v, v2, v3); m.neg(v3); - SASSERT(m.eq(v, v3)); - SASSERT(m.le(v, v3)); - SASSERT(m.ge(v, v3)); - SASSERT(m.lt(v2, v)); - SASSERT(m.le(v2, v)); - SASSERT(m.gt(v, v2)); - SASSERT(m.ge(v, v2)); - SASSERT(m.neq(v, v2)); - SASSERT(!m.neq(v, v3)); + ENSURE(m.eq(v, v3)); + ENSURE(m.le(v, v3)); + ENSURE(m.ge(v, v3)); + ENSURE(m.lt(v2, v)); + ENSURE(m.le(v2, v)); + ENSURE(m.gt(v, v2)); + ENSURE(m.ge(v, v2)); + ENSURE(m.neq(v, v2)); + ENSURE(!m.neq(v, v3)); m.del(v); m.del(v2); m.del(v3); @@ -68,7 +68,7 @@ static void mk_random_num_str(unsigned buffer_sz, char * buffer) { if (div_pos == 0) div_pos++; } - SASSERT(sz < buffer_sz); + ENSURE(sz < buffer_sz); for (unsigned i = 0; i < sz-1; i++) { if (i == div_pos && i < sz-2) { buffer[i] = '/'; @@ -90,7 +90,7 @@ static void bug1() { m.set(a, 2); m.set(b, 1, 2); m.inv(a, a); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); } static void bug2() { @@ -100,7 +100,7 @@ static void bug2() { m.set(a, -2); m.set(b, -1, 2); m.inv(a, a); - SASSERT(m.eq(a, b)); + ENSURE(m.eq(a, b)); } static void tst2() { @@ -122,22 +122,22 @@ static void set_str_bug() { m.set(a, "1.0"); std::cout << a << "\n"; m.set(b, 1); - SASSERT(a == b); + ENSURE(a == b); m.set(a, "1.1"); std::cout << a << "\n"; m.set(b, 11, 10); - SASSERT(a == b); + ENSURE(a == b); m.set(a, "1/3"); m.set(b, 1, 3); std::cout << a << "\n"; - SASSERT(a == b); + ENSURE(a == b); } static void tst_prev_power_2(int64 n, uint64 d, unsigned expected) { unsynch_mpq_manager m; scoped_mpq a(m); m.set(a, n, d); - SASSERT(m.prev_power_of_two(a) == expected); + ENSURE(m.prev_power_of_two(a) == expected); } static void tst_prev_power_2() { diff --git a/src/test/mpz.cpp b/src/test/mpz.cpp index 02627e842..7926388df 100644 --- a/src/test/mpz.cpp +++ b/src/test/mpz.cpp @@ -17,10 +17,10 @@ Revision History: --*/ -#include"mpz.h" -#include"rational.h" -#include"timeit.h" -#include"scoped_numeral.h" +#include "util/mpz.h" +#include "util/rational.h" +#include "util/timeit.h" +#include "util/scoped_numeral.h" static void tst1() { synch_mpz_manager m; @@ -33,15 +33,15 @@ static void tst1() { std::cout << "*-2 = \n" << m.to_string(v2) << "\n"; m.add(v, v2, v3); m.neg(v3); - SASSERT(m.eq(v, v3)); - SASSERT(m.le(v, v3)); - SASSERT(m.ge(v, v3)); - SASSERT(m.lt(v2, v)); - SASSERT(m.le(v2, v)); - SASSERT(m.gt(v, v2)); - SASSERT(m.ge(v, v2)); - SASSERT(m.neq(v, v2)); - SASSERT(!m.neq(v, v3)); + ENSURE(m.eq(v, v3)); + ENSURE(m.le(v, v3)); + ENSURE(m.ge(v, v3)); + ENSURE(m.lt(v2, v)); + ENSURE(m.le(v2, v)); + ENSURE(m.gt(v, v2)); + ENSURE(m.ge(v, v2)); + ENSURE(m.neq(v, v2)); + ENSURE(!m.neq(v, v3)); m.del(v); m.del(v2); m.del(v3); @@ -80,7 +80,7 @@ static void tst2b() { #if 0 static void mk_random_num_str(unsigned buffer_sz, char * buffer) { unsigned sz = (rand() % (buffer_sz-2)) + 1; - SASSERT(sz < buffer_sz); + ENSURE(sz < buffer_sz); for (unsigned i = 0; i < sz-1; i++) { buffer[i] = '0' + (rand() % 10); } @@ -96,7 +96,7 @@ static void bug1() { m.set(v1, "1002043949858757875676767675747473"); mpz v2; m.sub(v1, v1, v2); - SASSERT(m.is_zero(v2)); + ENSURE(m.is_zero(v2)); m.del(v1); m.del(v2); } @@ -119,7 +119,7 @@ static void bug3() { m.set(v2, INT_MAX); m.add(v2, m.mk_z(1), v2); m.neg(v1); - SASSERT(m.eq(v1, v2)); + ENSURE(m.eq(v1, v2)); m.del(v1); m.del(v2); } @@ -137,7 +137,7 @@ static void bug4() { m.bitwise_or(result2, y, result2); std::cout << m.to_string(result1) << " " << m.to_string(result2) << "\n"; - SASSERT(m.eq(result1, result2)); + ENSURE(m.eq(result1, result2)); m.del(x); m.del(y); m.del(result1); m.del(result2); } @@ -149,7 +149,7 @@ void tst_div2k(synch_mpz_manager & m, mpz const & v, unsigned k) { bool is_eq = m.eq(x, y); (void)is_eq; CTRACE("mpz_2k", !is_eq, tout << "div: " << m.to_string(v) << ", k: " << k << " r: " << m.to_string(x) << ", expected: " << m.to_string(y) << "\n";); - SASSERT(is_eq); + ENSURE(is_eq); m.del(x); m.del(y); m.del(pw); @@ -177,7 +177,7 @@ void tst_mul2k(synch_mpz_manager & m, mpz const & v, unsigned k) { bool is_eq = m.eq(x, y); (void)is_eq; CTRACE("mpz_2k", !is_eq, tout << "mul: " << m.to_string(v) << ", k: " << k << " r: " << m.to_string(x) << ", expected: " << m.to_string(y) << "\n";); - SASSERT(is_eq); + ENSURE(is_eq); m.del(x); m.del(y); m.del(pw); @@ -286,7 +286,7 @@ void tst_int_min_bug() { m.set(expected, "18446744075857035263"); m.sub(big, intmin, r); std::cout << "r: " << m.to_string(r) << "\nexpected: " << m.to_string(expected) << "\n"; - SASSERT(m.eq(r, expected)); + ENSURE(m.eq(r, expected)); m.del(intmin); m.del(big); m.del(expected); @@ -396,9 +396,9 @@ void tst_log2(unsynch_mpz_manager & m, mpz const & a) { scoped_mpz b(m); unsigned k = m.log2(a); m.power(mpz(2), k, b); - SASSERT(m.is_zero(a) || m.le(b, a)); + ENSURE(m.is_zero(a) || m.le(b, a)); m.power(mpz(2), k+1, b); - SASSERT(m.le(a, b)); + ENSURE(m.le(a, b)); scoped_mpz neg_a(m); m.set(neg_a, a); @@ -406,10 +406,10 @@ void tst_log2(unsynch_mpz_manager & m, mpz const & a) { k = m.mlog2(neg_a); m.power(mpz(2), k, b); m.neg(b); - SASSERT(m.is_zero(neg_a) || m.le(neg_a, b)); + ENSURE(m.is_zero(neg_a) || m.le(neg_a, b)); m.power(mpz(2), k+1, b); m.neg(b); - SASSERT(m.le(b, neg_a)); + ENSURE(m.le(b, neg_a)); } void tst_log2() { @@ -432,20 +432,20 @@ void tst_root() { m.set(a, 213); VERIFY(!m.root(a, 5)); std::cout << "213^{1/5}: " << a << "\n"; - SASSERT(m.eq(a, mpz(3))); + ENSURE(m.eq(a, mpz(3))); m.set(a, -213); VERIFY(!m.root(a, 5)); std::cout << "-213^{1/5}: " << a << "\n"; - SASSERT(m.eq(a, mpz(-2))); + ENSURE(m.eq(a, mpz(-2))); m.set(a, 0); VERIFY(m.root(a, 3)); - SASSERT(m.is_zero(a)); + ENSURE(m.is_zero(a)); m.set(a, 8); VERIFY(m.root(a, 3)); - SASSERT(m.eq(a, mpz(2))); + ENSURE(m.eq(a, mpz(2))); m.set(a, -8); VERIFY(m.root(a, 3)); - SASSERT(m.eq(a, mpz(-2))); + ENSURE(m.eq(a, mpz(-2))); } void tst_gcd_bug() { diff --git a/src/test/nlarith_util.cpp b/src/test/nlarith_util.cpp index 2def66b38..4769c1591 100644 --- a/src/test/nlarith_util.cpp +++ b/src/test/nlarith_util.cpp @@ -4,10 +4,10 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "nlarith_util.h" -#include "arith_decl_plugin.h" -#include "ast_pp.h" -#include "reg_decl_plugins.h" +#include "qe/nlarith_util.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/reg_decl_plugins.h" void tst_nlarith_util() { ast_manager M; diff --git a/src/test/nlsat.cpp b/src/test/nlsat.cpp index df25db927..ecf73843f 100644 --- a/src/test/nlsat.cpp +++ b/src/test/nlsat.cpp @@ -16,14 +16,14 @@ Author: Notes: --*/ -#include"nlsat_assignment.h" -#include"nlsat_interval_set.h" -#include"nlsat_evaluator.h" -#include"nlsat_solver.h" -#include"util.h" -#include"nlsat_explain.h" -#include"polynomial_cache.h" -#include"rlimit.h" +#include "nlsat/nlsat_assignment.h" +#include "nlsat/nlsat_interval_set.h" +#include "nlsat/nlsat_evaluator.h" +#include "nlsat/nlsat_solver.h" +#include "util/util.h" +#include "nlsat/nlsat_explain.h" +#include "math/polynomial/polynomial_cache.h" +#include "util/rlimit.h" nlsat::interval_set_ref tst_interval(nlsat::interval_set_ref const & s1, nlsat::interval_set_ref const & s2, @@ -35,25 +35,25 @@ nlsat::interval_set_ref tst_interval(nlsat::interval_set_ref const & s1, std::cout << "s2: " << s2 << "\n"; r = ism.mk_union(s1, s2); std::cout << "union(s1, s2): " << r << std::endl; - SASSERT(!check_num_intervals || ism.num_intervals(r) == expected_num_intervals); - SASSERT(ism.subset(s1, r)); - SASSERT(ism.subset(s2, r)); + ENSURE(!check_num_intervals || ism.num_intervals(r) == expected_num_intervals); + ENSURE(ism.subset(s1, r)); + ENSURE(ism.subset(s2, r)); if (ism.set_eq(s1, s2)) { - SASSERT(ism.set_eq(s1, r)); - SASSERT(ism.set_eq(s2, r)); + ENSURE(ism.set_eq(s1, r)); + ENSURE(ism.set_eq(s2, r)); } else { - SASSERT(ism.subset(s1, s2) || !ism.subset(r, s2)); - SASSERT(ism.subset(s2, s1) || !ism.subset(r, s1)); + ENSURE(ism.subset(s1, s2) || !ism.subset(r, s2)); + ENSURE(ism.subset(s2, s1) || !ism.subset(r, s1)); } nlsat::interval_set_ref r2(ism); r2 = ism.mk_union(s2, s1); - SASSERT(ism.set_eq(r, r2)); + ENSURE(ism.set_eq(r, r2)); anum zero; nlsat::interval_set_ref full(ism); nlsat::literal dummy(131, false); full = ism.mk(true, true, zero, true, true, zero, dummy); - SASSERT(ism.set_eq(r, full) == ism.is_full(r)); + ENSURE(ism.set_eq(r, full) == ism.is_full(r)); return r; } @@ -178,8 +178,8 @@ static void tst3() { static nlsat::interval_set_ref mk_random(nlsat::interval_set_manager & ism, anum_manager & am, int range, int space, int tries, bool minus_inf, bool plus_inf, nlsat::literal lit) { static random_gen gen; - SASSERT(range > 0); - SASSERT(space > 0); + ENSURE(range > 0); + ENSURE(space > 0); nlsat::interval_set_ref r(ism), curr(ism); scoped_anum lower(am); scoped_anum upper(am); @@ -227,17 +227,17 @@ static void check_subset_result(nlsat::interval_set_ref const & s1, unsigned num = ism.num_intervals(r); nlsat::literal_vector lits; ism.get_justifications(r, lits); - SASSERT(lits.size() <= 2); + ENSURE(lits.size() <= 2); for (unsigned i = 0; i < num; i++) { tmp = ism.get_interval(r, i); ism.get_justifications(tmp, lits); - SASSERT(lits.size() == 1); + ENSURE(lits.size() == 1); if (lits[0] == l1) { - SASSERT(ism.subset(tmp, s1)); + ENSURE(ism.subset(tmp, s1)); } else { - SASSERT(lits[0] == l2); - SASSERT(ism.subset(tmp, s2)); + ENSURE(lits[0] == l2); + ENSURE(ism.subset(tmp, s2)); } } } @@ -293,7 +293,7 @@ static void tst5() { bool is_even[1] = { false }; nlsat::bool_var b = s.mk_ineq_atom(nlsat::atom::GT, 1, _p, is_even); nlsat::atom * a = s.bool_var2atom(b); - SASSERT(a != 0); + ENSURE(a != 0); scoped_anum zero(am); am.set(zero, 0); as.set(0, zero); @@ -432,7 +432,7 @@ static void tst7() { litsv.reset(); litsv.append(2, lits.c_ptr()); res = s.check(litsv); - SASSERT(res == l_true); + ENSURE(res == l_true); s.display(std::cout); s.am().display(std::cout, s.value(x0)); std::cout << "\n"; s.am().display(std::cout, s.value(x1)); std::cout << "\n"; @@ -698,10 +698,8 @@ static void tst10() { void tst_nlsat() { tst10(); std::cout << "------------------\n"; - exit(0); tst9(); std::cout << "------------------\n"; - exit(0); tst8(); std::cout << "------------------\n"; tst7(); diff --git a/src/test/no_overflow.cpp b/src/test/no_overflow.cpp index d795bc1fd..bb87b1d30 100644 --- a/src/test/no_overflow.cpp +++ b/src/test/no_overflow.cpp @@ -18,9 +18,9 @@ Revision History: --*/ #ifdef _WINDOWS -#include "z3.h" -#include "trace.h" -#include "rational.h" +#include "api/z3.h" +#include "util/trace.h" +#include "util/rational.h" #define TEST(TEST_NAME, TEST_OUTCOME, NEG_TEST_OUTCOME) \ do { \ @@ -28,12 +28,12 @@ Revision History: { \ Z3_solver_push(ctx, s); \ Z3_solver_assert(ctx, s, TEST_NAME); \ - SASSERT(Z3_solver_check(ctx, s) == TEST_OUTCOME); \ + ENSURE(Z3_solver_check(ctx, s) == TEST_OUTCOME); \ Z3_solver_pop(ctx, s, 1); \ \ Z3_solver_push(ctx, s); \ Z3_solver_assert(ctx, s, Z3_mk_not(ctx, TEST_NAME)); \ - SASSERT(Z3_solver_check(ctx, s) == NEG_TEST_OUTCOME); \ + ENSURE(Z3_solver_check(ctx, s) == NEG_TEST_OUTCOME); \ Z3_solver_pop(ctx, s, 1); \ } \ } while (0) @@ -630,7 +630,7 @@ void test_equiv(Equivalence_params params, unsigned bvsize, bool is_signed) { equiv = Z3_mk_implies(ctx, cond, equiv); } Z3_solver_assert(ctx, s, Z3_mk_not(ctx, equiv)); - SASSERT(Z3_solver_check(ctx, s) == Z3_L_FALSE); + ENSURE(Z3_solver_check(ctx, s) == Z3_L_FALSE); Z3_solver_pop(ctx, s, 1); Z3_solver_dec_ref(ctx, s); @@ -662,7 +662,7 @@ void test_equiv(Equivalence_params params, unsigned bvsize, bool is_signed) { // Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, t2, Z3_mk_numeral(ctx, "1", bv))); // //TEST_NO_UNDERFLOW; // Z3_solver_assert(ctx, s, test_udfl); -// SASSERT(Z3_check(ctx) == Z3_TRUE); +// ENSURE(Z3_check(ctx) == Z3_TRUE); // Z3_solver_pop(ctx, s, 1); // // Z3_del_config(cfg); diff --git a/src/test/object_allocator.cpp b/src/test/object_allocator.cpp index cca42cf6f..ce2ae124c 100644 --- a/src/test/object_allocator.cpp +++ b/src/test/object_allocator.cpp @@ -17,8 +17,8 @@ Revision History: --*/ -#include"rational.h" -#include"object_allocator.h" +#include "util/rational.h" +#include "util/object_allocator.h" struct cell { rational m_coeff; @@ -62,12 +62,12 @@ static void tst1() { cell * c3 = m.allocate(); (void)c3; - SASSERT(c3->m_coeff.is_zero()); + ENSURE(c3->m_coeff.is_zero()); } static void tst2() { cell_allocator m; - SASSERT(m.capacity() >= 2); + ENSURE(m.capacity() >= 2); cell_allocator::worker_object_allocator m1 = m.get_worker_allocator(0); cell_allocator::worker_object_allocator m2 = m.get_worker_allocator(1); m.enable_concurrent(true); @@ -83,7 +83,7 @@ static void tst2() { c = m1.allocate(); else c = m2.allocate(); - SASSERT(c->m_coeff.is_zero()); + ENSURE(c->m_coeff.is_zero()); int val = rand(); c->m_coeff = rational(val); object_coeff_pairs.push_back(std::make_pair(c, val)); @@ -93,7 +93,7 @@ static void tst2() { unsigned idx = rand() % object_coeff_pairs.size(); cell * c = object_coeff_pairs[idx].first; CTRACE("object_allocator", c->m_coeff != rational(object_coeff_pairs[idx].second), tout << c->m_coeff << " != " << rational(object_coeff_pairs[idx].second) << "\n";); - SASSERT(c->m_coeff == rational(object_coeff_pairs[idx].second)); + ENSURE(c->m_coeff == rational(object_coeff_pairs[idx].second)); if (idx < 5) m1.recycle(c); else @@ -118,5 +118,5 @@ void tst_object_allocator() { tst2(); TRACE("object_allocator", tout << "num. allocated cells: " << cell::g_num_allocated_cells << "\nnum. deallocated cells: " << cell::g_num_deallocated_cells << "\nnum. recycled cells: " << cell::g_num_recycled_cells << "\n";); - SASSERT(cell::g_num_allocated_cells == cell::g_num_deallocated_cells); + ENSURE(cell::g_num_allocated_cells == cell::g_num_deallocated_cells); } diff --git a/src/test/old_interval.cpp b/src/test/old_interval.cpp index 12a45555d..4ab8b0dd0 100644 --- a/src/test/old_interval.cpp +++ b/src/test/old_interval.cpp @@ -16,103 +16,103 @@ Author: Revision History: --*/ -#include"old_interval.h" +#include "smt/old_interval.h" static void tst1() { ext_numeral inf(true); ext_numeral minus_inf(false); ext_numeral zero(0); - SASSERT(ext_numeral(10) + ext_numeral(3) == ext_numeral(13)); - SASSERT(inf + zero == inf); - SASSERT(minus_inf + zero == minus_inf); - SASSERT(minus_inf + ext_numeral(3) == minus_inf); - SASSERT(inf + inf == inf); - SASSERT(minus_inf + minus_inf == minus_inf); - SASSERT(minus_inf + ext_numeral(10) == minus_inf); - SASSERT(minus_inf + ext_numeral(-10) == minus_inf); - SASSERT(inf + ext_numeral(10) == inf); - SASSERT(inf + ext_numeral(-10) == inf); + ENSURE(ext_numeral(10) + ext_numeral(3) == ext_numeral(13)); + ENSURE(inf + zero == inf); + ENSURE(minus_inf + zero == minus_inf); + ENSURE(minus_inf + ext_numeral(3) == minus_inf); + ENSURE(inf + inf == inf); + ENSURE(minus_inf + minus_inf == minus_inf); + ENSURE(minus_inf + ext_numeral(10) == minus_inf); + ENSURE(minus_inf + ext_numeral(-10) == minus_inf); + ENSURE(inf + ext_numeral(10) == inf); + ENSURE(inf + ext_numeral(-10) == inf); - SASSERT(ext_numeral(10) - ext_numeral(3) == ext_numeral(7)); - SASSERT(inf - zero == inf); - SASSERT(minus_inf - zero == minus_inf); - SASSERT(minus_inf - ext_numeral(3) == minus_inf); - SASSERT(inf - minus_inf == inf); - SASSERT(minus_inf - inf == minus_inf); - SASSERT(zero - minus_inf == inf); - SASSERT(zero - inf == minus_inf); - SASSERT(ext_numeral(-10) - minus_inf == inf); - SASSERT(ext_numeral(10) - minus_inf == inf); - SASSERT(ext_numeral(-10) - inf == minus_inf); - SASSERT(ext_numeral(10) - inf == minus_inf); + ENSURE(ext_numeral(10) - ext_numeral(3) == ext_numeral(7)); + ENSURE(inf - zero == inf); + ENSURE(minus_inf - zero == minus_inf); + ENSURE(minus_inf - ext_numeral(3) == minus_inf); + ENSURE(inf - minus_inf == inf); + ENSURE(minus_inf - inf == minus_inf); + ENSURE(zero - minus_inf == inf); + ENSURE(zero - inf == minus_inf); + ENSURE(ext_numeral(-10) - minus_inf == inf); + ENSURE(ext_numeral(10) - minus_inf == inf); + ENSURE(ext_numeral(-10) - inf == minus_inf); + ENSURE(ext_numeral(10) - inf == minus_inf); - SASSERT(ext_numeral(10) * inf == inf); - SASSERT(ext_numeral(-10) * inf == minus_inf); - SASSERT(zero * inf == zero); - SASSERT(zero * minus_inf == zero); - SASSERT(zero * ext_numeral(10) == zero); - SASSERT(ext_numeral(10) * ext_numeral(-20) == ext_numeral(-200)); - SASSERT(ext_numeral(3) * ext_numeral(2) == ext_numeral(6)); - SASSERT(inf * inf == inf); - SASSERT(inf * minus_inf == minus_inf); - SASSERT(minus_inf * minus_inf == inf); - SASSERT(minus_inf * inf == minus_inf); - SASSERT(minus_inf * ext_numeral(10) == minus_inf); - SASSERT(minus_inf * ext_numeral(-10) == inf); + ENSURE(ext_numeral(10) * inf == inf); + ENSURE(ext_numeral(-10) * inf == minus_inf); + ENSURE(zero * inf == zero); + ENSURE(zero * minus_inf == zero); + ENSURE(zero * ext_numeral(10) == zero); + ENSURE(ext_numeral(10) * ext_numeral(-20) == ext_numeral(-200)); + ENSURE(ext_numeral(3) * ext_numeral(2) == ext_numeral(6)); + ENSURE(inf * inf == inf); + ENSURE(inf * minus_inf == minus_inf); + ENSURE(minus_inf * minus_inf == inf); + ENSURE(minus_inf * inf == minus_inf); + ENSURE(minus_inf * ext_numeral(10) == minus_inf); + ENSURE(minus_inf * ext_numeral(-10) == inf); - SASSERT(minus_inf < inf); - SASSERT(!(inf < minus_inf)); - SASSERT(minus_inf < ext_numeral(10)); - SASSERT(ext_numeral(-3) < inf); - SASSERT(ext_numeral(-10) < ext_numeral(4)); - SASSERT(ext_numeral(2) < ext_numeral(10)); - SASSERT(!(inf < ext_numeral(30))); - SASSERT(!(ext_numeral(10) < minus_inf)); - SASSERT(!(inf < inf)); - SASSERT(!(minus_inf < minus_inf)); - SASSERT(!(zero < zero)); - SASSERT(!(ext_numeral(10) < ext_numeral(10))); - SASSERT(inf > minus_inf); - SASSERT(inf > zero); - SASSERT(inf > ext_numeral(10)); - SASSERT(ext_numeral(10) > minus_inf); - SASSERT(zero > minus_inf); - SASSERT(!(zero > inf)); - SASSERT(!(minus_inf > inf)); - SASSERT(inf >= minus_inf); - SASSERT(inf >= inf); - SASSERT(minus_inf >= minus_inf); - SASSERT(inf >= zero); - SASSERT(zero >= minus_inf); - SASSERT(inf <= inf); - SASSERT(minus_inf <= minus_inf); - SASSERT(zero <= inf); - SASSERT(minus_inf <= zero); + ENSURE(minus_inf < inf); + ENSURE(!(inf < minus_inf)); + ENSURE(minus_inf < ext_numeral(10)); + ENSURE(ext_numeral(-3) < inf); + ENSURE(ext_numeral(-10) < ext_numeral(4)); + ENSURE(ext_numeral(2) < ext_numeral(10)); + ENSURE(!(inf < ext_numeral(30))); + ENSURE(!(ext_numeral(10) < minus_inf)); + ENSURE(!(inf < inf)); + ENSURE(!(minus_inf < minus_inf)); + ENSURE(!(zero < zero)); + ENSURE(!(ext_numeral(10) < ext_numeral(10))); + ENSURE(inf > minus_inf); + ENSURE(inf > zero); + ENSURE(inf > ext_numeral(10)); + ENSURE(ext_numeral(10) > minus_inf); + ENSURE(zero > minus_inf); + ENSURE(!(zero > inf)); + ENSURE(!(minus_inf > inf)); + ENSURE(inf >= minus_inf); + ENSURE(inf >= inf); + ENSURE(minus_inf >= minus_inf); + ENSURE(inf >= zero); + ENSURE(zero >= minus_inf); + ENSURE(inf <= inf); + ENSURE(minus_inf <= minus_inf); + ENSURE(zero <= inf); + ENSURE(minus_inf <= zero); ext_numeral val(10); val.neg(); - SASSERT(val == ext_numeral(-10)); + ENSURE(val == ext_numeral(-10)); val = inf; val.neg(); - SASSERT(val == minus_inf); + ENSURE(val == minus_inf); val.neg(); - SASSERT(val == inf); + ENSURE(val == inf); - SASSERT(minus_inf.sign()); - SASSERT(!zero.sign()); - SASSERT(!inf.sign()); - SASSERT(ext_numeral(-10).sign()); - SASSERT(!ext_numeral(10).sign()); + ENSURE(minus_inf.sign()); + ENSURE(!zero.sign()); + ENSURE(!inf.sign()); + ENSURE(ext_numeral(-10).sign()); + ENSURE(!ext_numeral(10).sign()); - SASSERT(inf.is_infinite()); - SASSERT(minus_inf.is_infinite()); - SASSERT(!zero.is_infinite()); - SASSERT(!ext_numeral(10).is_infinite()); - SASSERT(!inf.is_zero()); - SASSERT(!minus_inf.is_zero()); - SASSERT(zero.is_zero()); - SASSERT(!ext_numeral(10).is_zero()); + ENSURE(inf.is_infinite()); + ENSURE(minus_inf.is_infinite()); + ENSURE(!zero.is_infinite()); + ENSURE(!ext_numeral(10).is_infinite()); + ENSURE(!inf.is_zero()); + ENSURE(!minus_inf.is_zero()); + ENSURE(zero.is_zero()); + ENSURE(!ext_numeral(10).is_zero()); } class interval_tester { @@ -166,9 +166,9 @@ public: } }; -#include"basic_interval.h" -#include"mpz.h" -#include"scoped_numeral.h" +#include "util/basic_interval.h" +#include "util/mpz.h" +#include "util/scoped_numeral.h" static void tst2() { typedef basic_interval_manager mpzi_manager; @@ -182,12 +182,12 @@ static void tst2() { m.set(y, mpz(-2), mpz(3)); m.add(x, y, z); std::cout << "x: " << x << ", y: " << y << ", z: " << z << "\n"; - SASSERT(nm.eq(z.lower(), mpz(-1))); - SASSERT(nm.eq(z.upper(), mpz(5))); + ENSURE(nm.eq(z.lower(), mpz(-1))); + ENSURE(nm.eq(z.upper(), mpz(5))); m.mul(x, y, z); std::cout << "x: " << x << ", y: " << y << ", z: " << z << "\n"; - SASSERT(nm.eq(z.lower(), mpz(-4))); - SASSERT(nm.eq(z.upper(), mpz(6))); + ENSURE(nm.eq(z.lower(), mpz(-4))); + ENSURE(nm.eq(z.upper(), mpz(6))); } void tst_old_interval() { diff --git a/src/test/optional.cpp b/src/test/optional.cpp index 81b84cd59..d698f7289 100644 --- a/src/test/optional.cpp +++ b/src/test/optional.cpp @@ -16,17 +16,18 @@ Author: Revision History: --*/ -#include"trace.h" -#include"debug.h" -#include"optional.h" +#include "util/trace.h" +#include "util/debug.h" +#include "util/memory_manager.h" +#include "util/optional.h" static void tst1() { optional v; - SASSERT(!v); - SASSERT(v == false); + ENSURE(!v); + ENSURE(v == false); v = 10; - SASSERT(v); - SASSERT(*v == 10); + ENSURE(v); + ENSURE(*v == 10); TRACE("optional", tout << sizeof(v) << "\n";); } @@ -35,35 +36,35 @@ struct OptFoo { int m_y; OptFoo(int x, int y):m_x(x), m_y(y) { - TRACE("optional", tout << "OptFoo created: " << m_x << " : " << m_y << "\n";); + TRACE("optional", tout << "OptFoo created: " << m_x << " : " << m_y << "\n";); } ~OptFoo() { - TRACE("optional", tout << "OptFoo deleted: " << m_x << " : " << m_y << "\n";); + TRACE("optional", tout << "OptFoo deleted: " << m_x << " : " << m_y << "\n";); } }; static void tst2() { optional v; - SASSERT(!v); + ENSURE(!v); v = OptFoo(10, 20); - SASSERT(v->m_x == 10); - SASSERT(v->m_y == 20); + ENSURE(v->m_x == 10); + ENSURE(v->m_y == 20); v = OptFoo(200, 300); - SASSERT(v->m_x == 200); - SASSERT(v->m_y == 300); + ENSURE(v->m_x == 200); + ENSURE(v->m_y == 300); TRACE("optional", tout << sizeof(v) << "\n";); } static void tst3() { optional v; - SASSERT(!v); + ENSURE(!v); int x = 10; v = &x; - SASSERT(v); - SASSERT(*v == &x); + ENSURE(v); + ENSURE(*v == &x); TRACE("optional", tout << sizeof(v) << "\n";); - SASSERT(*(*v) == 10); + ENSURE(*(*v) == 10); } void tst_optional() { diff --git a/src/test/parray.cpp b/src/test/parray.cpp index 7976971d8..6aef4f359 100644 --- a/src/test/parray.cpp +++ b/src/test/parray.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"parray.h" -#include"small_object_allocator.h" -#include"ast.h" +#include "util/parray.h" +#include "util/small_object_allocator.h" +#include "ast/ast.h" template struct int_parray_config { @@ -46,36 +46,36 @@ static void tst1() { int_array a3; m.mk(a1); - SASSERT(m.size(a1) == 0); + ENSURE(m.size(a1) == 0); m.push_back(a1, 10, a2); TRACE("parray", m.display_info(tout, a1); tout << "\n"; m.display_info(tout, a2); tout << "\n";); - SASSERT(m.size(a1) == 0); - SASSERT(m.size(a2) == 1); + ENSURE(m.size(a1) == 0); + ENSURE(m.size(a2) == 1); m.push_back(a1, 20, a1); m.push_back(a1, 30, a1); TRACE("parray", m.display_info(tout, a1); tout << "\n"; m.display_info(tout, a2); tout << "\n";); - SASSERT(m.get(a1, 0) == 20); - SASSERT(m.get(a1, 1) == 30); - SASSERT(m.get(a2, 0) == 10); - SASSERT(m.size(a1) == 2); - SASSERT(m.size(a2) == 1); - SASSERT(m.size(a3) == 0); + ENSURE(m.get(a1, 0) == 20); + ENSURE(m.get(a1, 1) == 30); + ENSURE(m.get(a2, 0) == 10); + ENSURE(m.size(a1) == 2); + ENSURE(m.size(a2) == 1); + ENSURE(m.size(a3) == 0); m.push_back(a2, 100, a3); - SASSERT(m.size(a3) == 2); - SASSERT(m.get(a3, 0) == 10); - SASSERT(m.get(a3, 1) == 100); + ENSURE(m.size(a3) == 2); + ENSURE(m.get(a3, 0) == 10); + ENSURE(m.get(a3, 1) == 100); TRACE("parray", m.display_info(tout, a1); tout << "\n"; m.display_info(tout, a2); tout << "\n"; m.display_info(tout, a3); tout << "\n";); m.push_back(a2, 50); - SASSERT(m.get(a2, 0) == 10); - SASSERT(m.get(a2, 1) == 50); - SASSERT(m.size(a2) == 2); + ENSURE(m.get(a2, 0) == 10); + ENSURE(m.get(a2, 1) == 50); + ENSURE(m.size(a2) == 2); TRACE("parray", m.display_info(tout, a1); tout << "\n"; m.display_info(tout, a2); tout << "\n"; @@ -100,22 +100,22 @@ static void tst2() { for (unsigned i = 0; i < 100; i++) m.push_back(a1, i); - SASSERT(m.size(a1) == 100); + ENSURE(m.size(a1) == 100); m.push_back(a1, 100, a2); for (unsigned i = 0; i < 10; i++) m.push_back(a2, i+101); TRACE("parray", m.display_info(tout, a1); tout << "\n"; m.display_info(tout, a2); tout << "\n";); - SASSERT(m.get(a1, 0) == 0); + ENSURE(m.get(a1, 0) == 0); TRACE("parray", m.display_info(tout, a1); tout << "\n"; m.display_info(tout, a2); tout << "\n";); for (unsigned i = 0; i < m.size(a1); i++) { - SASSERT(static_cast(m.get(a1, i)) == i); + ENSURE(static_cast(m.get(a1, i)) == i); } for (unsigned i = 0; i < m.size(a2); i++) { - SASSERT(static_cast(m.get(a2, i)) == i); + ENSURE(static_cast(m.get(a2, i)) == i); } TRACE("parray", m.display_info(tout, a1); tout << "\n"; @@ -145,7 +145,7 @@ static void tst3() { for (unsigned i = 0; i < 20; i++) m.push_back(a1, i); - SASSERT(m.size(a1) == 20); + ENSURE(m.size(a1) == 20); m.set(a1, 0, 1, a2); for (unsigned i = 1; i < 20; i++) { if (i == 6) { @@ -161,7 +161,7 @@ static void tst3() { m.push_back(a4, 30); for (unsigned i = 0; i < 20; i++) { - SASSERT(static_cast(m.get(a2, i)) == i+1); + ENSURE(static_cast(m.get(a2, i)) == i+1); } TRACE("parray", m.display_info(tout, a1); tout << "\n"; @@ -169,7 +169,7 @@ static void tst3() { m.display_info(tout, a3); tout << "\n"; m.display_info(tout, a4); tout << "\n"; ); - SASSERT(m.get(a1, 10) == 10); + ENSURE(m.get(a1, 10) == 10); TRACE("parray", tout << "after rerooting...\n"; m.display_info(tout, a1); tout << "\n"; @@ -177,19 +177,19 @@ static void tst3() { m.display_info(tout, a3); tout << "\n"; m.display_info(tout, a4); tout << "\n"; ); - SASSERT(m.size(a1) == 20); - SASSERT(m.size(a2) == 20); - SASSERT(m.size(a3) == 19); - SASSERT(m.size(a4) == 19); + ENSURE(m.size(a1) == 20); + ENSURE(m.size(a2) == 20); + ENSURE(m.size(a3) == 19); + ENSURE(m.size(a4) == 19); for (unsigned i = 0; i < 20; i++) { - SASSERT(static_cast(m.get(a1, i)) == i); - SASSERT(static_cast(m.get(a2, i)) == i+1); - SASSERT(i >= 18 || static_cast(m.get(a4, i)) == i+1); - SASSERT(i >= 6 || static_cast(m.get(a3, i)) == i+1); - SASSERT(!(6 <= i && i <= 17) || static_cast(m.get(a3, i)) == i); + ENSURE(static_cast(m.get(a1, i)) == i); + ENSURE(static_cast(m.get(a2, i)) == i+1); + ENSURE(i >= 18 || static_cast(m.get(a4, i)) == i+1); + ENSURE(i >= 6 || static_cast(m.get(a3, i)) == i+1); + ENSURE(!(6 <= i && i <= 17) || static_cast(m.get(a3, i)) == i); } - SASSERT(m.get(a4, 18) == 30); - SASSERT(m.get(a3, 18) == 40); + ENSURE(m.get(a4, 18) == 30); + ENSURE(m.get(a3, 18) == 40); TRACE("parray", tout << "after many gets...\n"; m.display_info(tout, a1); tout << "\n"; diff --git a/src/test/pb2bv.cpp b/src/test/pb2bv.cpp index fcc309883..632b2d642 100644 --- a/src/test/pb2bv.cpp +++ b/src/test/pb2bv.cpp @@ -3,21 +3,21 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "trace.h" -#include "vector.h" -#include "ast.h" -#include "ast_pp.h" -#include "statistics.h" -#include "reg_decl_plugins.h" -#include "pb2bv_rewriter.h" -#include "smt_kernel.h" -#include "model_smt2_pp.h" -#include "smt_params.h" -#include "ast_util.h" -#include "pb_decl_plugin.h" -#include "th_rewriter.h" -#include "fd_solver.h" -#include "solver.h" +#include "util/trace.h" +#include "util/vector.h" +#include "ast/ast.h" +#include "ast/ast_pp.h" +#include "util/statistics.h" +#include "ast/reg_decl_plugins.h" +#include "ast/rewriter/pb2bv_rewriter.h" +#include "smt/smt_kernel.h" +#include "model/model_smt2_pp.h" +#include "smt/params/smt_params.h" +#include "ast/ast_util.h" +#include "ast/pb_decl_plugin.h" +#include "ast/rewriter/th_rewriter.h" +#include "tactic/portfolio/fd_solver.h" +#include "solver/solver.h" static void test1() { ast_manager m; @@ -81,7 +81,7 @@ static void test_semantics(ast_manager& m, expr_ref_vector const& vars, vectorcheck_sat(0,0); VERIFY(res == l_true); slv->assert_expr(m.is_true(result2) ? m.mk_not(result1) : result1.get()); diff --git a/src/test/pdr.cpp b/src/test/pdr.cpp index d95a55a24..7e2f1a5ad 100644 --- a/src/test/pdr.cpp +++ b/src/test/pdr.cpp @@ -4,8 +4,8 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "pdr_context.h" -#include "reg_decl_plugins.h" +#include "muz/pdr/pdr_context.h" +#include "ast/reg_decl_plugins.h" using namespace pdr; diff --git a/src/test/permutation.cpp b/src/test/permutation.cpp index d5929b6c0..74b97a365 100644 --- a/src/test/permutation.cpp +++ b/src/test/permutation.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"permutation.h" -#include"util.h" -#include"vector.h" +#include "util/permutation.h" +#include "util/util.h" +#include "util/vector.h" void apply_permutation_copy(unsigned sz, unsigned const * src, unsigned const * p, unsigned * target) { for (unsigned i = 0; i < sz; i++) { @@ -48,7 +48,7 @@ static void tst1(unsigned sz, unsigned num_tries, unsigned max = UINT_MAX) { apply_permutation(sz, data.c_ptr(), p.c_ptr()); // std::cout << "data: "; display(std::cout, data.begin(), data.end()); std::cout << "\n"; for (unsigned i = 0; i < 0; i++) - SASSERT(data[i] == new_data[i]); + ENSURE(data[i] == new_data[i]); } #endif } diff --git a/src/test/polynomial.cpp b/src/test/polynomial.cpp index 03eb321cd..00998a181 100644 --- a/src/test/polynomial.cpp +++ b/src/test/polynomial.cpp @@ -17,11 +17,11 @@ Notes: --*/ #if !defined(__clang__) -#include"polynomial.h" -#include"polynomial_var2value.h" -#include"polynomial_cache.h" -#include"linear_eq_solver.h" -#include"rlimit.h" +#include "math/polynomial/polynomial.h" +#include "math/polynomial/polynomial_var2value.h" +#include "math/polynomial/polynomial_cache.h" +#include "math/polynomial/linear_eq_solver.h" +#include "util/rlimit.h" static void tst1() { std::cout << "\n----- Basic testing -------\n"; @@ -39,7 +39,7 @@ static void tst1() { p = (x0^3) + x1*x0 + 2; std::cout << p << "\n"; std::cout << "max_var(p): " << max_var(p) << "\n"; - SASSERT(max_var(p) == 1); + ENSURE(max_var(p) == 1); std::cout << (2*x2 - x1*x0) << "\n"; std::cout << (p + (2*x2 - x1*x0)) << "\n"; std::cout << (p*p + 2*x2) << "\n"; @@ -79,7 +79,7 @@ static void tst_pseudo_div(polynomial_ref const & A, polynomial_ref const & B, p std::cout << "l_B^d: " << l_B_d << "\n"; std::cout << "Q * B + R: " << Q * B + R << "\n"; std::cout << "l_B_d * A: " << l_B_d * A << "\n"; - SASSERT(eq((Q * B + R), (l_B_d * A))); + ENSURE(eq((Q * B + R), (l_B_d * A))); } static void tst2() { @@ -329,13 +329,13 @@ static void tst11() { polynomial_ref d(m); d = exact_div(p, q); std::cout << "p: " << p << "\nq: " << q << "\nd: " << d << "\n"; - SASSERT(eq(q * d, p)); + ENSURE(eq(q * d, p)); q = ((x1^3) + x1 + 1)*((x2^2) + x2 + x2 + 1)*((x3^2) + 2); p = (x1 + (x3^2) + x3 + x2 + (x2^2) + 1)*((x1^3) + x1 + 1)*((x2^2) + x2 + x2 + 1)*((x3^2) + 2); d = exact_div(p, q); std::cout << "p: " << p << "\nq: " << q << "\nd: " << d << "\n"; - SASSERT(eq(q * d, p)); + ENSURE(eq(q * d, p)); } static void tst_discriminant(polynomial_ref const & p, polynomial::var x, polynomial_ref const & expected) { @@ -344,7 +344,7 @@ static void tst_discriminant(polynomial_ref const & p, polynomial::var x, polyno r = discriminant(p, x); std::cout << "r: " << r << "\n"; std::cout << "expected: " << expected << "\n"; - SASSERT(eq(r, expected)); + ENSURE(eq(r, expected)); m.lex_sort(r); std::cout << "r (sorted): " << r << "\n"; } @@ -463,7 +463,7 @@ static void tst_resultant(polynomial_ref const & p, polynomial_ref const & q, po std::cout << "expected: " << expected << "\n"; if (degree(p, x) > 0 && degree(q, x) > 0) std::cout << "quasi-resultant: " << quasi_resultant(p, q, x) << "\n"; - SASSERT(eq(r, expected)); + ENSURE(eq(r, expected)); m.lex_sort(r); std::cout << "r (sorted): " << r << "\n"; } @@ -570,8 +570,8 @@ static void tst_compose() { p = (x0^3) - x0 + 3; std::cout << "p: " << p << "\np(x - y): " << compose_x_minus_y(p, 1) << "\np(x + y): " << compose_x_plus_y(p, 1) << "\np(x - x): " << compose_x_minus_y(p, 0) << "\np(x + x): " << compose_x_plus_y(p, 0) << "\n"; - SASSERT(eq(compose_x_minus_y(p, 1), (x0^3) - 3*(x0^2)*x1 + 3*x0*(x1^2) - (x1^3) - x0 + x1 + 3)); - SASSERT(eq(compose_x_plus_y(p, 1), (x0^3) + 3*(x0^2)*x1 + 3*x0*(x1^2) + (x1^3) - x0 - x1 + 3)); + ENSURE(eq(compose_x_minus_y(p, 1), (x0^3) - 3*(x0^2)*x1 + 3*x0*(x1^2) - (x1^3) - x0 + x1 + 3)); + ENSURE(eq(compose_x_plus_y(p, 1), (x0^3) + 3*(x0^2)*x1 + 3*x0*(x1^2) + (x1^3) - x0 - x1 + 3)); } void tst_prem() { @@ -604,11 +604,11 @@ void tst_sqrt() { p = (4*x*y + 3*(x^2)*y + (y^2) + 3)^4; polynomial_ref q(m); VERIFY(sqrt(p, q)); - SASSERT(eq(p, q*q)); + ENSURE(eq(p, q*q)); std::cout << "p: " << p << "\n"; std::cout << "q: " << q << "\n"; p = p - 1; - SASSERT(!sqrt(p, q)); + ENSURE(!sqrt(p, q)); } static void tst_content(polynomial_ref const & p, polynomial::var x, polynomial_ref const & expected) { @@ -616,7 +616,7 @@ static void tst_content(polynomial_ref const & p, polynomial::var x, polynomial_ std::cout << "p: " << p << std::endl; std::cout << "content(p): " << content(p, x) << std::endl; std::cout << "expected: " << expected << std::endl; - SASSERT(eq(content(p, x), expected)); + ENSURE(eq(content(p, x), expected)); } static void tst_primitive(polynomial_ref const & p, polynomial::var x, polynomial_ref const & expected) { @@ -624,7 +624,7 @@ static void tst_primitive(polynomial_ref const & p, polynomial::var x, polynomia std::cout << "p: " << p << std::endl; std::cout << "primitive(p): " << primitive(p, x) << std::endl; std::cout << "expected: " << expected << std::endl; - SASSERT(eq(primitive(p, x), expected)); + ENSURE(eq(primitive(p, x), expected)); } static void tst_gcd(polynomial_ref const & p, polynomial_ref const & q, polynomial_ref const & expected) { @@ -635,7 +635,7 @@ static void tst_gcd(polynomial_ref const & p, polynomial_ref const & q, polynomi r = gcd(p, q); std::cout << "gcd(p, q): " << r << std::endl; std::cout << "expected: " << expected << std::endl; - SASSERT(eq(r, expected)); + ENSURE(eq(r, expected)); } static void tst_gcd() { @@ -711,15 +711,15 @@ static void tst_psc(polynomial_ref const & p, polynomial_ref const & q, polynomi std::cout << "S_" << i << ": " << polynomial_ref(S.get(i), m) << std::endl; } if (sz > 0) { - SASSERT(m.eq(S.get(0), first) || m.eq(S.get(0), neg(first))); + ENSURE(m.eq(S.get(0), first) || m.eq(S.get(0), neg(first))); } if (sz > 1) { - SASSERT(m.eq(S.get(1), second) || m.eq(S.get(1), neg(second))); + ENSURE(m.eq(S.get(1), second) || m.eq(S.get(1), neg(second))); } if (sz > 0) { polynomial_ref Res(m); Res = resultant(p, q, x); - SASSERT(m.eq(Res, S.get(0)) || m.eq(S.get(0), neg(Res))); + ENSURE(m.eq(Res, S.get(0)) || m.eq(S.get(0), neg(Res))); } } @@ -843,11 +843,11 @@ static void tst_vars(polynomial_ref const & p, unsigned sz, polynomial::var * xs std::cout << r[i] << " "; } std::cout << std::endl; - SASSERT(r.size() == sz); + ENSURE(r.size() == sz); std::sort(r.begin(), r.end()); std::sort(xs, xs + sz); for (unsigned i = 0; i < r.size(); i++) { - SASSERT(r[i] == xs[i]); + ENSURE(r[i] == xs[i]); } } @@ -886,9 +886,9 @@ static void tst_sqf(polynomial_ref const & p, polynomial_ref const & expected) { r = square_free(p); std::cout << "sqf(p): " << r << std::endl; std::cout << "expected: " << expected << std::endl; - SASSERT(is_square_free(r)); - SASSERT(!eq(r, p) || is_square_free(p)); - SASSERT(eq(expected, r)); + ENSURE(is_square_free(r)); + ENSURE(!eq(r, p) || is_square_free(p)); + ENSURE(eq(expected, r)); } static void tst_sqf() { @@ -931,7 +931,7 @@ static void tst_substitute(polynomial_ref const & p, r = p.m().substitute(p, 2, xs, vs.c_ptr()); std::cout << "r: " << r << std::endl; std::cout << "expected: " << expected << std::endl; - SASSERT(eq(r, expected)); + ENSURE(eq(r, expected)); p.m().lex_sort(r); std::cout << "r (sorted): " << r << std::endl; } @@ -972,7 +972,7 @@ static void tst_qsubstitute(polynomial_ref const & p, r = p.m().substitute(p, 2, xs, vs.c_ptr()); std::cout << "r: " << r << std::endl; std::cout << "expected (modulo a constant): " << expected << std::endl; - SASSERT(eq(r, normalize(expected))); + ENSURE(eq(r, normalize(expected))); p.m().lex_sort(r); std::cout << "r (sorted): " << r << std::endl; } @@ -1024,10 +1024,10 @@ void tst_mfact(polynomial_ref const & p, unsigned num_distinct_factors) { for (unsigned i = 0; i < fs.distinct_factors(); i++) { std::cout << "*(" << fs[i] << ")^" << fs.get_degree(i) << std::endl; } - SASSERT(fs.distinct_factors() == num_distinct_factors); + ENSURE(fs.distinct_factors() == num_distinct_factors); polynomial_ref p2(p.m()); fs.multiply(p2); - SASSERT(eq(p, p2)); + ENSURE(eq(p, p2)); } static void tst_mfact() { @@ -1247,7 +1247,7 @@ static void tst_translate(polynomial_ref const & p, polynomial::var x0, int v0, polynomial_ref r(p.m()); p.m().translate(p, 3, xs, vs, r); std::cout << "r: " << r << std::endl; - SASSERT(eq(expected, r)); + ENSURE(eq(expected, r)); } static void tst_translate() { @@ -1326,11 +1326,11 @@ static void tst_mm() { std::cout << "p1: " << p1 << "\n"; p2 = convert(pm1, p1, pm2); std::cout << "p2: " << p2 << "\n"; - SASSERT(pm1.get_monomial(p1, 0) == pm2.get_monomial(p2, 0)); + ENSURE(pm1.get_monomial(p1, 0) == pm2.get_monomial(p2, 0)); polynomial_ref p3(pm3); p3 = convert(pm1, p1, pm3); - SASSERT(pm1.get_monomial(p1, 0) != pm3.get_monomial(p3, 0)); + ENSURE(pm1.get_monomial(p1, 0) != pm3.get_monomial(p3, 0)); } dealloc(pm1_ptr); // p2 is still ok @@ -1351,7 +1351,7 @@ static void tst_eval(polynomial_ref const & p, polynomial::var x0, rational v0, std::cout << "r: " << r << "\nexpected: " << expected << "\n"; scoped_mpq ex(qm); qm.set(ex, expected.to_mpq()); - SASSERT(qm.eq(r, ex)); + ENSURE(qm.eq(r, ex)); } static void tst_eval() { @@ -1407,18 +1407,18 @@ static void tst_mk_unique() { std::cout << "p: " << p << "\n"; std::cout << "q: " << q << "\n"; std::cout << "r: " << r << "\n"; - SASSERT(m.eq(p, q)); - SASSERT(!m.eq(p, r)); - SASSERT(p.get() != q.get()); + ENSURE(m.eq(p, q)); + ENSURE(!m.eq(p, r)); + ENSURE(p.get() != q.get()); q = uniq.mk_unique(q); p = uniq.mk_unique(p); r = uniq.mk_unique(r); std::cout << "after mk_unique\np: " << p << "\n"; std::cout << "q: " << q << "\n"; std::cout << "r: " << r << "\n"; - SASSERT(m.eq(p, q)); - SASSERT(!m.eq(r, q)); - SASSERT(p.get() == q.get()); + ENSURE(m.eq(p, q)); + ENSURE(!m.eq(r, q)); + ENSURE(p.get() == q.get()); } struct dummy_del_eh : public polynomial::manager::del_eh { @@ -1442,24 +1442,24 @@ static void tst_del_eh() { m.add_del_eh(&eh1); x1 = 0; - SASSERT(eh1.m_counter == 1); + ENSURE(eh1.m_counter == 1); m.add_del_eh(&eh2); x1 = m.mk_polynomial(m.mk_var()); x1 = 0; - SASSERT(eh1.m_counter == 2); - SASSERT(eh2.m_counter == 1); + ENSURE(eh1.m_counter == 2); + ENSURE(eh2.m_counter == 1); m.remove_del_eh(&eh1); x0 = 0; x1 = m.mk_polynomial(m.mk_var()); x1 = 0; - SASSERT(eh1.m_counter == 2); - SASSERT(eh2.m_counter == 3); + ENSURE(eh1.m_counter == 2); + ENSURE(eh2.m_counter == 3); m.remove_del_eh(&eh2); x1 = m.mk_polynomial(m.mk_var()); x1 = 0; - SASSERT(eh1.m_counter == 2); - SASSERT(eh2.m_counter == 3); + ENSURE(eh1.m_counter == 2); + ENSURE(eh2.m_counter == 3); } static void tst_const_coeff() { @@ -1475,36 +1475,36 @@ static void tst_const_coeff() { polynomial_ref p(m); p = (x0^2)*x1 + 3*x0 + x1; - SASSERT(!m.const_coeff(p, 0, 2, c)); - SASSERT(m.const_coeff(p, 0, 1, c) && c == 3); - SASSERT(!m.const_coeff(p, 0, 0, c)); + ENSURE(!m.const_coeff(p, 0, 2, c)); + ENSURE(m.const_coeff(p, 0, 1, c) && c == 3); + ENSURE(!m.const_coeff(p, 0, 0, c)); p = (x0^2)*x1 + 3*x0 + x1 + 1; - SASSERT(!m.const_coeff(p, 0, 2, c)); - SASSERT(m.const_coeff(p, 0, 1, c) && c == 3); - SASSERT(!m.const_coeff(p, 0, 0, c)); + ENSURE(!m.const_coeff(p, 0, 2, c)); + ENSURE(m.const_coeff(p, 0, 1, c) && c == 3); + ENSURE(!m.const_coeff(p, 0, 0, c)); p = (x0^2)*x1 + 3*x0 + 1; - SASSERT(!m.const_coeff(p, 0, 2, c)); - SASSERT(m.const_coeff(p, 0, 1, c) && c == 3); - SASSERT(m.const_coeff(p, 0, 0, c) && c == 1); + ENSURE(!m.const_coeff(p, 0, 2, c)); + ENSURE(m.const_coeff(p, 0, 1, c) && c == 3); + ENSURE(m.const_coeff(p, 0, 0, c) && c == 1); p = x1 + 3*x0 + 1; - SASSERT(m.const_coeff(p, 0, 2, c) && c == 0); - SASSERT(m.const_coeff(p, 0, 1, c) && c == 3); - SASSERT(!m.const_coeff(p, 0, 0, c)); + ENSURE(m.const_coeff(p, 0, 2, c) && c == 0); + ENSURE(m.const_coeff(p, 0, 1, c) && c == 3); + ENSURE(!m.const_coeff(p, 0, 0, c)); p = 5*(x0^2) + 3*x0 + 7; - SASSERT(m.const_coeff(p, 0, 5, c) && c == 0); - SASSERT(m.const_coeff(p, 0, 2, c) && c == 5); - SASSERT(m.const_coeff(p, 0, 1, c) && c == 3); - SASSERT(m.const_coeff(p, 0, 0, c) && c == 7); + ENSURE(m.const_coeff(p, 0, 5, c) && c == 0); + ENSURE(m.const_coeff(p, 0, 2, c) && c == 5); + ENSURE(m.const_coeff(p, 0, 1, c) && c == 3); + ENSURE(m.const_coeff(p, 0, 0, c) && c == 7); p = 5*(x0^2) + 3*x0; - SASSERT(m.const_coeff(p, 0, 0, c) && c == 0); + ENSURE(m.const_coeff(p, 0, 0, c) && c == 0); p = - x0*x1 - x1 + 1; - SASSERT(!m.const_coeff(p, 0, 1, c)); + ENSURE(!m.const_coeff(p, 0, 1, c)); } static void tst_gcd2() { @@ -1669,7 +1669,7 @@ static void tst_newton_interpolation() { m.newton_interpolation(0, 2, ins.c_ptr(), outs, r); } std::cout << "interpolation result: " << r << "\n"; - SASSERT(m.eq((x^2)*y + 5*x*y + 41*x - 9*y - 21, r)); + ENSURE(m.eq((x^2)*y + 5*x*y + 41*x - 9*y - 21, r)); } static void tst_slow_mod_gcd() { @@ -1732,9 +1732,9 @@ void tst_linear_solver() { solver.add(2, as.c_ptr(), b); VERIFY(solver.solve(xs.c_ptr())); - SASSERT(qm.eq(xs[0], mpq(2))); - SASSERT(qm.eq(xs[1], mpq(3))); - SASSERT(qm.eq(xs[2], mpq(-1))); + ENSURE(qm.eq(xs[0], mpq(2))); + ENSURE(qm.eq(xs[1], mpq(3))); + ENSURE(qm.eq(xs[2], mpq(-1))); } static void tst_lex(polynomial_ref const & p1, polynomial_ref const & p2, int lex_expected, polynomial::var min, int lex2_expected) { @@ -1746,11 +1746,11 @@ static void tst_lex(polynomial_ref const & p1, polynomial_ref const & p2, int le std::cout << " "; std::cout.flush(); int r1 = lex_compare(m.get_monomial(p1, 0), m.get_monomial(p2, 0)); int r2 = lex_compare2(m.get_monomial(p1, 0), m.get_monomial(p2, 0), min); - SASSERT(r1 == lex_expected); - SASSERT(r2 == lex2_expected); + ENSURE(r1 == lex_expected); + ENSURE(r2 == lex2_expected); std::cout << r1 << " " << r2 << "\n"; - SASSERT(lex_compare(m.get_monomial(p2, 0), m.get_monomial(p1, 0)) == -r1); - SASSERT(lex_compare2(m.get_monomial(p2, 0), m.get_monomial(p1, 0), min) == -r2); + ENSURE(lex_compare(m.get_monomial(p2, 0), m.get_monomial(p1, 0)) == -r1); + ENSURE(lex_compare2(m.get_monomial(p2, 0), m.get_monomial(p1, 0), min) == -r2); } static void tst_lex() { diff --git a/src/test/polynorm.cpp b/src/test/polynorm.cpp index 987d8e13b..22df91b45 100644 --- a/src/test/polynorm.cpp +++ b/src/test/polynorm.cpp @@ -4,12 +4,12 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "th_rewriter.h" -#include "smt2parser.h" -#include "arith_decl_plugin.h" -#include "reg_decl_plugins.h" -#include "arith_rewriter.h" -#include "ast_pp.h" +#include "ast/rewriter/th_rewriter.h" +#include "parsers/smt2/smt2parser.h" +#include "ast/arith_decl_plugin.h" +#include "ast/reg_decl_plugins.h" +#include "ast/rewriter/arith_rewriter.h" +#include "ast/ast_pp.h" static expr_ref parse_fml(ast_manager& m, char const* str) { @@ -25,7 +25,7 @@ static expr_ref parse_fml(ast_manager& m, char const* str) { << "(assert " << str << ")\n"; std::istringstream is(buffer.str()); VERIFY(parse_smt2_commands(ctx, is)); - SASSERT(ctx.begin_assertions() != ctx.end_assertions()); + ENSURE(ctx.begin_assertions() != ctx.end_assertions()); result = *ctx.begin_assertions(); return result; } @@ -125,8 +125,8 @@ private: else if (m_arith.is_numeral(f, r)) { factors[i] = factors.back(); factors.pop_back(); - SASSERT(coefficient.is_zero()); - SASSERT(!r.is_zero()); + ENSURE(coefficient.is_zero()); + ENSURE(!r.is_zero()); coefficient = r; --i; // repeat examining 'i' } @@ -205,8 +205,8 @@ static void nf(expr_ref& term) { else if (arith.is_numeral(f, r)) { factors[i] = factors.back(); factors.pop_back(); - SASSERT(coefficient.is_zero()); - SASSERT(!r.is_zero()); + ENSURE(coefficient.is_zero()); + ENSURE(!r.is_zero()); coefficient = r; --i; // repeat examining 'i' } diff --git a/src/test/prime_generator.cpp b/src/test/prime_generator.cpp index a2610b35e..12c38ef78 100644 --- a/src/test/prime_generator.cpp +++ b/src/test/prime_generator.cpp @@ -16,8 +16,8 @@ Author: Notes: --*/ -#include"mpz.h" -#include"prime_generator.h" +#include "util/mpz.h" +#include "util/prime_generator.h" void tst_prime_generator() { unsynch_mpz_manager m; @@ -35,7 +35,7 @@ void tst_prime_generator() { m.root(sqrt_p, 2); uint64 k = m.get_uint64(sqrt_p); for (uint64 i = 2; i <= k; i++) { - SASSERT(p % i != 0); + ENSURE(p % i != 0); } } std::cout << std::endl; diff --git a/src/test/proof_checker.cpp b/src/test/proof_checker.cpp index 035326b26..7a9b619cd 100644 --- a/src/test/proof_checker.cpp +++ b/src/test/proof_checker.cpp @@ -4,11 +4,11 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "proof_checker.h" -#include "ast_ll_pp.h" +#include "ast/proofs/proof_checker.h" +#include "ast/ast_ll_pp.h" void tst_checker1() { - ast_manager m(PGM_FINE); + ast_manager m(PGM_ENABLED); expr_ref a(m); proof_ref p1(m), p2(m), p3(m), p4(m); expr_ref_vector side_conditions(m); diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index a52c02ecb..d18e0f717 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -4,17 +4,17 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "qe_arith.h" -#include "qe.h" -#include "th_rewriter.h" -#include "smt2parser.h" -#include "arith_decl_plugin.h" -#include "reg_decl_plugins.h" -#include "arith_rewriter.h" -#include "ast_pp.h" -#include "smt_context.h" -#include "expr_abstract.h" -#include "expr_safe_replace.h" +#include "qe/qe_arith.h" +#include "qe/qe.h" +#include "ast/rewriter/th_rewriter.h" +#include "parsers/smt2/smt2parser.h" +#include "ast/arith_decl_plugin.h" +#include "ast/reg_decl_plugins.h" +#include "ast/rewriter/arith_rewriter.h" +#include "ast/ast_pp.h" +#include "smt/smt_context.h" +#include "ast/expr_abstract.h" +#include "ast/rewriter/expr_safe_replace.h" static expr_ref parse_fml(ast_manager& m, char const* str) { expr_ref result(m); @@ -37,7 +37,7 @@ static expr_ref parse_fml(ast_manager& m, char const* str) { << "(assert " << str << ")\n"; std::istringstream is(buffer.str()); VERIFY(parse_smt2_commands(ctx, is)); - SASSERT(ctx.begin_assertions() != ctx.end_assertions()); + ENSURE(ctx.begin_assertions() != ctx.end_assertions()); result = *ctx.begin_assertions(); return result; } diff --git a/src/test/quant_elim.cpp b/src/test/quant_elim.cpp index 0fe7f8eec..3674e6b70 100644 --- a/src/test/quant_elim.cpp +++ b/src/test/quant_elim.cpp @@ -4,20 +4,15 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "ast.h" -#include "smt_params.h" -#include "simplifier.h" -#include "qe.h" -#include "basic_simplifier_plugin.h" -#include "arith_simplifier_plugin.h" -#include "array_simplifier_plugin.h" -#include "bv_simplifier_plugin.h" -#include "ast_pp.h" -#include "smtlib.h" -#include "smtparser.h" -#include "lbool.h" +#include "ast/ast.h" +#include "smt/params/smt_params.h" +#include "qe/qe.h" +#include "ast/ast_pp.h" +#include "parsers/smt/smtlib.h" +#include "parsers/smt/smtparser.h" +#include "util/lbool.h" #include -#include "reg_decl_plugins.h" +#include "ast/reg_decl_plugins.h" static void test_qe(ast_manager& m, lbool expected_outcome, expr* fml, char const* option) { @@ -38,7 +33,6 @@ static void test_qe(ast_manager& m, lbool expected_outcome, expr* fml, char cons // enable_trace("after_search"); // enable_trace("bv_bit_prop"); - simplifier simp(m); smt_params params; // params.m_quant_elim = true; diff --git a/src/test/quant_solve.cpp b/src/test/quant_solve.cpp index ed332ce26..ac334c718 100644 --- a/src/test/quant_solve.cpp +++ b/src/test/quant_solve.cpp @@ -4,20 +4,20 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "ast.h" -#include "smt_params.h" -#include "qe.h" -#include "arith_decl_plugin.h" -#include "ast_pp.h" -#include "lbool.h" +#include "ast/ast.h" +#include "smt/params/smt_params.h" +#include "qe/qe.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_pp.h" +#include "util/lbool.h" #include -#include "expr_replacer.h" -#include "smt_kernel.h" -#include "reg_decl_plugins.h" -#include "expr_abstract.h" -#include "model_smt2_pp.h" -#include "smt2parser.h" -#include "var_subst.h" +#include "ast/rewriter/expr_replacer.h" +#include "smt/smt_kernel.h" +#include "ast/reg_decl_plugins.h" +#include "ast/expr_abstract.h" +#include "model/model_smt2_pp.h" +#include "parsers/smt2/smt2parser.h" +#include "ast/rewriter/var_subst.h" static void validate_quant_solution(ast_manager& m, expr* fml, expr* guard, qe::def_vector const& defs) { // verify: @@ -39,7 +39,7 @@ static void validate_quant_solution(ast_manager& m, expr* fml, expr* guard, qe:: smt::kernel solver(m, fp); solver.assert_expr(tmp); lbool res = solver.check(); - //SASSERT(res == l_false); + //ENSURE(res == l_false); if (res != l_false) { std::cout << "Validation failed: " << res << "\n"; std::cout << mk_pp(tmp, m) << "\n"; @@ -75,7 +75,7 @@ static void validate_quant_solutions(app* x, expr* fml, expr_ref_vector& guards) solver.assert_expr(tmp); lbool res = solver.check(); std::cout << "checked\n"; - SASSERT(res == l_false); + ENSURE(res == l_false); if (res != l_false) { std::cout << res << "\n"; fatal_error(0); @@ -131,7 +131,7 @@ static expr_ref parse_fml(ast_manager& m, char const* str) { << "(assert " << str << ")\n"; std::istringstream is(buffer.str()); VERIFY(parse_smt2_commands(ctx, is)); - SASSERT(ctx.begin_assertions() != ctx.end_assertions()); + ENSURE(ctx.begin_assertions() != ctx.end_assertions()); result = *ctx.begin_assertions(); return result; } diff --git a/src/test/random.cpp b/src/test/random.cpp index a813b0f08..89d5a24cf 100644 --- a/src/test/random.cpp +++ b/src/test/random.cpp @@ -17,8 +17,8 @@ Revision History: --*/ -#include"util.h" -#include"trace.h" +#include "util/util.h" +#include "util/trace.h" static void tst1() { random_gen r(0); diff --git a/src/test/rational.cpp b/src/test/rational.cpp index ac478af98..7b5e474f0 100644 --- a/src/test/rational.cpp +++ b/src/test/rational.cpp @@ -17,95 +17,95 @@ Revision History: --*/ #include -#include"vector.h" -#include"rational.h" -#include"trace.h" -#include"ext_gcd.h" -#include"timeit.h" +#include "util/vector.h" +#include "util/rational.h" +#include "util/trace.h" +#include "util/ext_gcd.h" +#include "util/timeit.h" static void tst1() { rational r1(1); rational r2(1,2); rational r3(2,4); - SASSERT(r2 == r3); - SASSERT(r1 != r2); - SASSERT(r2 + r3 == r1); - SASSERT(r1.is_pos()); - SASSERT((r2 - r1).is_neg()); - SASSERT((r2 - r3).is_zero()); - SASSERT(floor(r2).is_zero()); - SASSERT(ceil(r2).is_one()); + ENSURE(r2 == r3); + ENSURE(r1 != r2); + ENSURE(r2 + r3 == r1); + ENSURE(r1.is_pos()); + ENSURE((r2 - r1).is_neg()); + ENSURE((r2 - r3).is_zero()); + ENSURE(floor(r2).is_zero()); + ENSURE(ceil(r2).is_one()); // std::cout << "-r2: " << (-r2) << ", floor(-r2):" << floor(-r2) << "\n"; - SASSERT(floor(-r2).is_minus_one()); - SASSERT(ceil(-r2).is_zero()); - SASSERT(floor(r1) == r1); - SASSERT(ceil(r1) == r1); + ENSURE(floor(-r2).is_minus_one()); + ENSURE(ceil(-r2).is_zero()); + ENSURE(floor(r1) == r1); + ENSURE(ceil(r1) == r1); rational r4(3,5); - SASSERT(r3 * r4 == rational(3, 10)); - SASSERT(r3 / r4 == rational(5, 6)); + ENSURE(r3 * r4 == rational(3, 10)); + ENSURE(r3 / r4 == rational(5, 6)); rational r5(2,3); - SASSERT(r4 * r5 == rational(2, 5)); + ENSURE(r4 * r5 == rational(2, 5)); --r2; - SASSERT(r2 == -r3); + ENSURE(r2 == -r3); r2.neg(); - SASSERT(r2 == r3); + ENSURE(r2 == r3); --r2; r2 = abs(r2); - SASSERT(r2 == r3); + ENSURE(r2 == r3); --r2; ++r2; - SASSERT(r2 == r3); - SASSERT(r2 == abs(r2)); - SASSERT(r4 * rational(1) == r4); - SASSERT((r4 * rational(0)).is_zero()); - SASSERT(r4 * rational(-1) == -r4); - SASSERT(rational(1) * r4 == r4); - SASSERT((rational(0) * r4).is_zero()); - SASSERT(rational(-1) * r4 == -r4); - SASSERT(r4 + rational(0) == r4); - SASSERT(ceil(r4).is_one()); + ENSURE(r2 == r3); + ENSURE(r2 == abs(r2)); + ENSURE(r4 * rational(1) == r4); + ENSURE((r4 * rational(0)).is_zero()); + ENSURE(r4 * rational(-1) == -r4); + ENSURE(rational(1) * r4 == r4); + ENSURE((rational(0) * r4).is_zero()); + ENSURE(rational(-1) * r4 == -r4); + ENSURE(r4 + rational(0) == r4); + ENSURE(ceil(r4).is_one()); // std::cout << "r3: " << r3 << ", r4: " << r4 << ", -r4: " << -r4 << ", r3 / (-r4): " << (r3 / (-r4)) << "\n"; - SASSERT(r3 / (-r4) == rational(5,-6)); - SASSERT(div(rational(7), rational(2)) == rational(3)); - SASSERT(rational(7) % rational(4) == rational(3)); - SASSERT(div(rational(7), rational(-2)) == rational(-3)); - SASSERT(rational(3) + rational(5) == rational(8)); - SASSERT(rational("13/10") + rational("7/10") == rational(2)); - SASSERT(rational("100/20") == rational(5)); - SASSERT(gcd(rational(12), rational(8)) == rational(4)); - SASSERT(ceil(rational(-3,2)) == rational(-1)); - SASSERT(floor(rational(-3,2)) == rational(-2)); - SASSERT(ceil(rational(3,2)) == rational(2)); - SASSERT(floor(rational(3,2)) == rational(1)); - SASSERT(rational(3).is_pos()); - SASSERT(rational(0).is_nonneg()); - SASSERT(rational(3).is_pos()); - SASSERT(rational(3).is_nonneg()); - SASSERT(rational(0).is_nonneg()); - SASSERT(!rational(3).is_zero()); - SASSERT(!rational(-3).is_zero()); - SASSERT(rational(0).is_zero()); - SASSERT(rational(1).is_one()); - SASSERT(!rational(2).is_one()); - SASSERT(rational(3,4) >= rational(2,8)); - SASSERT(rational(3,4) <= rational(7,8)); - SASSERT(rational(3,4) <= rational(3,4)); - SASSERT(rational(3,4) >= rational(3,4)); - SASSERT(rational(3,4) > rational(2,8)); - SASSERT(rational(3,4) < rational(7,8)); + ENSURE(r3 / (-r4) == rational(5,-6)); + ENSURE(div(rational(7), rational(2)) == rational(3)); + ENSURE(rational(7) % rational(4) == rational(3)); + ENSURE(div(rational(7), rational(-2)) == rational(-3)); + ENSURE(rational(3) + rational(5) == rational(8)); + ENSURE(rational("13/10") + rational("7/10") == rational(2)); + ENSURE(rational("100/20") == rational(5)); + ENSURE(gcd(rational(12), rational(8)) == rational(4)); + ENSURE(ceil(rational(-3,2)) == rational(-1)); + ENSURE(floor(rational(-3,2)) == rational(-2)); + ENSURE(ceil(rational(3,2)) == rational(2)); + ENSURE(floor(rational(3,2)) == rational(1)); + ENSURE(rational(3).is_pos()); + ENSURE(rational(0).is_nonneg()); + ENSURE(rational(3).is_pos()); + ENSURE(rational(3).is_nonneg()); + ENSURE(rational(0).is_nonneg()); + ENSURE(!rational(3).is_zero()); + ENSURE(!rational(-3).is_zero()); + ENSURE(rational(0).is_zero()); + ENSURE(rational(1).is_one()); + ENSURE(!rational(2).is_one()); + ENSURE(rational(3,4) >= rational(2,8)); + ENSURE(rational(3,4) <= rational(7,8)); + ENSURE(rational(3,4) <= rational(3,4)); + ENSURE(rational(3,4) >= rational(3,4)); + ENSURE(rational(3,4) > rational(2,8)); + ENSURE(rational(3,4) < rational(7,8)); TRACE("rational", tout << rational(3,4) << "\n";); TRACE("rational", tout << rational(7,9) << "\n";); TRACE("rational", tout << rational(-3,7) << "\n";); TRACE("rational", tout << rational(5,8) << "\n";); TRACE("rational", tout << rational(4,2) << "\n";); - SASSERT(rational(3) + rational(2) == rational(5)); - SASSERT(rational(3) - rational(2) == rational(1)); - SASSERT(rational(3) * rational(2) == rational(6)); - SASSERT(rational(6) / rational(2) == rational(3)); - SASSERT(rational(6) % rational(4) == rational(2)); - SASSERT(power(rational(2),0) == rational(1)); - SASSERT(power(rational(2),1) == rational(2)); - SASSERT(power(rational(2),3) == rational(8)); + ENSURE(rational(3) + rational(2) == rational(5)); + ENSURE(rational(3) - rational(2) == rational(1)); + ENSURE(rational(3) * rational(2) == rational(6)); + ENSURE(rational(6) / rational(2) == rational(3)); + ENSURE(rational(6) % rational(4) == rational(2)); + ENSURE(power(rational(2),0) == rational(1)); + ENSURE(power(rational(2),1) == rational(2)); + ENSURE(power(rational(2),3) == rational(8)); } static void tst2() { @@ -116,90 +116,90 @@ static void tst2() { TRACE("rational", tout << r2 << std::endl;); TRACE("rational", tout << r3 << std::endl;); - SASSERT(r2 == r3); - SASSERT(r1 != r2); - SASSERT(rational(2)*r2 + r3 == r1); - SASSERT(r1.is_pos()); - SASSERT((r2 - r1).is_neg()); - SASSERT((r2 - r3).is_zero()); + ENSURE(r2 == r3); + ENSURE(r1 != r2); + ENSURE(rational(2)*r2 + r3 == r1); + ENSURE(r1.is_pos()); + ENSURE((r2 - r1).is_neg()); + ENSURE((r2 - r3).is_zero()); // std::cout << "===> " << floor(r2) << "\n"; { rational r0("1/3000000000000000000000000"); - SASSERT(ceil(r0).is_one()); - SASSERT(floor(-r0).is_minus_one()); - SASSERT(ceil(-r0).is_zero()); + ENSURE(ceil(r0).is_one()); + ENSURE(floor(-r0).is_minus_one()); + ENSURE(ceil(-r0).is_zero()); } - SASSERT(floor(r1) == r1); - SASSERT(ceil(r1) == r1); + ENSURE(floor(r1) == r1); + ENSURE(ceil(r1) == r1); rational r4("300000000/5"); - SASSERT(rational(1,2) * r4 == rational("300000000/10")); - SASSERT(rational(1,2) / r4 == rational("5/600000000")); + ENSURE(rational(1,2) * r4 == rational("300000000/10")); + ENSURE(rational(1,2) / r4 == rational("5/600000000")); rational r5(2,3); - SASSERT(r4 * r5 == rational("200000000/5")); + ENSURE(r4 * r5 == rational("200000000/5")); rational r6("10000000000000000000000000000000003/3"); --r6; - SASSERT(r6 == r2); + ENSURE(r6 == r2); r6.neg(); - SASSERT(r6 != r2); - SASSERT(abs(r6) == r2); + ENSURE(r6 != r2); + ENSURE(abs(r6) == r2); --r2; ++r2; r2.neg(); - SASSERT(r2 == r6); - SASSERT(r6 * rational(1) == r6); - SASSERT((r6 * rational(0)).is_zero()); - SASSERT(r6 * rational(-1) == -r6); - SASSERT(rational(1) * r6 == r6); - SASSERT((rational(0) * r6).is_zero()); - SASSERT(rational(-1) * r6 == -r6); - SASSERT(r6 + rational(0) == r6); + ENSURE(r2 == r6); + ENSURE(r6 * rational(1) == r6); + ENSURE((r6 * rational(0)).is_zero()); + ENSURE(r6 * rational(-1) == -r6); + ENSURE(rational(1) * r6 == r6); + ENSURE((rational(0) * r6).is_zero()); + ENSURE(rational(-1) * r6 == -r6); + ENSURE(r6 + rational(0) == r6); - SASSERT(rational("300000000000000").is_pos()); - SASSERT(rational("0000000000000000000").is_nonneg()); - SASSERT(rational("0000000000000000000").is_nonpos()); - SASSERT(rational("3000000000000000000/2").is_pos()); - SASSERT(rational("3000000000000000000/2").is_nonneg()); - SASSERT((-rational("3000000000000000000/2")).is_neg()); - SASSERT(!rational("3000000000000000000/2").is_neg()); - SASSERT(!rational("3000000000000000000/2").is_zero()); - SASSERT(!rational("3000000000000000000/2").is_one()); - SASSERT(rational("99999999999/2") >= rational("23/2")); - SASSERT(rational("99999999999/2") > rational("23/2")); - SASSERT(rational("23/2") <= rational("99999999999/2")); - SASSERT(rational("23/2") < rational("99999999999/2")); - SASSERT(!(rational("99999999999/2") < rational("23/2"))); + ENSURE(rational("300000000000000").is_pos()); + ENSURE(rational("0000000000000000000").is_nonneg()); + ENSURE(rational("0000000000000000000").is_nonpos()); + ENSURE(rational("3000000000000000000/2").is_pos()); + ENSURE(rational("3000000000000000000/2").is_nonneg()); + ENSURE((-rational("3000000000000000000/2")).is_neg()); + ENSURE(!rational("3000000000000000000/2").is_neg()); + ENSURE(!rational("3000000000000000000/2").is_zero()); + ENSURE(!rational("3000000000000000000/2").is_one()); + ENSURE(rational("99999999999/2") >= rational("23/2")); + ENSURE(rational("99999999999/2") > rational("23/2")); + ENSURE(rational("23/2") <= rational("99999999999/2")); + ENSURE(rational("23/2") < rational("99999999999/2")); + ENSURE(!(rational("99999999999/2") < rational("23/2"))); rational int64_max("9223372036854775807"); rational int64_min((-int64_max) - rational(1)); // is_int64 - SASSERT(int64_max.is_int64()); - SASSERT(int64_min.is_int64()); - SASSERT(rational(0).is_int64()); - SASSERT(rational(1).is_int64()); - SASSERT(rational(-1).is_int64()); - SASSERT(!(int64_max + rational(1)).is_int64()); - SASSERT(!(int64_min - rational(1)).is_int64()); + ENSURE(int64_max.is_int64()); + ENSURE(int64_min.is_int64()); + ENSURE(rational(0).is_int64()); + ENSURE(rational(1).is_int64()); + ENSURE(rational(-1).is_int64()); + ENSURE(!(int64_max + rational(1)).is_int64()); + ENSURE(!(int64_min - rational(1)).is_int64()); // is_uint64 - SASSERT(int64_max.is_uint64()); - SASSERT(!int64_min.is_uint64()); - SASSERT(rational(0).is_uint64()); - SASSERT(rational(1).is_uint64()); - SASSERT(!rational(-1).is_uint64()); - SASSERT((int64_max + rational(1)).is_uint64()); - SASSERT(!(int64_min - rational(1)).is_uint64()); + ENSURE(int64_max.is_uint64()); + ENSURE(!int64_min.is_uint64()); + ENSURE(rational(0).is_uint64()); + ENSURE(rational(1).is_uint64()); + ENSURE(!rational(-1).is_uint64()); + ENSURE((int64_max + rational(1)).is_uint64()); + ENSURE(!(int64_min - rational(1)).is_uint64()); rational uint64_max(rational(1) + (rational(2) * int64_max)); - SASSERT(uint64_max.is_uint64()); + ENSURE(uint64_max.is_uint64()); // get_int64, get_uint64 uint64 u1 = uint64_max.get_uint64(); uint64 u2 = UINT64_MAX; VERIFY(u1 == u2); std::cout << "int64_max: " << int64_max << ", INT64_MAX: " << INT64_MAX << ", int64_max.get_int64(): " << int64_max.get_int64() << ", int64_max.get_uint64(): " << int64_max.get_uint64() << "\n"; - SASSERT(int64_max.get_int64() == INT64_MAX); - SASSERT(int64_min.get_int64() == INT64_MIN); + ENSURE(int64_max.get_int64() == INT64_MAX); + ENSURE(int64_min.get_int64() == INT64_MIN); // extended Euclid: @@ -219,7 +219,7 @@ void tst3() { TRACE("rational", tout << "n4: " << n4 << "\n"; tout << "n5: " << n5 << "\n";); - SASSERT(n5 == rational("2147483646")); + ENSURE(n5 == rational("2147483646")); } void tst4() { @@ -236,7 +236,7 @@ void tst5() { TRACE("rational", tout << n1 << " " << n2 << " " << n1.is_big() << " " << n2.is_big() << "\n";); n1 *= n2; TRACE("rational", tout << "after: " << n1 << " " << n2 << "\n";); - SASSERT(n1.is_minus_one()); + ENSURE(n1.is_minus_one()); } void tst6() { @@ -274,8 +274,8 @@ public: static void tst1() { rational n1(-1); rational n2(8); - SASSERT((n1 % n2).is_minus_one()); - SASSERT(mod(n1, n2) == rational(7)); + ENSURE((n1 % n2).is_minus_one()); + ENSURE(mod(n1, n2) == rational(7)); } static void tst_hash(int val) { @@ -283,7 +283,7 @@ public: rational n2("10203939394995449949494394932929"); rational n3(val); n2 = n3; - SASSERT(n1.hash() == n2.hash()); + ENSURE(n1.hash() == n2.hash()); } static void tst2() { @@ -306,47 +306,47 @@ static void tst7() { rational gcd; extended_gcd(n, p, gcd, x, y); TRACE("gcd", tout << n << " " << p << ": " << gcd << " " << x << " " << y << "\n";); - SASSERT(!mod(n, rational(2)).is_one() || mod(n * x, p).is_one()); + ENSURE(!mod(n, rational(2)).is_one() || mod(n * x, p).is_one()); } } static void tst8() { rational r; - SASSERT(!rational(-4).is_int_perfect_square(r) && r.is_zero()); - SASSERT(!rational(-3).is_int_perfect_square(r) && r.is_zero()); - SASSERT(!rational(-2).is_int_perfect_square(r) && r.is_zero()); - SASSERT(!rational(-1).is_int_perfect_square(r) && r.is_zero()); - SASSERT(rational(0).is_int_perfect_square(r) && r.is_zero()); - SASSERT(rational(1).is_int_perfect_square(r) && r.is_one()); - SASSERT(!rational(2).is_int_perfect_square(r) && r == rational(2)); - SASSERT(!rational(3).is_int_perfect_square(r) && r == rational(2)); - SASSERT(rational(4).is_int_perfect_square(r) && r == rational(2)); - SASSERT(!rational(5).is_int_perfect_square(r) && r == rational(3)); - SASSERT(!rational(6).is_int_perfect_square(r) && r == rational(3)); - SASSERT(!rational(7).is_int_perfect_square(r) && r == rational(3)); - SASSERT(!rational(8).is_int_perfect_square(r) && r == rational(3)); - SASSERT(rational(9).is_int_perfect_square(r) && r == rational(3)); - SASSERT(!rational(10).is_int_perfect_square(r) && r == rational(4)); - SASSERT(!rational(11).is_int_perfect_square(r) && r == rational(4)); - SASSERT(!rational(12).is_int_perfect_square(r) && r == rational(4)); - SASSERT(!rational(13).is_int_perfect_square(r) && r == rational(4)); - SASSERT(!rational(14).is_int_perfect_square(r) && r == rational(4)); - SASSERT(!rational(15).is_int_perfect_square(r) && r == rational(4)); - SASSERT(rational(16).is_int_perfect_square(r) && r == rational(4)); - SASSERT(!rational(17).is_int_perfect_square(r) && r == rational(5)); - SASSERT(!rational(18).is_int_perfect_square(r) && r == rational(5)); - SASSERT(!rational(19).is_int_perfect_square(r) && r == rational(5)); - SASSERT(!rational(20).is_int_perfect_square(r) && r == rational(5)); - SASSERT(!rational(21).is_int_perfect_square(r) && r == rational(5)); - SASSERT(!rational(22).is_int_perfect_square(r) && r == rational(5)); - SASSERT(!rational(23).is_int_perfect_square(r) && r == rational(5)); - SASSERT(!rational(24).is_int_perfect_square(r) && r == rational(5)); - SASSERT(rational(25).is_int_perfect_square(r) && r == rational(5)); - SASSERT(!rational(26).is_int_perfect_square(r) && r == rational(6)); - SASSERT(rational(36).is_int_perfect_square(r) && r == rational(6)); + ENSURE(!rational(-4).is_int_perfect_square(r) && r.is_zero()); + ENSURE(!rational(-3).is_int_perfect_square(r) && r.is_zero()); + ENSURE(!rational(-2).is_int_perfect_square(r) && r.is_zero()); + ENSURE(!rational(-1).is_int_perfect_square(r) && r.is_zero()); + ENSURE(rational(0).is_int_perfect_square(r) && r.is_zero()); + ENSURE(rational(1).is_int_perfect_square(r) && r.is_one()); + ENSURE(!rational(2).is_int_perfect_square(r) && r == rational(2)); + ENSURE(!rational(3).is_int_perfect_square(r) && r == rational(2)); + ENSURE(rational(4).is_int_perfect_square(r) && r == rational(2)); + ENSURE(!rational(5).is_int_perfect_square(r) && r == rational(3)); + ENSURE(!rational(6).is_int_perfect_square(r) && r == rational(3)); + ENSURE(!rational(7).is_int_perfect_square(r) && r == rational(3)); + ENSURE(!rational(8).is_int_perfect_square(r) && r == rational(3)); + ENSURE(rational(9).is_int_perfect_square(r) && r == rational(3)); + ENSURE(!rational(10).is_int_perfect_square(r) && r == rational(4)); + ENSURE(!rational(11).is_int_perfect_square(r) && r == rational(4)); + ENSURE(!rational(12).is_int_perfect_square(r) && r == rational(4)); + ENSURE(!rational(13).is_int_perfect_square(r) && r == rational(4)); + ENSURE(!rational(14).is_int_perfect_square(r) && r == rational(4)); + ENSURE(!rational(15).is_int_perfect_square(r) && r == rational(4)); + ENSURE(rational(16).is_int_perfect_square(r) && r == rational(4)); + ENSURE(!rational(17).is_int_perfect_square(r) && r == rational(5)); + ENSURE(!rational(18).is_int_perfect_square(r) && r == rational(5)); + ENSURE(!rational(19).is_int_perfect_square(r) && r == rational(5)); + ENSURE(!rational(20).is_int_perfect_square(r) && r == rational(5)); + ENSURE(!rational(21).is_int_perfect_square(r) && r == rational(5)); + ENSURE(!rational(22).is_int_perfect_square(r) && r == rational(5)); + ENSURE(!rational(23).is_int_perfect_square(r) && r == rational(5)); + ENSURE(!rational(24).is_int_perfect_square(r) && r == rational(5)); + ENSURE(rational(25).is_int_perfect_square(r) && r == rational(5)); + ENSURE(!rational(26).is_int_perfect_square(r) && r == rational(6)); + ENSURE(rational(36).is_int_perfect_square(r) && r == rational(6)); - SASSERT(rational(1,9).is_perfect_square(r) && r == rational(1,3)); - SASSERT(rational(4,9).is_perfect_square(r) && r == rational(2,3)); + ENSURE(rational(1,9).is_perfect_square(r) && r == rational(1,3)); + ENSURE(rational(4,9).is_perfect_square(r) && r == rational(2,3)); } @@ -363,9 +363,9 @@ static void tstmod(rational const& m, rational const& n) { std::cout << m << " " << n << " " << q << " " << r << "\n"; std::cout << m << " == " << n*q+r << "\n"; - SASSERT(m == (n * q) + r); - SASSERT(rational::zero() <= r); - SASSERT(r < abs(n)); + ENSURE(m == (n * q) + r); + ENSURE(rational::zero() <= r); + ENSURE(r < abs(n)); } diff --git a/src/test/rcf.cpp b/src/test/rcf.cpp index 170c053f1..2f97d49d2 100644 --- a/src/test/rcf.cpp +++ b/src/test/rcf.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"realclosure.h" -#include"mpz_matrix.h" -#include"rlimit.h" +#include "math/realclosure/realclosure.h" +#include "math/realclosure/mpz_matrix.h" +#include "util/rlimit.h" static void tst1() { unsynch_mpq_manager qm; @@ -116,13 +116,13 @@ static void tst_solve(unsigned n, int _A[], int _b[], int _c[], bool solved) { svector b; b.resize(n, 0); if (mm.solve(A, b.c_ptr(), _c)) { - SASSERT(solved); + ENSURE(solved); for (unsigned i = 0; i < n; i++) { - SASSERT(b[i] == _b[i]); + ENSURE(b[i] == _b[i]); } } else { - SASSERT(!solved); + ENSURE(!solved); } } @@ -140,7 +140,7 @@ static void tst_lin_indep(unsigned m, unsigned n, int _A[], unsigned ex_sz, unsi scoped_mpz_matrix B(mm); mm.linear_independent_rows(A, r.c_ptr(), B); for (unsigned i = 0; i < ex_sz; i++) { - SASSERT(r[i] == ex_r[i]); + ENSURE(r[i] == ex_r[i]); } } diff --git a/src/test/region.cpp b/src/test/region.cpp index 83127d552..9cd2e504d 100644 --- a/src/test/region.cpp +++ b/src/test/region.cpp @@ -17,7 +17,7 @@ Revision History: --*/ #include -#include"region.h" +#include "util/region.h" static void tst1() { // TODO diff --git a/src/test/sat_user_scope.cpp b/src/test/sat_user_scope.cpp index a271ce6bb..10abb44c3 100644 --- a/src/test/sat_user_scope.cpp +++ b/src/test/sat_user_scope.cpp @@ -4,8 +4,8 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "sat_solver.h" -#include "util.h" +#include "sat/sat_solver.h" +#include "util/util.h" typedef sat::literal_vector clause_t; typedef vector clauses_t; @@ -73,7 +73,7 @@ static void check_coherence(sat::solver& s1, trail_t& t) { s2.display(std::cout); } std::cout << is_sat1 << "\n"; - SASSERT(is_sat1 == is_sat2); + ENSURE(is_sat1 == is_sat2); } void tst_sat_user_scope() { diff --git a/src/test/simple_parser.cpp b/src/test/simple_parser.cpp index 934552711..1ba0d4b62 100644 --- a/src/test/simple_parser.cpp +++ b/src/test/simple_parser.cpp @@ -16,13 +16,13 @@ Author: Revision History: --*/ -#include"cost_parser.h" -#include"cost_evaluator.h" -#include"arith_decl_plugin.h" -#include"ast_pp.h" -#include"well_sorted.h" -#include"warning.h" -#include"reg_decl_plugins.h" +#include "parsers/util/cost_parser.h" +#include "smt/cost_evaluator.h" +#include "ast/arith_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/well_sorted.h" +#include "util/warning.h" +#include "ast/reg_decl_plugins.h" void tst_simple_parser() { ast_manager m; diff --git a/src/test/simplex.cpp b/src/test/simplex.cpp index 6f08bd04d..6620dc83b 100644 --- a/src/test/simplex.cpp +++ b/src/test/simplex.cpp @@ -4,14 +4,14 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "sparse_matrix.h" -#include "sparse_matrix_def.h" -#include "simplex.h" -#include "simplex_def.h" -#include "mpq_inf.h" -#include "vector.h" -#include "rational.h" -#include "rlimit.h" +#include "util/lp/sparse_matrix.h" +#include "math/simplex/sparse_matrix_def.h" +#include "math/simplex/simplex.h" +#include "math/simplex/simplex_def.h" +#include "util/mpq_inf.h" +#include "util/vector.h" +#include "util/rational.h" +#include "util/rlimit.h" #define R rational typedef simplex::simplex Simplex; @@ -84,7 +84,7 @@ void add_row(Simplex& S, vector const& _v, R const& _b, bool is_eq = false) { coeffs.push_back(b.to_mpq().numerator()); mpq_inf one(mpq(1),mpq(0)); mpq_inf zero(mpq(0),mpq(0)); - SASSERT(vars.size() == coeffs.size()); + ENSURE(vars.size() == coeffs.size()); S.set_lower(nv, zero); if (is_eq) S.set_upper(nv, zero); S.set_lower(nv+1, one); diff --git a/src/test/simplifier.cpp b/src/test/simplifier.cpp index 2e8f434e1..a42ed86b1 100644 --- a/src/test/simplifier.cpp +++ b/src/test/simplifier.cpp @@ -5,11 +5,11 @@ Copyright (c) 2015 Microsoft Corporation --*/ #ifdef _WINDOWS -#include "z3.h" -#include "z3_private.h" +#include "api/z3.h" +#include "api/z3_private.h" #include -#include "util.h" -#include "trace.h" +#include "util/util.h" +#include "util/trace.h" static void ev_const(Z3_context ctx, Z3_ast e) { @@ -18,7 +18,7 @@ static void ev_const(Z3_context ctx, Z3_ast e) { tout << Z3_ast_to_string(ctx, e) << " -> "; tout << Z3_ast_to_string(ctx, r) << "\n";); Z3_ast_kind k = Z3_get_ast_kind(ctx, r); - SASSERT(k == Z3_NUMERAL_AST || + ENSURE(k == Z3_NUMERAL_AST || (k == Z3_APP_AST && (Z3_OP_TRUE == Z3_get_decl_kind(ctx,Z3_get_app_decl(ctx, Z3_to_app(ctx, r))) || Z3_OP_FALSE == Z3_get_decl_kind(ctx,Z3_get_app_decl(ctx, Z3_to_app(ctx, r)))))); @@ -34,7 +34,7 @@ static void test_bv() { Z3_ast bit3_2 = Z3_mk_numeral(ctx, "3", bv2); Z3_ast e = Z3_mk_eq(ctx, bit3_2, Z3_mk_sign_ext(ctx, 1, bit1_1)); - SASSERT(Z3_simplify(ctx, e) == Z3_mk_true(ctx)); + ENSURE(Z3_simplify(ctx, e) == Z3_mk_true(ctx)); TRACE("simplifier", tout << Z3_ast_to_string(ctx, e) << "\n";); Z3_ast b12 = Z3_mk_numeral(ctx, "12", bv72); @@ -97,18 +97,18 @@ static void test_datatypes() { nil = Z3_mk_app(ctx, nil_decl, 0, 0); Z3_ast a = Z3_simplify(ctx, Z3_mk_app(ctx, is_nil_decl, 1, &nil)); - SASSERT(a == Z3_mk_true(ctx)); + ENSURE(a == Z3_mk_true(ctx)); a = Z3_simplify(ctx, Z3_mk_app(ctx, is_cons_decl, 1, &nil)); - SASSERT(a == Z3_mk_false(ctx)); + ENSURE(a == Z3_mk_false(ctx)); Z3_ast one = Z3_mk_numeral(ctx, "1", int_ty); Z3_ast args[2] = { one, nil }; l1 = Z3_mk_app(ctx, cons_decl, 2, args); - SASSERT(nil == Z3_simplify(ctx, Z3_mk_app(ctx, tail_decl, 1, &l1))); - SASSERT(one == Z3_simplify(ctx, Z3_mk_app(ctx, head_decl, 1, &l1))); + ENSURE(nil == Z3_simplify(ctx, Z3_mk_app(ctx, tail_decl, 1, &l1))); + ENSURE(one == Z3_simplify(ctx, Z3_mk_app(ctx, head_decl, 1, &l1))); - SASSERT(Z3_mk_false(ctx) == Z3_simplify(ctx, Z3_mk_eq(ctx, nil, l1))); + ENSURE(Z3_mk_false(ctx) == Z3_simplify(ctx, Z3_mk_eq(ctx, nil, l1))); Z3_del_config(cfg); Z3_del_context(ctx); @@ -147,8 +147,8 @@ static void test_bool() { Z3_ast a = Z3_simplify(ctx, Z3_mk_not(ctx, Z3_mk_eq(ctx, Z3_mk_false(ctx), Z3_mk_true(ctx)))); Z3_ast b = Z3_simplify(ctx, Z3_mk_not(ctx, Z3_mk_iff(ctx, Z3_mk_false(ctx), Z3_mk_true(ctx)))); - SASSERT(Z3_mk_true(ctx) == a); - SASSERT(Z3_mk_true(ctx) == b); + ENSURE(Z3_mk_true(ctx) == a); + ENSURE(Z3_mk_true(ctx) == b); TRACE("simplifier", tout << Z3_ast_to_string(ctx, a) << "\n";); TRACE("simplifier", tout << Z3_ast_to_string(ctx, b) << "\n";); @@ -179,8 +179,8 @@ static void test_array() { TRACE("simplifier", tout << Z3_ast_to_string(ctx, rxy) << "\n";); TRACE("simplifier", tout << Z3_ast_to_string(ctx, Z3_simplify(ctx, Z3_mk_eq(ctx, x2, x3))) << "\n";); - // SASSERT(rxy == Z3_mk_true(ctx)); - // SASSERT(Z3_simplify(ctx, Z3_mk_eq(ctx, x2, x3)) == Z3_mk_false(ctx)); + // ENSURE(rxy == Z3_mk_true(ctx)); + // ENSURE(Z3_simplify(ctx, Z3_mk_eq(ctx, x2, x3)) == Z3_mk_false(ctx)); for (unsigned i = 0; i < 4; ++i) { for (unsigned j = 0; j < 4; ++j) { diff --git a/src/test/small_object_allocator.cpp b/src/test/small_object_allocator.cpp index 5ae2836d0..2f08d553e 100644 --- a/src/test/small_object_allocator.cpp +++ b/src/test/small_object_allocator.cpp @@ -5,9 +5,9 @@ Copyright (c) 2015 Microsoft Corporation --*/ #include -#include"util.h" -#include"trace.h" -#include"small_object_allocator.h" +#include "util/util.h" +#include "util/trace.h" +#include "util/small_object_allocator.h" void tst_small_object_allocator() { small_object_allocator soa; @@ -18,8 +18,11 @@ void tst_small_object_allocator() { TRACE("small_object_allocator", tout << "p1: " << (void*)p1 << " q1: " << (void*)q1 << " p2: " << (void*)p2 << "\n";); soa.deallocate(13,p1); + soa.deallocate(14,q1); + soa.deallocate(13,p2); char * p3 = new (soa) char[13]; TRACE("small_object_allocator", tout << "p3: " << (void*)p3 << "\n";); + soa.deallocate(13,p3); char * r1 = new (soa) char[1]; char * r2 = new (soa) char[1]; @@ -36,6 +39,10 @@ void tst_small_object_allocator() { r3 = new (soa) char[1]; TRACE("small_object_allocator", tout << "r1: " << (void*)r1 << " r2: " << (void*)r2 << " r3: " << (void*)r3 << " r4: " << (void*)r4 << "\n";); + soa.deallocate(1,r1); + soa.deallocate(1,r2); + soa.deallocate(1,r3); + soa.deallocate(1,r4); (void)r1; (void)r2; (void)r3; diff --git a/src/test/smt2print_parse.cpp b/src/test/smt2print_parse.cpp index c79a80ae5..80a57c7d5 100644 --- a/src/test/smt2print_parse.cpp +++ b/src/test/smt2print_parse.cpp @@ -7,7 +7,7 @@ Copyright (c) 2015 Microsoft Corporation // This is to test the print-parse facilities over the API // for SMT-LIB2. -#include "z3.h" +#include "api/z3.h" #include void test_print(Z3_context ctx, Z3_ast a) { diff --git a/src/test/smt_context.cpp b/src/test/smt_context.cpp index 6c44b8b1d..d2ee858e5 100644 --- a/src/test/smt_context.cpp +++ b/src/test/smt_context.cpp @@ -4,8 +4,8 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "smt_context.h" -#include "reg_decl_plugins.h" +#include "smt/smt_context.h" +#include "ast/reg_decl_plugins.h" void tst_smt_context() { diff --git a/src/test/smt_reader.h b/src/test/smt_reader.h index 38e3f4157..437cb7a6b 100644 --- a/src/test/smt_reader.h +++ b/src/test/smt_reader.h @@ -1,9 +1,22 @@ -/* - Copyright (c) 2013 Microsoft Corporation. All rights reserved. - Released under Apache 2.0 license as described in the file LICENSE. +/*++ +Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once @@ -23,7 +36,7 @@ #include "util/lp/lar_constraints.h" #include #include -namespace lean { +namespace lp { template T from_string(const std::string& str) { @@ -108,13 +121,13 @@ namespace lean { void fill_simple_elem(lisp_elem & lm) { int separator = first_separator(); - lean_assert(-1 != separator && separator != 0); + SASSERT(-1 != separator && separator != 0); lm.m_head = m_line.substr(0, separator); m_line = m_line.substr(separator); } void fill_nested_elem(lisp_elem & lm) { - lean_assert(m_line[0] == '('); + SASSERT(m_line[0] == '('); m_line = m_line.substr(1); int separator = first_separator(); lm.m_head = m_line.substr(0, separator); @@ -181,11 +194,11 @@ namespace lean { } void adjust_rigth_side(formula_constraint & /* c*/, lisp_elem & /*el*/) { - // lean_assert(el.m_head == "0"); // do nothing for the time being + // SASSERT(el.m_head == "0"); // do nothing for the time being } void set_constraint_coeffs(formula_constraint & c, lisp_elem & el) { - lean_assert(el.m_elems.size() == 2); + SASSERT(el.m_elems.size() == 2); set_constraint_coeffs_on_coeff_element(c, el.m_elems[0]); adjust_rigth_side(c, el.m_elems[1]); } @@ -201,7 +214,7 @@ namespace lean { add_mult_elem(c, el.m_elems); } else if (el.m_head == "~") { lisp_elem & minel = el.m_elems[0]; - lean_assert(minel.is_simple()); + SASSERT(minel.is_simple()); c.m_right_side += mpq(str_to_int(minel.m_head)); } else { std::cout << "unexpected input " << el.m_head << std::endl; @@ -211,14 +224,14 @@ namespace lean { } std::string get_name(lisp_elem & name) { - lean_assert(name.is_simple()); - lean_assert(!is_integer(name.m_head)); + SASSERT(name.is_simple()); + SASSERT(!is_integer(name.m_head)); return name.m_head; } void add_mult_elem(formula_constraint & c, std::vector & els) { - lean_assert(els.size() == 2); + SASSERT(els.size() == 2); mpq coeff = get_coeff(els[0]); std::string col_name = get_name(els[1]); c.add_pair(coeff, col_name); @@ -228,16 +241,16 @@ namespace lean { if (le.is_simple()) { return mpq(str_to_int(le.m_head)); } else { - lean_assert(le.m_head == "~"); - lean_assert(le.size() == 1); + SASSERT(le.m_head == "~"); + SASSERT(le.size() == 1); lisp_elem & el = le.m_elems[0]; - lean_assert(el.is_simple()); + SASSERT(el.is_simple()); return -mpq(str_to_int(el.m_head)); } } int str_to_int(std::string & s) { - lean_assert(is_integer(s)); + SASSERT(is_integer(s)); return atoi(s.c_str()); } @@ -245,7 +258,7 @@ namespace lean { if (el.size()) { add_complex_sum_elem(c, el); } else { - lean_assert(is_integer(el.m_head)); + SASSERT(is_integer(el.m_head)); int v = atoi(el.m_head.c_str()); mpq vr(v); c.m_right_side -= vr; @@ -263,7 +276,7 @@ namespace lean { } else if (el.m_head == "+") { add_sum(c, el.m_elems); } else { - lean_assert(false); // unexpected input + SASSERT(false); // unexpected input } } diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 87cc05375..1062057f6 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -4,18 +4,16 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "trace.h" -#include "vector.h" -#include "ast.h" -#include "ast_pp.h" -#include "reg_decl_plugins.h" -#include "sorting_network.h" -#include "smt_kernel.h" -#include "model_smt2_pp.h" -#include "smt_params.h" -#include "ast_util.h" - - +#include "util/trace.h" +#include "util/vector.h" +#include "util/sorting_network.h" +#include "ast/ast.h" +#include "ast/ast_pp.h" +#include "ast/reg_decl_plugins.h" +#include "ast/ast_util.h" +#include "model/model_smt2_pp.h" +#include "smt/smt_kernel.h" +#include "smt/params/smt_params.h" struct ast_ext { ast_manager& m; @@ -57,7 +55,7 @@ struct unsigned_ext { static void is_sorted(svector const& v) { for (unsigned i = 0; i + 1 < v.size(); ++i) { - SASSERT(v[i] <= v[i+1]); + ENSURE(v[i] <= v[i+1]); } } @@ -184,7 +182,7 @@ struct ast_ext2 { static void test_sorting_eq(unsigned n, unsigned k) { - SASSERT(k < n); + ENSURE(k < n); ast_manager m; reg_decl_plugins(m); ast_ext2 ext(m); @@ -206,28 +204,28 @@ static void test_sorting_eq(unsigned n, unsigned k) { solver.assert_expr(ext.m_clauses[i].get()); } lbool res = solver.check(); - SASSERT(res == l_true); + ENSURE(res == l_true); solver.push(); for (unsigned i = 0; i < k; ++i) { solver.assert_expr(in[i].get()); } res = solver.check(); - SASSERT(res == l_true); + ENSURE(res == l_true); solver.assert_expr(in[k].get()); res = solver.check(); if (res == l_true) { TRACE("pb", unsigned sz = solver.size(); for (unsigned i = 0; i < sz; ++i) { - tout << mk_pp(solver.get_formulas()[i], m) << "\n"; + tout << mk_pp(solver.get_formula(i), m) << "\n"; }); model_ref model; solver.get_model(model); model_smt2_pp(std::cout, m, *model, 0); TRACE("pb", model_smt2_pp(tout, m, *model, 0);); } - SASSERT(res == l_false); + ENSURE(res == l_false); solver.pop(1); ext.m_clauses.reset(); } @@ -253,27 +251,27 @@ static void test_sorting_le(unsigned n, unsigned k) { solver.assert_expr(ext.m_clauses[i].get()); } lbool res = solver.check(); - SASSERT(res == l_true); + ENSURE(res == l_true); for (unsigned i = 0; i < k; ++i) { solver.assert_expr(in[i].get()); } res = solver.check(); - SASSERT(res == l_true); + ENSURE(res == l_true); solver.assert_expr(in[k].get()); res = solver.check(); if (res == l_true) { TRACE("pb", unsigned sz = solver.size(); for (unsigned i = 0; i < sz; ++i) { - tout << mk_pp(solver.get_formulas()[i], m) << "\n"; + tout << mk_pp(solver.get_formula(i), m) << "\n"; }); model_ref model; solver.get_model(model); model_smt2_pp(std::cout, m, *model, 0); TRACE("pb", model_smt2_pp(tout, m, *model, 0);); } - SASSERT(res == l_false); + ENSURE(res == l_false); solver.pop(1); ext.m_clauses.reset(); } @@ -300,28 +298,28 @@ void test_sorting_ge(unsigned n, unsigned k) { solver.assert_expr(ext.m_clauses[i].get()); } lbool res = solver.check(); - SASSERT(res == l_true); + ENSURE(res == l_true); solver.push(); for (unsigned i = 0; i < n - k; ++i) { solver.assert_expr(m.mk_not(in[i].get())); } res = solver.check(); - SASSERT(res == l_true); + ENSURE(res == l_true); solver.assert_expr(m.mk_not(in[n - k].get())); res = solver.check(); if (res == l_true) { TRACE("pb", unsigned sz = solver.size(); for (unsigned i = 0; i < sz; ++i) { - tout << mk_pp(solver.get_formulas()[i], m) << "\n"; + tout << mk_pp(solver.get_formula(i), m) << "\n"; }); model_ref model; solver.get_model(model); model_smt2_pp(std::cout, m, *model, 0); TRACE("pb", model_smt2_pp(tout, m, *model, 0);); } - SASSERT(res == l_false); + ENSURE(res == l_false); solver.pop(1); } @@ -388,7 +386,6 @@ void test_at_most_1(unsigned n, bool full) { std::cout << atom << "\n"; if (is_true) ++k; } - VERIFY(l_false == solver.check()); if (k > 1) { solver.assert_expr(result1); } @@ -427,6 +424,12 @@ void tst_sorting_network() { test_at_most_1(i, true); test_at_most_1(i, false); } + + for (unsigned n = 2; n < 20; ++n) { + std::cout << "verify eq-1 out of " << n << "\n"; + test_sorting_eq(n, 1); + } + test_at_most1(); test_sorting_eq(11,7); diff --git a/src/test/stack.cpp b/src/test/stack.cpp index 6a4dd3cd8..ddd2f85e9 100644 --- a/src/test/stack.cpp +++ b/src/test/stack.cpp @@ -16,8 +16,8 @@ Notes: --*/ #include -#include"stack.h" -#include"vector.h" +#include "util/stack.h" +#include "util/vector.h" typedef std::pair point; @@ -27,8 +27,8 @@ static void tst1() { point * p1 = new (s) point(10, 20); point * p2 = new (s) point(30, 40); void * ptr = s.allocate(16000); - SASSERT(p2->first == 30 && p2->second == 40); - SASSERT(p1->first == 10 && p1->second == 20); + ENSURE(p2->first == 30 && p2->second == 40); + ENSURE(p1->first == 10 && p1->second == 20); s.deallocate(static_cast(ptr)); s.deallocate(p2); s.deallocate(p1); @@ -38,8 +38,8 @@ static void tst2(unsigned num, unsigned del_rate) { ptr_vector ptrs; stack s; for (unsigned i = 0; i < num; i++) { - SASSERT(ptrs.empty() == s.empty()); - SASSERT(s.empty() || ptrs.back() == s.top()); + ENSURE(ptrs.empty() == s.empty()); + ENSURE(s.empty() || ptrs.back() == s.top()); if (!ptrs.empty() && rand() % del_rate == 0) { s.deallocate(); ptrs.pop_back(); @@ -57,8 +57,8 @@ static void tst2(unsigned num, unsigned del_rate) { } } while (s.empty()) { - SASSERT(ptrs.empty() == s.empty()); - SASSERT(s.empty() || ptrs.back() == s.top()); + ENSURE(ptrs.empty() == s.empty()); + ENSURE(s.empty() || ptrs.back() == s.top()); s.deallocate(); ptrs.pop_back(); } diff --git a/src/test/string_buffer.cpp b/src/test/string_buffer.cpp index 67d60528c..b3e3ce79d 100644 --- a/src/test/string_buffer.cpp +++ b/src/test/string_buffer.cpp @@ -17,14 +17,14 @@ Revision History: --*/ #include -#include"debug.h" -#include"string_buffer.h" -#include"trace.h" +#include "util/debug.h" +#include "util/string_buffer.h" +#include "util/trace.h" static void tst1() { string_buffer<> b; b << "Testing" << 10 << true; - SASSERT(strcmp(b.c_str(), "Testing10true") == 0); + ENSURE(strcmp(b.c_str(), "Testing10true") == 0); } static void tst2() { @@ -34,7 +34,7 @@ static void tst2() { b << r; } TRACE("string_buffer", tout << b.c_str() << "\n";); - SASSERT(strlen(b.c_str()) == 10000); + ENSURE(strlen(b.c_str()) == 10000); } static void tst3() { @@ -42,7 +42,7 @@ static void tst3() { string_buffer<128> b2; b2 << "World"; b << "Hello" << " " << b2; - SASSERT(strcmp(b.c_str(), "Hello World") == 0); + ENSURE(strcmp(b.c_str(), "Hello World") == 0); } void tst_string_buffer() { diff --git a/src/test/substitution.cpp b/src/test/substitution.cpp index 5609225c6..b713dfcfe 100644 --- a/src/test/substitution.cpp +++ b/src/test/substitution.cpp @@ -4,14 +4,14 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "expr_substitution.h" -#include "smt_params.h" -#include "substitution.h" -#include "unifier.h" -#include "bv_decl_plugin.h" -#include "ast_pp.h" -#include "arith_decl_plugin.h" -#include "reg_decl_plugins.h" +#include "ast/expr_substitution.h" +#include "smt/params/smt_params.h" +#include "ast/substitution/substitution.h" +#include "ast/substitution/unifier.h" +#include "ast/bv_decl_plugin.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" +#include "ast/reg_decl_plugins.h" void tst_substitution() { diff --git a/src/test/symbol.cpp b/src/test/symbol.cpp index c87955116..88dd02d73 100644 --- a/src/test/symbol.cpp +++ b/src/test/symbol.cpp @@ -17,38 +17,38 @@ Revision History: --*/ #include -#include"symbol.h" -#include"debug.h" +#include "util/symbol.h" +#include "util/debug.h" static void tst1() { symbol s1("foo"); symbol s2("boo"); symbol s3("foo"); - SASSERT(s1 != s2); - SASSERT(s1 == s3); + ENSURE(s1 != s2); + ENSURE(s1 == s3); std::cout << s1 << " " << s2 << " " << s3 << "\n"; - SASSERT(s1 == "foo"); - SASSERT(s1 != "boo"); - SASSERT(s2 != "foo"); - SASSERT(s3 == "foo"); - SASSERT(s2 == "boo"); + ENSURE(s1 == "foo"); + ENSURE(s1 != "boo"); + ENSURE(s2 != "foo"); + ENSURE(s3 == "foo"); + ENSURE(s2 == "boo"); - SASSERT(lt(s2, s1)); - SASSERT(!lt(s1, s2)); - SASSERT(!lt(s1, s3)); - SASSERT(lt(symbol("abcc"), symbol("abcd"))); - SASSERT(!lt(symbol("abcd"), symbol("abcc"))); - SASSERT(lt(symbol("abc"), symbol("abcc"))); - SASSERT(!lt(symbol("abcd"), symbol("abc"))); - SASSERT(lt(symbol(10), s1)); - SASSERT(!lt(s1, symbol(10))); - SASSERT(lt(symbol(10), symbol(20))); - SASSERT(!lt(symbol(20), symbol(10))); - SASSERT(!lt(symbol(10), symbol(10))); - SASSERT(lt(symbol("a"), symbol("b"))); - SASSERT(!lt(symbol("z"), symbol("b"))); - SASSERT(!lt(symbol("zzz"), symbol("b"))); - SASSERT(lt(symbol("zzz"), symbol("zzzb"))); + ENSURE(lt(s2, s1)); + ENSURE(!lt(s1, s2)); + ENSURE(!lt(s1, s3)); + ENSURE(lt(symbol("abcc"), symbol("abcd"))); + ENSURE(!lt(symbol("abcd"), symbol("abcc"))); + ENSURE(lt(symbol("abc"), symbol("abcc"))); + ENSURE(!lt(symbol("abcd"), symbol("abc"))); + ENSURE(lt(symbol(10), s1)); + ENSURE(!lt(s1, symbol(10))); + ENSURE(lt(symbol(10), symbol(20))); + ENSURE(!lt(symbol(20), symbol(10))); + ENSURE(!lt(symbol(10), symbol(10))); + ENSURE(lt(symbol("a"), symbol("b"))); + ENSURE(!lt(symbol("z"), symbol("b"))); + ENSURE(!lt(symbol("zzz"), symbol("b"))); + ENSURE(lt(symbol("zzz"), symbol("zzzb"))); } void tst_symbol() { diff --git a/src/test/symbol_table.cpp b/src/test/symbol_table.cpp index f67ef6f66..da1830ceb 100644 --- a/src/test/symbol_table.cpp +++ b/src/test/symbol_table.cpp @@ -16,29 +16,27 @@ Author: Revision History: --*/ -#include"symbol_table.h" +#include "util/symbol_table.h" static void tst1() { symbol_table t; t.insert(symbol("foo"), 35); - SASSERT(t.contains(symbol("foo"))); - SASSERT(!t.contains(symbol("boo"))); + ENSURE(t.contains(symbol("foo"))); + ENSURE(!t.contains(symbol("boo"))); t.begin_scope(); t.insert(symbol("boo"), 20); - SASSERT(t.contains(symbol("boo"))); -#ifdef Z3DEBUG + ENSURE(t.contains(symbol("boo"))); int tmp; -#endif - SASSERT(t.find(symbol("boo"), tmp) && tmp == 20); - SASSERT(t.find(symbol("foo"), tmp) && tmp == 35); + ENSURE(t.find(symbol("boo"), tmp) && tmp == 20); + ENSURE(t.find(symbol("foo"), tmp) && tmp == 35); t.insert(symbol("foo"), 100); - SASSERT(t.find(symbol("foo"), tmp) && tmp == 100); + ENSURE(t.find(symbol("foo"), tmp) && tmp == 100); t.end_scope(); - SASSERT(t.find(symbol("foo"), tmp) && tmp == 35); - SASSERT(!t.contains(symbol("boo"))); + ENSURE(t.find(symbol("foo"), tmp) && tmp == 35); + ENSURE(!t.contains(symbol("boo"))); t.reset(); - SASSERT(!t.contains(symbol("boo"))); - SASSERT(!t.contains(symbol("foo"))); + ENSURE(!t.contains(symbol("boo"))); + ENSURE(!t.contains(symbol("foo"))); } void tst_symbol_table() { diff --git a/src/test/tbv.cpp b/src/test/tbv.cpp index 7637c7e83..2bfd14047 100644 --- a/src/test/tbv.cpp +++ b/src/test/tbv.cpp @@ -4,7 +4,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "tbv.h" +#include "muz/rel/tbv.h" static void tst1(unsigned num_bits) { tbv_manager m(num_bits); @@ -17,18 +17,18 @@ static void tst1(unsigned num_bits) { m.display(std::cout, *b1) << "\n"; m.display(std::cout, *bX) << "\n"; m.display(std::cout, *bN) << "\n"; - SASSERT(!m.equals(*b1,*b0)); - SASSERT(!m.equals(*b1,*bX)); - SASSERT(!m.equals(*b0,*bX)); + ENSURE(!m.equals(*b1,*b0)); + ENSURE(!m.equals(*b1,*bX)); + ENSURE(!m.equals(*b0,*bX)); m.set_and(*bX,*b0); - SASSERT(m.equals(*b0,*bX)); - SASSERT(!m.equals(*b1,*bX)); + ENSURE(m.equals(*b0,*bX)); + ENSURE(!m.equals(*b1,*bX)); m.copy(*bX,*b1); - SASSERT(m.equals(*b1,*bX)); - SASSERT(!m.equals(*b0,*bX)); + ENSURE(m.equals(*b1,*bX)); + ENSURE(!m.equals(*b0,*bX)); m.fillX(*bX); VERIFY(m.intersect(*bX,*b0,*bN)); - SASSERT(m.equals(*b0, *bN)); + ENSURE(m.equals(*b0, *bN)); VERIFY(!m.intersect(*b0,*b1,*bN)); m.fill1(*b1); bit_vector to_delete; @@ -58,8 +58,8 @@ static void tst0() { m.display(std::cout, *t1) << "\n"; m.display(std::cout, *t2) << "\n"; m.display(std::cout, *t3) << "\n"; - SASSERT(m.equals(*t1, *t2)); - SASSERT(m.equals(*t1, *t3)); + ENSURE(m.equals(*t1, *t2)); + ENSURE(m.equals(*t1, *t3)); } static void tst2(unsigned num_bits) { @@ -67,10 +67,10 @@ static void tst2(unsigned num_bits) { tbv_ref t(m), t2(m); for (unsigned i = 0; i < 55; ++i) { t = m.allocate(i); - SASSERT(m.is_well_formed(*t)); + ENSURE(m.is_well_formed(*t)); t2 = m.allocate(i+1); VERIFY(!m.set_and(*t2, *t)); - SASSERT(!m.is_well_formed(*t2)); + ENSURE(!m.is_well_formed(*t2)); } } diff --git a/src/test/test_file_reader.h b/src/test/test_file_reader.h index c7a9e3b8b..74dad419b 100644 --- a/src/test/test_file_reader.h +++ b/src/test/test_file_reader.h @@ -1,9 +1,23 @@ -/* -Copyright (c) 2013 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ -Author: Lev Nachmanson -*/ #pragma once // reads a text file @@ -15,7 +29,7 @@ Author: Lev Nachmanson #include "util/lp/lp_utils.h" #include "util/lp/lp_solver.h" -namespace lean { +namespace lp { template struct test_result { diff --git a/src/test/test_util.h b/src/test/test_util.h index c81524b0e..f04af761f 100644 --- a/src/test/test_util.h +++ b/src/test/test_util.h @@ -6,7 +6,7 @@ Copyright (c) 2015 Microsoft Corporation #pragma once -#include "stopwatch.h" +#include "util/stopwatch.h" struct test_context { bool test_ok; diff --git a/src/test/theory_dl.cpp b/src/test/theory_dl.cpp index 463625c88..9a28f3653 100644 --- a/src/test/theory_dl.cpp +++ b/src/test/theory_dl.cpp @@ -4,11 +4,11 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "smt_context.h" -#include "dl_decl_plugin.h" -#include "ast_pp.h" -#include "model_v2_pp.h" -#include "reg_decl_plugins.h" +#include "smt/smt_context.h" +#include "ast/dl_decl_plugin.h" +#include "ast/ast_pp.h" +#include "model/model_v2_pp.h" +#include "ast/reg_decl_plugins.h" void tst_theory_dl() { ast_manager m; diff --git a/src/test/theory_pb.cpp b/src/test/theory_pb.cpp index 3a229d951..8fcbde706 100644 --- a/src/test/theory_pb.cpp +++ b/src/test/theory_pb.cpp @@ -4,15 +4,15 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "smt_context.h" -#include "ast_pp.h" -#include "model_v2_pp.h" -#include "reg_decl_plugins.h" -#include "theory_pb.h" -#include "th_rewriter.h" +#include "smt/smt_context.h" +#include "ast/ast_pp.h" +#include "model/model_v2_pp.h" +#include "ast/reg_decl_plugins.h" +#include "smt/theory_pb.h" +#include "ast/rewriter/th_rewriter.h" unsigned populate_literals(unsigned k, smt::literal_vector& lits) { - SASSERT(k < (1u << lits.size())); + ENSURE(k < (1u << lits.size())); unsigned t = 0; for (unsigned i = 0; i < lits.size(); ++i) { if (k & (1 << i)) { @@ -159,7 +159,7 @@ void tst_theory_pb() { smt::context ctx(m, params); ctx.push(); smt::literal l = smt::theory_pb::assert_ge(ctx, k, lits.size(), lits.c_ptr()); - SASSERT(l != smt::false_literal); + ENSURE(l != smt::false_literal); ctx.assign(l, 0, false); TRACE("pb", ctx.display(tout);); VERIFY(l_true == ctx.check()); diff --git a/src/test/timeout.cpp b/src/test/timeout.cpp index 320006928..80b28a691 100644 --- a/src/test/timeout.cpp +++ b/src/test/timeout.cpp @@ -5,8 +5,8 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "timeout.h" -#include "trace.h" +#include "util/timeout.h" +#include "util/trace.h" #ifdef _WINDOWS diff --git a/src/test/total_order.cpp b/src/test/total_order.cpp index 2fa22065f..a2ee234db 100644 --- a/src/test/total_order.cpp +++ b/src/test/total_order.cpp @@ -17,20 +17,20 @@ Revision History: --*/ -#include"total_order.h" -#include"timeit.h" +#include "util/total_order.h" +#include "util/timeit.h" static void tst1() { uint_total_order to; to.insert(1); to.insert_after(1, 2); to.insert_after(1, 3); - SASSERT(to.lt(1, 2)); - SASSERT(to.lt(3, 2)); - SASSERT(to.lt(1, 3)); - SASSERT(!to.lt(2, 3)); - SASSERT(!to.lt(3, 1)); - SASSERT(!to.lt(2, 2)); + ENSURE(to.lt(1, 2)); + ENSURE(to.lt(3, 2)); + ENSURE(to.lt(1, 3)); + ENSURE(!to.lt(2, 3)); + ENSURE(!to.lt(3, 1)); + ENSURE(!to.lt(2, 2)); std::cout << to << "\n"; } @@ -43,8 +43,8 @@ static void tst2() { to.move_after(3, 1); to.move_after(1, 2); to.move_after(2, 3); - SASSERT(to.lt(1,2)); - SASSERT(to.lt(2,3)); + ENSURE(to.lt(1,2)); + ENSURE(to.lt(2,3)); } } @@ -75,7 +75,7 @@ void move_after(unsigned_vector & v, unsigned_vector & inv_v, unsigned a, unsign // std::cout << "move_after(" << a << ", " << b << ")\n"; unsigned pos_a = inv_v[a]; unsigned pos_b = inv_v[b]; - SASSERT(pos_a != pos_b); + ENSURE(pos_a != pos_b); if (pos_b < pos_a) { for (unsigned i = pos_b; i < pos_a; i++) { v[i] = v[i+1]; @@ -83,17 +83,17 @@ void move_after(unsigned_vector & v, unsigned_vector & inv_v, unsigned a, unsign } v[pos_a] = b; inv_v[b] = pos_a; - SASSERT(inv_v[b] == inv_v[a] + 1); + ENSURE(inv_v[b] == inv_v[a] + 1); } else { - SASSERT(pos_b > pos_a); + ENSURE(pos_b > pos_a); for (unsigned i = pos_b; i > pos_a + 1; i--) { v[i] = v[i-1]; inv_v[v[i-1]] = i; } v[pos_a+1] = b; inv_v[b] = pos_a+1; - SASSERT(inv_v[b] == inv_v[a] + 1); + ENSURE(inv_v[b] == inv_v[a] + 1); } // display(std::cout, v.begin(), v.end()); std::cout << std::endl; } @@ -118,8 +118,8 @@ static void tst4(unsigned sz, unsigned num_rounds) { move_after(v, inv_v, v1, v2); } for (unsigned k = 0; k < sz - 1; k++) { - SASSERT(inv_v[v[k]] == k); - SASSERT(to.lt(v[k], v[k+1])); + ENSURE(inv_v[v[k]] == k); + ENSURE(to.lt(v[k], v[k+1])); } if (i % 1000 == 0) { std::cout << "*"; diff --git a/src/test/trigo.cpp b/src/test/trigo.cpp index 809d94fc2..686800162 100644 --- a/src/test/trigo.cpp +++ b/src/test/trigo.cpp @@ -17,13 +17,13 @@ Revision History: --*/ #include -#include"interval_def.h" -#include"dependency.h" -#include"mpq.h" -#include"ast.h" -#include"debug.h" -#include"im_float_config.h" -#include"rlimit.h" +#include "math/interval/interval_def.h" +#include "util/dependency.h" +#include "util/mpq.h" +#include "ast/ast.h" +#include "util/debug.h" +#include "test/im_float_config.h" +#include "util/rlimit.h" #define PREC 100000 @@ -39,9 +39,8 @@ static void tst_sine_core(std::ostream & out, unsynch_mpq_manager & nm, interval static void tst_sine(std::ostream & out, unsigned N, unsigned k) { unsynch_mpq_manager nm; - im_default_config imc(nm); reslimit rl; - interval_manager im(rl, imc); + interval_manager im(rl, nm); scoped_mpq a(nm); nm.set(a, 0); tst_sine_core(out, nm, im, a, 1); @@ -67,8 +66,7 @@ static void tst_cosine_core(std::ostream & out, unsynch_mpq_manager & nm, interv static void tst_cosine(std::ostream & out, unsigned N, unsigned k) { reslimit rl; unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(rl, imc); + interval_manager im(rl, nm); scoped_mpq a(nm); nm.set(a, 0); tst_cosine_core(out, nm, im, a, 1); @@ -100,8 +98,7 @@ template static void tst_float_sine(std::ostream & out, unsigned N, unsigned k) { reslimit rl; fmanager fm; - im_float_config ifc(fm, EBITS, SBITS); - interval_manager > im(rl, ifc); + interval_manager > im(rl, im_float_config(fm, EBITS, SBITS)); _scoped_numeral a(fm); fm.set(a, EBITS, SBITS, static_cast(0)); tst_float_sine_core(out, fm, im, a, 1); @@ -136,8 +133,7 @@ static void tst_mpf_bug() { static void tst_e(std::ostream & out) { reslimit rl; unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(rl, imc); + interval_manager im(rl, nm); im_default_config::interval r; for (unsigned i = 0; i < 64; i++) { im.e(i, r); @@ -152,8 +148,7 @@ static void tst_e_float(std::ostream & out) { reslimit rl; unsynch_mpq_manager qm; mpf_manager fm; - im_float_config ifc(fm); - interval_manager > im(rl, ifc); + interval_manager > im(rl, fm); scoped_mpq q(qm); im_float_config::interval r; for (unsigned i = 0; i < 64; i++) { @@ -161,7 +156,7 @@ static void tst_e_float(std::ostream & out) { out << fm.to_rational_string(im.lower(r)) << " <= E\n"; out << "E <= " << fm.to_rational_string(im.upper(r)) << "\n"; } - del_f_interval(ifc, r); + im.del(r); } void tst_trigo() { diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index dc88e20af..5f1bd7b36 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -4,24 +4,24 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "udoc_relation.h" -#include "trace.h" -#include "vector.h" -#include "ast.h" -#include "ast_pp.h" -#include "reg_decl_plugins.h" -#include "sorting_network.h" -#include "smt_kernel.h" -#include "model_smt2_pp.h" -#include "smt_params.h" -#include "ast_util.h" -#include "expr_safe_replace.h" -#include "th_rewriter.h" -#include "dl_relation_manager.h" -#include "dl_register_engine.h" -#include "rel_context.h" -#include "bv_decl_plugin.h" -#include "check_relation.h" +#include "muz/rel/udoc_relation.h" +#include "util/trace.h" +#include "util/vector.h" +#include "ast/ast.h" +#include "ast/ast_pp.h" +#include "ast/reg_decl_plugins.h" +#include "util/sorting_network.h" +#include "smt/smt_kernel.h" +#include "model/model_smt2_pp.h" +#include "smt/params/smt_params.h" +#include "ast/ast_util.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/rewriter/th_rewriter.h" +#include "muz/rel/dl_relation_manager.h" +#include "muz/fp/dl_register_engine.h" +#include "muz/rel/rel_context.h" +#include "ast/bv_decl_plugin.h" +#include "muz/rel/check_relation.h" class udoc_tester { @@ -85,7 +85,7 @@ class udoc_tester { doc_ref result(dm); t = mk_rand_tbv(dm); result = dm.allocate(*t); - SASSERT(dm.tbvm().equals(*t, result->pos())); + ENSURE(dm.tbvm().equals(*t, result->pos())); for (unsigned i = 0; i < num_diff; ++i) { t = mk_rand_tbv(dm, result->pos()); if (dm.tbvm().equals(*t, result->pos())) { @@ -97,7 +97,7 @@ class udoc_tester { } result->neg().push_back(t.detach()); } - SASSERT(dm.well_formed(*result)); + ENSURE(dm.well_formed(*result)); return result.detach(); } @@ -121,7 +121,7 @@ public: } udoc_relation* mk_empty(relation_signature const& sig) { - SASSERT(p.can_handle_signature(sig)); + ENSURE(p.can_handle_signature(sig)); relation_base* empty = p.mk_empty(sig); return dynamic_cast(empty); } @@ -210,7 +210,7 @@ public: jc1.push_back(1); jc2.push_back(1); datalog::relation_join_fn* join_fn = p.mk_join_fn(*t1, *t2, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); - SASSERT(join_fn); + ENSURE(join_fn); t = (*join_fn)(*t1, *t2); cr.verify_join(*t1, *t2, *t, jc1, jc2); t->display(std::cout); std::cout << "\n"; @@ -218,13 +218,13 @@ public: t = (*join_fn)(*t1, *t3); cr.verify_join(*t1, *t3, *t, jc1, jc2); - SASSERT(t->empty()); + ENSURE(t->empty()); t->display(std::cout); std::cout << "\n"; t->deallocate(); t = (*join_fn)(*t3, *t3); cr.verify_join(*t3, *t3, *t, jc1, jc2); - SASSERT(t->empty()); + ENSURE(t->empty()); t->display(std::cout); std::cout << "\n"; t->deallocate(); @@ -843,9 +843,9 @@ public: rel_union union_fn = p.mk_union_fn(r, r, 0); (*union_fn)(r, *full); doc_manager& dm = r.get_dm(); - SASSERT(r.get_udoc().size() == 1); + ENSURE(r.get_udoc().size() == 1); doc& d0 = r.get_udoc()[0]; - SASSERT(dm.is_full(d0)); + ENSURE(dm.is_full(d0)); for (unsigned i = 0; i < num_vals; ++i) { unsigned idx = m_rand(num_bits); unsigned val = m_rand(2); diff --git a/src/test/uint_set.cpp b/src/test/uint_set.cpp index fcbbd5c48..bcab106cc 100644 --- a/src/test/uint_set.cpp +++ b/src/test/uint_set.cpp @@ -17,8 +17,8 @@ Revision History: --*/ -#include"uint_set.h" -#include"vector.h" +#include "util/uint_set.h" +#include "util/vector.h" static void tst1(unsigned n) { uint_set s1; @@ -44,94 +44,94 @@ static void tst1(unsigned n) { s2[idx] = false; s1.remove(idx); } - SASSERT(s1.num_elems() == size); - SASSERT((size == 0) == s1.empty()); + ENSURE(s1.num_elems() == size); + ENSURE((size == 0) == s1.empty()); for (unsigned idx = 0; idx < n; idx++) { - SASSERT(s2[idx] == s1.contains(idx)); + ENSURE(s2[idx] == s1.contains(idx)); } } } static void tst2(unsigned n) { uint_set s; - SASSERT(s.empty()); + ENSURE(s.empty()); unsigned val = rand()%n; s.insert(val); - SASSERT(!s.empty()); - SASSERT(s.num_elems() == 1); + ENSURE(!s.empty()); + ENSURE(s.num_elems() == 1); for (unsigned i = 0; i < 100; i++) { unsigned val2 = rand()%n; if (val != val2) { - SASSERT(!s.contains(val2)); + ENSURE(!s.contains(val2)); } } s.remove(val); - SASSERT(s.num_elems() == 0); - SASSERT(s.empty()); + ENSURE(s.num_elems() == 0); + ENSURE(s.empty()); } static void tst3(unsigned n) { - SASSERT(n > 10); + ENSURE(n > 10); uint_set s1; uint_set s2; - SASSERT(s1 == s2); + ENSURE(s1 == s2); s1.insert(3); - SASSERT(s1.num_elems() == 1); - SASSERT(s2.num_elems() == 0); - SASSERT(s1 != s2); + ENSURE(s1.num_elems() == 1); + ENSURE(s2.num_elems() == 0); + ENSURE(s1 != s2); s2.insert(5); - SASSERT(s2.num_elems() == 1); - SASSERT(s1 != s2); - SASSERT(!s1.subset_of(s2)); + ENSURE(s2.num_elems() == 1); + ENSURE(s1 != s2); + ENSURE(!s1.subset_of(s2)); s2 |= s1; - SASSERT(s1.subset_of(s2)); - SASSERT(s2.num_elems() == 2); - SASSERT(s1 != s2); + ENSURE(s1.subset_of(s2)); + ENSURE(s2.num_elems() == 2); + ENSURE(s1 != s2); s1 |= s2; - SASSERT(s1.subset_of(s2)); - SASSERT(s2.subset_of(s1)); - SASSERT(s1.num_elems() == 2); - SASSERT(s2.num_elems() == 2); - SASSERT(s1 == s2); + ENSURE(s1.subset_of(s2)); + ENSURE(s2.subset_of(s1)); + ENSURE(s1.num_elems() == 2); + ENSURE(s2.num_elems() == 2); + ENSURE(s1 == s2); s1.insert(9); - SASSERT(s1.num_elems() == 3); - SASSERT(s2.num_elems() == 2); + ENSURE(s1.num_elems() == 3); + ENSURE(s2.num_elems() == 2); s1.insert(9); - SASSERT(s1.num_elems() == 3); - SASSERT(s2.num_elems() == 2); - SASSERT(s2.subset_of(s1)); - SASSERT(!s1.subset_of(s2)); - SASSERT(s1 != s2); + ENSURE(s1.num_elems() == 3); + ENSURE(s2.num_elems() == 2); + ENSURE(s2.subset_of(s1)); + ENSURE(!s1.subset_of(s2)); + ENSURE(s1 != s2); uint_set s3(s1); - SASSERT(s1 == s3); - SASSERT(s1.subset_of(s3)); - SASSERT(s3.subset_of(s1)); - SASSERT(s2 != s3); + ENSURE(s1 == s3); + ENSURE(s1.subset_of(s3)); + ENSURE(s3.subset_of(s1)); + ENSURE(s2 != s3); uint_set s4(s2); - SASSERT(s2 == s4); - SASSERT(s2.subset_of(s4)); - SASSERT(s4.subset_of(s2)); - SASSERT(s2 != s3); + ENSURE(s2 == s4); + ENSURE(s2.subset_of(s4)); + ENSURE(s4.subset_of(s2)); + ENSURE(s2 != s3); for (unsigned i = 0; i < n; i++) { uint_set s5; s5.insert(i); - SASSERT(s1.contains(i) == s5.subset_of(s1)); + ENSURE(s1.contains(i) == s5.subset_of(s1)); } } static void tst4() { uint_set s; s.insert(32); - SASSERT(s.contains(32)); - SASSERT(!s.contains(31)); - SASSERT(!s.contains(0)); + ENSURE(s.contains(32)); + ENSURE(!s.contains(31)); + ENSURE(!s.contains(0)); s.remove(32); - SASSERT(!s.contains(32)); - SASSERT(!s.contains(31)); - SASSERT(!s.contains(0)); + ENSURE(!s.contains(32)); + ENSURE(!s.contains(31)); + ENSURE(!s.contains(0)); } -#include "map.h" +#include "util/map.h" template struct uint_map : public map {}; diff --git a/src/test/upolynomial.cpp b/src/test/upolynomial.cpp index 43aefed99..fa106fe3f 100644 --- a/src/test/upolynomial.cpp +++ b/src/test/upolynomial.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"upolynomial.h" -#include"timeit.h" -#include"rlimit.h" +#include "math/polynomial/upolynomial.h" +#include "util/timeit.h" +#include "util/rlimit.h" static void tst1() { reslimit rl; @@ -101,10 +101,10 @@ static void tst_isolate_roots(polynomial_ref const & p, unsigned prec, mpbq_mana std::cout << "num. roots: " << roots.size() + lowers.size() << "\n"; std::cout << "sign var(-oo): " << um.sign_variations_at_minus_inf(sseq) << "\n"; std::cout << "sign var(+oo): " << um.sign_variations_at_plus_inf(sseq) << "\n"; - SASSERT(roots.size() + lowers.size() == um.sign_variations_at_minus_inf(sseq) - um.sign_variations_at_plus_inf(sseq)); + ENSURE(roots.size() + lowers.size() == um.sign_variations_at_minus_inf(sseq) - um.sign_variations_at_plus_inf(sseq)); std::cout << "roots:"; for (unsigned i = 0; i < roots.size(); i++) { - SASSERT(um.eval_sign_at(q.size(), q.c_ptr(), roots[i]) == 0); + ENSURE(um.eval_sign_at(q.size(), q.c_ptr(), roots[i]) == 0); std::cout << " "; bqm.display_decimal(std::cout, roots[i], prec); } { @@ -118,7 +118,7 @@ static void tst_isolate_roots(polynomial_ref const & p, unsigned prec, mpbq_mana bqm.display_decimal(std::cout, uppers[i], prec); std::cout << ")"; // Check interval with Sturm sequence. Small detail: Sturm sequence is for close intervals. - SASSERT(um.eval_sign_at(q.size(), q.c_ptr(), lowers[i]) == 0 || + ENSURE(um.eval_sign_at(q.size(), q.c_ptr(), lowers[i]) == 0 || um.eval_sign_at(q.size(), q.c_ptr(), uppers[i]) == 0 || um.sign_variations_at(sseq, lowers[i]) - um.sign_variations_at(sseq, uppers[i]) == 1); // Fourier sequence may also be used to check if the interval is isolating @@ -155,7 +155,7 @@ static void tst_isolate_roots(polynomial_ref const & p, unsigned prec = 5) { } static void check_roots(mpbq_vector const & roots, mpbq_vector const & lowers, mpbq_vector const & uppers, unsigned expected_sz, rational const * expected_roots) { - SASSERT(expected_sz == roots.size() + lowers.size()); + ENSURE(expected_sz == roots.size() + lowers.size()); svector visited; visited.resize(expected_sz, false); for (unsigned i = 0; i < expected_sz; i++) { @@ -163,7 +163,7 @@ static void check_roots(mpbq_vector const & roots, mpbq_vector const & lowers, m bool found = false; for (unsigned j = 0; j < roots.size(); j++) { if (to_rational(roots[j]) == r) { - SASSERT(!visited[j]); + ENSURE(!visited[j]); VERIFY(!found); found = true; visited[j] = true; @@ -173,12 +173,12 @@ static void check_roots(mpbq_vector const & roots, mpbq_vector const & lowers, m unsigned j_prime = j + roots.size(); if (to_rational(lowers[j]) < r && r < to_rational(uppers[j])) { VERIFY(!found); - SASSERT(!visited[j_prime]); + ENSURE(!visited[j_prime]); found = true; visited[j_prime] = true; } } - SASSERT(found); + ENSURE(found); } } @@ -292,21 +292,21 @@ static void tst_remove_one_half() { upolynomial::scoped_numeral_vector _p(um), _q(um), _r(um); um.to_numeral_vector(p, _p); um.to_numeral_vector(r, _r); - SASSERT(um.has_one_half_root(_p.size(), _p.c_ptr())); + ENSURE(um.has_one_half_root(_p.size(), _p.c_ptr())); um.remove_one_half_root(_p.size(), _p.c_ptr(), _q); - SASSERT(!um.has_one_half_root(_q.size(), _q.c_ptr())); + ENSURE(!um.has_one_half_root(_q.size(), _q.c_ptr())); std::cout << "_p: "; um.display(std::cout, _p); std::cout << "\n"; std::cout << "_r: "; um.display(std::cout, _r); std::cout << "\n"; std::cout << "_q: "; um.display(std::cout, _q); std::cout << "\n"; - SASSERT(um.eq(_q, _r)); + ENSURE(um.eq(_q, _r)); p = (((x^5) - 1000000000)^3)*((3*x - 10000000)^2)*((10*x - 632)^2); um.to_numeral_vector(p, _p); - SASSERT(!um.has_one_half_root(_p.size(), _p.c_ptr())); + ENSURE(!um.has_one_half_root(_p.size(), _p.c_ptr())); p = (x - 2)*(x - 4)*(x - 8)*(x - 16)*(x - 32)*(x - 64)*(2*x - 1)*(4*x - 1)*(8*x - 1)*(16*x - 1)*(32*x - 1); um.to_numeral_vector(p, _p); - SASSERT(um.has_one_half_root(_p.size(), _p.c_ptr())); + ENSURE(um.has_one_half_root(_p.size(), _p.c_ptr())); } template @@ -503,7 +503,7 @@ static void tst_refinable(polynomial_ref const & p, mpbq_manager & bqm, mpbq & a } else { std::cout << "new root: " << bqm.to_string(a) << "\n"; - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), a) == 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), a) == 0); } } @@ -608,13 +608,13 @@ static void tst_translate_q() { upolynomial::manager um(rl, nm); upolynomial::scoped_numeral_vector _p(um), _q(um); um.to_numeral_vector(p, _p); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(1)) == 0); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(2)) == 0); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(3)) == 0); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(4)) == 0); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(-1)) != 0); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(5)) != 0); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(-2)) != 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(1)) == 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(2)) == 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(3)) == 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(4)) == 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(-1)) != 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(5)) != 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(-2)) != 0); scoped_mpq c(nm); nm.set(c, 1, 3); scoped_mpq r1(nm); @@ -623,32 +623,32 @@ static void tst_translate_q() { scoped_mpq r2(nm); r2 = 3; r2 -= c; - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), r1) != 0); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), r2) != 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), r1) != 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), r2) != 0); std::cout << "p: "; um.display(std::cout, _p); std::cout << "\n"; um.translate_q(_p.size(), _p.c_ptr(), c, _q); std::cout << "q: "; um.display(std::cout, _q); std::cout << "\n"; - SASSERT(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(1)) != 0); - SASSERT(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(2)) != 0); - SASSERT(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(3)) != 0); - SASSERT(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(4)) != 0); - SASSERT(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(-1)) != 0); - SASSERT(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(5)) != 0); - SASSERT(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(-2)) != 0); - SASSERT(um.eval_sign_at(_q.size(), _q.c_ptr(), r1) == 0); - SASSERT(um.eval_sign_at(_q.size(), _q.c_ptr(), r2) == 0); + ENSURE(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(1)) != 0); + ENSURE(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(2)) != 0); + ENSURE(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(3)) != 0); + ENSURE(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(4)) != 0); + ENSURE(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(-1)) != 0); + ENSURE(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(5)) != 0); + ENSURE(um.eval_sign_at(_q.size(), _q.c_ptr(), mpq(-2)) != 0); + ENSURE(um.eval_sign_at(_q.size(), _q.c_ptr(), r1) == 0); + ENSURE(um.eval_sign_at(_q.size(), _q.c_ptr(), r2) == 0); um.p_1_div_x(_p.size(), _p.c_ptr()); std::cout << "p: "; um.display(std::cout, _p); std::cout << "\n"; - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(1)) == 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(1)) == 0); nm.set(c, 1, 2); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), c) == 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), c) == 0); nm.set(c, 1, 3); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), c) == 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), c) == 0); nm.set(c, 1, 4); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), c) == 0); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(2)) != 0); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(3)) != 0); - SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(4)) != 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), c) == 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(2)) != 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(3)) != 0); + ENSURE(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(4)) != 0); } static void tst_convert_q2bq(unsynch_mpq_manager & m, polynomial_ref const & p, mpq const & a, mpq const & b) { @@ -848,9 +848,9 @@ static void tst_exact_div(polynomial_ref const & p1, polynomial_ref const & p2, std::cout << "expected: "; um.display(std::cout, _q); std::cout << "\n"; } std::cout.flush(); - SASSERT(res == expected); - SASSERT(expected == um.divides(_p1.size(), _p1.c_ptr(), _p2.size(), _p2.c_ptr())); - SASSERT(!expected || um.eq(_r, _q)); + ENSURE(res == expected); + ENSURE(expected == um.divides(_p1.size(), _p1.c_ptr(), _p2.size(), _p2.c_ptr())); + ENSURE(!expected || um.eq(_r, _q)); } static void tst_exact_div() { @@ -878,7 +878,7 @@ static void tst_exact_div() { } static void tst_fact(polynomial_ref const & p, unsigned num_distinct_factors, upolynomial::factor_params const & params = upolynomial::factor_params()) { - SASSERT(is_univariate(p)); + ENSURE(is_univariate(p)); std::cout << "---------------\n"; std::cout << "p: " << p << std::endl; reslimit rl; upolynomial::manager um(rl, p.m().m()); @@ -891,11 +891,11 @@ static void tst_fact(polynomial_ref const & p, unsigned num_distinct_factors, up for (unsigned i = 0; i < fs.distinct_factors(); i++) { std::cout << "*("; um.display(std::cout, fs[i]); std::cout << ")^" << fs.get_degree(i) << std::endl; } - SASSERT(fs.distinct_factors() == num_distinct_factors); + ENSURE(fs.distinct_factors() == num_distinct_factors); upolynomial::scoped_numeral_vector _r(um); fs.multiply(_r); TRACE("upolynomial", tout << "_r: "; um.display(tout, _r); tout << "\n_p: "; um.display(tout, _p); tout << "\n";); - SASSERT(um.eq(_p, _r)); + ENSURE(um.eq(_p, _r)); } static void tst_fact() { @@ -992,8 +992,8 @@ static void tst_fact() { } static void tst_rem(polynomial_ref const & p, polynomial_ref const & q, polynomial_ref const & expected) { - SASSERT(is_univariate(p)); - SASSERT(is_univariate(q)); + ENSURE(is_univariate(p)); + ENSURE(is_univariate(q)); std::cout << "---------------\n"; std::cout << "p: " << p << std::endl; std::cout << "q: " << q << std::endl; @@ -1005,7 +1005,7 @@ static void tst_rem(polynomial_ref const & p, polynomial_ref const & q, polynomi polynomial_ref r(p.m()); r = p.m().to_polynomial(_r.size(), _r.c_ptr(), 0); std::cout << "r: " << r << std::endl; - SASSERT(eq(expected, r)); + ENSURE(eq(expected, r)); } static void tst_rem() { @@ -1022,7 +1022,7 @@ static void tst_rem() { } static void tst_lower_bound(polynomial_ref const & p) { - SASSERT(is_univariate(p)); + ENSURE(is_univariate(p)); std::cout << "---------------\n"; std::cout << "p: " << p << std::endl; reslimit rl; upolynomial::manager um(rl, p.m().m()); diff --git a/src/test/var_subst.cpp b/src/test/var_subst.cpp index e82c09218..169b1e131 100644 --- a/src/test/var_subst.cpp +++ b/src/test/var_subst.cpp @@ -16,13 +16,13 @@ Author: Revision History: --*/ -#include"var_subst.h" -#include"ast_pp.h" -#include"arith_decl_plugin.h" -#include"bv_decl_plugin.h" -#include"array_decl_plugin.h" -#include"for_each_expr.h" -#include"reg_decl_plugins.h" +#include "ast/rewriter/var_subst.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/for_each_expr.h" +#include "ast/reg_decl_plugins.h" namespace find_q { struct proc { @@ -87,7 +87,7 @@ void tst_subst(ast_manager& m) { std::cout << mk_pp(e2, m) << "\n"; std::cout << mk_pp(e3, m) << "\n"; std::cout << mk_pp(t1, m) << "\n"; - SASSERT(e3.get() == t1.get()); + ENSURE(e3.get() == t1.get()); // replace #2 -> #3, #3 -> #2 e2 = m.mk_forall(2, ss, names, e1); @@ -95,7 +95,7 @@ void tst_subst(ast_manager& m) { std::cout << mk_pp(e2, m) << "\n"; std::cout << mk_pp(e3, m) << "\n"; std::cout << mk_pp(t2, m) << "\n"; - SASSERT(e3.get() == t2.get()); + ENSURE(e3.get() == t2.get()); } diff --git a/src/test/vector.cpp b/src/test/vector.cpp index 86ae997ca..4632a9c29 100644 --- a/src/test/vector.cpp +++ b/src/test/vector.cpp @@ -16,32 +16,32 @@ Author: Revision History: --*/ -#include"vector.h" +#include "util/vector.h" static void tst1() { svector v1; - SASSERT(v1.empty()); + ENSURE(v1.empty()); for (unsigned i = 0; i < 1000; i++) { v1.push_back(i + 3); - SASSERT(static_cast(v1[i]) == i + 3); - SASSERT(v1.capacity() >= v1.size()); - SASSERT(!v1.empty()); + ENSURE(static_cast(v1[i]) == i + 3); + ENSURE(v1.capacity() >= v1.size()); + ENSURE(!v1.empty()); } for (unsigned i = 0; i < 1000; i++) { - SASSERT(static_cast(v1[i]) == i + 3); + ENSURE(static_cast(v1[i]) == i + 3); } svector::iterator it = v1.begin(); svector::iterator end = v1.end(); for (int i = 0; it != end; ++it, ++i) { - SASSERT(*it == i + 3); + ENSURE(*it == i + 3); } for (unsigned i = 0; i < 1000; i++) { - SASSERT(static_cast(v1.back()) == 1000 - i - 1 + 3); - SASSERT(v1.size() == 1000 - i); + ENSURE(static_cast(v1.back()) == 1000 - i - 1 + 3); + ENSURE(v1.size() == 1000 - i); v1.pop_back(); } - SASSERT(v1.empty()); - SASSERT(v1.size() == 0); + ENSURE(v1.empty()); + ENSURE(v1.size() == 0); unsigned i = 1000000000; while (true) { std::cout << "resize " << i << "\n"; diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 7ed68c89f..85b6f955c 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -28,6 +28,7 @@ z3_add_component(util lbool.cpp luby.cpp memory_manager.cpp + min_cut.cpp mpbq.cpp mpf.cpp mpff.cpp diff --git a/src/util/approx_nat.cpp b/src/util/approx_nat.cpp index 0739a65aa..cf0c17029 100644 --- a/src/util/approx_nat.cpp +++ b/src/util/approx_nat.cpp @@ -17,7 +17,7 @@ Author: Notes: --*/ -#include"approx_nat.h" +#include "util/approx_nat.h" approx_nat::approx_nat(unsigned val) { m_value = val > m_limit ? UINT_MAX : val; diff --git a/src/util/approx_set.cpp b/src/util/approx_set.cpp index e6757cf05..521197137 100644 --- a/src/util/approx_set.cpp +++ b/src/util/approx_set.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"approx_set.h" +#include "util/approx_set.h" void approx_set::display(std::ostream & out) const { out << "{"; diff --git a/src/util/approx_set.h b/src/util/approx_set.h index c0f3d39dd..1cb7ae9f2 100644 --- a/src/util/approx_set.h +++ b/src/util/approx_set.h @@ -19,7 +19,7 @@ Revision History: #ifndef APPROX_SET_H_ #define APPROX_SET_H_ #include -#include"debug.h" +#include "util/debug.h" template class approx_set_traits; @@ -29,7 +29,7 @@ public: static const unsigned long long zero = 0ull; static const unsigned long long one = 1ull; }; -COMPILE_TIME_ASSERT(sizeof(unsigned long long) == 8); +static_assert(sizeof(unsigned long long) == 8, ""); template <> class approx_set_traits { public: @@ -37,7 +37,7 @@ public: static const unsigned zero = 0; static const unsigned one = 1; }; -COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); +static_assert(sizeof(unsigned) == 4, "unsigned are 4 bytes"); template class approx_set_tpl : private T2U_Proc { diff --git a/src/util/array_map.h b/src/util/array_map.h index 14d404e9d..f3f99d015 100644 --- a/src/util/array_map.h +++ b/src/util/array_map.h @@ -19,8 +19,8 @@ Revision History: #ifndef ARRAY_MAP_H_ #define ARRAY_MAP_H_ -#include"vector.h" -#include"optional.h" +#include "util/vector.h" +#include "util/optional.h" /** \brief Implements a mapping from Key to Data. @@ -63,10 +63,7 @@ class array_map { } void really_flush() { - typename vector >::iterator it = m_map.begin(); - typename vector >::iterator end = m_map.end(); - for (; it != end; ++it) { - optional & e = *it; + for (optional & e : m_map) { if (e) { m_plugin.del_eh(e->m_key, e->m_data); e.set_invalid(); diff --git a/src/util/backtrackable_set.h b/src/util/backtrackable_set.h index ea82a5c81..13a741cff 100644 --- a/src/util/backtrackable_set.h +++ b/src/util/backtrackable_set.h @@ -19,7 +19,7 @@ Revision History: #ifndef BACKTRACKABLE_SET_H_ #define BACKTRACKABLE_SET_H_ -#include"vector.h" +#include "util/vector.h" template struct default_eh { diff --git a/src/util/bit_util.cpp b/src/util/bit_util.cpp index fde66b054..a38f42fdd 100644 --- a/src/util/bit_util.cpp +++ b/src/util/bit_util.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"bit_util.h" -#include"util.h" -#include"debug.h" +#include "util/bit_util.h" +#include "util/util.h" +#include "util/debug.h" #include /** diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index c15a743a9..f9f0a0797 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -17,8 +17,8 @@ Revision History: --*/ #include -#include"bit_vector.h" -#include"trace.h" +#include "util/bit_vector.h" +#include "util/trace.h" #define DEFAULT_CAPACITY 2 diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index a8c348aeb..2d42e35a2 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -20,11 +20,11 @@ Revision History: #define BIT_VECTOR_H_ #include -#include"debug.h" -#include"vector.h" -#include"memory_manager.h" +#include "util/debug.h" +#include "util/vector.h" +#include "util/memory_manager.h" -COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); +static_assert(sizeof(unsigned) == 4, "unsigned are 4 bytes"); #define BV_DEFAULT_CAPACITY 2 class bit_vector { diff --git a/src/util/buffer.h b/src/util/buffer.h index 422db07aa..c64e23d8b 100644 --- a/src/util/buffer.h +++ b/src/util/buffer.h @@ -20,7 +20,7 @@ Revision History: #define BUFFER_H_ #include -#include"memory_manager.h" +#include "util/memory_manager.h" template class buffer { @@ -149,6 +149,13 @@ public: new (m_buffer + m_pos) T(elem); m_pos++; } + + void push_back(T && elem) { + if (m_pos >= m_capacity) + expand(); + new (m_buffer + m_pos) T(std::move(elem)); + m_pos++; + } void pop_back() { if (CallDestructors) { diff --git a/src/util/cancel_eh.h b/src/util/cancel_eh.h index d23e5f544..59f11b3f3 100644 --- a/src/util/cancel_eh.h +++ b/src/util/cancel_eh.h @@ -19,7 +19,7 @@ Revision History: #ifndef CANCEL_EH_H_ #define CANCEL_EH_H_ -#include"event_handler.h" +#include "util/event_handler.h" /** \brief Generic event handler for invoking cancel method. @@ -31,10 +31,14 @@ class cancel_eh : public event_handler { public: cancel_eh(T & o): m_canceled(false), m_obj(o) {} ~cancel_eh() { if (m_canceled) m_obj.dec_cancel(); } - virtual void operator()() { - m_canceled = true; - m_obj.inc_cancel(); + virtual void operator()(event_handler_caller_t caller_id) { + if (!m_canceled) { + m_caller_id = caller_id; + m_canceled = true; + m_obj.inc_cancel(); + } } + bool canceled() const { return m_canceled; } }; #endif diff --git a/src/util/chashtable.h b/src/util/chashtable.h index cdc6e6295..69c48207a 100644 --- a/src/util/chashtable.h +++ b/src/util/chashtable.h @@ -28,11 +28,11 @@ Revision History: #ifndef CHASHTABLE_H_ #define CHASHTABLE_H_ -#include"memory_manager.h" -#include"debug.h" -#include"trace.h" +#include "util/memory_manager.h" +#include "util/debug.h" +#include "util/trace.h" #ifdef Z3DEBUG -#include"hashtable.h" +#include "util/hashtable.h" #endif #define CH_STATISTICS diff --git a/src/util/checked_int64.h b/src/util/checked_int64.h index db1dd2521..a9087e1c2 100644 --- a/src/util/checked_int64.h +++ b/src/util/checked_int64.h @@ -24,8 +24,8 @@ Revision History: #ifndef CHECKED_INT64_H_ #define CHECKED_INT64_H_ -#include"z3_exception.h" -#include"rational.h" +#include "util/z3_exception.h" +#include "util/rational.h" template class checked_int64 { diff --git a/src/util/cmd_context_types.cpp b/src/util/cmd_context_types.cpp index 3d631c28e..61a7bd755 100644 --- a/src/util/cmd_context_types.cpp +++ b/src/util/cmd_context_types.cpp @@ -15,7 +15,7 @@ Notes: --*/ #include -#include"cmd_context_types.h" +#include "util/cmd_context_types.h" std::ostream & operator<<(std::ostream & out, cmd_arg_kind k) { switch (k) { diff --git a/src/util/cmd_context_types.h b/src/util/cmd_context_types.h index 29ac56a49..ae64e2de6 100644 --- a/src/util/cmd_context_types.h +++ b/src/util/cmd_context_types.h @@ -17,8 +17,8 @@ Notes: #ifndef CMD_CONTEXT_TYPES_H_ #define CMD_CONTEXT_TYPES_H_ -#include"symbol.h" -#include"z3_exception.h" +#include "util/symbol.h" +#include "util/z3_exception.h" #include class rational; class expr; diff --git a/src/util/common_msgs.cpp b/src/util/common_msgs.cpp index 412116bb9..f55591b43 100644 --- a/src/util/common_msgs.cpp +++ b/src/util/common_msgs.cpp @@ -16,7 +16,7 @@ Author: Notes: --*/ -#include"common_msgs.h" +#include "util/common_msgs.h" char const * common_msgs::g_canceled_msg = "canceled"; char const * common_msgs::g_max_memory_msg = "max. memory exceeded"; diff --git a/src/util/container_util.h b/src/util/container_util.h new file mode 100644 index 000000000..e114c87b9 --- /dev/null +++ b/src/util/container_util.h @@ -0,0 +1,122 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + container_util.h + +Abstract: + + Useful functions for containers + +Author: + + Krystof Hoder, Nikolaj Bjorner 2017-10-24 + +Revision History: + + Extracted from dl_util.h + +--*/ + +#ifndef CONTAINER_UTIL_H_ +#define CONTAINER_UTIL_H_ + +// ----------------------------------- +// +// container functions +// +// ----------------------------------- + +template + void set_intersection(Set1 & tgt, const Set2 & src) { + svector to_remove; + for (auto const& itm : tgt) + if (!src.contains(itm)) + to_remove.push_back(itm); + while (!to_remove.empty()) { + tgt.remove(to_remove.back()); + to_remove.pop_back(); + } +} + +template +void set_difference(Set & tgt, const Set & to_remove) { + for (auto const& itm : to_remove) + tgt.remove(itm); +} + +template +void set_union(Set1 & tgt, const Set2 & to_add) { + for (auto const& itm : to_add) + tgt.insert(itm); +} + +template +void unite_disjoint_maps(T & tgt, const T & src) { + for (auto const& kv : src) { + SASSERT(!tgt.contains(kv.m_key)); + tgt.insert(kv.m_key, kv.m_value); + } +} + +template +void collect_map_range(T & acc, const U & map) { + for (auto const& kv : map) + acc.push_back(kv.m_value); +} + + +template +void print_container(const T & begin, const T & end, std::ostream & out) { + T it = begin; + out << "("; + bool first = true; + for(; it!=end; ++it) { + if(first) { first = false; } else { out << ","; } + out << (*it); + } + out << ")"; +} + +template +void print_container(const T & cont, std::ostream & out) { + print_container(cont.begin(), cont.end(), out); +} + +template +void print_container(const ref_vector & cont, std::ostream & out) { + print_container(cont.c_ptr(), cont.c_ptr() + cont.size(), out); +} + +template +void print_map(const T & cont, std::ostream & out) { + out << "("; + bool first = true; + for (auto const& kv : cont) { + if (first) { first = false; } else { out << ","; } + out << kv.m_key << "->" << kv.m_value; + } + out << ")"; +} + +template +unsigned find_index(const It & begin, const It & end, const V & val) { + It it = begin; + for (unsigned idx = 0; it != end; it++, idx++) { + if (*it == val) { + return idx; + } + } + return UINT_MAX; +} + +template +bool containers_equal(const T & begin1, const T & end1, const U & begin2, const U & end2) { + T it1 = begin1; + U it2 = begin2; + for (; it1 != end1 && it2 != end2 && *it1 == *it2; ++it1, ++it2) {}; + return it1 == end1 && it2 == end2; +} + +#endif diff --git a/src/util/cooperate.cpp b/src/util/cooperate.cpp index cdd91bfdd..2ae250206 100644 --- a/src/util/cooperate.cpp +++ b/src/util/cooperate.cpp @@ -16,10 +16,10 @@ Author: Notes: --*/ -#include"cooperate.h" -#include"trace.h" -#include"debug.h" -#include"z3_omp.h" +#include "util/cooperate.h" +#include "util/trace.h" +#include "util/debug.h" +#include "util/z3_omp.h" struct cooperation_lock { omp_nest_lock_t m_lock; diff --git a/src/util/debug.cpp b/src/util/debug.cpp index 66676c619..5d39e7c02 100644 --- a/src/util/debug.cpp +++ b/src/util/debug.cpp @@ -21,8 +21,8 @@ Revision History: #include #endif #include -#include"str_hashtable.h" -#include"z3_exception.h" +#include "util/str_hashtable.h" +#include "util/z3_exception.h" static volatile bool g_enable_assertions = true; diff --git a/src/util/debug.h b/src/util/debug.h index 6e295dcaa..536df4588 100644 --- a/src/util/debug.h +++ b/src/util/debug.h @@ -35,8 +35,8 @@ bool assertions_enabled(); # define __has_builtin(x) 0 #endif -#include"error_codes.h" -#include"warning.h" +#include "util/error_codes.h" +#include "util/warning.h" #ifdef Z3DEBUG #define DEBUG_CODE(CODE) { CODE } ((void) 0) @@ -79,14 +79,10 @@ bool is_debug_enabled(const char * tag); #define NOT_IMPLEMENTED_YET() { std::cerr << "NOT IMPLEMENTED YET!\n"; UNREACHABLE(); exit(ERR_NOT_IMPLEMENTED_YET); } ((void) 0) -#ifdef Z3DEBUG #define VERIFY(_x_) if (!(_x_)) { \ std::cerr << "Failed to verify: " << #_x_ << "\n"; \ UNREACHABLE(); \ } -#else -#define VERIFY(_x_) (void)(_x_) -#endif #define ENSURE(_x_) \ if (!(_x_)) { \ @@ -94,14 +90,6 @@ bool is_debug_enabled(const char * tag); exit(-1); \ } -#define MAKE_NAME2(LINE) zofty_ ## LINE -#define MAKE_NAME(LINE) MAKE_NAME2(LINE) -#define DBG_UNIQUE_NAME MAKE_NAME(__LINE__) -#ifdef __GNUC__ -#define COMPILE_TIME_ASSERT(expr) extern __attribute__((unused)) char DBG_UNIQUE_NAME[expr] -#else -#define COMPILE_TIME_ASSERT(expr) extern char DBG_UNIQUE_NAME[expr] -#endif void finalize_debug(); /* diff --git a/src/util/dependency.h b/src/util/dependency.h index 4c438e520..5055399bc 100644 --- a/src/util/dependency.h +++ b/src/util/dependency.h @@ -19,8 +19,8 @@ Revision History: #ifndef DEPENDENCY_H_ #define DEPENDENCY_H_ -#include"vector.h" -#include"region.h" +#include "util/vector.h" +#include "util/region.h" template class dependency_manager { @@ -201,7 +201,7 @@ public: m_todo.push_back(d); unsigned qhead = 0; while (qhead < m_todo.size()) { - d = m_todo[qhead]; + d = m_todo[qhead]; qhead++; if (d->is_leaf()) { vs.push_back(to_leaf(d)->m_value); diff --git a/src/util/dictionary.h b/src/util/dictionary.h index e319e6a27..7dd55bc16 100644 --- a/src/util/dictionary.h +++ b/src/util/dictionary.h @@ -17,8 +17,8 @@ Notes: #ifndef DICTIONARY_H_ #define DICTIONARY_H_ -#include"map.h" -#include"symbol.h" +#include "util/map.h" +#include "util/symbol.h" template class dictionary : public map { diff --git a/src/util/double_manager.h b/src/util/double_manager.h index a426e9b1b..7532a3b8b 100644 --- a/src/util/double_manager.h +++ b/src/util/double_manager.h @@ -23,10 +23,10 @@ Revision History: #include #include #include -#include"util.h" -#include"debug.h" -#include"hash.h" -#include"params.h" +#include "util/util.h" +#include "util/debug.h" +#include "util/hash.h" +#include "util/params.h" /** \brief Create an interface for manipulating double numbers compatible with the one for mpq. @@ -97,7 +97,7 @@ public: } }; -COMPILE_TIME_ASSERT(sizeof(uint64) == sizeof(double)); +static_assert(sizeof(uint64) == sizeof(double), ""); #endif /* DOUBLE_MANAGER_H_ */ diff --git a/src/util/env_params.cpp b/src/util/env_params.cpp index 6748598bf..c2b5f7974 100644 --- a/src/util/env_params.cpp +++ b/src/util/env_params.cpp @@ -16,11 +16,11 @@ Author: Notes: --*/ -#include"env_params.h" -#include"params.h" -#include"gparams.h" -#include"util.h" -#include"memory_manager.h" +#include "util/env_params.h" +#include "util/params.h" +#include "util/gparams.h" +#include "util/util.h" +#include "util/memory_manager.h" void env_params::updt_params() { params_ref p = gparams::get(); diff --git a/src/util/event_handler.h b/src/util/event_handler.h index 4b13f9c48..2a951c3ce 100644 --- a/src/util/event_handler.h +++ b/src/util/event_handler.h @@ -19,10 +19,22 @@ Revision History: #ifndef EVENT_HANDLER_H_ #define EVENT_HANDLER_H_ +enum event_handler_caller_t { + UNSET_EH_CALLER, + CTRL_C_EH_CALLER, + TIMEOUT_EH_CALLER, + RESLIMIT_EH_CALLER, + API_INTERRUPT_EH_CALLER +}; + class event_handler { +protected: + event_handler_caller_t m_caller_id; public: + event_handler(): m_caller_id(UNSET_EH_CALLER) {} virtual ~event_handler() {} - virtual void operator()() = 0; + virtual void operator()(event_handler_caller_t caller_id) = 0; + event_handler_caller_t caller_id() const { return m_caller_id; } }; #endif diff --git a/src/util/ext_numeral.h b/src/util/ext_numeral.h index a37ec6aee..9cb5a1f09 100644 --- a/src/util/ext_numeral.h +++ b/src/util/ext_numeral.h @@ -21,7 +21,7 @@ Revision History: #define EXT_NUMERAL_H_ #include -#include"debug.h" +#include "util/debug.h" enum ext_numeral_kind { EN_MINUS_INFINITY, EN_NUMERAL, EN_PLUS_INFINITY }; diff --git a/src/util/f2n.h b/src/util/f2n.h index 0f453911d..d55b21d3d 100644 --- a/src/util/f2n.h +++ b/src/util/f2n.h @@ -20,7 +20,7 @@ Revision History: #ifndef F2N_H_ #define F2N_H_ -#include"mpf.h" +#include "util/mpf.h" template class f2n { @@ -46,6 +46,9 @@ public: m_manager.set(m_one, ebits, sbits, 1); } + f2n(f2n && other) : m_manager(other.m_manager), m_mode(other.m_mode), m_ebits(other.m_ebits), m_sbits(other.m_sbits), + m_tmp1(std::move(other.m_tmp1)), m_one(std::move(other.m_one)) {} + ~f2n() { m().del(m_tmp1); m().del(m_one); diff --git a/src/util/fixed_bit_vector.cpp b/src/util/fixed_bit_vector.cpp index 8843db736..aafc58404 100644 --- a/src/util/fixed_bit_vector.cpp +++ b/src/util/fixed_bit_vector.cpp @@ -20,9 +20,9 @@ Revision History: --*/ #include -#include"fixed_bit_vector.h" -#include"trace.h" -#include"hash.h" +#include "util/fixed_bit_vector.h" +#include "util/trace.h" +#include "util/hash.h" void fixed_bit_vector::set(fixed_bit_vector const& other, unsigned hi, unsigned lo) { if ((lo % 32) == 0) { diff --git a/src/util/fixed_bit_vector.h b/src/util/fixed_bit_vector.h index be840204c..3bbc73248 100644 --- a/src/util/fixed_bit_vector.h +++ b/src/util/fixed_bit_vector.h @@ -22,8 +22,8 @@ Revision History: #define FIXED_BIT_VECTOR_H_ #include -#include"debug.h" -#include"small_object_allocator.h" +#include "util/debug.h" +#include "util/small_object_allocator.h" class fixed_bit_vector { friend class fixed_bit_vector_manager; diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 97f84af6a..e71594810 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"gparams.h" -#include"dictionary.h" -#include"trace.h" +#include "util/gparams.h" +#include "util/dictionary.h" +#include "util/trace.h" extern void gparams_register_modules(); diff --git a/src/util/gparams.h b/src/util/gparams.h index 139640c78..894732890 100644 --- a/src/util/gparams.h +++ b/src/util/gparams.h @@ -19,7 +19,7 @@ Notes: #ifndef GPARAMS_H_ #define GPARAMS_H_ -#include"params.h" +#include "util/params.h" class gparams { struct imp; diff --git a/src/util/hash.cpp b/src/util/hash.cpp index a54f993af..cacf0a220 100644 --- a/src/util/hash.cpp +++ b/src/util/hash.cpp @@ -17,8 +17,8 @@ Revision History: --*/ -#include"debug.h" -#include"hash.h" +#include "util/debug.h" +#include "util/hash.h" #include static unsigned read_unsigned(const char *s) { diff --git a/src/util/hash.h b/src/util/hash.h index 82d343661..bc6117cac 100644 --- a/src/util/hash.h +++ b/src/util/hash.h @@ -20,7 +20,7 @@ Revision History: #define HASH_H_ #include -#include"util.h" +#include "util/util.h" #define mix(a,b,c) \ { \ @@ -236,7 +236,7 @@ template struct ptr_hash { typedef T * data; unsigned operator()(T * ptr) const { - return get_ptr_hash(ptr); + return get_ptr_hash(ptr); } }; diff --git a/src/util/hashtable.h b/src/util/hashtable.h index 44e05319d..fa9fef180 100644 --- a/src/util/hashtable.h +++ b/src/util/hashtable.h @@ -18,12 +18,12 @@ Revision History: --*/ #ifndef HASHTABLE_H_ #define HASHTABLE_H_ -#include"debug.h" +#include "util/debug.h" #include -#include"util.h" +#include "util/util.h" #include -#include"memory_manager.h" -#include"hash.h" +#include "util/memory_manager.h" +#include "util/hash.h" #define DEFAULT_HASHTABLE_INITIAL_CAPACITY 8 #define SMALL_TABLE_CAPACITY 64 @@ -54,7 +54,7 @@ public: bool is_used() const { return m_state == HT_USED; } T & get_data() { return m_data; } const T & get_data() const { return m_data; } - void set_data(const T & d) { m_data = d; m_state = HT_USED; } + void set_data(T && d) { m_data = std::move(d); m_state = HT_USED; } void set_hash(unsigned h) { m_hash = h; } void mark_as_deleted() { m_state = HT_DELETED; } void mark_as_free() { m_state = HT_FREE; } @@ -187,10 +187,42 @@ protected: } } + static void move_table(entry * source, unsigned source_capacity, entry * target, unsigned target_capacity) { + SASSERT(target_capacity >= source_capacity); + unsigned target_mask = target_capacity - 1; + entry * source_end = source + source_capacity; + entry * target_end = target + target_capacity; + for (entry * source_curr = source; source_curr != source_end; ++source_curr) { + if (source_curr->is_used()) { + unsigned hash = source_curr->get_hash(); + unsigned idx = hash & target_mask; + entry * target_begin = target + idx; + entry * target_curr = target_begin; + for (; target_curr != target_end; ++target_curr) { + SASSERT(!target_curr->is_deleted()); + if (target_curr->is_free()) { + *target_curr = std::move(*source_curr); + goto end; + } + } + for (target_curr = target; target_curr != target_begin; ++target_curr) { + SASSERT(!target_curr->is_deleted()); + if (target_curr->is_free()) { + *target_curr = std::move(*source_curr); + goto end; + } + } + UNREACHABLE(); + end: + ; + } + } + } + void expand_table() { unsigned new_capacity = m_capacity << 1; entry * new_table = alloc_table(new_capacity); - copy_table(m_table, m_capacity, new_table, new_capacity); + move_table(m_table, m_capacity, new_table, new_capacity); delete_table(); m_table = new_table; m_capacity = new_capacity; @@ -202,7 +234,7 @@ protected: if (memory::is_out_of_memory()) return; entry * new_table = alloc_table(m_capacity); - copy_table(m_table, m_capacity, new_table, m_capacity); + move_table(m_table, m_capacity, new_table, m_capacity); delete_table(); m_table = new_table; m_num_deleted = 0; @@ -321,7 +353,7 @@ public: #define INSERT_LOOP_BODY() { \ if (curr->is_used()) { \ if (curr->get_hash() == hash && equals(curr->get_data(), e)) { \ - curr->set_data(e); \ + curr->set_data(std::move(e)); \ return; \ } \ HS_CODE(m_st_collision++;); \ @@ -330,7 +362,7 @@ public: entry * new_entry; \ if (del_entry) { new_entry = del_entry; m_num_deleted--; } \ else { new_entry = curr; } \ - new_entry->set_data(e); \ + new_entry->set_data(std::move(e)); \ new_entry->set_hash(hash); \ m_size++; \ return; \ @@ -342,7 +374,7 @@ public: } \ } ((void) 0) - void insert(data const & e) { + void insert(data && e) { if ((m_size + m_num_deleted) << 2 > (m_capacity * 3)) { // if ((m_size + m_num_deleted) * 2 > (m_capacity)) { expand_table(); @@ -363,6 +395,11 @@ public: UNREACHABLE(); } + void insert(const data & e) { + data tmp(e); + insert(std::move(tmp)); + } + #define INSERT_LOOP_CORE_BODY() { \ if (curr->is_used()) { \ if (curr->get_hash() == hash && equals(curr->get_data(), e)) { \ @@ -375,7 +412,7 @@ public: entry * new_entry; \ if (del_entry) { new_entry = del_entry; m_num_deleted--; } \ else { new_entry = curr; } \ - new_entry->set_data(e); \ + new_entry->set_data(std::move(e)); \ new_entry->set_hash(hash); \ m_size++; \ et = new_entry; \ @@ -393,7 +430,7 @@ public: Return true if it is a new element, and false otherwise. Store the entry/slot of the table in et. */ - bool insert_if_not_there_core(data const & e, entry * & et) { + bool insert_if_not_there_core(data && e, entry * & et) { if ((m_size + m_num_deleted) << 2 > (m_capacity * 3)) { // if ((m_size + m_num_deleted) * 2 > (m_capacity)) { expand_table(); @@ -415,6 +452,11 @@ public: return 0; } + bool insert_if_not_there_core(const data & e, entry * & et) { + data temp(e); + return insert_if_not_there_core(std::move(temp), et); + } + /** \brief Insert the element e if it is not in the table. Return a reference to e or to an object identical to e diff --git a/src/util/heap.h b/src/util/heap.h index e8964a4f0..02e30bf04 100644 --- a/src/util/heap.h +++ b/src/util/heap.h @@ -19,8 +19,8 @@ Revision History: #ifndef HEAP_H_ #define HEAP_H_ -#include"vector.h" -#include"debug.h" +#include "util/vector.h" +#include "util/debug.h" template class heap : private LT { @@ -43,7 +43,15 @@ class heap : private LT { return i >> 1; } -#ifdef Z3DEBUG + void display(std::ostream& out, unsigned indent, int idx) const { + if (idx < static_cast(m_values.size())) { + for (unsigned i = 0; i < indent; ++i) out << " "; + out << m_values[idx] << "\n"; + display(out, indent + 1, left(idx)); + display(out, indent + 1, right(idx)); + } + } + // Return true if the value can be inserted in the heap. That is, the vector m_value2indices is big enough to store this value. bool is_valid_value(int v) const { SASSERT(v >= 0 && v < static_cast(m_value2indices.size())); @@ -59,11 +67,13 @@ class heap : private LT { } return true; } + + public: bool check_invariant() const { return check_invariant_core(1); } -#endif + private: void move_up(int idx) { @@ -219,6 +229,7 @@ public: void insert(int val) { CASSERT("heap", check_invariant()); + CASSERT("heap", !contains(val)); SASSERT(is_valid_value(val)); int idx = static_cast(m_values.size()); m_value2indices[val] = idx; @@ -272,6 +283,11 @@ public: } } } + + void display(std::ostream& out) const { + display(out, 0, 1); + } + }; diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index a522c9a41..014e62625 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -34,7 +34,7 @@ Revision History: #define USE_INTRINSICS #endif -#include"hwf.h" +#include "util/hwf.h" // Note: // Which FPU will be used is determined by compiler settings. On x64 it's always SSE2, diff --git a/src/util/hwf.h b/src/util/hwf.h index 8816e5b37..5f7692204 100644 --- a/src/util/hwf.h +++ b/src/util/hwf.h @@ -20,9 +20,9 @@ Revision History: #define HWF_H_ #include -#include"mpz.h" -#include"mpq.h" -#include"mpf.h" // we use the same rounding modes as mpf's +#include "util/mpz.h" +#include "util/mpq.h" +#include "util/mpf.h" class hwf { friend class hwf_manager; diff --git a/src/util/id_gen.h b/src/util/id_gen.h index b119a88ac..951ab3f52 100644 --- a/src/util/id_gen.h +++ b/src/util/id_gen.h @@ -19,8 +19,8 @@ Revision History: #ifndef ID_GEN_H_ #define ID_GEN_H_ -#include"vector.h" -#include"util.h" +#include "util/vector.h" +#include "util/util.h" class id_gen { unsigned m_next_id; diff --git a/src/util/inf_eps_rational.h b/src/util/inf_eps_rational.h index 048b6f383..c184623ca 100644 --- a/src/util/inf_eps_rational.h +++ b/src/util/inf_eps_rational.h @@ -20,10 +20,10 @@ Revision History: #define INF_EPS_RATIONAL_H_ #include #include -#include"debug.h" -#include"vector.h" -#include"rational.h" -#include"inf_rational.h" +#include "util/debug.h" +#include "util/vector.h" +#include "util/rational.h" +#include "util/inf_rational.h" template class inf_eps_rational { @@ -119,12 +119,12 @@ class inf_eps_rational { bool is_rational() const { return m_infty.is_zero() && m_r.is_rational(); } int64 get_int64() const { - SASSERT(is_int64()); + SASSERT(is_int64()); return m_r.get_int64(); } uint64 get_uint64() const { - SASSERT(is_uint64()); + SASSERT(is_uint64()); return m_r.get_uint64(); } @@ -168,45 +168,45 @@ class inf_eps_rational { inf_eps_rational & operator=(const inf_eps_rational & r) { m_infty = r.m_infty; m_r = r.m_r; - return *this; + return *this; } inf_eps_rational & operator=(const Numeral & r) { m_infty.reset(); m_r = r; - return *this; + return *this; } inf_eps_rational & operator+=(const inf_eps_rational & r) { m_infty += r.m_infty; m_r += r.m_r; - return *this; + return *this; } inf_eps_rational & operator-=(const inf_eps_rational & r) { m_infty -= r.m_infty; m_r -= r.m_r; - return *this; + return *this; } inf_eps_rational & operator-=(const inf_rational & r) { m_r -= r; - return *this; + return *this; } inf_eps_rational & operator+=(const inf_rational & r) { m_r += r; - return *this; + return *this; } inf_eps_rational & operator+=(const rational & r) { m_r += r; - return *this; + return *this; } inf_eps_rational & operator-=(const rational & r) { m_r -= r; - return *this; + return *this; } inf_eps_rational & operator*=(const rational & r1) { diff --git a/src/util/inf_int_rational.cpp b/src/util/inf_int_rational.cpp index 7bc68e641..c12c939fd 100644 --- a/src/util/inf_int_rational.cpp +++ b/src/util/inf_int_rational.cpp @@ -17,7 +17,7 @@ Revision History: --*/ #include -#include"inf_int_rational.h" +#include "util/inf_int_rational.h" inf_int_rational inf_int_rational::m_zero; inf_int_rational inf_int_rational::m_one; diff --git a/src/util/inf_int_rational.h b/src/util/inf_int_rational.h index a7c920295..c9c82052e 100644 --- a/src/util/inf_int_rational.h +++ b/src/util/inf_int_rational.h @@ -21,9 +21,9 @@ Revision History: #define INF_INT_RATIONAL_H_ #include #include -#include"debug.h" -#include"vector.h" -#include"rational.h" +#include "util/debug.h" +#include "util/vector.h" +#include "util/rational.h" class inf_int_rational { @@ -110,12 +110,12 @@ class inf_int_rational { bool is_rational() const { return m_second == 0; } int64 get_int64() const { - SASSERT(is_int64()); + SASSERT(is_int64()); return m_first.get_int64(); } uint64 get_uint64() const { - SASSERT(is_uint64()); + SASSERT(is_uint64()); return m_first.get_uint64(); } @@ -132,7 +132,7 @@ class inf_int_rational { inf_int_rational & operator=(const inf_int_rational & r) { m_first = r.m_first; m_second = r.m_second; - return *this; + return *this; } inf_int_rational & operator=(const rational & r) { @@ -154,7 +154,7 @@ class inf_int_rational { inf_int_rational & operator+=(const inf_int_rational & r) { m_first += r.m_first; m_second += r.m_second; - return *this; + return *this; } inf_int_rational & operator*=(const rational & r) { @@ -163,7 +163,7 @@ class inf_int_rational { } m_first *= r; m_second *= r.get_int32(); - return *this; + return *this; } @@ -171,17 +171,17 @@ class inf_int_rational { inf_int_rational & operator-=(const inf_int_rational & r) { m_first -= r.m_first; m_second -= r.m_second; - return *this; + return *this; } inf_int_rational & operator+=(const rational & r) { m_first += r; - return *this; + return *this; } inf_int_rational & operator-=(const rational & r) { m_first -= r; - return *this; + return *this; } inf_int_rational & operator++() { diff --git a/src/util/inf_rational.cpp b/src/util/inf_rational.cpp index 0b043e94d..78bf61038 100644 --- a/src/util/inf_rational.cpp +++ b/src/util/inf_rational.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"inf_rational.h" +#include "util/inf_rational.h" inf_rational inf_rational::m_zero; inf_rational inf_rational::m_one; diff --git a/src/util/inf_rational.h b/src/util/inf_rational.h index 0488d5fd3..d49e45f50 100644 --- a/src/util/inf_rational.h +++ b/src/util/inf_rational.h @@ -21,9 +21,9 @@ Revision History: #define INF_RATIONAL_H_ #include #include -#include"debug.h" -#include"vector.h" -#include"rational.h" +#include "util/debug.h" +#include "util/vector.h" +#include "util/rational.h" class inf_rational { @@ -123,12 +123,12 @@ class inf_rational { bool is_rational() const { return m_second.is_zero(); } int64 get_int64() const { - SASSERT(is_int64()); + SASSERT(is_int64()); return m_first.get_int64(); } uint64 get_uint64() const { - SASSERT(is_uint64()); + SASSERT(is_uint64()); return m_first.get_uint64(); } @@ -145,7 +145,7 @@ class inf_rational { inf_rational & operator=(const inf_rational & r) { m_first = r.m_first; m_second = r.m_second; - return *this; + return *this; } inf_rational & operator=(const rational & r) { @@ -167,23 +167,23 @@ class inf_rational { inf_rational & operator+=(const inf_rational & r) { m_first += r.m_first; m_second += r.m_second; - return *this; + return *this; } inf_rational & operator-=(const inf_rational & r) { m_first -= r.m_first; m_second -= r.m_second; - return *this; + return *this; } inf_rational & operator+=(const rational & r) { m_first += r; - return *this; + return *this; } inf_rational & operator-=(const rational & r) { m_first -= r; - return *this; + return *this; } inf_rational & operator*=(const rational & r1) { diff --git a/src/util/inf_s_integer.cpp b/src/util/inf_s_integer.cpp index 602dc14ac..26b226e15 100644 --- a/src/util/inf_s_integer.cpp +++ b/src/util/inf_s_integer.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"inf_s_integer.h" +#include "util/inf_s_integer.h" inf_s_integer inf_s_integer::m_zero(0); inf_s_integer inf_s_integer::m_one(1); diff --git a/src/util/inf_s_integer.h b/src/util/inf_s_integer.h index 80c81350f..067000202 100644 --- a/src/util/inf_s_integer.h +++ b/src/util/inf_s_integer.h @@ -19,8 +19,8 @@ Revision History: #ifndef INF_S_INTEGER_H_ #define INF_S_INTEGER_H_ -#include"s_integer.h" -#include"rational.h" +#include "util/s_integer.h" +#include "util/rational.h" class inf_s_integer { static inf_s_integer m_zero; @@ -67,7 +67,7 @@ class inf_s_integer { inf_s_integer & operator=(const inf_s_integer & r) { m_first = r.m_first; m_second = r.m_second; - return *this; + return *this; } inf_s_integer & operator=(const rational & r) { m_first = static_cast(r.get_int64()); @@ -90,20 +90,20 @@ class inf_s_integer { inf_s_integer & operator+=(const inf_s_integer & r) { m_first += r.m_first; m_second += r.m_second; - return *this; + return *this; } inf_s_integer & operator-=(const inf_s_integer & r) { m_first -= r.m_first; m_second -= r.m_second; - return *this; + return *this; } inf_s_integer & operator+=(const s_integer & r) { m_first += r.get_int(); - return *this; + return *this; } inf_s_integer & operator-=(const s_integer & r) { m_first -= r.get_int(); - return *this; + return *this; } inf_s_integer & operator*=(const s_integer & r1) { m_first *= r1.get_int(); diff --git a/src/util/lbool.cpp b/src/util/lbool.cpp index b77a9b892..08f08163a 100644 --- a/src/util/lbool.cpp +++ b/src/util/lbool.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"lbool.h" +#include "util/lbool.h" std::ostream & operator<<(std::ostream & out, lbool b) { switch(b) { diff --git a/src/util/lbool.h b/src/util/lbool.h index ff2466eca..dfc28926d 100644 --- a/src/util/lbool.h +++ b/src/util/lbool.h @@ -19,7 +19,7 @@ Revision History: #ifndef LBOOL_H_ #define LBOOL_H_ -#include"util.h" +#include "util/util.h" typedef enum { l_false = -1, l_undef, l_true } lbool; diff --git a/src/util/list.h b/src/util/list.h index 8d5ff40f2..efde5ada1 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -19,8 +19,8 @@ Revision History: #ifndef LIST_H_ #define LIST_H_ -#include"buffer.h" -#include"region.h" +#include "util/buffer.h" +#include "util/region.h" template class list { diff --git a/src/util/lp/CMakeLists.txt b/src/util/lp/CMakeLists.txt index 57ebecc8d..70c5f9e3b 100644 --- a/src/util/lp/CMakeLists.txt +++ b/src/util/lp/CMakeLists.txt @@ -3,7 +3,7 @@ z3_add_component(lp lp_utils.cpp binary_heap_priority_queue_instances.cpp binary_heap_upair_queue_instances.cpp - bound_propagator.cpp + lp_bound_propagator.cpp core_solver_pretty_printer_instances.cpp dense_matrix_instances.cpp eta_matrix_instances.cpp @@ -19,7 +19,7 @@ z3_add_component(lp lu_instances.cpp matrix_instances.cpp permutation_matrix_instances.cpp - quick_xplain.cpp + quick_xplain.cpp row_eta_matrix_instances.cpp scaler_instances.cpp sparse_matrix_instances.cpp diff --git a/src/util/lp/binary_heap_priority_queue.h b/src/util/lp/binary_heap_priority_queue.h index a6206948c..8282ece9c 100644 --- a/src/util/lp/binary_heap_priority_queue.h +++ b/src/util/lp/binary_heap_priority_queue.h @@ -1,13 +1,28 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include "util/debug.h" #include "util/lp/lp_utils.h" -namespace lean { +namespace lp { // the elements with the smallest priority are dequeued first template class binary_heap_priority_queue { @@ -22,7 +37,7 @@ class binary_heap_priority_queue { void put_at(unsigned i, unsigned h); void decrease_priority(unsigned o, T newPriority); public: -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG bool is_consistent() const; #endif public: @@ -60,10 +75,10 @@ public: /// return the first element of the queue and removes it from the queue unsigned dequeue(); unsigned peek() const { - lean_assert(m_heap_size > 0); + SASSERT(m_heap_size > 0); return m_heap[1]; } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG void print(std::ostream & out); #endif }; diff --git a/src/util/lp/binary_heap_priority_queue.hpp b/src/util/lp/binary_heap_priority_queue.hpp index 440b45b02..e7378309d 100644 --- a/src/util/lp/binary_heap_priority_queue.hpp +++ b/src/util/lp/binary_heap_priority_queue.hpp @@ -1,11 +1,26 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/vector.h" #include "util/lp/binary_heap_priority_queue.h" -namespace lean { -// is is the child place in heap +namespace lp { +// this is the child place in the heap template void binary_heap_priority_queue::swap_with_parent(unsigned i) { unsigned parent = m_heap[i >> 1]; put_at(i >> 1, m_heap[i]); @@ -29,12 +44,12 @@ template void binary_heap_priority_queue::decrease_priority(unsi } } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template bool binary_heap_priority_queue::is_consistent() const { for (int i = 0; i < m_heap_inverse.size(); i++) { int i_index = m_heap_inverse[i]; - lean_assert(i_index <= static_cast(m_heap_size)); - lean_assert(i_index == -1 || m_heap[i_index] == i); + SASSERT(i_index <= static_cast(m_heap_size)); + SASSERT(i_index == -1 || m_heap[i_index] == i); } for (unsigned i = 1; i < m_heap_size; i++) { unsigned ch = i << 1; @@ -49,13 +64,14 @@ template bool binary_heap_priority_queue::is_consistent() const return true; } #endif + template void binary_heap_priority_queue::remove(unsigned o) { T priority_of_o = m_priorities[o]; int o_in_heap = m_heap_inverse[o]; if (o_in_heap == -1) { return; // nothing to do } - lean_assert(static_cast(o_in_heap) <= m_heap_size); + SASSERT(static_cast(o_in_heap) <= m_heap_size); if (static_cast(o_in_heap) < m_heap_size) { put_at(o_in_heap, m_heap[m_heap_size--]); if (m_priorities[m_heap[o_in_heap]] > priority_of_o) { @@ -72,11 +88,11 @@ template void binary_heap_priority_queue::remove(unsigned o) { } } } else { - lean_assert(static_cast(o_in_heap) == m_heap_size); + SASSERT(static_cast(o_in_heap) == m_heap_size); m_heap_size--; } m_heap_inverse[o] = -1; - // lean_assert(is_consistent()); + // SASSERT(is_consistent()); } // n is the initial queue capacity. // The capacity will be enlarged two times automatically if needed @@ -102,7 +118,7 @@ template void binary_heap_priority_queue::put_to_heap(unsigned i template void binary_heap_priority_queue::enqueue_new(unsigned o, const T& priority) { m_heap_size++; int i = m_heap_size; - lean_assert(o < m_priorities.size()); + SASSERT(o < m_priorities.size()); m_priorities[o] = priority; put_at(i, o); while (i > 1 && m_priorities[m_heap[i >> 1]] > priority) { @@ -134,7 +150,7 @@ template void binary_heap_priority_queue::change_priority_for_ex /// return the first element of the queue and removes it from the queue template unsigned binary_heap_priority_queue::dequeue_and_get_priority(T & priority) { - lean_assert(m_heap_size != 0); + SASSERT(m_heap_size != 0); int ret = m_heap[1]; priority = m_priorities[ret]; put_the_last_at_the_top_and_fix_the_heap(); @@ -168,13 +184,13 @@ template void binary_heap_priority_queue::put_the_last_at_the_to } /// return the first element of the queue and removes it from the queue template unsigned binary_heap_priority_queue::dequeue() { - lean_assert(m_heap_size > 0); + SASSERT(m_heap_size > 0); int ret = m_heap[1]; put_the_last_at_the_top_and_fix_the_heap(); m_heap_inverse[ret] = -1; return ret; } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template void binary_heap_priority_queue::print(std::ostream & out) { vector index; vector prs; diff --git a/src/util/lp/binary_heap_priority_queue_instances.cpp b/src/util/lp/binary_heap_priority_queue_instances.cpp index 567494d6f..fca826a6b 100644 --- a/src/util/lp/binary_heap_priority_queue_instances.cpp +++ b/src/util/lp/binary_heap_priority_queue_instances.cpp @@ -1,10 +1,25 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/numeric_pair.h" #include "util/lp/binary_heap_priority_queue.hpp" -namespace lean { +namespace lp { template binary_heap_priority_queue::binary_heap_priority_queue(unsigned int); template unsigned binary_heap_priority_queue::dequeue(); template void binary_heap_priority_queue::enqueue(unsigned int, int const&); @@ -16,11 +31,11 @@ template unsigned binary_heap_priority_queue::dequeue(); template unsigned binary_heap_priority_queue::dequeue(); template void binary_heap_priority_queue >::enqueue(unsigned int, numeric_pair const&); template void binary_heap_priority_queue >::resize(unsigned int); -template void lean::binary_heap_priority_queue::resize(unsigned int); +template void lp::binary_heap_priority_queue::resize(unsigned int); template binary_heap_priority_queue::binary_heap_priority_queue(unsigned int); template void binary_heap_priority_queue::resize(unsigned int); template unsigned binary_heap_priority_queue::dequeue(); template void binary_heap_priority_queue::enqueue(unsigned int, unsigned int const&); template void binary_heap_priority_queue::remove(unsigned int); -template void lean::binary_heap_priority_queue::resize(unsigned int); +template void lp::binary_heap_priority_queue::resize(unsigned int); } diff --git a/src/util/lp/binary_heap_upair_queue.h b/src/util/lp/binary_heap_upair_queue.h index 26cfd5532..640c4bb81 100644 --- a/src/util/lp/binary_heap_upair_queue.h +++ b/src/util/lp/binary_heap_upair_queue.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include @@ -15,7 +30,7 @@ typedef std::pair upair; -namespace lean { +namespace lp { template class binary_heap_upair_queue { binary_heap_priority_queue m_q; @@ -38,7 +53,7 @@ public: void enqueue(unsigned i, unsigned j, const T & priority); void dequeue(unsigned & i, unsigned &j); T get_priority(unsigned i, unsigned j) const; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG bool pair_to_index_is_a_bijection() const; bool available_spots_are_correct() const; bool is_correct() const { diff --git a/src/util/lp/binary_heap_upair_queue.hpp b/src/util/lp/binary_heap_upair_queue.hpp index a48bdb5b7..d12be9707 100644 --- a/src/util/lp/binary_heap_upair_queue.hpp +++ b/src/util/lp/binary_heap_upair_queue.hpp @@ -1,12 +1,27 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/lp/lp_utils.h" #include "util/lp/binary_heap_upair_queue.h" -namespace lean { +namespace lp { template binary_heap_upair_queue::binary_heap_upair_queue(unsigned size) : m_q(size), m_pairs(size) { for (unsigned i = 0; i < size; i++) m_available_spots.push_back(i); @@ -14,7 +29,7 @@ template binary_heap_upair_queue::binary_heap_upair_queue(unsign template unsigned binary_heap_upair_queue::dequeue_available_spot() { - lean_assert(m_available_spots.empty() == false); + SASSERT(m_available_spots.empty() == false); unsigned ret = m_available_spots.back(); m_available_spots.pop_back(); return ret; @@ -54,7 +69,7 @@ template void binary_heap_upair_queue::enqueue(unsigned i, unsig m_pairs.resize(new_size); } ij_index = dequeue_available_spot(); - // lean_assert(ij_index void binary_heap_upair_queue::enqueue(unsigned i, unsig } template void binary_heap_upair_queue::dequeue(unsigned & i, unsigned &j) { - lean_assert(!m_q.is_empty()); + SASSERT(!m_q.is_empty()); unsigned ij_index = m_q.dequeue(); upair & p = m_pairs[ij_index]; i = p.first; @@ -81,7 +96,7 @@ template T binary_heap_upair_queue::get_priority(unsigned i, uns return m_q.get_priority(it->second); } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template bool binary_heap_upair_queue::pair_to_index_is_a_bijection() const { std::set tmp; for (auto p : m_pairs_to_index) { diff --git a/src/util/lp/binary_heap_upair_queue_instances.cpp b/src/util/lp/binary_heap_upair_queue_instances.cpp index 4c4603110..6d093b175 100644 --- a/src/util/lp/binary_heap_upair_queue_instances.cpp +++ b/src/util/lp/binary_heap_upair_queue_instances.cpp @@ -1,9 +1,24 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/binary_heap_upair_queue.hpp" -namespace lean { +namespace lp { template binary_heap_upair_queue::binary_heap_upair_queue(unsigned int); template binary_heap_upair_queue::binary_heap_upair_queue(unsigned int); template unsigned binary_heap_upair_queue::dequeue_available_spot(); diff --git a/src/util/lp/bound_analyzer_on_row.h b/src/util/lp/bound_analyzer_on_row.h index 508692e5a..52b8ece64 100644 --- a/src/util/lp/bound_analyzer_on_row.h +++ b/src/util/lp/bound_analyzer_on_row.h @@ -1,24 +1,39 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include "util/lp/linear_combination_iterator.h" -#include "implied_bound.h" -#include "test_bound_analyzer.h" +#include "util/lp/implied_bound.h" +#include "util/lp/test_bound_analyzer.h" #include -#include "util/lp/bound_propagator.h" +#include "util/lp/lp_bound_propagator.h" // We have an equality : sum by j of row[j]*x[j] = rs // We try to pin a var by pushing the total by using the variable bounds // In a loop we drive the partial sum down, denoting the variables of this process by _u. // In the same loop trying to pin variables by pushing the partial sum up, denoting the variable related to it by _l -namespace lean { +namespace lp { class bound_analyzer_on_row { - + linear_combination_iterator & m_it; - bound_propagator & m_bp; + lp_bound_propagator & m_bp; unsigned m_row_or_term_index; int m_column_of_u; // index of an unlimited from above monoid // -1 means that such a value is not found, -2 means that at least two of such monoids were found @@ -31,7 +46,7 @@ public : linear_combination_iterator &it, const numeric_pair& rs, unsigned row_or_term_index, - bound_propagator & bp + lp_bound_propagator & bp ) : m_it(it), @@ -45,7 +60,7 @@ public : unsigned j; void analyze() { - + mpq a; unsigned j; while (((m_column_of_l != -2) || (m_column_of_u != -2)) && m_it.next(a, j)) analyze_bound_on_var_on_coeff(j, a); @@ -91,11 +106,11 @@ public : } const impq & ub(unsigned j) const { - lean_assert(upper_bound_is_available(j)); + SASSERT(upper_bound_is_available(j)); return m_bp.get_upper_bound(j); } const impq & lb(unsigned j) const { - lean_assert(low_bound_is_available(j)); + SASSERT(low_bound_is_available(j)); return m_bp.get_low_bound(j); } @@ -114,29 +129,29 @@ public : } return a * lb(j).x; } - mpq monoid_max(const mpq & a, unsigned j, bool & strict) const { - if (is_pos(a)) { - strict = !is_zero(ub(j).y); - return a * ub(j).x; - } - strict = !is_zero(lb(j).y); - return a * lb(j).x; - } - const mpq & monoid_min_no_mult(bool a_is_pos, unsigned j, bool & strict) const { - if (!a_is_pos) { - strict = !is_zero(ub(j).y); - return ub(j).x; - } - strict = !is_zero(lb(j).y); - return lb(j).x; - } + mpq monoid_max(const mpq & a, unsigned j, bool & strict) const { + if (is_pos(a)) { + strict = !is_zero(ub(j).y); + return a * ub(j).x; + } + strict = !is_zero(lb(j).y); + return a * lb(j).x; + } + const mpq & monoid_min_no_mult(bool a_is_pos, unsigned j, bool & strict) const { + if (!a_is_pos) { + strict = !is_zero(ub(j).y); + return ub(j).x; + } + strict = !is_zero(lb(j).y); + return lb(j).x; + } mpq monoid_min(const mpq & a, unsigned j, bool& strict) const { if (is_neg(a)) { strict = !is_zero(ub(j).y); return a * ub(j).x; } - + strict = !is_zero(lb(j).y); return a * lb(j).x; } @@ -145,15 +160,15 @@ public : if (is_neg(a)) { return a * ub(j).x; } - + return a * lb(j).x; } - + void limit_all_monoids_from_above() { int strict = 0; mpq total; - lean_assert(is_zero(total)); + SASSERT(is_zero(total)); m_it.reset(); mpq a; unsigned j; while (m_it.next(a, j)) { @@ -166,7 +181,7 @@ public : m_it.reset(); while (m_it.next(a, j)) { bool str; - bool a_is_pos = is_pos(a); + bool a_is_pos = is_pos(a); mpq bound = total / a + monoid_min_no_mult(a_is_pos, j, str); if (a_is_pos) { limit_j(j, bound, true, false, strict - static_cast(str) > 0); @@ -180,7 +195,7 @@ public : void limit_all_monoids_from_below() { int strict = 0; mpq total; - lean_assert(is_zero(total)); + SASSERT(is_zero(total)); m_it.reset(); mpq a; unsigned j; while (m_it.next(a, j)) { @@ -192,9 +207,9 @@ public : m_it.reset(); while (m_it.next(a, j)) { bool str; - bool a_is_pos = is_pos(a); - mpq bound = total / a + monoid_max_no_mult(a_is_pos, j, str); - bool astrict = strict - static_cast(str) > 0; + bool a_is_pos = is_pos(a); + mpq bound = total / a + monoid_max_no_mult(a_is_pos, j, str); + bool astrict = strict - static_cast(str) > 0; if (a_is_pos) { limit_j(j, bound, true, true, astrict); } @@ -204,7 +219,7 @@ public : } } - + void limit_monoid_u_from_below() { // we are going to limit from below the monoid m_column_of_u, // every other monoid is impossible to limit from below @@ -225,7 +240,7 @@ public : } bound /= u_coeff; - + if (numeric_traits::is_pos(u_coeff)) { limit_j(m_column_of_u, bound, true, true, strict); } else { @@ -260,7 +275,7 @@ public : limit_j(m_column_of_l, bound, false, true, strict); } } - + // // it is the coefficent before the bounded column // void provide_evidence(bool coeff_is_pos) { // /* @@ -272,7 +287,7 @@ public : // mpq a; unsigned j; // while (it->next(a, j)) { // if (be.m_j == j) continue; - // lean_assert(bound_is_available(j, is_neg(a) ? low_bound : !low_bound)); + // SASSERT(bound_is_available(j, is_neg(a) ? low_bound : !low_bound)); // be.m_vector_of_bound_signatures.emplace_back(a, j, numeric_traits:: // is_neg(a)? low_bound: !low_bound); // } @@ -284,27 +299,27 @@ public : m_bp.try_add_bound(u, j, is_low_bound, coeff_before_j_is_pos, m_row_or_term_index, strict); } - + void advance_u(unsigned j) { if (m_column_of_u == -1) m_column_of_u = j; else m_column_of_u = -2; } - + void advance_l(unsigned j) { if (m_column_of_l == -1) m_column_of_l = j; else m_column_of_l = -2; } - + void analyze_bound_on_var_on_coeff(int j, const mpq &a) { switch (m_bp.get_column_type(j)) { case column_type::low_bound: if (numeric_traits::is_pos(a)) advance_u(j); - else + else advance_l(j); break; case column_type::upper_bound: @@ -325,7 +340,7 @@ public : static void analyze_row(linear_combination_iterator &it, const numeric_pair& rs, unsigned row_or_term_index, - bound_propagator & bp + lp_bound_propagator & bp ) { bound_analyzer_on_row a(it, rs, row_or_term_index, bp); a.analyze(); diff --git a/src/util/lp/bound_propagator.cpp b/src/util/lp/bound_propagator.cpp deleted file mode 100644 index 0d58ec2be..000000000 --- a/src/util/lp/bound_propagator.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ -#include "util/lp/lar_solver.h" -namespace lean { -bound_propagator::bound_propagator(lar_solver & ls): - m_lar_solver(ls) {} -column_type bound_propagator::get_column_type(unsigned j) const { - return m_lar_solver.m_mpq_lar_core_solver.m_column_types()[j]; -} -const impq & bound_propagator::get_low_bound(unsigned j) const { - return m_lar_solver.m_mpq_lar_core_solver.m_r_low_bounds()[j]; -} -const impq & bound_propagator::get_upper_bound(unsigned j) const { - return m_lar_solver.m_mpq_lar_core_solver.m_r_upper_bounds()[j]; -} -void bound_propagator::try_add_bound(const mpq & v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict) { - j = m_lar_solver.adjust_column_index_to_term_index(j); - lconstraint_kind kind = is_low? GE : LE; - if (strict) - kind = static_cast(kind / 2); - - if (!bound_is_interesting(j, kind, v)) - return; - unsigned k; // index to ibounds - if (is_low) { - if (try_get_val(m_improved_low_bounds, j, k)) { - auto & found_bound = m_ibounds[k]; - if (v > found_bound.m_bound || (v == found_bound.m_bound && found_bound.m_strict == false && strict)) - found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict); - } else { - m_improved_low_bounds[j] = m_ibounds.size(); - m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict)); - } - } else { // the upper bound case - if (try_get_val(m_improved_upper_bounds, j, k)) { - auto & found_bound = m_ibounds[k]; - if (v < found_bound.m_bound || (v == found_bound.m_bound && found_bound.m_strict == false && strict)) - found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict); - } else { - m_improved_upper_bounds[j] = m_ibounds.size(); - m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict)); - } - } -} -} diff --git a/src/util/lp/breakpoint.h b/src/util/lp/breakpoint.h index e5454db0e..40fab293f 100644 --- a/src/util/lp/breakpoint.h +++ b/src/util/lp/breakpoint.h @@ -1,11 +1,26 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once -namespace lean { +namespace lp { enum breakpoint_type { low_break, upper_break, fixed_break }; diff --git a/src/util/lp/column_info.h b/src/util/lp/column_info.h index 56e75a1fb..e4b449bbf 100644 --- a/src/util/lp/column_info.h +++ b/src/util/lp/column_info.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" @@ -9,7 +24,7 @@ #include #include #include "util/lp/lp_settings.h" -namespace lean { +namespace lp { inline bool is_valid(unsigned j) { return static_cast(j) >= 0;} template @@ -100,11 +115,11 @@ public: } T get_low_bound() const { - lean_assert(m_low_bound_is_set); + SASSERT(m_low_bound_is_set); return m_low_bound; } T get_upper_bound() const { - lean_assert(m_upper_bound_is_set); + SASSERT(m_upper_bound_is_set); return m_upper_bound; } @@ -156,7 +171,7 @@ public: } T get_fixed_value() const { - lean_assert(m_is_fixed); + SASSERT(m_is_fixed); return m_fixed_value; } diff --git a/src/util/lp/column_namer.h b/src/util/lp/column_namer.h index 1a10a5a23..97d371f48 100644 --- a/src/util/lp/column_namer.h +++ b/src/util/lp/column_namer.h @@ -1,11 +1,26 @@ #pragma once -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/lp/linear_combination_iterator.h" -namespace lean { +namespace lp { class column_namer { public: virtual std::string get_column_name(unsigned j) const = 0; @@ -15,7 +30,7 @@ public: T a; unsigned i; while (it->next(a, i)) { - coeff.emplace_back(a, i); + coeff.push_back(std::make_pair(a, i)); } print_linear_combination_of_column_indices(coeff, out); } diff --git a/src/util/lp/conversion_helper.h b/src/util/lp/conversion_helper.h index bff2ad563..f80b1c2c6 100644 --- a/src/util/lp/conversion_helper.h +++ b/src/util/lp/conversion_helper.h @@ -1,10 +1,25 @@ -/* - Copyright (c) 2013 Microsoft Corporation. All rights reserved. +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ - Author: Lev Nachmanson -*/ #pragma once -namespace lean { +namespace lp { template struct conversion_helper { static V get_low_bound(const column_info & ci) { diff --git a/src/util/lp/core_solver_pretty_printer.h b/src/util/lp/core_solver_pretty_printer.h index 2a3a14b31..20b2c1cbe 100644 --- a/src/util/lp/core_solver_pretty_printer.h +++ b/src/util/lp/core_solver_pretty_printer.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include #include @@ -10,7 +25,7 @@ #include #include "util/lp/lp_settings.h" #include "util/lp/indexed_vector.h" -namespace lean { +namespace lp { template class lp_core_solver_base; // forward definition template diff --git a/src/util/lp/core_solver_pretty_printer.hpp b/src/util/lp/core_solver_pretty_printer.hpp index 786b8b3a1..4ae49a550 100644 --- a/src/util/lp/core_solver_pretty_printer.hpp +++ b/src/util/lp/core_solver_pretty_printer.hpp @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include @@ -9,7 +24,7 @@ #include "util/lp/lp_core_solver_base.h" #include "util/lp/core_solver_pretty_printer.h" #include "util/lp/numeric_pair.h" -namespace lean { +namespace lp { template @@ -148,7 +163,7 @@ template void core_solver_pretty_printer::adjust_ case column_type::free_column: break; default: - lean_assert(false); + SASSERT(false); break; } } @@ -357,7 +372,7 @@ template void core_solver_pretty_printer::print_g unsigned width = m_column_widths[col]; string s = row[col]; int number_of_blanks = width - static_cast(s.size()); - lean_assert(number_of_blanks >= 0); + SASSERT(number_of_blanks >= 0); print_blanks(number_of_blanks, m_out); m_out << s << ' '; if (col < row.size() - 1) { @@ -368,7 +383,7 @@ template void core_solver_pretty_printer::print_g string rs = T_to_string(rst); int nb = m_rs_width - static_cast(rs.size()); - lean_assert(nb >= 0); + SASSERT(nb >= 0); print_blanks(nb + 1, m_out); m_out << rs << std::endl; } diff --git a/src/util/lp/core_solver_pretty_printer_instances.cpp b/src/util/lp/core_solver_pretty_printer_instances.cpp index cfa72f725..0bd7f5559 100644 --- a/src/util/lp/core_solver_pretty_printer_instances.cpp +++ b/src/util/lp/core_solver_pretty_printer_instances.cpp @@ -1,15 +1,30 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/numeric_pair.h" #include "util/lp/core_solver_pretty_printer.hpp" -template lean::core_solver_pretty_printer::core_solver_pretty_printer(lean::lp_core_solver_base &, std::ostream & out); -template void lean::core_solver_pretty_printer::print(); -template lean::core_solver_pretty_printer::~core_solver_pretty_printer(); -template lean::core_solver_pretty_printer::core_solver_pretty_printer(lean::lp_core_solver_base &, std::ostream & out); -template void lean::core_solver_pretty_printer::print(); -template lean::core_solver_pretty_printer::~core_solver_pretty_printer(); -template lean::core_solver_pretty_printer >::core_solver_pretty_printer(lean::lp_core_solver_base > &, std::ostream & out); -template lean::core_solver_pretty_printer >::~core_solver_pretty_printer(); -template void lean::core_solver_pretty_printer >::print(); +template lp::core_solver_pretty_printer::core_solver_pretty_printer(lp::lp_core_solver_base &, std::ostream & out); +template void lp::core_solver_pretty_printer::print(); +template lp::core_solver_pretty_printer::~core_solver_pretty_printer(); +template lp::core_solver_pretty_printer::core_solver_pretty_printer(lp::lp_core_solver_base &, std::ostream & out); +template void lp::core_solver_pretty_printer::print(); +template lp::core_solver_pretty_printer::~core_solver_pretty_printer(); +template lp::core_solver_pretty_printer >::core_solver_pretty_printer(lp::lp_core_solver_base > &, std::ostream & out); +template lp::core_solver_pretty_printer >::~core_solver_pretty_printer(); +template void lp::core_solver_pretty_printer >::print(); diff --git a/src/util/lp/dense_matrix.h b/src/util/lp/dense_matrix.h index 233f74016..6b157ffd4 100644 --- a/src/util/lp/dense_matrix.h +++ b/src/util/lp/dense_matrix.h @@ -1,12 +1,27 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG #include "util/vector.h" #include "util/lp/matrix.h" -namespace lean { +namespace lp { // used for debugging purposes only template class dense_matrix: public matrix { @@ -31,7 +46,7 @@ public: dense_matrix(unsigned m, unsigned n); dense_matrix operator*=(matrix const & a) { - lean_assert(column_count() == a.row_count()); + SASSERT(column_count() == a.row_count()); dense_matrix c(row_count(), a.column_count()); for (unsigned i = 0; i < row_count(); i++) { for (unsigned j = 0; j < a.column_count(); j++) { diff --git a/src/util/lp/dense_matrix.hpp b/src/util/lp/dense_matrix.hpp index e42d9e3a4..a1f815109 100644 --- a/src/util/lp/dense_matrix.hpp +++ b/src/util/lp/dense_matrix.hpp @@ -1,13 +1,28 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/lp_settings.h" -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG #include "util/vector.h" #include "util/lp/numeric_pair.h" #include "util/lp/dense_matrix.h" -namespace lean { +namespace lp { template void print_vector(const vector & t, std::ostream & out); template dense_matrix::dense_matrix(unsigned m, unsigned n) : m_m(m), m_n(n), m_values(m * n, numeric_traits::zero()) { } @@ -170,7 +185,7 @@ template void dense_matrix::multiply_row_by_const template dense_matrix operator* (matrix & a, matrix & b){ - lean_assert(a.column_count() == b.row_count()); + SASSERT(a.column_count() == b.row_count()); dense_matrix ret(a.row_count(), b.column_count()); for (unsigned i = 0; i < ret.m_m; i++) for (unsigned j = 0; j< ret.m_n; j++) { diff --git a/src/util/lp/dense_matrix_instances.cpp b/src/util/lp/dense_matrix_instances.cpp index 95ba01801..54b0d15d6 100644 --- a/src/util/lp/dense_matrix_instances.cpp +++ b/src/util/lp/dense_matrix_instances.cpp @@ -1,25 +1,40 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/lp_settings.h" #include "util/lp/dense_matrix.hpp" -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG #include "util/vector.h" -template lean::dense_matrix lean::operator*(lean::matrix&, lean::matrix&); -template void lean::dense_matrix::apply_from_left(vector &); -template lean::dense_matrix::dense_matrix(lean::matrix const*); -template lean::dense_matrix::dense_matrix(unsigned int, unsigned int); -template lean::dense_matrix& lean::dense_matrix::operator=(lean::dense_matrix const&); -template lean::dense_matrix::dense_matrix(unsigned int, unsigned int); -template lean::dense_matrix >::dense_matrix(lean::matrix > const*); -template void lean::dense_matrix >::apply_from_left(vector&); -template lean::dense_matrix lean::operator*(lean::matrix&, lean::matrix&); -template lean::dense_matrix & lean::dense_matrix::operator=(lean::dense_matrix const&); -template lean::dense_matrix >::dense_matrix(unsigned int, unsigned int); -template lean::dense_matrix >& lean::dense_matrix >::operator=(lean::dense_matrix > const&); -template lean::dense_matrix > lean::operator* >(lean::matrix >&, lean::matrix >&); -template void lean::dense_matrix >::apply_from_right( vector< lean::mpq> &); -template void lean::dense_matrix::apply_from_right(class vector &); -template void lean::dense_matrix::apply_from_left(vector&); +template lp::dense_matrix lp::operator*(lp::matrix&, lp::matrix&); +template void lp::dense_matrix::apply_from_left(vector &); +template lp::dense_matrix::dense_matrix(lp::matrix const*); +template lp::dense_matrix::dense_matrix(unsigned int, unsigned int); +template lp::dense_matrix& lp::dense_matrix::operator=(lp::dense_matrix const&); +template lp::dense_matrix::dense_matrix(unsigned int, unsigned int); +template lp::dense_matrix >::dense_matrix(lp::matrix > const*); +template void lp::dense_matrix >::apply_from_left(vector&); +template lp::dense_matrix lp::operator*(lp::matrix&, lp::matrix&); +template lp::dense_matrix & lp::dense_matrix::operator=(lp::dense_matrix const&); +template lp::dense_matrix >::dense_matrix(unsigned int, unsigned int); +template lp::dense_matrix >& lp::dense_matrix >::operator=(lp::dense_matrix > const&); +template lp::dense_matrix > lp::operator* >(lp::matrix >&, lp::matrix >&); +template void lp::dense_matrix >::apply_from_right( vector< lp::mpq> &); +template void lp::dense_matrix::apply_from_right(class vector &); +template void lp::dense_matrix::apply_from_left(vector&); #endif diff --git a/src/util/lp/eta_matrix.h b/src/util/lp/eta_matrix.h index 51b015066..6c30e2146 100644 --- a/src/util/lp/eta_matrix.h +++ b/src/util/lp/eta_matrix.h @@ -1,32 +1,47 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include "util/lp/tail_matrix.h" #include "util/lp/permutation_matrix.h" -namespace lean { +namespace lp { // This is the sum of a unit matrix and a one-column matrix template class eta_matrix : public tail_matrix { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG unsigned m_length; #endif unsigned m_column_index; public: sparse_vector m_column_vector; T m_diagonal_element; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG eta_matrix(unsigned column_index, unsigned length): #else eta_matrix(unsigned column_index): #endif -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG m_length(length), #endif m_column_index(column_index) {} @@ -61,7 +76,7 @@ public: void push_back(unsigned row_index, T val ) { - lean_assert(row_index != m_column_index); + SASSERT(row_index != m_column_index); m_column_vector.push_back(row_index, val); } @@ -69,7 +84,7 @@ public: void apply_from_right(indexed_vector & w); T get_elem(unsigned i, unsigned j) const; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG unsigned row_count() const { return m_length; } unsigned column_count() const { return m_length; } void set_number_of_rows(unsigned m) { m_length = m; } diff --git a/src/util/lp/eta_matrix.hpp b/src/util/lp/eta_matrix.hpp index 142a408d1..ae4ed712e 100644 --- a/src/util/lp/eta_matrix.hpp +++ b/src/util/lp/eta_matrix.hpp @@ -1,12 +1,27 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include "util/lp/eta_matrix.h" -namespace lean { +namespace lp { // This is the sum of a unit matrix and a one-column matrix template @@ -49,7 +64,7 @@ apply_from_left_local(indexed_vector & w, lp_settings & settings) { } template void eta_matrix::apply_from_right(vector & w) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // dense_matrix deb(*this); // auto clone_w = clone_vector(w, get_number_of_rows()); // deb.apply_from_right(clone_w); @@ -59,8 +74,8 @@ void eta_matrix::apply_from_right(vector & w) { t += w[it.first] * it.second; } w[m_column_index] = t; -#ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(clone_w, w, get_number_of_rows())); +#ifdef Z3DEBUG + // SASSERT(vectors_are_equal(clone_w, w, get_number_of_rows())); // delete clone_w; #endif } @@ -68,7 +83,7 @@ template void eta_matrix::apply_from_right(indexed_vector & w) { if (w.m_index.size() == 0) return; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // vector wcopy(w.m_data); // apply_from_right(wcopy); #endif @@ -99,12 +114,12 @@ void eta_matrix::apply_from_right(indexed_vector & w) { } } -#ifdef LEAN_DEBUG - // lean_assert(w.is_OK()); - // lean_assert(vectors_are_equal(wcopy, w.m_data)); +#ifdef Z3DEBUG + // SASSERT(w.is_OK()); + // SASSERT(vectors_are_equal(wcopy, w.m_data)); #endif } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template T eta_matrix::get_elem(unsigned i, unsigned j) const { if (j == m_column_index){ @@ -120,7 +135,7 @@ T eta_matrix::get_elem(unsigned i, unsigned j) const { template void eta_matrix::conjugate_by_permutation(permutation_matrix & p) { // this = p * this * p(-1) -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // auto rev = p.get_reverse(); // auto deb = ((*this) * rev); // deb = p * deb; @@ -129,8 +144,8 @@ void eta_matrix::conjugate_by_permutation(permutation_matrix & p) { for (auto & pair : m_column_vector.m_data) { pair.first = p.get_rev(pair.first); } -#ifdef LEAN_DEBUG - // lean_assert(deb == *this); +#ifdef Z3DEBUG + // SASSERT(deb == *this); #endif } } diff --git a/src/util/lp/eta_matrix_instances.cpp b/src/util/lp/eta_matrix_instances.cpp index d57d43fed..87e12c913 100644 --- a/src/util/lp/eta_matrix_instances.cpp +++ b/src/util/lp/eta_matrix_instances.cpp @@ -1,28 +1,43 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/vector.h" #include "util/lp/numeric_pair.h" #include "util/lp/eta_matrix.hpp" -#ifdef LEAN_DEBUG -template double lean::eta_matrix::get_elem(unsigned int, unsigned int) const; -template lean::mpq lean::eta_matrix::get_elem(unsigned int, unsigned int) const; -template lean::mpq lean::eta_matrix >::get_elem(unsigned int, unsigned int) const; +#ifdef Z3DEBUG +template double lp::eta_matrix::get_elem(unsigned int, unsigned int) const; +template lp::mpq lp::eta_matrix::get_elem(unsigned int, unsigned int) const; +template lp::mpq lp::eta_matrix >::get_elem(unsigned int, unsigned int) const; #endif -template void lean::eta_matrix::apply_from_left(vector&, lean::lp_settings&); -template void lean::eta_matrix::apply_from_right(vector&); -template void lean::eta_matrix::conjugate_by_permutation(lean::permutation_matrix&); -template void lean::eta_matrix::apply_from_left(vector&, lean::lp_settings&); -template void lean::eta_matrix::apply_from_right(vector&); -template void lean::eta_matrix::conjugate_by_permutation(lean::permutation_matrix&); -template void lean::eta_matrix >::apply_from_left(vector >&, lean::lp_settings&); -template void lean::eta_matrix >::apply_from_right(vector&); -template void lean::eta_matrix >::conjugate_by_permutation(lean::permutation_matrix >&); -template void lean::eta_matrix::apply_from_left_local(lean::indexed_vector&, lean::lp_settings&); -template void lean::eta_matrix::apply_from_left_local(lean::indexed_vector&, lean::lp_settings&); -template void lean::eta_matrix >::apply_from_left_local(lean::indexed_vector&, lean::lp_settings&); -template void lean::eta_matrix >::apply_from_right(lean::indexed_vector&); -template void lean::eta_matrix::apply_from_right(lean::indexed_vector&); -template void lean::eta_matrix::apply_from_right(lean::indexed_vector&); +template void lp::eta_matrix::apply_from_left(vector&, lp::lp_settings&); +template void lp::eta_matrix::apply_from_right(vector&); +template void lp::eta_matrix::conjugate_by_permutation(lp::permutation_matrix&); +template void lp::eta_matrix::apply_from_left(vector&, lp::lp_settings&); +template void lp::eta_matrix::apply_from_right(vector&); +template void lp::eta_matrix::conjugate_by_permutation(lp::permutation_matrix&); +template void lp::eta_matrix >::apply_from_left(vector >&, lp::lp_settings&); +template void lp::eta_matrix >::apply_from_right(vector&); +template void lp::eta_matrix >::conjugate_by_permutation(lp::permutation_matrix >&); +template void lp::eta_matrix::apply_from_left_local(lp::indexed_vector&, lp::lp_settings&); +template void lp::eta_matrix::apply_from_left_local(lp::indexed_vector&, lp::lp_settings&); +template void lp::eta_matrix >::apply_from_left_local(lp::indexed_vector&, lp::lp_settings&); +template void lp::eta_matrix >::apply_from_right(lp::indexed_vector&); +template void lp::eta_matrix::apply_from_right(lp::indexed_vector&); +template void lp::eta_matrix::apply_from_right(lp::indexed_vector&); diff --git a/src/util/lp/hash_helper.h b/src/util/lp/hash_helper.h index 6fe31d5cd..ab5fa844b 100644 --- a/src/util/lp/hash_helper.h +++ b/src/util/lp/hash_helper.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include #include @@ -12,8 +27,8 @@ #endif namespace std { template<> -struct hash { - inline size_t operator()(const lean::mpq & v) const { +struct hash { + inline size_t operator()(const lp::mpq & v) const { return v.hash(); } }; diff --git a/src/util/lp/implied_bound.h b/src/util/lp/implied_bound.h index 9583e3cd8..f1c711ffa 100644 --- a/src/util/lp/implied_bound.h +++ b/src/util/lp/implied_bound.h @@ -1,11 +1,26 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/lp/lp_settings.h" #include "util/lp/lar_constraints.h" -namespace lean { +namespace lp { struct implied_bound { mpq m_bound; unsigned m_j; // the column for which the bound has been found diff --git a/src/util/lp/indexed_value.h b/src/util/lp/indexed_value.h index 7963dfdf9..216a6f953 100644 --- a/src/util/lp/indexed_value.h +++ b/src/util/lp/indexed_value.h @@ -1,10 +1,25 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once -namespace lean { +namespace lp { template class indexed_value { public: @@ -41,7 +56,7 @@ public: m_value = val; } }; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template bool check_vector_for_small_values(indexed_vector & w, lp_settings & settings) { for (unsigned i : w.m_index) { diff --git a/src/util/lp/indexed_vector.h b/src/util/lp/indexed_vector.h index 6e6a6009b..3b1258ed7 100644 --- a/src/util/lp/indexed_vector.h +++ b/src/util/lp/indexed_vector.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" @@ -11,7 +26,7 @@ #include "util/lp/lp_utils.h" #include "util/lp/lp_settings.h" #include -namespace lean { +namespace lp { template void print_vector(const vector & t, std::ostream & out); template void print_vector(const buffer & t, std::ostream & out); @@ -76,7 +91,7 @@ public: void set_value(const T& value, unsigned index); void set_value_as_in_dictionary(unsigned index) { - lean_assert(index < m_data.size()); + SASSERT(index < m_data.size()); T & loc = m_data[index]; if (is_zero(loc)) { m_index.push_back(index); @@ -161,7 +176,7 @@ public: } } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG bool is_OK() const; void print(std::ostream & out); #endif diff --git a/src/util/lp/indexed_vector.hpp b/src/util/lp/indexed_vector.hpp index 64e329adc..73055d6da 100644 --- a/src/util/lp/indexed_vector.hpp +++ b/src/util/lp/indexed_vector.hpp @@ -1,11 +1,26 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/vector.h" #include "util/lp/indexed_vector.h" #include "util/lp/lp_settings.h" -namespace lean { +namespace lp { template void print_vector(const vector & t, std::ostream & out) { @@ -41,13 +56,13 @@ template void indexed_vector::resize(unsigned data_size) { clear(); m_data.resize(data_size, numeric_traits::zero()); - lean_assert(is_OK()); + SASSERT(is_OK()); } template void indexed_vector::set_value(const T& value, unsigned index) { m_data[index] = value; - lean_assert(std::find(m_index.begin(), m_index.end(), index) == m_index.end()); + SASSERT(std::find(m_index.begin(), m_index.end(), index) == m_index.end()); m_index.push_back(index); } @@ -70,7 +85,7 @@ void indexed_vector::erase_from_index(unsigned j) { m_index.erase(it); } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template bool indexed_vector::is_OK() const { return true; diff --git a/src/util/lp/indexed_vector_instances.cpp b/src/util/lp/indexed_vector_instances.cpp index 6f17a894f..79c3ee1a1 100644 --- a/src/util/lp/indexed_vector_instances.cpp +++ b/src/util/lp/indexed_vector_instances.cpp @@ -1,10 +1,25 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/vector.h" #include "util/lp/indexed_vector.hpp" -namespace lean { +namespace lp { template void indexed_vector::clear(); template void indexed_vector::clear_all(); template void indexed_vector::erase_from_index(unsigned int); @@ -17,20 +32,21 @@ template void indexed_vector::resize(unsigned int); template void indexed_vector::resize(unsigned int); template void indexed_vector::set_value(const mpq&, unsigned int); template void indexed_vector::set_value(const unsigned&, unsigned int); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG +template bool indexed_vector::is_OK() const; template bool indexed_vector::is_OK() const; template bool indexed_vector::is_OK() const; -template bool indexed_vector >::is_OK() const; -template void lean::indexed_vector< lean::mpq>::print(std::basic_ostream > &); -template void lean::indexed_vector::print(std::basic_ostream > &); -template void lean::indexed_vector >::print(std::ostream&); +template bool indexed_vector >::is_OK() const; +template void lp::indexed_vector< lp::mpq>::print(std::basic_ostream > &); +template void lp::indexed_vector::print(std::basic_ostream > &); +template void lp::indexed_vector >::print(std::ostream&); #endif } -template void lean::print_vector(vector const&, std::ostream&); -template void lean::print_vector(vector const&, std::ostream&); -template void lean::print_vector(vector const&, std::ostream&); -template void lean::print_vector >(vector> const&, std::ostream&); -template void lean::indexed_vector::resize(unsigned int); -template void lean::print_vector< lean::mpq>(vector< lean::mpq> const &, std::basic_ostream > &); -template void lean::print_vector >(vector> const&, std::ostream&); -template void lean::indexed_vector >::erase_from_index(unsigned int); +template void lp::print_vector(vector const&, std::ostream&); +template void lp::print_vector(vector const&, std::ostream&); +template void lp::print_vector(vector const&, std::ostream&); +template void lp::print_vector >(vector> const&, std::ostream&); +template void lp::indexed_vector::resize(unsigned int); +template void lp::print_vector< lp::mpq>(vector< lp::mpq> const &, std::basic_ostream > &); +template void lp::print_vector >(vector> const&, std::ostream&); +template void lp::indexed_vector >::erase_from_index(unsigned int); diff --git a/src/util/lp/init_lar_solver.h b/src/util/lp/init_lar_solver.h index 3fc29f25b..5d78c3ba7 100644 --- a/src/util/lp/init_lar_solver.h +++ b/src/util/lp/init_lar_solver.h @@ -1,9 +1,24 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation -// here we are inside lean::lar_solver class +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ + +// here we are inside lp::lar_solver class bool strategy_is_undecided() const { return m_settings.simplex_strategy() == simplex_strategy_enum::undecided; @@ -11,7 +26,7 @@ bool strategy_is_undecided() const { var_index add_var(unsigned ext_j) { var_index i; - lean_assert (ext_j < m_terms_start_index); + SASSERT (ext_j < m_terms_start_index); if (ext_j >= m_terms_start_index) throw 0; // todo : what is the right way to exit? @@ -19,19 +34,19 @@ var_index add_var(unsigned ext_j) { if (try_get_val(m_ext_vars_to_columns, ext_j, i)) { return i; } - lean_assert(m_vars_to_ul_pairs.size() == A_r().column_count()); + SASSERT(m_vars_to_ul_pairs.size() == A_r().column_count()); i = A_r().column_count(); m_vars_to_ul_pairs.push_back (ul_pair(static_cast(-1))); add_non_basic_var_to_core_fields(ext_j); - lean_assert(sizes_are_correct()); + SASSERT(sizes_are_correct()); return i; } void register_new_ext_var_index(unsigned ext_v) { - lean_assert(!contains(m_ext_vars_to_columns, ext_v)); + SASSERT(!contains(m_ext_vars_to_columns, ext_v)); unsigned j = static_cast(m_ext_vars_to_columns.size()); m_ext_vars_to_columns[ext_v] = j; - lean_assert(m_columns_to_ext_vars_or_term_indices.size() == j); + SASSERT(m_columns_to_ext_vars_or_term_indices.size() == j); m_columns_to_ext_vars_or_term_indices.push_back(ext_v); } @@ -47,12 +62,12 @@ void add_non_basic_var_to_core_fields(unsigned ext_j) { void add_new_var_to_core_fields_for_doubles(bool register_in_basis) { unsigned j = A_d().column_count(); A_d().add_column(); - lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j); - // lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later + SASSERT(m_mpq_lar_core_solver.m_d_x.size() == j); + // SASSERT(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); - lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method + SASSERT(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method if (register_in_basis) { A_d().add_row(); m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); @@ -66,15 +81,15 @@ void add_new_var_to_core_fields_for_doubles(bool register_in_basis) { void add_new_var_to_core_fields_for_mpq(bool register_in_basis) { unsigned j = A_r().column_count(); A_r().add_column(); - lean_assert(m_mpq_lar_core_solver.m_r_x.size() == j); - // lean_assert(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later + SASSERT(m_mpq_lar_core_solver.m_r_x.size() == j); + // SASSERT(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later m_mpq_lar_core_solver.m_r_x.resize(j + 1); m_mpq_lar_core_solver.m_r_low_bounds.increase_size_by_one(); m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one(); m_mpq_lar_core_solver.m_r_solver.m_inf_set.increase_size_by_one(); m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1); m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1); - lean_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method + SASSERT(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method if (register_in_basis) { A_r().add_row(); m_mpq_lar_core_solver.m_r_heading.push_back(m_mpq_lar_core_solver.m_r_basis.size()); @@ -110,20 +125,20 @@ var_index add_term(const vector> & coeffs, if (m_settings.bound_propagation()) m_rows_with_changed_bounds.insert(A_r().row_count() - 1); } - lean_assert(m_ext_vars_to_columns.size() == A_r().column_count()); + SASSERT(m_ext_vars_to_columns.size() == A_r().column_count()); return ret; } void add_row_for_term(const lar_term * term, unsigned term_ext_index) { - lean_assert(sizes_are_correct()); + SASSERT(sizes_are_correct()); add_row_from_term_no_constraint(term, term_ext_index); - lean_assert(sizes_are_correct()); + SASSERT(sizes_are_correct()); } void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) { register_new_ext_var_index(term_ext_index); // j will be a new variable - unsigned j = A_r().column_count(); + unsigned j = A_r().column_count(); ul_pair ul(j); m_vars_to_ul_pairs.push_back(ul); add_basic_var_to_core_fields(); @@ -142,7 +157,7 @@ void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_in void add_basic_var_to_core_fields() { bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver(); - lean_assert(!use_lu || A_r().column_count() == A_d().column_count()); + SASSERT(!use_lu || A_r().column_count() == A_d().column_count()); m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); m_columns_with_changed_bound.increase_size_by_one(); m_rows_with_changed_bounds.increase_size_by_one(); @@ -152,7 +167,7 @@ void add_basic_var_to_core_fields() { } constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) { - constraint_index ci = m_constraints.size(); + constraint_index ci = m_constraints.size(); if (!is_term(j)) { // j is a var auto vc = new lar_var_constraint(j, kind, right_side); m_constraints.push_back(vc); @@ -160,7 +175,7 @@ constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & r } else { add_var_bound_on_constraint_for_term(j, kind, right_side, ci); } - lean_assert(sizes_are_correct()); + SASSERT(sizes_are_correct()); return ci; } @@ -182,12 +197,12 @@ void update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq update_fixed_column_type_and_bound(j, kind, right_side, constr_index); break; default: - lean_assert(false); // cannot be here + SASSERT(false); // cannot be here } } void add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(is_term(j)); + SASSERT(is_term(j)); unsigned adjusted_term_index = adjust_term_index(j); unsigned term_j; if (try_get_val(m_ext_vars_to_columns, j, term_j)) { @@ -208,12 +223,12 @@ void add_constraint_from_term_and_create_new_column_row(unsigned term_j, const l unsigned j = A_r().column_count() - 1; update_column_type_and_bound(j, kind, right_side - term->m_v, m_constraints.size()); m_constraints.push_back(new lar_term_constraint(term, kind, right_side)); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + SASSERT(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); } void decide_on_strategy_and_adjust_initial_state() { - lean_assert(strategy_is_undecided()); - if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { + SASSERT(strategy_is_undecided()); + if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { m_settings.simplex_strategy() = simplex_strategy_enum::lu; } else { m_settings.simplex_strategy() = simplex_strategy_enum::tableau_rows; // todo: when to switch to tableau_costs? @@ -230,7 +245,7 @@ void adjust_initial_state() { adjust_initial_state_for_tableau_rows(); break; case simplex_strategy_enum::tableau_costs: - lean_assert(false); // not implemented + SASSERT(false); // not implemented case simplex_strategy_enum::undecided: adjust_initial_state_for_tableau_rows(); break; @@ -239,22 +254,22 @@ void adjust_initial_state() { void adjust_initial_state_for_lu() { copy_from_mpq_matrix(A_d()); - unsigned n = A_d().column_count(); - m_mpq_lar_core_solver.m_d_x.resize(n); - m_mpq_lar_core_solver.m_d_low_bounds.resize(n); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(n); - m_mpq_lar_core_solver.m_d_heading = m_mpq_lar_core_solver.m_r_heading; - m_mpq_lar_core_solver.m_d_basis = m_mpq_lar_core_solver.m_r_basis; + unsigned n = A_d().column_count(); + m_mpq_lar_core_solver.m_d_x.resize(n); + m_mpq_lar_core_solver.m_d_low_bounds.resize(n); + m_mpq_lar_core_solver.m_d_upper_bounds.resize(n); + m_mpq_lar_core_solver.m_d_heading = m_mpq_lar_core_solver.m_r_heading; + m_mpq_lar_core_solver.m_d_basis = m_mpq_lar_core_solver.m_r_basis; - /* + /* unsigned j = A_d().column_count(); A_d().add_column(); - lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j); - // lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later + SASSERT(m_mpq_lar_core_solver.m_d_x.size() == j); + // SASSERT(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); - lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method + SASSERT(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method if (register_in_basis) { A_d().add_row(); m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); @@ -275,13 +290,13 @@ void adjust_initial_state_for_tableau_rows() { // this fills the last row of A_d and sets the basis column: -1 in the last column of the row void fill_last_row_of_A_d(static_matrix & A, const lar_term* ls) { - lean_assert(A.row_count() > 0); - lean_assert(A.column_count() > 0); + SASSERT(A.row_count() > 0); + SASSERT(A.column_count() > 0); unsigned last_row = A.row_count() - 1; - lean_assert(A.m_rows[last_row].empty()); + SASSERT(A.m_rows[last_row].empty()); for (auto & t : ls->m_coeffs) { - lean_assert(!is_zero(t.second)); + SASSERT(!is_zero(t.second)); var_index j = t.first; A.set(last_row, j, - t.second.get_double()); } @@ -297,8 +312,8 @@ void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const y_of_bound = -1; case LE: m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound; - lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); - lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); + SASSERT(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); + SASSERT(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); { auto up = numeric_pair(right_side, y_of_bound); m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; @@ -309,7 +324,7 @@ void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const y_of_bound = 1; case GE: m_mpq_lar_core_solver.m_column_types[j] = column_type::low_bound; - lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); + SASSERT(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); { auto low = numeric_pair(right_side, y_of_bound); m_mpq_lar_core_solver.m_r_low_bounds[j] = low; @@ -324,14 +339,14 @@ void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const break; default: - lean_unreachable(); + SASSERT(false); } m_columns_with_changed_bound.insert(j); } void update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); + SASSERT(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); mpq y_of_bound(0); switch (kind) { case LT: @@ -382,13 +397,13 @@ void update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind break; default: - lean_unreachable(); + SASSERT(false); } } void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); + SASSERT(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); mpq y_of_bound(0); switch (kind) { case LT: @@ -404,7 +419,7 @@ void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, cons if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { m_status = INFEASIBLE; - lean_assert(false); + SASSERT(false); m_infeasible_column_index = j; } else { if (m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j]) @@ -453,12 +468,12 @@ void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, cons } default: - lean_unreachable(); + SASSERT(false); } } void update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound); + SASSERT(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound); mpq y_of_bound(0); switch (kind) { case LT: @@ -508,14 +523,14 @@ void update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, } default: - lean_unreachable(); + SASSERT(false); } } void update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); - lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); + SASSERT(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); + SASSERT(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); auto v = numeric_pair(right_side, mpq(0)); mpq y_of_bound(0); @@ -569,7 +584,7 @@ void update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, cons } default: - lean_unreachable(); + SASSERT(false); } } diff --git a/src/util/lp/int_set.h b/src/util/lp/int_set.h index 0619facd8..698b8bc49 100644 --- a/src/util/lp/int_set.h +++ b/src/util/lp/int_set.h @@ -1,12 +1,27 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include "util/lp/indexed_vector.h" #include -namespace lean { +namespace lp { // serves at a set of non-negative integers smaller than the set size class int_set { vector m_data; @@ -20,7 +35,7 @@ public: return m_data[j] >= 0; } void insert(unsigned j) { - lean_assert(j < m_data.size()); + SASSERT(j < m_data.size()); if (contains(j)) return; m_data[j] = m_index.size(); m_index.push_back(j); diff --git a/src/util/lp/iterator_on_column.h b/src/util/lp/iterator_on_column.h index 215514b39..5bb43f4c6 100644 --- a/src/util/lp/iterator_on_column.h +++ b/src/util/lp/iterator_on_column.h @@ -1,12 +1,27 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/lp/linear_combination_iterator.h" #include "util/lp/static_matrix.h" #include "util/lp/lar_term.h" -namespace lean { +namespace lp { template struct iterator_on_column:linear_combination_iterator { const vector& m_column; // the offset in term coeffs diff --git a/src/util/lp/iterator_on_indexed_vector.h b/src/util/lp/iterator_on_indexed_vector.h index 532b62617..2c8daf83b 100644 --- a/src/util/lp/iterator_on_indexed_vector.h +++ b/src/util/lp/iterator_on_indexed_vector.h @@ -1,10 +1,25 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/lp/linear_combination_iterator.h" -namespace lean { +namespace lp { template struct iterator_on_indexed_vector:linear_combination_iterator { const indexed_vector & m_v; diff --git a/src/util/lp/iterator_on_pivot_row.h b/src/util/lp/iterator_on_pivot_row.h index 1a9381a70..8aa498477 100644 --- a/src/util/lp/iterator_on_pivot_row.h +++ b/src/util/lp/iterator_on_pivot_row.h @@ -1,10 +1,25 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/lp/iterator_on_indexed_vector.h" -namespace lean { +namespace lp { template struct iterator_on_pivot_row:linear_combination_iterator { bool m_basis_returned; diff --git a/src/util/lp/iterator_on_row.h b/src/util/lp/iterator_on_row.h index 96a1a8cf3..1ac5b66bc 100644 --- a/src/util/lp/iterator_on_row.h +++ b/src/util/lp/iterator_on_row.h @@ -1,10 +1,25 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/lp/linear_combination_iterator.h" -namespace lean { +namespace lp { template struct iterator_on_row:linear_combination_iterator { const vector> & m_row; diff --git a/src/util/lp/iterator_on_term_with_basis_var.h b/src/util/lp/iterator_on_term_with_basis_var.h index 3dd217103..e566b92b5 100644 --- a/src/util/lp/iterator_on_term_with_basis_var.h +++ b/src/util/lp/iterator_on_term_with_basis_var.h @@ -1,12 +1,27 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/lp/linear_combination_iterator.h" #include "util/lp/numeric_pair.h" #include "util/lp/lar_term.h" -namespace lean { +namespace lp { struct iterator_on_term_with_basis_var:linear_combination_iterator { const lar_term & m_term; std::unordered_map::const_iterator m_i; // the offset in term coeffs diff --git a/src/util/lp/lar_constraints.h b/src/util/lp/lar_constraints.h index ee0864a4e..7b573bab7 100644 --- a/src/util/lp/lar_constraints.h +++ b/src/util/lp/lar_constraints.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" @@ -12,7 +27,7 @@ #include "util/lp/lp_utils.h" #include "util/lp/ul_pair.h" #include "util/lp/lar_term.h" -namespace lean { +namespace lp { inline lconstraint_kind flip_kind(lconstraint_kind t) { return static_cast( - static_cast(t)); } @@ -25,7 +40,7 @@ inline std::string lconstraint_kind_string(lconstraint_kind t) { case GT: return std::string(">"); case EQ: return std::string("="); } - lean_unreachable(); + SASSERT(false); return std::string(); // it is unreachable } @@ -74,7 +89,7 @@ public: : lar_base_constraint(kind, right_side), m_coeffs(left_side) {} lar_constraint(const lar_base_constraint & c) { - lean_assert(false); // should not be called : todo! + SASSERT(false); // should not be called : todo! } unsigned size() const { diff --git a/src/util/lp/lar_core_solver.h b/src/util/lp/lar_core_solver.h index 71d69c3a4..61b0d9b38 100644 --- a/src/util/lp/lar_core_solver.h +++ b/src/util/lp/lar_core_solver.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include @@ -18,7 +33,7 @@ #include "util/lp/iterator_on_column.h" #include "util/lp/iterator_on_indexed_vector.h" #include "util/lp/stacked_value.h" -namespace lean { +namespace lp { class lar_core_solver { // m_sign_of_entering is set to 1 if the entering variable needs @@ -168,9 +183,9 @@ public: } void push() { - lean_assert(m_r_solver.basis_heading_is_correct()); - lean_assert(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct()); - lean_assert(m_column_types.size() == m_r_A.column_count()); + SASSERT(m_r_solver.basis_heading_is_correct()); + SASSERT(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct()); + SASSERT(m_column_types.size() == m_r_A.column_count()); m_stacked_simplex_strategy = settings().simplex_strategy(); m_stacked_simplex_strategy.push(); m_column_types.push(); @@ -192,7 +207,7 @@ public: template void push_vector(stacked_vector & pushed_vector, const vector & vector) { - lean_assert(pushed_vector.size() <= vector.size()); + SASSERT(pushed_vector.size() <= vector.size()); for (unsigned i = 0; i < vector.size();i++) { if (i == pushed_vector.size()) { pushed_vector.push_back(vector[i]); @@ -242,8 +257,8 @@ public: pop_basis(k); m_stacked_simplex_strategy.pop(k); settings().simplex_strategy() = m_stacked_simplex_strategy; - lean_assert(m_r_solver.basis_heading_is_correct()); - lean_assert(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct()); + SASSERT(m_r_solver.basis_heading_is_correct()); + SASSERT(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct()); } bool need_to_presolve_with_double_solver() const { @@ -304,11 +319,11 @@ public: break; default: - lean_assert(false); + SASSERT(false); } break; default: - lean_unreachable(); + SASSERT(false); } m_r_solver.remove_column_from_inf_set(j); return true; @@ -317,7 +332,7 @@ public: void prepare_solver_x_with_signature_tableau(const lar_solution_signature & signature) { - lean_assert(m_r_solver.inf_set_is_correct()); + SASSERT(m_r_solver.inf_set_is_correct()); for (auto &t : signature) { unsigned j = t.first; if (m_r_heading[j] >= 0) @@ -332,9 +347,9 @@ public: m_r_solver.m_x[jb] -= delta * m_r_solver.m_A.get_val(cc); m_r_solver.update_column_in_inf_set(jb); } - lean_assert(m_r_solver.A_mult_x_is_off() == false); + SASSERT(m_r_solver.A_mult_x_is_off() == false); } - lean_assert(m_r_solver.inf_set_is_correct()); + SASSERT(m_r_solver.inf_set_is_correct()); } @@ -342,7 +357,7 @@ public: void prepare_solver_x_with_signature(const lar_solution_signature & signature, lp_primal_core_solver & s) { for (auto &t : signature) { unsigned j = t.first; - lean_assert(m_r_heading[j] < 0); + SASSERT(m_r_heading[j] < 0); auto pos_type = t.second; switch (pos_type) { case at_low_bound: @@ -359,7 +374,7 @@ public: case not_at_bound: switch (m_column_types[j]) { case column_type::free_column: - lean_assert(false); // unreachable + SASSERT(false); // unreachable case column_type::upper_bound: s.m_x[j] = s.m_upper_bounds[j]; break; @@ -377,15 +392,15 @@ public: s.m_x[j] = s.m_low_bounds[j]; break; default: - lean_assert(false); + SASSERT(false); } break; default: - lean_unreachable(); + SASSERT(false); } } - lean_assert(is_zero_vector(s.m_b)); + SASSERT(is_zero_vector(s.m_b)); s.solve_Ax_eq_b(); } @@ -418,7 +433,7 @@ public: // the queues of delayed indices std::queue entr_q, leav_q; auto * l = cs.m_factorization; - lean_assert(l->get_status() == LU_status::OK); + SASSERT(l->get_status() == LU_status::OK); for (unsigned i = 0; i < trace_of_basis_change.size(); i+= 2) { unsigned entering = trace_of_basis_change[i]; unsigned leaving = trace_of_basis_change[i+1]; @@ -446,8 +461,8 @@ public: continue; } } - lean_assert(cs.m_basis_heading[entering] < 0); - lean_assert(cs.m_basis_heading[leaving] >= 0); + SASSERT(cs.m_basis_heading[entering] < 0); + SASSERT(cs.m_basis_heading[leaving] >= 0); if (l->get_status() == LU_status::OK) { l->prepare_entering(entering, w); // to init vector w l->replace_column(zero_of_type(), w, cs.m_basis_heading[leaving]); @@ -471,7 +486,7 @@ public: void solve_on_signature_tableau(const lar_solution_signature & signature, const vector & changes_of_basis) { r_basis_is_OK(); - lean_assert(settings().use_tableau()); + SASSERT(settings().use_tableau()); bool r = catch_up_in_lu_tableau(changes_of_basis, m_d_solver.m_basis_heading); if (!r) { // it is the case where m_d_solver gives a degenerated basis @@ -490,10 +505,10 @@ public: return; m_r_solver.stop_tracing_basis_changes(); // and now catch up in the double solver - lean_assert(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2); + SASSERT(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2); catch_up_in_lu(m_r_solver.m_trace_of_basis_change_vector, m_r_solver.m_basis_heading, m_d_solver); } - lean_assert(r_basis_is_OK()); + SASSERT(r_basis_is_OK()); } bool adjust_x_of_column(unsigned j) { @@ -507,16 +522,16 @@ public: } m_r_solver.snap_column_to_bound_tableau(j); - lean_assert(m_r_solver.column_is_feasible(j)); + SASSERT(m_r_solver.column_is_feasible(j)); m_r_solver.m_inf_set.erase(j); */ - lean_assert(false); + SASSERT(false); return true; } bool catch_up_in_lu_tableau(const vector & trace_of_basis_change, const vector & basis_heading) { - lean_assert(r_basis_is_OK()); + SASSERT(r_basis_is_OK()); // the queues of delayed indices std::queue entr_q, leav_q; for (unsigned i = 0; i < trace_of_basis_change.size(); i+= 2) { @@ -546,47 +561,47 @@ public: continue; } } - lean_assert(m_r_solver.m_basis_heading[entering] < 0); - lean_assert(m_r_solver.m_basis_heading[leaving] >= 0); + SASSERT(m_r_solver.m_basis_heading[entering] < 0); + SASSERT(m_r_solver.m_basis_heading[leaving] >= 0); m_r_solver.change_basis_unconditionally(entering, leaving); if(!m_r_solver.pivot_column_tableau(entering, m_r_solver.m_basis_heading[entering])) { - // unroll the last step + // unroll the last step m_r_solver.change_basis_unconditionally(leaving, entering); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG bool t = #endif m_r_solver.pivot_column_tableau(leaving, m_r_solver.m_basis_heading[leaving]); -#ifdef LEAN_DEBUG - lean_assert(t); +#ifdef Z3DEBUG + SASSERT(t); #endif return false; } } - lean_assert(r_basis_is_OK()); + SASSERT(r_basis_is_OK()); return true; } bool r_basis_is_OK() const { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG if (!m_r_solver.m_settings.use_tableau()) return true; for (unsigned j : m_r_solver.m_basis) { - lean_assert(m_r_solver.m_A.m_columns[j].size() == 1); - lean_assert(m_r_solver.m_A.get_val(m_r_solver.m_A.m_columns[j][0]) == one_of_type()); + SASSERT(m_r_solver.m_A.m_columns[j].size() == 1); + SASSERT(m_r_solver.m_A.get_val(m_r_solver.m_A.m_columns[j][0]) == one_of_type()); } for (unsigned j =0; j < m_r_solver.m_basis_heading.size(); j++) { if (m_r_solver.m_basis_heading[j] >= 0) continue; if (m_r_solver.m_column_types[j] == column_type::fixed) continue; - lean_assert(static_cast(- m_r_solver.m_basis_heading[j] - 1) < m_r_solver.m_column_types.size()); - lean_assert( m_r_solver.m_basis_heading[j] <= -1); + SASSERT(static_cast(- m_r_solver.m_basis_heading[j] - 1) < m_r_solver.m_column_types.size()); + SASSERT( m_r_solver.m_basis_heading[j] <= -1); } #endif return true; } void solve_on_signature(const lar_solution_signature & signature, const vector & changes_of_basis) { - lean_assert(!settings().use_tableau()); + SASSERT(!settings().use_tableau()); if (m_r_solver.m_factorization == nullptr) { for (unsigned j = 0; j < changes_of_basis.size(); j+=2) { unsigned entering = changes_of_basis[j]; @@ -615,7 +630,7 @@ public: return; m_r_solver.stop_tracing_basis_changes(); // and now catch up in the double solver - lean_assert(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2); + SASSERT(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2); catch_up_in_lu(m_r_solver.m_trace_of_basis_change_vector, m_r_solver.m_basis_heading, m_d_solver); } } @@ -641,7 +656,7 @@ public: template void extract_signature_from_lp_core_solver(const lp_primal_core_solver & solver, lar_solution_signature & signature) { signature.clear(); - lean_assert(signature.size() == 0); + SASSERT(signature.size() == 0); for (unsigned j = 0; j < solver.m_basis_heading.size(); j++) { if (solver.m_basis_heading[j] < 0) { signature[j] = solver.get_non_basic_column_value_position(j); @@ -664,7 +679,7 @@ public: if (upper_bound_is_set(j)) { const auto & ub = m_r_solver.m_upper_bounds[j]; m_d_upper_bounds[j] = ub.x.get_double() + delta * ub.y.get_double(); - lean_assert(!low_bound_is_set(j) || (m_d_upper_bounds[j] >= m_d_low_bounds[j])); + SASSERT(!low_bound_is_set(j) || (m_d_upper_bounds[j] >= m_d_low_bounds[j])); } } } @@ -729,7 +744,7 @@ public: case column_type::fixed: return true; default: - lean_assert(false); + SASSERT(false); } return false; } @@ -744,20 +759,20 @@ public: case column_type::fixed: return true; default: - lean_assert(false); + SASSERT(false); } return false; } void update_delta(mpq& delta, numeric_pair const& l, numeric_pair const& u) const { - lean_assert(l <= u); + SASSERT(l <= u); if (l.x < u.x && l.y > u.y) { mpq delta1 = (u.x - l.x) / (l.y - u.y); if (delta1 < delta) { delta = delta1; } } - lean_assert(l.x + delta * l.y <= u.x + delta * u.y); + SASSERT(l.x + delta * l.y <= u.x + delta * u.y); } diff --git a/src/util/lp/lar_core_solver.hpp b/src/util/lp/lar_core_solver.hpp index a6dd7e3e0..62a5c7887 100644 --- a/src/util/lp/lar_core_solver.hpp +++ b/src/util/lp/lar_core_solver.hpp @@ -1,16 +1,46 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/vector.h" #include "util/lp/lar_core_solver.h" #include "util/lp/lar_solution_signature.h" -namespace lean { +namespace lp { lar_core_solver::lar_core_solver( lp_settings & settings, const column_namer & column_names @@ -42,9 +72,9 @@ lar_core_solver::lar_core_solver( column_names){} void lar_core_solver::init_costs(bool first_time) { - lean_assert(false); // should not be called - // lean_assert(this->m_x.size() >= this->m_n()); - // lean_assert(this->m_column_types.size() >= this->m_n()); + SASSERT(false); // should not be called + // SASSERT(this->m_x.size() >= this->m_n()); + // SASSERT(this->m_column_types.size() >= this->m_n()); // if (first_time) // this->m_costs.resize(this->m_n()); // X inf = this->m_infeasibility; @@ -54,7 +84,7 @@ void lar_core_solver::init_costs(bool first_time) { // if (!(first_time || inf >= this->m_infeasibility)) { // LP_OUT(this->m_settings, "iter = " << this->total_iterations() << std::endl); // LP_OUT(this->m_settings, "inf was " << T_to_string(inf) << " and now " << T_to_string(this->m_infeasibility) << std::endl); - // lean_assert(false); + // SASSERT(false); // } // if (inf == this->m_infeasibility) // this->m_iters_with_no_cost_growing++; @@ -105,7 +135,7 @@ void lar_core_solver::init_cost_for_column(unsigned j) { this->m_costs[j] = numeric_traits::zero(); break; default: - lean_assert(false); + SASSERT(false); break; }*/ } @@ -138,15 +168,15 @@ int lar_core_solver::column_is_out_of_bounds(unsigned j) { return 0; break; }*/ - lean_assert(false); + SASSERT(false); return true; } void lar_core_solver::calculate_pivot_row(unsigned i) { - lean_assert(!m_r_solver.use_tableau()); - lean_assert(m_r_solver.m_pivot_row.is_OK()); + SASSERT(!m_r_solver.use_tableau()); + SASSERT(m_r_solver.m_pivot_row.is_OK()); m_r_solver.m_pivot_row_of_B_1.clear(); m_r_solver.m_pivot_row_of_B_1.resize(m_r_solver.m_m()); m_r_solver.m_pivot_row.clear(); @@ -208,7 +238,7 @@ void lar_core_solver::calculate_pivot_row(unsigned i) { } void lar_core_solver::fill_not_improvable_zero_sum_from_inf_row() { - lean_assert(m_r_solver.A_mult_x_is_off() == false); + SASSERT(m_r_solver.A_mult_x_is_off() == false); unsigned bj = m_r_basis[m_r_solver.m_inf_row_index_for_tableau]; m_infeasible_sum_sign = m_r_solver.inf_sign_of_column(bj); m_infeasible_linear_combination.clear(); @@ -243,15 +273,15 @@ void lar_core_solver::fill_not_improvable_zero_sum() { void lar_core_solver::solve() { - lean_assert(m_r_solver.non_basic_columns_are_set_correctly()); - lean_assert(m_r_solver.inf_set_is_correct()); + SASSERT(m_r_solver.non_basic_columns_are_set_correctly()); + SASSERT(m_r_solver.inf_set_is_correct()); if (m_r_solver.current_x_is_feasible() && m_r_solver.m_look_for_feasible_solution_only) { m_r_solver.set_status(OPTIMAL); return; } ++settings().st().m_need_to_solve_inf; - lean_assert(!m_r_solver.A_mult_x_is_off()); - lean_assert((!settings().use_tableau()) || r_basis_is_OK()); + SASSERT(!m_r_solver.A_mult_x_is_off()); + SASSERT((!settings().use_tableau()) || r_basis_is_OK()); if (need_to_presolve_with_double_solver()) { prefix_d(); lar_solution_signature solution_signature; @@ -264,11 +294,11 @@ void lar_core_solver::solve() { solve_on_signature_tableau(solution_signature, changes_of_basis); else solve_on_signature(solution_signature, changes_of_basis); - lean_assert(!settings().use_tableau() || r_basis_is_OK()); + SASSERT(!settings().use_tableau() || r_basis_is_OK()); } else { if (!settings().use_tableau()) { bool snapped = m_r_solver.snap_non_basic_x_to_bound(); - lean_assert(m_r_solver.non_basic_columns_are_set_correctly()); + SASSERT(m_r_solver.non_basic_columns_are_set_correctly()); if (snapped) m_r_solver.solve_Ax_eq_b(); } @@ -276,16 +306,16 @@ void lar_core_solver::solve() { m_r_solver.find_feasible_solution(); else m_r_solver.solve(); - lean_assert(!settings().use_tableau() || r_basis_is_OK()); + SASSERT(!settings().use_tableau() || r_basis_is_OK()); } if (m_r_solver.get_status() == INFEASIBLE) { fill_not_improvable_zero_sum(); } else if (m_r_solver.get_status() != UNBOUNDED) { m_r_solver.set_status(OPTIMAL); } - lean_assert(r_basis_is_OK()); - lean_assert(m_r_solver.non_basic_columns_are_set_correctly()); - lean_assert(m_r_solver.inf_set_is_correct()); + SASSERT(r_basis_is_OK()); + SASSERT(m_r_solver.non_basic_columns_are_set_correctly()); + SASSERT(m_r_solver.inf_set_is_correct()); } diff --git a/src/util/lp/lar_core_solver_instances.cpp b/src/util/lp/lar_core_solver_instances.cpp index 432d1a939..a6a4048e5 100644 --- a/src/util/lp/lar_core_solver_instances.cpp +++ b/src/util/lp/lar_core_solver_instances.cpp @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include diff --git a/src/util/lp/lar_solution_signature.h b/src/util/lp/lar_solution_signature.h index 2c4169c81..08551a2d0 100644 --- a/src/util/lp/lar_solution_signature.h +++ b/src/util/lp/lar_solution_signature.h @@ -1,13 +1,28 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include "util/debug.h" #include "util/lp/lp_settings.h" #include -namespace lean { +namespace lp { typedef std::unordered_map lar_solution_signature; } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index b74515566..6d2cbea7d 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include @@ -30,7 +45,7 @@ #include "util/lp/iterator_on_row.h" #include "util/lp/quick_xplain.h" #include "util/lp/conversion_helper.h" -namespace lean { +namespace lp { class lar_solver : public column_namer { //////////////////// fields ////////////////////////// @@ -51,7 +66,7 @@ class lar_solver : public column_namer { vector m_terms; vector m_orig_terms; const var_index m_terms_start_index; - indexed_vector m_column_buffer; + indexed_vector m_column_buffer; public: lar_core_solver m_mpq_lar_core_solver; unsigned constraint_count() const { @@ -66,7 +81,7 @@ public: static_matrix> const & A_r() const { return m_mpq_lar_core_solver.m_r_A;} static_matrix & A_d() { return m_mpq_lar_core_solver.m_d_A;} static_matrix const & A_d() const { return m_mpq_lar_core_solver.m_d_A;} - + static bool valid_index(unsigned j){ return static_cast(j) >= 0;} @@ -75,7 +90,7 @@ public: lp_settings const & settings() const { return m_settings;} - void clear() {lean_assert(false); // not implemented + void clear() {SASSERT(false); // not implemented } @@ -84,7 +99,7 @@ public: m_terms_start_index(1000000), m_mpq_lar_core_solver(m_settings, *this) {} - + void set_propagate_bounds_on_pivoted_rows_mode(bool v) { m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows = v? (& m_rows_with_changed_bounds) : nullptr; } @@ -99,7 +114,7 @@ public: } #include "util/lp/init_lar_solver.h" - + numeric_pair const& get_value(var_index vi) const { return m_mpq_lar_core_solver.m_r_x[vi]; } bool is_term(var_index j) const { @@ -107,22 +122,22 @@ public: } unsigned adjust_term_index(unsigned j) const { - lean_assert(is_term(j)); + SASSERT(is_term(j)); return j - m_terms_start_index; } bool use_lu() const { return m_settings.simplex_strategy() == simplex_strategy_enum::lu; } - + bool sizes_are_correct() const { - lean_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); + SASSERT(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); + SASSERT(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); + SASSERT(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + SASSERT(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); return true; } - - + + void print_implied_bound(const implied_bound& be, std::ostream & out) const { out << "implied bound\n"; unsigned v = be.m_j; @@ -138,11 +153,11 @@ public: // out << p.first << " : "; // print_constraint(p.second, out); // } - + // m_mpq_lar_core_solver.m_r_solver.print_column_info(be.m_j< m_terms_start_index? be.m_j : adjust_term_index(be.m_j), out); out << "end of implied bound" << std::endl; } - + bool implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const { std::unordered_map coeff_map; auto rs_of_evidence = zero_of_type(); @@ -160,11 +175,11 @@ public: else if (kind == LE || kind == LT) n_of_L++; rs_of_evidence += coeff*constr.m_right_side; } - lean_assert(n_of_G == 0 || n_of_L == 0); + SASSERT(n_of_G == 0 || n_of_L == 0); lconstraint_kind kind = n_of_G ? GE : (n_of_L ? LE : EQ); if (strict) kind = static_cast((static_cast(kind) / 2)); - + if (!is_term(be.m_j)) { if (coeff_map.size() != 1) return false; @@ -200,13 +215,13 @@ public: return kind == be.kind() && rs_of_evidence == be.m_bound; } - + void analyze_new_bounds_on_row( unsigned row_index, - bound_propagator & bp) { - lean_assert(!use_tableau()); + lp_bound_propagator & bp) { + SASSERT(!use_tableau()); iterator_on_pivot_row it(m_mpq_lar_core_solver.get_pivot_row(), m_mpq_lar_core_solver.m_r_basis[row_index]); - + bound_analyzer_on_row ra_pos(it, zero_of_type>(), row_index, @@ -217,13 +232,13 @@ public: void analyze_new_bounds_on_row_tableau( unsigned row_index, - bound_propagator & bp + lp_bound_propagator & bp ) { if (A_r().m_rows[row_index].size() > settings().max_row_length_for_bound_propagation) return; iterator_on_row it(A_r().m_rows[row_index]); - lean_assert(use_tableau()); + SASSERT(use_tableau()); bound_analyzer_on_row::analyze_row(it, zero_of_type>(), row_index, @@ -231,20 +246,20 @@ public: ); } - + void substitute_basis_var_in_terms_for_row(unsigned i) { // todo : create a map from term basic vars to the rows where they are used unsigned basis_j = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; for (unsigned k = 0; k < m_terms.size(); k++) { if (term_is_used_as_row(k)) continue; - if (!m_terms[k]->contains(basis_j)) + if (!m_terms[k]->contains(basis_j)) continue; m_terms[k]->subst(basis_j, m_mpq_lar_core_solver.m_r_solver.m_pivot_row); } } - - void calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp) { + + void calculate_implied_bounds_for_row(unsigned i, lp_bound_propagator & bp) { if(use_tableau()) { analyze_new_bounds_on_row_tableau(i, bp); } else { @@ -269,9 +284,9 @@ public: bound_evidences.push_back(fill_bound_evidence(implied_evidence)); } } - + void fill_bound_evidence_on_term(implied_bound & ie, implied_bound& be) { - lean_assert(false); + SASSERT(false); } void fill_implied_bound_on_row(implied_bound & ie, implied_bound& be) { iterator_on_row it(A_r().m_rows[ie.m_row_or_term_index]); @@ -282,10 +297,10 @@ public: while (it.next(a, j)) { if (j == ie.m_j) continue; const ul_pair & ul = m_vars_to_ul_pairs[j]; - + if (is_neg(a)) { // so the monoid has a positive coeff on the right side constraint_index witness = toggle ? ul.m_low_bound_witness : ul.m_upper_bound_witness; - lean_assert(is_valid(witness)); + SASSERT(is_valid(witness)); be.m_explanation.emplace_back(a, witness); } } @@ -304,23 +319,23 @@ public: } implied_bound fill_implied_bound_for_upper_bound(implied_bound& implied_evidence) { - lean_assert(false); - + SASSERT(false); + be.m_j = implied_evidence.m_j; be.m_bound = implied_evidence.m_bound.x; be.m_kind = implied_evidence.m_bound.y.is_zero() ? LE : LT; for (auto t : implied_evidence.m_vector_of_bound_signatures) { const ul_pair & ul = m_vars_to_ul_pairs[t.m_column_index]; constraint_index witness = t.m_low_bound ? ul.m_low_bound_witness : ul.m_upper_bound_witness; - lean_assert(is_valid(witness)); + SASSERT(is_valid(witness)); be.m_explanation.emplace_back(t.m_coeff, witness); } - + } */ /* void process_new_implied_evidence_for_upper_bound( - implied_bound& implied_evidence, + implied_bound& implied_evidence, vector & implied_bounds, std::unordered_map & improved_upper_bounds) { unsigned existing_index; @@ -336,9 +351,9 @@ public: } */ // implied_bound * get_existing_ - + linear_combination_iterator * create_new_iter_from_term(unsigned term_index) const { - lean_assert(false); // not implemented + SASSERT(false); // not implemented return nullptr; // new linear_combination_iterator_on_vector(m_terms[adjust_term_index(term_index)]->coeffs_as_vector()); } @@ -347,13 +362,13 @@ public: unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j]; return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term; } - - void propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset) { - lean_assert(false); // not implemented + + void propagate_bounds_on_a_term(const lar_term& t, lp_bound_propagator & bp, unsigned term_offset) { + SASSERT(false); // not implemented } - void explain_implied_bound(implied_bound & ib, bound_propagator & bp) { + void explain_implied_bound(implied_bound & ib, lp_bound_propagator & bp) { unsigned i = ib.m_row_or_term_index; int bound_sign = ib.m_is_low_bound? 1: -1; int j_sign = (ib.m_coeff_before_j_is_pos ? 1 :-1) * bound_sign; @@ -367,24 +382,24 @@ public: if (j == m_j) continue; if (is_term(j)) { j = m_ext_vars_to_columns[j]; - } + } int a_sign = is_pos(a)? 1: -1; int sign = j_sign * a_sign; const ul_pair & ul = m_vars_to_ul_pairs[j]; auto witness = sign > 0? ul.upper_bound_witness(): ul.low_bound_witness(); - lean_assert(is_valid(witness)); + SASSERT(is_valid(witness)); bp.consume(a, witness); } - // lean_assert(implied_bound_is_correctly_explained(ib, explanation)); + // SASSERT(implied_bound_is_correctly_explained(ib, explanation)); } bool term_is_used_as_row(unsigned term) const { - lean_assert(is_term(term)); - return contains(m_ext_vars_to_columns, term); + SASSERT(is_term(term)); + return contains(m_ext_vars_to_columns, term); } - - void propagate_bounds_on_terms(bound_propagator & bp) { + + void propagate_bounds_on_terms(lp_bound_propagator & bp) { for (unsigned i = 0; i < m_terms.size(); i++) { if (term_is_used_as_row(i + m_terms_start_index)) continue; // this term is used a left side of a constraint, @@ -395,13 +410,15 @@ public: // goes over touched rows and tries to induce bounds - void propagate_bounds_for_touched_rows(bound_propagator & bp) { + void propagate_bounds_for_touched_rows(lp_bound_propagator & bp) { if (!use_tableau()) return; // ! todo : enable bound propagaion here. The current bug is that after the pop // the changed terms become incorrect! for (unsigned i : m_rows_with_changed_bounds.m_index) { calculate_implied_bounds_for_row(i, bp); + if (settings().get_cancel_flag()) + return; } m_rows_with_changed_bounds.clear(); if (!use_tableau()) { @@ -420,7 +437,7 @@ public: m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true; return solve(); } - + lp_status solve() { if (m_status == INFEASIBLE) { return m_status; @@ -430,7 +447,7 @@ public: if (m_settings.bound_propagation()) detect_rows_with_changed_bounds(); } - + m_columns_with_changed_bound.clear(); return m_status; } @@ -443,7 +460,7 @@ public: evidence.push_back(std::make_pair(-numeric_traits::one(), ul.low_bound_witness())); } - + unsigned get_total_iterations() const { return m_mpq_lar_core_solver.m_r_solver.total_iterations(); } // see http://research.microsoft.com/projects/z3/smt07.pdf // This method searches for a feasible solution with as many different values of variables, reverenced in vars, as it can find @@ -481,35 +498,35 @@ public: set.resize(n); } - + void pop(unsigned k) { int n_was = static_cast(m_ext_vars_to_columns.size()); - m_status.pop(k); - m_infeasible_column_index.pop(k); + m_status.pop(k); + m_infeasible_column_index.pop(k); unsigned n = m_vars_to_ul_pairs.peek_size(k); - for (unsigned j = n_was; j-- > n;) - m_ext_vars_to_columns.erase(m_columns_to_ext_vars_or_term_indices[j]); - m_columns_to_ext_vars_or_term_indices.resize(n); - if (m_settings.use_tableau()) { + for (unsigned j = n_was; j-- > n;) + m_ext_vars_to_columns.erase(m_columns_to_ext_vars_or_term_indices[j]); + m_columns_to_ext_vars_or_term_indices.resize(n); + if (m_settings.use_tableau()) { pop_tableau(); } - m_vars_to_ul_pairs.pop(k); + m_vars_to_ul_pairs.pop(k); m_mpq_lar_core_solver.pop(k); clean_large_elements_after_pop(n, m_columns_with_changed_bound); unsigned m = A_r().row_count(); clean_large_elements_after_pop(m, m_rows_with_changed_bounds); clean_inf_set_of_r_solver_after_pop(); - lean_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || - (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - - - lean_assert(ax_is_correct()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct()); + SASSERT(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || + (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + + + SASSERT(ax_is_correct()); + SASSERT(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct()); m_constraint_count.pop(k); for (unsigned i = m_constraint_count; i < m_constraints.size(); i++) delete m_constraints[i]; - + m_constraints.resize(m_constraint_count); m_term_count.pop(k); for (unsigned i = m_term_count; i < m_terms.size(); i++) { @@ -518,12 +535,12 @@ public: } m_terms.resize(m_term_count); m_orig_terms.resize(m_term_count); - m_simplex_strategy.pop(k); - m_settings.simplex_strategy() = m_simplex_strategy; - lean_assert(sizes_are_correct()); - lean_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + m_simplex_strategy.pop(k); + m_settings.simplex_strategy() = m_simplex_strategy; + SASSERT(sizes_are_correct()); + SASSERT((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); } - + vector get_all_constraint_indices() const { vector ret; constraint_index i = 0; @@ -536,7 +553,7 @@ public: impq &term_max) { if (settings().simplex_strategy() == simplex_strategy_enum::undecided) decide_on_strategy_and_adjust_initial_state(); - + m_mpq_lar_core_solver.solve(); if (m_mpq_lar_core_solver.m_r_solver.get_status() == UNBOUNDED) return false; @@ -550,22 +567,22 @@ public: bool costs_are_zeros_for_r_solver() const { for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_costs.size(); j++) { - lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_costs[j])); + SASSERT(is_zero(m_mpq_lar_core_solver.m_r_solver.m_costs[j])); } return true; } bool reduced_costs_are_zeroes_for_r_solver() const { for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_d.size(); j++) { - lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_d[j])); + SASSERT(is_zero(m_mpq_lar_core_solver.m_r_solver.m_d[j])); } return true; } - + void set_costs_to_zero(const vector> & term) { auto & rslv = m_mpq_lar_core_solver.m_r_solver; auto & jset = m_mpq_lar_core_solver.m_r_solver.m_inf_set; // hijack this set that should be empty right now - lean_assert(jset.m_index.size()==0); - + SASSERT(jset.m_index.size()==0); + for (auto & p : term) { unsigned j = p.second; rslv.m_costs[j] = zero_of_type(); @@ -582,17 +599,17 @@ public: rslv.m_d[j] = zero_of_type(); jset.clear(); - - lean_assert(reduced_costs_are_zeroes_for_r_solver()); - lean_assert(costs_are_zeros_for_r_solver()); + + SASSERT(reduced_costs_are_zeroes_for_r_solver()); + SASSERT(costs_are_zeros_for_r_solver()); } void prepare_costs_for_r_solver(const vector> & term) { - + auto & rslv = m_mpq_lar_core_solver.m_r_solver; rslv.m_using_infeas_costs = false; - lean_assert(costs_are_zeros_for_r_solver()); - lean_assert(reduced_costs_are_zeroes_for_r_solver()); + SASSERT(costs_are_zeros_for_r_solver()); + SASSERT(reduced_costs_are_zeroes_for_r_solver()); rslv.m_costs.resize(A_r().column_count(), zero_of_type()); for (auto & p : term) { unsigned j = p.second; @@ -602,9 +619,9 @@ public: else rslv.update_reduced_cost_for_basic_column_cost_change(- p.first, j); } - lean_assert(rslv.reduced_costs_are_correct_tableau()); + SASSERT(rslv.reduced_costs_are_correct_tableau()); } - + bool maximize_term_on_corrected_r_solver(const vector> & term, impq &term_max) { settings().backup_costs = false; @@ -627,28 +644,28 @@ public: m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); return ret; } - + case simplex_strategy_enum::lu: - lean_assert(false); // not implemented + SASSERT(false); // not implemented return false; default: - lean_unreachable(); // wrong mode + SASSERT(false); // wrong mode } return false; - } + } // starting from a given feasible state look for the maximum of the term // return true if found and false if unbounded bool maximize_term(const vector> & term, impq &term_max) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()); + SASSERT(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()); m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = false; return maximize_term_on_corrected_r_solver(term, term_max); } - - + + const lar_term & get_term(unsigned j) const { - lean_assert(j >= m_terms_start_index); + SASSERT(j >= m_terms_start_index); return *m_terms[j - m_terms_start_index]; } @@ -680,7 +697,7 @@ public: vector> &left_side, mpq & right_side) const { for (auto & t : left_side_with_terms) { if (t.second < m_terms_start_index) { - lean_assert(t.second < A_r().column_count()); + SASSERT(t.second < A_r().column_count()); left_side.push_back(std::pair(mult * t.first, t.second)); } else { const lar_term & term = * m_terms[adjust_term_index(t.second)]; @@ -696,15 +713,15 @@ public: m_column_buffer.resize(A_r().row_count()); else m_column_buffer.clear(); - lean_assert(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); - + SASSERT(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); + m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); for (unsigned i : m_column_buffer.m_index) m_rows_with_changed_bounds.insert(i); } - + void detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j) { for (auto & rc : m_mpq_lar_core_solver.m_r_A.m_columns[j]) m_rows_with_changed_bounds.insert(rc.m_i); @@ -715,7 +732,7 @@ public: bool use_tableau_costs() const { return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; } - + void detect_rows_of_column_with_bound_change(unsigned j) { if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { // it is a basic column // just mark the row at touched and exit @@ -730,7 +747,7 @@ public: } void adjust_x_of_column(unsigned j) { - lean_assert(false); + SASSERT(false); } bool row_is_correct(unsigned i) const { @@ -739,7 +756,7 @@ public: r += c.m_value * m_mpq_lar_core_solver.m_r_x[c.m_j]; return is_zero(r); } - + bool ax_is_correct() const { for (unsigned i = 0; i < A_r().row_count(); i++) { if (!row_is_correct(i)) @@ -755,7 +772,7 @@ public: bool costs_are_used() const { return m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows; } - + void change_basic_x_by_delta_on_column(unsigned j, const numeric_pair & delta) { if (use_tableau()) { for (const auto & c : A_r().m_columns[j]) { @@ -795,7 +812,7 @@ public: } } - + void detect_rows_with_changed_bounds_for_column(unsigned j) { if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); @@ -804,10 +821,10 @@ public: if (use_tableau()) detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); - else + else detect_rows_of_bound_change_column_for_nbasic_column(j); } - + void detect_rows_with_changed_bounds() { for (auto j : m_columns_with_changed_bound.m_index) detect_rows_with_changed_bounds_for_column(j); @@ -819,18 +836,18 @@ public: } void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { - lean_assert(ax_is_correct()); + SASSERT(ax_is_correct()); for (auto j : m_columns_with_changed_bound.m_index) update_x_and_inf_costs_for_column_with_changed_bounds(j); if (tableau_with_costs()) { for (unsigned j : m_basic_columns_with_changed_cost.m_index) m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + SASSERT(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); } } - + void solve_with_core_solver() { if (!use_tableau()) add_last_rows_to_lu(m_mpq_lar_core_solver.m_r_solver); @@ -844,38 +861,38 @@ public: } if (use_tableau()) update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); - else + else update_x_and_inf_costs_for_columns_with_changed_bounds(); m_mpq_lar_core_solver.solve(); set_status(m_mpq_lar_core_solver.m_r_solver.get_status()); - lean_assert(m_status != OPTIMAL || all_constraints_hold()); + SASSERT(m_status != OPTIMAL || all_constraints_hold()); } - + numeric_pair get_basic_var_value_from_row_directly(unsigned i) { numeric_pair r = zero_of_type>(); - + unsigned bj = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; for (const auto & c: A_r().m_rows[i]) { if (c.m_j == bj) continue; const auto & x = m_mpq_lar_core_solver.m_r_x[c.m_j]; - if (!is_zero(x)) + if (!is_zero(x)) r -= c.m_value * x; } return r; } - - - + + + numeric_pair get_basic_var_value_from_row(unsigned i) { if (settings().use_tableau()) { return get_basic_var_value_from_row_directly(i); } - + numeric_pair r = zero_of_type>(); m_mpq_lar_core_solver.calculate_pivot_row(i); for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_index) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); + SASSERT(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); r -= m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_data[j] * m_mpq_lar_core_solver.m_r_x[j]; } return r; @@ -900,9 +917,9 @@ public: f = nullptr; } } - + } - + bool x_is_correct() const { if (m_mpq_lar_core_solver.m_r_x.size() != A_r().column_count()) { // std::cout << "the size is off " << m_r_solver.m_x.size() << ", " << A().column_count() << std::endl; @@ -921,7 +938,7 @@ public: } } return true;; - + } bool var_is_registered(var_index vj) const { @@ -938,13 +955,13 @@ public: return m_constraint_count.stack_size(); } - void fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls) { - lean_assert(A.row_count() > 0); - lean_assert(A.column_count() > 0); + void fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls) { + SASSERT(A.row_count() > 0); + SASSERT(A.column_count() > 0); unsigned last_row = A.row_count() - 1; - lean_assert(A.m_rows[last_row].size() == 0); + SASSERT(A.m_rows[last_row].size() == 0); for (auto & t : ls->m_coeffs) { - lean_assert(!is_zero(t.second)); + SASSERT(!is_zero(t.second)); var_index j = t.first; A.set(last_row, j, - t.second); } @@ -954,7 +971,7 @@ public: template void create_matrix_A(static_matrix & matr) { - lean_assert(false); // not implemented + SASSERT(false); // not implemented /* unsigned m = number_or_nontrivial_left_sides(); unsigned n = m_vec_of_canonic_left_sides.size(); @@ -967,8 +984,8 @@ public: template void copy_from_mpq_matrix(static_matrix & matr) { - matr.m_rows.resize(A_r().row_count()); - matr.m_columns.resize(A_r().column_count()); + matr.m_rows.resize(A_r().row_count()); + matr.m_columns.resize(A_r().column_count()); for (unsigned i = 0; i < matr.row_count(); i++) { for (auto & it : A_r().m_rows[i]) { matr.set(i, it.m_j, convert_struct::convert(it.get_val())); @@ -995,7 +1012,7 @@ public: } std::string get_column_name(unsigned j) const { - if (j >= m_terms_start_index) + if (j >= m_terms_start_index) return std::string("_t") + T_to_string(j); if (j >= m_columns_to_ext_vars_or_term_indices.size()) return std::string("_s") + T_to_string(j); @@ -1016,8 +1033,8 @@ public: mpq rs = right_side_parm; vector> left_side; substitute_terms(one_of_type(), left_side_with_terms, left_side, rs); - lean_assert(left_side.size() > 0); - lean_assert(all_constrained_variables_are_registered(left_side)); + SASSERT(left_side.size() > 0); + SASSERT(all_constrained_variables_are_registered(left_side)); lar_constraint original_constr(left_side, kind_par, rs); unsigned j; // j is the index of the basic variables corresponding to the left side canonic_left_side ls = create_or_fetch_canonic_left_side(left_side, j); @@ -1030,7 +1047,7 @@ public: update_column_type_and_bound(j, kind, rs, constr_ind); return constr_ind; */ - lean_assert(false); // not implemented + SASSERT(false); // not implemented return 0; } @@ -1039,7 +1056,7 @@ public: return true; std::unordered_map var_map; get_model(var_map); - + for (unsigned i = 0; i < m_constraints.size(); i++) { if (!constraint_holds(*m_constraints[i], var_map)) { print_constraint(i, std::cout); @@ -1058,7 +1075,7 @@ public: case GT: return left_side_val > constr.m_right_side; case EQ: return left_side_val == constr.m_right_side; default: - lean_unreachable(); + SASSERT(false); } return false; // it is unreachable } @@ -1108,7 +1125,7 @@ public: for (auto & it : evidence) { mpq coeff = it.first; constraint_index con_ind = it.second; - lean_assert(con_ind < m_constraints.size()); + SASSERT(con_ind < m_constraints.size()); register_in_map(coeff_map, *m_constraints[con_ind], coeff); } @@ -1131,7 +1148,7 @@ public: for (auto & it : evidence) { mpq coeff = it.first; constraint_index con_ind = it.second; - lean_assert(con_ind < m_constraints.size()); + SASSERT(con_ind < m_constraints.size()); const lar_constraint & constr = *m_constraints[con_ind]; ret += constr.m_right_side * coeff; } @@ -1139,24 +1156,24 @@ public: } bool explanation_is_correct(const vector>& explanation) const { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG lconstraint_kind kind; - lean_assert(the_relations_are_of_same_type(explanation, kind)); - lean_assert(the_left_sides_sum_to_zero(explanation)); + SASSERT(the_relations_are_of_same_type(explanation, kind)); + SASSERT(the_left_sides_sum_to_zero(explanation)); mpq rs = sum_of_right_sides_of_explanation(explanation); switch (kind) { - case LE: lean_assert(rs < zero_of_type()); + case LE: SASSERT(rs < zero_of_type()); break; - case LT: lean_assert(rs <= zero_of_type()); + case LT: SASSERT(rs <= zero_of_type()); break; - case GE: lean_assert(rs > zero_of_type()); + case GE: SASSERT(rs > zero_of_type()); break; - case GT: lean_assert(rs >= zero_of_type()); + case GT: SASSERT(rs >= zero_of_type()); break; - case EQ: lean_assert(rs != zero_of_type()); + case EQ: SASSERT(rs != zero_of_type()); break; default: - lean_assert(false); + SASSERT(false); return false; } #endif @@ -1164,7 +1181,7 @@ public: } bool inf_explanation_is_correct() const { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG vector> explanation; get_infeasibility_explanation(explanation); return explanation_is_correct(explanation); @@ -1177,7 +1194,7 @@ public: for (auto & it : explanation) { mpq coeff = it.first; constraint_index con_ind = it.second; - lean_assert(con_ind < m_constraints.size()); + SASSERT(con_ind < m_constraints.size()); ret += (m_constraints[con_ind]->m_right_side - m_constraints[con_ind]->get_free_coeff_of_left_side()) * coeff; } return ret; @@ -1201,7 +1218,7 @@ public: return false; } } - + bool has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { if (var >= m_vars_to_ul_pairs.size()) { @@ -1235,7 +1252,7 @@ public: int inf_sign; auto inf_row = m_mpq_lar_core_solver.get_infeasibility_info(inf_sign); get_infeasibility_explanation_for_inf_sign(explanation, inf_row, inf_sign); - lean_assert(explanation_is_correct(explanation)); + SASSERT(explanation_is_correct(explanation)); } void get_infeasibility_explanation_for_inf_sign( @@ -1251,23 +1268,22 @@ public: const ul_pair & ul = m_vars_to_ul_pairs[j]; constraint_index bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.low_bound_witness(); - lean_assert(bound_constr_i < m_constraints.size()); + SASSERT(bound_constr_i < m_constraints.size()); explanation.push_back(std::make_pair(coeff, bound_constr_i)); - } + } } void get_model(std::unordered_map & variable_values) const { - mpq delta = mpq(1, 2); // start from 0.5 to have less clashes - lean_assert(m_status == OPTIMAL); + mpq delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(mpq(1, 2)); // start from 0.5 to have less clashes + SASSERT(m_status == OPTIMAL); unsigned i; do { - + // different pairs have to produce different singleton values - std::unordered_set set_of_different_pairs; + std::unordered_set set_of_different_pairs; std::unordered_set set_of_different_singles; - delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta); for (i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { const numeric_pair & rp = m_mpq_lar_core_solver.m_r_x[i]; set_of_different_pairs.insert(rp); @@ -1278,7 +1294,7 @@ public: delta /= mpq(2); break; } - + variable_values[i] = x; } } while (i != m_mpq_lar_core_solver.m_r_x.size()); @@ -1318,7 +1334,7 @@ public: mpq free_coeff = c->get_free_coeff_of_left_side(); if (!is_zero(free_coeff)) out << " + " << free_coeff; - + } void print_term(lar_term const& term, std::ostream & out) const { @@ -1333,7 +1349,7 @@ public: for (auto & it : cns.get_left_side_coefficients()) { var_index j = it.second; auto vi = var_map.find(j); - lean_assert(vi != var_map.end()); + SASSERT(vi != var_map.end()); ret += it.first * vi->second; } return ret; @@ -1345,7 +1361,7 @@ public: } void fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector& column_list) { - for (unsigned i = 0; i < sz; i++) { + for (unsigned i = 0; i < sz; i++) { var_index var = vars[i]; if (var >= m_terms_start_index) { // handle the term for (auto & it : m_terms[var - m_terms_start_index]->m_coeffs) { @@ -1380,7 +1396,7 @@ public: void make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) { // i, j - is the indices of the bottom-right element of the tableau - lean_assert(A_r().row_count() == i + 1 && A_r().column_count() == j + 1); + SASSERT(A_r().row_count() == i + 1 && A_r().column_count() == j + 1); auto & last_column = A_r().m_columns[j]; int non_zero_column_cell_index = -1; for (unsigned k = last_column.size(); k-- > 0;){ @@ -1390,13 +1406,13 @@ public: non_zero_column_cell_index = k; } - lean_assert(non_zero_column_cell_index != -1); - lean_assert(static_cast(non_zero_column_cell_index) != i); + SASSERT(non_zero_column_cell_index != -1); + SASSERT(static_cast(non_zero_column_cell_index) != i); m_mpq_lar_core_solver.m_r_solver.transpose_rows_tableau(last_column[non_zero_column_cell_index].m_i, i); } void remove_last_row_and_column_from_tableau(unsigned j) { - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + SASSERT(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); auto & slv = m_mpq_lar_core_solver.m_r_solver; unsigned i = A_r().row_count() - 1; //last row index make_sure_that_the_bottom_right_elem_not_zero_in_tableau(i, j); @@ -1412,20 +1428,20 @@ public: if (cost_is_nz) { m_mpq_lar_core_solver.m_r_solver.m_d[rc.m_j] += cost_j*rc.get_val(); } - + A_r().remove_element(last_row, rc); } - lean_assert(last_row.size() == 0); - lean_assert(A_r().m_columns[j].size() == 0); + SASSERT(last_row.size() == 0); + SASSERT(A_r().m_columns[j].size() == 0); A_r().m_rows.pop_back(); A_r().m_columns.pop_back(); slv.m_b.pop_back(); } void remove_last_column_from_tableau(unsigned j) { - lean_assert(j == A_r().column_count() - 1); + SASSERT(j == A_r().column_count() - 1); // the last column has to be empty - lean_assert(A_r().m_columns[j].size() == 0); + SASSERT(A_r().m_columns[j].size() == 0); A_r().m_columns.pop_back(); } @@ -1434,7 +1450,7 @@ public: int i = rslv.m_basis_heading[j]; if (i >= 0) { // j is a basic var int last_pos = static_cast(rslv.m_basis.size()) - 1; - lean_assert(last_pos >= 0); + SASSERT(last_pos >= 0); if (i != last_pos) { unsigned j_at_last_pos = rslv.m_basis[last_pos]; rslv.m_basis[i] = j_at_last_pos; @@ -1443,7 +1459,7 @@ public: rslv.m_basis.pop_back(); // remove j from the basis } else { int last_pos = static_cast(rslv.m_nbasis.size()) - 1; - lean_assert(last_pos >= 0); + SASSERT(last_pos >= 0); i = - 1 - i; if (i != last_pos) { unsigned j_at_last_pos = rslv.m_nbasis[last_pos]; @@ -1453,14 +1469,14 @@ public: rslv.m_nbasis.pop_back(); // remove j from the basis } rslv.m_basis_heading.pop_back(); - lean_assert(rslv.m_basis.size() == A_r().row_count()); - lean_assert(rslv.basis_heading_is_correct()); + SASSERT(rslv.m_basis.size() == A_r().row_count()); + SASSERT(rslv.basis_heading_is_correct()); } void remove_column_from_tableau(unsigned j) { auto& rslv = m_mpq_lar_core_solver.m_r_solver; - lean_assert(j == A_r().column_count() - 1); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + SASSERT(j == A_r().column_count() - 1); + SASSERT(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); if (column_represents_row_in_tableau(j)) { remove_last_row_and_column_from_tableau(j); if (rslv.m_basis_heading[j] < 0) @@ -1474,23 +1490,23 @@ public: rslv.m_costs.pop_back(); remove_last_column_from_basis_tableau(j); - lean_assert(m_mpq_lar_core_solver.r_basis_is_OK()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + SASSERT(m_mpq_lar_core_solver.r_basis_is_OK()); + SASSERT(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); } void pop_tableau() { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + SASSERT(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); - // We remove last variables starting from m_column_names.size() to m_vec_of_canonic_left_sides.size(). + SASSERT(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); + SASSERT(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); + // We remove last variables starting from m_column_names.size() to m_vec_of_canonic_left_sides.size(). // At this moment m_column_names is already popped for (unsigned j = A_r().column_count(); j-- > m_columns_to_ext_vars_or_term_indices.size();) remove_column_from_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); + SASSERT(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + SASSERT(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); + SASSERT(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); } @@ -1513,27 +1529,27 @@ public: } for (unsigned j : became_feas) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); + SASSERT(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j]; m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type(); m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); } became_feas.clear(); for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index) { - lean_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0); + SASSERT(m_mpq_lar_core_solver.m_r_heading[j] >= 0); if (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j)) became_feas.push_back(j); } for (unsigned j : became_feas) m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); - - + + if (use_tableau_costs()) { for (unsigned j : became_feas) m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); for (unsigned j : basic_columns_with_changed_cost) m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + SASSERT(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); } } @@ -1541,9 +1557,7 @@ public: void shrink_explanation_to_minimum(vector> & explanation) const { // implementing quickXplain quick_xplain::run(explanation, *this); - lean_assert(this->explanation_is_correct(explanation)); + SASSERT(this->explanation_is_correct(explanation)); } - - }; } diff --git a/src/util/lp/lar_term.h b/src/util/lp/lar_term.h index 0e715ad0b..16b5a938d 100644 --- a/src/util/lp/lar_term.h +++ b/src/util/lp/lar_term.h @@ -1,10 +1,25 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/lp/indexed_vector.h" -namespace lean { +namespace lp { struct lar_term { // the term evaluates to sum of m_coeffs + m_v std::unordered_map m_coeffs; diff --git a/src/util/lp/linear_combination_iterator.h b/src/util/lp/linear_combination_iterator.h index 634accfd4..417bdcf82 100644 --- a/src/util/lp/linear_combination_iterator.h +++ b/src/util/lp/linear_combination_iterator.h @@ -1,9 +1,24 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once -namespace lean { +namespace lp { template struct linear_combination_iterator { virtual bool next(T & a, unsigned & i) = 0; diff --git a/src/util/lp/lp_bound_propagator.cpp b/src/util/lp/lp_bound_propagator.cpp new file mode 100644 index 000000000..53218fced --- /dev/null +++ b/src/util/lp/lp_bound_propagator.cpp @@ -0,0 +1,67 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ +#include "util/lp/lar_solver.h" +namespace lp { + lp_bound_propagator::lp_bound_propagator(lar_solver & ls): + m_lar_solver(ls) {} +column_type lp_bound_propagator::get_column_type(unsigned j) const { + return m_lar_solver.m_mpq_lar_core_solver.m_column_types()[j]; +} +const impq & lp_bound_propagator::get_low_bound(unsigned j) const { + return m_lar_solver.m_mpq_lar_core_solver.m_r_low_bounds()[j]; +} +const impq & lp_bound_propagator::get_upper_bound(unsigned j) const { + return m_lar_solver.m_mpq_lar_core_solver.m_r_upper_bounds()[j]; +} +void lp_bound_propagator::try_add_bound(const mpq & v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict) { + unsigned term_j = m_lar_solver.adjust_column_index_to_term_index(j); + mpq w = v; + if (term_j != j) { + j = term_j; + w += m_lar_solver.get_term(term_j).m_v; // when terms are turned into the columns they "lose" the right side, at this moment they aquire it back + } + lconstraint_kind kind = is_low? GE : LE; + if (strict) + kind = static_cast(kind / 2); + + if (!bound_is_interesting(j, kind, w)) + return; + unsigned k; // index to ibounds + if (is_low) { + if (try_get_val(m_improved_low_bounds, j, k)) { + auto & found_bound = m_ibounds[k]; + if (w > found_bound.m_bound || (w == found_bound.m_bound && found_bound.m_strict == false && strict)) + found_bound = implied_bound(w, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict); + } else { + m_improved_low_bounds[j] = m_ibounds.size(); + m_ibounds.push_back(implied_bound(w, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict)); + } + } else { // the upper bound case + if (try_get_val(m_improved_upper_bounds, j, k)) { + auto & found_bound = m_ibounds[k]; + if (w < found_bound.m_bound || (w == found_bound.m_bound && found_bound.m_strict == false && strict)) + found_bound = implied_bound(w, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict); + } else { + m_improved_upper_bounds[j] = m_ibounds.size(); + m_ibounds.push_back(implied_bound(w, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict)); + } + } +} +} diff --git a/src/util/lp/bound_propagator.h b/src/util/lp/lp_bound_propagator.h similarity index 74% rename from src/util/lp/bound_propagator.h rename to src/util/lp/lp_bound_propagator.h index 92523d75f..76870f457 100644 --- a/src/util/lp/bound_propagator.h +++ b/src/util/lp/lp_bound_propagator.h @@ -1,25 +1,40 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/lp/lp_settings.h" -namespace lean { +namespace lp { class lar_solver; -class bound_propagator { +class lp_bound_propagator { std::unordered_map m_improved_low_bounds; // these maps map a column index to the corresponding index in ibounds std::unordered_map m_improved_upper_bounds; lar_solver & m_lar_solver; public: vector m_ibounds; public: - bound_propagator(lar_solver & ls); + lp_bound_propagator(lar_solver & ls); column_type get_column_type(unsigned) const; const impq & get_low_bound(unsigned) const; const impq & get_upper_bound(unsigned) const; void try_add_bound(const mpq & v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict); virtual bool bound_is_interesting(unsigned vi, - lean::lconstraint_kind kind, + lp::lconstraint_kind kind, const rational & bval) {return true;} unsigned number_of_found_bounds() const { return m_ibounds.size(); } virtual void consume(mpq const& v, unsigned j) { std::cout << "doh\n"; } diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index a12b7b5d2..fd115669c 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include #include "util/vector.h" @@ -13,7 +28,7 @@ #include "util/lp/lu.h" #include "util/lp/permutation_matrix.h" #include "util/lp/column_namer.h" -namespace lean { +namespace lp { template // X represents the type of the x variable and the bounds class lp_core_solver_base { @@ -182,11 +197,11 @@ public: bool need_to_pivot_to_basis_tableau() const { - lean_assert(m_A.is_correct()); + SASSERT(m_A.is_correct()); unsigned m = m_A.row_count(); for (unsigned i = 0; i < m; i++) { unsigned bj = m_basis[i]; - lean_assert(m_A.m_columns[bj].size() > 0); + SASSERT(m_A.m_columns[bj].size() > 0); if (m_A.m_columns[bj].size() > 1 || m_A.get_val(m_A.m_columns[bj][0]) != one_of_type()) return true; } return false; @@ -195,7 +210,7 @@ public: bool reduced_costs_are_correct_tableau() const { if (m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) return true; - lean_assert(m_A.is_correct()); + SASSERT(m_A.is_correct()); if (m_using_infeas_costs) { if (infeasibility_costs_are_correct() == false) { std::cout << "infeasibility_costs_are_correct() does not hold" << std::endl; @@ -370,11 +385,11 @@ public: } bool make_column_feasible(unsigned j, numeric_pair & delta) { - lean_assert(m_basis_heading[j] < 0); + SASSERT(m_basis_heading[j] < 0); auto & x = m_x[j]; switch (m_column_types[j]) { case column_type::fixed: - lean_assert(m_low_bounds[j] == m_upper_bounds[j]); + SASSERT(m_low_bounds[j] == m_upper_bounds[j]); if (x != m_low_bounds[j]) { delta = m_low_bounds[j] - x; x = m_low_bounds[j]; @@ -410,7 +425,7 @@ public: case column_type::free_column: break; default: - lean_assert(false); + SASSERT(false); break; } return false; @@ -458,7 +473,7 @@ public: } void change_basis_unconditionally(unsigned entering, unsigned leaving) { - lean_assert(m_basis_heading[entering] < 0); + SASSERT(m_basis_heading[entering] < 0); int place_in_non_basis = -1 - m_basis_heading[entering]; if (static_cast(place_in_non_basis) >= m_nbasis.size()) { // entering variable in not in m_nbasis, we need to put it back; @@ -477,7 +492,7 @@ public: } void change_basis(unsigned entering, unsigned leaving) { - lean_assert(m_basis_heading[entering] < 0); + SASSERT(m_basis_heading[entering] < 0); int place_in_basis = m_basis_heading[leaving]; int place_in_non_basis = - m_basis_heading[entering] - 1; @@ -518,7 +533,7 @@ public: case column_type::free_column: break; default: - lean_assert(false); + SASSERT(false); break; } return true; @@ -566,7 +581,7 @@ public: case column_type::free_column: break; default: - lean_assert(false); + SASSERT(false); } std::cout << "basis heading = " << m_basis_heading[j] << std::endl; std::cout << "x = " << m_x[j] << std::endl; @@ -665,17 +680,17 @@ public: } void insert_column_into_inf_set(unsigned j) { m_inf_set.insert(j); - lean_assert(!column_is_feasible(j)); + SASSERT(!column_is_feasible(j)); } void remove_column_from_inf_set(unsigned j) { m_inf_set.erase(j); - lean_assert(column_is_feasible(j)); + SASSERT(column_is_feasible(j)); } bool costs_on_nbasis_are_zeros() const { - lean_assert(this->basis_heading_is_correct()); + SASSERT(this->basis_heading_is_correct()); for (unsigned j = 0; j < this->m_n(); j++) { if (this->m_basis_heading[j] < 0) - lean_assert(is_zero(this->m_costs[j])); + SASSERT(is_zero(this->m_costs[j])); } return true; } diff --git a/src/util/lp/lp_core_solver_base.hpp b/src/util/lp/lp_core_solver_base.hpp index a0dba9de7..b49dd0638 100644 --- a/src/util/lp/lp_core_solver_base.hpp +++ b/src/util/lp/lp_core_solver_base.hpp @@ -1,13 +1,28 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include "util/vector.h" #include "util/lp/lp_utils.h" #include "util/lp/lp_core_solver_base.h" -namespace lean { +namespace lp { template lp_core_solver_base:: lp_core_solver_base(static_matrix & A, @@ -53,7 +68,7 @@ lp_core_solver_base(static_matrix & A, m_tracing_basis_changes(false), m_pivoted_rows(nullptr), m_look_for_feasible_solution_only(false) { - lean_assert(bounds_for_boxed_are_set_correctly()); + SASSERT(bounds_for_boxed_are_set_correctly()); init(); init_basis_heading_and_non_basic_columns_vector(); } @@ -61,7 +76,7 @@ lp_core_solver_base(static_matrix & A, template void lp_core_solver_base:: allocate_basis_heading() { // the rest of initilization will be handled by the factorization class init_basis_heading_and_non_basic_columns_vector(); - lean_assert(basis_heading_is_correct()); + SASSERT(basis_heading_is_correct()); } template void lp_core_solver_base:: init() { @@ -83,8 +98,8 @@ pivot_for_tableau_on_basis() { // i is the pivot row, and j is the pivot column template void lp_core_solver_base:: pivot_to_reduced_costs_tableau(unsigned i, unsigned j) { - if (j >= m_d.size()) - return; + if (j >= m_d.size()) + return; T &a = m_d[j]; if (is_zero(a)) return; @@ -127,7 +142,7 @@ solve_yB(vector & y) { // } // } template void lp_core_solver_base::solve_Bd(unsigned entering, indexed_vector & column) { - lean_assert(!m_settings.use_tableau()); + SASSERT(!m_settings.use_tableau()); if (m_factorization == nullptr) { init_factorization(m_factorization, m_A, m_basis, m_settings); } @@ -137,19 +152,19 @@ template void lp_core_solver_base::solve_Bd(unsig template void lp_core_solver_base:: solve_Bd(unsigned entering) { - lean_assert(m_ed.is_OK()); + SASSERT(m_ed.is_OK()); m_factorization->solve_Bd(entering, m_ed, m_w); if (this->precise()) m_columns_nz[entering] = m_ed.m_index.size(); - lean_assert(m_ed.is_OK()); - lean_assert(m_w.is_OK()); -#ifdef LEAN_DEBUG + SASSERT(m_ed.is_OK()); + SASSERT(m_w.is_OK()); +#ifdef Z3DEBUG // auto B = get_B(*m_factorization, m_basis); // vector a(m_m()); // m_A.copy_column_to_vector(entering, a); // vector cd(m_ed.m_data); // B.apply_from_left(cd, m_settings); - // lean_assert(vectors_are_equal(cd , a)); + // SASSERT(vectors_are_equal(cd , a)); #endif } @@ -208,7 +223,7 @@ restore_m_ed(T * buffer) { template bool lp_core_solver_base:: A_mult_x_is_off() const { - lean_assert(m_x.size() == m_A.column_count()); + SASSERT(m_x.size() == m_A.column_count()); if (numeric_traits::precise()) { for (unsigned i = 0; i < m_m(); i++) { X delta = m_b[i] - m_A.dot_product_with_row(i, m_x); @@ -244,7 +259,7 @@ A_mult_x_is_off() const { } template bool lp_core_solver_base:: A_mult_x_is_off_on_index(const vector & index) const { - lean_assert(m_x.size() == m_A.column_count()); + SASSERT(m_x.size() == m_A.column_count()); if (numeric_traits::precise()) return false; #if RUN_A_MULT_X_IS_OFF_FOR_PRECESE for (unsigned i : index) { @@ -284,13 +299,13 @@ A_mult_x_is_off_on_index(const vector & index) const { // from page 182 of Istvan Maros's book template void lp_core_solver_base:: calculate_pivot_row_of_B_1(unsigned pivot_row) { - lean_assert(! use_tableau()); - lean_assert(m_pivot_row_of_B_1.is_OK()); + SASSERT(! use_tableau()); + SASSERT(m_pivot_row_of_B_1.is_OK()); m_pivot_row_of_B_1.clear(); m_pivot_row_of_B_1.set_value(numeric_traits::one(), pivot_row); - lean_assert(m_pivot_row_of_B_1.is_OK()); + SASSERT(m_pivot_row_of_B_1.is_OK()); m_factorization->solve_yB_with_error_check_indexed(m_pivot_row_of_B_1, m_basis_heading, m_basis, m_settings); - lean_assert(m_pivot_row_of_B_1.is_OK()); + SASSERT(m_pivot_row_of_B_1.is_OK()); } @@ -380,11 +395,11 @@ set_non_basic_x_to_correct_bounds() { break; case column_type::low_bound: m_x[j] = m_low_bounds[j]; - lean_assert(column_is_dual_feasible(j)); + SASSERT(column_is_dual_feasible(j)); break; case column_type::upper_bound: m_x[j] = m_upper_bounds[j]; - lean_assert(column_is_dual_feasible(j)); + SASSERT(column_is_dual_feasible(j)); break; default: break; @@ -402,15 +417,15 @@ column_is_dual_feasible(unsigned j) const { return x_is_at_low_bound(j) && d_is_not_negative(j); case column_type::upper_bound: LP_OUT(m_settings, "upper_bound type should be switched to low_bound" << std::endl); - lean_assert(false); // impossible case + SASSERT(false); // impossible case case column_type::free_column: return numeric_traits::is_zero(m_d[j]); default: LP_OUT(m_settings, "column = " << j << std::endl); LP_OUT(m_settings, "unexpected column type = " << column_type_to_string(m_column_types[j]) << std::endl); - lean_unreachable(); + SASSERT(false); } - lean_unreachable(); + SASSERT(false); return false; } template bool lp_core_solver_base:: @@ -493,7 +508,7 @@ template bool lp_core_solver_base::column_is_feas return true; break; default: - lean_unreachable(); + SASSERT(false); } return false; // it is unreachable } @@ -575,7 +590,7 @@ update_basis_and_x(int entering, int leaving, X const & tt) { restore_x_and_refactor(entering, leaving, tt); if (m_status == FLOATING_POINT_ERROR) return false; - lean_assert(!A_mult_x_is_off()); + SASSERT(!A_mult_x_is_off()); m_iters_with_no_cost_growing++; // LP_OUT(m_settings, "rolled back after failing of init_factorization()" << std::endl); m_status = UNSTABLE; @@ -587,7 +602,7 @@ update_basis_and_x(int entering, int leaving, X const & tt) { template bool lp_core_solver_base:: divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { - lean_assert(numeric_traits::precise()); + SASSERT(numeric_traits::precise()); int pivot_index = -1; auto & row = m_A.m_rows[pivot_row]; unsigned size = row.size(); @@ -628,7 +643,7 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) { return false; if (pivot_col_cell_index != 0) { - lean_assert(column.size() > 1); + SASSERT(column.size() > 1); // swap the pivot column cell with the head cell auto c = column[0]; column[0] = column[pivot_col_cell_index]; @@ -639,7 +654,7 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) { } while (column.size() > 1) { auto & c = column.back(); - lean_assert(c.m_i != piv_row_index); + SASSERT(c.m_i != piv_row_index); if(! m_A.pivot_row_to_row_given_cell(piv_row_index, c, j)) { return false; } @@ -687,7 +702,7 @@ non_basis_is_correctly_represented_in_heading() const { } for (unsigned j = 0; j < m_A.column_count(); j++) { if (m_basis_heading[j] >= 0) { - lean_assert(static_cast(m_basis_heading[j]) < m_A.row_count() && m_basis[m_basis_heading[j]] == j); + SASSERT(static_cast(m_basis_heading[j]) < m_A.row_count() && m_basis[m_basis_heading[j]] == j); } } return true; @@ -695,9 +710,9 @@ non_basis_is_correctly_represented_in_heading() const { template bool lp_core_solver_base:: basis_heading_is_correct() const { - lean_assert(m_basis_heading.size() == m_A.column_count()); - lean_assert(m_basis.size() == m_A.row_count()); - lean_assert(m_nbasis.size() <= m_A.column_count() - m_A.row_count()); // for the dual the size of non basis can be smaller + SASSERT(m_basis_heading.size() == m_A.column_count()); + SASSERT(m_basis.size() == m_A.row_count()); + SASSERT(m_nbasis.size() <= m_A.column_count() - m_A.row_count()); // for the dual the size of non basis can be smaller if (!basis_has_no_doubles()) { // std::cout << "basis_has_no_doubles" << std::endl; return false; @@ -841,7 +856,7 @@ solve_Ax_eq_b() { template void lp_core_solver_base:: snap_non_basic_x_to_bound_and_free_to_zeroes() { for (unsigned j : non_basis()) { - lean_assert(j < m_x.size()); + SASSERT(j < m_x.size()); switch (m_column_types[j]) { case column_type::fixed: case column_type::boxed: @@ -892,9 +907,9 @@ get_non_basic_column_value_position(unsigned j) const { case column_type::upper_bound: return x_is_at_upper_bound(j)? at_upper_bound : not_at_bound; default: - lean_unreachable(); + SASSERT(false); } - lean_unreachable(); + SASSERT(false); return at_low_bound; } @@ -958,7 +973,7 @@ template void lp_core_solver_base::pivot_fixed_v break; } } - lean_assert(m_factorization->get_status()== LU_status::OK); + SASSERT(m_factorization->get_status()== LU_status::OK); } } @@ -966,7 +981,7 @@ template bool lp_core_solver_base::infeasibility_costs_are_correct() const { if (! this->m_using_infeas_costs) return true; - lean_assert(costs_on_nbasis_are_zeros()); + SASSERT(costs_on_nbasis_are_zeros()); for (unsigned j :this->m_basis) { if (!infeasibility_cost_is_correct_for_column(j)) { std::cout << "infeasibility_cost_is_correct_for_column does not hold\n"; @@ -1011,7 +1026,7 @@ lp_core_solver_base::infeasibility_cost_is_correct_for_column(unsigned j) case column_type::free_column: return is_zero(this->m_costs[j]); default: - lean_assert(false); + SASSERT(false); return true; } } diff --git a/src/util/lp/lp_core_solver_base_instances.cpp b/src/util/lp/lp_core_solver_base_instances.cpp index 17dcb87db..f5853eecf 100644 --- a/src/util/lp/lp_core_solver_base_instances.cpp +++ b/src/util/lp/lp_core_solver_base_instances.cpp @@ -1,131 +1,146 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include #include "util/vector.h" #include #include "util/lp/lp_core_solver_base.hpp" -template bool lean::lp_core_solver_base::A_mult_x_is_off() const; -template bool lean::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; -template bool lean::lp_core_solver_base::basis_heading_is_correct() const; -template void lean::lp_core_solver_base::calculate_pivot_row_of_B_1(unsigned int); -template void lean::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); -template bool lean::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; -template void lean::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); -template bool lean::lp_core_solver_base::find_x_by_solving(); -template lean::non_basic_column_value_position lean::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; -template lean::non_basic_column_value_position lean::lp_core_solver_base >::get_non_basic_column_value_position(unsigned int) const; -template lean::non_basic_column_value_position lean::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; -template void lean::lp_core_solver_base::init_reduced_costs_for_one_iteration(); -template lean::lp_core_solver_base::lp_core_solver_base( - lean::static_matrix&, vector&, +template bool lp::lp_core_solver_base::A_mult_x_is_off() const; +template bool lp::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; +template bool lp::lp_core_solver_base::basis_heading_is_correct() const; +template void lp::lp_core_solver_base::calculate_pivot_row_of_B_1(unsigned int); +template void lp::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); +template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; +template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); +template bool lp::lp_core_solver_base::find_x_by_solving(); +template lp::non_basic_column_value_position lp::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; +template lp::non_basic_column_value_position lp::lp_core_solver_base >::get_non_basic_column_value_position(unsigned int) const; +template lp::non_basic_column_value_position lp::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; +template void lp::lp_core_solver_base::init_reduced_costs_for_one_iteration(); +template lp::lp_core_solver_base::lp_core_solver_base( + lp::static_matrix&, vector&, vector&, vector &, vector &, vector&, vector&, - lean::lp_settings&, const column_namer&, const vector&, + lp::lp_settings&, const column_namer&, const vector&, const vector&, const vector&); -template bool lean::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); -template bool lean::lp_core_solver_base >::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); -template void lean::lp_core_solver_base::restore_x(unsigned int, double const&); -template void lean::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); -template void lean::lp_core_solver_base::snap_xN_to_bounds_and_free_columns_to_zeroes(); -template void lean::lp_core_solver_base >::snap_xN_to_bounds_and_free_columns_to_zeroes(); -template void lean::lp_core_solver_base::solve_Ax_eq_b(); -template void lean::lp_core_solver_base::solve_Bd(unsigned int); -template void lean::lp_core_solver_base>::solve_Bd(unsigned int, indexed_vector&); -template void lean::lp_core_solver_base::solve_yB(vector&); -template bool lean::lp_core_solver_base::update_basis_and_x(int, int, double const&); -template void lean::lp_core_solver_base::update_x(unsigned int, const double&); -template bool lean::lp_core_solver_base::A_mult_x_is_off() const; -template bool lean::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; -template bool lean::lp_core_solver_base::basis_heading_is_correct() const ; -template void lean::lp_core_solver_base::calculate_pivot_row_of_B_1(unsigned int); -template void lean::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); -template bool lean::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; -template void lean::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); -template bool lean::lp_core_solver_base::find_x_by_solving(); -template void lean::lp_core_solver_base::init_reduced_costs_for_one_iteration(); -template bool lean::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); -template void lean::lp_core_solver_base::restore_x(unsigned int, lean::mpq const&); -template void lean::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); -template void lean::lp_core_solver_base::solve_Ax_eq_b(); -template void lean::lp_core_solver_base::solve_Bd(unsigned int); -template void lean::lp_core_solver_base::solve_yB(vector&); -template bool lean::lp_core_solver_base::update_basis_and_x(int, int, lean::mpq const&); -template void lean::lp_core_solver_base::update_x(unsigned int, const lean::mpq&); -template void lean::lp_core_solver_base >::calculate_pivot_row_of_B_1(unsigned int); -template void lean::lp_core_solver_base >::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); -template void lean::lp_core_solver_base >::init(); -template void lean::lp_core_solver_base >::init_basis_heading_and_non_basic_columns_vector(); -template void lean::lp_core_solver_base >::init_reduced_costs_for_one_iteration(); -template lean::lp_core_solver_base >::lp_core_solver_base(lean::static_matrix >&, vector >&, vector&, vector &, vector &, vector >&, vector&, lean::lp_settings&, const column_namer&, const vector&, - const vector >&, - const vector >&); -template bool lean::lp_core_solver_base >::print_statistics_with_cost_and_check_that_the_time_is_over(lean::numeric_pair, std::ostream&); -template void lean::lp_core_solver_base >::snap_xN_to_bounds_and_fill_xB(); -template void lean::lp_core_solver_base >::solve_Bd(unsigned int); -template bool lean::lp_core_solver_base >::update_basis_and_x(int, int, lean::numeric_pair const&); -template void lean::lp_core_solver_base >::update_x(unsigned int, const lean::numeric_pair&); -template lean::lp_core_solver_base::lp_core_solver_base( - lean::static_matrix&, - vector&, +template bool lp::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); +template bool lp::lp_core_solver_base >::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); +template void lp::lp_core_solver_base::restore_x(unsigned int, double const&); +template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); +template void lp::lp_core_solver_base::snap_xN_to_bounds_and_free_columns_to_zeroes(); +template void lp::lp_core_solver_base >::snap_xN_to_bounds_and_free_columns_to_zeroes(); +template void lp::lp_core_solver_base::solve_Ax_eq_b(); +template void lp::lp_core_solver_base::solve_Bd(unsigned int); +template void lp::lp_core_solver_base>::solve_Bd(unsigned int, indexed_vector&); +template void lp::lp_core_solver_base::solve_yB(vector&); +template bool lp::lp_core_solver_base::update_basis_and_x(int, int, double const&); +template void lp::lp_core_solver_base::update_x(unsigned int, const double&); +template bool lp::lp_core_solver_base::A_mult_x_is_off() const; +template bool lp::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; +template bool lp::lp_core_solver_base::basis_heading_is_correct() const ; +template void lp::lp_core_solver_base::calculate_pivot_row_of_B_1(unsigned int); +template void lp::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); +template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; +template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); +template bool lp::lp_core_solver_base::find_x_by_solving(); +template void lp::lp_core_solver_base::init_reduced_costs_for_one_iteration(); +template bool lp::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); +template void lp::lp_core_solver_base::restore_x(unsigned int, lp::mpq const&); +template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); +template void lp::lp_core_solver_base::solve_Ax_eq_b(); +template void lp::lp_core_solver_base::solve_Bd(unsigned int); +template void lp::lp_core_solver_base::solve_yB(vector&); +template bool lp::lp_core_solver_base::update_basis_and_x(int, int, lp::mpq const&); +template void lp::lp_core_solver_base::update_x(unsigned int, const lp::mpq&); +template void lp::lp_core_solver_base >::calculate_pivot_row_of_B_1(unsigned int); +template void lp::lp_core_solver_base >::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); +template void lp::lp_core_solver_base >::init(); +template void lp::lp_core_solver_base >::init_basis_heading_and_non_basic_columns_vector(); +template void lp::lp_core_solver_base >::init_reduced_costs_for_one_iteration(); +template lp::lp_core_solver_base >::lp_core_solver_base(lp::static_matrix >&, vector >&, vector&, vector &, vector &, vector >&, vector&, lp::lp_settings&, const column_namer&, const vector&, + const vector >&, + const vector >&); +template bool lp::lp_core_solver_base >::print_statistics_with_cost_and_check_that_the_time_is_over(lp::numeric_pair, std::ostream&); +template void lp::lp_core_solver_base >::snap_xN_to_bounds_and_fill_xB(); +template void lp::lp_core_solver_base >::solve_Bd(unsigned int); +template bool lp::lp_core_solver_base >::update_basis_and_x(int, int, lp::numeric_pair const&); +template void lp::lp_core_solver_base >::update_x(unsigned int, const lp::numeric_pair&); +template lp::lp_core_solver_base::lp_core_solver_base( + lp::static_matrix&, + vector&, vector&, vector &, vector &, - vector&, - vector&, - lean::lp_settings&, + vector&, + vector&, + lp::lp_settings&, const column_namer&, - const vector&, - const vector&, - const vector&); -template bool lean::lp_core_solver_base >::print_statistics_with_iterations_and_check_that_the_time_is_over(std::ostream &); -template std::string lean::lp_core_solver_base::column_name(unsigned int) const; -template void lean::lp_core_solver_base::pretty_print(std::ostream & out); -template void lean::lp_core_solver_base::restore_state(double*, double*); -template void lean::lp_core_solver_base::save_state(double*, double*); -template std::string lean::lp_core_solver_base::column_name(unsigned int) const; -template void lean::lp_core_solver_base::pretty_print(std::ostream & out); -template void lean::lp_core_solver_base::restore_state(lean::mpq*, lean::mpq*); -template void lean::lp_core_solver_base::save_state(lean::mpq*, lean::mpq*); -template std::string lean::lp_core_solver_base >::column_name(unsigned int) const; -template void lean::lp_core_solver_base >::pretty_print(std::ostream & out); -template void lean::lp_core_solver_base >::restore_state(lean::mpq*, lean::mpq*); -template void lean::lp_core_solver_base >::save_state(lean::mpq*, lean::mpq*); -template void lean::lp_core_solver_base >::solve_yB(vector&); -template void lean::lp_core_solver_base::init_lu(); -template void lean::lp_core_solver_base::init_lu(); -template int lean::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; -template int lean::lp_core_solver_base >::pivots_in_column_and_row_are_different(int, int) const; -template int lean::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; -template bool lean::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; -template bool lean::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; -template bool lean::lp_core_solver_base >::calc_current_x_is_feasible_include_non_basis() const; -template void lean::lp_core_solver_base >::pivot_fixed_vars_from_basis(); -template bool lean::lp_core_solver_base::column_is_feasible(unsigned int) const; -template bool lean::lp_core_solver_base::column_is_feasible(unsigned int) const; -// template void lean::lp_core_solver_base >::print_linear_combination_of_column_indices(vector, std::allocator > > const&, std::ostream&) const; -template bool lean::lp_core_solver_base >::column_is_feasible(unsigned int) const; -template bool lean::lp_core_solver_base >::snap_non_basic_x_to_bound(); -template void lean::lp_core_solver_base >::init_lu(); -template bool lean::lp_core_solver_base >::A_mult_x_is_off_on_index(vector const&) const; -template bool lean::lp_core_solver_base >::find_x_by_solving(); -template void lean::lp_core_solver_base >::restore_x(unsigned int, lean::numeric_pair const&); -template bool lean::lp_core_solver_base::pivot_for_tableau_on_basis(); -template bool lean::lp_core_solver_base::pivot_for_tableau_on_basis(); -template bool lean::lp_core_solver_base>::pivot_for_tableau_on_basis(); -template bool lean::lp_core_solver_base>::pivot_column_tableau(unsigned int, unsigned int); -template bool lean::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); -template bool lean::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); -template void lean::lp_core_solver_base >::transpose_rows_tableau(unsigned int, unsigned int); -template bool lean::lp_core_solver_base >::inf_set_is_correct() const; -template bool lean::lp_core_solver_base::inf_set_is_correct() const; -template bool lean::lp_core_solver_base::inf_set_is_correct() const; -template bool lean::lp_core_solver_base >::infeasibility_costs_are_correct() const; -template bool lean::lp_core_solver_base::infeasibility_costs_are_correct() const; -template bool lean::lp_core_solver_base::infeasibility_costs_are_correct() const; + const vector&, + const vector&, + const vector&); +template bool lp::lp_core_solver_base >::print_statistics_with_iterations_and_check_that_the_time_is_over(std::ostream &); +template std::string lp::lp_core_solver_base::column_name(unsigned int) const; +template void lp::lp_core_solver_base::pretty_print(std::ostream & out); +template void lp::lp_core_solver_base::restore_state(double*, double*); +template void lp::lp_core_solver_base::save_state(double*, double*); +template std::string lp::lp_core_solver_base::column_name(unsigned int) const; +template void lp::lp_core_solver_base::pretty_print(std::ostream & out); +template void lp::lp_core_solver_base::restore_state(lp::mpq*, lp::mpq*); +template void lp::lp_core_solver_base::save_state(lp::mpq*, lp::mpq*); +template std::string lp::lp_core_solver_base >::column_name(unsigned int) const; +template void lp::lp_core_solver_base >::pretty_print(std::ostream & out); +template void lp::lp_core_solver_base >::restore_state(lp::mpq*, lp::mpq*); +template void lp::lp_core_solver_base >::save_state(lp::mpq*, lp::mpq*); +template void lp::lp_core_solver_base >::solve_yB(vector&); +template void lp::lp_core_solver_base::init_lu(); +template void lp::lp_core_solver_base::init_lu(); +template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; +template int lp::lp_core_solver_base >::pivots_in_column_and_row_are_different(int, int) const; +template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; +template bool lp::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; +template bool lp::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; +template bool lp::lp_core_solver_base >::calc_current_x_is_feasible_include_non_basis() const; +template void lp::lp_core_solver_base >::pivot_fixed_vars_from_basis(); +template bool lp::lp_core_solver_base::column_is_feasible(unsigned int) const; +template bool lp::lp_core_solver_base::column_is_feasible(unsigned int) const; +// template void lp::lp_core_solver_base >::print_linear_combination_of_column_indices(vector, std::allocator > > const&, std::ostream&) const; +template bool lp::lp_core_solver_base >::column_is_feasible(unsigned int) const; +template bool lp::lp_core_solver_base >::snap_non_basic_x_to_bound(); +template void lp::lp_core_solver_base >::init_lu(); +template bool lp::lp_core_solver_base >::A_mult_x_is_off_on_index(vector const&) const; +template bool lp::lp_core_solver_base >::find_x_by_solving(); +template void lp::lp_core_solver_base >::restore_x(unsigned int, lp::numeric_pair const&); +template bool lp::lp_core_solver_base::pivot_for_tableau_on_basis(); +template bool lp::lp_core_solver_base::pivot_for_tableau_on_basis(); +template bool lp::lp_core_solver_base>::pivot_for_tableau_on_basis(); +template bool lp::lp_core_solver_base>::pivot_column_tableau(unsigned int, unsigned int); +template bool lp::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); +template bool lp::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); +template void lp::lp_core_solver_base >::transpose_rows_tableau(unsigned int, unsigned int); +template bool lp::lp_core_solver_base >::inf_set_is_correct() const; +template bool lp::lp_core_solver_base::inf_set_is_correct() const; +template bool lp::lp_core_solver_base::inf_set_is_correct() const; +template bool lp::lp_core_solver_base >::infeasibility_costs_are_correct() const; +template bool lp::lp_core_solver_base::infeasibility_costs_are_correct() const; +template bool lp::lp_core_solver_base::infeasibility_costs_are_correct() const; diff --git a/src/util/lp/lp_dual_core_solver.h b/src/util/lp/lp_dual_core_solver.h index b873cb711..ba4be494f 100644 --- a/src/util/lp/lp_dual_core_solver.h +++ b/src/util/lp/lp_dual_core_solver.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/lp/static_matrix.h" #include "util/lp/lp_core_solver_base.h" @@ -11,7 +26,7 @@ #include #include "util/vector.h" -namespace lean { +namespace lp { template class lp_dual_core_solver:public lp_core_solver_base { public: diff --git a/src/util/lp/lp_dual_core_solver.hpp b/src/util/lp/lp_dual_core_solver.hpp index 6565331b3..5d48fe24d 100644 --- a/src/util/lp/lp_dual_core_solver.hpp +++ b/src/util/lp/lp_dual_core_solver.hpp @@ -1,13 +1,28 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include "util/vector.h" #include "util/lp/lp_dual_core_solver.h" -namespace lean { +namespace lp { template void lp_dual_core_solver::init_a_wave_by_zeros() { unsigned j = this->m_m(); @@ -23,7 +38,7 @@ template void lp_dual_core_solver::restore_non_ba while (j--) { if (this->m_basis_heading[j] >= 0 ) continue; if (m_can_enter_basis[j]) { - lean_assert(std::find(nb.begin(), nb.end(), j) == nb.end()); + SASSERT(std::find(nb.begin(), nb.end(), j) == nb.end()); nb.push_back(j); this->m_basis_heading[j] = - static_cast(nb.size()); } @@ -93,14 +108,14 @@ template bool lp_dual_core_solver::done() { } template T lp_dual_core_solver::get_edge_steepness_for_low_bound(unsigned p) { - lean_assert(this->m_basis_heading[p] >= 0 && static_cast(this->m_basis_heading[p]) < this->m_m()); + SASSERT(this->m_basis_heading[p] >= 0 && static_cast(this->m_basis_heading[p]) < this->m_m()); T del = this->m_x[p] - this->m_low_bounds[p]; del *= del; return del / this->m_betas[this->m_basis_heading[p]]; } template T lp_dual_core_solver::get_edge_steepness_for_upper_bound(unsigned p) { - lean_assert(this->m_basis_heading[p] >= 0 && static_cast(this->m_basis_heading[p]) < this->m_m()); + SASSERT(this->m_basis_heading[p] >= 0 && static_cast(this->m_basis_heading[p]) < this->m_m()); T del = this->m_x[p] - this->m_upper_bounds[p]; del *= del; return del / this->m_betas[this->m_basis_heading[p]]; @@ -135,12 +150,12 @@ template T lp_dual_core_solver::pricing_for_row(u return numeric_traits::zero(); break; case column_type::free_column: - lean_assert(numeric_traits::is_zero(this->m_d[p])); + SASSERT(numeric_traits::is_zero(this->m_d[p])); return numeric_traits::zero(); default: - lean_unreachable(); + SASSERT(false); } - lean_unreachable(); + SASSERT(false); return numeric_traits::zero(); } @@ -209,9 +224,9 @@ template bool lp_dual_core_solver::advance_on_kno int pivot_compare_result = this->pivots_in_column_and_row_are_different(m_q, m_p); if (!pivot_compare_result){;} else if (pivot_compare_result == 2) { // the sign is changed, cannot continue - lean_unreachable(); // not implemented yet + SASSERT(false); // not implemented yet } else { - lean_assert(pivot_compare_result == 1); + SASSERT(pivot_compare_result == 1); this->init_lu(); } DSE_FTran(); @@ -228,21 +243,21 @@ template int lp_dual_core_solver::define_sign_of_ if (this->x_above_upper_bound(m_p)) { return 1; } - lean_unreachable(); + SASSERT(false); case column_type::low_bound: if (this->x_below_low_bound(m_p)) { return -1; } - lean_unreachable(); + SASSERT(false); case column_type::upper_bound: if (this->x_above_upper_bound(m_p)) { return 1; } - lean_unreachable(); + SASSERT(false); default: - lean_unreachable(); + SASSERT(false); } - lean_unreachable(); + SASSERT(false); return 0; } @@ -250,10 +265,10 @@ template bool lp_dual_core_solver::can_be_breakpo if (this->pivot_row_element_is_too_small_for_ratio_test(j)) return false; switch (this->m_column_types[j]) { case column_type::low_bound: - lean_assert(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_low_bounds[j])); + SASSERT(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_low_bounds[j])); return m_sign_of_alpha_r * this->m_pivot_row[j] > 0; case column_type::upper_bound: - lean_assert(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_upper_bounds[j])); + SASSERT(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_upper_bounds[j])); return m_sign_of_alpha_r * this->m_pivot_row[j] < 0; case column_type::boxed: { @@ -292,23 +307,23 @@ template T lp_dual_core_solver::get_delta() { if (this->x_above_upper_bound(m_p)) { return this->m_x[m_p] - this->m_upper_bounds[m_p]; } - lean_unreachable(); + SASSERT(false); case column_type::low_bound: if (this->x_below_low_bound(m_p)) { return this->m_x[m_p] - this->m_low_bounds[m_p]; } - lean_unreachable(); + SASSERT(false); case column_type::upper_bound: if (this->x_above_upper_bound(m_p)) { return get_edge_steepness_for_upper_bound(m_p); } - lean_unreachable(); + SASSERT(false); case column_type::fixed: return this->m_x[m_p] - this->m_upper_bounds[m_p]; default: - lean_unreachable(); + SASSERT(false); } - lean_unreachable(); + SASSERT(false); return zero_of_type(); } @@ -355,7 +370,7 @@ template void lp_dual_core_solver::update_betas() template void lp_dual_core_solver::apply_flips() { for (unsigned j : m_flipped_boxed) { - lean_assert(this->x_is_at_bound(j)); + SASSERT(this->x_is_at_bound(j)); if (this->x_is_at_low_bound(j)) { this->m_x[j] = this->m_upper_bounds[j]; } else { @@ -385,7 +400,7 @@ template void lp_dual_core_solver::snap_xN_column case column_type::free_column: break; default: - lean_unreachable(); + SASSERT(false); } } @@ -441,7 +456,7 @@ template bool lp_dual_core_solver::basis_change_a return false; } - lean_assert(d_is_correct()); + SASSERT(d_is_correct()); return true; } @@ -457,7 +472,7 @@ template void lp_dual_core_solver::recover_leavin case free_of_bounds: this->m_x[m_q] = zero_of_type(); default: - lean_unreachable(); + SASSERT(false); } } @@ -584,7 +599,7 @@ template bool lp_dual_core_solver::tight_breakpoi template T lp_dual_core_solver::calculate_harris_delta_on_breakpoint_set() { bool first_time = true; T ret = zero_of_type(); - lean_assert(m_breakpoint_set.size() > 0); + SASSERT(m_breakpoint_set.size() > 0); for (auto j : m_breakpoint_set) { T t; if (this->x_is_at_low_bound(j)) { @@ -633,7 +648,7 @@ template void lp_dual_core_solver::find_q_on_tigh } } m_tight_set.erase(m_q); - lean_assert(m_q != -1); + SASSERT(m_q != -1); } template void lp_dual_core_solver::find_q_and_tight_set() { @@ -722,13 +737,13 @@ template void lp_dual_core_solver::one_iteration( this->set_status(FEASIBLE); } pricing_loop(number_of_rows_to_try, offset_in_rows); - lean_assert(problem_is_dual_feasible()); + SASSERT(problem_is_dual_feasible()); } template void lp_dual_core_solver::solve() { // see the page 35 - lean_assert(d_is_correct()); - lean_assert(problem_is_dual_feasible()); - lean_assert(this->basis_heading_is_correct()); + SASSERT(d_is_correct()); + SASSERT(problem_is_dual_feasible()); + SASSERT(this->basis_heading_is_correct()); this->set_total_iterations(0); this->iters_with_no_cost_growing() = 0; do { diff --git a/src/util/lp/lp_dual_core_solver_instances.cpp b/src/util/lp/lp_dual_core_solver_instances.cpp index 8016088f8..db68bda65 100644 --- a/src/util/lp/lp_dual_core_solver_instances.cpp +++ b/src/util/lp/lp_dual_core_solver_instances.cpp @@ -1,29 +1,44 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include #include "util/vector.h" #include #include "util/lp/lp_dual_core_solver.hpp" -template void lean::lp_dual_core_solver::start_with_initial_basis_and_make_it_dual_feasible(); -template void lean::lp_dual_core_solver::solve(); -template lean::lp_dual_core_solver::lp_dual_core_solver(lean::static_matrix&, vector&, +template void lp::lp_dual_core_solver::start_with_initial_basis_and_make_it_dual_feasible(); +template void lp::lp_dual_core_solver::solve(); +template lp::lp_dual_core_solver::lp_dual_core_solver(lp::static_matrix&, vector&, vector&, vector&, vector&, vector &, vector &, vector&, - vector&, + vector&, vector&, vector&, - lean::lp_settings&, const lean::column_namer&); -template void lean::lp_dual_core_solver::start_with_initial_basis_and_make_it_dual_feasible(); -template void lean::lp_dual_core_solver::solve(); -template void lean::lp_dual_core_solver::restore_non_basis(); -template void lean::lp_dual_core_solver::restore_non_basis(); -template void lean::lp_dual_core_solver::revert_to_previous_basis(); -template void lean::lp_dual_core_solver::revert_to_previous_basis(); + lp::lp_settings&, const lp::column_namer&); +template void lp::lp_dual_core_solver::start_with_initial_basis_and_make_it_dual_feasible(); +template void lp::lp_dual_core_solver::solve(); +template void lp::lp_dual_core_solver::restore_non_basis(); +template void lp::lp_dual_core_solver::restore_non_basis(); +template void lp::lp_dual_core_solver::revert_to_previous_basis(); +template void lp::lp_dual_core_solver::revert_to_previous_basis(); diff --git a/src/util/lp/lp_dual_simplex.h b/src/util/lp/lp_dual_simplex.h index 4dff2a4f1..c17a9e99e 100644 --- a/src/util/lp/lp_dual_simplex.h +++ b/src/util/lp/lp_dual_simplex.h @@ -1,13 +1,28 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include "util/lp/lp_utils.h" #include "util/lp/lp_solver.h" #include "util/lp/lp_dual_core_solver.h" -namespace lean { +namespace lp { template class lp_dual_simplex: public lp_solver { diff --git a/src/util/lp/lp_dual_simplex.hpp b/src/util/lp/lp_dual_simplex.hpp index 5047e117f..248dff448 100644 --- a/src/util/lp/lp_dual_simplex.hpp +++ b/src/util/lp/lp_dual_simplex.hpp @@ -1,9 +1,24 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/lp_dual_simplex.h" -namespace lean{ +namespace lp{ template void lp_dual_simplex::decide_on_status_after_stage1() { switch (m_core_solver->get_status()) { @@ -15,7 +30,7 @@ template void lp_dual_simplex::decide_on_status_a } break; case DUAL_UNBOUNDED: - lean_unreachable(); + SASSERT(false); case ITERATIONS_EXHAUSTED: this->m_status = ITERATIONS_EXHAUSTED; break; @@ -26,12 +41,12 @@ template void lp_dual_simplex::decide_on_status_a this->m_status = FLOATING_POINT_ERROR; break; default: - lean_unreachable(); + SASSERT(false); } } template void lp_dual_simplex::fix_logical_for_stage2(unsigned j) { - lean_assert(j >= this->number_of_core_structurals()); + SASSERT(j >= this->number_of_core_structurals()); switch (m_column_types_of_logicals[j - this->number_of_core_structurals()]) { case column_type::low_bound: m_low_bounds[j] = numeric_traits::zero(); @@ -44,7 +59,7 @@ template void lp_dual_simplex::fix_logical_for_st m_can_enter_basis[j] = false; break; default: - lean_unreachable(); + SASSERT(false); } } @@ -58,7 +73,7 @@ template void lp_dual_simplex::fix_structural_for break; case column_type::fixed: case column_type::upper_bound: - lean_unreachable(); + SASSERT(false); case column_type::boxed: this->m_upper_bounds[j] = ci->get_adjusted_upper_bound() / this->m_column_scale[j]; m_low_bounds[j] = numeric_traits::zero(); @@ -70,7 +85,7 @@ template void lp_dual_simplex::fix_structural_for m_column_types_of_core_solver[j] = column_type::free_column; break; default: - lean_unreachable(); + SASSERT(false); } // T cost_was = this->m_costs[j]; this->set_scaled_cost(j); @@ -115,7 +130,7 @@ template void lp_dual_simplex::solve_for_stage2() this->m_status = FLOATING_POINT_ERROR; break; default: - lean_unreachable(); + SASSERT(false); } this->m_second_stage_iterations = m_core_solver->total_iterations(); this->m_total_iterations = (this->m_first_stage_iterations + this->m_second_stage_iterations); @@ -129,7 +144,7 @@ template void lp_dual_simplex::fill_x_with_zeros( } template void lp_dual_simplex::stage1() { - lean_assert(m_core_solver == nullptr); + SASSERT(m_core_solver == nullptr); this->m_x.resize(this->m_A->column_count(), numeric_traits::zero()); if (this->m_settings.get_message_ostream() != nullptr) this->print_statistics_on_A(*this->m_settings.get_message_ostream()); @@ -177,7 +192,7 @@ template void lp_dual_simplex::fill_first_stage_s } template column_type lp_dual_simplex::get_column_type(unsigned j) { - lean_assert(j < this->m_A->column_count()); + SASSERT(j < this->m_A->column_count()); if (j >= this->number_of_core_structurals()) { return m_column_types_of_logicals[j - this->number_of_core_structurals()]; } @@ -186,12 +201,12 @@ template column_type lp_dual_simplex::get_column_ template void lp_dual_simplex::fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_structural_column(unsigned j) { // see 4.7 in the dissertation of Achim Koberstein - lean_assert(this->m_core_solver_columns_to_external_columns.find(j) != + SASSERT(this->m_core_solver_columns_to_external_columns.find(j) != this->m_core_solver_columns_to_external_columns.end()); T free_bound = T(1e4); // see 4.8 unsigned jj = this->m_core_solver_columns_to_external_columns[j]; - lean_assert(this->m_map_from_var_index_to_column_info.find(jj) != this->m_map_from_var_index_to_column_info.end()); + SASSERT(this->m_map_from_var_index_to_column_info.find(jj) != this->m_map_from_var_index_to_column_info.end()); column_info * ci = this->m_map_from_var_index_to_column_info[jj]; switch (ci->get_column_type()) { case column_type::upper_bound: { @@ -221,14 +236,14 @@ template void lp_dual_simplex::fill_costs_bounds_ this->m_upper_bounds[j] = this->m_low_bounds[j] = numeric_traits::zero(); // is it needed? break; default: - lean_unreachable(); + SASSERT(false); } m_column_types_of_core_solver[j] = column_type::boxed; } template void lp_dual_simplex::fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_logical_column(unsigned j) { this->m_costs[j] = 0; - lean_assert(get_column_type(j) != column_type::upper_bound); + SASSERT(get_column_type(j) != column_type::upper_bound); if ((m_can_enter_basis[j] = (get_column_type(j) == column_type::low_bound))) { m_column_types_of_core_solver[j] = column_type::boxed; this->m_low_bounds[j] = numeric_traits::zero(); @@ -254,7 +269,7 @@ template void lp_dual_simplex::fill_costs_and_bou template void lp_dual_simplex::fill_first_stage_solver_fields_for_row_slack_and_artificial(unsigned row, unsigned & slack_var, unsigned & artificial) { - lean_assert(row < this->row_count()); + SASSERT(row < this->row_count()); auto & constraint = this->m_constraints[this->m_core_solver_rows_to_external_rows[row]]; // we need to bring the program to the form Ax = b T rs = this->m_b[row]; diff --git a/src/util/lp/lp_dual_simplex_instances.cpp b/src/util/lp/lp_dual_simplex_instances.cpp index 6610814d8..9e45849de 100644 --- a/src/util/lp/lp_dual_simplex_instances.cpp +++ b/src/util/lp/lp_dual_simplex_instances.cpp @@ -1,9 +1,24 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/lp_dual_simplex.hpp" -template lean::mpq lean::lp_dual_simplex::get_current_cost() const; -template void lean::lp_dual_simplex::find_maximal_solution(); -template double lean::lp_dual_simplex::get_current_cost() const; -template void lean::lp_dual_simplex::find_maximal_solution(); +template lp::mpq lp::lp_dual_simplex::get_current_cost() const; +template void lp::lp_dual_simplex::find_maximal_solution(); +template double lp::lp_dual_simplex::get_current_cost() const; +template void lp::lp_dual_simplex::find_maximal_solution(); diff --git a/src/util/lp/lp_primal_core_solver.h b/src/util/lp/lp_primal_core_solver.h index f77aae6eb..a7614862b 100644 --- a/src/util/lp/lp_primal_core_solver.h +++ b/src/util/lp/lp_primal_core_solver.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include @@ -23,7 +38,7 @@ #include "util/lp/binary_heap_priority_queue.h" #include "util/lp/int_set.h" #include "util/lp/iterator_on_row.h" -namespace lean { +namespace lp { // This core solver solves (Ax=b, low_bound_values \leq x \leq upper_bound_values, maximize costs*x ) // The right side b is given implicitly by x and the basis @@ -70,7 +85,7 @@ public: // unsigned len = 100000000; // for (unsigned j : this->m_inf_set.m_index) { // int i = this->m_basis_heading[j]; - // lean_assert(i >= 0); + // SASSERT(i >= 0); // unsigned row_len = this->m_A.m_rows[i].size(); // if (row_len < len) { // choices.clear(); @@ -98,8 +113,8 @@ public: bool column_is_benefitial_for_entering_basis_on_sign_row_strategy(unsigned j, int sign) const { // sign = 1 means the x of the basis column of the row has to grow to become feasible, when the coeff before j is neg, or x - has to diminish when the coeff is pos // we have xbj = -aj * xj - lean_assert(this->m_basis_heading[j] < 0); - lean_assert(this->column_is_feasible(j)); + SASSERT(this->m_basis_heading[j] < 0); + SASSERT(this->column_is_feasible(j)); switch (this->m_column_types[j]) { case column_type::free_column: return true; case column_type::fixed: return false; @@ -117,13 +132,13 @@ public: return !this->x_is_at_upper_bound(j); } - lean_assert(false); // cannot be here + SASSERT(false); // cannot be here return false; } bool needs_to_grow(unsigned bj) const { - lean_assert(!this->column_is_feasible(bj)); + SASSERT(!this->column_is_feasible(bj)); switch(this->m_column_types[bj]) { case column_type::free_column: return false; @@ -134,12 +149,12 @@ public: default: return false; } - lean_assert(false); // unreachable + SASSERT(false); // unreachable return false; } int inf_sign_of_column(unsigned bj) const { - lean_assert(!this->column_is_feasible(bj)); + SASSERT(!this->column_is_feasible(bj)); switch(this->m_column_types[bj]) { case column_type::free_column: return 0; @@ -151,7 +166,7 @@ public: default: return -1; } - lean_assert(false); // unreachable + SASSERT(false); // unreachable return 0; } @@ -159,7 +174,7 @@ public: bool monoid_can_decrease(const row_cell & rc) const { unsigned j = rc.m_j; - lean_assert(this->column_is_feasible(j)); + SASSERT(this->column_is_feasible(j)); switch (this->m_column_types[j]) { case column_type::free_column: return true; @@ -186,13 +201,13 @@ public: default: return false; } - lean_assert(false); // unreachable + SASSERT(false); // unreachable return false; } bool monoid_can_increase(const row_cell & rc) const { unsigned j = rc.m_j; - lean_assert(this->column_is_feasible(j)); + SASSERT(this->column_is_feasible(j)); switch (this->m_column_types[j]) { case column_type::free_column: return true; @@ -219,7 +234,7 @@ public: default: return false; } - lean_assert(false); // unreachable + SASSERT(false); // unreachable return false; } @@ -329,24 +344,24 @@ public: } void limit_theta_on_basis_column_for_inf_case_m_neg_upper_bound(unsigned j, const T & m, X & theta, bool & unlimited) { - lean_assert(m < 0 && this->m_column_types[j] == column_type::upper_bound); + SASSERT(m < 0 && this->m_column_types[j] == column_type::upper_bound); limit_inf_on_upper_bound_m_neg(m, this->m_x[j], this->m_upper_bounds[j], theta, unlimited); } void limit_theta_on_basis_column_for_inf_case_m_neg_low_bound(unsigned j, const T & m, X & theta, bool & unlimited) { - lean_assert(m < 0 && this->m_column_types[j] == column_type::low_bound); + SASSERT(m < 0 && this->m_column_types[j] == column_type::low_bound); limit_inf_on_bound_m_neg(m, this->m_x[j], this->m_low_bounds[j], theta, unlimited); } void limit_theta_on_basis_column_for_inf_case_m_pos_low_bound(unsigned j, const T & m, X & theta, bool & unlimited) { - lean_assert(m > 0 && this->m_column_types[j] == column_type::low_bound); + SASSERT(m > 0 && this->m_column_types[j] == column_type::low_bound); limit_inf_on_low_bound_m_pos(m, this->m_x[j], this->m_low_bounds[j], theta, unlimited); } void limit_theta_on_basis_column_for_inf_case_m_pos_upper_bound(unsigned j, const T & m, X & theta, bool & unlimited) { - lean_assert(m > 0 && this->m_column_types[j] == column_type::upper_bound); + SASSERT(m > 0 && this->m_column_types[j] == column_type::upper_bound); limit_inf_on_bound_m_pos(m, this->m_x[j], this->m_upper_bounds[j], theta, unlimited); }; @@ -359,7 +374,7 @@ public: X get_max_bound(vector & b); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG void check_Ax_equal_b(); void check_the_bounds(); void check_bound(unsigned i); @@ -388,7 +403,7 @@ public: bool need_to_switch_costs() const { if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) return false; - // lean_assert(calc_current_x_is_feasible() == current_x_is_feasible()); + // SASSERT(calc_current_x_is_feasible() == current_x_is_feasible()); return this->current_x_is_feasible() == this->m_using_infeas_costs; } @@ -443,7 +458,7 @@ public: if (j == -1) return -1; - lean_assert(!this->column_is_feasible(j)); + SASSERT(!this->column_is_feasible(j)); switch (this->m_column_types[j]) { case column_type::fixed: case column_type::upper_bound: @@ -459,7 +474,7 @@ public: new_val_for_leaving = this->m_low_bounds[j]; break; default: - lean_assert(false); + SASSERT(false); new_val_for_leaving = numeric_traits::zero(); // does not matter } return j; @@ -490,7 +505,7 @@ public: } X theta = (this->m_x[leaving] - new_val_for_leaving) / a_ent; advance_on_entering_and_leaving_tableau_rows(entering, leaving, theta ); - lean_assert(this->m_x[leaving] == new_val_for_leaving); + SASSERT(this->m_x[leaving] == new_val_for_leaving); if (this->current_x_is_feasible()) this->set_status(OPTIMAL); } @@ -507,13 +522,13 @@ public: void update_basis_and_x_with_comparison(unsigned entering, unsigned leaving, X delta); void decide_on_status_when_cannot_find_entering() { - lean_assert(!need_to_switch_costs()); + SASSERT(!need_to_switch_costs()); this->set_status(this->current_x_is_feasible()? OPTIMAL: INFEASIBLE); } // void limit_theta_on_basis_column_for_feas_case_m_neg(unsigned j, const T & m, X & theta) { - // lean_assert(m < 0); - // lean_assert(this->m_column_type[j] == low_bound || this->m_column_type[j] == boxed); + // SASSERT(m < 0); + // SASSERT(this->m_column_type[j] == low_bound || this->m_column_type[j] == boxed); // const X & eps = harris_eps_for_bound(this->m_low_bounds[j]); // if (this->above_bound(this->m_x[j], this->m_low_bounds[j])) { // theta = std::min((this->m_low_bounds[j] -this->m_x[j] - eps) / m, theta); @@ -522,7 +537,7 @@ public: // } void limit_theta_on_basis_column_for_feas_case_m_neg_no_check(unsigned j, const T & m, X & theta, bool & unlimited) { - lean_assert(m < 0); + SASSERT(m < 0); const X& eps = harris_eps_for_bound(this->m_low_bounds[j]); limit_theta((this->m_low_bounds[j] - this->m_x[j] - eps) / m, theta, unlimited); if (theta < zero_of_type()) theta = zero_of_type(); @@ -530,7 +545,7 @@ public: bool limit_inf_on_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { // x gets smaller - lean_assert(m < 0); + SASSERT(m < 0); if (numeric_traits::precise()) { if (this->below_bound(x, bound)) return false; if (this->above_bound(x, bound)) { @@ -554,7 +569,7 @@ public: bool limit_inf_on_bound_m_pos(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { // x gets larger - lean_assert(m > 0); + SASSERT(m > 0); if (numeric_traits::precise()) { if (this->above_bound(x, bound)) return false; if (this->below_bound(x, bound)) { @@ -579,14 +594,14 @@ public: void limit_inf_on_low_bound_m_pos(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { if (numeric_traits::precise()) { // x gets larger - lean_assert(m > 0); + SASSERT(m > 0); if (this->below_bound(x, bound)) { limit_theta((bound - x) / m, theta, unlimited); } } else { // x gets larger - lean_assert(m > 0); + SASSERT(m > 0); const X& eps = harris_eps_for_bound(bound); if (this->below_bound(x, bound)) { limit_theta((bound - x + eps) / m, theta, unlimited); @@ -596,7 +611,7 @@ public: void limit_inf_on_upper_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { // x gets smaller - lean_assert(m < 0); + SASSERT(m < 0); const X& eps = harris_eps_for_bound(bound); if (this->above_bound(x, bound)) { limit_theta((bound - x - eps) / m, theta, unlimited); @@ -604,7 +619,7 @@ public: } void limit_theta_on_basis_column_for_inf_case_m_pos_boxed(unsigned j, const T & m, X & theta, bool & unlimited) { - // lean_assert(m > 0 && this->m_column_type[j] == column_type::boxed); + // SASSERT(m > 0 && this->m_column_type[j] == column_type::boxed); const X & x = this->m_x[j]; const X & lbound = this->m_low_bounds[j]; @@ -624,7 +639,7 @@ public: } void limit_theta_on_basis_column_for_inf_case_m_neg_boxed(unsigned j, const T & m, X & theta, bool & unlimited) { - // lean_assert(m < 0 && this->m_column_type[j] == column_type::boxed); + // SASSERT(m < 0 && this->m_column_type[j] == column_type::boxed); const X & x = this->m_x[j]; const X & ubound = this->m_upper_bounds[j]; if (this->above_bound(x, ubound)) { @@ -642,7 +657,7 @@ public: } } void limit_theta_on_basis_column_for_feas_case_m_pos(unsigned j, const T & m, X & theta, bool & unlimited) { - lean_assert(m > 0); + SASSERT(m > 0); const T& eps = harris_eps_for_bound(this->m_upper_bounds[j]); if (this->below_bound(this->m_x[j], this->m_upper_bounds[j])) { limit_theta((this->m_upper_bounds[j] - this->m_x[j] + eps) / m, theta, unlimited); @@ -654,7 +669,7 @@ public: } void limit_theta_on_basis_column_for_feas_case_m_pos_no_check(unsigned j, const T & m, X & theta, bool & unlimited ) { - lean_assert(m > 0); + SASSERT(m > 0); const X& eps = harris_eps_for_bound(this->m_upper_bounds[j]); limit_theta( (this->m_upper_bounds[j] - this->m_x[j] + eps) / m, theta, unlimited); if (theta < zero_of_type()) { @@ -720,7 +735,7 @@ public: break; default: - lean_unreachable(); + SASSERT(false); } if (!unlimited && theta < zero_of_type()) { theta = zero_of_type(); @@ -803,7 +818,7 @@ public: case column_type::free_column: return 0; default: - lean_assert(false); + SASSERT(false); } return 0; } @@ -838,7 +853,7 @@ public: return -1; break; default: - lean_assert(false); + SASSERT(false); } return 0; @@ -864,7 +879,7 @@ public: // the delta is between the old and the new cost (old - new) void update_reduced_cost_for_basic_column_cost_change(const T & delta, unsigned j) { - lean_assert(this->m_basis_heading[j] >= 0); + SASSERT(this->m_basis_heading[j] >= 0); unsigned i = static_cast(this->m_basis_heading[j]); for (const row_cell & rc : this->m_A.m_rows[i]) { unsigned k = rc.m_j; @@ -943,10 +958,10 @@ public: upper_bound_values), m_beta(A.row_count()), m_converted_harris_eps(convert_struct::convert(this->m_settings.harris_feasibility_tolerance)) { - lean_assert(initial_x_is_correct()); + SASSERT(initial_x_is_correct()); m_low_bounds_dummy.resize(A.column_count(), zero_of_type()); m_enter_price_eps = numeric_traits::precise() ? numeric_traits::zero() : T(1e-5); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // check_correctness(); #endif } diff --git a/src/util/lp/lp_primal_core_solver.hpp b/src/util/lp/lp_primal_core_solver.hpp index 969d56812..5f81def51 100644 --- a/src/util/lp/lp_primal_core_solver.hpp +++ b/src/util/lp/lp_primal_core_solver.hpp @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/vector.h" #include @@ -9,13 +24,13 @@ #include #include #include "util/lp/lp_primal_core_solver.h" -namespace lean { +namespace lp { // This core solver solves (Ax=b, low_bound_values \leq x \leq upper_bound_values, maximize costs*x ) // The right side b is given implicitly by x and the basis template void lp_primal_core_solver::sort_non_basis_rational() { - lean_assert(numeric_traits::precise()); + SASSERT(numeric_traits::precise()); if (this->m_settings.use_tableau()) { std::sort(this->m_nbasis.begin(), this->m_nbasis.end(), [this](unsigned a, unsigned b) { unsigned ca = this->m_A.number_of_non_zeroes_in_column(a); @@ -70,11 +85,11 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_on_breakpoin const T & d = this->m_d[j]; switch (this->m_column_types[j]) { case column_type::low_bound: - lean_assert(this->x_is_at_low_bound(j)); + SASSERT(this->x_is_at_low_bound(j)); ret = d < -m_epsilon_of_reduced_cost; break; case column_type::upper_bound: - lean_assert(this->x_is_at_upper_bound(j)); + SASSERT(this->x_is_at_upper_bound(j)); ret = d > m_epsilon_of_reduced_cost; break; case column_type::fixed: @@ -83,7 +98,7 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_on_breakpoin case column_type::boxed: { bool low_bound = this->x_is_at_low_bound(j); - lean_assert(low_bound || this->x_is_at_upper_bound(j)); + SASSERT(low_bound || this->x_is_at_upper_bound(j)); ret = (low_bound && d < -m_epsilon_of_reduced_cost) || ((!low_bound) && d > m_epsilon_of_reduced_cost); } break; @@ -91,7 +106,7 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_on_breakpoin ret = d > m_epsilon_of_reduced_cost || d < - m_epsilon_of_reduced_cost; break; default: - lean_unreachable(); + SASSERT(false); ret = false; break; } @@ -127,14 +142,14 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_basis(unsign } break; default: - lean_unreachable(); + SASSERT(false); break; } return false; } template bool lp_primal_core_solver::column_is_benefitial_for_entering_basis_precise(unsigned j) const { - lean_assert (numeric_traits::precise()); + SASSERT (numeric_traits::precise()); if (this->m_using_infeas_costs && this->m_settings.use_breakpoints_in_feasibility_search) return column_is_benefitial_for_entering_on_breakpoints(j); const T& dj = this->m_d[j]; @@ -167,7 +182,7 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_basis_precis } break; default: - lean_unreachable(); + SASSERT(false); break; } return false; @@ -175,7 +190,7 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_basis_precis template int lp_primal_core_solver::choose_entering_column_presize(unsigned number_of_benefitial_columns_to_go_over) { // at this moment m_y = cB * B(-1) - lean_assert(numeric_traits::precise()); + SASSERT(numeric_traits::precise()); if (number_of_benefitial_columns_to_go_over == 0) return -1; if (this->m_basis_sort_counter == 0) { @@ -259,7 +274,7 @@ int lp_primal_core_solver::choose_entering_column(unsigned number_of_benef template int lp_primal_core_solver::advance_on_sorted_breakpoints(unsigned entering, X &t) { T slope_at_entering = this->m_d[entering]; breakpoint * last_bp = nullptr; - lean_assert(m_breakpoint_indices_queue.is_empty()==false); + SASSERT(m_breakpoint_indices_queue.is_empty()==false); while (m_breakpoint_indices_queue.is_empty() == false) { unsigned bi = m_breakpoint_indices_queue.dequeue(); breakpoint *b = &m_breakpoints[bi]; @@ -274,7 +289,7 @@ template int lp_primal_core_solver::advance_on_so } } } - lean_assert (last_bp != nullptr); + SASSERT (last_bp != nullptr); t = last_bp->m_delta; return last_bp->m_j; } @@ -282,13 +297,13 @@ template int lp_primal_core_solver::advance_on_so template int lp_primal_core_solver::find_leaving_and_t_with_breakpoints(unsigned entering, X & t){ - lean_assert(this->precise() == false); + SASSERT(this->precise() == false); fill_breakpoints_array(entering); return advance_on_sorted_breakpoints(entering, t); } template bool lp_primal_core_solver::get_harris_theta(X & theta) { - lean_assert(this->m_ed.is_OK()); + SASSERT(this->m_ed.is_OK()); bool unlimited = true; for (unsigned i : this->m_ed.m_index) { if (this->m_settings.abs_val_is_smaller_than_pivot_tolerance(this->m_ed[i])) continue; @@ -345,13 +360,13 @@ template bool lp_primal_core_solver::try_jump_to_ if (m_sign_of_entering_delta > 0) { t = this->m_upper_bounds[entering] - this->m_x[entering]; if (unlimited || t <= theta){ - lean_assert(t >= zero_of_type()); + SASSERT(t >= zero_of_type()); return true; } } else { // m_sign_of_entering_delta == -1 t = this->m_x[entering] - this->m_low_bounds[entering]; if (unlimited || t <= theta) { - lean_assert(t >= zero_of_type()); + SASSERT(t >= zero_of_type()); return true; } } @@ -360,7 +375,7 @@ template bool lp_primal_core_solver::try_jump_to_ if (m_sign_of_entering_delta > 0) { t = this->m_upper_bounds[entering] - this->m_x[entering]; if (unlimited || t <= theta){ - lean_assert(t >= zero_of_type()); + SASSERT(t >= zero_of_type()); return true; } } @@ -369,7 +384,7 @@ template bool lp_primal_core_solver::try_jump_to_ if (m_sign_of_entering_delta < 0) { t = this->m_x[entering] - this->m_low_bounds[entering]; if (unlimited || t <= theta) { - lean_assert(t >= zero_of_type()); + SASSERT(t >= zero_of_type()); return true; } } @@ -405,7 +420,7 @@ template int lp_primal_core_solver::find_leaving_ do { unsigned i = this->m_ed.m_index[k]; const T & ed = this->m_ed[i]; - lean_assert(!numeric_traits::is_zero(ed)); + SASSERT(!numeric_traits::is_zero(ed)); unsigned j = this->m_basis[i]; limit_theta_on_basis_column(j, - ed * m_sign_of_entering_delta, t, unlimited); if (!unlimited) { @@ -424,7 +439,7 @@ template int lp_primal_core_solver::find_leaving_ while (k != initial_k) { unsigned i = this->m_ed.m_index[k]; const T & ed = this->m_ed[i]; - lean_assert(!numeric_traits::is_zero(ed)); + SASSERT(!numeric_traits::is_zero(ed)); unsigned j = this->m_basis[i]; unlimited = true; limit_theta_on_basis_column(j, -ed * m_sign_of_entering_delta, ratio, unlimited); @@ -464,7 +479,7 @@ template int lp_primal_core_solver::find_leavi return find_leaving_and_t_with_breakpoints(entering, t); X theta; bool unlimited = get_harris_theta(theta); - lean_assert(unlimited || theta >= zero_of_type()); + SASSERT(unlimited || theta >= zero_of_type()); if (try_jump_to_another_bound_on_entering(entering, theta, t, unlimited)) return entering; if (unlimited) return -1; @@ -529,11 +544,11 @@ template X lp_primal_core_solver::get_max_boun return ret; } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template void lp_primal_core_solver::check_Ax_equal_b() { dense_matrix d(this->m_A); T * ls = d.apply_from_left_with_different_dims(this->m_x); - lean_assert(vectors_are_equal(ls, this->m_b, this->m_m())); + SASSERT(vectors_are_equal(ls, this->m_b, this->m_m())); delete [] ls; } template void lp_primal_core_solver::check_the_bounds() { @@ -543,8 +558,8 @@ template void lp_primal_core_solver::check_the } template void lp_primal_core_solver::check_bound(unsigned i) { - lean_assert (!(this->column_has_low_bound(i) && (numeric_traits::zero() > this->m_x[i]))); - lean_assert (!(this->column_has_upper_bound(i) && (this->m_upper_bounds[i] < this->m_x[i]))); + SASSERT (!(this->column_has_low_bound(i) && (numeric_traits::zero() > this->m_x[i]))); + SASSERT (!(this->column_has_upper_bound(i) && (this->m_upper_bounds[i] < this->m_x[i]))); } template void lp_primal_core_solver::check_correctness() { @@ -558,10 +573,10 @@ template void lp_primal_core_solver::check_cor template void lp_primal_core_solver::update_reduced_costs_from_pivot_row(unsigned entering, unsigned leaving) { // the basis heading has changed already -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG auto & basis_heading = this->m_basis_heading; - lean_assert(basis_heading[entering] >= 0 && static_cast(basis_heading[entering]) < this->m_m()); - lean_assert(basis_heading[leaving] < 0); + SASSERT(basis_heading[entering] >= 0 && static_cast(basis_heading[entering]) < this->m_m()); + SASSERT(basis_heading[leaving] < 0); #endif T pivot = this->m_pivot_row[entering]; T dq = this->m_d[entering]/pivot; @@ -584,7 +599,7 @@ void lp_primal_core_solver::update_reduced_costs_from_pivot_row(unsigned e template int lp_primal_core_solver::refresh_reduced_cost_at_entering_and_check_that_it_is_off(unsigned entering) { if (numeric_traits::precise()) return 0; T reduced_at_entering_was = this->m_d[entering]; // can benefit from going over non-zeros of m_ed - lean_assert(abs(reduced_at_entering_was) > m_epsilon_of_reduced_cost); + SASSERT(abs(reduced_at_entering_was) > m_epsilon_of_reduced_cost); T refreshed_cost = this->m_costs[entering]; unsigned i = this->m_m(); while (i--) refreshed_cost -= this->m_costs[this->m_basis[i]] * this->m_ed[i]; @@ -619,7 +634,7 @@ template void lp_primal_core_solver::backup_an m_costs_backup = this->m_costs; } else { T cost_max = std::max(max_abs_in_vector(this->m_costs), T(1)); - lean_assert(m_costs_backup.size() == 0); + SASSERT(m_costs_backup.size() == 0); for (unsigned j = 0; j < this->m_costs.size(); j++) m_costs_backup.push_back(this->m_costs[j] /= cost_max); } @@ -649,16 +664,16 @@ template void lp_primal_core_solver::init_run( template void lp_primal_core_solver::calc_working_vector_beta_for_column_norms(){ - lean_assert(numeric_traits::precise() == false); - lean_assert(this->m_ed.is_OK()); - lean_assert(m_beta.is_OK()); + SASSERT(numeric_traits::precise() == false); + SASSERT(this->m_ed.is_OK()); + SASSERT(m_beta.is_OK()); m_beta = this->m_ed; this->m_factorization->solve_yB_with_error_check_indexed(m_beta, this->m_basis_heading, this->m_basis, this->m_settings); } template void lp_primal_core_solver::advance_on_entering_equal_leaving(int entering, X & t) { - lean_assert(!this->A_mult_x_is_off() ); + SASSERT(!this->A_mult_x_is_off() ); this->update_x(entering, t * m_sign_of_entering_delta); if (this->A_mult_x_is_off_on_index(this->m_ed.m_index) && !this->find_x_by_solving()) { this->init_lu(); @@ -670,7 +685,7 @@ void lp_primal_core_solver::advance_on_entering_equal_leaving(int entering } } if (this->m_using_infeas_costs) { - lean_assert(is_zero(this->m_costs[entering])); + SASSERT(is_zero(this->m_costs[entering])); init_infeasibility_costs_for_changed_basis_only(); } if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) @@ -683,10 +698,10 @@ void lp_primal_core_solver::advance_on_entering_equal_leaving(int entering } template void lp_primal_core_solver::advance_on_entering_and_leaving(int entering, int leaving, X & t) { - lean_assert(entering >= 0 && m_non_basis_list.back() == static_cast(entering)); - lean_assert(this->m_using_infeas_costs || t >= zero_of_type()); - lean_assert(leaving >= 0 && entering >= 0); - lean_assert(entering != leaving || !is_zero(t)); // otherwise nothing changes + SASSERT(entering >= 0 && m_non_basis_list.back() == static_cast(entering)); + SASSERT(this->m_using_infeas_costs || t >= zero_of_type()); + SASSERT(leaving >= 0 && entering >= 0); + SASSERT(entering != leaving || !is_zero(t)); // otherwise nothing changes if (entering == leaving) { advance_on_entering_equal_leaving(entering, t); return; @@ -702,7 +717,7 @@ template void lp_primal_core_solver::advance_on_en this->iters_with_no_cost_growing()++; return; } else { - lean_assert(pivot_compare_result == 1); + SASSERT(pivot_compare_result == 1); this->init_lu(); if (this->m_factorization == nullptr || this->m_factorization->get_status() != LU_status::OK) { this->set_status(UNSTABLE); @@ -746,7 +761,7 @@ template void lp_primal_core_solver::advance_on_en } else { update_reduced_costs_from_pivot_row(entering, leaving); } - lean_assert(!need_to_switch_costs()); + SASSERT(!need_to_switch_costs()); std::list::iterator it = m_non_basis_list.end(); it--; * it = static_cast(leaving); @@ -754,8 +769,8 @@ template void lp_primal_core_solver::advance_on_en template void lp_primal_core_solver::advance_on_entering_precise(int entering) { - lean_assert(numeric_traits::precise()); - lean_assert(entering > -1); + SASSERT(numeric_traits::precise()); + SASSERT(entering > -1); this->solve_Bd(entering); X t; int leaving = find_leaving_and_t_precise(entering, t); @@ -771,7 +786,7 @@ template void lp_primal_core_solver::advance_on_e advance_on_entering_precise(entering); return; } - lean_assert(entering > -1); + SASSERT(entering > -1); this->solve_Bd(entering); int refresh_result = refresh_reduced_cost_at_entering_and_check_that_it_is_off(entering); if (refresh_result) { @@ -791,7 +806,7 @@ template void lp_primal_core_solver::advance_on_e int leaving = find_leaving_and_t(entering, t); if (leaving == -1){ if (!this->current_x_is_feasible()) { - lean_assert(!numeric_traits::precise()); // we cannot have unbounded with inf costs + SASSERT(!numeric_traits::precise()); // we cannot have unbounded with inf costs // if (m_look_for_feasible_solution_only) { // this->m_status = INFEASIBLE; @@ -865,7 +880,7 @@ template unsigned lp_primal_core_solver::solve() return this->total_iterations(); } one_iteration(); - lean_assert(!this->m_using_infeas_costs || this->costs_on_nbasis_are_zeros()); + SASSERT(!this->m_using_infeas_costs || this->costs_on_nbasis_are_zeros()); switch (this->get_status()) { case OPTIMAL: // double check that we are at optimum case INFEASIBLE: @@ -914,7 +929,7 @@ template unsigned lp_primal_core_solver::solve() break; case UNSTABLE: - lean_assert(! (numeric_traits::precise())); + SASSERT(! (numeric_traits::precise())); this->init_lu(); if (this->m_factorization->get_status() != LU_status::OK) { this->set_status(FLOATING_POINT_ERROR); @@ -940,7 +955,7 @@ template unsigned lp_primal_core_solver::solve() && !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)); - lean_assert(this->get_status() == FLOATING_POINT_ERROR + SASSERT(this->get_status() == FLOATING_POINT_ERROR || this->current_x_is_feasible() == false || @@ -957,7 +972,7 @@ template void lp_primal_core_solver::delete_fa // according to Swietanowski, " A new steepest edge approximation for the simplex method for linear programming" template void lp_primal_core_solver::init_column_norms() { - lean_assert(numeric_traits::precise() == false); + SASSERT(numeric_traits::precise() == false); for (unsigned j = 0; j < this->m_n(); j++) { this->m_column_norms[j] = T(static_cast(this->m_A.m_columns[j].size() + 1)) @@ -967,7 +982,7 @@ template void lp_primal_core_solver::init_column_ // debug only template T lp_primal_core_solver::calculate_column_norm_exactly(unsigned j) { - lean_assert(numeric_traits::precise() == false); + SASSERT(numeric_traits::precise() == false); indexed_vector w(this->m_m()); this->m_A.copy_column_to_vector(j, w); vector d(this->m_m()); @@ -979,8 +994,8 @@ template T lp_primal_core_solver::calculate_colum } template void lp_primal_core_solver::update_or_init_column_norms(unsigned entering, unsigned leaving) { - lean_assert(numeric_traits::precise() == false); - lean_assert(m_column_norm_update_counter <= this->m_settings.column_norms_update_frequency); + SASSERT(numeric_traits::precise() == false); + SASSERT(m_column_norm_update_counter <= this->m_settings.column_norms_update_frequency); if (m_column_norm_update_counter == this->m_settings.column_norms_update_frequency) { m_column_norm_update_counter = 0; init_column_norms(); @@ -992,7 +1007,7 @@ template void lp_primal_core_solver::update_or // following Swietanowski - A new steepest ... template void lp_primal_core_solver::update_column_norms(unsigned entering, unsigned leaving) { - lean_assert(numeric_traits::precise() == false); + SASSERT(numeric_traits::precise() == false); T pivot = this->m_pivot_row[entering]; T g_ent = calculate_norm_of_entering_exactly() / pivot / pivot; if (!numeric_traits::precise()) { @@ -1027,7 +1042,7 @@ template T lp_primal_core_solver::calculate_no // calling it stage1 is too cryptic template void lp_primal_core_solver::find_feasible_solution() { this->m_look_for_feasible_solution_only = true; - lean_assert(this->non_basic_columns_are_set_correctly()); + SASSERT(this->non_basic_columns_are_set_correctly()); this->set_status(UNKNOWN); solve(); } @@ -1095,8 +1110,8 @@ void lp_primal_core_solver::init_infeasibility_costs_for_changed_basis_onl template void lp_primal_core_solver::init_infeasibility_costs() { - lean_assert(this->m_x.size() >= this->m_n()); - lean_assert(this->m_column_types.size() >= this->m_n()); + SASSERT(this->m_x.size() >= this->m_n()); + SASSERT(this->m_column_types.size() >= this->m_n()); for (unsigned j = this->m_n(); j--;) init_infeasibility_cost_for_column(j); this->m_using_infeas_costs = true; @@ -1138,7 +1153,7 @@ lp_primal_core_solver::get_infeasibility_cost_for_column(unsigned j) const ret = numeric_traits::zero(); break; default: - lean_assert(false); + SASSERT(false); ret = numeric_traits::zero(); // does not matter break; } @@ -1192,7 +1207,7 @@ lp_primal_core_solver::init_infeasibility_cost_for_column(unsigned j) { this->m_costs[j] = numeric_traits::zero(); break; default: - lean_assert(false); + SASSERT(false); break; } @@ -1223,7 +1238,7 @@ template void lp_primal_core_solver::print_column case column_type::free_column: out << "( _" << this->m_x[j] << "_)" << std::endl; default: - lean_unreachable(); + SASSERT(false); } } @@ -1262,7 +1277,7 @@ template std::string lp_primal_core_solver::break case upper_break: return "upper_break"; case fixed_break: return "fixed_break"; default: - lean_assert(false); + SASSERT(false); break; } return "type is not found"; @@ -1275,7 +1290,7 @@ template void lp_primal_core_solver::print_breakp template void lp_primal_core_solver::init_reduced_costs() { - lean_assert(!this->use_tableau()); + SASSERT(!this->use_tableau()); if (this->current_x_is_infeasible() && !this->m_using_infeas_costs) { init_infeasibility_costs(); } else if (this->current_x_is_feasible() && this->m_using_infeas_costs) { @@ -1290,12 +1305,12 @@ void lp_primal_core_solver::init_reduced_costs() { template void lp_primal_core_solver::change_slope_on_breakpoint(unsigned entering, breakpoint * b, T & slope_at_entering) { if (b->m_j == entering) { - lean_assert(b->m_type != fixed_break && (!is_zero(b->m_delta))); + SASSERT(b->m_type != fixed_break && (!is_zero(b->m_delta))); slope_at_entering += m_sign_of_entering_delta; return; } - lean_assert(this->m_basis_heading[b->m_j] >= 0); + SASSERT(this->m_basis_heading[b->m_j] >= 0); unsigned i_row = this->m_basis_heading[b->m_j]; const T & d = - this->m_ed[i_row]; if (numeric_traits::is_zero(d)) return; @@ -1314,13 +1329,13 @@ template void lp_primal_core_solver::change_sl slope_at_entering += delta; break; default: - lean_assert(false); + SASSERT(false); } } template void lp_primal_core_solver::try_add_breakpoint_in_row(unsigned i) { - lean_assert(i < this->m_m()); + SASSERT(i < this->m_m()); const T & d = this->m_ed[i]; // the coefficient before m_entering in the i-th row if (d == 0) return; // the change of x[m_entering] will not change the corresponding basis x unsigned j = this->m_basis[i]; @@ -1342,7 +1357,7 @@ template void lp_primal_core_solver::try_add_b case column_type::free_column: break; default: - lean_assert(false); + SASSERT(false); break; } } @@ -1366,7 +1381,7 @@ template void lp_primal_core_solver::print_bound_ out << "inf, inf" << std::endl; break; default: - lean_assert(false); + SASSERT(false); break; } } diff --git a/src/util/lp/lp_primal_core_solver_instances.cpp b/src/util/lp/lp_primal_core_solver_instances.cpp index ca231fd34..fd5f42d67 100644 --- a/src/util/lp/lp_primal_core_solver_instances.cpp +++ b/src/util/lp/lp_primal_core_solver_instances.cpp @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include @@ -9,19 +24,19 @@ #include #include "util/lp/lar_solver.h" #include "util/lp/lp_primal_core_solver.hpp" -#include "util/lp/lp_primal_core_solver_tableau.hpp" -namespace lean { +#include "util/lp/lp_primal_core_solver_tableau.h" +namespace lp { template void lp_primal_core_solver::find_feasible_solution(); -template void lean::lp_primal_core_solver >::find_feasible_solution(); +template void lp::lp_primal_core_solver >::find_feasible_solution(); template unsigned lp_primal_core_solver::solve(); template unsigned lp_primal_core_solver::solve_with_tableau(); template unsigned lp_primal_core_solver::solve(); template unsigned lp_primal_core_solver >::solve(); -template void lean::lp_primal_core_solver::clear_breakpoints(); -template bool lean::lp_primal_core_solver::update_basis_and_x_tableau(int, int, lean::mpq const&); -template bool lean::lp_primal_core_solver::update_basis_and_x_tableau(int, int, double const&); -template bool lean::lp_primal_core_solver >::update_basis_and_x_tableau(int, int, lean::numeric_pair const&); +template void lp::lp_primal_core_solver::clear_breakpoints(); +template bool lp::lp_primal_core_solver::update_basis_and_x_tableau(int, int, lp::mpq const&); +template bool lp::lp_primal_core_solver::update_basis_and_x_tableau(int, int, double const&); +template bool lp::lp_primal_core_solver >::update_basis_and_x_tableau(int, int, lp::numeric_pair const&); } diff --git a/src/util/lp/lp_primal_core_solver_tableau.hpp b/src/util/lp/lp_primal_core_solver_tableau.h similarity index 85% rename from src/util/lp/lp_primal_core_solver_tableau.hpp rename to src/util/lp/lp_primal_core_solver_tableau.h index 0c09c22c9..0c56f0ab9 100644 --- a/src/util/lp/lp_primal_core_solver_tableau.hpp +++ b/src/util/lp/lp_primal_core_solver_tableau.h @@ -1,10 +1,25 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ // this is a part of lp_primal_core_solver that deals with the tableau #include "util/lp/lp_primal_core_solver.h" -namespace lean { +namespace lp { template void lp_primal_core_solver::one_iteration_tableau() { int entering = choose_entering_column_tableau(); if (entering == -1) { @@ -13,7 +28,7 @@ template void lp_primal_core_solver::one_iteratio else { advance_on_entering_tableau(entering); } - lean_assert(this->inf_set_is_correct()); + SASSERT(this->inf_set_is_correct()); } template void lp_primal_core_solver::advance_on_entering_tableau(int entering) { @@ -37,7 +52,7 @@ template int lp_primal_core_solver::choose_enteri //this moment m_y = cB * B(-1) unsigned number_of_benefitial_columns_to_go_over = get_number_of_non_basic_column_to_try_for_enter(); - lean_assert(numeric_traits::precise()); + SASSERT(numeric_traits::precise()); if (number_of_benefitial_columns_to_go_over == 0) return -1; if (this->m_basis_sort_counter == 0) { @@ -149,7 +164,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { break; case UNSTABLE: - lean_assert(! (numeric_traits::precise())); + SASSERT(! (numeric_traits::precise())); this->init_lu(); if (this->m_factorization->get_status() != LU_status::OK) { this->set_status(FLOATING_POINT_ERROR); @@ -161,36 +176,45 @@ unsigned lp_primal_core_solver::solve_with_tableau() { default: break; // do nothing } - } while (this->get_status() != FLOATING_POINT_ERROR - && - this->get_status() != UNBOUNDED - && - this->get_status() != OPTIMAL - && - this->get_status() != INFEASIBLE - && - this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements - && - this->total_iterations() <= this->m_settings.max_total_number_of_iterations - && - !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)); + } while (this->get_status() != FLOATING_POINT_ERROR + && + this->get_status() != UNBOUNDED + && + this->get_status() != OPTIMAL + && + this->get_status() != INFEASIBLE + && + this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements + && + this->total_iterations() <= this->m_settings.max_total_number_of_iterations + && + !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) + && + this->m_settings.get_cancel_flag() == false); + + if (this->m_settings.get_cancel_flag()) { + this->set_status(CANCELLED); + } - lean_assert(this->get_status() == FLOATING_POINT_ERROR - || - this->current_x_is_feasible() == false - || - this->calc_current_x_is_feasible_include_non_basis()); + SASSERT( + this->get_status() == FLOATING_POINT_ERROR + || + this->get_status() == CANCELLED + || + this->current_x_is_feasible() == false + || + this->calc_current_x_is_feasible_include_non_basis()); return this->total_iterations(); } template void lp_primal_core_solver::advance_on_entering_and_leaving_tableau(int entering, int leaving, X & t) { - lean_assert(this->A_mult_x_is_off() == false); - lean_assert(leaving >= 0 && entering >= 0); - lean_assert((this->m_settings.simplex_strategy() == + SASSERT(this->A_mult_x_is_off() == false); + SASSERT(leaving >= 0 && entering >= 0); + SASSERT((this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) || m_non_basis_list.back() == static_cast(entering)); - lean_assert(this->m_using_infeas_costs || !is_neg(t)); - lean_assert(entering != leaving || !is_zero(t)); // otherwise nothing changes + SASSERT(this->m_using_infeas_costs || !is_neg(t)); + SASSERT(entering != leaving || !is_zero(t)); // otherwise nothing changes if (entering == leaving) { advance_on_entering_equal_leaving_tableau(entering, t); return; @@ -201,7 +225,7 @@ template void lp_primal_core_solver::advance_on_en t = -t; } this->update_basis_and_x_tableau(entering, leaving, t); - lean_assert(this->A_mult_x_is_off() == false); + SASSERT(this->A_mult_x_is_off() == false); this->iters_with_no_cost_growing() = 0; } else { this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); @@ -216,7 +240,7 @@ template void lp_primal_core_solver::advance_on_en this->init_reduced_costs_tableau(); } - lean_assert(!need_to_switch_costs()); + SASSERT(!need_to_switch_costs()); std::list::iterator it = m_non_basis_list.end(); it--; * it = static_cast(leaving); @@ -225,7 +249,7 @@ template void lp_primal_core_solver::advance_on_en template void lp_primal_core_solver::advance_on_entering_equal_leaving_tableau(int entering, X & t) { - lean_assert(!this->A_mult_x_is_off() ); + SASSERT(!this->A_mult_x_is_off() ); this->update_x_tableau(entering, t * m_sign_of_entering_delta); if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) return; @@ -246,7 +270,7 @@ template int lp_primal_core_solver::find_leaving_ const column_cell & c = col[k]; unsigned i = c.m_i; const T & ed = this->m_A.get_val(c); - lean_assert(!numeric_traits::is_zero(ed)); + SASSERT(!numeric_traits::is_zero(ed)); unsigned j = this->m_basis[i]; limit_theta_on_basis_column(j, - ed * m_sign_of_entering_delta, t, unlimited); if (!unlimited) { @@ -265,7 +289,7 @@ template int lp_primal_core_solver::find_leaving_ const column_cell & c = col[k]; unsigned i = c.m_i; const T & ed = this->m_A.get_val(c); - lean_assert(!numeric_traits::is_zero(ed)); + SASSERT(!numeric_traits::is_zero(ed)); unsigned j = this->m_basis[i]; unlimited = true; limit_theta_on_basis_column(j, -ed * m_sign_of_entering_delta, ratio, unlimited); @@ -298,12 +322,12 @@ template int lp_primal_core_solver::find_leaving_ } template void lp_primal_core_solver::init_run_tableau() { // print_matrix(&(this->m_A), std::cout); - lean_assert(this->A_mult_x_is_off() == false); - lean_assert(basis_columns_are_set_correctly()); + SASSERT(this->A_mult_x_is_off() == false); + SASSERT(basis_columns_are_set_correctly()); this->m_basis_sort_counter = 0; // to initiate the sort of the basis this->set_total_iterations(0); this->iters_with_no_cost_growing() = 0; - lean_assert(this->inf_set_is_correct()); + SASSERT(this->inf_set_is_correct()); if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) return; if (this->m_settings.backup_costs) @@ -317,13 +341,13 @@ template void lp_primal_core_solver::init_run_tab } if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) init_tableau_rows(); - lean_assert(this->reduced_costs_are_correct_tableau()); - lean_assert(!this->need_to_pivot_to_basis_tableau()); + SASSERT(this->reduced_costs_are_correct_tableau()); + SASSERT(!this->need_to_pivot_to_basis_tableau()); } template bool lp_primal_core_solver:: update_basis_and_x_tableau(int entering, int leaving, X const & tt) { - lean_assert(this->use_tableau()); + SASSERT(this->use_tableau()); update_x_tableau(entering, tt); this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); this->change_basis(entering, leaving); @@ -340,8 +364,8 @@ update_x_tableau(unsigned entering, const X& delta) { } } else { // m_using_infeas_costs == true this->m_x[entering] += delta; - lean_assert(this->column_is_feasible(entering)); - lean_assert(this->m_costs[entering] == zero_of_type()); + SASSERT(this->column_is_feasible(entering)); + SASSERT(this->m_costs[entering] == zero_of_type()); // m_d[entering] can change because of the cost change for basic columns. for (const auto & c : this->m_A.m_columns[entering]) { unsigned i = c.m_i; @@ -354,13 +378,13 @@ update_x_tableau(unsigned entering, const X& delta) { this->m_inf_set.insert(j); } } - lean_assert(this->A_mult_x_is_off() == false); + SASSERT(this->A_mult_x_is_off() == false); } template void lp_primal_core_solver:: update_inf_cost_for_column_tableau(unsigned j) { - lean_assert(this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows); - lean_assert(this->m_using_infeas_costs); + SASSERT(this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows); + SASSERT(this->m_using_infeas_costs); T new_cost = get_infeasibility_cost_for_column(j); T delta = this->m_costs[j] - new_cost; if (is_zero(delta)) diff --git a/src/util/lp/lp_primal_simplex.h b/src/util/lp/lp_primal_simplex.h index 715d76408..d8fd114e4 100644 --- a/src/util/lp/lp_primal_simplex.h +++ b/src/util/lp/lp_primal_simplex.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include @@ -12,7 +27,7 @@ #include "util/lp/lp_primal_core_solver.h" #include "util/lp/lp_solver.h" #include "util/lp/iterator_on_row.h" -namespace lean { +namespace lp { template class lp_primal_simplex: public lp_solver { lp_primal_core_solver * m_core_solver; diff --git a/src/util/lp/lp_primal_simplex.hpp b/src/util/lp/lp_primal_simplex.hpp index b6b6006e5..fd717ec7f 100644 --- a/src/util/lp/lp_primal_simplex.hpp +++ b/src/util/lp/lp_primal_simplex.hpp @@ -1,12 +1,27 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/vector.h" #include "util/lp/lp_primal_simplex.h" -namespace lean { +namespace lp { template void lp_primal_simplex::fill_costs_and_x_for_first_stage_solver(unsigned original_number_of_columns) { unsigned slack_var = original_number_of_columns; unsigned artificial = original_number_of_columns + this->m_slacks; @@ -61,7 +76,7 @@ template void lp_primal_simplex::fill_costs_and_x int row, unsigned & slack_var, unsigned & artificial) { - lean_assert(row >= 0 && row < this->row_count()); + SASSERT(row >= 0 && row < this->row_count()); auto & constraint = this->m_constraints[this->m_core_solver_rows_to_external_rows[row]]; // we need to bring the program to the form Ax = b T rs = this->m_b[row]; @@ -86,7 +101,7 @@ template void lp_primal_simplex::fill_costs_and_x (*this->m_A)(row, slack_var) = - numeric_traits::one(); if (rs > 0) { - lean_assert(numeric_traits::is_zero(this->m_x[slack_var])); + SASSERT(numeric_traits::is_zero(this->m_x[slack_var])); // adding one artificial this->m_column_types[artificial] = column_type::low_bound; (*this->m_A)(row, artificial) = numeric_traits::one(); @@ -108,7 +123,7 @@ template void lp_primal_simplex::fill_costs_and_x if (rs < 0) { // adding one artificial - lean_assert(numeric_traits::is_zero(this->m_x[slack_var])); + SASSERT(numeric_traits::is_zero(this->m_x[slack_var])); this->m_column_types[artificial] = column_type::low_bound; (*this->m_A)(row, artificial) = - numeric_traits::one(); this->m_costs[artificial] = artificial_cost; @@ -177,12 +192,12 @@ template void lp_primal_simplex::fill_A_x_and_bas } template void lp_primal_simplex::fill_A_x_and_basis_for_stage_one_total_inf_for_row(unsigned row) { - lean_assert(row < this->row_count()); + SASSERT(row < this->row_count()); auto ext_row_it = this->m_core_solver_rows_to_external_rows.find(row); - lean_assert(ext_row_it != this->m_core_solver_rows_to_external_rows.end()); + SASSERT(ext_row_it != this->m_core_solver_rows_to_external_rows.end()); unsigned ext_row = ext_row_it->second; auto constr_it = this->m_constraints.find(ext_row); - lean_assert(constr_it != this->m_constraints.end()); + SASSERT(constr_it != this->m_constraints.end()); auto & constraint = constr_it->second; unsigned j = this->m_A->column_count(); // j is a slack variable this->m_A->add_column(); @@ -209,7 +224,7 @@ template void lp_primal_simplex::fill_A_x_and_bas this->m_upper_bounds[j] = m_low_bounds[j] = zero_of_type(); break; default: - lean_unreachable(); + SASSERT(false); } } @@ -281,10 +296,10 @@ template T lp_primal_simplex::get_row_value(unsig T ret = numeric_traits::zero(); for (auto & pair : it->second) { auto cit = this->m_map_from_var_index_to_column_info.find(pair.first); - lean_assert(cit != this->m_map_from_var_index_to_column_info.end()); + SASSERT(cit != this->m_map_from_var_index_to_column_info.end()); column_info * ci = cit->second; auto sol_it = solution.find(ci->get_name()); - lean_assert(sol_it != solution.end()); + SASSERT(sol_it != solution.end()); T column_val = sol_it->second; if (out != nullptr) { (*out) << pair.second << "(" << ci->get_name() << "=" << column_val << ") "; @@ -329,7 +344,7 @@ template bool lp_primal_simplex::row_constraint_h } return true;; } - lean_unreachable(); + SASSERT(false); return false; // it is unreachable } diff --git a/src/util/lp/lp_primal_simplex_instances.cpp b/src/util/lp/lp_primal_simplex_instances.cpp index 37b639489..92e3a77ff 100644 --- a/src/util/lp/lp_primal_simplex_instances.cpp +++ b/src/util/lp/lp_primal_simplex_instances.cpp @@ -1,20 +1,35 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include #include "util/vector.h" #include #include "util/lp/lp_primal_simplex.hpp" -template bool lean::lp_primal_simplex::bounds_hold(std::unordered_map, std::equal_to, std::allocator > > const&); -template bool lean::lp_primal_simplex::row_constraints_hold(std::unordered_map, std::equal_to, std::allocator > > const&); -template double lean::lp_primal_simplex::get_current_cost() const; -template double lean::lp_primal_simplex::get_column_value(unsigned int) const; -template lean::lp_primal_simplex::~lp_primal_simplex(); -template lean::lp_primal_simplex::~lp_primal_simplex(); -template lean::mpq lean::lp_primal_simplex::get_current_cost() const; -template lean::mpq lean::lp_primal_simplex::get_column_value(unsigned int) const; -template void lean::lp_primal_simplex::find_maximal_solution(); -template void lean::lp_primal_simplex::find_maximal_solution(); +template bool lp::lp_primal_simplex::bounds_hold(std::unordered_map, std::equal_to, std::allocator > > const&); +template bool lp::lp_primal_simplex::row_constraints_hold(std::unordered_map, std::equal_to, std::allocator > > const&); +template double lp::lp_primal_simplex::get_current_cost() const; +template double lp::lp_primal_simplex::get_column_value(unsigned int) const; +template lp::lp_primal_simplex::~lp_primal_simplex(); +template lp::lp_primal_simplex::~lp_primal_simplex(); +template lp::mpq lp::lp_primal_simplex::get_current_cost() const; +template lp::mpq lp::lp_primal_simplex::get_column_value(unsigned int) const; +template void lp::lp_primal_simplex::find_maximal_solution(); +template void lp::lp_primal_simplex::find_maximal_solution(); diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index aac3692f9..a7e6e2665 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" @@ -12,7 +27,7 @@ #include "util/lp/lp_utils.h" #include "util/stopwatch.h" -namespace lean { +namespace lp { typedef unsigned var_index; typedef unsigned constraint_index; typedef unsigned row_index; @@ -46,7 +61,8 @@ enum lp_status { TIME_EXHAUSTED, ITERATIONS_EXHAUSTED, EMPTY, - UNSTABLE + UNSTABLE, + CANCELLED }; // when the ratio of the vector lenth to domain size to is greater than the return value we switch to solve_By_for_T_indexed_only @@ -278,13 +294,13 @@ public: return m_simplex_strategy; } - bool use_lu() const { - return m_simplex_strategy == simplex_strategy_enum::lu; - } + bool use_lu() const { + return m_simplex_strategy == simplex_strategy_enum::lu; + } bool use_tableau() const { - return m_simplex_strategy == simplex_strategy_enum::tableau_rows || - m_simplex_strategy == simplex_strategy_enum::tableau_costs; + return m_simplex_strategy == simplex_strategy_enum::tableau_rows || + m_simplex_strategy == simplex_strategy_enum::tableau_costs; } bool use_tableau_rows() const { @@ -296,7 +312,7 @@ public: unsigned column_norms_update_frequency; bool scale_with_ratio; double density_threshold; // need to tune it up, todo -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG static unsigned ddd; // used for debugging #endif bool use_breakpoints_in_feasibility_search; @@ -366,7 +382,7 @@ inline void print_blanks(int n, std::ostream & out) { // after a push of the last element we ensure that the vector increases // we also suppose that before the last push the vector was increasing inline void ensure_increasing(vector & v) { - lean_assert(v.size() > 0); + SASSERT(v.size() > 0); unsigned j = v.size() - 1; for (; j > 0; j-- ) if (v[j] <= v[j - 1]) { @@ -381,7 +397,7 @@ inline void ensure_increasing(vector & v) { -#if LEAN_DEBUG +#if Z3DEBUG bool D(); #endif } diff --git a/src/util/lp/lp_settings.hpp b/src/util/lp/lp_settings.hpp index b27d837e0..659d47c62 100644 --- a/src/util/lp/lp_settings.hpp +++ b/src/util/lp/lp_settings.hpp @@ -1,12 +1,27 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include "util/vector.h" #include "util/lp/lp_settings.h" -namespace lean { +namespace lp { std::string column_type_to_string(column_type t) { switch (t) { case column_type::fixed: return "fixed"; @@ -14,7 +29,7 @@ std::string column_type_to_string(column_type t) { case column_type::low_bound: return "low_bound"; case column_type::upper_bound: return "upper_bound"; case column_type::free_column: return "free_column"; - default: lean_unreachable(); + default: SASSERT(false); } return "unknown"; // it is unreachable } @@ -34,7 +49,7 @@ const char* lp_status_to_string(lp_status status) { case EMPTY: return "EMPTY"; case UNSTABLE: return "UNSTABLE"; default: - lean_unreachable(); + SASSERT(false); } return "UNKNOWN"; // it is unreachable } @@ -49,7 +64,7 @@ lp_status lp_status_from_string(std::string status) { if (status == "TIME_EXHAUSTED") return lp_status::TIME_EXHAUSTED; if (status == "ITERATIONS_EXHAUSTED") return lp_status::ITERATIONS_EXHAUSTED; if (status == "EMPTY") return lp_status::EMPTY; - lean_unreachable(); + SASSERT(false); return lp_status::UNKNOWN; // it is unreachable } @@ -104,7 +119,7 @@ bool vectors_are_equal(const vector & a, const vector &b) { } return true; } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG unsigned lp_settings::ddd = 0; #endif } diff --git a/src/util/lp/lp_settings_instances.cpp b/src/util/lp/lp_settings_instances.cpp index ac2ed4b51..bd5a1515f 100644 --- a/src/util/lp/lp_settings_instances.cpp +++ b/src/util/lp/lp_settings_instances.cpp @@ -1,10 +1,25 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/vector.h" #include "util/lp/lp_settings.hpp" -template bool lean::vectors_are_equal(vector const&, vector const&); -template bool lean::vectors_are_equal(vector const&, vector const&); +template bool lp::vectors_are_equal(vector const&, vector const&); +template bool lp::vectors_are_equal(vector const&, vector const&); diff --git a/src/util/lp/lp_solver.h b/src/util/lp/lp_solver.h index 1bfe7dcdc..c447b1870 100644 --- a/src/util/lp/lp_solver.h +++ b/src/util/lp/lp_solver.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include @@ -15,7 +30,7 @@ #include "util/lp/scaler.h" #include "util/lp/linear_combination_iterator.h" #include "util/lp/bound_analyzer_on_row.h" -namespace lean { +namespace lp { enum lp_relation { Less_or_equal, Equal, diff --git a/src/util/lp/lp_solver.hpp b/src/util/lp/lp_solver.hpp index 135616a69..3bc83b316 100644 --- a/src/util/lp/lp_solver.hpp +++ b/src/util/lp/lp_solver.hpp @@ -1,12 +1,27 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include "util/vector.h" #include "util/lp/lp_solver.h" -namespace lean { +namespace lp { template column_info * lp_solver::get_or_create_column_info(unsigned column) { auto it = m_map_from_var_index_to_column_info.find(column); return (it == m_map_from_var_index_to_column_info.end())? (m_map_from_var_index_to_column_info[column] = new column_info(static_cast(-1))) : it->second; @@ -32,7 +47,7 @@ template T lp_solver::get_column_cost_value(unsig return ci->get_cost() * get_column_value(j); } template void lp_solver::add_constraint(lp_relation relation, T right_side, unsigned row_index) { - lean_assert(m_constraints.find(row_index) == m_constraints.end()); + SASSERT(m_constraints.find(row_index) == m_constraints.end()); lp_constraint cs(right_side, relation); m_constraints[row_index] = cs; } @@ -158,10 +173,10 @@ template void lp_solver::pin_vars_on_row_with_sig column_info * ci = m_map_from_var_index_to_column_info[j]; T a = t.second; if (a * sign > numeric_traits::zero()) { - lean_assert(ci->upper_bound_is_set()); + SASSERT(ci->upper_bound_is_set()); ci->set_fixed_value(ci->get_upper_bound()); } else { - lean_assert(ci->low_bound_is_set()); + SASSERT(ci->low_bound_is_set()); ci->set_fixed_value(ci->get_low_bound()); } } @@ -328,7 +343,7 @@ template bool lp_solver::row_is_obsolete(std:: case lp_relation::Less_or_equal: return row_le_is_obsolete(row, row_index); } - lean_unreachable(); + SASSERT(false); return false; // it is unreachable } @@ -343,7 +358,7 @@ template void lp_solver::remove_fixed_or_zero_col vector removed; for (auto & col : row) { unsigned j = col.first; - lean_assert(m_map_from_var_index_to_column_info.find(j) != m_map_from_var_index_to_column_info.end()); + SASSERT(m_map_from_var_index_to_column_info.find(j) != m_map_from_var_index_to_column_info.end()); column_info * ci = m_map_from_var_index_to_column_info[j]; if (ci->is_fixed()) { removed.push_back(j); @@ -412,7 +427,7 @@ template void lp_solver::map_external_columns_to_ } unsigned j = col.first; auto column_info_it = m_map_from_var_index_to_column_info.find(j); - lean_assert(column_info_it != m_map_from_var_index_to_column_info.end()); + SASSERT(column_info_it != m_map_from_var_index_to_column_info.end()); auto j_column = column_info_it->second->get_column_index(); if (!is_valid(j_column)) { // j is a newcomer @@ -435,14 +450,14 @@ template void lp_solver::fill_A_from_A_values() { m_A = new static_matrix(static_cast(m_A_values.size()), number_of_core_structurals()); for (auto & t : m_A_values) { auto row_it = m_external_rows_to_core_solver_rows.find(t.first); - lean_assert(row_it != m_external_rows_to_core_solver_rows.end()); + SASSERT(row_it != m_external_rows_to_core_solver_rows.end()); unsigned row = row_it->second; for (auto k : t.second) { auto column_info_it = m_map_from_var_index_to_column_info.find(k.first); - lean_assert(column_info_it != m_map_from_var_index_to_column_info.end()); + SASSERT(column_info_it != m_map_from_var_index_to_column_info.end()); column_info *ci = column_info_it->second; unsigned col = ci->get_column_index(); - lean_assert(is_valid(col)); + SASSERT(is_valid(col)); bool col_is_flipped = m_map_from_var_index_to_column_info[k.first]->is_flipped(); if (!col_is_flipped) { (*m_A)(row, col) = k.second; @@ -456,7 +471,7 @@ template void lp_solver::fill_A_from_A_values() { template void lp_solver::fill_matrix_A_and_init_right_side() { map_external_rows_to_core_solver_rows(); map_external_columns_to_core_solver_columns(); - lean_assert(m_A == nullptr); + SASSERT(m_A == nullptr); fill_A_from_A_values(); m_b.resize(m_A->row_count()); } @@ -468,7 +483,7 @@ template void lp_solver::count_slacks_and_artific } template void lp_solver::count_slacks_and_artificials_for_row(unsigned i) { - lean_assert(this->m_constraints.find(this->m_core_solver_rows_to_external_rows[i]) != this->m_constraints.end()); + SASSERT(this->m_constraints.find(this->m_core_solver_rows_to_external_rows[i]) != this->m_constraints.end()); auto & constraint = this->m_constraints[this->m_core_solver_rows_to_external_rows[i]]; switch (constraint.m_relation) { case Equal: @@ -504,7 +519,7 @@ template T lp_solver::low_bound_shift_for_row( template void lp_solver::fill_m_b() { for (int i = this->row_count() - 1; i >= 0; i--) { - lean_assert(this->m_constraints.find(this->m_core_solver_rows_to_external_rows[i]) != this->m_constraints.end()); + SASSERT(this->m_constraints.find(this->m_core_solver_rows_to_external_rows[i]) != this->m_constraints.end()); unsigned external_i = this->m_core_solver_rows_to_external_rows[i]; auto & constraint = this->m_constraints[external_i]; this->m_b[i] = constraint.m_rs - low_bound_shift_for_row(external_i); @@ -542,13 +557,13 @@ template T lp_solver::get_column_value_with_core_ template void lp_solver::set_scaled_cost(unsigned j) { // grab original costs but modify it with the column scales - lean_assert(j < this->m_column_scale.size()); + SASSERT(j < this->m_column_scale.size()); column_info * ci = this->m_map_from_var_index_to_column_info[this->m_core_solver_columns_to_external_columns[j]]; T cost = ci->get_cost(); if (ci->is_flipped()){ cost *= -1; } - lean_assert(ci->is_fixed() == false); + SASSERT(ci->is_fixed() == false); this->m_costs[j] = cost * this->m_column_scale[j]; } } diff --git a/src/util/lp/lp_solver_instances.cpp b/src/util/lp/lp_solver_instances.cpp index 5df490cae..4fe04c05f 100644 --- a/src/util/lp/lp_solver_instances.cpp +++ b/src/util/lp/lp_solver_instances.cpp @@ -1,40 +1,55 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/lp/lp_solver.hpp" -template void lean::lp_solver::add_constraint(lean::lp_relation, double, unsigned int); -template void lean::lp_solver::cleanup(); -template void lean::lp_solver::count_slacks_and_artificials(); -template void lean::lp_solver::fill_m_b(); -template void lean::lp_solver::fill_matrix_A_and_init_right_side(); -template void lean::lp_solver::flip_costs(); -template double lean::lp_solver::get_column_cost_value(unsigned int, lean::column_info*) const; -template int lean::lp_solver::get_column_index_by_name(std::string) const; -template double lean::lp_solver::get_column_value_with_core_solver(unsigned int, lean::lp_core_solver_base*) const; -template lean::column_info* lean::lp_solver::get_or_create_column_info(unsigned int); -template void lean::lp_solver::give_symbolic_name_to_column(std::string, unsigned int); -template void lean::lp_solver::print_statistics_on_A(std::ostream & out); -template bool lean::lp_solver::problem_is_empty(); -template void lean::lp_solver::scale(); -template void lean::lp_solver::set_scaled_cost(unsigned int); -template lean::lp_solver::~lp_solver(); -template void lean::lp_solver::add_constraint(lean::lp_relation, lean::mpq, unsigned int); -template void lean::lp_solver::cleanup(); -template void lean::lp_solver::count_slacks_and_artificials(); -template void lean::lp_solver::fill_m_b(); -template void lean::lp_solver::fill_matrix_A_and_init_right_side(); -template void lean::lp_solver::flip_costs(); -template lean::mpq lean::lp_solver::get_column_cost_value(unsigned int, lean::column_info*) const; -template int lean::lp_solver::get_column_index_by_name(std::string) const; -template lean::mpq lean::lp_solver::get_column_value_by_name(std::string) const; -template lean::mpq lean::lp_solver::get_column_value_with_core_solver(unsigned int, lean::lp_core_solver_base*) const; -template lean::column_info* lean::lp_solver::get_or_create_column_info(unsigned int); -template void lean::lp_solver::give_symbolic_name_to_column(std::string, unsigned int); -template void lean::lp_solver::print_statistics_on_A(std::ostream & out); -template bool lean::lp_solver::problem_is_empty(); -template void lean::lp_solver::scale(); -template void lean::lp_solver::set_scaled_cost(unsigned int); -template lean::lp_solver::~lp_solver(); -template double lean::lp_solver::get_column_value_by_name(std::string) const; +template void lp::lp_solver::add_constraint(lp::lp_relation, double, unsigned int); +template void lp::lp_solver::cleanup(); +template void lp::lp_solver::count_slacks_and_artificials(); +template void lp::lp_solver::fill_m_b(); +template void lp::lp_solver::fill_matrix_A_and_init_right_side(); +template void lp::lp_solver::flip_costs(); +template double lp::lp_solver::get_column_cost_value(unsigned int, lp::column_info*) const; +template int lp::lp_solver::get_column_index_by_name(std::string) const; +template double lp::lp_solver::get_column_value_with_core_solver(unsigned int, lp::lp_core_solver_base*) const; +template lp::column_info* lp::lp_solver::get_or_create_column_info(unsigned int); +template void lp::lp_solver::give_symbolic_name_to_column(std::string, unsigned int); +template void lp::lp_solver::print_statistics_on_A(std::ostream & out); +template bool lp::lp_solver::problem_is_empty(); +template void lp::lp_solver::scale(); +template void lp::lp_solver::set_scaled_cost(unsigned int); +template lp::lp_solver::~lp_solver(); +template void lp::lp_solver::add_constraint(lp::lp_relation, lp::mpq, unsigned int); +template void lp::lp_solver::cleanup(); +template void lp::lp_solver::count_slacks_and_artificials(); +template void lp::lp_solver::fill_m_b(); +template void lp::lp_solver::fill_matrix_A_and_init_right_side(); +template void lp::lp_solver::flip_costs(); +template lp::mpq lp::lp_solver::get_column_cost_value(unsigned int, lp::column_info*) const; +template int lp::lp_solver::get_column_index_by_name(std::string) const; +template lp::mpq lp::lp_solver::get_column_value_by_name(std::string) const; +template lp::mpq lp::lp_solver::get_column_value_with_core_solver(unsigned int, lp::lp_core_solver_base*) const; +template lp::column_info* lp::lp_solver::get_or_create_column_info(unsigned int); +template void lp::lp_solver::give_symbolic_name_to_column(std::string, unsigned int); +template void lp::lp_solver::print_statistics_on_A(std::ostream & out); +template bool lp::lp_solver::problem_is_empty(); +template void lp::lp_solver::scale(); +template void lp::lp_solver::set_scaled_cost(unsigned int); +template lp::lp_solver::~lp_solver(); +template double lp::lp_solver::get_column_value_by_name(std::string) const; diff --git a/src/util/lp/lp_utils.cpp b/src/util/lp/lp_utils.cpp index 8cb98974e..46a82e9ec 100644 --- a/src/util/lp/lp_utils.cpp +++ b/src/util/lp/lp_utils.cpp @@ -1,11 +1,26 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/lp_utils.h" -#ifdef lp_for_z3 -namespace lean { + +namespace lp { double numeric_traits::g_zero = 0.0; double numeric_traits::g_one = 1.0; } -#endif + diff --git a/src/util/lp/lp_utils.h b/src/util/lp/lp_utils.h index 2be15d79a..fce9f4d02 100644 --- a/src/util/lp/lp_utils.h +++ b/src/util/lp/lp_utils.h @@ -1,8 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson - This file should be present in z3 and in Lean. -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include #include "util/lp/numeric_pair.h" @@ -18,23 +32,15 @@ bool try_get_val(const std::unordered_map & map, const A& key, B & val) { template bool contains(const std::unordered_map & map, const A& key) { - return map.find(key) != map.end(); + return map.find(key) != map.end(); } -#ifdef lp_for_z3 - -#ifdef Z3DEBUG -#define LEAN_DEBUG 1 -#endif - -namespace lean { +namespace lp { inline void throw_exception(const std::string & str) { throw default_exception(str); } typedef z3_exception exception; -#define lean_assert(_x_) { SASSERT(_x_); } - inline void lean_unreachable() { lean_assert(false); } template inline X zero_of_type() { return numeric_traits::zero(); } template inline X one_of_type() { return numeric_traits::one(); } template inline bool is_zero(const X & v) { return numeric_traits::is_zero(v); } @@ -68,8 +74,8 @@ template struct hash> { }; template<> -struct hash> { - inline size_t operator()(const lean::numeric_pair & v) const { +struct hash> { + inline size_t operator()(const lp::numeric_pair & v) const { size_t seed = 0; hash_combine(seed, v.x); hash_combine(seed, v.y); @@ -78,64 +84,3 @@ struct hash> { }; } -#else // else of #if lp_for_z3 -#include -#include -//include "util/numerics/mpq.h" -//include "util/numerics/numeric_traits.h" -//include "util/numerics/double.h" - -#ifdef __CLANG__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmismatched-tags" -#endif -namespace std { -template<> -struct hash { - inline size_t operator()(const lean::mpq & v) const { - return v.hash(); - } -}; -} -namespace lean { -template inline bool precise() { return numeric_traits::precise();} -template inline X one_of_type() { return numeric_traits::one(); } -template inline bool is_zero(const X & v) { return numeric_traits::is_zero(v); } -template inline double get_double(const X & v) { return numeric_traits::get_double(v); } -template inline T zero_of_type() {return numeric_traits::zero();} -inline void throw_exception(std::string str) { throw exception(str); } -template inline T from_string(std::string const & ) { lean_unreachable();} -template <> double inline from_string(std::string const & str) { return atof(str.c_str());} -template <> mpq inline from_string(std::string const & str) { - return mpq(atof(str.c_str())); -} - -} // closing lean -template -inline void hash_combine(std::size_t & seed, const T & v) { - seed ^= std::hash()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); -} - -namespace std { -template struct hash> { - inline size_t operator()(const pair & v) const { - size_t seed = 0; - hash_combine(seed, v.first); - hash_combine(seed, v.second); - return seed; - } -}; -template<> -struct hash> { - inline size_t operator()(const lean::numeric_pair & v) const { - size_t seed = 0; - hash_combine(seed, v.x); - hash_combine(seed, v.y); - return seed; - } -}; -} // std -#ifdef __CLANG__ -#pragma clang diagnostic pop -#endif -#endif diff --git a/src/util/lp/lu.h b/src/util/lp/lu.h index 0d8163a14..5498a1849 100644 --- a/src/util/lp/lu.h +++ b/src/util/lp/lu.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once @@ -18,8 +33,8 @@ #include "util/lp/row_eta_matrix.h" #include "util/lp/square_dense_submatrix.h" #include "util/lp/dense_matrix.h" -namespace lean { -#ifdef LEAN_DEBUG +namespace lp { +#ifdef Z3DEBUG template // print the nr x nc submatrix at the top left corner void print_submatrix(sparse_matrix & m, unsigned mr, unsigned nc); @@ -32,7 +47,7 @@ void print_matrix(sparse_matrix& m, std::ostream & out); template X dot_product(const vector & a, const vector & b) { - lean_assert(a.size() == b.size()); + SASSERT(a.size() == b.size()); auto r = zero_of_type(); for (unsigned i = 0; i < a.size(); i++) { r += a[i] * b[i]; @@ -47,7 +62,7 @@ class one_elem_on_diag: public tail_matrix { T m_val; public: one_elem_on_diag(unsigned i, T val) : m_i(i), m_val(val) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG m_one_over_val = numeric_traits::one() / m_val; #endif } @@ -56,7 +71,7 @@ public: one_elem_on_diag(const one_elem_on_diag & o); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG unsigned m_m; unsigned m_n; virtual void set_number_of_rows(unsigned m) { m_m = m; m_n = m; } @@ -91,15 +106,15 @@ public: void conjugate_by_permutation(permutation_matrix & p) { // this = p * this * p(-1) -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // auto rev = p.get_reverse(); // auto deb = ((*this) * rev); // deb = p * deb; #endif m_i = p.apply_reverse(m_i); -#ifdef LEAN_DEBUG - // lean_assert(*this == deb); +#ifdef Z3DEBUG + // SASSERT(*this == deb); #endif } }; // end of one_elem_on_diag @@ -212,7 +227,7 @@ public: // see page 407 of Chvatal unsigned transform_U_to_V_by_replacing_column(indexed_vector & w, unsigned leaving_column_of_U); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG void check_vector_w(unsigned entering); void check_apply_matrix_to_vector(matrix *lp, T *w); @@ -248,7 +263,7 @@ public: bool is_correct(const vector& basis); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG dense_matrix tail_product(); dense_matrix get_left_side(const vector& basis); @@ -291,7 +306,7 @@ public: bool need_to_refactor() { return m_refactor_counter >= 200; } void adjust_dimension_with_matrix_A() { - lean_assert(m_A.row_count() >= m_dim); + SASSERT(m_A.row_count() >= m_dim); m_dim = m_A.row_count(); m_U.resize(m_dim); m_Q.resize(m_dim); @@ -305,7 +320,7 @@ public: unsigned m = m_A.row_count(); unsigned m_prev = m_U.dimension(); - lean_assert(m_A.column_count() == heading.size()); + SASSERT(m_A.column_count() == heading.size()); for (unsigned i = m_prev; i < m; i++) { for (const row_cell & c : m_A.m_rows[i]) { @@ -321,14 +336,14 @@ public: void add_last_rows_to_B(const vector & heading, const std::unordered_set & columns_to_replace) { unsigned m = m_A.row_count(); - lean_assert(m_A.column_count() == heading.size()); + SASSERT(m_A.column_count() == heading.size()); adjust_dimension_with_matrix_A(); m_w_for_extension.resize(m); // At this moment the LU is correct // for B extended by only by ones at the diagonal in the lower right corner for (unsigned j :columns_to_replace) { - lean_assert(heading[j] >= 0); + SASSERT(heading[j] >= 0); replace_column_with_only_change_at_last_rows(j, heading[j]); if (get_status() == LU_status::Degenerated) break; @@ -352,7 +367,7 @@ public: template void init_factorization(lu* & factorization, static_matrix & m_A, vector & m_basis, lp_settings &m_settings); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template dense_matrix get_B(lu& f, const vector& basis); #endif diff --git a/src/util/lp/lu.hpp b/src/util/lp/lu.hpp index 2d2c7c7c4..9d1532ac9 100644 --- a/src/util/lp/lu.hpp +++ b/src/util/lp/lu.hpp @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include @@ -9,8 +24,8 @@ #include #include "util/debug.h" #include "util/lp/lu.h" -namespace lean { -#ifdef LEAN_DEBUG +namespace lp { +#ifdef Z3DEBUG template // print the nr x nc submatrix at the top left corner void print_submatrix(sparse_matrix & m, unsigned mr, unsigned nc, std::ostream & out) { vector> A; @@ -72,13 +87,13 @@ template one_elem_on_diag::one_elem_on_diag(const one_elem_on_diag & o) { m_i = o.m_i; m_val = o.m_val; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG m_m = m_n = o.m_m; m_one_over_val = numeric_traits::one() / o.m_val; #endif } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template T one_elem_on_diag::get_elem(unsigned i, unsigned j) const { if (i == j){ @@ -122,29 +137,29 @@ lu::lu(static_matrix const & A, m_failure(false), m_row_eta_work_vector(A.row_count()), m_refactor_counter(0) { - lean_assert(!(numeric_traits::precise() && settings.use_tableau())); -#ifdef LEAN_DEBUG + SASSERT(!(numeric_traits::precise() && settings.use_tableau())); +#ifdef Z3DEBUG debug_test_of_basis(A, basis); #endif ++m_settings.st().m_num_factorizations; create_initial_factorization(); -#ifdef LEAN_DEBUG - // lean_assert(check_correctness()); +#ifdef Z3DEBUG + // SASSERT(check_correctness()); #endif } template void lu::debug_test_of_basis(static_matrix const & A, vector & basis) { std::set set; for (unsigned i = 0; i < A.row_count(); i++) { - lean_assert(basis[i]< A.column_count()); + SASSERT(basis[i]< A.column_count()); set.insert(basis[i]); } - lean_assert(set.size() == A.row_count()); + SASSERT(set.size() == A.row_count()); } template void lu::solve_By(indexed_vector & y) { - lean_assert(false); // not implemented + SASSERT(false); // not implemented // init_vector_y(y); // solve_By_when_y_is_ready(y); } @@ -268,7 +283,7 @@ void lu::solve_yB(vector& y) { m_U.solve_y_U(y); // got y*U=cb*R(-1) m_Q.apply_reverse_from_right_to_T(y); // for (auto e = m_tail.rbegin(); e != m_tail.rend(); ++e) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG (*e)->set_number_of_columns(m_dim); #endif (*e)->apply_from_right(y); @@ -277,20 +292,20 @@ void lu::solve_yB(vector& y) { template void lu::solve_yB_indexed(indexed_vector& y) { - lean_assert(y.is_OK()); + SASSERT(y.is_OK()); // first solve yU = cb*R(-1) m_R.apply_reverse_from_right_to_T(y); // got y = cb*R(-1) - lean_assert(y.is_OK()); + SASSERT(y.is_OK()); m_U.solve_y_U_indexed(y, m_settings); // got y*U=cb*R(-1) - lean_assert(y.is_OK()); + SASSERT(y.is_OK()); m_Q.apply_reverse_from_right_to_T(y); - lean_assert(y.is_OK()); + SASSERT(y.is_OK()); for (auto e = m_tail.rbegin(); e != m_tail.rend(); ++e) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG (*e)->set_number_of_columns(m_dim); #endif (*e)->apply_from_right(y); - lean_assert(y.is_OK()); + SASSERT(y.is_OK()); } } @@ -304,8 +319,8 @@ void lu::add_delta_to_solution(const vector& yc, vector& y){ template void lu::add_delta_to_solution_indexed(indexed_vector& y) { // the delta sits in m_y_copy, put result into y - lean_assert(y.is_OK()); - lean_assert(m_y_copy.is_OK()); + SASSERT(y.is_OK()); + SASSERT(m_y_copy.is_OK()); m_ii.clear(); m_ii.resize(y.data_size()); for (unsigned i : y.m_index) @@ -315,7 +330,7 @@ void lu::add_delta_to_solution_indexed(indexed_vector& y) { if (m_ii[i] == 0) m_ii.set_value(1, i); } - lean_assert(m_ii.is_OK()); + SASSERT(m_ii.is_OK()); y.m_index.clear(); for (unsigned i : m_ii.m_index) { @@ -326,7 +341,7 @@ void lu::add_delta_to_solution_indexed(indexed_vector& y) { v = zero_of_type(); } - lean_assert(y.is_OK()); + SASSERT(y.is_OK()); } template @@ -343,7 +358,7 @@ void lu::find_error_of_yB_indexed(const indexed_vector& y, const vector // it is a non efficient version indexed_vector yc = m_y_copy; yc.m_index.clear(); - lean_assert(!numeric_traits::precise()); + SASSERT(!numeric_traits::precise()); { vector d_basis(y.m_data.size()); @@ -364,10 +379,10 @@ void lu::find_error_of_yB_indexed(const indexed_vector& y, const vector } } #endif - lean_assert(m_ii.is_OK()); + SASSERT(m_ii.is_OK()); m_ii.clear(); m_ii.resize(y.data_size()); - lean_assert(m_y_copy.is_OK()); + SASSERT(m_y_copy.is_OK()); // put the error into m_y_copy for (auto k : y.m_index) { auto & row = m_A.m_rows[k]; @@ -399,7 +414,7 @@ void lu::find_error_of_yB_indexed(const indexed_vector& y, const vector m_y_copy.set_value(v, k); } } - lean_assert(m_y_copy.is_OK()); + SASSERT(m_y_copy.is_OK()); } @@ -419,12 +434,12 @@ void lu::solve_yB_with_error_check_indexed(indexed_vector & y, const ve } return; } - lean_assert(m_y_copy.is_OK()); - lean_assert(y.is_OK()); + SASSERT(m_y_copy.is_OK()); + SASSERT(y.is_OK()); if (y.m_index.size() * ratio_of_index_size_to_all_size() < m_A.column_count()) { m_y_copy = y; solve_yB_indexed(y); - lean_assert(y.is_OK()); + SASSERT(y.is_OK()); if (y.m_index.size() * ratio_of_index_size_to_all_size() >= m_A.column_count()) { find_error_of_yB(m_y_copy.m_data, y.m_data, basis); solve_yB(m_y_copy.m_data); @@ -436,7 +451,7 @@ void lu::solve_yB_with_error_check_indexed(indexed_vector & y, const ve solve_yB_indexed(m_y_copy); add_delta_to_solution_indexed(y); } - lean_assert(m_y_copy.is_OK()); + SASSERT(m_y_copy.is_OK()); } else { solve_yB_with_error_check(y.m_data, basis); y.restore_index_and_clean_from_data(); @@ -489,7 +504,7 @@ template void lu::perform_transformations_on_w(indexed_vector& w) { apply_lp_list_to_w(w); m_Q.apply_reverse_from_left(w); - // TBD does not compile: lean_assert(numeric_traits::precise() || check_vector_for_small_values(w, m_settings)); + // TBD does not compile: SASSERT(numeric_traits::precise() || check_vector_for_small_values(w, m_settings)); } // see Chvatal 24.3 @@ -503,7 +518,7 @@ template void lu::apply_lp_list_to_w(indexed_vector & w) { for (unsigned i = 0; i < m_tail.size(); i++) { m_tail[i]->apply_from_left_to_T(w, m_settings); - // TBD does not compile: lean_assert(check_vector_for_small_values(w, m_settings)); + // TBD does not compile: SASSERT(check_vector_for_small_values(w, m_settings)); } } template @@ -570,7 +585,7 @@ unsigned lu::transform_U_to_V_by_replacing_column(indexed_vector & w, return column_to_replace; } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template void lu::check_vector_w(unsigned entering) { T * w = new T[m_dim]; @@ -595,7 +610,7 @@ void lu::check_apply_lp_lists_to_w(T * w) { permutation_matrix qr = m_Q.get_reverse(); apply_to_vector(qr, w); for (int i = m_dim - 1; i >= 0; i--) { - lean_assert(abs(w[i] - w[i]) < 0.0000001); + SASSERT(abs(w[i] - w[i]) < 0.0000001); } } @@ -624,7 +639,7 @@ void lu::process_column(int j) { } template bool lu::is_correct(const vector& basis) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG if (get_status() != LU_status::OK) { return false; } @@ -637,10 +652,10 @@ bool lu::is_correct(const vector& basis) { } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template dense_matrix lu::tail_product() { - lean_assert(tail_size() > 0); + SASSERT(tail_size() > 0); dense_matrix left_side = permutation_matrix(m_dim); for (unsigned i = 0; i < tail_size(); i++) { matrix* lp = get_lp_matrix(i); @@ -690,8 +705,8 @@ template bool lu::all_columns_and_rows_are_active() { unsigned i = m_dim; while (i--) { - lean_assert(m_U.col_is_active(i)); - lean_assert(m_U.row_is_active(i)); + SASSERT(m_U.col_is_active(i)); + SASSERT(m_U.row_is_active(i)); } return true; } @@ -733,9 +748,9 @@ void lu::create_initial_factorization(){ } } if (j == m_dim) { - // TBD does not compile: lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); - // lean_assert(is_correct()); - // lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + // TBD does not compile: SASSERT(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + // SASSERT(is_correct()); + // SASSERT(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); return; } j++; @@ -748,12 +763,12 @@ void lu::create_initial_factorization(){ } } m_dense_LU->update_parent_matrix(m_settings); - lean_assert(m_dense_LU->is_L_matrix()); + SASSERT(m_dense_LU->is_L_matrix()); m_dense_LU->conjugate_by_permutation(m_Q); push_matrix_to_tail(m_dense_LU); m_refactor_counter = 0; - // lean_assert(is_correct()); - // lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + // SASSERT(is_correct()); + // SASSERT(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); } template @@ -780,7 +795,7 @@ void lu::scan_last_row_to_work_vector(unsigned lowest_row_of_the_bump) { vector> & last_row_vec = m_U.get_row_values(m_U.adjust_row(lowest_row_of_the_bump)); for (auto & iv : last_row_vec) { if (is_zero(iv.m_value)) continue; - lean_assert(!m_settings.abs_val_is_smaller_than_drop_tolerance(iv.m_value)); + SASSERT(!m_settings.abs_val_is_smaller_than_drop_tolerance(iv.m_value)); unsigned adjusted_col = m_U.adjust_column_inverse(iv.m_index); if (adjusted_col < lowest_row_of_the_bump) { m_row_eta_work_vector.set_value(-iv.m_value, adjusted_col); @@ -801,14 +816,14 @@ void lu::pivot_and_solve_the_system(unsigned replaced_column, unsigned low vector> & row = m_U.get_row_values(aj); for (auto & iv : row) { unsigned col = m_U.adjust_column_inverse(iv.m_index); - lean_assert(col >= j || numeric_traits::is_zero(iv.m_value)); + SASSERT(col >= j || numeric_traits::is_zero(iv.m_value)); if (col == j) continue; if (numeric_traits::is_zero(iv.m_value)) { continue; } // the -v is for solving the system ( to zero the last row), and +v is for pivoting T delta = col < lowest_row_of_the_bump? -v * iv.m_value: v * iv.m_value; - lean_assert(numeric_traits::is_zero(delta) == false); + SASSERT(numeric_traits::is_zero(delta) == false); @@ -845,7 +860,7 @@ row_eta_matrix *lu::get_row_eta_matrix_and_set_row_vector(unsigned r return nullptr; } } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG auto ret = new row_eta_matrix(replaced_column, lowest_row_of_the_bump, m_dim); #else auto ret = new row_eta_matrix(replaced_column, lowest_row_of_the_bump); @@ -885,15 +900,15 @@ void lu::replace_column(T pivot_elem_for_checking, indexed_vector & w, push_matrix_to_tail(row_eta); } calculate_Lwave_Pwave_for_bump(replaced_column, lowest_row_of_the_bump); - // lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); - // lean_assert(w.is_OK() && m_row_eta_work_vector.is_OK()); + // SASSERT(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + // SASSERT(w.is_OK() && m_row_eta_work_vector.is_OK()); } template void lu::calculate_Lwave_Pwave_for_bump(unsigned replaced_column, unsigned lowest_row_of_the_bump){ T diagonal_elem; if (replaced_column < lowest_row_of_the_bump) { diagonal_elem = m_row_eta_work_vector[lowest_row_of_the_bump]; - // lean_assert(m_row_eta_work_vector.is_OK()); + // SASSERT(m_row_eta_work_vector.is_OK()); m_U.set_row_from_work_vector_and_clean_work_vector_not_adjusted(m_U.adjust_row(lowest_row_of_the_bump), m_row_eta_work_vector, m_settings); } else { diagonal_elem = m_U(lowest_row_of_the_bump, lowest_row_of_the_bump); // todo - get it more efficiently @@ -904,13 +919,13 @@ void lu::calculate_Lwave_Pwave_for_bump(unsigned replaced_column, unsigned } calculate_Lwave_Pwave_for_last_row(lowest_row_of_the_bump, diagonal_elem); - // lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + // SASSERT(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); } template void lu::calculate_Lwave_Pwave_for_last_row(unsigned lowest_row_of_the_bump, T diagonal_element) { auto l = new one_elem_on_diag(lowest_row_of_the_bump, diagonal_element); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG l->set_number_of_columns(m_dim); #endif push_matrix_to_tail(l); @@ -927,11 +942,11 @@ void init_factorization(lu* & factorization, static_matrix & m_A, ve // LP_OUT(m_settings, "failing in init_factorization" << std::endl); } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template dense_matrix get_B(lu& f, const vector& basis) { - lean_assert(basis.size() == f.dimension()); - lean_assert(basis.size() == f.m_U.dimension()); + SASSERT(basis.size() == f.dimension()); + SASSERT(basis.size() == f.m_U.dimension()); dense_matrix B(f.dimension(), f.dimension()); for (unsigned i = 0; i < f.dimension(); i++) for (unsigned j = 0; j < f.dimension(); j++) diff --git a/src/util/lp/lu_instances.cpp b/src/util/lp/lu_instances.cpp index c8ff7b2f4..057895068 100644 --- a/src/util/lp/lu_instances.cpp +++ b/src/util/lp/lu_instances.cpp @@ -1,63 +1,78 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include #include "util/vector.h" #include "util/debug.h" #include "util/lp/lu.hpp" -template double lean::dot_product(vector const&, vector const&); -template lean::lu::lu(lean::static_matrix const&, vector&, lean::lp_settings&); -template void lean::lu::push_matrix_to_tail(lean::tail_matrix*); -template void lean::lu::replace_column(double, lean::indexed_vector&, unsigned); -template void lean::lu::solve_Bd(unsigned int, lean::indexed_vector&, lean::indexed_vector&); -template lean::lu::~lu(); -template void lean::lu::push_matrix_to_tail(lean::tail_matrix*); -template void lean::lu::solve_Bd(unsigned int, lean::indexed_vector&, lean::indexed_vector&); -template lean::lu::~lu(); -template void lean::lu >::push_matrix_to_tail(lean::tail_matrix >*); -template void lean::lu >::solve_Bd(unsigned int, lean::indexed_vector&, lean::indexed_vector&); -template lean::lu >::~lu(); -template lean::mpq lean::dot_product(vector const&, vector const&); -template void lean::init_factorization(lean::lu*&, lean::static_matrix&, vector&, lean::lp_settings&); -template void lean::init_factorization(lean::lu*&, lean::static_matrix&, vector&, lean::lp_settings&); -template void lean::init_factorization >(lean::lu >*&, lean::static_matrix >&, vector&, lean::lp_settings&); -#ifdef LEAN_DEBUG -template void lean::print_matrix(lean::sparse_matrix&, std::ostream & out); -template void lean::print_matrix(lean::static_matrix&, std::ostream&); -template void lean::print_matrix >(lean::static_matrix >&, std::ostream&); -template void lean::print_matrix(lean::static_matrix&, std::ostream & out); -template bool lean::lu::is_correct(const vector& basis); -template bool lean::lu >::is_correct( vector const &); -template lean::dense_matrix lean::get_B(lean::lu&, const vector& basis); -template lean::dense_matrix lean::get_B(lean::lu&, vector const&); +template double lp::dot_product(vector const&, vector const&); +template lp::lu::lu(lp::static_matrix const&, vector&, lp::lp_settings&); +template void lp::lu::push_matrix_to_tail(lp::tail_matrix*); +template void lp::lu::replace_column(double, lp::indexed_vector&, unsigned); +template void lp::lu::solve_Bd(unsigned int, lp::indexed_vector&, lp::indexed_vector&); +template lp::lu::~lu(); +template void lp::lu::push_matrix_to_tail(lp::tail_matrix*); +template void lp::lu::solve_Bd(unsigned int, lp::indexed_vector&, lp::indexed_vector&); +template lp::lu::~lu(); +template void lp::lu >::push_matrix_to_tail(lp::tail_matrix >*); +template void lp::lu >::solve_Bd(unsigned int, lp::indexed_vector&, lp::indexed_vector&); +template lp::lu >::~lu(); +template lp::mpq lp::dot_product(vector const&, vector const&); +template void lp::init_factorization(lp::lu*&, lp::static_matrix&, vector&, lp::lp_settings&); +template void lp::init_factorization(lp::lu*&, lp::static_matrix&, vector&, lp::lp_settings&); +template void lp::init_factorization >(lp::lu >*&, lp::static_matrix >&, vector&, lp::lp_settings&); +#ifdef Z3DEBUG +template void lp::print_matrix(lp::sparse_matrix&, std::ostream & out); +template void lp::print_matrix(lp::static_matrix&, std::ostream&); +template void lp::print_matrix >(lp::static_matrix >&, std::ostream&); +template void lp::print_matrix(lp::static_matrix&, std::ostream & out); +template bool lp::lu::is_correct(const vector& basis); +template bool lp::lu >::is_correct( vector const &); +template lp::dense_matrix lp::get_B(lp::lu&, const vector& basis); +template lp::dense_matrix lp::get_B(lp::lu&, vector const&); #endif -template bool lean::lu::pivot_the_row(int); // NOLINT -template void lean::lu::init_vector_w(unsigned int, lean::indexed_vector&); -template void lean::lu::solve_By(vector&); -template void lean::lu::solve_By_when_y_is_ready_for_X(vector&); -template void lean::lu::solve_yB_with_error_check(vector&, const vector& basis); -template void lean::lu::solve_yB_with_error_check_indexed(lean::indexed_vector&, vector const&, const vector & basis, const lp_settings&); -template void lean::lu::replace_column(lean::mpq, lean::indexed_vector&, unsigned); -template void lean::lu::solve_By(vector&); -template void lean::lu::solve_By_when_y_is_ready_for_X(vector&); -template void lean::lu::solve_yB_with_error_check(vector&, const vector& basis); -template void lean::lu::solve_yB_with_error_check_indexed(lean::indexed_vector&, vector< int > const&, const vector & basis, const lp_settings&); -template void lean::lu >::solve_yB_with_error_check_indexed(lean::indexed_vector&, vector< int > const&, const vector & basis, const lp_settings&); -template void lean::lu >::init_vector_w(unsigned int, lean::indexed_vector&); -template void lean::lu >::replace_column(lean::mpq, lean::indexed_vector&, unsigned); -template void lean::lu >::solve_Bd_faster(unsigned int, lean::indexed_vector&); -template void lean::lu >::solve_By(vector >&); -template void lean::lu >::solve_By_when_y_is_ready_for_X(vector >&); -template void lean::lu >::solve_yB_with_error_check(vector&, const vector& basis); -template void lean::lu::solve_By(lean::indexed_vector&); -template void lean::lu::solve_By(lean::indexed_vector&); -template void lean::lu::solve_yB_indexed(lean::indexed_vector&); -template void lean::lu::solve_yB_indexed(lean::indexed_vector&); -template void lean::lu >::solve_yB_indexed(lean::indexed_vector&); -template void lean::lu::solve_By_for_T_indexed_only(lean::indexed_vector&, lean::lp_settings const&); -template void lean::lu::solve_By_for_T_indexed_only(lean::indexed_vector&, lean::lp_settings const&); +template bool lp::lu::pivot_the_row(int); // NOLINT +template void lp::lu::init_vector_w(unsigned int, lp::indexed_vector&); +template void lp::lu::solve_By(vector&); +template void lp::lu::solve_By_when_y_is_ready_for_X(vector&); +template void lp::lu::solve_yB_with_error_check(vector&, const vector& basis); +template void lp::lu::solve_yB_with_error_check_indexed(lp::indexed_vector&, vector const&, const vector & basis, const lp_settings&); +template void lp::lu::replace_column(lp::mpq, lp::indexed_vector&, unsigned); +template void lp::lu::solve_By(vector&); +template void lp::lu::solve_By_when_y_is_ready_for_X(vector&); +template void lp::lu::solve_yB_with_error_check(vector&, const vector& basis); +template void lp::lu::solve_yB_with_error_check_indexed(lp::indexed_vector&, vector< int > const&, const vector & basis, const lp_settings&); +template void lp::lu >::solve_yB_with_error_check_indexed(lp::indexed_vector&, vector< int > const&, const vector & basis, const lp_settings&); +template void lp::lu >::init_vector_w(unsigned int, lp::indexed_vector&); +template void lp::lu >::replace_column(lp::mpq, lp::indexed_vector&, unsigned); +template void lp::lu >::solve_Bd_faster(unsigned int, lp::indexed_vector&); +template void lp::lu >::solve_By(vector >&); +template void lp::lu >::solve_By_when_y_is_ready_for_X(vector >&); +template void lp::lu >::solve_yB_with_error_check(vector&, const vector& basis); +template void lp::lu::solve_By(lp::indexed_vector&); +template void lp::lu::solve_By(lp::indexed_vector&); +template void lp::lu::solve_yB_indexed(lp::indexed_vector&); +template void lp::lu::solve_yB_indexed(lp::indexed_vector&); +template void lp::lu >::solve_yB_indexed(lp::indexed_vector&); +template void lp::lu::solve_By_for_T_indexed_only(lp::indexed_vector&, lp::lp_settings const&); +template void lp::lu::solve_By_for_T_indexed_only(lp::indexed_vector&, lp::lp_settings const&); diff --git a/src/util/lp/matrix.h b/src/util/lp/matrix.h index 63fd5c01e..f6374756f 100644 --- a/src/util/lp/matrix.h +++ b/src/util/lp/matrix.h @@ -1,14 +1,29 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #ifdef Z3DEBUG #pragma once #include "util/lp/numeric_pair.h" #include "util/vector.h" #include #include "util/lp/lp_settings.h" -namespace lean { +namespace lp { // used for debugging purposes only template class matrix { diff --git a/src/util/lp/matrix.hpp b/src/util/lp/matrix.hpp index d032cab8c..6eb82a9cc 100644 --- a/src/util/lp/matrix.hpp +++ b/src/util/lp/matrix.hpp @@ -1,13 +1,28 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #ifdef Z3DEBUG #include #include #include "util/lp/matrix.h" -namespace lean { +namespace lp { template bool matrix::is_equal(const matrix& other) { if (other.row_count() != row_count() || other.column_count() != column_count()) diff --git a/src/util/lp/matrix_instances.cpp b/src/util/lp/matrix_instances.cpp index aeee62786..8271a4d8a 100644 --- a/src/util/lp/matrix_instances.cpp +++ b/src/util/lp/matrix_instances.cpp @@ -1,16 +1,31 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/lp_settings.h" -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG #include "util/lp/matrix.hpp" #include "util/lp/static_matrix.h" #include -template void lean::print_matrix(lean::matrix const*, std::ostream & out); -template bool lean::matrix::is_equal(lean::matrix const&); -template void lean::print_matrix >(lean::matrix > const *, std::basic_ostream > &); -template void lean::print_matrix(lean::matrix const*, std::ostream&); -template bool lean::matrix >::is_equal(lean::matrix > const&); -template bool lean::matrix::is_equal(lean::matrix const&); +template void lp::print_matrix(lp::matrix const*, std::ostream & out); +template bool lp::matrix::is_equal(lp::matrix const&); +template void lp::print_matrix >(lp::matrix > const *, std::basic_ostream > &); +template void lp::print_matrix(lp::matrix const*, std::ostream&); +template bool lp::matrix >::is_equal(lp::matrix > const&); +template bool lp::matrix::is_equal(lp::matrix const&); #endif diff --git a/src/util/lp/mps_reader.h b/src/util/lp/mps_reader.h index 4c793d56e..1b020407d 100644 --- a/src/util/lp/mps_reader.h +++ b/src/util/lp/mps_reader.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once @@ -19,7 +34,7 @@ #include "util/lp/lar_solver.h" #include "util/lp/lp_utils.h" #include "util/lp/lp_solver.h" -namespace lean { +namespace lp { inline bool my_white_space(const char & a) { return a == ' ' || a == '\t'; } @@ -160,9 +175,9 @@ class mps_reader { if (m_line[i] == ' ') break; } - lean_assert(m_line.size() >= offset); - lean_assert(m_line.size() >> i); - lean_assert(i >= offset); + SASSERT(m_line.size() >= offset); + SASSERT(m_line.size() >> i); + SASSERT(i >= offset); return m_line.substr(offset, i - offset); } @@ -497,7 +512,7 @@ class mps_reader { void create_or_update_bound() { const unsigned name_offset = 14; - lean_assert(m_line.size() >= 14); + SASSERT(m_line.size() >= 14); vector bound_string = split_and_trim(m_line.substr(name_offset, m_line.size())); if (bound_string.size() == 0) { @@ -603,7 +618,7 @@ class mps_reader { } for (auto s : row_with_range->m_row_columns) { - lean_assert(m_columns.find(s.first) != m_columns.end()); + SASSERT(m_columns.find(s.first) != m_columns.end()); other_bound_range_row->m_row_columns[s.first] = s.second; } } @@ -679,7 +694,7 @@ class mps_reader { if (row->m_name != m_cost_row_name) { solver->add_constraint(get_relation_from_row(row->m_type), row->m_right_side, row->m_index); for (auto s : row->m_row_columns) { - lean_assert(m_columns.find(s.first) != m_columns.end()); + SASSERT(m_columns.find(s.first) != m_columns.end()); solver->set_row_column_coefficient(row->m_index, m_columns[s.first]->m_index, s.second); } } else { @@ -714,7 +729,7 @@ class mps_reader { void set_solver_cost(row * row, lp_solver *solver) { for (auto s : row->m_row_columns) { std::string name = s.first; - lean_assert(m_columns.find(name) != m_columns.end()); + SASSERT(m_columns.find(name) != m_columns.end()); mps_reader::column * col = m_columns[name]; solver->set_cost_for_column(col->m_index, s.second); } @@ -723,7 +738,7 @@ class mps_reader { public: void set_message_stream(std::ostream * o) { - lean_assert(o != nullptr); + SASSERT(o != nullptr); m_message_stream = o; } vector column_names() { diff --git a/src/util/lp/numeric_pair.h b/src/util/lp/numeric_pair.h index 84c99b3b1..4ebe63613 100644 --- a/src/util/lp/numeric_pair.h +++ b/src/util/lp/numeric_pair.h @@ -1,33 +1,38 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson - The idea is that it is only one different file in Lean and z3 source inside of LP -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once -#define lp_for_z3 + #include #include #include -#ifdef lp_for_z3 #include "../rational.h" #include "../sstream.h" #include "../z3_exception.h" -#else - // include "util/numerics/mpq.h" - // include "util/numerics/numeric_traits.h" -#endif -namespace lean { -#ifdef lp_for_z3 // rename rationals - typedef rational mpq; -#else - typedef lean::mpq mpq; -#endif +namespace lp { + typedef rational mpq; // rename rationals template std::string T_to_string(const T & t); // forward definition -#ifdef lp_for_z3 + template class numeric_traits {}; template <> class numeric_traits { @@ -67,14 +72,13 @@ template <> class numeric_traits { static bool is_pos(const rational & d) {return d.is_pos();} static bool is_neg(const rational & d) {return d.is_neg();} }; -#endif template struct convert_struct { static X convert(const Y & y){ return X(y);} static bool is_epsilon_small(const X & x, const double & y) { return std::abs(numeric_traits::get_double(x)) < y; } - static bool below_bound_numeric(const X &, const X &, const Y &) { /*lean_unreachable();*/ return false;} - static bool above_bound_numeric(const X &, const X &, const Y &) { /*lean_unreachable();*/ return false; } + static bool below_bound_numeric(const X &, const X &, const Y &) { /*SASSERT(false);*/ return false;} + static bool above_bound_numeric(const X &, const X &, const Y &) { /*SASSERT(false);*/ return false; } }; @@ -104,9 +108,9 @@ struct numeric_pair { template numeric_pair(const X & n) : x(n), y(0) { } - + numeric_pair(const numeric_pair & n) : x(n.x), y(n.y) {} - + template numeric_pair(X xp, Y yp) : x(convert_struct::convert(xp)), y(convert_struct::convert(yp)) {} @@ -144,16 +148,16 @@ struct numeric_pair { } numeric_pair operator/(const numeric_pair &) const { - // lean_unreachable(); + // SASSERT(false); } - - + + numeric_pair operator+(const numeric_pair & a) const { return numeric_pair(a.x + x, a.y + y); } numeric_pair operator*(const numeric_pair & /*a*/) const { - // lean_unreachable(); + // SASSERT(false); } numeric_pair& operator+=(const numeric_pair & a) { @@ -188,14 +192,14 @@ struct numeric_pair { return numeric_pair(-x, -y); } - static bool precize() { return lean::numeric_traits::precize();} + static bool precize() { return lp::numeric_traits::precize();} bool is_zero() const { return x.is_zero() && y.is_zero(); } bool is_pos() const { return x.is_pos() || (x.is_zero() && y.is_pos());} bool is_neg() const { return x.is_neg() || (x.is_zero() && y.is_neg());} - + std::string to_string() const { return std::string("(") + T_to_string(x) + ", " + T_to_string(y) + ")"; } @@ -225,15 +229,15 @@ numeric_pair operator/(const numeric_pair & r, const X & a) { } // template bool precise() { return numeric_traits::precise();} -template double get_double(const lean::numeric_pair & ) { /* lean_unreachable(); */ return 0;} +template double get_double(const lp::numeric_pair & ) { /* SASSERT(false); */ return 0;} template -class numeric_traits> { +class numeric_traits> { public: static bool precise() { return numeric_traits::precise();} - static lean::numeric_pair zero() { return lean::numeric_pair(numeric_traits::zero(), numeric_traits::zero()); } - static bool is_zero(const lean::numeric_pair & v) { return numeric_traits::is_zero(v.x) && numeric_traits::is_zero(v.y); } - static double get_double(const lean::numeric_pair & v){ return numeric_traits::get_double(v.x); } // just return the double of the first coordinate - static double one() { /*lean_unreachable();*/ return 0;} + static lp::numeric_pair zero() { return lp::numeric_pair(numeric_traits::zero(), numeric_traits::zero()); } + static bool is_zero(const lp::numeric_pair & v) { return numeric_traits::is_zero(v.x) && numeric_traits::is_zero(v.y); } + static double get_double(const lp::numeric_pair & v){ return numeric_traits::get_double(v.x); } // just return the double of the first coordinate + static double one() { /*SASSERT(false);*/ return 0;} static bool is_pos(const numeric_pair &p) { return numeric_traits::is_pos(p.x) || (numeric_traits::is_zero(p.x) && numeric_traits::is_pos(p.y)); @@ -242,7 +246,7 @@ class numeric_traits> { return numeric_traits::is_neg(p.x) || (numeric_traits::is_zero(p.x) && numeric_traits::is_neg(p.y)); } - + }; template <> @@ -263,11 +267,11 @@ struct convert_struct, double> { return convert_struct::is_epsilon_small(p.x, eps) && convert_struct::is_epsilon_small(p.y, eps); } static bool below_bound_numeric(const numeric_pair &, const numeric_pair &, const double &) { - // lean_unreachable(); + // SASSERT(false); return false; } static bool above_bound_numeric(const numeric_pair &, const numeric_pair &, const double &) { - // lean_unreachable(); + // SASSERT(false); return false; } }; diff --git a/src/util/lp/permutation_matrix.h b/src/util/lp/permutation_matrix.h index 4bdd57f25..7cf64a5c7 100644 --- a/src/util/lp/permutation_matrix.h +++ b/src/util/lp/permutation_matrix.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include @@ -12,8 +27,8 @@ #include "util/lp/lp_settings.h" #include "util/lp/matrix.h" #include "util/lp/tail_matrix.h" -namespace lean { -#ifdef LEAN_DEBUG +namespace lp { +#ifdef Z3DEBUG inline bool is_even(int k) { return (k/2)*2 == k; } #endif @@ -50,7 +65,7 @@ class permutation_matrix : public tail_matrix { void init(unsigned length); unsigned get_rev(unsigned i) { return m_rev[i]; } bool is_dense() const { return false; } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG permutation_matrix get_inverse() const { return permutation_matrix(size(), m_rev); } @@ -86,14 +101,14 @@ class permutation_matrix : public tail_matrix { void apply_reverse_from_right_to_X(vector & w); void set_val(unsigned i, unsigned pi) { - lean_assert(i < size() && pi < size()); m_permutation[i] = pi; m_rev[pi] = i; } + SASSERT(i < size() && pi < size()); m_permutation[i] = pi; m_rev[pi] = i; } void transpose_from_left(unsigned i, unsigned j); unsigned apply_reverse(unsigned i) const { return m_rev[i]; } void transpose_from_right(unsigned i, unsigned j); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG T get_elem(unsigned i, unsigned j) const{ return m_permutation[i] == j? numeric_traits::one() : numeric_traits::zero(); } diff --git a/src/util/lp/permutation_matrix.hpp b/src/util/lp/permutation_matrix.hpp index ec9af5a50..be96ca99f 100644 --- a/src/util/lp/permutation_matrix.hpp +++ b/src/util/lp/permutation_matrix.hpp @@ -1,10 +1,25 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/vector.h" #include "util/lp/permutation_matrix.h" -namespace lean { +namespace lp { template permutation_matrix::permutation_matrix(unsigned length): m_permutation(length), m_rev(length), m_T_buffer(length), m_X_buffer(length) { for (unsigned i = 0; i < length; i++) { // do not change the direction of the loop because of the vectorization bug in clang3.3 m_permutation[i] = m_rev[i] = i; @@ -27,7 +42,7 @@ template void permutation_matrix::init(unsigned l } } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template void permutation_matrix::print(std::ostream & out) const { out << "["; for (unsigned i = 0; i < size(); i++) { @@ -44,13 +59,13 @@ template void permutation_matrix::print(std::ostr template void permutation_matrix::apply_from_left(vector & w, lp_settings & ) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // dense_matrix deb(*this); // L * deb_w = clone_vector(w, row_count()); // deb.apply_from_left(deb_w); #endif // std::cout << " apply_from_left " << std::endl; - lean_assert(m_X_buffer.size() == w.size()); + SASSERT(m_X_buffer.size() == w.size()); unsigned i = size(); while (i-- > 0) { m_X_buffer[i] = w[m_permutation[i]]; @@ -59,8 +74,8 @@ void permutation_matrix::apply_from_left(vector & w, lp_settings & ) { while (i-- > 0) { w[i] = m_X_buffer[i]; } -#ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(deb_w, w, row_count())); +#ifdef Z3DEBUG + // SASSERT(vectors_are_equal(deb_w, w, row_count())); // delete [] deb_w; #endif } @@ -81,12 +96,12 @@ void permutation_matrix::apply_from_left_to_T(indexed_vector & w, lp_se } template void permutation_matrix::apply_from_right(vector & w) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // dense_matrix deb(*this); // T * deb_w = clone_vector(w, row_count()); // deb.apply_from_right(deb_w); #endif - lean_assert(m_T_buffer.size() == w.size()); + SASSERT(m_T_buffer.size() == w.size()); for (unsigned i = 0; i < size(); i++) { m_T_buffer[i] = w[m_rev[i]]; } @@ -94,14 +109,14 @@ template void permutation_matrix::apply_from_righ for (unsigned i = 0; i < size(); i++) { w[i] = m_T_buffer[i]; } -#ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(deb_w, w, row_count())); +#ifdef Z3DEBUG + // SASSERT(vectors_are_equal(deb_w, w, row_count())); // delete [] deb_w; #endif } template void permutation_matrix::apply_from_right(indexed_vector & w) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG vector wcopy(w.m_data); apply_from_right(wcopy); #endif @@ -117,9 +132,9 @@ template void permutation_matrix::apply_from_righ unsigned pj = m_permutation[j]; w.set_value(buffer[i], pj); } - lean_assert(w.is_OK()); -#ifdef LEAN_DEBUG - lean_assert(vectors_are_equal(wcopy, w.m_data)); + SASSERT(w.is_OK()); +#ifdef Z3DEBUG + SASSERT(vectors_are_equal(wcopy, w.m_data)); #endif } @@ -147,7 +162,7 @@ void permutation_matrix::clear_data(indexed_vector & w) { template template void permutation_matrix::apply_reverse_from_left(indexed_vector & w) { // the result will be w = p(-1) * w -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // dense_matrix deb(get_reverse()); // L * deb_w = clone_vector(w.m_data, row_count()); // deb.apply_from_left(deb_w); @@ -165,8 +180,8 @@ void permutation_matrix::apply_reverse_from_left(indexed_vector & w) { w[j] = t[i]; w.m_index[i] = j; } -#ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(deb_w, w.m_data, row_count())); +#ifdef Z3DEBUG + // SASSERT(vectors_are_equal(deb_w, w.m_data, row_count())); // delete [] deb_w; #endif } @@ -174,7 +189,7 @@ void permutation_matrix::apply_reverse_from_left(indexed_vector & w) { template void permutation_matrix::apply_reverse_from_left_to_T(vector & w) { // the result will be w = p(-1) * w - lean_assert(m_T_buffer.size() == w.size()); + SASSERT(m_T_buffer.size() == w.size()); unsigned i = size(); while (i-- > 0) { m_T_buffer[m_permutation[i]] = w[i]; @@ -187,7 +202,7 @@ void permutation_matrix::apply_reverse_from_left_to_T(vector & w) { template void permutation_matrix::apply_reverse_from_left_to_X(vector & w) { // the result will be w = p(-1) * w - lean_assert(m_X_buffer.size() == w.size()); + SASSERT(m_X_buffer.size() == w.size()); unsigned i = size(); while (i-- > 0) { m_X_buffer[m_permutation[i]] = w[i]; @@ -201,7 +216,7 @@ void permutation_matrix::apply_reverse_from_left_to_X(vector & w) { template void permutation_matrix::apply_reverse_from_right_to_T(vector & w) { // the result will be w = w * p(-1) - lean_assert(m_T_buffer.size() == w.size()); + SASSERT(m_T_buffer.size() == w.size()); unsigned i = size(); while (i-- > 0) { m_T_buffer[i] = w[m_permutation[i]]; @@ -215,11 +230,11 @@ void permutation_matrix::apply_reverse_from_right_to_T(vector & w) { template void permutation_matrix::apply_reverse_from_right_to_T(indexed_vector & w) { // the result will be w = w * p(-1) -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // vector wcopy(w.m_data); // apply_reverse_from_right_to_T(wcopy); #endif - lean_assert(w.is_OK()); + SASSERT(w.is_OK()); vector tmp; vector tmp_index(w.m_index); for (auto i : w.m_index) { @@ -232,15 +247,15 @@ void permutation_matrix::apply_reverse_from_right_to_T(indexed_vector & w.set_value(tmp[k], m_rev[j]); } - // lean_assert(w.is_OK()); - // lean_assert(vectors_are_equal(w.m_data, wcopy)); + // SASSERT(w.is_OK()); + // SASSERT(vectors_are_equal(w.m_data, wcopy)); } template void permutation_matrix::apply_reverse_from_right_to_X(vector & w) { // the result will be w = w * p(-1) - lean_assert(m_X_buffer.size() == w.size()); + SASSERT(m_X_buffer.size() == w.size()); unsigned i = size(); while (i-- > 0) { m_X_buffer[i] = w[m_permutation[i]]; @@ -253,7 +268,7 @@ void permutation_matrix::apply_reverse_from_right_to_X(vector & w) { template void permutation_matrix::transpose_from_left(unsigned i, unsigned j) { // the result will be this = (i,j)*this - lean_assert(i < size() && j < size() && i != j); + SASSERT(i < size() && j < size() && i != j); auto pi = m_rev[i]; auto pj = m_rev[j]; set_val(pi, j); @@ -262,7 +277,7 @@ template void permutation_matrix::transpose_from_ template void permutation_matrix::transpose_from_right(unsigned i, unsigned j) { // the result will be this = this * (i,j) - lean_assert(i < size() && j < size() && i != j); + SASSERT(i < size() && j < size() && i != j); auto pi = m_permutation[i]; auto pj = m_permutation[j]; set_val(i, pj); @@ -271,7 +286,7 @@ template void permutation_matrix::transpose_from_ template void permutation_matrix::multiply_by_permutation_from_left(permutation_matrix & p) { m_work_array = m_permutation; - lean_assert(p.size() == size()); + SASSERT(p.size() == size()); unsigned i = size(); while (i-- > 0) { set_val(i, m_work_array[p[i]]); // we have m(P)*m(Q) = m(QP), where m is the matrix of the permutation @@ -281,7 +296,7 @@ template void permutation_matrix::multiply_by_per // this is multiplication in the matrix sense template void permutation_matrix::multiply_by_permutation_from_right(permutation_matrix & p) { m_work_array = m_permutation; - lean_assert(p.size() == size()); + SASSERT(p.size() == size()); unsigned i = size(); while (i-- > 0) set_val(i, p[m_work_array[i]]); // we have m(P)*m(Q) = m(QP), where m is the matrix of the permutation @@ -289,7 +304,7 @@ template void permutation_matrix::multiply_by_per } template void permutation_matrix::multiply_by_reverse_from_right(permutation_matrix & q){ // todo : condensed permutations ? - lean_assert(q.size() == size()); + SASSERT(q.size() == size()); m_work_array = m_permutation; // the result is this = this*q(-1) unsigned i = size(); diff --git a/src/util/lp/permutation_matrix_instances.cpp b/src/util/lp/permutation_matrix_instances.cpp index 91473fabc..692d32337 100644 --- a/src/util/lp/permutation_matrix_instances.cpp +++ b/src/util/lp/permutation_matrix_instances.cpp @@ -1,55 +1,70 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/vector.h" #include "util/lp/permutation_matrix.hpp" #include "util/lp/numeric_pair.h" -template void lean::permutation_matrix::apply_from_right(vector&); -template void lean::permutation_matrix::init(unsigned int); -template void lean::permutation_matrix::init(unsigned int); -template void lean::permutation_matrix>::init(unsigned int); -template bool lean::permutation_matrix::is_identity() const; -template void lean::permutation_matrix::multiply_by_permutation_from_left(lean::permutation_matrix&); -template void lean::permutation_matrix::multiply_by_permutation_reverse_from_left(lean::permutation_matrix&); -template void lean::permutation_matrix::multiply_by_reverse_from_right(lean::permutation_matrix&); -template lean::permutation_matrix::permutation_matrix(unsigned int, vector const&); -template void lean::permutation_matrix::transpose_from_left(unsigned int, unsigned int); +template void lp::permutation_matrix::apply_from_right(vector&); +template void lp::permutation_matrix::init(unsigned int); +template void lp::permutation_matrix::init(unsigned int); +template void lp::permutation_matrix>::init(unsigned int); +template bool lp::permutation_matrix::is_identity() const; +template void lp::permutation_matrix::multiply_by_permutation_from_left(lp::permutation_matrix&); +template void lp::permutation_matrix::multiply_by_permutation_reverse_from_left(lp::permutation_matrix&); +template void lp::permutation_matrix::multiply_by_reverse_from_right(lp::permutation_matrix&); +template lp::permutation_matrix::permutation_matrix(unsigned int, vector const&); +template void lp::permutation_matrix::transpose_from_left(unsigned int, unsigned int); -template void lean::permutation_matrix::apply_from_right(vector&); -template bool lean::permutation_matrix::is_identity() const; -template void lean::permutation_matrix::multiply_by_permutation_from_left(lean::permutation_matrix&); -template void lean::permutation_matrix::multiply_by_permutation_from_right(lean::permutation_matrix&); -template void lean::permutation_matrix::multiply_by_permutation_reverse_from_left(lean::permutation_matrix&); -template void lean::permutation_matrix::multiply_by_reverse_from_right(lean::permutation_matrix&); -template lean::permutation_matrix::permutation_matrix(unsigned int); -template void lean::permutation_matrix::transpose_from_left(unsigned int, unsigned int); -template void lean::permutation_matrix::transpose_from_right(unsigned int, unsigned int); -template void lean::permutation_matrix >::apply_from_right(vector&); -template bool lean::permutation_matrix >::is_identity() const; -template void lean::permutation_matrix >::multiply_by_permutation_from_left(lean::permutation_matrix >&); -template void lean::permutation_matrix >::multiply_by_permutation_from_right(lean::permutation_matrix >&); -template void lean::permutation_matrix >::multiply_by_permutation_reverse_from_left(lean::permutation_matrix >&); -template void lean::permutation_matrix >::multiply_by_reverse_from_right(lean::permutation_matrix >&); -template lean::permutation_matrix >::permutation_matrix(unsigned int); -template void lean::permutation_matrix >::transpose_from_left(unsigned int, unsigned int); -template void lean::permutation_matrix >::transpose_from_right(unsigned int, unsigned int); -template void lean::permutation_matrix::apply_reverse_from_left(lean::indexed_vector&); -template void lean::permutation_matrix::apply_reverse_from_left_to_T(vector&); -template void lean::permutation_matrix::apply_reverse_from_right_to_T(vector&); -template void lean::permutation_matrix::transpose_from_right(unsigned int, unsigned int); -template void lean::permutation_matrix::apply_reverse_from_left(lean::indexed_vector&); -template void lean::permutation_matrix::apply_reverse_from_left_to_T(vector&); -template void lean::permutation_matrix::apply_reverse_from_right_to_T(vector&); -template void lean::permutation_matrix >::apply_reverse_from_left(lean::indexed_vector&); -template void lean::permutation_matrix >::apply_reverse_from_left_to_T(vector&); -template void lean::permutation_matrix >::apply_reverse_from_right_to_T(vector&); -template void lean::permutation_matrix::multiply_by_permutation_from_right(lean::permutation_matrix&); -template lean::permutation_matrix::permutation_matrix(unsigned int); -template void lean::permutation_matrix::apply_reverse_from_left_to_X(vector &); -template void lean::permutation_matrix< lean::mpq, lean::mpq>::apply_reverse_from_left_to_X(vector &); -template void lean::permutation_matrix< lean::mpq, lean::numeric_pair< lean::mpq> >::apply_reverse_from_left_to_X(vector> &); -template void lean::permutation_matrix::apply_reverse_from_right_to_T(lean::indexed_vector&); -template void lean::permutation_matrix::apply_reverse_from_right_to_T(lean::indexed_vector&); -template void lean::permutation_matrix >::apply_reverse_from_right_to_T(lean::indexed_vector&); +template void lp::permutation_matrix::apply_from_right(vector&); +template bool lp::permutation_matrix::is_identity() const; +template void lp::permutation_matrix::multiply_by_permutation_from_left(lp::permutation_matrix&); +template void lp::permutation_matrix::multiply_by_permutation_from_right(lp::permutation_matrix&); +template void lp::permutation_matrix::multiply_by_permutation_reverse_from_left(lp::permutation_matrix&); +template void lp::permutation_matrix::multiply_by_reverse_from_right(lp::permutation_matrix&); +template lp::permutation_matrix::permutation_matrix(unsigned int); +template void lp::permutation_matrix::transpose_from_left(unsigned int, unsigned int); +template void lp::permutation_matrix::transpose_from_right(unsigned int, unsigned int); +template void lp::permutation_matrix >::apply_from_right(vector&); +template bool lp::permutation_matrix >::is_identity() const; +template void lp::permutation_matrix >::multiply_by_permutation_from_left(lp::permutation_matrix >&); +template void lp::permutation_matrix >::multiply_by_permutation_from_right(lp::permutation_matrix >&); +template void lp::permutation_matrix >::multiply_by_permutation_reverse_from_left(lp::permutation_matrix >&); +template void lp::permutation_matrix >::multiply_by_reverse_from_right(lp::permutation_matrix >&); +template lp::permutation_matrix >::permutation_matrix(unsigned int); +template void lp::permutation_matrix >::transpose_from_left(unsigned int, unsigned int); +template void lp::permutation_matrix >::transpose_from_right(unsigned int, unsigned int); +template void lp::permutation_matrix::apply_reverse_from_left(lp::indexed_vector&); +template void lp::permutation_matrix::apply_reverse_from_left_to_T(vector&); +template void lp::permutation_matrix::apply_reverse_from_right_to_T(vector&); +template void lp::permutation_matrix::transpose_from_right(unsigned int, unsigned int); +template void lp::permutation_matrix::apply_reverse_from_left(lp::indexed_vector&); +template void lp::permutation_matrix::apply_reverse_from_left_to_T(vector&); +template void lp::permutation_matrix::apply_reverse_from_right_to_T(vector&); +template void lp::permutation_matrix >::apply_reverse_from_left(lp::indexed_vector&); +template void lp::permutation_matrix >::apply_reverse_from_left_to_T(vector&); +template void lp::permutation_matrix >::apply_reverse_from_right_to_T(vector&); +template void lp::permutation_matrix::multiply_by_permutation_from_right(lp::permutation_matrix&); +template lp::permutation_matrix::permutation_matrix(unsigned int); +template void lp::permutation_matrix::apply_reverse_from_left_to_X(vector &); +template void lp::permutation_matrix< lp::mpq, lp::mpq>::apply_reverse_from_left_to_X(vector &); +template void lp::permutation_matrix< lp::mpq, lp::numeric_pair< lp::mpq> >::apply_reverse_from_left_to_X(vector> &); +template void lp::permutation_matrix::apply_reverse_from_right_to_T(lp::indexed_vector&); +template void lp::permutation_matrix::apply_reverse_from_right_to_T(lp::indexed_vector&); +template void lp::permutation_matrix >::apply_reverse_from_right_to_T(lp::indexed_vector&); diff --git a/src/util/lp/quick_xplain.cpp b/src/util/lp/quick_xplain.cpp index a4b6fb0e6..f9506c056 100644 --- a/src/util/lp/quick_xplain.cpp +++ b/src/util/lp/quick_xplain.cpp @@ -1,9 +1,24 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/lar_solver.h" -namespace lean { +namespace lp { quick_xplain::quick_xplain(vector> & explanation, const lar_solver & ls, lar_solver & qsol) : m_explanation(explanation), m_parent_solver(ls), @@ -15,7 +30,7 @@ void quick_xplain::add_constraint_to_qsol(unsigned j) { auto ci = m_qsol.add_constraint(ls, lar_c.m_kind, lar_c.m_right_side); m_local_ci_to_constraint_offsets[ci] = j; } - + void quick_xplain::copy_constraint_and_add_constraint_vars(const lar_constraint& lar_c) { vector < std::pair> ls; for (auto & p : lar_c.get_left_side_coefficients()) { @@ -56,9 +71,9 @@ void quick_xplain::minimize(const vector& u) { } } if (m > 0) { - lean_assert(m_qsol.constraint_stack_size() >= initial_stack_size); + SASSERT(m_qsol.constraint_stack_size() >= initial_stack_size); m_qsol.pop(m_qsol.constraint_stack_size() - initial_stack_size); - for (auto j : m_x) + for (auto j : m_x) add_constraint_to_qsol(j); if (!infeasible()) { vector un; @@ -69,11 +84,11 @@ void quick_xplain::minimize(const vector& u) { } } - + void quick_xplain::run(vector> & explanation, const lar_solver & ls){ if (explanation.size() <= 2) return; lar_solver qsol; - lean_assert(ls.explanation_is_correct(explanation)); + SASSERT(ls.explanation_is_correct(explanation)); quick_xplain q(explanation, ls, qsol); q.solve(); } @@ -109,7 +124,7 @@ bool quick_xplain::x_is_minimal() const { x.push_back(j); for (unsigned k = 0; k < x.size(); k++) { - lean_assert(is_feasible(x, x[k])); + SASSERT(is_feasible(x, x[k])); } return true; } @@ -117,8 +132,8 @@ bool quick_xplain::x_is_minimal() const { void quick_xplain::solve() { copy_constraints_to_local_constraints(); m_qsol.push(); - lean_assert(m_qsol.constraint_count() == 0) - vector u; + SASSERT(m_qsol.constraint_count() == 0); + vector u; for (unsigned k = 0; k < m_constraints_in_local_vars.size(); k++) u.push_back(k); minimize(u); @@ -127,10 +142,10 @@ void quick_xplain::solve() { for (unsigned i : m_x) add_constraint_to_qsol(i); m_qsol.solve(); - lean_assert(m_qsol.get_status() == INFEASIBLE); + SASSERT(m_qsol.get_status() == INFEASIBLE); m_qsol.get_infeasibility_explanation(m_explanation); - lean_assert(m_qsol.explanation_is_correct(m_explanation)); - lean_assert(x_is_minimal()); + SASSERT(m_qsol.explanation_is_correct(m_explanation)); + SASSERT(x_is_minimal()); for (auto & p : m_explanation) { p.second = this->m_local_constraint_offset_to_external_ci[m_local_ci_to_constraint_offsets[p.second]]; } diff --git a/src/util/lp/quick_xplain.h b/src/util/lp/quick_xplain.h index 9faa5f41c..902fa08cd 100644 --- a/src/util/lp/quick_xplain.h +++ b/src/util/lp/quick_xplain.h @@ -1,13 +1,28 @@ -/* +/*++ Copyright (c) 2017 Microsoft Corporation -Author: Lev Nachmanson -*/ + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include -namespace lean { +namespace lp { class lar_solver; // forward definition class quick_xplain { diff --git a/src/util/lp/random_updater.h b/src/util/lp/random_updater.h index 8cb9740ea..6b03ad941 100644 --- a/src/util/lp/random_updater.h +++ b/src/util/lp/random_updater.h @@ -1,7 +1,23 @@ -/* +/*++ Copyright (c) 2017 Microsoft Corporation -Author: Lev Nachmanson -*/ + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ + #pragma once #include #include "util/vector.h" @@ -12,7 +28,7 @@ Author: Lev Nachmanson #include "util/lp/linear_combination_iterator.h" // see http://research.microsoft.com/projects/z3/smt07.pdf // The class searches for a feasible solution with as many different values of variables as it can find -namespace lean { +namespace lp { template struct numeric_pair; // forward definition class lar_core_solver; // forward definition class random_updater { diff --git a/src/util/lp/random_updater.hpp b/src/util/lp/random_updater.hpp index 7c6a0539f..5bbcdf27c 100644 --- a/src/util/lp/random_updater.hpp +++ b/src/util/lp/random_updater.hpp @@ -1,12 +1,27 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/random_updater.h" #include "util/lp/static_matrix.h" #include "util/lp/lar_solver.h" #include "util/vector.h" -namespace lean { +namespace lp { @@ -36,7 +51,7 @@ random_updater::interval random_updater::get_interval_of_non_basic_var(unsigned ret.set_upper_bound(m_core_solver.m_r_upper_bounds[j]); break; default: - lean_assert(false); + SASSERT(false); } return ret; } @@ -44,15 +59,15 @@ random_updater::interval random_updater::get_interval_of_non_basic_var(unsigned void random_updater::diminish_interval_for_basic_var(numeric_pair& nb_x, unsigned j, mpq & a, interval & r) { - lean_assert(m_core_solver.m_r_heading[j] >= 0); + SASSERT(m_core_solver.m_r_heading[j] >= 0); numeric_pair delta; - lean_assert(a != zero_of_type()); + SASSERT(a != zero_of_type()); switch (m_core_solver.get_column_type(j)) { case column_type::free_column: break; case column_type::low_bound: delta = m_core_solver.m_r_x[j] - m_core_solver.m_r_low_bounds[j]; - lean_assert(delta >= zero_of_type>()); + SASSERT(delta >= zero_of_type>()); if (a > 0) { r.set_upper_bound(nb_x + delta / a); } else { @@ -61,7 +76,7 @@ void random_updater::diminish_interval_for_basic_var(numeric_pair& nb_x, un break; case column_type::upper_bound: delta = m_core_solver.m_r_upper_bounds()[j] - m_core_solver.m_r_x[j]; - lean_assert(delta >= zero_of_type>()); + SASSERT(delta >= zero_of_type>()); if (a > 0) { r.set_low_bound(nb_x - delta / a); } else { @@ -71,17 +86,17 @@ void random_updater::diminish_interval_for_basic_var(numeric_pair& nb_x, un case column_type::boxed: if (a > 0) { delta = m_core_solver.m_r_x[j] - m_core_solver.m_r_low_bounds[j]; - lean_assert(delta >= zero_of_type>()); + SASSERT(delta >= zero_of_type>()); r.set_upper_bound(nb_x + delta / a); delta = m_core_solver.m_r_upper_bounds()[j] - m_core_solver.m_r_x[j]; - lean_assert(delta >= zero_of_type>()); + SASSERT(delta >= zero_of_type>()); r.set_low_bound(nb_x - delta / a); } else { // a < 0 delta = m_core_solver.m_r_upper_bounds()[j] - m_core_solver.m_r_x[j]; - lean_assert(delta >= zero_of_type>()); + SASSERT(delta >= zero_of_type>()); r.set_upper_bound(nb_x - delta / a); delta = m_core_solver.m_r_x[j] - m_core_solver.m_r_low_bounds[j]; - lean_assert(delta >= zero_of_type>()); + SASSERT(delta >= zero_of_type>()); r.set_low_bound(nb_x + delta / a); } break; @@ -90,7 +105,7 @@ void random_updater::diminish_interval_for_basic_var(numeric_pair& nb_x, un r.set_upper_bound(nb_x); break; default: - lean_assert(false); + SASSERT(false); } } @@ -113,15 +128,15 @@ random_updater::interval random_updater::find_shift_interval(unsigned j) { } void random_updater::shift_var(unsigned j, interval & r) { - lean_assert(r.contains(m_core_solver.m_r_x[j])); - lean_assert(m_core_solver.m_r_solver.column_is_feasible(j)); + SASSERT(r.contains(m_core_solver.m_r_x[j])); + SASSERT(m_core_solver.m_r_solver.column_is_feasible(j)); auto old_x = m_core_solver.m_r_x[j]; remove_value(old_x); auto new_val = m_core_solver.m_r_x[j] = get_random_from_interval(r); add_value(new_val); - lean_assert(r.contains(m_core_solver.m_r_x[j])); - lean_assert(m_core_solver.m_r_solver.column_is_feasible(j)); + SASSERT(r.contains(m_core_solver.m_r_x[j])); + SASSERT(m_core_solver.m_r_solver.column_is_feasible(j)); auto delta = m_core_solver.m_r_x[j] - old_x; unsigned i; @@ -130,9 +145,9 @@ void random_updater::shift_var(unsigned j, interval & r) { while(m_column_j->next(a, i)) { unsigned bj = m_core_solver.m_r_basis[i]; m_core_solver.m_r_x[bj] -= a * delta; - lean_assert(m_core_solver.m_r_solver.column_is_feasible(bj)); + SASSERT(m_core_solver.m_r_solver.column_is_feasible(bj)); } - lean_assert(m_core_solver.m_r_solver.A_mult_x_is_off() == false); + SASSERT(m_core_solver.m_r_solver.A_mult_x_is_off() == false); } numeric_pair random_updater::get_random_from_interval(interval & r) { @@ -143,7 +158,7 @@ numeric_pair random_updater::get_random_from_interval(interval & r) { return r.low_bound + numeric_pair(rand % range, 0); if ((!r.low_bound_is_set) && r.upper_bound_is_set) return r.upper_bound - numeric_pair(rand % range, 0); - lean_assert(r.low_bound_is_set && r.upper_bound_is_set); + SASSERT(r.low_bound_is_set && r.upper_bound_is_set); return r.low_bound + (rand % range) * (r.upper_bound - r.low_bound)/ range; } @@ -183,7 +198,7 @@ void random_updater::add_value(numeric_pair& v) { void random_updater::remove_value(numeric_pair& v) { std::unordered_map, unsigned>::iterator it = m_values.find(v); - lean_assert(it != m_values.end()); + SASSERT(it != m_values.end()); it->second--; if (it->second == 0) m_values.erase((std::unordered_map, unsigned>::const_iterator)it); diff --git a/src/util/lp/random_updater_instances.cpp b/src/util/lp/random_updater_instances.cpp index 5b4c89bd5..4f9b880c0 100644 --- a/src/util/lp/random_updater_instances.cpp +++ b/src/util/lp/random_updater_instances.cpp @@ -1,5 +1,20 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/random_updater.hpp" diff --git a/src/util/lp/row_eta_matrix.h b/src/util/lp/row_eta_matrix.h index 90acb89f3..c287e263a 100644 --- a/src/util/lp/row_eta_matrix.h +++ b/src/util/lp/row_eta_matrix.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" @@ -10,26 +25,26 @@ #include "util/lp/sparse_vector.h" #include "util/lp/indexed_vector.h" #include "util/lp/permutation_matrix.h" -namespace lean { +namespace lp { // This is the sum of a unit matrix and a lower triangular matrix // with non-zero elements only in one row template class row_eta_matrix : public tail_matrix { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG unsigned m_dimension; #endif unsigned m_row_start; unsigned m_row; sparse_vector m_row_vector; public: -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG row_eta_matrix(unsigned row_start, unsigned row, unsigned dim): #else row_eta_matrix(unsigned row_start, unsigned row): #endif -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG m_dimension(dim), #endif m_row_start(row_start), m_row(row) { @@ -55,7 +70,7 @@ public: } void push_back(unsigned row_index, T val ) { - lean_assert(row_index != m_row); + SASSERT(row_index != m_row); m_row_vector.push_back(row_index, val); } @@ -63,7 +78,7 @@ public: void apply_from_right(indexed_vector & w); void conjugate_by_permutation(permutation_matrix & p); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG T get_elem(unsigned row, unsigned col) const; unsigned row_count() const { return m_dimension; } unsigned column_count() const { return m_dimension; } diff --git a/src/util/lp/row_eta_matrix.hpp b/src/util/lp/row_eta_matrix.hpp index 5758abeb8..969b4af7d 100644 --- a/src/util/lp/row_eta_matrix.hpp +++ b/src/util/lp/row_eta_matrix.hpp @@ -1,13 +1,28 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/vector.h" #include "util/lp/row_eta_matrix.h" -namespace lean { +namespace lp { template void row_eta_matrix::apply_from_left(vector & w, lp_settings &) { - // #ifdef LEAN_DEBUG + // #ifdef Z3DEBUG // dense_matrix deb(*this); // auto clone_w = clone_vector(w, m_dimension); // deb.apply_from_left(clone_w, settings); @@ -18,8 +33,8 @@ void row_eta_matrix::apply_from_left(vector & w, lp_settings &) { w_at_row += w[it.first] * it.second; } // w[m_row] = w_at_row; - // #ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(clone_w, w, m_dimension)); + // #ifdef Z3DEBUG + // SASSERT(vectors_are_equal(clone_w, w, m_dimension)); // delete [] clone_w; // #endif } @@ -43,7 +58,7 @@ void row_eta_matrix::apply_from_left_local_to_T(indexed_vector & w, lp_ auto it = std::find(w.m_index.begin(), w.m_index.end(), m_row); w.m_index.erase(it); } - // TBD: lean_assert(check_vector_for_small_values(w, settings)); + // TBD: SASSERT(check_vector_for_small_values(w, settings)); } template @@ -65,14 +80,14 @@ void row_eta_matrix::apply_from_left_local_to_X(indexed_vector & w, lp_ auto it = std::find(w.m_index.begin(), w.m_index.end(), m_row); w.m_index.erase(it); } - // TBD: does not compile lean_assert(check_vector_for_small_values(w, settings)); + // TBD: does not compile SASSERT(check_vector_for_small_values(w, settings)); } template void row_eta_matrix::apply_from_right(vector & w) { const T & w_row = w[m_row]; if (numeric_traits::is_zero(w_row)) return; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // dense_matrix deb(*this); // auto clone_w = clone_vector(w, m_dimension); // deb.apply_from_right(clone_w); @@ -80,18 +95,18 @@ void row_eta_matrix::apply_from_right(vector & w) { for (auto & it : m_row_vector.m_data) { w[it.first] += w_row * it.second; } -#ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(clone_w, w, m_dimension)); +#ifdef Z3DEBUG + // SASSERT(vectors_are_equal(clone_w, w, m_dimension)); // delete clone_w; #endif } template void row_eta_matrix::apply_from_right(indexed_vector & w) { - lean_assert(w.is_OK()); + SASSERT(w.is_OK()); const T & w_row = w[m_row]; if (numeric_traits::is_zero(w_row)) return; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // vector wcopy(w.m_data); // apply_from_right(wcopy); #endif @@ -129,8 +144,8 @@ void row_eta_matrix::apply_from_right(indexed_vector & w) { } } } -#ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(wcopy, w.m_data)); +#ifdef Z3DEBUG + // SASSERT(vectors_are_equal(wcopy, w.m_data)); #endif } @@ -138,7 +153,7 @@ void row_eta_matrix::apply_from_right(indexed_vector & w) { template void row_eta_matrix::conjugate_by_permutation(permutation_matrix & p) { // this = p * this * p(-1) -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // auto rev = p.get_reverse(); // auto deb = ((*this) * rev); // deb = p * deb; @@ -150,11 +165,11 @@ void row_eta_matrix::conjugate_by_permutation(permutation_matrix & p columns.push_back(it.first); for (unsigned i = static_cast(columns.size()); i-- > 0;) m_row_vector.m_data[i].first = p.get_rev(columns[i]); -#ifdef LEAN_DEBUG - // lean_assert(deb == *this); +#ifdef Z3DEBUG + // SASSERT(deb == *this); #endif } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template T row_eta_matrix::get_elem(unsigned row, unsigned col) const { if (row == m_row){ diff --git a/src/util/lp/row_eta_matrix_instances.cpp b/src/util/lp/row_eta_matrix_instances.cpp index c172eda11..3c4ab9bed 100644 --- a/src/util/lp/row_eta_matrix_instances.cpp +++ b/src/util/lp/row_eta_matrix_instances.cpp @@ -1,16 +1,31 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/vector.h" #include "util/lp/row_eta_matrix.hpp" #include "util/lp/lu.h" -namespace lean { +namespace lp { template void row_eta_matrix::conjugate_by_permutation(permutation_matrix&); template void row_eta_matrix >::conjugate_by_permutation(permutation_matrix >&); template void row_eta_matrix::conjugate_by_permutation(permutation_matrix&); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template mpq row_eta_matrix::get_elem(unsigned int, unsigned int) const; template mpq row_eta_matrix >::get_elem(unsigned int, unsigned int) const; template double row_eta_matrix::get_elem(unsigned int, unsigned int) const; diff --git a/src/util/lp/scaler.h b/src/util/lp/scaler.h index 33c5a6cc4..509671528 100644 --- a/src/util/lp/scaler.h +++ b/src/util/lp/scaler.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" @@ -11,7 +26,7 @@ #include /* exit, EXIT_FAILURE */ #include "util/lp/lp_utils.h" #include "util/lp/static_matrix.h" -namespace lean { +namespace lp { // for scaling an LP template class scaler { @@ -31,7 +46,7 @@ public: m_scaling_maximum(scaling_maximum), m_column_scale(column_scale), m_settings(settings) { - lean_assert(m_column_scale.size() == 0); + SASSERT(m_column_scale.size() == 0); m_column_scale.resize(m_A.column_count(), numeric_traits::one()); } diff --git a/src/util/lp/scaler.hpp b/src/util/lp/scaler.hpp index 69427eea0..ea8dc98c4 100644 --- a/src/util/lp/scaler.hpp +++ b/src/util/lp/scaler.hpp @@ -1,11 +1,26 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/lp/scaler.h" #include "util/lp/numeric_pair.h" -namespace lean { +namespace lp { // for scaling an LP template T scaler::right_side_balance() { T ret = zero_of_type(); @@ -41,7 +56,7 @@ template T scaler::A_max() const { template T scaler::get_A_ratio() const { T min = A_min(); T max = A_max(); - lean_assert(!m_settings.abs_val_is_smaller_than_zero_tolerance(min)); + SASSERT(!m_settings.abs_val_is_smaller_than_zero_tolerance(min)); T ratio = max / min; return ratio; } @@ -51,7 +66,7 @@ template T scaler::get_max_ratio_on_rows() con unsigned i = m_A.row_count(); while (i--) { T den = m_A.get_min_abs_in_row(i); - lean_assert(!m_settings.abs_val_is_smaller_than_zero_tolerance(den)); + SASSERT(!m_settings.abs_val_is_smaller_than_zero_tolerance(den)); T t = m_A.get_max_abs_in_row(i)/ den; if (t > ret) ret = t; @@ -78,7 +93,7 @@ template void scaler::scale_rows_with_geometri while (i--) { T max = m_A.get_max_abs_in_row(i); T min = m_A.get_min_abs_in_row(i); - lean_assert(max > zero_of_type() && min > zero_of_type()); + SASSERT(max > zero_of_type() && min > zero_of_type()); if (is_zero(max) || is_zero(min)) continue; T gm = T(sqrt(numeric_traits::get_double(max*min))); diff --git a/src/util/lp/scaler_instances.cpp b/src/util/lp/scaler_instances.cpp index f97e8098f..ba02321ea 100644 --- a/src/util/lp/scaler_instances.cpp +++ b/src/util/lp/scaler_instances.cpp @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/lp/scaler.hpp" -template bool lean::scaler::scale(); -template bool lean::scaler::scale(); +template bool lp::scaler::scale(); +template bool lp::scaler::scale(); diff --git a/src/util/lp/signature_bound_evidence.h b/src/util/lp/signature_bound_evidence.h index a22c188b4..e4eeb328d 100644 --- a/src/util/lp/signature_bound_evidence.h +++ b/src/util/lp/signature_bound_evidence.h @@ -1,11 +1,26 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/lp/lp_settings.h" #include "util/lp/lar_constraints.h" -namespace lean { +namespace lp { struct bound_signature { unsigned m_i; bool m_at_low; diff --git a/src/util/lp/sparse_matrix.h b/src/util/lp/sparse_matrix.h index 7256004da..400f2bfc0 100644 --- a/src/util/lp/sparse_matrix.h +++ b/src/util/lp/sparse_matrix.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" @@ -21,11 +36,11 @@ #include "util/lp/binary_heap_upair_queue.h" #include "util/lp/numeric_pair.h" #include "util/lp/int_set.h" -namespace lean { +namespace lp { // it is a square matrix template class sparse_matrix -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG : public matrix #endif { @@ -57,7 +72,7 @@ public: vector m_processed; unsigned get_n_of_active_elems() const { return m_n_of_active_elems; } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // dense_matrix m_dense; #endif /* @@ -146,7 +161,7 @@ public: unsigned dimension() const {return static_cast(m_row_permutation.size());} -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG unsigned row_count() const {return dimension();} unsigned column_count() const {return dimension();} #endif @@ -206,19 +221,19 @@ public: void multiply_from_right(permutation_matrix& p) { // m_dense = m_dense * p; m_column_permutation.multiply_by_permutation_from_right(p); - // lean_assert(*this == m_dense); + // SASSERT(*this == m_dense); } void multiply_from_left(permutation_matrix& p) { // m_dense = p * m_dense; m_row_permutation.multiply_by_permutation_from_left(p); - // lean_assert(*this == m_dense); + // SASSERT(*this == m_dense); } void multiply_from_left_with_reverse(permutation_matrix& p) { // m_dense = p * m_dense; m_row_permutation.multiply_by_permutation_reverse_from_left(p); - // lean_assert(*this == m_dense); + // SASSERT(*this == m_dense); } // adding delta columns at the end of the matrix @@ -231,13 +246,13 @@ public: // dense_matrix d(*this); m_column_permutation.transpose_from_left(a, b); // d.swap_columns(a, b); - // lean_assert(*this == d); + // SASSERT(*this == d); } void swap_rows(unsigned a, unsigned b) { m_row_permutation.transpose_from_right(a, b); // m_dense.swap_rows(a, b); - // lean_assert(*this == m_dense); + // SASSERT(*this == m_dense); } void divide_row_by_constant(unsigned i, const T & t, lp_settings & settings); @@ -286,7 +301,7 @@ public: template void solve_U_y_indexed_only(indexed_vector & y, const lp_settings&, vector & sorted_active_rows ); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG T get_elem(unsigned i, unsigned j) const { return get(i, j); } unsigned get_number_of_rows() const { return dimension(); } unsigned get_number_of_columns() const { return dimension(); } @@ -341,7 +356,7 @@ public: bool shorten_active_matrix(unsigned row, eta_matrix *eta_matrix); unsigned pivot_score_without_shortened_counters(unsigned i, unsigned j, unsigned k); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG bool can_improve_score_for_row(unsigned row, unsigned score, T const & c_partial_pivoting, unsigned k); bool really_best_pivot(unsigned i, unsigned j, T const & c_partial_pivoting, unsigned k); void print_active_matrix(unsigned k, std::ostream & out); @@ -373,7 +388,7 @@ public: } bool fill_eta_matrix(unsigned j, eta_matrix ** eta); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG bool is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings & settings) const; bool is_upper_triangular_until(unsigned k) const; @@ -393,7 +408,7 @@ public: void process_index_recursively_for_y_U(unsigned j, vector & sorted_rows); void resize(unsigned new_dim) { unsigned old_dim = dimension(); - lean_assert(new_dim >= old_dim); + SASSERT(new_dim >= old_dim); for (unsigned j = old_dim; j < new_dim; j++) { m_rows.push_back(vector>()); m_columns.push_back(col_header()); @@ -407,7 +422,7 @@ public: add_new_element(j, j, numeric_traits::one()); } } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG vector get_full_row(unsigned i) const; #endif unsigned pivot_queue_size() const { return m_pivot_queue.size(); } diff --git a/src/util/lp/sparse_matrix.hpp b/src/util/lp/sparse_matrix.hpp index 32bb8ed4e..d2040d313 100644 --- a/src/util/lp/sparse_matrix.hpp +++ b/src/util/lp/sparse_matrix.hpp @@ -1,13 +1,28 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/vector.h" #include "util/lp/sparse_matrix.h" #include #include -namespace lean { +namespace lp { template void sparse_matrix::copy_column_from_static_matrix(unsigned col, static_matrix const &A, unsigned col_index_in_the_new_matrix) { vector const & A_col_vector = A.m_columns[col]; @@ -82,12 +97,12 @@ void sparse_matrix::set_with_no_adjusting(unsigned row, unsigned col, T va template void sparse_matrix::set(unsigned row, unsigned col, T val) { // should not be used in efficient code - lean_assert(row < dimension() && col < dimension()); + SASSERT(row < dimension() && col < dimension()); // m_dense.set_elem(row, col, val); row = adjust_row(row); col = adjust_column(col); set_with_no_adjusting(row, col, val); - // lean_assert(*this == m_dense); + // SASSERT(*this == m_dense); } template @@ -243,7 +258,7 @@ void sparse_matrix::scan_row_to_work_vector_and_remove_pivot_column(unsign } } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template vector sparse_matrix::get_full_row(unsigned i) const { vector r; @@ -261,8 +276,8 @@ vector sparse_matrix::get_full_row(unsigned i) const { // Returns false if the resulting row is all zeroes, and true otherwise template bool sparse_matrix::pivot_row_to_row(unsigned i, const T& alpha, unsigned i0, lp_settings & settings ) { - lean_assert(i < dimension() && i0 < dimension()); - lean_assert(i != i0); + SASSERT(i < dimension() && i0 < dimension()); + SASSERT(i != i0); unsigned pivot_col = adjust_column(i); i = adjust_row(i); i0 = adjust_row(i0); @@ -327,7 +342,7 @@ bool sparse_matrix::set_row_from_work_vector_and_clean_work_vector_not_adj if (numeric_traits::is_zero(work_vec[j])) { continue; } - lean_assert(!settings.abs_val_is_smaller_than_drop_tolerance(work_vec[j])); + SASSERT(!settings.abs_val_is_smaller_than_drop_tolerance(work_vec[j])); add_new_element(i0, adjust_column(j), work_vec[j]); work_vec[j] = numeric_traits::zero(); } @@ -372,7 +387,7 @@ void sparse_matrix::remove_zero_elements_and_set_data_on_existing_elements T val = work_vec[rj]; if (settings.abs_val_is_smaller_than_drop_tolerance(val)) { remove_element(row_vals, row_el_iv); - lean_assert(numeric_traits::is_zero(val)); + SASSERT(numeric_traits::is_zero(val)); } else { m_columns[j].m_values[row_el_iv.m_other].set_value(row_el_iv.m_value = val); work_vec[rj] = numeric_traits::zero(); @@ -393,7 +408,7 @@ void sparse_matrix::add_columns_at_the_end(unsigned delta) { template void sparse_matrix::delete_column(int i) { - lean_assert(i < dimension()); + SASSERT(i < dimension()); for (auto cell = m_columns[i].m_head; cell != nullptr;) { auto next_cell = cell->m_down; kill_cell(cell); @@ -403,7 +418,7 @@ void sparse_matrix::delete_column(int i) { template void sparse_matrix::divide_row_by_constant(unsigned i, const T & t, lp_settings & settings) { - lean_assert(!settings.abs_val_is_smaller_than_zero_tolerance(t)); + SASSERT(!settings.abs_val_is_smaller_than_zero_tolerance(t)); i = adjust_row(i); for (auto & iv : m_rows[i]) { T &v = iv.m_value; @@ -420,7 +435,7 @@ void sparse_matrix::divide_row_by_constant(unsigned i, const T & t, lp_set // the matrix here has to be upper triangular template void sparse_matrix::solve_y_U(vector & y) const { // works by rows -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // T * rs = clone_vector(y, dimension()); #endif unsigned end = dimension(); @@ -436,11 +451,11 @@ void sparse_matrix::solve_y_U(vector & y) const { // works by rows } } } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // dense_matrix deb(*this); // T * clone_y = clone_vector(y, dimension()); // deb.apply_from_right(clone_y); - // lean_assert(vectors_are_equal(rs, clone_y, dimension())); + // SASSERT(vectors_are_equal(rs, clone_y, dimension())); // delete [] clone_y; // delete [] rs; #endif @@ -450,7 +465,7 @@ void sparse_matrix::solve_y_U(vector & y) const { // works by rows // the matrix here has to be upper triangular template void sparse_matrix::solve_y_U_indexed(indexed_vector & y, const lp_settings & settings) { -#if 0 && LEAN_DEBUG +#if 0 && Z3DEBUG vector ycopy(y.m_data); if (numeric_traits::precise() == false) solve_y_U(ycopy); @@ -474,10 +489,10 @@ void sparse_matrix::solve_y_U_indexed(indexed_vector & y, const lp_sett y.m_data[j] = zero_of_type(); } - lean_assert(y.is_OK()); -#if 0 && LEAN_DEBUG + SASSERT(y.is_OK()); +#if 0 && Z3DEBUG if (numeric_traits::precise() == false) - lean_assert(vectors_are_equal(ycopy, y.m_data)); + SASSERT(vectors_are_equal(ycopy, y.m_data)); #endif } @@ -537,8 +552,8 @@ void sparse_matrix::add_delta_to_solution(const vector& del, vector template template void sparse_matrix::add_delta_to_solution(const indexed_vector& del, indexed_vector & y) { -// lean_assert(del.is_OK()); - // lean_assert(y.is_OK()); +// SASSERT(del.is_OK()); + // SASSERT(y.is_OK()); for (auto i : del.m_index) { y.add_value_at_index(i, del[i]); } @@ -546,11 +561,11 @@ void sparse_matrix::add_delta_to_solution(const indexed_vector& del, in template template void sparse_matrix::double_solve_U_y(indexed_vector& y, const lp_settings & settings){ - lean_assert(y.is_OK()); + SASSERT(y.is_OK()); indexed_vector y_orig(y); // copy y aside vector active_rows; solve_U_y_indexed_only(y, settings, active_rows); - lean_assert(y.is_OK()); + SASSERT(y.is_OK()); find_error_in_solution_U_y_indexed(y_orig, y, active_rows); // y_orig contains the error now if (y_orig.m_index.size() * ratio_of_index_size_to_all_size() < 32 * dimension()) { @@ -563,7 +578,7 @@ void sparse_matrix::double_solve_U_y(indexed_vector& y, const lp_settin add_delta_to_solution(y_orig.m_data, y.m_data); y.restore_index_and_clean_from_data(); } - lean_assert(y.is_OK()); + SASSERT(y.is_OK()); } template template @@ -581,7 +596,7 @@ void sparse_matrix::double_solve_U_y(vector& y){ template template void sparse_matrix::solve_U_y(vector & y) { // it is a column wise version -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // T * rs = clone_vector(y, dimension()); #endif @@ -595,16 +610,16 @@ void sparse_matrix::solve_U_y(vector & y) { // it is a column wise vers } } } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // dense_matrix deb(*this); // T * clone_y = clone_vector(y, dimension()); // deb.apply_from_left(clone_y); - // lean_assert(vectors_are_equal(rs, clone_y, dimension())); + // SASSERT(vectors_are_equal(rs, clone_y, dimension())); #endif } template void sparse_matrix::process_index_recursively_for_y_U(unsigned j, vector & sorted_active_rows) { - lean_assert(m_processed[j] == false); + SASSERT(m_processed[j] == false); m_processed[j]=true; auto & row = m_rows[adjust_row(j)]; for (auto & c : row) { @@ -619,7 +634,7 @@ void sparse_matrix::process_index_recursively_for_y_U(unsigned j, vector void sparse_matrix::process_column_recursively(unsigned j, vector & sorted_active_rows) { - lean_assert(m_processed[j] == false); + SASSERT(m_processed[j] == false); auto & mc = m_columns[adjust_column(j)].m_values; for (auto & iv : mc) { unsigned i = adjust_row_inverse(iv.m_index); @@ -684,12 +699,12 @@ void sparse_matrix::solve_U_y_indexed_only(indexed_vector & y, const lp y[j] = zero_of_type(); } - lean_assert(y.is_OK()); -#ifdef LEAN_DEBUG + SASSERT(y.is_OK()); +#ifdef Z3DEBUG // dense_matrix deb(this); // vector clone_y(y.m_data); // deb.apply_from_left(clone_y); - // lean_assert(vectors_are_equal(rs, clone_y)); + // SASSERT(vectors_are_equal(rs, clone_y)); #endif } @@ -802,7 +817,7 @@ void sparse_matrix::add_new_elements_of_w_and_clear_w(unsigned column_to_r unsigned ai = adjust_row(i); add_new_element(ai, column_to_replace, w_at_i); auto & row_chunk = m_rows[ai]; - lean_assert(row_chunk.size() > 0); + SASSERT(row_chunk.size() > 0); if (abs(w_at_i) > abs(row_chunk[0].m_value)) put_max_index_to_0(row_chunk, static_cast(row_chunk.size()) - 1); } @@ -833,7 +848,7 @@ unsigned sparse_matrix::pivot_score(unsigned i, unsigned j) { template void sparse_matrix::enqueue_domain_into_pivot_queue() { - lean_assert(m_pivot_queue.size() == 0); + SASSERT(m_pivot_queue.size() == 0); for (unsigned i = 0; i < dimension(); i++) { auto & rh = m_rows[i]; unsigned rnz = static_cast(rh.size()); @@ -919,7 +934,7 @@ void sparse_matrix::update_active_pivots(unsigned row) { for (const auto & iv : m_rows[arow]) { col_header & ch = m_columns[iv.m_index]; int cols = static_cast(ch.m_values.size()) - ch.m_shortened_markovitz - 1; - lean_assert(cols >= 0); + SASSERT(cols >= 0); for (const auto &ivc : ch.m_values) { unsigned i = ivc.m_index; if (adjust_row_inverse(i) <= row) continue; // the i is not an active row @@ -945,7 +960,7 @@ bool sparse_matrix::shorten_active_matrix(unsigned row, eta_matrix * for (auto & iv : row_values) { const col_header& ch = m_columns[iv.m_index]; int cnz = static_cast(ch.m_values.size()) - ch.m_shortened_markovitz - 1; - lean_assert(cnz >= 0); + SASSERT(cnz >= 0); m_pivot_queue.enqueue(row, iv.m_index, rnz * cnz); } } @@ -961,25 +976,25 @@ unsigned sparse_matrix::pivot_score_without_shortened_counters(unsigned i, if (adjust_row_inverse(iv.m_index) < k) cnz--; } - lean_assert(cnz > 0); + SASSERT(cnz > 0); return m_rows[i].m_values.size() * (cnz - 1); } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template bool sparse_matrix::can_improve_score_for_row(unsigned row, unsigned score, T const & c_partial_pivoting, unsigned k) { unsigned arow = adjust_row(row); auto & row_vals = m_rows[arow].m_values; auto & begin_iv = row_vals[0]; T row_max = abs(begin_iv.m_value); - lean_assert(adjust_column_inverse(begin_iv.m_index) >= k); + SASSERT(adjust_column_inverse(begin_iv.m_index) >= k); if (pivot_score_without_shortened_counters(arow, begin_iv.m_index, k) < score) { print_active_matrix(k); return true; } for (unsigned jj = 1; jj < row_vals.size(); jj++) { auto & iv = row_vals[jj]; - lean_assert(adjust_column_inverse(iv.m_index) >= k); - lean_assert(abs(iv.m_value) <= row_max); + SASSERT(adjust_column_inverse(iv.m_index) >= k); + SASSERT(abs(iv.m_value) <= row_max); if (c_partial_pivoting * abs(iv.m_value) < row_max) continue; if (pivot_score_without_shortened_counters(arow, iv.m_index, k) < score) { print_active_matrix(k); @@ -993,7 +1008,7 @@ template bool sparse_matrix::really_best_pivot(unsigned i, unsigned j, T const & c_partial_pivoting, unsigned k) { unsigned queue_pivot_score = pivot_score_without_shortened_counters(i, j, k); for (unsigned ii = k; ii < dimension(); ii++) { - lean_assert(!can_improve_score_for_row(ii, queue_pivot_score, c_partial_pivoting, k)); + SASSERT(!can_improve_score_for_row(ii, queue_pivot_score, c_partial_pivoting, k)); } return true; } @@ -1026,7 +1041,7 @@ template bool sparse_matrix::pivot_queue_is_correct_for_row(unsigned i, unsigned k) { unsigned arow = adjust_row(i); for (auto & iv : m_rows[arow].m_values) { - lean_assert(pivot_score_without_shortened_counters(arow, iv.m_index, k + 1) == + SASSERT(pivot_score_without_shortened_counters(arow, iv.m_index, k + 1) == m_pivot_queue.get_priority(arow, iv.m_index)); } return true; @@ -1035,8 +1050,8 @@ bool sparse_matrix::pivot_queue_is_correct_for_row(unsigned i, unsigned k) template bool sparse_matrix::pivot_queue_is_correct_after_pivoting(int k) { for (unsigned i = k + 1; i < dimension(); i++ ) - lean_assert(pivot_queue_is_correct_for_row(i, k)); - lean_assert(m_pivot_queue.is_correct()); + SASSERT(pivot_queue_is_correct_for_row(i, k)); + SASSERT(m_pivot_queue.is_correct()); return true; } #endif @@ -1052,10 +1067,10 @@ bool sparse_matrix::get_pivot_for_column(unsigned &i, unsigned &j, int c_p if (j_inv < k) continue; int _small = elem_is_too_small(i, j, c_partial_pivoting); if (!_small) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // if (!really_best_pivot(i, j, c_partial_pivoting, k)) { // print_active_matrix(k); - // lean_assert(false); + // SASSERT(false); // } #endif recover_pivot_queue(pivots_candidates_that_are_too_small); @@ -1088,7 +1103,7 @@ bool sparse_matrix::shorten_columns_by_pivot_row(unsigned i, unsigned pivo for (indexed_value & iv : row_chunk) { unsigned j = iv.m_index; if (j == pivot_column) { - lean_assert(!col_is_active(j)); + SASSERT(!col_is_active(j)); continue; } m_columns[j].shorten_markovich_by_one(); @@ -1121,7 +1136,7 @@ bool sparse_matrix::fill_eta_matrix(unsigned j, eta_matrix ** eta) { return true; } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG *eta = new eta_matrix(j, dimension()); #else *eta = new eta_matrix(j); @@ -1146,16 +1161,16 @@ bool sparse_matrix::fill_eta_matrix(unsigned j, eta_matrix ** eta) { (*eta)->divide_by_diagonal_element(); return true; } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template bool sparse_matrix::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings & settings) const { for (unsigned i = 0; i < dimension(); i++) { vector> const & row_chunk = get_row_values(i); - lean_assert(row_chunk.size()); + SASSERT(row_chunk.size()); T const & max = abs(row_chunk[0].m_value); unsigned ai = adjust_row_inverse(i); for (auto & iv : row_chunk) { - lean_assert(abs(iv.m_value) <= max); + SASSERT(abs(iv.m_value) <= max); unsigned aj = adjust_column_inverse(iv.m_index); if (!(ai <= aj || numeric_traits::is_zero(iv.m_value))) return false; @@ -1193,18 +1208,18 @@ void sparse_matrix::check_column_vs_rows(unsigned col) { indexed_value & row_iv = column_iv_other(column_iv); if (row_iv.m_index != col) { // std::cout << "m_other in row does not belong to column " << col << ", but to column " << row_iv.m_index << std::endl; - lean_assert(false); + SASSERT(false); } if (& row_iv_other(row_iv) != &column_iv) { // std::cout << "row and col do not point to each other" << std::endl; - lean_assert(false); + SASSERT(false); } if (row_iv.m_value != column_iv.m_value) { // std::cout << "the data from col " << col << " for row " << column_iv.m_index << " is different in the column " << std::endl; // std::cout << "in the col it is " << column_iv.m_value << ", but in the row it is " << row_iv.m_value << std::endl; - lean_assert(false); + SASSERT(false); } } } @@ -1217,18 +1232,18 @@ void sparse_matrix::check_row_vs_columns(unsigned row) { if (column_iv.m_index != row) { // std::cout << "col_iv does not point to correct row " << row << " but to " << column_iv.m_index << std::endl; - lean_assert(false); + SASSERT(false); } if (& row_iv != & column_iv_other(column_iv)) { // std::cout << "row and col do not point to each other" << std::endl; - lean_assert(false); + SASSERT(false); } if (row_iv.m_value != column_iv.m_value) { // std::cout << "the data from col " << column_iv.m_index << " for row " << row << " is different in the column " << std::endl; // std::cout << "in the col it is " << column_iv.m_value << ", but in the row it is " << row_iv.m_value << std::endl; - lean_assert(false); + SASSERT(false); } } } diff --git a/src/util/lp/sparse_matrix_instances.cpp b/src/util/lp/sparse_matrix_instances.cpp index c06fcbf05..64a555bb2 100644 --- a/src/util/lp/sparse_matrix_instances.cpp +++ b/src/util/lp/sparse_matrix_instances.cpp @@ -1,14 +1,29 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/vector.h" #include "util/lp/lp_settings.h" #include "util/lp/lu.h" #include "util/lp/sparse_matrix.hpp" #include "util/lp/dense_matrix.h" -namespace lean { +namespace lp { template double sparse_matrix::dot_product_with_row(unsigned int, vector const&) const; template void sparse_matrix::add_new_element(unsigned int, unsigned int, const double&); template void sparse_matrix::divide_row_by_constant(unsigned int, const double&, lp_settings&); @@ -65,37 +80,37 @@ template void sparse_matrix::double_solve_U_y(indexed_ve template void sparse_matrix::double_solve_U_y(indexed_vector&, const lp_settings&); template void sparse_matrix>::double_solve_U_y(indexed_vector&, const lp_settings&); template void sparse_matrix >::double_solve_U_y >(indexed_vector>&, const lp_settings&); -template void lean::sparse_matrix::solve_U_y_indexed_only(lean::indexed_vector&, const lp_settings&, vector &); -template void lean::sparse_matrix::solve_U_y_indexed_only(lean::indexed_vector&, const lp_settings &, vector &); -#ifdef LEAN_DEBUG +template void lp::sparse_matrix::solve_U_y_indexed_only(lp::indexed_vector&, const lp_settings&, vector &); +template void lp::sparse_matrix::solve_U_y_indexed_only(lp::indexed_vector&, const lp_settings &, vector &); +#ifdef Z3DEBUG template bool sparse_matrix::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings&) const; template bool sparse_matrix::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings&) const; template bool sparse_matrix >::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings&) const; #endif } -template void lean::sparse_matrix >::solve_U_y_indexed_only(lean::indexed_vector&, const lp_settings &, vector &); -template void lean::sparse_matrix::solve_U_y(vector&); -template void lean::sparse_matrix::double_solve_U_y(vector&); -template void lean::sparse_matrix::solve_U_y(vector&); -template void lean::sparse_matrix::double_solve_U_y(vector&); -template void lean::sparse_matrix >::solve_U_y >(vector >&); -template void lean::sparse_matrix >::double_solve_U_y >(vector >&); -template void lean::sparse_matrix::find_error_in_solution_U_y_indexed(lean::indexed_vector&, lean::indexed_vector&, const vector &); -template double lean::sparse_matrix::dot_product_with_row(unsigned int, lean::indexed_vector const&) const; -template void lean::sparse_matrix::find_error_in_solution_U_y_indexed(lean::indexed_vector&, lean::indexed_vector&, const vector &); -template lean::mpq lean::sparse_matrix::dot_product_with_row(unsigned int, lean::indexed_vector const&) const; -template void lean::sparse_matrix >::find_error_in_solution_U_y_indexed(lean::indexed_vector&, lean::indexed_vector&, const vector &); -template lean::mpq lean::sparse_matrix >::dot_product_with_row(unsigned int, lean::indexed_vector const&) const; -template void lean::sparse_matrix >::find_error_in_solution_U_y_indexed >(lean::indexed_vector >&, lean::indexed_vector >&, const vector &); -template lean::numeric_pair lean::sparse_matrix >::dot_product_with_row >(unsigned int, lean::indexed_vector > const&) const; -template void lean::sparse_matrix::extend_and_sort_active_rows(vector const&, vector&); +template void lp::sparse_matrix >::solve_U_y_indexed_only(lp::indexed_vector&, const lp_settings &, vector &); +template void lp::sparse_matrix::solve_U_y(vector&); +template void lp::sparse_matrix::double_solve_U_y(vector&); +template void lp::sparse_matrix::solve_U_y(vector&); +template void lp::sparse_matrix::double_solve_U_y(vector&); +template void lp::sparse_matrix >::solve_U_y >(vector >&); +template void lp::sparse_matrix >::double_solve_U_y >(vector >&); +template void lp::sparse_matrix::find_error_in_solution_U_y_indexed(lp::indexed_vector&, lp::indexed_vector&, const vector &); +template double lp::sparse_matrix::dot_product_with_row(unsigned int, lp::indexed_vector const&) const; +template void lp::sparse_matrix::find_error_in_solution_U_y_indexed(lp::indexed_vector&, lp::indexed_vector&, const vector &); +template lp::mpq lp::sparse_matrix::dot_product_with_row(unsigned int, lp::indexed_vector const&) const; +template void lp::sparse_matrix >::find_error_in_solution_U_y_indexed(lp::indexed_vector&, lp::indexed_vector&, const vector &); +template lp::mpq lp::sparse_matrix >::dot_product_with_row(unsigned int, lp::indexed_vector const&) const; +template void lp::sparse_matrix >::find_error_in_solution_U_y_indexed >(lp::indexed_vector >&, lp::indexed_vector >&, const vector &); +template lp::numeric_pair lp::sparse_matrix >::dot_product_with_row >(unsigned int, lp::indexed_vector > const&) const; +template void lp::sparse_matrix::extend_and_sort_active_rows(vector const&, vector&); -template void lean::sparse_matrix >::extend_and_sort_active_rows(vector const&, vector&); +template void lp::sparse_matrix >::extend_and_sort_active_rows(vector const&, vector&); -template void lean::sparse_matrix >::solve_U_y(vector&); -template void lean::sparse_matrix >::double_solve_U_y(vector&); -template void lean::sparse_matrix< lean::mpq,lean::numeric_pair< lean::mpq> >::set(unsigned int,unsigned int, lean::mpq); -template void lean::sparse_matrix::solve_y_U_indexed(lean::indexed_vector&, const lp_settings & ); -template void lean::sparse_matrix::solve_y_U_indexed(lean::indexed_vector&, const lp_settings &); -template void lean::sparse_matrix >::solve_y_U_indexed(lean::indexed_vector&, const lp_settings &); +template void lp::sparse_matrix >::solve_U_y(vector&); +template void lp::sparse_matrix >::double_solve_U_y(vector&); +template void lp::sparse_matrix< lp::mpq,lp::numeric_pair< lp::mpq> >::set(unsigned int,unsigned int, lp::mpq); +template void lp::sparse_matrix::solve_y_U_indexed(lp::indexed_vector&, const lp_settings & ); +template void lp::sparse_matrix::solve_y_U_indexed(lp::indexed_vector&, const lp_settings &); +template void lp::sparse_matrix >::solve_y_U_indexed(lp::indexed_vector&, const lp_settings &); diff --git a/src/util/lp/sparse_vector.h b/src/util/lp/sparse_vector.h index 975cb7f28..51639674c 100644 --- a/src/util/lp/sparse_vector.h +++ b/src/util/lp/sparse_vector.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" @@ -9,7 +24,7 @@ #include "util/debug.h" #include "util/lp/lp_utils.h" #include "util/lp/lp_settings.h" -namespace lean { +namespace lp { template class sparse_vector { @@ -18,7 +33,7 @@ public: void push_back(unsigned index, T val) { m_data.push_back(std::make_pair(index, val)); } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG T operator[] (unsigned i) const { for (auto &t : m_data) { if (t.first == i) return t.second; @@ -27,7 +42,7 @@ public: } #endif void divide(T const & a) { - lean_assert(!lp_settings::is_eps_small_general(a, 1e-12)); + SASSERT(!lp_settings::is_eps_small_general(a, 1e-12)); for (auto & t : m_data) { t.second /= a; } } diff --git a/src/util/lp/square_dense_submatrix.h b/src/util/lp/square_dense_submatrix.h index 019497aa5..3e88e8114 100644 --- a/src/util/lp/square_dense_submatrix.h +++ b/src/util/lp/square_dense_submatrix.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" @@ -20,7 +35,7 @@ #include "util/lp/eta_matrix.h" #include "util/lp/binary_heap_upair_queue.h" #include "util/lp/sparse_matrix.h" -namespace lean { +namespace lp { template class square_dense_submatrix : public tail_matrix { // the submatrix uses the permutations of the parent matrix to access the elements @@ -30,11 +45,11 @@ class square_dense_submatrix : public tail_matrix { ref(unsigned i, square_dense_submatrix & s) : m_i_offset((i - s.m_index_start) * s.m_dim), m_s(s){} T & operator[] (unsigned j) { - lean_assert(j >= m_s.m_index_start); + SASSERT(j >= m_s.m_index_start); return m_s.m_v[m_i_offset + m_s.adjust_column(j) - m_s.m_index_start]; } const T & operator[] (unsigned j) const { - lean_assert(j >= m_s.m_index_start); + SASSERT(j >= m_s.m_index_start); return m_s.m_v[m_i_offset + m_s.adjust_column(j) - m_s.m_index_start]; } }; @@ -58,8 +73,8 @@ public: bool is_dense() const { return true; } ref operator[] (unsigned i) { - lean_assert(i >= m_index_start); - lean_assert(i < m_parent->dimension()); + SASSERT(i >= m_index_start); + SASSERT(i < m_parent->dimension()); return ref(i, *this); } @@ -148,7 +163,7 @@ public: } } } - lean_assert(wcopy.is_OK()); + SASSERT(wcopy.is_OK()); apply_from_right(w.m_data); w.m_index.clear(); if (numeric_traits::precise()) { @@ -167,11 +182,11 @@ public: } } #else - lean_assert(w.is_OK()); - lean_assert(m_work_vector.is_OK()); + SASSERT(w.is_OK()); + SASSERT(m_work_vector.is_OK()); m_work_vector.resize(w.data_size()); m_work_vector.clear(); - lean_assert(m_work_vector.is_OK()); + SASSERT(m_work_vector.is_OK()); unsigned end = m_index_start + m_dim; for (unsigned k : w.m_index) { // find j such that k = adjust_row_inverse(j) @@ -188,7 +203,7 @@ public: } } m_work_vector.clean_up(); - lean_assert(m_work_vector.is_OK()); + SASSERT(m_work_vector.is_OK()); w = m_work_vector; #endif } @@ -198,7 +213,7 @@ public: void apply_from_right(vector & w); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG T get_elem (unsigned i, unsigned j) const; unsigned row_count() const { return m_parent->row_count();} unsigned column_count() const { return row_count();} diff --git a/src/util/lp/square_dense_submatrix.hpp b/src/util/lp/square_dense_submatrix.hpp index 365c9d7f0..cbf69c5dd 100644 --- a/src/util/lp/square_dense_submatrix.hpp +++ b/src/util/lp/square_dense_submatrix.hpp @@ -1,10 +1,25 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/vector.h" #include "util/lp/square_dense_submatrix.h" -namespace lean { +namespace lp { template square_dense_submatrix::square_dense_submatrix (sparse_matrix *parent_matrix, unsigned index_start) : m_index_start(index_start), @@ -18,7 +33,7 @@ square_dense_submatrix::square_dense_submatrix (sparse_matrix *paren unsigned row = parent_matrix->adjust_row(i); for (auto & iv : parent_matrix->get_row_values(row)) { unsigned j = parent_matrix->adjust_column_inverse(iv.m_index); - lean_assert(j>= m_index_start); + SASSERT(j>= m_index_start); m_v[row_offset + j] = iv.m_value; } row_offset += m_dim; @@ -43,7 +58,7 @@ template void square_dense_submatrix::init(sparse template int square_dense_submatrix::find_pivot_column_in_row(unsigned i) const { int j = -1; T max = zero_of_type(); - lean_assert(i >= m_index_start); + SASSERT(i >= m_index_start); unsigned row_start = (i - m_index_start) * m_dim; for (unsigned k = i; k < m_parent->dimension(); k++) { unsigned col = adjust_column(k); // this is where the column is in the row @@ -64,14 +79,14 @@ template void square_dense_submatrix::pivot(un } template void square_dense_submatrix::pivot_row_to_row(unsigned i, unsigned row, lp_settings & settings) { - lean_assert(i < row); + SASSERT(i < row); unsigned pj = adjust_column(i); // the pivot column unsigned pjd = pj - m_index_start; unsigned pivot_row_offset = (i-m_index_start)*m_dim; T pivot = m_v[pivot_row_offset + pjd]; unsigned row_offset= (row-m_index_start)*m_dim; T m = m_v[row_offset + pjd]; - lean_assert(!is_zero(pivot)); + SASSERT(!is_zero(pivot)); m_v[row_offset + pjd] = -m * pivot; // creating L matrix for (unsigned j = m_index_start; j < m_parent->dimension(); j++) { if (j == pj) { @@ -94,7 +109,7 @@ template void square_dense_submatrix::divide_r unsigned pj = adjust_column(i); // the pivot column unsigned irow_offset = (i - m_index_start) * m_dim; T pivot = m_v[irow_offset + pj - m_index_start]; - lean_assert(!is_zero(pivot)); + SASSERT(!is_zero(pivot)); for (unsigned k = m_index_start; k < m_parent->dimension(); k++) { if (k == pj){ m_v[irow_offset++] = one_of_type() / pivot; // creating the L matrix diagonal @@ -158,7 +173,7 @@ template void square_dense_submatrix::push_new template template L square_dense_submatrix::row_by_vector_product(unsigned i, const vector & v) { - lean_assert(i >= m_index_start); + SASSERT(i >= m_index_start); unsigned row_in_subm = i - m_index_start; unsigned row_offset = row_in_subm * m_dim; @@ -171,7 +186,7 @@ L square_dense_submatrix::row_by_vector_product(unsigned i, const vector template L square_dense_submatrix::column_by_vector_product(unsigned j, const vector & v) { - lean_assert(j >= m_index_start); + SASSERT(j >= m_index_start); unsigned offset = j - m_index_start; L r = zero_of_type(); @@ -182,7 +197,7 @@ L square_dense_submatrix::column_by_vector_product(unsigned j, const vecto template template L square_dense_submatrix::row_by_indexed_vector_product(unsigned i, const indexed_vector & v) { - lean_assert(i >= m_index_start); + SASSERT(i >= m_index_start); unsigned row_in_subm = i - m_index_start; unsigned row_offset = row_in_subm * m_dim; @@ -194,7 +209,7 @@ L square_dense_submatrix::row_by_indexed_vector_product(unsigned i, const template template void square_dense_submatrix::apply_from_left_local(indexed_vector & w, lp_settings & settings) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // dense_matrix deb(*this); // vector deb_w(w.m_data.size()); // for (unsigned i = 0; i < w.m_data.size(); i++) @@ -246,11 +261,11 @@ void square_dense_submatrix::apply_from_left_local(indexed_vector & w, w.m_data[i] = v; } #endif -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // cout << "w final" << endl; // print_vector(w.m_data); - // lean_assert(vectors_are_equal(deb_w, w.m_data)); - // lean_assert(w.is_OK()); + // SASSERT(vectors_are_equal(deb_w, w.m_data)); + // SASSERT(w.is_OK()); #endif } @@ -277,19 +292,19 @@ void square_dense_submatrix::apply_from_left_to_vector(vector & w) { for (unsigned i = 0; i < m_parent->dimension(); i++) { w[i] = t[i]; } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // cout << "w final" << endl; // print_vector(w.m_data); - // lean_assert(vectors_are_equal(deb_w, w)); + // SASSERT(vectors_are_equal(deb_w, w)); #endif } template bool square_dense_submatrix::is_L_matrix() const { -#ifdef LEAN_DEBUG - lean_assert(m_row_permutation.is_identity()); +#ifdef Z3DEBUG + SASSERT(m_row_permutation.is_identity()); for (unsigned i = 0; i < m_parent->dimension(); i++) { if (i < m_index_start) { - lean_assert(m_column_permutation[i] == i); + SASSERT(m_column_permutation[i] == i); continue; } unsigned row_offs = (i-m_index_start)*m_dim; @@ -297,9 +312,9 @@ template bool square_dense_submatrix::is_L_mat unsigned j = m_index_start + k; unsigned jex = adjust_column_inverse(j); if (jex > i) { - lean_assert(is_zero(m_v[row_offs + k])); + SASSERT(is_zero(m_v[row_offs + k])); } else if (jex == i) { - lean_assert(!is_zero(m_v[row_offs + k])); + SASSERT(!is_zero(m_v[row_offs + k])); } } } @@ -308,7 +323,7 @@ template bool square_dense_submatrix::is_L_mat } template void square_dense_submatrix::apply_from_right(vector & w) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG // dense_matrix deb(*this); // vector deb_w(w); // deb.apply_from_right(deb_w); @@ -326,15 +341,15 @@ template void square_dense_submatrix::apply_from_ t[adjust_column_inverse(j)] = column_by_vector_product(j, w); } w = t; -#ifdef LEAN_DEBUG - // lean_assert(vector_are_equal(deb_w, w)); +#ifdef Z3DEBUG + // SASSERT(vector_are_equal(deb_w, w)); #endif } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template T square_dense_submatrix::get_elem (unsigned i, unsigned j) const { i = adjust_row(i); diff --git a/src/util/lp/square_dense_submatrix_instances.cpp b/src/util/lp/square_dense_submatrix_instances.cpp index 7d45aaaa1..e1df0036e 100644 --- a/src/util/lp/square_dense_submatrix_instances.cpp +++ b/src/util/lp/square_dense_submatrix_instances.cpp @@ -1,33 +1,48 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include "util/vector.h" #include "util/lp/square_dense_submatrix.hpp" -template void lean::square_dense_submatrix::init(lean::sparse_matrix*, unsigned int); -template lean::square_dense_submatrix::square_dense_submatrix(lean::sparse_matrix*, unsigned int); -template void lean::square_dense_submatrix::update_parent_matrix(lean::lp_settings&); -template bool lean::square_dense_submatrix::is_L_matrix() const; -template void lean::square_dense_submatrix::conjugate_by_permutation(lean::permutation_matrix&); -template int lean::square_dense_submatrix::find_pivot_column_in_row(unsigned int) const; -template void lean::square_dense_submatrix::pivot(unsigned int, lean::lp_settings&); -template lean::square_dense_submatrix >::square_dense_submatrix(lean::sparse_matrix >*, unsigned int); -template void lean::square_dense_submatrix >::update_parent_matrix(lean::lp_settings&); -template bool lean::square_dense_submatrix >::is_L_matrix() const; -template void lean::square_dense_submatrix >::conjugate_by_permutation(lean::permutation_matrix >&); -template int lean::square_dense_submatrix >::find_pivot_column_in_row(unsigned int) const; -template void lean::square_dense_submatrix >::pivot(unsigned int, lean::lp_settings&); -#ifdef LEAN_DEBUG -template double lean::square_dense_submatrix::get_elem(unsigned int, unsigned int) const; +template void lp::square_dense_submatrix::init(lp::sparse_matrix*, unsigned int); +template lp::square_dense_submatrix::square_dense_submatrix(lp::sparse_matrix*, unsigned int); +template void lp::square_dense_submatrix::update_parent_matrix(lp::lp_settings&); +template bool lp::square_dense_submatrix::is_L_matrix() const; +template void lp::square_dense_submatrix::conjugate_by_permutation(lp::permutation_matrix&); +template int lp::square_dense_submatrix::find_pivot_column_in_row(unsigned int) const; +template void lp::square_dense_submatrix::pivot(unsigned int, lp::lp_settings&); +template lp::square_dense_submatrix >::square_dense_submatrix(lp::sparse_matrix >*, unsigned int); +template void lp::square_dense_submatrix >::update_parent_matrix(lp::lp_settings&); +template bool lp::square_dense_submatrix >::is_L_matrix() const; +template void lp::square_dense_submatrix >::conjugate_by_permutation(lp::permutation_matrix >&); +template int lp::square_dense_submatrix >::find_pivot_column_in_row(unsigned int) const; +template void lp::square_dense_submatrix >::pivot(unsigned int, lp::lp_settings&); +#ifdef Z3DEBUG +template double lp::square_dense_submatrix::get_elem(unsigned int, unsigned int) const; #endif -template void lean::square_dense_submatrix::apply_from_right(vector&); +template void lp::square_dense_submatrix::apply_from_right(vector&); -template void lean::square_dense_submatrix::apply_from_left_local(lean::indexed_vector&, lean::lp_settings&); -template void lean::square_dense_submatrix::apply_from_left_to_vector(vector&); -template lean::square_dense_submatrix::square_dense_submatrix(lean::sparse_matrix*, unsigned int); -template void lean::square_dense_submatrix::update_parent_matrix(lean::lp_settings&); -template bool lean::square_dense_submatrix::is_L_matrix() const; -template void lean::square_dense_submatrix::conjugate_by_permutation(lean::permutation_matrix&); -template int lean::square_dense_submatrix::find_pivot_column_in_row(unsigned int) const; -template void lean::square_dense_submatrix::pivot(unsigned int, lean::lp_settings&); +template void lp::square_dense_submatrix::apply_from_left_local(lp::indexed_vector&, lp::lp_settings&); +template void lp::square_dense_submatrix::apply_from_left_to_vector(vector&); +template lp::square_dense_submatrix::square_dense_submatrix(lp::sparse_matrix*, unsigned int); +template void lp::square_dense_submatrix::update_parent_matrix(lp::lp_settings&); +template bool lp::square_dense_submatrix::is_L_matrix() const; +template void lp::square_dense_submatrix::conjugate_by_permutation(lp::permutation_matrix&); +template int lp::square_dense_submatrix::find_pivot_column_in_row(unsigned int) const; +template void lp::square_dense_submatrix::pivot(unsigned int, lp::lp_settings&); diff --git a/src/util/lp/stacked_map.h b/src/util/lp/stacked_map.h index 4692540dd..1bcad5649 100644 --- a/src/util/lp/stacked_map.h +++ b/src/util/lp/stacked_map.h @@ -1,14 +1,29 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once // this class implements a map with some stack functionality #include #include #include -namespace lean { +namespace lp { template second; } }; @@ -73,7 +88,7 @@ public: const B & operator[]( const A & a) const { auto it = m_map.find(a); if (it == m_map.end()) { - lean_assert(false); + SASSERT(false); } return it->second; @@ -128,7 +143,7 @@ public: for (auto & t: d.m_original_changed) { m_map[t.first] = t.second; } - // lean_assert(d.m_deb_copy == m_map); + // SASSERT(d.m_deb_copy == m_map); m_stack.pop(); } } @@ -142,7 +157,7 @@ public: delta & d = m_stack.top(); auto it = m_map.find(key); if (it == m_map.end()) { - lean_assert(d.m_new.find(key) == d.m_new.end()); + SASSERT(d.m_new.find(key) == d.m_new.end()); return; } auto &orig_changed = d.m_original_changed; @@ -151,7 +166,7 @@ public: if (orig_changed.find(key) == orig_changed.end()) orig_changed.emplace(it->first, it->second); // need to restore } else { // k is new - lean_assert(orig_changed.find(key) == orig_changed.end()); + SASSERT(orig_changed.find(key) == orig_changed.end()); d.m_new.erase(nit); } diff --git a/src/util/lp/stacked_unordered_set.h b/src/util/lp/stacked_unordered_set.h index 69c4cf03b..6e313e6c0 100644 --- a/src/util/lp/stacked_unordered_set.h +++ b/src/util/lp/stacked_unordered_set.h @@ -1,14 +1,29 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once // this class implements an unordered_set with some stack functionality #include #include #include -namespace lean { +namespace lp { template , @@ -81,7 +96,7 @@ public: for (auto & t : d.m_erased) { m_set.insert(t); } - lean_assert(d.m_deb_copy == m_set); + SASSERT(d.m_deb_copy == m_set); m_stack.pop(); } } diff --git a/src/util/lp/stacked_value.h b/src/util/lp/stacked_value.h index 2a1e85be7..5ef7ea0c8 100644 --- a/src/util/lp/stacked_value.h +++ b/src/util/lp/stacked_value.h @@ -1,12 +1,27 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once // add to value the stack semantics #include -namespace lean { +namespace lp { template class stacked_value { T m_value; std::stack m_stack; diff --git a/src/util/lp/stacked_vector.h b/src/util/lp/stacked_vector.h index 3f39dd346..e8234d1e4 100644 --- a/src/util/lp/stacked_vector.h +++ b/src/util/lp/stacked_vector.h @@ -1,13 +1,29 @@ -/* +/*++ Copyright (c) 2017 Microsoft Corporation -Author: Lev Nachmanson -*/ + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ + #pragma once #include #include #include #include "util/vector.h" -namespace lean { +namespace lp { template < typename B> class stacked_vector { vector m_stack_of_vector_sizes; vector m_stack_of_change_sizes; @@ -19,7 +35,7 @@ public: unsigned m_i; public: ref(stacked_vector &m, unsigned key) :m_vec(m), m_i(key) { - lean_assert(key < m.size()); + SASSERT(key < m.size()); } ref & operator=(const B & b) { m_vec.emplace_replace(m_i, b); @@ -40,7 +56,7 @@ public: unsigned m_i; public: ref_const(const stacked_vector &m, unsigned key) :m_vec(m), m_i(key) { - lean_assert(key < m.size()); + SASSERT(key < m.size()); } operator const B&() const { @@ -51,10 +67,10 @@ public: private: void emplace_replace(unsigned i,const B & b) { - if (m_vector[i] != b) { - m_changes.push_back(std::make_pair(i, m_vector[i])); - m_vector[i] = b; - } + if (m_vector[i] != b) { + m_changes.push_back(std::make_pair(i, m_vector[i])); + m_vector[i] = b; + } } public: @@ -68,7 +84,7 @@ public: /* const B & operator[](unsigned a) const { - lean_assert(a < m_vector.size()); + SASSERT(a < m_vector.size()); return m_vector[a]; } */ @@ -87,19 +103,19 @@ public: } template - void pop_tail(vector & v, unsigned k) { - lean_assert(v.size() >= k); - v.resize(v.size() - k); - } + void pop_tail(vector & v, unsigned k) { + SASSERT(v.size() >= k); + v.resize(v.size() - k); + } template void resize(vector & v, unsigned new_size) { - v.resize(new_size); + v.resize(new_size); } void pop(unsigned k) { - lean_assert(m_stack_of_vector_sizes.size() >= k); - lean_assert(k > 0); + SASSERT(m_stack_of_vector_sizes.size() >= k); + SASSERT(k > 0); resize(m_vector, m_stack_of_vector_sizes[m_stack_of_vector_sizes.size() - k]); pop_tail(m_stack_of_vector_sizes, k); unsigned first_change = m_stack_of_change_sizes[m_stack_of_change_sizes.size() - k]; @@ -119,15 +135,15 @@ public: return; delta & d = m_stack.back(); - lean_assert(m_vector.size() >= d.m_size); + SASSERT(m_vector.size() >= d.m_size); while (m_vector.size() > d.m_size) m_vector.pop_back(); for (auto & t : d.m_original_changed) { - lean_assert(t.first < m_vector.size()); + SASSERT(t.first < m_vector.size()); m_vector[t.first] = t.second; } - // lean_assert(d.m_deb_copy == m_vector); + // SASSERT(d.m_deb_copy == m_vector); m_stack.pop_back();*/ } @@ -156,10 +172,10 @@ public: m_vector.resize(m_vector.size() + 1); } - unsigned peek_size(unsigned k) const { - lean_assert(k > 0 && k <= m_stack_of_vector_sizes.size()); - return m_stack_of_vector_sizes[m_stack_of_vector_sizes.size() - k]; - } + unsigned peek_size(unsigned k) const { + SASSERT(k > 0 && k <= m_stack_of_vector_sizes.size()); + return m_stack_of_vector_sizes[m_stack_of_vector_sizes.size() - k]; + } const vector& operator()() const { return m_vector; } }; diff --git a/src/util/lp/static_matrix.h b/src/util/lp/static_matrix.h index 5ef4b449f..29b7ed646 100644 --- a/src/util/lp/static_matrix.h +++ b/src/util/lp/static_matrix.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" @@ -13,7 +28,7 @@ #include "util/lp/permutation_matrix.h" #include "util/lp/linear_combination_iterator.h" #include -namespace lean { +namespace lp { struct column_cell { unsigned m_i; // points to the row @@ -37,7 +52,7 @@ struct row_cell { // each assignment for this matrix should be issued only once!!! template class static_matrix -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG : public matrix #endif { @@ -47,7 +62,7 @@ class static_matrix dim(unsigned m, unsigned n) :m_m(m), m_n(n) {} }; std::stack m_stack; - vector m_became_zeros; // the row indices that became zeroes during the pivoting + vector m_became_zeros; // the row indices that became zeroes during the pivoting public: typedef vector> row_strip; typedef vector column_strip; @@ -130,7 +145,7 @@ public: } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG void regen_domain(); #endif @@ -163,7 +178,7 @@ public: T get_min_abs_in_column(unsigned column) const; -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG void check_consistency(); #endif @@ -196,14 +211,14 @@ public: void clean_row_work_vector(unsigned i); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG unsigned get_number_of_rows() const { return row_count(); } unsigned get_number_of_columns() const { return column_count(); } virtual void set_number_of_rows(unsigned /*m*/) { } virtual void set_number_of_columns(unsigned /*n*/) { } #endif - T get_max_val_in_row(unsigned /* i */) const { lean_unreachable(); } + T get_max_val_in_row(unsigned /* i */) const { SASSERT(false); } T get_balance() const; @@ -219,7 +234,7 @@ public: for (auto & c : row) { unsigned j = c.m_j; auto & col = m_columns[j]; - lean_assert(col[col.size() - 1].m_i == m_rows.size() -1 ); // todo : start here!!!! + SASSERT(col[col.size() - 1].m_i == m_rows.size() -1 ); // todo : start here!!!! col.pop_back(); } } @@ -227,7 +242,7 @@ public: void pop(unsigned k) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG std::set> pairs_to_remove_from_domain; #endif @@ -246,7 +261,7 @@ public: m_columns.pop_back(); // delete the last column m_stack.pop(); } - lean_assert(is_correct()); + SASSERT(is_correct()); } void multiply_row(unsigned row, T const & alpha) { @@ -262,7 +277,7 @@ public: } T dot_product_with_column(const vector & y, unsigned j) const { - lean_assert(j < column_count()); + SASSERT(j < column_count()); T ret = numeric_traits::zero(); for (auto & it : m_columns[j]) { ret += y[it.m_i] * get_val(it); // get_value_of_column_cell(it); @@ -281,20 +296,20 @@ public: // now fix the columns for (auto & rc : m_rows[i]) { column_cell & cc = m_columns[rc.m_j][rc.m_offset]; - lean_assert(cc.m_i == ii); + SASSERT(cc.m_i == ii); cc.m_i = i; } for (auto & rc : m_rows[ii]) { column_cell & cc = m_columns[rc.m_j][rc.m_offset]; - lean_assert(cc.m_i == i); + SASSERT(cc.m_i == i); cc.m_i = ii; } } void fill_last_row_with_pivoting(linear_combination_iterator & it, const vector & basis_heading) { - lean_assert(numeric_traits::precise()); - lean_assert(row_count() > 0); + SASSERT(numeric_traits::precise()); + SASSERT(row_count() > 0); m_work_vector.resize(column_count()); T a; unsigned j; @@ -332,13 +347,13 @@ public: alpha = zero_of_type(); m_work_vector.erase_from_index(j); } - lean_assert(m_work_vector.is_OK()); + SASSERT(m_work_vector.is_OK()); unsigned last_row = row_count() - 1; for (unsigned j : m_work_vector.m_index) { set (last_row, j, m_work_vector.m_data[j]); } - lean_assert(column_count() > 0); + SASSERT(column_count() > 0); set(last_row, column_count() - 1, one_of_type()); } @@ -354,7 +369,7 @@ public: template L dot_product_with_row(unsigned row, const vector & w) const { L ret = zero_of_type(); - lean_assert(row < m_rows.size()); + SASSERT(row < m_rows.size()); for (auto & it : m_rows[row]) { ret += w[it.m_j] * it.get_val(); } diff --git a/src/util/lp/static_matrix.hpp b/src/util/lp/static_matrix.hpp index fb12da8c4..846c2a19f 100644 --- a/src/util/lp/static_matrix.hpp +++ b/src/util/lp/static_matrix.hpp @@ -1,16 +1,31 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include "util/vector.h" #include #include #include "util/lp/static_matrix.h" -namespace lean { +namespace lp { // each assignment for this matrix should be issued only once!!! template void static_matrix::init_row_columns(unsigned m, unsigned n) { - lean_assert(m_rows.size() == 0 && m_columns.size() == 0); + SASSERT(m_rows.size() == 0 && m_columns.size() == 0); for (unsigned i = 0; i < m; i++){ m_rows.push_back(row_strip()); } @@ -30,23 +45,23 @@ template void static_matrix::scan_row_ii_to_offse template bool static_matrix::pivot_row_to_row_given_cell(unsigned i, column_cell & c, unsigned pivot_col) { unsigned ii = c.m_i; - lean_assert(i < row_count() && ii < column_count()); - lean_assert(i != ii); + SASSERT(i < row_count() && ii < column_count()); + SASSERT(i != ii); - m_became_zeros.reset(); + m_became_zeros.reset(); T alpha = -get_val(c); - lean_assert(!is_zero(alpha)); + SASSERT(!is_zero(alpha)); auto & ii_row_vals = m_rows[ii]; remove_element(ii_row_vals, ii_row_vals[c.m_offset]); scan_row_ii_to_offset_vector(ii); - lean_assert(!is_zero(alpha)); + SASSERT(!is_zero(alpha)); unsigned prev_size_ii = ii_row_vals.size(); // run over the pivot row and update row ii for (const auto & iv : m_rows[i]) { unsigned j = iv.m_j; if (j == pivot_col) continue; T alv = alpha * iv.m_value; - lean_assert(!is_zero(iv.m_value)); + SASSERT(!is_zero(iv.m_value)); int j_offs = m_vector_of_row_offsets[j]; if (j_offs == -1) { // it is a new element add_new_element(ii, j, alv); @@ -104,9 +119,9 @@ template void static_matrix::init_empty_matrix } template unsigned static_matrix::lowest_row_in_column(unsigned col) { - lean_assert(col < column_count()); + SASSERT(col < column_count()); column_strip & colstrip = m_columns[col]; - lean_assert(colstrip.size() > 0); + SASSERT(colstrip.size() > 0); unsigned ret = 0; for (auto & t : colstrip) { if (t.m_i > ret) { @@ -122,7 +137,7 @@ template void static_matrix::add_columns_at_th } template void static_matrix::forget_last_columns(unsigned how_many_to_forget) { - lean_assert(m_columns.size() >= how_many_to_forget); + SASSERT(m_columns.size() >= how_many_to_forget); unsigned j = column_count() - 1; for (; how_many_to_forget > 0; how_many_to_forget--) { remove_last_column(j --); @@ -151,7 +166,7 @@ template void static_matrix::remove_last_column(u template void static_matrix::set(unsigned row, unsigned col, T const & val) { if (numeric_traits::is_zero(val)) return; - lean_assert(row < row_count() && col < column_count()); + SASSERT(row < row_count() && col < column_count()); auto & r = m_rows[row]; unsigned offs_in_cols = static_cast(m_columns[col].size()); m_columns[col].push_back(make_column_cell(row, static_cast(r.size()))); @@ -171,7 +186,7 @@ std::set> static_matrix::get_domain() { template void static_matrix::copy_column_to_indexed_vector (unsigned j, indexed_vector & v) const { - lean_assert(j < m_columns.size()); + SASSERT(j < m_columns.size()); for (auto & it : m_columns[j]) { const T& val = get_val(it); if (!is_zero(val)) @@ -234,13 +249,13 @@ template T static_matrix::get_min_abs_in_colu return ret; } -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template void static_matrix::check_consistency() { std::unordered_map, T> by_rows; for (int i = 0; i < m_rows.size(); i++){ for (auto & t : m_rows[i]) { std::pair p(i, t.m_j); - lean_assert(by_rows.find(p) == by_rows.end()); + SASSERT(by_rows.find(p) == by_rows.end()); by_rows[p] = t.get_val(); } } @@ -248,11 +263,11 @@ template void static_matrix::check_consistency for (int i = 0; i < m_columns.size(); i++){ for (auto & t : m_columns[i]) { std::pair p(t.m_i, i); - lean_assert(by_cols.find(p) == by_cols.end()); + SASSERT(by_cols.find(p) == by_cols.end()); by_cols[p] = get_val(t); } } - lean_assert(by_rows.size() == by_cols.size()); + SASSERT(by_rows.size() == by_cols.size()); for (auto & t : by_rows) { auto ic = by_cols.find(t.first); @@ -260,21 +275,21 @@ template void static_matrix::check_consistency //std::cout << "rows have pair (" << t.first.first <<"," << t.first.second // << "), but columns don't " << std::endl; } - lean_assert(ic != by_cols.end()); - lean_assert(t.second == ic->second); + SASSERT(ic != by_cols.end()); + SASSERT(t.second == ic->second); } } #endif template void static_matrix::cross_out_row(unsigned k) { -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG check_consistency(); #endif cross_out_row_from_columns(k, m_rows[k]); fix_row_indices_in_each_column_for_crossed_row(k); m_rows.erase(m_rows.begin() + k); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG regen_domain(); check_consistency(); #endif diff --git a/src/util/lp/static_matrix_instances.cpp b/src/util/lp/static_matrix_instances.cpp index ef4374a50..c57f31177 100644 --- a/src/util/lp/static_matrix_instances.cpp +++ b/src/util/lp/static_matrix_instances.cpp @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #include #include #include @@ -13,18 +28,18 @@ #include "util/lp/lp_primal_core_solver.h" #include "util/lp/scaler.h" #include "util/lp/lar_solver.h" -namespace lean { +namespace lp { template void static_matrix::add_columns_at_the_end(unsigned int); template void static_matrix::clear(); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template bool static_matrix::is_correct() const; #endif template void static_matrix::copy_column_to_indexed_vector(unsigned int, indexed_vector&) const; template double static_matrix::get_balance() const; template std::set> static_matrix::get_domain(); -template std::set> lean::static_matrix::get_domain(); -template std::set> lean::static_matrix >::get_domain(); +template std::set> lp::static_matrix::get_domain(); +template std::set> lp::static_matrix >::get_domain(); template double static_matrix::get_elem(unsigned int, unsigned int) const; template double static_matrix::get_max_abs_in_column(unsigned int) const; template double static_matrix::get_min_abs_in_column(unsigned int) const; @@ -51,7 +66,7 @@ template static_matrix::ref& static_matrix::ref::operator=(m template void static_matrix::set(unsigned int, unsigned int, mpq const&); template static_matrix::static_matrix(unsigned int, unsigned int); -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG template bool static_matrix >::is_correct() const; #endif template void static_matrix >::copy_column_to_indexed_vector(unsigned int, indexed_vector&) const; @@ -60,10 +75,10 @@ template void static_matrix >::init_empty_matrix(unsigned template void static_matrix >::set(unsigned int, unsigned int, mpq const&); -template bool lean::static_matrix::pivot_row_to_row_given_cell(unsigned int, column_cell &, unsigned int); -template bool lean::static_matrix::pivot_row_to_row_given_cell(unsigned int, column_cell& , unsigned int); -template bool lean::static_matrix >::pivot_row_to_row_given_cell(unsigned int, column_cell&, unsigned int); -template void lean::static_matrix >::remove_element(vector, true, unsigned int>&, lean::row_cell&); +template bool lp::static_matrix::pivot_row_to_row_given_cell(unsigned int, column_cell &, unsigned int); +template bool lp::static_matrix::pivot_row_to_row_given_cell(unsigned int, column_cell& , unsigned int); +template bool lp::static_matrix >::pivot_row_to_row_given_cell(unsigned int, column_cell&, unsigned int); +template void lp::static_matrix >::remove_element(vector, true, unsigned int>&, lp::row_cell&); } diff --git a/src/util/lp/tail_matrix.h b/src/util/lp/tail_matrix.h index c337b0933..37b217205 100644 --- a/src/util/lp/tail_matrix.h +++ b/src/util/lp/tail_matrix.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" @@ -10,10 +25,10 @@ #include "util/lp/lp_settings.h" // These matrices appear at the end of the list -namespace lean { +namespace lp { template class tail_matrix -#ifdef LEAN_DEBUG +#ifdef Z3DEBUG : public matrix #endif { diff --git a/src/util/lp/test_bound_analyzer.h b/src/util/lp/test_bound_analyzer.h index 262c610c7..30f2dd16a 100644 --- a/src/util/lp/test_bound_analyzer.h +++ b/src/util/lp/test_bound_analyzer.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" #include "util/lp/linear_combination_iterator.h" @@ -16,7 +31,7 @@ // In the same loop trying to pin variables by pushing the partial sum up, denoting the variable related to it by _l // here in addition we assume that all coefficient in the row are positive -namespace lean { +namespace lp { class test_bound_analyzer { linear_combination_iterator & m_it; @@ -74,7 +89,7 @@ public : void analyze_i_for_upper(unsigned i) { mpq l; bool strict = false; - lean_assert(is_zero(l)); + SASSERT(is_zero(l)); for (unsigned k = 0; k < m_index.size(); k++) { if (k == i) continue; @@ -165,7 +180,7 @@ public : void analyze_i_for_lower(unsigned i) { mpq l; - lean_assert(is_zero(l)); + SASSERT(is_zero(l)); bool strict = false; for (unsigned k = 0; k < m_index.size(); k++) { if (k == i) diff --git a/src/util/lp/ul_pair.h b/src/util/lp/ul_pair.h index 2e77a7db0..cbf511d90 100644 --- a/src/util/lp/ul_pair.h +++ b/src/util/lp/ul_pair.h @@ -1,7 +1,22 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ #pragma once #include "util/vector.h" @@ -10,7 +25,7 @@ #include #include "util/lp/column_info.h" -namespace lean { +namespace lp { enum lconstraint_kind { LE = -2, LT = -1 , GE = 2, GT = 1, EQ = 0 @@ -49,8 +64,8 @@ public: && m_upper_bound_witness == p.m_upper_bound_witness && m_i == p.m_i; } - // empty constructor - ul_pair() : + // empty constructor + ul_pair() : m_low_bound_witness(static_cast(-1)), m_upper_bound_witness(static_cast(-1)), m_i(static_cast(-1)) diff --git a/src/util/map.h b/src/util/map.h index d9dc4463c..3a59c8975 100644 --- a/src/util/map.h +++ b/src/util/map.h @@ -19,7 +19,7 @@ Revision History: #ifndef MAP_H_ #define MAP_H_ -#include"hashtable.h" +#include "util/hashtable.h" template struct _key_data { @@ -135,7 +135,7 @@ public: value const& get(key const& k, value const& default_value) const { entry* e = find_core(k); if (e) { - return e->get_data().m_value; + return e->get_data().m_value; } else { return default_value; diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index ec888c84b..340d3fee7 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -18,8 +18,8 @@ Notes: --*/ -#include "vector.h" -#include "uint_set.h" +#include "util/vector.h" +#include "util/uint_set.h" template @@ -92,7 +92,7 @@ public: m_next.reserve(std::max(src, dst) + 1); m_next.reserve(std::max(negate(src), negate(dst)) + 1); m_next[src].push_back(dst); - m_next[dst].push_back(src); + m_next[dst].push_back(src); } void cliques(unsigned_vector const& ps, vector& cliques) { @@ -104,7 +104,7 @@ public: max = std::max(max, std::max(np, p) + 1); } m_next.reserve(max); - m_tc.reserve(m_next.size()); + m_tc.reserve(m_next.size()); unsigned_vector clique; uint_set vars; for (unsigned i = 0; i < num_ps; ++i) { diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 76069ce44..44157aa65 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -7,10 +7,10 @@ Copyright (c) 2015 Microsoft Corporation #include #include #include -#include"trace.h" -#include"memory_manager.h" -#include"error_codes.h" -#include"z3_omp.h" +#include "util/trace.h" +#include "util/memory_manager.h" +#include "util/error_codes.h" +#include "util/z3_omp.h" // The following two function are automatically generated by the mk_make.py script. // The script collects ADD_INITIALIZER and ADD_FINALIZER commands in the .h files. // For example, rational.h contains diff --git a/src/util/memory_manager.h b/src/util/memory_manager.h index aac61ea2a..5aa512018 100644 --- a/src/util/memory_manager.h +++ b/src/util/memory_manager.h @@ -21,7 +21,7 @@ Revision History: #include #include -#include"z3_exception.h" +#include "util/z3_exception.h" #ifndef __has_builtin # define __has_builtin(x) 0 diff --git a/src/util/min_cut.cpp b/src/util/min_cut.cpp new file mode 100644 index 000000000..b7c30f546 --- /dev/null +++ b/src/util/min_cut.cpp @@ -0,0 +1,232 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + min_cut.cpp + +Abstract: + min cut solver + +Author: + Bernhard Gleiss + +Revision History: + + +--*/ +#include "util/min_cut.h" +#include "util/trace.h" + +min_cut::min_cut() { + // push back two empty vectors for source and sink + m_edges.push_back(edge_vector()); + m_edges.push_back(edge_vector()); +} + +unsigned min_cut::new_node() { + m_edges.push_back(edge_vector()); + return m_edges.size() - 1; +} + +void min_cut::add_edge(unsigned int i, unsigned int j, unsigned capacity) { + m_edges.reserve(i + 1); + m_edges[i].push_back(edge(j, capacity)); + TRACE("spacer.mincut", tout << "adding edge (" << i << "," << j << ")\n";); +} + +void min_cut::compute_min_cut(unsigned_vector& cut_nodes) { + if (m_edges.size() == 2) { + return; + } + + m_d.resize(m_edges.size()); + m_pred.resize(m_edges.size()); + + // compute initial distances and number of nodes + compute_initial_distances(); + + unsigned i = 0; + + while (m_d[0] < m_edges.size()) { + unsigned j = get_admissible_edge(i); + + if (j < m_edges.size()) { + // advance(i) + m_pred[j] = i; + i = j; + + // if i is the sink, augment path + if (i == 1) { + augment_path(); + i = 0; + } + } + else { + // retreat + compute_distance(i); + if (i != 0) { + i = m_pred[i]; + } + } + } + + // split nodes into reachable and unreachable ones + bool_vector reachable(m_edges.size()); + compute_reachable_nodes(reachable); + + // find all edges between reachable and unreachable nodes and + // for each such edge, add corresponding lemma to unsat-core + compute_cut_and_add_lemmas(reachable, cut_nodes); +} + +void min_cut::compute_initial_distances() { + unsigned_vector todo; + bool_vector visited(m_edges.size()); + + todo.push_back(0); // start at the source, since we do postorder traversel + + while (!todo.empty()) { + unsigned current = todo.back(); + + // if we haven't already visited current + if (!visited[current]) { + bool exists_unvisited_parent = false; + + // add unprocessed parents to stack for DFS. If there is at least + // one unprocessed parent, don't compute the result + // for current now, but wait until those unprocessed parents are processed + for (auto const& edge : m_edges[current]) { + unsigned parent = edge.node; + + // if we haven't visited the current parent yet + if (!visited[parent]) { + // add it to the stack + todo.push_back(parent); + exists_unvisited_parent = true; + } + } + + // if we already visited all parents, we can visit current too + if (!exists_unvisited_parent) { + visited[current] = true; + todo.pop_back(); + + compute_distance(current); // I.H. all parent distances are already computed + } + } + else { + todo.pop_back(); + } + } +} + +unsigned min_cut::get_admissible_edge(unsigned i) { + for (const auto& edge : m_edges[i]) { + if (edge.weight > 0 && m_d[i] == m_d[edge.node] + 1) { + return edge.node; + } + } + return m_edges.size(); // no element found +} + +void min_cut::augment_path() { + // find bottleneck capacity + unsigned max = std::numeric_limits::max(); + unsigned k = 1; + while (k != 0) { + unsigned l = m_pred[k]; + for (const auto& edge : m_edges[l]) { + if (edge.node == k) { + max = std::min(max, edge.weight); + } + } + k = l; + } + + k = 1; + while (k != 0) { + unsigned l = m_pred[k]; + + // decrease capacity + for (auto& edge : m_edges[l]) { + if (edge.node == k) { + edge.weight -= max; + } + } + // increase reverse flow + bool already_exists = false; + for (auto& edge : m_edges[k]) { + if (edge.node == l) { + already_exists = true; + edge.weight += max; + } + } + if (!already_exists) { + m_edges[k].push_back(edge(1, max)); + } + k = l; + } +} + +void min_cut::compute_distance(unsigned i) { + if (i == 1) { // sink node + m_d[1] = 0; + } + else { + unsigned min = std::numeric_limits::max(); + + // find edge (i,j) with positive residual capacity and smallest distance + for (const auto& edge : m_edges[i]) { + if (edge.weight > 0) { + min = std::min(min, m_d[edge.node] + 1); + } + } + m_d[i] = min; + } +} + +void min_cut::compute_reachable_nodes(bool_vector& reachable) { + unsigned_vector todo; + + todo.push_back(0); + while (!todo.empty()) { + unsigned current = todo.back(); + todo.pop_back(); + + if (!reachable[current]) { + reachable[current] = true; + + for (const auto& edge : m_edges[current]) { + if (edge.weight > 0) { + todo.push_back(edge.node); + } + } + } + } +} + +void min_cut::compute_cut_and_add_lemmas(bool_vector& reachable, unsigned_vector& cut_nodes) { + unsigned_vector todo; + bool_vector visited(m_edges.size()); + + todo.push_back(0); + while (!todo.empty()) { + unsigned current = todo.back(); + todo.pop_back(); + + if (!visited[current]) { + visited[current] = true; + + for (const auto& edge : m_edges[current]) { + unsigned successor = edge.node; + if (reachable[successor]) { + todo.push_back(successor); + } + else { + cut_nodes.push_back(successor); + } + } + } + } +} diff --git a/src/util/min_cut.h b/src/util/min_cut.h new file mode 100644 index 000000000..51a330126 --- /dev/null +++ b/src/util/min_cut.h @@ -0,0 +1,63 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + min_cut.h + +Abstract: + min cut solver + +Author: + Bernhard Gleiss + +Revision History: + + +--*/ + +#ifndef MIN_CUT_H_ +#define MIN_CUT_H_ + +#include "util/vector.h" + + +class min_cut { +public: + min_cut(); + + /* + \brief create a node + */ + unsigned new_node(); + + /* + \brief add an i -> j edge with (unit) capacity + */ + void add_edge(unsigned i, unsigned j, unsigned capacity = 1); + + /* + \brief produce a min cut between source node = 0 and target node = 1. + NB. the function changes capacities on edges. + */ + void compute_min_cut(unsigned_vector& cut_nodes); + +private: + + typedef svector bool_vector; + struct edge { unsigned node; unsigned weight; edge(unsigned n, unsigned w): node(n), weight(w) {} edge(): node(0), weight(0) {} }; + typedef svector edge_vector; + + vector m_edges; // map from node to all outgoing edges together with their weights (also contains "reverse edges") + unsigned_vector m_d; // approximation of distance from node to sink in residual graph + unsigned_vector m_pred; // predecessor-information for reconstruction of augmenting path + + void compute_initial_distances(); + unsigned get_admissible_edge(unsigned i); + void augment_path(); + void compute_distance(unsigned i); + void compute_reachable_nodes(bool_vector& reachable); + void compute_cut_and_add_lemmas(bool_vector& reachable, unsigned_vector& cut_nodes); +}; + +#endif diff --git a/src/util/mpbq.cpp b/src/util/mpbq.cpp index 1ff7fb04d..9fcd1b58f 100644 --- a/src/util/mpbq.cpp +++ b/src/util/mpbq.cpp @@ -25,7 +25,7 @@ Revision History: --*/ #include -#include"mpbq.h" +#include "util/mpbq.h" #ifdef Z3DEBUG #define MPBQ_DEBUG diff --git a/src/util/mpbq.h b/src/util/mpbq.h index a6c7ddbfa..61ef2b0e2 100644 --- a/src/util/mpbq.h +++ b/src/util/mpbq.h @@ -27,9 +27,9 @@ Revision History: #ifndef MPBQ_H_ #define MPBQ_H_ -#include"mpq.h" -#include"rational.h" -#include"vector.h" +#include "util/mpq.h" +#include "util/rational.h" +#include "util/vector.h" class mpbq { mpz m_num; diff --git a/src/util/mpbqi.h b/src/util/mpbqi.h index 0dc569525..924e1e121 100644 --- a/src/util/mpbqi.h +++ b/src/util/mpbqi.h @@ -19,8 +19,8 @@ Revision History: #ifndef MPBQI_H_ #define MPBQI_H_ -#include"mpbq.h" -#include"basic_interval.h" +#include "util/mpbq.h" +#include "util/basic_interval.h" class mpbqi_manager : public basic_interval_manager { typedef basic_interval_manager super; diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index e9d108cec..9e309a726 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -18,7 +18,7 @@ Revision History: --*/ #include #include -#include"mpf.h" +#include "util/mpf.h" mpf::mpf() : ebits(0), @@ -40,12 +40,6 @@ mpf::mpf(unsigned _ebits, unsigned _sbits): set(ebits, sbits); } -mpf::mpf(mpf const & other) { - // It is safe if the mpz numbers are small. - // I need it for resize method in vector. - // UNREACHABLE(); -} - mpf::~mpf() { } @@ -73,7 +67,7 @@ mpf_manager::~mpf_manager() { } void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, int value) { - COMPILE_TIME_ASSERT(sizeof(int) == 4); + static_assert(sizeof(int) == 4, "assume integers are 4 bytes"); o.sign = false; o.ebits = ebits; @@ -119,7 +113,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, double value) { // double === mpf(11, 53) - COMPILE_TIME_ASSERT(sizeof(double) == 8); + static_assert(sizeof(double) == 8, "doubles are 8 bytes"); uint64 raw; memcpy(&raw, &value, sizeof(double)); @@ -155,7 +149,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, double value) { void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, float value) { // single === mpf(8, 24) - COMPILE_TIME_ASSERT(sizeof(float) == 4); + static_assert(sizeof(float) == 4, "floats are 4 bytes"); unsigned int raw; memcpy(&raw, &value, sizeof(float)); @@ -556,8 +550,6 @@ void mpf_manager::add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mp SASSERT(exp_delta <= INT_MAX); scoped_mpz sticky_rem(m_mpz_manager); m_mpz_manager.machine_div_rem(b.significand(), m_powers2((int)exp_delta), b.significand(), sticky_rem); - if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(b.significand())) - m_mpz_manager.inc(b.significand()); TRACE("mpf_dbg", tout << "A' = " << m_mpz_manager.to_string(a.significand()) << std::endl;); TRACE("mpf_dbg", tout << "B' = " << m_mpz_manager.to_string(b.significand()) << std::endl;); @@ -566,10 +558,14 @@ void mpf_manager::add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mp if (sgn(a) != sgn(b)) { TRACE("mpf_dbg", tout << "SUBTRACTING" << std::endl;); m_mpz_manager.sub(a.significand(), b.significand(), o.significand); + if (!sticky_rem.is_zero() && m_mpz_manager.is_even(o.significand)) + m_mpz_manager.dec(o.significand); } else { TRACE("mpf_dbg", tout << "ADDING" << std::endl;); m_mpz_manager.add(a.significand(), b.significand(), o.significand); + if (!sticky_rem.is_zero() && m_mpz_manager.is_even(o.significand)) + m_mpz_manager.inc(o.significand); } TRACE("mpf_dbg", tout << "sum[-2:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl;); @@ -795,9 +791,9 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co set(o, z); } else if (is_zero(x) || is_zero(y)) { - bool xy_sgn = is_neg(x) ^ is_neg(y); - if (is_zero(z) && xy_sgn ^ is_neg(z)) - mk_zero(x.ebits, x.sbits, rm != MPF_ROUND_TOWARD_NEGATIVE, o); + bool xy_sgn = sgn(x) ^ sgn(y); + if (is_zero(z) && (xy_sgn ^ sgn(z))) + mk_zero(x.ebits, x.sbits, rm == MPF_ROUND_TOWARD_NEGATIVE, o); else set(o, z); } @@ -805,7 +801,7 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co o.ebits = x.ebits; o.sbits = x.sbits; - scoped_mpf mul_res(*this, x.ebits+2, 2*x.sbits); + scoped_mpf mr(*this); scoped_mpf a(*this, x.ebits, x.sbits), b(*this, x.ebits, x.sbits), c(*this, x.ebits, x.sbits); set(a, x); set(b, y); @@ -814,9 +810,12 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co unpack(b, true); unpack(c, true); - TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;); - TRACE("mpf_dbg", tout << "B = " << to_string(b) << std::endl;); - TRACE("mpf_dbg", tout << "C = " << to_string(c) << std::endl;); + TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl; + tout << "B = " << to_string(b) << std::endl; + tout << "C = " << to_string(c) << std::endl; + tout << "A = " << to_string_binary(a, 1, 0) << std::endl; + tout << "B = " << to_string_binary(b, 1, 0) << std::endl; + tout << "C = " << to_string_binary(c, 1, 0) << std::endl;); SASSERT(m_mpz_manager.lt(a.significand(), m_powers2(x.sbits))); SASSERT(m_mpz_manager.lt(b.significand(), m_powers2(x.sbits))); @@ -824,98 +823,127 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co SASSERT(m_mpz_manager.ge(a.significand(), m_powers2(x.sbits-1))); SASSERT(m_mpz_manager.ge(b.significand(), m_powers2(x.sbits-1))); - mul_res.get().sign = (a.sign() != b.sign()); - mul_res.get().exponent = a.exponent() + b.exponent(); - m_mpz_manager.mul(a.significand(), b.significand(), mul_res.get().significand); + // A/B in _1.[sbits-1]. + mr.set(x.ebits+2, 2*x.sbits-1, a.sign() != b.sign(), a.exponent() + b.exponent()); + m_mpz_manager.mul(a.significand(), b.significand(), mr.significand()); - TRACE("mpf_dbg", tout << "PRODUCT = " << to_string(mul_res) << std::endl;); + TRACE("mpf_dbg", tout << "M = " << to_string(mr) << std::endl; + tout << "M = " << to_string_binary(mr, 1, 0) << std::endl;); - // mul_res is [-1][0].[2*sbits - 2], i.e., between 2*sbits-1 and 2*sbits. - SASSERT(m_mpz_manager.lt(mul_res.significand(), m_powers2(2*x.sbits))); - SASSERT(m_mpz_manager.ge(mul_res.significand(), m_powers2(2*x.sbits - 2))); + // mul_res is [-1][0].[2*sbits - 2], i.e., >= 2^(2*sbits-2) and < 2^(2*sbits). + SASSERT(m_mpz_manager.lt(mr.significand(), m_powers2(2*x.sbits))); + SASSERT(m_mpz_manager.ge(mr.significand(), m_powers2(2*x.sbits - 2))); - // Introduce extra bits into c. - m_mpz_manager.mul2k(c.significand(), x.sbits-1, c.significand()); + // Introduce (sbits+3) extra bits into c in _[0].[sbits-1] s.t. c in _[0].[2*sbits-2] + c.set(x.ebits+2, 2*x.sbits-1+3, c.sign(), c.exponent(), c.significand()); + m_mpz_manager.mul2k(c.significand(), x.sbits - 1 + 3); + // And + 3 bits into mr as well. + mr.set(x.ebits + 2, 2 * x.sbits - 1 + 3, mr.sign(), mr.exponent(), mr.significand()); + m_mpz_manager.mul2k(mr.significand(), 3); - SASSERT(m_mpz_manager.lt(c.significand(), m_powers2(2 * x.sbits - 1))); + TRACE("mpf_dbg", tout << "C_= " << to_string(c) << std::endl; + tout << "C_= " << to_string_binary(c, 1, 0) << std::endl;); + + SASSERT(m_mpz_manager.lt(c.significand(), m_powers2(2*x.sbits + 3))); SASSERT(m_mpz_manager.is_zero(c.significand()) || - m_mpz_manager.ge(c.significand(), m_powers2(2 * x.sbits - 2))); + m_mpz_manager.ge(c.significand(), m_powers2(2*x.sbits - 2 + 3))); - TRACE("mpf_dbg", tout << "C = " << to_string(c) << std::endl;); - - if (exp(c) > exp(mul_res)) - mul_res.swap(c); - - mpf_exp_t exp_delta = exp(mul_res) - exp(c); - - SASSERT(exp(mul_res) >= exp(c) && exp_delta >= 0); - - if (exp_delta > 2 * x.sbits) - exp_delta = 2 * x.sbits; - TRACE("mpf_dbg", tout << "exp_delta = " << exp_delta << std::endl;); + if (exp(c) > exp(mr)) { + TRACE("mpf_dbg", tout << "Swap!" << std::endl;); + mr.swap(c); + } // Alignment shift with sticky bit computation. - scoped_mpz sticky_rem(m_mpz_manager); - m_mpz_manager.machine_div_rem(c.significand(), m_powers2((int)exp_delta), c.significand(), sticky_rem); - TRACE("mpf_dbg", tout << "alignment shift -> sig = " << m_mpz_manager.to_string(c.significand()) << - " sticky_rem = " << m_mpz_manager.to_string(sticky_rem) << std::endl;); - if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(c.significand())) - m_mpz_manager.inc(c.significand()); + mpf_exp_t exp_delta_w = exp(mr) - exp(c); + SASSERT(exp(mr) >= exp(c) && exp_delta_w >= 0); - TRACE("mpf_dbg", tout << "M' = " << m_mpz_manager.to_string(mul_res.significand()) << std::endl;); - TRACE("mpf_dbg", tout << "C' = " << m_mpz_manager.to_string(c.significand()) << std::endl;); + if (exp_delta_w > 2 * x.sbits + 3) + exp_delta_w = 2 * x.sbits + 3; + + unsigned exp_delta = (unsigned)exp_delta_w; + + scoped_mpz sticky_rem(m_mpz_manager); + m_mpz_manager.machine_div_rem(c.significand(), m_powers2(exp_delta), c.significand(), sticky_rem); + TRACE("mpf_dbg", tout << "alignment shift by delta=" << exp_delta << " -> sig = " << m_mpz_manager.to_string(c.significand()) << + " sticky_rem = " << m_mpz_manager.to_string(sticky_rem) << std::endl;); + bool alignment_sticky = !m_mpz_manager.is_zero(sticky_rem); + + TRACE("mpf_dbg", tout << "M'= " << m_mpz_manager.to_string(mr.significand()) << std::endl; + tout << "M'= " << to_string_binary(mr, 1, 0) << std::endl; ); + TRACE("mpf_dbg", tout << "C'= " << m_mpz_manager.to_string(c.significand()) << std::endl; + tout << "C'= " << to_string_binary(c, 1, 0) << std::endl; ); // Significand addition - if (sgn(mul_res) != sgn(c)) { + scoped_mpf res(mr); + + if (sgn(mr) != sgn(c)) { TRACE("mpf_dbg", tout << "SUBTRACTING" << std::endl;); - m_mpz_manager.sub(mul_res.significand(), c.significand(), o.significand); + m_mpz_manager.sub(mr.significand(), c.significand(), res.significand()); + + if (alignment_sticky && m_mpz_manager.is_even(res.significand())) + m_mpz_manager.dec(res.get().significand); + + if (m_mpz_manager.is_neg(res.significand())) { + m_mpz_manager.abs(res.significand()); + res.get().sign = !res.sign(); + } } else { TRACE("mpf_dbg", tout << "ADDING" << std::endl;); - m_mpz_manager.add(mul_res.significand(), c.significand(), o.significand); + m_mpz_manager.add(mr.significand(), c.significand(), res.significand()); + + if (alignment_sticky && m_mpz_manager.is_even(res.significand())) + m_mpz_manager.inc(res.get().significand); } - TRACE("mpf_dbg", tout << "sum[-1:] = " << m_mpz_manager.to_string(o.significand) << std::endl;); + TRACE("mpf_dbg", tout << "S'= " << m_mpz_manager.to_string(res.significand()) << std::endl; + tout << "S'= " << to_string_binary(res, 1, 0) << std::endl; ); - bool neg = m_mpz_manager.is_neg(o.significand); - TRACE("mpf_dbg", tout << "NEG=" << neg << std::endl;); - if (neg) m_mpz_manager.abs(o.significand); + // Renormalize + bool renorm_sticky = false; - o.exponent = mul_res.exponent(); - - unsigned extra = 0; - // Result could overflow into 4.xxx ... - SASSERT(m_mpz_manager.lt(o.significand, m_powers2(2 * x.sbits + 2))); - if(m_mpz_manager.ge(o.significand, m_powers2(2 * x.sbits + 1))) + SASSERT(m_mpz_manager.lt(res.significand(), m_powers2(2 * x.sbits + 1 + 3))); + if (m_mpz_manager.ge(res.significand(), m_powers2(2 * x.sbits + 3))) { - extra++; - o.exponent++; - TRACE("mpf_dbg", tout << "Addition overflew!" << std::endl;); + SASSERT(exp(res) < mk_max_exp(x.ebits)); // NYI. + + res.get().exponent++; + renorm_sticky = !m_mpz_manager.is_even(res.significand()); + m_mpz_manager.machine_div2k(res.significand(), 1); + TRACE("mpf_dbg", tout << "Add/Sub overflew into 4.xxx!" << std::endl; + tout << "S*= " << to_string_binary(res, 2, 0) << std::endl;); } - // Remove the extra bits, keeping a sticky bit. - m_mpz_manager.set(sticky_rem, 0); - unsigned minbits = (4 + extra); - if (o.sbits >= minbits) - m_mpz_manager.machine_div_rem(o.significand, m_powers2(o.sbits - minbits), o.significand, sticky_rem); - else - m_mpz_manager.mul2k(o.significand, minbits - o.sbits, o.significand); + mpf_exp_t min_exp = mk_min_exp(x.ebits); + unsigned sig_width = m_mpz_manager.prev_power_of_two(res.get().significand) + 1; + mpf_exp_t sig_lz = 2 * x.sbits + 3 - sig_width; + mpf_exp_t max_exp_delta = res.exponent() - min_exp; + unsigned renorm_delta = (unsigned) std::max((mpf_exp_t)0, std::min(sig_lz, max_exp_delta)); + res.get().exponent -= renorm_delta; + m_mpz_manager.mul2k(res.significand(), renorm_delta); - if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(o.significand)) + TRACE("mpf_dbg", tout << "R*= " << to_string_binary(res, 2, 0) << " (renormalized, delta=" << renorm_delta << ")" << std::endl;); + + set(o, x.ebits, x.sbits, res.sign(), res.exponent(), mpz(0)); + + if (x.sbits >= 4) { + m_mpz_manager.machine_div_rem(res.significand(), m_powers2(x.sbits - 4 + 3), o.significand, sticky_rem); + renorm_sticky |= !m_mpz_manager.is_zero(sticky_rem); + } + else { + m_mpz_manager.mul2k(res.significand(), 4 - x.sbits + 3, o.significand); + } + + if (renorm_sticky && m_mpz_manager.is_even(o.significand)) m_mpz_manager.inc(o.significand); - TRACE("mpf_dbg", tout << "sum[-1:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl;); + TRACE("mpf_dbg", tout << "sum[-1:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl; + tout << "R = " << to_string_binary(o, 1, 3) << std::endl;); if (m_mpz_manager.is_zero(o.significand)) mk_zero(x.ebits, x.sbits, rm == MPF_ROUND_TOWARD_NEGATIVE, o); - else { - o.sign = ((!mul_res.sign() && c.sign() && neg) || - ( mul_res.sign() && !c.sign() && !neg) || - ( mul_res.sign() && c.sign())); - TRACE("mpf_dbg", tout << "before round = " << to_string(o) << std::endl << - "fs[-1:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl;); + else round(rm, o); - } } } @@ -1183,12 +1211,18 @@ void mpf_manager::to_sbv_mpq(mpf_rounding_mode rm, const mpf & x, scoped_mpq & o default: UNREACHABLE(); } if (inc) m_mpz_manager.inc(z); + TRACE("mpf_dbg_sbv", + tout << "SBV: (" << to_string(x) << ") == " << m_mpq_manager.to_string(z) << std::endl; + tout << "sign=" << t.sign() << " last=" << last << " round=" << round << + " sticky=" << sticky << " inc=" << inc << std::endl; ); } else m_mpz_manager.mul2k(z, (unsigned) e); m_mpq_manager.set(o, z); if (x.sign) m_mpq_manager.neg(o); + + TRACE("mpf_dbg", tout << "SBV = " << m_mpq_manager.to_string(o) << std::endl;); } void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) { @@ -1214,6 +1248,8 @@ void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) { m_mpz_manager.mul2k(o, sbits - 1); m_mpz_manager.add(o, sig(x), o); } + + TRACE("mpf_dbg", tout << "IEEE_BV = " << m_mpz_manager.to_string(o) << std::endl;); } void mpf_manager::renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, mpz & sig) { @@ -1596,6 +1632,66 @@ std::string mpf_manager::to_string_hexfloat(mpf const & x) { return ss.str(); } +std::string mpf_manager::to_string_binary(mpf const & x, unsigned upper_extra, unsigned lower_extra) { + std::string res; + + if (is_nan(x)) + res = std::string("") + "#b0 " + + "#b" + std::string(x.ebits, '1') + " " + + "#b" + std::string(x.sbits-2, '0') + "1 " + + "(NaN)"; + else if (is_inf(x)) + res = std::string("") + "#b" + (sgn(x)?"1":"0") + " " + + "#b" + std::string(x.ebits, '1') + " " + + "#b" + std::string(x.sbits - 1, '0') + "1 " + + "(" + (sgn(x)?"-":"+") + "oo)"; + else if (is_zero(x)) + res = std::string("") + "#b" + (sgn(x) ? "1" : "0") + " " + + "#b" + std::string(x.ebits, '0') + " " + + "#b" + std::string(x.sbits - 1, '0') + " " + + "(" + (sgn(x) ? "-" : "+") + "zero)"; + else { + SASSERT(m_mpz_manager.is_nonneg(sig(x))); + + res = std::string("") + "#b" + (sgn(x) ? "1" : "0") + " "; + + scoped_mpz tmp(m_mpz_manager); + + if (is_denormal(x)) + m_mpz_manager.set(tmp, bias_exp(x.ebits, mk_min_exp(x.ebits))); + else { + m_mpz_manager.set(tmp, bias_exp(x.ebits, exp(x))); + } + + std::string tmp_str = ""; + for (unsigned i = 0; i < x.ebits; i++) { + tmp_str += m_mpz_manager.is_odd(tmp) ? "1" : "0"; + tmp /= 2; + } + std::reverse(tmp_str.begin(), tmp_str.end()); + res += "#b" + tmp_str + " "; + + tmp_str = ""; + m_mpz_manager.set(tmp, sig(x)); + unsigned num_bits = upper_extra + x.sbits + lower_extra; + for (unsigned i = 0; i < num_bits || !tmp.is_zero(); i++) { + tmp_str += m_mpz_manager.is_odd(tmp) ? "1" : "0"; + tmp /= 2; + if (i == lower_extra - 1) + tmp_str += ","; + if (i == x.sbits + lower_extra - 2) { + tmp_str += "."; + if (i == num_bits - 1) + tmp_str += " "; + } + } + std::reverse(tmp_str.begin(), tmp_str.end()); + res += "#b" + tmp_str; + } + + return res; +} + void mpf_manager::to_rational(mpf const & x, unsynch_mpq_manager & qm, mpq & o) { scoped_mpf a(*this); scoped_mpz n(m_mpq_manager), d(m_mpq_manager); @@ -1865,139 +1961,76 @@ void mpf_manager::mk_round_inf(mpf_rounding_mode rm, mpf & o) { } void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { - // Assumptions: o.significand is of the form f[-1:0] . f[1:sbits-1] [guard,round,sticky], + // Assumptions: o.significand is of the form f[-1:0] . f[1:sbits-1] [round,extra,sticky], // i.e., it has 2 + (sbits-1) + 3 = sbits + 4 bits. - TRACE("mpf_dbg", tout << "RND: " << to_string(o) << std::endl;); + TRACE("mpf_dbg", tout << "RND: " << to_string(o) << std::endl; + tout << to_string_binary(o, 1, 3) << std::endl;); DEBUG_CODE({ - const mpz & p_m3 = m_powers2(o.sbits+5); + const mpz & p_m3 = m_powers2(o.sbits+4); SASSERT(m_mpz_manager.lt(o.significand, p_m3)); }); - // Structure of the rounder: - // (s, e_out, f_out) == (s, exprd(s, post(e, sigrd(s, f)))). + mpf_exp_t e_max = mk_max_exp(o.ebits); + mpf_exp_t e_min = mk_min_exp(o.ebits); - bool UNFen = false; // Are these supposed to be persistent flags accross calls? - bool OVFen = false; + unsigned sig_width = m_mpz_manager.prev_power_of_two(o.significand) + 1; + mpf_exp_t lz = o.sbits + 4 - sig_width; + mpf_exp_t beta = o.exponent - lz + 1; - mpf_exp_t e_max_norm = mk_max_exp(o.ebits); - mpf_exp_t e_min_norm = mk_min_exp(o.ebits); - scoped_mpz temporary(m_mpq_manager); + scoped_mpz sigma(m_mpz_manager); - TRACE("mpf_dbg", tout << "e_min_norm = " << e_min_norm << std::endl << - "e_max_norm = " << e_max_norm << std::endl;); - - const mpz & p_m1 = m_powers2(o.sbits+2); - const mpz & p_m2 = m_powers2(o.sbits+3); - (void)p_m1; - - TRACE("mpf_dbg", tout << "p_m1 = " << m_mpz_manager.to_string(p_m1) << std::endl << - "p_m2 = " << m_mpz_manager.to_string(p_m2) << std::endl;); - - bool OVF1 = o.exponent > e_max_norm || // Exponent OVF - (o.exponent == e_max_norm && m_mpz_manager.ge(o.significand, p_m2)); - - TRACE("mpf_dbg", tout << "OVF1 = " << OVF1 << std::endl;); - - int lz = 0; - scoped_mpz t(m_mpq_manager); - m_mpz_manager.set(t, p_m2); - while (m_mpz_manager.gt(t, o.significand)) { - m_mpz_manager.machine_div2k(t, 1); - lz++; + if (beta < e_min) { + // denormal significand/TINY + m_mpz_manager.set(sigma, o.exponent - e_min); + o.exponent = e_min; + } + else { + m_mpz_manager.set(sigma, lz - 1); + o.exponent = beta; } - TRACE("mpf_dbg", tout << "LZ = " << lz << std::endl;); + scoped_mpz sigma_cap(m_mpz_manager); + sigma_cap = o.sbits + 2; + m_mpz_manager.neg(sigma_cap); + if (m_mpz_manager.lt(sigma, sigma_cap)) + m_mpz_manager.set(sigma, sigma_cap); - m_mpz_manager.set(t, o.exponent); - m_mpz_manager.inc(t); - m_mpz_manager.sub(t, lz, t); - m_mpz_manager.set(temporary, e_min_norm); - m_mpz_manager.sub(t, temporary, t); - bool TINY = m_mpz_manager.is_neg(t); - - TRACE("mpf_dbg", tout << "TINY = " << TINY << std::endl;); - - mpf_exp_t alpha = 3 << (o.ebits-2); - mpf_exp_t beta = o.exponent - lz + 1; - - TRACE("mpf_dbg", tout << "alpha = " << alpha << std::endl << - "beta = " << beta << std::endl; ); - - scoped_mpz sigma(m_mpq_manager); - sigma = 0; - - if (TINY && !UNFen) { - m_mpz_manager.set(sigma, o.exponent); - m_mpz_manager.sub(sigma, temporary, sigma); - m_mpz_manager.inc(sigma); - } - else - m_mpz_manager.set(sigma, lz); - - scoped_mpz limit(m_mpq_manager); - limit = o.sbits + 2; - m_mpz_manager.neg(limit); - if (m_mpz_manager.lt(sigma, limit)) { - m_mpz_manager.set(sigma, limit); - } + TRACE("mpf_dbg", tout << "e_min_norm = " << e_min << std::endl; + tout << "e_max_norm = " << e_max << std::endl; + tout << "beta = " << beta << ", (beta < e_min) = " << (beta < e_min) << std::endl; + tout << "LZ = " << lz << std::endl; + tout << "sigma = " << m_mpz_manager.to_string(sigma) << std::endl; + tout << "sigma_cap = " << m_mpz_manager.to_string(sigma_cap) << std::endl;); // Normalization shift TRACE("mpf_dbg", tout << "Shift distance: " << m_mpz_manager.to_string(sigma) << " " << ((m_mpz_manager.is_nonneg(sigma))?"(LEFT)":"(RIGHT)") << std::endl;); - bool sticky = !m_mpz_manager.is_even(o.significand); - m_mpz_manager.machine_div2k(o.significand, 1); // Let f' = f_r/2 - - if (!m_mpz_manager.is_zero(sigma)) { - if (m_mpz_manager.is_neg(sigma)) { // Right shift - unsigned sigma_uint = (unsigned) -m_mpz_manager.get_int64(sigma); // sigma is capped, this is safe. - if (sticky) - m_mpz_manager.machine_div2k(o.significand, sigma_uint); - else - { - scoped_mpz sticky_rem(m_mpz_manager); - m_mpz_manager.machine_div_rem(o.significand, m_powers2(sigma_uint), o.significand, sticky_rem); - sticky = !m_mpz_manager.is_zero(sticky_rem); - } - } - else { // Left shift - unsigned sh_m = static_cast(m_mpz_manager.get_int64(sigma)); - m_mpz_manager.mul2k(o.significand, sh_m, o.significand); - m_mpz_manager.set(sigma, 0); - } + if (m_mpz_manager.le(sigma, -1)) { + // Right shift + scoped_mpz sticky_rem(m_mpz_manager); + unsigned nsigma_uint = (unsigned)-m_mpz_manager.get_int64(sigma); // sigma is capped, this is safe. + m_mpz_manager.machine_div_rem(o.significand, m_powers2(nsigma_uint), o.significand, sticky_rem); + bool sticky = !m_mpz_manager.is_zero(sticky_rem); + if (sticky && m_mpz_manager.is_even(o.significand)) + m_mpz_manager.inc(o.significand); + } + else { + // Left shift + unsigned sigma_uint = static_cast(m_mpz_manager.get_int64(sigma)); + m_mpz_manager.mul2k(o.significand, sigma_uint, o.significand); } - TRACE("mpf_dbg", tout << "Before sticky: " << to_string(o) << std::endl;); - - // Make sure o.significand is a [sbits+2] bit number (i.e. f1[0:sbits+1] == f1[0:sbits-1][round][sticky]) - sticky = sticky || !m_mpz_manager.is_even(o.significand); - m_mpz_manager.machine_div2k(o.significand, 1); - if (sticky && m_mpz_manager.is_even(o.significand)) - m_mpz_manager.inc(o.significand); - - if (OVF1 && OVFen) { - o.exponent = beta; - o.exponent -= alpha; - } - else if (TINY && UNFen) { - o.exponent = beta; - o.exponent += alpha; - } - else if (TINY && !UNFen) - o.exponent = e_min_norm; - else - o.exponent = beta; - - TRACE("mpf_dbg", tout << "Shifted: " << to_string(o) << std::endl;); - - const mpz & p_sig = m_powers2(o.sbits); - SASSERT(TINY || (m_mpz_manager.ge(o.significand, p_sig))); + TRACE("mpf_dbg", tout << "Shifted: " << to_string(o) << std::endl; + tout << to_string_binary(o, 1, 3) << std::endl;); // Significand rounding (sigrd) - sticky = !m_mpz_manager.is_even(o.significand); // new sticky bit! + bool sticky = !m_mpz_manager.is_even(o.significand); + m_mpz_manager.machine_div2k(o.significand, 1); + sticky = sticky || !m_mpz_manager.is_even(o.significand); m_mpz_manager.machine_div2k(o.significand, 1); bool round = !m_mpz_manager.is_even(o.significand); m_mpz_manager.machine_div2k(o.significand, 1); @@ -2012,56 +2045,47 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { bool inc = false; switch (rm) { case MPF_ROUND_NEAREST_TEVEN: inc = round && (last || sticky); break; - // case MPF_ROUND_NEAREST_TAWAY: inc = round; break; // CMW: Check - case MPF_ROUND_NEAREST_TAWAY: inc = round && (!last || sticky); break; // CMW: Fix ok? + case MPF_ROUND_NEAREST_TAWAY: inc = round && (!last || sticky); break; case MPF_ROUND_TOWARD_POSITIVE: inc = (!o.sign && (round || sticky)); break; case MPF_ROUND_TOWARD_NEGATIVE: inc = (o.sign && (round || sticky)); break; case MPF_ROUND_TOWARD_ZERO: inc = false; break; default: UNREACHABLE(); } - if (inc) { - TRACE("mpf_dbg", tout << "Rounding increment -> significand +1" << std::endl;); + TRACE("mpf_dbg", tout << "Rounding increment -> significand +" << (int)inc << std::endl;); + if (inc) m_mpz_manager.inc(o.significand); - } - else - TRACE("mpf_dbg", tout << "Rounding increment -> significand +0" << std::endl;); TRACE("mpf_dbg", tout << "Rounded significand: " << to_string(o) << std::endl;); - bool SIGovf = false; - // Post normalization (post) + const mpz & p_sig = m_powers2(o.sbits); if (m_mpz_manager.ge(o.significand, p_sig)) { m_mpz_manager.machine_div2k(o.significand, 1); o.exponent++; } - if (o.exponent > e_max_norm) - SIGovf = true; - + bool SIGovf = o.exponent > e_max; TRACE("mpf_dbg", tout << "Post-normalized: " << to_string(o) << std::endl;); - TRACE("mpf_dbg", tout << "SIGovf = " << SIGovf << std::endl;); // Exponent rounding (exprd) - bool o_has_max_exp = (o.exponent > e_max_norm); + bool o_has_max_exp = (o.exponent > e_max); bool OVF2 = SIGovf && o_has_max_exp; TRACE("mpf_dbg", tout << "OVF2 = " << OVF2 << std::endl;); TRACE("mpf_dbg", tout << "o_has_max_exp = " << o_has_max_exp << std::endl;); - if (!OVFen && OVF2) + if (OVF2) mk_round_inf(rm, o); else { const mpz & p = m_powers2(o.sbits-1); - TRACE("mpf_dbg", tout << "P: " << m_mpz_manager.to_string(p_m1) << std::endl;); if (m_mpz_manager.ge(o.significand, p)) { TRACE("mpf_dbg", tout << "NORMAL: " << m_mpz_manager.to_string(o.significand) << std::endl;); - m_mpz_manager.sub(o.significand, p, o.significand); + m_mpz_manager.sub(o.significand, p, o.significand); // Strips the hidden bit. } else { TRACE("mpf_dbg", tout << "DENORMAL: " << m_mpz_manager.to_string(o.significand) << std::endl;); @@ -2069,7 +2093,8 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { } } - TRACE("mpf_dbg", tout << "ROUNDED = " << to_string(o) << std::endl;); + TRACE("mpf_dbg", tout << "ROUNDED = " << to_string(o) << std::endl; + tout << to_string_binary(o, -1, 0) << " (hidden bit, unbiased exp)." << std::endl;); } void mpf_manager::round_sqrt(mpf_rounding_mode rm, mpf & o) { diff --git a/src/util/mpf.h b/src/util/mpf.h index 31523c3ed..e679be558 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -20,12 +20,12 @@ Revision History: #define MPF_H_ #include -#include"mpz.h" -#include"mpq.h" -#include"map.h" -#include"scoped_numeral.h" -#include"scoped_numeral_vector.h" -#include"hash.h" +#include "util/mpz.h" +#include "util/mpq.h" +#include "util/map.h" +#include "util/scoped_numeral.h" +#include "util/scoped_numeral_vector.h" +#include "util/hash.h" typedef enum { MPF_ROUND_NEAREST_TEVEN, @@ -50,7 +50,12 @@ class mpf { public: mpf(); mpf(unsigned ebits, unsigned sbits); - mpf(mpf const & other); + mpf(mpf && other) : + ebits(other.ebits), + sbits(other.sbits), + sign(other.sign), + significand(std::move(other.significand)), + exponent(other.exponent) {} ~mpf(); unsigned get_ebits() const { return ebits; } unsigned get_sbits() const { return sbits; } @@ -285,8 +290,9 @@ protected: }; std::string to_string_raw(mpf const & a); - std::string to_string_hexfloat(mpf const & a); + std::string to_string_hexfloat(mpf const & a); std::string to_string_hexfloat(bool sgn, mpf_exp_t exp, scoped_mpz const & sig, unsigned ebits, unsigned sbits, unsigned rbits); + std::string to_string_binary(mpf const & x, unsigned upper_extra, unsigned lower_extra); public: powers2 m_powers2; }; @@ -299,6 +305,19 @@ class scoped_mpf : public _scoped_numeral { mpf_exp_t exponent() const { return get().exponent; } unsigned sbits() const { return get().sbits; } void set(unsigned ebits, unsigned sbits) { get().set(ebits, sbits); } + void set(unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exp, mpz & significand) { + get().set(ebits, sbits); + get().exponent = exp; + get().sign = sign; + if (&get().significand != &significand) + m().mpz_manager().set(get().significand, significand); + } + void set(unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exp) { + get().set(ebits, sbits); + get().exponent = exp; + get().sign = sign; + m().mpz_manager().set(get().significand, 0); + } public: scoped_mpf(mpf_manager & m):_scoped_numeral(m) {} scoped_mpf(scoped_mpf const & n):_scoped_numeral(n) {} diff --git a/src/util/mpff.cpp b/src/util/mpff.cpp index d26b3743c..eac9cc80c 100644 --- a/src/util/mpff.cpp +++ b/src/util/mpff.cpp @@ -20,15 +20,15 @@ Revision History: --*/ #include #include -#include"mpff.h" -#include"mpn.h" -#include"mpz.h" -#include"mpq.h" -#include"bit_util.h" -#include"trace.h" +#include "util/mpff.h" +#include "util/mpn.h" +#include "util/mpz.h" +#include "util/mpq.h" +#include "util/bit_util.h" +#include "util/trace.h" -COMPILE_TIME_ASSERT(sizeof(mpn_digit) == sizeof(unsigned)); -COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); +static_assert(sizeof(mpn_digit) == sizeof(unsigned), ""); +static_assert(sizeof(unsigned) == 4, "unsigned haven't changed size for a while"); // MIN_MSW is an shorthand for 0x8000..00, i.e., the minimal most significand word. #define MIN_MSW (1u << (sizeof(unsigned) * 8 - 1)) diff --git a/src/util/mpff.h b/src/util/mpff.h index eadfa0390..4fdd0baef 100644 --- a/src/util/mpff.h +++ b/src/util/mpff.h @@ -23,13 +23,13 @@ Revision History: #ifndef MPFF_H_ #define MPFF_H_ -#include"id_gen.h" -#include"util.h" -#include"vector.h" -#include"z3_exception.h" -#include"scoped_numeral.h" -#include"scoped_numeral_vector.h" -#include"mpn.h" +#include "util/id_gen.h" +#include "util/util.h" +#include "util/vector.h" +#include "util/z3_exception.h" +#include "util/scoped_numeral.h" +#include "util/scoped_numeral_vector.h" +#include "util/mpn.h" class mpff_manager; diff --git a/src/util/mpfx.cpp b/src/util/mpfx.cpp index 41ed93617..24ef4dc73 100644 --- a/src/util/mpfx.cpp +++ b/src/util/mpfx.cpp @@ -18,12 +18,12 @@ Revision History: --*/ #include #include -#include"mpfx.h" -#include"mpn.h" -#include"mpz.h" -#include"mpq.h" -#include"bit_util.h" -#include"trace.h" +#include "util/mpfx.h" +#include "util/mpn.h" +#include "util/mpz.h" +#include "util/mpq.h" +#include "util/bit_util.h" +#include "util/trace.h" mpfx_manager::mpfx_manager(unsigned int_sz, unsigned frac_sz, unsigned initial_capacity) { SASSERT(initial_capacity > 0); diff --git a/src/util/mpfx.h b/src/util/mpfx.h index 55242bdf8..98f9bb322 100644 --- a/src/util/mpfx.h +++ b/src/util/mpfx.h @@ -19,13 +19,13 @@ Revision History: #ifndef MPFX_H_ #define MPFX_H_ -#include"id_gen.h" -#include"util.h" -#include"vector.h" -#include"z3_exception.h" -#include"scoped_numeral.h" -#include"scoped_numeral_vector.h" -#include"mpn.h" +#include "util/id_gen.h" +#include "util/util.h" +#include "util/vector.h" +#include "util/z3_exception.h" +#include "util/scoped_numeral.h" +#include "util/scoped_numeral_vector.h" +#include "util/mpn.h" class mpfx_manager; diff --git a/src/util/mpn.cpp b/src/util/mpn.cpp index df69ce76d..2059ea6fd 100644 --- a/src/util/mpn.cpp +++ b/src/util/mpn.cpp @@ -16,15 +16,15 @@ Author: Revision History: --*/ -#include"debug.h" -#include"trace.h" -#include"buffer.h" -#include"mpn.h" +#include "util/debug.h" +#include "util/trace.h" +#include "util/buffer.h" +#include "util/mpn.h" #define max(a,b) (((a) > (b)) ? (a) : (b)) typedef uint64 mpn_double_digit; -COMPILE_TIME_ASSERT(sizeof(mpn_double_digit) == 2 * sizeof(mpn_digit)); +static_assert(sizeof(mpn_double_digit) == 2 * sizeof(mpn_digit), "size alignment"); const mpn_digit mpn_manager::zero = 0; diff --git a/src/util/mpn.h b/src/util/mpn.h index 1f0e2acab..a5d3c30d8 100644 --- a/src/util/mpn.h +++ b/src/util/mpn.h @@ -20,9 +20,9 @@ Revision History: #define MPN_H_ #include -#include"util.h" -#include"buffer.h" -#include"z3_omp.h" +#include "util/util.h" +#include "util/buffer.h" +#include "util/z3_omp.h" typedef unsigned int mpn_digit; diff --git a/src/util/mpq.cpp b/src/util/mpq.cpp index feb051033..bc6f99213 100644 --- a/src/util/mpq.cpp +++ b/src/util/mpq.cpp @@ -16,9 +16,9 @@ Author: Revision History: --*/ -#include"mpq.h" -#include"warning.h" -#include"z3_exception.h" +#include "util/mpq.h" +#include "util/warning.h" +#include "util/z3_exception.h" template mpq_manager::mpq_manager() { diff --git a/src/util/mpq.h b/src/util/mpq.h index 11e17bbf9..fd0ae13d4 100644 --- a/src/util/mpq.h +++ b/src/util/mpq.h @@ -19,8 +19,8 @@ Revision History: #ifndef MPQ_H_ #define MPQ_H_ -#include"mpz.h" -#include"trace.h" +#include "util/mpz.h" +#include "util/trace.h" class mpq { mpz m_num; @@ -31,11 +31,10 @@ class mpq { public: mpq(int v):m_num(v), m_den(1) {} mpq():m_den(1) {} + mpq(mpq && other) : m_num(std::move(other.m_num)), m_den(std::move(other.m_den)) {} void swap(mpq & other) { m_num.swap(other.m_num); m_den.swap(other.m_den); } mpz const & numerator() const { return m_num; } mpz const & denominator() const { return m_den; } - - double get_double() const; }; inline void swap(mpq & m1, mpq & m2) { m1.swap(m2); } @@ -745,6 +744,12 @@ public: reset_denominator(a); } + mpq dup(const mpq & source) { + mpq temp; + set(temp, source); + return temp; + } + void swap(mpz & a, mpz & b) { mpz_manager::swap(a, b); } void swap(mpq & a, mpq & b) { diff --git a/src/util/mpq_inf.cpp b/src/util/mpq_inf.cpp index 19289b737..c6c160941 100644 --- a/src/util/mpq_inf.cpp +++ b/src/util/mpq_inf.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"mpq_inf.h" +#include "util/mpq_inf.h" template std::string mpq_inf_manager::to_string(mpq_inf const & a) { diff --git a/src/util/mpq_inf.h b/src/util/mpq_inf.h index b041b6d4f..7b866994d 100644 --- a/src/util/mpq_inf.h +++ b/src/util/mpq_inf.h @@ -19,8 +19,8 @@ Revision History: #ifndef MPQ_INF_H_ #define MPQ_INF_H_ -#include"mpq.h" -#include"hash.h" +#include "util/mpq.h" +#include "util/hash.h" typedef std::pair mpq_inf; diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 7dca14bfa..7ad472ef1 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -17,14 +17,14 @@ Revision History: --*/ #include -#include"mpz.h" -#include"buffer.h" -#include"trace.h" -#include"hash.h" -#include"bit_util.h" +#include "util/mpz.h" +#include "util/buffer.h" +#include "util/trace.h" +#include "util/hash.h" +#include "util/bit_util.h" #if defined(_MP_INTERNAL) -#include"mpn.h" +#include "util/mpn.h" #elif defined(_MP_GMP) #include #else @@ -558,14 +558,13 @@ void mpz_manager::big_rem(mpz const & a, mpz const & b, mpz & c) { template void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { - if (is_small(a) && is_small(b)) { + static_assert(sizeof(a.m_val) == sizeof(int), "size mismatch"); + if (is_small(a) && is_small(b) && a.m_val != INT_MIN && b.m_val != INT_MIN) { int _a = a.m_val; int _b = b.m_val; if (_a < 0) _a = -_a; if (_b < 0) _b = -_b; unsigned r = u_gcd(_a, _b); - // Remark: r is (INT_MAX + 1) - // If a == b == INT_MIN set(c, r); } else { @@ -725,7 +724,7 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { #ifdef LEHMER_GCD // For now, it only works if sizeof(digit_t) == sizeof(unsigned) - COMPILE_TIME_ASSERT(sizeof(digit_t) == sizeof(unsigned)); + static_assert(sizeof(digit_t) == sizeof(unsigned), ""); int64 a_hat, b_hat, A, B, C, D, T, q, a_sz, b_sz; mpz a1, b1, t, r, tmp; @@ -1755,7 +1754,7 @@ void mpz_manager::mul2k(mpz & a, unsigned k) { } #ifndef _MP_GMP -COMPILE_TIME_ASSERT(sizeof(digit_t) == 4 || sizeof(digit_t) == 8); +static_assert(sizeof(digit_t) == 4 || sizeof(digit_t) == 8, ""); #endif template @@ -1822,7 +1821,7 @@ unsigned mpz_manager::log2(mpz const & a) { if (is_small(a)) return ::log2((unsigned)a.m_val); #ifndef _MP_GMP - COMPILE_TIME_ASSERT(sizeof(digit_t) == 8 || sizeof(digit_t) == 4); + static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, ""); mpz_cell * c = a.m_ptr; unsigned sz = c->m_size; digit_t * ds = c->m_digits; @@ -1844,7 +1843,7 @@ unsigned mpz_manager::mlog2(mpz const & a) { if (is_small(a)) return ::log2((unsigned)-a.m_val); #ifndef _MP_GMP - COMPILE_TIME_ASSERT(sizeof(digit_t) == 8 || sizeof(digit_t) == 4); + static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, ""); mpz_cell * c = a.m_ptr; unsigned sz = c->m_size; digit_t * ds = c->m_digits; diff --git a/src/util/mpz.h b/src/util/mpz.h index c02ac7c36..f04430e17 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -21,13 +21,13 @@ Revision History: #include #include -#include"util.h" -#include"small_object_allocator.h" -#include"trace.h" -#include"scoped_numeral.h" -#include"scoped_numeral_vector.h" -#include"z3_omp.h" -#include"mpn.h" +#include "util/util.h" +#include "util/small_object_allocator.h" +#include "util/trace.h" +#include "util/scoped_numeral.h" +#include "util/scoped_numeral_vector.h" +#include "util/z3_omp.h" +#include "util/mpn.h" unsigned u_gcd(unsigned u, unsigned v); uint64 u64_gcd(uint64 u, uint64 v); @@ -94,6 +94,9 @@ class mpz { public: mpz(int v):m_val(v), m_ptr(0) {} mpz():m_val(0), m_ptr(0) {} + mpz(mpz && other) : m_val(other.m_val), m_ptr(0) { + std::swap(m_ptr, other.m_ptr); + } void swap(mpz & other) { std::swap(m_val, other.m_val); std::swap(m_ptr, other.m_ptr); @@ -668,6 +671,12 @@ public: } } + void set(mpz & target, mpz && source) { + del(target); + target.m_val = source.m_val; + std::swap(target.m_ptr, source.m_ptr); + } + void set(mpz & a, int val) { del(a); a.m_val = val; @@ -700,6 +709,12 @@ public: void set(mpz & target, unsigned sz, digit_t const * digits); + mpz dup(const mpz & source) { + mpz temp; + set(temp, source); + return temp; + } + void reset(mpz & a) { del(a); a.m_val = 0; diff --git a/src/util/mpzzp.h b/src/util/mpzzp.h index 812b6e1bc..a30eff7b6 100644 --- a/src/util/mpzzp.h +++ b/src/util/mpzzp.h @@ -26,7 +26,7 @@ Revision History: #ifndef MPZZP_H_ #define MPZZP_H_ -#include "mpz.h" +#include "util/mpz.h" class mpzzp_manager { typedef unsynch_mpz_manager numeral_manager; diff --git a/src/util/nat_set.h b/src/util/nat_set.h index dcde26034..6e9ab1b6d 100644 --- a/src/util/nat_set.h +++ b/src/util/nat_set.h @@ -20,7 +20,7 @@ Revision History: #define NAT_SET_H_ #include -#include"vector.h" +#include "util/vector.h" class nat_set { unsigned m_curr_timestamp; diff --git a/src/util/numeral_buffer.h b/src/util/numeral_buffer.h index 3c2ea0f05..eee415efb 100644 --- a/src/util/numeral_buffer.h +++ b/src/util/numeral_buffer.h @@ -19,7 +19,7 @@ Revision History: #ifndef NUMERAL_BUFFER_H_ #define NUMERAL_BUFFER_H_ -#include"vector.h" +#include "util/vector.h" template class numeral_buffer { diff --git a/src/util/obj_hashtable.h b/src/util/obj_hashtable.h index 2720f1b00..df279383b 100644 --- a/src/util/obj_hashtable.h +++ b/src/util/obj_hashtable.h @@ -19,8 +19,8 @@ Revision History: #ifndef OBJ_HASHTABLE_H_ #define OBJ_HASHTABLE_H_ -#include"hash.h" -#include"hashtable.h" +#include "util/hash.h" +#include "util/hashtable.h" /** @@ -69,6 +69,10 @@ public: m_key(k), m_value(v) { } + key_data(Key * k, Value && v) : + m_key(k), + m_value(std::move(v)) { + } Value const & get_value() const { return m_value; } Key & get_key () const { return *m_key; } unsigned hash() const { return m_key->hash(); } @@ -86,7 +90,7 @@ public: bool is_used() const { return m_data.m_key != reinterpret_cast(0) && m_data.m_key != reinterpret_cast(1); } key_data const & get_data() const { return m_data; } key_data & get_data() { return m_data; } - void set_data(key_data const & d) { m_data = d; } + void set_data(key_data && d) { m_data = std::move(d); } void set_hash(unsigned h) { SASSERT(h == m_data.hash()); } void mark_as_deleted() { m_data.m_key = reinterpret_cast(1); } void mark_as_free() { m_data.m_key = 0; } @@ -134,9 +138,13 @@ public: return m_table.end(); } - void insert(Key * k, Value const & v) { + void insert(Key * const k, Value const & v) { m_table.insert(key_data(k, v)); } + + void insert(Key * const k, Value && v) { + m_table.insert(key_data(k, std::move(v))); + } key_data const & insert_if_not_there(Key * k, Value const & v) { return m_table.insert_if_not_there(key_data(k, v)); @@ -150,7 +158,7 @@ public: return m_table.find_core(key_data(k)); } - bool find(Key * k, Value & v) const { + bool find(Key * const k, Value & v) const { obj_map_entry * e = find_core(k); if (e) { v = e->get_data().m_value; diff --git a/src/util/obj_mark.h b/src/util/obj_mark.h index 749122b8f..d2fa65d32 100644 --- a/src/util/obj_mark.h +++ b/src/util/obj_mark.h @@ -19,7 +19,7 @@ Revision History: #ifndef OBJ_MARK_H_ #define OBJ_MARK_H_ -#include"bit_vector.h" +#include "util/bit_vector.h" template struct default_t2uint { diff --git a/src/util/obj_pair_hashtable.h b/src/util/obj_pair_hashtable.h index 8e7365909..2addc3902 100644 --- a/src/util/obj_pair_hashtable.h +++ b/src/util/obj_pair_hashtable.h @@ -19,8 +19,8 @@ Revision History: #ifndef OBJ_PAIR_HASHTABLE_H_ #define OBJ_PAIR_HASHTABLE_H_ -#include"hash.h" -#include"hashtable.h" +#include "util/hash.h" +#include "util/hashtable.h" /** \brief Special entry for a hashtable of pairs of obj pointers (i.e., diff --git a/src/util/obj_pair_set.h b/src/util/obj_pair_set.h index c4212977c..d565d31b9 100644 --- a/src/util/obj_pair_set.h +++ b/src/util/obj_pair_set.h @@ -19,7 +19,7 @@ Revision History: #ifndef OBJ_PAIR_SET_H_ #define OBJ_PAIR_SET_H_ -#include"chashtable.h" +#include "util/chashtable.h" template class obj_pair_set { diff --git a/src/util/obj_ref.h b/src/util/obj_ref.h index 1aa562a8f..72762ea5b 100644 --- a/src/util/obj_ref.h +++ b/src/util/obj_ref.h @@ -53,6 +53,10 @@ public: inc_ref(); } + obj_ref(obj_ref && other) : m_obj(0), m_manager(other.m_manager) { + std::swap(m_obj, other.m_obj); + } + ~obj_ref() { dec_ref(); } TManager & get_manager() const { return m_manager; } diff --git a/src/util/obj_triple_hashtable.h b/src/util/obj_triple_hashtable.h index 4fda9e655..316b63b93 100644 --- a/src/util/obj_triple_hashtable.h +++ b/src/util/obj_triple_hashtable.h @@ -19,7 +19,7 @@ Revision History: #ifndef OBJ_TRIPLE_HASHTABLE_H_ #define OBJ_TRIPLE_HASHTABLE_H_ -#include"hashtable.h" +#include "util/hashtable.h" /** \brief Special entry for a hashtable of pairs of obj pointers (i.e., diff --git a/src/util/object_allocator.h b/src/util/object_allocator.h index 901ec46ec..e51f7a438 100644 --- a/src/util/object_allocator.h +++ b/src/util/object_allocator.h @@ -20,8 +20,8 @@ Revision History: #ifndef OBJECT_ALLOCATOR_H_ #define OBJECT_ALLOCATOR_H_ -#include"util.h" -#include"vector.h" +#include "util/util.h" +#include "util/vector.h" #define DEFAULT_NUM_WORKERS 8 #define NUM_OBJECTS_PER_PAGE 1024 diff --git a/src/util/optional.h b/src/util/optional.h index 22757f3bd..5b3753ac6 100644 --- a/src/util/optional.h +++ b/src/util/optional.h @@ -21,26 +21,27 @@ Revision History: #ifndef OPTIONAL_H_ #define OPTIONAL_H_ -template +template class optional { - char m_obj[sizeof(T)]; + T* m_obj; char m_initialized; void construct(const T & val) { m_initialized = 1; - new (reinterpret_cast(m_obj)) T(val); + m_obj = alloc(T, val); } void destroy() { if (m_initialized == 1) { - reinterpret_cast(m_obj)->~T(); + dealloc(m_obj); + m_obj = 0; } m_initialized = 0; } public: optional(): - m_initialized(0) {} + m_obj(0), m_initialized(0) {} explicit optional(const T & val) { construct(val); @@ -65,7 +66,7 @@ public: T * get() const { if (m_initialized == 1) { - return reinterpret_cast(m_obj); + return m_obj; } else { return 0; @@ -80,22 +81,22 @@ public: T * operator->() { SASSERT(m_initialized==1); - return reinterpret_cast(m_obj); + return m_obj; } T const * operator->() const { SASSERT(m_initialized==1); - return reinterpret_cast(m_obj); + return m_obj; } const T & operator*() const { SASSERT(m_initialized==1); - return *reinterpret_cast(m_obj); + return *m_obj; } T & operator*() { SASSERT(m_initialized==1); - return *reinterpret_cast(m_obj); + return *m_obj; } optional & operator=(const T & val) { diff --git a/src/util/page.cpp b/src/util/page.cpp index 8fddcc075..4f6cea83c 100644 --- a/src/util/page.cpp +++ b/src/util/page.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"page.h" -#include"debug.h" +#include "util/page.h" +#include "util/debug.h" inline void set_page_header(char * page, char * prev, bool default_page) { size_t header = reinterpret_cast(prev) | static_cast(default_page); diff --git a/src/util/page.h b/src/util/page.h index 4ccfb6cab..0f44d6794 100644 --- a/src/util/page.h +++ b/src/util/page.h @@ -19,7 +19,7 @@ Revision History: #ifndef PAGE_H_ #define PAGE_H_ -#include"memory_manager.h" +#include "util/memory_manager.h" #define PAGE_HEADER_SZ sizeof(size_t) #define DEFAULT_PAGE_SIZE (8192 - PAGE_HEADER_SZ) diff --git a/src/util/params.cpp b/src/util/params.cpp index b869f8e3d..ee6ce6627 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -16,10 +16,10 @@ Author: Notes: --*/ -#include"params.h" -#include"rational.h" -#include"symbol.h" -#include"dictionary.h" +#include "util/params.h" +#include "util/rational.h" +#include "util/symbol.h" +#include "util/dictionary.h" params_ref params_ref::g_empty_params_ref; diff --git a/src/util/params.h b/src/util/params.h index 8d95c200c..bad70a318 100644 --- a/src/util/params.h +++ b/src/util/params.h @@ -19,8 +19,8 @@ Notes: #ifndef PARAMS_H_ #define PARAMS_H_ -#include"cmd_context_types.h" -#include"vector.h" +#include "util/cmd_context_types.h" +#include "util/vector.h" std::string norm_param_name(char const * n); std::string norm_param_name(symbol const & n); diff --git a/src/util/parray.h b/src/util/parray.h index 1802f6ade..44b075db9 100644 --- a/src/util/parray.h +++ b/src/util/parray.h @@ -19,8 +19,8 @@ Revision History: #ifndef PARRAY_H_ #define PARRAY_H_ -#include"vector.h" -#include"trace.h" +#include "util/vector.h" +#include "util/trace.h" template class parray_manager { diff --git a/src/util/permutation.cpp b/src/util/permutation.cpp index a5c1b2e8b..5b20580eb 100644 --- a/src/util/permutation.cpp +++ b/src/util/permutation.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"permutation.h" +#include "util/permutation.h" permutation::permutation(unsigned size) { reset(size); diff --git a/src/util/permutation.h b/src/util/permutation.h index 45759fc01..77205bb1d 100644 --- a/src/util/permutation.h +++ b/src/util/permutation.h @@ -20,7 +20,7 @@ Revision History: #define PERMUTATION_H_ #include -#include"vector.h" +#include "util/vector.h" class permutation { unsigned_vector m_p; diff --git a/src/util/plugin_manager.h b/src/util/plugin_manager.h index 5e82c190c..da7017aa1 100644 --- a/src/util/plugin_manager.h +++ b/src/util/plugin_manager.h @@ -19,7 +19,7 @@ Revision History: #ifndef PLUGIN_MANAGER_H_ #define PLUGIN_MANAGER_H_ -#include"util.h" +#include "util/util.h" template class plugin_manager { diff --git a/src/util/pool.h b/src/util/pool.h index 3ea9dca9d..184f6470e 100644 --- a/src/util/pool.h +++ b/src/util/pool.h @@ -19,8 +19,8 @@ Revision History: #ifndef POOL_H_ #define POOL_H_ -#include"util.h" -#include"vector.h" +#include "util/util.h" +#include "util/vector.h" template class pool { diff --git a/src/util/prime_generator.cpp b/src/util/prime_generator.cpp index 6aef1305b..eac47f61b 100644 --- a/src/util/prime_generator.cpp +++ b/src/util/prime_generator.cpp @@ -16,7 +16,7 @@ Author: Notes: --*/ -#include"prime_generator.h" +#include "util/prime_generator.h" #define PRIME_LIST_MAX_SIZE 1<<20 diff --git a/src/util/prime_generator.h b/src/util/prime_generator.h index 44306cec5..6a284c57c 100644 --- a/src/util/prime_generator.h +++ b/src/util/prime_generator.h @@ -19,9 +19,9 @@ Notes: #ifndef PRIME_GENERATOR_H_ #define PRIME_GENERATOR_H_ -#include"vector.h" -#include"z3_exception.h" -#include"util.h" +#include "util/vector.h" +#include "util/z3_exception.h" +#include "util/util.h" class prime_generator_exception : public default_exception { public: diff --git a/src/util/ptr_scoped_buffer.h b/src/util/ptr_scoped_buffer.h index aa66a0398..d6b4c6563 100644 --- a/src/util/ptr_scoped_buffer.h +++ b/src/util/ptr_scoped_buffer.h @@ -19,9 +19,9 @@ Revision History: #ifndef PTR_SCOPED_BUFFER_H_ #define PTR_SCOPED_BUFFER_H_ -#include"util.h" -#include"debug.h" -#include"buffer.h" +#include "util/util.h" +#include "util/debug.h" +#include "util/buffer.h" template > class ptr_scoped_buffer : private ptr_buffer { diff --git a/src/util/rational.cpp b/src/util/rational.cpp index 43dc9110a..ce38bcaa7 100644 --- a/src/util/rational.cpp +++ b/src/util/rational.cpp @@ -17,8 +17,8 @@ Revision History: --*/ #include -#include"util.h" -#include"rational.h" +#include "util/util.h" +#include "util/rational.h" #ifdef _WINDOWS #include #endif diff --git a/src/util/rational.h b/src/util/rational.h index 26ef7dbb1..392a1982b 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -19,7 +19,7 @@ Revision History: #ifndef RATIONAL_H_ #define RATIONAL_H_ -#include"mpq.h" +#include "util/mpq.h" class rational { mpq m_val; @@ -41,6 +41,7 @@ public: rational() {} rational(rational const & r) { m().set(m_val, r.m_val); } + rational(rational && r) : m_val(std::move(r.m_val)) {} explicit rational(int n) { m().set(m_val, n); } @@ -422,7 +423,7 @@ inline bool operator>(rational const & r1, rational const & r2) { } inline bool operator<(rational const & r1, int r2) { - return r1 < rational(r2); + return r1 < rational(r2); } inline bool operator<=(rational const & r1, rational const & r2) { @@ -450,11 +451,11 @@ inline rational operator+(rational const & r1, rational const & r2) { } inline rational operator+(int r1, rational const & r2) { - return rational(r1) + r2; + return rational(r1) + r2; } inline rational operator+(rational const & r1, int r2) { - return r1 + rational(r2); + return r1 + rational(r2); } @@ -463,11 +464,11 @@ inline rational operator-(rational const & r1, rational const & r2) { } inline rational operator-(rational const & r1, int r2) { - return r1 - rational(r2); + return r1 - rational(r2); } inline rational operator-(int r1, rational const & r2) { - return rational(r1) - r2; + return rational(r1) - r2; } inline rational operator-(rational const & r) { @@ -492,11 +493,11 @@ inline rational operator/(rational const & r1, rational const & r2) { } inline rational operator/(rational const & r1, int r2) { - return r1 / rational(r2); + return r1 / rational(r2); } -inline rational operator/(int r1, rational const & r2) { - return rational(r1) / r2; +inline rational operator/(int r1, rational const & r2) { + return rational(r1) / r2; } inline rational power(rational const & r, unsigned p) { diff --git a/src/util/ref.h b/src/util/ref.h index d9663f9a4..811aba9af 100644 --- a/src/util/ref.h +++ b/src/util/ref.h @@ -50,6 +50,7 @@ public: inc_ref(); } + ref (ref && r): m_ptr (r.detach ()) {} ~ref() { dec_ref(); } @@ -89,6 +90,14 @@ public: return *this; } + ref & operator=(ref &&r) { + if (this != &r) { + dec_ref (); + m_ptr = r.detach (); + } + return *this; + } + void reset() { dec_ref(); m_ptr = 0; @@ -107,6 +116,11 @@ public: friend bool operator!=(const ref & r1, const ref & r2) { return r1.m_ptr != r2.m_ptr; } + friend void swap (ref &r1, ref &r2) { + T* tmp = r1.m_ptr; + r1.m_ptr = r2.m_ptr; + r2.m_ptr = tmp; + } }; /** diff --git a/src/util/ref_buffer.h b/src/util/ref_buffer.h index cd4e0c5ba..612dde2da 100644 --- a/src/util/ref_buffer.h +++ b/src/util/ref_buffer.h @@ -19,9 +19,9 @@ Revision History: #ifndef REF_BUFFER_H_ #define REF_BUFFER_H_ -#include"buffer.h" -#include"obj_ref.h" -#include"ref_vector.h" +#include "util/buffer.h" +#include "util/obj_ref.h" +#include "util/ref_vector.h" /** diff --git a/src/util/ref_vector.h b/src/util/ref_vector.h index fdfb94d93..f340d8886 100644 --- a/src/util/ref_vector.h +++ b/src/util/ref_vector.h @@ -19,8 +19,8 @@ Revision History: #ifndef REF_VECTOR_H_ #define REF_VECTOR_H_ -#include"vector.h" -#include"obj_ref.h" +#include "util/vector.h" +#include "util/obj_ref.h" /** \brief Vector of smart pointers. @@ -45,6 +45,10 @@ public: typedef T * data; ref_vector_core(Ref const & r = Ref()):Ref(r) {} + + ref_vector_core(ref_vector_core && other) : + Ref(std::move(other)), + m_nodes(std::move(other.m_nodes)) {} ~ref_vector_core() { dec_range_ref(m_nodes.begin(), m_nodes.end()); @@ -63,7 +67,7 @@ public: void resize(unsigned sz) { if (sz < m_nodes.size()) dec_range_ref(m_nodes.begin() + sz, m_nodes.end()); - m_nodes.resize(sz, 0); + m_nodes.resize(sz); } void resize(unsigned sz, T * d) { @@ -80,7 +84,7 @@ public: void reserve(unsigned sz) { if (sz <= m_nodes.size()) return; - m_nodes.resize(sz, 0); + m_nodes.resize(sz); } void shrink(unsigned sz) { @@ -207,6 +211,8 @@ public: this->append(other); } + ref_vector(ref_vector && other) : super(std::move(other)) {} + ref_vector(TManager & m, unsigned sz, T * const * data): super(ref_manager_wrapper(m)) { this->append(sz, data); diff --git a/src/util/region.cpp b/src/util/region.cpp index 0100c60f3..4e5b5f2f2 100644 --- a/src/util/region.cpp +++ b/src/util/region.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include"region.h" +#include "util/region.h" #ifdef Z3DEBUG @@ -26,10 +26,10 @@ void region::display_mem_stats(std::ostream & out) const { #else -#include"tptr.h" -#include"debug.h" -#include"memory_manager.h" -#include"page.h" +#include "util/tptr.h" +#include "util/debug.h" +#include "util/memory_manager.h" +#include "util/page.h" inline void region::allocate_page() { m_curr_page = allocate_default_page(m_curr_page, m_free_pages); diff --git a/src/util/region.h b/src/util/region.h index 2c43e26d4..60c5378e1 100644 --- a/src/util/region.h +++ b/src/util/region.h @@ -23,7 +23,7 @@ Revision History: #ifdef Z3DEBUG -#include"vector.h" +#include "util/vector.h" class region { ptr_vector m_chuncks; diff --git a/src/util/rlimit.cpp b/src/util/rlimit.cpp index bda06157d..e625cab95 100644 --- a/src/util/rlimit.cpp +++ b/src/util/rlimit.cpp @@ -16,11 +16,12 @@ Author: Revision History: --*/ -#include "rlimit.h" -#include "common_msgs.h" +#include "util/rlimit.h" +#include "util/common_msgs.h" reslimit::reslimit(): m_cancel(0), + m_suspend(false), m_count(0), m_limit(0) { } @@ -31,12 +32,12 @@ uint64 reslimit::count() const { bool reslimit::inc() { ++m_count; - return m_cancel == 0 && (m_limit == 0 || m_count <= m_limit); + return (m_cancel == 0 && (m_limit == 0 || m_count <= m_limit)) || m_suspend; } bool reslimit::inc(unsigned offset) { m_count += offset; - return m_cancel == 0 && (m_limit == 0 || m_count <= m_limit); + return (m_cancel == 0 && (m_limit == 0 || m_count <= m_limit)) || m_suspend; } void reslimit::push(unsigned delta_limit) { diff --git a/src/util/rlimit.h b/src/util/rlimit.h index 283d7613d..0c81f9449 100644 --- a/src/util/rlimit.h +++ b/src/util/rlimit.h @@ -19,16 +19,18 @@ Revision History: #ifndef RLIMIT_H_ #define RLIMIT_H_ -#include "vector.h" +#include "util/vector.h" class reslimit { volatile unsigned m_cancel; + bool m_suspend; uint64 m_count; uint64 m_limit; svector m_limits; ptr_vector m_children; void set_cancel(unsigned f); + friend class scoped_suspend_rlimit; public: reslimit(); @@ -42,7 +44,7 @@ public: uint64 count() const; - bool get_cancel_flag() const { return m_cancel > 0; } + bool get_cancel_flag() const { return m_cancel > 0 && !m_suspend; } char const* get_cancel_msg() const; void cancel(); void reset_cancel(); @@ -61,6 +63,17 @@ public: }; +class scoped_suspend_rlimit { + reslimit & m_limit; +public: + scoped_suspend_rlimit(reslimit& r): m_limit(r) { + r.m_suspend = true; + } + ~scoped_suspend_rlimit() { + m_limit.m_suspend = false; + } +}; + struct scoped_limits { reslimit& m_limit; unsigned m_sz; diff --git a/src/util/s_integer.cpp b/src/util/s_integer.cpp index f55e77487..cfaf34fff 100644 --- a/src/util/s_integer.cpp +++ b/src/util/s_integer.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"s_integer.h" +#include "util/s_integer.h" s_integer s_integer::m_zero(0); s_integer s_integer::m_one(1); diff --git a/src/util/s_integer.h b/src/util/s_integer.h index c215505ea..658ae8eea 100644 --- a/src/util/s_integer.h +++ b/src/util/s_integer.h @@ -19,7 +19,7 @@ Revision History: #ifndef S_INTEGER_H_ #define S_INTEGER_H_ -#include"rational.h" +#include "util/rational.h" class s_integer { int m_val; diff --git a/src/util/scoped_ctrl_c.cpp b/src/util/scoped_ctrl_c.cpp index feaceea8d..1cb3a03c4 100644 --- a/src/util/scoped_ctrl_c.cpp +++ b/src/util/scoped_ctrl_c.cpp @@ -18,13 +18,13 @@ Revision History: --*/ #include #include -#include"scoped_ctrl_c.h" +#include "util/scoped_ctrl_c.h" scoped_ctrl_c * scoped_ctrl_c::g_obj = 0; void scoped_ctrl_c::on_ctrl_c(int) { if (g_obj->m_first) { - g_obj->m_cancel_eh(); + g_obj->m_cancel_eh(CTRL_C_EH_CALLER); if (g_obj->m_once) { g_obj->m_first = false; signal(SIGINT, on_ctrl_c); // re-install the handler diff --git a/src/util/scoped_ctrl_c.h b/src/util/scoped_ctrl_c.h index b79db28fe..b3abf0e26 100644 --- a/src/util/scoped_ctrl_c.h +++ b/src/util/scoped_ctrl_c.h @@ -19,8 +19,8 @@ Revision History: #ifndef SCOPED_CTRL_C_H_ #define SCOPED_CTRL_C_H_ -#include"event_handler.h" -#include"util.h" +#include "util/event_handler.h" +#include "util/util.h" struct scoped_ctrl_c { event_handler & m_cancel_eh; diff --git a/src/util/scoped_numeral_buffer.h b/src/util/scoped_numeral_buffer.h index 6da287dd2..1f294cee0 100644 --- a/src/util/scoped_numeral_buffer.h +++ b/src/util/scoped_numeral_buffer.h @@ -19,7 +19,7 @@ Revision History: #ifndef SCOPED_NUMERAL_BUFFER_H_ #define SCOPED_NUMERAL_BUFFER_H_ -#include"buffer.h" +#include "util/buffer.h" template class _scoped_numeral_buffer : public sbuffer { diff --git a/src/util/scoped_numeral_vector.h b/src/util/scoped_numeral_vector.h index bbd06f898..cb9a6b4fd 100644 --- a/src/util/scoped_numeral_vector.h +++ b/src/util/scoped_numeral_vector.h @@ -19,7 +19,7 @@ Revision History: #ifndef SCOPED_NUMERAL_VECTOR_H_ #define SCOPED_NUMERAL_VECTOR_H_ -#include"vector.h" +#include "util/vector.h" template class _scoped_numeral_vector : public svector { @@ -63,8 +63,7 @@ public: unsigned old_sz = this->size(); if (sz <= old_sz) shrink(sz); - typename Manager::numeral zero(0); - svector::resize(sz, zero); + svector::resize(sz, 0); } }; diff --git a/src/util/scoped_ptr_vector.h b/src/util/scoped_ptr_vector.h index d1ff89733..0bd0fd47e 100644 --- a/src/util/scoped_ptr_vector.h +++ b/src/util/scoped_ptr_vector.h @@ -20,8 +20,8 @@ Notes: #ifndef SCOPED_PTR_VECTOR_H_ #define SCOPED_PTR_VECTOR_H_ -#include"vector.h" -#include"util.h" +#include "util/vector.h" +#include "util/util.h" template class scoped_ptr_vector { @@ -42,7 +42,7 @@ public: bool empty() const { return m_vector.empty(); } void resize(unsigned sz) { if (sz < m_vector.size()) { - for (unsigned i = m_vector.size(); i < sz; i++) + for (unsigned i = m_vector.size(); i-- > sz; ) dealloc(m_vector[i]); m_vector.shrink(sz); } diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index f6b0429d9..3991abd36 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -21,8 +21,8 @@ Revision History: #define _WIN32_WINNT 0x0600 #endif -#include"z3_exception.h" -#include"z3_omp.h" +#include "util/z3_exception.h" +#include "util/z3_omp.h" #if defined(_WINDOWS) || defined(_CYGWIN) // Windows #include @@ -44,14 +44,14 @@ Revision History: // Other platforms #endif -#include"scoped_timer.h" +#include "util/scoped_timer.h" #ifdef _CYGWIN #undef min #undef max #endif -#include"util.h" +#include "util/util.h" #include -#include"z3_omp.h" +#include "util/z3_omp.h" struct scoped_timer::imp { event_handler * m_eh; @@ -85,7 +85,7 @@ struct scoped_timer::imp { obj->m_first = false; } else { - obj->m_eh->operator()(); + obj->m_eh->operator()(TIMEOUT_EH_CALLER); } } #elif defined(__APPLE__) && defined(__MACH__) @@ -98,7 +98,7 @@ struct scoped_timer::imp { int e = pthread_cond_timedwait(&st->m_condition_var, &st->m_mutex, &st->m_end_time); if (e != 0 && e != ETIMEDOUT) throw default_exception("failed to start timed wait"); - st->m_eh->operator()(); + st->m_eh->operator()(TIMEOUT_EH_CALLER); pthread_mutex_unlock(&st->m_mutex); @@ -133,7 +133,7 @@ struct scoped_timer::imp { pthread_mutex_unlock(&st->m_mutex); if (e == ETIMEDOUT) - st->m_eh->operator()(); + st->m_eh->operator()(TIMEOUT_EH_CALLER); return 0; } #else diff --git a/src/util/scoped_timer.h b/src/util/scoped_timer.h index a3e2568f9..cfce957f3 100644 --- a/src/util/scoped_timer.h +++ b/src/util/scoped_timer.h @@ -19,7 +19,7 @@ Revision History: #ifndef SCOPED_TIMER_H_ #define SCOPED_TIMER_H_ -#include"event_handler.h" +#include "util/event_handler.h" class scoped_timer { struct imp; diff --git a/src/util/scoped_vector.h b/src/util/scoped_vector.h index f62fbc8a6..5935ab6fa 100644 --- a/src/util/scoped_vector.h +++ b/src/util/scoped_vector.h @@ -19,7 +19,7 @@ Revision History: #ifndef SCOPED_VECTOR_H_ #define SCOPED_VECTOR_H_ -#include"vector.h" +#include "util/vector.h" template class scoped_vector { @@ -113,8 +113,8 @@ public: } }; - iterator begin() { return iterator(*this, 0); } - iterator end() { return iterator(*this, m_size); } + iterator begin() const { return iterator(*this, 0); } + iterator end() const { return iterator(*this, m_size); } void push_back(T const& t) { set_index(m_size, m_elems.size()); diff --git a/src/util/sexpr.cpp b/src/util/sexpr.cpp index c5d4a976f..4757330c2 100644 --- a/src/util/sexpr.cpp +++ b/src/util/sexpr.cpp @@ -16,9 +16,9 @@ Author: Notes: --*/ -#include"sexpr.h" -#include"vector.h" -#include"buffer.h" +#include "util/sexpr.h" +#include "util/vector.h" +#include "util/buffer.h" #ifdef _MSC_VER #pragma warning(disable : 4200) diff --git a/src/util/sexpr.h b/src/util/sexpr.h index 350c1ffec..7f5fdc67d 100644 --- a/src/util/sexpr.h +++ b/src/util/sexpr.h @@ -19,10 +19,10 @@ Notes: #ifndef SEXPR_H_ #define SEXPR_H_ -#include"rational.h" -#include"symbol.h" -#include"obj_ref.h" -#include"ref_vector.h" +#include "util/rational.h" +#include "util/symbol.h" +#include "util/obj_ref.h" +#include "util/ref_vector.h" class sexpr_manager; diff --git a/src/util/small_object_allocator.cpp b/src/util/small_object_allocator.cpp index ac2f64482..0eb7b9ec3 100644 --- a/src/util/small_object_allocator.cpp +++ b/src/util/small_object_allocator.cpp @@ -18,11 +18,11 @@ Revision History: Rewrote/Simplified the allocator --*/ -#include"memory_manager.h" -#include"small_object_allocator.h" -#include"debug.h" -#include"util.h" -#include"vector.h" +#include "util/memory_manager.h" +#include "util/small_object_allocator.h" +#include "util/debug.h" +#include "util/util.h" +#include "util/vector.h" #include small_object_allocator::small_object_allocator(char const * id) { diff --git a/src/util/small_object_allocator.h b/src/util/small_object_allocator.h index 9433b093e..740218242 100644 --- a/src/util/small_object_allocator.h +++ b/src/util/small_object_allocator.h @@ -20,8 +20,8 @@ Revision History: #ifndef SMALL_OBJECT_ALLOCATOR_H_ #define SMALL_OBJECT_ALLOCATOR_H_ -#include"machine.h" -#include"debug.h" +#include "util/machine.h" +#include "util/debug.h" class small_object_allocator { static const unsigned CHUNK_SIZE = (8192 - sizeof(void*)*2); diff --git a/src/util/smt2_util.cpp b/src/util/smt2_util.cpp index 70979cc01..731c91848 100644 --- a/src/util/smt2_util.cpp +++ b/src/util/smt2_util.cpp @@ -16,7 +16,7 @@ Author: Notes: --*/ -#include"smt2_util.h" +#include "util/smt2_util.h" bool is_smt2_simple_symbol_char(char s) { return diff --git a/src/util/smt2_util.h b/src/util/smt2_util.h index bddef03fb..5338daed9 100644 --- a/src/util/smt2_util.h +++ b/src/util/smt2_util.h @@ -19,7 +19,7 @@ Notes: #ifndef SMT2_UTIL_H_ #define SMT2_UTIL_H_ -#include"symbol.h" +#include "util/symbol.h" bool is_smt2_simple_symbol_char(char c); bool is_smt2_quoted_symbol(char const * s); diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index b0efbd346..17808ea48 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -19,7 +19,7 @@ Notes: --*/ -#include "vector.h" +#include "util/vector.h" #ifndef SORTING_NETWORK_H_ #define SORTING_NETWORK_H_ diff --git a/src/util/stack.cpp b/src/util/stack.cpp index 3c442d74b..81383e2fe 100644 --- a/src/util/stack.cpp +++ b/src/util/stack.cpp @@ -15,9 +15,9 @@ Author: Notes: --*/ -#include"stack.h" -#include"page.h" -#include"tptr.h" +#include "util/stack.h" +#include "util/page.h" +#include "util/tptr.h" inline void stack::store_mark(size_t m) { reinterpret_cast(m_curr_ptr)[0] = m; diff --git a/src/util/stack.h b/src/util/stack.h index a2605edcc..e29a09fcd 100644 --- a/src/util/stack.h +++ b/src/util/stack.h @@ -18,8 +18,8 @@ Notes: #ifndef STACK_H_ #define STACK_H_ -#include"page.h" -#include"debug.h" +#include "util/page.h" +#include "util/debug.h" class stack { char * m_curr_page; diff --git a/src/util/statistics.cpp b/src/util/statistics.cpp index 99cc4f3a4..9c8d1fd99 100644 --- a/src/util/statistics.cpp +++ b/src/util/statistics.cpp @@ -16,11 +16,11 @@ Author: Notes: --*/ -#include"statistics.h" -#include"map.h" -#include"str_hashtable.h" -#include"buffer.h" -#include"smt2_util.h" +#include "util/statistics.h" +#include "util/map.h" +#include "util/str_hashtable.h" +#include "util/buffer.h" +#include "util/smt2_util.h" #include void statistics::update(char const * key, unsigned inc) { diff --git a/src/util/statistics.h b/src/util/statistics.h index 041c2cf99..249c0ccc3 100644 --- a/src/util/statistics.h +++ b/src/util/statistics.h @@ -20,8 +20,8 @@ Notes: #define STATISTICS_H_ #include -#include"vector.h" -#include"rlimit.h" +#include "util/vector.h" +#include "util/rlimit.h" class statistics { typedef std::pair key_val_pair; diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index 7a9066030..9ba707af0 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -110,7 +110,7 @@ public: mach_timespec_t _stop; clock_get_time(m_host_clock, &_stop); m_time += (_stop.tv_sec - m_start.tv_sec) * 1000000000ull; - m_time += (_stop.tv_nsec - m_start.tv_nsec); + m_time += (_stop.tv_nsec - m_start.tv_nsec); m_running = false; } } @@ -163,8 +163,8 @@ public: struct timespec _stop; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &_stop); m_time += (_stop.tv_sec - m_start.tv_sec) * 1000000000ull; - if (m_time != 0 || _stop.tv_nsec >= m_start.tv_nsec) - m_time += (_stop.tv_nsec - m_start.tv_nsec); + if (m_time != 0 || _stop.tv_nsec >= m_start.tv_nsec) + m_time += (_stop.tv_nsec - m_start.tv_nsec); m_running = false; } } @@ -185,4 +185,15 @@ public: #endif +struct scoped_watch { + stopwatch &m_sw; + scoped_watch (stopwatch &sw, bool reset=false): m_sw(sw) { + if (reset) m_sw.reset(); + m_sw.start(); + } + ~scoped_watch() { + m_sw.stop (); + } +}; + #endif diff --git a/src/util/str_hashtable.h b/src/util/str_hashtable.h index 2cfc2856c..e12cdc7a7 100644 --- a/src/util/str_hashtable.h +++ b/src/util/str_hashtable.h @@ -21,8 +21,8 @@ Revision History: #include -#include"hashtable.h" -#include"hash.h" +#include "util/hashtable.h" +#include "util/hash.h" struct str_hash_proc { unsigned operator()(char const * s) const { return string_hash(s, static_cast(strlen(s)), 17); } diff --git a/src/util/string_buffer.h b/src/util/string_buffer.h index a1607f5c4..28ce84fc4 100644 --- a/src/util/string_buffer.h +++ b/src/util/string_buffer.h @@ -22,8 +22,8 @@ #include #include #include -#include"util.h" -#include"memory_manager.h" +#include "util/util.h" +#include "util/memory_manager.h" // This string buffer will not use the heap if the data consumes less than INITIAL_SIZE bytes. template diff --git a/src/util/symbol.cpp b/src/util/symbol.cpp index 895c26b67..8f46272f0 100644 --- a/src/util/symbol.cpp +++ b/src/util/symbol.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include"symbol.h" -#include"str_hashtable.h" -#include"region.h" -#include"string_buffer.h" -#include"z3_omp.h" +#include "util/symbol.h" +#include "util/str_hashtable.h" +#include "util/region.h" +#include "util/string_buffer.h" +#include "util/z3_omp.h" symbol symbol::m_dummy(TAG(void*, static_cast(0), 2)); const symbol symbol::null; diff --git a/src/util/symbol.h b/src/util/symbol.h index d0eef4f3b..874b258e9 100644 --- a/src/util/symbol.h +++ b/src/util/symbol.h @@ -21,9 +21,9 @@ Revision History: #include #include -#include"util.h" -#include"tptr.h" -#include"string_buffer.h" +#include "util/util.h" +#include "util/tptr.h" +#include "util/string_buffer.h" template class symbol_table; diff --git a/src/util/symbol_table.h b/src/util/symbol_table.h index d3be2cb9c..818cb7584 100644 --- a/src/util/symbol_table.h +++ b/src/util/symbol_table.h @@ -18,10 +18,10 @@ Revision History: --*/ #ifndef SYMBOL_TABLE_H_ #define SYMBOL_TABLE_H_ -#include"vector.h" -#include"hashtable.h" -#include"hash.h" -#include"symbol.h" +#include "util/vector.h" +#include "util/hashtable.h" +#include "util/hash.h" +#include "util/symbol.h" /** \brief Quick & Dirty symbol table. @@ -182,29 +182,20 @@ public: } void append(symbol_table const& other) { - typename sym_table::iterator it = other.m_sym_table.begin(); - typename sym_table::iterator end = other.m_sym_table.end(); - - for (; it != end; ++it) { - insert((*it).m_key, (*it).m_data); + for (auto const& kv : other.m_sym_table) { + insert(kv.m_key, kv.m_data); } } void get_range(vector& range) const { - typename sym_table::iterator it = m_sym_table.begin(); - typename sym_table::iterator end = m_sym_table.end(); - - for (; it != end; ++it) { - range.push_back((*it).m_data); + for (auto kv : m_sym_table) { + range.push_back(kv.m_data); } } void get_dom(svector& dom) const { - typename sym_table::iterator it = m_sym_table.begin(); - typename sym_table::iterator end = m_sym_table.end(); - - for (; it != end; ++it) { - dom.push_back((*it).m_key); + for (auto kv : m_sym_table) { + dom.push_back(kv.m_key); } } }; diff --git a/src/util/timeit.cpp b/src/util/timeit.cpp index 5246beced..97df87ecd 100644 --- a/src/util/timeit.cpp +++ b/src/util/timeit.cpp @@ -17,9 +17,9 @@ Revision History: --*/ #include -#include"timeit.h" -#include"memory_manager.h" -#include"stopwatch.h" +#include "util/timeit.h" +#include "util/memory_manager.h" +#include "util/stopwatch.h" #include struct timeit::imp { diff --git a/src/util/timeout.cpp b/src/util/timeout.cpp index 75621995c..67995c2aa 100644 --- a/src/util/timeout.cpp +++ b/src/util/timeout.cpp @@ -19,23 +19,24 @@ Revision History: --*/ #include -#include"z3_omp.h" -#include"util.h" -#include"timeout.h" -#include"error_codes.h" +#include "util/z3_omp.h" +#include "util/util.h" +#include "util/timeout.h" +#include "util/error_codes.h" -#include"event_handler.h" -#include"scoped_timer.h" +#include "util/event_handler.h" +#include "util/scoped_timer.h" scoped_timer * g_timeout = 0; void (* g_on_timeout)() = 0; class g_timeout_eh : public event_handler { public: - void operator()() { + void operator()(event_handler_caller_t caller_id) { #pragma omp critical (g_timeout_cs) { std::cout << "timeout\n"; + m_caller_id = caller_id; if (g_on_timeout) g_on_timeout(); if (g_timeout) diff --git a/src/util/timer.cpp b/src/util/timer.cpp index ace67ead8..2d80b732c 100644 --- a/src/util/timer.cpp +++ b/src/util/timer.cpp @@ -16,10 +16,10 @@ Author: Revision History: --*/ -#include"util.h" -#include"memory_manager.h" -#include"stopwatch.h" -#include"timer.h" +#include "util/util.h" +#include "util/memory_manager.h" +#include "util/stopwatch.h" +#include "util/timer.h" timer::timer(){ m_watch = alloc(stopwatch); diff --git a/src/util/total_order.h b/src/util/total_order.h index 6fda88110..a309b63a1 100644 --- a/src/util/total_order.h +++ b/src/util/total_order.h @@ -19,11 +19,11 @@ Revision History: #ifndef TOTAL_ORDER_H_ #define TOTAL_ORDER_H_ -#include"util.h" -#include"small_object_allocator.h" -#include"map.h" -#include"uint_map.h" -#include"trace.h" +#include "util/util.h" +#include "util/small_object_allocator.h" +#include "util/map.h" +#include "util/uint_map.h" +#include "util/trace.h" /** \brief An object for maintaining a total-order on sets of T values. diff --git a/src/util/tptr.h b/src/util/tptr.h index 23c28078b..d7319954d 100644 --- a/src/util/tptr.h +++ b/src/util/tptr.h @@ -20,7 +20,7 @@ Revision History: #ifndef TPTR_H_ #define TPTR_H_ -#include"machine.h" +#include "util/machine.h" #define TAG_SHIFT PTR_ALIGNMENT #define ALIGNMENT_VALUE (1 << PTR_ALIGNMENT) diff --git a/src/util/trace.cpp b/src/util/trace.cpp index 05a3e49bd..d993ebd11 100644 --- a/src/util/trace.cpp +++ b/src/util/trace.cpp @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#include"trace.h" -#include"str_hashtable.h" +#include "util/trace.h" +#include "util/str_hashtable.h" #ifdef _TRACE std::ofstream tout(".z3-trace"); diff --git a/src/util/trail.h b/src/util/trail.h index 56c3d805f..bba71fb00 100644 --- a/src/util/trail.h +++ b/src/util/trail.h @@ -19,9 +19,10 @@ Revision History: #ifndef TRAIL_H_ #define TRAIL_H_ -#include"obj_hashtable.h" -#include"region.h" -#include"obj_ref.h" +#include "util/obj_hashtable.h" +#include "util/region.h" +#include "util/obj_ref.h" +#include "util/vector.h" template class trail { @@ -35,16 +36,16 @@ template class value_trail : public trail { T & m_value; T m_old_value; - + public: value_trail(T & value): m_value(value), m_old_value(value) { } - + virtual ~value_trail() { } - + virtual void undo(Ctx & ctx) { m_value = m_old_value; } @@ -57,10 +58,10 @@ public: reset_flag_trail(bool & value): m_value(value) { } - + virtual ~reset_flag_trail() { } - + virtual void undo(Ctx & ctx) { m_value = false; } @@ -74,7 +75,7 @@ public: m_ptr(ptr) { SASSERT(m_ptr == 0); } - + virtual void undo(Ctx & ctx) { m_ptr = 0; } @@ -98,8 +99,8 @@ public: virtual void undo(Ctx & ctx) { m_vector.shrink(m_old_size); } -}; - +}; + template class vector_value_trail : public trail { vector & m_vector; @@ -111,10 +112,10 @@ public: m_idx(idx), m_old_value(v[idx]) { } - + virtual ~vector_value_trail() { } - + virtual void undo(Ctx & ctx) { m_vector[m_idx] = m_old_value; } @@ -150,7 +151,7 @@ public: push_back_vector(V & v): m_vector(v) { } - + virtual void undo(Ctx & ctx) { m_vector.pop_back(); } @@ -165,15 +166,15 @@ public: m_vector(v), m_idx(idx) { } - + virtual ~set_vector_idx_trail() { } - + virtual void undo(Ctx & ctx) { m_vector[m_idx] = 0; } }; - + template class pop_back_trail : public trail { vector & m_vector; @@ -183,7 +184,7 @@ public: m_vector(v), m_value(m_vector.back()) { } - + virtual void undo(Ctx & ctx) { m_vector.push_back(m_value); } @@ -201,7 +202,7 @@ public: m_index(index), m_value(m_vector[index].back()) { } - + virtual void undo(Ctx & ctx) { m_vector[m_index].push_back(m_value); } @@ -216,7 +217,7 @@ public: push_back_trail(vector & v): m_vector(v) { } - + virtual void undo(Ctx & ctx) { m_vector.pop_back(); } @@ -228,11 +229,11 @@ class push_back2_trail : public trail { vector_t & m_vector; unsigned m_index; public: - push_back2_trail(vector_t & v, unsigned index) : + push_back2_trail(vector_t & v, unsigned index) : m_vector(v), m_index(index) { } - + virtual void undo(Ctx & ctx) { m_vector[m_index].pop_back(); } @@ -249,12 +250,12 @@ public: SASSERT(m_vector[m_idx] == false); m_vector[m_idx] = true; } - + virtual void undo(Ctx & ctx) { m_vector[m_idx] = false; } }; - + template class new_obj_trail : public trail { T * m_obj; @@ -262,7 +263,7 @@ public: new_obj_trail(T * obj): m_obj(obj) { } - + virtual void undo(Ctx & ctx) { dealloc(m_obj); } @@ -275,7 +276,7 @@ public: obj_ref_trail(obj_ref& obj): m_obj(obj) { } - + virtual void undo(Ctx & ctx) { m_obj.reset(); } @@ -300,7 +301,7 @@ class remove_obj_trail : public trail { public: remove_obj_trail(obj_hashtable& t, T* o) : m_table(t), m_obj(o) {} virtual ~remove_obj_trail() {} - virtual void undo(Ctx & ctx) { m_table.insert(m_obj); } + virtual void undo(Ctx & ctx) { m_table.insert(m_obj); } }; @@ -326,13 +327,13 @@ public: trail_stack(Ctx & c):m_ctx(c) {} ~trail_stack() {} - + region & get_region() { return m_region; } - - void reset() { - pop_scope(m_scopes.size()); + + void reset() { + pop_scope(m_scopes.size()); // Undo trail objects stored at lvl 0 (avoid memory leaks if lvl 0 contains new_obj_trail objects). - undo_trail_stack(m_ctx, m_trail_stack, 0); + undo_trail_stack(m_ctx, m_trail_stack, 0); } void push_ptr(trail * t) { m_trail_stack.push_back(t); } @@ -357,4 +358,3 @@ public: }; #endif /* TRAIL_H_ */ - diff --git a/src/util/uint_map.h b/src/util/uint_map.h index 0344de322..b7dec8676 100644 --- a/src/util/uint_map.h +++ b/src/util/uint_map.h @@ -19,7 +19,7 @@ Revision History: #ifndef UINT_MAP_H_ #define UINT_MAP_H_ -#include"vector.h" +#include "util/vector.h" /** \brief Implement a map from unsigned to T * using vectors diff --git a/src/util/uint_set.h b/src/util/uint_set.h index e78a4b0b6..352189ef1 100644 --- a/src/util/uint_set.h +++ b/src/util/uint_set.h @@ -19,10 +19,9 @@ Revision History: #ifndef UINT_SET_H_ #define UINT_SET_H_ -#include"util.h" -#include"vector.h" +#include "util/util.h" +#include "util/vector.h" -COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); class uint_set : unsigned_vector { diff --git a/src/util/union_find.h b/src/util/union_find.h index 6f6cc7a3b..7a99b149e 100644 --- a/src/util/union_find.h +++ b/src/util/union_find.h @@ -19,8 +19,8 @@ Revision History: #ifndef UNION_FIND_H_ #define UNION_FIND_H_ -#include "trail.h" -#include "trace.h" +#include "util/trail.h" +#include "util/trace.h" class union_find_default_ctx { public: diff --git a/src/util/util.cpp b/src/util/util.cpp index bfd4923a8..b16dbe292 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include"util.h" +#include "util/util.h" static unsigned g_verbosity_level = 0; diff --git a/src/util/util.h b/src/util/util.h index a040a79ae..6d38231ba 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -19,8 +19,8 @@ Revision History: #ifndef UTIL_H_ #define UTIL_H_ -#include"debug.h" -#include"memory_manager.h" +#include "util/debug.h" +#include "util/memory_manager.h" #include #include #include @@ -33,13 +33,13 @@ Revision History: typedef unsigned long long uint64; #endif -COMPILE_TIME_ASSERT(sizeof(uint64) == 8); +static_assert(sizeof(uint64) == 8, "64 bits please"); #ifndef int64 typedef long long int64; #endif -COMPILE_TIME_ASSERT(sizeof(int64) == 8); +static_assert(sizeof(int64) == 8, "64 bits"); #ifndef INT64_MIN #define INT64_MIN static_cast(0x8000000000000000ull) @@ -54,6 +54,7 @@ COMPILE_TIME_ASSERT(sizeof(int64) == 8); #ifdef _WINDOWS #define SSCANF sscanf_s #define SPRINTF sprintf_s +#define _Exit exit #else #define SSCANF sscanf #define SPRINTF sprintf @@ -111,7 +112,7 @@ inline unsigned next_power_of_two(unsigned v) { unsigned log2(unsigned v); unsigned uint64_log2(uint64 v); -COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); +static_assert(sizeof(unsigned) == 4, "unsigned are 32 bits"); // Return the number of 1 bits in v. static inline unsigned get_num_1bits(unsigned v) { @@ -153,13 +154,13 @@ template char (*ArraySizer(T (&)[N]))[N]; template void display(std::ostream & out, const IT & begin, const IT & end, const char * sep, bool & first) { for(IT it = begin; it != end; ++it) { - if (first) { - first = false; - } - else { - out << sep; - } - out << *it; + if (first) { + first = false; + } + else { + out << sep; + } + out << *it; } } @@ -172,9 +173,9 @@ void display(std::ostream & out, const IT & begin, const IT & end, const char * template struct delete_proc { void operator()(T * ptr) { - if (ptr) { - dealloc(ptr); - } + if (ptr) { + dealloc(ptr); + } } }; @@ -322,7 +323,7 @@ bool compare_arrays(const T * array1, const T * array2, unsigned size) { template void force_ptr_array_size(T & v, unsigned sz) { if (sz > v.size()) { - v.resize(sz, 0); + v.resize(sz); } } diff --git a/src/util/vector.h b/src/util/vector.h index 7e89a773c..f5792a5d3 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -24,12 +24,13 @@ Revision History: #ifndef VECTOR_H_ #define VECTOR_H_ -#include"debug.h" +#include "util/debug.h" #include +#include #include -#include"memory_manager.h" -#include"hash.h" -#include"z3_exception.h" +#include "util/memory_manager.h" +#include "util/hash.h" +#include "util/z3_exception.h" // disable warning for constant 'if' expressions. // these are used heavily in templates. @@ -74,9 +75,27 @@ class vector { if (new_capacity <= old_capacity || new_capacity_T <= old_capacity_T) { throw default_exception("Overflow encountered when expanding vector"); } - SZ *mem = (SZ*)memory::reallocate(reinterpret_cast(m_data)-2, new_capacity_T); - *mem = new_capacity; - m_data = reinterpret_cast(mem + 2); + SZ *mem, *old_mem = reinterpret_cast(m_data) - 2; +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 + if (__has_trivial_copy(T)) { +#else + if (std::is_trivially_copyable::value) { +#endif + mem = (SZ*)memory::reallocate(old_mem, new_capacity_T); + m_data = reinterpret_cast(mem + 2); + } else { + mem = (SZ*)memory::allocate(new_capacity_T); + auto old_data = m_data; + auto old_size = size(); + mem[1] = old_size; + m_data = reinterpret_cast(mem + 2); + for (unsigned i = 0; i < old_size; ++i) { + new (&m_data[i]) T(std::move(old_data[i])); + old_data[i].~T(); + } + memory::deallocate(old_mem); + } + *mem = new_capacity; } } @@ -148,6 +167,10 @@ public: SASSERT(size() == source.size()); } + vector(vector&& other) : m_data(0) { + std::swap(m_data, other.m_data); + } + vector(SZ s, T const * data): m_data(0) { for (SZ i = 0; i < s; i++) { @@ -179,6 +202,16 @@ public: return *this; } + vector & operator=(vector && source) { + if (this == &source) { + return *this; + } + destroy(); + m_data = 0; + std::swap(m_data, source.m_data); + return *this; + } + void reset() { if (m_data) { if (CallDestructors) { @@ -292,6 +325,11 @@ public: m_data[idx] = val; } + void set(SZ idx, T && val) { + SASSERT(idx < size()); + m_data[idx] = std::move(val); + } + T & back() { SASSERT(!empty()); return operator[](size() - 1); @@ -318,6 +356,14 @@ public: reinterpret_cast(m_data)[SIZE_IDX]++; } + void push_back(T && elem) { + if (m_data == 0 || reinterpret_cast(m_data)[SIZE_IDX] == reinterpret_cast(m_data)[CAPACITY_IDX]) { + expand_vector(); + } + new (m_data + reinterpret_cast(m_data)[SIZE_IDX]) T(std::move(elem)); + reinterpret_cast(m_data)[SIZE_IDX]++; + } + void insert(T const & elem) { push_back(elem); } @@ -357,7 +403,8 @@ public: } } - void resize(SZ s, T const & elem=T()) { + template + void resize(SZ s, Args args...) { SZ sz = size(); if (s <= sz) { shrink(s); return; } while (s > capacity()) { @@ -367,8 +414,23 @@ public: reinterpret_cast(m_data)[SIZE_IDX] = s; iterator it = m_data + sz; iterator end = m_data + s; - for(; it != end; ++it) { - new (it) T(elem); + for (; it != end; ++it) { + new (it) T(std::forward(args)); + } + } + + void resize(SZ s) { + SZ sz = size(); + if (s <= sz) { shrink(s); return; } + while (s > capacity()) { + expand_vector(); + } + SASSERT(m_data != 0); + reinterpret_cast(m_data)[SIZE_IDX] = s; + iterator it = m_data + sz; + iterator end = m_data + s; + for (; it != end; ++it) { + new (it) T(); } } @@ -439,10 +501,15 @@ public: return m_data[idx]; } - void reserve(SZ s, T const & d = T()) { + void reserve(SZ s, T const & d) { if (s > size()) resize(s, d); } + + void reserve(SZ s) { + if (s > size()) + resize(s); + } }; template @@ -452,7 +519,12 @@ public: ptr_vector(unsigned s):vector(s) {} ptr_vector(unsigned s, T * elem):vector(s, elem) {} ptr_vector(ptr_vector const & source):vector(source) {} + ptr_vector(ptr_vector && other) : vector(std::move(other)) {} ptr_vector(unsigned s, T * const * data):vector(s, const_cast(data)) {} + ptr_vector & operator=(ptr_vector const & source) { + vector::operator=(source); + return *this; + } }; template @@ -462,7 +534,12 @@ public: svector(SZ s):vector(s) {} svector(SZ s, T const & elem):vector(s, elem) {} svector(svector const & source):vector(source) {} + svector(svector && other) : vector(std::move(other)) {} svector(SZ s, T const * data):vector(s, data) {} + svector & operator=(svector const & source) { + vector::operator=(source); + return *this; + } }; typedef svector int_vector; @@ -494,23 +571,4 @@ struct vector_hash : public vector_hash_tpl > template struct svector_hash : public vector_hash_tpl > {}; -#include -// Specialize vector to be an instance of std::vector instead. -// This will catch any regression of issue #564 and #420. - -template <> -class vector : public std::vector { -public: - vector(vector const& other): std::vector(other) {} - vector(size_t sz, char const* s): std::vector(sz, s) {} - vector() {} - - void reset() { clear(); } - - -}; - - - #endif /* VECTOR_H_ */ - diff --git a/src/util/warning.cpp b/src/util/warning.cpp index 9c6a285b9..a794b064a 100644 --- a/src/util/warning.cpp +++ b/src/util/warning.cpp @@ -19,10 +19,10 @@ Revision History: #include #include -#include "error_codes.h" -#include "util.h" -#include "buffer.h" -#include "vector.h" +#include "util/error_codes.h" +#include "util/util.h" +#include "util/buffer.h" +#include "util/vector.h" #ifdef _WINDOWS #define PRF sprintf_s diff --git a/src/util/z3_exception.cpp b/src/util/z3_exception.cpp index ee225ba48..d028a688a 100644 --- a/src/util/z3_exception.cpp +++ b/src/util/z3_exception.cpp @@ -19,10 +19,10 @@ Notes: #include #include #include -#include"z3_exception.h" -#include"warning.h" -#include"error_codes.h" -#include"debug.h" +#include "util/z3_exception.h" +#include "util/warning.h" +#include "util/error_codes.h" +#include "util/debug.h" unsigned z3_exception::error_code() const { return ERR_OK;