3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-26 18:45:33 +00:00

Merge branch 'master' of https://github.com/Z3Prover/z3 into new-ml-api

This commit is contained in:
Christoph M. Wintersteiger 2016-03-31 18:11:30 +01:00
commit b178420797
174 changed files with 9762 additions and 2502 deletions

2
.gitignore vendored
View file

@ -84,3 +84,5 @@ src/CMakeLists.txt
src/*/CMakeLists.txt
src/*/*/CMakeLists.txt
src/*/*/*/CMakeLists.txt
src/api/dotnet/cmake_install_gac.cmake.in
src/api/dotnet/cmake_uninstall_gac.cmake.in

View file

@ -105,7 +105,7 @@ else()
message(STATUS "CMAKE_BUILD_TYPE is not set. Setting default")
message(STATUS "The available build types are: ${available_build_types}")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE String
"Options are ${build_types}"
"Options are ${available_build_types}"
FORCE)
# Provide drop down menu options in cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${available_build_types})
@ -239,6 +239,7 @@ if (OPENMP_FOUND)
else()
list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_NO_OMP_")
message(STATUS "Not using OpenMP")
set(USE_OPENMP OFF CACHE BOOL "Use OpenMP" FORCE)
endif()
################################################################################
@ -288,15 +289,16 @@ endif()
################################################################################
# Tracing
################################################################################
option(ENABLE_TRACING OFF "Enable tracing")
if (ENABLE_TRACING)
option(ENABLE_TRACING_FOR_NON_DEBUG "Enable tracing in non-debug builds." OFF)
if (ENABLE_TRACING_FOR_NON_DEBUG)
list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_TRACE")
else()
# Tracing is always enabled in debug builds
list(APPEND Z3_COMPONENT_CXX_DEFINES $<$<CONFIG:Debug>:_TRACE>)
endif()
# Should we always enable tracing when doing a debug build?
#list(APPEND Z3_COMPONENT_CXX_DEFINES $<$<CONFIG:Debug>:_TRACE>)
################################################################################
# Postion indepdent code
# Postion independent code
################################################################################
# This is required because code built in the components will end up in a shared
# library. If not building a shared library ``-fPIC`` isn't needed and would add
@ -320,9 +322,36 @@ message(STATUS "Z3_DEPENDENT_EXTRA_C_LINK_FLAGS: ${Z3_DEPENDENT_EXTRA_C_LINK_FLA
################################################################################
# Z3 installation locations
################################################################################
set (Z3_INSTALL_LIB_DIR "lib")
set (Z3_INSTALL_BIN_DIR "bin")
set (Z3_INSTALL_INCLUDE_DIR "include")
include(GNUInstallDirs)
set(CMAKE_INSTALL_PKGCONFIGDIR
"${CMAKE_INSTALL_LIBDIR}/pkgconfig"
CACHE
PATH
"Directory to install pkgconfig 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}\"")
################################################################################
# Uninstall rule
################################################################################
configure_file(
"${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
@ONLY
)
# Target needs to be declared before the components so that they can add
# dependencies to this target so they can run their own custom uninstall rules.
add_custom_target(uninstall
COMMAND
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
COMMENT "Uninstalling..."
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
VERBATIM
)
################################################################################
# CMake build file locations
@ -333,6 +362,17 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
################################################################################
# Extra dependencies for build rules that use the Python infrastructure to
# generate files used for Z3's build. Changes to these files will trigger
# a rebuild of all the generated files.
################################################################################
# Note: ``update_api.py`` is deliberately not here because it not used
# to generate every generated file. The targets that need it list it explicitly.
set(Z3_GENERATED_FILE_EXTRA_DEPENDENCIES
"${CMAKE_SOURCE_DIR}/scripts/mk_genfile_common.py"
)
################################################################################
# Z3 components, library and executables
################################################################################
@ -348,19 +388,3 @@ if (ENABLE_EXAMPLE_TARGETS)
add_subdirectory(examples)
endif()
################################################################################
# Uninstall rule
################################################################################
configure_file(
"${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
@ONLY
)
add_custom_target(uninstall
COMMAND
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
COMMENT "Uninstalling..."
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
VERBATIM
)

View file

@ -261,14 +261,24 @@ when invoking CMake and instead set the build type within Visual Studio itself.
The following useful options can be passed to CMake whilst configuring.
* ``CMAKE_BUILD_TYPE`` - STRING. The build type to use. Only relevant for single configuration generators (e.g. "Unix Makefile" and "Ninja").
* ``CMAKE_INSTALL_PREFIX`` - STRING. The install prefix to use (e.g. ``/usr/local/``)
* ``ENABLE_TRACING`` - BOOL. If set to ``TRUE`` enable tracing, if set to ``FALSE`` disable tracing.
* ``CMAKE_INSTALL_BINDIR`` - STRING. The path to install z3 binaries (relative to ``CMAKE_INSTALL_PREFIX``), e.g. ``bin``.
* ``CMAKE_INSTALL_INCLUDEDIR`` - STRING. The path to install z3 include files (relative to ``CMAKE_INSTALL_PREFIX``), e.g. ``include``.
* ``CMAKE_INSTALL_LIBDIR`` - STRING. The path to install z3 libraries (relative to ``CMAKE_INSTALL_PREFIX``), e.g. ``lib``.
* ``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.
* ``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.
* ``USE_OPENMP`` - BOOL. If set to ``TRUE`` and OpenMP support is detected build with OpenMP support.
* ``USE_LIB_GMP`` - BOOL. If set to ``TRUE`` use the GNU multiple precision library. If set to ``FALSE`` use an internal implementation.
* ``PYTHON_EXECUTABLE`` - STRING. The python executable to use during the build.
* ``BUILD_PYTHON_BINDINGS`` - BOOL. If set to ``TRUE`` then Z3's python bindings will be built.
* ``INSTALL_PYTHON_BINDINGS`` - BOOL. If set to ``TRUE`` and ``BUILD_PYTHON_BINDINGS`` is ``TRUE`` then running the ``install`` target will install Z3's Python bindings.
* ``BUILD_DOTNET_BINDINGS`` - BOOL. If set to ``TRUE`` then Z3's .NET bindings will be built.
* ``INSTALL_DOTNET_BINDINGS`` - BOOL. If set to ``TRUE`` and ``BUILD_DOTNET_BINDINGS`` is ``TRUE`` then running the ``install`` target will install Z3's .NET bindings.
* ``DOTNET_CSC_EXECUTABLE`` - STRING. The path to the C# compiler to use. Only relevant if ``BUILD_DOTNET_BINDINGS`` is set to ``TRUE``.
* ``DOTNET_GACUTIL_EXECUTABLE`` - STRING. The path to the gacutil program to use. Only relevant if ``BUILD_DOTNET_BINDINGS`` is set to ``TRUE``.
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.
@ -322,8 +332,9 @@ in order to be sure that the copied CMake files are not out of date.
### Install/Uninstall
Install and uninstall targets are supported. Use ``CMAKE_INSTALL_PREFIX`` to set the install
prefix.
Install and uninstall targets are supported. Use ``CMAKE_INSTALL_PREFIX`` to
set the install prefix. If you also need need to control which directories are
used for install set the documented ``CMAKE_INSTALL_*`` options.
To install run

View file

@ -3,14 +3,17 @@
Z3 is a theorem prover from Microsoft Research. It is licensed
under the [MIT license](LICENSE.txt).
Z3 can be built using [Visual Studio][1] or a [Makefile][2]. It provides
[bindings for several programming languages][3].
If you are not familiar with Z3, you can start [here](https://github.com/Z3Prover/z3/wiki#background).
Z3 can be built using [Visual Studio][1], a [Makefile][2] or using [CMake][3]. It provides
[bindings for several programming languages][4].
See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z3.
[1]: #building-z3-on-windows-using-visual-studio-command-prompt
[2]: #building-z3-using-make-and-gccclang
[3]: #z3-bindings
[3]: #building-z3-using-cmake
[4]: #z3-bindings
## Building Z3 on Windows using Visual Studio Command Prompt

View file

@ -1,6 +1,6 @@
# 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 make sure ``-DNDEBUG`` is never set by default.
# 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)
@ -9,19 +9,25 @@ 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 but -DNDEBUG is removed
# 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")
set(CMAKE_${_lang}_FLAGS_RELEASE_INIT "-O3")
set(CMAKE_${_lang}_FLAGS_RELWITHDEBINFO_INIT "-O2 -g")
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")
set(CMAKE_${_lang}_FLAGS_RELEASE_INIT "/MT /O2 /Ob2")
set(CMAKE_${_lang}_FLAGS_RELWITHDEBINFO_INIT "/MT /Zi /O2 /Ob1")
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")

View file

@ -0,0 +1,53 @@
# Tries to find a working .NET tool chain
#
# Once complete this will define
# DOTNET_TOOLCHAIN_FOUND : BOOL : System has a .NET toolchain
# DOTNET_CSC_EXECUTABLE - STRING : Path to C# compiler
# DOTNET_GACUTIL_EXECUTABLE - STRING : Path to gacutil
# DOTNET_TOOLCHAIN_IS_MONO : BOOL : True if detected .NET toolchain is Mono
# DOTNET_TOOLCHAIN_IS_WINDOWS : BOOL : True if detected .NET toolchain is native Windows
include(FindPackageHandleStandardArgs)
find_program(
DOTNET_CSC_EXECUTABLE
NAMES "csc.exe" "mcs" "dmcs"
)
message(STATUS "DOTNET_CSC_EXECUTABLE: \"${DOTNET_CSC_EXECUTABLE}\"")
find_program(
DOTNET_GACUTIL_EXECUTABLE
NAMES "gacutil.exe" "gacutil"
)
message(STATUS "DOTNET_GACUTIL_EXECUTABLE: \"${DOTNET_GACUTIL_EXECUTABLE}\"")
# Try to determine the tool chain vendor
set(DOTNET_DETERMINED_VENDOR FALSE)
if (DOTNET_CSC_EXECUTABLE)
execute_process(COMMAND "${DOTNET_CSC_EXECUTABLE}" "/help"
RESULT_VARIABLE CSC_EXIT_CODE
OUTPUT_VARIABLE CSC_STD_OUT
)
if (${CSC_EXIT_CODE} EQUAL 0)
if ("${CSC_STD_OUT}" MATCHES "^Mono[ ]+C#")
set(DOTNET_DETERMINED_VENDOR TRUE)
set(DOTNET_TOOLCHAIN_IS_MONO TRUE)
set(DOTNET_TOOLCHAIN_IS_WINDOWS FALSE)
message(STATUS ".NET toolchain is Mono")
elseif ("${CSC_STD_OUT}" MATCHES "^Microsoft.+Visual[ ]+C#")
set(DOTNET_DETERMINED_VENDOR TRUE)
set(DOTNET_TOOLCHAIN_IS_MONO FALSE)
set(DOTNET_TOOLCHAIN_IS_WINDOWS TRUE)
message(STATUS ".NET toolchain is Windows native")
else()
message(STATUS ".NET toolchain is unknown")
endif()
endif()
endif()
# TODO: Check C# compiler works
find_package_handle_standard_args(DotNetToolChain DEFAULT_MSG
DOTNET_CSC_EXECUTABLE
DOTNET_GACUTIL_EXECUTABLE
DOTNET_DETERMINED_VENDOR
)

View file

@ -104,7 +104,8 @@ macro(z3_add_component component_name)
add_custom_command(OUTPUT "${_output_file}"
COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/scripts/pyg2hpp.py" "${_full_pyg_file_path}" "${CMAKE_CURRENT_BINARY_DIR}"
MAIN_DEPENDENCY "${_full_pyg_file_path}"
DEPENDS "${CMAKE_SOURCE_DIR}/scripts/pyg2hpp.py" "${CMAKE_SOURCE_DIR}/scripts/mk_util.py"
DEPENDS "${CMAKE_SOURCE_DIR}/scripts/pyg2hpp.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
COMMENT "Generating \"${_full_output_file_path}\" from \"${pyg_file}\""
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
@ -203,7 +204,7 @@ macro(z3_add_install_tactic_rule)
"${CMAKE_CURRENT_BINARY_DIR}"
${_search_paths}
DEPENDS "${CMAKE_SOURCE_DIR}/scripts/mk_install_tactic_cpp.py"
"${CMAKE_SOURCE_DIR}/scripts/mk_util.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
${_expanded_components}
COMMENT "Generating \"${CMAKE_CURRENT_BINARY_DIR}/install_tactic.cpp\""
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
@ -235,7 +236,7 @@ macro(z3_add_memory_initializer_rule)
"${CMAKE_CURRENT_BINARY_DIR}"
${_search_paths}
DEPENDS "${CMAKE_SOURCE_DIR}/scripts/mk_mem_initializer_cpp.py"
"${CMAKE_SOURCE_DIR}/scripts/mk_util.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
${_expanded_components}
COMMENT "Generating \"${CMAKE_CURRENT_BINARY_DIR}/mem_initializer.cpp\""
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
@ -267,7 +268,7 @@ macro(z3_add_gparams_register_modules_rule)
"${CMAKE_CURRENT_BINARY_DIR}"
${_search_paths}
DEPENDS "${CMAKE_SOURCE_DIR}/scripts/mk_gparams_register_modules_cpp.py"
"${CMAKE_SOURCE_DIR}/scripts/mk_util.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
${_expanded_components}
COMMENT "Generating \"${CMAKE_CURRENT_BINARY_DIR}/gparams_register_modules.cpp\""
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}

View file

@ -165,9 +165,9 @@ foreach (header ${libz3_public_headers})
endforeach()
install(TARGETS libz3
LIBRARY DESTINATION "${Z3_INSTALL_LIB_DIR}"
ARCHIVE DESTINATION "${Z3_INSTALL_LIB_DIR}"
PUBLIC_HEADER DESTINATION "${Z3_INSTALL_INCLUDE_DIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
if (MSVC)
@ -186,7 +186,7 @@ if (MSVC)
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
DEPENDS
"${CMAKE_SOURCE_DIR}/scripts/mk_def_file.py"
"${CMAKE_SOURCE_DIR}/scripts/mk_util.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
COMMENT "Generating \"${dll_module_exports_file}\""
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
@ -222,4 +222,16 @@ if (BUILD_PYTHON_BINDINGS)
add_subdirectory(api/python)
endif()
################################################################################
# .NET bindings
################################################################################
option(BUILD_DOTNET_BINDINGS "Build .NET bindings for Z3" OFF)
if (BUILD_DOTNET_BINDINGS)
if (NOT BUILD_LIBZ3_SHARED)
message(FATAL_ERROR "The .NET bindings will not work with a static libz3. "
"You either need to disable BUILD_DOTNET_BINDINGS or enable BUILD_LIBZ3_SHARED")
endif()
add_subdirectory(api/dotnet)
endif()
# TODO: Implement support for other bindigns

View file

@ -24,8 +24,10 @@ add_custom_command(OUTPUT ${generated_files}
"--api_output_dir"
"${CMAKE_CURRENT_BINARY_DIR}"
DEPENDS "${CMAKE_SOURCE_DIR}/scripts/update_api.py"
"${CMAKE_SOURCE_DIR}/scripts/mk_util.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
# FIXME: When update_api.py no longer uses ``mk_util`` drop this dependency
"${CMAKE_SOURCE_DIR}/scripts/mk_util.py"
COMMENT "Generating ${generated_files}"
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
VERBATIM

View file

@ -0,0 +1,276 @@
find_package(DotNetToolchain REQUIRED)
# Configure AssemblyInfo.cs
set(VER_MAJOR "${Z3_VERSION_MAJOR}")
set(VER_MINOR "${Z3_VERSION_MINOR}")
set(VER_BUILD "${Z3_VERSION_PATCH}")
set(VER_REVISION "${Z3_VERSION_TWEAK}")
set(Z3_DOTNET_ASSEMBLY_INFO_FILE "${CMAKE_CURRENT_BINARY_DIR}/Properties/AssemblyInfo.cs")
configure_file("Properties/AssemblyInfo.cs.in" "${Z3_DOTNET_ASSEMBLY_INFO_FILE}" @ONLY)
# Generate Native.cs
set(Z3_DOTNET_NATIVE_FILE "${CMAKE_CURRENT_BINARY_DIR}/Native.cs")
add_custom_command(OUTPUT "${Z3_DOTNET_NATIVE_FILE}"
COMMAND "${PYTHON_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/update_api.py"
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
"--dotnet-output-dir"
"${CMAKE_CURRENT_BINARY_DIR}"
DEPENDS
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
"${CMAKE_SOURCE_DIR}/scripts/update_api.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
# FIXME: When update_api.py no longer uses ``mk_util`` drop this dependency
"${CMAKE_SOURCE_DIR}/scripts/mk_util.py"
COMMENT "Generating ${Z3_DOTNET_NATIVE_FILE}"
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
)
# Generate Enumerations.cs
set(Z3_DOTNET_CONST_FILE "${CMAKE_CURRENT_BINARY_DIR}/Enumerations.cs")
add_custom_command(OUTPUT "${Z3_DOTNET_CONST_FILE}"
COMMAND "${PYTHON_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/mk_consts_files.py"
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
"--dotnet-output-dir"
"${CMAKE_CURRENT_BINARY_DIR}"
DEPENDS
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
"${CMAKE_SOURCE_DIR}/scripts/mk_consts_files.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
COMMENT "Generating ${Z3_DOTNET_CONST_FILE}"
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
)
set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE
AlgebraicNum.cs
ApplyResult.cs
ArithExpr.cs
ArithSort.cs
ArrayExpr.cs
ArraySort.cs
AST.cs
ASTMap.cs
ASTVector.cs
BitVecExpr.cs
BitVecNum.cs
BitVecSort.cs
BoolExpr.cs
BoolSort.cs
Constructor.cs
ConstructorList.cs
Context.cs
DatatypeExpr.cs
DatatypeSort.cs
Deprecated.cs
EnumSort.cs
Expr.cs
FiniteDomainExpr.cs
FiniteDomainNum.cs
FiniteDomainSort.cs
Fixedpoint.cs
FPExpr.cs
FPNum.cs
FPRMExpr.cs
FPRMNum.cs
FPRMSort.cs
FPSort.cs
FuncDecl.cs
FuncInterp.cs
Global.cs
Goal.cs
IDecRefQueue.cs
InterpolationContext.cs
IntExpr.cs
IntNum.cs
IntSort.cs
IntSymbol.cs
ListSort.cs
Log.cs
Model.cs
Optimize.cs
ParamDescrs.cs
Params.cs
Pattern.cs
Probe.cs
Quantifier.cs
RatNum.cs
RealExpr.cs
RealSort.cs
ReExpr.cs
RelationSort.cs
ReSort.cs
SeqExpr.cs
SeqSort.cs
SetSort.cs
Solver.cs
Sort.cs
Statistics.cs
Status.cs
StringSymbol.cs
Symbol.cs
Tactic.cs
TupleSort.cs
UninterpretedSort.cs
Version.cs
Z3Exception.cs
Z3Object.cs
)
set(Z3_DOTNET_ASSEMBLY_SOURCES "")
# Make paths to source files absolute
foreach (csfile ${Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE})
list(APPEND Z3_DOTNET_ASSEMBLY_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${csfile}")
endforeach()
# Add generated files
list(APPEND Z3_DOTNET_ASSEMBLY_SOURCES
"${Z3_DOTNET_CONST_FILE}"
"${Z3_DOTNET_NATIVE_FILE}"
"${Z3_DOTNET_ASSEMBLY_INFO_FILE}"
)
# ``csc.exe`` doesn't like UNIX style paths so convert them
# if necessary first to native paths.
set(Z3_DOTNET_ASSEMBLY_SOURCES_NATIVE_PATH "")
foreach (csfile_path ${Z3_DOTNET_ASSEMBLY_SOURCES})
file(TO_NATIVE_PATH "${csfile_path}" csfile_path_native)
list(APPEND Z3_DOTNET_ASSEMBLY_SOURCES_NATIVE_PATH "${csfile_path_native}")
endforeach()
set(CSC_FLAGS "")
if (DOTNET_TOOLCHAIN_IS_WINDOWS)
# FIXME: Why use these flags?
# Note these flags have been copied from the Python build system.
list(APPEND CSC_FLAGS
"/noconfig"
"/nostdlib+"
"/reference:mscorlib.dll"
)
# FIXME: This flag only works when the working directory of csc.exe is
# the directory containing the ``libz3`` target. I can't get this to work
# correctly with multi-configuration generators (i.e. Visual Studio) so
# just don't set the flag for now.
#list(APPEND CSC_FLAGS "/linkresource:$<TARGET_FILE_NAME:libz3>")
elseif (DOTNET_TOOLCHAIN_IS_MONO)
# We need to give the assembly a strong name so that it can be installed
# into the GAC.
list(APPEND CSC_FLAGS
"/keyfile:${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.mono.snk"
)
else()
message(FATAL_ERROR "Unknown .NET toolchain")
endif()
# Common flags
list(APPEND CSC_FLAGS
"/unsafe+"
"/nowarn:1701,1702"
"/errorreport:prompt"
"/warn:4"
"/reference:System.Core.dll"
"/reference:System.dll"
"/reference:System.Numerics.dll"
"/filealign:512" # Why?
"/target:library"
)
# Set the build type flags. The build type for the assembly roughly corresponds
# with the native code build type.
list(APPEND CSC_FLAGS
# Debug flags, expands to nothing if we aren't doing a debug build
"$<$<CONFIG:Debug>:/debug+>"
"$<$<CONFIG:Debug>:/debug:full>"
"$<$<CONFIG:Debug>:/optimize->"
# This has to be quoted otherwise the ``;`` is interpreted as a command separator
"$<$<CONFIG:Debug>:\"/define:DEBUG$<SEMICOLON>TRACE\">"
# Release flags, expands to nothing if we are doing a debug build
"$<$<NOT:$<CONFIG:Debug>>:/optimize+>"
)
# Mono's gacutil crashes when trying to install an assembly if we set the
# platform in some cases, so only set it on Windows. This bug has been
# reported at https://bugzilla.xamarin.com/show_bug.cgi?id=39955 . However mono
# ignores the platform of an assembly when running it (
# http://lists.ximian.com/pipermail/mono-devel-list/2015-November/043370.html )
# so this shouldn't matter in practice.
if (DOTNET_TOOLCHAIN_IS_WINDOWS)
# Set platform for assembly
if ("${TARGET_ARCHITECTURE}" STREQUAL "x86_64")
list(APPEND CSC_FLAGS "/platform:x64")
elseif ("${TARGET_ARCHITECTURE}" STREQUAL "i686")
list(APPEND CSC_FLAGS "/platform:x86")
endif()
endif()
# FIXME: The get_property() command only works correctly for single configuration generators
# so we can't use it. We also can't use ``$<TARGET_FILE_DIR:libz3>`` because the ``OUTPUT``
# argument to ``add_custom_commands()`` won't accept it. For now just output file to the
# current binary directory.
# get_property(Z3_DOTNET_ASSEMBLY_OUTPUT_DIR TARGET libz3 PROPERTY LIBRARY_OUTPUT_DIRECTORY)
set(Z3_DOTNET_ASSEMBLY_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
set(Z3_DOTNET_ASSEMBLY_NAME "Microsoft.Z3.dll")
set(Z3_DOTNET_ASSEMBLY_DLL "${Z3_DOTNET_ASSEMBLY_OUTPUT_DIR}/${Z3_DOTNET_ASSEMBLY_NAME}")
# csc.exe doesn't work with UNIX style paths so convert to native path
file(TO_NATIVE_PATH "${Z3_DOTNET_ASSEMBLY_DLL}" Z3_DOTNET_ASSEMBLY_DLL_NATIVE_PATH)
set(Z3_DOTNET_ASSEMBLY_DLL_DOC "${Z3_DOTNET_ASSEMBLY_OUTPUT_DIR}/Microsoft.Z3.xml")
file(TO_NATIVE_PATH "${Z3_DOTNET_ASSEMBLY_DLL_DOC}" Z3_DOTNET_ASSEMBLY_DLL_DOC_NATIVE_PATH)
add_custom_command(OUTPUT "${Z3_DOTNET_ASSEMBLY_DLL}" "${Z3_DOTNET_ASSEMBLY_DLL_DOC}"
COMMAND
"${DOTNET_CSC_EXECUTABLE}"
${CSC_FLAGS}
"/out:${Z3_DOTNET_ASSEMBLY_DLL_NATIVE_PATH}"
"/doc:${Z3_DOTNET_ASSEMBLY_DLL_DOC_NATIVE_PATH}"
${Z3_DOTNET_ASSEMBLY_SOURCES_NATIVE_PATH}
DEPENDS
${Z3_DOTNET_ASSEMBLY_SOURCES}
libz3
WORKING_DIRECTORY "${Z3_DOTNET_ASSEMBLY_OUTPUT_DIR}"
COMMENT "Building \"${Z3_DOTNET_ASSEMBLY_DLL}\""
)
# Convenient top-level target
add_custom_target(build_z3_dotnet_bindings
ALL
DEPENDS
"${Z3_DOTNET_ASSEMBLY_DLL}"
)
###############################################################################
# Install
###############################################################################
option(INSTALL_DOTNET_BINDINGS "Install .NET bindings when invoking install target" ON)
set(GAC_PKG_NAME "Microsoft.Z3.Sharp")
set(PREFIX "${CMAKE_INSTALL_PREFIX}")
set(VERSION "${Z3_VERSION}")
set(Z3_DOTNET_PKGCONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/Microsoft.Z3.Sharp.pc")
configure_file("Microsoft.Z3.Sharp.pc.in" "${Z3_DOTNET_PKGCONFIG_FILE}" @ONLY)
if (DOTNET_TOOLCHAIN_IS_MONO)
message(STATUS "Emitting install rules for .NET bindings")
# Install pkgconfig file for the assembly. This is needed by Monodevelop
# to find the assembly
install(FILES "${Z3_DOTNET_PKGCONFIG_FILE}" DESTINATION "${CMAKE_INSTALL_PKGCONFIGDIR}")
# Configure the install and uninstall scripts
configure_file(cmake_install_gac.cmake.in cmake_install_gac.cmake @ONLY)
configure_file(cmake_uninstall_gac.cmake.in cmake_uninstall_gac.cmake @ONLY)
# Tell CMake to Invoke a script to install assembly to the GAC during install
install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/cmake_install_gac.cmake")
# Add custom target to uninstall the assembly from the GAC
add_custom_target(remove_dotnet_dll_from_gac
COMMAND "${CMAKE_COMMAND}" "-P" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall_gac.cmake"
COMMENT "Uninstalling ${Z3_DOTNET_ASSEMBLY_NAME} from the GAC"
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
)
add_dependencies(uninstall remove_dotnet_dll_from_gac)
elseif(DOTNET_TOOLCHAIN_IS_WINDOWS)
# FIXME: This isn't implemented because I'm not sure how/if the assembly should
# be installed to the GAC.
message(WARNING "Install of .NET bindings is not implemented for Windows")
else()
message(FATAL_ERROR "Unknown .NET toolchain")
endif()

View file

@ -0,0 +1,18 @@
# Install assembly to the GAC
set(GAC_ROOT "$ENV{DESTDIR}@CMAKE_INSTALL_FULL_LIBDIR@")
execute_process(COMMAND
"@DOTNET_GACUTIL_EXECUTABLE@"
"-i"
"@Z3_DOTNET_ASSEMBLY_DLL@"
"-f"
"-package" "@GAC_PKG_NAME@"
"-root" "${GAC_ROOT}"
WORKING_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@"
RESULT_VARIABLE gacutil_exit_code
)
if ("${gacutil_exit_code}" EQUAL 0)
message(STATUS "Installed \"@Z3_DOTNET_ASSEMBLY_DLL@\" to the GAC")
else()
message(FATAL_ERROR "Failed to install \"@Z3_DOTNET_ASSEMBLY_DLL@\" to the GAC")
endif()

View file

@ -0,0 +1,20 @@
# Uninstall assembly from the GAC
set(GAC_ROOT "$ENV{DESTDIR}@CMAKE_INSTALL_FULL_LIBDIR@")
execute_process(COMMAND
"@DOTNET_GACUTIL_EXECUTABLE@"
# Note ``-us`` takes assembly file name rather than
# ``-u`` which takes an assembly display name
"-us"
"@Z3_DOTNET_ASSEMBLY_NAME@"
"-f"
"-package" "@GAC_PKG_NAME@"
"-root" "${GAC_ROOT}"
WORKING_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@"
RESULT_VARIABLE gacutil_exit_code
)
if ("${gacutil_exit_code}" EQUAL 0)
message(STATUS "Uninstalled \"@Z3_DOTNET_ASSEMBLY_NAME@\" from the GAC")
else()
message(FATAL_ERROR "Failed to uninstall \"@Z3_DOTNET_ASSEMBLY_NAME@\" from the GAC")
endif()

View file

@ -38,6 +38,8 @@ add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3core.py"
DEPENDS
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
"${CMAKE_SOURCE_DIR}/scripts/update_api.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
# FIXME: When update_api.py no longer uses ``mk_util`` drop this dependency
"${CMAKE_SOURCE_DIR}/scripts/mk_util.py"
COMMENT "Generating z3core.py"
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
@ -54,7 +56,7 @@ add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3consts.py"
DEPENDS
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
"${CMAKE_SOURCE_DIR}/scripts/mk_consts_files.py"
"${CMAKE_SOURCE_DIR}/scripts/mk_util.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
COMMENT "Generating z3consts.py"
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
)
@ -72,35 +74,50 @@ add_custom_target(build_z3_python_bindings
###############################################################################
option(INSTALL_PYTHON_BINDINGS "Install Python bindings when invoking install target" ON)
if (INSTALL_PYTHON_BINDINGS)
# Determine the installation path for the bindings
message(STATUS "Emitting rules to install Z3 python bindings")
execute_process(
COMMAND "${PYTHON_EXECUTABLE}" "-c"
"import distutils.sysconfig; print(distutils.sysconfig.get_python_lib())"
RESULT_VARIABLE exit_code
OUTPUT_VARIABLE python_pkg_dir
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Try to guess the installation path for the bindings
if (NOT DEFINED CMAKE_INSTALL_PYTHON_PKG_DIR)
message(STATUS "CMAKE_INSTALL_PYTHON_PKG_DIR not set. Trying to guess")
execute_process(
COMMAND "${PYTHON_EXECUTABLE}" "-c"
"import distutils.sysconfig; print(distutils.sysconfig.get_python_lib())"
RESULT_VARIABLE exit_code
OUTPUT_VARIABLE CMAKE_INSTALL_PYTHON_PKG_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (NOT ("${exit_code}" EQUAL 0))
message(FATAL_ERROR "Failed to determine your Python package directory")
if (NOT ("${exit_code}" EQUAL 0))
message(FATAL_ERROR "Failed to determine your Python package directory")
endif()
message(STATUS "Detected Python package directory: \"${CMAKE_INSTALL_PYTHON_PKG_DIR}\"")
# Set a cache variable that the user can modify if needed
set(CMAKE_INSTALL_PYTHON_PKG_DIR
"${CMAKE_INSTALL_PYTHON_PKG_DIR}"
CACHE PATH
"Path to install python bindings. This can be relative or absolute.")
mark_as_advanced(CMAKE_INSTALL_PYTHON_PKG_DIR)
else()
message(STATUS "CMAKE_INSTALL_PYTHON_PKG_DIR already set (\"${CMAKE_INSTALL_PYTHON_PKG_DIR}\")"
". Not trying to guess.")
endif()
message(STATUS "Detected Python package directory: \"${python_pkg_dir}\"")
# Check if path exists under the install prefix
set(python_install_dir "")
string(FIND "${python_pkg_dir}" "${CMAKE_INSTALL_PREFIX}" position)
if (NOT ("${position}" EQUAL 0))
message(WARNING "The detected Python package directory \"${python_pkg_dir}\" "
"does not exist under the install prefix \"${CMAKE_INSTALL_PREFIX}\"."
" Running the install target may lead to a broken installation."
)
# Check if path exists under the install prefix if it is absolute. If the
# path is relative it will be installed under the install prefix so there
# if nothing to check
if (IS_ABSOLUTE "${CMAKE_INSTALL_PYTHON_PKG_DIR}")
string(FIND "${CMAKE_INSTALL_PYTHON_PKG_DIR}" "${CMAKE_INSTALL_PREFIX}" position)
if (NOT ("${position}" EQUAL 0))
message(WARNING "The directory to install the python bindings \"${CMAKE_INSTALL_PYTHON_PKG_DIR}\" "
"is not under the install prefix \"${CMAKE_INSTALL_PREFIX}\"."
" Running the install target may lead to a broken installation. "
"To change the install directory modify the CMAKE_INSTALL_PYTHON_PKG_DIR cache variable."
)
endif()
endif()
# Using DESTDIR still seems to work even if we use an absolute path
set(python_install_dir "${python_pkg_dir}")
message(STATUS "Python bindings will be installed to \"${python_install_dir}\"")
message(STATUS "Python bindings will be installed to \"${CMAKE_INSTALL_PYTHON_PKG_DIR}\"")
install(FILES ${build_z3_python_bindings_target_depends}
DESTINATION "${python_install_dir}"
DESTINATION "${CMAKE_INSTALL_PYTHON_PKG_DIR}"
)
else()
message(STATUS "Not emitting rules to install Z3 python bindings")

View file

@ -13,7 +13,7 @@ add_custom_command(OUTPUT "database.h"
"${CMAKE_CURRENT_BINARY_DIR}/database.h"
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/database.smt2"
DEPENDS "${CMAKE_SOURCE_DIR}/scripts/mk_pat_db.py"
"${CMAKE_SOURCE_DIR}/scripts/mk_util.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
COMMENT "Generating \"database.h\""
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
VERBATIM

View file

@ -12,6 +12,7 @@ z3_add_component(rewriter
expr_safe_replace.cpp
factor_rewriter.cpp
fpa_rewriter.cpp
label_rewriter.cpp
mk_simplified_app.cpp
pb_rewriter.cpp
quant_hoist.cpp

View file

@ -1,21 +1,28 @@
z3_add_component(qe
SOURCES
nlarith_util.cpp
nlqsat.cpp
qe_arith.cpp
qe_arith_plugin.cpp
qe_array_plugin.cpp
qe_arrays.cpp
qe_bool_plugin.cpp
qe_bv_plugin.cpp
qe_cmd.cpp
qe.cpp
qe_datatype_plugin.cpp
qe_datatypes.cpp
qe_dl_plugin.cpp
qe_lite.cpp
qe_mbp.cpp
qe_sat_tactic.cpp
qe_tactic.cpp
qe_util.cpp
qsat.cpp
vsubst_tactic.cpp
COMPONENT_DEPENDENCIES
nlsat_tactic
nlsat
sat
smt
smt
tactic
)

View file

@ -43,5 +43,5 @@ target_link_libraries(shell PRIVATE ${Z3_DEPENDENT_LIBS})
z3_add_component_dependencies_to_target(shell ${shell_expanded_deps})
z3_append_linker_flag_list_to_target(shell ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS})
install(TARGETS shell
RUNTIME DESTINATION "${Z3_INSTALL_BIN_DIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
)

View file

@ -18,6 +18,7 @@ z3_add_component(core_tactics
split_clause_tactic.cpp
symmetry_reduce_tactic.cpp
tseitin_cnf_tactic.cpp
collect_occs.cpp
COMPONENT_DEPENDENCIES
normal_forms
tactic

View file

@ -1,7 +1,7 @@
API documentation
-----------------
To generate the API documentation for the C, .NET and Python APIs, we must execute
To generate the API documentation for the C, C++, .NET, Java and Python APIs, we must execute
python mk_api_doc.py

View file

@ -1,4 +1,4 @@
Small example using the c++ bindings.
Small example using the C bindings.
To build the example execute
make examples
in the build directory.

View file

@ -1,4 +1,4 @@
Small example using the c++ bindings.
Small example using the C bindings.
To build the example execute
make examples
in the build directory.

View file

@ -4,44 +4,48 @@ Reads a list of Z3 API header files and
generate the constant declarations need
by one or more Z3 language bindings
"""
import mk_util
import mk_genfile_common
import argparse
import logging
import os
import sys
def check_dir(output_dir):
if not os.path.isdir(output_dir):
logging.error('"{}" is not an existing directory'.format(output_dir))
return 1
return 0
def main(args):
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("api_files", nargs="+")
parser.add_argument("--z3py-output-dir", dest="z3py_output_dir", default=None)
pargs = parser.parse_args(args)
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("api_files", nargs="+")
parser.add_argument("--z3py-output-dir", dest="z3py_output_dir", default=None)
parser.add_argument("--dotnet-output-dir", dest="dotnet_output_dir", default=None)
pargs = parser.parse_args(args)
for api_file in pargs.api_files:
if not os.path.exists(api_file):
logging.error('"{}" does not exist'.format(api_file))
return 1
if not mk_genfile_common.check_files_exist(pargs.api_files):
logging.error('One or more API files do not exist')
return 1
count = 0
count = 0
if pargs.z3py_output_dir:
if check_dir(pargs.z3py_output_dir) != 0:
return 1
mk_util.mk_z3consts_py_internal(pargs.api_files, pargs.z3py_output_dir)
count += 1
if pargs.z3py_output_dir:
if not mk_genfile_common.check_dir_exists(pargs.z3py_output_dir):
return 1
output = mk_genfile_common.mk_z3consts_py_internal(pargs.api_files, pargs.z3py_output_dir)
logging.info('Generated "{}"'.format(output))
count += 1
if count == 0:
logging.info('No files generated. You need to specific an output directory'
' for the relevant langauge bindings')
# TODO: Add support for other bindings
return 0
if pargs.dotnet_output_dir:
if not mk_genfile_common.check_dir_exists(pargs.dotnet_output_dir):
return 1
output = mk_genfile_common.mk_z3consts_dotnet_internal(
pargs.api_files,
pargs.dotnet_output_dir)
logging.info('Generated "{}"'.format(output))
count += 1
if count == 0:
logging.info('No files generated. You need to specific an output directory'
' for the relevant langauge bindings')
# TODO: Add support for other bindings
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
sys.exit(main(sys.argv[1:]))

View file

@ -6,31 +6,31 @@ exported symbols of a dll. This file
can be passed to the ``/DEF`` to the
linker used by MSVC.
"""
import mk_util
import mk_genfile_common
import argparse
import logging
import os
import sys
def main(args):
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("output_file", help="output def file path")
parser.add_argument("dllname", help="dllname to use in def file")
parser.add_argument("api_files", nargs="+")
pargs = parser.parse_args(args)
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("output_file", help="output def file path")
parser.add_argument("dllname", help="dllname to use in def file")
parser.add_argument("api_files", nargs="+")
pargs = parser.parse_args(args)
for api_file in pargs.api_files:
if not os.path.exists(api_file):
logging.error('"{}" does not exist'.format(api_file))
return 1
if not mk_genfile_common.check_files_exist(pargs.api_files):
logging.error('One or more api files do not exist')
return 1
mk_util.mk_def_file_internal(
pargs.output_file,
pargs.dllname,
pargs.api_files)
return 0
mk_genfile_common.mk_def_file_internal(
pargs.output_file,
pargs.dllname,
pargs.api_files)
logging.info('Generated "{}"'.format(pargs.output_file))
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
sys.exit(main(sys.argv[1:]))

View file

@ -0,0 +1,655 @@
# This file contains code that is common to
# both the Python build system and the CMake
# build system.
#
# The code here generally is involved in
# generating files needed by Z3 at build time.
#
# You should **not** import ``mk_util`` here
# to avoid having this code depend on the
# of the Python build system.
import os
import pprint
import logging
import re
import sys
# Logger for this module
_logger = logging.getLogger(__name__)
###############################################################################
# Utility functions
###############################################################################
def check_dir_exists(output_dir):
"""
Returns ``True`` if ``output_dir`` exists, otherwise
returns ``False``.
"""
if not os.path.isdir(output_dir):
_logger.error('"{}" is not an existing directory'.format(output_dir))
return False
return True
def check_files_exist(files):
assert isinstance(files, list)
for f in files:
if not os.path.exists(f):
_logger.error('"{}" does not exist'.format(f))
return False
return True
def sorted_headers_by_component(l):
"""
Take a list of header files and sort them by the
path after ``src/``. E.g. for ``src/ast/fpa/fpa2bv_converter.h`` the sorting
key is ``ast/fpa/fpa2bv_converter.h``.
The sort is done this way because for the CMake build
there are two directories for every component (e.g.
``<src_dir>/src/ast/fpa`` and ``<build_dir>/src/ast/fpa``).
We don't want to sort based on different ``<src_dir>``
and ``<build_dir>`` prefixes so that we can match the Python build
system's behaviour.
"""
assert isinstance(l, list)
def get_key(path):
_logger.debug("get_key({})".format(path))
path_components = []
stripped_path = path
assert 'src' in stripped_path.split(os.path.sep) or 'src' in stripped_path.split('/')
# Keep stripping off directory components until we hit ``src``
while os.path.basename(stripped_path) != 'src':
path_components.append(os.path.basename(stripped_path))
stripped_path = os.path.dirname(stripped_path)
assert len(path_components) > 0
path_components.reverse()
# For consistency across platforms use ``/`` rather than ``os.sep``.
# This is a sorting key so it doesn't need to a platform suitable
# path
r = '/'.join(path_components)
_logger.debug("return key:'{}'".format(r))
return r
sorted_headers = sorted(l, key=get_key)
_logger.debug('sorted headers:{}'.format(pprint.pformat(sorted_headers)))
return sorted_headers
###############################################################################
# Functions for generating constant declarations for language bindings
###############################################################################
def mk_z3consts_py_internal(api_files, output_dir):
"""
Generate ``z3consts.py`` from the list of API header files
in ``api_files`` and write the output file into
the ``output_dir`` directory
Returns the path to the generated file.
"""
assert os.path.isdir(output_dir)
assert isinstance(api_files, list)
blank_pat = re.compile("^ *\r?$")
comment_pat = re.compile("^ *//.*$")
typedef_pat = re.compile("typedef enum *")
typedef2_pat = re.compile("typedef enum { *")
openbrace_pat = re.compile("{ *")
closebrace_pat = re.compile("}.*;")
z3consts = open(os.path.join(output_dir, 'z3consts.py'), 'w')
z3consts_output_path = z3consts.name
z3consts.write('# Automatically generated file\n\n')
for api_file in api_files:
api = open(api_file, 'r')
SEARCHING = 0
FOUND_ENUM = 1
IN_ENUM = 2
mode = SEARCHING
decls = {}
idx = 0
linenum = 1
for line in api:
m1 = blank_pat.match(line)
m2 = comment_pat.match(line)
if m1 or m2:
# skip blank lines and comments
linenum = linenum + 1
elif mode == SEARCHING:
m = typedef_pat.match(line)
if m:
mode = FOUND_ENUM
m = typedef2_pat.match(line)
if m:
mode = IN_ENUM
decls = {}
idx = 0
elif mode == FOUND_ENUM:
m = openbrace_pat.match(line)
if m:
mode = IN_ENUM
decls = {}
idx = 0
else:
assert False, "Invalid %s, line: %s" % (api_file, linenum)
else:
assert mode == IN_ENUM
words = re.split('[^\-a-zA-Z0-9_]+', line)
m = closebrace_pat.match(line)
if m:
name = words[1]
z3consts.write('# enum %s\n' % name)
# Iterate over key-value pairs ordered by value
for k, v in sorted(decls.items(), key=lambda pair: pair[1]):
z3consts.write('%s = %s\n' % (k, v))
z3consts.write('\n')
mode = SEARCHING
elif len(words) <= 2:
assert False, "Invalid %s, line: %s" % (api_file, linenum)
else:
if words[2] != '':
if len(words[2]) > 1 and words[2][1] == 'x':
idx = int(words[2], 16)
else:
idx = int(words[2])
decls[words[1]] = idx
idx = idx + 1
linenum = linenum + 1
api.close()
z3consts.close()
return z3consts_output_path
def mk_z3consts_dotnet_internal(api_files, output_dir):
"""
Generate ``Enumerations.cs`` from the list of API header files
in ``api_files`` and write the output file into
the ``output_dir`` directory
Returns the path to the generated file.
"""
assert os.path.isdir(output_dir)
assert isinstance(api_files, list)
blank_pat = re.compile("^ *\r?$")
comment_pat = re.compile("^ *//.*$")
typedef_pat = re.compile("typedef enum *")
typedef2_pat = re.compile("typedef enum { *")
openbrace_pat = re.compile("{ *")
closebrace_pat = re.compile("}.*;")
DeprecatedEnums = [ 'Z3_search_failure' ]
z3consts = open(os.path.join(output_dir, 'Enumerations.cs'), 'w')
z3consts_output_path = z3consts.name
z3consts.write('// Automatically generated file\n\n')
z3consts.write('using System;\n\n'
'#pragma warning disable 1591\n\n'
'namespace Microsoft.Z3\n'
'{\n')
for api_file in api_files:
api = open(api_file, 'r')
SEARCHING = 0
FOUND_ENUM = 1
IN_ENUM = 2
mode = SEARCHING
decls = {}
idx = 0
linenum = 1
for line in api:
m1 = blank_pat.match(line)
m2 = comment_pat.match(line)
if m1 or m2:
# skip blank lines and comments
linenum = linenum + 1
elif mode == SEARCHING:
m = typedef_pat.match(line)
if m:
mode = FOUND_ENUM
m = typedef2_pat.match(line)
if m:
mode = IN_ENUM
decls = {}
idx = 0
elif mode == FOUND_ENUM:
m = openbrace_pat.match(line)
if m:
mode = IN_ENUM
decls = {}
idx = 0
else:
assert False, "Invalid %s, line: %s" % (api_file, linenum)
else:
assert mode == IN_ENUM
words = re.split('[^\-a-zA-Z0-9_]+', line)
m = closebrace_pat.match(line)
if m:
name = words[1]
if name not in DeprecatedEnums:
z3consts.write(' /// <summary>%s</summary>\n' % name)
z3consts.write(' public enum %s {\n' % name)
z3consts.write
# Iterate over key-value pairs ordered by value
for k, v in sorted(decls.items(), key=lambda pair: pair[1]):
z3consts.write(' %s = %s,\n' % (k, v))
z3consts.write(' }\n\n')
mode = SEARCHING
elif len(words) <= 2:
assert False, "Invalid %s, line: %s" % (api_file, linenum)
else:
if words[2] != '':
if len(words[2]) > 1 and words[2][1] == 'x':
idx = int(words[2], 16)
else:
idx = int(words[2])
decls[words[1]] = idx
idx = idx + 1
linenum = linenum + 1
api.close()
z3consts.write('}\n');
z3consts.close()
return z3consts_output_path
###############################################################################
# Functions for generating a "module definition file" for MSVC
###############################################################################
def mk_def_file_internal(defname, dll_name, export_header_files):
"""
Writes to a module definition file to a file named ``defname``.
``dll_name`` is the name of the dll (without the ``.dll`` suffix).
``export_header_file`` is a list of header files to scan for symbols
to include in the module definition file.
"""
assert isinstance(export_header_files, list)
pat1 = re.compile(".*Z3_API.*")
fout = open(defname, 'w')
fout.write('LIBRARY "%s"\nEXPORTS\n' % dll_name)
num = 1
for export_header_file in export_header_files:
api = open(export_header_file, 'r')
for line in api:
m = pat1.match(line)
if m:
words = re.split('\W+', line)
i = 0
for w in words:
if w == 'Z3_API':
f = words[i+1]
fout.write('\t%s @%s\n' % (f, num))
i = i + 1
num = num + 1
api.close()
fout.close()
###############################################################################
# Functions for generating ``gparams_register_modules.cpp``
###############################################################################
def mk_gparams_register_modules_internal(component_src_dirs, path):
"""
Generate a ``gparams_register_modules.cpp`` file in the directory ``path``.
Returns the path to the generated file.
This file implements the procedure
```
void gparams_register_modules()
```
This procedure is invoked by gparams::init()
"""
assert isinstance(component_src_dirs, list)
assert check_dir_exists(path)
cmds = []
mod_cmds = []
mod_descrs = []
fullname = os.path.join(path, 'gparams_register_modules.cpp')
fout = open(fullname, 'w')
fout.write('// Automatically generated file.\n')
fout.write('#include"gparams.h"\n')
reg_pat = re.compile('[ \t]*REG_PARAMS\(\'([^\']*)\'\)')
reg_mod_pat = re.compile('[ \t]*REG_MODULE_PARAMS\(\'([^\']*)\', *\'([^\']*)\'\)')
reg_mod_descr_pat = re.compile('[ \t]*REG_MODULE_DESCRIPTION\(\'([^\']*)\', *\'([^\']*)\'\)')
h_files_full_path = []
for component_src_dir in component_src_dirs:
h_files = filter(lambda f: f.endswith('.h') or f.endswith('.hpp'), os.listdir(component_src_dir))
h_files = list(map(lambda p: os.path.join(component_src_dir, p), h_files))
h_files_full_path.extend(h_files)
for h_file in sorted_headers_by_component(h_files_full_path):
added_include = False
with open(h_file, 'r') as fin:
for line in fin:
m = reg_pat.match(line)
if m:
if not added_include:
added_include = True
fout.write('#include"%s"\n' % os.path.basename(h_file))
cmds.append((m.group(1)))
m = reg_mod_pat.match(line)
if m:
if not added_include:
added_include = True
fout.write('#include"%s"\n' % os.path.basename(h_file))
mod_cmds.append((m.group(1), m.group(2)))
m = reg_mod_descr_pat.match(line)
if m:
mod_descrs.append((m.group(1), m.group(2)))
fout.write('void gparams_register_modules() {\n')
for code in cmds:
fout.write('{ param_descrs d; %s(d); gparams::register_global(d); }\n' % code)
for (mod, code) in mod_cmds:
fout.write('{ param_descrs * d = alloc(param_descrs); %s(*d); gparams::register_module("%s", d); }\n' % (code, mod))
for (mod, descr) in mod_descrs:
fout.write('gparams::register_module_descr("%s", "%s");\n' % (mod, descr))
fout.write('}\n')
fout.close()
return fullname
###############################################################################
# Functions/data structures for generating ``install_tactics.cpp``
###############################################################################
def mk_install_tactic_cpp_internal(component_src_dirs, path):
"""
Generate a ``install_tactics.cpp`` file in the directory ``path``.
Returns the path the generated file.
This file implements the procedure
```
void install_tactics(tactic_manager & ctx)
```
It installs all tactics found in the given component directories
``component_src_dirs`` The procedure looks for ``ADD_TACTIC`` commands
in the ``.h`` and ``.hpp`` files of these components.
"""
ADD_TACTIC_DATA = []
ADD_PROBE_DATA = []
def ADD_TACTIC(name, descr, cmd):
ADD_TACTIC_DATA.append((name, descr, cmd))
def ADD_PROBE(name, descr, cmd):
ADD_PROBE_DATA.append((name, descr, cmd))
eval_globals = {
'ADD_TACTIC': ADD_TACTIC,
'ADD_PROBE': ADD_PROBE,
}
assert isinstance(component_src_dirs, list)
assert check_dir_exists(path)
fullname = os.path.join(path, 'install_tactic.cpp')
fout = open(fullname, 'w')
fout.write('// Automatically generated file.\n')
fout.write('#include"tactic.h"\n')
fout.write('#include"tactic_cmds.h"\n')
fout.write('#include"cmd_context.h"\n')
tactic_pat = re.compile('[ \t]*ADD_TACTIC\(.*\)')
probe_pat = re.compile('[ \t]*ADD_PROBE\(.*\)')
h_files_full_path = []
for component_src_dir in sorted(component_src_dirs):
h_files = filter(lambda f: f.endswith('.h') or f.endswith('.hpp'), os.listdir(component_src_dir))
h_files = list(map(lambda p: os.path.join(component_src_dir, p), h_files))
h_files_full_path.extend(h_files)
for h_file in sorted_headers_by_component(h_files_full_path):
added_include = False
with open(h_file, 'r') as fin:
for line in fin:
if tactic_pat.match(line):
if not added_include:
added_include = True
fout.write('#include"%s"\n' % os.path.basename(h_file))
try:
eval(line.strip('\n '), eval_globals, None)
except Exception as e:
_logger.error("Failed processing ADD_TACTIC command at '{}'\n{}".format(
fullname, line))
raise e
if probe_pat.match(line):
if not added_include:
added_include = True
fout.write('#include"%s"\n' % os.path.basename(h_file))
try:
eval(line.strip('\n '), eval_globals, None)
except Exception as e:
_logger.error("Failed processing ADD_PROBE command at '{}'\n{}".format(
fullname, line))
raise e
# First pass will just generate the tactic factories
idx = 0
for data in ADD_TACTIC_DATA:
fout.write('MK_SIMPLE_TACTIC_FACTORY(__Z3_local_factory_%s, %s);\n' % (idx, data[2]))
idx = idx + 1
fout.write('#define ADD_TACTIC_CMD(NAME, DESCR, FACTORY) ctx.insert(alloc(tactic_cmd, symbol(NAME), DESCR, alloc(FACTORY)))\n')
fout.write('#define ADD_PROBE(NAME, DESCR, PROBE) ctx.insert(alloc(probe_info, symbol(NAME), DESCR, PROBE))\n')
fout.write('void install_tactics(tactic_manager & ctx) {\n')
idx = 0
for data in ADD_TACTIC_DATA:
fout.write(' ADD_TACTIC_CMD("%s", "%s", __Z3_local_factory_%s);\n' % (data[0], data[1], idx))
idx = idx + 1
for data in ADD_PROBE_DATA:
fout.write(' ADD_PROBE("%s", "%s", %s);\n' % data)
fout.write('}\n')
fout.close()
return fullname
###############################################################################
# Functions for generating ``mem_initializer.cpp``
###############################################################################
def mk_mem_initializer_cpp_internal(component_src_dirs, path):
"""
Generate a ``mem_initializer.cpp`` file in the directory ``path``.
Returns the path to the generated file.
This file implements the procedures
```
void mem_initialize()
void mem_finalize()
```
These procedures are invoked by the Z3 memory_manager
"""
assert isinstance(component_src_dirs, list)
assert check_dir_exists(path)
initializer_cmds = []
finalizer_cmds = []
fullname = os.path.join(path, 'mem_initializer.cpp')
fout = open(fullname, 'w')
fout.write('// Automatically generated file.\n')
initializer_pat = re.compile('[ \t]*ADD_INITIALIZER\(\'([^\']*)\'\)')
# ADD_INITIALIZER with priority
initializer_prio_pat = re.compile('[ \t]*ADD_INITIALIZER\(\'([^\']*)\',[ \t]*(-?[0-9]*)\)')
finalizer_pat = re.compile('[ \t]*ADD_FINALIZER\(\'([^\']*)\'\)')
h_files_full_path = []
for component_src_dir in sorted(component_src_dirs):
h_files = filter(lambda f: f.endswith('.h') or f.endswith('.hpp'), os.listdir(component_src_dir))
h_files = list(map(lambda p: os.path.join(component_src_dir, p), h_files))
h_files_full_path.extend(h_files)
for h_file in sorted_headers_by_component(h_files_full_path):
added_include = False
with open(h_file, 'r') as fin:
for line in fin:
m = initializer_pat.match(line)
if m:
if not added_include:
added_include = True
fout.write('#include"%s"\n' % os.path.basename(h_file))
initializer_cmds.append((m.group(1), 0))
m = initializer_prio_pat.match(line)
if m:
if not added_include:
added_include = True
fout.write('#include"%s"\n' % os.path.basename(h_file))
initializer_cmds.append((m.group(1), int(m.group(2))))
m = finalizer_pat.match(line)
if m:
if not added_include:
added_include = True
fout.write('#include"%s"\n' % os.path.basename(h_file))
finalizer_cmds.append(m.group(1))
initializer_cmds.sort(key=lambda tup: tup[1])
fout.write('void mem_initialize() {\n')
for (cmd, prio) in initializer_cmds:
fout.write(cmd)
fout.write('\n')
fout.write('}\n')
fout.write('void mem_finalize() {\n')
for cmd in finalizer_cmds:
fout.write(cmd)
fout.write('\n')
fout.write('}\n')
fout.close()
return fullname
###############################################################################
# Functions for generating ``database.h``
###############################################################################
def mk_pat_db_internal(inputFilePath, outputFilePath):
"""
Generate ``g_pattern_database[]`` declaration header file.
"""
with open(inputFilePath, 'r') as fin:
with open(outputFilePath, 'w') as fout:
fout.write('static char const g_pattern_database[] =\n')
for line in fin:
fout.write('"%s\\n"\n' % line.strip('\n'))
fout.write(';\n')
###############################################################################
# Functions and data structures for generating ``*_params.hpp`` files from
# ``*.pyg`` files
###############################################################################
UINT = 0
BOOL = 1
DOUBLE = 2
STRING = 3
SYMBOL = 4
UINT_MAX = 4294967295
TYPE2CPK = { UINT : 'CPK_UINT', BOOL : 'CPK_BOOL', DOUBLE : 'CPK_DOUBLE', STRING : 'CPK_STRING', SYMBOL : 'CPK_SYMBOL' }
TYPE2CTYPE = { UINT : 'unsigned', BOOL : 'bool', DOUBLE : 'double', STRING : 'char const *', SYMBOL : 'symbol' }
TYPE2GETTER = { UINT : 'get_uint', BOOL : 'get_bool', DOUBLE : 'get_double', STRING : 'get_str', SYMBOL : 'get_sym' }
def pyg_default(p):
if p[1] == BOOL:
if p[2]:
return "true"
else:
return "false"
return p[2]
def pyg_default_as_c_literal(p):
if p[1] == BOOL:
if p[2]:
return "true"
else:
return "false"
elif p[1] == STRING:
return '"%s"' % p[2]
elif p[1] == SYMBOL:
return 'symbol("%s")' % p[2]
elif p[1] == UINT:
return '%su' % p[2]
else:
return p[2]
def to_c_method(s):
return s.replace('.', '_')
def max_memory_param():
return ('max_memory', UINT, UINT_MAX, 'maximum amount of memory in megabytes')
def max_steps_param():
return ('max_steps', UINT, UINT_MAX, 'maximum number of steps')
def mk_hpp_from_pyg(pyg_file, output_dir):
"""
Generates the corresponding header file for the input pyg file
at the path ``pyg_file``. The file is emitted into the directory
``output_dir``.
Returns the path to the generated file
"""
CURRENT_PYG_HPP_DEST_DIR = output_dir
# Note OUTPUT_HPP_FILE cannot be a string as we need a mutable variable
# for the nested function to modify
OUTPUT_HPP_FILE = [ ]
# The function below has been nested so that it can use closure to capture
# the above variables that aren't global but instead local to this
# function. This avoids use of global state which makes this function safer.
def def_module_params(module_name, export, params, class_name=None, description=None):
dirname = CURRENT_PYG_HPP_DEST_DIR
assert(os.path.exists(dirname))
if class_name is None:
class_name = '%s_params' % module_name
hpp = os.path.join(dirname, '%s.hpp' % class_name)
out = open(hpp, 'w')
out.write('// Automatically generated file\n')
out.write('#ifndef __%s_HPP_\n' % class_name.upper())
out.write('#define __%s_HPP_\n' % class_name.upper())
out.write('#include"params.h"\n')
if export:
out.write('#include"gparams.h"\n')
out.write('struct %s {\n' % class_name)
out.write(' params_ref const & p;\n')
if export:
out.write(' params_ref g;\n')
out.write(' %s(params_ref const & _p = params_ref::get_empty()):\n' % class_name)
out.write(' p(_p)')
if export:
out.write(', g(gparams::get_module("%s"))' % module_name)
out.write(' {}\n')
out.write(' static void collect_param_descrs(param_descrs & d) {\n')
for param in params:
out.write(' d.insert("%s", %s, "%s", "%s","%s");\n' % (param[0], TYPE2CPK[param[1]], param[3], pyg_default(param), module_name))
out.write(' }\n')
if export:
out.write(' /*\n')
out.write(" REG_MODULE_PARAMS('%s', '%s::collect_param_descrs')\n" % (module_name, class_name))
if description is not None:
out.write(" REG_MODULE_DESCRIPTION('%s', '%s')\n" % (module_name, description))
out.write(' */\n')
# Generated accessors
for param in params:
if export:
out.write(' %s %s() const { return p.%s("%s", g, %s); }\n' %
(TYPE2CTYPE[param[1]], to_c_method(param[0]), TYPE2GETTER[param[1]], param[0], pyg_default_as_c_literal(param)))
else:
out.write(' %s %s() const { return p.%s("%s", %s); }\n' %
(TYPE2CTYPE[param[1]], to_c_method(param[0]), TYPE2GETTER[param[1]], param[0], pyg_default_as_c_literal(param)))
out.write('};\n')
out.write('#endif\n')
out.close()
OUTPUT_HPP_FILE.append(hpp)
# Globals to use when executing the ``.pyg`` file.
pyg_globals = {
'UINT' : UINT,
'BOOL' : BOOL,
'DOUBLE' : DOUBLE,
'STRING' : STRING,
'SYMBOL' : SYMBOL,
'UINT_MAX' : UINT_MAX,
'max_memory_param' : max_memory_param,
'max_steps_param' : max_steps_param,
# Note that once this function is enterred that function
# executes with respect to the globals of this module and
# not the globals defined here
'def_module_params' : def_module_params,
}
with open(pyg_file, 'r') as fh:
eval(fh.read() + "\n", pyg_globals, None)
assert len(OUTPUT_HPP_FILE) == 1
return OUTPUT_HPP_FILE[0]

View file

@ -6,42 +6,34 @@ and generates a ``gparams_register_modules.cpp`` file in
the destination directory that defines a function
``void gparams_register_modules()``.
"""
import mk_util
import mk_genfile_common
import argparse
import logging
import os
import sys
def check_dir(path):
if not os.path.exists(path):
logging.error('"{}" does not exist'.format(path))
return 1
if not os.path.isdir(path):
logging.error('"{}" is not a directory'.format(path))
return 1
return 0
def main(args):
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("destination_dir", help="destination directory")
parser.add_argument("source_dirs", nargs="+",
help="One or more source directories to search")
pargs = parser.parse_args(args)
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("destination_dir", help="destination directory")
parser.add_argument("source_dirs", nargs="+",
help="One or more source directories to search")
pargs = parser.parse_args(args)
if check_dir(pargs.destination_dir) != 0:
return 1
if not mk_genfile_common.check_dir_exists(pargs.destination_dir):
return 1
for source_dir in pargs.source_dirs:
if check_dir(source_dir) != 0:
return 1
for source_dir in pargs.source_dirs:
if not mk_genfile_common.check_dir_exists(source_dir):
return 1
mk_util.mk_gparams_register_modules_internal(pargs.source_dirs, pargs.destination_dir)
return 0
output = mk_genfile_common.mk_gparams_register_modules_internal(
pargs.source_dirs,
pargs.destination_dir
)
logging.info('Generated "{}"'.format(output))
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
sys.exit(main(sys.argv[1:]))

View file

@ -6,42 +6,33 @@ and generates a ``install_tactic.cpp`` file in
the destination directory that defines a function
``void install_tactics(tactic_manager& ctx)``.
"""
import mk_util
import mk_genfile_common
import argparse
import logging
import os
import sys
def check_dir(path):
if not os.path.exists(path):
logging.error('"{}" does not exist'.format(path))
return 1
if not os.path.isdir(path):
logging.error('"{}" is not a directory'.format(path))
return 1
return 0
def main(args):
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("destination_dir", help="destination directory")
parser.add_argument("source_dirs", nargs="+",
help="One or more source directories to search")
pargs = parser.parse_args(args)
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("destination_dir", help="destination directory")
parser.add_argument("source_dirs", nargs="+",
help="One or more source directories to search")
pargs = parser.parse_args(args)
if check_dir(pargs.destination_dir) != 0:
return 1
if not mk_genfile_common.check_dir_exists(pargs.destination_dir):
return 1
for source_dir in pargs.source_dirs:
if check_dir(source_dir) != 0:
return 1
for source_dir in pargs.source_dirs:
if not mk_genfile_common.check_dir_exists(source_dir):
return 1
mk_util.mk_install_tactic_cpp_internal(pargs.source_dirs, pargs.destination_dir)
return 0
output = mk_genfile_common.mk_install_tactic_cpp_internal(
pargs.source_dirs,
pargs.destination_dir
)
logging.info('Generated "{}"'.format(output))
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
sys.exit(main(sys.argv[1:]))

View file

@ -7,42 +7,34 @@ emits and implementation of
``void mem_finalize()`` into ``mem_initializer.cpp``
in the destination directory.
"""
import mk_util
import mk_genfile_common
import argparse
import logging
import os
import sys
def check_dir(path):
if not os.path.exists(path):
logging.error('"{}" does not exist'.format(path))
return 1
if not os.path.isdir(path):
logging.error('"{}" is not a directory'.format(path))
return 1
return 0
def main(args):
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("destination_dir", help="destination directory")
parser.add_argument("source_dirs", nargs="+",
help="One or more source directories to search")
pargs = parser.parse_args(args)
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("destination_dir", help="destination directory")
parser.add_argument("source_dirs", nargs="+",
help="One or more source directories to search")
pargs = parser.parse_args(args)
if check_dir(pargs.destination_dir) != 0:
return 1
if not mk_genfile_common.check_dir_exists(pargs.destination_dir):
return 1
for source_dir in pargs.source_dirs:
if check_dir(source_dir) != 0:
return 1
for source_dir in pargs.source_dirs:
if not mk_genfile_common.check_dir_exists(source_dir):
return 1
mk_util.mk_mem_initializer_cpp_internal(pargs.source_dirs, pargs.destination_dir)
return 0
output = mk_genfile_common.mk_mem_initializer_cpp_internal(
pargs.source_dirs,
pargs.destination_dir
)
logging.info('Generated "{}"'.format(output))
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
sys.exit(main(sys.argv[1:]))

View file

@ -3,32 +3,27 @@
Reads a pattern database and generates the corresponding
header file.
"""
import mk_util
import mk_genfile_common
import argparse
import logging
import os
import sys
def main(args):
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("db_file", help="pattern database file")
parser.add_argument("output_file", help="output header file path")
pargs = parser.parse_args(args)
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("db_file", help="pattern database file")
parser.add_argument("output_file", help="output header file path")
pargs = parser.parse_args(args)
if not os.path.exists(pargs.db_file):
logging.error('"{}" does not exist'.format(pargs.db_file))
return 1
if not os.path.exists(pargs.db_file):
logging.error('"{}" does not exist'.format(pargs.db_file))
return 1
if (os.path.exists(pargs.output_file) and
not os.path.isfile(pargs.output_file)):
logging.error('Refusing to overwrite "{}"'.format(
pargs.output_file))
return 1
mk_util.mk_pat_db_internal(pargs.db_file, pargs.output_file)
return 0
mk_genfile_common.mk_pat_db_internal(pargs.db_file, pargs.output_file)
logging.info('Generated "{}"'.format(pargs.output_file))
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
sys.exit(main(sys.argv[1:]))

View file

@ -57,7 +57,7 @@ def init_project_def():
add_lib('fuzzing', ['ast'], 'test/fuzzing')
add_lib('smt_tactic', ['smt'], 'smt/tactic')
add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls')
add_lib('qe', ['smt','sat'], 'qe')
add_lib('qe', ['smt','sat','nlsat','tactic','nlsat_tactic'], 'qe')
add_lib('duality', ['smt', 'interp', 'qe'])
add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe'], 'muz/base')
add_lib('dataflow', ['muz'], 'muz/dataflow')

View file

@ -12,6 +12,7 @@ import re
import getopt
import shutil
from mk_exception import *
import mk_genfile_common
from fnmatch import fnmatch
import distutils.sysconfig
import compileall
@ -27,6 +28,7 @@ CXX=getenv("CXX", None)
CC=getenv("CC", None)
CPPFLAGS=getenv("CPPFLAGS", "")
CXXFLAGS=getenv("CXXFLAGS", "")
AR=getenv("AR", "ar")
EXAMP_DEBUG_FLAG=''
LDFLAGS=getenv("LDFLAGS", "")
JNI_HOME=getenv("JNI_HOME", None)
@ -499,8 +501,8 @@ def is64():
def check_ar():
if is_verbose():
print("Testing ar...")
if which('ar') is None:
raise MKException('ar (archive tool) was not found')
if which(AR) is None:
raise MKException('%s (archive tool) was not found' % AR)
def find_cxx_compiler():
global CXX, CXX_COMPILERS
@ -1934,6 +1936,7 @@ class MLComponent(Component):
else:
out.write(' ' + os.path.join(self.sub_dir, m) + '.mli')
out.write(' ' + os.path.join(self.sub_dir, m) + '.cmi')
out.write(' ' + os.path.join(self.sub_dir, m) + '.cmx')
out.write(' %s' % ((os.path.join(self.sub_dir, 'libz3ml$(LIB_EXT)'))))
out.write(' %s' % ((os.path.join(self.sub_dir, 'z3ml$(LIB_EXT)'))))
out.write(' %s' % ((os.path.join(self.sub_dir, 'z3ml.cma'))))
@ -2034,7 +2037,7 @@ class DotNetExampleComponent(ExampleComponent):
if VS_X64:
out.write(' /platform:x64')
elif VS_ARM:
out.write(' /platform:arm')
out.write(' /platform:arm')
else:
out.write(' /platform:x86')
for csfile in get_cs_files(self.ex_dir):
@ -2227,7 +2230,7 @@ def mk_config():
static_opt = static_opt + 'd'
config.write(
'AR_FLAGS=/nologo\n'
'LINK_FLAGS=/nologo %s\n'
'LINK_FLAGS=/nologo %s\n'
'SLINK_FLAGS=/nologo /LDd\n' % static_opt)
if VS_X64:
config.write(
@ -2270,7 +2273,7 @@ def mk_config():
'LINK_EXTRA_FLAGS=/link%s /DEBUG /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT\n'
'SLINK_EXTRA_FLAGS=/link%s /DEBUG /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n' % (LTCG, LTCG))
# End of Windows VS config.mk
if is_verbose():
@ -2387,7 +2390,7 @@ def mk_config():
config.write('CXX_OUT_FLAG=-o \n')
config.write('OBJ_EXT=.o\n')
config.write('LIB_EXT=.a\n')
config.write('AR=ar\n')
config.write('AR=%s\n' % AR)
config.write('AR_FLAGS=rcs\n')
config.write('AR_OUTFLAG=\n')
config.write('EXE_EXT=\n')
@ -2408,6 +2411,7 @@ def mk_config():
print('Host platform: %s' % sysname)
print('C++ Compiler: %s' % CXX)
print('C Compiler : %s' % CC)
print('Archive Tool: %s' % AR)
print('Arithmetic: %s' % ARITH)
print('OpenMP: %s' % HAS_OMP)
print('Prefix: %s' % PREFIX)
@ -2503,7 +2507,7 @@ def mk_makefile():
print("To build Z3, open a [Visual Studio x64 Command Prompt], then")
elif VS_ARM:
print(" platform: ARM\n")
print("To build Z3, open a [Visual Studio ARM Command Prompt], then")
print("To build Z3, open a [Visual Studio ARM Command Prompt], then")
else:
print(" platform: x86")
print("To build Z3, open a [Visual Studio Command Prompt], then")
@ -2521,104 +2525,6 @@ def mk_auto_src():
mk_all_mem_initializer_cpps()
mk_all_gparams_register_modules()
UINT = 0
BOOL = 1
DOUBLE = 2
STRING = 3
SYMBOL = 4
UINT_MAX = 4294967295
CURRENT_PYG_HPP_DEST_DIR = None
def get_current_pyg_hpp_dest_dir():
return CURRENT_PYG_HPP_DEST_DIR
TYPE2CPK = { UINT : 'CPK_UINT', BOOL : 'CPK_BOOL', DOUBLE : 'CPK_DOUBLE', STRING : 'CPK_STRING', SYMBOL : 'CPK_SYMBOL' }
TYPE2CTYPE = { UINT : 'unsigned', BOOL : 'bool', DOUBLE : 'double', STRING : 'char const *', SYMBOL : 'symbol' }
TYPE2GETTER = { UINT : 'get_uint', BOOL : 'get_bool', DOUBLE : 'get_double', STRING : 'get_str', SYMBOL : 'get_sym' }
def pyg_default(p):
if p[1] == BOOL:
if p[2]:
return "true"
else:
return "false"
return p[2]
def pyg_default_as_c_literal(p):
if p[1] == BOOL:
if p[2]:
return "true"
else:
return "false"
elif p[1] == STRING:
return '"%s"' % p[2]
elif p[1] == SYMBOL:
return 'symbol("%s")' % p[2]
elif p[1] == UINT:
return '%su' % p[2]
else:
return p[2]
def to_c_method(s):
return s.replace('.', '_')
def def_module_params(module_name, export, params, class_name=None, description=None):
dirname = get_current_pyg_hpp_dest_dir()
assert(os.path.exists(dirname))
if class_name is None:
class_name = '%s_params' % module_name
hpp = os.path.join(dirname, '%s.hpp' % class_name)
out = open(hpp, 'w')
out.write('// Automatically generated file\n')
out.write('#ifndef __%s_HPP_\n' % class_name.upper())
out.write('#define __%s_HPP_\n' % class_name.upper())
out.write('#include"params.h"\n')
if export:
out.write('#include"gparams.h"\n')
out.write('struct %s {\n' % class_name)
out.write(' params_ref const & p;\n')
if export:
out.write(' params_ref g;\n')
out.write(' %s(params_ref const & _p = params_ref::get_empty()):\n' % class_name)
out.write(' p(_p)')
if export:
out.write(', g(gparams::get_module("%s"))' % module_name)
out.write(' {}\n')
out.write(' static void collect_param_descrs(param_descrs & d) {\n')
for param in params:
out.write(' d.insert("%s", %s, "%s", "%s","%s");\n' % (param[0], TYPE2CPK[param[1]], param[3], pyg_default(param), module_name))
out.write(' }\n')
if export:
out.write(' /*\n')
out.write(" REG_MODULE_PARAMS('%s', '%s::collect_param_descrs')\n" % (module_name, class_name))
if description is not None:
out.write(" REG_MODULE_DESCRIPTION('%s', '%s')\n" % (module_name, description))
out.write(' */\n')
# Generated accessors
for param in params:
if export:
out.write(' %s %s() const { return p.%s("%s", g, %s); }\n' %
(TYPE2CTYPE[param[1]], to_c_method(param[0]), TYPE2GETTER[param[1]], param[0], pyg_default_as_c_literal(param)))
else:
out.write(' %s %s() const { return p.%s("%s", %s); }\n' %
(TYPE2CTYPE[param[1]], to_c_method(param[0]), TYPE2GETTER[param[1]], param[0], pyg_default_as_c_literal(param)))
out.write('};\n')
out.write('#endif\n')
out.close()
if is_verbose():
print("Generated '%s'" % hpp)
def max_memory_param():
return ('max_memory', UINT, UINT_MAX, 'maximum amount of memory in megabytes')
def max_steps_param():
return ('max_steps', UINT, UINT_MAX, 'maximum number of steps')
PYG_GLOBALS = { 'UINT' : UINT, 'BOOL' : BOOL, 'DOUBLE' : DOUBLE, 'STRING' : STRING, 'SYMBOL' : SYMBOL,
'UINT_MAX' : UINT_MAX,
'max_memory_param' : max_memory_param,
'max_steps_param' : max_steps_param,
'def_module_params' : def_module_params }
def _execfile(file, globals=globals(), locals=locals()):
if sys.version < "2.7":
@ -2629,13 +2535,13 @@ def _execfile(file, globals=globals(), locals=locals()):
# Execute python auxiliary scripts that generate extra code for Z3.
def exec_pyg_scripts():
global CURRENT_PYG_HPP_DEST_DIR
for root, dirs, files in os.walk('src'):
for f in files:
if f.endswith('.pyg'):
script = os.path.join(root, f)
CURRENT_PYG_HPP_DEST_DIR = root
_execfile(script, PYG_GLOBALS)
generated_file = mk_genfile_common.mk_hpp_from_pyg(script, root)
if is_verbose():
print("Generated '{}'".format(generated_file))
# TODO: delete after src/ast/pattern/expr_pattern_match
# database.smt ==> database.h
@ -2643,17 +2549,9 @@ def mk_pat_db():
c = get_component(PATTERN_COMPONENT)
fin = os.path.join(c.src_dir, 'database.smt2')
fout = os.path.join(c.src_dir, 'database.h')
mk_pat_db_internal(fin, fout)
def mk_pat_db_internal(inputFilePath, outputFilePath):
with open(inputFilePath, 'r') as fin:
with open(outputFilePath, 'w') as fout:
fout.write('static char const g_pattern_database[] =\n')
for line in fin:
fout.write('"%s\\n"\n' % line.strip('\n'))
fout.write(';\n')
mk_genfile_common.mk_pat_db_internal(fin, fout)
if VERBOSE:
print("Generated '%s'" % outputFilePath)
print("Generated '{}'".format(fout))
# Update version numbers
def update_version():
@ -2704,82 +2602,14 @@ def mk_all_assembly_infos(major, minor, build, revision):
else:
raise MKException("Failed to find assembly template info file '%s'" % assembly_info_template)
ADD_TACTIC_DATA=[]
ADD_PROBE_DATA=[]
def ADD_TACTIC(name, descr, cmd):
global ADD_TACTIC_DATA
ADD_TACTIC_DATA.append((name, descr, cmd))
def ADD_PROBE(name, descr, cmd):
global ADD_PROBE_DATA
ADD_PROBE_DATA.append((name, descr, cmd))
# Generate an install_tactics.cpp at path.
# This file implements the procedure
# void install_tactics(tactic_manager & ctx)
# It installs all tactics in the given component (name) list cnames
# The procedure looks for ADD_TACTIC commands in the .h files of these components.
def mk_install_tactic_cpp(cnames, path):
component_src_dirs = []
for cname in cnames:
c = get_component(cname)
component_src_dirs.append(c.src_dir)
mk_install_tactic_cpp_internal(component_src_dirs, path)
def mk_install_tactic_cpp_internal(component_src_dirs, path):
global ADD_TACTIC_DATA, ADD_PROBE_DATA
ADD_TACTIC_DATA = []
ADD_PROBE_DATA = []
fullname = os.path.join(path, 'install_tactic.cpp')
fout = open(fullname, 'w')
fout.write('// Automatically generated file.\n')
fout.write('#include"tactic.h"\n')
fout.write('#include"tactic_cmds.h"\n')
fout.write('#include"cmd_context.h"\n')
tactic_pat = re.compile('[ \t]*ADD_TACTIC\(.*\)')
probe_pat = re.compile('[ \t]*ADD_PROBE\(.*\)')
for component_src_dir in component_src_dirs:
h_files = filter(lambda f: f.endswith('.h') or f.endswith('.hpp'), os.listdir(component_src_dir))
for h_file in h_files:
added_include = False
fin = open(os.path.join(component_src_dir, h_file), 'r')
for line in fin:
if tactic_pat.match(line):
if not added_include:
added_include = True
fout.write('#include"%s"\n' % h_file)
try:
exec(line.strip('\n '), globals())
except:
raise MKException("Failed processing ADD_TACTIC command at '%s'\n%s" % (fullname, line))
if probe_pat.match(line):
if not added_include:
added_include = True
fout.write('#include"%s"\n' % h_file)
try:
exec(line.strip('\n '), globals())
except:
raise MKException("Failed processing ADD_PROBE command at '%s'\n%s" % (fullname, line))
fin.close()
# First pass will just generate the tactic factories
idx = 0
for data in ADD_TACTIC_DATA:
fout.write('MK_SIMPLE_TACTIC_FACTORY(__Z3_local_factory_%s, %s);\n' % (idx, data[2]))
idx = idx + 1
fout.write('#define ADD_TACTIC_CMD(NAME, DESCR, FACTORY) ctx.insert(alloc(tactic_cmd, symbol(NAME), DESCR, alloc(FACTORY)))\n')
fout.write('#define ADD_PROBE(NAME, DESCR, PROBE) ctx.insert(alloc(probe_info, symbol(NAME), DESCR, PROBE))\n')
fout.write('void install_tactics(tactic_manager & ctx) {\n')
idx = 0
for data in ADD_TACTIC_DATA:
fout.write(' ADD_TACTIC_CMD("%s", "%s", __Z3_local_factory_%s);\n' % (data[0], data[1], idx))
idx = idx + 1
for data in ADD_PROBE_DATA:
fout.write(' ADD_PROBE("%s", "%s", %s);\n' % data)
fout.write('}\n')
fout.close()
component_src_dirs = []
for cname in cnames:
c = get_component(cname)
component_src_dirs.append(c.src_dir)
generated_file = mk_genfile_common.mk_install_tactic_cpp_internal(component_src_dirs, path)
if VERBOSE:
print("Generated '%s'" % fullname)
print("Generated '{}'".format(generated_file))
def mk_all_install_tactic_cpps():
if not ONLY_MAKEFILES:
@ -2790,67 +2620,14 @@ def mk_all_install_tactic_cpps():
cnames.append(c.name)
mk_install_tactic_cpp(cnames, c.src_dir)
# Generate an mem_initializer.cpp at path.
# This file implements the procedures
# void mem_initialize()
# void mem_finalize()
# These procedures are invoked by the Z3 memory_manager
def mk_mem_initializer_cpp(cnames, path):
component_src_dirs = []
for cname in cnames:
c = get_component(cname)
component_src_dirs.append(c.src_dir)
mk_mem_initializer_cpp_internal(component_src_dirs, path)
def mk_mem_initializer_cpp_internal(component_src_dirs, path):
initializer_cmds = []
finalizer_cmds = []
fullname = os.path.join(path, 'mem_initializer.cpp')
fout = open(fullname, 'w')
fout.write('// Automatically generated file.\n')
initializer_pat = re.compile('[ \t]*ADD_INITIALIZER\(\'([^\']*)\'\)')
# ADD_INITIALIZER with priority
initializer_prio_pat = re.compile('[ \t]*ADD_INITIALIZER\(\'([^\']*)\',[ \t]*(-?[0-9]*)\)')
finalizer_pat = re.compile('[ \t]*ADD_FINALIZER\(\'([^\']*)\'\)')
for component_src_dir in component_src_dirs:
h_files = filter(lambda f: f.endswith('.h') or f.endswith('.hpp'), os.listdir(component_src_dir))
for h_file in h_files:
added_include = False
fin = open(os.path.join(component_src_dir, h_file), 'r')
for line in fin:
m = initializer_pat.match(line)
if m:
if not added_include:
added_include = True
fout.write('#include"%s"\n' % h_file)
initializer_cmds.append((m.group(1), 0))
m = initializer_prio_pat.match(line)
if m:
if not added_include:
added_include = True
fout.write('#include"%s"\n' % h_file)
initializer_cmds.append((m.group(1), int(m.group(2))))
m = finalizer_pat.match(line)
if m:
if not added_include:
added_include = True
fout.write('#include"%s"\n' % h_file)
finalizer_cmds.append(m.group(1))
fin.close()
initializer_cmds.sort(key=lambda tup: tup[1])
fout.write('void mem_initialize() {\n')
for (cmd, prio) in initializer_cmds:
fout.write(cmd)
fout.write('\n')
fout.write('}\n')
fout.write('void mem_finalize() {\n')
for cmd in finalizer_cmds:
fout.write(cmd)
fout.write('\n')
fout.write('}\n')
fout.close()
component_src_dirs = []
for cname in cnames:
c = get_component(cname)
component_src_dirs.append(c.src_dir)
generated_file = mk_genfile_common.mk_mem_initializer_cpp_internal(component_src_dirs, path)
if VERBOSE:
print("Generated '%s'" % fullname)
print("Generated '{}'".format(generated_file))
def mk_all_mem_initializer_cpps():
if not ONLY_MAKEFILES:
@ -2861,61 +2638,14 @@ def mk_all_mem_initializer_cpps():
cnames.append(c.name)
mk_mem_initializer_cpp(cnames, c.src_dir)
# Generate an ``gparams_register_modules.cpp`` at path.
# This file implements the procedure
# void gparams_register_modules()
# This procedure is invoked by gparams::init()
def mk_gparams_register_modules(cnames, path):
component_src_dirs = []
for cname in cnames:
c = get_component(cname)
component_src_dirs.append(c.src_dir)
mk_gparams_register_modules_internal(component_src_dirs, path)
def mk_gparams_register_modules_internal(component_src_dirs, path):
cmds = []
mod_cmds = []
mod_descrs = []
fullname = os.path.join(path, 'gparams_register_modules.cpp')
fout = open(fullname, 'w')
fout.write('// Automatically generated file.\n')
fout.write('#include"gparams.h"\n')
reg_pat = re.compile('[ \t]*REG_PARAMS\(\'([^\']*)\'\)')
reg_mod_pat = re.compile('[ \t]*REG_MODULE_PARAMS\(\'([^\']*)\', *\'([^\']*)\'\)')
reg_mod_descr_pat = re.compile('[ \t]*REG_MODULE_DESCRIPTION\(\'([^\']*)\', *\'([^\']*)\'\)')
for component_src_dir in component_src_dirs:
h_files = filter(lambda f: f.endswith('.h') or f.endswith('.hpp'), os.listdir(component_src_dir))
for h_file in h_files:
added_include = False
fin = open(os.path.join(component_src_dir, h_file), 'r')
for line in fin:
m = reg_pat.match(line)
if m:
if not added_include:
added_include = True
fout.write('#include"%s"\n' % h_file)
cmds.append((m.group(1)))
m = reg_mod_pat.match(line)
if m:
if not added_include:
added_include = True
fout.write('#include"%s"\n' % h_file)
mod_cmds.append((m.group(1), m.group(2)))
m = reg_mod_descr_pat.match(line)
if m:
mod_descrs.append((m.group(1), m.group(2)))
fin.close()
fout.write('void gparams_register_modules() {\n')
for code in cmds:
fout.write('{ param_descrs d; %s(d); gparams::register_global(d); }\n' % code)
for (mod, code) in mod_cmds:
fout.write('{ param_descrs * d = alloc(param_descrs); %s(*d); gparams::register_module("%s", d); }\n' % (code, mod))
for (mod, descr) in mod_descrs:
fout.write('gparams::register_module_descr("%s", "%s");\n' % (mod, descr))
fout.write('}\n')
fout.close()
component_src_dirs = []
for cname in cnames:
c = get_component(cname)
component_src_dirs.append(c.src_dir)
generated_file = mk_genfile_common.mk_gparams_register_modules_internal(component_src_dirs, path)
if VERBOSE:
print("Generated '%s'" % fullname)
print("Generated '{}'".format(generated_file))
def mk_all_gparams_register_modules():
if not ONLY_MAKEFILES:
@ -2935,28 +2665,7 @@ def mk_def_file(c):
dot_h_c = c.find_file(dot_h, c.name)
api = os.path.join(dot_h_c.src_dir, dot_h)
export_header_files.append(api)
mk_def_file_internal(defname, dll_name, export_header_files)
def mk_def_file_internal(defname, dll_name, export_header_files):
pat1 = re.compile(".*Z3_API.*")
fout = open(defname, 'w')
fout.write('LIBRARY "%s"\nEXPORTS\n' % dll_name)
num = 1
for export_header_file in export_header_files:
api = open(export_header_file, 'r')
for line in api:
m = pat1.match(line)
if m:
words = re.split('\W+', line)
i = 0
for w in words:
if w == 'Z3_API':
f = words[i+1]
fout.write('\t%s @%s\n' % (f, num))
i = i + 1
num = num + 1
api.close()
fout.close()
mk_genfile_common.mk_def_file_internal(defname, dll_name, export_header_files)
if VERBOSE:
print("Generated '%s'" % defname)
@ -3049,174 +2758,21 @@ def mk_z3consts_py(api_files):
api_file_c = api_dll.find_file(api_file, api_dll.name)
api_file = os.path.join(api_file_c.src_dir, api_file)
full_path_api_files.append(api_file)
mk_z3consts_py_internal(full_path_api_files, Z3PY_SRC_DIR)
def mk_z3consts_py_internal(api_files, output_dir):
assert os.path.isdir(output_dir)
assert isinstance(api_files, list)
blank_pat = re.compile("^ *\r?$")
comment_pat = re.compile("^ *//.*$")
typedef_pat = re.compile("typedef enum *")
typedef2_pat = re.compile("typedef enum { *")
openbrace_pat = re.compile("{ *")
closebrace_pat = re.compile("}.*;")
z3consts = open(os.path.join(output_dir, 'z3consts.py'), 'w')
z3consts.write('# Automatically generated file\n\n')
for api_file in api_files:
api = open(api_file, 'r')
SEARCHING = 0
FOUND_ENUM = 1
IN_ENUM = 2
mode = SEARCHING
decls = {}
idx = 0
linenum = 1
for line in api:
m1 = blank_pat.match(line)
m2 = comment_pat.match(line)
if m1 or m2:
# skip blank lines and comments
linenum = linenum + 1
elif mode == SEARCHING:
m = typedef_pat.match(line)
if m:
mode = FOUND_ENUM
m = typedef2_pat.match(line)
if m:
mode = IN_ENUM
decls = {}
idx = 0
elif mode == FOUND_ENUM:
m = openbrace_pat.match(line)
if m:
mode = IN_ENUM
decls = {}
idx = 0
else:
assert False, "Invalid %s, line: %s" % (api_file, linenum)
else:
assert mode == IN_ENUM
words = re.split('[^\-a-zA-Z0-9_]+', line)
m = closebrace_pat.match(line)
if m:
name = words[1]
z3consts.write('# enum %s\n' % name)
for k in decls:
i = decls[k]
z3consts.write('%s = %s\n' % (k, i))
z3consts.write('\n')
mode = SEARCHING
elif len(words) <= 2:
assert False, "Invalid %s, line: %s" % (api_file, linenum)
else:
if words[2] != '':
if len(words[2]) > 1 and words[2][1] == 'x':
idx = int(words[2], 16)
else:
idx = int(words[2])
decls[words[1]] = idx
idx = idx + 1
linenum = linenum + 1
api.close()
z3consts.close()
generated_file = mk_genfile_common.mk_z3consts_py_internal(full_path_api_files, Z3PY_SRC_DIR)
if VERBOSE:
print("Generated '%s'" % os.path.join(output_dir, 'z3consts.py'))
print("Generated '{}".format(generated_file))
# Extract enumeration types from z3_api.h, and add .Net definitions
def mk_z3consts_dotnet(api_files):
blank_pat = re.compile("^ *\r?$")
comment_pat = re.compile("^ *//.*$")
typedef_pat = re.compile("typedef enum *")
typedef2_pat = re.compile("typedef enum { *")
openbrace_pat = re.compile("{ *")
closebrace_pat = re.compile("}.*;")
dotnet = get_component(DOTNET_COMPONENT)
DeprecatedEnums = [ 'Z3_search_failure' ]
z3consts = open(os.path.join(dotnet.src_dir, 'Enumerations.cs'), 'w')
z3consts.write('// Automatically generated file\n\n')
z3consts.write('using System;\n\n'
'#pragma warning disable 1591\n\n'
'namespace Microsoft.Z3\n'
'{\n')
full_path_api_files = []
for api_file in api_files:
api_file_c = dotnet.find_file(api_file, dotnet.name)
api_file = os.path.join(api_file_c.src_dir, api_file)
api = open(api_file, 'r')
SEARCHING = 0
FOUND_ENUM = 1
IN_ENUM = 2
mode = SEARCHING
decls = {}
idx = 0
linenum = 1
for line in api:
m1 = blank_pat.match(line)
m2 = comment_pat.match(line)
if m1 or m2:
# skip blank lines and comments
linenum = linenum + 1
elif mode == SEARCHING:
m = typedef_pat.match(line)
if m:
mode = FOUND_ENUM
m = typedef2_pat.match(line)
if m:
mode = IN_ENUM
decls = {}
idx = 0
elif mode == FOUND_ENUM:
m = openbrace_pat.match(line)
if m:
mode = IN_ENUM
decls = {}
idx = 0
else:
assert False, "Invalid %s, line: %s" % (api_file, linenum)
else:
assert mode == IN_ENUM
words = re.split('[^\-a-zA-Z0-9_]+', line)
m = closebrace_pat.match(line)
if m:
name = words[1]
if name not in DeprecatedEnums:
z3consts.write(' /// <summary>%s</summary>\n' % name)
z3consts.write(' public enum %s {\n' % name)
z3consts.write
for k in decls:
i = decls[k]
z3consts.write(' %s = %s,\n' % (k, i))
z3consts.write(' }\n\n')
mode = SEARCHING
elif len(words) <= 2:
assert False, "Invalid %s, line: %s" % (api_file, linenum)
else:
if words[2] != '':
if len(words[2]) > 1 and words[2][1] == 'x':
idx = int(words[2], 16)
else:
idx = int(words[2])
decls[words[1]] = idx
idx = idx + 1
linenum = linenum + 1
api.close()
z3consts.write('}\n');
z3consts.close()
full_path_api_files.append(api_file)
generated_file = mk_genfile_common.mk_z3consts_dotnet_internal(full_path_api_files, dotnet.src_dir)
if VERBOSE:
print("Generated '%s'" % os.path.join(dotnet.src_dir, 'Enumerations.cs'))
print("Generated '{}".format(generated_file))
# Extract enumeration types from z3_api.h, and add Java definitions
def mk_z3consts_java(api_files):
@ -3777,7 +3333,7 @@ class MakeRuleCmd(object):
cls.write_cmd(out, "mkdir -p {install_root}{dir}".format(
install_root=install_root,
dir=dir))
@classmethod
def _is_path_prefix_of(cls, temp_path, target_as_abs):
"""
@ -3906,4 +3462,3 @@ def configure_file(template_file_path, output_file_path, substitutions):
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -4,39 +4,33 @@ Reads a pyg file and emits the corresponding
C++ header file into the specified destination
directory.
"""
import mk_util
import mk_genfile_common
import argparse
import logging
import os
import sys
def main(args):
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("pyg_file", help="pyg file")
parser.add_argument("destination_dir", help="destination directory")
pargs = parser.parse_args(args)
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("pyg_file", help="pyg file")
parser.add_argument("destination_dir", help="destination directory")
pargs = parser.parse_args(args)
if not os.path.exists(pargs.pyg_file):
logging.error('"{}" does not exist'.format(pargs.pyg_file))
return 1
if not os.path.exists(pargs.pyg_file):
logging.error('"{}" does not exist'.format(pargs.pyg_file))
return 1
if not os.path.exists(pargs.destination_dir):
logging.error('"{}" does not exist'.format(pargs.destination_dir))
return 1
if not mk_genfile_common.check_dir_exists(pargs.destination_dir):
return 1
if not os.path.isdir(pargs.destination_dir):
logging.error('"{}" is not a directory'.format(pargs.destination_dir))
return 1
pyg_full_path = os.path.abspath(pargs.pyg_file)
destination_dir_full_path = os.path.abspath(pargs.destination_dir)
logging.info('Using {}'.format(pyg_full_path))
# Use the existing infrastructure to do this
mk_util.CURRENT_PYG_HPP_DEST_DIR = destination_dir_full_path
mk_util._execfile(pyg_full_path, mk_util.PYG_GLOBALS)
return 0
pyg_full_path = os.path.abspath(pargs.pyg_file)
destination_dir_full_path = os.path.abspath(pargs.destination_dir)
logging.info('Using {}'.format(pyg_full_path))
output = mk_genfile_common.mk_hpp_from_pyg(pyg_full_path, destination_dir_full_path)
logging.info('Generated "{}"'.format(output))
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
sys.exit(main(sys.argv[1:]))

View file

@ -38,6 +38,7 @@ public:
tactic_report report("ackermannize", *g);
fail_if_unsat_core_generation("ackermannize", g);
fail_if_proof_generation("ackermannize", g);
TRACE("ackermannize", g->display(tout << "in\n"););
expr_ref_vector flas(m);
const unsigned sz = g->size();
@ -48,6 +49,7 @@ public:
goal_ref resg(alloc(goal, *g, true));
const bool success = lackr.mk_ackermann(resg, m_lemma_limit);
if (!success) { // Just pass on the input unchanged
TRACE("ackermannize", tout << "ackermannize not run due to limit" << std::endl;);
result.reset();
result.push_back(g.get());
mc = 0;
@ -62,7 +64,7 @@ public:
}
resg->inc_depth();
TRACE("ackermannize", resg->display(tout););
TRACE("ackermannize", resg->display(tout << "out\n"););
SASSERT(resg->is_well_sorted());
}

View file

@ -53,7 +53,7 @@ lackr::~lackr() {
lbool lackr::operator() () {
SASSERT(m_sat);
init();
if (!init()) return l_undef;
const lbool rv = m_eager ? eager() : lazy();
if (rv == l_true) m_sat->get_model(m_model);
CTRACE("lackr", rv == l_true,
@ -63,7 +63,7 @@ lbool lackr::operator() () {
bool lackr::mk_ackermann(/*out*/goal_ref& g, double lemmas_upper_bound) {
if (lemmas_upper_bound <= 0) return false;
init();
if (!init()) return false;
if (lemmas_upper_bound != std::numeric_limits<double>::infinity()) {
const double lemmas_bound = ackr_helper::calculate_lemma_bound(m_fun2terms);
if (lemmas_bound > lemmas_upper_bound) return false;
@ -74,14 +74,15 @@ bool lackr::mk_ackermann(/*out*/goal_ref& g, double lemmas_upper_bound) {
return true;
}
void lackr::init() {
SASSERT(!m_is_init);
m_is_init = true;
bool lackr::init() {
SASSERT(!m_is_init);
params_ref simp_p(m_p);
m_simp.updt_params(simp_p);
m_info = alloc(ackr_info, m_m);
collect_terms();
if (!collect_terms()) return false;
abstract();
m_is_init = true;
return true;
}
//
@ -96,10 +97,8 @@ bool lackr::ackr(app * const t1, app * const t2) {
for (unsigned i = 0; i < sz; ++i) {
expr * const arg1 = t1->get_arg(i);
expr * const arg2 = t2->get_arg(i);
if (arg1 == arg2) continue; // quickly skip syntactically equal
if (m_ackr_helper.bvutil().is_numeral(arg1) && m_ackr_helper.bvutil().is_numeral(arg2)) {
// quickly abort if there are two distinct numerals
SASSERT(arg1 != arg2);
if (m_m.are_equal(arg1, arg2)) continue; // quickly skip syntactically equal
if (m_m.are_distinct(arg1, arg2)){ // quickly abort if there are two distinct (e.g. numerals)
TRACE("lackr", tout << "never eq\n";);
return false;
}
@ -110,7 +109,8 @@ bool lackr::ackr(app * const t1, app * const t2) {
SASSERT(a1 && a2);
TRACE("lackr", tout << "abstr1 " << mk_ismt2_pp(a1, m_m, 2) << "\n";);
TRACE("lackr", tout << "abstr2 " << mk_ismt2_pp(a2, m_m, 2) << "\n";);
expr_ref lhs(m_m.mk_and(eqs.size(), eqs.c_ptr()), m_m);
expr_ref lhs(m_m);
lhs = (eqs.size() == 1) ? eqs.get(0) : m_m.mk_and(eqs.size(), eqs.c_ptr());
TRACE("lackr", tout << "ackr constr lhs" << mk_ismt2_pp(lhs, m_m, 2) << "\n";);
expr_ref rhs(m_m.mk_eq(a1, a2),m_m);
TRACE("lackr", tout << "ackr constr rhs" << mk_ismt2_pp(rhs, m_m, 2) << "\n";);
@ -203,6 +203,7 @@ void lackr::push_abstraction() {
}
lbool lackr::eager() {
SASSERT(m_is_init);
push_abstraction();
TRACE("lackr", tout << "run sat 0\n"; );
const lbool rv0 = m_sat->check_sat(0, 0);
@ -217,6 +218,7 @@ lbool lackr::eager() {
}
lbool lackr::lazy() {
SASSERT(m_is_init);
lackr_model_constructor mc(m_m, m_info);
push_abstraction();
unsigned ackr_head = 0;
@ -247,7 +249,7 @@ lbool lackr::lazy() {
//
// Collect all uninterpreted terms, skipping 0-arity.
//
void lackr::collect_terms() {
bool lackr::collect_terms() {
ptr_vector<expr> stack;
expr * curr;
expr_mark visited;
@ -279,12 +281,11 @@ void lackr::collect_terms() {
}
break;
case AST_QUANTIFIER:
UNREACHABLE();
break;
return false; // quantifiers not supported
default:
UNREACHABLE();
return;
return false;
}
}
visited.reset();
return true;
}

View file

@ -95,7 +95,7 @@ class lackr {
lackr_stats& m_st;
bool m_is_init;
void init();
bool init();
lbool eager();
lbool lazy();
@ -118,6 +118,6 @@ class lackr {
//
// Collect all uninterpreted terms, skipping 0-arity.
//
void collect_terms();
bool collect_terms();
};
#endif /* LACKR_H_ */

View file

@ -34,11 +34,13 @@ struct lackr_model_constructor::imp {
, m_conflicts(conflicts)
, m_b_rw(m)
, m_bv_rw(m)
, m_evaluator(NULL)
, m_empty_model(m)
, m_ackr_helper(m)
{}
~imp() {
if (m_evaluator) dealloc(m_evaluator);
{
values2val_t::iterator i = m_values2val.begin();
const values2val_t::iterator e = m_values2val.end();
@ -60,15 +62,17 @@ struct lackr_model_constructor::imp {
//
// Returns true iff model was successfully constructed.
// Conflicts are saved as a side effect.
//
bool check() {
bool retv = true;
for (unsigned i = 0; i < m_abstr_model->get_num_constants(); i++) {
func_decl * const c = m_abstr_model->get_constant(i);
app * const term = m_info->find_term(c);
if (term) m_stack.push_back(term);
else m_stack.push_back(m_m.mk_const(c));
app * const _term = m_info->find_term(c);
expr * const term = _term ? _term : m_m.mk_const(c);
if (!check_term(term)) retv = false;
}
return run();
return retv;
}
@ -134,7 +138,7 @@ struct lackr_model_constructor::imp {
conflict_list& m_conflicts;
bool_rewriter m_b_rw;
bv_rewriter m_bv_rw;
scoped_ptr<model_evaluator> m_evaluator;
model_evaluator * m_evaluator;
model m_empty_model;
private:
struct val_info { expr * value; app * source_term; };
@ -144,6 +148,7 @@ struct lackr_model_constructor::imp {
app2val_t m_app2val;
ptr_vector<expr> m_stack;
ackr_helper m_ackr_helper;
expr_mark m_visited;
static inline val_info mk_val_info(expr* value, app* source_term) {
val_info rv;
@ -152,17 +157,23 @@ struct lackr_model_constructor::imp {
return rv;
}
//
// Performs congruence check on a given term.
bool check_term(expr * term) {
m_stack.push_back(term);
const bool rv = _check_stack();
m_stack.reset();
return rv;
}
// Performs congruence check on terms on the stack.
// (Currently stops upon the first failure).
// Returns true if and only if congruence check succeeded.
bool run() {
m_evaluator = alloc(model_evaluator, m_empty_model);
expr_mark visited;
// Stops upon the first failure.
// Returns true if and only if all congruence checks succeeded.
bool _check_stack() {
if (m_evaluator == NULL) m_evaluator = alloc(model_evaluator, m_empty_model);
expr * curr;
while (!m_stack.empty()) {
curr = m_stack.back();
if (visited.is_marked(curr)) {
if (m_visited.is_marked(curr)) {
m_stack.pop_back();
continue;
}
@ -173,8 +184,8 @@ struct lackr_model_constructor::imp {
return false;
case AST_APP: {
app * a = to_app(curr);
if (for_each_expr_args(m_stack, visited, a->get_num_args(), a->get_args())) {
visited.mark(a, true);
if (for_each_expr_args(m_stack, m_visited, a->get_num_args(), a->get_args())) {
m_visited.mark(a, true);
m_stack.pop_back();
if (!mk_value(a)) return false;
}
@ -212,7 +223,11 @@ struct lackr_model_constructor::imp {
for (unsigned i = 0; i < num; ++i) {
expr * val;
const bool b = eval_cached(to_app(args[i]), val); // TODO: OK conversion to_app?
CTRACE("model_constructor", !b, tout << "fail arg val(\n" << mk_ismt2_pp(args[i], m_m, 2); );
CTRACE("model_constructor", m_conflicts.empty() && !b, tout << "fail arg val(\n" << mk_ismt2_pp(args[i], m_m, 2) << '\n'; );
if (!b) {
// bailing out because args eval failed previously
return false;
}
TRACE("model_constructor", tout <<
"arg val " << i << "(\n" << mk_ismt2_pp(args[i], m_m, 2)
<< " : " << mk_ismt2_pp(val, m_m, 2) << '\n'; );

View file

@ -1129,7 +1129,7 @@ extern "C" {
case Z3_OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX;
case Z3_OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE;
case Z3_OP_SEQ_IN_RE: return Z3_OP_SEQ_IN_RE;
case Z3_OP_RE_PLUS: return Z3_OP_RE_PLUS;
case Z3_OP_RE_STAR: return Z3_OP_RE_STAR;
case Z3_OP_RE_OPTION: return Z3_OP_RE_OPTION;
@ -1186,9 +1186,14 @@ extern "C" {
case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV;
case OP_FPA_INTERNAL_BVWRAP:
case OP_FPA_INTERNAL_BVUNWRAP:
case OP_FPA_INTERNAL_MIN_I:
case OP_FPA_INTERNAL_MAX_I:
case OP_FPA_INTERNAL_MIN_UNSPECIFIED:
case OP_FPA_INTERNAL_MAX_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
return Z3_OP_UNINTERPRETED;
default:
UNREACHABLE();

View file

@ -604,8 +604,16 @@ namespace z3 {
/**
\brief Return true if this expression is a numeral.
Specialized functions also return representations for the numerals as
small integers, 64 bit integers or rational or decimal strings.
*/
bool is_numeral() const { return kind() == Z3_NUMERAL_AST; }
bool is_numeral_i64(__int64& i) const { bool r = 0 != Z3_get_numeral_int64(ctx(), m_ast, &i); check_error(); return r;}
bool is_numeral_u64(__uint64& i) const { bool r = 0 != Z3_get_numeral_uint64(ctx(), m_ast, &i); check_error(); return r;}
bool is_numeral_i(int& i) const { bool r = 0 != Z3_get_numeral_int(ctx(), m_ast, &i); check_error(); return r;}
bool is_numeral_u(unsigned& i) const { bool r = 0 != Z3_get_numeral_uint(ctx(), m_ast, &i); check_error(); return r;}
bool is_numeral(std::string& s) const { if (!is_numeral()) return false; s = Z3_get_numeral_string(ctx(), m_ast); check_error(); return true; }
bool is_numeral(std::string& s, unsigned precision) const { if (!is_numeral()) return false; s = Z3_get_numeral_decimal_string(ctx(), m_ast, precision); check_error(); return true; }
/**
\brief Return true if this expression is an application.
*/
@ -622,11 +630,86 @@ namespace z3 {
\brief Return true if this expression is a variable.
*/
bool is_var() const { return kind() == Z3_VAR_AST; }
/**
\brief Return true if expression is an algebraic number.
*/
bool is_algebraic() const { return 0 != Z3_is_algebraic_number(ctx(), m_ast); }
/**
\brief Return true if this expression is well sorted (aka type correct).
*/
bool is_well_sorted() const { bool r = Z3_is_well_sorted(ctx(), m_ast) != 0; check_error(); return r; }
/**
\brief Return string representation of numeral or algebraic number
This method assumes the expression is numeral or algebraic
\pre is_numeral() || is_algebraic()
*/
std::string get_decimal_string(int precision) const {
assert(is_numeral() || is_algebraic());
return std::string(Z3_get_numeral_decimal_string(ctx(), m_ast, precision));
}
/**
\brief Return int value of numeral, throw if result cannot fit in
machine int
\pre is_numeral()
*/
int get_numeral_int() const {
int result;
if (!is_numeral_i(result)) {
throw exception("numeral does not fit in machine int");
}
return result;
}
/**
\brief Return uint value of numeral, throw if result cannot fit in
machine uint
\pre is_numeral()
*/
unsigned get_numeral_uint() const {
assert(is_numeral());
unsigned result;
if (!is_numeral_u(result)) {
throw exception("numeral does not fit in machine uint");
}
return result;
}
/**
\brief Return __int64 value of numeral, throw if result cannot fit in
__int64
\pre is_numeral()
*/
__int64 get_numeral_int64() const {
assert(is_numeral());
__int64 result;
if (!is_numeral_i64(result)) {
throw exception("numeral does not fit in machine __int64");
}
return result;
}
/**
\brief Return __uint64 value of numeral, throw if result cannot fit in
__uint64
\pre is_numeral()
*/
__uint64 get_numeral_uint64() const {
assert(is_numeral());
__uint64 result;
if (!is_numeral_u64(result)) {
throw exception("numeral does not fit in machine __uint64");
}
return result;
}
operator Z3_app() const { assert(is_app()); return reinterpret_cast<Z3_app>(m_ast); }

View file

@ -3940,7 +3940,7 @@ class ArraySortRef(SortRef):
>>> A.range()
Bool
"""
return _to_sort_ref(Z3_get_array_sort_range(self.ctx_ref(), self.ast), self.ctx)
return _to_sort_ref(Z3_get_array_sort_range(self.ctx_ref(), self.ast), self.ctx)
class ArrayRef(ExprRef):
"""Array expressions. """
@ -4162,6 +4162,7 @@ def Select(a, i):
_z3_assert(is_array(a), "First argument must be a Z3 array expression")
return a[i]
def Map(f, *args):
"""Return a Z3 map array expression.
@ -8178,8 +8179,13 @@ class FPRef(ExprRef):
return self
def __neg__(self):
"""Create the Z3 expression `-self`."""
return FPRef(fpNeg(self))
"""Create the Z3 expression `-self`.
>>> x = FP('x', Float32())
>>> -x
-x
"""
return fpNeg(self)
def __div__(self, other):
"""Create the Z3 expression `self / other`.

View file

@ -664,3 +664,45 @@ algebraic_numbers::anum const & arith_util::to_irrational_algebraic_numeral(expr
SASSERT(is_irrational_algebraic_numeral(n));
return plugin().aw().to_anum(to_app(n)->get_decl());
}
expr_ref arith_util::mk_mul_simplify(expr_ref_vector const& args) {
return mk_mul_simplify(args.size(), args.c_ptr());
}
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);
break;
case 1:
result = args[0];
break;
default:
result = mk_mul(sz, args);
break;
}
return result;
}
expr_ref arith_util::mk_add_simplify(expr_ref_vector const& args) {
return mk_add_simplify(args.size(), args.c_ptr());
}
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);
break;
case 1:
result = args[0];
break;
default:
result = mk_add(sz, args);
break;
}
return result;
}

View file

@ -149,7 +149,6 @@ protected:
func_decl * m_mod_0_decl;
func_decl * m_u_asin_decl;
func_decl * m_u_acos_decl;
ptr_vector<app> m_small_ints;
ptr_vector<app> m_small_reals;
@ -416,6 +415,11 @@ public:
return m_manager.mk_eq(lhs, rhs);
}
expr_ref mk_mul_simplify(expr_ref_vector const& args);
expr_ref mk_mul_simplify(unsigned sz, expr* const* args);
expr_ref mk_add_simplify(expr_ref_vector const& args);
expr_ref mk_add_simplify(unsigned sz, expr* const* args);
};
#endif /* ARITH_DECL_PLUGIN_H_ */

View file

@ -1560,6 +1560,9 @@ bool ast_manager::is_unique_value(expr* e) const {
}
bool ast_manager::are_equal(expr * a, expr * b) const {
if (a == b) {
return true;
}
if (is_app(a) && is_app(b)) {
app* ap = to_app(a), *bp = to_app(b);
decl_plugin const * p = get_plugin(ap->get_family_id());

View file

@ -87,10 +87,10 @@ bool smt2_pp_environment::is_indexed_fdecl(func_decl * f) const {
}
bool smt2_pp_environment::is_sort_param(func_decl * f) const {
return
return
f->get_family_id() != null_family_id &&
f->get_num_parameters() == 1 &&
f->get_parameter(0).is_ast() &&
f->get_num_parameters() == 1 &&
f->get_parameter(0).is_ast() &&
is_sort(f->get_parameter(0).get_ast()) &&
f->get_range() == to_sort(f->get_parameter(0).get_ast());
}
@ -107,8 +107,8 @@ format * smt2_pp_environment::pp_fdecl_params(format * fname, func_decl * f) {
ptr_buffer<format> fs;
fs.push_back(fname);
for (unsigned i = 0; i < num; i++) {
SASSERT(f->get_parameter(i).is_int() ||
f->get_parameter(i).is_rational() ||
SASSERT(f->get_parameter(i).is_int() ||
f->get_parameter(i).is_rational() ||
(f->get_parameter(i).is_ast() && is_func_decl(f->get_parameter(i).get_ast())));
if (f->get_parameter(i).is_int())
fs.push_back(mk_int(get_manager(), f->get_parameter(i).get_int()));
@ -122,7 +122,7 @@ format * smt2_pp_environment::pp_fdecl_params(format * fname, func_decl * f) {
format * smt2_pp_environment::pp_fdecl(func_decl * f, unsigned & len) {
format * fname = pp_fdecl_name(f, len);
if (f->get_family_id() == null_family_id)
if (f->get_family_id() == null_family_id)
return fname;
if (is_sort_param(f)) {
len = UINT_MAX;
@ -247,7 +247,7 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits, bool u
buf << "(_ -oo " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
return mk_string(m, buf.c_str());
}
else if (fm.is_pzero(v)) {
else if (fm.is_pzero(v)) {
buf << "(_ +zero " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
return mk_string(m, buf.c_str());
}
@ -257,9 +257,9 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits, bool u
}
else if (use_float_real_lits)
{
buf << "((_ to_fp " << v.get().get_ebits() << " " <<
v.get().get_sbits() << ") RTZ " <<
fm.to_string(v).c_str() << ")";
buf << "((_ to_fp " << v.get().get_ebits() << " " <<
v.get().get_sbits() << ") RTZ " <<
fm.to_string(v).c_str() << ")";
return mk_string(m, buf.c_str());
}
else {
@ -283,7 +283,7 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits, bool u
app_ref e_sig(m);
e_sig = get_bvutil().mk_numeral(rational(sig), v.get().get_sbits() - 1);
body = mk_compose(m, body, pp_bv_literal(e_sig, use_bv_lits, false));
body = mk_compose(m, body, mk_string(m, ")"));
return body;
}
@ -356,7 +356,7 @@ format * smt2_pp_environment::pp_arith_literal(app * t, bool decimal, unsigned d
am.display_decimal(buffer, abs_val, decimal_prec);
}
else {
am.display_root_smt2(buffer, val2);
am.display_root_smt2(buffer, val2);
}
vf = mk_string(get_manager(), buffer.str().c_str());
return is_neg ? mk_neg(vf) : vf;
@ -378,7 +378,7 @@ format * smt2_pp_environment::pp_string_literal(app * t) {
buffer << encs[i];
}
}
buffer << "\"";
buffer << "\"";
return mk_string(get_manager(), buffer.str().c_str());
}
@ -395,7 +395,7 @@ format_ns::format * smt2_pp_environment::pp_sort(sort * s) {
// This method is redefined in cmd_context::pp_env: support for parametric sorts.
// Here, we just pretty print builtin sorts: Bool, Int, Real, BitVec and Array.
ast_manager & m = get_manager();
if (m.is_bool(s))
if (m.is_bool(s))
return mk_string(m, "Bool");
if (get_autil().is_int(s))
return mk_string(m, "Int");
@ -431,7 +431,7 @@ format_ns::format * smt2_pp_environment::pp_sort(sort * s) {
fs.push_back(pp_sort(to_sort(s->get_parameter(0).get_ast())));
return mk_seq1(m, fs.begin(), fs.end(), f2f(), get_sutil().is_seq(s)?"Seq":"Re");
}
return format_ns::mk_string(get_manager(), s->get_name().str().c_str());
return format_ns::mk_string(get_manager(), s->get_name().str().c_str());
}
typedef app_ref_vector format_ref_vector;
@ -449,8 +449,8 @@ class smt2_printer {
expr2alias * m_expr2alias; // expr -> position @ m_aliased_exprs, m_aliased_pps, m_aliased_lvls_names.
ptr_vector<expr> m_aliased_exprs;
format_ref_vector m_aliased_pps;
svector<std::pair<unsigned, symbol> > m_aliased_lvls_names;
unsigned m_next_alias_idx;
svector<std::pair<unsigned, symbol> > m_aliased_lvls_names;
unsigned m_next_alias_idx;
struct scope {
unsigned m_aliased_exprs_lim;
unsigned m_old_next_alias_idx;
@ -461,7 +461,7 @@ class smt2_printer {
svector<symbol> m_var_names;
typedef hashtable<symbol, symbol_hash_proc, symbol_eq_proc> symbol_set;
symbol_set m_var_names_set;
struct frame {
expr * m_curr;
unsigned m_idx;
@ -469,7 +469,7 @@ class smt2_printer {
bool m_use_alias; // if new aliases can be created
frame(expr * c, unsigned i, unsigned s, bool use_alias):m_curr(c), m_idx(i), m_spos(s), m_use_alias(use_alias) {}
};
svector<frame> m_frame_stack;
format_ref_vector m_format_stack;
struct info {
@ -517,7 +517,7 @@ class smt2_printer {
SASSERT(m_aliased_exprs.size() == m_aliased_pps.size());
SASSERT(m_aliased_exprs.size() == m_aliased_lvls_names.size());
unsigned idx = m_aliased_exprs.size();
m_expr2alias->insert(n, idx);
m_expr2alias->insert(n, idx);
m_aliased_exprs.push_back(n);
m_aliased_pps.push_back(nf);
m_aliased_lvls_names.push_back(std::make_pair(lvl, name));
@ -567,12 +567,12 @@ class smt2_printer {
buf.append(")");
f = mk_string(m(), buf.c_str());
}
m_format_stack.push_back(f);
m_format_stack.push_back(f);
m_info_stack.push_back(info(0, 1, 1));
}
format * pp_attribute(char const * attr, format * f) {
return mk_compose(m(),
return mk_compose(m(),
mk_string(m(), attr),
mk_indent(m(), static_cast<unsigned>(strlen(attr)), f));
}
@ -639,7 +639,7 @@ class smt2_printer {
}
return false;
}
void process_var(var * v) {
pp_var(v);
pop_frame();
@ -651,7 +651,7 @@ class smt2_printer {
expr * arg = t->get_arg(fr.m_idx);
fr.m_idx++;
if (pp_aliased(arg))
continue;
continue;
switch (arg->get_kind()) {
case AST_VAR:
pp_var(to_var(arg));
@ -679,11 +679,11 @@ class smt2_printer {
m_format_stack.shrink(fr.m_spos);
m_info_stack.shrink(fr.m_spos);
if (fr.m_use_alias && m_root != t &&
((f_info.m_depth >= m_pp_max_depth) ||
((f_info.m_depth >= m_pp_max_depth) ||
((f_info.m_weight >= m_pp_min_alias_size || is_quantifier(t)) && m_soccs.is_shared(t)))) {
symbol a = next_alias();
TRACE("smt2_pp", tout << "a: " << a << " depth: " << f_info.m_depth << ", weight: " << f_info.m_weight
<< ", lvl: " << f_info.m_lvl << " t: #" << t->get_id() << "\n" << mk_ll_pp(t, m())
TRACE("smt2_pp", tout << "a: " << a << " depth: " << f_info.m_depth << ", weight: " << f_info.m_weight
<< ", lvl: " << f_info.m_lvl << " t: #" << t->get_id() << "\n" << mk_ll_pp(t, m())
<< ", is-shared: " << m_soccs.is_shared(t) << "\n";);
register_alias(t, f, f_info.m_lvl, a);
m_format_stack.push_back(mk_string(m(), a.str().c_str()));
@ -745,7 +745,7 @@ class smt2_printer {
f = mk_group(m(), mk_compose(m(),
mk_indent(m(), 1, mk_compose(m(), mk_string(m(), "("), fname)),
mk_indent(m(), SMALL_INDENT, mk_compose(m(),
mk_seq<format**, f2f>(m(), it, end, f2f()),
mk_seq<format**, f2f>(m(), it, end, f2f()),
mk_string(m(), ")")))));
}
else {
@ -756,7 +756,7 @@ class smt2_printer {
mk_indent(m(), len + 2, mk_compose(m(),
mk_string(m(), " "),
first,
mk_seq<format**, f2f>(m(), it, end, f2f()),
mk_seq<format**, f2f>(m(), it, end, f2f()),
mk_string(m(), ")")))));
}
}
@ -832,7 +832,7 @@ class smt2_printer {
m_expr2alias = m_expr2alias_stack[lvl];
m_next_alias_idx = 1;
}
void end_scope() {
TRACE("pp_scope", tout << "[end-scope] before sz: " << m_aliased_exprs.size() << ", m_root: " << m_root << "\n";);
m_expr2alias->reset();
@ -853,7 +853,7 @@ class smt2_printer {
void register_var_names(quantifier * q) {
unsigned num_decls = q->get_num_decls();
for (unsigned i = 0; i < num_decls; i++) {
symbol name = ensure_quote_sym(q->get_decl_name(i));
symbol name = ensure_quote_sym(q->get_decl_name(i));
if (name.is_numerical()) {
unsigned idx = 1;
name = next_name("x", idx);
@ -914,7 +914,7 @@ class smt2_printer {
format * f_body = pp_let(m_format_stack.back(), num_lets);
// The current SMT2 frontend uses weight 1 as default.
#define MIN_WEIGHT 1
if (q->has_patterns() || q->get_weight() > MIN_WEIGHT ||
if (q->has_patterns() || q->get_weight() > MIN_WEIGHT ||
q->get_skid() != symbol::null || (q->get_qid() != symbol::null && !q->get_qid().is_numerical())) {
ptr_buffer<format> buf;
buf.push_back(f_body);
@ -952,12 +952,12 @@ class smt2_printer {
format * fs[2] = { f_decls, f_body };
char const * header = q->is_forall() ? "forall" : "exists";
format * f = mk_seq3<format**, f2f>(m(), fs, fs+2, f2f(), header, 1, SMALL_INDENT);
info f_info = m_info_stack.back();
f_info.m_lvl = 0; // quantifiers don't depend on any let-decls, pp_let added all dependencies for the body.
f_info.m_depth++;
f_info.m_weight += q->get_num_decls()*2 + num_lets*8;
unregister_var_names(q);
end_scope();
@ -1002,7 +1002,7 @@ class smt2_printer {
reset_stacks();
SASSERT(&(r.get_manager()) == &(fm()));
m_soccs(n);
TRACE("smt2_pp_shared",
TRACE("smt2_pp_shared",
tout << "shared terms for:\n" << mk_pp(n, m()) << "\n";
tout << "------>\n";
shared_occs::iterator it = m_soccs.begin_shared();
@ -1043,7 +1043,7 @@ public:
m_env(env),
m_soccs(m_manager),
m_root(0),
m_aliased_pps(fm()),
m_aliased_pps(fm()),
m_next_alias_idx(1),
m_format_stack(fm()) {
init_expr2alias_stack();
@ -1108,7 +1108,7 @@ public:
};
void mk_smt2_format(expr * n, smt2_pp_environment & env, params_ref const & p,
void mk_smt2_format(expr * n, smt2_pp_environment & env, params_ref const & p,
unsigned num_vars, char const * var_prefix,
format_ref & r, sbuffer<symbol> & var_names) {
smt2_printer pr(env, p);
@ -1125,13 +1125,13 @@ void mk_smt2_format(func_decl * f, smt2_pp_environment & env, params_ref const &
pr(f, r);
}
std::ostream & ast_smt2_pp(std::ostream & out, expr * n, smt2_pp_environment & env, params_ref const & p, unsigned indent,
std::ostream & ast_smt2_pp(std::ostream & out, expr * n, smt2_pp_environment & env, params_ref const & p, unsigned indent,
unsigned num_vars, char const * var_prefix) {
ast_manager & m = env.get_manager();
format_ref r(fm(m));
sbuffer<symbol> var_names;
mk_smt2_format(n, env, p, num_vars, var_prefix, r, var_names);
if (indent > 0)
if (indent > 0)
r = mk_indent(m, indent, r.get());
pp(out, r.get(), m, p);
return out;
@ -1142,7 +1142,7 @@ std::ostream & ast_smt2_pp(std::ostream & out, sort * s, smt2_pp_environment & e
format_ref r(fm(m));
sbuffer<symbol> var_names;
mk_smt2_format(s, env, p, r);
if (indent > 0)
if (indent > 0)
r = mk_indent(m, indent, r.get());
pp(out, r.get(), m, p);
return out;
@ -1153,7 +1153,7 @@ std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environmen
format_ref r(fm(m));
sbuffer<symbol> var_names;
mk_smt2_format(f, env, p, r);
if (indent > 0)
if (indent > 0)
r = mk_indent(m, indent, r.get());
pp(out, r.get(), m, p);
return out;
@ -1200,6 +1200,14 @@ std::ostream& operator<<(std::ostream& out, app_ref const& e) {
return out << mk_ismt2_pp(e.get(), e.get_manager());
}
std::ostream& operator<<(std::ostream& out, func_decl_ref const& e) {
return out << mk_ismt2_pp(e.get(), e.get_manager());
}
std::ostream& operator<<(std::ostream& out, sort_ref const& e) {
return out << mk_ismt2_pp(e.get(), e.get_manager());
}
std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e) {
for (unsigned i = 0; i < e.size(); ++i) {
out << mk_ismt2_pp(e[i], e.get_manager());
@ -1216,6 +1224,18 @@ std::ostream& operator<<(std::ostream& out, app_ref_vector const& e) {
return out;
}
std::ostream& operator<<(std::ostream& out, func_decl_ref_vector const& e) {
for (unsigned i = 0; i < e.size(); ++i)
out << mk_ismt2_pp(e[i], e.get_manager()) << "\n";
return out;
}
std::ostream& operator<<(std::ostream& out, sort_ref_vector const& e) {
for (unsigned i = 0; i < e.size(); ++i)
out << mk_ismt2_pp(e[i], e.get_manager()) << "\n";
return out;
}
#ifdef Z3DEBUG
void pp(expr const * n, ast_manager & m) {
std::cout << mk_ismt2_pp(const_cast<expr*>(n), m) << std::endl;

View file

@ -117,8 +117,13 @@ std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p);
std::ostream& operator<<(std::ostream& out, expr_ref const& e);
std::ostream& operator<<(std::ostream& out, app_ref const& e);
std::ostream& operator<<(std::ostream& out, func_decl_ref const& e);
std::ostream& operator<<(std::ostream& out, sort_ref const& e);
std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e);
std::ostream& operator<<(std::ostream& out, app_ref_vector const& e);
std::ostream& operator<<(std::ostream& out, func_decl_ref_vector const& e);
std::ostream& operator<<(std::ostream& out, sort_ref_vector const& e);
#endif

View file

@ -26,6 +26,7 @@ Revision History:
#include"bv_decl_plugin.h"
#include"array_decl_plugin.h"
#include"datatype_decl_plugin.h"
#include"fpa_decl_plugin.h"
#include"vector.h"
#include"for_each_ast.h"
#include"decl_collector.h"
@ -43,7 +44,7 @@ static const char m_predef_names[][8] = {
symbol smt_renaming::fix_symbol(symbol s, int k) {
std::ostringstream buffer;
char const * data = s.is_numerical() ? "" : s.bare_str();
if (data[0] && !data[1]) {
switch (data[0]) {
case '/': data = "op_div"; break;
@ -51,7 +52,7 @@ symbol smt_renaming::fix_symbol(symbol s, int k) {
default: break;
}
}
if (k == 0 && *data) {
if (s.is_numerical()) {
return s;
@ -63,10 +64,10 @@ symbol smt_renaming::fix_symbol(symbol s, int k) {
return s;
}
}
if (s.is_numerical()) {
buffer << s << k;
return symbol(buffer.str().c_str());
return symbol(buffer.str().c_str());
}
if (is_smt2_quoted_symbol(s)) {
@ -78,12 +79,12 @@ symbol smt_renaming::fix_symbol(symbol s, int k) {
if (k > 0) {
buffer << k;
}
return symbol(buffer.str().c_str());
}
bool smt_renaming::is_legal(char c) {
return c == '.' || c == '_' || c == '\''
return c == '.' || c == '_' || c == '\''
|| c == '?' || c == '!' || isalnum(c);
}
@ -134,11 +135,11 @@ symbol smt_renaming::get_symbol(symbol s0) {
if (m_translate.find(s0, s)) {
return s;
}
int k = 0;
do {
s = fix_symbol(s0, k++);
}
}
while (m_rev_translate.contains(s));
m_translate.insert(s0, s);
m_rev_translate.insert(s, s0);
@ -162,11 +163,13 @@ class smt_printer {
arith_util m_autil;
bv_util m_bvutil;
seq_util m_sutil;
fpa_util m_futil;
family_id m_basic_fid;
family_id m_bv_fid;
family_id m_arith_fid;
family_id m_array_fid;
family_id m_dt_fid;
family_id m_fpa_fid;
family_id m_label_fid;
symbol m_logic;
symbol m_AUFLIRA;
@ -176,7 +179,7 @@ class smt_printer {
expr* m_top;
bool is_bool(sort* s) {
return
return
m_basic_fid == s->get_family_id() &&
s->get_decl_kind() == BOOL_SORT;
}
@ -186,13 +189,13 @@ class smt_printer {
}
bool is_proof(sort* s) {
return
return
m_basic_fid == s->get_family_id() &&
s->get_decl_kind() == PROOF_SORT;
s->get_decl_kind() == PROOF_SORT;
}
bool is_proof(expr* e) {
return is_proof(m_manager.get_sort(e));
bool is_proof(expr* e) {
return is_proof(m_manager.get_sort(e));
}
void pp_id(expr* n) {
@ -236,8 +239,8 @@ class smt_printer {
}
bool is_sort_param(unsigned num_params, parameter const* params) {
return
num_params == 1 &&
return
num_params == 1 &&
params[0].is_ast() &&
is_sort(params[0].get_ast());
}
@ -253,14 +256,17 @@ class smt_printer {
m_out << "String";
return;
}
if (is_sort_symbol && sym != symbol("BitVec")) {
m_out << "(" << sym << " ";
if (is_sort_symbol &&
sym != symbol("BitVec") &&
sym != symbol("FloatingPoint") &&
sym != symbol("RoundingMode")) {
m_out << "(" << sym << " ";
}
else if (!is_sort_symbol && is_sort_param(num_params, params)) {
m_out << "(as " << sym << " ";
}
else {
m_out << "(_ " << sym << " ";
m_out << "(_ " << sym << " ";
}
}
else {
@ -302,13 +308,13 @@ class smt_printer {
m_out << "]";
}
}
bool is_auflira() const {
return m_logic == m_AUFLIRA;
}
void visit_sort(sort* s, bool bool2int = false) {
symbol sym;
symbol sym;
if (bool2int && is_bool(s) && !m_is_smt2) {
sym = symbol("Int");
} else if (s->is_sort_of(m_bv_fid, BV_SORT)) {
@ -326,7 +332,7 @@ class smt_printer {
else if (s->is_sort_of(m_array_fid, ARRAY_SORT) && m_is_smt2) {
sym = "Array";
}
else if (s->is_sort_of(m_array_fid, ARRAY_SORT) && !m_is_smt2) {
else if (s->is_sort_of(m_array_fid, ARRAY_SORT) && !m_is_smt2) {
unsigned num_params = s->get_num_parameters();
SASSERT(num_params >= 2);
if (is_auflira()) {
@ -341,12 +347,12 @@ class smt_printer {
}
sort* s1 = to_sort(s->get_parameter(0).get_ast());
sort* s2 = to_sort(s->get_parameter(1).get_ast());
if (num_params == 2 &&
if (num_params == 2 &&
s1->is_sort_of(m_bv_fid, BV_SORT) &&
s2->is_sort_of(m_bv_fid, BV_SORT)) {
m_out << "Array";
m_out << "[" << s1->get_parameter(0).get_int();
m_out << ":" << s2->get_parameter(0).get_int() << "]";
m_out << ":" << s2->get_parameter(0).get_int() << "]";
return;
}
m_out << "(Array ";
@ -379,7 +385,7 @@ class smt_printer {
}
}
void pp_arg(expr *arg, app *parent)
{
if (!m_is_smt2 && is_bool(arg) && is_var(arg) && parent->get_family_id() == m_basic_fid) {
@ -387,7 +393,7 @@ class smt_printer {
pp_marked_expr(arg);
m_out << " 0))";
} else if (!m_is_smt2 && is_bool(arg) && !is_var(arg) &&
parent->get_family_id() != m_basic_fid &&
parent->get_family_id() != m_basic_fid &&
parent->get_family_id() != m_dt_fid) {
m_out << "(ite ";
@ -403,9 +409,10 @@ class smt_printer {
bool is_int, pos;
buffer<symbol> names;
unsigned bv_size;
zstring s;
zstring s;
unsigned num_args = n->get_num_args();
func_decl* decl = n->get_decl();
scoped_mpf float_val(m_futil.fm());
if (m_autil.is_numeral(n, val, is_int)) {
if (val.is_neg()) {
val.neg();
@ -433,7 +440,7 @@ class smt_printer {
m_out << encs[i];
}
}
m_out << "\"";
m_out << "\"";
}
else if (m_bvutil.is_numeral(n, val, bv_size)) {
if (m_is_smt2) {
@ -443,7 +450,13 @@ class smt_printer {
m_out << "bv" << val << "[" << bv_size << "]";
}
}
else if (m_bvutil.is_bit2bool(n)) {
else if (m_futil.is_numeral(n, float_val)) {
m_out << "((_ to_fp " <<
float_val.get().get_ebits() << " " <<
float_val.get().get_sbits() << ") RTZ " <<
m_futil.fm().to_string(float_val).c_str() << ")";
}
else if (m_bvutil.is_bit2bool(n)) {
unsigned bit = n->get_decl()->get_parameter(0).get_int();
if (m_is_smt2) {
m_out << "(= ((_ extract " << bit << " " << bit << ") ";
@ -458,14 +471,14 @@ class smt_printer {
}
else if (m_manager.is_label(n, pos, names) && names.size() >= 1) {
if (m_is_smt2) {
m_out << "(! ";
m_out << "(! ";
pp_marked_expr(n->get_arg(0));
m_out << (pos?":lblpos":":lblneg") << " " << m_renaming.get_symbol(names[0]) << ")";
}
else {
m_out << "(" << (pos?"lblpos":"lblneg") << " " << m_renaming.get_symbol(names[0]) << " ";
expr* ch = n->get_arg(0);
pp_marked_expr(ch);
pp_marked_expr(ch);
m_out << ")";
}
}
@ -547,13 +560,13 @@ class smt_printer {
m_out << " ";
}
}
m_out << ")";
m_out << ")";
}
}
void print_no_lets(expr *e)
{
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, m_is_smt2, m_indent, m_num_var_names, m_var_names);
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, m_is_smt2, m_indent, m_num_var_names, m_var_names);
p(e);
}
@ -565,7 +578,7 @@ class smt_printer {
}
void visit_quantifier(quantifier* q) {
m_qlists.push_back(q);
m_qlists.push_back(q);
m_out << "(";
if (q->is_forall()) {
@ -588,12 +601,12 @@ class smt_printer {
if (m_is_smt2) {
m_out << ")";
}
if (m_is_smt2 && (q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) {
m_out << "(! ";
}
{
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, m_is_smt2, m_simplify_implies, m_indent, m_num_var_names, m_var_names);
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, m_is_smt2, m_simplify_implies, m_indent, m_num_var_names, m_var_names);
p(q->get_expr());
}
@ -644,7 +657,7 @@ class smt_printer {
void newline() {
unsigned i = m_indent;
m_out << "\n";
while (i > 0) { m_out << " "; --i; }
while (i > 0) { m_out << " "; --i; }
}
void visit_var(var* v) {
@ -685,15 +698,15 @@ class smt_printer {
case AST_QUANTIFIER:
visit_quantifier(to_quantifier(n));
break;
case AST_APP:
case AST_APP:
visit_app(to_app(n));
break;
case AST_VAR:
case AST_VAR:
visit_var(to_var(n));
break;
default:
UNREACHABLE();
}
}
}
void visit_expr(expr* n) {
@ -714,7 +727,7 @@ class smt_printer {
}
m_out << ")";
newline();
}
}
bool is_unit(expr* n) {
if (n->get_ref_count() <= 2 && is_small(n)) {
@ -724,9 +737,9 @@ class smt_printer {
return true;
}
switch(n->get_kind()) {
case AST_VAR:
case AST_VAR:
return true;
case AST_APP:
case AST_APP:
return to_app(n)->get_num_args() == 0;
default:
return false;
@ -749,9 +762,9 @@ class smt_printer {
return sz <= m_line_length;
}
switch(n->get_kind()) {
case AST_QUANTIFIER:
case AST_QUANTIFIER:
return false;
case AST_VAR:
case AST_VAR:
sz += 5;
return sz <= m_line_length;
case AST_APP: {
@ -777,14 +790,14 @@ class smt_printer {
}
default:
return false;
}
}
}
}
bool visit_children(expr* n) {
unsigned todo_size = m_todo.size();
switch(n->get_kind()) {
case AST_QUANTIFIER:
case AST_VAR:
case AST_QUANTIFIER:
case AST_VAR:
break;
case AST_APP: {
app* a = to_app(n);
@ -805,9 +818,9 @@ class smt_printer {
}
public:
smt_printer(std::ostream& out, ast_manager& m, ptr_vector<quantifier>& ql, smt_renaming& rn,
smt_printer(std::ostream& out, ast_manager& m, ptr_vector<quantifier>& ql, smt_renaming& rn,
symbol logic, bool no_lets, bool is_smt2, bool simplify_implies, unsigned indent, unsigned num_var_names = 0, char const* const* var_names = 0) :
m_out(out),
m_out(out),
m_manager(m),
m_qlists(ql),
m_renaming(rn),
@ -818,6 +831,7 @@ public:
m_autil(m),
m_bvutil(m),
m_sutil(m),
m_futil(m),
m_logic(logic),
m_AUFLIRA("AUFLIRA"),
// It's much easier to read those testcases with that.
@ -831,8 +845,9 @@ public:
m_arith_fid = m.mk_family_id("arith");
m_array_fid = m.mk_family_id("array");
m_dt_fid = m.mk_family_id("datatype");
m_fpa_fid = m.mk_family_id("fpa");
}
void operator()(expr* n) {
m_top = n;
if (!m_no_lets) {
@ -842,7 +857,7 @@ public:
m_todo.push_back(to_app(n)->get_arg(i));
}
break;
// Don't do this for quantifiers -- they need to have the body be
// Don't do this for quantifiers -- they need to have the body be
// visited when the m_qlist contains the relevant quantifier.
default:
break;
@ -867,7 +882,7 @@ public:
pp_marked_expr(n);
for (unsigned i = 0; i < m_num_lets; ++i) {
m_out << ")";
m_out << ")";
}
m_mark.reset();
m_num_lets = 0;
@ -880,7 +895,7 @@ public:
ptr_vector<func_decl> const* decls;
ptr_vector<sort> rec_sorts;
rec_sorts.push_back(s);
rec_sorts.push_back(s);
mark.mark(s, true);
// collect siblings and sorts that have not already been printed.
@ -905,20 +920,20 @@ public:
}
else {
pp_sort_decl(mark, s2);
}
}
}
}
}
}
if (m_is_smt2) {
// TBD: datatypes may be declared parametrically.
// TBD: datatypes may be declared parametrically.
// get access to parametric generalization, or print
// monomorphic specialization with a tag that gets reused at use-point.
m_out << "(declare-datatypes () (";
}
else {
m_out << ":datatypes (";
m_out << ":datatypes (";
}
for (unsigned si = 0; si < rec_sorts.size(); ++si) {
s = rec_sorts[si];
@ -928,7 +943,7 @@ public:
decls = util.get_datatype_constructors(s);
for (unsigned i = 0; i < decls->size(); ++i) {
func_decl* f = (*decls)[i];
func_decl* f = (*decls)[i];
ptr_vector<func_decl> const& accs = *util.get_constructor_accessors(f);
if (m_is_smt2 || accs.size() > 0) {
m_out << "(";
@ -937,7 +952,7 @@ public:
if (!accs.empty() || !m_is_smt2) {
m_out << " ";
}
for (unsigned j = 0; j < accs.size(); ++j) {
for (unsigned j = 0; j < accs.size(); ++j) {
func_decl* a = accs[j];
m_out << "(" << m_renaming.get_symbol(a->get_name()) << " ";
visit_sort(a->get_range());
@ -1081,7 +1096,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
ptr_vector<quantifier> ql;
ast_manager& m = m_manager;
decl_collector decls(m);
smt_renaming rn;
smt_renaming rn;
for (unsigned i = 0; i < m_assumptions.size(); ++i) {
decls.visit(m_assumptions[i].get());
@ -1089,7 +1104,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
for (unsigned i = 0; i < m_assumptions_star.size(); ++i) {
decls.visit(m_assumptions_star[i].get());
}
decls.visit(n);
decls.visit(n);
if (m.is_proof(n)) {
strm << "(";
@ -1099,7 +1114,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
}
if (m_source_info != symbol::null && m_source_info != symbol("")) {
strm << "; :source { " << m_source_info << " }\n";
}
}
if (m.is_bool(n)) {
strm << "(set-info :status " << m_status << ")\n";
}
@ -1119,7 +1134,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
if (!(*m_is_declared)(s)) {
smt_printer p(strm, m, ql, rn, m_logic, true, true, m_simplify_implies, 0);
p.pp_sort_decl(sort_mark, s);
}
}
}
for (unsigned i = 0; i < decls.get_num_decls(); ++i) {
@ -1147,7 +1162,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
strm << ")\n";
}
for (unsigned i = 0; i < m_assumptions_star.size(); ++i) {
for (unsigned i = 0; i < m_assumptions_star.size(); ++i) {
smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 1);
strm << "(assert\n ";
p(m_assumptions_star[i].get());
@ -1170,13 +1185,13 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
}
else {
p(n);
}
}
}
void ast_smt_pp::display(std::ostream& strm, expr* n) {
ptr_vector<quantifier> ql;
decl_collector decls(m_manager);
smt_renaming rn;
smt_renaming rn;
for (unsigned i = 0; i < m_assumptions.size(); ++i) {
decls.visit(m_assumptions[i].get());
@ -1185,7 +1200,7 @@ void ast_smt_pp::display(std::ostream& strm, expr* n) {
decls.visit(m_assumptions_star[i].get());
}
decls.visit(n);
strm << "(benchmark ";
if (m_benchmark_name != symbol::null) {
@ -1214,8 +1229,8 @@ void ast_smt_pp::display(std::ostream& strm, expr* n) {
sort* s = decls.get_sorts()[i];
if (!(*m_is_declared)(s)) {
smt_printer p(strm, m_manager, ql, rn, m_logic, true, false, m_simplify_implies, 0);
p.pp_sort_decl(sort_mark, s);
}
p.pp_sort_decl(sort_mark, s);
}
}
for (unsigned i = 0; i < decls.get_num_decls(); ++i) {
@ -1242,14 +1257,14 @@ void ast_smt_pp::display(std::ostream& strm, expr* n) {
expr * e = m_assumptions[i].get();
strm << ":assumption\n";
smt_printer p(strm, m_manager, ql, rn, m_logic, false, false, m_simplify_implies, 0);
p(e);
strm << "\n";
p(e);
strm << "\n";
}
for (unsigned i = 0; i < m_assumptions_star.size(); ++i) {
strm << ":assumption-core\n";
smt_printer p(strm, m_manager, ql, rn, m_logic, false, false, m_simplify_implies, 0);
p(m_assumptions_star[i].get());
p(m_assumptions_star[i].get());
strm << "\n";
}

View file

@ -170,7 +170,6 @@ app* mk_and(ast_manager & m, unsigned num_args, app * const * args) {
return to_app(mk_and(m, num_args, (expr* const*) args));
}
expr * mk_or(ast_manager & m, unsigned num_args, expr * const * args) {
if (num_args == 0)
return m.mk_false();
@ -188,10 +187,43 @@ expr * mk_not(ast_manager & m, expr * arg) {
expr * atom;
if (m.is_not(arg, atom))
return atom;
else if (m.is_true(arg))
return m.mk_false();
else if (m.is_false(arg))
return m.mk_true();
else
return m.mk_not(arg);
}
expr_ref push_not(const expr_ref& e) {
ast_manager& m = e.get_manager();
if (!is_app(e)) {
return expr_ref(m.mk_not(e), m);
}
app* a = to_app(e);
if (m.is_and(a)) {
if (a->get_num_args() == 0) {
return expr_ref(m.mk_false(), m);
}
expr_ref_vector args(m);
for (unsigned i = 0; i < a->get_num_args(); ++i) {
args.push_back(push_not(expr_ref(a->get_arg(i), m)));
}
return mk_or(args);
}
if (m.is_or(a)) {
if (a->get_num_args() == 0) {
return expr_ref(m.mk_true(), m);
}
expr_ref_vector args(m);
for (unsigned i = 0; i < a->get_num_args(); ++i) {
args.push_back(push_not(expr_ref(a->get_arg(i), m)));
}
return mk_and(args);
}
return expr_ref(mk_not(m, e), m);
}
expr * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args) {
expr_ref_buffer new_diseqs(m);
for (unsigned i = 0; i < num_args; i++) {
@ -201,6 +233,24 @@ expr * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args)
return mk_and(m, new_diseqs.size(), new_diseqs.c_ptr());
}
expr* mk_distinct(ast_manager& m, unsigned num_args, expr * const * args) {
switch (num_args) {
case 0:
case 1:
return m.mk_true();
case 2:
return m.mk_not(m.mk_eq(args[0], args[1]));
default:
return m.mk_distinct(num_args, args);
}
}
expr_ref mk_distinct(expr_ref_vector const& args) {
ast_manager& m = args.get_manager();
return expr_ref(mk_distinct(m, args.size(), args.c_ptr()), m);
}
void flatten_and(expr_ref_vector& result) {
ast_manager& m = result.get_manager();
expr* e1, *e2, *e3;

View file

@ -121,18 +121,29 @@ app * mk_or(ast_manager & m, unsigned num_args, app * const * args);
inline app_ref mk_or(app_ref_vector const& args) { return app_ref(mk_or(args.get_manager(), args.size(), args.c_ptr()), args.get_manager()); }
inline expr_ref mk_or(expr_ref_vector const& args) { return expr_ref(mk_or(args.get_manager(), args.size(), args.c_ptr()), args.get_manager()); }
/**
Return a if arg = (not a)
Retur (not arg) otherwise
*/
expr * mk_not(ast_manager & m, expr * arg);
/**
Negate and push over conjunction or disjunction.
*/
expr_ref push_not(const expr_ref& arg);
/**
Return the expression (and (not (= args[0] args[1])) (not (= args[0] args[2])) ... (not (= args[num_args-2] args[num_args-1])))
*/
expr * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args);
/**
Create simplified distinct term. Binary distinct becomes a single disequality.
*/
expr * mk_distinct(ast_manager& m, unsigned num_args, expr * const * args);
expr_ref mk_distinct(expr_ref_vector const& args);
/**
\brief Collect top-level conjunctions and disjunctions.
*/

View file

@ -865,6 +865,12 @@ sort * bv_util::mk_sort(unsigned bv_size) {
return m_manager.mk_sort(get_fid(), BV_SORT, 1, p);
}
unsigned bv_util::get_int2bv_size(parameter const& p) {
int sz;
VERIFY(m_plugin->get_int2bv_size(1, &p, sz));
return static_cast<unsigned>(sz);
}
app * bv_util::mk_bv2int(expr* e) {
sort* s = m_manager.mk_sort(m_manager.mk_family_id("arith"), INT_SORT);
parameter p(s);

View file

@ -234,7 +234,6 @@ protected:
func_decl * mk_mkbv(unsigned arity, sort * const * domain);
bool get_int2bv_size(unsigned num_parameters, parameter const * parameters, int & result);
func_decl * mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity);
@ -267,6 +266,8 @@ public:
virtual expr * get_some_value(sort * s);
bool get_int2bv_size(unsigned num_parameters, parameter const * parameters, int & result);
virtual bool is_considered_uninterpreted(func_decl * f) {
if (f->get_family_id() != get_family_id())
return false;
@ -390,6 +391,8 @@ public:
return static_cast<unsigned>(s->get_parameter(0).get_int());
}
unsigned get_bv_size(expr const * n) const { return get_bv_size(m_manager.get_sort(n)); }
unsigned get_int2bv_size(parameter const& p);
app * mk_ule(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_ULEQ, arg1, arg2); }
app * mk_sle(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_SLEQ, arg1, arg2); }
@ -427,6 +430,7 @@ public:
app * mk_bvumul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUMUL_NO_OVFL, n, m); }
app * mk_bv(unsigned n, expr* const* es) { return m_manager.mk_app(get_fid(), OP_MKBV, n, es); }
};
#endif /* BV_DECL_PLUGIN_H_ */

View file

@ -1000,3 +1000,25 @@ void datatype_util::display_datatype(sort *s0, std::ostream& strm) {
}
}
bool datatype_util::is_func_decl(datatype_op_kind k, unsigned num_params, parameter const* params, func_decl* f) {
bool eq =
f->get_decl_kind() == k &&
f->get_family_id() == m_family_id &&
f->get_num_parameters() == num_params;
for (unsigned i = 0; eq && i < num_params; ++i) {
eq = params[i] == f->get_parameter(i);
}
return eq;
}
bool datatype_util::is_constructor_of(unsigned num_params, parameter const* params, func_decl* f) {
return
num_params == 2 &&
m_family_id == f->get_family_id() &&
OP_DT_CONSTRUCTOR == f->get_decl_kind() &&
2 == f->get_num_parameters() &&
params[0] == f->get_parameter(0) &&
params[1] == f->get_parameter(1);
}

View file

@ -209,6 +209,8 @@ public:
func_decl * get_recognizer_constructor(func_decl * recognizer);
family_id get_family_id() const { return m_family_id; }
bool are_siblings(sort * s1, sort * s2);
bool is_func_decl(datatype_op_kind k, unsigned num_params, parameter const* params, func_decl* f);
bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f);
void reset();
void display_datatype(sort *s, std::ostream& strm);

View file

@ -22,6 +22,10 @@ Notes:
void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
if (num_bound == 0) {
result = n;
return;
}
expr * curr = 0, *b = 0;
SASSERT(n->get_ref_count() > 0);
@ -106,3 +110,27 @@ void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* cons
expr_abstractor abs(m);
abs(base, num_bound, bound, n, result);
}
expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
expr_ref result(m);
expr_abstract(m, 0, num_bound, (expr* const*)bound, n, result);
if (num_bound > 0) {
ptr_vector<sort> sorts;
svector<symbol> names;
for (unsigned i = 0; i < num_bound; ++i) {
sorts.push_back(m.get_sort(bound[i]));
names.push_back(bound[i]->get_decl()->get_name());
}
result = m.mk_quantifier(is_forall, num_bound, sorts.c_ptr(), names.c_ptr(), result);
}
return result;
}
expr_ref mk_forall(ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
return mk_quantifier(true, m, num_bound, bound, n);
}
expr_ref mk_exists(ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
return mk_quantifier(false, m, num_bound, bound, n);
}

View file

@ -33,6 +33,8 @@ public:
};
void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result);
expr_ref mk_forall(ast_manager& m, unsigned num_bound, app* const* bound, expr* n);
expr_ref mk_exists(ast_manager& m, unsigned num_bound, app* const* bound, expr* n);
#endif

View file

@ -980,6 +980,9 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args,
x = args[0];
y = args[1];
TRACE("fpa2bv_rem", tout << "X = " << mk_ismt2_pp(x, m) << std::endl;
tout << "Y = " << mk_ismt2_pp(y, m) << std::endl;);
expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m);
mk_nan(f, nan);
mk_nzero(f, nzero);
@ -1039,6 +1042,15 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args,
unpack(x, a_sgn, a_sig, a_exp, a_lz, true);
unpack(y, b_sgn, b_sig, b_exp, b_lz, true);
dbg_decouple("fpa2bv_rem_a_sgn", a_sgn);
dbg_decouple("fpa2bv_rem_a_sig", a_sig);
dbg_decouple("fpa2bv_rem_a_exp", a_exp);
dbg_decouple("fpa2bv_rem_a_lz", a_lz);
dbg_decouple("fpa2bv_rem_b_sgn", b_sgn);
dbg_decouple("fpa2bv_rem_b_sig", b_sig);
dbg_decouple("fpa2bv_rem_b_exp", b_exp);
dbg_decouple("fpa2bv_rem_b_lz", b_lz);
BVSLT(a_exp, b_exp, c6);
v6 = x;
@ -1052,15 +1064,25 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args,
unsigned int max_exp_diff_ui = (unsigned int)m_mpz_manager.get_uint64(max_exp_diff);
m_mpz_manager.del(max_exp_diff);
expr_ref a_exp_ext(m), b_exp_ext(m);
a_exp_ext = m_bv_util.mk_sign_extend(2, a_exp);
b_exp_ext = m_bv_util.mk_sign_extend(2, b_exp);
expr_ref a_lz_ext(m), b_lz_ext(m);
a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz);
b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz);
expr_ref exp_diff(m);
exp_diff = m_bv_util.mk_bv_sub(a_exp, b_exp);
exp_diff = m_bv_util.mk_bv_sub(
m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext),
m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext));
dbg_decouple("fpa2bv_rem_exp_diff", exp_diff);
// CMW: This creates _huge_ bit-vectors, which is potentially sub-optimal,
// but calculating this via rem = x - y * nearest(x/y) creates huge circuits.
expr_ref huge_sig(m), shifted_sig(m), huge_rem(m);
huge_sig = m_bv_util.mk_zero_extend(max_exp_diff_ui, a_sig);
shifted_sig = m_bv_util.mk_bv_shl(huge_sig, m_bv_util.mk_zero_extend(max_exp_diff_ui + sbits - ebits, exp_diff));
shifted_sig = m_bv_util.mk_bv_shl(huge_sig, m_bv_util.mk_zero_extend(max_exp_diff_ui + sbits - ebits - 2, exp_diff));
huge_rem = m_bv_util.mk_bv_urem(shifted_sig, m_bv_util.mk_zero_extend(max_exp_diff_ui, b_sig));
dbg_decouple("fpa2bv_rem_huge_rem", huge_rem);
@ -1068,7 +1090,8 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args,
res_sgn = a_sgn;
res_sig = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits, 0, huge_rem),
m_bv_util.mk_numeral(0, 3));
res_exp = m_bv_util.mk_sign_extend(2, b_exp);
res_exp = m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext);
// CMW: Actual rounding is not necessary here, this is
// just convenience to get rid of the extra bits.
@ -1155,38 +1178,34 @@ expr_ref fpa2bv_converter::mk_min_unspecified(func_decl * f, expr * x, expr * y)
expr_ref res(m);
// The only cases in which min is unspecified for is when the arguments are +0.0 and -0.0.
// There is no "hardware interpretation" for fp.min.
if (m_hi_fp_unspecified)
// The hardware interpretation is -0.0.
mk_nzero(f, res);
else {
std::pair<app*, app*> decls(0, 0);
if (!m_specials.find(f, decls)) {
decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
m_specials.insert(f, decls);
m.inc_ref(f);
m.inc_ref(decls.first);
m.inc_ref(decls.second);
}
expr_ref pn(m), np(m);
mk_fp(decls.first,
m_bv_util.mk_numeral(0, ebits),
m_bv_util.mk_numeral(0, sbits - 1),
pn);
mk_fp(decls.second,
m_bv_util.mk_numeral(0, ebits),
m_bv_util.mk_numeral(0, sbits - 1),
np);
expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m);
mk_is_pzero(x, x_is_pzero);
mk_is_nzero(y, x_is_nzero);
m_simp.mk_and(x_is_pzero, x_is_nzero, xyzero);
mk_ite(xyzero, pn, np, res);
std::pair<app*, app*> decls(0, 0);
if (!m_specials.find(f, decls)) {
decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
m_specials.insert(f, decls);
m.inc_ref(f);
m.inc_ref(decls.first);
m.inc_ref(decls.second);
}
expr_ref pn(m), np(m);
mk_fp(decls.first,
m_bv_util.mk_numeral(0, ebits),
m_bv_util.mk_numeral(0, sbits - 1),
pn);
mk_fp(decls.second,
m_bv_util.mk_numeral(0, ebits),
m_bv_util.mk_numeral(0, sbits - 1),
np);
expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m);
mk_is_pzero(x, x_is_pzero);
mk_is_nzero(y, x_is_nzero);
m_simp.mk_and(x_is_pzero, x_is_nzero, xyzero);
mk_ite(xyzero, pn, np, res);
return res;
}
@ -1244,38 +1263,34 @@ expr_ref fpa2bv_converter::mk_max_unspecified(func_decl * f, expr * x, expr * y)
expr_ref res(m);
// The only cases in which max is unspecified for is when the arguments are +0.0 and -0.0.
// There is no "hardware interpretation" for fp.max.
if (m_hi_fp_unspecified)
// The hardware interpretation is +0.0.
mk_pzero(f, res);
else {
std::pair<app*, app*> decls(0, 0);
if (!m_specials.find(f, decls)) {
decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
m_specials.insert(f, decls);
m.inc_ref(f);
m.inc_ref(decls.first);
m.inc_ref(decls.second);
}
expr_ref pn(m), np(m);
mk_fp(decls.first,
m_bv_util.mk_numeral(0, ebits),
m_bv_util.mk_numeral(0, sbits - 1),
pn);
mk_fp(decls.second,
m_bv_util.mk_numeral(0, ebits),
m_bv_util.mk_numeral(0, sbits - 1),
np);
expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m);
mk_is_pzero(x, x_is_pzero);
mk_is_nzero(y, x_is_nzero);
m_simp.mk_and(x_is_pzero, x_is_nzero, xyzero);
mk_ite(xyzero, pn, np, res);
std::pair<app*, app*> decls(0, 0);
if (!m_specials.find(f, decls)) {
decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
m_specials.insert(f, decls);
m.inc_ref(f);
m.inc_ref(decls.first);
m.inc_ref(decls.second);
}
expr_ref pn(m), np(m);
mk_fp(decls.first,
m_bv_util.mk_numeral(0, ebits),
m_bv_util.mk_numeral(0, sbits - 1),
pn);
mk_fp(decls.second,
m_bv_util.mk_numeral(0, ebits),
m_bv_util.mk_numeral(0, sbits - 1),
np);
expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m);
mk_is_pzero(x, x_is_pzero);
mk_is_nzero(y, x_is_nzero);
m_simp.mk_and(x_is_pzero, x_is_nzero, xyzero);
mk_ite(xyzero, pn, np, res);
return res;
}
@ -2366,7 +2381,7 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr *
void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result) {
TRACE("fpa2bv_to_fp_real", tout << "rm: " << mk_ismt2_pp(rm, m) << std::endl <<
"x: " << mk_ismt2_pp(x, m) << std::endl;);
"x: " << mk_ismt2_pp(x, m) << std::endl;);
SASSERT(m_util.is_float(s));
SASSERT(au().is_real(x) || au().is_int(x));
SASSERT(is_app_of(rm, m_util.get_family_id(), OP_FPA_INTERNAL_RM));
@ -2632,8 +2647,8 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar
tout << "exp2 = " << mk_ismt2_pp(exp2, m) << std::endl;);
result = m.mk_ite(x_is_zero, zero, res);
result = m.mk_ite(x_is_inf, mk_to_real_unspecified(), result);
result = m.mk_ite(x_is_nan, mk_to_real_unspecified(), result);
result = m.mk_ite(x_is_inf, mk_to_real_unspecified(ebits, sbits), result);
result = m.mk_ite(x_is_nan, mk_to_real_unspecified(ebits, sbits), result);
SASSERT(is_well_sorted(m, result));
}
@ -2912,9 +2927,29 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con
void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 1);
expr_ref x(m), x_is_nan(m);
expr * sgn, * s, * e;
split_fp(args[0], sgn, e, s);
result = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, e), s);
x = args[0];
split_fp(x, sgn, e, s);
mk_is_nan(x, x_is_nan);
sort * fp_srt = m.get_sort(x);
unsigned ebits = m_util.get_ebits(fp_srt);
unsigned sbits = m_util.get_sbits(fp_srt);
expr_ref nanv(m);
if (m_hi_fp_unspecified)
// The "hardware interpretation" is 01...10...01.
nanv = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1),
m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits),
m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2),
m_bv_util.mk_numeral(1, 1))));
else
nanv = mk_to_ieee_bv_unspecified(ebits, sbits);
result = m.mk_ite(x_is_nan, nanv, m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, e), s));
SASSERT(is_well_sorted(m, result));
}
void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result) {
@ -2950,7 +2985,7 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
c1 = m.mk_or(x_is_nan, x_is_inf, m.mk_and(x_is_neg, m.mk_not(x_is_nzero)));
else
c1 = m.mk_or(x_is_nan, x_is_inf);
v1 = mk_to_ubv_unspecified(bv_sz);
v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz);
dbg_decouple("fpa2bv_to_bv_c1", c1);
// +-Zero -> 0
@ -3049,8 +3084,8 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
dbg_decouple("fpa2bv_to_bv_rnd", rnd);
result = m.mk_ite(rnd_has_overflown, mk_to_ubv_unspecified(bv_sz), rnd);
result = m.mk_ite(c_in_limits, result, mk_to_ubv_unspecified(bv_sz));
result = m.mk_ite(rnd_has_overflown, mk_to_ubv_unspecified(ebits, sbits, bv_sz), rnd);
result = m.mk_ite(c_in_limits, result, mk_to_ubv_unspecified(ebits, sbits, bv_sz));
result = m.mk_ite(c2, v2, result);
result = m.mk_ite(c1, v1, result);
@ -3069,25 +3104,100 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg
mk_to_bv(f, num, args, true, result);
}
expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned width) {
expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
expr_ref result(m);
if (m_hi_fp_unspecified)
return expr_ref(m_bv_util.mk_numeral(0, width), m);
else
return expr_ref(m_util.mk_internal_to_ubv_unspecified(width), m);
result = m_bv_util.mk_numeral(0, width);
else {
app_ref unspec(m);
unspec = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width);
func_decl * unspec_fd = unspec->get_decl();
func_decl * fd;
if (!m_uf2bvuf.find(unspec_fd, fd)) {
app_ref bvc(m);
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
fd = bvc->get_decl();
m_uf2bvuf.insert(unspec_fd, fd);
m.inc_ref(unspec_fd);
m.inc_ref(fd);
}
result = m.mk_const(fd);
}
return result;
}
expr_ref fpa2bv_converter::mk_to_sbv_unspecified(unsigned width) {
expr_ref fpa2bv_converter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
expr_ref result(m);
if (m_hi_fp_unspecified)
return expr_ref(m_bv_util.mk_numeral(0, width), m);
else
return expr_ref(m_util.mk_internal_to_sbv_unspecified(width), m);
result = m_bv_util.mk_numeral(0, width);
else {
app_ref unspec(m);
unspec = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width);
func_decl * unspec_fd = unspec->get_decl();
func_decl * fd;
if (!m_uf2bvuf.find(unspec_fd, fd)) {
app_ref bvc(m);
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
fd = bvc->get_decl();
m_uf2bvuf.insert(unspec_fd, fd);
m.inc_ref(unspec_fd);
m.inc_ref(fd);
}
result = m.mk_const(fd);
}
return result;
}
expr_ref fpa2bv_converter::mk_to_real_unspecified() {
expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits) {
expr_ref result(m);
if (m_hi_fp_unspecified)
return expr_ref(m_arith_util.mk_numeral(rational(0), false), m);
else
return expr_ref(m_util.mk_internal_to_real_unspecified(), m);
result = m_arith_util.mk_numeral(rational(0), false);
else {
app_ref unspec(m);
unspec = m_util.mk_internal_to_real_unspecified(ebits, sbits);
func_decl * unspec_fd = unspec->get_decl();
func_decl * fd;
if (!m_uf2bvuf.find(unspec_fd, fd)) {
app_ref bvc(m);
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
fd = bvc->get_decl();
m_uf2bvuf.insert(unspec_fd, fd);
m.inc_ref(unspec_fd);
m.inc_ref(fd);
}
result = m.mk_const(fd);
result = unspec;
}
return result;
}
expr_ref fpa2bv_converter::mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits) {
expr_ref result(m);
app_ref unspec(m);
unspec = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits);
func_decl * unspec_fd = unspec->get_decl();
func_decl * fd;
if (!m_uf2bvuf.find(unspec_fd, fd)) {
app_ref bvc(m);
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
fd = bvc->get_decl();
m_uf2bvuf.insert(unspec_fd, fd);
m.inc_ref(unspec_fd);
m.inc_ref(fd);
}
result = m.mk_const(fd);
app_ref mask(m), extra(m);
mask = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1),
m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits),
m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2),
m_bv_util.mk_numeral(1, 1))));
expr * args[2] = { result, mask };
extra = m.mk_eq(m.mk_app(m_bv_util.get_fid(), OP_BAND, 2, args), mask);
m_extra_assertions.push_back(extra);
return result;
}
void fpa2bv_converter::mk_rm(expr * bv3, expr_ref & result) {

View file

@ -134,9 +134,10 @@ public:
void mk_max_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
virtual expr_ref mk_max_unspecified(func_decl * f, expr * x, expr * y);
expr_ref mk_to_ubv_unspecified(unsigned width);
expr_ref mk_to_sbv_unspecified(unsigned width);
expr_ref mk_to_real_unspecified();
expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits);
expr_ref mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits);
void reset(void);

View file

@ -28,7 +28,7 @@ fpa2bv_rewriter_cfg::fpa2bv_rewriter_cfg(ast_manager & m, fpa2bv_converter & c,
m_manager(m),
m_out(m),
m_conv(c),
m_bindings(m)
m_bindings(m)
{
updt_params(p);
// We need to make sure that the mananger has the BV plugin loaded.
@ -49,7 +49,7 @@ void fpa2bv_rewriter_cfg::updt_params(params_ref const & p) {
updt_local_params(p);
}
bool fpa2bv_rewriter_cfg::max_steps_exceeded(unsigned num_steps) const {
bool fpa2bv_rewriter_cfg::max_steps_exceeded(unsigned num_steps) const {
cooperate("fpa2bv");
return num_steps > m_max_steps;
}
@ -57,22 +57,22 @@ bool fpa2bv_rewriter_cfg::max_steps_exceeded(unsigned num_steps) const {
br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
TRACE("fpa2bv_rw", tout << "APP: " << f->get_name() << std::endl; );
if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_float(f->get_range())) {
m_conv.mk_const(f, result);
return BR_DONE;
}
if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_rm(f->get_range())) {
m_conv.mk_rm_const(f, result);
return BR_DONE;
}
if (m().is_eq(f)) {
SASSERT(num == 2);
TRACE("fpa2bv_rw", tout << "(= " << mk_ismt2_pp(args[0], m()) << " " <<
TRACE("fpa2bv_rw", tout << "(= " << mk_ismt2_pp(args[0], m()) << " " <<
mk_ismt2_pp(args[1], m()) << ")" << std::endl;);
SASSERT(m().get_sort(args[0]) == m().get_sort(args[1]));
SASSERT(m().get_sort(args[0]) == m().get_sort(args[1]));
sort * ds = f->get_domain()[0];
if (m_conv.is_float(ds)) {
m_conv.mk_eq(args[0], args[1], result);
@ -100,7 +100,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
}
return BR_FAILED;
}
if (m_conv.is_float_family(f)) {
switch (f->get_decl_kind()) {
case OP_FPA_RM_NEAREST_TIES_TO_AWAY:
@ -108,7 +108,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
case OP_FPA_RM_TOWARD_NEGATIVE:
case OP_FPA_RM_TOWARD_POSITIVE:
case OP_FPA_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f, result); return BR_DONE;
case OP_FPA_NUM: m_conv.mk_numeral(f, num, args, result); return BR_DONE;
case OP_FPA_NUM: m_conv.mk_numeral(f, num, args, result); return BR_DONE;
case OP_FPA_PLUS_INF: m_conv.mk_pinf(f, result); return BR_DONE;
case OP_FPA_MINUS_INF: m_conv.mk_ninf(f, result); return BR_DONE;
case OP_FPA_PLUS_ZERO: m_conv.mk_pzero(f, result); return BR_DONE;
@ -120,7 +120,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
case OP_FPA_MUL: m_conv.mk_mul(f, num, args, result); return BR_DONE;
case OP_FPA_DIV: m_conv.mk_div(f, num, args, result); return BR_DONE;
case OP_FPA_REM: m_conv.mk_rem(f, num, args, result); return BR_DONE;
case OP_FPA_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE;
case OP_FPA_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE;
case OP_FPA_FMA: m_conv.mk_fma(f, num, args, result); return BR_DONE;
case OP_FPA_SQRT: m_conv.mk_sqrt(f, num, args, result); return BR_DONE;
case OP_FPA_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, num, args, result); return BR_DONE;
@ -129,7 +129,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
case OP_FPA_GT: m_conv.mk_float_gt(f, num, args, result); return BR_DONE;
case OP_FPA_LE: m_conv.mk_float_le(f, num, args, result); return BR_DONE;
case OP_FPA_GE: m_conv.mk_float_ge(f, num, args, result); return BR_DONE;
case OP_FPA_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE;
case OP_FPA_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE;
case OP_FPA_IS_NAN: m_conv.mk_is_nan(f, num, args, result); return BR_DONE;
case OP_FPA_IS_INF: m_conv.mk_is_inf(f, num, args, result); return BR_DONE;
case OP_FPA_IS_NORMAL: m_conv.mk_is_normal(f, num, args, result); return BR_DONE;
@ -143,21 +143,23 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
case OP_FPA_TO_SBV: m_conv.mk_to_sbv(f, num, args, result); return BR_DONE;
case OP_FPA_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE;
case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE;
case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_REWRITE_FULL;
case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_REWRITE_FULL;
case OP_FPA_INTERNAL_MIN_UNSPECIFIED: result = m_conv.mk_min_unspecified(f, args[0], args[1]); return BR_DONE;
case OP_FPA_INTERNAL_MAX_UNSPECIFIED: result = m_conv.mk_max_unspecified(f, args[0], args[1]); return BR_DONE;
case OP_FPA_INTERNAL_MIN_I: m_conv.mk_min_i(f, num, args, result); return BR_DONE;
case OP_FPA_INTERNAL_MAX_I: m_conv.mk_max_i(f, num, args, result); return BR_DONE;
case OP_FPA_INTERNAL_RM:
case OP_FPA_INTERNAL_BVWRAP:
case OP_FPA_INTERNAL_BVUNWRAP:
case OP_FPA_INTERNAL_BVWRAP:
case OP_FPA_INTERNAL_BVUNWRAP:
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: return BR_FAILED;
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
return BR_FAILED;
default:
TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n";
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;);
@ -167,27 +169,27 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
else {
SASSERT(!m_conv.is_float_family(f));
bool is_float_uf = m_conv.is_float(f->get_range()) || m_conv.is_rm(f->get_range());
for (unsigned i = 0; i < f->get_arity(); i++) {
sort * di = f->get_domain()[i];
is_float_uf |= m_conv.is_float(di) || m_conv.is_rm(di);
}
if (is_float_uf) {
m_conv.mk_uninterpreted_function(f, num, args, result);
return BR_DONE;
}
}
return BR_FAILED;
}
bool fpa2bv_rewriter_cfg::pre_visit(expr * t)
{
TRACE("fpa2bv", tout << "pre_visit: " << mk_ismt2_pp(t, m()) << std::endl;);
if (is_quantifier(t)) {
quantifier * q = to_quantifier(t);
if (is_quantifier(t)) {
quantifier * q = to_quantifier(t);
TRACE("fpa2bv", tout << "pre_visit quantifier [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m()) << std::endl;);
sort_ref_vector new_bindings(m_manager);
for (unsigned i = 0 ; i < q->get_num_decls(); i++)
@ -199,9 +201,9 @@ bool fpa2bv_rewriter_cfg::pre_visit(expr * t)
}
bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
@ -221,7 +223,7 @@ bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
name_buffer.reset();
name_buffer << n << ".bv";
new_decl_names.push_back(symbol(name_buffer.c_str()));
new_decl_sorts.push_back(m_conv.bu().mk_sort(sbits+ebits));
new_decl_sorts.push_back(m_conv.bu().mk_sort(sbits+ebits));
}
else {
new_decl_sorts.push_back(s);
@ -232,19 +234,19 @@ bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(),
old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns);
result_pr = 0;
m_bindings.shrink(old_sz);
TRACE("fpa2bv", tout << "reduce_quantifier[" << old_q->get_depth() << "]: " <<
m_bindings.shrink(old_sz);
TRACE("fpa2bv", tout << "reduce_quantifier[" << old_q->get_depth() << "]: " <<
mk_ismt2_pp(old_q->get_expr(), m()) << std::endl <<
" new body: " << mk_ismt2_pp(new_body, m()) << std::endl;
tout << "result = " << mk_ismt2_pp(result, m()) << std::endl;);
tout << "result = " << mk_ismt2_pp(result, m()) << std::endl;);
return true;
}
bool fpa2bv_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref & result_pr) {
bool fpa2bv_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref & result_pr) {
if (t->get_idx() >= m_bindings.size())
return false;
// unsigned inx = m_bindings.size() - t->get_idx() - 1;
// unsigned inx = m_bindings.size() - t->get_idx() - 1;
expr_ref new_exp(m());
sort * s = t->get_sort();
if (m_conv.is_float(s))
@ -255,14 +257,14 @@ bool fpa2bv_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref & res
new_var = m().mk_var(t->get_idx(), m_conv.bu().mk_sort(sbits+ebits));
m_conv.mk_fp(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var),
m_conv.bu().mk_extract(ebits - 1, 0, new_var),
m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var),
m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var),
new_exp);
}
else
new_exp = m().mk_var(t->get_idx(), s);
result = new_exp;
result_pr = 0;
result_pr = 0;
TRACE("fpa2bv", tout << "reduce_var: " << mk_ismt2_pp(t, m()) << " -> " << mk_ismt2_pp(result, m()) << std::endl;);
return true;
}

View file

@ -593,7 +593,7 @@ func_decl * fpa_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_paramet
}
func_decl * fpa_decl_plugin::mk_fp(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
unsigned arity, sort * const * domain, sort * range) {
if (arity != 3)
m_manager->raise_exception("invalid number of arguments to fp");
if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) ||
@ -610,7 +610,7 @@ func_decl * fpa_decl_plugin::mk_fp(decl_kind k, unsigned num_parameters, paramet
}
func_decl * fpa_decl_plugin::mk_to_ubv(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
unsigned arity, sort * const * domain, sort * range) {
SASSERT(m_bv_plugin);
if (arity != 2)
m_manager->raise_exception("invalid number of arguments to fp.to_ubv");
@ -631,7 +631,7 @@ func_decl * fpa_decl_plugin::mk_to_ubv(decl_kind k, unsigned num_parameters, par
}
func_decl * fpa_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
unsigned arity, sort * const * domain, sort * range) {
SASSERT(m_bv_plugin);
if (arity != 2)
m_manager->raise_exception("invalid number of arguments to fp.to_sbv");
@ -671,9 +671,9 @@ func_decl * fpa_decl_plugin::mk_to_ieee_bv(decl_kind k, unsigned num_parameters,
unsigned float_sz = domain[0]->get_parameter(0).get_int() + domain[0]->get_parameter(1).get_int();
parameter ps[] = { parameter(float_sz) };
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps);
sort * bv_srt = m_bv_plugin->mk_sort(BV_SORT, 1, ps);
symbol name("to_ieee_bv");
return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k));
}
func_decl * fpa_decl_plugin::mk_internal_rm(decl_kind k, unsigned num_parameters, parameter const * parameters,
@ -693,7 +693,7 @@ func_decl * fpa_decl_plugin::mk_internal_rm(decl_kind k, unsigned num_parameters
func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 1)
m_manager->raise_exception("invalid number of arguments to internal_bv_wrap");
m_manager->raise_exception("invalid number of arguments to bv_wrap");
if (!is_float_sort(domain[0]) && !is_rm_sort(domain[0]))
m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint or RoundingMode sort");
@ -714,7 +714,7 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param
func_decl * fpa_decl_plugin::mk_internal_bv_unwrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 1)
m_manager->raise_exception("invalid number of arguments to internal_bv_unwrap");
m_manager->raise_exception("invalid number of arguments to bv_unwrap");
if (!is_sort_of(domain[0], m_bv_fid, BV_SORT))
m_manager->raise_exception("sort mismatch, expected argument of bitvector sort");
if (!is_float_sort(range) && !is_rm_sort(range))
@ -728,12 +728,12 @@ func_decl * fpa_decl_plugin::mk_internal_to_ubv_unspecified(
unsigned arity, sort * const * domain, sort * range) {
if (arity != 0)
m_manager->raise_exception("invalid number of arguments to fp.to_ubv_unspecified");
if (num_parameters != 1)
m_manager->raise_exception("invalid number of parameters to fp.to_ubv_unspecified; expecting 1");
if (!parameters[0].is_int())
m_manager->raise_exception("invalid parameters type provided to fp.to_ubv_unspecified; expecting an integer");
if (num_parameters != 3)
m_manager->raise_exception("invalid number of parameters to fp.to_ubv_unspecified; expecting 3");
if (!parameters[0].is_int() || !parameters[1].is_int() || !parameters[2].is_int())
m_manager->raise_exception("invalid parameters type provided to fp.to_ubv_unspecified; expecting 3 integers");
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, parameters);
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, &parameters[2]);
return m_manager->mk_func_decl(symbol("fp.to_ubv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
}
@ -741,12 +741,13 @@ func_decl * fpa_decl_plugin::mk_internal_to_sbv_unspecified(
decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 0)
m_manager->raise_exception("invalid number of arguments to internal_to_sbv_unspecified");
if (num_parameters != 1)
m_manager->raise_exception("invalid number of parameters to fp.to_sbv_unspecified; expecting 1");
if (!parameters[0].is_int())
m_manager->raise_exception("invalid parameters type provided to fp.to_sbv_unspecified; expecting an integer");
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, parameters);
m_manager->raise_exception("invalid number of arguments to fp.to_sbv_unspecified");
if (num_parameters != 3)
m_manager->raise_exception("invalid number of parameters to fp.to_sbv_unspecified; expecting 3");
if (!parameters[0].is_int() || !parameters[1].is_int() || !parameters[2].is_int())
m_manager->raise_exception("invalid parameters type provided to fp.to_sbv_unspecified; expecting 3 integers");
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, &parameters[2]);
return m_manager->mk_func_decl(symbol("fp.to_sbv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
}
@ -754,13 +755,32 @@ func_decl * fpa_decl_plugin::mk_internal_to_real_unspecified(
decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 0)
m_manager->raise_exception("invalid number of arguments to internal_to_real_unspecified");
m_manager->raise_exception("invalid number of arguments to fp.to_real_unspecified");
if (num_parameters != 2)
m_manager->raise_exception("invalid number of parameters to fp.to_real_unspecified; expecting 2");
if (!parameters[0].is_int() || !parameters[1].is_int())
m_manager->raise_exception("invalid parameters type provided to fp.to_real_unspecified; expecting 2 integers");
if (!is_sort_of(range, m_arith_fid, REAL_SORT))
m_manager->raise_exception("sort mismatch, expected range of FloatingPoint sort");
m_manager->raise_exception("sort mismatch, expected range of Real sort");
return m_manager->mk_func_decl(symbol("fp.to_real_unspecified"), 0, domain, m_real_sort, func_decl_info(m_family_id, k, num_parameters, parameters));
}
func_decl * fpa_decl_plugin::mk_internal_to_ieee_bv_unspecified(
decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 0)
m_manager->raise_exception("invalid number of arguments to to_ieee_bv_unspecified; expecting none");
if (num_parameters != 2)
m_manager->raise_exception("invalid number of parameters to to_ieee_bv_unspecified; expecting 2");
if (!parameters[0].is_int() || !parameters[1].is_int())
m_manager->raise_exception("invalid parameters type provided to to_ieee_bv_unspecified; expecting 2 integers");
parameter width_p[1] = { parameter(parameters[0].get_int() + parameters[1].get_int()) };
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, width_p);
return m_manager->mk_func_decl(symbol("to_ieee_bv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
}
func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
@ -846,6 +866,8 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
return mk_internal_to_sbv_unspecified(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
return mk_internal_to_real_unspecified(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
return mk_internal_to_ieee_bv_unspecified(k, num_parameters, parameters, arity, domain, range);
default:
m_manager->raise_exception("unsupported floating point operator");
return 0;
@ -1045,25 +1067,26 @@ app * fpa_util::mk_nzero(unsigned ebits, unsigned sbits) {
return mk_value(v);
}
app * fpa_util::mk_internal_to_ubv_unspecified(unsigned width) {
parameter ps[] = { parameter(width) };
app * fpa_util::mk_internal_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
parameter ps[] = { parameter(ebits), parameter(sbits), parameter(width) };
sort * range = m_bv_util.mk_sort(width);
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, 1, ps, 0, 0, range);
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, 3, ps, 0, 0, range);
}
app * fpa_util::mk_internal_to_sbv_unspecified(unsigned width) {
parameter ps[] = { parameter(width) };
app * fpa_util::mk_internal_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
parameter ps[] = { parameter(ebits), parameter(sbits), parameter(width) };
sort * range = m_bv_util.mk_sort(width);
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, 1, ps, 0, 0, range);
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, 3, ps, 0, 0, range);
}
app * fpa_util::mk_internal_to_ieee_bv_unspecified(unsigned width) {
parameter ps[] = { parameter(width) };
sort * range = m_bv_util.mk_sort(width);
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, 1, ps, 0, 0, range);
app * fpa_util::mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits) {
parameter ps[] = { parameter(ebits), parameter(sbits) };
sort * range = m_bv_util.mk_sort(ebits+sbits);
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED, 2, ps, 0, 0, range);
}
app * fpa_util::mk_internal_to_real_unspecified() {
app * fpa_util::mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits) {
parameter ps[] = { parameter(ebits), parameter(sbits) };
sort * range = m_a_util.mk_real();
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, 0, 0, 0, 0, range);
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, 2, ps, 0, 0, range);
}

View file

@ -177,11 +177,29 @@ class fpa_decl_plugin : public decl_plugin {
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_internal_to_real_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_internal_to_ieee_bv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
virtual void set_manager(ast_manager * m, family_id id);
unsigned mk_id(mpf const & v);
void recycled_id(unsigned id);
virtual bool is_considered_uninterpreted(func_decl * f) {
if (f->get_family_id() != get_family_id())
return false;
switch (f->get_decl_kind())
{
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
return true;
default:
return false;
}
return false;
}
public:
fpa_decl_plugin();
@ -344,10 +362,10 @@ public:
app * mk_to_ieee_bv(expr * arg1) { return m().mk_app(m_fid, OP_FPA_TO_IEEE_BV, arg1); }
app * mk_internal_to_ubv_unspecified(unsigned width);
app * mk_internal_to_sbv_unspecified(unsigned width);
app * mk_internal_to_ieee_bv_unspecified(unsigned width);
app * mk_internal_to_real_unspecified();
app * mk_internal_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
app * mk_internal_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
app * mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits);
app * mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits);
bool is_wrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); }
bool is_unwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVUNWRAP); }

View file

@ -638,9 +638,13 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul
set_curr_sort(m().get_sort(arg1));
numeral v1, v2;
bool is_int;
if (m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) {
if (m_util.is_numeral(arg2, v2, is_int)) {
SASSERT(!is_int);
if (m_util.is_numeral(arg1, v1, is_int)) {
if (v2.is_zero()) {
result = m_util.mk_div0(arg1);
return BR_REWRITE1;
}
else if (m_util.is_numeral(arg1, v1, is_int)) {
result = m_util.mk_numeral(v1/v2, false);
return BR_DONE;
}
@ -691,6 +695,10 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu
result = m_util.mk_numeral(div(v1, v2), is_int);
return BR_DONE;
}
if (m_util.is_numeral(arg2, v2, is_int) && v2.is_zero()) {
result = m_util.mk_idiv0(arg1);
return BR_REWRITE1;
}
return BR_FAILED;
}

View file

@ -892,7 +892,7 @@ br_status bv_rewriter::mk_bv_urem_core(expr * arg1, expr * arg2, bool hi_div0, e
if (r2.is_zero()) {
if (!hi_div0) {
result = m().mk_app(get_fid(), OP_BUREM0, arg1);
return BR_DONE;
return BR_REWRITE1;
}
else {
// The "hardware interpretation" for (bvurem x 0) is x

View file

@ -30,6 +30,14 @@ void expr_safe_replace::insert(expr* src, expr* dst) {
m_subst.insert(src, dst);
}
void expr_safe_replace::operator()(expr_ref_vector& es) {
expr_ref val(m);
for (unsigned i = 0; i < es.size(); ++i) {
(*this)(es[i].get(), val);
es[i] = val;
}
}
void expr_safe_replace::operator()(expr* e, expr_ref& res) {
m_todo.push_back(e);
expr* a, *b;

View file

@ -42,6 +42,8 @@ public:
void operator()(expr* src, expr_ref& e);
void operator()(expr_ref_vector& es);
void apply_substitution(expr* s, expr* def, expr_ref& t);
void reset();

View file

@ -102,11 +102,10 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
case OP_FPA_INTERNAL_RM:
SASSERT(num_args == 1); st = mk_rm(args[0], result); break;
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
SASSERT(num_args == 0); st = mk_to_ubv_unspecified(f, result); break;
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
SASSERT(num_args == 0); st = mk_to_sbv_unspecified(f, result); break;
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
SASSERT(num_args == 0); st = mk_to_real_unspecified(result); break;
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
st = BR_FAILED;
case OP_FPA_INTERNAL_BVWRAP:
case OP_FPA_INTERNAL_BVUNWRAP:
@ -119,57 +118,34 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
return st;
}
br_status fpa_rewriter::mk_to_ubv_unspecified(func_decl * f, expr_ref & result) {
SASSERT(f->get_num_parameters() == 1);
SASSERT(f->get_parameter(0).is_int());
unsigned bv_sz = f->get_parameter(0).get_int();
br_status fpa_rewriter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) {
bv_util bu(m());
if (m_hi_fp_unspecified)
// The "hardware interpretation" is 0.
result = bu.mk_numeral(0, bv_sz);
result = bu.mk_numeral(0, width);
else
result = m_util.mk_internal_to_ubv_unspecified(bv_sz);
result = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width);
return BR_DONE;
}
br_status fpa_rewriter::mk_to_sbv_unspecified(func_decl * f, expr_ref & result) {
SASSERT(f->get_num_parameters() == 1);
SASSERT(f->get_parameter(0).is_int());
unsigned bv_sz = f->get_parameter(0).get_int();
br_status fpa_rewriter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) {
bv_util bu(m());
if (m_hi_fp_unspecified)
// The "hardware interpretation" is 0.
result = bu.mk_numeral(0, bv_sz);
result = bu.mk_numeral(0, width);
else
result = m_util.mk_internal_to_sbv_unspecified(bv_sz);
result = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width);
return BR_DONE;
}
br_status fpa_rewriter::mk_to_ieee_bv_unspecified(func_decl * f, expr_ref & result) {
SASSERT(f->get_num_parameters() == 1);
SASSERT(f->get_parameter(0).is_int());
unsigned bv_sz = f->get_parameter(0).get_int();
bv_util bu(m());
if (m_hi_fp_unspecified)
// The "hardware interpretation" is 0.
result = bu.mk_numeral(0, bv_sz);
else
result = m_util.mk_internal_to_ieee_bv_unspecified(bv_sz);
return BR_DONE;
}
br_status fpa_rewriter::mk_to_real_unspecified(expr_ref & result) {
br_status fpa_rewriter::mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result) {
if (m_hi_fp_unspecified)
// The "hardware interpretation" is 0.
result = m_util.au().mk_numeral(rational(0), false);
else
result = m_util.mk_internal_to_real_unspecified();
result = m_util.mk_internal_to_real_unspecified(ebits, sbits);
return BR_DONE;
}
@ -801,9 +777,10 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_
if (m_util.is_rm_numeral(arg1, rmv) &&
m_util.is_numeral(arg2, v)) {
const mpf & x = v.get();
if (m_fm.is_nan(v) || m_fm.is_inf(v) || m_fm.is_neg(v)) {
mk_to_ubv_unspecified(f, result);
mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
return BR_REWRITE_FULL;
}
@ -818,7 +795,7 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_
if (r >= ll && r <= ul)
result = bu.mk_numeral(r, bv_sz);
else
mk_to_ubv_unspecified(f, result);
mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
return BR_DONE;
}
@ -834,9 +811,10 @@ br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_
if (m_util.is_rm_numeral(arg1, rmv) &&
m_util.is_numeral(arg2, v)) {
const mpf & x = v.get();
if (m_fm.is_nan(v) || m_fm.is_inf(v)) {
mk_to_sbv_unspecified(f, result);
mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
return BR_REWRITE_FULL;
}
@ -851,7 +829,7 @@ br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_
if (r >= ll && r <= ul)
result = bu.mk_numeral(r, bv_sz);
else
mk_to_sbv_unspecified(f, result);
mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
return BR_DONE;
}
@ -862,17 +840,35 @@ br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & resu
scoped_mpf v(m_fm);
if (m_util.is_numeral(arg, v)) {
bv_util bu(m());
const mpf & x = v.get();
if (m_fm.is_nan(v) || m_fm.is_inf(v)) {
mk_to_ieee_bv_unspecified(f, result);
if (m_fm.is_nan(v)) {
if (m_hi_fp_unspecified) {
result = bu.mk_concat(bu.mk_numeral(0, 1),
bu.mk_concat(bu.mk_numeral(-1, x.get_ebits()),
bu.mk_concat(bu.mk_numeral(0, x.get_sbits() - 2),
bu.mk_numeral(1, 1))));
}
else {
app_ref unspec(m()), mask(m()), extra(m());
unspec = m_util.mk_internal_to_ieee_bv_unspecified(x.get_ebits(), x.get_sbits());
mask = bu.mk_concat(bu.mk_numeral(0, 1),
bu.mk_concat(bu.mk_numeral(-1, x.get_ebits()),
bu.mk_concat(bu.mk_numeral(0, x.get_sbits() - 2),
bu.mk_numeral(1, 1))));
expr * args[2] = { unspec, mask };
result = m().mk_app(bu.get_fid(), OP_BOR, 2, args);
}
return BR_REWRITE_FULL;
}
else {
scoped_mpz rz(m_fm.mpq_manager());
m_fm.to_ieee_bv_mpz(v, rz);
bv_util bu(m());
scoped_mpz rz(m_fm.mpq_manager());
m_fm.to_ieee_bv_mpz(v, rz);
result = bu.mk_numeral(rational(rz), v.get().get_ebits() + v.get().get_sbits());
return BR_DONE;
result = bu.mk_numeral(rational(rz), x.get_ebits() + x.get_sbits());
return BR_DONE;
}
}
return BR_FAILED;
@ -883,7 +879,8 @@ br_status fpa_rewriter::mk_to_real(expr * arg, expr_ref & result) {
if (m_util.is_numeral(arg, v)) {
if (m_fm.is_nan(v) || m_fm.is_inf(v)) {
result = m_util.mk_internal_to_real_unspecified();
const mpf & x = v.get();
result = m_util.mk_internal_to_real_unspecified(x.get_ebits(), x.get_sbits());
}
else {
scoped_mpq r(m_fm.mpq_manager());

View file

@ -86,10 +86,9 @@ public:
br_status mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & result);
br_status mk_to_real(expr * arg, expr_ref & result);
br_status mk_to_ubv_unspecified(func_decl * f, expr_ref & result);
br_status mk_to_sbv_unspecified(func_decl * f, expr_ref & result);
br_status mk_to_ieee_bv_unspecified(func_decl * f, expr_ref & result);
br_status mk_to_real_unspecified(expr_ref & result);
br_status mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result);
br_status mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result);
br_status mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result);
};
#endif

View file

@ -0,0 +1,53 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
label_rewriter.cpp
Abstract:
Basic rewriting rules for removing labels.
Author:
Nikolaj Bjorner (nbjorner) 2015-19-10
Notes:
--*/
#include"rewriter.h"
#include"rewriter_def.h"
#include"label_rewriter.h"
label_rewriter::label_rewriter(ast_manager & m) :
m_label_fid(m.get_label_family_id()),
m_rwr(m, false, *this) {}
label_rewriter::~label_rewriter() {}
br_status label_rewriter::reduce_app(
func_decl * f, unsigned num, expr * const * args, expr_ref & result,
proof_ref & result_pr) {
if (is_decl_of(f, m_label_fid, OP_LABEL)) {
SASSERT(num == 1);
result = args[0];
return BR_DONE;
}
return BR_FAILED;
}
void label_rewriter::remove_labels(expr_ref& fml, proof_ref& pr) {
ast_manager& m = fml.get_manager();
expr_ref tmp(m);
m_rwr(fml, tmp);
if (pr && fml != tmp) {
pr = m.mk_modus_ponens(pr, m.mk_rewrite(fml, tmp));
}
fml = tmp;
}
//template class rewriter_tpl<label_rewriter>;

View file

@ -0,0 +1,41 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
label_rewriter.h
Abstract:
Basic rewriting rules for labels.
Author:
Nikolaj Bjorner (nbjorner) 2015-19-10
Notes:
--*/
#ifndef LABEL_REWRITER_H_
#define LABEL_REWRITER_H_
#include"ast.h"
#include"rewriter_types.h"
class label_rewriter : public default_rewriter_cfg {
family_id m_label_fid;
rewriter_tpl<label_rewriter> m_rwr;
public:
label_rewriter(ast_manager & m);
~label_rewriter();
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,
proof_ref & result_pr);
void remove_labels(expr_ref& fml, proof_ref& pr);
};
#endif

View file

@ -73,7 +73,7 @@ public:
unsigned nd = q->get_num_decls();
for (unsigned i = 0; i < nd; ++i) {
sort* s = q->get_decl_sort(i);
app* a = m.mk_fresh_const("x", s);
app* a = m.mk_fresh_const(q->get_decl_name(i).str().c_str(), s);
vars.push_back(a);
}
expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd);
@ -154,9 +154,7 @@ private:
}
quantifier_type& negate(quantifier_type& qt) {
TRACE("qe", display(qt, tout); tout << "\n";);
qt = static_cast<quantifier_type>(qt ^0x1);
TRACE("qe", display(qt, tout); tout << "\n";);
return qt;
}
@ -205,6 +203,7 @@ private:
case AST_APP: {
expr_ref_vector args(m);
expr_ref tmp(m);
expr* t1, *t2, *t3;
unsigned num_args = 0;
app* a = to_app(fml);
if (m.is_and(fml)) {
@ -228,16 +227,35 @@ private:
negate(qt);
result = m.mk_not(tmp);
}
else if (m.is_implies(fml)) {
pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp);
else if (m.is_implies(fml, t1, t2)) {
pull_quantifier(t1, negate(qt), vars, tmp);
negate(qt);
pull_quantifier(to_app(fml)->get_arg(1), qt, vars, result);
pull_quantifier(t2, qt, vars, result);
result = m.mk_implies(tmp, result);
}
else if (m.is_ite(fml)) {
pull_quantifier(to_app(fml)->get_arg(1), qt, vars, tmp);
pull_quantifier(to_app(fml)->get_arg(2), qt, vars, result);
result = m.mk_ite(to_app(fml)->get_arg(0), tmp, result);
else if (m.is_ite(fml, t1, t2, t3)) {
expr_ref tt1(m), tt2(m), tt3(m), ntt1(m), nt1(m);
pull_quantifier(t2, qt, vars, tt2);
pull_quantifier(t3, qt, vars, tt3);
if (has_quantifiers(t1)) {
pull_quantifier(t1, qt, vars, tt1);
nt1 = m.mk_not(t1);
pull_quantifier(nt1, qt, vars, ntt1);
result = m.mk_and(m.mk_or(ntt1, tt2), m.mk_or(tt1, tt3));
}
else {
result = m.mk_ite(t1, tt2, tt3);
}
}
else if ((m.is_eq(fml, t1, t2) && m.is_bool(t1)) || m.is_iff(fml, t1, t2)) {
expr_ref tt1(m), tt2(m), ntt1(m), ntt2(m), nt1(m), nt2(m);
pull_quantifier(t1, qt, vars, tt1);
pull_quantifier(t2, qt, vars, tt2);
nt1 = m.mk_not(t1);
nt2 = m.mk_not(t2);
pull_quantifier(nt1, qt, vars, ntt1);
pull_quantifier(nt2, qt, vars, ntt2);
result = m.mk_and(m.mk_or(ntt1, tt2), m.mk_or(ntt2, tt1));
}
else {
// the formula contains a quantifier, but it is "inaccessible"

View file

@ -595,6 +595,9 @@ void rewriter_tpl<Config>::set_inv_bindings(unsigned num_bindings, expr * const
template<typename Config>
template<bool ProofGen>
void rewriter_tpl<Config>::main_loop(expr * t, expr_ref & result, proof_ref & result_pr) {
if (m().canceled()) {
throw rewriter_exception(m().limit().get_cancel_msg());
}
SASSERT(!ProofGen || result_stack().size() == result_pr_stack().size());
SASSERT(not_rewriting());
m_root = t;

View file

@ -246,6 +246,8 @@ eautomaton* re2automaton::re2aut(expr* e) {
expr_ref _stop(bv.mk_numeral(stop, nb), m);
expr_ref _pred(m.mk_not(m.mk_and(bv.mk_ule(_start, v), bv.mk_ule(v, _stop))), m);
a = alloc(eautomaton, sm, sym_expr::mk_pred(_pred, s));
display_expr1 disp(m);
TRACE("seq", tout << mk_pp(e, m) << "\n"; a->display(tout, disp););
return a.detach();
}
else if (u.re.is_to_re(e0, e1) && u.str.is_string(e1, s1) && s1.length() == 1) {
@ -255,6 +257,8 @@ eautomaton* re2automaton::re2aut(expr* e) {
expr_ref _ch(bv.mk_numeral(s1[0], nb), m);
expr_ref _pred(m.mk_not(m.mk_eq(v, _ch)), m);
a = alloc(eautomaton, sm, sym_expr::mk_pred(_pred, s));
display_expr1 disp(m);
TRACE("seq", tout << mk_pp(e, m) << "\n"; a->display(tout, disp););
return a.detach();
}
else if (u.re.is_to_re(e0, e1) && u.str.is_unit(e1, e2)) {
@ -262,6 +266,8 @@ eautomaton* re2automaton::re2aut(expr* e) {
expr_ref v(m.mk_var(0, s), m);
expr_ref _pred(m.mk_not(m.mk_eq(v, e2)), m);
a = alloc(eautomaton, sm, sym_expr::mk_pred(_pred, s));
display_expr1 disp(m);
TRACE("seq", tout << mk_pp(e, m) << "\n"; a->display(tout, disp););
return a.detach();
}
else {

View file

@ -578,6 +578,16 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
return st;
}
expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args) {
expr_ref result(m());
proof_ref pr(m());
if (BR_FAILED == reduce_app(f, num_args, args, result, pr)) {
result = m().mk_app(f, num_args, args);
}
return result;
}
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
@ -695,6 +705,9 @@ struct th_rewriter::imp : public rewriter_tpl<th_rewriter_cfg> {
rewriter_tpl<th_rewriter_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m, p) {
}
expr_ref mk_app(func_decl* f, unsigned sz, expr* const* args) {
return m_cfg.mk_app(f, sz, args);
}
};
th_rewriter::th_rewriter(ast_manager & m, params_ref const & p):
@ -776,3 +789,7 @@ void th_rewriter::reset_used_dependencies() {
m_imp->cfg().m_used_dependencies = 0;
}
}
expr_ref th_rewriter::mk_app(func_decl* f, unsigned num_args, expr* const* args) {
return m_imp->mk_app(f, num_args, args);
}

View file

@ -45,6 +45,8 @@ public:
void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result);
expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args);
void cleanup();
void reset();

View file

@ -112,6 +112,11 @@ zstring::zstring(zstring const& other) {
m_encoding = other.m_encoding;
}
zstring::zstring(unsigned sz, unsigned const* s, encoding enc) {
m_buffer.append(sz, s);
m_encoding = enc;
}
zstring::zstring(unsigned num_bits, bool const* ch) {
SASSERT(num_bits == 8 || num_bits == 16);
m_encoding = (num_bits == 8)?ascii:unicode;
@ -578,6 +583,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
case OP_RE_OF_PRED:
case OP_STRING_ITOS:
case OP_STRING_STOI:
case OP_RE_COMPLEMENT:
match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
@ -632,7 +638,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
default:
m.raise_exception("Incorrect number of arguments passed to loop. Expected 1 regular expression and two integer parameters");
}
case OP_STRING_CONST:
if (!(num_parameters == 1 && arity == 0 && parameters[0].is_symbol())) {
@ -641,7 +647,6 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
return m.mk_const_decl(m_stringc_sym, m_string,
func_decl_info(m_family_id, OP_STRING_CONST, num_parameters, parameters));
case OP_RE_COMPLEMENT:
case OP_RE_UNION:
case OP_RE_CONCAT:
case OP_RE_INTERSECT:
@ -761,10 +766,27 @@ app* seq_decl_plugin::mk_string(zstring const& s) {
bool seq_decl_plugin::is_value(app* e) const {
return
is_app_of(e, m_family_id, OP_SEQ_EMPTY) ||
(is_app_of(e, m_family_id, OP_SEQ_UNIT) &&
m_manager->is_value(e->get_arg(0)));
while (true) {
if (is_app_of(e, m_family_id, OP_SEQ_EMPTY)) {
return true;
}
if (is_app_of(e, m_family_id, OP_STRING_CONST)) {
return true;
}
if (is_app_of(e, m_family_id, OP_SEQ_UNIT) &&
m_manager->is_value(e->get_arg(0))) {
return true;
}
if (is_app_of(e, m_family_id, OP_SEQ_CONCAT) &&
e->get_num_args() == 2 &&
is_app(e->get_arg(0)) &&
is_app(e->get_arg(1)) &&
is_value(to_app(e->get_arg(0)))) {
e = to_app(e->get_arg(1));
continue;
}
return false;
}
}
expr* seq_decl_plugin::get_some_value(sort* s) {

View file

@ -95,6 +95,7 @@ private:
public:
zstring(encoding enc = ascii);
zstring(char const* s, encoding enc = ascii);
zstring(unsigned sz, unsigned const* s, encoding enc = ascii);
zstring(zstring const& other);
zstring(unsigned num_bits, bool const* ch);
zstring(unsigned ch, encoding enc = ascii);

View file

@ -406,8 +406,9 @@ bool arith_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * co
case OP_POWER: return false;
case OP_ABS: SASSERT(num_args == 1); mk_abs(args[0], result); break;
case OP_IRRATIONAL_ALGEBRAIC_NUM: return false;
case OP_DIV_0: return false;
case OP_IDIV_0: return false;
default:
UNREACHABLE();
return false;
}
TRACE("arith_simplifier_plugin", tout << mk_pp(result.get(), m_manager) << "\n";);

View file

@ -473,6 +473,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);
}

View file

@ -303,8 +303,8 @@ public:
goal_ref g = alloc(goal, m, ctx.produce_proofs(), ctx.produce_models(), ctx.produce_unsat_cores());
assert_exprs_from(ctx, *g);
unsigned timeout = p.get_uint("timeout", UINT_MAX);
unsigned rlimit = p.get_uint("rlimit", 0);
unsigned timeout = p.get_uint("timeout", ctx.params().m_timeout);
unsigned rlimit = p.get_uint("rlimit", ctx.params().m_rlimit);
goal_ref_buffer result_goals;
model_converter_ref mc;

View file

@ -539,7 +539,6 @@ namespace algebraic_numbers {
}
bool factor(scoped_upoly const & up, factors & r) {
// std::cout << "factor: "; upm().display(std::cout, up); std::cout << std::endl;
if (m_factor) {
return upm().factor(up, r, m_factor_params);
}
@ -547,7 +546,7 @@ namespace algebraic_numbers {
scoped_upoly & up_sqf = m_isolate_tmp3;
up_sqf.reset();
upm().square_free(up.size(), up.c_ptr(), up_sqf);
TRACE("anum_bug", upm().display(tout, up_sqf.size(), up_sqf.c_ptr()); tout << "\n";);
TRACE("algebraic", upm().display(tout, up_sqf.size(), up_sqf.c_ptr()); tout << "\n";);
r.push_back(up_sqf, 1);
return false;
}
@ -566,6 +565,7 @@ namespace algebraic_numbers {
}
void isolate_roots(scoped_upoly const & up, numeral_vector & roots) {
TRACE("algebraic", upm().display(tout, up); tout << "\n";);
if (up.empty())
return; // ignore the zero polynomial
factors & fs = m_isolate_factors;
@ -586,6 +586,7 @@ namespace algebraic_numbers {
upolynomial::numeral_vector const & f = fs[i];
// polynomial f contains the non zero roots
unsigned d = upm().degree(f);
TRACE("algebraic", tout << "factor " << i << " degree: " << d << "\n";);
if (d == 0)
continue; // found all roots of f
scoped_mpq r(qm());
@ -601,8 +602,9 @@ namespace algebraic_numbers {
}
SASSERT(m_isolate_roots.empty() && m_isolate_lowers.empty() && m_isolate_uppers.empty());
upm().sqf_isolate_roots(f.size(), f.c_ptr(), bqm(), m_isolate_roots, m_isolate_lowers, m_isolate_uppers);
// collect rational/basic roots
// collect rational/basic roots
unsigned sz = m_isolate_roots.size();
TRACE("algebraic", tout << "isolated roots: " << sz << "\n";);
for (unsigned i = 0; i < sz; i++) {
to_mpq(qm(), m_isolate_roots[i], r);
roots.push_back(numeral(mk_basic_cell(r)));

View file

@ -111,7 +111,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
result_pr = 0;
family_id fid = f->get_family_id();
if (fid == null_family_id && num == 0) {
if (num == 0 && (fid == null_family_id || m().get_plugin(f->get_family_id())->is_considered_uninterpreted(f))) {
expr * val = m_model.get_const_interp(f);
if (val != 0) {
result = val;
@ -178,7 +178,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
return BR_DONE;
}
}
TRACE("model_evaluator", tout << f->get_name() << "\n";);
CTRACE("model_evaluator", st != BR_FAILED, tout << result << "\n";);
return st;
}

View file

@ -4,6 +4,5 @@ def_module_params('model',
('v1', BOOL, False, 'use Z3 version 1.x pretty printer'),
('v2', BOOL, False, 'use Z3 version 2.x (x <= 16) pretty printer'),
('compact', BOOL, False, 'try to compact function graph (i.e., function interpretations that are lookup tables)'),
('new_eval', BOOL, True, 'use new evaluator (temporary parameter for testing)'),
))

View file

@ -55,8 +55,7 @@ namespace datalog {
m_args(m),
m_hnf(m),
m_qe(m),
m_cfg(m),
m_rwr(m, false, m_cfg),
m_rwr(m),
m_ufproc(m) {}
void rule_manager::inc_ref(rule * r) {
@ -76,28 +75,8 @@ namespace datalog {
}
}
rule_manager::remove_label_cfg::~remove_label_cfg() {}
br_status rule_manager::remove_label_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,
proof_ref & result_pr)
{
if (is_decl_of(f, m_label_fid, OP_LABEL)) {
SASSERT(num == 1);
result = args[0];
return BR_DONE;
}
return BR_FAILED;
}
void rule_manager::remove_labels(expr_ref& fml, proof_ref& pr) {
expr_ref tmp(m);
m_rwr(fml, tmp);
if (pr && fml != tmp) {
pr = m.mk_modus_ponens(pr, m.mk_rewrite(fml, tmp));
}
fml = tmp;
m_rwr.remove_labels(fml, pr);
}
var_idx_set& rule_manager::collect_vars(expr* e) {
@ -1092,5 +1071,4 @@ namespace datalog {
};
template class rewriter_tpl<datalog::rule_manager::remove_label_cfg>;

View file

@ -32,6 +32,7 @@ Revision History:
#include"qe_lite.h"
#include"var_subst.h"
#include"datatype_decl_plugin.h"
#include"label_rewriter.h"
namespace datalog {
@ -102,16 +103,6 @@ namespace datalog {
*/
class rule_manager
{
class remove_label_cfg : public default_rewriter_cfg {
family_id m_label_fid;
public:
remove_label_cfg(ast_manager& m): m_label_fid(m.get_label_family_id()) {}
virtual ~remove_label_cfg();
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,
proof_ref & result_pr);
};
ast_manager& m;
context& m_ctx;
rule_counter m_counter;
@ -124,8 +115,7 @@ namespace datalog {
svector<bool> m_neg;
hnf m_hnf;
qe_lite m_qe;
remove_label_cfg m_cfg;
rewriter_tpl<remove_label_cfg> m_rwr;
label_rewriter m_rwr;
mutable uninterpreted_function_finder_proc m_ufproc;
mutable quantifier_finder_proc m_qproc;
mutable expr_sparse_mark m_visited;

View file

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

View file

@ -20,6 +20,7 @@ Revision History:
#include "pdr_closure.h"
#include "pdr_context.h"
#include "expr_safe_replace.h"
#include "ast_util.h"
namespace pdr {
@ -147,7 +148,7 @@ namespace pdr {
for (unsigned i = 0; i < fmls.size(); ++i) {
fmls[i] = close_fml(fmls[i].get());
}
return qe::mk_and(fmls);
return expr_ref(mk_and(fmls), m);
}
expr_ref closure::relax(unsigned i, expr* fml) {
@ -169,7 +170,7 @@ namespace pdr {
for (unsigned i = 0; i < As.size(); ++i) {
fmls.push_back(relax(i, As[i]));
}
B = qe::mk_and(fmls);
B = mk_and(fmls);
return B;
}

View file

@ -45,7 +45,6 @@ Notes:
#include "smt_value_sort.h"
#include "proof_utils.h"
#include "dl_boogie_proof.h"
#include "qe_util.h"
#include "scoped_proof.h"
#include "blast_term_ite_tactic.h"
#include "model_implicant.h"

View file

@ -201,7 +201,7 @@ namespace pdr {
lits.push_back(extract_consequence(lo, hi));
lo = hi;
}
res = qe::mk_or(lits);
res = mk_or(lits);
IF_VERBOSE(2, { if (lits.size() > 1) { verbose_stream() << "combined lemma: " << mk_pp(res, m) << "\n"; } });
#endif
}
@ -415,6 +415,7 @@ namespace pdr {
return false;
}
}
};
class collect_pure_proc {

View file

@ -117,7 +117,7 @@ namespace pdr {
void core_farkas_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) {
ast_manager& m = n.pt().get_manager();
if (core.empty()) return;
expr_ref A(m), B(qe::mk_and(core)), C(m);
expr_ref A(m), B(mk_and(core)), C(m);
expr_ref_vector Bs(m);
flatten_or(B, Bs);
A = n.pt().get_propagation_formula(m_ctx.get_pred_transformers(), n.level());
@ -129,13 +129,13 @@ namespace pdr {
if (m_farkas_learner.get_lemma_guesses(A, B, lemmas)) {
TRACE("pdr",
tout << "Old core:\n" << mk_pp(B, m) << "\n";
tout << "New core:\n" << mk_pp(qe::mk_and(lemmas), m) << "\n";);
Bs[i] = qe::mk_and(lemmas);
tout << "New core:\n" << mk_and(lemmas) << "\n";);
Bs[i] = mk_and(lemmas);
change = true;
}
}
if (change) {
C = qe::mk_or(Bs);
C = mk_or(Bs);
TRACE("pdr", tout << "prop:\n" << mk_pp(A,m) << "\ngen:" << mk_pp(B, m) << "\nto: " << mk_pp(C, m) << "\n";);
core.reset();
flatten_and(C, core);
@ -186,7 +186,7 @@ namespace pdr {
}
closure cl(n.pt(), m_is_closure);
expr_ref fml1 = qe::mk_and(core);
expr_ref fml1 = mk_and(core);
expr_ref fml2 = n.pt().get_formulas(n.level(), false);
fml1_2.push_back(fml1);
fml1_2.push_back(0);
@ -205,7 +205,7 @@ namespace pdr {
if (l_false == n.pt().is_reachable(nd, &conv2, uses_level1)) {
new_cores.push_back(std::make_pair(conv2, uses_level1));
change = true;
expr_ref state1 = qe::mk_and(conv2);
expr_ref state1 = mk_and(conv2);
TRACE("pdr",
tout << mk_pp(state, m) << "\n";
tout << "Generalized to:\n" << mk_pp(state1, m) << "\n";);
@ -593,7 +593,7 @@ namespace pdr {
for (unsigned i = ut_size; i < t_size; i++) {
conj.push_back(rule.get_tail(i));
}
result = qe::mk_and(conj);
result = mk_and(conj);
if (!sub.empty()) {
expr_ref tmp = result;
var_subst(m, false)(tmp, sub.size(), sub.c_ptr(), result);
@ -685,7 +685,7 @@ namespace pdr {
for (unsigned i = 0; i < rules.size(); ++i) {
fmls.push_back(m.mk_not(mk_transition_rule(reps, level, *rules[i])));
}
fml = qe::mk_and(fmls);
fml = mk_and(fmls);
TRACE("pdr", tout << mk_pp(fml, m) << "\n";);
return fml;
}
@ -741,7 +741,7 @@ namespace pdr {
}
}
expr_ref result = qe::mk_and(conjs);
expr_ref result = mk_and(conjs);
TRACE("pdr", tout << mk_pp(result, m) << "\n";);
return result;
}

View file

@ -32,7 +32,7 @@ sym_mux::sym_mux(ast_manager & m)
: m(m), m_ref_holder(m),
m_next_sym_suffix_idx(0) {
m_suffixes.push_back("_n");
unsigned suf_sz = m_suffixes.size();
size_t suf_sz = m_suffixes.size();
for(unsigned i = 0; i < suf_sz; ++i) {
symbol suff_sym = symbol(m_suffixes[i].c_str());
m_used_suffixes.insert(suff_sym);

View file

@ -93,7 +93,6 @@ private:
std::string get_suffix(unsigned i);
void ensure_tuple_size(func_decl * prim, unsigned sz);
expr_ref isolate_o_idx(expr* e, unsigned idx) const;
public:
sym_mux(ast_manager & m);
@ -241,8 +240,6 @@ public:
func_decl * const * begin_prim_preds() const { return m_prim_preds.begin(); }
func_decl * const * end_prim_preds() const { return m_prim_preds.end(); }
void get_muxed_cube_from_model(const model_core & model, expr_ref_vector & res) const;
std::string pp_model(const model_core & mdl) const;
};
}

View file

@ -6,7 +6,6 @@ Copyright (c) 2015 Microsoft Corporation
#include "check_relation.h"
#include "dl_relation_manager.h"
#include "qe_util.h"
#include "ast_util.h"
#include "smt_kernel.h"
#include <typeinfo>

View file

@ -23,7 +23,6 @@ Notes:
--*/
#include "udoc_relation.h"
#include "dl_relation_manager.h"
#include "qe_util.h"
#include "ast_util.h"
#include "smt_kernel.h"

View file

@ -39,6 +39,17 @@ namespace nlsat {
m_values.swap(other.m_values);
m_assigned.swap(other.m_assigned);
}
void copy(assignment const& other) {
m_assigned.reset();
m_assigned.append(other.m_assigned);
m_values.reserve(m_assigned.size(), anum());
for (unsigned i = 0; i < m_assigned.size(); ++i) {
if (is_assigned(i)) {
am().set(m_values[i], other.value(i));
}
}
}
void set_core(var x, anum & v) {
m_values.reserve(x+1, anum());
m_assigned.reserve(x+1, false);
@ -52,11 +63,26 @@ namespace nlsat {
am().set(m_values[x], v);
}
void reset(var x) { if (x < m_assigned.size()) m_assigned[x] = false; }
void reset() { m_assigned.reset(); }
bool is_assigned(var x) const { return m_assigned.get(x, false); }
anum const & value(var x) const { return m_values[x]; }
virtual anum_manager & m() const { return am(); }
virtual bool contains(var x) const { return is_assigned(x); }
virtual anum const & operator()(var x) const { SASSERT(is_assigned(x)); return value(x); }
void swap(var x, var y) {
SASSERT(x < m_values.size() && y < m_values.size());
std::swap(m_assigned[x], m_assigned[y]);
std::swap(m_values[x], m_values[y]);
}
void display(std::ostream& out) const {
for (unsigned i = 0; i < m_assigned.size(); ++i) {
if (m_assigned[i]) {
out << "x" << i << " := ";
m_values.m().display(out, m_values[i]);
out << "\n";
}
}
}
};
/**

View file

@ -18,10 +18,12 @@ Revision History:
--*/
#include"nlsat_evaluator.h"
#include"nlsat_solver.h"
namespace nlsat {
struct evaluator::imp {
solver& m_solver;
assignment const & m_assignment;
pmanager & m_pm;
small_object_allocator & m_allocator;
@ -357,7 +359,8 @@ namespace nlsat {
sign_table m_sign_table_tmp;
imp(assignment const & x2v, pmanager & pm, small_object_allocator & allocator):
imp(solver& s, assignment const & x2v, pmanager & pm, small_object_allocator & allocator):
m_solver(s),
m_assignment(x2v),
m_pm(pm),
m_allocator(allocator),
@ -420,10 +423,25 @@ namespace nlsat {
scoped_anum_vector & roots = m_tmp_values;
roots.reset();
m_am.isolate_roots(polynomial_ref(a->p(), m_pm), undef_var_assignment(m_assignment, a->x()), roots);
TRACE("nlsat",
m_solver.display(tout << (neg?"!":""), *a); tout << "\n";
if (roots.empty()) {
tout << "No roots\n";
}
else {
tout << "Roots for ";
for (unsigned i = 0; i < roots.size(); ++i) {
m_am.display_interval(tout, roots[i]); tout << " ";
}
tout << "\n";
}
m_assignment.display(tout);
);
SASSERT(a->i() > 0);
if (a->i() > roots.size())
return false; // p does have sufficient roots
int sign = m_am.compare(m_assignment.value(a->x()), roots[a->i() - 1]);
if (a->i() > roots.size()) {
return neg;
}
int sign = m_am.compare(m_assignment.value(a->x()), roots[a->i() - 1]);
return satisfied(sign, k, neg);
}
@ -649,8 +667,8 @@ namespace nlsat {
}
};
evaluator::evaluator(assignment const & x2v, pmanager & pm, small_object_allocator & allocator) {
m_imp = alloc(imp, x2v, pm, allocator);
evaluator::evaluator(solver& s, assignment const & x2v, pmanager & pm, small_object_allocator & allocator) {
m_imp = alloc(imp, s, x2v, pm, allocator);
}
evaluator::~evaluator() {

View file

@ -26,11 +26,13 @@ Revision History:
namespace nlsat {
class solver;
class evaluator {
struct imp;
imp * m_imp;
public:
evaluator(assignment const & x2v, pmanager & pm, small_object_allocator & allocator);
evaluator(solver& s, assignment const & x2v, pmanager & pm, small_object_allocator & allocator);
~evaluator();
interval_set_manager & ism() const;

View file

@ -36,6 +36,7 @@ namespace nlsat {
polynomial::cache & m_cache;
pmanager & m_pm;
polynomial_ref_vector m_ps;
polynomial_ref_vector m_ps2;
polynomial_ref_vector m_psc_tmp;
polynomial_ref_vector m_factors;
scoped_anum_vector m_roots_tmp;
@ -43,6 +44,7 @@ namespace nlsat {
bool m_full_dimensional;
bool m_minimize_cores;
bool m_factor;
bool m_signed_project;
struct todo_set {
polynomial::cache & m_cache;
@ -137,6 +139,7 @@ namespace nlsat {
m_cache(u),
m_pm(u.pm()),
m_ps(m_pm),
m_ps2(m_pm),
m_psc_tmp(m_pm),
m_factors(m_pm),
m_roots_tmp(m_am),
@ -148,6 +151,7 @@ namespace nlsat {
m_simplify_cores = false;
m_full_dimensional = false;
m_minimize_cores = false;
m_signed_project = false;
}
~imp() {
@ -202,7 +206,7 @@ namespace nlsat {
void reset_already_added() {
SASSERT(m_result != 0);
unsigned sz = m_result->size();
for (unsigned i = 0; i < sz; i++)
for (unsigned i = 0; i < sz; i++)
m_already_added_literal[(*m_result)[i].index()] = false;
}
@ -212,7 +216,7 @@ namespace nlsat {
max_var(p) must be assigned in the current interpretation.
*/
int sign(polynomial_ref const & p) {
TRACE("nlsat_explain", tout << "p: " << p << "\n";);
TRACE("nlsat_explain", tout << "p: " << p << " var: " << max_var(p) << "\n";);
SASSERT(max_var(p) == null_var || m_assignment.is_assigned(max_var(p)));
return m_am.eval_sign_at(p, m_assignment);
}
@ -697,39 +701,163 @@ namespace nlsat {
}
}
void test_root_literal(atom::kind k, var y, unsigned i, poly * p, scoped_literal_vector& result) {
m_result = &result;
add_root_literal(k, y, i, p);
reset_already_added();
m_result = 0;
}
void add_root_literal(atom::kind k, var y, unsigned i, poly * p) {
polynomial_ref pr(p, m_pm);
TRACE("nlsat_explain",
display(tout << "x" << y << " " << k << "[" << i << "](", pr); tout << ")\n";);
if (!mk_linear_root(k, y, i, p) &&
//!mk_plinear_root(k, y, i, p) &&
!mk_quadratic_root(k, y, i, p)&&
true) {
bool_var b = m_solver.mk_root_atom(k, y, i, p);
literal l(b, true);
TRACE("nlsat_explain", tout << "adding literal\n"; display(tout, l); tout << "\n";);
add_literal(l);
}
}
/**
* literal can be expressed using a linear ineq_atom
*/
bool mk_linear_root(atom::kind k, var y, unsigned i, poly * p) {
scoped_mpz c(m_pm.m());
bool_var b;
bool lsign = false;
if (m_pm.degree(p, y) == 1 && m_pm.const_coeff(p, y, 1, c)) {
SASSERT(!m_pm.m().is_zero(c));
// literal can be expressed using a linear ineq_atom
polynomial_ref p_prime(m_pm);
p_prime = p;
if (m_pm.m().is_neg(c))
p_prime = neg(p_prime);
p = p_prime.get();
switch (k) {
case atom::ROOT_EQ: k = atom::EQ; lsign = false; break;
case atom::ROOT_LT: k = atom::LT; lsign = false; break;
case atom::ROOT_GT: k = atom::GT; lsign = false; break;
case atom::ROOT_LE: k = atom::GT; lsign = true; break;
case atom::ROOT_GE: k = atom::LT; lsign = true; break;
default:
UNREACHABLE();
break;
}
bool is_even = false;
b = m_solver.mk_ineq_atom(k, 1, &p, &is_even);
mk_linear_root(k, y, i, p, m_pm.m().is_neg(c));
return true;
}
else {
b = m_solver.mk_root_atom(k, y, i, p);
lsign = false;
return false;
}
/**
Create pseudo-linear root depending on the sign of the coefficient to y.
*/
bool mk_plinear_root(atom::kind k, var y, unsigned i, poly * p) {
if (m_pm.degree(p, y) != 1) {
return false;
}
lsign = !lsign; // adding as an assumption
literal l(b, lsign);
TRACE("nlsat_explain", tout << "adding literal\n"; display(tout, l); tout << "\n";);
add_literal(l);
polynomial_ref c(m_pm);
c = m_pm.coeff(p, y, 1);
int s = sign(c);
if (s == 0) {
return false;
}
ensure_sign(c);
mk_linear_root(k, y, i, p, s < 0);
return true;
}
/**
Encode root conditions for quadratic polynomials.
Basically implements Thom's theorem. The roots are characterized by the sign of polynomials and their derivatives.
b^2 - 4ac = 0:
- there is only one root, which is -b/2a.
- relation to root is a function of the sign of
- 2ax + b
b^2 - 4ac > 0:
- assert i == 1 or i == 2
- relation to root is a function of the signs of:
- 2ax + b
- ax^2 + bx + c
*/
bool mk_quadratic_root(atom::kind k, var y, unsigned i, poly * p) {
if (m_pm.degree(p, y) != 2) {
return false;
}
if (i != 1 && i != 2) {
return false;
}
SASSERT(m_assignment.is_assigned(y));
polynomial_ref A(m_pm), B(m_pm), C(m_pm), q(m_pm), p_diff(m_pm), yy(m_pm);
A = m_pm.coeff(p, y, 2);
B = m_pm.coeff(p, y, 1);
C = m_pm.coeff(p, y, 0);
// TBD throttle based on degree of q?
q = (B*B) - (4*A*C);
yy = m_pm.mk_polynomial(y);
p_diff = 2*A*yy + B;
p_diff = m_pm.normalize(p_diff);
int sq = ensure_sign(q);
if (sq < 0) {
return false;
}
int sa = ensure_sign(A);
if (sa == 0) {
q = B*yy + C;
return mk_plinear_root(k, y, i, q);
}
ensure_sign(p_diff);
if (sq > 0) {
polynomial_ref pr(p, m_pm);
ensure_sign(pr);
}
return true;
}
int ensure_sign(polynomial_ref & p) {
#if 0
polynomial_ref f(m_pm);
factor(p, m_factors);
m_is_even.reset();
unsigned num_factors = m_factors.size();
int s = 1;
for (unsigned i = 0; i < num_factors; i++) {
f = m_factors.get(i);
s *= sign(f);
m_is_even.push_back(false);
}
if (num_factors > 0) {
atom::kind k = atom::EQ;
if (s == 0) k = atom::EQ;
if (s < 0) k = atom::LT;
if (s > 0) k = atom::GT;
bool_var b = m_solver.mk_ineq_atom(k, num_factors, m_factors.c_ptr(), m_is_even.c_ptr());
add_literal(literal(b, true));
}
return s;
#else
int s = sign(p);
if (!is_const(p)) {
add_simple_assumption(s == 0 ? atom::EQ : (s < 0 ? atom::LT : atom::GT), p);
}
return s;
#endif
}
/**
Auxiliary function to linear roots.
*/
void mk_linear_root(atom::kind k, var y, unsigned i, poly * p, bool mk_neg) {
polynomial_ref p_prime(m_pm);
p_prime = p;
bool lsign = false;
if (mk_neg)
p_prime = neg(p_prime);
p = p_prime.get();
switch (k) {
case atom::ROOT_EQ: k = atom::EQ; lsign = false; break;
case atom::ROOT_LT: k = atom::LT; lsign = false; break;
case atom::ROOT_GT: k = atom::GT; lsign = false; break;
case atom::ROOT_LE: k = atom::GT; lsign = true; break;
case atom::ROOT_GE: k = atom::LT; lsign = true; break;
default:
UNREACHABLE();
break;
}
add_simple_assumption(k, p, lsign);
}
/**
@ -1332,10 +1460,333 @@ namespace nlsat {
TRACE("nlsat_explain", tout << "[explain] result\n"; display(tout, result););
CASSERT("nlsat", check_already_added());
}
void project(var x, unsigned num, literal const * ls, scoped_literal_vector & result) {
m_result = &result;
svector<literal> lits;
TRACE("nlsat", tout << "project x" << x << "\n"; m_solver.display(tout););
DEBUG_CODE(
for (unsigned i = 0; i < num; ++i) {
SASSERT(m_solver.value(ls[i]) == l_true);
atom* a = m_atoms[ls[i].var()];
SASSERT(!a || m_evaluator.eval(a, ls[i].sign()));
});
split_literals(x, num, ls, lits);
collect_polys(lits.size(), lits.c_ptr(), m_ps);
var mx_var = max_var(m_ps);
if (!m_ps.empty()) {
svector<var> renaming;
if (x != mx_var) {
for (var i = 0; i < m_solver.num_vars(); ++i) {
renaming.push_back(i);
}
std::swap(renaming[x], renaming[mx_var]);
m_solver.reorder(renaming.size(), renaming.c_ptr());
TRACE("qe", tout << "x: " << x << " max: " << mx_var << " num_vars: " << m_solver.num_vars() << "\n";
m_solver.display(tout););
}
elim_vanishing(m_ps);
if (m_signed_project) {
signed_project(m_ps, mx_var);
}
else {
project(m_ps, mx_var);
}
reset_already_added();
m_result = 0;
if (x != mx_var) {
m_solver.restore_order();
}
}
else {
reset_already_added();
m_result = 0;
}
for (unsigned i = 0; i < result.size(); ++i) {
result.set(i, ~result[i]);
}
DEBUG_CODE(
for (unsigned i = 0; i < result.size(); ++i) {
SASSERT(l_true == m_solver.value(result[i]));
});
}
void split_literals(var x, unsigned n, literal const* ls, svector<literal>& lits) {
var_vector vs;
for (unsigned i = 0; i < n; ++i) {
vs.reset();
m_solver.vars(ls[i], vs);
if (vs.contains(x)) {
lits.push_back(ls[i]);
}
else {
add_literal(~ls[i]);
}
}
}
/**
Signed projection.
Assumptions:
- any variable in ps is at most x.
- root expressions are satisfied (positive literals)
Effect:
- if x not in p, then
- if sign(p) < 0: p < 0
- if sign(p) = 0: p = 0
- if sign(p) > 0: p > 0
else:
- let roots_j be the roots of p_j or roots_j[i]
- let L = { roots_j[i] | M(roots_j[i]) < M(x) }
- let U = { roots_j[i] | M(roots_j[i]) > M(x) }
- let E = { roots_j[i] | M(roots_j[i]) = M(x) }
- let glb in L, s.t. forall l in L . M(glb) >= M(l)
- let lub in U, s.t. forall u in U . M(lub) <= M(u)
- if root in E, then
- add E x . x = root & x > lb for lb in L
- add E x . x = root & x < ub for ub in U
- add E x . x = root & x = root2 for root2 in E \ { root }
- else
- assume |L| <= |U| (other case is symmetric)
- add E x . lb <= x & x <= glb for lb in L
- add E x . x = glb & x < ub for ub in U
*/
void signed_project(polynomial_ref_vector& ps, var x) {
TRACE("nlsat_explain", tout << "Signed projection\n";);
polynomial_ref p(m_pm);
unsigned eq_index = 0;
bool eq_valid = false;
unsigned eq_degree = 0;
for (unsigned i = 0; i < ps.size(); ++i) {
p = ps.get(i);
int s = sign(p);
if (max_var(p) != x) {
atom::kind k = (s == 0)?(atom::EQ):((s < 0)?(atom::LT):(atom::GT));
add_simple_assumption(k, p, false);
ps[i] = ps.back();
ps.pop_back();
--i;
}
else if (s == 0) {
if (!eq_valid || degree(p, x) < eq_degree) {
eq_index = i;
eq_valid = true;
eq_degree = degree(p, x);
}
}
}
if (ps.empty()) {
return;
}
if (ps.size() == 1) {
project_single(x, ps.get(0));
return;
}
// ax + b = 0, p(x) > 0 ->
if (eq_valid) {
p = ps.get(eq_index);
if (degree(p, x) == 1) {
// ax + b = 0
// let d be maximal degree of x in p.
// p(x) -> a^d*p(-b/a), a
// perform virtual substitution with equality.
solve_eq(x, eq_index, ps);
}
else {
project_pairs(x, eq_index, ps);
}
return;
}
unsigned num_lub = 0, num_glb = 0;
unsigned glb_index = 0, lub_index = 0;
scoped_anum lub(m_am), glb(m_am), x_val(m_am);
x_val = m_assignment.value(x);
for (unsigned i = 0; i < ps.size(); ++i) {
p = ps.get(i);
scoped_anum_vector & roots = m_roots_tmp;
roots.reset();
m_am.isolate_roots(p, undef_var_assignment(m_assignment, x), roots);
bool glb_valid = false, lub_valid = false;
for (unsigned j = 0; j < roots.size(); ++j) {
int s = m_am.compare(x_val, roots[j]);
SASSERT(s != 0);
lub_valid |= s < 0;
glb_valid |= s > 0;
if (s < 0 && m_am.lt(roots[j], lub)) {
lub_index = i;
m_am.set(lub, roots[j]);
}
if (s > 0 && m_am.lt(glb, roots[j])) {
glb_index = i;
m_am.set(glb, roots[j]);
}
}
if (glb_valid) {
++num_glb;
}
if (lub_valid) {
++num_lub;
}
}
if (num_lub == 0) {
project_plus_infinity(x, ps);
return;
}
if (num_glb == 0) {
project_minus_infinity(x, ps);
return;
}
if (num_lub <= num_glb) {
glb_index = lub_index;
}
project_pairs(x, glb_index, ps);
}
void project_plus_infinity(var x, polynomial_ref_vector const& ps) {
polynomial_ref p(m_pm), lc(m_pm);
for (unsigned i = 0; i < ps.size(); ++i) {
p = ps.get(i);
unsigned d = degree(p, x);
lc = m_pm.coeff(p, x, d);
if (!is_const(lc)) {
unsigned s = sign(p);
SASSERT(s != 0);
atom::kind k = (s > 0)?(atom::GT):(atom::LT);
add_simple_assumption(k, lc);
}
}
}
void project_minus_infinity(var x, polynomial_ref_vector const& ps) {
polynomial_ref p(m_pm), lc(m_pm);
for (unsigned i = 0; i < ps.size(); ++i) {
p = ps.get(i);
unsigned d = degree(p, x);
lc = m_pm.coeff(p, x, d);
if (!is_const(lc)) {
unsigned s = sign(p);
SASSERT(s != 0);
atom::kind k;
if (s > 0) {
k = (d % 2 == 0)?(atom::GT):(atom::LT);
}
else {
k = (d % 2 == 0)?(atom::LT):(atom::GT);
}
add_simple_assumption(k, lc);
}
}
}
void project_pairs(var x, unsigned idx, polynomial_ref_vector const& ps) {
polynomial_ref p(m_pm);
p = ps.get(idx);
for (unsigned i = 0; i < ps.size(); ++i) {
if (i != idx) {
project_pair(x, ps.get(i), p);
}
}
}
void project_pair(var x, polynomial::polynomial* p1, polynomial::polynomial* p2) {
m_ps2.reset();
m_ps2.push_back(p1);
m_ps2.push_back(p2);
project(m_ps2, x);
}
void project_single(var x, polynomial::polynomial* p) {
m_ps2.reset();
m_ps2.push_back(p);
project(m_ps2, x);
}
void solve_eq(var x, unsigned idx, polynomial_ref_vector const& ps) {
polynomial_ref p(m_pm), A(m_pm), B(m_pm), C(m_pm), D(m_pm), E(m_pm), q(m_pm), r(m_pm);
polynomial_ref_vector qs(m_pm);
p = ps.get(idx);
SASSERT(degree(p, x) == 1);
A = m_pm.coeff(p, x, 1);
B = m_pm.coeff(p, x, 0);
B = neg(B);
TRACE("nlsat_explain", tout << "p: " << p << " A: " << A << " B: " << B << "\n";);
// x = B/A
for (unsigned i = 0; i < ps.size(); ++i) {
if (i != idx) {
q = ps.get(i);
unsigned d = degree(q, x);
D = m_pm.mk_const(rational(1));
E = D;
r = m_pm.mk_zero();
for (unsigned j = 0; j <= d; ++j) {
qs.push_back(D);
D = D*A;
}
for (unsigned j = 0; j <= d; ++j) {
// A^d*p0 + A^{d-1}*B*p1 + ... + B^j*A^{d-j}*pj + ... + B^d*p_d
C = m_pm.coeff(q, x, j);
if (!is_zero(C)) {
D = qs.get(d-j);
r = r + D*E*C;
}
E = E*B;
}
TRACE("nlsat_explain", tout << "q: " << q << " r: " << r << "\n";);
ensure_sign(r);
}
else {
ensure_sign(A);
}
}
}
void maximize(var x, unsigned num, literal const * ls, scoped_anum& val, bool& unbounded) {
svector<literal> lits;
polynomial_ref p(m_pm);
split_literals(x, num, ls, lits);
collect_polys(lits.size(), lits.c_ptr(), m_ps);
unbounded = true;
scoped_anum x_val(m_am);
x_val = m_assignment.value(x);
for (unsigned i = 0; i < m_ps.size(); ++i) {
p = m_ps.get(i);
scoped_anum_vector & roots = m_roots_tmp;
roots.reset();
m_am.isolate_roots(p, undef_var_assignment(m_assignment, x), roots);
for (unsigned j = 0; j < roots.size(); ++j) {
int s = m_am.compare(x_val, roots[j]);
if (s <= 0 && (unbounded || m_am.compare(roots[j], val) <= 0)) {
unbounded = false;
val = roots[j];
}
}
}
}
};
explain::explain(solver & s, assignment const & x2v, polynomial::cache & u, atom_vector const & atoms, atom_vector const & x2eq,
evaluator & ev) {
explain::explain(solver & s, assignment const & x2v, polynomial::cache & u,
atom_vector const& atoms, atom_vector const& x2eq, evaluator & ev) {
m_imp = alloc(imp, s, x2v, u, atoms, x2eq, ev);
}
@ -1364,10 +1815,26 @@ namespace nlsat {
m_imp->m_factor = f;
}
void explain::set_signed_project(bool f) {
m_imp->m_signed_project = f;
}
void explain::operator()(unsigned n, literal const * ls, scoped_literal_vector & result) {
(*m_imp)(n, ls, result);
}
void explain::project(var x, unsigned n, literal const * ls, scoped_literal_vector & result) {
m_imp->project(x, n, ls, result);
}
void explain::maximize(var x, unsigned n, literal const * ls, scoped_anum& val, bool& unbounded) {
m_imp->maximize(x, n, ls, val, unbounded);
}
void explain::test_root_literal(atom::kind k, var y, unsigned i, poly* p, scoped_literal_vector & result) {
m_imp->test_root_literal(k, y, i, p, result);
}
};
#ifdef Z3DEBUG
@ -1398,3 +1865,4 @@ void pp_lit(nlsat::explain::imp & ex, nlsat::literal l) {
std::cout << std::endl;
}
#endif

View file

@ -22,9 +22,11 @@ Revision History:
#include"nlsat_solver.h"
#include"nlsat_scoped_literal_vector.h"
#include"polynomial_cache.h"
#include"algebraic_numbers.h"
namespace nlsat {
class evaluator;
class explain {
public:
@ -32,8 +34,8 @@ namespace nlsat {
private:
imp * m_imp;
public:
explain(solver & s, assignment const & x2v, polynomial::cache & u, atom_vector const & atoms, atom_vector const & x2eq,
evaluator & ev);
explain(solver & s, assignment const & x2v, polynomial::cache & u,
atom_vector const& atoms, atom_vector const& x2eq, evaluator & ev);
~explain();
void reset();
@ -41,6 +43,7 @@ namespace nlsat {
void set_full_dimensional(bool f);
void set_minimize_cores(bool f);
void set_factor(bool f);
void set_signed_project(bool f);
/**
\brief Given a set of literals ls[0], ... ls[n-1] s.t.
@ -60,6 +63,48 @@ namespace nlsat {
- s_1, ..., s_m are false in the current interpretation
*/
void operator()(unsigned n, literal const * ls, scoped_literal_vector & result);
/**
\brief projection for a given variable.
Given: M |= l1[x] /\ ... /\ ln[x]
Find: M |= s1, ..., sm
Such that: |= ~s1 \/ ... \/ ~sm \/ E x. l1[x] /\ ... /\ ln[x]
Contrast this with with the core-based projection above:
Given: M |= A x . l1[x] \/ ... \/ ln[x]
Find: M |= ~s1, ..., ~sm.
Such that: |= s1 \/ ... \/ sm \/ A x . l1[x] \/ ... \/ ln[x]
Claim: the two compute the same solutions if the projection operators are independent of the value of x.
Claim: A complete, convergent projection operator can be obtained from M in a way that is independent of x.
*/
void project(var x, unsigned n, literal const * ls, scoped_literal_vector & result);
/**
Maximize the value of x (locally) under the current assignment to other variables and
while maintaining the assignment to the literals ls.
Set unbounded to 'true' if the value of x is unbounded.
Precondition: the set of literals are true in the current model.
By local optimization we understand that x is increased to the largest value within
the signs delineated by the roots of the polynomials in ls.
*/
void maximize(var x, unsigned n, literal const * ls, scoped_anum& val, bool& unbounded);
/**
Unit test routine.
*/
void test_root_literal(atom::kind k, var y, unsigned i, poly* p, scoped_literal_vector & result);
};
};

View file

@ -64,6 +64,13 @@ namespace nlsat {
for (unsigned i = 0; i < sz; i++)
push_back(ls[i]);
}
void append(scoped_literal_vector const& ls) {
append(ls.size(), ls.c_ptr());
}
void swap(scoped_literal_vector& other) {
SASSERT(&m_solver == &other.m_solver);
m_lits.swap(other.m_lits);
}
};

View file

@ -66,7 +66,6 @@ namespace nlsat {
typedef polynomial::cache cache;
typedef ptr_vector<interval_set> interval_set_vector;
solver & m_solver;
reslimit& m_rlimit;
small_object_allocator m_allocator;
unsynch_mpq_manager m_qm;
@ -159,8 +158,7 @@ namespace nlsat {
unsigned m_stages;
unsigned m_irrational_assignments; // number of irrational witnesses
imp(solver & s, reslimit& rlim, params_ref const & p):
m_solver(s),
imp(solver& s, reslimit& rlim, params_ref const & p):
m_rlimit(rlim),
m_allocator("nlsat"),
m_pm(rlim, m_qm, &m_allocator),
@ -168,7 +166,7 @@ namespace nlsat {
m_am(rlim, m_qm, p, &m_allocator),
m_asm(*this, m_allocator),
m_assignment(m_am),
m_evaluator(m_assignment, m_pm, m_allocator),
m_evaluator(s, m_assignment, m_pm, m_allocator),
m_ism(m_evaluator.ism()),
m_num_bool_vars(0),
m_display_var(m_perm),
@ -183,12 +181,7 @@ namespace nlsat {
}
~imp() {
m_explain.reset();
m_lemma.reset();
m_lazy_clause.reset();
undo_until_size(0);
del_clauses();
del_unref_atoms();
reset();
}
void mk_true_bvar() {
@ -216,6 +209,18 @@ namespace nlsat {
m_am.updt_params(p.p);
}
void reset() {
m_explain.reset();
m_lemma.reset();
m_lazy_clause.reset();
undo_until_size(0);
del_clauses();
del_unref_atoms();
m_cache.reset();
m_assignment.reset();
}
void checkpoint() {
if (!m_rlimit.inc()) throw solver_exception(m_rlimit.get_cancel_msg());
if (memory::get_allocation_size() > m_max_memory) throw solver_exception(Z3_MAX_MEMORY_MSG);
@ -252,6 +257,7 @@ namespace nlsat {
}
void inc_ref(bool_var b) {
TRACE("ref", tout << "inc: " << b << "\n";);
if (b == null_bool_var)
return;
if (m_atoms[b] == 0)
@ -264,6 +270,7 @@ namespace nlsat {
}
void dec_ref(bool_var b) {
TRACE("ref", tout << "dec: " << b << "\n";);
if (b == null_bool_var)
return;
atom * a = m_atoms[b];
@ -412,6 +419,34 @@ namespace nlsat {
return x;
}
svector<bool> m_found_vars;
void vars(literal l, var_vector& vs) {
vs.reset();
atom * a = m_atoms[l.var()];
if (a == 0) {
}
else if (a->is_ineq_atom()) {
unsigned sz = to_ineq_atom(a)->size();
var_vector new_vs;
for (unsigned j = 0; j < sz; j++) {
m_found_vars.reset();
m_pm.vars(to_ineq_atom(a)->p(j), new_vs);
for (unsigned i = 0; i < new_vs.size(); ++i) {
if (!m_found_vars.get(new_vs[i], false)) {
m_found_vars.setx(new_vs[i], true, false);
vs.push_back(new_vs[i]);
}
}
}
}
else {
m_pm.vars(to_root_atom(a)->p(), vs);
//vs.erase(max_var(to_root_atom(a)->p()));
vs.push_back(to_root_atom(a)->x());
}
}
void deallocate(ineq_atom * a) {
unsigned obj_sz = ineq_atom::get_obj_size(a->size());
a->~ineq_atom();
@ -425,7 +460,7 @@ namespace nlsat {
void del(bool_var b) {
SASSERT(m_bwatches[b].empty());
SASSERT(m_bvalues[b] == l_undef);
//SASSERT(m_bvalues[b] == l_undef);
m_num_bool_vars--;
m_dead[b] = true;
m_atoms[b] = 0;
@ -491,6 +526,7 @@ namespace nlsat {
TRACE("nlsat_table_bug", ineq_atom::hash_proc h;
tout << "mk_ineq_atom hash: " << h(new_atom) << "\n"; display(tout, *new_atom, m_display_var); tout << "\n";);
ineq_atom * old_atom = m_ineq_atoms.insert_if_not_there(new_atom);
CTRACE("nlsat_table_bug", old_atom->max_var() != max, display(tout, *old_atom, m_display_var); tout << "\n";);
SASSERT(old_atom->max_var() == max);
if (old_atom != new_atom) {
deallocate(new_atom);
@ -726,7 +762,7 @@ namespace nlsat {
template<typename Predicate>
void undo_until(Predicate const & pred) {
while (pred()) {
while (pred() && !m_trail.empty()) {
trail & t = m_trail.back();
switch (t.m_kind) {
case trail::BVAR_ASSIGNMENT:
@ -803,6 +839,14 @@ namespace nlsat {
SASSERT(m_bvalues[b] == l_undef);
}
struct true_pred {
bool operator()() const { return true; }
};
void undo_until_empty() {
undo_until(true_pred());
}
/**
\brief Create a new scope level
*/
@ -868,10 +912,11 @@ namespace nlsat {
var max = a->max_var();
if (!m_assignment.is_assigned(max))
return l_undef;
TRACE("value_bug", tout << "value of: "; display(tout, l); tout << "\n"; tout << "xk: " << m_xk << ", a->max_var(): " << a->max_var() << "\n";
display_assignment(tout);
display_bool_assignment(tout););
return to_lbool(m_evaluator.eval(a, l.sign()));
val = to_lbool(m_evaluator.eval(a, l.sign()));
TRACE("value_bug", tout << "value of: "; display(tout, l); tout << " := " << val << "\n";
tout << "xk: " << m_xk << ", a->max_var(): " << a->max_var() << "\n";
display_assignment(tout););
return val;
}
/**
@ -880,8 +925,10 @@ namespace nlsat {
bool is_satisfied(clause const & cls) const {
unsigned sz = cls.size();
for (unsigned i = 0; i < sz; i++) {
if (const_cast<imp*>(this)->value(cls[i]) == l_true)
if (const_cast<imp*>(this)->value(cls[i]) == l_true) {
TRACE("value_bug:", tout << cls[i] << " := true\n";);
return true;
}
}
return false;
}
@ -984,8 +1031,10 @@ namespace nlsat {
If satisfy_learned is true, then learned clauses are satisfied even if m_lazy > 0
*/
bool process_arith_clause(clause const & cls, bool satisfy_learned) {
if (!satisfy_learned && m_lazy >= 2 && cls.is_learned())
if (!satisfy_learned && m_lazy >= 2 && cls.is_learned()) {
TRACE("nlsat", tout << "skip learned\n";);
return true; // ignore lemmas in super lazy mode
}
SASSERT(m_xk == max_var(cls));
unsigned num_undef = 0; // number of undefined literals
unsigned first_undef = UINT_MAX; // position of the first undefined literal
@ -1064,7 +1113,7 @@ namespace nlsat {
If satisfy_learned is true, then (arithmetic) learned clauses are satisfied even if m_lazy > 0
*/
bool process_clause(clause const & cls, bool satisfy_learned) {
TRACE("nlsat", tout << "processing clause:\n"; display(tout, cls); tout << "\n";);
TRACE("nlsat", tout << "processing clause: "; display(tout, cls); tout << "\n";);
if (is_satisfied(cls))
return true;
if (m_xk == null_var)
@ -1151,7 +1200,7 @@ namespace nlsat {
}
TRACE("nlsat_bug", tout << "xk: x" << m_xk << " bk: b" << m_bk << "\n";);
if (m_bk == null_bool_var && m_xk >= num_vars()) {
TRACE("nlsat", tout << "found model\n"; display_assignment(tout); display_bool_assignment(tout););
TRACE("nlsat", tout << "found model\n"; display_assignment(tout););
return l_true; // all variables were assigned, and all clauses were satisfied.
}
TRACE("nlsat", tout << "processing variable ";
@ -1186,23 +1235,102 @@ namespace nlsat {
lbool check() {
TRACE("nlsat_smt2", display_smt2(tout););
TRACE("nlsat_fd", tout << "is_full_dimensional: " << is_full_dimensional() << "\n";);
m_xk = null_var;
init_search();
m_explain.set_full_dimensional(is_full_dimensional());
if (m_random_order) {
bool reordered = false;
if (!can_reorder()) {
}
else if (m_random_order) {
shuffle_vars();
reordered = true;
}
else if (m_reorder) {
heuristic_reorder();
reordered = true;
}
sort_watched_clauses();
lbool r = search();
CTRACE("nlsat_model", r == l_true, tout << "model before restore order\n"; display_assignment(tout); display_bool_assignment(tout););
if (m_reorder)
CTRACE("nlsat_model", r == l_true, tout << "model before restore order\n"; display_assignment(tout););
if (reordered)
restore_order();
CTRACE("nlsat_model", r == l_true, tout << "model\n"; display_assignment(tout); display_bool_assignment(tout););
CTRACE("nlsat_model", r == l_true, tout << "model\n"; display_assignment(tout););
CTRACE("nlsat", r == l_false, display(tout););
return r;
}
void init_search() {
undo_until_empty();
while (m_scope_lvl > 0) {
undo_new_level();
}
m_xk = null_var;
for (unsigned i = 0; i < m_bvalues.size(); ++i) {
m_bvalues[i] = l_undef;
}
m_assignment.reset();
}
lbool check(literal_vector& assumptions) {
literal_vector result;
unsigned sz = assumptions.size();
literal const* ptr = assumptions.c_ptr();
for (unsigned i = 0; i < sz; ++i) {
mk_clause(1, ptr+i, (assumption)(ptr+i));
}
lbool r = check();
if (r == l_false) {
// collect used literals from m_lemma_assumptions
vector<assumption, false> deps;
m_asm.linearize(m_lemma_assumptions.get(), deps);
for (unsigned i = 0; i < deps.size(); ++i) {
literal const* lp = (literal const*)(deps[i]);
if (ptr <= lp && lp < ptr + sz) {
result.push_back(*lp);
}
}
}
collect(assumptions, m_clauses);
collect(assumptions, m_learned);
assumptions.reset();
assumptions.append(result);
return r;
}
void collect(literal_vector const& assumptions, clause_vector& clauses) {
unsigned n = clauses.size();
unsigned j = 0;
for (unsigned i = 0; i < n; i++) {
clause * c = clauses[i];
if (collect(assumptions, *c)) {
del_clause(c);
}
else {
clauses[j] = c;
j++;
}
}
clauses.shrink(j);
}
bool collect(literal_vector const& assumptions, clause const& c) {
unsigned sz = assumptions.size();
literal const* ptr = assumptions.c_ptr();
_assumption_set asms = static_cast<_assumption_set>(c.assumptions());
if (asms == 0) {
return false;
}
vector<assumption, false> deps;
m_asm.linearize(asms, deps);
bool found = false;
for (unsigned i = 0; !found && i < deps.size(); ++i) {
found = ptr <= deps[i] && deps[i] < ptr + sz;
}
return found;
}
// -----------------------
//
// Conflict Resolution
@ -1447,7 +1575,7 @@ namespace nlsat {
TRACE("nlsat", tout << "resolve, conflicting clause:\n"; display(tout, *conflict_clause); tout << "\n";
tout << "xk: "; if (m_xk != null_var) m_display_var(tout, m_xk); else tout << "<null>"; tout << "\n";
tout << "scope_lvl: " << scope_lvl() << "\n";
tout << "current assignment\n"; display_assignment(tout); display_bool_assignment(tout););
tout << "current assignment\n"; display_assignment(tout););
// static unsigned counter = 0;
// counter++;
@ -1588,7 +1716,7 @@ namespace nlsat {
conflict_clause = new_cls;
goto start;
}
TRACE("nlsat_resolve_done", display_assignment(tout); display_bool_assignment(tout););
TRACE("nlsat_resolve_done", display_assignment(tout););
return true;
}
@ -1801,6 +1929,15 @@ namespace nlsat {
reorder(p.size(), p.c_ptr());
}
bool can_reorder() const {
for (unsigned i = 0; i < m_atoms.size(); ++i) {
if (m_atoms[i]) {
if (m_atoms[i]->is_root_atom()) return false;
}
}
return true;
}
/**
\brief Reorder variables using the giving permutation.
p maps internal variables to their new positions
@ -1921,6 +2058,9 @@ namespace nlsat {
void reinit_cache() {
reinit_cache(m_clauses);
reinit_cache(m_learned);
for (unsigned i = 0; i < m_atoms.size(); ++i) {
reinit_cache(m_atoms[i]);
}
}
void reinit_cache(clause_vector const & cs) {
unsigned sz = cs.size();
@ -1934,10 +2074,13 @@ namespace nlsat {
}
void reinit_cache(literal l) {
bool_var b = l.var();
atom * a = m_atoms[b];
if (a == 0)
return;
if (a->is_ineq_atom()) {
reinit_cache(m_atoms[b]);
}
void reinit_cache(atom* a) {
if (a == 0) {
}
else if (a->is_ineq_atom()) {
var max = 0;
unsigned sz = to_ineq_atom(a)->size();
for (unsigned i = 0; i < sz; i++) {
@ -2073,7 +2216,7 @@ namespace nlsat {
//
// -----------------------
void display_assignment(std::ostream & out, display_var_proc const & proc) const {
void display_num_assignment(std::ostream & out, display_var_proc const & proc) const {
for (var x = 0; x < num_vars(); x++) {
if (m_assignment.is_assigned(x)) {
proc(out, x);
@ -2084,7 +2227,7 @@ namespace nlsat {
}
}
void display_bool_assignment(std::ostream & out, display_var_proc const & proc) const {
void display_bool_assignment(std::ostream & out) const {
unsigned sz = m_atoms.size();
for (bool_var b = 0; b < sz; b++) {
if (m_atoms[b] == 0 && m_bvalues[b] != l_undef) {
@ -2112,12 +2255,13 @@ namespace nlsat {
return !first;
}
void display_assignment(std::ostream & out) const {
display_assignment(out, m_display_var);
void display_num_assignment(std::ostream & out) const {
display_num_assignment(out, m_display_var);
}
void display_bool_assignment(std::ostream & out) const {
display_bool_assignment(out, m_display_var);
void display_assignment(std::ostream& out) const {
display_bool_assignment(out);
display_num_assignment(out);
}
void display(std::ostream & out, ineq_atom const & a, display_var_proc const & proc, bool use_star = false) const {
@ -2511,6 +2655,7 @@ namespace nlsat {
void display(std::ostream & out) const {
display(out, m_display_var);
display_assignment(out);
}
void display_vars(std::ostream & out) const {
@ -2562,6 +2707,20 @@ namespace nlsat {
return m_imp->check();
}
lbool solver::check(literal_vector& assumptions) {
return m_imp->check(assumptions);
}
void solver::reset() {
m_imp->reset();
}
void solver::updt_params(params_ref const & p) {
m_imp->updt_params(p);
}
void solver::collect_param_descrs(param_descrs & d) {
algebraic_numbers::manager::collect_param_descrs(d);
nlsat_params::collect_param_descrs(d);
@ -2583,6 +2742,10 @@ namespace nlsat {
m_imp->m_display_var.m_proc = &proc;
}
unsigned solver::num_vars() const {
return m_imp->num_vars();
}
bool solver::is_int(var x) const {
return m_imp->is_int(x);
}
@ -2590,10 +2753,61 @@ namespace nlsat {
bool_var solver::mk_bool_var() {
return m_imp->mk_bool_var();
}
literal solver::mk_true() {
return literal(0, false);
}
atom * solver::bool_var2atom(bool_var b) {
return m_imp->m_atoms[b];
}
void solver::vars(literal l, var_vector& vs) {
m_imp->vars(l, vs);
}
atom_vector const& solver::get_atoms() {
return m_imp->m_atoms;
}
atom_vector const& solver::get_var2eq() {
return m_imp->m_var2eq;
}
evaluator& solver::get_evaluator() {
return m_imp->m_evaluator;
}
explain& solver::get_explain() {
return m_imp->m_explain;
}
void solver::reorder(unsigned sz, var const* p) {
m_imp->reorder(sz, p);
}
void solver::restore_order() {
m_imp->restore_order();
}
void solver::set_rvalues(assignment const& as) {
m_imp->m_assignment.copy(as);
}
void solver::get_rvalues(assignment& as) {
as.copy(m_imp->m_assignment);
}
void solver::get_bvalues(svector<lbool>& vs) {
vs.reset();
vs.append(m_imp->m_bvalues);
}
void solver::set_bvalues(svector<lbool> const& vs) {
m_imp->m_bvalues.reset();
m_imp->m_bvalues.append(vs);
m_imp->m_bvalues.resize(m_imp->m_atoms.size(), l_undef);
}
var solver::mk_var(bool is_int) {
return m_imp->mk_var(is_int);
@ -2631,10 +2845,21 @@ namespace nlsat {
m_imp->display(out, l);
}
void solver::display(std::ostream & out, unsigned n, literal const* ls) const {
for (unsigned i = 0; i < n; ++i) {
display(out, ls[i]);
out << "; ";
}
}
void solver::display(std::ostream & out, var x) const {
m_imp->m_display_var(out, x);
}
void solver::display(std::ostream & out, atom const& a) const {
m_imp->display(out, a, m_imp->m_display_var);
}
display_var_proc const & solver::display_proc() const {
return m_imp->m_display_var;
}

View file

@ -28,6 +28,9 @@ Revision History:
namespace nlsat {
class evaluator;
class explain;
class solver {
struct imp;
imp * m_imp;
@ -63,7 +66,9 @@ namespace nlsat {
nonlinear arithmetic atom.
*/
bool_var mk_bool_var();
literal mk_true();
/**
\brief Create a real/integer variable.
*/
@ -121,6 +126,48 @@ namespace nlsat {
*/
atom * bool_var2atom(bool_var b);
/**
\brief extract free variables from literal.
*/
void vars(literal l, var_vector& vs);
/**
\brief provide access to atoms. Used by explain.
*/
atom_vector const& get_atoms();
/**
\brief Access var -> asserted equality.
*/
atom_vector const& get_var2eq();
/**
\brief expose evaluator.
*/
evaluator& get_evaluator();
/**
\brief Access explanation module.
*/
explain& get_explain();
/**
\brief Access assignments to variables.
*/
void get_rvalues(assignment& as);
void set_rvalues(assignment const& as);
void get_bvalues(svector<lbool>& vs);
void set_bvalues(svector<lbool> const& vs);
/**
\brief reorder variables.
*/
void reorder(unsigned sz, var const* permutation);
void restore_order();
/**
\brief Return number of integer/real variables
*/
@ -135,6 +182,8 @@ namespace nlsat {
// -----------------------
lbool check();
lbool check(literal_vector& assumptions);
// -----------------------
//
// Model
@ -154,6 +203,7 @@ namespace nlsat {
void updt_params(params_ref const & p);
static void collect_param_descrs(param_descrs & d);
void reset();
void collect_statistics(statistics & st);
void reset_statistics();
void display_status(std::ostream & out) const;
@ -174,6 +224,10 @@ namespace nlsat {
*/
void display(std::ostream & out, literal l) const;
void display(std::ostream & out, unsigned n, literal const* ls) const;
void display(std::ostream & out, atom const& a) const;
/**
\brief Display variable
*/

View file

@ -111,6 +111,21 @@ namespace nlsat {
struct eq_proc { bool operator()(ineq_atom const * a1, ineq_atom const * a2) const; };
};
inline std::ostream& operator<<(std::ostream& out, atom::kind k) {
switch (k) {
case atom::EQ: return out << "=";
case atom::LT: return out << "<";
case atom::GT: return out << ">";
case atom::ROOT_EQ: return out << "= root";
case atom::ROOT_LT: return out << "< root";
case atom::ROOT_LE: return out << "<= root";
case atom::ROOT_GT: return out << "> root";
case atom::ROOT_GE: return out << ">= root";
default: return out << (int)k;
}
return out;
}
class root_atom : public atom {
friend class solver;
var m_x;

View file

@ -29,7 +29,9 @@ Notes:
#include"expr2var.h"
#include"arith_decl_plugin.h"
#include"tactic.h"
#include"ast_smt2_pp.h"
#include"ast_pp.h"
#include"polynomial.h"
#include"algebraic_numbers.h"
struct goal2nlsat::imp {
struct nlsat_expr2polynomial : public expr2polynomial {
@ -124,7 +126,7 @@ struct goal2nlsat::imp {
m_qm.neg(d2);
polynomial_ref p(m_pm);
p = m_pm.addmul(d1, m_pm.mk_unit(), p1, d2, m_pm.mk_unit(), p2);
TRACE("goal2nlsat_bug", tout << "p: " << p << "\nk: " << k << "\n";);
TRACE("goal2nlsat_bug", tout << mk_pp(f, m) << " p: " << p << "\nk: " << k << "\n";);
if (is_const(p)) {
int sign;
if (is_zero(p))
@ -192,7 +194,7 @@ struct goal2nlsat::imp {
switch (to_app(f)->get_decl_kind()) {
case OP_TRUE:
case OP_FALSE:
TRACE("goal2nlsat", tout << "f: " << mk_ismt2_pp(f, m) << "\n";);
TRACE("goal2nlsat", tout << "f: " << mk_pp(f, m) << "\n";);
throw tactic_exception("apply simplify before applying nlsat");
case OP_AND:
case OP_OR:
@ -257,6 +259,7 @@ struct goal2nlsat::imp {
process(g.form(i), g.dep(i));
}
}
};
struct goal2nlsat::scoped_set_imp {
@ -289,4 +292,154 @@ void goal2nlsat::operator()(goal const & g, params_ref const & p, nlsat::solver
scoped_set_imp setter(*this, local_imp);
local_imp(g);
}
struct nlsat2goal::imp {
ast_manager& m;
arith_util a;
u_map<expr*> const* m_x2t;
public:
imp(ast_manager& m):m(m),a(m) {}
expr_ref operator()(nlsat::solver& s, u_map<expr*> const& b2a, u_map<expr*> const& x2t, nlsat::literal l) {
m_x2t = &x2t;
expr_ref result(m);
expr* t;
if (b2a.find(l.var(), t)) {
result = t;
}
else {
nlsat::atom const* at = s.bool_var2atom(l.var());
SASSERT(at != 0);
if (at->is_ineq_atom()) {
nlsat::ineq_atom const* ia = to_ineq_atom(at);
unsigned sz = ia->size();
expr_ref_vector ps(m);
bool is_int = true;
for (unsigned i = 0; is_int && i < sz; ++i) {
is_int = poly_is_int(ia->p(i));
}
for (unsigned i = 0; i < sz; ++i) {
polynomial::polynomial* p = ia->p(i);
expr_ref t = poly2expr(s, p, is_int);
if (ia->is_even(i)) {
t = a.mk_power(t, a.mk_numeral(rational(2), a.is_int(t)));
}
ps.push_back(t);
}
result = a.mk_mul_simplify(ps);
expr_ref zero(m);
zero = a.mk_numeral(rational(0), a.is_int(result));
switch (ia->get_kind()) {
case nlsat::atom::EQ:
result = m.mk_eq(result, zero);
break;
case nlsat::atom::LT:
if (l.sign()) {
l.neg();
result = a.mk_ge(result, zero);
}
else {
result = a.mk_lt(result, zero);
}
break;
case nlsat::atom::GT:
if (l.sign()) {
l.neg();
result = a.mk_le(result, zero);
}
else {
result = a.mk_gt(result, zero);
}
break;
default:
UNREACHABLE();
}
}
else {
//nlsat::root_atom const* ra = nlsat::to_root_atom(at);
//ra->i();
//expr_ref p = poly2expr(s, ra->p());
//expr* x = m_x2t->find(ra->x());
std::ostringstream strm;
s.display(strm, l.sign()?~l:l);
result = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort());
}
}
if (l.sign()) {
result = m.mk_not(result);
}
return result;
}
expr_ref poly2expr(nlsat::solver& s, polynomial::polynomial* p, bool is_int) {
expr_ref result(m);
unsigned sz = polynomial::manager::size(p);
expr_ref_vector args(m);
for (unsigned i = 0; i < sz; ++i) {
args.push_back(mono2expr(s,
polynomial::manager::coeff(p, i),
polynomial::manager::get_monomial(p, i), is_int));
}
result = a.mk_add_simplify(args);
return result;
}
expr_ref mono2expr(nlsat::solver& s, polynomial::numeral const& c, polynomial::monomial* mon, bool is_int) {
expr_ref result(m);
expr_ref_vector args(m);
unsigned sz = polynomial::manager::size(mon);
for (unsigned i = 0; i < sz; ++i) {
unsigned d = polynomial::manager::degree(mon, i);
expr* t = m_x2t->find(polynomial::manager::get_var(mon, i));
SASSERT(d >= 1);
if (d == 1) {
args.push_back(t);
}
else {
args.push_back(a.mk_power(t, a.mk_numeral(rational(d), a.is_int(t))));
}
}
if (!s.pm().m().is_one(c)) {
args.push_back(a.mk_numeral(c, is_int));
}
result = a.mk_mul_simplify(args);
return result;
}
bool poly_is_int(polynomial::polynomial* p) {
bool is_int = true;
unsigned sz = polynomial::manager::size(p);
for (unsigned i = 0; is_int && i < sz; ++i) {
is_int = mono_is_int(polynomial::manager::get_monomial(p, i));
}
return is_int;
}
bool mono_is_int(polynomial::monomial* mon) {
bool is_int = true;
unsigned sz = polynomial::manager::size(mon);
for (unsigned i = 0; is_int && i < sz; ++i) {
is_int = a.is_int(m_x2t->find(polynomial::manager::get_var(mon, i)));
}
return is_int;
}
};
nlsat2goal::nlsat2goal(ast_manager& m) {
m_imp = alloc(imp, m);
}
nlsat2goal::~nlsat2goal() {
dealloc(m_imp);
}
expr_ref nlsat2goal::operator()(nlsat::solver& s, u_map<expr*> const& b2a, u_map<expr*> const& x2t, nlsat::literal l) {
return (*m_imp)(s, b2a, x2t, l);
}

View file

@ -57,17 +57,16 @@ class nlsat2goal {
struct imp;
imp * m_imp;
public:
nlsat2goal();
nlsat2goal(ast_manager& m);
~nlsat2goal();
static void collect_param_descrs(param_descrs & r);
/**
\brief Translate the state of the nlsat engine back into a goal.
*/
void operator()(nlsat::solver const & s, expr2var const & a2b, expr2var const & t2x,
params_ref const & p, goal & g, model_converter_ref & mc);
\brief Translate a literal into a formula.
*/
expr_ref operator()(nlsat::solver& s, u_map<expr*> const& b2a, u_map<expr*> const& x2t, nlsat::literal l);
};
#endif

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