3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-08 10:25:18 +00:00
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2017-05-08 13:50:33 -07:00
commit f61f2b1f55
174 changed files with 18128 additions and 1711 deletions

View file

@ -24,9 +24,8 @@ if (NOT (EXISTS "${CMAKE_SOURCE_DIR}/src/CMakeLists.txt"))
"``python contrib/cmake/bootstrap.py create``")
endif()
# This overrides the default flags for the different CMAKE_BUILD_TYPEs
set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/compiler_flags_override.cmake")
project(Z3 C CXX)
set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake")
project(Z3 CXX)
################################################################################
# Project version
@ -37,16 +36,20 @@ set(Z3_VERSION_PATCH 1)
set(Z3_VERSION_TWEAK 0304)
set(Z3_FULL_VERSION 0)
set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}")
set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified
message(STATUS "Z3 version ${Z3_VERSION}")
################################################################################
# Set various useful variables depending on CMake version
################################################################################
if (("${CMAKE_VERSION}" VERSION_EQUAL "3.2") OR ("${CMAKE_VERSION}" VERSION_GREATER "3.2"))
# In CMake >= 3.2 add_custom_command() supports a ``USES_TERMINAL`` argument
# In CMake >= 3.2 add_custom_command() and add_custom_target()
# supports a ``USES_TERMINAL`` argument
set(ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG "USES_TERMINAL")
set(ADD_CUSTOM_TARGET_USES_TERMINAL_ARG "USES_TERMINAL")
else()
set(ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG "")
set(ADD_CUSTOM_TARGET_USES_TERMINAL_ARG "")
endif()
################################################################################
@ -75,6 +78,64 @@ endif()
################################################################################
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
################################################################################
# Handle git hash and description
################################################################################
include(${CMAKE_SOURCE_DIR}/cmake/git_utils.cmake)
macro(disable_git_describe)
message(WARNING "Disabling INCLUDE_GIT_DESCRIBE")
set(INCLUDE_GIT_DESCRIBE OFF CACHE BOOL "Include git describe output in version output" FORCE)
endmacro()
macro(disable_git_hash)
message(WARNING "Disabling INCLUDE_GIT_HASH")
set(INCLUDE_GIT_HASH OFF CACHE BOOL "Include git hash in version output" FORCE)
unset(Z3GITHASH) # Used in configure_file()
endmacro()
option(INCLUDE_GIT_HASH "Include git hash in version output" ON)
option(INCLUDE_GIT_DESCRIBE "Include git describe output in version output" ON)
set(GIT_DIR "${CMAKE_SOURCE_DIR}/.git")
if (EXISTS "${GIT_DIR}")
# Try to make CMake configure depend on the current git HEAD so that
# a re-configure is triggered when the HEAD changes.
add_git_dir_dependency("${GIT_DIR}" ADD_GIT_DEP_SUCCESS)
if (ADD_GIT_DEP_SUCCESS)
if (INCLUDE_GIT_HASH)
get_git_head_hash("${GIT_DIR}" Z3GITHASH)
if (NOT Z3GITHASH)
message(WARNING "Failed to get Git hash")
disable_git_hash()
endif()
message(STATUS "Using Git hash in version output: ${Z3GITHASH}")
# This mimics the behaviour of the old build system.
string(APPEND Z3_FULL_VERSION_STR " ${Z3GITHASH}")
else()
message(STATUS "Not using Git hash in version output")
unset(Z3GITHASH) # Used in configure_file()
endif()
if (INCLUDE_GIT_DESCRIBE)
get_git_head_describe("${GIT_DIR}" Z3_GIT_DESCRIPTION)
if (NOT Z3_GIT_DESCRIPTION)
message(WARNING "Failed to get Git description")
disable_git_describe()
endif()
message(STATUS "Using Git description in version output: ${Z3_GIT_DESCRIPTION}")
# This mimics the behaviour of the old build system.
string(APPEND Z3_FULL_VERSION_STR " ${Z3_GIT_DESCRIPTION}")
else()
message(STATUS "Not including git descrption in version")
endif()
else()
message(WARNING "Failed to add git dependency.")
disable_git_describe()
disable_git_hash()
endif()
else()
message(STATUS "Failed to find git directory.")
disable_git_describe()
disable_git_hash()
endif()
################################################################################
# Useful CMake functions/Macros
################################################################################
@ -89,19 +150,18 @@ set(Z3_COMPONENT_CXX_FLAGS "")
set(Z3_COMPONENT_EXTRA_INCLUDE_DIRS "")
set(Z3_DEPENDENT_LIBS "")
set(Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS "")
set(Z3_DEPENDENT_EXTRA_C_LINK_FLAGS "")
################################################################################
# Build type
################################################################################
message(STATUS "CMake generator: ${CMAKE_GENERATOR}")
set(available_build_types Debug Release RelWithDebInfo MinSizeRel)
if (DEFINED CMAKE_CONFIGURATION_TYPES)
# Multi-configuration build (e.g. Visual Studio and Xcode). Here
# CMAKE_BUILD_TYPE doesn't matter
message(STATUS "Available configurations: ${CMAKE_CONFIGURATION_TYPES}")
else()
# Single configuration generator (e.g. Unix Makefiles, Ninja)
set(available_build_types Debug Release RelWithDebInfo MinSizeRel)
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "CMAKE_BUILD_TYPE is not set. Setting default")
message(STATUS "The available build types are: ${available_build_types}")
@ -236,11 +296,7 @@ if (OPENMP_FOUND)
# 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_C_FLAGS})
endif()
if (("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") OR
("${CMAKE_C_COMPILER_ID}" MATCHES "GNU"))
list(APPEND Z3_DEPENDENT_EXTRA_C_LINK_FLAGS ${OpenMP_CXX_FLAGS})
list(APPEND Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS ${OpenMP_CXX_FLAGS})
endif()
unset(CMAKE_REQUIRED_FLAGS)
message(STATUS "Using OpenMP")
@ -270,6 +326,15 @@ if (("${TARGET_ARCHITECTURE}" STREQUAL "x86_64") OR ("${TARGET_ARCHITECTURE}" ST
unset(SSE_FLAGS)
endif()
# FIXME: Remove "x.." when CMP0054 is set to NEW
if ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
# This is the default for MSVC already but to replicate the
# python/Makefile build system behaviour this flag is set
# explicitly.
z3_add_cxx_flag("/fp:precise" REQUIRED)
endif()
# There doesn't seem to be an equivalent for clang/gcc
################################################################################
# Threading support
################################################################################
@ -320,6 +385,41 @@ if (BUILD_LIBZ3_SHARED)
endif()
endif()
################################################################################
# Link time optimization
################################################################################
include(${CMAKE_SOURCE_DIR}/cmake/compiler_lto.cmake)
################################################################################
# MSVC specific flags inherited from old build system
################################################################################
# FIXME: Remove "x.." when CMP0054 is set to NEW
if ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
include(${CMAKE_SOURCE_DIR}/cmake/msvc_legacy_quirks.cmake)
endif()
################################################################################
# Report default CMake flags
################################################################################
# This is mainly for debugging.
message(STATUS "CMAKE_CXX_FLAGS: \"${CMAKE_CXX_FLAGS}\"")
message(STATUS "CMAKE_EXE_LINKER_FLAGS: \"${CMAKE_EXE_LINKER_FLAGS}\"")
message(STATUS "CMAKE_STATIC_LINKER_FLAGS: \"${CMAKE_STATIC_LINKER_FLAGS}\"")
message(STATUS "CMAKE_SHARED_LINKER_FLAGS: \"${CMAKE_SHARED_LINKER_FLAGS}\"")
if (DEFINED CMAKE_CONFIGURATION_TYPES)
# Multi configuration generator
string(TOUPPER "${available_build_types}" build_types_to_report)
else()
# Single configuration generator
string(TOUPPER "${CMAKE_BUILD_TYPE}" build_types_to_report)
endif()
foreach (_build_type ${build_types_to_report})
message(STATUS "CMAKE_CXX_FLAGS_${_build_type}: \"${CMAKE_CXX_FLAGS_${_build_type}}\"")
message(STATUS "CMAKE_EXE_LINKER_FLAGS_${_build_type}: \"${CMAKE_EXE_LINKER_FLAGS_${_build_type}}\"")
message(STATUS "CMAKE_SHARED_LINKER_FLAGS_${_build_type}: \"${CMAKE_SHARED_LINKER_FLAGS_${_build_type}}\"")
message(STATUS "CMAKE_STATIC_LINKER_FLAGS_${_build_type}: \"${CMAKE_STATIC_LINKER_FLAGS_${_build_type}}\"")
endforeach()
################################################################################
# Report Z3_COMPONENT flags
################################################################################
@ -328,7 +428,6 @@ message(STATUS "Z3_COMPONENT_CXX_FLAGS: ${Z3_COMPONENT_CXX_FLAGS}")
message(STATUS "Z3_DEPENDENT_LIBS: ${Z3_DEPENDENT_LIBS}")
message(STATUS "Z3_COMPONENT_EXTRA_INCLUDE_DIRS: ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS}")
message(STATUS "Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS: ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS}")
message(STATUS "Z3_DEPENDENT_EXTRA_C_LINK_FLAGS: ${Z3_DEPENDENT_EXTRA_C_LINK_FLAGS}")
################################################################################
# Z3 installation locations
@ -340,10 +439,18 @@ set(CMAKE_INSTALL_PKGCONFIGDIR
PATH
"Directory to install pkgconfig files"
)
set(CMAKE_INSTALL_Z3_CMAKE_PACKAGE_DIR
"${CMAKE_INSTALL_LIBDIR}/cmake/z3"
CACHE
PATH
"Directory to install Z3 CMake package files"
)
message(STATUS "CMAKE_INSTALL_LIBDIR: \"${CMAKE_INSTALL_LIBDIR}\"")
message(STATUS "CMAKE_INSTALL_BINDIR: \"${CMAKE_INSTALL_BINDIR}\"")
message(STATUS "CMAKE_INSTALL_INCLUDEDIR: \"${CMAKE_INSTALL_INCLUDEDIR}\"")
message(STATUS "CMAKE_INSTALL_PKGCONFIGDIR: \"${CMAKE_INSTALL_PKGCONFIGDIR}\"")
message(STATUS "CMAKE_INSTALL_Z3_CMAKE_PACKAGE_DIR: \"${CMAKE_INSTALL_Z3_CMAKE_PACKAGE_DIR}\"")
################################################################################
# Uninstall rule
@ -391,6 +498,76 @@ include(${CMAKE_SOURCE_DIR}/cmake/z3_add_component.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/z3_append_linker_flag_list_to_target.cmake)
add_subdirectory(src)
################################################################################
# Create `Z3Config.cmake` and related files for the build tree so clients can
# use Z3 via CMake.
################################################################################
include(CMakePackageConfigHelpers)
export(EXPORT Z3_EXPORTED_TARGETS
NAMESPACE z3::
FILE "${CMAKE_BINARY_DIR}/Z3Targets.cmake"
)
set(Z3_FIRST_PACKAGE_INCLUDE_DIR "${CMAKE_BINARY_DIR}/src/api")
set(Z3_SECOND_PACKAGE_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/src/api")
set(Z3_CXX_PACKAGE_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/src/api/c++")
set(AUTO_GEN_MSG "Automatically generated. DO NOT EDIT")
set(CONFIG_FILE_TYPE "build tree")
configure_package_config_file("${CMAKE_SOURCE_DIR}/cmake/Z3Config.cmake.in"
"Z3Config.cmake"
INSTALL_DESTINATION "${CMAKE_BINARY_DIR}"
PATH_VARS
Z3_FIRST_PACKAGE_INCLUDE_DIR
Z3_SECOND_PACKAGE_INCLUDE_DIR
Z3_CXX_PACKAGE_INCLUDE_DIR
INSTALL_PREFIX "${CMAKE_BINARY_DIR}"
)
unset(Z3_FIRST_PACKAGE_INCLUDE_DIR)
unset(Z3_SECOND_PACKAGE_INCLUDE_DIR)
unset(Z3_CXX_PACKAGE_INCLUDE_DIR)
unset(AUTO_GEN_MSG)
unset(CONFIG_FILE_TYPE)
# TODO: Provide a `Z3Version.cmake` file so that clients can specify the version
# of Z3 they want.
################################################################################
# Create `Z3Config.cmake` and related files for install tree so clients can use
# Z3 via CMake.
################################################################################
install(EXPORT
Z3_EXPORTED_TARGETS
FILE "Z3Targets.cmake"
NAMESPACE z3::
DESTINATION "${CMAKE_INSTALL_Z3_CMAKE_PACKAGE_DIR}"
)
set(Z3_INSTALL_TREE_CMAKE_CONFIG_FILE "${CMAKE_BINARY_DIR}/cmake/Z3Config.cmake")
set(Z3_FIRST_PACKAGE_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}")
set(Z3_SECOND_INCLUDE_DIR "")
set(Z3_CXX_PACKAGE_INCLUDE_DIR "")
set(AUTO_GEN_MSG "Automatically generated. DO NOT EDIT")
set(CONFIG_FILE_TYPE "install tree")
# We use `configure_package_config_file()` to try and create CMake files
# that are re-locatable so that it doesn't matter if the files aren't placed
# in the original install prefix.
configure_package_config_file("${CMAKE_SOURCE_DIR}/cmake/Z3Config.cmake.in"
"${Z3_INSTALL_TREE_CMAKE_CONFIG_FILE}"
INSTALL_DESTINATION "${CMAKE_INSTALL_Z3_CMAKE_PACKAGE_DIR}"
PATH_VARS Z3_FIRST_PACKAGE_INCLUDE_DIR
)
unset(Z3_FIRST_PACKAGE_INCLUDE_DIR)
unset(Z3_SECOND_PACKAGE_INCLUDE_DIR)
unset(Z3_CXX_PACKAGE_INCLUDE_DIR)
unset(AUTO_GEN_MSG)
unset(CONFIG_FILE_TYPE)
# Add install rule to install ${Z3_INSTALL_TREE_CMAKE_CONFIG_FILE}
install(
FILES "${Z3_INSTALL_TREE_CMAKE_CONFIG_FILE}"
DESTINATION "${CMAKE_INSTALL_Z3_CMAKE_PACKAGE_DIR}"
)
# TODO: Provide a `Z3Version.cmake` file so that clients can specify the version
# of Z3 they want.
################################################################################
# Examples
################################################################################
@ -398,3 +575,14 @@ option(ENABLE_EXAMPLE_TARGETS "Build Z3 api examples" ON)
if (ENABLE_EXAMPLE_TARGETS)
add_subdirectory(examples)
endif()
################################################################################
# Documentation
################################################################################
option(BUILD_DOCUMENTATION "Build API documentation" OFF)
if (BUILD_DOCUMENTATION)
message(STATUS "Building documentation enabled")
add_subdirectory(doc)
else()
message(STATUS "Building documentation disabled")
endif()

View file

@ -2,6 +2,9 @@ Z3
Copyright (c) Microsoft Corporation
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -267,6 +267,8 @@ The following useful options can be passed to CMake whilst configuring.
* ``CMAKE_INSTALL_PREFIX`` - STRING. The install prefix to use (e.g. ``/usr/local/``).
* ``CMAKE_INSTALL_PKGCONFIGDIR`` - STRING. The path to install pkgconfig files.
* ``CMAKE_INSTALL_PYTHON_PKG_DIR`` - STRING. The path to install the z3 python bindings. This can be relative (to ``CMAKE_INSTALL_PREFIX``) or absolute.
* ``CMAKE_INSTALL_Z3_CMAKE_PACKAGE_DIR`` - STRING. The path to install CMake package files (e.g. ``/usr/lib/cmake/z3``).
* ``CMAKE_INSTALL_API_BINDINGS_DOC`` - STRING. The path to install documentation for API bindings.
* ``ENABLE_TRACING_FOR_NON_DEBUG`` - BOOL. If set to ``TRUE`` enable tracing in non-debug builds, if set to ``FALSE`` disable tracing in non-debug builds. Note in debug builds tracing is always enabled.
* ``BUILD_LIBZ3_SHARED`` - BOOL. If set to ``TRUE`` build libz3 as a shared library otherwise build as a static library.
* ``ENABLE_EXAMPLE_TARGETS`` - BOOL. If set to ``TRUE`` add the build targets for building the API examples.
@ -283,6 +285,14 @@ The following useful options can be passed to CMake whilst configuring.
* ``INSTALL_JAVA_BINDINGS`` - BOOL. If set to ``TRUE`` and ``BUILD_JAVA_BINDINGS`` is ``TRUE`` then running the ``install`` target will install Z3's Java bindings.
* ``Z3_JAVA_JAR_INSTALLDIR`` - STRING. The path to directory to install the Z3 Java ``.jar`` file. This path should be relative to ``CMAKE_INSTALL_PREFIX``.
* ``Z3_JAVA_JNI_LIB_INSTALLDIRR`` - STRING. The path to directory to install the Z3 Java JNI bridge library. This path should be relative to ``CMAKE_INSTALL_PREFIX``.
* ``INCLUDE_GIT_DESCRIBE`` - BOOL. If set to ``TRUE`` and the source tree of Z3 is a git repository then the output of ``git describe`` will be included in the build.
* ``INCLUDE_GIT_HASH`` - BOOL. If set to ``TRUE`` and the source tree of Z3 is a git repository then the git hash will be included in the build.
* ``BUILD_DOCUMENTATION`` - BOOL. If set to ``TRUE`` then documentation for the API bindings can be built by invoking the ``api_docs`` target.
* ``INSTALL_API_BINDINGS_DOCUMENTATION`` - BOOL. If set to ``TRUE`` and ``BUILD_DOCUMENTATION` is ``TRUE`` then documentation for API bindings will be installed
when running the ``install`` target.
* ``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.
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.
@ -414,6 +424,7 @@ There are a few special targets:
* ``clean`` all the built targets in the current directory and below
* ``edit_cache`` will invoke one of the CMake tools (depending on which is available) to let you change configuration options.
* ``rebuild_cache`` will reinvoke ``cmake`` for the project.
* ``api_docs`` will build the documentation for the API bindings.
### Setting build type specific flags

View file

@ -53,8 +53,8 @@ make
sudo make install
```
Note by default ``gcc`` is used as the C++ compiler if it is available. If you
would prefer to use Clang change the ``mk_make.py`` line to
Note by default ``g++`` is used as the C++ compiler if it is available. If you
would prefer to use Clang change the ``mk_make.py`` invocation to:
```bash
CXX=clang++ CC=clang python scripts/mk_make.py

View file

@ -0,0 +1,30 @@
################################################################################
# @AUTO_GEN_MSG@
#
# This file is intended to be consumed by clients who wish to use Z3 from CMake.
# It can be use by doing `find_package(Z3 config)` from within a
# `CMakeLists.txt` file. If CMake doesn't find this package automatically you
# can give it a hint by passing `-DZ3_DIR=<path>` to the CMake invocation where
# `<path>` is the path to the directory containing this file.
#
# This file was built for the @CONFIG_FILE_TYPE@.
################################################################################
# Exported targets
include("${CMAKE_CURRENT_LIST_DIR}/Z3Targets.cmake")
@PACKAGE_INIT@
# Version information
set(Z3_VERSION_MAJOR @Z3_VERSION_MAJOR@)
set(Z3_VERSION_MINOR @Z3_VERSION_MINOR@)
set(Z3_VERSION_PATCH @Z3_VERSION_PATCH@)
set(Z3_VERSION_TWEAK @Z3_VERSION_TWEAK@)
set(Z3_VERSION_STRING "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}")
# NOTE: We can't use `set_and_check()` here because this a list of paths.
# List of include directories
set(Z3_C_INCLUDE_DIRS @PACKAGE_Z3_FIRST_PACKAGE_INCLUDE_DIR@ @PACKAGE_Z3_SECOND_PACKAGE_INCLUDE_DIR@)
set(Z3_CXX_INCLUDE_DIRS @PACKAGE_Z3_CXX_PACKAGE_INCLUDE_DIR@ ${Z3_C_INCLUDE_DIRS})
# List of libraries to link against
set(Z3_LIBRARIES "z3::libz3")

View file

@ -1,43 +0,0 @@
# This file overrides the default compiler flags for CMake's built-in
# configurations (CMAKE_BUILD_TYPE). Most compiler flags should not be set here.
# The main purpose is to have very fine grained control of the compiler flags.
if (CMAKE_C_COMPILER_ID)
set(_lang C)
elseif(CMAKE_CXX_COMPILER_ID)
set(_lang CXX)
else()
message(FATAL_ERROR "Unknown language")
endif()
# TODO: The value of doing this is debatable. The flags set here are pretty
# much the CMake defaults now (they didn't use to be) and makes extra work for
# us when supporting different compilers. Perhaps we should move the remaining
# code that sets non-default flags out into the CMakeLists.txt files and remove
# any overrides here?
if (("${CMAKE_${_lang}_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_${_lang}_COMPILER_ID}" MATCHES "GNU"))
# Taken from Modules/Compiler/GNU.cmake
set(CMAKE_${_lang}_FLAGS_INIT "")
set(CMAKE_${_lang}_FLAGS_DEBUG_INIT "-g -O0")
set(CMAKE_${_lang}_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG")
set(CMAKE_${_lang}_FLAGS_RELEASE_INIT "-O3 -DNDEBUG")
set(CMAKE_${_lang}_FLAGS_RELWITHDEBINFO_INIT "-O2 -g -DNDEBUG")
# FIXME: Remove "x.." when CMP0054 is set to NEW
elseif ("x${CMAKE_${_lang}_COMPILER_ID}" STREQUAL "xMSVC")
# FIXME: Perhaps we should be using /MD instead?
set(CMAKE_${_lang}_FLAGS_DEBUG_INIT "/MTd /Zi /Ob0 /Od /RTC1")
set(CMAKE_${_lang}_FLAGS_MINSIZEREL_INIT "/MT /O1 /Ob1 /D NDEBUG")
set(CMAKE_${_lang}_FLAGS_RELEASE_INIT "/MT /O2 /Ob2 /D NDEBUG")
set(CMAKE_${_lang}_FLAGS_RELWITHDEBINFO_INIT "/MT /Zi /O2 /Ob1 /D NDEBUG")
# Override linker flags (see Windows-MSVC.cmake for CMake's defaults)
# The stack size comes from the Python build system.
set(_msvc_stack_size "8388608")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG_INIT "/debug /INCREMENTAL:NO /STACK:${_msvc_stack_size}")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO_INIT "/debug /INCREMENTAL:NO /STACK:${_msvc_stack_size}")
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL_INIT "/INCREMENTAL:NO /STACK:${_msvc_stack_size}")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE_INIT "/INCREMENTAL:NO /STACK:${_msvc_stack_size}")
unset(_msvc_stack_size)
else()
message(FATAL_ERROR "Overrides not set for ${_lang} compiler \"${CMAKE_${_lang}_COMPILER_ID}\"")
endif()
unset(_lang)

View file

@ -0,0 +1,52 @@
option(LINK_TIME_OPTIMIZATION "Use link time optimiziation" OFF)
if (LINK_TIME_OPTIMIZATION)
message(STATUS "LTO enabled")
set(build_types_with_lto "RELEASE" "RELWITHDEBINFO")
if (DEFINED CMAKE_CONFIGURATION_TYPES)
# Multi configuration generator
message(STATUS "Note LTO is only enabled for the following configurations: ${build_types_with_lto}")
else()
# Single configuration generator
string(TOUPPER "${CMAKE_BUILD_TYPE}" _build_type_upper)
list(FIND build_types_with_lto "${_build_type_upper}" _index)
if ("${_index}" EQUAL -1)
message(FATAL_ERROR "Configuration ${CMAKE_BUILD_TYPE} does not support LTO."
"You should set LINK_TIME_OPTIMIZATION to OFF.")
endif()
endif()
set(_lto_compiler_flag "")
set(_lto_linker_flag "")
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR
("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU"))
set(_lto_compiler_flag "-flto")
set(_lto_linker_flag "-flto")
# FIXME: Remove "x.." when CMP0054 is set to NEW
elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
set(_lto_compiler_flag "/GL")
set(_lto_linker_flag "/LTCG")
else()
message(FATAL_ERROR "Can't enable LTO for compiler \"${CMAKE_CXX_COMPILER_ID}\"."
"You should set LINK_TIME_OPTIMIZATION to OFF.")
endif()
CHECK_CXX_COMPILER_FLAG("${_lto_compiler_flag}" HAS_LTO)
if (NOT HAS_LTO)
message(FATAL_ERROR "Compiler does not support LTO")
endif()
foreach (_config ${build_types_with_lto})
# Set flags compiler and linker flags globally rather than using
# `Z3_COMPONENT_CXX_FLAGS` and `Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS`
# respectively. We need per configuration compiler and linker flags. The
# `LINK_FLAGS` property (which we populate with
# `Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS`) doesn't seem to support generator
# expressions so we can't do `$<$<CONFIG:Release>:${_lto_linker_flag}>`.
set(CMAKE_CXX_FLAGS_${_config} "${CMAKE_CXX_FLAGS_${_config}} ${_lto_compiler_flag}")
set(CMAKE_EXE_LINKER_FLAGS_${_config} "${CMAKE_EXE_LINKER_FLAGS_${_config}} ${_lto_linker_flag}")
set(CMAKE_SHARED_LINKER_FLAGS_${_config} "${CMAKE_SHARED_LINKER_FLAGS_${_config}} ${_lto_linker_flag}")
set(CMAKE_STATIC_LINKER_FLAGS_${_config} "${CMAKE_STATIC_LINKER_FLAGS_${_config}} ${_lto_linker_flag}")
endforeach()
else()
message(STATUS "LTO disabled")
endif()

View file

@ -15,6 +15,13 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
# FIXME: Remove "x.." when CMP0054 is set to NEW
elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
list(APPEND WARNING_FLAGS_TO_CHECK ${MSVC_WARNINGS})
# CMake's default flags include /W3 already so remove them if
# they already exist.
if ("${CMAKE_CXX_FLAGS}" MATCHES "/W3")
string(REPLACE "/W3" "" _cmake_cxx_flags_remove_w3 "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${_cmake_cxx_flags_remove_w3}" CACHE STRING "" FORCE)
endif()
else()
message(AUTHOR_WARNING "Unknown compiler")
endif()
@ -37,4 +44,11 @@ if (WARNINGS_AS_ERRORS)
message(STATUS "Treating compiler warnings as errors")
else()
message(STATUS "Not treating compiler warnings as errors")
# FIXME: Remove "x.." when CMP0054 is set to NEW
if ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
# Warnings as errors is off by default for MSVC so setting this
# is not necessary but this duplicates the behaviour of the old
# build system.
list(APPEND Z3_COMPONENT_CXX_FLAGS "/WX-")
endif()
endif()

View file

@ -0,0 +1,14 @@
# This file overrides the default compiler flags for CMake's built-in
# configurations (CMAKE_BUILD_TYPE). Most compiler flags should not be set here.
# The main purpose is to have very fine grained control of the compiler flags.
# We only override the defaults for Clang and GCC right now.
# CMake's MSVC logic is complicated so for now it's better to just inherit CMake's defaults.
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU"))
# Taken from Modules/Compiler/GNU.cmake
set(CMAKE_CXX_FLAGS_INIT "")
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g -O0")
set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O2 -g -DNDEBUG")
endif()

View file

@ -0,0 +1,173 @@
# add_git_dir_dependency(GIT_DIR SUCCESS_VAR)
#
# Adds a configure time dependency on the git directory such that if the HEAD
# 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)
# `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)
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")
endif()
if (NOT IS_DIRECTORY "${GIT_DIR}")
message(FATAL_ERROR "GIT_DIR (\"${GIT_DIR}\") is not a directory")
endif()
set(GIT_HEAD_FILE "${GIT_DIR}/HEAD")
if (NOT EXISTS "${GIT_HEAD_FILE}")
message(AUTHOR_WARNING "Git head file \"${GIT_HEAD_FILE}\" cannot be found")
set(${SUCCESS_VAR} FALSE PARENT_SCOPE)
return()
endif()
# List of files in the git tree that CMake configuration should depend on
set(GIT_FILE_DEPS "${GIT_HEAD_FILE}")
# Examine the HEAD and workout what additional dependencies there are.
file(READ "${GIT_HEAD_FILE}" GIT_HEAD_DATA LIMIT 128)
string(STRIP "${GIT_HEAD_DATA}" GIT_HEAD_DATA_STRIPPED)
if ("${GIT_HEAD_DATA_STRIPPED}" MATCHES "^ref:[ ]*(.+)$")
# HEAD points at a reference.
set(GIT_REF "${CMAKE_MATCH_1}")
if (EXISTS "${GIT_DIR}/${GIT_REF}")
# Unpacked reference. The file contains the commit hash
# so add a dependency on this file so that if we stay on this
# reference (i.e. branch) but change commit CMake will be forced
# to reconfigure.
list(APPEND GIT_FILE_DEPS "${GIT_DIR}/${GIT_REF}")
elseif(EXISTS "${GIT_DIR}/packed-refs")
# The ref must be packed (see `man git-pack-refs`).
list(APPEND GIT_FILE_DEPS "${GIT_DIR}/packed-refs")
else()
# Fail
message(AUTHOR_WARNING "Unhandled git reference")
set(${SUCCESS_VAR} FALSE PARENT_SCOPE)
return()
endif()
else()
# Detached HEAD.
# No other dependencies needed
endif()
# FIXME:
# This is the directory we will copy (via `configure_file()`) git files
# into. This is a hack. It would be better to use the
# `CMAKE_CONFIGURE_DEPENDS` directory property but that feature is not
# available in CMake 2.8.12. So we use `configure_file()` to effectively
# do the same thing. When the source file to `configure_file()` changes
# it will trigger a re-run of CMake.
set(GIT_CMAKE_FILES_DIR "${CMAKE_CURRENT_BINARY_DIR}/git_cmake_files")
file(MAKE_DIRECTORY "${GIT_CMAKE_FILES_DIR}")
foreach (git_dependency ${GIT_FILE_DEPS})
message(STATUS "Adding git dependency \"${git_dependency}\"")
configure_file(
"${git_dependency}"
"${GIT_CMAKE_FILES_DIR}"
COPYONLY
)
endforeach()
set(${SUCCESS_VAR} TRUE PARENT_SCOPE)
endfunction()
# get_git_head_hash(GIT_DIR 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.
#
# `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)
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")
endif()
if (NOT IS_ABSOLUTE "${GIT_DIR}")
message(FATAL_ERROR \""${GIT_DIR}\" is not an absolute path")
endif()
find_package(Git)
if (NOT Git_FOUND)
set(${OUTPUT_VAR} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
get_filename_component(GIT_WORKING_DIR "${GIT_DIR}" DIRECTORY)
execute_process(
COMMAND
"${GIT_EXECUTABLE}"
"rev-parse"
"-q" # Quiet
"HEAD"
WORKING_DIRECTORY
"${GIT_WORKING_DIR}"
RESULT_VARIABLE
GIT_EXIT_CODE
OUTPUT_VARIABLE
Z3_GIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (NOT "${GIT_EXIT_CODE}" EQUAL 0)
message(WARNING "Failed to execute git")
set(${OUTPUT_VAR} NOTFOUND PARENT_SCOPE)
return()
endif()
set(${OUTPUT_VAR} "${Z3_GIT_HASH}" PARENT_SCOPE)
endfunction()
# get_git_head_describe(GIT_DIR 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.
#
# `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)
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")
endif()
if (NOT IS_ABSOLUTE "${GIT_DIR}")
message(FATAL_ERROR \""${GIT_DIR}\" is not an absolute path")
endif()
find_package(Git)
if (NOT Git_FOUND)
set(${OUTPUT_VAR} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
get_filename_component(GIT_WORKING_DIR "${GIT_DIR}" DIRECTORY)
execute_process(
COMMAND
"${GIT_EXECUTABLE}"
"describe"
"--long"
WORKING_DIRECTORY
"${GIT_WORKING_DIR}"
RESULT_VARIABLE
GIT_EXIT_CODE
OUTPUT_VARIABLE
Z3_GIT_DESCRIPTION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (NOT "${GIT_EXIT_CODE}" EQUAL 0)
message(WARNING "Failed to execute git")
set(${OUTPUT_VAR} NOTFOUND PARENT_SCOPE)
return()
endif()
set(${OUTPUT_VAR} "${Z3_GIT_DESCRIPTION}" PARENT_SCOPE)
endfunction()

View file

@ -0,0 +1,194 @@
# This file ether sets or notes various compiler and linker flags for MSVC that
# were defined by the old python/Makefile based build system but
# don't obviously belong in the other sections in the CMake build system.
################################################################################
# Compiler definitions
################################################################################
# FIXME: All the commented out defines should be removed once
# we are confident it is correct to not set them.
set(Z3_MSVC_LEGACY_DEFINES
# Don't set `_DEBUG`. The old build sytem sets this but this
# is wrong. MSVC will set this depending on which runtime is being used.
# See https://msdn.microsoft.com/en-us/library/b0084kay.aspx
# _DEBUG
# The old build system only set `UNICODE` and `_UNICODE` for x86_64 release.
# That seems completly wrong so set it for all configurations.
# According to https://blogs.msdn.microsoft.com/oldnewthing/20040212-00/?p=40643/
# `UNICODE` affects Windows headers and `_UNICODE` affects C runtime header files.
# There is some discussion of this define at https://msdn.microsoft.com/en-us/library/dybsewaf.aspx
UNICODE
_UNICODE
)
if ("${TARGET_ARCHITECTURE}" STREQUAL "x86_64")
list(APPEND Z3_MSVC_LEGACY_DEFINES ""
# Don't set `_LIB`. The old build system sets this for x86_64 release
# build. This flag doesn't seem to be documented but a stackoverflow
# post hints that this is usually set when building a static library.
# See http://stackoverflow.com/questions/35034683/how-to-tell-if-current-project-is-dll-or-static-lib
# This seems wrong give that the old build system set this regardless
# whether or not libz3 was static or shared so its probably best
# to not set for now.
#$<$<CONFIG:Release>:_LIB>
#$<$<CONFIG:RelWithDebInfo>:_LIB>
# Don't set `_CONSOLE`. The old build system sets for all configurations
# except x86_64 release. It seems ( https://codeyarns.com/2010/12/02/visual-c-windows-and-console-subsystems/ )
# that `_CONSOLE` used to be defined by older Visual C++ environments.
# Setting this undocumented option seems like a bad idea so let's not do it.
#$<$<CONFIG:Debug:_CONSOLE>
#$<$<CONFIG:MinSizeRel:_CONSOLE>
# Don't set `ASYNC_COMMANDS`. The old build system sets this for x86_64
# release but this macro does not appear to be used anywhere and is not
# documented so don't set it for now.
#$<$<CONFIG:Release>:ASYNC_COMMANDS>
#$<$<CONFIG:RelWithDebInfo>:ASYNC_COMMANDS>
)
else()
list(APPEND Z3_MSVC_LEGACY_DEFINES ""
# Don't set `_CONSOLE`. See reasoning above.
#_CONSOLE
)
endif()
# Note we don't set WIN32 or _WINDOWS because
# CMake provides that for us. As a sanity check make sure the option
# is present.
if (NOT "${CMAKE_CXX_FLAGS}" MATCHES "/D[ ]*WIN32")
message(FATAL_ERROR "\"/D WIN32\" is missing")
endif()
if (NOT "${CMAKE_CXX_FLAGS}" MATCHES "/D[ ]*_WINDOWS")
message(FATAL_ERROR "\"/D _WINDOWS\" is missing")
endif()
list(APPEND Z3_COMPONENT_CXX_DEFINES ${Z3_MSVC_LEGACY_DEFINES})
################################################################################
# Compiler flags
################################################################################
# By default in MSVC this is on but the old build system set this explicitly so
# for completeness set it too.
# See https://msdn.microsoft.com/en-us/library/dh8che7s.aspx
z3_add_cxx_flag("/Zc:wchar_t" REQUIRED)
# By default in MSVC this on but the old build system set this explicitly so
# for completeness set it too.
z3_add_cxx_flag("/Zc:forScope" REQUIRED)
# FIXME: We might want to move this out somewhere else if we decide
# we want to set `-fno-omit-frame-pointer` for gcc/clang.
# No omit frame pointer
set(NO_OMIT_FRAME_POINTER_MSVC_FLAG "/Oy-")
CHECK_CXX_COMPILER_FLAG(${NO_OMIT_FRAME_POINTER_MSVC_FLAG} HAS_MSVC_NO_OMIT_FRAME_POINTER)
if (NOT HAS_MSVC_NO_OMIT_FRAME_POINTER)
message(FATAL_ERROR "${NO_OMIT_FRAME_POINTER_MSVC_FLAG} flag not supported")
endif()
# FIXME: This doesn't make a huge amount of sense but the old
# build system kept the frame pointer for all configurations
# except x86_64 release (I don't know why the frame pointer
# is kept for i686 release).
if ("${TARGET_ARCHITECTURE}" STREQUAL "x86_64")
list(APPEND Z3_COMPONENT_CXX_FLAGS
$<$<CONFIG:Debug>:${NO_OMIT_FRAME_POINTER_MSVC_FLAG}>
$<$<CONFIG:MinSizeRel>:${NO_OMIT_FRAME_POINTER_MSVC_FLAG}>
)
else()
list(APPEND Z3_COMPONENT_CXX_FLAGS ${NO_OMIT_FRAME_POINTER_MSVC_FLAG})
endif()
if (("${TARGET_ARCHITECTURE}" STREQUAL "x86_64") OR ("${TARGET_ARCHITECTURE}" STREQUAL "i686"))
# Use __cdecl calling convention. Apparently this is MSVC's default
# but the old build system set it so for completeness set it too.
# See https://msdn.microsoft.com/en-us/library/46t77ak2.aspx
z3_add_cxx_flag("/Gd" REQUIRED)
endif()
# FIXME: The old build system explicitly disables code analysis.
# I don't know why. Duplicate this behaviour for now.
# See https://msdn.microsoft.com/en-us/library/ms173498.aspx
z3_add_cxx_flag("/analyze-" REQUIRED)
################################################################################
# Linker flags
################################################################################
# By default CMake enables incremental linking for Debug and RelWithDebInfo
# builds. The old build sytem disables it for all builds so try to do the same
# by changing all configurations if necessary
string(TOUPPER "${available_build_types}" _build_types_as_upper)
foreach (_build_type ${_build_types_as_upper})
foreach (t EXE SHARED STATIC)
set(_replacement "/INCREMENTAL:NO")
# Remove any existing incremental flags
string(REGEX REPLACE
"/INCREMENTAL:YES"
"${_replacement}"
_replaced_linker_flags
"${CMAKE_${t}_LINKER_FLAGS_${_build_type}}")
string(REGEX REPLACE
"(/INCREMENTAL$)|(/INCREMENTAL )"
"${_replacement} "
_replaced_linker_flags
"${_replaced_linker_flags}")
if (NOT "${_replaced_linker_flags}" MATCHES "${_replacement}")
# Flag not present. Add it
string(APPEND _replaced_linker_flags " ${_replacement}")
endif()
set(CMAKE_${t}_LINKER_FLAGS_${_build_type} "${_replaced_linker_flags}")
endforeach()
endforeach()
# The original build system passes `/STACK:` to the linker.
# This size comes from the original build system.
# FIXME: What is the rationale behind this?
set(STACK_SIZE_MSVC_LINKER 8388608)
# MSVC documentation (https://msdn.microsoft.com/en-us/library/35yc2tc3.aspx)
# says this only matters for executables which is why this is not being
# set for CMAKE_SHARED_LINKER_FLAGS or CMAKE_STATIC_LINKER_FLAGS.
string(APPEND CMAKE_EXE_LINKER_FLAGS " /STACK:${STACK_SIZE_MSVC_LINKER}")
# The original build system passes `/SUBSYSTEM:<X>` to the linker where `<X>`
# depends on what is being linked. Where `<X>` is `CONSOLE` for executables
# and `WINDOWS` for shard libraries.
# We don't need to pass `/SUBSYSTEM:CONSOLE` because CMake will do this for
# us when building executables because we don't pass the `WIN32` argument to
# `add_executable()`.
# FIXME: We probably don't need this. https://msdn.microsoft.com/en-us/library/fcc1zstk.aspx
# suggests that `/SUBSYSTEM:` only matters for executables.
string(APPEND CMAKE_SHARED_LINKER_FLAGS " /SUBSYSTEM:WINDOWS")
# FIXME: The following linker flags are weird. They are set in all configurations
# in the old build system except release x86_64. We try to emulate this here but
# this is likely the wrong thing to do.
foreach (_build_type ${_build_types_as_upper})
if ("${TARGET_ARCHITECTURE}" STREQUAL "x86_64" AND
("${_build_type}" STREQUAL "RELEASE" OR
"${_build_type}" STREQUAL "RELWITHDEBINFO")
)
message(AUTHOR_WARNING "Skipping legacy linker MSVC options for x86_64 ${_build_type}")
else()
# Linker optimizations.
# See https://msdn.microsoft.com/en-us/library/bxwfs976.aspx
string(APPEND CMAKE_EXE_LINKER_FLAGS_${_build_type} " /OPT:REF /OPT:ICF")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_${_build_type} " /OPT:REF /OPT:ICF")
# FIXME: This is not necessary. This is MSVC's default.
# See https://msdn.microsoft.com/en-us/library/b1kw34cb.aspx
string(APPEND CMAKE_EXE_LINKER_FLAGS_${_build_type} " /TLBID:1")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_${_build_type} " /TLBID:1")
# FIXME: This is not necessary. This is MSVC's default.
# 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")
# FIXME: This is not necessary. This is MSVC's default.
# Indicate that the executable is compatible with DEP
# See https://msdn.microsoft.com/en-us/library/ms235442.aspx
string(APPEND CMAKE_EXE_LINKER_FLAGS_${_build_type} " /NXCOMPAT")
endif()
endforeach()

View file

@ -7,6 +7,7 @@ function(z3_add_cxx_flag flag)
string(REPLACE "/" "_" SANITIZED_FLAG_NAME "${SANITIZED_FLAG_NAME}")
string(REPLACE "=" "_" SANITIZED_FLAG_NAME "${SANITIZED_FLAG_NAME}")
string(REPLACE " " "_" SANITIZED_FLAG_NAME "${SANITIZED_FLAG_NAME}")
string(REPLACE ":" "_" SANITIZED_FLAG_NAME "${SANITIZED_FLAG_NAME}")
unset(HAS_${SANITIZED_FLAG_NAME})
CHECK_CXX_COMPILER_FLAG("${flag}" HAS_${SANITIZED_FLAG_NAME})
if (z3_add_flag_REQUIRED AND NOT HAS_${SANITIZED_FLAG_NAME})

View file

@ -0,0 +1,92 @@
find_package(Doxygen REQUIRED)
message(STATUS "DOXYGEN_EXECUTABLE: \"${DOXYGEN_EXECUTABLE}\"")
message(STATUS "DOXYGEN_VERSION: \"${DOXYGEN_VERSION}\"")
set(DOC_DEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/api")
set(DOC_TEMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/temp")
set(MK_API_DOC_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/mk_api_doc.py")
set(PYTHON_API_OPTIONS "")
set(DOTNET_API_OPTIONS "")
set(JAVA_API_OPTIONS "")
SET(DOC_EXTRA_DEPENDS "")
if (BUILD_PYTHON_BINDINGS)
# FIXME: Don't hard code this path
list(APPEND PYTHON_API_OPTIONS "--z3py-package-path" "${CMAKE_BINARY_DIR}/python/z3")
list(APPEND DOC_EXTRA_DEPENDS "build_z3_python_bindings")
else()
list(APPEND PYTHON_API_OPTIONS "--no-z3py")
endif()
if (BUILD_DOTNET_BINDINGS)
# FIXME: Don't hard code these paths
list(APPEND DOTNET_API_OPTIONS "--dotnet-search-paths"
"${CMAKE_SOURCE_DIR}/src/api/dotnet"
"${CMAKE_BINARY_DIR}/src/api/dotnet"
)
list(APPEND DOC_EXTRA_DEPENDS "build_z3_dotnet_bindings")
else()
list(APPEND DOTNET_API_OPTIONS "--no-dotnet")
endif()
if (BUILD_JAVA_BINDINGS)
# FIXME: Don't hard code these paths
list(APPEND JAVA_API_OPTIONS "--java-search-paths"
"${CMAKE_SOURCE_DIR}/src/api/java"
"${CMAKE_BINARY_DIR}/src/api/java"
)
list(APPEND DOC_EXTRA_DEPENDS "build_z3_java_bindings")
else()
list(APPEND JAVA_API_OPTIONS "--no-java")
endif()
option(ALWAYS_BUILD_DOCS "Always build documentation for API bindings" ON)
if (ALWAYS_BUILD_DOCS)
set(ALWAYS_BUILD_DOCS_ARG "ALL")
else()
set(ALWAYS_BUILD_DOCS_ARG "")
# FIXME: This sucks but there doesn't seem to be a way to make the top level
# install target depend on the `api_docs` target.
message(WARNING "Building documentation for API bindings is not part of the"
" all target. This may result in stale files being installed when running"
" the install target. You should run the api_docs target before running"
" the install target. Alternatively Set ALWAYS_BUILD_DOCS to ON to"
" automatically build documentation when running the install target."
)
endif()
add_custom_target(api_docs ${ALWAYS_BUILD_DOCS_ARG}
COMMAND
"${PYTHON_EXECUTABLE}" "${MK_API_DOC_SCRIPT}"
--doxygen-executable "${DOXYGEN_EXECUTABLE}"
--output-dir "${DOC_DEST_DIR}"
--temp-dir "${DOC_TEMP_DIR}"
${PYTHON_API_OPTIONS}
${DOTNET_API_OPTIONS}
${JAVA_API_OPTIONS}
DEPENDS
${DOC_EXTRA_DEPENDS}
COMMENT "Generating documentation"
${ADD_CUSTOM_TARGET_USES_TERMINAL_ARG}
)
# Remove generated documentation when running `clean` target.
set_property(DIRECTORY APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
"${DOC_DEST_DIR}"
)
option(INSTALL_API_BINDINGS_DOCUMENTATION "Install documentation for API bindings" ON)
set(CMAKE_INSTALL_API_BINDINGS_DOC
"${CMAKE_INSTALL_DOCDIR}"
CACHE
PATH
"Path to install documentation for API bindings"
)
if (INSTALL_API_BINDINGS_DOCUMENTATION)
install(
DIRECTORY "${DOC_DEST_DIR}"
DESTINATION "${CMAKE_INSTALL_API_BINDINGS_DOC}"
)
endif()

View file

@ -1,4 +1,64 @@
add_subdirectory(c)
add_subdirectory(c++)
add_subdirectory(tptp)
add_subdirectory(python)
include(ExternalProject)
# Unfortunately `BUILD_ALWAYS` only seems to be supported with the version of ExternalProject
# that shipped with CMake >= 3.1.
if (("${CMAKE_VERSION}" VERSION_EQUAL "3.1") OR ("${CMAKE_VERSION}" VERSION_GREATER "3.1"))
set(EXTERNAL_PROJECT_BUILD_ALWAYS_ARG BUILD_ALWAYS 1)
else()
set(EXTERNAL_PROJECT_BUILD_ALWAYS_ARG "")
endif()
################################################################################
# Build example project using libz3's C API as an external project
################################################################################
ExternalProject_Add(c_example
DEPENDS libz3
# Configure step
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/c"
CMAKE_ARGS "-DZ3_DIR=${CMAKE_BINARY_DIR}"
# Build step
${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG}
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/c_example_build_dir"
# Install Step
INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "" # Dummy command
)
set_target_properties(c_example PROPERTIES EXCLUDE_FROM_ALL TRUE)
################################################################################
# Build example project using libz3's C++ API as an external project
################################################################################
ExternalProject_Add(cpp_example
DEPENDS libz3
# Configure step
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/c++"
CMAKE_ARGS "-DZ3_DIR=${CMAKE_BINARY_DIR}"
# Build step
${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG}
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/cpp_example_build_dir"
# Install Step
INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "" # Dummy command
)
set_target_properties(cpp_example PROPERTIES EXCLUDE_FROM_ALL TRUE)
################################################################################
# Build example tptp5 project using libz3's C++ API as an external project
################################################################################
ExternalProject_Add(z3_tptp5
DEPENDS libz3
# Configure step
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tptp"
CMAKE_ARGS "-DZ3_DIR=${CMAKE_BINARY_DIR}"
# Build step
${EXTERNAL_PROJECT_BUILD_ALWAYS_ARG}
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/tptp_build_dir"
# Install Step
INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "" # Dummy command
)
set_target_properties(z3_tptp5 PROPERTIES EXCLUDE_FROM_ALL TRUE)
################################################################################
# Build Python examples
################################################################################
if (BUILD_PYTHON_BINDINGS)
add_subdirectory(python)
endif()

View file

@ -1,9 +1,38 @@
# FIXME: We should build this as an external project and consume
# Z3 as `find_package(z3 CONFIG)`.
add_executable(cpp_example EXCLUDE_FROM_ALL example.cpp)
target_link_libraries(cpp_example PRIVATE libz3)
target_include_directories(cpp_example PRIVATE "${CMAKE_SOURCE_DIR}/src/api")
target_include_directories(cpp_example PRIVATE "${CMAKE_SOURCE_DIR}/src/api/c++")
if (NOT BUILD_LIBZ3_SHARED)
z3_append_linker_flag_list_to_target(cpp_example ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS})
################################################################################
# Example C++ project
################################################################################
project(Z3_C_EXAMPLE CXX)
cmake_minimum_required(VERSION 2.8.12)
find_package(Z3
REQUIRED
CONFIG
# `NO_DEFAULT_PATH` is set so that -DZ3_DIR has to be passed to find Z3.
# This should prevent us from accidently picking up an installed
# copy of Z3. This is here to benefit Z3's build sytem when building
# this project. When making your own project you probably shouldn't
# use this option.
NO_DEFAULT_PATH
)
message(STATUS "Z3_FOUND: ${Z3_FOUND}")
message(STATUS "Found Z3 ${Z3_VERSION_STRING}")
message(STATUS "Z3_DIR: ${Z3_DIR}")
add_executable(cpp_example example.cpp)
target_include_directories(cpp_example PRIVATE ${Z3_CXX_INCLUDE_DIRS})
target_link_libraries(cpp_example PRIVATE ${Z3_LIBRARIES})
if ("${CMAKE_SYSTEM_NAME}" MATCHES "[Ww]indows")
# On Windows we need to copy the Z3 libraries
# into the same directory as the executable
# so that they can be found.
foreach (z3_lib ${Z3_LIBRARIES})
message(STATUS "Adding copy rule for ${z3_lib}")
add_custom_command(TARGET cpp_example
POST_BUILD
COMMAND
${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:${z3_lib}>
$<TARGET_FILE_DIR:cpp_example>
)
endforeach()
endif()

View file

@ -1,9 +1,42 @@
# FIXME: We should build this as an external project and consume
# Z3 as `find_package(z3 CONFIG)`.
add_executable(c_example EXCLUDE_FROM_ALL test_capi.c)
target_link_libraries(c_example PRIVATE libz3)
target_include_directories(c_example PRIVATE "${CMAKE_SOURCE_DIR}/src/api")
# This is needed for when libz3 is built as a static library
if (NOT BUILD_LIBZ3_SHARED)
z3_append_linker_flag_list_to_target(c_example ${Z3_DEPENDENT_EXTRA_C_LINK_FLAGS})
################################################################################
# Example C project
################################################################################
# NOTE: Even though this is a C project, libz3 uses C++. When using libz3
# as a static library if we don't configure this project to also support
# C++ we will use the C linker rather than the C++ linker and will not link
# the C++ standard library in resulting in a link failure.
project(Z3_C_EXAMPLE C CXX)
cmake_minimum_required(VERSION 2.8.12)
find_package(Z3
REQUIRED
CONFIG
# `NO_DEFAULT_PATH` is set so that -DZ3_DIR has to be passed to find Z3.
# This should prevent us from accidently picking up an installed
# copy of Z3. This is here to benefit Z3's build sytem when building
# this project. When making your own project you probably shouldn't
# use this option.
NO_DEFAULT_PATH
)
message(STATUS "Z3_FOUND: ${Z3_FOUND}")
message(STATUS "Found Z3 ${Z3_VERSION_STRING}")
message(STATUS "Z3_DIR: ${Z3_DIR}")
add_executable(c_example test_capi.c)
target_include_directories(c_example PRIVATE ${Z3_C_INCLUDE_DIRS})
target_link_libraries(c_example PRIVATE ${Z3_LIBRARIES})
if ("${CMAKE_SYSTEM_NAME}" MATCHES "[Ww]indows")
# On Windows we need to copy the Z3 libraries
# into the same directory as the executable
# so that they can be found.
foreach (z3_lib ${Z3_LIBRARIES})
message(STATUS "Adding copy rule for ${z3_lib}")
add_custom_command(TARGET c_example
POST_BUILD
COMMAND
${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:${z3_lib}>
$<TARGET_FILE_DIR:c_example>
)
endforeach()
endif()

View file

@ -1,4 +1,39 @@
add_executable(z3_tptp5 EXCLUDE_FROM_ALL tptp5.cpp tptp5.lex.cpp)
target_link_libraries(z3_tptp5 PRIVATE libz3)
target_include_directories(z3_tptp5 PRIVATE "${CMAKE_SOURCE_DIR}/src/api")
target_include_directories(z3_tptp5 PRIVATE "${CMAKE_SOURCE_DIR}/src/api/c++")
################################################################################
# TPTP example
################################################################################
project(Z3_TPTP5 CXX)
cmake_minimum_required(VERSION 2.8.12)
find_package(Z3
REQUIRED
CONFIG
# `NO_DEFAULT_PATH` is set so that -DZ3_DIR has to be passed to find Z3.
# This should prevent us from accidently picking up an installed
# copy of Z3. This is here to benefit Z3's build sytem when building
# this project. When making your own project you probably shouldn't
# use this option.
NO_DEFAULT_PATH
)
message(STATUS "Z3_FOUND: ${Z3_FOUND}")
message(STATUS "Found Z3 ${Z3_VERSION_STRING}")
message(STATUS "Z3_DIR: ${Z3_DIR}")
add_executable(z3_tptp5 tptp5.cpp tptp5.lex.cpp)
target_include_directories(z3_tptp5 PRIVATE ${Z3_CXX_INCLUDE_DIRS})
target_link_libraries(z3_tptp5 PRIVATE ${Z3_LIBRARIES})
if ("${CMAKE_SYSTEM_NAME}" MATCHES "[Ww]indows")
# On Windows we need to copy the Z3 libraries
# into the same directory as the executable
# so that they can be found.
foreach (z3_lib ${Z3_LIBRARIES})
message(STATUS "Adding copy rule for ${z3_lib}")
add_custom_command(TARGET z3_tptp5
POST_BUILD
COMMAND
${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:${z3_lib}>
$<TARGET_FILE_DIR:z3_tptp5>
)
endforeach()
endif()

View file

@ -143,7 +143,13 @@ endif()
# so that if those are also shared libraries they are referenced by `libz3.so`.
target_link_libraries(libz3 PRIVATE ${Z3_DEPENDENT_LIBS})
z3_append_linker_flag_list_to_target(libz3 ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS})
# This is currently only for the OpenMP flags. It needs to be set
# via `target_link_libraries()` rather than `z3_append_linker_flag_list_to_target()`
# because when building the `libz3` as a static library when the target is exported
# the link dependencies need to be exported too.
foreach (flag_name ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS})
target_link_libraries(libz3 PRIVATE ${flag_name})
endforeach()
# Declare which header file are the public header files of libz3
# these will automatically installed when the libz3 target is installed
@ -168,6 +174,7 @@ foreach (header ${libz3_public_headers})
endforeach()
install(TARGETS libz3
EXPORT Z3_EXPORTED_TARGETS
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" # On Windows this installs ``libz3.lib`` which CMake calls the "corresponding import library". Do we want this installed?
RUNTIME DESTINATION "${CMAKE_INSTALL_LIBDIR}" # For Windows. DLLs are runtime targets for CMake

View file

@ -44,7 +44,6 @@ target_link_libraries(z3java PRIVATE libz3)
# Z3's components to build ``Native.cpp`` lets do the same for now.
target_compile_options(z3java PRIVATE ${Z3_COMPONENT_CXX_FLAGS})
target_compile_definitions(z3java PRIVATE ${Z3_COMPONENT_CXX_DEFINES})
z3_append_linker_flag_list_to_target(z3java ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS})
target_include_directories(z3java PRIVATE
"${CMAKE_SOURCE_DIR}/src/api"
"${CMAKE_BINARY_DIR}/src/api"

View file

@ -3,6 +3,7 @@ z3_add_component(sat
card_extension.cpp
dimacs.cpp
sat_asymm_branch.cpp
sat_ccc.cpp
sat_clause.cpp
sat_clause_set.cpp
sat_clause_use_list.cpp

View file

@ -58,6 +58,7 @@ z3_add_component(smt
theory_opt.cpp
theory_pb.cpp
theory_seq.cpp
theory_str.cpp
theory_utvpi.cpp
theory_wmaxsat.cpp
uses_theory.cpp

View file

@ -8,6 +8,7 @@ z3_add_component(smt_params
theory_array_params.cpp
theory_bv_params.cpp
theory_pb_params.cpp
theory_str_params.cpp
COMPONENT_DEPENDENCIES
ast
bit_blaster

View file

@ -23,6 +23,7 @@ add_executable(test-z3
bv_simplifier_plugin.cpp
chashtable.cpp
check_assumptions.cpp
cnf_backbones.cpp
datalog_parser.cpp
ddnf.cpp
diff_logic.cpp

View file

@ -3,7 +3,9 @@ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/version.h")
${z3_polluted_tree_msg}
)
endif()
configure_file(version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h @ONLY)
set(Z3_FULL_VERSION "\"${Z3_FULL_VERSION_STR}\"")
configure_file(version.h.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
z3_add_component(util
SOURCES

View file

@ -0,0 +1,7 @@
qprofdiff: main.cpp
$(CXX) $(CXXFLAGS) main.cpp -o qprofdiff
all: qprofdiff
clean:
rm -f qprofdiff

284
contrib/qprofdiff/main.cpp Normal file
View file

@ -0,0 +1,284 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
main.cpp
Abstract:
Main file for qprofdiff.
Author:
Christoph M. Wintersteiger (cwinter)
Revision History:
--*/
#include<errno.h>
#include<limits.h>
#include<string>
#include<iostream>
#include<fstream>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
set<string> options;
// Profile format:
// [quantifier_instances] qname : num_instances : max_generation : max_cost_s
const string prefix = "[quantifier_instances]";
unsigned prefix_len = prefix.length();
typedef struct { unsigned num_instances, max_generation, max_cost; } map_entry;
string trim(string str) {
size_t linx = str.find_first_not_of(' ');
size_t rinx = str.find_last_not_of(' ');
return str.substr(linx, rinx-linx+1);
}
int parse(string const & filename, map<string, map_entry> & data) {
ifstream fs(filename.c_str());
if (!fs.is_open()) {
cout << "Can't open file '" << filename << "'" << endl;
return ENOENT;
}
string qid;
string tokens[4];
unsigned cur_token = 0;
while (!fs.eof()) {
string line;
getline(fs, line);
if (line.substr(0, prefix_len) == prefix) {
line = trim(line.substr(prefix_len));
size_t from = 0, ti = 0;
for (size_t inx = line.find(':', from);
inx != string::npos;
inx = line.find(':', from)) {
tokens[ti] = trim(line.substr(from, inx-from));
from = inx+1;
ti++;
}
if (from != line.length() && ti < 4)
tokens[ti] = trim(line.substr(from));
qid = tokens[0];
if (data.find(qid) == data.end()) {
map_entry & entry = data[qid];
entry.num_instances = entry.max_generation = entry.max_cost = 0;
}
map_entry & entry = data[qid];
entry.num_instances = atoi(tokens[1].c_str());
entry.max_generation = (unsigned)atoi(tokens[2].c_str());
entry.max_cost = (unsigned)atoi(tokens[3].c_str());
}
}
fs.close();
return 0;
}
void display_data(map<string, map_entry> & data) {
for (map<string, map_entry>::iterator it = data.begin();
it != data.end();
it++)
cout << it->first << ": " << it->second.num_instances <<
", " << it->second.max_generation <<
", " << it->second.max_cost << endl;
}
typedef struct {
int d_num_instances, d_max_generation, d_max_cost;
bool left_only, right_only;
} diff_entry;
typedef struct { string qid; diff_entry e; } diff_item;
#define DIFF_LT(X) bool diff_item_lt_ ## X (diff_item const & l, diff_item const & r) { \
int l_lt_r = l.e.d_ ## X < r.e.d_ ## X; \
int l_eq_r = l.e.d_ ## X == r.e.d_ ## X; \
return \
l.e.left_only ? (r.e.left_only ? ((l_eq_r) ? l.qid < r.qid : l_lt_r) : false) : \
l.e.right_only ? (r.e.right_only ? ((l_eq_r) ? l.qid < r.qid : l_lt_r) : true) : \
r.e.right_only ? false : \
r.e.left_only ? true : \
l_lt_r; \
}
DIFF_LT(num_instances)
DIFF_LT(max_generation)
DIFF_LT(max_cost)
int indicate(diff_entry const & e, bool suppress_unchanged) {
if (e.left_only) {
cout << "< ";
return INT_MIN;
}
else if (e.right_only) {
cout << "> ";
return INT_MAX;
}
else {
int const & delta =
(options.find("-si") != options.end()) ? e.d_num_instances :
(options.find("-sg") != options.end()) ? e.d_max_generation :
(options.find("-sc") != options.end()) ? e.d_max_cost :
e.d_num_instances;
if (delta < 0)
cout << "+ ";
else if (delta > 0)
cout << "- ";
else if (delta == 0 && !suppress_unchanged)
cout << "= ";
return delta;
}
}
void diff(map<string, map_entry> & left, map<string, map_entry> & right) {
map<string, diff_entry> diff_data;
for (map<string, map_entry>::const_iterator lit = left.begin();
lit != left.end();
lit++) {
string const & qid = lit->first;
map_entry const & lentry = lit->second;
map<string, map_entry>::const_iterator rit = right.find(qid);
if (rit != right.end()) {
map_entry const & rentry = rit->second;
diff_entry & de = diff_data[qid];
de.left_only = de.right_only = false;
de.d_num_instances = lentry.num_instances - rentry.num_instances;
de.d_max_generation = lentry.max_generation - rentry.max_generation;
de.d_max_cost = lentry.max_cost - rentry.max_cost;
}
else {
diff_entry & de = diff_data[qid];
de.left_only = true;
de.right_only = false;
de.d_num_instances = lentry.num_instances;
de.d_max_generation = lentry.max_generation;
de.d_max_cost = lentry.max_cost;
}
}
for (map<string, map_entry>::const_iterator rit = right.begin();
rit != right.end();
rit++) {
string const & qid = rit->first;
map_entry const & rentry = rit->second;
map<string, map_entry>::const_iterator lit = left.find(qid);
if (lit == left.end()) {
diff_entry & de = diff_data[qid];
de.left_only = false;
de.right_only = true;
de.d_num_instances = -(int)rentry.num_instances;
de.d_max_generation = -(int)rentry.max_generation;
de.d_max_cost = -(int)rentry.max_cost;
}
}
vector<diff_item> flat_data;
for (map<string, diff_entry>::const_iterator it = diff_data.begin();
it != diff_data.end();
it++) {
flat_data.push_back(diff_item());
flat_data.back().qid = it->first;
flat_data.back().e = it->second;
}
stable_sort(flat_data.begin(), flat_data.end(),
options.find("-si") != options.end() ? diff_item_lt_num_instances:
options.find("-sg") != options.end() ? diff_item_lt_max_generation :
options.find("-sc") != options.end() ? diff_item_lt_max_cost :
diff_item_lt_num_instances);
bool suppress_unchanged = options.find("-n") != options.end();
for (vector<diff_item>::const_iterator it = flat_data.begin();
it != flat_data.end();
it++) {
diff_item const & d = *it;
string const & qid = d.qid;
diff_entry const & e = d.e;
int delta = indicate(e, suppress_unchanged);
if (!(delta == 0 && suppress_unchanged))
cout << qid << " (" <<
(e.d_num_instances > 0 ? "" : "+") << -e.d_num_instances << " inst., " <<
(e.d_max_generation > 0 ? "" : "+") << -e.d_max_generation << " max. gen., " <<
(e.d_max_cost > 0 ? "" : "+") << -e.d_max_cost << " max. cost)" <<
endl;
}
}
void display_usage() {
cout << "Usage: qprofdiff [options] <filename> <filename>" << endl;
cout << "Options:" << endl;
cout << " -n Suppress unchanged items" << endl;
cout << " -si Sort by difference in number of instances" << endl;
cout << " -sg Sort by difference in max. generation" << endl;
cout << " -sc Sort by difference in max. cost" << endl;
}
int main(int argc, char ** argv) {
char * filename1 = 0;
char * filename2 = 0;
for (int i = 1; i < argc; i++) {
int len = string(argv[i]).length();
if (len > 1 && argv[i][0] == '-') {
options.insert(string(argv[i]));
}
else if (filename1 == 0)
filename1 = argv[i];
else if (filename2 == 0)
filename2 = argv[i];
else {
cout << "Invalid argument: " << argv[i] << endl << endl;
display_usage();
return EINVAL;
}
}
if (filename1 == 0 || filename2 == 0) {
cout << "Two filenames required." << endl << endl;
display_usage();
return EINVAL;
}
cout << "Comparing " << filename1 << " to " << filename2 << endl;
map<string, map_entry> data1, data2;
int r = parse(filename1, data1);
if (r != 0) return r;
r = parse(filename2, data2);
if (r != 0) return r;
// display_data(data1);
// display_data(data2);
diff(data1, data2);
return 0;
}

View file

@ -0,0 +1,3 @@
# Maintainers
- Christoph M. Wintersteiger (@wintersteiger, cwinter@microsoft.com)

View file

@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{96E7E3EF-4162-474D-BD32-C702632AAF2B}</ProjectGuid>
<RootNamespace>qprofdiff</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<AdditionalIncludeDirectories>..\..\src\util;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>
</MultiProcessorCompilation>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(LibraryPath);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\src\util;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\src\util;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\src\util;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -1,5 +1,9 @@
# Copyright (c) Microsoft Corporation 2015
"""
Z3 API documentation generator script
"""
import argparse
import os
import shutil
import re
@ -11,124 +15,293 @@ import shutil
ML_ENABLED=False
BUILD_DIR='../build'
def display_help(exit_code):
print("mk_api_doc.py: Z3 documentation generator\n")
print("\nOptions:")
print(" -h, --help display this message.")
print(" -b <subdir>, --build=<subdir> subdirectory where Z3 is built (default: ../build).")
print(" --ml include ML/OCaml API documentation.")
DOXYGEN_EXE='doxygen'
TEMP_DIR=os.path.join(os.getcwd(), 'tmp')
OUTPUT_DIRECTORY=os.path.join(os.getcwd(), 'api')
Z3PY_PACKAGE_PATH='../src/api/python/z3'
Z3PY_ENABLED=True
DOTNET_ENABLED=True
JAVA_ENABLED=True
DOTNET_API_SEARCH_PATHS=['../src/api/dotnet']
JAVA_API_SEARCH_PATHS=['../src/api/java']
SCRIPT_DIR=os.path.abspath(os.path.dirname(__file__))
def parse_options():
global ML_ENABLED, BUILD_DIR
try:
options, remainder = getopt.gnu_getopt(sys.argv[1:],
'b:h',
['build=', 'help', 'ml'])
except:
print("ERROR: Invalid command line option")
display_help(1)
for opt, arg in options:
if opt in ('-b', '--build'):
BUILD_DIR = mk_util.norm_path(arg)
elif opt in ('h', '--help'):
display_help()
exit(1)
elif opt in ('--ml'):
ML_ENABLED=True
else:
print("ERROR: Invalid command line option: %s" % opt)
display_help(1)
global ML_ENABLED, BUILD_DIR, DOXYGEN_EXE, TEMP_DIR, OUTPUT_DIRECTORY
global Z3PY_PACKAGE_PATH, Z3PY_ENABLED, DOTNET_ENABLED, JAVA_ENABLED
global DOTNET_API_SEARCH_PATHS, JAVA_API_SEARCH_PATHS
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-b',
'--build',
default=BUILD_DIR,
help='Directory where Z3 is built (default: %(default)s)',
)
parser.add_argument('--ml',
action='store_true',
default=False,
help='Include ML/OCaml API documentation'
)
parser.add_argument('--doxygen-executable',
dest='doxygen_executable',
default=DOXYGEN_EXE,
help='Doxygen executable to use (default: %(default)s)',
)
parser.add_argument('--temp-dir',
dest='temp_dir',
default=TEMP_DIR,
help='Path to directory to use as temporary directory. '
'(default: %(default)s)',
)
parser.add_argument('--output-dir',
dest='output_dir',
default=OUTPUT_DIRECTORY,
help='Path to output directory (default: %(default)s)',
)
parser.add_argument('--z3py-package-path',
dest='z3py_package_path',
default=Z3PY_PACKAGE_PATH,
help='Path to directory containing Z3py package (default: %(default)s)',
)
# FIXME: I would prefer not to have negative options (i.e. `--z3py`
# instead of `--no-z3py`) but historically these bindings have been on by
# default so we have options to disable generating documentation for these
# bindings rather than enable them.
parser.add_argument('--no-z3py',
dest='no_z3py',
action='store_true',
default=False,
help='Do not generate documentation for Python bindings',
)
parser.add_argument('--no-dotnet',
dest='no_dotnet',
action='store_true',
default=False,
help='Do not generate documentation for .NET bindings',
)
parser.add_argument('--no-java',
dest='no_java',
action='store_true',
default=False,
help='Do not generate documentation for Java bindings',
)
parser.add_argument('--dotnet-search-paths',
dest='dotnet_search_paths',
nargs='+',
default=DOTNET_API_SEARCH_PATHS,
help='Specify one or more path to look for .NET files (default: %(default)s).',
)
parser.add_argument('--java-search-paths',
dest='java_search_paths',
nargs='+',
default=JAVA_API_SEARCH_PATHS,
help='Specify one or more paths to look for Java files (default: %(default)s).',
)
pargs = parser.parse_args()
ML_ENABLED = pargs.ml
BUILD_DIR = pargs.build
DOXYGEN_EXE = pargs.doxygen_executable
TEMP_DIR = pargs.temp_dir
OUTPUT_DIRECTORY = pargs.output_dir
Z3PY_PACKAGE_PATH = pargs.z3py_package_path
Z3PY_ENABLED = not pargs.no_z3py
DOTNET_ENABLED = not pargs.no_dotnet
JAVA_ENABLED = not pargs.no_java
DOTNET_API_SEARCH_PATHS = pargs.dotnet_search_paths
JAVA_API_SEARCH_PATHS = pargs.java_search_paths
if Z3PY_ENABLED:
if not os.path.exists(Z3PY_PACKAGE_PATH):
raise Exception('"{}" does not exist'.format(Z3PY_PACKAGE_PATH))
if not os.path.basename(Z3PY_PACKAGE_PATH) == 'z3':
raise Exception('"{}" does not end with "z3"'.format(Z3PY_PACKAGE_PATH))
return
def mk_dir(d):
if not os.path.exists(d):
os.makedirs(d)
# Eliminate def_API and extra_API directives from file 'inf'.
# Eliminate def_API, extra_API, and def_Type directives from file 'inf'.
# The result is stored in 'outf'.
def cleanup_API(inf, outf):
pat1 = re.compile(".*def_API.*")
pat2 = re.compile(".*extra_API.*")
pat3 = re.compile(r".*def_Type\(.*")
_inf = open(inf, 'r')
_outf = open(outf, 'w')
for line in _inf:
if not pat1.match(line) and not pat2.match(line):
if not pat1.match(line) and not pat2.match(line) and not pat3.match(line):
_outf.write(line)
def configure_file(template_file_path, output_file_path, substitutions):
"""
Read a template file ``template_file_path``, perform substitutions
found in the ``substitutions`` dictionary and write the result to
the output file ``output_file_path``.
The template file should contain zero or more template strings of the
form ``@NAME@``.
The substitutions dictionary maps old strings (without the ``@``
symbols) to their replacements.
"""
assert isinstance(template_file_path, str)
assert isinstance(output_file_path, str)
assert isinstance(substitutions, dict)
assert len(template_file_path) > 0
assert len(output_file_path) > 0
print("Generating {} from {}".format(output_file_path, template_file_path))
if not os.path.exists(template_file_path):
raise Exception('Could not find template file "{}"'.format(template_file_path))
# Read whole template file into string
template_string = None
with open(template_file_path, 'r') as f:
template_string = f.read()
# Do replacements
for (old_string, replacement) in substitutions.items():
template_string = template_string.replace('@{}@'.format(old_string), replacement)
# Write the string to the file
with open(output_file_path, 'w') as f:
f.write(template_string)
try:
parse_options()
fi = open('website.dox', 'r')
fo = open('website-adj.dox', 'w')
print("Creating temporary directory \"{}\"".format(TEMP_DIR))
mk_dir(TEMP_DIR)
# Short-hand for path to temporary file
def temp_path(path):
return os.path.join(TEMP_DIR, path)
# Short-hand for path to file in `doc` directory
def doc_path(path):
return os.path.join(SCRIPT_DIR, path)
for line in fi:
if (line != '[ML]\n'):
fo.write(line)
elif (ML_ENABLED):
fo.write(' - <a class="el" href="ml/index.html">ML/OCaml API</a>\n')
fi.close()
fo.close()
# Create configuration file from template
doxygen_config_substitutions = {
'OUTPUT_DIRECTORY': OUTPUT_DIRECTORY,
'TEMP_DIR': TEMP_DIR,
'CXX_API_SEARCH_PATHS': doc_path('../src/api/c++'),
}
mk_dir('api/html')
mk_dir('tmp')
shutil.copyfile('website-adj.dox', 'tmp/website.dox')
os.remove('website-adj.dox')
shutil.copyfile('../src/api/python/z3/z3.py', 'tmp/z3py.py')
cleanup_API('../src/api/z3_api.h', 'tmp/z3_api.h')
cleanup_API('../src/api/z3_ast_containers.h', 'tmp/z3_ast_containers.h')
cleanup_API('../src/api/z3_algebraic.h', 'tmp/z3_algebraic.h')
cleanup_API('../src/api/z3_polynomial.h', 'tmp/z3_polynomial.h')
cleanup_API('../src/api/z3_rcf.h', 'tmp/z3_rcf.h')
cleanup_API('../src/api/z3_fixedpoint.h', 'tmp/z3_fixedpoint.h')
cleanup_API('../src/api/z3_optimization.h', 'tmp/z3_optimization.h')
cleanup_API('../src/api/z3_interp.h', 'tmp/z3_interp.h')
cleanup_API('../src/api/z3_fpa.h', 'tmp/z3_fpa.h')
if Z3PY_ENABLED:
print("Z3Py documentation enabled")
doxygen_config_substitutions['PYTHON_API_FILES'] = 'z3.py'
else:
print("Z3Py documentation disabled")
doxygen_config_substitutions['PYTHON_API_FILES'] = ''
if DOTNET_ENABLED:
print(".NET documentation enabled")
doxygen_config_substitutions['DOTNET_API_FILES'] = '*.cs'
dotnet_api_search_path_str = ""
for p in DOTNET_API_SEARCH_PATHS:
# Quote path so that paths with spaces are handled correctly
dotnet_api_search_path_str += "\"{}\" ".format(p)
doxygen_config_substitutions['DOTNET_API_SEARCH_PATHS'] = dotnet_api_search_path_str
else:
print(".NET documentation disabled")
doxygen_config_substitutions['DOTNET_API_FILES'] = ''
doxygen_config_substitutions['DOTNET_API_SEARCH_PATHS'] = ''
if JAVA_ENABLED:
print("Java documentation enabled")
doxygen_config_substitutions['JAVA_API_FILES'] = '*.java'
java_api_search_path_str = ""
for p in JAVA_API_SEARCH_PATHS:
# Quote path so that paths with spaces are handled correctly
java_api_search_path_str += "\"{}\" ".format(p)
doxygen_config_substitutions['JAVA_API_SEARCH_PATHS'] = java_api_search_path_str
else:
print("Java documentation disabled")
doxygen_config_substitutions['JAVA_API_FILES'] = ''
doxygen_config_substitutions['JAVA_API_SEARCH_PATHS'] = ''
doxygen_config_file = temp_path('z3api.cfg')
configure_file(
doc_path('z3api.cfg.in'),
doxygen_config_file,
doxygen_config_substitutions)
website_dox_substitutions = {}
bullet_point_prefix='\n - '
if Z3PY_ENABLED:
website_dox_substitutions['PYTHON_API'] = (
'{prefix}<a class="el" href="namespacez3py.html">Python API</a> '
'(also available in <a class="el" href="z3.html">pydoc format</a>)'
).format(
prefix=bullet_point_prefix)
else:
website_dox_substitutions['PYTHON_API'] = ''
if DOTNET_ENABLED:
website_dox_substitutions['DOTNET_API'] = (
'{prefix}'
'<a class="el" href="namespace_microsoft_1_1_z3.html">'
'.NET API</a>').format(
prefix=bullet_point_prefix)
else:
website_dox_substitutions['DOTNET_API'] = ''
if JAVA_ENABLED:
website_dox_substitutions['JAVA_API'] = (
'{prefix}<a class="el" href="namespacecom_1_1microsoft_1_1z3.html">'
'Java API</a>').format(
prefix=bullet_point_prefix)
else:
website_dox_substitutions['JAVA_API'] = ''
if ML_ENABLED:
website_dox_substitutions['OCAML_API'] = (
'<a class="el" href="ml/index.html">ML/OCaml API</a>'
).format(
prefix=bullet_point_prefix)
else:
website_dox_substitutions['OCAML_API'] = ''
configure_file(
doc_path('website.dox.in'),
temp_path('website.dox'),
website_dox_substitutions)
mk_dir(os.path.join(OUTPUT_DIRECTORY, 'html'))
if Z3PY_ENABLED:
shutil.copyfile(doc_path('../src/api/python/z3/z3.py'), temp_path('z3py.py'))
cleanup_API(doc_path('../src/api/z3_api.h'), temp_path('z3_api.h'))
cleanup_API(doc_path('../src/api/z3_ast_containers.h'), temp_path('z3_ast_containers.h'))
cleanup_API(doc_path('../src/api/z3_algebraic.h'), temp_path('z3_algebraic.h'))
cleanup_API(doc_path('../src/api/z3_polynomial.h'), temp_path('z3_polynomial.h'))
cleanup_API(doc_path('../src/api/z3_rcf.h'), temp_path('z3_rcf.h'))
cleanup_API(doc_path('../src/api/z3_fixedpoint.h'), temp_path('z3_fixedpoint.h'))
cleanup_API(doc_path('../src/api/z3_optimization.h'), temp_path('z3_optimization.h'))
cleanup_API(doc_path('../src/api/z3_interp.h'), temp_path('z3_interp.h'))
cleanup_API(doc_path('../src/api/z3_fpa.h'), temp_path('z3_fpa.h'))
print("Removed annotations from z3_api.h.")
try:
if subprocess.call(['doxygen', 'z3api.dox']) != 0:
if subprocess.call([DOXYGEN_EXE, doxygen_config_file]) != 0:
print("ERROR: doxygen returned nonzero return code")
exit(1)
except:
print("ERROR: failed to execute 'doxygen', make sure doxygen (http://www.doxygen.org) is available in your system.")
exit(1)
print("Generated C and .NET API documentation.")
os.remove('tmp/z3_api.h')
os.remove('tmp/z3_ast_containers.h')
os.remove('tmp/z3_algebraic.h')
os.remove('tmp/z3_polynomial.h')
os.remove('tmp/z3_rcf.h')
os.remove('tmp/z3_fixedpoint.h')
os.remove('tmp/z3_optimization.h')
os.remove('tmp/z3_interp.h')
os.remove('tmp/z3_fpa.h')
print("Removed temporary file header files.")
os.remove('tmp/website.dox')
print("Removed temporary file website.dox")
os.remove('tmp/z3py.py')
print("Removed temporary file z3py.py")
os.removedirs('tmp')
print("Removed temporary directory tmp.")
sys.path.append('../src/api/python/z3')
pydoc.writedoc('z3')
shutil.move('z3.html', 'api/html/z3.html')
print("Generated Python documentation.")
print("Generated Doxygen based documentation")
shutil.rmtree(os.path.realpath(TEMP_DIR))
print("Removed temporary directory \"{}\"".format(TEMP_DIR))
if Z3PY_ENABLED:
# 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'))
print("Generated pydoc Z3Py documentation.")
if ML_ENABLED:
mk_dir('api/html/ml')
if subprocess.call(['ocamldoc', '-html', '-d', 'api\html\ml', '-sort', '-hide', 'Z3', '-I', '%s/api/ml' % BUILD_DIR, '../src/api/ml/z3enums.mli', '../src/api/ml/z3.mli']) != 0:
ml_output_dir = os.path.join(OUTPUT_DIRECTORY, 'html', 'ml')
mk_dir(ml_output_dir)
if subprocess.call(['ocamldoc', '-html', '-d', ml_output_dir, '-sort', '-hide', 'Z3', '-I', '%s/api/ml' % BUILD_DIR, doc_path('../src/api/ml/z3enums.mli'), doc_path('../src/api/ml/z3.mli')]) != 0:
print("ERROR: ocamldoc failed.")
exit(1)
print("Generated ML/OCaml documentation.")
print("Documentation was successfully generated at subdirectory './api/html'.")
except:
print("Documentation was successfully generated at subdirectory '{}'.".format(OUTPUT_DIRECTORY))
except Exception:
exctype, value = sys.exc_info()[:2]
print("ERROR: failed to generate documentation: %s" % value)
exit(1)

View file

@ -10,11 +10,7 @@
This website hosts the automatically generated documentation for the Z3 APIs.
- \ref capi
- \ref cppapi
- <a class="el" href="class_microsoft_1_1_z3_1_1_context.html">.NET API</a>
- <a class="el" href="namespacecom_1_1microsoft_1_1z3.html">Java API</a>
- <a class="el" href="namespacez3py.html">Python API</a> (also available in <a class="el" href="z3.html">pydoc format</a>)
[ML]
- \ref capi
- \ref cppapi @DOTNET_API@ @JAVA_API@ @PYTHON_API@ @OCAML_API@
- Try Z3 online at <a href="http://rise4fun.com/z3">RiSE4Fun</a>.
*/

View file

@ -52,7 +52,7 @@ PROJECT_LOGO =
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
OUTPUT_DIRECTORY = api
OUTPUT_DIRECTORY = "@OUTPUT_DIRECTORY@"
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
# 4096 sub-directories (in 2 levels) under the output directory of each output
@ -681,10 +681,9 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = ../src/api/dotnet \
../src/api/java \
../src/api/c++ \
./tmp
INPUT = "@TEMP_DIR@" \
"@CXX_API_SEARCH_PATHS@" \
@DOTNET_API_SEARCH_PATHS@ @JAVA_API_SEARCH_PATHS@
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@ -703,16 +702,14 @@ INPUT_ENCODING = UTF-8
# *.f90 *.f *.for *.vhd *.vhdl
FILE_PATTERNS = website.dox \
z3_api.h \
z3_algebraic.h \
z3_polynomial.h \
z3_rcf.h \
z3_interp.h \
z3_fpa.h \
z3_api.h \
z3_algebraic.h \
z3_polynomial.h \
z3_rcf.h \
z3_interp.h \
z3_fpa.h \
z3++.h \
z3py.py \
*.cs \
*.java
@PYTHON_API_FILES@ @DOTNET_API_FILES@ @JAVA_API_FILES@
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.

View file

@ -1633,6 +1633,8 @@ class DotNetDLLComponent(Component):
if not self.key_file is None:
print("%s.dll will be signed using key '%s'." % (self.dll_name, self.key_file))
if (self.key_file.find(' ') != -1):
self.key_file = '"' + self.key_file + '"'
cscCmdLine.append('/keyfile:{}'.format(self.key_file))
cscCmdLine.extend( ['/unsafe+',
@ -2419,6 +2421,7 @@ def mk_config():
FOCI2 = False
if GIT_HASH:
CPPFLAGS = '%s -DZ3GITHASH=%s' % (CPPFLAGS, GIT_HASH)
CXXFLAGS = '%s -std=c++11' % CXXFLAGS
CXXFLAGS = '%s -fvisibility=hidden -c' % CXXFLAGS
FPMATH = test_fpmath(CXX)
CXXFLAGS = '%s %s' % (CXXFLAGS, FPMATH_FLAGS)
@ -2443,8 +2446,8 @@ def mk_config():
CXXFLAGS = '%s -Wno-unknown-pragmas -Wno-overloaded-virtual -Wno-unused-value' % CXXFLAGS
sysname, _, _, _, machine = os.uname()
if sysname == 'Darwin':
SO_EXT = '.dylib'
SLIBFLAGS = '-dynamiclib'
SO_EXT = '.dylib'
SLIBFLAGS = '-dynamiclib'
elif sysname == 'Linux':
CXXFLAGS = '%s -fno-strict-aliasing -D_LINUX_' % CXXFLAGS
OS_DEFINES = '-D_LINUX_'
@ -2685,8 +2688,8 @@ def get_full_version_string(major, minor, build, revision):
if GIT_HASH:
res += " " + GIT_HASH
if GIT_DESCRIBE:
branch = check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD', '--long'])
res += " master " + check_output(['git', 'describe'])
branch = check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
res += " " + branch + " " + check_output(['git', 'describe'])
return '"' + res + '"'
# Update files with the version number

View file

@ -128,7 +128,7 @@ extern "C" {
lbool r = l_undef;
cancel_eh<reslimit> eh(mk_c(c)->m().limit());
unsigned timeout = to_optimize_ptr(o)->get_params().get_uint("timeout", mk_c(c)->get_timeout());
unsigned rlimit = mk_c(c)->get_rlimit();
unsigned rlimit = to_optimize_ptr(o)->get_params().get_uint("rlimit", mk_c(c)->get_rlimit());
api::context::set_interruptable si(*(mk_c(c)), eh);
{
scoped_timer timer(timeout, &eh);

View file

@ -52,7 +52,7 @@ extern "C" {
}
Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args,
Z3_ast const args[], int _coeffs[],
Z3_ast const args[], int const _coeffs[],
int k) {
Z3_TRY;
LOG_Z3_mk_pble(c, num_args, args, _coeffs, k);
@ -70,7 +70,7 @@ extern "C" {
}
Z3_ast Z3_API Z3_mk_pbge(Z3_context c, unsigned num_args,
Z3_ast const args[], int _coeffs[],
Z3_ast const args[], int const _coeffs[],
int k) {
Z3_TRY;
LOG_Z3_mk_pble(c, num_args, args, _coeffs, k);
@ -88,7 +88,7 @@ extern "C" {
}
Z3_ast Z3_API Z3_mk_pbeq(Z3_context c, unsigned num_args,
Z3_ast const args[], int _coeffs[],
Z3_ast const args[], int const _coeffs[],
int k) {
Z3_TRY;
LOG_Z3_mk_pble(c, num_args, args, _coeffs, k);

View file

@ -69,14 +69,17 @@ extern "C" {
}
expr * const* ps = reinterpret_cast<expr * const*>(patterns);
expr * const* no_ps = reinterpret_cast<expr * const*>(no_patterns);
pattern_validator v(mk_c(c)->m());
for (unsigned i = 0; i < num_patterns; i++) {
if (!v(num_decls, ps[i], 0, 0)) {
SET_ERROR_CODE(Z3_INVALID_PATTERN);
return 0;
symbol qid = to_symbol(quantifier_id);
bool is_rec = mk_c(c)->m().rec_fun_qid() == qid;
if (!is_rec) {
pattern_validator v(mk_c(c)->m());
for (unsigned i = 0; i < num_patterns; i++) {
if (!v(num_decls, ps[i], 0, 0)) {
SET_ERROR_CODE(Z3_INVALID_PATTERN);
return 0;
}
}
}
sort* const* ts = reinterpret_cast<sort * const*>(sorts);
svector<symbol> names;
for (unsigned i = 0; i < num_decls; ++i) {
@ -88,7 +91,7 @@ extern "C" {
(0 != is_forall),
names.size(), ts, names.c_ptr(), to_expr(body),
weight,
to_symbol(quantifier_id),
qid,
to_symbol(skolem_id),
num_patterns, ps,
num_no_patterns, no_ps

View file

@ -86,7 +86,13 @@ namespace z3 {
};
inline std::ostream & operator<<(std::ostream & out, exception const & e) { out << e.msg(); return out; }
#if !defined(Z3_THROW)
#if __cpp_exceptions || _CPPUNWIND
#define Z3_THROW(x) throw x
#else
#define Z3_THROW(x) {}
#endif
#endif // !defined(Z3_THROW)
/**
\brief Z3 global configuration object.
@ -165,7 +171,7 @@ namespace z3 {
Z3_error_code check_error() const {
Z3_error_code e = Z3_get_error_code(m_ctx);
if (e != Z3_OK && enable_exceptions())
throw exception(Z3_get_error_msg(m_ctx, e));
Z3_THROW(exception(Z3_get_error_msg(m_ctx, e)));
return e;
}
@ -701,7 +707,7 @@ namespace z3 {
if (!is_numeral_i(result)) {
assert(ctx().enable_exceptions());
if (!ctx().enable_exceptions()) return 0;
throw exception("numeral does not fit in machine int");
Z3_THROW(exception("numeral does not fit in machine int"));
}
return result;
}
@ -721,7 +727,7 @@ namespace z3 {
if (!is_numeral_u(result)) {
assert(ctx().enable_exceptions());
if (!ctx().enable_exceptions()) return 0;
throw exception("numeral does not fit in machine uint");
Z3_THROW(exception("numeral does not fit in machine uint"));
}
return result;
}
@ -738,7 +744,7 @@ namespace z3 {
if (!is_numeral_i64(result)) {
assert(ctx().enable_exceptions());
if (!ctx().enable_exceptions()) return 0;
throw exception("numeral does not fit in machine __int64");
Z3_THROW(exception("numeral does not fit in machine __int64"));
}
return result;
}
@ -755,7 +761,7 @@ namespace z3 {
if (!is_numeral_u64(result)) {
assert(ctx().enable_exceptions());
if (!ctx().enable_exceptions()) return 0;
throw exception("numeral does not fit in machine __uint64");
Z3_THROW(exception("numeral does not fit in machine __uint64"));
}
return result;
}
@ -890,6 +896,7 @@ namespace z3 {
friend expr operator+(expr const & a, expr const & b);
friend expr operator+(expr const & a, int b);
friend expr operator+(int a, expr const & b);
friend expr sum(expr_vector const& args);
friend expr operator*(expr const & a, expr const & b);
friend expr operator*(expr const & a, int b);
@ -928,7 +935,6 @@ namespace z3 {
friend expr operator>=(expr const & a, expr const & b);
friend expr wasoperator(expr const & a, expr const & b);
friend expr operator>=(expr const & a, int b);
friend expr operator>=(int a, expr const & b);
@ -940,6 +946,12 @@ namespace z3 {
friend expr operator>(expr const & a, int b);
friend expr operator>(int a, expr const & b);
friend expr pble(expr_vector const& es, int const * coeffs, int bound);
friend expr pbge(expr_vector const& es, int const * coeffs, int bound);
friend expr pbeq(expr_vector const& es, int const * coeffs, int bound);
friend expr atmost(expr_vector const& es, unsigned bound);
friend expr atleast(expr_vector const& es, unsigned bound);
friend expr operator&(expr const & a, expr const & b);
friend expr operator&(expr const & a, int b);
friend expr operator&(int a, expr const & b);
@ -1559,7 +1571,54 @@ namespace z3 {
array<Z3_app> vars(xs);
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr pble(expr_vector const& es, int const* coeffs, int bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_pble(ctx, _es.size(), _es.ptr(), coeffs, bound);
ctx.check_error();
return expr(ctx, r);
}
inline expr pbge(expr_vector const& es, int const* coeffs, int bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_pbge(ctx, _es.size(), _es.ptr(), coeffs, bound);
ctx.check_error();
return expr(ctx, r);
}
inline expr pbeq(expr_vector const& es, int const* coeffs, int bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_pbeq(ctx, _es.size(), _es.ptr(), coeffs, bound);
ctx.check_error();
return expr(ctx, r);
}
inline expr atmost(expr_vector const& es, unsigned bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_atmost(ctx, _es.size(), _es.ptr(), bound);
ctx.check_error();
return expr(ctx, r);
}
inline expr atleast(expr_vector const& es, unsigned bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_atleast(ctx, _es.size(), _es.ptr(), bound);
ctx.check_error();
return expr(ctx, r);
}
inline expr sum(expr_vector const& args) {
assert(args.size() > 0);
context& ctx = args[0].ctx();
array<Z3_ast> _args(args);
Z3_ast r = Z3_mk_add(ctx, _args.size(), _args.ptr());
ctx.check_error();
return expr(ctx, r);
}
inline expr distinct(expr_vector const& args) {
assert(args.size() > 0);
@ -1699,7 +1758,7 @@ namespace z3 {
Z3_bool status = Z3_model_eval(ctx(), m_model, n, model_completion, &r);
check_error();
if (status == Z3_FALSE && ctx().enable_exceptions())
throw exception("failed to evaluate expression");
Z3_THROW(exception("failed to evaluate expression"));
return expr(ctx(), r);
}
@ -2023,7 +2082,7 @@ namespace z3 {
}
inline tactic par_or(unsigned n, tactic const* tactics) {
if (n == 0) {
throw exception("a non-zero number of tactics need to be passed to par_or");
Z3_THROW(exception("a non-zero number of tactics need to be passed to par_or"));
}
array<Z3_tactic> buffer(n);
for (unsigned i = 0; i < n; ++i) buffer[i] = tactics[i];
@ -2178,14 +2237,14 @@ namespace z3 {
class fixedpoint : public object {
Z3_fixedpoint m_fp;
public:
fixedpoint(context& c):object(c) { mfp = Z3_mk_fixedpoint(c); Z3_fixedpoint_inc_ref(c, m_fp); }
fixedpoint(context& c):object(c) { m_fp = Z3_mk_fixedpoint(c); Z3_fixedpoint_inc_ref(c, m_fp); }
~fixedpoint() { Z3_fixedpoint_dec_ref(ctx(), m_fp); }
operator Z3_fixedpoint() const { return m_fp; }
void from_string(char const* s) { Z3_fixedpoint_from_string(ctx(), m_fp, s); check_error(); }
void from_file(char const* s) { Z3_fixedpoint_from_file(ctx(), m_fp, s); check_error(); }
void add_rule(expr& rule, symbol const& name) { Z3_fixedpoint_add_rule(ctx(), m_fp, rule, name); check_error(); }
void add_fact(func_decl& f, unsigned const* args) { Z3_fixedpoint_add_fact(ctx(), m_fp, f, f.num_args(), args); check_error(); }
check_result query(expr& q) { Z3_lbool r = Z3_fixedpoint_query(ctx(), m_fp, q); check_error(); to_check_result(r); }
void add_fact(func_decl& f, unsigned * args) { Z3_fixedpoint_add_fact(ctx(), m_fp, f, f.arity(), args); check_error(); }
check_result query(expr& q) { Z3_lbool r = Z3_fixedpoint_query(ctx(), m_fp, q); check_error(); return to_check_result(r); }
check_result query(func_decl_vector& relations) {
array<Z3_func_decl> rs(relations);
Z3_lbool r = Z3_fixedpoint_query_relations(ctx(), m_fp, rs.size(), rs.ptr());
@ -2194,9 +2253,13 @@ namespace z3 {
}
expr get_answer() { Z3_ast r = Z3_fixedpoint_get_answer(ctx(), m_fp); check_error(); return expr(ctx(), r); }
std::string reason_unknown() { return Z3_fixedpoint_get_reason_unknown(ctx(), m_fp); }
void update_rule(expr& rule, synbol const& name) { Z3_fixedpoint_update_rule(ctx(), m_fp, rule, name); check_error(); }
void update_rule(expr& rule, symbol const& name) { Z3_fixedpoint_update_rule(ctx(), m_fp, rule, name); check_error(); }
unsigned get_num_levels(func_decl& p) { unsigned r = Z3_fixedpoint_get_num_levels(ctx(), m_fp, p); check_error(); return r; }
expr get_cover_delta(int level, func_decl& p) { return Z3_fixedpoint_get_cover_delta(ctx(), m_fp, level, p); check_error(); }
expr get_cover_delta(int level, func_decl& p) {
Z3_ast r = Z3_fixedpoint_get_cover_delta(ctx(), m_fp, level, p);
check_error();
return expr(ctx(), r);
}
void add_cover(int level, func_decl& p, expr& property) { Z3_fixedpoint_add_cover(ctx(), m_fp, level, p, property); check_error(); }
stats statistics() const { Z3_stats r = Z3_fixedpoint_get_statistics(ctx(), m_fp); check_error(); return stats(ctx(), r); }
void register_relation(func_decl& p) { Z3_fixedpoint_register_relation(ctx(), m_fp, p); }
@ -2205,11 +2268,15 @@ namespace z3 {
void set(params const & p) { Z3_fixedpoint_set_params(ctx(), m_fp, p); check_error(); }
std::string help() const { return Z3_fixedpoint_get_help(ctx(), m_fp); }
param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_fixedpoint_get_param_descrs(ctx(), m_fp)); }
std::string to_string() { return Z3_fixedpoint_to_string(ctx(), m_fp); }
std::string to_string() { return Z3_fixedpoint_to_string(ctx(), m_fp, 0, 0); }
std::string to_string(expr_vector const& queries) {
array<Z3_ast> qs(queries);
return Z3_fixedpoint_to_string(ctx(), m_fp, qs.size(), qs.ptr());
}
void push() { Z3_fixedpoint_push(ctx(), m_fp); check_error(); }
void pop() { Z3_fixedpoint_pop(ctx(), m_fp); check_error(); }
};
inline std::ostream & operator<<(std::ostream & out, fixedpoint const & f) { return out << Z3_fixedpoint_to_string(f.ctx(), f); }
inline std::ostream & operator<<(std::ostream & out, fixedpoint const & f) { return out << Z3_fixedpoint_to_string(f.ctx(), f, 0, 0); }
inline tactic fail_if(probe const & p) {
Z3_tactic r = Z3_tactic_fail_if(p.ctx(), p);

View file

@ -1890,43 +1890,43 @@ public class Context implements AutoCloseable {
/**
* Create the empty sequence.
*/
public SeqExpr MkEmptySeq(Sort s)
public SeqExpr mkEmptySeq(Sort s)
{
checkContextMatch(s);
return new SeqExpr(this, Native.mkSeqEmpty(nCtx(), s.getNativeObject()));
return (SeqExpr) Expr.create(this, Native.mkSeqEmpty(nCtx(), s.getNativeObject()));
}
/**
* Create the singleton sequence.
*/
public SeqExpr MkUnit(Expr elem)
public SeqExpr mkUnit(Expr elem)
{
checkContextMatch(elem);
return new SeqExpr(this, Native.mkSeqUnit(nCtx(), elem.getNativeObject()));
return (SeqExpr) Expr.create(this, Native.mkSeqUnit(nCtx(), elem.getNativeObject()));
}
/**
* Create a string constant.
*/
public SeqExpr MkString(String s)
public SeqExpr mkString(String s)
{
return new SeqExpr(this, Native.mkString(nCtx(), s));
return (SeqExpr) Expr.create(this, Native.mkString(nCtx(), s));
}
/**
* Concatentate sequences.
*/
public SeqExpr MkConcat(SeqExpr... t)
public SeqExpr mkConcat(SeqExpr... t)
{
checkContextMatch(t);
return new SeqExpr(this, Native.mkSeqConcat(nCtx(), t.length, AST.arrayToNative(t)));
return (SeqExpr) Expr.create(this, Native.mkSeqConcat(nCtx(), t.length, AST.arrayToNative(t)));
}
/**
* Retrieve the length of a given sequence.
*/
public IntExpr MkLength(SeqExpr s)
public IntExpr mkLength(SeqExpr s)
{
checkContextMatch(s);
return (IntExpr) Expr.create(this, Native.mkSeqLength(nCtx(), s.getNativeObject()));
@ -1935,130 +1935,221 @@ public class Context implements AutoCloseable {
/**
* Check for sequence prefix.
*/
public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2)
public BoolExpr mkPrefixOf(SeqExpr s1, SeqExpr s2)
{
checkContextMatch(s1, s2);
return new BoolExpr(this, Native.mkSeqPrefix(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
return (BoolExpr) Expr.create(this, Native.mkSeqPrefix(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
}
/**
* Check for sequence suffix.
*/
public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2)
public BoolExpr mkSuffixOf(SeqExpr s1, SeqExpr s2)
{
checkContextMatch(s1, s2);
return new BoolExpr(this, Native.mkSeqSuffix(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
return (BoolExpr)Expr.create(this, Native.mkSeqSuffix(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
}
/**
* Check for sequence containment of s2 in s1.
*/
public BoolExpr MkContains(SeqExpr s1, SeqExpr s2)
public BoolExpr mkContains(SeqExpr s1, SeqExpr s2)
{
checkContextMatch(s1, s2);
return new BoolExpr(this, Native.mkSeqContains(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
return (BoolExpr) Expr.create(this, Native.mkSeqContains(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
}
/**
* Retrieve sequence of length one at index.
*/
public SeqExpr MkAt(SeqExpr s, IntExpr index)
public SeqExpr mkAt(SeqExpr s, IntExpr index)
{
checkContextMatch(s, index);
return new SeqExpr(this, Native.mkSeqAt(nCtx(), s.getNativeObject(), index.getNativeObject()));
return (SeqExpr) Expr.create(this, Native.mkSeqAt(nCtx(), s.getNativeObject(), index.getNativeObject()));
}
/**
* Extract subsequence.
*/
public SeqExpr MkExtract(SeqExpr s, IntExpr offset, IntExpr length)
public SeqExpr mkExtract(SeqExpr s, IntExpr offset, IntExpr length)
{
checkContextMatch(s, offset, length);
return new SeqExpr(this, Native.mkSeqExtract(nCtx(), s.getNativeObject(), offset.getNativeObject(), length.getNativeObject()));
return (SeqExpr) Expr.create(this, Native.mkSeqExtract(nCtx(), s.getNativeObject(), offset.getNativeObject(), length.getNativeObject()));
}
/**
* Extract index of sub-string starting at offset.
*/
public IntExpr MkIndexOf(SeqExpr s, SeqExpr substr, ArithExpr offset)
public IntExpr mkIndexOf(SeqExpr s, SeqExpr substr, ArithExpr offset)
{
checkContextMatch(s, substr, offset);
return new IntExpr(this, Native.mkSeqIndex(nCtx(), s.getNativeObject(), substr.getNativeObject(), offset.getNativeObject()));
return (IntExpr)Expr.create(this, Native.mkSeqIndex(nCtx(), s.getNativeObject(), substr.getNativeObject(), offset.getNativeObject()));
}
/**
* Replace the first occurrence of src by dst in s.
*/
public SeqExpr MkReplace(SeqExpr s, SeqExpr src, SeqExpr dst)
public SeqExpr mkReplace(SeqExpr s, SeqExpr src, SeqExpr dst)
{
checkContextMatch(s, src, dst);
return new SeqExpr(this, Native.mkSeqReplace(nCtx(), s.getNativeObject(), src.getNativeObject(), dst.getNativeObject()));
return (SeqExpr) Expr.create(this, Native.mkSeqReplace(nCtx(), s.getNativeObject(), src.getNativeObject(), dst.getNativeObject()));
}
/**
* Convert a regular expression that accepts sequence s.
*/
public ReExpr MkToRe(SeqExpr s)
public ReExpr mkToRe(SeqExpr s)
{
checkContextMatch(s);
return new ReExpr(this, Native.mkSeqToRe(nCtx(), s.getNativeObject()));
return (ReExpr) Expr.create(this, Native.mkSeqToRe(nCtx(), s.getNativeObject()));
}
/**
* Check for regular expression membership.
*/
public BoolExpr MkInRe(SeqExpr s, ReExpr re)
public BoolExpr mkInRe(SeqExpr s, ReExpr re)
{
checkContextMatch(s, re);
return new BoolExpr(this, Native.mkSeqInRe(nCtx(), s.getNativeObject(), re.getNativeObject()));
return (BoolExpr) Expr.create(this, Native.mkSeqInRe(nCtx(), s.getNativeObject(), re.getNativeObject()));
}
/**
* Take the Kleene star of a regular expression.
*/
public ReExpr MkStar(ReExpr re)
public ReExpr mkStar(ReExpr re)
{
checkContextMatch(re);
return new ReExpr(this, Native.mkReStar(nCtx(), re.getNativeObject()));
return (ReExpr) Expr.create(this, Native.mkReStar(nCtx(), re.getNativeObject()));
}
/**
* Take the lower and upper-bounded Kleene star of a regular expression.
*/
public ReExpr mkLoop(ReExpr re, int lo, int hi)
{
return (ReExpr) Expr.create(this, Native.mkReLoop(nCtx(), re.getNativeObject(), lo, hi));
}
/**
* Take the lower-bounded Kleene star of a regular expression.
*/
public ReExpr mkLoop(ReExpr re, int lo)
{
return (ReExpr) Expr.create(this, Native.mkReLoop(nCtx(), re.getNativeObject(), lo, 0));
}
/**
* Take the Kleene plus of a regular expression.
*/
public ReExpr MPlus(ReExpr re)
public ReExpr mkPlus(ReExpr re)
{
checkContextMatch(re);
return new ReExpr(this, Native.mkRePlus(nCtx(), re.getNativeObject()));
return (ReExpr) Expr.create(this, Native.mkRePlus(nCtx(), re.getNativeObject()));
}
/**
* Create the optional regular expression.
*/
public ReExpr MOption(ReExpr re)
public ReExpr mkOption(ReExpr re)
{
checkContextMatch(re);
return new ReExpr(this, Native.mkReOption(nCtx(), re.getNativeObject()));
return (ReExpr) Expr.create(this, Native.mkReOption(nCtx(), re.getNativeObject()));
}
/**
* Create the complement regular expression.
*/
public ReExpr mkComplement(ReExpr re)
{
checkContextMatch(re);
return (ReExpr) Expr.create(this, Native.mkReComplement(nCtx(), re.getNativeObject()));
}
/**
* Create the concatenation of regular languages.
*/
public ReExpr MkConcat(ReExpr... t)
public ReExpr mkConcat(ReExpr... t)
{
checkContextMatch(t);
return new ReExpr(this, Native.mkReConcat(nCtx(), t.length, AST.arrayToNative(t)));
return (ReExpr) Expr.create(this, Native.mkReConcat(nCtx(), t.length, AST.arrayToNative(t)));
}
/**
* Create the union of regular languages.
*/
public ReExpr MkUnion(ReExpr... t)
public ReExpr mkUnion(ReExpr... t)
{
checkContextMatch(t);
return new ReExpr(this, Native.mkReUnion(nCtx(), t.length, AST.arrayToNative(t)));
return (ReExpr) Expr.create(this, Native.mkReUnion(nCtx(), t.length, AST.arrayToNative(t)));
}
/**
* Create the intersection of regular languages.
*/
public ReExpr mkIntersect(ReExpr... 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)
{
checkContextMatch(lo, hi);
return (ReExpr) Expr.create(this, Native.mkReRange(nCtx(), lo.getNativeObject(), hi.getNativeObject()));
}
/**
* Create an at-most-k constraint.
*/
public BoolExpr mkAtMost(BoolExpr[] args, int k)
{
checkContextMatch(args);
return (BoolExpr) Expr.create(this, Native.mkAtmost(nCtx(), args.length, AST.arrayToNative(args), k));
}
/**
* Create an at-least-k constraint.
*/
public BoolExpr mkAtLeast(BoolExpr[] args, int k)
{
checkContextMatch(args);
return (BoolExpr) Expr.create(this, Native.mkAtleast(nCtx(), args.length, AST.arrayToNative(args), k));
}
/**
* Create a pseudo-Boolean less-or-equal constraint.
*/
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));
}
/**
* Create a pseudo-Boolean greater-or-equal constraint.
*/
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));
}
/**
* Create a pseudo-Boolean equal constraint.
*/
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));
}
/**
* Create a Term of a given sort.

View file

@ -3701,12 +3701,8 @@ def Extract(high, low, a):
high = StringVal(high)
if is_seq(high):
s = high
offset = _py2expr(low, high.ctx)
length = _py2expr(a, high.ctx)
if __debug__:
_z3_assert(is_int(offset) and is_int(length), "Second and third arguments must be integers")
return SeqRef(Z3_mk_seq_extract(s.ctx_ref(), s.as_ast(), offset.as_ast(), length.as_ast()), s.ctx)
offset, length = _coerce_exprs(low, a, s.ctx)
return SeqRef(Z3_mk_seq_extract(s.ctx_ref(), s.as_ast(), offset.as_ast(), length.as_ast()), s.ctx)
if __debug__:
_z3_assert(low <= high, "First argument must be greater than or equal to second argument")
_z3_assert(_is_int(high) and high >= 0 and _is_int(low) and low >= 0, "First and second arguments must be non negative integers")
@ -6198,7 +6194,7 @@ class Solver(Z3PPObject):
>>> s.consequences([a],[b,c,d])
(sat, [Implies(a, b), Implies(a, c)])
>>> s.consequences([Not(c),d],[a,b,c,d])
(sat, [Implies(Not(c), Not(c)), Implies(d, d), Implies(Not(c), Not(b)), Implies(Not(c), Not(a))])
(sat, [Implies(d, d), Implies(Not(c), Not(c)), Implies(Not(c), Not(b)), Implies(Not(c), Not(a))])
"""
if isinstance(assumptions, list):
_asms = AstVector(None, self.ctx)
@ -7204,7 +7200,7 @@ def With(t, *args, **keys):
>>> t((x + 1)*(y + 2) == 0)
[[2*x + y + x*y == -2]]
"""
ctx = keys.get('ctx', None)
ctx = keys.pop('ctx', None)
t = _to_tactic(t, ctx)
p = args2params(args, keys, t.ctx)
return Tactic(Z3_tactic_using_params(t.ctx.ref(), t.tactic, p.params), t.ctx)

View file

@ -1500,7 +1500,7 @@ extern "C" {
All main interaction with Z3 happens in the context of a \c Z3_context.
In contrast to #Z3_mk_context_rc, the life time of Z3_ast objects
are determined by the scope level of #Z3_push and #Z3_pop.
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
the object was created.
@ -3091,8 +3091,8 @@ extern "C" {
\brief Create a numeral of a given sort.
\param c logical context.
\param numeral A string representing the numeral value in decimal notation. The string may be of the form \code{[num]*[.[num]*][E[+|-][num]+]}.
If the given sort is a real, then the numeral can be a rational, that is, a string of the form \ccode{[num]* / [num]*}.
\param numeral A string representing the numeral value in decimal notation. The string may be of the form `[num]*[.[num]*][E[+|-][num]+]`.
If the given sort is a real, then the numeral can be a rational, that is, a string of the form `[num]* / [num]*` .
\param ty The sort of the numeral. In the current implementation, the given sort can be an int, real, finite-domain, or bit-vectors of arbitrary size.
\sa Z3_mk_int
@ -3306,7 +3306,7 @@ extern "C" {
Z3_ast Z3_API Z3_mk_seq_replace(Z3_context c, Z3_ast s, Z3_ast src, Z3_ast dst);
/**
\brief Retrieve from \s the unit sequence positioned at position \c index.
\brief Retrieve from \c s the unit sequence positioned at position \c index.
def_API('Z3_mk_seq_at' ,AST ,(_in(CONTEXT), _in(AST), _in(AST)))
*/
@ -4006,7 +4006,7 @@ extern "C" {
def_API('Z3_mk_pble', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT)))
*/
Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args,
Z3_ast const args[], int coeffs[],
Z3_ast const args[], int const coeffs[],
int k);
/**
@ -4017,7 +4017,7 @@ extern "C" {
def_API('Z3_mk_pbge', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT)))
*/
Z3_ast Z3_API Z3_mk_pbge(Z3_context c, unsigned num_args,
Z3_ast const args[], int coeffs[],
Z3_ast const args[], int const coeffs[],
int k);
/**
@ -4028,7 +4028,7 @@ extern "C" {
def_API('Z3_mk_pbeq', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT)))
*/
Z3_ast Z3_API Z3_mk_pbeq(Z3_context c, unsigned num_args,
Z3_ast const args[], int coeffs[],
Z3_ast const args[], int const coeffs[],
int k);
/**

View file

@ -35,7 +35,7 @@ struct arith_decl_plugin::algebraic_numbers_wrapper {
~algebraic_numbers_wrapper() {
}
unsigned mk_id(algebraic_numbers::anum const & val) {
SASSERT(!m_amanager.is_rational(val));
unsigned new_id = m_id_gen.mk();
@ -121,7 +121,7 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) {
m_int_decl = m->mk_sort(symbol("Int"), sort_info(id, INT_SORT));
m->inc_ref(m_int_decl);
sort * i = m_int_decl;
sort * b = m->mk_bool_sort();
#define MK_PRED(FIELD, NAME, KIND, SORT) { \
@ -140,7 +140,7 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) {
MK_PRED(m_i_ge_decl, ">=", OP_GE, i);
MK_PRED(m_i_lt_decl, "<", OP_LT, i);
MK_PRED(m_i_gt_decl, ">", OP_GT, i);
#define MK_AC_OP(FIELD, NAME, KIND, SORT) { \
func_decl_info info(id, KIND); \
info.set_associative(); \
@ -205,7 +205,7 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) {
MK_UNARY(m_asinh_decl, "asinh", OP_ASINH, r);
MK_UNARY(m_acosh_decl, "acosh", OP_ACOSH, r);
MK_UNARY(m_atanh_decl, "atanh", OP_ATANH, r);
func_decl * pi_decl = m->mk_const_decl(symbol("pi"), r, func_decl_info(id, OP_PI));
m_pi = m->mk_const(pi_decl);
m->inc_ref(m_pi);
@ -213,7 +213,7 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) {
func_decl * e_decl = m->mk_const_decl(symbol("euler"), r, func_decl_info(id, OP_E));
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);
@ -221,7 +221,7 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) {
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);
@ -285,7 +285,8 @@ arith_decl_plugin::arith_decl_plugin():
m_idiv_0_decl(0),
m_mod_0_decl(0),
m_u_asin_decl(0),
m_u_acos_decl(0) {
m_u_acos_decl(0),
m_convert_int_numerals_to_real(false) {
}
arith_decl_plugin::~arith_decl_plugin() {
@ -418,7 +419,7 @@ app * arith_decl_plugin::mk_numeral(rational const & val, bool is_int) {
if (val.is_unsigned()) {
unsigned u_val = val.get_unsigned();
if (u_val < MAX_SMALL_NUM_TO_CACHE) {
if (is_int) {
if (is_int && !m_convert_int_numerals_to_real) {
app * r = m_small_ints.get(u_val, 0);
if (r == 0) {
parameter p[2] = { parameter(val), parameter(1) };
@ -442,7 +443,7 @@ app * arith_decl_plugin::mk_numeral(rational const & val, bool is_int) {
}
parameter p[2] = { parameter(val), parameter(static_cast<int>(is_int)) };
func_decl * decl;
if (is_int)
if (is_int && !m_convert_int_numerals_to_real)
decl = m_manager->mk_const_decl(m_intv_sym, m_int_decl, func_decl_info(m_family_id, OP_NUM, 2, p));
else
decl = m_manager->mk_const_decl(m_realv_sym, m_real_decl, func_decl_info(m_family_id, OP_NUM, 2, p));
@ -479,14 +480,14 @@ 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 ||
return
k == OP_PI ||
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,
func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (k == OP_NUM)
return mk_num_decl(num_parameters, parameters, arity);
@ -503,7 +504,7 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
}
}
func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned num_args, expr * const * args, sort * range) {
if (k == OP_NUM)
return mk_num_decl(num_parameters, parameters, num_args);
@ -521,9 +522,17 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
}
void arith_decl_plugin::get_sort_names(svector<builtin_name>& sort_names, symbol const & logic) {
// TODO: only define Int and Real in the right logics
sort_names.push_back(builtin_name("Int", INT_SORT));
sort_names.push_back(builtin_name("Real", REAL_SORT));
if (logic == "NRA" ||
logic == "QF_NRA" ||
logic == "QF_UFNRA") {
m_convert_int_numerals_to_real = true;
sort_names.push_back(builtin_name("Real", REAL_SORT));
}
else {
// TODO: only define Int and Real in the right logics
sort_names.push_back(builtin_name("Int", INT_SORT));
sort_names.push_back(builtin_name("Real", REAL_SORT));
}
}
void arith_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol const & logic) {
@ -563,16 +572,16 @@ void arith_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol con
}
bool arith_decl_plugin::is_value(app * e) const {
return
is_app_of(e, m_family_id, OP_NUM) ||
return
is_app_of(e, m_family_id, OP_NUM) ||
is_app_of(e, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM) ||
is_app_of(e, m_family_id, OP_PI) ||
is_app_of(e, m_family_id, OP_E);
}
bool arith_decl_plugin::is_unique_value(app * e) const {
return
is_app_of(e, m_family_id, OP_NUM) ||
return
is_app_of(e, m_family_id, OP_NUM) ||
is_app_of(e, m_family_id, OP_PI) ||
is_app_of(e, m_family_id, OP_E);
}
@ -671,7 +680,7 @@ expr_ref arith_util::mk_mul_simplify(expr_ref_vector const& args) {
}
expr_ref arith_util::mk_mul_simplify(unsigned sz, expr* const* args) {
expr_ref result(m_manager);
switch (sz) {
case 0:
result = mk_numeral(rational(1), true);
@ -681,7 +690,7 @@ expr_ref arith_util::mk_mul_simplify(unsigned sz, expr* const* args) {
break;
default:
result = mk_mul(sz, args);
break;
break;
}
return result;
}
@ -692,7 +701,7 @@ expr_ref arith_util::mk_add_simplify(expr_ref_vector const& args) {
}
expr_ref arith_util::mk_add_simplify(unsigned sz, expr* const* args) {
expr_ref result(m_manager);
switch (sz) {
case 0:
result = mk_numeral(rational(0), true);
@ -702,7 +711,7 @@ expr_ref arith_util::mk_add_simplify(unsigned sz, expr* const* args) {
break;
default:
result = mk_add(sz, args);
break;
break;
}
return result;
}

View file

@ -152,6 +152,8 @@ protected:
ptr_vector<app> m_small_ints;
ptr_vector<app> m_small_reals;
bool m_convert_int_numerals_to_real;
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);

View file

@ -17,6 +17,7 @@ Revision History:
--*/
#include<sstream>
#include<cstring>
#include"ast.h"
#include"ast_pp.h"
#include"ast_ll_pp.h"

View file

@ -117,6 +117,9 @@ public:
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(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(unsigned ext_id, bool):m_kind(PARAM_EXTERNAL), m_ext_id(ext_id) {}
parameter(parameter const&);

View file

@ -1002,14 +1002,6 @@ class smt2_printer {
reset_stacks();
SASSERT(&(r.get_manager()) == &(fm()));
m_soccs(n);
TRACE("smt2_pp_shared",
tout << "shared terms for:\n" << mk_pp(n, m()) << "\n";
tout << "------>\n";
shared_occs::iterator it = m_soccs.begin_shared();
shared_occs::iterator end = m_soccs.end_shared();
for (; it != end; ++it) {
tout << mk_pp(*it, m()) << "\n";
});
m_root = n;
push_frame(n, true);
while (!m_frame_stack.empty()) {

View file

@ -406,11 +406,11 @@ public:
app * mk_bv_not(expr * arg) { return m_manager.mk_app(get_fid(), OP_BNOT, arg); }
app * mk_bv_xor(unsigned num, expr * const * args) { return m_manager.mk_app(get_fid(), OP_BXOR, num, args); }
app * mk_bv_neg(expr * arg) { return m_manager.mk_app(get_fid(), OP_BNEG, arg); }
app * mk_bv_urem(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_BUREM, arg1, arg2); }
app * mk_bv_srem(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_BSREM, arg1, arg2); }
app * mk_bv_add(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_BADD, arg1, arg2); }
app * mk_bv_sub(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_BSUB, arg1, arg2); }
app * mk_bv_mul(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_BMUL, arg1, arg2); }
app * mk_bv_urem(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BUREM, arg1, arg2); }
app * mk_bv_srem(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BSREM, arg1, arg2); }
app * mk_bv_add(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BADD, arg1, arg2); }
app * mk_bv_sub(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BSUB, arg1, arg2); }
app * mk_bv_mul(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BMUL, arg1, arg2); }
app * mk_zero_extend(unsigned n, expr* e) {
parameter p(n);
return m_manager.mk_app(get_fid(), OP_ZERO_EXT, 1, &p, 1, &e);

View file

@ -23,8 +23,21 @@ void decl_collector::visit_sort(sort * n) {
family_id fid = n->get_family_id();
if (m().is_uninterp(n))
m_sorts.push_back(n);
if (fid == m_dt_fid)
if (fid == m_dt_fid) {
m_sorts.push_back(n);
unsigned num_cnstr = m_dt_util.get_datatype_num_constructors(n);
for (unsigned i = 0; i < num_cnstr; i++) {
func_decl * cnstr = m_dt_util.get_datatype_constructors(n)->get(i);
m_decls.push_back(cnstr);
ptr_vector<func_decl> const & cnstr_acc = *m_dt_util.get_constructor_accessors(cnstr);
unsigned num_cas = cnstr_acc.size();
for (unsigned j = 0; j < num_cas; j++) {
func_decl * accsr = cnstr_acc.get(j);
m_decls.push_back(accsr);
}
}
}
}
bool decl_collector::is_bool(sort * s) {
@ -38,14 +51,15 @@ void decl_collector::visit_func(func_decl * n) {
m_preds.push_back(n);
else
m_decls.push_back(n);
}
}
}
decl_collector::decl_collector(ast_manager & m, bool preds):
m_manager(m),
m_sep_preds(preds) {
m_sep_preds(preds),
m_dt_util(m) {
m_basic_fid = m_manager.get_basic_family_id();
m_dt_fid = m_manager.mk_family_id("datatype");
m_dt_fid = m_dt_util.get_family_id();
}
void decl_collector::visit(ast* n) {
@ -55,7 +69,7 @@ void decl_collector::visit(ast* n) {
n = todo.back();
todo.pop_back();
if (!m_visited.is_marked(n)) {
m_visited.mark(n, true);
m_visited.mark(n, true);
switch(n->get_kind()) {
case AST_APP: {
app * a = to_app(n);
@ -64,7 +78,7 @@ void decl_collector::visit(ast* n) {
}
todo.push_back(a->get_decl());
break;
}
}
case AST_QUANTIFIER: {
quantifier * q = to_quantifier(n);
unsigned num_decls = q->get_num_decls();
@ -77,7 +91,7 @@ void decl_collector::visit(ast* n) {
}
break;
}
case AST_SORT:
case AST_SORT:
visit_sort(to_sort(n));
break;
case AST_FUNC_DECL: {

View file

@ -21,6 +21,7 @@ Revision History:
#define SMT_DECL_COLLECTOR_H_
#include"ast.h"
#include"datatype_decl_plugin.h"
class decl_collector {
ast_manager & m_manager;
@ -28,9 +29,10 @@ class decl_collector {
ptr_vector<sort> m_sorts;
ptr_vector<func_decl> m_decls;
ptr_vector<func_decl> m_preds;
ast_mark m_visited;
family_id m_basic_fid;
family_id m_dt_fid;
ast_mark m_visited;
family_id m_basic_fid;
family_id m_dt_fid;
datatype_util m_dt_util;
void visit_sort(sort* n);
bool is_bool(sort* s);

View file

@ -19,22 +19,22 @@ Revision History:
--*/
#include"macro_util.h"
#include"occurs.h"
#include"ast_util.h"
#include"arith_simplifier_plugin.h"
#include"basic_simplifier_plugin.h"
#include"bv_simplifier_plugin.h"
#include"var_subst.h"
#include"ast_pp.h"
#include"ast_ll_pp.h"
#include"ast_util.h"
#include"for_each_expr.h"
#include"well_sorted.h"
#include"bool_rewriter.h"
macro_util::macro_util(ast_manager & m, simplifier & s):
m_manager(m),
m_bv(m),
m_simplifier(s),
m_arith_simp(0),
m_bv_simp(0),
m_basic_simp(0),
m_forbidden_set(0),
m_curr_clause(0) {
}
@ -55,24 +55,17 @@ bv_simplifier_plugin * macro_util::get_bv_simp() const {
return m_bv_simp;
}
basic_simplifier_plugin * macro_util::get_basic_simp() const {
if (m_basic_simp == 0) {
const_cast<macro_util*>(this)->m_basic_simp = static_cast<basic_simplifier_plugin*>(m_simplifier.get_plugin(m_manager.get_basic_family_id()));
}
SASSERT(m_basic_simp != 0);
return m_basic_simp;
}
bool macro_util::is_bv(expr * n) const {
return get_bv_simp()->is_bv(n);
return m_bv.is_bv(n);
}
bool macro_util::is_bv_sort(sort * s) const {
return get_bv_simp()->is_bv_sort(s);
return m_bv.is_bv_sort(s);
}
bool macro_util::is_add(expr * n) const {
return get_arith_simp()->is_add(n) || get_bv_simp()->is_add(n);
return get_arith_simp()->is_add(n) || m_bv.is_bv_add(n);
}
bool macro_util::is_times_minus_one(expr * n, expr * & arg) const {
@ -80,11 +73,11 @@ bool macro_util::is_times_minus_one(expr * n, expr * & arg) const {
}
bool macro_util::is_le(expr * n) const {
return get_arith_simp()->is_le(n) || get_bv_simp()->is_le(n);
return get_arith_simp()->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) || get_bv_simp()->is_le_ge(n);
return get_arith_simp()->is_le_ge(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 {
@ -102,7 +95,7 @@ app * macro_util::mk_zero(sort * s) const {
void macro_util::mk_sub(expr * t1, expr * t2, expr_ref & r) const {
if (is_bv(t1)) {
get_bv_simp()->mk_sub(t1, t2, r);
r = m_bv.mk_bv_sub(t1, t2);
}
else {
get_arith_simp()->mk_sub(t1, t2, r);
@ -111,7 +104,7 @@ void macro_util::mk_sub(expr * t1, expr * t2, expr_ref & r) const {
void macro_util::mk_add(expr * t1, expr * t2, expr_ref & r) const {
if (is_bv(t1)) {
get_bv_simp()->mk_add(t1, t2, r);
r = m_bv.mk_bv_add(t1, t2);
}
else {
get_arith_simp()->mk_add(t1, t2, r);
@ -429,7 +422,7 @@ void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned & num_decl
new_args.push_back(new_var);
new_conds.push_back(new_cond);
}
get_basic_simp()->mk_and(new_conds.size(), new_conds.c_ptr(), cond);
bool_rewriter(m_manager).mk_and(new_conds.size(), new_conds.c_ptr(), cond);
head = m_manager.mk_app(qhead->get_decl(), new_args.size(), new_args.c_ptr());
num_decls = next_var_idx;
}
@ -687,7 +680,7 @@ void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def,
if (cond == 0)
new_cond = extra_cond;
else
get_basic_simp()->mk_and(cond, extra_cond, new_cond);
bool_rewriter(m_manager).mk_and(cond, extra_cond, new_cond);
}
else {
hint_to_macro_head(m_manager, head, num_decls, new_head);
@ -719,20 +712,19 @@ void macro_util::get_rest_clause_as_cond(expr * except_lit, expr_ref & extra_con
if (m_curr_clause == 0)
return;
SASSERT(is_clause(m_manager, m_curr_clause));
basic_simplifier_plugin * bs = get_basic_simp();
expr_ref_buffer neg_other_lits(m_manager);
unsigned num_lits = get_clause_num_literals(m_manager, m_curr_clause);
for (unsigned i = 0; i < num_lits; i++) {
expr * l = get_clause_literal(m_manager, m_curr_clause, i);
if (l != except_lit) {
expr_ref neg_l(m_manager);
bs->mk_not(l, neg_l);
bool_rewriter(m_manager).mk_not(l, neg_l);
neg_other_lits.push_back(neg_l);
}
}
if (neg_other_lits.empty())
return;
get_basic_simp()->mk_and(neg_other_lits.size(), neg_other_lits.c_ptr(), extra_cond);
bool_rewriter(m_manager).mk_and(neg_other_lits.size(), neg_other_lits.c_ptr(), extra_cond);
}
void macro_util::collect_poly_args(expr * n, expr * exception, ptr_buffer<expr> & args) {

View file

@ -62,10 +62,10 @@ 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;
basic_simplifier_plugin * m_basic_simp;
obj_hashtable<func_decl> * m_forbidden_set;
bool is_forbidden(func_decl * f) const { return m_forbidden_set != 0 && m_forbidden_set->contains(f); }
@ -99,7 +99,6 @@ public:
arith_simplifier_plugin * get_arith_simp() const;
bv_simplifier_plugin * get_bv_simp() const;
basic_simplifier_plugin * get_basic_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;

View file

@ -28,7 +28,7 @@ struct defined_names::impl {
typedef obj_map<expr, proof *> expr2proof;
ast_manager & m_manager;
symbol m_z3name;
/**
\brief Mapping from expressions to their names. A name is an application.
If the expression does not have free variables, then the name is just a constant.
@ -38,25 +38,25 @@ struct defined_names::impl {
\brief Mapping from expressions to the apply-def proof.
That is, for each expression e, m_expr2proof[e] is the
proof e and m_expr2name[2] are observ. equivalent.
This mapping is not used if proof production is disabled.
*/
expr2proof m_expr2proof;
/**
\brief Domain of m_expr2name. It is used to keep the expressions
alive and for backtracking
*/
expr_ref_vector m_exprs;
expr_ref_vector m_exprs;
expr_ref_vector m_names; //!< Range of m_expr2name. It is used to keep the names alive.
proof_ref_vector m_apply_proofs; //!< Range of m_expr2proof. It is used to keep the def-intro proofs alive.
unsigned_vector m_lims; //!< Backtracking support.
impl(ast_manager & m, char const * prefix);
virtual ~impl();
app * gen_name(expr * e, sort_ref_buffer & var_sorts, buffer<symbol> & var_names);
void cache_new_name(expr * e, app * name);
void cache_new_name_intro_proof(expr * e, proof * pr);
@ -106,7 +106,7 @@ app * defined_names::impl::gen_name(expr * e, sort_ref_buffer & var_sorts, buffe
for (unsigned i = 0; i < num_vars; i++) {
sort * s = uv.get(i);
if (s) {
domain.push_back(s);
domain.push_back(s);
new_args.push_back(m_manager.mk_var(i, s));
var_sorts.push_back(s);
}
@ -162,7 +162,7 @@ void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbo
1, symbol::null, symbol::null,
1, patterns);
TRACE("mk_definition_bug", tout << "before elim_unused_vars:\n" << mk_ismt2_pp(q, m_manager) << "\n";);
elim_unused_vars(m_manager, q, result);
elim_unused_vars(m_manager, q, params_ref(), result);
TRACE("mk_definition_bug", tout << "after elim_unused_vars:\n" << mk_ismt2_pp(result, m_manager) << "\n";);
}
}
@ -207,7 +207,7 @@ bool defined_names::impl::mk_name(expr * e, expr_ref & new_def, proof_ref & new_
app * n_ptr;
if (m_expr2name.find(e, n_ptr)) {
TRACE("mk_definition_bug", tout << "name for expression is already cached..., returning false...\n";);
TRACE("mk_definition_bug", tout << "name for expression is already cached..., returning false...\n";);
n = n_ptr;
if (m_manager.proofs_enabled()) {
proof * pr_ptr = 0;
@ -220,19 +220,19 @@ bool defined_names::impl::mk_name(expr * e, expr_ref & new_def, proof_ref & new_
else {
sort_ref_buffer var_sorts(m_manager);
buffer<symbol> var_names;
n = gen_name(e, var_sorts, var_names);
cache_new_name(e, n);
TRACE("mk_definition_bug", tout << "name: " << mk_ismt2_pp(n, m_manager) << "\n";);
// variables are in reverse order in quantifiers
std::reverse(var_sorts.c_ptr(), var_sorts.c_ptr() + var_sorts.size());
std::reverse(var_names.c_ptr(), var_names.c_ptr() + var_names.size());
mk_definition(e, n, var_sorts, var_names, new_def);
TRACE("mk_definition_bug", tout << "new_def:\n" << mk_ismt2_pp(new_def, m_manager) << "\n";);
if (m_manager.proofs_enabled()) {
new_def_pr = m_manager.mk_def_intro(new_def);
pr = m_manager.mk_apply_def(e, n, new_def_pr);
@ -311,11 +311,11 @@ void defined_names::reset() {
m_pos_impl->reset();
}
unsigned defined_names::get_num_names() const {
unsigned defined_names::get_num_names() const {
return m_impl->get_num_names() + m_pos_impl->get_num_names();
}
func_decl * defined_names::get_name_decl(unsigned i) const {
func_decl * defined_names::get_name_decl(unsigned i) const {
SASSERT(i < get_num_names());
unsigned n1 = m_impl->get_num_names();
return i < n1 ? m_impl->get_name_decl(i) : m_pos_impl->get_name_decl(i - n1);

View file

@ -194,7 +194,7 @@ bool arith_rewriter::is_bound(expr * arg1, expr * arg2, op_kind kind, expr_ref &
}
}
expr* t1, *t2;
bool is_int;
bool is_int = false;
if (m_util.is_mod(arg2)) {
std::swap(arg1, arg2);
switch (kind) {

View file

@ -36,7 +36,7 @@ static bool is_neg_var(ast_manager & m, expr * e, unsigned num_decls) {
/**
\brief Return true if \c e is of the form (not (= VAR t)) or (not (iff VAR t)) or (iff VAR t) or (iff (not VAR) t) or (VAR IDX) or (not (VAR IDX)).
The last case can be viewed
The last case can be viewed
*/
bool der::is_var_diseq(expr * e, unsigned num_decls, var * & v, expr_ref & t) {
// (not (= VAR t)) and (not (iff VAR t)) cases
@ -49,7 +49,7 @@ bool der::is_var_diseq(expr * e, unsigned num_decls, var * & v, expr_ref & t) {
return false;
if (!is_var(lhs, num_decls))
std::swap(lhs, rhs);
SASSERT(is_var(lhs, num_decls));
SASSERT(is_var(lhs, num_decls));
// Remark: Occurs check is not necessary here... the top-sort procedure will check for cycles...
// if (occurs(lhs, rhs)) {
// return false;
@ -67,7 +67,7 @@ bool der::is_var_diseq(expr * e, unsigned num_decls, var * & v, expr_ref & t) {
if (is_var(lhs, num_decls) || is_var(rhs, num_decls)) {
if (!is_var(lhs, num_decls))
std::swap(lhs, rhs);
SASSERT(is_var(lhs, num_decls));
SASSERT(is_var(lhs, num_decls));
// Remark: Occurs check is not necessary here... the top-sort procedure will check for cycles...
// if (occurs(lhs, rhs)) {
// return false;
@ -83,11 +83,11 @@ bool der::is_var_diseq(expr * e, unsigned num_decls, var * & v, expr_ref & t) {
if (!is_neg_var(m_manager, lhs, num_decls))
std::swap(lhs, rhs);
SASSERT(is_neg_var(m_manager, lhs, num_decls));
expr * lhs_var = to_app(lhs)->get_arg(0);
expr * lhs_var = to_app(lhs)->get_arg(0);
// Remark: Occurs check is not necessary here... the top-sort procedure will check for cycles...
// if (occurs(lhs_var, rhs)) {
// return false;
// }
// }
v = to_var(lhs_var);
t = rhs;
TRACE("der", tout << mk_pp(e, m_manager) << "\n";);
@ -134,11 +134,11 @@ void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
pr = m_manager.mk_transitivity(pr, curr_pr);
}
} while (q != r && is_quantifier(r));
// Eliminate variables that have become unused
if (reduced && is_forall(r)) {
quantifier * q = to_quantifier(r);
elim_unused_vars(m_manager, q, r);
elim_unused_vars(m_manager, q, params_ref(), r);
if (m_manager.proofs_enabled()) {
proof * p1 = m_manager.mk_elim_unused_vars(q, r);
pr = m_manager.mk_transitivity(pr, p1);
@ -153,24 +153,24 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
r = q;
return;
}
expr * e = q->get_expr();
unsigned num_decls = q->get_num_decls();
var * v = 0;
expr_ref t(m_manager);
expr_ref t(m_manager);
if (m_manager.is_or(e)) {
unsigned num_args = to_app(e)->get_num_args();
unsigned i = 0;
unsigned diseq_count = 0;
unsigned largest_vinx = 0;
m_map.reset();
m_pos2var.reset();
m_inx2var.reset();
m_pos2var.reserve(num_args, -1);
// Find all disequalities
for (; i < num_args; i++) {
if (is_var_diseq(to_app(e)->get_arg(i), num_decls, v, t)) {
@ -192,7 +192,7 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
get_elimination_order();
SASSERT(m_order.size() <= diseq_count); // some might be missing because of cycles
if (!m_order.empty()) {
if (!m_order.empty()) {
create_substitution(largest_vinx + 1);
apply_substitution(q, r);
}
@ -202,22 +202,22 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
r = q;
}
}
// Remark: get_elimination_order/top-sort checks for cycles, but it is not invoked for unit clauses.
// Remark: get_elimination_order/top-sort checks for cycles, but it is not invoked for unit clauses.
// So, we must perform a occurs check here.
else if (is_var_diseq(e, num_decls, v, t) && !occurs(v, t)) {
r = m_manager.mk_false();
}
else
else
r = q;
if (m_manager.proofs_enabled()) {
pr = r == q ? 0 : m_manager.mk_der(q, r);
}
}
}
void der_sort_vars(ptr_vector<var> & vars, ptr_vector<expr> & definitions, unsigned_vector & order) {
order.reset();
// eliminate self loops, and definitions containing quantifiers.
bool found = false;
for (unsigned i = 0; i < definitions.size(); i++) {
@ -228,7 +228,7 @@ void der_sort_vars(ptr_vector<var> & vars, ptr_vector<expr> & definitions, unsig
else
found = true; // found at least one candidate
}
if (!found)
return;
@ -329,14 +329,14 @@ void der::get_elimination_order() {
// der::top_sort ts(m_manager);
der_sort_vars(m_inx2var, m_map, m_order);
TRACE("der",
TRACE("der",
tout << "Elimination m_order:" << std::endl;
for(unsigned i=0; i<m_order.size(); i++)
{
if (i != 0) tout << ",";
tout << m_order[i];
}
tout << std::endl;
tout << std::endl;
);
}
@ -359,24 +359,24 @@ void der::create_substitution(unsigned sz) {
void der::apply_substitution(quantifier * q, expr_ref & r) {
expr * e = q->get_expr();
unsigned num_args=to_app(e)->get_num_args();
unsigned num_args=to_app(e)->get_num_args();
// get a new expression
m_new_args.reset();
for(unsigned i = 0; i < num_args; i++) {
int x = m_pos2var[i];
if (x != -1 && m_map[x] != 0)
if (x != -1 && m_map[x] != 0)
continue; // this is a disequality with definition (vanishes)
m_new_args.push_back(to_app(e)->get_arg(i));
}
unsigned sz = m_new_args.size();
expr_ref t(m_manager);
t = (sz == 1) ? m_new_args[0] : m_manager.mk_or(sz, m_new_args.c_ptr());
expr_ref new_e(m_manager);
expr_ref new_e(m_manager);
m_subst(t, m_subst_map.size(), m_subst_map.c_ptr(), new_e);
// don't forget to update the quantifier patterns
expr_ref_buffer new_patterns(m_manager);
expr_ref_buffer new_no_patterns(m_manager);
@ -392,7 +392,7 @@ void der::apply_substitution(quantifier * q, expr_ref & r) {
new_no_patterns.push_back(new_nopat);
}
r = m_manager.update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(),
r = m_manager.update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(),
new_no_patterns.size(), new_no_patterns.c_ptr(), new_e);
}
@ -404,9 +404,9 @@ struct der_rewriter_cfg : public default_rewriter_cfg {
ast_manager & m() const { return m_der.m(); }
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
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) {

View file

@ -53,6 +53,7 @@ struct pb2bv_rewriter::imp {
rational m_k;
vector<rational> m_coeffs;
bool m_keep_cardinality_constraints;
bool m_keep_pb_constraints;
unsigned m_min_arity;
template<lbool is_le>
@ -113,12 +114,15 @@ struct pb2bv_rewriter::imp {
return expr_ref((is_le == l_false)?m.mk_true():m.mk_false(), m);
}
#if 0
expr_ref result(m);
switch (is_le) {
case l_true: if (mk_le_tot(sz, args, k, result)) return result; else break;
case l_false: if (mk_ge_tot(sz, args, k, result)) return result; else break;
case l_undef: break;
}
#endif
#if 0
expr_ref result(m);
switch (is_le) {
@ -562,6 +566,7 @@ struct pb2bv_rewriter::imp {
m_trail(m),
m_args(m),
m_keep_cardinality_constraints(false),
m_keep_pb_constraints(false),
m_min_arity(2)
{}
@ -698,11 +703,33 @@ struct pb2bv_rewriter::imp {
if (m_keep_cardinality_constraints && f->get_arity() >= m_min_arity) return false;
result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args);
}
else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_keep_pb_constraints) {
return false;
}
else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_keep_pb_constraints) {
return false;
}
else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_keep_pb_constraints) {
return false;
}
else {
result = mk_bv(f, sz, args);
}
return true;
}
bool has_small_coefficients(func_decl* f) {
unsigned sz = f->get_arity();
unsigned sum = 0;
for (unsigned i = 0; i < sz; ++i) {
rational c = pb.get_coeff(f, i);
if (!c.is_unsigned()) return false;
unsigned sum1 = sum + c.get_unsigned();
if (sum1 < sum) return false;
sum = sum1;
}
return true;
}
// definitions used for sorting network
literal mk_false() { return m.mk_false(); }
@ -730,6 +757,10 @@ struct pb2bv_rewriter::imp {
void keep_cardinality_constraints(bool f) {
m_keep_cardinality_constraints = f;
}
void keep_pb_constraints(bool f) {
m_keep_pb_constraints = f;
}
};
struct card2bv_rewriter_cfg : public default_rewriter_cfg {
@ -742,6 +773,7 @@ struct pb2bv_rewriter::imp {
}
card2bv_rewriter_cfg(imp& i, ast_manager & m):m_r(i, m) {}
void keep_cardinality_constraints(bool f) { m_r.keep_cardinality_constraints(f); }
void keep_pb_constraints(bool f) { m_r.keep_pb_constraints(f); }
};
class card_pb_rewriter : public rewriter_tpl<card2bv_rewriter_cfg> {
@ -751,6 +783,7 @@ struct pb2bv_rewriter::imp {
rewriter_tpl<card2bv_rewriter_cfg>(m, false, m_cfg),
m_cfg(i, m) {}
void keep_cardinality_constraints(bool f) { m_cfg.keep_cardinality_constraints(f); }
void keep_pb_constraints(bool f) { m_cfg.keep_pb_constraints(f); }
};
card_pb_rewriter m_rw;
@ -761,14 +794,17 @@ struct pb2bv_rewriter::imp {
m_num_translated(0),
m_rw(*this, m) {
m_rw.keep_cardinality_constraints(p.get_bool("keep_cardinality_constraints", false));
m_rw.keep_pb_constraints(p.get_bool("keep_pb_constraints", false));
}
void updt_params(params_ref const & p) {
m_params.append(p);
m_rw.keep_cardinality_constraints(m_params.get_bool("keep_cardinality_constraints", false));
m_rw.keep_pb_constraints(m_params.get_bool("keep_pb_constraints", false));
}
void collect_param_descrs(param_descrs& r) const {
r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: true) retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver");
r.insert("keep_pb_constraints", CPK_BOOL, "(default: true) retain pb constraints (don't bit-blast them) and use built-in pb solver");
}
unsigned get_num_steps() const { return m_rw.get_num_steps(); }

View file

@ -315,6 +315,8 @@ protected:
template<bool ProofGen>
void process_app(app * t, frame & fr);
bool constant_fold(app* t, frame& fr);
template<bool ProofGen>
void process_quantifier(quantifier * q, frame & fr);

View file

@ -7,6 +7,7 @@ The following classes implement theory specific rewriting rules:
- array_rewriter
- datatype_rewriter
- fpa_rewriter
- seq_rewriter
Each of them provide the method
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result)

View file

@ -174,6 +174,37 @@ bool rewriter_tpl<Config>::visit(expr * t, unsigned max_depth) {
}
}
template<typename Config>
bool rewriter_tpl<Config>::constant_fold(app * t, frame & fr) {
if (fr.m_i == 1 && m().is_ite(t)) {
expr * cond = result_stack()[fr.m_spos].get();
expr* arg = 0;
if (m().is_true(cond)) {
arg = t->get_arg(1);
}
else if (m().is_false(cond)) {
arg = t->get_arg(2);
}
if (arg) {
result_stack().shrink(fr.m_spos);
result_stack().push_back(arg);
fr.m_state = REWRITE_BUILTIN;
if (visit<false>(arg, fr.m_max_depth)) {
m_r = result_stack().back();
result_stack().pop_back();
result_stack().pop_back();
result_stack().push_back(m_r);
cache_result<false>(t, m_r, m_pr, fr.m_cache_result);
frame_stack().pop_back();
set_new_child_flag(t);
}
m_r = 0;
return true;
}
}
return false;
}
template<typename Config>
template<bool ProofGen>
void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
@ -183,16 +214,10 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
case PROCESS_CHILDREN: {
unsigned num_args = t->get_num_args();
while (fr.m_i < num_args) {
expr * arg = t->get_arg(fr.m_i);
if (fr.m_i >= 1 && m().is_ite(t) && !ProofGen) {
expr * cond = result_stack()[fr.m_spos].get();
if (m().is_true(cond)) {
arg = t->get_arg(1);
}
else if (m().is_false(cond)) {
arg = t->get_arg(2);
}
if (!ProofGen && constant_fold(t, fr)) {
return;
}
expr * arg = t->get_arg(fr.m_i);
fr.m_i++;
if (!visit<ProofGen>(arg, fr.m_max_depth))
return;

View file

@ -8,5 +8,6 @@ def_module_params('rewriter',
("push_ite_bv", BOOL, False, "push if-then-else over bit-vector terms."),
("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.")))
("cache_all", BOOL, False, "cache all intermediate results."),
("ignore_patterns_on_ground_qbody", BOOL, True, "ignores patterns on quantifiers that don't mention their bound variables.")))

View file

@ -12,6 +12,7 @@ Abstract:
Author:
Nikolaj Bjorner (nbjorner) 2015-12-5
Murphy Berzish 2017-02-21
Notes:
@ -59,7 +60,12 @@ expr_ref sym_expr::accept(expr* e) {
}
std::ostream& sym_expr::display(std::ostream& out) const {
return out << m_t;
switch (m_ty) {
case t_char: return out << m_t;
case t_range: return out << m_t << ":" << m_s;
case t_pred: return out << m_t;
}
return out << "expression type not recognized";
}
struct display_expr1 {
@ -236,6 +242,7 @@ eautomaton* re2automaton::re2aut(expr* e) {
unsigned nb = s1.num_bits();
expr_ref _start(bv.mk_numeral(start, nb), m);
expr_ref _stop(bv.mk_numeral(stop, nb), m);
TRACE("seq", tout << "Range: " << start << " " << stop << "\n";);
a = alloc(eautomaton, sm, sym_expr::mk_range(_start, _stop));
return a.detach();
}
@ -322,7 +329,8 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
switch(f->get_decl_kind()) {
case OP_SEQ_UNIT:
return BR_FAILED;
SASSERT(num_args == 1);
return mk_seq_unit(args[0], result);
case OP_SEQ_EMPTY:
return BR_FAILED;
case OP_RE_PLUS:
@ -344,7 +352,8 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
SASSERT(num_args == 2);
return mk_re_union(args[0], args[1], result);
case OP_RE_RANGE:
return BR_FAILED;
SASSERT(num_args == 2);
return mk_re_range(args[0], args[1], result);
case OP_RE_INTERSECT:
SASSERT(num_args == 2);
return mk_re_inter(args[0], args[1], result);
@ -427,6 +436,33 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
return BR_FAILED;
}
/*
* (seq.unit (_ BitVector 8)) ==> String constant
*/
br_status seq_rewriter::mk_seq_unit(expr* e, expr_ref& result) {
sort * s = m().get_sort(e);
bv_util bvu(m());
if (is_sort_of(s, bvu.get_family_id(), BV_SORT)) {
// specifically we want (_ BitVector 8)
rational n_val;
unsigned int n_size;
if (bvu.is_numeral(e, n_val, n_size)) {
if (n_size == 8) {
// convert to string constant
char ch = (char)n_val.get_int32();
TRACE("seq", tout << "rewrite seq.unit of 8-bit value " << n_val.to_string() << " to string constant \"" << ch << "\"" << std::endl;);
char s_tmp[2] = {ch, '\0'};
symbol s(s_tmp);
result = m_util.str.mk_string(s);
return BR_DONE;
}
}
}
return BR_FAILED;
}
/*
string + string = string
a + (b + c) = (a + b) + c
@ -509,15 +545,66 @@ br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) {
br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& result) {
zstring s;
rational pos, len;
if (m_util.str.is_string(a, s) && m_autil.is_numeral(b, pos) && m_autil.is_numeral(c, len) &&
pos.is_unsigned() && len.is_unsigned() && pos.get_unsigned() + len.get_unsigned() <= s.length()) {
unsigned _pos = pos.get_unsigned();
unsigned _len = len.get_unsigned();
result = m_util.str.mk_string(s.extract(_pos, _len));
bool constantBase = m_util.str.is_string(a, s);
bool constantPos = m_autil.is_numeral(b, pos);
bool constantLen = m_autil.is_numeral(c, len);
// case 1: pos<0 or len<=0
// rewrite to ""
if ( (constantPos && pos.is_neg()) || (constantLen && !len.is_pos()) ) {
result = m_util.str.mk_empty(m().get_sort(a));
return BR_DONE;
}
// case 1.1: pos >= length(base)
// rewrite to ""
if (constantBase && constantPos && pos >= rational(s.length())) {
result = m_util.str.mk_empty(m().get_sort(a));
return BR_DONE;
}
constantPos &= pos.is_unsigned();
constantLen &= len.is_unsigned();
if (constantBase && constantPos && constantLen) {
if (pos.get_unsigned() + len.get_unsigned() >= s.length()) {
// case 2: pos+len goes past the end of the string
unsigned _len = s.length() - pos.get_unsigned() + 1;
result = m_util.str.mk_string(s.extract(pos.get_unsigned(), _len));
} else {
// case 3: pos+len still within string
result = m_util.str.mk_string(s.extract(pos.get_unsigned(), len.get_unsigned()));
}
return BR_DONE;
}
if (constantPos && constantLen) {
unsigned _pos = pos.get_unsigned();
unsigned _len = len.get_unsigned();
SASSERT(_len > 0);
expr_ref_vector as(m()), bs(m());
m_util.str.get_concat(a, as);
for (unsigned i = 0; i < as.size() && _len > 0; ++i) {
if (m_util.str.is_unit(as[i].get())) {
if (_pos == 0) {
bs.push_back(as[i].get());
--_len;
}
else {
--_pos;
}
}
else {
return BR_FAILED;
}
}
result = m_util.str.mk_concat(bs);
return BR_DONE;
}
return BR_FAILED;
}
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)) {
@ -594,19 +681,77 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
result = m().mk_true();
return BR_DONE;
}
bool all_units = true;
for (unsigned i = 0; i < bs.size(); ++i) {
all_units = m_util.str.is_unit(bs[i].get());
}
for (unsigned i = 0; i < as.size(); ++i) {
all_units = m_util.str.is_unit(as[i].get());
}
if (all_units) {
if (as.size() < bs.size()) {
result = m().mk_false();
return BR_DONE;
}
expr_ref_vector ors(m());
for (unsigned i = 0; i < as.size() - bs.size() + 1; ++i) {
expr_ref_vector ands(m());
for (unsigned j = 0; j < bs.size(); ++j) {
ands.push_back(m().mk_eq(as[i + j].get(), bs[j].get()));
}
ors.push_back(::mk_and(ands));
}
result = ::mk_or(ors);
return BR_REWRITE_FULL;
}
return BR_FAILED;
}
/*
* (str.at s i), constants s/i, i < 0 or i >= |s| ==> (str.at s i) = ""
*/
br_status seq_rewriter::mk_seq_at(expr* a, expr* b, expr_ref& result) {
zstring c;
rational r;
if (m_util.str.is_string(a, c) && m_autil.is_numeral(b, r) && r.is_unsigned()) {
unsigned j = r.get_unsigned();
if (j < c.length()) {
result = m_util.str.mk_string(c.extract(j, 1));
if (m_autil.is_numeral(b, r)) {
if (r.is_neg()) {
result = m_util.str.mk_empty(m().get_sort(a));
return BR_DONE;
}
unsigned len = 0;
bool bounded = min_length(1, &a, len);
if (bounded && r >= rational(len)) {
result = m_util.str.mk_empty(m().get_sort(a));
return BR_DONE;
}
if (m_util.str.is_string(a, c)) {
if (r.is_unsigned() && r < rational(c.length())) {
result = m_util.str.mk_string(c.extract(r.get_unsigned(), 1));
}
else {
result = m_util.str.mk_empty(m().get_sort(a));
}
return BR_DONE;
}
if (r.is_unsigned()) {
len = r.get_unsigned();
expr_ref_vector as(m());
m_util.str.get_concat(a, as);
for (unsigned i = 0; i < as.size(); ++i) {
if (m_util.str.is_unit(as[i].get())) {
if (len == 0) {
result = as[i].get();
return BR_DONE;
}
--len;
}
else {
return BR_FAILED;
}
}
}
}
return BR_FAILED;
}
@ -664,6 +809,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
bool isc2 = m_util.str.is_string(b, s2);
if (isc1 && isc2) {
result = m().mk_bool_val(s1.prefixof(s2));
TRACE("seq", tout << result << "\n";);
return BR_DONE;
}
if (m_util.str.is_empty(a)) {
@ -677,6 +823,7 @@ 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) {
@ -721,26 +868,27 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
m_util.str.get_concat(a, as);
m_util.str.get_concat(b, bs);
unsigned i = 0;
bool all_values = true;
expr_ref_vector eqs(m());
for (; i < as.size() && i < bs.size(); ++i) {
expr* a = as[i].get(), *b = bs[i].get();
if (a == b) {
continue;
}
all_values &= m().is_value(a) && m().is_value(b);
if (all_values) {
result = m().mk_false();
return BR_DONE;
}
if (m_util.str.is_unit(a) && m_util.str.is_unit(b)) {
eqs.push_back(m().mk_eq(a, b));
continue;
}
if (m().is_value(a) && m().is_value(b) && m_util.str.is_string(a) && m_util.str.is_string(b)) {
TRACE("seq", tout << mk_pp(a, m()) << " != " << mk_pp(b, m()) << "\n";);
result = m().mk_false();
return BR_DONE;
}
break;
}
if (i == as.size()) {
result = mk_and(eqs);
TRACE("seq", tout << result << "\n";);
if (m().is_true(result)) {
return BR_DONE;
}
@ -752,6 +900,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
eqs.push_back(m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), as[j].get()));
}
result = mk_and(eqs);
TRACE("seq", tout << result << "\n";);
return BR_REWRITE3;
}
if (i > 0) {
@ -759,6 +908,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
a = m_util.str.mk_concat(as.size() - i, as.c_ptr() + i);
b = m_util.str.mk_concat(bs.size() - i, bs.c_ptr() + i);
result = m_util.str.mk_prefix(a, b);
TRACE("seq", tout << result << "\n";);
return BR_DONE;
}
else {
@ -1280,6 +1430,40 @@ br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) {
return BR_FAILED;
}
/*
* (re.range c_1 c_n) = (re.union (str.to.re c1) (str.to.re c2) ... (str.to.re cn))
*/
br_status seq_rewriter::mk_re_range(expr* lo, expr* hi, expr_ref& result) {
return BR_FAILED;
TRACE("seq", tout << "rewrite re.range [" << mk_pp(lo, m()) << " " << mk_pp(hi, m()) << "]\n";);
zstring str_lo, str_hi;
if (m_util.str.is_string(lo, str_lo) && m_util.str.is_string(hi, str_hi)) {
if (str_lo.length() == 1 && str_hi.length() == 1) {
unsigned int c1 = str_lo[0];
unsigned int c2 = str_hi[0];
if (c1 > c2) {
// exchange c1 and c2
unsigned int tmp = c1;
c2 = c1;
c1 = tmp;
}
zstring s(c1);
expr_ref acc(m_util.re.mk_to_re(m_util.str.mk_string(s)), m());
for (unsigned int ch = c1 + 1; ch <= c2; ++ch) {
zstring s_ch(ch);
expr_ref acc2(m_util.re.mk_to_re(m_util.str.mk_string(s_ch)), m());
acc = m_util.re.mk_union(acc, acc2);
}
result = acc;
return BR_REWRITE2;
} else {
m().raise_exception("string constants in re.range must have length 1");
}
}
return BR_FAILED;
}
/*
emp+ = emp
all+ = all
@ -1309,9 +1493,9 @@ br_status seq_rewriter::mk_re_plus(expr* a, expr_ref& result) {
return BR_DONE;
}
return BR_FAILED;
// result = m_util.re.mk_concat(a, m_util.re.mk_star(a));
// return BR_REWRITE2;
//return BR_FAILED;
result = m_util.re.mk_concat(a, m_util.re.mk_star(a));
return BR_REWRITE2;
}
br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) {
@ -1343,6 +1527,7 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_
zstring s;
bool lchange = false;
SASSERT(lhs.empty());
TRACE("seq", tout << ls << "\n"; tout << rs << "\n";);
// solve from back
while (true) {
while (!rs.empty() && m_util.str.is_empty(rs.back())) {
@ -1460,9 +1645,11 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_
head2 < rs.size() &&
m_util.str.is_string(ls[head1].get(), s1) &&
m_util.str.is_string(rs[head2].get(), s2)) {
TRACE("seq", tout << s1 << " - " << s2 << " " << s1.length() << " " << s2.length() << "\n";);
unsigned l = std::min(s1.length(), s2.length());
for (unsigned i = 0; i < l; ++i) {
if (s1[i] != s2[i]) {
TRACE("seq", tout << "different at position " << i << " " << s1[i] << " " << s2[i] << "\n";);
return false;
}
}

View file

@ -98,6 +98,7 @@ class seq_rewriter {
re2automaton m_re2aut;
expr_ref_vector m_es, m_lhs, m_rhs;
br_status mk_seq_unit(expr* e, expr_ref& result);
br_status mk_seq_concat(expr* a, expr* b, expr_ref& result);
br_status mk_seq_length(expr* a, expr_ref& result);
br_status mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& result);
@ -119,6 +120,7 @@ class seq_rewriter {
br_status mk_re_plus(expr* a, expr_ref& result);
br_status mk_re_opt(expr* a, expr_ref& result);
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 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,

View file

@ -54,6 +54,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
bool m_cache_all;
bool m_push_ite_arith;
bool m_push_ite_bv;
bool m_ignore_patterns_on_ground_qbody;
// substitution support
expr_dependency_ref m_used_dependencies; // set of dependencies of used substitutions
@ -70,8 +71,9 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
m_cache_all = p.cache_all();
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();
}
void updt_params(params_ref const & p) {
m_b_rw.updt_params(p);
m_a_rw.updt_params(p);
@ -82,7 +84,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
updt_local_params(p);
}
bool flat_assoc(func_decl * f) const {
bool flat_assoc(func_decl * f) const {
if (!m_flat) return false;
family_id fid = f->get_family_id();
if (fid == null_family_id)
@ -98,10 +100,10 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
}
bool rewrite_patterns() const { return false; }
bool cache_all_results() const { return m_cache_all; }
bool max_steps_exceeded(unsigned num_steps) const {
bool max_steps_exceeded(unsigned num_steps) const {
cooperate("simplifier");
if (memory::get_allocation_size() > m_max_memory)
throw rewriter_exception(Z3_MAX_MEMORY_MSG);
@ -179,13 +181,13 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
st = m_ar_rw.mk_eq_core(args[0], args[1], result);
else if (s_fid == m_seq_rw.get_fid())
st = m_seq_rw.mk_eq_core(args[0], args[1], result);
if (st != BR_FAILED)
return st;
}
if (k == OP_EQ || k == OP_IFF) {
SASSERT(num == 2);
st = apply_tamagotchi(args[0], args[1], result);
st = apply_tamagotchi(args[0], args[1], result);
if (st != BR_FAILED)
return st;
}
@ -239,13 +241,13 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
}
else {
if (SWAP) {
result = m().mk_ite(ite->get_arg(0),
result = m().mk_ite(ite->get_arg(0),
m().mk_app(p, value, ite->get_arg(1)),
m().mk_app(p, value, ite->get_arg(2)));
return BR_REWRITE2;
}
else {
result = m().mk_ite(ite->get_arg(0),
result = m().mk_ite(ite->get_arg(0),
m().mk_app(p, ite->get_arg(1), value),
m().mk_app(p, ite->get_arg(2), value));
return BR_REWRITE2;
@ -257,7 +259,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
// ite-value-tree := (ite c <subtree> <subtree>)
// subtree := value
// | (ite c <subtree> <subtree>)
//
//
bool is_ite_value_tree(expr * t) {
if (!m().is_ite(t))
return false;
@ -281,7 +283,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
}
return true;
}
br_status pull_ite(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
if (num == 2 && m().is_bool(f->get_range()) && !m().is_bool(args[0])) {
if (m().is_ite(args[0])) {
@ -325,7 +327,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
if (!is_app(t))
return false;
family_id fid = to_app(t)->get_family_id();
return ((fid == m_a_rw.get_fid() && m_push_ite_arith) ||
return ((fid == m_a_rw.get_fid() && m_push_ite_arith) ||
(fid == m_bv_rw.get_fid() && m_push_ite_bv));
}
@ -349,7 +351,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
}
return false;
}
/**
\brief Try to "unify" t1 and t2
Examples
@ -463,7 +465,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
}
// terms matched...
bool is_int = m_a_util.is_int(t1);
if (!new_t1)
if (!new_t1)
new_t1 = m_a_util.mk_numeral(rational(0), is_int);
if (!new_t2)
new_t2 = m_a_util.mk_numeral(rational(0), is_int);
@ -476,7 +478,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
args.push_back(arg);
}
SASSERT(!args.empty());
if (args.size() == 1)
if (args.size() == 1)
c = args[0];
else
c = m_a_util.mk_add(args.size(), args.c_ptr());
@ -518,7 +520,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
// Apply transformations of the form
//
// (ite c (+ k1 a) (+ k2 a)) --> (+ (ite c k1 k2) a)
// (ite c (+ k1 a) (+ k2 a)) --> (+ (ite c k1 k2) a)
// (ite c (* k1 a) (* k2 a)) --> (* (ite c k1 k2) a)
//
// These transformations are useful for bit-vector problems, since
@ -536,7 +538,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
if (unify(t, e, f_prime, new_t, new_e, common, first)) {
if (first)
result = m().mk_app(f_prime, common, m().mk_ite(c, new_t, new_e));
else
else
result = m().mk_app(f_prime, m().mk_ite(c, new_t, new_e), common);
return BR_DONE;
}
@ -558,7 +560,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
result_pr = 0;
br_status st = reduce_app_core(f, num, args, result);
if (st != BR_DONE && st != BR_FAILED) {
CTRACE("th_rewriter_step", st != BR_FAILED,
CTRACE("th_rewriter_step", st != BR_FAILED,
tout << 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";);
@ -576,7 +578,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
else
st = pull_ite(result);
}
CTRACE("th_rewriter_step", st != BR_FAILED,
CTRACE("th_rewriter_step", st != BR_FAILED,
tout << 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";);
@ -593,28 +595,28 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
}
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
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) {
quantifier_ref q1(m());
proof * p1 = 0;
if (is_quantifier(new_body) &&
if (is_quantifier(new_body) &&
to_quantifier(new_body)->is_forall() == old_q->is_forall() &&
!old_q->has_patterns() &&
!to_quantifier(new_body)->has_patterns()) {
quantifier * nested_q = to_quantifier(new_body);
ptr_buffer<sort> sorts;
buffer<symbol> names;
buffer<symbol> names;
sorts.append(old_q->get_num_decls(), old_q->get_decl_sorts());
names.append(old_q->get_num_decls(), old_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(old_q->is_forall(),
sorts.size(),
sorts.c_ptr(),
@ -624,9 +626,9 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
old_q->get_qid(),
old_q->get_skid(),
0, 0, 0, 0);
SASSERT(is_well_sorted(m(), q1));
if (m().proofs_enabled()) {
SASSERT(old_q->get_expr() == new_body);
p1 = m().mk_pull_quant(old_q, q1);
@ -635,24 +637,24 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
else {
ptr_buffer<expr> new_patterns_buf;
ptr_buffer<expr> new_no_patterns_buf;
new_patterns_buf.append(old_q->get_num_patterns(), new_patterns);
new_no_patterns_buf.append(old_q->get_num_no_patterns(), new_no_patterns);
remove_duplicates(new_patterns_buf);
remove_duplicates(new_no_patterns_buf);
q1 = m().update_quantifier(old_q,
q1 = m().update_quantifier(old_q,
new_patterns_buf.size(), new_patterns_buf.c_ptr(), new_no_patterns_buf.size(), new_no_patterns_buf.c_ptr(),
new_body);
TRACE("reduce_quantifier", tout << mk_ismt2_pp(old_q, m()) << "\n----->\n" << mk_ismt2_pp(q1, m()) << "\n";);
SASSERT(is_well_sorted(m(), q1));
}
elim_unused_vars(m(), q1, result);
elim_unused_vars(m(), q1, params_ref(), result);
TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << mk_ismt2_pp(result, m()) << "\n";);
result_pr = 0;
if (m().proofs_enabled()) {
proof * p2 = 0;
@ -758,7 +760,7 @@ unsigned th_rewriter::get_num_steps() const {
void th_rewriter::cleanup() {
ast_manager & m = m_imp->m();
dealloc(m_imp);
m_imp = alloc(imp, m, m_params);
m_imp = alloc(imp, m, m_params);
}
void th_rewriter::reset() {

View file

@ -39,10 +39,16 @@ void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, exp
tout << mk_ismt2_pp(result, m_reducer.m()) << "\n";);
}
unused_vars_eliminator::unused_vars_eliminator(ast_manager & m, params_ref const & params) :
m(m), m_subst(m), m_params(params)
{
m_ignore_patterns_on_ground_qbody = m_params.get_bool("ignore_patterns_on_ground_qbody", true);
}
void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
SASSERT(is_well_sorted(m, q));
if (is_ground(q->get_expr())) {
// ignore patterns if the body is a ground formula.
if (m_ignore_patterns_on_ground_qbody && is_ground(q->get_expr())) {
// Ignore patterns if the body is a ground formula.
result = q->get_expr();
return;
}
@ -146,8 +152,8 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
SASSERT(is_well_sorted(m, result));
}
void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
unused_vars_eliminator el(m);
void elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params, expr_ref & result) {
unused_vars_eliminator el(m, params);
el(q, result);
}

View file

@ -21,6 +21,7 @@ Notes:
#include"rewriter.h"
#include"used_vars.h"
#include"params.h"
/**
\brief Alias for var_shifter class.
@ -31,7 +32,7 @@ typedef var_shifter shift_vars;
\brief Variable substitution functor. It substitutes variables by expressions.
The expressions may contain variables.
*/
class var_subst {
class var_subst {
beta_reducer m_reducer;
bool m_std_order;
public:
@ -39,7 +40,7 @@ public:
bool std_order() const { return m_std_order; }
/**
When std_order() == true,
When std_order() == true,
I'm using the same standard used in quantifier instantiation.
(VAR 0) is stored in the last position of the array.
...
@ -55,15 +56,17 @@ public:
\brief Eliminate the unused variables from \c q. Store the result in \c r.
*/
class unused_vars_eliminator {
ast_manager& m;
var_subst m_subst;
used_vars m_used;
ast_manager & m;
var_subst m_subst;
used_vars m_used;
params_ref m_params;
bool m_ignore_patterns_on_ground_qbody;
public:
unused_vars_eliminator(ast_manager& m): m(m), m_subst(m) {}
unused_vars_eliminator(ast_manager & m, params_ref const & params);
void operator()(quantifier* q, expr_ref& r);
};
void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & r);
void elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params, expr_ref & r);
/**
\brief Instantiate quantifier q using the given exprs.
@ -86,7 +89,7 @@ class expr_free_vars {
expr_sparse_mark m_mark;
ptr_vector<sort> m_sorts;
ptr_vector<expr> m_todo;
public:
public:
void reset();
void operator()(expr* e);
void accumulate(expr* e);
@ -96,7 +99,7 @@ public:
bool contains(unsigned idx) const { return idx < m_sorts.size() && m_sorts[idx] != 0; }
void set_default_sort(sort* s);
void reverse() { m_sorts.reverse(); }
sort*const* c_ptr() const { return m_sorts.c_ptr(); }
sort*const* c_ptr() const { return m_sorts.c_ptr(); }
};
#endif

View file

@ -126,13 +126,14 @@ static bool is_escape_char(char const *& s, unsigned& result) {
zstring::zstring(encoding enc): m_encoding(enc) {}
zstring::zstring(char const* s, encoding enc): m_encoding(enc) {
unsigned mask = 0xFF; // TBD for UTF
while (*s) {
unsigned ch;
if (is_escape_char(s, ch)) {
m_buffer.push_back(ch);
m_buffer.push_back(ch & mask);
}
else {
m_buffer.push_back(*s);
m_buffer.push_back(*s & mask);
++s;
}
}
@ -830,7 +831,9 @@ void seq_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol
init();
sort_names.push_back(builtin_name("Seq", SEQ_SORT));
sort_names.push_back(builtin_name("RegEx", RE_SORT));
// SMT-LIB 2.5 compatibility
sort_names.push_back(builtin_name("String", _STRING_SORT));
sort_names.push_back(builtin_name("StringSequence", _STRING_SORT));
}
app* seq_decl_plugin::mk_string(symbol const& s) {

View file

@ -273,6 +273,15 @@ public:
bool is_in_re(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_IN_RE); }
bool is_unit(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_UNIT); }
bool is_string_term(expr const * n) const {
sort * s = get_sort(n);
return u.is_string(s);
}
bool is_non_string_sequence(expr const * n) const {
sort * s = get_sort(n);
return (u.is_seq(s) && !u.is_string(s));
}
MATCH_BINARY(is_concat);
MATCH_UNARY(is_length);
@ -304,6 +313,7 @@ public:
app* mk_to_re(expr* s) { return m.mk_app(m_fid, OP_SEQ_TO_RE, 1, &s); }
app* mk_in_re(expr* s, expr* r) { return m.mk_app(m_fid, OP_SEQ_IN_RE, s, r); }
app* mk_range(expr* s1, expr* s2) { return m.mk_app(m_fid, OP_RE_RANGE, s1, s2); }
app* mk_concat(expr* r1, expr* r2) { return m.mk_app(m_fid, OP_RE_CONCAT, r1, r2); }
app* mk_union(expr* r1, expr* r2) { return m.mk_app(m_fid, OP_RE_UNION, r1, r2); }
app* mk_inter(expr* r1, expr* r2) { return m.mk_app(m_fid, OP_RE_INTERSECT, r1, r2); }

View file

@ -1517,13 +1517,24 @@ void bv_simplifier_plugin::mk_bv2int(expr * arg, sort* range, expr_ref & result)
result = m_arith.mk_add(tmp1, tmp2);
}
// commented out to reproduce bug in reduction of int2bv/bv2int
else if (m_util.is_concat(arg)) {
expr_ref tmp1(m_manager), tmp2(m_manager);
unsigned sz2 = get_bv_size(to_app(arg)->get_arg(1));
mk_bv2int(to_app(arg)->get_arg(0), range, tmp1);
mk_bv2int(to_app(arg)->get_arg(1), range, tmp2);
tmp1 = m_arith.mk_mul(m_arith.mk_numeral(power(numeral(2), sz2), true), tmp1);
result = m_arith.mk_add(tmp1, tmp2);
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);

View file

@ -14,7 +14,7 @@ Author:
Leonardo de Moura (leonardo) 2010-04-02.
Revision History:
Christoph Wintersteiger 2010-04-06: Added implementation.
--*/
@ -40,7 +40,7 @@ bool distribute_forall::visit_children(expr * n) {
bool visited = true;
unsigned j;
switch(n->get_kind()) {
case AST_VAR:
case AST_VAR:
break;
case AST_APP:
j = to_app(n)->get_num_args();
@ -86,15 +86,15 @@ void distribute_forall::reduce1_app(app * a) {
SASSERT(is_cached(a->get_arg(j)));
expr * c = get_cached(a->get_arg(j));
SASSERT(c!=0);
if (c != a->get_arg(j))
if (c != a->get_arg(j))
reduced = true;
m_new_args[j] = c;
}
}
if (reduced) {
na = m_manager.mk_app(a->get_decl(), num_args, m_new_args.c_ptr());
}
cache_result(a, na);
}
@ -126,11 +126,11 @@ void distribute_forall::reduce1_quantifier(quantifier * q) {
quantifier_ref tmp_q(m_manager);
tmp_q = m_manager.update_quantifier(q, not_arg);
expr_ref new_q(m_manager);
elim_unused_vars(m_manager, tmp_q, new_q);
elim_unused_vars(m_manager, tmp_q, params_ref(), new_q);
new_args.push_back(new_q);
}
expr_ref result(m_manager);
// m_bsimp.mk_and actually constructs a (not (or ...)) formula,
// m_bsimp.mk_and actually constructs a (not (or ...)) formula,
// it will also apply basic simplifications.
m_bsimp.mk_and(new_args.size(), new_args.c_ptr(), result);
cache_result(q, result);
@ -148,15 +148,15 @@ void distribute_forall::operator()(expr * f, expr_ref & result) {
while (!m_todo.empty()) {
expr * e = m_todo.back();
if (visit_children(e)) {
if (visit_children(e)) {
m_todo.pop_back();
reduce1(e);
}
}
}
result = get_cached(f);
SASSERT(result!=0);
TRACE("distribute_forall", tout << mk_ll_pp(f, m_manager) << "======>\n"
TRACE("distribute_forall", tout << mk_ll_pp(f, m_manager) << "======>\n"
<< mk_ll_pp(result, m_manager););
}
@ -166,5 +166,5 @@ expr * distribute_forall::get_cached(expr * n) const {
void distribute_forall::cache_result(expr * n, expr * r) {
SASSERT(r != 0);
m_cache.insert(n, r);
m_cache.insert(n, r);
}

View file

@ -32,7 +32,7 @@ elim_bounds::elim_bounds(ast_manager & m):
(<= x k)
(<= (+ x (* -1 y)) k)
(<= (+ x (* -1 t)) 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
@ -65,14 +65,14 @@ bool elim_bounds::is_bound(expr * n, var * & lower, var * & upper) {
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))
if (is_var(arg1))
upper = to_var(arg1);
else if (!is_ground(arg1))
return false;
@ -95,7 +95,7 @@ bool elim_bounds::is_bound(expr * n, var * & lower, var * & upper) {
if (!le)
std::swap(upper, lower);
return true;
}
@ -188,7 +188,7 @@ void elim_bounds::operator()(quantifier * q, expr_ref & r) {
}
quantifier_ref new_q(m_manager);
new_q = m_manager.update_quantifier(q, new_body);
elim_unused_vars(m_manager, new_q, r);
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";);
}
@ -199,10 +199,10 @@ bool elim_bounds_star::visit_quantifier(quantifier * q) {
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);
cache_result(q, q, 0);
return;
}
quantifier_ref new_q(m);

View file

@ -37,7 +37,7 @@ protected:
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_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<expr> & result);

View file

@ -33,8 +33,8 @@ simplifier::simplifier(ast_manager & m):
m_ac_support(true) {
}
void simplifier::register_plugin(plugin * p) {
m_plugins.register_plugin(p);
void simplifier::register_plugin(plugin * p) {
m_plugins.register_plugin(p);
}
simplifier::~simplifier() {
@ -46,13 +46,13 @@ void simplifier::enable_ac_support(bool flag) {
ptr_vector<plugin>::const_iterator it = m_plugins.begin();
ptr_vector<plugin>::const_iterator end = m_plugins.end();
for (; it != end; ++it) {
if (*it != 0)
if (*it != 0)
(*it)->enable_ac_support(flag);
}
}
/**
\brief External interface for the simplifier.
\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)
@ -69,14 +69,14 @@ void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) {
proof * result_proof;
switch (m.proof_mode()) {
case PGM_DISABLED: // proof generation is disabled.
reduce_core(s);
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.
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;
@ -163,7 +163,7 @@ bool simplifier::visit_children(expr * n) {
// 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:
// 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.
@ -178,7 +178,7 @@ bool simplifier::visit_children(expr * n) {
}
return visited;
}
case AST_QUANTIFIER:
case AST_QUANTIFIER:
return visit_quantifier(to_quantifier(n));
default:
UNREACHABLE();
@ -188,7 +188,7 @@ bool simplifier::visit_children(expr * n) {
/**
\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.
@ -216,7 +216,7 @@ bool simplifier::visit_ac(app * n) {
expr * arg = n->get_arg(i);
if (is_app_of(arg, decl))
todo.push_back(to_app(arg));
else
else
visit(arg, visited);
}
}
@ -319,7 +319,7 @@ void simplifier::reduce1_app_core(app * n) {
proof * p;
if (n == r)
p = 0;
else if (r != s)
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));
@ -368,7 +368,7 @@ void simplifier::reduce1_ac_app_core(app * n) {
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);
expr_ref r(m);
func_decl * decl = n->get_decl();
family_id fid = decl->get_family_id();
plugin * p = get_plugin(fid);
@ -415,7 +415,7 @@ void simplifier::reduce1_ac_app_core(app * n) {
proof * p;
if (n == r.get())
p = 0;
else if (r.get() != n_c.get())
else if (r.get() != n_c.get())
p = m.mk_transitivity(p1, m.mk_rewrite(n_c, r));
else
p = p1;
@ -434,7 +434,7 @@ void simplifier::dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr *
sprintf_s(buffer, ARRAYSIZE(buffer), "lemma_%d.smt", g_rewrite_lemma_id);
#else
sprintf(buffer, "rewrite_lemma_%d.smt", g_rewrite_lemma_id);
#endif
#endif
ast_smt_pp pp(m);
pp.set_benchmark_name("rewrite_lemma");
pp.set_status("unsat");
@ -450,7 +450,7 @@ void simplifier::dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr *
/**
\brief Return in \c result an expression \c e equivalent to <tt>(f args[0] ... args[num_args - 1])</tt>, and
store in \c pr a proof for <tt>(= (f args[0] ... args[num_args - 1]) e)</tt>
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) {
@ -474,7 +474,7 @@ void simplifier::mk_app(func_decl * decl, unsigned num_args, expr * const * args
//dump_rewrite_lemma(decl, num_args, args, result.get());
return;
}
result = m.mk_app(decl, num_args, args);
}
@ -494,17 +494,17 @@ void simplifier::mk_congruent_term(app * n, app_ref & r, proof_ref & p) {
proof * arg_proof;
get_cached(arg, new_arg, arg_proof);
CTRACE("simplifier_bug", (arg != new_arg) != (arg_proof != 0),
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);
}
@ -526,10 +526,10 @@ void simplifier::mk_congruent_term(app * n, app_ref & r, proof_ref & p) {
/**
\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.
Return true there are new arguments.
*/
bool simplifier::get_args(app * n, ptr_vector<expr> & result, proof_ref & p) {
bool has_new_args = false;
@ -565,10 +565,10 @@ bool simplifier::get_args(app * n, ptr_vector<expr> & result, proof_ref & p) {
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<app> todo;
ptr_buffer<expr> new_args;
ptr_buffer<proof> new_arg_prs;
@ -621,7 +621,7 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) {
todo.pop_back();
if (!has_new_arg) {
m_ac_cache.insert(curr, curr);
if (m.fine_grain_proofs())
if (m.fine_grain_proofs())
m_ac_pr_cache.insert(curr, 0);
}
else {
@ -634,7 +634,7 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) {
}
}
}
SASSERT(m_ac_cache.contains(n));
app * new_n = 0;
m_ac_cache.find(n, new_n);
@ -646,7 +646,7 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) {
}
}
#define White 0
#define White 0
#define Grey 1
#define Black 2
@ -688,7 +688,7 @@ void simplifier::ac_top_sort(app * n, ptr_buffer<expr> & result) {
while (!todo.empty()) {
expr * curr = todo.back();
int color;
obj_map<expr, int>::obj_map_entry * entry = colors.insert_if_not_there2(curr, White);
obj_map<expr, int>::obj_map_entry * entry = colors.insert_if_not_there2(curr, White);
SASSERT(entry);
color = entry->get_data().m_value;
switch (color) {
@ -731,7 +731,7 @@ void simplifier::get_ac_args(app * n, ptr_vector<expr> & args, vector<rational>
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() << " ";
@ -747,7 +747,7 @@ void simplifier::get_ac_args(app * n, ptr_vector<expr> & args, vector<rational>
expr * curr = sorted_exprs[j];
rational mult;
m_ac_mults.find(curr, mult);
SASSERT(!mult.is_zero());
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++) {
@ -772,16 +772,16 @@ void simplifier::reduce1_quantifier(quantifier * q) {
quantifier_ref q1(m);
proof * p1 = 0;
if (is_quantifier(new_body) &&
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<sort> sorts;
buffer<symbol> names;
buffer<symbol> 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());
@ -797,7 +797,7 @@ void simplifier::reduce1_quantifier(quantifier * q) {
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);
@ -817,13 +817,13 @@ void simplifier::reduce1_quantifier(quantifier * q) {
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);
@ -833,7 +833,7 @@ void simplifier::reduce1_quantifier(quantifier * q) {
q->get_decl_sorts(),
q->get_decl_names(),
new_body,
q->get_weight(),
q->get_weight(),
q->get_qid(),
q->get_skid(),
new_patterns.size(),
@ -850,10 +850,10 @@ void simplifier::reduce1_quantifier(quantifier * q) {
p1 = q == q1 ? 0 : m.mk_quant_intro(q, q1, new_body_pr);
}
}
expr_ref r(m);
elim_unused_vars(m, q1, r);
elim_unused_vars(m, q1, params_ref(), r);
proof * pr = 0;
if (m.fine_grain_proofs()) {
proof * p2 = 0;
@ -871,7 +871,7 @@ void simplifier::reduce1_quantifier(quantifier * q) {
void simplifier::borrow_plugins(simplifier const & s) {
ptr_vector<plugin>::const_iterator it = s.begin_plugins();
ptr_vector<plugin>::const_iterator end = s.end_plugins();
for (; it != end; ++it)
for (; it != end; ++it)
register_plugin(*it);
}
@ -882,7 +882,7 @@ void simplifier::enable_presimp() {
enable_ac_support(false);
ptr_vector<plugin>::const_iterator it = begin_plugins();
ptr_vector<plugin>::const_iterator end = end_plugins();
for (; it != end; ++it)
for (; it != end; ++it)
(*it)->enable_presimp(true);
}
@ -905,7 +905,7 @@ bool subst_simplifier::get_subst(expr * n, expr_ref & r, proof_ref & p) {
m_subst_map->get(n, _r, _p);
r = _r;
p = _p;
if (m.coarse_grain_proofs())
if (m.coarse_grain_proofs())
m_subst_proofs.push_back(p);
return true;
}
@ -917,7 +917,7 @@ static void push_core(ast_manager & m, expr * e, proof * pr, expr_ref_vector & r
TRACE("preprocessor",
tout << mk_pp(e, m) << "\n";
if (pr) tout << mk_ll_pp(pr, m) << "\n\n";);
if (m.is_true(e))
if (m.is_true(e))
return;
result.push_back(e);
if (m.proofs_enabled())
@ -952,9 +952,9 @@ void push_assertion(ast_manager & m, expr * e, proof * pr, expr_ref_vector & res
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))
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)))
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);

View file

@ -25,6 +25,7 @@ static_features::static_features(ast_manager & m):
m_bvutil(m),
m_arrayutil(m),
m_fpautil(m),
m_sequtil(m),
m_bfid(m.get_basic_family_id()),
m_afid(m.mk_family_id("arith")),
m_lfid(m.mk_family_id("label")),
@ -77,6 +78,8 @@ void static_features::reset() {
m_has_real = false;
m_has_bv = false;
m_has_fpa = false;
m_has_str = false;
m_has_seq_non_str = false;
m_has_arrays = false;
m_arith_k_sum .reset();
m_num_arith_terms = 0;
@ -279,6 +282,11 @@ void static_features::update_core(expr * e) {
m_has_fpa = true;
if (!m_has_arrays && m_arrayutil.is_array(e))
m_has_arrays = true;
if (!m_has_str && m_sequtil.str.is_string_term(e))
m_has_str = true;
if (!m_has_seq_non_str && m_sequtil.str.is_non_string_sequence(e)) {
m_has_seq_non_str = true;
}
if (is_app(e)) {
family_id fid = to_app(e)->get_family_id();
mark_theory(fid);

View file

@ -24,6 +24,7 @@ Revision History:
#include"bv_decl_plugin.h"
#include"array_decl_plugin.h"
#include"fpa_decl_plugin.h"
#include"seq_decl_plugin.h"
#include"map.h"
struct static_features {
@ -32,6 +33,7 @@ struct static_features {
bv_util m_bvutil;
array_util m_arrayutil;
fpa_util m_fpautil;
seq_util m_sequtil;
family_id m_bfid;
family_id m_afid;
family_id m_lfid;
@ -77,6 +79,8 @@ struct static_features {
bool m_has_real; //
bool m_has_bv; //
bool m_has_fpa; //
bool m_has_str; // has String-typed terms
bool m_has_seq_non_str; // has non-String-typed Sequence terms
bool m_has_arrays; //
rational m_arith_k_sum; // sum of the numerals in arith atoms.
unsigned m_num_arith_terms;

View file

@ -100,13 +100,34 @@ public:
ATOMIC_CMD(exit_cmd, "exit", "exit.", ctx.print_success(); throw stop_parser_exception(););
ATOMIC_CMD(get_model_cmd, "get-model", "retrieve model for the last check-sat command", {
if (!ctx.is_model_available() || ctx.get_check_sat_result() == 0)
throw cmd_exception("model is not available");
model_ref m;
ctx.get_check_sat_result()->get_model(m);
ctx.display_model(m);
});
class get_model_cmd : public cmd {
unsigned m_index;
public:
get_model_cmd(): cmd("get-model"), m_index(0) {}
virtual char const * get_usage() const { return "[<index of box objective>]"; }
virtual char const * get_descr(cmd_context & ctx) const {
return "retrieve model for the last check-sat command.\nSupply optional index if retrieving a model corresponding to a box optimization objective";
}
virtual unsigned get_arity() const { return VAR_ARITY; }
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_UINT; }
virtual void set_next_arg(cmd_context & ctx, unsigned index) { m_index = index; }
virtual void execute(cmd_context & ctx) {
if (!ctx.is_model_available() || ctx.get_check_sat_result() == 0)
throw cmd_exception("model is not available");
model_ref m;
if (m_index > 0 && ctx.get_opt()) {
ctx.get_opt()->get_box_model(m, m_index);
}
else {
ctx.get_check_sat_result()->get_model(m);
}
ctx.display_model(m);
}
virtual void reset(cmd_context& ctx) {
m_index = 0;
}
};
ATOMIC_CMD(get_assignment_cmd, "get-assignment", "retrieve assignment", {
if (!ctx.is_model_available() || ctx.get_check_sat_result() == 0)

View file

@ -187,6 +187,7 @@ struct check_logic::imp {
m_bvs = true;
m_uf = true;
m_ints = true;
m_nonlinear = true; // non-linear 0-1 variables may get eliminated
}
else {
m_unknown_logic = true;

View file

@ -249,6 +249,7 @@ protected:
array_util m_arutil;
fpa_util m_futil;
seq_util m_sutil;
datalog::dl_decl_util m_dlutil;
format_ns::format * pp_fdecl_name(symbol const & s, func_decls const & fs, func_decl * f, unsigned & len) {
@ -277,6 +278,7 @@ public:
virtual array_util & get_arutil() { return m_arutil; }
virtual fpa_util & get_futil() { return m_futil; }
virtual seq_util & get_sutil() { return m_sutil; }
virtual datalog::dl_decl_util& get_dlutil() { return m_dlutil; }
virtual bool uses(symbol const & s) const {
return
@ -527,6 +529,9 @@ bool cmd_context::logic_has_fpa() const {
return !has_logic() || smt_logics::logic_has_fpa(m_logic);
}
bool cmd_context::logic_has_str() const {
return !has_logic() || m_logic == "QF_S";
}
bool cmd_context::logic_has_array() const {
return !has_logic() || smt_logics::logic_has_array(m_logic);
@ -568,7 +573,6 @@ 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<family_id>::iterator it = fids.begin();
svector<family_id>::iterator end = fids.end();
for (; it != end; ++it) {
@ -616,7 +620,6 @@ void cmd_context::init_external_manager() {
init_manager_core(false);
}
bool cmd_context::set_logic(symbol const & s) {
if (has_logic())
throw cmd_exception("the logic has already been set");
@ -739,8 +742,11 @@ 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()) {
expr* pat = m().mk_pattern(lhs);
eq = m().mk_forall(ids.size(), f->get_domain(), ids.c_ptr(), eq, 0, m().rec_fun_qid(), symbol::null, 1, &pat);
if (!is_app(e)) {
throw cmd_exception("Z3 only supports recursive definitions that are proper terms (not binders or variables)");
}
expr* pats[2] = { m().mk_pattern(lhs), m().mk_pattern(to_app(e)) };
eq = m().mk_forall(ids.size(), f->get_domain(), ids.c_ptr(), eq, 0, m().rec_fun_qid(), symbol::null, 2, pats);
}
//
@ -1551,6 +1557,7 @@ void cmd_context::validate_model() {
p.set_uint("sort_store", true);
p.set_bool("completion", true);
model_evaluator evaluator(*(md.get()), p);
evaluator.set_expand_array_equalities(false);
contains_array_op_proc contains_array(m());
{
scoped_rlimit _rlimit(m().limit(), 0);

View file

@ -124,6 +124,7 @@ public:
virtual bool is_pareto() = 0;
virtual void set_logic(symbol const& s) = 0;
virtual bool print_model() const = 0;
virtual void get_box_model(model_ref& mdl, unsigned index) = 0;
virtual void updt_params(params_ref const& p) = 0;
};
@ -256,6 +257,7 @@ protected:
bool logic_has_array() const;
bool logic_has_datatype() const;
bool logic_has_fpa() const;
bool logic_has_str() const;
void print_unsupported_msg() { regular_stream() << "unsupported" << std::endl; }
void print_unsupported_info(symbol const& s, int line, int pos) { if (s != symbol::null) diagnostic_stream() << "; " << s << " line: " << line << " position: " << pos << std::endl;}

View file

@ -38,6 +38,7 @@ public:
virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) {
model_evaluator::get_param_descrs(p);
insert_timeout(p);
p.insert("model_index", CPK_UINT, "(default: 0) index of model from box optimization objective");
}
virtual void prepare(cmd_context & ctx) {
@ -58,9 +59,15 @@ public:
if (!ctx.is_model_available())
throw cmd_exception("model is not available");
model_ref md;
unsigned index = m_params.get_uint("model_index", 0);
check_sat_result * last_result = ctx.get_check_sat_result();
SASSERT(last_result);
last_result->get_model(md);
if (index == 0 || !ctx.get_opt()) {
last_result->get_model(md);
}
else {
ctx.get_opt()->get_box_model(md, index);
}
expr_ref r(ctx.m());
unsigned timeout = m_params.get_uint("timeout", UINT_MAX);
unsigned rlimit = m_params.get_uint("rlimit", 0);

View file

@ -29,11 +29,12 @@ Notes:
#include"bound_manager.h"
#include"used_vars.h"
#include"var_subst.h"
#include"gparams.h"
#ifndef _EXTERNAL_RELEASE
BINARY_SYM_CMD(get_quantifier_body_cmd,
"dbg-get-qbody",
BINARY_SYM_CMD(get_quantifier_body_cmd,
"dbg-get-qbody",
"<symbol> <quantifier>",
"store the body of the quantifier in the global variable <symbol>",
CPK_EXPR,
@ -43,8 +44,8 @@ BINARY_SYM_CMD(get_quantifier_body_cmd,
store_expr_ref(ctx, m_sym, to_quantifier(arg)->get_expr());
});
BINARY_SYM_CMD(set_cmd,
"dbg-set",
BINARY_SYM_CMD(set_cmd,
"dbg-set",
"<symbol> <term>",
"store <term> in the global variable <symbol>",
CPK_EXPR,
@ -57,7 +58,7 @@ UNARY_CMD(pp_var_cmd, "dbg-pp-var", "<symbol>", "pretty print a global variable
expr * t = get_expr_ref(ctx, arg);
SASSERT(t != 0);
ctx.display(ctx.regular_stream(), t);
ctx.regular_stream() << std::endl;
ctx.regular_stream() << std::endl;
});
BINARY_SYM_CMD(shift_vars_cmd,
@ -71,7 +72,7 @@ BINARY_SYM_CMD(shift_vars_cmd,
var_shifter s(ctx.m());
s(t, arg, r);
store_expr_ref(ctx, m_sym, r.get());
});
});
UNARY_CMD(pp_shared_cmd, "dbg-pp-shared", "<term>", "display shared subterms of the given term", CPK_EXPR, expr *, {
shared_occs s(ctx.m());
@ -81,7 +82,7 @@ UNARY_CMD(pp_shared_cmd, "dbg-pp-shared", "<term>", "display shared subterms of
shared_occs::iterator end = s.end_shared();
for (; it != end; ++it) {
expr * curr = *it;
ctx.regular_stream() << std::endl << " ";
ctx.regular_stream() << std::endl << " ";
ctx.display(ctx.regular_stream(), curr, 2);
}
ctx.regular_stream() << ")" << std::endl;
@ -112,7 +113,7 @@ public:
if (m_idx == 1) return CPK_SYMBOL_LIST;
return CPK_SYMBOL;
}
virtual void set_next_arg(cmd_context & ctx, symbol const & s) {
virtual void set_next_arg(cmd_context & ctx, symbol const & s) {
if (m_idx == 0) {
m_source = get_expr_ref(ctx, s);
}
@ -146,24 +147,24 @@ UNARY_CMD(bool_rewriter_cmd, "dbg-bool-rewriter", "<term>", "apply the Boolean r
bool_rewriter_star r(ctx.m(), p);
r(arg, t);
ctx.display(ctx.regular_stream(), t);
ctx.regular_stream() << std::endl;
ctx.regular_stream() << std::endl;
});
UNARY_CMD(bool_frewriter_cmd, "dbg-bool-flat-rewriter", "<term>", "apply the Boolean (flattening) rewriter to the given term", CPK_EXPR, expr *, {
expr_ref t(ctx.m());
{
{
params_ref p;
p.set_bool("flat", true);
bool_rewriter_star r(ctx.m(), p);
r(arg, t);
}
ctx.display(ctx.regular_stream(), t);
ctx.regular_stream() << std::endl;
ctx.regular_stream() << std::endl;
});
UNARY_CMD(elim_and_cmd, "dbg-elim-and", "<term>", "apply the Boolean rewriter (eliminating AND operator and flattening) to the given term", CPK_EXPR, expr *, {
expr_ref t(ctx.m());
{
{
params_ref p;
p.set_bool("flat", true);
p.set_bool("elim_and", true);
@ -171,7 +172,7 @@ UNARY_CMD(elim_and_cmd, "dbg-elim-and", "<term>", "apply the Boolean rewriter (e
r(arg, t);
}
ctx.display(ctx.regular_stream(), t);
ctx.regular_stream() << std::endl;
ctx.regular_stream() << std::endl;
});
class lt_cmd : public cmd {
@ -192,7 +193,7 @@ public:
}
virtual void execute(cmd_context & ctx) {
bool r = lt(m_t1, m_t2);
ctx.regular_stream() << (r ? "true" : "false") << std::endl;
ctx.regular_stream() << (r ? "true" : "false") << std::endl;
}
};
@ -249,7 +250,7 @@ UNARY_CMD(set_next_id, "dbg-set-next-id", "<unsigned>", "set the next expression
UNARY_CMD(used_vars_cmd, "dbg-used-vars", "<expr>", "test used_vars functor", CPK_EXPR, expr *, {
used_vars proc;
if (is_quantifier(arg))
if (is_quantifier(arg))
arg = to_quantifier(arg)->get_expr();
proc(arg);
ctx.regular_stream() << "(vars";
@ -258,7 +259,7 @@ UNARY_CMD(used_vars_cmd, "dbg-used-vars", "<expr>", "test used_vars functor", CP
ctx.regular_stream() << "\n (" << std::left << std::setw(6) << i << " ";
if (s != 0)
ctx.display(ctx.regular_stream(), s, 10);
else
else
ctx.regular_stream() << "<not-used>";
ctx.regular_stream() << ")";
}
@ -271,7 +272,7 @@ UNARY_CMD(elim_unused_vars_cmd, "dbg-elim-unused-vars", "<expr>", "eliminate unu
return;
}
expr_ref r(ctx.m());
elim_unused_vars(ctx.m(), to_quantifier(arg), r);
elim_unused_vars(ctx.m(), to_quantifier(arg), gparams::get(), r);
SASSERT(!is_quantifier(r) || !to_quantifier(r)->may_have_unused_vars());
ctx.display(ctx.regular_stream(), r);
ctx.regular_stream() << std::endl;
@ -287,18 +288,18 @@ public:
virtual char const * get_descr() 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(); }
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const {
if (m_q == 0) return CPK_EXPR;
else return CPK_EXPR_LIST;
}
virtual void set_next_arg(cmd_context & ctx, expr * s) {
if (!is_quantifier(s))
throw cmd_exception("invalid command, quantifier expected.");
m_q = to_quantifier(s);
}
virtual void set_next_arg(cmd_context & ctx, unsigned num, expr * const * ts) {
if (num != m_q->get_num_decls())
throw cmd_exception("invalid command, mismatch between the number of quantified variables and the number of arguments.");
@ -331,7 +332,7 @@ public:
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 void set_next_arg(cmd_context & ctx, expr * s) {

View file

@ -41,8 +41,8 @@ namespace Duality {
params_ref p;
p.set_bool("proof", true); // this is currently useless
if(models)
p.set_bool("model", true);
p.set_bool("unsat_core", true);
p.set_bool("model", true);
p.set_bool("unsat_core", true);
bool mbqi = c.get_config().get().get_bool("mbqi",true);
p.set_bool("mbqi",mbqi); // just to test
p.set_str("mbqi.id","itp"); // use mbqi for quantifiers in interpolants
@ -57,7 +57,7 @@ namespace Duality {
m_mode = m().proof_mode();
}
expr context::constant(const std::string &name, const sort &ty){
expr context::constant(const std::string &name, const sort &ty){
symbol s = str_symbol(name.c_str());
return cook(m().mk_const(m().mk_const_decl(s, ty)));
}
@ -111,7 +111,7 @@ namespace Duality {
}
expr context::mki(family_id fid, ::decl_kind dk, int n, ::expr **args){
return cook(m().mk_app(fid, dk, 0, 0, n, (::expr **)args));
return cook(m().mk_app(fid, dk, 0, 0, n, (::expr **)args));
}
expr context::make(decl_kind op, const std::vector<expr> &args){
@ -168,9 +168,9 @@ namespace Duality {
expr_abstract(m(), 0, num_bound, VEC2PTR(bound_asts), to_expr(body.raw()), abs_body);
expr_ref result(m());
result = m().mk_quantifier(
op == Forall,
names.size(), VEC2PTR(types), VEC2PTR(names), abs_body.get(),
0,
op == Forall,
names.size(), VEC2PTR(types), VEC2PTR(names), abs_body.get(),
0,
::symbol(),
::symbol(),
0, 0,
@ -194,9 +194,9 @@ namespace Duality {
}
expr_ref result(m());
result = m().mk_quantifier(
op == Forall,
names.size(), VEC2PTR(types), VEC2PTR(names), to_expr(body.raw()),
0,
op == Forall,
names.size(), VEC2PTR(types), VEC2PTR(names), to_expr(body.raw()),
0,
::symbol(),
::symbol(),
0, 0,
@ -273,7 +273,7 @@ namespace Duality {
return OtherArray;
}
}
return Other;
}
@ -340,7 +340,7 @@ namespace Duality {
params p;
return simplify(p);
}
expr context::make_var(int idx, const sort &s){
::sort * a = to_sort(s.raw());
return cook(m().mk_var(idx,a));
@ -348,7 +348,7 @@ namespace Duality {
expr expr::qe_lite() const {
::qe_lite qe(m());
::qe_lite qe(m(), params_ref());
expr_ref result(to_expr(raw()),m());
proof_ref pf(m());
qe(result,pf);
@ -356,7 +356,7 @@ namespace Duality {
}
expr expr::qe_lite(const std::set<int> &idxs, bool index_of_bound) const {
::qe_lite qe(m());
::qe_lite qe(m(), params_ref());
expr_ref result(to_expr(raw()),m());
proof_ref pf(m());
uint_set uis;
@ -412,16 +412,16 @@ namespace Duality {
std::vector < ::sort * > _domain(domain.size());
for(unsigned i = 0; i < domain.size(); i++)
_domain[i] = to_sort(domain[i].raw());
::func_decl* d = m().mk_fresh_func_decl(prefix,
_domain.size(),
::func_decl* d = m().mk_fresh_func_decl(prefix,
_domain.size(),
VEC2PTR(_domain),
to_sort(range.raw()));
return func_decl(*this,d);
}
func_decl context::fresh_func_decl(char const * prefix, sort const & range){
::func_decl* d = m().mk_fresh_func_decl(prefix,
0,
::func_decl* d = m().mk_fresh_func_decl(prefix,
0,
0,
to_sort(range.raw()));
return func_decl(*this,d);
@ -462,30 +462,30 @@ namespace Duality {
incremental,
_theory.size(),
VEC2PTR(_theory));
if(lb == Z3_L_FALSE){
interpolants.resize(_interpolants.size());
for (unsigned i = 0; i < _interpolants.size(); ++i) {
interpolants[i] = expr(ctx(),_interpolants[i]);
}
}
}
if (_model) {
model = iz3wrapper::model(ctx(), _model);
}
if(_labels){
labels = _labels;
}
return lb;
}
#endif
static int linearize_assumptions(int num,
TermTree *assumptions,
std::vector<std::vector <expr> > &linear_assumptions,
std::vector<std::vector <expr> > &linear_assumptions,
std::vector<int> &parents){
for(unsigned i = 0; i < assumptions->getChildren().size(); i++)
num = linearize_assumptions(num, assumptions->getChildren()[i], linear_assumptions, parents);
@ -501,7 +501,7 @@ namespace Duality {
}
static int unlinearize_interpolants(int num,
TermTree* assumptions,
TermTree* assumptions,
const std::vector<expr> &interpolant,
TermTree * &tree_interpolant)
{
@ -522,7 +522,7 @@ namespace Duality {
literals &labels,
bool incremental
)
{
int size = assumptions->number(0);
std::vector<std::vector<expr> > linear_assumptions(size);
@ -540,36 +540,36 @@ namespace Duality {
ptr_vector< ::ast> _theory(theory.size());
for(unsigned i = 0; i < theory.size(); i++)
_theory[i] = theory[i];
if(!incremental){
push();
for(unsigned i = 0; i < linear_assumptions.size(); i++)
for(unsigned j = 0; j < linear_assumptions[i].size(); j++)
add(linear_assumptions[i][j]);
}
check_result res = unsat;
if(!m_solver->get_proof())
res = check();
if(res == unsat){
interpolation_options_struct opts;
if(weak_mode)
opts.set("weak","1");
opts.set("weak","1");
::ast *proof = m_solver->get_proof();
try {
iz3interpolate(m(),proof,_assumptions,_parents,_interpolants,_theory,&opts);
}
// If there's an interpolation bug, throw a char *
// exception so duality can catch it and restart.
// exception so duality can catch it and restart.
catch (const interpolation_failure &f) {
throw f.msg();
}
std::vector<expr> linearized_interpolants(_interpolants.size());
for(unsigned i = 0; i < _interpolants.size(); i++)
linearized_interpolants[i] = expr(ctx(),_interpolants[i]);
@ -585,13 +585,13 @@ namespace Duality {
model_ref _m;
m_solver->get_model(_m);
model = Duality::model(ctx(),_m.get());
#if 0
if(_labels){
labels = _labels;
}
#endif
if(!incremental)
pop();
@ -603,7 +603,7 @@ namespace Duality {
void interpolating_solver::SetWeakInterpolants(bool weak){
weak_mode = weak;
}
void interpolating_solver::SetPrintToFile(const std::string &filename){
print_filename = filename;
@ -618,14 +618,14 @@ namespace Duality {
void interpolating_solver::RemoveInterpolationAxiom(const expr & t){
// theory.remove(t);
}
const char *interpolating_solver::profile(){
// return Z3_interpolation_profile(ctx());
return "";
}
static void get_assumptions_rec(stl_ext::hash_set<ast> &memo, const proof &pf, std::vector<expr> &assumps){
if(memo.find(pf) != memo.end())return;
memo.insert(pf);
@ -657,7 +657,7 @@ namespace Duality {
model_smt2_pp(std::cout, m(), *m_model, 0);
std::cout << std::endl;
}
void model::show_hash() const {
std::ostringstream ss;
model_smt2_pp(ss, m(), *m_model, 0);

View file

@ -541,6 +541,7 @@ class iz3proof_itp_impl : public iz3proof_itp {
placeholder_arg |= is_placeholder(args[i]);
}
try {
TRACE("duality", print_expr(tout, e); tout << "\n";);
opr f = op(e);
if(f == Equal && args[0] == args[1]) res = mk_true();
else if(f == And) res = my_and(args);
@ -853,6 +854,7 @@ class iz3proof_itp_impl : public iz3proof_itp {
ast simplify_rotate_eq2leq(const ast &pl, const ast &neg_equality, const ast &pf){
if(pl == arg(pf,1)){
TRACE("duality", print_expr(tout, pl); print_expr(tout << "\n", neg_equality); print_expr(tout << "\n", pf); tout << "\n";);
ast cond = mk_true();
ast equa = sep_cond(arg(pf,0),cond);
if(is_equivrel_chain(equa)){
@ -1870,10 +1872,13 @@ class iz3proof_itp_impl : public iz3proof_itp {
ast chain_ineqs(opr comp_op, LitType t, const ast &chain, const ast &lhs, const ast &rhs){
if(is_true(chain)){
if(lhs != rhs)
if (lhs != rhs) {
TRACE("duality", print_expr(tout, lhs); tout << " "; print_expr(tout, rhs); tout << "\n";);
throw bad_ineq_inference();
}
return make(Leq,make_int(rational(0)),make_int(rational(0)));
}
TRACE("duality", print_expr(tout, chain); print_expr(tout << "\n", lhs); tout << " "; print_expr(tout, rhs); tout << "\n";);
ast last = chain_last(chain);
ast rest = chain_rest(chain);
ast mid = subst_in_pos(rhs,rewrite_pos(last),rewrite_lhs(last));

View file

@ -47,14 +47,14 @@ Revision History:
namespace datalog {
rule_manager::rule_manager(context& ctx)
rule_manager::rule_manager(context& ctx)
: m(ctx.get_manager()),
m_ctx(ctx),
m_body(m),
m_head(m),
m_args(m),
m_hnf(m),
m_qe(m),
m_qe(m, params_ref()),
m_rwr(m),
m_ufproc(m) {}
@ -98,7 +98,7 @@ namespace datalog {
var_idx_set& rule_manager::finalize_collect_vars() {
unsigned sz = m_free_vars.size();
for (unsigned i = 0; i < sz; ++i) {
if (m_free_vars[i]) m_var_idx.insert(i);
if (m_free_vars[i]) m_var_idx.insert(i);
}
return m_var_idx;
}
@ -139,7 +139,7 @@ namespace datalog {
}
void rule_manager::mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) {
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);
proof_ref pr(p, m);
expr_ref fml1(m);
@ -147,7 +147,7 @@ namespace datalog {
if (fml1 != fml && pr) {
pr = m.mk_asserted(fml1);
}
remove_labels(fml1, pr);
remove_labels(fml1, pr);
mk_rule_core(fml1, pr, rules, name);
}
@ -162,7 +162,7 @@ namespace datalog {
else {
is_negated.push_back(false);
}
}
}
}
void rule_manager::mk_rule_core(expr* fml, proof* p, rule_set& rules, symbol const& name) {
@ -170,7 +170,7 @@ namespace datalog {
proof_ref_vector prs(m);
m_hnf.reset();
m_hnf.set_name(name);
m_hnf(fml, p, fmls, prs);
for (unsigned i = 0; i < m_hnf.get_fresh_predicates().size(); ++i) {
m_ctx.register_predicate(m_hnf.get_fresh_predicates()[i], false);
@ -181,7 +181,7 @@ namespace datalog {
}
void rule_manager::mk_horn_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) {
m_body.reset();
m_neg.reset();
unsigned index = extract_horn(fml, m_body, m_head);
@ -208,13 +208,13 @@ namespace datalog {
}
else if (is_quantifier(fml1)) {
p = m.mk_modus_ponens(p, m.mk_symmetry(m.mk_der(to_quantifier(fml1), fml)));
}
}
else {
p = m.mk_modus_ponens(p, m.mk_rewrite(fml, fml1));
}
}
if (m_ctx.fix_unbound_vars()) {
if (m_ctx.fix_unbound_vars()) {
fix_unbound_vars(r, true);
}
@ -242,10 +242,10 @@ namespace datalog {
for (unsigned i = 0; i < m_args.size(); ++i) {
body.push_back(ensure_app(m_args[i].get()));
}
}
}
else {
head = ensure_app(fml);
}
}
return index;
}
@ -262,12 +262,12 @@ namespace datalog {
func_decl* rule_manager::mk_query(expr* query, rule_set& rules) {
TRACE("dl", tout << mk_pp(query, m) << "\n";);
ptr_vector<sort> vars;
svector<symbol> names;
app_ref_vector body(m);
expr_ref q(m);
// Add implicit variables.
// Remove existential prefix.
bind_variables(query, false, q);
@ -278,7 +278,7 @@ namespace datalog {
m_free_vars(q);
vars.append(m_free_vars.size(), m_free_vars.c_ptr());
if (vars.contains(static_cast<sort*>(0))) {
var_subst sub(m, false);
var_subst sub(m, false);
expr_ref_vector args(m);
// [s0, 0, s2, ..]
// [0 -> 0, 1 -> x, 2 -> 1, ..]
@ -313,7 +313,7 @@ namespace datalog {
}
}
// we want outermost declared variable first to
// we want outermost declared variable first to
// follow order of quantified variables so we reverse vars.
while (vars.size() > names.size()) {
names.push_back(symbol(names.size()));
@ -321,9 +321,9 @@ namespace datalog {
vars.reverse();
names.reverse();
func_decl* qpred = m_ctx.mk_fresh_head_predicate(symbol("query"), symbol(), vars.size(), vars.c_ptr(), body_pred);
m_ctx.register_predicate(qpred, false);
m_ctx.register_predicate(qpred, false);
rules.set_output_predicate(qpred);
if (m_ctx.get_model_converter()) {
filter_model_converter* mc = alloc(filter_model_converter, m);
mc->insert(qpred);
@ -366,7 +366,7 @@ namespace datalog {
for (unsigned i = 0; i < r.size(); ++i) {
body.push_back(ensure_app(r[i].get()));
}
}
}
void rule_manager::hoist_compound(unsigned& num_bound, app_ref& fml, app_ref_vector& body) {
@ -440,7 +440,7 @@ namespace datalog {
if (is_quantifier(e)) {
q = to_quantifier(e);
return q->is_forall();
}
}
return false;
}
@ -454,7 +454,7 @@ namespace datalog {
return app_ref(m.mk_eq(e, m.mk_true()), m);
}
}
void rule_manager::check_app(expr* e) {
if (!is_app(e)) {
std::ostringstream out;
@ -481,7 +481,7 @@ namespace datalog {
bool has_neg = false;
for (unsigned i = 0; i < n; i++) {
bool is_neg = (is_negated != 0 && is_negated[i]);
bool is_neg = (is_negated != 0 && is_negated[i]);
app * curr = tail[i];
if (is_neg && !m_ctx.is_predicate(curr)) {
@ -571,7 +571,7 @@ namespace datalog {
case 1: fml = m.mk_implies(body[0].get(), fml); break;
default: fml = m.mk_implies(m.mk_and(body.size(), body.c_ptr()), fml); break;
}
m_free_vars(fml);
if (m_free_vars.empty()) {
return;
@ -579,7 +579,7 @@ namespace datalog {
svector<symbol> names;
used_symbols<> us;
m_free_vars.set_default_sort(m.mk_bool_sort());
us(fml);
m_free_vars.reverse();
for (unsigned j = 0, i = 0; i < m_free_vars.size(); ++j) {
@ -594,8 +594,8 @@ namespace datalog {
++i;
}
}
}
fml = m.mk_forall(m_free_vars.size(), m_free_vars.c_ptr(), names.c_ptr(), fml);
}
fml = m.mk_forall(m_free_vars.size(), m_free_vars.c_ptr(), names.c_ptr(), fml);
}
std::ostream& rule_manager::display_smt2(rule const& r, std::ostream & out) {
@ -749,7 +749,7 @@ namespace datalog {
quant_tail = m.mk_exists(q_var_cnt, qsorts.c_ptr(), qnames.c_ptr(), unbound_tail_pre_quant);
if (try_quantifier_elimination) {
TRACE("dl_rule_unbound_fix_pre_qe",
TRACE("dl_rule_unbound_fix_pre_qe",
tout<<"rule: ";
r->display(m_ctx, tout);
tout<<"tail with unbound vars: "<<mk_pp(unbound_tail, m)<<"\n";
@ -764,7 +764,7 @@ namespace datalog {
fixed_tail = quant_tail;
}
TRACE("dl_rule_unbound_fix",
TRACE("dl_rule_unbound_fix",
tout<<"rule: ";
r->display(m_ctx, tout);
tout<<"tail with unbound vars: "<<mk_pp(unbound_tail, m)<<"\n";
@ -796,7 +796,7 @@ namespace datalog {
to_formula(new_rule, fml);
scoped_proof _sc(m);
proof* p = m.mk_rewrite(m.get_fact(old_rule.get_proof()), fml);
new_rule.set_proof(m, m.mk_modus_ponens(old_rule.get_proof(), p));
new_rule.set_proof(m, m.mk_modus_ponens(old_rule.get_proof(), p));
}
}
@ -824,7 +824,7 @@ namespace datalog {
}
r = mk(new_head.get(), new_tail.size(), new_tail.c_ptr(), tail_neg.c_ptr(), r->name(), false);
// keep old variable indices around so we can compose with substitutions.
// keep old variable indices around so we can compose with substitutions.
// r->norm_vars(*this);
}
@ -835,7 +835,7 @@ namespace datalog {
void rule_manager::check_valid_head(expr * head) const {
SASSERT(head);
if (!m_ctx.is_predicate(head)) {
std::ostringstream out;
out << "Illegal head. The head predicate needs to be uninterpreted and registered (as recursive) " << mk_pp(head, m);
@ -874,14 +874,14 @@ namespace datalog {
m.get_allocator().deallocate(get_obj_size(n), this);
}
void rule::set_proof(ast_manager& m, proof* p) {
void rule::set_proof(ast_manager& m, proof* p) {
if (p) {
m.inc_ref(p);
m.inc_ref(p);
}
if (m_proof) {
m.dec_ref(m_proof);
m.dec_ref(m_proof);
}
m_proof = p;
m_proof = p;
}
bool rule::is_in_tail(const func_decl * p, bool only_positive) const {
@ -896,7 +896,7 @@ namespace datalog {
//
// non-predicates may appear only in the interpreted tail, it is therefore
// non-predicates may appear only in the interpreted tail, it is therefore
// sufficient only to check the tail.
//
bool rule_manager::has_uninterpreted_non_predicates(rule const& r, func_decl*& f) const {
@ -911,7 +911,7 @@ namespace datalog {
//
// Quantifiers may appear only in the interpreted tail, it is therefore
// Quantifiers may appear only in the interpreted tail, it is therefore
// sufficient only to check the interpreted tail.
//
void rule_manager::has_quantifiers(rule const& r, bool& existential, bool& universal) const {
@ -945,7 +945,7 @@ namespace datalog {
unsigned sz = get_tail_size();
for (unsigned i = 0; i < sz; ++i) {
used.process(get_tail(i));
}
}
}
void rule::get_vars(ast_manager& m, ptr_vector<sort>& sorts) const {
@ -994,13 +994,13 @@ namespace datalog {
app * old_tail = get_tail(i);
expr_ref new_tail_e(m);
vs(old_tail, subst_vals.size(), subst_vals.c_ptr(), new_tail_e);
bool sign = is_neg_tail(i);
bool sign = is_neg_tail(i);
m.inc_ref(new_tail_e);
m.dec_ref(old_tail);
m_tail[i] = TAG(app *, to_app(new_tail_e), sign);
}
}
void rule::display(context & ctx, std::ostream & out) const {
ast_manager & m = ctx.get_manager();
//out << mk_pp(m_head, m);
@ -1068,7 +1068,7 @@ namespace datalog {
}
};

View file

@ -29,6 +29,7 @@ Revision History:
#include"substitution.h"
#include"ast_counter.h"
#include"statistics.h"
#include"stopwatch.h"
#include"lbool.h"
namespace datalog {

View file

@ -1007,7 +1007,7 @@ namespace pdr {
return m_cache[l];
}
void model_search::erase_children(model_node& n, bool backtrack) {
void model_search::erase_children(model_node& n, bool backtrack) {
ptr_vector<model_node> todo, nodes;
todo.append(n.children());
remove_goal(n);
@ -2241,7 +2241,7 @@ namespace pdr {
vars.append(aux_vars.size(), aux_vars.c_ptr());
scoped_ptr<expr_replacer> rep;
qe_lite qe(m);
qe_lite qe(m, m_params.p);
expr_ref phi1 = m_pm.mk_and(Phi);
qe(vars, phi1);
TRACE("pdr", tout << "Eliminated\n" << mk_pp(phi1, m) << "\n";);

View file

@ -30,7 +30,6 @@ Revision History:
namespace datalog {
class execution_context;
class instruction_block;
class rel_context;

View file

@ -53,10 +53,10 @@ namespace tb {
app* t = to_app(_t);
if (m.is_value(s) && m.is_value(t)) {
IF_VERBOSE(2, verbose_stream() << "different:" << mk_pp(s, m) << " " << mk_pp(t, m) << "\n";);
IF_VERBOSE(2, verbose_stream() << "different:" << mk_pp(s, m) << " " << mk_pp(t, m) << "\n";);
return l_false;
}
if (m_dt.is_constructor(s) && m_dt.is_constructor(t)) {
if (s->get_decl() == t->get_decl()) {
lbool state = l_true;
@ -75,7 +75,7 @@ namespace tb {
return state;
}
else {
IF_VERBOSE(2, verbose_stream() << "different constructors:" << mk_pp(s, m) << " " << mk_pp(t, m) << "\n";);
IF_VERBOSE(2, verbose_stream() << "different constructors:" << mk_pp(s, m) << " " << mk_pp(t, m) << "\n";);
return l_false;
}
}
@ -109,7 +109,7 @@ namespace tb {
case l_false:
return false;
default:
conds.push_back(m.mk_eq(p, t));
conds.push_back(m.mk_eq(p, t));
return true;
}
}
@ -117,7 +117,7 @@ namespace tb {
public:
matcher(ast_manager& m): m(m), m_dt(m) {}
bool operator()(app* pat, app* term, substitution& s, expr_ref_vector& conds) {
// top-most term to match is a predicate. The predicates should be the same.
if (pat->get_decl() != term->get_decl() ||
@ -149,7 +149,7 @@ namespace tb {
}
}
return true;
}
}
};
class clause {
@ -165,22 +165,22 @@ namespace tb {
unsigned m_next_rule; // next rule to expand goal on
unsigned m_ref; // reference count
public:
public:
clause(ast_manager& m):
m_head(m),
m_predicates(m),
m_constraint(m),
m_seqno(0),
m_index(0),
m_index(0),
m_num_vars(0),
m_predicate_index(0),
m_predicate_index(0),
m_parent_rule(0),
m_parent_index(0),
m_next_rule(static_cast<unsigned>(-1)),
m_ref(0) {
}
void set_seqno(unsigned seqno) { m_seqno = seqno; }
unsigned get_seqno() const { return m_seqno; }
unsigned get_next_rule() const { return m_next_rule; }
@ -198,10 +198,10 @@ namespace tb {
void set_head(app* h) { m_head = h; }
unsigned get_parent_index() const { return m_parent_index; }
unsigned get_parent_rule() const { return m_parent_rule; }
void set_parent(ref<tb::clause>& parent) {
void set_parent(ref<tb::clause>& parent) {
m_parent_index = parent->get_index();
m_parent_rule = parent->get_next_rule();
}
}
expr_ref get_body() const {
ast_manager& m = get_manager();
@ -247,7 +247,7 @@ namespace tb {
}
if (!vars.empty()) {
body = m.mk_forall(vars.size(), vars.c_ptr(), names.c_ptr(), body);
}
}
return body;
}
@ -273,18 +273,18 @@ namespace tb {
reduce_equalities();
// IF_VERBOSE(1, display(verbose_stream()););
}
void inc_ref() {
m_ref++;
}
void dec_ref() {
--m_ref;
if (m_ref == 0) {
dealloc(this);
}
}
void display(std::ostream& out) const {
ast_manager& m = m_head.get_manager();
expr_ref_vector fmls(m);
@ -304,7 +304,7 @@ namespace tb {
}
out << mk_pp(fml, m) << "\n";
}
private:
ast_manager& get_manager() const { return m_head.get_manager(); }
@ -314,7 +314,7 @@ namespace tb {
// - m_head - head predicate
// - m_predicates - auxiliary predicates in body.
// - m_constraint - side constraint
//
//
void init_from_rule(datalog::rule_ref const& r) {
ast_manager& m = get_manager();
expr_ref_vector fmls(m);
@ -328,7 +328,7 @@ namespace tb {
m_predicates.reset();
for (unsigned i = 0; i < utsz; ++i) {
m_predicates.push_back(r->get_tail(i));
}
}
bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), m_constraint);
}
@ -348,13 +348,13 @@ namespace tb {
if (get_subst(rw, subst, i, fmls)) {
fmls[i] = m.mk_true();
}
}
}
subst.apply(1, delta, expr_offset(m_head, 0), tmp);
m_head = to_app(tmp);
for (unsigned i = 0; i < m_predicates.size(); ++i) {
subst.apply(1, delta, expr_offset(m_predicates[i].get(), 0), tmp);
m_predicates[i] = to_app(tmp);
}
}
bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), m_constraint);
subst.apply(1, delta, expr_offset(m_constraint, 0), m_constraint);
rw(m_constraint);
@ -404,7 +404,7 @@ namespace tb {
throw non_constructor();
}
}
void operator()(var* v) { }
void operator()(var* v) { }
void operator()(quantifier* ) {
throw non_constructor();
}
@ -421,7 +421,7 @@ namespace tb {
return true;
}
};
};
// rules
class rules {
@ -456,7 +456,7 @@ namespace tb {
func_decl* f = g->get_decl();
map::obj_map_entry* e = m_index.insert_if_not_there2(f, unsigned_vector());
SASSERT(e);
e->get_data().m_value.push_back(idx);
e->get_data().m_value.push_back(idx);
}
unsigned get_num_rules(func_decl* p) const {
@ -475,14 +475,14 @@ namespace tb {
for (; it != end; ++it) {
decls.push_back(it->m_key);
}
}
}
ref<clause> get_rule(func_decl* p, unsigned idx) const {
map::obj_map_entry* e = m_index.find_core(p);
SASSERT(p);
unsigned rule_id = e->get_data().get_value()[idx];
return m_rules[rule_id];
}
}
private:
void reset() {
m_rules.reset();
@ -509,7 +509,7 @@ namespace tb {
bool_rewriter m_rw;
smt_params m_fparams;
smt::kernel m_solver;
public:
index(ast_manager& m):
m(m),
@ -520,7 +520,7 @@ namespace tb {
m_matcher(m),
m_refs(m),
m_subst(m),
m_qe(m),
m_qe(m, params_ref()),
m_rw(m),
m_solver(m, m_fparams) {}
@ -544,7 +544,7 @@ namespace tb {
}
private:
void setup(clause const& g) {
m_preds.reset();
m_refs.reset();
@ -569,8 +569,8 @@ namespace tb {
}
vs(g.get_constraint(), vars.size(), vars.c_ptr(), fml);
fmls.push_back(fml);
m_precond = m.mk_and(fmls.size(), fmls.c_ptr());
IF_VERBOSE(2,
m_precond = m.mk_and(fmls.size(), fmls.c_ptr());
IF_VERBOSE(2,
verbose_stream() << "setup-match: ";
for (unsigned i = 0; i < m_preds.size(); ++i) {
verbose_stream() << mk_pp(m_preds[i].get(), m) << " ";
@ -587,18 +587,18 @@ namespace tb {
return true;
}
}
return false;
return false;
}
//
// check that each predicate in r is matched by some predicate in premise.
// for now: skip multiple matches within the same rule (incomplete).
//
bool match_rule(unsigned rule_index) {
clause const& g = *m_index[rule_index];
clause const& g = *m_index[rule_index];
m_sideconds.reset();
m_subst.reset();
m_subst.reserve(2, g.get_num_vars());
IF_VERBOSE(2, g.display(verbose_stream() << "try-match\n"););
return match_head(g);
@ -628,9 +628,9 @@ namespace tb {
}
verbose_stream() << mk_pp(q, m) << " = " << mk_pp(p, m) << "\n";
);
if (q->get_decl() == p->get_decl() &&
if (q->get_decl() == p->get_decl() &&
m_matcher(q, p, m_subst, m_sideconds) &&
match_predicates(predicate_index + 1, g)) {
return true;
@ -646,7 +646,7 @@ namespace tb {
expr_ref q(m), postcond(m);
expr_ref_vector fmls(m_sideconds);
m_subst.reset_cache();
for (unsigned i = 0; !m.canceled() && i < fmls.size(); ++i) {
m_subst.apply(2, deltas, expr_offset(fmls[i].get(), 0), q);
fmls[i] = q;
@ -680,7 +680,7 @@ namespace tb {
verbose_stream() << "check: " << mk_pp(postcond, m, 7 + g.get_num_predicates()) << "\n";);
if (!is_ground(postcond)) {
IF_VERBOSE(1, verbose_stream() << "TBD: non-ground\n"
IF_VERBOSE(1, verbose_stream() << "TBD: non-ground\n"
<< mk_pp(postcond, m) << "\n";
m_clause->display(verbose_stream());
verbose_stream() << "\n=>\n";
@ -743,7 +743,7 @@ namespace tb {
double m_weight_multiply;
unsigned m_update_frequency;
unsigned m_next_update;
public:
selection(datalog::context& ctx):
@ -766,7 +766,7 @@ namespace tb {
scores.reset();
basic_score_predicate(p, scores);
insert_score(p->get_decl(), scores);
}
}
normalize_scores(rs);
}
@ -783,7 +783,7 @@ namespace tb {
default:
return weight_select(g);
}
}
}
void reset() {
@ -867,8 +867,8 @@ namespace tb {
}
}
IF_VERBOSE(1, verbose_stream() << "select:" << result << "\n";);
return result;
return result;
}
unsigned basic_weight_select(clause const& g) {
@ -957,7 +957,7 @@ namespace tb {
}
}
double score_predicate(app* p) {
double score = 1;
if (find_score(p, score)) {
@ -1031,7 +1031,7 @@ namespace tb {
}
else {
m_score_map.insert(f, scores);
}
}
}
};
@ -1044,15 +1044,15 @@ namespace tb {
expr_ref_vector m_sub1;
expr_ref_vector m_sub2;
public:
unifier(ast_manager& m):
m(m),
unifier(ast_manager& m):
m(m),
m_unifier(m),
m_S1(m),
m_S2(m, false),
m_rename(m),
m_sub1(m),
m_sub1(m),
m_sub2(m) {}
bool operator()(ref<clause>& tgt, unsigned idx, ref<clause>& src, bool compute_subst, ref<clause>& result) {
return unify(*tgt, idx, *src, compute_subst, result);
}
@ -1066,12 +1066,12 @@ namespace tb {
}
}
bool unify(clause const& tgt, unsigned idx, clause const& src, bool compute_subst, ref<clause>& result) {
qe_lite qe(m);
bool unify(clause const& tgt, unsigned idx, clause const& src, bool compute_subst, ref<clause>& result) {
qe_lite qe(m, params_ref());
reset();
SASSERT(tgt.get_predicate(idx)->get_decl() == src.get_decl());
unsigned var_cnt = std::max(tgt.get_num_vars(), src.get_num_vars());
m_S1.reserve(2, var_cnt);
m_S1.reserve(2, var_cnt);
if (!m_unifier(tgt.get_predicate(idx), src.get_head(), m_S1)) {
return false;
}
@ -1080,7 +1080,7 @@ namespace tb {
app_ref head(m);
result = alloc(clause, m);
unsigned delta[2] = { 0, var_cnt };
m_S1.apply(2, delta, expr_offset(tgt.get_head(), 0), tmp);
m_S1.apply(2, delta, expr_offset(tgt.get_head(), 0), tmp);
head = to_app(tmp);
for (unsigned i = 0; i < tgt.get_num_predicates(); ++i) {
if (i != idx) {
@ -1096,7 +1096,7 @@ namespace tb {
}
m_S1.apply(2, delta, expr_offset(tgt.get_constraint(), 0), tmp);
m_S1.apply(2, delta, expr_offset(src.get_constraint(), 1), tmp2);
constraint = m.mk_and(tmp, tmp2);
constraint = m.mk_and(tmp, tmp2);
// perform trival quantifier-elimination:
uint_set index_set;
@ -1114,7 +1114,7 @@ namespace tb {
if (m.is_false(constraint)) {
return false;
}
// initialize rule.
result->init(head, predicates, constraint);
ptr_vector<sort> vars;
@ -1147,10 +1147,10 @@ namespace tb {
extract_subst(delta, src, 1);
}
// init result using head, predicates, constraint
return true;
return true;
}
private:
void reset() {
m_S1.reset();
@ -1175,9 +1175,9 @@ namespace tb {
else {
insert_subst(offset, m.mk_true());
}
}
}
}
void insert_subst(unsigned offset, expr* e) {
if (offset == 0) {
m_sub1.push_back(e);
@ -1201,7 +1201,7 @@ namespace tb {
//
// Given a clause
// Given a clause
// P(s) :- P(t), Phi(x).
// Compute the clauses:
// acc: P(s) :- Delta(z,t), P(z), Phi(x).
@ -1237,7 +1237,7 @@ namespace tb {
head = m.mk_app(delta, zszs.size(), zszs.c_ptr());
for (unsigned i = 0; i < zs.size(); ++i) {
zszs[i+zs.size()] = q->get_arg(i);
}
}
pred = m.mk_app(delta, zszs.size(), zszs.c_ptr());
preds.push_back(pred);
for (unsigned i = 1; i < g.get_num_predicates(); ++i) {
@ -1247,28 +1247,28 @@ namespace tb {
preds.push_back(m.mk_app(q->get_decl(), zs.size(), zs.c_ptr()));
acc->init(p, preds, g.get_constraint());
IF_VERBOSE(1,
IF_VERBOSE(1,
delta1->display(verbose_stream() << "delta1:\n");
delta2->display(verbose_stream() << "delta2:\n");
acc->display(verbose_stream() << "acc:\n"););
}
//
//
// Given a sequence of clauses and inference rules
// compute a super-predicate and auxiliary clauses.
//
//
// P1(x) :- P2(y), R(z)
// P2(y) :- P3(z), T(u)
// P3(z) :- P1(x), U(v)
// =>
// P1(x) :- P1(x), R(z), T(u), U(v)
//
//
ref<clause> resolve_rules(unsigned num_clauses, clause*const* clauses, unsigned const* positions) {
ref<clause> result = clauses[0];
ref<clause> tmp;
unsigned offset = 0;
for (unsigned i = 0; i + 1 < num_clauses; ++i) {
for (unsigned i = 0; i + 1 < num_clauses; ++i) {
clause const& cl = *clauses[i+1];
offset += positions[i];
VERIFY (m_unifier.unify(*result, offset, cl, false, tmp));
@ -1276,7 +1276,7 @@ namespace tb {
}
return result;
}
private:
@ -1286,7 +1286,7 @@ namespace tb {
unsigned num_vars = g.get_num_vars();
for (unsigned i = 0; i < p->get_num_args(); ++i) {
result.push_back(m.mk_var(num_vars+i, m.get_sort(p->get_arg(i))));
}
}
return result;
}
};
@ -1341,7 +1341,7 @@ namespace datalog {
uint_set m_displayed_rules;
public:
imp(context& ctx):
m_ctx(ctx),
m_ctx(ctx),
m(ctx.get_manager()),
rm(ctx.get_rule_manager()),
m_index(m),
@ -1358,7 +1358,7 @@ namespace datalog {
m_fparams.m_timeout = 1000;
}
~imp() {}
~imp() {}
lbool query(expr* query) {
m_ctx.ensure_opened();
@ -1378,7 +1378,7 @@ namespace datalog {
IF_VERBOSE(1, display_clause(*get_clause(), verbose_stream() << "g" << get_clause()->get_seqno() << " "););
return run();
}
void cleanup() {
m_clauses.reset();
}
@ -1400,7 +1400,7 @@ namespace datalog {
expr_ref get_answer() const {
switch(m_status) {
case l_undef:
case l_undef:
UNREACHABLE();
return expr_ref(m.mk_false(), m);
case l_true: {
@ -1415,7 +1415,7 @@ namespace datalog {
return expr_ref(m.mk_true(), m);
}
private:
void select_predicate() {
tb::clause & g = *get_clause();
unsigned num_predicates = g.get_num_predicates();
@ -1430,17 +1430,17 @@ namespace datalog {
IF_VERBOSE(2, verbose_stream() << mk_pp(g.get_predicate(pi), m) << "\n";);
}
}
void apply_rule(ref<tb::clause>& r) {
ref<tb::clause> clause = get_clause();
ref<tb::clause> next_clause;
ref<tb::clause> next_clause;
if (m_unifier(clause, clause->get_predicate_index(), r, false, next_clause) &&
!query_is_tautology(*next_clause)) {
init_clause(next_clause);
unsigned subsumer = 0;
IF_VERBOSE(1,
IF_VERBOSE(1,
display_rule(*clause, verbose_stream());
display_premise(*clause,
display_premise(*clause,
verbose_stream() << "g" << next_clause->get_seqno() << " ");
display_clause(*next_clause, verbose_stream());
);
@ -1462,8 +1462,8 @@ namespace datalog {
m_instruction = tb::SELECT_RULE;
}
}
void select_rule() {
void select_rule() {
tb::clause& g = *get_clause();
g.inc_next_rule();
unsigned pi = g.get_predicate_index();
@ -1481,7 +1481,7 @@ namespace datalog {
void backtrack() {
SASSERT(!m_clauses.empty());
m_clauses.pop_back();
m_clauses.pop_back();
if (m_clauses.empty()) {
m_instruction = tb::SATISFIABLE;
}
@ -1500,16 +1500,16 @@ namespace datalog {
return l_undef;
}
switch(m_instruction) {
case tb::SELECT_PREDICATE:
select_predicate();
case tb::SELECT_PREDICATE:
select_predicate();
break;
case tb::SELECT_RULE:
select_rule();
case tb::SELECT_RULE:
select_rule();
break;
case tb::BACKTRACK:
backtrack();
break;
case tb::SATISFIABLE:
case tb::SATISFIABLE:
m_status = l_false;
return l_false;
case tb::UNSATISFIABLE:
@ -1522,18 +1522,18 @@ namespace datalog {
return l_undef;
}
}
}
}
bool query_is_tautology(tb::clause const& g) {
expr_ref fml = g.to_formula();
fml = m.mk_not(fml);
m_solver.push();
m_solver.assert_expr(fml);
lbool is_sat = m_solver.check();
lbool is_sat = m_solver.check();
m_solver.pop(1);
TRACE("dl", tout << is_sat << ":\n" << mk_pp(fml, m) << "\n";);
return l_false == is_sat;
}
@ -1560,7 +1560,7 @@ namespace datalog {
void display_premise(tb::clause& p, std::ostream& out) {
func_decl* f = p.get_predicate(p.get_predicate_index())->get_decl();
out << "{g" << p.get_seqno() << " " << f->get_name() << " pos: "
out << "{g" << p.get_seqno() << " " << f->get_name() << " pos: "
<< p.get_predicate_index() << " rule: " << p.get_next_rule() << "}\n";
}
@ -1576,21 +1576,21 @@ namespace datalog {
ref<tb::clause> replayed_clause;
replace_proof_converter pc(m);
// clause is a empty clause.
// clause is a empty clause.
// Pretend it is asserted.
// It gets replaced by premises.
SASSERT(clause->get_num_predicates() == 0);
SASSERT(clause->get_num_predicates() == 0);
expr_ref root = clause->to_formula();
vector<expr_ref_vector> substs;
while (0 != clause->get_index()) {
SASSERT(clause->get_parent_index() < clause->get_index());
while (0 != clause->get_index()) {
SASSERT(clause->get_parent_index() < clause->get_index());
unsigned p_index = clause->get_parent_index();
unsigned p_rule = clause->get_parent_rule();
ref<tb::clause> parent = m_clauses[p_index];
unsigned pi = parent->get_predicate_index();
func_decl* pred = parent->get_predicate(pi)->get_decl();
ref<tb::clause> rl = m_rules.get_rule(pred, p_rule);
ref<tb::clause> rl = m_rules.get_rule(pred, p_rule);
VERIFY(m_unifier(parent, parent->get_predicate_index(), rl, true, replayed_clause));
expr_ref_vector s1(m_unifier.get_rule_subst(true));
expr_ref_vector s2(m_unifier.get_rule_subst(false));
@ -1614,36 +1614,36 @@ namespace datalog {
}
expr_ref body = clause.get_body();
var_subst vs(m, false);
vs(body, subst.size(), subst.c_ptr(), body);
vs(body, subst.size(), subst.c_ptr(), body);
out << mk_pp(body, m) << "\n";
}
void resolve_rule(replace_proof_converter& pc, tb::clause const& r1, tb::clause const& r2,
void resolve_rule(replace_proof_converter& pc, tb::clause const& r1, tb::clause const& r2,
expr_ref_vector const& s1, expr_ref_vector const& s2, tb::clause const& res) const {
unsigned idx = r1.get_predicate_index();
expr_ref fml = res.to_formula();
vector<expr_ref_vector> substs;
svector<std::pair<unsigned, unsigned> > positions;
substs.push_back(s1);
substs.push_back(s2);
substs.push_back(s2);
scoped_proof _sc(m);
proof_ref pr(m);
proof_ref_vector premises(m);
premises.push_back(m.mk_asserted(r1.to_formula()));
premises.push_back(m.mk_asserted(r2.to_formula()));
positions.push_back(std::make_pair(idx+1, 0));
positions.push_back(std::make_pair(idx+1, 0));
pr = m.mk_hyper_resolve(2, premises.c_ptr(), fml, positions, substs);
pc.insert(pr);
}
}
};
tab::tab(context& ctx):
datalog::engine_base(ctx.get_manager(),"tabulation"),
m_imp(alloc(imp, ctx)) {
m_imp(alloc(imp, ctx)) {
}
tab::~tab() {
dealloc(m_imp);
}
}
lbool tab::query(expr* query) {
return m_imp->query(query);
}

View file

@ -126,6 +126,12 @@ namespace datalog {
app* s;
var* v;
// disable Ackerman reduction if head contains a non-variable or non-constant argument.
for (unsigned i = 0; i < to_app(head)->get_num_args(); ++i) {
expr* arg = to_app(head)->get_arg(i);
if (!is_var(arg) && !m.is_value(arg)) return false;
}
for (unsigned i = 0; i < conjs.size(); ++i) {
expr* e = conjs[i].get();
if (is_select_eq_var(e, s, v)) {
@ -281,6 +287,7 @@ namespace datalog {
m_rewriter(body);
sub(head);
m_rewriter(head);
TRACE("dl", tout << body << " => " << head << "\n";);
change = ackermanize(r, body, head);
if (!change) {
rules.add_rule(&r);

View file

@ -394,10 +394,6 @@ namespace datalog {
m_simp(a, simp1_res);
(*m_rw)(simp1_res.get(), res);
/*if (simp1_res.get()!=res.get()) {
std::cout<<"pre norm:\n"<<mk_pp(simp1_res.get(),m)<<"post norm:\n"<<mk_pp(res.get(),m)<<"\n";
}*/
m_simp(res.get(), res);
}

View file

@ -272,7 +272,8 @@ namespace opt {
s.assert_expr(m_hard_constraints);
IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n";);
lbool is_sat = s.check_sat(0,0);
TRACE("opt", tout << "initial search result: " << is_sat << "\n";);
TRACE("opt", tout << "initial search result: " << is_sat << "\n";
s.display(tout););
if (is_sat != l_false) {
s.get_model(m_model);
s.get_labels(m_labels);
@ -340,6 +341,14 @@ namespace opt {
fix_model(mdl);
}
void context::get_box_model(model_ref& mdl, unsigned index) {
if (index >= m_box_models.size()) {
throw default_exception("index into models is out of bounds");
}
mdl = m_box_models[index];
fix_model(mdl);
}
lbool context::execute_min_max(unsigned index, bool committed, bool scoped, bool is_max) {
if (scoped) get_solver().push();
lbool result = m_optsmt.lex(index, is_max);
@ -1036,6 +1045,10 @@ namespace opt {
TRACE("opt", tout << "Purifying " << term << "\n";);
term = purify(fm, term);
}
else if (m.is_ite(term)) {
TRACE("opt", tout << "Purifying " << term << "\n";);
term = purify(fm, term);
}
if (fm) {
m_model_converter = concat(m_model_converter.get(), fm.get());
}
@ -1226,7 +1239,7 @@ namespace opt {
out << " (";
display_objective(out, obj);
if (get_lower_as_num(i) != get_upper_as_num(i)) {
out << " (" << get_lower(i) << " " << get_upper(i) << ")";
out << " (interval " << get_lower(i) << " " << get_upper(i) << ")";
}
else {
out << " " << get_lower(i);

View file

@ -186,6 +186,7 @@ namespace opt {
virtual bool print_model() const;
virtual void set_model(model_ref& _m) { m_model = _m; }
virtual void get_model(model_ref& _m);
virtual void get_box_model(model_ref& _m, unsigned index);
virtual void fix_model(model_ref& _m);
virtual void collect_statistics(statistics& stats) const;
virtual proof* get_proof() { return 0; }

View file

@ -5,6 +5,8 @@ def_module_params('opt',
('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)'),
('rlimit', UINT, 0, 'resource limit (0 means no limit)'),
('print_model', BOOL, False, 'display model for satisfiable constraints'),
('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'),
('enable_sat', BOOL, True, 'enable the new SAT core for propositional constraints'),

View file

@ -50,6 +50,7 @@ namespace opt {
if (m_params.m_case_split_strategy == CS_ACTIVITY_DELAY_NEW) {
m_params.m_relevancy_lvl = 0;
}
// m_params.m_auto_config = false;
}
unsigned opt_solver::m_dump_count = 0;
@ -357,6 +358,7 @@ namespace opt {
}
smt::theory_opt& opt = get_optimizer();
smt::theory_var v = m_objective_vars[var];
TRACE("opt", tout << "v" << var << " " << val << "\n";);
if (typeid(smt::theory_inf_arith) == typeid(opt)) {
smt::theory_inf_arith& th = dynamic_cast<smt::theory_inf_arith&>(opt);
@ -386,8 +388,32 @@ namespace opt {
smt::theory_rdl& th = dynamic_cast<smt::theory_rdl&>(opt);
return th.mk_ge(m_fm, v, val);
}
if (typeid(smt::theory_dense_i) == typeid(opt) &&
val.get_infinitesimal().is_zero()) {
smt::theory_dense_i& th = dynamic_cast<smt::theory_dense_i&>(opt);
return th.mk_ge(m_fm, v, val);
}
// difference logic?
if (typeid(smt::theory_dense_mi) == typeid(opt) &&
val.get_infinitesimal().is_zero()) {
smt::theory_dense_mi& th = dynamic_cast<smt::theory_dense_mi&>(opt);
return th.mk_ge(m_fm, v, val);
}
if (typeid(smt::theory_dense_si) == typeid(opt) &&
val.get_infinitesimal().is_zero()) {
smt::theory_dense_si& th = dynamic_cast<smt::theory_dense_si&>(opt);
return th.mk_ge(m_fm, v, val);
}
if (typeid(smt::theory_dense_smi) == typeid(opt) &&
val.get_infinitesimal().is_zero()) {
smt::theory_dense_smi& th = dynamic_cast<smt::theory_dense_smi&>(opt);
return th.mk_ge(m_fm, v, val);
}
IF_VERBOSE(0, verbose_stream() << "WARNING: unhandled theory " << typeid(opt).name() << "\n";);
return expr_ref(m.mk_true(), m);
}

View file

@ -61,13 +61,12 @@ namespace opt {
return is_sat;
}
m_upper = m_lower;
bool was_sat = false;
expr_ref_vector asms(m);
vector<expr_ref_vector> cores;
obj_map<expr, rational>::iterator it = soft.begin(), end = soft.end();
for (; it != end; ++it) {
expr* c = assert_weighted(wth(), it->m_key, it->m_value);
assert_weighted(wth(), it->m_key, it->m_value);
if (!is_true(it->m_key)) {
m_upper += it->m_value;
}
@ -97,7 +96,6 @@ namespace opt {
expr_ref fml = wth().mk_block();
//DEBUG_CODE(verify_cores(cores););
s().assert_expr(fml);
was_sat = true;
}
else {
//DEBUG_CODE(verify_cores(cores););

View file

@ -66,7 +66,7 @@ namespace smt2 {
scoped_ptr<bv_util> m_bv_util;
scoped_ptr<arith_util> m_arith_util;
scoped_ptr<seq_util> m_seq_util;
scoped_ptr<seq_util> m_seq_util;
scoped_ptr<pattern_validator> m_pattern_validator;
scoped_ptr<var_shifter> m_var_shifter;
@ -2218,11 +2218,27 @@ namespace smt2 {
if (m_cached_strings.empty())
throw cmd_exception("invalid get-value command, empty list of terms");
next();
unsigned index = 0;
if (curr_is_keyword() && (curr_id() == ":model-index" || curr_id() == ":model_index")) {
next();
check_int("integer index expected to indexed model evaluation");
if (!curr_numeral().is_unsigned())
throw parser_exception("expected unsigned integer index to model evaluation");
index = curr_numeral().get_unsigned();
next();
}
check_rparen("invalid get-value command, ')' expected");
if (!m_ctx.is_model_available() || m_ctx.get_check_sat_result() == 0)
throw cmd_exception("model is not available");
model_ref md;
m_ctx.get_check_sat_result()->get_model(md);
if (index == 0) {
m_ctx.get_check_sat_result()->get_model(md);
}
else {
m_ctx.get_opt()->get_box_model(md, index);
}
m_ctx.regular_stream() << "(";
expr ** expr_it = expr_stack().c_ptr() + spos;
expr ** expr_end = expr_it + m_cached_strings.size();

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@ Module Name:
Abstract:
Light weight partial quantifier-elimination procedures
Light weight partial quantifier-elimination procedures
Author:
@ -31,14 +31,14 @@ class qe_lite {
class impl;
impl * m_impl;
public:
qe_lite(ast_manager& m);
qe_lite(ast_manager & m, params_ref const & p);
~qe_lite();
/**
\brief
Apply light-weight quantifier elimination
on constants provided as vector of variables.
Apply light-weight quantifier elimination
on constants provided as vector of variables.
Return the updated formula and updated set of variables that were not eliminated.
*/
@ -66,4 +66,4 @@ tactic * mk_qe_lite_tactic(ast_manager & m, params_ref const & p = params_ref())
ADD_TACTIC("qe-light", "apply light-weight quantifier elimination.", "mk_qe_lite_tactic(m, p)")
*/
#endif
#endif

View file

@ -26,8 +26,7 @@ namespace sat {
m_index(index),
m_lit(lit),
m_k(k),
m_size(lits.size())
{
m_size(lits.size()) {
for (unsigned i = 0; i < lits.size(); ++i) {
m_lits[i] = lits[i];
}
@ -42,6 +41,32 @@ namespace sat {
SASSERT(m_size >= m_k && m_k > 0);
}
card_extension::pb::pb(unsigned index, literal lit, svector<card_extension::wliteral> const& wlits, unsigned k):
m_index(index),
m_lit(lit),
m_k(k),
m_size(wlits.size()),
m_max_sum(0) {
for (unsigned i = 0; i < wlits.size(); ++i) {
m_wlits[i] = wlits[i];
if (m_max_sum + wlits[i].first < m_max_sum) {
throw default_exception("addition of pb coefficients overflows");
}
m_max_sum += wlits[i].first;
}
}
void card_extension::pb::negate() {
m_lit.neg();
unsigned w = 0;
for (unsigned i = 0; i < m_size; ++i) {
m_wlits[i].second.neg();
w += m_wlits[i].first;
}
m_k = w - m_k + 1;
SASSERT(w >= m_k && m_k > 0);
}
card_extension::xor::xor(unsigned index, literal lit, literal_vector const& lits):
m_index(index),
m_lit(lit),
@ -191,6 +216,356 @@ namespace sat {
SASSERT(s().inconsistent());
}
// pb:
void card_extension::copy_pb(card_extension& result) {
for (unsigned i = 0; i < m_pbs.size(); ++i) {
svector<wliteral> wlits;
pb& p = *m_pbs[i];
for (unsigned i = 0; i < p.size(); ++i) {
wlits.push_back(p[i]);
}
bool_var v = p.lit() == null_literal ? null_bool_var : p.lit().var();
result.add_pb_ge(v, wlits, p.k());
}
}
// watch a prefix of literals, such that the slack of these is >= k
void card_extension::init_watch(pb& p, bool is_true) {
clear_watch(p);
if (p.lit() != null_literal && p.lit().sign() == is_true) {
p.negate();
}
TRACE("sat", display(tout << "init watch: ", p, true););
SASSERT(p.lit() == null_literal || value(p.lit()) == l_true);
unsigned sz = p.size(), bound = p.k();
// put the non-false literals into the head.
unsigned slack = 0, num_watch = 0, j = 0;
for (unsigned i = 0; i < sz; ++i) {
if (value(p[i].second) != l_false) {
if (j != i) {
p.swap(i, j);
}
if (slack < bound) {
slack += p[i].first;
++num_watch;
}
++j;
}
}
DEBUG_CODE(
bool is_false = false;
for (unsigned k = 0; k < sz; ++k) {
SASSERT(!is_false || value(p[k].second) == l_false);
SASSERT(k < j == (value(p[k].second) != l_false));
is_false = value(p[k].second) == l_false;
});
if (slack < bound) {
literal lit = p[j].second;
SASSERT(value(p[j].second) == l_false);
for (unsigned i = j + 1; j < sz; ++i) {
if (lvl(lit) < lvl(p[i].second)) {
lit = p[i].second;
}
}
set_conflict(p, lit);
}
else {
for (unsigned i = 0; i < num_watch; ++i) {
watch_literal(p, p[i]);
}
p.set_slack(slack);
p.set_num_watch(num_watch);
}
}
/*
Chai Kuhlmann:
Lw - set of watched literals
Lu - set of unwatched literals that are not false
Lw = Lw \ { alit }
Sw -= value
a_max = max { a | l in Lw u Lu, l = undef }
while (Sw < k + a_max & Lu != 0) {
a_s = max { a | l in Lu }
Sw += a_s
Lw = Lw u {l_s}
Lu = Lu \ {l_s}
}
if (Sw < bound) conflict
while (Sw < k + a_max) {
assign (l_max)
a_max = max { ai | li in Lw, li = undef }
}
ASSERT(Sw >= bound)
return no-conflict
a_max index: index of non-false literal with maximal weight.
*/
lbool card_extension::add_assign(pb& p, literal alit) {
unsigned sz = p.size();
unsigned bound = p.k();
unsigned num_watch = p.num_watch();
unsigned slack = p.slack();
SASSERT(value(alit) == l_false);
SASSERT(p.lit() == null_literal || value(p.lit()) == l_true);
SASSERT(num_watch <= sz);
unsigned index = 0;
unsigned a_max = 0;
unsigned max_index = 0;
m_pb_undef.reset();
for (; index < num_watch; ++index) {
literal lit = p[index].second;
if (lit == alit) {
break;
}
if (value(lit) == l_undef) {
m_pb_undef.push_back(index);
if (p[index].first > a_max) {
a_max = p[index].first;
max_index = index;
}
}
}
for (unsigned j = index + 1; a_max == 0 && j < num_watch; ++j) {
literal lit = p[j].second;
if (value(lit) == l_undef) {
m_pb_undef.push_back(j);
a_max = p[j].first;
max_index = j;
}
}
for (unsigned j = num_watch; a_max == 0 && j < sz; ++j) {
literal lit = p[j].second;
if (value(lit) == l_undef) {
p.swap(j, num_watch);
m_pb_undef.push_back(num_watch);
a_max = p[num_watch].first;
max_index = num_watch;
}
}
unsigned val = p[index].first;
SASSERT(num_watch > 0);
SASSERT(index < num_watch);
SASSERT(value(p[index].second) == l_false);
SASSERT(val <= slack);
slack -= val;
// find literals to swap with:
for (unsigned j = num_watch; j < sz && slack < bound + a_max; ++j) {
if (value(p[j].second) != l_false) {
slack += p[j].first;
watch_literal(p, p[j]);
p.swap(num_watch, j);
if (value(p[num_watch].second) == l_undef && a_max < p[num_watch].first) {
m_pb_undef.push_back(num_watch);
a_max = p[num_watch].first;
max_index = num_watch;
}
++num_watch;
}
}
if (slack < bound) {
// maintain watching the literal
slack += val;
p.set_slack(slack);
p.set_num_watch(num_watch);
SASSERT(bound <= slack);
TRACE("sat", tout << "conflict " << alit << "\n";);
set_conflict(p, alit);
return l_false;
}
// swap out the watched literal.
p.set_slack(slack);
--num_watch;
SASSERT(num_watch > 0);
p.set_num_watch(num_watch);
p.swap(num_watch, index);
if (num_watch == max_index) {
max_index = index;
}
SASSERT(max_index < sz);
while (slack < bound + a_max && !s().inconsistent()) {
// variable at max-index must be assigned to true.
assign(p, p[max_index].second);
a_max = 0;
// find the next a_max among m_pb_undef
while (!m_pb_undef.empty() && l_undef != value(p[m_pb_undef.back()].second)) {
m_pb_undef.pop_back();
}
if (m_pb_undef.empty()) {
break;
}
max_index = m_pb_undef.back();
a_max = p[max_index].first;
m_pb_undef.pop_back();
}
return s().inconsistent() ? l_false : l_true;
}
void card_extension::watch_literal(pb& p, wliteral l) {
literal lit = l.second;
init_watch(lit.var());
ptr_vector<pb>* pbs = m_var_infos[lit.var()].m_pb_watch[lit.sign()];
if (pbs == 0) {
pbs = alloc(ptr_vector<pb>);
m_var_infos[lit.var()].m_pb_watch[lit.sign()] = pbs;
}
else if (is_tag_empty(pbs)) {
pbs = set_tag_non_empty(pbs);
m_var_infos[lit.var()].m_pb_watch[lit.sign()] = pbs;
}
TRACE("sat_verbose", tout << "insert: " << lit.var() << " " << lit.sign() << "\n";);
pbs->push_back(&p);
}
void card_extension::clear_watch(pb& p) {
unsigned sz = p.size();
for (unsigned i = 0; i < sz; ++i) {
unwatch_literal(p[i].second, &p);
}
}
void card_extension::unwatch_literal(literal lit, pb* p) {
if (m_var_infos.size() <= static_cast<unsigned>(lit.var())) {
return;
}
pb_watch*& pbs = m_var_infos[lit.var()].m_pb_watch[lit.sign()];
if (!is_tag_empty(pbs)) {
if (remove(*pbs, p)) {
pbs = set_tag_empty(pbs);
}
}
}
void card_extension::set_conflict(pb& p, literal lit) {
m_stats.m_num_pb_conflicts++;
TRACE("sat", display(tout, p, true); );
// SASSERT(validate_conflict(p));
SASSERT(value(lit) == l_false);
s().set_conflict(justification::mk_ext_justification(p.index()), ~lit);
SASSERT(s().inconsistent());
}
void card_extension::assign(pb& p, literal lit) {
switch (value(lit)) {
case l_true:
break;
case l_false:
set_conflict(p, lit);
break;
default:
m_stats.m_num_pb_propagations++;
m_num_propagations_since_pop++;
if (s().m_config.m_drat) {
svector<drat::premise> ps;
literal_vector lits;
get_pb_antecedents(lit, p, lits);
lits.push_back(lit);
ps.push_back(drat::premise(drat::s_ext(), p.lit()));
s().m_drat.add(lits, ps);
}
s().assign(lit, justification::mk_ext_justification(p.index()));
break;
}
}
void card_extension::display(std::ostream& out, pb& p, bool values) const {
out << p.lit() << "[" << p.size() << "]";
if (p.lit() != null_literal && values) {
out << "@(" << value(p.lit());
if (value(p.lit()) != l_undef) {
out << ":" << lvl(p.lit());
}
out << "): ";
}
else {
out << ": ";
}
for (unsigned i = 0; i < p.size(); ++i) {
literal l = p[i].second;
unsigned w = p[i].first;
if (w > 1) out << w << " * ";
out << l;
if (values) {
out << "@(" << value(l);
if (value(l) != l_undef) {
out << ":" << lvl(l);
}
out << ") ";
}
else {
out << " ";
}
}
out << ">= " << p.k() << "\n";
}
void card_extension::asserted_pb(literal l, ptr_vector<pb>* pbs, pb* p0) {
TRACE("sat", tout << l << " " << !is_tag_empty(pbs) << " " << (p0 != 0) << "\n";);
if (!is_tag_empty(pbs)) {
ptr_vector<pb>::iterator begin = pbs->begin();
ptr_vector<pb>::iterator it = begin, it2 = it, end = pbs->end();
for (; it != end; ++it) {
pb& p = *(*it);
if (p.lit() != null_literal && value(p.lit()) != l_true) {
continue;
}
switch (add_assign(p, ~l)) {
case l_false: // conflict
for (; it != end; ++it, ++it2) {
*it2 = *it;
}
SASSERT(s().inconsistent());
pbs->set_end(it2);
return;
case l_true: // unit propagation, keep watching the literal
if (it2 != it) {
*it2 = *it;
}
++it2;
break;
case l_undef: // watch literal was swapped
break;
}
}
pbs->set_end(it2);
if (pbs->empty()) {
m_var_infos[l.var()].m_pb_watch[!l.sign()] = set_tag_empty(pbs);
}
}
if (p0 != 0 && !s().inconsistent()) {
init_watch(*p0, !l.sign());
}
}
// xor:
void card_extension::copy_xor(card_extension& result) {
for (unsigned i = 0; i < m_xors.size(); ++i) {
literal_vector lits;
xor& x = *m_xors[i];
for (unsigned i = 0; i < x.size(); ++i) {
lits.push_back(x[i]);
}
bool_var v = x.lit() == null_literal ? null_bool_var : x.lit().var();
result.add_xor(v, lits);
}
}
void card_extension::clear_watch(xor& x) {
unwatch_literal(x[0], &x);
unwatch_literal(x[1], &x);
@ -200,7 +575,7 @@ namespace sat {
if (m_var_infos.size() <= static_cast<unsigned>(lit.var())) {
return;
}
xor_watch* xors = m_var_infos[lit.var()].m_xor_watch;
xor_watch*& xors = m_var_infos[lit.var()].m_xor_watch;
if (!is_tag_empty(xors)) {
if (remove(*xors, c)) {
xors = set_tag_empty(xors);
@ -355,6 +730,45 @@ namespace sat {
return s().inconsistent() ? l_false : l_true;
}
void card_extension::asserted_xor(literal l, ptr_vector<xor>* xors, xor* x) {
TRACE("sat", tout << l << " " << !is_tag_empty(xors) << " " << (x != 0) << "\n";);
if (!is_tag_empty(xors)) {
ptr_vector<xor>::iterator begin = xors->begin();
ptr_vector<xor>::iterator it = begin, it2 = it, end = xors->end();
for (; it != end; ++it) {
xor& c = *(*it);
if (c.lit() != null_literal && value(c.lit()) != l_true) {
continue;
}
switch (add_assign(c, ~l)) {
case l_false: // conflict
for (; it != end; ++it, ++it2) {
*it2 = *it;
}
SASSERT(s().inconsistent());
xors->set_end(it2);
return;
case l_undef: // watch literal was swapped
break;
case l_true: // unit propagation, keep watching the literal
if (it2 != it) {
*it2 = *it;
}
++it2;
break;
}
}
xors->set_end(it2);
if (xors->empty()) {
m_var_infos[l.var()].m_xor_watch = set_tag_empty(xors);
}
}
if (x != 0 && !s().inconsistent()) {
init_watch(*x, !l.sign());
}
}
void card_extension::normalize_active_coeffs() {
while (!m_active_var_set.empty()) m_active_var_set.erase();
@ -510,7 +924,7 @@ namespace sat {
process_card(c, offset);
++m_stats.m_num_card_resolves;
}
else {
else if (is_xor_index(index)) {
// jus.push_back(js);
m_lemma.reset();
m_bound += offset;
@ -521,6 +935,20 @@ namespace sat {
}
++m_stats.m_num_xor_resolves;
}
else if (is_pb_index(index)) {
pb& p = index2pb(index);
m_lemma.reset();
m_bound += offset;
inc_coeff(consequent, offset);
get_pb_antecedents(consequent, p, m_lemma);
for (unsigned i = 0; i < m_lemma.size(); ++i) {
process_antecedent(~m_lemma[i], offset);
}
++m_stats.m_num_pb_resolves;
}
else {
UNREACHABLE();
}
break;
}
default:
@ -758,7 +1186,7 @@ namespace sat {
}
void card_extension::add_at_least(bool_var v, literal_vector const& lits, unsigned k) {
unsigned index = 2*m_cards.size();
unsigned index = 4*m_cards.size();
literal lit = v == null_bool_var ? null_literal : literal(v, false);
card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, lit, lits, k);
m_cards.push_back(c);
@ -774,9 +1202,26 @@ namespace sat {
}
}
void card_extension::add_pb_ge(bool_var v, svector<wliteral> const& wlits, unsigned k) {
unsigned index = 4*m_pbs.size() + 0x11;
literal lit = v == null_bool_var ? null_literal : literal(v, false);
pb* p = new (memory::allocate(pb::get_obj_size(wlits.size()))) pb(index, lit, wlits, k);
m_pbs.push_back(p);
if (v == null_bool_var) {
init_watch(*p, true);
m_pb_axioms.push_back(p);
}
else {
init_watch(v);
m_var_infos[v].m_pb = p;
m_var_trail.push_back(v);
}
}
void card_extension::add_xor(bool_var v, literal_vector const& lits) {
m_has_xor = true;
unsigned index = 2*m_xors.size()+1;
unsigned index = 4*m_xors.size() + 0x01;
xor* x = new (memory::allocate(xor::get_obj_size(lits.size()))) xor(index, literal(v, false), lits);
m_xors.push_back(x);
init_watch(v);
@ -819,7 +1264,7 @@ namespace sat {
unsigned level = lvl(l);
bool_var v = l.var();
SASSERT(js.get_kind() == justification::EXT_JUSTIFICATION);
SASSERT(!is_card_index(js.get_ext_justification_idx()));
SASSERT(is_xor_index(js.get_ext_justification_idx()));
TRACE("sat", tout << l << ": " << js << "\n"; tout << s().m_trail << "\n";);
unsigned num_marks = 0;
@ -828,7 +1273,7 @@ namespace sat {
++count;
if (js.get_kind() == justification::EXT_JUSTIFICATION) {
unsigned idx = js.get_ext_justification_idx();
if (is_card_index(idx)) {
if (!is_xor_index(idx)) {
r.push_back(l);
}
else {
@ -894,6 +1339,25 @@ namespace sat {
TRACE("sat", tout << r << "\n";);
}
void card_extension::get_pb_antecedents(literal l, pb const& p, literal_vector& r) {
if (p.lit() != null_literal) r.push_back(p.lit());
SASSERT(p.lit() == null_literal || value(p.lit()) == l_true);
unsigned k = p.k();
unsigned max_sum = p.max_sum();
for (unsigned i = p.size(); i > 0 && max_sum >= k; ) {
--i;
literal lit = p[i].second;
if (lit == l) {
max_sum -= p[i].first;
}
else if (value(lit) == l_false) {
r.push_back(~p[i].second);
max_sum -= p[i].first;
}
}
SASSERT(max_sum < k);
}
void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) {
if (is_card_index(idx)) {
card& c = index2card(idx);
@ -912,7 +1376,7 @@ namespace sat {
r.push_back(~c[i]);
}
}
else {
else if (is_xor_index(idx)) {
xor& x = index2xor(idx);
if (x.lit() != null_literal) r.push_back(x.lit());
TRACE("sat", display(tout << l << " ", x, true););
@ -931,6 +1395,13 @@ namespace sat {
r.push_back(value(x[i]) == l_true ? x[i] : ~x[i]);
}
}
else if (is_pb_index(idx)) {
pb const& p = index2pb(idx);
get_pb_antecedents(l, p, r);
}
else {
UNREACHABLE();
}
}
@ -996,9 +1467,11 @@ namespace sat {
if (v >= m_var_infos.size()) return;
var_info& vinfo = m_var_infos[v];
ptr_vector<card>* cards = vinfo.m_card_watch[!l.sign()];
ptr_vector<xor>* xors = vinfo.m_xor_watch;
ptr_vector<pb>* pbs = vinfo.m_pb_watch[!l.sign()];
pb* p = vinfo.m_pb;
card* crd = vinfo.m_card;
xor* x = vinfo.m_xor;
ptr_vector<xor>* xors = vinfo.m_xor_watch;
if (!is_tag_empty(cards)) {
ptr_vector<card>::iterator begin = cards->begin();
@ -1035,51 +1508,17 @@ namespace sat {
if (crd != 0 && !s().inconsistent()) {
init_watch(*crd, !l.sign());
}
if ((!is_tag_empty(pbs) || p) && !s().inconsistent()) {
asserted_pb(l, pbs, p);
}
if (m_has_xor && !s().inconsistent()) {
asserted_xor(l, xors, x);
}
}
void card_extension::asserted_xor(literal l, ptr_vector<xor>* xors, xor* x) {
TRACE("sat", tout << l << " " << !is_tag_empty(xors) << " " << (x != 0) << "\n";);
if (!is_tag_empty(xors)) {
ptr_vector<xor>::iterator begin = xors->begin();
ptr_vector<xor>::iterator it = begin, it2 = it, end = xors->end();
for (; it != end; ++it) {
xor& c = *(*it);
if (c.lit() != null_literal && value(c.lit()) != l_true) {
continue;
}
switch (add_assign(c, ~l)) {
case l_false: // conflict
for (; it != end; ++it, ++it2) {
*it2 = *it;
}
SASSERT(s().inconsistent());
xors->set_end(it2);
return;
case l_undef: // watch literal was swapped
break;
case l_true: // unit propagation, keep watching the literal
if (it2 != it) {
*it2 = *it;
}
++it2;
break;
}
}
xors->set_end(it2);
if (xors->empty()) {
m_var_infos[l.var()].m_xor_watch = set_tag_empty(xors);
}
}
if (x != 0 && !s().inconsistent()) {
init_watch(*x, !l.sign());
}
}
check_result card_extension::check() { return CR_DONE; }
void card_extension::push() {
@ -1095,13 +1534,17 @@ namespace sat {
m_var_trail.pop_back();
if (v != null_bool_var) {
card* c = m_var_infos[v].m_card;
clear_watch(*c);
m_var_infos[v].m_card = 0;
dealloc(c);
if (c) {
clear_watch(*c);
m_var_infos[v].m_card = 0;
dealloc(c);
}
xor* x = m_var_infos[v].m_xor;
clear_watch(*x);
m_var_infos[v].m_xor = 0;
dealloc(x);
if (x) {
clear_watch(*x);
m_var_infos[v].m_xor = 0;
dealloc(x);
}
}
}
m_var_lim.resize(new_lim);
@ -1124,15 +1567,8 @@ namespace sat {
bool_var v = c.lit() == null_literal ? null_bool_var : c.lit().var();
result->add_at_least(v, lits, c.k());
}
for (unsigned i = 0; i < m_xors.size(); ++i) {
literal_vector lits;
xor& x = *m_xors[i];
for (unsigned i = 0; i < x.size(); ++i) {
lits.push_back(x[i]);
}
bool_var v = x.lit() == null_literal ? null_bool_var : x.lit().var();
result->add_xor(v, lits);
}
copy_xor(*result);
copy_pb(*result);
return result;
}
@ -1281,13 +1717,27 @@ namespace sat {
}
out << ">= " << c.k();
}
else {
else if (is_xor_index(idx)) {
xor& x = index2xor(idx);
out << "xor " << x.lit() << ": ";
for (unsigned i = 0; i < x.size(); ++i) {
out << x[i] << " ";
}
}
else if (is_pb_index(idx)) {
pb& p = index2pb(idx);
out << "pb " << p.lit() << ": ";
for (unsigned i = 0; i < p.size(); ++i) {
if (p[i].first != 1) {
out << p[i].first << " ";
}
out << p[i].second << " ";
}
out << ">= " << p.k();
}
else {
UNREACHABLE();
}
return out;
}
@ -1298,6 +1748,9 @@ namespace sat {
st.update("xor propagations", m_stats.m_num_xor_propagations);
st.update("xor conflicts", m_stats.m_num_xor_conflicts);
st.update("xor resolves", m_stats.m_num_xor_resolves);
st.update("pb propagations", m_stats.m_num_pb_propagations);
st.update("pb conflicts", m_stats.m_num_pb_conflicts);
st.update("pb resolves", m_stats.m_num_pb_resolves);
}
bool card_extension::validate_conflict(card& c) {
@ -1382,7 +1835,7 @@ namespace sat {
}
if (c.lit() != null_literal) p.push(~c.lit(), offset*c.k());
}
else {
else if (is_xor_index(index)) {
literal_vector ls;
get_antecedents(lit, index, ls);
p.reset(offset);
@ -1392,6 +1845,17 @@ namespace sat {
literal lxor = index2xor(index).lit();
if (lxor != null_literal) p.push(~lxor, offset);
}
else if (is_pb_index(index)) {
pb& pb = index2pb(index);
p.reset(pb.k());
for (unsigned i = 0; i < pb.size(); ++i) {
p.push(pb[i].second, pb[i].first);
}
if (pb.lit() != null_literal) p.push(~pb.lit(), pb.k());
}
else {
UNREACHABLE();
}
break;
}
default:

View file

@ -36,6 +36,9 @@ namespace sat {
unsigned m_num_xor_propagations;
unsigned m_num_xor_conflicts;
unsigned m_num_xor_resolves;
unsigned m_num_pb_propagations;
unsigned m_num_pb_conflicts;
unsigned m_num_pb_resolves;
stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); }
};
@ -58,6 +61,34 @@ namespace sat {
void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); }
void negate();
};
typedef std::pair<unsigned, literal> wliteral;
class pb {
unsigned m_index;
literal m_lit;
unsigned m_k;
unsigned m_size;
unsigned m_slack;
unsigned m_num_watch;
unsigned m_max_sum;
wliteral m_wlits[0];
public:
static size_t get_obj_size(unsigned num_lits) { return sizeof(card) + num_lits * sizeof(wliteral); }
pb(unsigned index, literal lit, svector<wliteral> const& wlits, unsigned k);
unsigned index() const { return m_index; }
literal lit() const { return m_lit; }
wliteral operator[](unsigned i) const { return m_wlits[i]; }
unsigned k() const { return m_k; }
unsigned size() const { return m_size; }
unsigned slack() const { return m_slack; }
void set_slack(unsigned s) { m_slack = s; }
unsigned num_watch() const { return m_num_watch; }
unsigned max_sum() const { return m_max_sum; }
void set_num_watch(unsigned s) { m_num_watch = s; }
void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); }
void negate();
};
class xor {
unsigned m_index;
@ -85,20 +116,28 @@ namespace sat {
typedef ptr_vector<card> card_watch;
typedef ptr_vector<xor> xor_watch;
typedef ptr_vector<pb> pb_watch;
struct var_info {
card_watch* m_card_watch[2];
pb_watch* m_pb_watch[2];
xor_watch* m_xor_watch;
card* m_card;
pb* m_pb;
xor* m_xor;
var_info(): m_xor_watch(0), m_card(0), m_xor(0) {
var_info(): m_xor_watch(0), m_card(0), m_xor(0), m_pb(0) {
m_card_watch[0] = 0;
m_card_watch[1] = 0;
m_pb_watch[0] = 0;
m_pb_watch[1] = 0;
}
void reset() {
dealloc(m_card);
dealloc(m_xor);
dealloc(m_pb);
dealloc(card_extension::set_tag_non_empty(m_card_watch[0]));
dealloc(card_extension::set_tag_non_empty(m_card_watch[1]));
dealloc(card_extension::set_tag_non_empty(m_pb_watch[0]));
dealloc(card_extension::set_tag_non_empty(m_pb_watch[1]));
dealloc(card_extension::set_tag_non_empty(m_xor_watch));
}
};
@ -125,8 +164,10 @@ namespace sat {
ptr_vector<card> m_cards;
ptr_vector<xor> m_xors;
ptr_vector<pb> m_pbs;
scoped_ptr_vector<card> m_card_axioms;
scoped_ptr_vector<pb> m_pb_axioms;
// watch literals
svector<var_info> m_var_infos;
@ -145,6 +186,9 @@ namespace sat {
bool m_has_xor;
unsigned_vector m_parity_marks;
literal_vector m_parity_trail;
unsigned_vector m_pb_undef;
void ensure_parity_size(bool_var v);
unsigned get_parity(bool_var v);
void inc_parity(bool_var v);
@ -163,6 +207,7 @@ namespace sat {
void unwatch_literal(literal w, card* c);
// xor specific functionality
void copy_xor(card_extension& result);
void clear_watch(xor& x);
void watch_literal(xor& x, literal lit);
void unwatch_literal(literal w, xor* x);
@ -172,11 +217,28 @@ namespace sat {
bool parity(xor const& x, unsigned offset) const;
lbool add_assign(xor& x, literal alit);
void asserted_xor(literal l, ptr_vector<xor>* xors, xor* x);
void get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r);
bool is_card_index(unsigned idx) const { return 0 == (idx & 0x1); }
card& index2card(unsigned idx) const { SASSERT(is_card_index(idx)); return *m_cards[idx >> 1]; }
xor& index2xor(unsigned idx) const { SASSERT(!is_card_index(idx)); return *m_xors[idx >> 1]; }
void get_xor_antecedents(literal l, unsigned inddex, justification js, literal_vector& r);
bool is_card_index(unsigned idx) const { return 0x00 == (idx & 0x11); }
bool is_xor_index(unsigned idx) const { return 0x01 == (idx & 0x11); }
bool is_pb_index(unsigned idx) const { return 0x11 == (idx & 0x11); }
card& index2card(unsigned idx) const { SASSERT(is_card_index(idx)); return *m_cards[idx >> 2]; }
xor& index2xor(unsigned idx) const { SASSERT(!is_card_index(idx)); return *m_xors[idx >> 2]; }
pb& index2pb(unsigned idx) const { SASSERT(is_pb_index(idx)); return *m_pbs[idx >> 2]; }
// pb functionality
void copy_pb(card_extension& result);
void asserted_pb(literal l, ptr_vector<pb>* pbs, pb* p);
void init_watch(pb& p, bool is_true);
lbool add_assign(pb& p, literal alit);
void watch_literal(pb& p, wliteral lit);
void clear_watch(pb& p);
void set_conflict(pb& p, literal lit);
void assign(pb& p, literal l);
void unwatch_literal(literal w, pb* p);
void get_pb_antecedents(literal l, pb const& p, literal_vector & r);
template<typename T>
@ -224,6 +286,7 @@ namespace sat {
void display(std::ostream& out, ineq& p) const;
void display(std::ostream& out, card& c, bool values) const;
void display(std::ostream& out, pb& p, bool values) const;
void display(std::ostream& out, xor& c, bool values) const;
void display_watch(std::ostream& out, bool_var v) const;
void display_watch(std::ostream& out, bool_var v, bool sign) const;
@ -233,6 +296,7 @@ namespace sat {
virtual ~card_extension();
virtual void set_solver(solver* s) { m_solver = s; }
void add_at_least(bool_var v, literal_vector const& lits, unsigned k);
void add_pb_ge(bool_var v, svector<wliteral> const& wlits, unsigned k);
void add_xor(bool_var v, literal_vector const& lits);
virtual void propagate(literal l, ext_constraint_idx idx, bool & keep);
virtual bool resolve_conflict();

View file

@ -96,7 +96,6 @@ namespace sat {
if (!process(c))
continue; // clause was removed
*it2 = *it;
// throw exception to test bug fix: if (it2 != it) throw solver_exception("trigger bug");
++it2;
}
s.m_clauses.set_end(it2);
@ -129,14 +128,14 @@ namespace sat {
// check if the clause is already satisfied
for (i = 0; i < sz; i++) {
if (s.value(c[i]) == l_true) {
s.dettach_clause(c);
s.detach_clause(c);
s.del_clause(c);
return false;
}
}
// try asymmetric branching
// clause must not be used for propagation
s.dettach_clause(c);
solver::scoped_detach scoped_d(s, c);
s.push();
for (i = 0; i < sz - 1; i++) {
literal l = c[i];
@ -154,7 +153,6 @@ namespace sat {
SASSERT(s.m_qhead == s.m_trail.size());
if (i == sz - 1) {
// clause size can't be reduced.
s.attach_clause(c);
return true;
}
// clause can be reduced
@ -190,14 +188,14 @@ namespace sat {
case 1:
TRACE("asymm_branch", tout << "produced unit clause: " << c[0] << "\n";);
s.assign(c[0], justification());
s.del_clause(c);
s.propagate_core(false);
scoped_d.del_clause();
SASSERT(s.inconsistent() || s.m_qhead == s.m_trail.size());
return false; // check_missed_propagation() may fail, since m_clauses is not in a consistent state.
case 2:
SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef);
s.mk_bin_clause(c[0], c[1], false);
s.del_clause(c);
scoped_d.del_clause();
SASSERT(s.m_qhead == s.m_trail.size());
return false;
default:

561
src/sat/sat_ccc.cpp Normal file
View file

@ -0,0 +1,561 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
sat_ccc.cpp
Abstract:
A variant of Concurrent Cube and Conquer
Author:
Nikolaj Bjorner (nbjorner) 2017-4-17
Notes:
The cube process spawns conquer threads to search parts of the
state space.
The conquer threads have two modes:
- emulation mode - where they try to outpace the cuber on the same search tree
- complement mode - where they solve a sub-branch not yet explored by the cuber.
When the conquer thread returns a solved cube it is processed in the following ways:
- ignore if solved_id \not\in decisions
- mark d as closed if d \in decisions, such that d is marked by solved id
- backjump otherwise, conquer thread has solved a branch attempted by the cuber
--*/
#include "sat_solver.h"
#include "sat_lookahead.h"
#include "sat_ccc.h"
using namespace sat;
// ------------
// cuber
ccc::cuber::cuber(ccc& c): m_ccc(c), lh(c.m_s), m_branch_id(0) {}
lbool ccc::cuber::search() {
m_branch_id = 0;
m_last_closure_level = 1000;
lh.init_search();
lh.m_model.reset();
lookahead::scoped_level _sl(lh, lh.c_fixed_truth);
lh.m_search_mode = lookahead_mode::searching;
lbool r = research();
if (r == l_true) {
m_ccc.m_model = lh.get_model();
}
lh.collect_statistics(m_ccc.m_lh_stats);
return r;
}
lbool ccc::cuber::research() {
m_ccc.m_s.checkpoint();
if (lh.inconsistent()) {
return l_false;
}
if (get_solved()) {
return l_false;
}
lh.inc_istamp();
literal l = lh.choose();
if (lh.inconsistent()) {
return l_false;
}
if (l == null_literal) {
return l_true;
}
if (!decisions.empty()) {
m_ccc.put_decision(decisions.back());
}
// update trail and decisions
++lh.m_stats.m_decisions;
unsigned parent_id = decisions.empty() ? 0 : decisions.back().m_id;
unsigned spawn_id = spawn_conquer();
unsigned branch1 = m_branch_id++;
unsigned branch2 = m_branch_id++;
decision d(branch1, decisions.size() + 1, l, parent_id, spawn_id);
decisions.push_back(d);
IF_VERBOSE(1, d.pp(verbose_stream() << "select " << m_last_closure_level << " ") << "\n";);
IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << "\n";);
IF_VERBOSE(2, pp(verbose_stream(), decisions) << "\n"; );
TRACE("sat", tout << "choose: " << l << "\n";);
lh.push(l, lh.c_fixed_truth);
lbool r = research();
if (r == l_false) {
lh.pop();
if (decisions.back().is_closed()) {
// branch was solved by a spawned conquer process
IF_VERBOSE(1, decisions.back().pp(verbose_stream() << "closed ") << "\n";);
r = l_false;
decisions.pop_back();
}
else {
if (spawn_id > 0) {
free_conquer(spawn_id);
m_last_closure_level *= 3;
m_last_closure_level /= 4;
}
lh.inc_istamp();
lh.flip_prefix();
lh.push(~l, lh.c_fixed_truth);
decisions.back().negate();
decisions.back().m_id = branch2;
decisions.back().m_spawn_id = 0;
r = research();
if (r == l_false) {
lh.pop();
decisions.pop_back();
}
}
}
return r;
}
void ccc::cuber::update_closure_level(decision const& d, int offset) {
m_last_closure_level = (d.m_depth + 3*m_last_closure_level) / 4;
if (m_last_closure_level >= static_cast<unsigned>(abs(offset))) {
m_last_closure_level += offset;
}
}
unsigned ccc::cuber::spawn_conquer() {
unsigned result = 0;
//
// decisions must have been solved at a higher level by a conquer thread
//
if (!m_free_threads.empty()) {
if (m_last_closure_level <= decisions.size()) {
result = m_free_threads.back();
++m_ccc.m_ccc_stats.m_spawn_opened;
m_free_threads.pop_back();
}
else {
IF_VERBOSE(1, verbose_stream() << m_last_closure_level << " " << decisions.size() << "\n";);
}
}
return result;
}
void ccc::cuber::free_conquer(unsigned id) {
if (id != 0) {
m_free_threads.push_back(id);
}
}
bool ccc::cuber::get_solved() {
// check if CDCL solver got ahead.
bool do_pop = false;
solution sol;
while (true) {
bool is_empty = true;
#pragma omp critical (ccc_solved)
{
if (do_pop) m_ccc.m_solved.pop_front();
if (!m_ccc.m_solved.empty()) {
sol = m_ccc.m_solved.top();
is_empty = false;
}
}
if (is_empty) {
return false;
}
do_pop = true;
unsigned branch_id = sol.m_branch_id;
unsigned thread_id = sol.m_thread_id;
bool found = false;
for (unsigned i = decisions.size(); i > 0; ) {
--i;
decision& d = decisions[i];
if (branch_id == d.m_id) {
if (d.m_spawn_id == thread_id && thread_id != 0) {
SASSERT(d.m_spawn_id > 0);
IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": spawn close ") << "\n";);
++m_ccc.m_ccc_stats.m_spawn_closed;
d.close();
free_conquer(thread_id);
update_closure_level(d, -1);
break;
}
else {
IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": conquer ") << "\n";);
++m_ccc.m_ccc_stats.m_cdcl_closed;
update_closure_level(d, 1);
return true;
}
}
// branch is even, d has moved to the next branch
if (branch_id == (d.m_id & ~0x1) && d.m_spawn_id == thread_id && thread_id != 0) {
IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": spawn conquer ") << "\n";);
++m_ccc.m_ccc_stats.m_cdcl_closed;
update_closure_level(d, 1);
return true;
}
}
}
}
// ---------------------
// conquer state machine
lbool ccc::conquer::search() {
try {
if (s.inconsistent()) return l_false;
s.init_search();
s.propagate(false);
if (s.inconsistent()) return l_false;
s.cleanup();
s.simplify_problem();
if (s.inconsistent()) return l_false;
while (true) {
SASSERT(!s.inconsistent());
lbool r = bounded_search();
if (r != l_undef)
return r;
s.restart();
s.simplify_problem();
if (s.check_inconsistent()) return l_false;
s.gc();
}
}
catch (solver::abort_solver) {
return l_undef;
}
}
void ccc::conquer::replay_decisions() {
s.propagate(true);
for (unsigned i = s.scope_lvl(); !s.inconsistent() && i < decisions.size(); ++i) {
decision const& d = decisions[i];
IF_VERBOSE(2, verbose_stream() << thread_id << ": replay " << d.get_literal(thread_id) << " " << s.value(d.get_literal(thread_id)) << "\n";);
if (!push_decision(d)) {
// negation of decision is implied.
IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": backjump to level " << i << " ") << "\n";);
while (decisions.size() > i) {
pop_decision(decisions.back());
decisions.pop_back();
}
break;
}
if (d.m_spawn_id == thread_id && d.is_left()) {
// we pushed the right branch on this thread.
IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": skip left branch on level " << i + 1 << " ") << "\n";);
break;
}
}
}
void ccc::conquer::pop_decision(decision const& d) {
unsigned tid = 0;
if (d.is_spawned(thread_id)) {
tid = thread_id;
m_spawned = false;
IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": retire spawn ") << "\n";);
}
#pragma omp critical (ccc_solved)
{
m_ccc.m_solved.push(solution(tid, d.m_id));
}
}
bool ccc::conquer::push_decision(decision const& d) {
literal lit = d.get_literal(thread_id);
switch (s.value(lit)) {
case l_false:
//TBD:
s.m_restart_threshold = s.m_config.m_restart_initial;
//s.m_conflicts_since_last_restart = 0;
return false;
case l_true:
s.push();
break;
case l_undef:
s.push();
s.assign(lit, justification());
s.propagate(true);
break;
}
m_spawned |= d.is_spawned(thread_id);
return true;
}
bool ccc::conquer::cube_decision() {
decision d;
bool use_cube_decision = false;
SASSERT(s.m_qhead == s.m_trail.size());
while (true) {
if (!m_ccc.get_decision(thread_id, d)) {
return false;
}
if (d.is_spawned(thread_id)) IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << " ") << "\n";);
if (!decisions.empty() && decisions.back().m_depth + 1 < d.m_depth) {
if (d.is_spawned(thread_id)) {
pop_decision(d);
}
}
else {
break;
}
}
SASSERT(decisions.empty() || decisions.back().m_depth + 1 >= d.m_depth);
if (!decisions.empty() && decisions.back().is_spawned(thread_id) && decisions.back().m_depth == d.m_depth) {
SASSERT(d.m_spawn_id == 0);
SASSERT(decisions.back().is_left());
SASSERT(!d.is_left());
IF_VERBOSE(1, verbose_stream() << thread_id << " inherit spawn\n";);
decisions.back().m_spawn_id = 0;
m_spawned = false;
}
SASSERT(decisions.empty() || decisions.back().m_depth + 1 >= d.m_depth);
while (!decisions.empty() && decisions.back().m_depth >= d.m_depth) {
// check_non_model("cube decision", decisions);
if (decisions.back().is_spawned(thread_id)) {
pop_decision(decisions.back());
}
decisions.pop_back();
}
SASSERT(decisions.empty() || decisions.back().m_depth + 1 == d.m_depth);
SASSERT(decisions.empty() || decisions.back().m_id == d.m_parent);
if (m_spawned) {
decisions.push_back(d);
return true;
}
s.pop_reinit(s.scope_lvl() - decisions.size());
SASSERT(s.m_qhead == s.m_trail.size());
SASSERT(s.scope_lvl() == decisions.size());
literal lit = d.get_literal(thread_id);
IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": cube ") << "\n";);
IF_VERBOSE(2, pp(verbose_stream() << thread_id << ": push ", decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n";
if (s.value(lit) == l_false) verbose_stream() << "level: " << s.lvl(lit) << "\n";);
if (push_decision(d)) {
decisions.push_back(d);
}
else {
pop_decision(d);
}
return true;
}
lbool ccc::conquer::bounded_search() {
while (true) {
s.checkpoint();
bool done = false;
while (!done) {
replay_decisions();
lbool is_sat = s.propagate_and_backjump_step(done);
if (is_sat != l_true) return is_sat;
}
s.gc();
if (!cube_decision() && !s.decide()) {
lbool is_sat = s.final_check();
if (is_sat != l_undef) {
return is_sat;
}
}
}
}
// --------------
// shared state
std::ostream& ccc::decision::pp(std::ostream& out) const {
out << "("
<< "id:" << m_id
<< " l:" << m_literal
<< " d:" << m_depth;
if (m_spawn_id != 0) {
out << " s:" << m_spawn_id;
}
out << ") ";
return out;
}
std::ostream& ccc::pp(std::ostream& out, svector<decision> const& v) {
for (unsigned i = 0; i < v.size(); ++i) {
v[i].pp(out);
}
return out;
}
bool ccc::get_decision(unsigned thread_id, decision& d) {
SASSERT(0 < thread_id && thread_id <= m_decisions.size());
bool result = false;
#pragma omp critical (ccc_decisions)
{
if (!m_decisions[thread_id - 1].empty()) {
d = m_decisions[thread_id - 1].pop_front();
result = true;
}
}
return result;
}
void ccc::put_decision(decision const& d) {
for (unsigned i = 0; i < m_num_conquer; ++i) {
#pragma omp critical (ccc_decisions)
{
while (false && !m_decisions[i].empty()) { // introduces contention.
decision d = m_decisions[i].back();
if (d.m_depth < d.m_depth || d.m_spawn_id != 0) {
break;
}
m_decisions[i].pop_back();
}
m_decisions[i].push(d);
}
}
}
lbool ccc::search() {
enum par_exception_kind {
DEFAULT_EX,
ERROR_EX
};
// set_model();
m_cancel = false;
scoped_limits scoped_rlimit(m_s.rlimit());
ptr_vector<conquer> solvers;
int finished_id = -1;
std::string ex_msg;
par_exception_kind ex_kind;
unsigned error_code = 0;
lbool result = l_undef;
m_decisions.reset();
cuber cuber(*this);
m_num_conquer = m_s.m_config.m_num_threads;
int num_threads = 1 + m_num_conquer; // for ccc-infinity only two threads.
for (int i = 1; i < num_threads; ++i) {
m_s.m_params.set_uint("random_seed", m_s.m_rand());
conquer* s1 = alloc(conquer, *this, m_s.m_params, i);
solvers.push_back(s1);
s1->s.copy(m_s);
scoped_rlimit.push_child(&(s1->m_limit));
m_decisions.push_back(queue<decision>());
}
for (unsigned i = 1; i < m_num_conquer; ++i) {
cuber.m_free_threads.push_back(i);
}
#pragma omp parallel for
for (int i = 0; i < num_threads; ++i) {
try {
lbool r = l_undef;
if (i == 0) {
r = cuber.search();
}
else {
r = solvers[i-1]->search();
}
bool first = false;
#pragma omp critical (par_solver)
{
if (finished_id == -1) {
finished_id = i;
first = true;
result = r;
}
}
if (first) {
for (unsigned j = 0; j < solvers.size(); ++j) {
solvers[j]->m_limit.cancel();
}
// cancel lookahead solver:
m_cancel = true;
}
}
catch (z3_error & err) {
error_code = err.error_code();
ex_kind = ERROR_EX;
}
catch (z3_exception & ex) {
ex_msg = ex.msg();
ex_kind = DEFAULT_EX;
}
}
if (finished_id > 0 && result == l_true) {
// set model from auxiliary solver
m_model = solvers[finished_id - 1]->s.get_model();
}
for (unsigned i = 0; i < solvers.size(); ++i) {
solvers[i]->s.collect_statistics(m_lh_stats);
dealloc(solvers[i]);
}
if (finished_id == -1) {
switch (ex_kind) {
case ERROR_EX: throw z3_error(error_code);
default: throw default_exception(ex_msg.c_str());
}
}
#if 0
if (result == l_true) {
for (unsigned i = 1; i < m_model.size(); ++i) {
std::cout << "push_model(" << i << ", " << (m_model[i] > 0 ? "false" : "true") << ");\n";
}
}
#endif
return result;
}
#if 0
void ccc::push_model(unsigned v, bool sign) {
if (m_values.size() <= v) {
m_values.resize(v + 1);
}
m_values[v] = sign;
}
void ccc::check_non_model(char const* fn, svector<decision> const& decisions) {
for (unsigned i = 0; i < decisions.size(); ++i) {
decision d = decisions[i];
literal lit = d.m_literal;
if (m_values[lit.var()] != lit.sign()) return;
}
IF_VERBOSE(1, pp(verbose_stream() << "backtracking from model " << fn << " ", decisions) << "\n";);
}
#endif

146
src/sat/sat_ccc.h Normal file
View file

@ -0,0 +1,146 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
sat_ccc.h
Abstract:
A variant of Concurrent Cube and Conquer
Author:
Nikolaj Bjorner (nbjorner) 2017-4-17
Notes:
--*/
#ifndef _SAT_CCC_H_
#define _SAT_CCC_H_
#include "queue.h"
namespace sat {
class ccc {
struct decision {
unsigned m_id; // unique identifier for decision
unsigned m_depth; // depth of decision
literal m_literal; // decision literal
unsigned m_parent; // id of parent
int m_spawn_id; // thread id of conquer thread processing complented branch.
// = 0 if not spawned.
// > 0 if active spawn is in progress
// < 0 if thread has closed the branch
decision(unsigned id, unsigned d, literal last, unsigned parent_id, unsigned spawn):
m_id(id), m_depth(d), m_literal(last), m_parent(parent_id), m_spawn_id(spawn) {}
decision():
m_id(0), m_depth(0), m_literal(null_literal), m_parent(0), m_spawn_id(0) {}
void close() { SASSERT(m_spawn_id > 0); m_spawn_id = -m_spawn_id; }
bool is_closed() const { return m_spawn_id < 0; }
void negate() { m_literal.neg(); }
bool is_left() const { return 0 == (m_id & 0x1); }
bool is_spawned(unsigned thread_id) const { return m_spawn_id == thread_id; }
// the left branch has an even branch_id.
// the branch is spawned if it is even and the spawn_id is the same as the thread_id, and furthermore it is exploring the left branch.
// it may explore the right branch, but is then not in a spawned mode.
// we retain the spawn id so that the spawned thread can be re-spun.
literal get_literal(unsigned thread_id) const { return ((m_id & 0x1) == 0 && thread_id == m_spawn_id) ? ~m_literal : m_literal; }
std::ostream& pp(std::ostream& out) const;
};
struct solution {
unsigned m_thread_id;
unsigned m_branch_id;
solution(unsigned t, unsigned s): m_thread_id(t), m_branch_id(s) {}
solution(): m_thread_id(0), m_branch_id(0) {}
};
struct stats {
unsigned m_spawn_closed;
unsigned m_spawn_opened;
unsigned m_cdcl_closed;
stats() { reset(); }
void reset() {
memset(this, 0, sizeof(*this));
}
};
struct conquer {
reslimit m_limit;
ccc& m_ccc;
solver s;
svector<decision> decisions;
unsigned thread_id;
bool m_spawned;
conquer(ccc& super, params_ref const& p, unsigned tid): m_ccc(super), s(p, m_limit), thread_id(tid), m_spawned(false) {}
lbool search();
bool cube_decision();
lbool bounded_search();
bool push_decision(decision const& d);
void pop_decision(decision const& d);
void replay_decisions();
};
struct cuber {
ccc& m_ccc;
lookahead lh;
unsigned m_branch_id;
unsigned m_last_closure_level;
unsigned_vector m_free_threads;
svector<decision> decisions;
cuber(ccc& c);
lbool search();
lbool research();
bool get_solved();
void update_closure_level(decision const& d, int offset);
unsigned spawn_conquer();
void free_conquer(unsigned thread_id);
};
solver& m_s;
queue<solution> m_solved;
vector<queue<decision> > m_decisions;
unsigned m_num_conquer;
model m_model;
volatile bool m_cancel;
::statistics m_lh_stats;
stats m_ccc_stats;
void put_decision(decision const& d);
bool get_decision(unsigned thread_id, decision& d);
static std::ostream& pp(std::ostream& out, svector<decision> const& v);
void push_model(unsigned v, bool sign);
void set_model();
bool trail_in_model(literal_vector const& trail) const;
void check_non_model(char const* fn, svector<decision> const& decisions);
public:
ccc(solver& s): m_s(s) {}
lbool search();
model const& get_model() const { return m_model; }
void collect_statistics(::statistics& st) {
st.copy(m_lh_stats);
st.update("ccc-spawn-closed", m_ccc_stats.m_spawn_closed);
st.update("ccc-cdcl-closed", m_ccc_stats.m_cdcl_closed);
st.update("ccc-spawn-opened", m_ccc_stats.m_spawn_opened);
}
};
}
#endif

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